cogpit-memory 0.3.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,10 +45,39 @@ 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
- var AGENT_KINDS = ["codex", "copilot", "claude"];
51
+ var AGENT_KINDS = ["acp", "codex", "copilot", "claude"];
52
+
53
+ // src/lib/instances.ts
54
+ function instanceSessionId(instanceId, nativeId) {
55
+ if (instanceId === "default") return nativeId;
56
+ const bytes = new TextEncoder().encode(nativeId);
57
+ const encoded = btoa(Array.from(bytes, (byte) => String.fromCharCode(byte)).join("")).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
58
+ return `i-${instanceId}__${encoded}`;
59
+ }
60
+ function splitInstanceSessionId(id) {
61
+ const match = /^i-([A-Za-z0-9-]+)__([A-Za-z0-9_-]+)$/.exec(id);
62
+ if (!match) return { instanceId: "default", nativeId: id };
63
+ try {
64
+ const bytes = Uint8Array.from(atob(match[2].replace(/-/g, "+").replace(/_/g, "/")), (character) => character.charCodeAt(0));
65
+ return { instanceId: match[1], nativeId: new TextDecoder("utf-8", { fatal: true }).decode(bytes) };
66
+ } catch {
67
+ throw new Error("Invalid instance session ID");
68
+ }
69
+ }
70
+ function instanceDirName(instanceId, nativeDirName) {
71
+ return instanceId === "default" ? nativeDirName : `instance__${instanceId}__${nativeDirName}`;
72
+ }
73
+ function splitInstanceDirName(dirName) {
74
+ const match = /^instance__([A-Za-z0-9-]+)__(.+)$/.exec(dirName ?? "");
75
+ return match ? { instanceId: match[1], nativeDirName: match[2] } : { instanceId: "default", nativeDirName: dirName ?? "" };
76
+ }
77
+ function scopeParsedSession(session, instanceId) {
78
+ if (instanceId === "default") return session;
79
+ return { ...session, instanceId, sessionId: instanceSessionId(instanceId, splitInstanceSessionId(session.sessionId).nativeId), ...session.branchedFrom ? { branchedFrom: { ...session.branchedFrom, sessionId: instanceSessionId(instanceId, splitInstanceSessionId(session.branchedFrom.sessionId).nativeId) } } : {} };
80
+ }
52
81
 
53
82
  // src/lib/agent-descriptors.ts
54
83
  var SESSION_UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
@@ -75,14 +104,26 @@ function base64DirNameCodec(prefix) {
75
104
  return {
76
105
  lossy: false,
77
106
  owns: (dirName) => typeof dirName === "string" && dirName.startsWith(prefix),
107
+ recognizes: (dirName) => {
108
+ const cwd = decodeBase64DirName(prefix, dirName);
109
+ return cwd !== null && cwd !== "" && encodeBase64DirName(prefix, cwd) === dirName;
110
+ },
78
111
  encode: (cwd) => encodeBase64DirName(prefix, cwd),
79
112
  decode: (dirName) => decodeBase64DirName(prefix, dirName)
80
113
  };
81
114
  }
82
115
  function sessionIdFromJsonlName(fileName) {
83
- const match = new RegExp(`(${SESSION_UUID})\\.jsonl$`, "i").exec(fileName);
116
+ const match = new RegExp(`(${SESSION_UUID})\\.jsonl(?:\\.zst)?$`, "i").exec(fileName);
84
117
  return match ? match[1] : null;
85
118
  }
119
+ function ownTranscriptRoot(sessionId) {
120
+ return sessionId ? { rootSessionId: sessionId.toLowerCase(), isRootTranscript: true } : null;
121
+ }
122
+ function plainPathSegments(relativePath) {
123
+ const segments = relativePath.split("/");
124
+ const plain = segments.every((segment) => segment !== "" && segment !== "." && segment !== ".." && !segment.includes("\\"));
125
+ return plain ? segments : null;
126
+ }
86
127
  var jsonlPathUrlCodec = {
87
128
  urlId: (fileName) => fileName.replace(/\.jsonl$/, ""),
88
129
  fileNameFromUrlId: (urlId) => urlId.endsWith(".jsonl") ? urlId : `${urlId}.jsonl`
@@ -100,6 +141,17 @@ var ARGV_SESSION_ID = "[0-9a-f-]{36}";
100
141
  var CODEX_DIR_PREFIX = "codex__";
101
142
  var COPILOT_DIR_PREFIX = "copilot__";
102
143
  var CLAUDE_PERMISSION_MODES = /* @__PURE__ */ new Set(["default", "plan", "acceptEdits", "dontAsk", "auto"]);
144
+ var CLAUDE_SESSION_CHILD_DIRS = /* @__PURE__ */ new Set(["subagents", "workflows"]);
145
+ function claudeTranscriptRoot(relativePath) {
146
+ const segments = plainPathSegments(relativePath);
147
+ if (!segments) return null;
148
+ const [root, childDir] = segments;
149
+ if (segments.length === 1) {
150
+ const sessionId = root.replace(/\.jsonl$/, "");
151
+ return sessionId !== root && isSessionUuid(sessionId) ? ownTranscriptRoot(sessionId) : null;
152
+ }
153
+ return segments.length > 2 && CLAUDE_SESSION_CHILD_DIRS.has(childDir) && isSessionUuid(root) ? { rootSessionId: root.toLowerCase(), isRootTranscript: false } : null;
154
+ }
103
155
  var claude = {
104
156
  kind: "claude",
105
157
  displayName: "Claude Code",
@@ -110,6 +162,8 @@ var claude = {
110
162
  // registry checks the prefixed agents first, so this is only ever reached
111
163
  // as the terminal arm.
112
164
  owns: (dirName) => typeof dirName === "string" && !dirName.startsWith(CODEX_DIR_PREFIX) && !dirName.startsWith(COPILOT_DIR_PREFIX),
165
+ // An absolute path starts with `/` or `\` (`-`) or a drive (`C:\` → `C--`); a drive root alone is `C-`.
166
+ recognizes: (dirName) => /^(?:(?:-|[A-Za-z]--)[A-Za-z0-9-]*|[A-Za-z]-)$/.test(dirName),
113
167
  /**
114
168
  * Claude Code's own convention: every character outside `[A-Za-z0-9]`
115
169
  * becomes `-`, so `/Users/x/proj` and `C:\Users\x\proj` both collapse into a
@@ -127,10 +181,12 @@ var claude = {
127
181
  return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
128
182
  }
129
183
  },
184
+ projectWorktreeDir: ".claude/worktrees",
130
185
  sessionFile: {
131
186
  name: (sessionId) => `${sessionId}.jsonl`,
132
187
  sessionId: sessionIdFromJsonlName,
133
- ...jsonlPathUrlCodec
188
+ ...jsonlPathUrlCodec,
189
+ transcriptRoot: claudeTranscriptRoot
134
190
  },
135
191
  metadataFromHead: true,
136
192
  resume: {
@@ -165,6 +221,7 @@ var claude = {
165
221
  bundledBySdk: true,
166
222
  homeDirName: ".claude",
167
223
  homeEnvVar: null,
224
+ sdkHomeEnvVar: "CLAUDE_CONFIG_DIR",
168
225
  installMarker: "projects",
169
226
  homeIsDiscoverable: false,
170
227
  process: {
@@ -176,7 +233,8 @@ var claude = {
176
233
  rootDirName: ".claude",
177
234
  instructions: [
178
235
  { in: "scope", path: "CLAUDE.md", scopes: ["global", "project"] },
179
- { in: "root", path: "CLAUDE.md", label: ".claude/CLAUDE.md", scopes: ["project"] }
236
+ { in: "root", path: "CLAUDE.md", label: ".claude/CLAUDE.md", scopes: ["project"] },
237
+ { in: "scope", path: "AGENTS.md", scopes: ["project"], fallback: true }
180
238
  ],
181
239
  settings: [
182
240
  { in: "root", path: "settings.json", scopes: ["global"] },
@@ -221,9 +279,12 @@ var claude = {
221
279
  nativeRewind: false,
222
280
  fileCheckpoints: true,
223
281
  reasoningEffort: true,
282
+ configurableContextWindow: false,
224
283
  fastTier: true,
284
+ lowPriorityInTerminal: true,
225
285
  imageInput: true,
226
- midTurnSteering: false,
286
+ midTurnSteering: true,
287
+ activeNotifications: true,
227
288
  stopSession: true,
228
289
  ultracode: true,
229
290
  contextWindow: true,
@@ -231,6 +292,7 @@ var claude = {
231
292
  accountSwitching: true,
232
293
  modelFallbackNotices: true,
233
294
  autoPermissionMode: "per-model",
295
+ toolPermissionRules: true,
234
296
  settingsApply: "live",
235
297
  turnLiveness: "transcript",
236
298
  tokenStreaming: true,
@@ -247,6 +309,7 @@ var codex = {
247
309
  displayName: "Codex",
248
310
  binName: "codex",
249
311
  dirName: base64DirNameCodec(CODEX_DIR_PREFIX),
312
+ projectWorktreeDir: null,
250
313
  sessionFile: {
251
314
  /**
252
315
  * Codex nests rollouts by local date:
@@ -263,7 +326,9 @@ var codex = {
263
326
  },
264
327
  sessionId: sessionIdFromJsonlName,
265
328
  // The date nesting is unrecoverable from the id, so the URL keeps the path.
266
- ...jsonlPathUrlCodec
329
+ ...jsonlPathUrlCodec,
330
+ // A sub-agent is a rollout of its own, linked to its parent only in its header.
331
+ transcriptRoot: (relativePath) => plainPathSegments(relativePath) ? ownTranscriptRoot(sessionIdFromJsonlName(relativePath)) : null
267
332
  },
268
333
  // A rollout's header carries no turn count and no last user message; both
269
334
  // only settle at the end of the file.
@@ -276,6 +341,7 @@ var codex = {
276
341
  permissions: (permissions) => {
277
342
  const mode = permissions?.mode || "default";
278
343
  if (mode === "bypassPermissions") return ["--dangerously-bypass-approvals-and-sandbox"];
344
+ if (mode === "auto") return ["--approve-for-me"];
279
345
  return [
280
346
  "--sandbox",
281
347
  mode === "plan" ? "read-only" : "workspace-write",
@@ -304,6 +370,7 @@ var codex = {
304
370
  bundledBySdk: false,
305
371
  homeDirName: ".codex",
306
372
  homeEnvVar: "CODEX_HOME",
373
+ sessionIdEnvVar: "CODEX_THREAD_ID",
307
374
  installMarker: "",
308
375
  homeIsDiscoverable: true,
309
376
  process: {
@@ -335,7 +402,7 @@ var codex = {
335
402
  extendedContext: null
336
403
  },
337
404
  capabilities: {
338
- worktrees: false,
405
+ worktrees: true,
339
406
  mcp: false,
340
407
  slashCommands: false,
341
408
  workflows: false,
@@ -349,16 +416,20 @@ var codex = {
349
416
  nativeRewind: false,
350
417
  fileCheckpoints: false,
351
418
  reasoningEffort: true,
419
+ configurableContextWindow: true,
352
420
  fastTier: true,
421
+ lowPriorityInTerminal: false,
353
422
  imageInput: true,
354
423
  midTurnSteering: true,
424
+ activeNotifications: true,
355
425
  stopSession: false,
356
426
  ultracode: false,
357
427
  contextWindow: false,
358
428
  externalProcesses: false,
359
429
  accountSwitching: false,
360
430
  modelFallbackNotices: false,
361
- autoPermissionMode: "never",
431
+ autoPermissionMode: "always",
432
+ toolPermissionRules: true,
362
433
  settingsApply: "next-turn",
363
434
  turnLiveness: "runtime",
364
435
  tokenStreaming: true,
@@ -367,24 +438,25 @@ var codex = {
367
438
  namedSessions: false
368
439
  }
369
440
  };
441
+ function copilotSessionId(fileName) {
442
+ const match = new RegExp(`^(${SESSION_UUID})/events\\.jsonl$`, "i").exec(fileName);
443
+ return match ? match[1] : null;
444
+ }
370
445
  var copilot = {
371
446
  kind: "copilot",
372
447
  displayName: "GitHub Copilot CLI",
373
448
  binName: "copilot",
374
449
  dirName: base64DirNameCodec(COPILOT_DIR_PREFIX),
450
+ projectWorktreeDir: null,
375
451
  sessionFile: {
376
452
  /** Copilot keeps one directory per session: `<uuid>/events.jsonl`. */
377
453
  name: (sessionId) => `${sessionId}/events.jsonl`,
378
- sessionId: (fileName) => {
379
- const match = new RegExp(`^(${SESSION_UUID})/events\\.jsonl$`, "i").exec(fileName);
380
- return match ? match[1] : null;
381
- },
454
+ sessionId: copilotSessionId,
382
455
  // `<id>/events.jsonl` rebuilds from the id, so URLs stay short.
383
- urlId: (fileName) => {
384
- const match = new RegExp(`^(${SESSION_UUID})/events\\.jsonl$`, "i").exec(fileName);
385
- return match ? match[1] : fileName.replace(/\.jsonl$/, "");
386
- },
387
- fileNameFromUrlId: (urlId) => urlId.endsWith(".jsonl") ? urlId : `${urlId}/events.jsonl`
456
+ urlId: (fileName) => copilotSessionId(fileName) ?? fileName.replace(/\.jsonl$/, ""),
457
+ fileNameFromUrlId: (urlId) => urlId.endsWith(".jsonl") ? urlId : `${urlId}/events.jsonl`,
458
+ // Sub-agents are events inside the parent transcript, so every file is a root.
459
+ transcriptRoot: (relativePath) => ownTranscriptRoot(copilotSessionId(relativePath))
388
460
  },
389
461
  metadataFromHead: true,
390
462
  resume: {
@@ -466,9 +538,12 @@ var copilot = {
466
538
  fileCheckpoints: false,
467
539
  // Effort is only offered for models whose catalog entry advertises it.
468
540
  reasoningEffort: false,
541
+ configurableContextWindow: false,
469
542
  fastTier: false,
543
+ lowPriorityInTerminal: false,
470
544
  imageInput: false,
471
545
  midTurnSteering: true,
546
+ activeNotifications: true,
472
547
  stopSession: true,
473
548
  ultracode: false,
474
549
  contextWindow: false,
@@ -476,6 +551,7 @@ var copilot = {
476
551
  accountSwitching: false,
477
552
  modelFallbackNotices: false,
478
553
  autoPermissionMode: "always",
554
+ toolPermissionRules: true,
479
555
  settingsApply: "next-turn",
480
556
  turnLiveness: "runtime",
481
557
  tokenStreaming: false,
@@ -483,21 +559,56 @@ var copilot = {
483
559
  namedSessions: true
484
560
  }
485
561
  };
562
+ var acp = {
563
+ ...copilot,
564
+ kind: "acp",
565
+ displayName: "ACP agent",
566
+ binName: "acp",
567
+ dirName: base64DirNameCodec("acp__"),
568
+ sessionFile: { name: (id) => `${id}.jsonl`, sessionId: sessionIdFromJsonlName, ...jsonlPathUrlCodec, transcriptRoot: (path) => {
569
+ const segments = plainPathSegments(path);
570
+ return segments?.length === 1 ? ownTranscriptRoot(sessionIdFromJsonlName(path)) : null;
571
+ } },
572
+ resume: { command: () => "Resume this session in Cogpit", args: () => [] },
573
+ launchArgs: { permissions: () => [], model: () => [], effort: () => [], fastTier: () => [] },
574
+ cli: { ...copilot.cli, packageName: "", homebrew: null, wingetId: null, selfUpdate: null, requiresConfiguration: true, homeDirName: ".cogpit-acp", homeEnvVar: "COGPIT_ACP_HOME", homeIsDiscoverable: true, installMarker: "projects" },
575
+ config: { ...copilot.config, rootDirName: ".cogpit-acp", instructions: [], settings: [], skillsDir: null },
576
+ capabilities: { ...copilot.capabilities, undo: false, redo: false, nativeRewind: false, nativeFork: false, midTurnSteering: false, activeNotifications: false, externalProcesses: false, autoPermissionMode: "never", toolPermissionRules: false, namedSessions: false }
577
+ };
486
578
  var DESCRIPTORS = Object.freeze({
487
579
  claude,
488
580
  codex,
489
- copilot
581
+ copilot,
582
+ acp
490
583
  });
491
584
  function descriptorFor(kind) {
492
585
  return DESCRIPTORS[kind];
493
586
  }
494
587
  function descriptorForDirName(dirName) {
588
+ const scoped = splitInstanceDirName(dirName);
589
+ if (scoped.instanceId !== "default") {
590
+ const descriptor = descriptorForDirName(scoped.nativeDirName);
591
+ return {
592
+ ...descriptor,
593
+ dirName: { ...descriptor.dirName, encode: (cwd) => instanceDirName(scoped.instanceId, descriptor.dirName.encode(cwd)), decode: (name) => descriptor.dirName.decode(splitInstanceDirName(name).nativeDirName) },
594
+ sessionFile: { ...descriptor.sessionFile, name: (id) => descriptor.sessionFile.name(splitInstanceSessionId(id).nativeId), sessionId: (file) => {
595
+ const nativeId = descriptor.sessionFile.sessionId(file);
596
+ return nativeId ? instanceSessionId(scoped.instanceId, nativeId) : null;
597
+ }, transcriptRoot: (file) => {
598
+ const root = descriptor.sessionFile.transcriptRoot(file);
599
+ return root ? { ...root, rootSessionId: instanceSessionId(scoped.instanceId, root.rootSessionId) } : null;
600
+ } }
601
+ };
602
+ }
495
603
  for (const kind of AGENT_KINDS) {
496
604
  if (kind === "claude") continue;
497
605
  if (DESCRIPTORS[kind].dirName.owns(dirName)) return DESCRIPTORS[kind];
498
606
  }
499
607
  return claude;
500
608
  }
609
+ function isSessionUuid(value) {
610
+ return SESSION_UUID_RE.test(value);
611
+ }
501
612
 
502
613
  // src/lib/codex-exec.ts
503
614
  var JS_SIMPLE_ESCAPES = {
@@ -566,6 +677,27 @@ function readJsStringLiteral(source, startIndex) {
566
677
  return null;
567
678
  }
568
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
+
569
701
  // src/lib/messageTypeGuards.ts
570
702
  function isUserMessage(msg) {
571
703
  return msg.type === "user";
@@ -673,6 +805,36 @@ function parseAgentEnvelope(text) {
673
805
  return { sender, matched, body: matched ? unwrapped.trim() : text };
674
806
  }
675
807
 
808
+ // src/lib/toolResults.ts
809
+ function record(value) {
810
+ return value && typeof value === "object" ? value : {};
811
+ }
812
+ function toolResultMetadata(name, value) {
813
+ const result = record(value);
814
+ if (name === "Edit" || name === "Write") {
815
+ return result.staged === true ? { awaitingReview: true } : {};
816
+ }
817
+ if (name !== "Bash") return {};
818
+ const diff = record(result.bashEditDiff);
819
+ if (!Array.isArray(diff.files)) return {};
820
+ const files = [];
821
+ for (const raw of diff.files) {
822
+ const file = record(raw);
823
+ if (typeof file.filePath !== "string" || !file.filePath || !Array.isArray(file.hunks)) continue;
824
+ const hunks = [];
825
+ for (const rawHunk of file.hunks) {
826
+ const hunk = record(rawHunk);
827
+ const { oldStart, oldLines, newStart, newLines, lines } = hunk;
828
+ if (![oldStart, oldLines, newStart, newLines].every((n) => typeof n === "number" && Number.isInteger(n) && n >= 0)) continue;
829
+ if (!Array.isArray(lines) || !lines.every((line) => typeof line === "string" && /^[ +\\-]/.test(line))) continue;
830
+ hunks.push({ oldStart, oldLines, newStart, newLines, lines });
831
+ }
832
+ if (hunks.length) files.push({ filePath: file.filePath, hunks });
833
+ }
834
+ const more = typeof diff.moreFiles === "number" && Number.isInteger(diff.moreFiles) && diff.moreFiles > 0 ? diff.moreFiles : 0;
835
+ return { fileDiffs: files, ...more ? { additionalFileDiffs: more } : {} };
836
+ }
837
+
676
838
  // src/lib/turnBuilder.ts
677
839
  function extractTextFromContent(content) {
678
840
  if (typeof content === "string") return content;
@@ -700,6 +862,17 @@ function isTaskNotificationRecord(msg) {
700
862
  if (!text.includes("<task-notification>")) return false;
701
863
  return text.replace(TASK_NOTIFICATION_BLOCK_RE, "").replace(ANY_TAG_RE, "").trim() === "";
702
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
+ }
703
876
  function queuedCommandPrompt(msg) {
704
877
  if (!isAttachmentMessage(msg)) return null;
705
878
  const attachment = msg.attachment;
@@ -1040,6 +1213,16 @@ function buildTurnsWithStarts(messages) {
1040
1213
  pendingRecap = { content: msg.content, timestamp: msg.timestamp };
1041
1214
  continue;
1042
1215
  }
1216
+ if (isSystemMessage(msg) && msg.subtype === "local_command" && msg.content) {
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
+ });
1224
+ continue;
1225
+ }
1043
1226
  if (isQueueOperationMessage(msg)) {
1044
1227
  if (current && msg.operation === "enqueue" && isVisibleQueuedPrompt(msg.content)) {
1045
1228
  const parsed = parseAgentEnvelope(msg.content);
@@ -1091,6 +1274,8 @@ function buildTurnsWithStarts(messages) {
1091
1274
  if (pending) {
1092
1275
  pending.turn.toolCalls[pending.index].result = extractToolResultText(block.content);
1093
1276
  pending.turn.toolCalls[pending.index].isError = block.is_error === true;
1277
+ const call = pending.turn.toolCalls[pending.index];
1278
+ Object.assign(call, toolResultMetadata(call.name, msg.toolUseResult));
1094
1279
  pendingToolUses.delete(block.tool_use_id);
1095
1280
  }
1096
1281
  }
@@ -1111,6 +1296,7 @@ function buildTurnsWithStarts(messages) {
1111
1296
  parentToolUseId: toolUseId || void 0,
1112
1297
  agentName: taskMeta?.name ?? null,
1113
1298
  subagentType: taskMeta?.subagentType ?? null,
1299
+ ...taskMeta?.effort ? { effort: taskMeta.effort } : {},
1114
1300
  type: "assistant",
1115
1301
  content: toolUseResult.content,
1116
1302
  toolCalls: [],
@@ -1249,15 +1435,12 @@ function buildTurnsWithStarts(messages) {
1249
1435
  current.toolCalls.push(tc);
1250
1436
  msgToolCalls.push(tc);
1251
1437
  pendingToolUses.set(block.id, { turn: current, index: idx });
1252
- if (block.name === "Task" || block.name === "Agent") {
1438
+ if (isTaskToolName(block.name)) {
1253
1439
  const input = block.input;
1254
1440
  if (input.run_in_background === true) {
1255
1441
  backgroundAgentParentIds.add(block.id);
1256
1442
  }
1257
- taskMetaMap.set(block.id, {
1258
- name: input.name ?? null,
1259
- subagentType: input.subagent_type ?? null
1260
- });
1443
+ taskMetaMap.set(block.id, readTaskMeta(input));
1261
1444
  }
1262
1445
  }
1263
1446
  }
@@ -1268,6 +1451,7 @@ function buildTurnsWithStarts(messages) {
1268
1451
  if (isProgressMessage(msg) && msg.data.type === "agent_progress") {
1269
1452
  const data = msg.data;
1270
1453
  const parentId = msg.parentToolUseID ?? "";
1454
+ const ownToolUseId = data.toolUseId ?? parentId;
1271
1455
  let subAgentUsage = null;
1272
1456
  if (data.message.type === "assistant") {
1273
1457
  const innerMsg = data.message.message;
@@ -1284,12 +1468,14 @@ function buildTurnsWithStarts(messages) {
1284
1468
  }
1285
1469
  }
1286
1470
  const innerModel = data.message.type === "assistant" ? data.message.message.model ?? null : null;
1287
- const taskMeta = taskMetaMap.get(parentId);
1471
+ const taskMeta = taskMetaMap.get(ownToolUseId);
1288
1472
  const agentMsg = {
1289
1473
  agentId: data.agentId,
1290
- parentToolUseId: parentId || void 0,
1474
+ parentToolUseId: ownToolUseId || void 0,
1475
+ ...data.parentAgentId ? { parentAgentId: data.parentAgentId } : {},
1476
+ ...taskMeta?.effort ? { effort: taskMeta.effort } : {},
1291
1477
  agentName: taskMeta?.name ?? null,
1292
- subagentType: taskMeta?.subagentType ?? null,
1478
+ subagentType: taskMeta?.subagentType ?? data.subagentType ?? null,
1293
1479
  type: data.message.type,
1294
1480
  content: data.message.message.content,
1295
1481
  toolCalls: [],
@@ -1309,6 +1495,7 @@ function buildTurnsWithStarts(messages) {
1309
1495
  } else if (block.type === "text") {
1310
1496
  agentMsg.text.push(block.text);
1311
1497
  } else if (block.type === "tool_use") {
1498
+ if (isTaskToolName(block.name)) taskMetaMap.set(block.id, readTaskMeta(block.input));
1312
1499
  agentMsg.toolCalls.push({
1313
1500
  id: block.id,
1314
1501
  name: block.name,
@@ -1401,11 +1588,19 @@ function buildTurns(messages) {
1401
1588
  function isClaudeSessionText() {
1402
1589
  return true;
1403
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
+ }
1404
1599
  function parseRecords(lines) {
1405
1600
  const messages = [];
1406
1601
  for (const line of lines) {
1407
1602
  const trimmed = line.trim();
1408
- if (!trimmed) continue;
1603
+ if (!trimmed || isClaudeNoiseLine(trimmed)) continue;
1409
1604
  try {
1410
1605
  messages.push(JSON.parse(trimmed));
1411
1606
  } catch {
@@ -1510,21 +1705,24 @@ function userMessageTexts(msg) {
1510
1705
  }
1511
1706
  function collectClaudeBackgroundWork(rawMessages) {
1512
1707
  const launches = [];
1513
- const resolved = /* @__PURE__ */ new Set();
1708
+ const resolvedAt = /* @__PURE__ */ new Map();
1514
1709
  const queuedIds = /* @__PURE__ */ new Set();
1515
1710
  const deliveredIds = /* @__PURE__ */ new Set();
1516
- 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) {
1517
1715
  if (!text.includes(TASK_NOTIFICATION_MARKER)) return;
1518
1716
  for (const match of text.matchAll(TASK_ID_RE)) {
1519
- resolved.add(match[1]);
1717
+ resolve2(match[1], index);
1520
1718
  sink?.add(match[1]);
1521
1719
  }
1522
1720
  for (const match of text.matchAll(TOOL_USE_ID_RE)) {
1523
- resolved.add(match[1]);
1721
+ resolve2(match[1], index);
1524
1722
  sink?.add(match[1]);
1525
1723
  }
1526
1724
  }
1527
- for (const msg of rawMessages) {
1725
+ for (const [index, msg] of rawMessages.entries()) {
1528
1726
  if (msg.type === "user") {
1529
1727
  const toolUseResult = isObject(msg.toolUseResult) ? msg.toolUseResult : null;
1530
1728
  if (toolUseResult?.status === "async_launched") {
@@ -1533,9 +1731,11 @@ function collectClaudeBackgroundWork(rawMessages) {
1533
1731
  const toolUseIds = blocks.filter((block) => isObject(block) && block.type === "tool_result").map((block) => block.tool_use_id);
1534
1732
  const ids = [toolUseResult.agentId, toolUseResult.taskId, ...toolUseIds].filter((id) => typeof id === "string" && id.length > 0);
1535
1733
  const description = [toolUseResult.description, toolUseResult.workflowName, toolUseResult.summary].find((value) => typeof value === "string" && value.length > 0) ?? "";
1536
- 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 } });
1537
1737
  }
1538
- for (const text of userMessageTexts(msg)) noteNotifications(text, deliveredIds);
1738
+ for (const text of userMessageTexts(msg)) noteNotifications(text, index, deliveredIds);
1539
1739
  continue;
1540
1740
  }
1541
1741
  if (msg.type === "assistant") {
@@ -1545,33 +1745,28 @@ function collectClaudeBackgroundWork(rawMessages) {
1545
1745
  if (!isObject(block) || block.type !== "tool_use" || block.name !== "TaskStop") continue;
1546
1746
  const input = isObject(block.input) ? block.input : null;
1547
1747
  const taskId = input?.task_id ?? input?.shell_id;
1548
- if (typeof taskId === "string") resolved.add(taskId);
1748
+ if (typeof taskId === "string") resolve2(taskId, index);
1549
1749
  }
1550
1750
  continue;
1551
1751
  }
1552
1752
  if (msg.type === "attachment") {
1553
1753
  const attachment = isObject(msg.attachment) ? msg.attachment : null;
1554
- if (typeof attachment?.prompt === "string") noteNotifications(attachment.prompt, deliveredIds);
1754
+ if (typeof attachment?.prompt === "string") noteNotifications(attachment.prompt, index, deliveredIds);
1555
1755
  continue;
1556
1756
  }
1557
1757
  if (msg.type === "queue-operation" && typeof msg.content === "string") {
1558
1758
  const op = msg.operation;
1559
- noteNotifications(msg.content, op === "enqueue" ? queuedIds : deliveredIds);
1759
+ noteNotifications(msg.content, index, op === "enqueue" ? queuedIds : deliveredIds);
1560
1760
  }
1561
1761
  }
1562
1762
  return {
1563
- 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
+ }),
1564
1767
  undeliveredNotifications: [...queuedIds].filter((id) => !deliveredIds.has(id)).length
1565
1768
  };
1566
1769
  }
1567
- function awaitingAgentsResult(pendingDescriptions, pendingQueue) {
1568
- return {
1569
- status: "awaiting_agents",
1570
- pendingQueue,
1571
- pendingAgents: pendingDescriptions.length,
1572
- pendingAgentDescriptions: pendingDescriptions.filter((description) => description.length > 0)
1573
- };
1574
- }
1575
1770
  function deriveClaudeSessionStatus(rawMessages) {
1576
1771
  let pendingEnqueues = 0;
1577
1772
  let backgroundWork = null;
@@ -1617,9 +1812,8 @@ function deriveClaudeSessionStatus(rawMessages) {
1617
1812
  if (stopReason === "end_turn") {
1618
1813
  const work = getBackgroundWork();
1619
1814
  if (deliveringNotification || work.undeliveredNotifications > 0) return result("processing");
1620
- if (work.pendingDescriptions.length > 0) {
1621
- return awaitingAgentsResult(work.pendingDescriptions, Math.max(0, pendingEnqueues));
1622
- }
1815
+ const awaiting = awaitingAgentsStatus(work.launches, Math.max(0, pendingEnqueues));
1816
+ if (awaiting) return awaiting;
1623
1817
  let hasActivity = false;
1624
1818
  for (let j = i - 1; j >= 0; j--) {
1625
1819
  const m = rawMessages[j];
@@ -2007,9 +2201,60 @@ function safeParseLine(line) {
2007
2201
  function isObject3(value) {
2008
2202
  return typeof value === "object" && value !== null;
2009
2203
  }
2010
- function isCodexRecord(record) {
2011
- if (!record || typeof record.type !== "string") return false;
2012
- return record.type === "session_meta" || record.type === "turn_context" || record.type === "event_msg" || record.type === "response_item" || record.type === "inter_agent_communication_metadata" || record.type === "compacted" || record.type === "world_state";
2204
+ function codexParentId(payload) {
2205
+ const source = isObject3(payload.source) ? payload.source : null;
2206
+ const subagent = source && isObject3(source.subagent) ? source.subagent : null;
2207
+ const threadSpawn = subagent && isObject3(subagent.thread_spawn) ? subagent.thread_spawn : null;
2208
+ for (const candidate of [payload.forked_from_id, payload.parent_thread_id, threadSpawn?.parent_thread_id]) {
2209
+ if (typeof candidate === "string" && candidate) return candidate;
2210
+ }
2211
+ return null;
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
+ }
2255
+ function isCodexRecord(record2) {
2256
+ if (!record2 || typeof record2.type !== "string") return false;
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";
2013
2258
  }
2014
2259
  function extractMessageText(payload, blockType) {
2015
2260
  const content = payload?.content;
@@ -2204,22 +2449,39 @@ function createTurn2(turnId, timestamp, model) {
2204
2449
  model
2205
2450
  };
2206
2451
  }
2207
- function extractPromptFromRecord(record) {
2208
- if (record.type === "event_msg" && isObject3(record.payload) && record.payload.type === "user_message" && typeof record.payload.message === "string") {
2209
- return normalizePromptText(record.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);
2210
2456
  }
2211
- if (record.type === "response_item" && isObject3(record.payload) && record.payload.type === "message" && record.payload.role === "user") {
2212
- return normalizePromptText(extractMessageText(record.payload, "input_text"));
2457
+ if (record2.type === "response_item" && payload?.type === "message" && payload.role === "user") {
2458
+ return normalizePromptText(extractMessageText(payload, "input_text"));
2213
2459
  }
2214
2460
  return "";
2215
2461
  }
2216
- function recordOpensTurn(record, payload) {
2217
- if (record.type === "session_meta") return false;
2218
- if (record.type === "event_msg" && payload?.type === "task_started") return false;
2219
- if (record.type === "response_item" && payload?.type === "message") {
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
+ }
2478
+ function recordOpensTurn(record2, payload) {
2479
+ if (record2.type === "session_meta") return false;
2480
+ if (record2.type === "event_msg" && payload?.type === "task_started") return false;
2481
+ if (record2.type === "response_item" && payload?.type === "message") {
2220
2482
  if (payload.role === "developer" || payload.role === "system") return false;
2221
2483
  if (payload.role === "user") {
2222
- return extractPromptFromRecord(record) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
2484
+ return codexPromptText(record2) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
2223
2485
  }
2224
2486
  }
2225
2487
  return true;
@@ -2239,23 +2501,24 @@ function extractMetadataFromRecords(records) {
2239
2501
  let isSubagent = false;
2240
2502
  let parentSessionId = null;
2241
2503
  let agentPath = "/root";
2242
- let previousPrompt = "";
2243
- for (const record of records) {
2244
- if (!isObject3(record.payload)) continue;
2245
- if (record.type === "session_meta") {
2246
- sessionId ||= typeof record.payload.id === "string" ? record.payload.id : "";
2247
- version ||= typeof record.payload.cli_version === "string" ? record.payload.cli_version : "";
2248
- cwd ||= typeof record.payload.cwd === "string" ? record.payload.cwd : "";
2249
- if (!branchedFrom && isObject3(record.payload.branchedFrom)) {
2250
- const sourceId = typeof record.payload.branchedFrom.sessionId === "string" ? record.payload.branchedFrom.sessionId : "";
2504
+ const readPrompt = createCodexPromptReader();
2505
+ const isInherited = inheritedHistoryFilter(records);
2506
+ for (const record2 of records) {
2507
+ if (!isObject3(record2.payload) || isInherited?.(record2)) continue;
2508
+ if (record2.type === "session_meta") {
2509
+ sessionId ||= typeof record2.payload.id === "string" ? record2.payload.id : "";
2510
+ version ||= typeof record2.payload.cli_version === "string" ? record2.payload.cli_version : "";
2511
+ cwd ||= typeof record2.payload.cwd === "string" ? record2.payload.cwd : "";
2512
+ if (!branchedFrom && isObject3(record2.payload.branchedFrom)) {
2513
+ const sourceId = typeof record2.payload.branchedFrom.sessionId === "string" ? record2.payload.branchedFrom.sessionId : "";
2251
2514
  if (sourceId) {
2252
2515
  branchedFrom = {
2253
2516
  sessionId: sourceId,
2254
- turnIndex: typeof record.payload.branchedFrom.turnIndex === "number" ? record.payload.branchedFrom.turnIndex : null
2517
+ turnIndex: typeof record2.payload.branchedFrom.turnIndex === "number" ? record2.payload.branchedFrom.turnIndex : null
2255
2518
  };
2256
2519
  }
2257
2520
  }
2258
- const source = isObject3(record.payload.source) ? record.payload.source : null;
2521
+ const source = isObject3(record2.payload.source) ? record2.payload.source : null;
2259
2522
  if (source && isObject3(source.subagent)) {
2260
2523
  isSubagent = true;
2261
2524
  const threadSpawn = isObject3(source.subagent.thread_spawn) ? source.subagent.thread_spawn : null;
@@ -2263,25 +2526,21 @@ function extractMetadataFromRecords(records) {
2263
2526
  agentPath = threadSpawn.agent_path;
2264
2527
  }
2265
2528
  }
2266
- if (typeof record.payload.forked_from_id === "string" && record.payload.forked_from_id) {
2267
- parentSessionId = record.payload.forked_from_id;
2268
- }
2269
- const git = isObject3(record.payload.git) ? record.payload.git : null;
2529
+ parentSessionId = codexParentId(record2.payload) ?? parentSessionId;
2530
+ const git = isObject3(record2.payload.git) ? record2.payload.git : null;
2270
2531
  gitBranch ||= git && typeof git.branch === "string" ? git.branch : "";
2271
2532
  }
2272
- if (record.type === "turn_context") {
2273
- model ||= typeof record.payload.model === "string" ? record.payload.model : "";
2274
- cwd ||= typeof record.payload.cwd === "string" ? record.payload.cwd : "";
2533
+ if (record2.type === "turn_context") {
2534
+ model ||= typeof record2.payload.model === "string" ? record2.payload.model : "";
2535
+ cwd ||= typeof record2.payload.cwd === "string" ? record2.payload.cwd : "";
2275
2536
  }
2276
- const prompt = extractPromptFromRecord(record);
2537
+ const prompt = readPrompt(record2);
2277
2538
  if (!prompt) continue;
2278
- if (prompt === previousPrompt) continue;
2279
2539
  if (!firstUserMessage) firstUserMessage = prompt;
2280
2540
  lastUserMessage = prompt;
2281
- previousPrompt = prompt;
2282
2541
  turnCount++;
2283
- if (!timestamp) timestamp = record.timestamp ?? "";
2284
- lastTimestamp = record.timestamp ?? lastTimestamp;
2542
+ if (!timestamp) timestamp = record2.timestamp ?? "";
2543
+ lastTimestamp = record2.timestamp ?? lastTimestamp;
2285
2544
  }
2286
2545
  if (lastTimestamp === "") lastTimestamp = timestamp;
2287
2546
  return {
@@ -2348,6 +2607,7 @@ function walkCodexRecords(records, options) {
2348
2607
  timestamp: info?.timestamp ?? eventTimestamp2,
2349
2608
  tokenUsage: null,
2350
2609
  model: info?.model ?? null,
2610
+ ...info?.effort ? { effort: info.effort } : {},
2351
2611
  isBackground: false,
2352
2612
  prompt: info?.message || void 0,
2353
2613
  status: update.status ?? "running"
@@ -2368,6 +2628,7 @@ function walkCodexRecords(records, options) {
2368
2628
  agentMessage.agentName = info.nickname ?? (info.agentPath ? agentNameFromPath(info.agentPath) : agentMessage.agentName);
2369
2629
  agentMessage.subagentType = info.agentType;
2370
2630
  agentMessage.model = info.model;
2631
+ if (info.effort) agentMessage.effort = info.effort;
2371
2632
  agentMessage.prompt = info.message || agentMessage.prompt;
2372
2633
  }
2373
2634
  if (update.text && !agentMessage.text.includes(update.text)) {
@@ -2438,20 +2699,21 @@ function walkCodexRecords(records, options) {
2438
2699
  webSearchCalls.set(id, toolCall);
2439
2700
  appendToolCall(targetTurn, toolCall, timestamp);
2440
2701
  }
2702
+ const isInherited = inheritedHistoryFilter(records);
2441
2703
  for (let index = 0; index < records.length; index++) {
2442
- const record = records[index];
2443
- if (!isCodexRecord(record)) continue;
2704
+ const record2 = records[index];
2705
+ if (!isCodexRecord(record2) || isInherited?.(record2)) continue;
2444
2706
  recordIndex = index;
2445
- const payload = isObject3(record.payload) ? record.payload : void 0;
2446
- const timestamp = record.timestamp ?? "";
2447
- if (record.type === "compacted") {
2707
+ const payload = isObject3(record2.payload) ? record2.payload : void 0;
2708
+ const timestamp = record2.timestamp ?? "";
2709
+ if (record2.type === "compacted") {
2448
2710
  current = commitTurn(current);
2449
2711
  pendingCompaction = "Conversation compacted";
2450
2712
  lastTurnTimestamp = timestamp;
2451
2713
  continue;
2452
2714
  }
2453
- if (record.type === "world_state") continue;
2454
- if (record.type === "turn_context") {
2715
+ if (record2.type === "world_state") continue;
2716
+ if (record2.type === "turn_context") {
2455
2717
  current = commitTurn(current);
2456
2718
  pendingContextIndex = index;
2457
2719
  currentTurnId = typeof payload?.turn_id === "string" ? payload.turn_id : null;
@@ -2460,7 +2722,7 @@ function walkCodexRecords(records, options) {
2460
2722
  sawTurnStart = true;
2461
2723
  continue;
2462
2724
  }
2463
- if (record.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
2725
+ if (record2.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
2464
2726
  if (current && (current.assistantText.length > 0 || current.toolCalls.length > 0 || current.thinking.length > 0)) {
2465
2727
  current = commitTurn(current);
2466
2728
  }
@@ -2484,12 +2746,12 @@ function walkCodexRecords(records, options) {
2484
2746
  lastTurnTimestamp = timestamp;
2485
2747
  continue;
2486
2748
  }
2487
- if (!current && !recordOpensTurn(record, payload)) continue;
2749
+ if (!current && !recordOpensTurn(record2, payload)) continue;
2488
2750
  current ??= createActiveTurn(currentTurnId, timestamp, currentModel);
2489
2751
  if (!current.model && currentModel) current.model = currentModel;
2490
2752
  if (!current.timestamp) current.timestamp = timestamp;
2491
2753
  if (timestamp) lastTurnTimestamp = timestamp;
2492
- if (record.type === "event_msg" && payload?.type === "token_count") {
2754
+ if (record2.type === "event_msg" && payload?.type === "token_count") {
2493
2755
  const info = isObject3(payload.info) ? payload.info : null;
2494
2756
  const lastUsage = info ? parseTokenUsage(info.last_token_usage) : null;
2495
2757
  if (lastUsage) {
@@ -2497,14 +2759,14 @@ function walkCodexRecords(records, options) {
2497
2759
  }
2498
2760
  continue;
2499
2761
  }
2500
- if (record.type === "event_msg" && payload?.type === "web_search_end" && typeof payload.call_id === "string") {
2762
+ if (record2.type === "event_msg" && payload?.type === "web_search_end" && typeof payload.call_id === "string") {
2501
2763
  const input = {};
2502
2764
  if (typeof payload.query === "string" && payload.query) input.query = payload.query;
2503
2765
  if (isObject3(payload.action)) input.action = payload.action;
2504
2766
  upsertWebSearchCall(current, payload.call_id, input, "completed", timestamp);
2505
2767
  continue;
2506
2768
  }
2507
- if (record.type === "event_msg" && payload?.type === "mcp_tool_call_end" && typeof payload.call_id === "string" && isObject3(payload.invocation)) {
2769
+ if (record2.type === "event_msg" && payload?.type === "mcp_tool_call_end" && typeof payload.call_id === "string" && isObject3(payload.invocation)) {
2508
2770
  const invocation = payload.invocation;
2509
2771
  const server = typeof invocation.server === "string" ? invocation.server : "mcp";
2510
2772
  const tool = typeof invocation.tool === "string" ? invocation.tool : "tool";
@@ -2529,12 +2791,18 @@ function walkCodexRecords(records, options) {
2529
2791
  }
2530
2792
  continue;
2531
2793
  }
2532
- if (record.type === "event_msg" && payload?.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
2533
- const agentId = payload.agent_thread_id;
2534
- const eventId2 = typeof payload.event_id === "string" ? payload.event_id : "";
2535
- 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;
2536
2804
  const spawnInfo = eventId2 ? spawnAgentCalls.get(eventId2) : void 0;
2537
- const existingId = agentIdByPath.get(payload.agent_path);
2805
+ const existingId = agentIdByPath.get(agentPath);
2538
2806
  const existing = agentRegistry.get(agentId) ?? (existingId ? agentRegistry.get(existingId) : void 0);
2539
2807
  if (kind !== "started" && !existing && !spawnInfo) continue;
2540
2808
  if (existingId && existingId !== agentId && !agentMessages.has(agentId)) {
@@ -2548,22 +2816,23 @@ function walkCodexRecords(records, options) {
2548
2816
  }
2549
2817
  const info = {
2550
2818
  agentId,
2551
- nickname: existing?.nickname ?? agentNameFromPath(payload.agent_path) ?? spawnInfo?.taskName ?? null,
2552
- agentPath: payload.agent_path,
2819
+ nickname: existing?.nickname ?? agentNameFromPath(agentPath) ?? spawnInfo?.taskName ?? null,
2820
+ agentPath,
2553
2821
  message: existing?.message ?? spawnInfo?.message ?? "",
2554
- model: existing?.model ?? spawnInfo?.model ?? null,
2822
+ model: activity.model ?? existing?.model ?? spawnInfo?.model ?? null,
2823
+ effort: activity.effort ?? existing?.effort ?? null,
2555
2824
  agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
2556
2825
  timestamp: existing?.timestamp ?? (timestamp || spawnInfo?.timestamp || ""),
2557
2826
  parentToolCallId: existing?.parentToolCallId ?? eventId2
2558
2827
  };
2559
2828
  agentRegistry.set(agentId, info);
2560
- agentIdByPath.set(payload.agent_path, agentId);
2829
+ agentIdByPath.set(agentPath, agentId);
2561
2830
  if (eventId2 && (kind === "started" || spawnInfo)) agentIdBySpawnCall.set(eventId2, agentId);
2562
- const status = kind === "interrupted" ? "interrupted" : "running";
2831
+ const status = kind === "interrupted" || kind === "completed" ? kind : "running";
2563
2832
  upsertAgentMessage(agentId, current, timestamp, { status });
2564
2833
  continue;
2565
2834
  }
2566
- if (record.type !== "response_item" || !payload) continue;
2835
+ if (record2.type !== "response_item" || !payload) continue;
2567
2836
  if (payload.type === "reasoning") {
2568
2837
  const summary = Array.isArray(payload.summary) ? payload.summary.filter((item) => typeof item === "string").join("\n") : "";
2569
2838
  appendThinking(current, summary.trim(), timestamp);
@@ -2715,6 +2984,7 @@ function walkCodexRecords(records, options) {
2715
2984
  agentPath: agentPath ?? existing?.agentPath ?? null,
2716
2985
  message: existing?.message ?? spawnInfo?.message ?? "",
2717
2986
  model: existing?.model ?? spawnInfo?.model ?? null,
2987
+ effort: existing?.effort ?? null,
2718
2988
  agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
2719
2989
  timestamp: existing?.timestamp ?? spawnInfo?.timestamp ?? timestamp,
2720
2990
  parentToolCallId: existing?.parentToolCallId ?? toolCall.id
@@ -2833,14 +3103,16 @@ function walkCodexRecords(records, options) {
2833
3103
  }
2834
3104
  function parseCodexSession(jsonlText, options) {
2835
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;
2836
3108
  const { turnStartIndices: _starts, ...session } = walkCodexRecords(
2837
- records,
3109
+ ownRecords,
2838
3110
  options
2839
3111
  );
2840
3112
  return session;
2841
3113
  }
2842
3114
  function appendCodexSession(existing, newJsonlText) {
2843
- const prefix = existing.rawMessages.map((record) => JSON.stringify(record)).join("\n");
3115
+ const prefix = existing.rawMessages.map((record2) => JSON.stringify(record2)).join("\n");
2844
3116
  return parseCodexSession(prefix ? `${prefix}
2845
3117
  ${newJsonlText}` : newJsonlText);
2846
3118
  }
@@ -2859,40 +3131,48 @@ function parseJsonObject(value) {
2859
3131
  return null;
2860
3132
  }
2861
3133
  }
2862
- function collectCodexPendingAgents(rawMessages) {
2863
- const alive = /* @__PURE__ */ new Map();
2864
- 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();
2865
3138
  const agentIdByPath = /* @__PURE__ */ new Map();
2866
3139
  const spawnCalls = /* @__PURE__ */ new Map();
2867
3140
  const waitCalls = /* @__PURE__ */ new Set();
2868
3141
  const interruptCalls = /* @__PURE__ */ new Map();
2869
- function markAlive(agentId, description) {
2870
- if (!done.has(agentId)) alive.set(agentId, alive.get(agentId) || description);
2871
- }
2872
- 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()) {
2873
3154
  const payload = isObject3(msg.payload) ? msg.payload : null;
2874
3155
  if (!payload) continue;
2875
- if (msg.type === "event_msg" && payload.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
2876
- const agentId = payload.agent_thread_id;
2877
- const kind = typeof payload.kind === "string" ? payload.kind : "started";
2878
- const eventId2 = typeof payload.event_id === "string" ? payload.event_id : "";
2879
- const existingId = agentIdByPath.get(payload.agent_path);
2880
- 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);
2881
3162
  if (kind !== "started" && !known) continue;
2882
3163
  if (existingId && existingId !== agentId) {
2883
- if (alive.has(existingId)) {
2884
- markAlive(agentId, alive.get(existingId) ?? "");
2885
- alive.delete(existingId);
2886
- }
2887
- if (done.has(existingId)) done.add(agentId);
2888
- }
2889
- agentIdByPath.set(payload.agent_path, agentId);
2890
- if (kind === "interrupted") {
2891
- done.add(agentId);
2892
- alive.delete(agentId);
2893
- } else {
2894
- 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);
2895
3172
  }
3173
+ agentIdByPath.set(agentPath, agentId);
3174
+ if (kind === "interrupted" || kind === "completed") markEnded(agentId, index);
3175
+ else markAlive(agentId, spawnCalls.get(eventId2) ?? "", index, timestamp);
2896
3176
  continue;
2897
3177
  }
2898
3178
  if (msg.type !== "response_item") continue;
@@ -2916,7 +3196,7 @@ function collectCodexPendingAgents(rawMessages) {
2916
3196
  const output = parseJsonObject(payload.output);
2917
3197
  const agentId = typeof output?.agent_id === "string" ? output.agent_id : "";
2918
3198
  if (agentId) {
2919
- markAlive(agentId, spawnCalls.get(callId) ?? "");
3199
+ markAlive(agentId, spawnCalls.get(callId) ?? "", index, timestamp);
2920
3200
  const agentPath = typeof output?.task_name === "string" ? output.task_name : "";
2921
3201
  if (agentPath && !agentIdByPath.has(agentPath)) agentIdByPath.set(agentPath, agentId);
2922
3202
  }
@@ -2927,16 +3207,10 @@ function collectCodexPendingAgents(rawMessages) {
2927
3207
  const statusValue = isObject3(status) ? status : {};
2928
3208
  const lifecycle = typeof statusValue.status === "string" ? statusValue.status : "";
2929
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";
2930
- if (isTerminal) {
2931
- done.add(agentId);
2932
- alive.delete(agentId);
2933
- }
3210
+ if (isTerminal) markEnded(agentId, index);
2934
3211
  }
2935
3212
  } else if (interruptCalls.has(callId)) {
2936
- for (const agentId of interruptCalls.get(callId) ?? []) {
2937
- done.add(agentId);
2938
- alive.delete(agentId);
2939
- }
3213
+ for (const agentId of interruptCalls.get(callId) ?? []) markEnded(agentId, index);
2940
3214
  }
2941
3215
  continue;
2942
3216
  }
@@ -2944,12 +3218,14 @@ function collectCodexPendingAgents(rawMessages) {
2944
3218
  const text = codexPayloadText(payload);
2945
3219
  const messageType = text.match(/^Message Type:\s*([^\r\n]+)/)?.[1]?.trim().toUpperCase() ?? "";
2946
3220
  if (!TERMINAL_INTER_AGENT_TYPES.has(messageType)) continue;
2947
- const agentId = agentIdByPath.get(payload.author) ?? payload.author;
2948
- done.add(agentId);
2949
- alive.delete(agentId);
3221
+ markEnded(agentIdByPath.get(payload.author) ?? payload.author, index);
2950
3222
  }
2951
3223
  }
2952
- 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
+ }));
2953
3229
  }
2954
3230
  function deriveCodexSessionStatus(rawMessages) {
2955
3231
  for (let i = rawMessages.length - 1; i >= 0; i--) {
@@ -2958,16 +3234,7 @@ function deriveCodexSessionStatus(rawMessages) {
2958
3234
  const payload = msg.payload;
2959
3235
  switch (payload?.type) {
2960
3236
  case "task_complete": {
2961
- const pending = collectCodexPendingAgents(rawMessages);
2962
- if (pending.length > 0) {
2963
- return {
2964
- status: "awaiting_agents",
2965
- pendingQueue: 0,
2966
- pendingAgents: pending.length,
2967
- pendingAgentDescriptions: pending.filter((description) => description.length > 0)
2968
- };
2969
- }
2970
- return { status: "completed" };
3237
+ return awaitingAgentsStatus(collectCodexBackgroundAgents(rawMessages)) ?? { status: "completed" };
2971
3238
  }
2972
3239
  case "task_started":
2973
3240
  return { status: "processing" };
@@ -2991,11 +3258,11 @@ function deriveCodexSessionStatus(rawMessages) {
2991
3258
  }
2992
3259
  return { status: "idle" };
2993
3260
  }
2994
- function brandCodexBranch(firstRecord, sessionId, turnIndex) {
3261
+ function brandCodexBranch(firstRecord, sessionId, turnIndex, branchedAt) {
2995
3262
  const payload = isObject3(firstRecord.payload) ? { ...firstRecord.payload } : {};
2996
3263
  const originalId = typeof payload.id === "string" ? payload.id : "";
2997
3264
  payload.id = sessionId;
2998
- payload.branchedFrom = { sessionId: originalId, turnIndex };
3265
+ payload.branchedFrom = { sessionId: originalId, turnIndex, at: new Date(branchedAt).toISOString() };
2999
3266
  return { record: { ...firstRecord, payload }, originalId };
3000
3267
  }
3001
3268
  function codexTurnBoundaries(records) {
@@ -3757,7 +4024,7 @@ function parseCopilotSession(jsonlText, options) {
3757
4024
  };
3758
4025
  }
3759
4026
  function appendCopilotSession(existing, newJsonlText) {
3760
- const prefix = existing.rawMessages.map((record) => JSON.stringify(record)).join("\n");
4027
+ const prefix = existing.rawMessages.map((record2) => JSON.stringify(record2)).join("\n");
3761
4028
  return parseCopilotSession(prefix ? `${prefix}
3762
4029
  ${newJsonlText}` : newJsonlText);
3763
4030
  }
@@ -3765,33 +4032,32 @@ function isCopilotEventType(type) {
3765
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."));
3766
4033
  }
3767
4034
  function deriveCopilotSessionStatus(rawMessages) {
3768
- const pendingAgents = /* @__PURE__ */ new Map();
3769
- for (const event of rawMessages) {
4035
+ const agents = /* @__PURE__ */ new Map();
4036
+ for (const [index, event] of rawMessages.entries()) {
3770
4037
  const agentId = typeof event.agentId === "string" ? event.agentId : "";
3771
4038
  if (!agentId && (event.type === "abort" || event.type === "session.shutdown" || event.type === "session.error")) {
3772
- pendingAgents.clear();
4039
+ agents.clear();
3773
4040
  continue;
3774
4041
  }
3775
4042
  if (!agentId || !event.type.startsWith("subagent.")) continue;
3776
4043
  const data = isObject4(event.data) ? event.data : {};
4044
+ const launch = agents.get(agentId);
3777
4045
  if (event.type === "subagent.completed" || event.type === "subagent.failed") {
3778
- pendingAgents.delete(agentId);
4046
+ if (launch) launch.endedAt ??= index;
3779
4047
  continue;
3780
4048
  }
3781
4049
  if (event.type === "subagent.started" || event.type === "subagent.configured") {
3782
4050
  const description = [data.agentDisplayName, data.description, data.agentName].find((value) => typeof value === "string") ?? "";
3783
- 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
+ }
3784
4057
  }
3785
4058
  }
3786
- if (pendingAgents.size > 0) {
3787
- const descriptions = [...pendingAgents.values()];
3788
- return {
3789
- status: "awaiting_agents",
3790
- pendingQueue: 0,
3791
- pendingAgents: descriptions.length,
3792
- pendingAgentDescriptions: descriptions.filter((description) => description.length > 0)
3793
- };
3794
- }
4059
+ const awaiting = awaitingAgentsStatus([...agents.values()]);
4060
+ if (awaiting) return awaiting;
3795
4061
  let sawUserActivity = false;
3796
4062
  const completedPermissionRequests = /* @__PURE__ */ new Set();
3797
4063
  for (let i = rawMessages.length - 1; i >= 0; i--) {
@@ -3865,11 +4131,11 @@ function brandCopilotBranch() {
3865
4131
  function copilotTurnBoundaries(records) {
3866
4132
  const boundaries = [];
3867
4133
  for (let index = 0; index < records.length; index++) {
3868
- const record = records[index];
3869
- if (record.type !== "user.message" || typeof record.agentId === "string") continue;
3870
- const data = record.data;
4134
+ const record2 = records[index];
4135
+ if (record2.type !== "user.message" || typeof record2.agentId === "string") continue;
4136
+ const data = record2.data;
3871
4137
  if (!data || typeof data !== "object" || Array.isArray(data)) continue;
3872
- if (typeof record.id !== "string" || !record.id) continue;
4138
+ if (typeof record2.id !== "string" || !record2.id) continue;
3873
4139
  boundaries.push(index);
3874
4140
  }
3875
4141
  return boundaries;
@@ -3877,6 +4143,7 @@ function copilotTurnBoundaries(records) {
3877
4143
 
3878
4144
  // src/lib/agents.ts
3879
4145
  var TERMINAL_AGENT_KIND = AGENT_KINDS[AGENT_KINDS.length - 1];
4146
+ var hasNoNoiseLines = () => false;
3880
4147
  var codexFormat = {
3881
4148
  kind: "codex",
3882
4149
  descriptor: descriptorFor("codex"),
@@ -3886,6 +4153,8 @@ var codexFormat = {
3886
4153
  append: appendCodexSession,
3887
4154
  metadataFromLines: extractCodexMetadataFromLines,
3888
4155
  status: deriveCodexSessionStatus,
4156
+ isNoiseLine: hasNoNoiseLines,
4157
+ pageHeaderLine: codexPageHeaderLine,
3889
4158
  brandBranch: brandCodexBranch,
3890
4159
  turnBoundaries: codexTurnBoundaries
3891
4160
  };
@@ -3898,6 +4167,7 @@ var copilotFormat = {
3898
4167
  append: appendCopilotSession,
3899
4168
  metadataFromLines: extractCopilotMetadataFromLines,
3900
4169
  status: deriveCopilotSessionStatus,
4170
+ isNoiseLine: hasNoNoiseLines,
3901
4171
  brandBranch: brandCopilotBranch,
3902
4172
  turnBoundaries: copilotTurnBoundaries
3903
4173
  };
@@ -3911,10 +4181,20 @@ var claudeFormat = {
3911
4181
  append: appendClaudeSession,
3912
4182
  metadataFromLines: extractClaudeMetadataFromLines,
3913
4183
  status: deriveClaudeSessionStatus,
4184
+ isNoiseLine: isClaudeNoiseLine,
3914
4185
  brandBranch: brandClaudeBranch,
3915
4186
  turnBoundaries: claudeTurnBoundaries
3916
4187
  };
3917
4188
  var FORMATS = Object.freeze({
4189
+ acp: {
4190
+ ...claudeFormat,
4191
+ kind: "acp",
4192
+ descriptor: descriptorFor("acp"),
4193
+ detectsText: (text) => text.split("\n", 1)[0]?.includes('"type":"acp_session"') ?? false,
4194
+ detectsRecords: (records) => records[0]?.type === "acp_session",
4195
+ parse: (text, options) => ({ ...parseClaudeSession(text, options), agentKind: "acp" }),
4196
+ append: (session, text) => ({ ...appendClaudeSession(session, text), agentKind: "acp" })
4197
+ },
3918
4198
  claude: claudeFormat,
3919
4199
  codex: codexFormat,
3920
4200
  copilot: copilotFormat
@@ -3931,6 +4211,9 @@ function formatForText(jsonlText) {
3931
4211
  function formatForRecords(records) {
3932
4212
  return firstMatch((format) => format.detectsRecords(records));
3933
4213
  }
4214
+ function isAnyAgentNoiseLine(line) {
4215
+ return AGENT_KINDS.some((kind) => FORMATS[kind].isNoiseLine(line));
4216
+ }
3934
4217
 
3935
4218
  // src/lib/parser.ts
3936
4219
  function extractTextFromContent2(content) {
@@ -3946,16 +4229,63 @@ function getUserMessageText(content) {
3946
4229
  return extractTextFromContent2(content);
3947
4230
  }
3948
4231
 
3949
- // src/lib/stores.ts
4232
+ // src/lib/transcriptFile.ts
3950
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");
3951
4281
  var import_node_path2 = require("node:path");
3952
4282
 
3953
4283
  // src/lib/dirs.ts
3954
4284
  var import_node_path = require("node:path");
3955
4285
  var import_node_os = require("node:os");
3956
4286
  function agentHomeDir(kind, env = process.env, homeDirectory = (0, import_node_os.homedir)()) {
3957
- const { homeEnvVar, homeDirName } = descriptorFor(kind).cli;
3958
- const override = homeEnvVar ? env[homeEnvVar] : void 0;
4287
+ const { homeEnvVar, homeDirName, sdkHomeEnvVar } = descriptorFor(kind).cli;
4288
+ const override = env[homeEnvVar ?? sdkHomeEnvVar ?? ""];
3959
4289
  return override || (0, import_node_path.join)(homeDirectory, homeDirName);
3960
4290
  }
3961
4291
  var dirs = {
@@ -3963,7 +4293,8 @@ var dirs = {
3963
4293
  TEAMS_DIR: (0, import_node_path.join)(agentHomeDir("claude"), "teams"),
3964
4294
  TASKS_DIR: (0, import_node_path.join)(agentHomeDir("claude"), "tasks"),
3965
4295
  CODEX_SESSIONS_DIR: (0, import_node_path.join)(agentHomeDir("codex"), "sessions"),
3966
- COPILOT_SESSIONS_DIR: (0, import_node_path.join)(agentHomeDir("copilot"), "session-state")
4296
+ COPILOT_SESSIONS_DIR: (0, import_node_path.join)(agentHomeDir("copilot"), "session-state"),
4297
+ ACP_PROJECTS_DIR: (0, import_node_path.join)(agentHomeDir("acp"), "projects")
3967
4298
  };
3968
4299
  var DEFAULT_DB_PATH = (0, import_node_path.join)(agentHomeDir("claude"), "cogpit-memory", "search-index.db");
3969
4300
 
@@ -3973,14 +4304,14 @@ var MAX_WALK_DEPTH = 4;
3973
4304
  var SUBAGENTS_DIR = "subagents";
3974
4305
  function mtimeOf(filePath) {
3975
4306
  try {
3976
- return (0, import_node_fs.statSync)(filePath).mtimeMs;
4307
+ return (0, import_node_fs2.statSync)(filePath).mtimeMs;
3977
4308
  } catch {
3978
4309
  return null;
3979
4310
  }
3980
4311
  }
3981
4312
  function readDirSafe(dir) {
3982
4313
  try {
3983
- return (0, import_node_fs.readdirSync)(dir, { withFileTypes: true });
4314
+ return (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true });
3984
4315
  } catch {
3985
4316
  return [];
3986
4317
  }
@@ -3991,8 +4322,8 @@ function isWithin(root, target) {
3991
4322
  }
3992
4323
  function canonicalWithinRoot(root, filePath) {
3993
4324
  try {
3994
- const realRoot = (0, import_node_fs.realpathSync)(root);
3995
- 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);
3996
4327
  return isWithin(realRoot, real) ? real : null;
3997
4328
  } catch {
3998
4329
  return null;
@@ -4058,13 +4389,15 @@ function walkClaude(root, cutoffMs) {
4058
4389
  function walkCodex(root, cutoffMs, dir = root, depth = 0) {
4059
4390
  if (depth > MAX_WALK_DEPTH) return [];
4060
4391
  const found = [];
4061
- 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) {
4062
4395
  const filePath = (0, import_node_path2.join)(dir, entry.name);
4063
4396
  if (entry.isDirectory()) {
4064
4397
  found.push(...walkCodex(root, cutoffMs, filePath, depth + 1));
4065
4398
  continue;
4066
4399
  }
4067
- if (!entry.name.endsWith(".jsonl")) continue;
4400
+ if (!isListableTranscript(entry.name, names)) continue;
4068
4401
  const mtimeMs = mtimeOf(filePath);
4069
4402
  if (mtimeMs === null || mtimeMs < cutoffMs) continue;
4070
4403
  found.push({
@@ -4125,14 +4458,18 @@ var WALKERS = {
4125
4458
  find(root, sessionId) {
4126
4459
  const walk = (dir, depth) => {
4127
4460
  if (depth > MAX_WALK_DEPTH) return null;
4128
- 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) {
4129
4464
  const filePath = (0, import_node_path2.join)(dir, entry.name);
4130
4465
  if (entry.isDirectory()) {
4131
4466
  const match = walk(filePath, depth + 1);
4132
4467
  if (match) return match;
4133
4468
  continue;
4134
4469
  }
4135
- if (entry.name.endsWith(`${sessionId}.jsonl`)) return filePath;
4470
+ if (uncompressedTranscriptName(entry.name).endsWith(`${sessionId}.jsonl`) && isListableTranscript(entry.name, names)) {
4471
+ return filePath;
4472
+ }
4136
4473
  }
4137
4474
  return null;
4138
4475
  };
@@ -4151,24 +4488,48 @@ var WALKERS = {
4151
4488
  const candidate = copilotTranscript(root, sessionId);
4152
4489
  return mtimeOf(candidate) === null ? null : candidate;
4153
4490
  }
4491
+ },
4492
+ acp: {
4493
+ root: () => dirs.ACP_PROJECTS_DIR,
4494
+ list: walkClaude,
4495
+ identify: claudeIdentify,
4496
+ find: (root, id) => WALKERS.claude.find(root, id)
4154
4497
  }
4155
4498
  };
4156
- function makeStore(kind) {
4499
+ function makeStore(kind, home, configuredId) {
4157
4500
  const walker = WALKERS[kind];
4501
+ const instanceId = configuredId ?? (process.env.COGPIT_WORKER_AGENT === kind ? process.env.COGPIT_AGENT_INSTANCE_ID : void 0) ?? "default";
4502
+ const root = home ? () => (0, import_node_path2.join)(home, kind === "codex" ? "sessions" : kind === "copilot" ? "session-state" : "projects") : walker.root;
4503
+ const identify = (filePath, directory = root()) => {
4504
+ const identity = walker.identify(filePath, directory);
4505
+ return { ...identity, sessionId: instanceSessionId(instanceId, identity.sessionId), parentSessionId: identity.parentSessionId ? instanceSessionId(instanceId, identity.parentSessionId) : null };
4506
+ };
4158
4507
  return {
4159
4508
  kind,
4509
+ instanceId,
4160
4510
  descriptor: descriptorFor(kind),
4161
- root: walker.root,
4162
- ownsPath: (filePath) => isWithin((0, import_node_path2.resolve)(walker.root()), (0, import_node_path2.resolve)(filePath)),
4163
- identify: (filePath, root = walker.root()) => walker.identify(filePath, root),
4164
- list: (cutoffMs, root = walker.root()) => walker.list(root, cutoffMs),
4165
- find: (sessionId) => walker.find(walker.root(), sessionId)
4511
+ root,
4512
+ ownsPath: (filePath) => {
4513
+ if (isWithin((0, import_node_path2.resolve)(root()), (0, import_node_path2.resolve)(filePath))) return true;
4514
+ try {
4515
+ return isWithin((0, import_node_fs2.realpathSync)(root()), (0, import_node_fs2.realpathSync)(filePath));
4516
+ } catch {
4517
+ return false;
4518
+ }
4519
+ },
4520
+ identify,
4521
+ list: (cutoffMs, directory = root()) => walker.list(directory, cutoffMs).map((file) => ({ ...file, ...identify(file.path, directory) })),
4522
+ find: (sessionId) => {
4523
+ const parts = splitInstanceSessionId(sessionId);
4524
+ return parts.instanceId === instanceId ? walker.find(root(), parts.nativeId) : null;
4525
+ }
4166
4526
  };
4167
4527
  }
4168
4528
  var STORES = {
4169
4529
  claude: makeStore("claude"),
4170
4530
  codex: makeStore("codex"),
4171
- copilot: makeStore("copilot")
4531
+ copilot: makeStore("copilot"),
4532
+ acp: makeStore("acp")
4172
4533
  };
4173
4534
  function storeFor(kind) {
4174
4535
  return STORES[kind];
@@ -4177,7 +4538,20 @@ function defaultStore() {
4177
4538
  return storeFor(descriptorForDirName(null).kind);
4178
4539
  }
4179
4540
  function allStores() {
4180
- return AGENT_KINDS.map((kind) => STORES[kind]);
4541
+ if (process.env.COGPIT_AGENT_INSTANCE_ID && AGENT_KINDS.includes(process.env.COGPIT_WORKER_AGENT)) return [STORES[process.env.COGPIT_WORKER_AGENT]];
4542
+ const stores = AGENT_KINDS.map((kind) => STORES[kind]);
4543
+ const root = process.env.COGPIT_ORCHESTRATION_ROOT;
4544
+ if (!root) return stores;
4545
+ for (const entry of readDirSafe((0, import_node_path2.join)(root, "provider-instances"))) {
4546
+ if (!entry.isDirectory()) continue;
4547
+ const home = (0, import_node_path2.join)(root, "provider-instances", entry.name);
4548
+ try {
4549
+ const config = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(home, "config.json"), "utf8"));
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));
4551
+ } catch {
4552
+ }
4553
+ }
4554
+ return stores;
4181
4555
  }
4182
4556
  function storeForPath(filePath) {
4183
4557
  return allStores().find((store) => store.ownsPath(filePath)) ?? null;
@@ -4247,7 +4621,7 @@ var SearchIndex = class {
4247
4621
  const { count: totalRows } = this.db.prepare("SELECT COUNT(*) as count FROM search_content").get();
4248
4622
  let dbSizeBytes = 0;
4249
4623
  try {
4250
- dbSizeBytes = (0, import_node_fs2.statSync)(this.dbPath).size;
4624
+ dbSizeBytes = (0, import_node_fs3.statSync)(this.dbPath).size;
4251
4625
  } catch {
4252
4626
  }
4253
4627
  return {
@@ -4320,9 +4694,9 @@ var SearchIndex = class {
4320
4694
  indexFile(filePath, sessionId, mtimeMs, opts) {
4321
4695
  const resolvedSessionId = sessionId ?? identifyTranscript(filePath).sessionId;
4322
4696
  if (mtimeMs == null) {
4323
- mtimeMs = (0, import_node_fs2.statSync)(filePath).mtimeMs;
4697
+ mtimeMs = (0, import_node_fs3.statSync)(filePath).mtimeMs;
4324
4698
  }
4325
- const content = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
4699
+ const content = readTranscriptTextSync(filePath);
4326
4700
  const session = parseSession(content, { skipStats: true });
4327
4701
  const isSubagent = opts?.isSubagent ? 1 : 0;
4328
4702
  const parentSessionId = opts?.parentSessionId ?? null;
@@ -4351,7 +4725,7 @@ var SearchIndex = class {
4351
4725
  const files = this.db.prepare("SELECT file_path FROM indexed_files").all();
4352
4726
  const missing = files.filter(({ file_path }) => {
4353
4727
  try {
4354
- (0, import_node_fs2.statSync)(file_path);
4728
+ (0, import_node_fs3.statSync)(file_path);
4355
4729
  return false;
4356
4730
  } catch (error) {
4357
4731
  const code = error.code;
@@ -4468,7 +4842,7 @@ var SearchIndex = class {
4468
4842
  this.db.close();
4469
4843
  for (const suffix of ["", "-wal", "-shm"]) {
4470
4844
  try {
4471
- (0, import_node_fs2.unlinkSync)(this.dbPath + suffix);
4845
+ (0, import_node_fs3.unlinkSync)(this.dbPath + suffix);
4472
4846
  } catch {
4473
4847
  }
4474
4848
  }
@@ -4492,7 +4866,7 @@ var SearchIndex = class {
4492
4866
  const txn = this.db.transaction(() => {
4493
4867
  for (const file of files) {
4494
4868
  try {
4495
- const content = (0, import_node_fs2.readFileSync)(file.path, "utf-8");
4869
+ const content = readTranscriptTextSync(file.path);
4496
4870
  const session = parseSession(content, { skipStats: true });
4497
4871
  this.insertSessionContent(insert, file.sessionId, file.path, session);
4498
4872
  insertFile.run(file.path, file.mtimeMs, file.sessionId, file.isSubagent ? 1 : 0, file.parentSessionId);
@@ -4571,6 +4945,11 @@ function parseMaxAge(raw) {
4571
4945
  }
4572
4946
  }
4573
4947
 
4948
+ // src/lib/read-session.ts
4949
+ function parseTranscript(content, filePath) {
4950
+ return scopeParsedSession(parseSession(content), storeForPath(filePath)?.instanceId ?? "default");
4951
+ }
4952
+
4574
4953
  // src/commands/search.ts
4575
4954
  async function searchSessions(query, opts, searchIndex) {
4576
4955
  if (!query || query.length < 2) {
@@ -4583,9 +4962,9 @@ async function searchSessions(query, opts, searchIndex) {
4583
4962
  let ownedIndex = false;
4584
4963
  if (!index && searchIndex === void 0) {
4585
4964
  try {
4586
- const dbExists = (0, import_node_fs3.existsSync)(DEFAULT_DB_PATH);
4965
+ const dbExists = (0, import_node_fs4.existsSync)(DEFAULT_DB_PATH);
4587
4966
  if (!dbExists) {
4588
- (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 });
4589
4968
  }
4590
4969
  index = new SearchIndex(DEFAULT_DB_PATH);
4591
4970
  ownedIndex = true;
@@ -4659,7 +5038,7 @@ async function cwdFromFilePath(filePath) {
4659
5038
  const cached = cwdCache.get(filePath);
4660
5039
  if (cached !== void 0) return cached;
4661
5040
  try {
4662
- const fh = await (0, import_promises.open)(filePath, "r");
5041
+ const fh = await openTranscript(filePath);
4663
5042
  try {
4664
5043
  const buf = Buffer.alloc(CWD_READ_BYTES);
4665
5044
  const { bytesRead } = await fh.read(buf, 0, CWD_READ_BYTES, 0);
@@ -4717,7 +5096,7 @@ function searchField(text, location, query, caseSensitive, extras) {
4717
5096
  async function discoverSingleSession(sessionId) {
4718
5097
  const jsonlPath = await findSessionFile(sessionId);
4719
5098
  if (!jsonlPath) return [];
4720
- const s = await (0, import_promises.stat)(jsonlPath);
5099
+ const s = await (0, import_promises2.stat)(jsonlPath);
4721
5100
  return [{ path: jsonlPath, mtimeMs: s.mtimeMs, sessionId }];
4722
5101
  }
4723
5102
  function discoverAllSessions(maxAgeMs) {
@@ -4725,7 +5104,7 @@ function discoverAllSessions(maxAgeMs) {
4725
5104
  }
4726
5105
  async function rawTextMatch(filePath, query, caseSensitive) {
4727
5106
  try {
4728
- const content = await (0, import_promises.readFile)(filePath, "utf-8");
5107
+ const content = await readTranscriptText(filePath);
4729
5108
  const haystack = caseSensitive ? content : content.toLowerCase();
4730
5109
  const needle = caseSensitive ? query : query.toLowerCase();
4731
5110
  if (haystack.includes(needle)) return content;
@@ -4800,7 +5179,7 @@ async function walkSubagentFiles(parentJsonlPath, query, caseSensitive, currentD
4800
5179
  const subDir = parentJsonlPath.replace(/\.jsonl$/, "") + "/subagents";
4801
5180
  let files;
4802
5181
  try {
4803
- files = await (0, import_promises.readdir)(subDir);
5182
+ files = await (0, import_promises2.readdir)(subDir);
4804
5183
  } catch {
4805
5184
  return [];
4806
5185
  }
@@ -4817,7 +5196,7 @@ async function walkSubagentFiles(parentJsonlPath, query, caseSensitive, currentD
4817
5196
  );
4818
5197
  const hitArrays = await Promise.all(
4819
5198
  matched.filter((m) => m.rawContent).map(async ({ agentId, filePath, rawContent }) => {
4820
- const subSession = parseSession(rawContent);
5199
+ const subSession = parseTranscript(rawContent, filePath);
4821
5200
  const subHits = walkSession(subSession, query, caseSensitive, `agent/${agentId}/`);
4822
5201
  const nestedHits = await walkSubagentFiles(filePath, query, caseSensitive, currentDepth + 1, maxDepth);
4823
5202
  return [...subHits, ...nestedHits];
@@ -4838,7 +5217,7 @@ async function rawScanSearch(query, sessionId, maxAgeMs, limit, caseSensitive, e
4838
5217
  const rawContent = await rawTextMatch(file.path, query, caseSensitive);
4839
5218
  sessionsSearched++;
4840
5219
  if (!rawContent) continue;
4841
- const session = parseSession(rawContent);
5220
+ const session = parseTranscript(rawContent, file.path);
4842
5221
  const sessionHits = walkSession(session, query, caseSensitive);
4843
5222
  const subagentHits = await walkSubagentFiles(file.path, query, caseSensitive, 0, MAX_SUBAGENT_DEPTH);
4844
5223
  const allHits = [...sessionHits, ...subagentHits];
@@ -4878,14 +5257,14 @@ async function rawScanSearch(query, sessionId, maxAgeMs, limit, caseSensitive, e
4878
5257
  }
4879
5258
 
4880
5259
  // src/commands/context.ts
4881
- var import_promises3 = require("node:fs/promises");
5260
+ var import_promises4 = require("node:fs/promises");
4882
5261
  var import_node_path5 = require("node:path");
4883
5262
 
4884
5263
  // src/lib/helpers.ts
4885
- var import_promises2 = require("node:fs/promises");
5264
+ var import_promises3 = require("node:fs/promises");
4886
5265
  var import_node_path4 = require("node:path");
4887
5266
  async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
4888
- 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 });
4889
5268
  for (const entry of entries) {
4890
5269
  if (!entry.isDirectory() || entry.name === "memory") continue;
4891
5270
  const filePath = (0, import_node_path4.join)(
@@ -4896,7 +5275,7 @@ async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
4896
5275
  subagentFileName
4897
5276
  );
4898
5277
  try {
4899
- const fh = await (0, import_promises2.open)(filePath, "r");
5278
+ const fh = await (0, import_promises3.open)(filePath, "r");
4900
5279
  try {
4901
5280
  const buf = Buffer.alloc(16384);
4902
5281
  const { bytesRead } = await fh.read(buf, 0, 16384, 0);
@@ -5090,6 +5469,14 @@ function mapContentBlock(block) {
5090
5469
  return { kind: "recap", content: block.content, timestamp: block.timestamp ?? null };
5091
5470
  case "task_notification":
5092
5471
  return { kind: "task_notification", content: block.content, timestamp: block.timestamp ?? null };
5472
+ case "local_command":
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
+ };
5093
5480
  default: {
5094
5481
  const exhaustive = block;
5095
5482
  return exhaustive;
@@ -5099,7 +5486,7 @@ function mapContentBlock(block) {
5099
5486
  async function findSubagentFile(parentJsonlPath, agentId) {
5100
5487
  const subagentsDir = parentJsonlPath.replace(/\.jsonl$/, "") + "/subagents";
5101
5488
  try {
5102
- const files = await (0, import_promises3.readdir)(subagentsDir);
5489
+ const files = await (0, import_promises4.readdir)(subagentsDir);
5103
5490
  for (const f of files) {
5104
5491
  if (!f.startsWith("agent-") || !f.endsWith(".jsonl")) continue;
5105
5492
  const fileAgentId = f.replace("agent-", "").replace(".jsonl", "");
@@ -5113,12 +5500,12 @@ async function findSubagentFile(parentJsonlPath, agentId) {
5113
5500
  }
5114
5501
  async function findTeamContext(sessionId, subagentFileName) {
5115
5502
  try {
5116
- 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 });
5117
5504
  for (const entry of teamEntries) {
5118
5505
  if (!entry.isDirectory()) continue;
5119
5506
  const configPath = (0, import_node_path5.join)(dirs.TEAMS_DIR, entry.name, "config.json");
5120
5507
  try {
5121
- const raw = await (0, import_promises3.readFile)(configPath, "utf-8");
5508
+ const raw = await (0, import_promises4.readFile)(configPath, "utf-8");
5122
5509
  const config = JSON.parse(raw);
5123
5510
  if (config.leadSessionId !== sessionId) continue;
5124
5511
  const members = config.members ?? [];
@@ -5127,10 +5514,10 @@ async function findTeamContext(sessionId, subagentFileName) {
5127
5514
  let currentTask = null;
5128
5515
  try {
5129
5516
  const taskDir = (0, import_node_path5.join)(dirs.TASKS_DIR, entry.name);
5130
- const taskFiles = await (0, import_promises3.readdir)(taskDir);
5517
+ const taskFiles = await (0, import_promises4.readdir)(taskDir);
5131
5518
  for (const tf of taskFiles) {
5132
5519
  if (!tf.endsWith(".json")) continue;
5133
- 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");
5134
5521
  const task = JSON.parse(taskRaw);
5135
5522
  if (task.owner === memberName && task.status === "in_progress") {
5136
5523
  currentTask = { id: task.id, subject: task.subject, status: task.status };
@@ -5178,27 +5565,27 @@ function findAgentMetadata(session, agentId) {
5178
5565
  async function getSessionOverview(sessionId) {
5179
5566
  const jsonlPath = await findSessionFile(sessionId);
5180
5567
  if (!jsonlPath) return { error: "Session not found" };
5181
- const content = await (0, import_promises3.readFile)(jsonlPath, "utf-8");
5182
- const session = parseSession(content);
5568
+ const content = await readTranscriptText(jsonlPath);
5569
+ const session = parseTranscript(content, jsonlPath);
5183
5570
  return mapSessionToOverview(session);
5184
5571
  }
5185
5572
  async function getTurnDetail(sessionId, turnIndex) {
5186
5573
  const jsonlPath = await findSessionFile(sessionId);
5187
5574
  if (!jsonlPath) return { error: "Session not found" };
5188
- const content = await (0, import_promises3.readFile)(jsonlPath, "utf-8");
5189
- const session = parseSession(content);
5575
+ const content = await readTranscriptText(jsonlPath);
5576
+ const session = parseTranscript(content, jsonlPath);
5190
5577
  if (turnIndex < 0 || turnIndex >= session.turns.length) return { error: "Turn not found" };
5191
5578
  return mapTurnToDetail(session, turnIndex);
5192
5579
  }
5193
5580
  async function getAgentOverview(sessionId, agentId) {
5194
5581
  const jsonlPath = await findSessionFile(sessionId);
5195
5582
  if (!jsonlPath) return { error: "Session not found" };
5196
- const content = await (0, import_promises3.readFile)(jsonlPath, "utf-8");
5197
- const session = parseSession(content);
5583
+ const content = await readTranscriptText(jsonlPath);
5584
+ const session = parseTranscript(content, jsonlPath);
5198
5585
  const subagentFile = await findSubagentFile(jsonlPath, agentId);
5199
5586
  if (!subagentFile) return { error: "Agent not found" };
5200
- const subagentContent = await (0, import_promises3.readFile)(subagentFile.filePath, "utf-8");
5201
- const subagentSession = parseSession(subagentContent);
5587
+ const subagentContent = await readTranscriptText(subagentFile.filePath);
5588
+ const subagentSession = parseTranscript(subagentContent, subagentFile.filePath);
5202
5589
  const metadata = findAgentMetadata(session, agentId);
5203
5590
  const parentToolCallId = findParentToolCallId(session, agentId);
5204
5591
  const teamContext = await findTeamContext(sessionId, subagentFile.fileName);
@@ -5218,8 +5605,8 @@ async function getAgentTurnDetail(sessionId, agentId, turnIndex) {
5218
5605
  if (!jsonlPath) return { error: "Session not found" };
5219
5606
  const subagentFile = await findSubagentFile(jsonlPath, agentId);
5220
5607
  if (!subagentFile) return { error: "Agent not found" };
5221
- const subagentContent = await (0, import_promises3.readFile)(subagentFile.filePath, "utf-8");
5222
- const subagentSession = parseSession(subagentContent);
5608
+ const subagentContent = await readTranscriptText(subagentFile.filePath);
5609
+ const subagentSession = parseTranscript(subagentContent, subagentFile.filePath);
5223
5610
  if (turnIndex < 0 || turnIndex >= subagentSession.turns.length) return { error: "Turn not found" };
5224
5611
  return mapTurnToDetail(subagentSession, turnIndex);
5225
5612
  }
@@ -5228,7 +5615,7 @@ async function getAgentTurnDetail(sessionId, agentId, turnIndex) {
5228
5615
  var import_node_path6 = require("node:path");
5229
5616
 
5230
5617
  // src/lib/metadata.ts
5231
- var import_promises4 = require("node:fs/promises");
5618
+ var import_promises5 = require("node:fs/promises");
5232
5619
 
5233
5620
  // src/lib/sessionStatus.ts
5234
5621
  function deriveSessionStatus(rawMessages) {
@@ -5253,15 +5640,16 @@ function scanClaudeMessages(lines) {
5253
5640
  turnCount: 0
5254
5641
  };
5255
5642
  for (const line of lines) {
5256
- let record;
5643
+ if (isAnyAgentNoiseLine(line)) continue;
5644
+ let record2;
5257
5645
  try {
5258
- record = JSON.parse(line);
5646
+ record2 = JSON.parse(line);
5259
5647
  } catch {
5260
5648
  continue;
5261
5649
  }
5262
- if (record.type !== "user" || record.isMeta) continue;
5263
- if (!meta.timestamp) meta.timestamp = record.timestamp || "";
5264
- const content = record.message?.content;
5650
+ if (record2.type !== "user" || record2.isMeta) continue;
5651
+ if (!meta.timestamp) meta.timestamp = record2.timestamp || "";
5652
+ const content = record2.message?.content;
5265
5653
  let extracted = "";
5266
5654
  if (typeof content === "string") {
5267
5655
  extracted = cleanUserText(content);
@@ -5281,11 +5669,11 @@ function scanClaudeMessages(lines) {
5281
5669
  return meta;
5282
5670
  }
5283
5671
  async function readLines(filePath, size) {
5284
- if (size <= FULL_READ_LIMIT) {
5285
- const content = await (0, import_promises4.readFile)(filePath, "utf-8");
5672
+ if (size <= FULL_READ_LIMIT || isCompressedTranscript(filePath)) {
5673
+ const content = await readTranscriptText(filePath);
5286
5674
  return { lines: content.split("\n").filter(Boolean), isPartialRead: false };
5287
5675
  }
5288
- const handle = await (0, import_promises4.open)(filePath, "r");
5676
+ const handle = await (0, import_promises5.open)(filePath, "r");
5289
5677
  try {
5290
5678
  const buffer = Buffer.alloc(HEAD_READ_BYTES);
5291
5679
  const { bytesRead } = await handle.read(buffer, 0, HEAD_READ_BYTES, 0);
@@ -5300,14 +5688,15 @@ async function readLines(filePath, size) {
5300
5688
  }
5301
5689
  }
5302
5690
  async function getSessionMeta(filePath) {
5303
- const fileStat = await (0, import_promises4.stat)(filePath);
5691
+ const fileStat = await (0, import_promises5.stat)(filePath);
5304
5692
  let { lines, isPartialRead } = await readLines(filePath, fileStat.size);
5305
5693
  const format = formatForText(lines.join("\n"));
5306
5694
  if (isPartialRead && !format.descriptor.metadataFromHead) {
5307
- 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);
5308
5696
  isPartialRead = false;
5309
5697
  }
5310
5698
  const header = readHeader(format, lines);
5699
+ const instanceId = storeForPath(filePath)?.instanceId ?? "default";
5311
5700
  const conversation = header.turnCount === void 0 ? scanClaudeMessages(lines) : {
5312
5701
  firstUserMessage: header.firstUserMessage ?? "",
5313
5702
  lastUserMessage: header.lastUserMessage ?? "",
@@ -5315,7 +5704,7 @@ async function getSessionMeta(filePath) {
5315
5704
  turnCount: header.turnCount
5316
5705
  };
5317
5706
  return {
5318
- sessionId: header.sessionId,
5707
+ sessionId: instanceSessionId(instanceId, header.sessionId),
5319
5708
  version: header.version,
5320
5709
  gitBranch: header.gitBranch,
5321
5710
  model: header.model,
@@ -5325,17 +5714,17 @@ async function getSessionMeta(filePath) {
5325
5714
  // A head read saw a known number of lines in a known number of bytes;
5326
5715
  // scaling that by the file size is the only estimate available.
5327
5716
  lineCount: isPartialRead ? Math.round(fileStat.size / (HEAD_READ_BYTES / lines.length)) : lines.length,
5328
- branchedFrom: header.branchedFrom
5717
+ branchedFrom: header.branchedFrom ? { ...header.branchedFrom, sessionId: instanceSessionId(instanceId, header.branchedFrom.sessionId) } : void 0
5329
5718
  };
5330
5719
  }
5331
5720
  async function getSessionStatus(filePath) {
5332
5721
  const CHUNK = 4096;
5333
5722
  const MAX_CHUNKS = 64;
5334
5723
  try {
5335
- const fileStat = await (0, import_promises4.stat)(filePath);
5336
- if (fileStat.size === 0) return { status: "idle" };
5337
- const fh = await (0, import_promises4.open)(filePath, "r");
5724
+ const fh = await openTranscript(filePath);
5338
5725
  try {
5726
+ const fileStat = await fh.stat();
5727
+ if (fileStat.size === 0) return { status: "idle" };
5339
5728
  const meaningful = [];
5340
5729
  let cursor = fileStat.size;
5341
5730
  let leftover = "";
@@ -5351,7 +5740,7 @@ async function getSessionStatus(filePath) {
5351
5740
  const startIdx = cursor > 0 ? 1 : 0;
5352
5741
  for (let i = lines.length - 1; i >= startIdx; i--) {
5353
5742
  const line = lines[i];
5354
- if (!line) continue;
5743
+ if (!line || isAnyAgentNoiseLine(line)) continue;
5355
5744
  let obj;
5356
5745
  try {
5357
5746
  obj = JSON.parse(line);
@@ -5420,7 +5809,7 @@ async function getSessionStatus(filePath) {
5420
5809
  // src/commands/sessions.ts
5421
5810
  function toSessionSummary(file, meta, status) {
5422
5811
  return {
5423
- sessionId: meta.sessionId,
5812
+ sessionId: file.sessionId || meta.sessionId,
5424
5813
  filePath: file.path,
5425
5814
  timestamp: meta.timestamp,
5426
5815
  model: meta.model,
@@ -5482,11 +5871,11 @@ async function currentSession(cwd) {
5482
5871
  }
5483
5872
 
5484
5873
  // src/commands/index-cmd.ts
5485
- var import_node_fs4 = require("node:fs");
5874
+ var import_node_fs5 = require("node:fs");
5486
5875
  var import_node_path7 = require("node:path");
5487
5876
  async function indexStats(dbPath) {
5488
5877
  const path = dbPath ?? DEFAULT_DB_PATH;
5489
- if (!(0, import_node_fs4.existsSync)(path)) {
5878
+ if (!(0, import_node_fs5.existsSync)(path)) {
5490
5879
  return { error: `Database not found at ${path}. Run 'cogpit-memory index rebuild' to create it.` };
5491
5880
  }
5492
5881
  const index = new SearchIndex(path);
@@ -5496,7 +5885,7 @@ async function indexStats(dbPath) {
5496
5885
  }
5497
5886
  async function indexRebuild(dbPath) {
5498
5887
  const path = dbPath ?? DEFAULT_DB_PATH;
5499
- (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 });
5500
5889
  const index = new SearchIndex(path);
5501
5890
  index.buildFull();
5502
5891
  const stats = index.getStats();
@@ -5505,7 +5894,7 @@ async function indexRebuild(dbPath) {
5505
5894
  }
5506
5895
 
5507
5896
  // src/commands/install-skill.ts
5508
- var import_node_fs5 = require("node:fs");
5897
+ var import_node_fs6 = require("node:fs");
5509
5898
  var import_node_path8 = require("node:path");
5510
5899
  function findSkillContent() {
5511
5900
  const candidates = [];
@@ -5515,8 +5904,8 @@ function findSkillContent() {
5515
5904
  }
5516
5905
  for (const candidate of candidates) {
5517
5906
  try {
5518
- if ((0, import_node_fs5.existsSync)(candidate)) {
5519
- 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");
5520
5909
  }
5521
5910
  } catch {
5522
5911
  }
@@ -5526,10 +5915,10 @@ function findSkillContent() {
5526
5915
  function installSkill(cwd, global) {
5527
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");
5528
5917
  const skillDir = (0, import_node_path8.join)(root, "skills", "cogpit-memory");
5529
- (0, import_node_fs5.mkdirSync)(skillDir, { recursive: true });
5918
+ (0, import_node_fs6.mkdirSync)(skillDir, { recursive: true });
5530
5919
  const content = findSkillContent();
5531
5920
  const dest = (0, import_node_path8.join)(skillDir, "SKILL.md");
5532
- (0, import_node_fs5.writeFileSync)(dest, content);
5921
+ (0, import_node_fs6.writeFileSync)(dest, content);
5533
5922
  return { installed: true, path: skillDir };
5534
5923
  }
5535
5924