sidekick-shared 0.29.0 → 0.30.0

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.
Files changed (142) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +198 -56
  3. package/dist/aggregation/EventAggregator.d.ts +96 -2
  4. package/dist/aggregation/EventAggregator.js +535 -42
  5. package/dist/aggregation/snapshot.d.ts +37 -8
  6. package/dist/aggregation/snapshot.js +31 -9
  7. package/dist/aggregation/types.d.ts +38 -1
  8. package/dist/browser.d.ts +9 -1
  9. package/dist/browser.js +29 -3
  10. package/dist/context/sessionContext.js +8 -0
  11. package/dist/esm/aggregation/EventAggregator.js +535 -42
  12. package/dist/esm/aggregation/snapshot.js +31 -9
  13. package/dist/esm/browser.js +3 -0
  14. package/dist/esm/context/sessionContext.js +8 -0
  15. package/dist/esm/fileContinuity.js +149 -0
  16. package/dist/esm/formatters/toolSummary.js +4 -1
  17. package/dist/esm/index.js +7 -2
  18. package/dist/esm/modelCatalog.js +5 -4
  19. package/dist/esm/modelContext.js +4 -3
  20. package/dist/esm/modelInfo.js +4 -3
  21. package/dist/esm/node.js +3 -1
  22. package/dist/esm/observedContextWindows.js +2 -1
  23. package/dist/esm/ownKey.js +26 -0
  24. package/dist/esm/parsers/codexParser.js +372 -7
  25. package/dist/esm/parsers/openCodeParser.js +2 -1
  26. package/dist/esm/parsers/subagentEndState.js +61 -0
  27. package/dist/esm/parsers/subagentScanner.js +37 -12
  28. package/dist/esm/parsers/subagentTraceParser.js +103 -37
  29. package/dist/esm/pricingCatalog.js +3 -2
  30. package/dist/esm/promptHistory.js +22 -11
  31. package/dist/esm/providers/claudeCode.js +60 -29
  32. package/dist/esm/providers/codex.js +235 -201
  33. package/dist/esm/providers/codexCompressedReader.js +184 -0
  34. package/dist/esm/providers/codexDatabase.js +47 -2
  35. package/dist/esm/providers/codexRollouts.js +20 -2
  36. package/dist/esm/providers/codexSubagents.js +456 -0
  37. package/dist/esm/providers/compressedRollouts.js +330 -0
  38. package/dist/esm/providers/factory.js +4 -1
  39. package/dist/esm/providers/rolloutWalker.js +32 -4
  40. package/dist/esm/schemas/sessionEvent.js +63 -14
  41. package/dist/esm/sessionMonitor.js +7 -1
  42. package/dist/esm/sessionPreviews.js +9 -0
  43. package/dist/esm/sessionPromptHistory.js +5 -3
  44. package/dist/esm/subagentActivity.js +125 -0
  45. package/dist/esm/subagentDisplayState.js +81 -0
  46. package/dist/esm/subagentSpawn.js +363 -0
  47. package/dist/esm/testing/codexSubagentFixtures.js +336 -0
  48. package/dist/esm/toolCallOrigins.js +17 -10
  49. package/dist/esm/toolCategory.js +6 -2
  50. package/dist/esm/transcript.js +8 -0
  51. package/dist/esm/turns/assistantTurn.js +6 -2
  52. package/dist/esm/usage/claudeUsageDedupe.js +68 -0
  53. package/dist/esm/usage/usageEvents.js +4 -1
  54. package/dist/esm/watchers/eventBridge.js +45 -0
  55. package/dist/esm/watchers/factory.js +5 -3
  56. package/dist/esm/watchers/jsonlTail.js +82 -48
  57. package/dist/esm/watchers/jsonlWatcher.js +61 -4
  58. package/dist/esm/watchers/providerReaderWatcher.js +18 -4
  59. package/dist/esm/zaiQuota.js +2 -1
  60. package/dist/fileContinuity.d.ts +95 -0
  61. package/dist/fileContinuity.js +187 -0
  62. package/dist/formatters/toolSummary.js +4 -1
  63. package/dist/index.d.ts +19 -7
  64. package/dist/index.js +48 -10
  65. package/dist/modelCatalog.js +5 -4
  66. package/dist/modelContext.js +4 -3
  67. package/dist/modelInfo.js +4 -3
  68. package/dist/node.d.ts +5 -1
  69. package/dist/node.js +18 -2
  70. package/dist/observedContextWindows.js +2 -1
  71. package/dist/ownKey.d.ts +16 -0
  72. package/dist/ownKey.js +30 -0
  73. package/dist/parsers/codexParser.d.ts +107 -0
  74. package/dist/parsers/codexParser.js +373 -7
  75. package/dist/parsers/openCodeParser.js +2 -1
  76. package/dist/parsers/subagentEndState.d.ts +20 -0
  77. package/dist/parsers/subagentEndState.js +65 -0
  78. package/dist/parsers/subagentScanner.d.ts +19 -6
  79. package/dist/parsers/subagentScanner.js +37 -12
  80. package/dist/parsers/subagentTraceParser.d.ts +33 -5
  81. package/dist/parsers/subagentTraceParser.js +103 -37
  82. package/dist/pricingCatalog.js +3 -2
  83. package/dist/promptHistory.d.ts +13 -3
  84. package/dist/promptHistory.js +22 -11
  85. package/dist/providers/claudeCode.js +59 -28
  86. package/dist/providers/codex.d.ts +35 -5
  87. package/dist/providers/codex.js +232 -198
  88. package/dist/providers/codexCompressedReader.d.ts +58 -0
  89. package/dist/providers/codexCompressedReader.js +221 -0
  90. package/dist/providers/codexDatabase.d.ts +25 -0
  91. package/dist/providers/codexDatabase.js +48 -2
  92. package/dist/providers/codexRollouts.d.ts +16 -2
  93. package/dist/providers/codexRollouts.js +20 -2
  94. package/dist/providers/codexSubagents.d.ts +66 -0
  95. package/dist/providers/codexSubagents.js +495 -0
  96. package/dist/providers/compressedRollouts.d.ts +114 -0
  97. package/dist/providers/compressedRollouts.js +380 -0
  98. package/dist/providers/factory.d.ts +5 -0
  99. package/dist/providers/factory.js +4 -1
  100. package/dist/providers/rolloutWalker.d.ts +15 -2
  101. package/dist/providers/rolloutWalker.js +33 -4
  102. package/dist/providers/types.d.ts +36 -1
  103. package/dist/schemas/index.d.ts +1 -0
  104. package/dist/schemas/sessionEvent.d.ts +51 -10
  105. package/dist/schemas/sessionEvent.js +63 -14
  106. package/dist/sessionMonitor.d.ts +6 -0
  107. package/dist/sessionMonitor.js +7 -1
  108. package/dist/sessionPreviews.js +9 -0
  109. package/dist/sessionPromptHistory.d.ts +5 -0
  110. package/dist/sessionPromptHistory.js +5 -36
  111. package/dist/subagentActivity.d.ts +91 -0
  112. package/dist/subagentActivity.js +132 -0
  113. package/dist/subagentDisplayState.d.ts +81 -0
  114. package/dist/subagentDisplayState.js +86 -0
  115. package/dist/subagentSpawn.d.ts +175 -0
  116. package/dist/subagentSpawn.js +385 -0
  117. package/dist/testing/codexSubagentFixtures.d.ts +48 -0
  118. package/dist/testing/codexSubagentFixtures.js +344 -0
  119. package/dist/toolCallOrigins.d.ts +5 -0
  120. package/dist/toolCallOrigins.js +17 -10
  121. package/dist/toolCategory.js +6 -2
  122. package/dist/transcript.js +8 -0
  123. package/dist/turns/assistantTurn.d.ts +4 -0
  124. package/dist/turns/assistantTurn.js +6 -2
  125. package/dist/types/codex.d.ts +71 -2
  126. package/dist/types/sessionEvent.d.ts +38 -3
  127. package/dist/usage/claudeUsageDedupe.d.ts +31 -0
  128. package/dist/usage/claudeUsageDedupe.js +68 -0
  129. package/dist/usage/usageEvents.d.ts +4 -1
  130. package/dist/usage/usageEvents.js +4 -1
  131. package/dist/watchers/eventBridge.js +45 -0
  132. package/dist/watchers/factory.d.ts +6 -0
  133. package/dist/watchers/factory.js +5 -3
  134. package/dist/watchers/jsonlTail.d.ts +27 -4
  135. package/dist/watchers/jsonlTail.js +84 -48
  136. package/dist/watchers/jsonlWatcher.d.ts +22 -1
  137. package/dist/watchers/jsonlWatcher.js +60 -3
  138. package/dist/watchers/providerReaderWatcher.d.ts +7 -0
  139. package/dist/watchers/providerReaderWatcher.js +18 -4
  140. package/dist/watchers/types.d.ts +12 -0
  141. package/dist/zaiQuota.js +2 -1
  142. package/package.json +1 -1
@@ -60,9 +60,11 @@ export declare const sessionMessageSchema: z.ZodObject<{
60
60
  }, z.core.$strip>;
61
61
  export declare const permissionModeSchema: z.ZodEnum<{
62
62
  default: "default";
63
+ auto: "auto";
63
64
  acceptEdits: "acceptEdits";
64
65
  bypassPermissions: "bypassPermissions";
65
66
  plan: "plan";
67
+ dontAsk: "dontAsk";
66
68
  }>;
67
69
  export declare const userSessionEventSchema: z.ZodObject<{
68
70
  timestamp: z.ZodString;
@@ -76,12 +78,14 @@ export declare const userSessionEventSchema: z.ZodObject<{
76
78
  promptSource: z.ZodOptional<z.ZodString>;
77
79
  cwd: z.ZodOptional<z.ZodString>;
78
80
  gitBranch: z.ZodOptional<z.ZodString>;
79
- permissionMode: z.ZodOptional<z.ZodEnum<{
81
+ permissionMode: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
80
82
  default: "default";
83
+ auto: "auto";
81
84
  acceptEdits: "acceptEdits";
82
85
  bypassPermissions: "bypassPermissions";
83
86
  plan: "plan";
84
- }>>;
87
+ dontAsk: "dontAsk";
88
+ }>>>;
85
89
  rateLimits: z.ZodOptional<z.ZodObject<{
86
90
  primary: z.ZodOptional<z.ZodObject<{
87
91
  usedPercent: z.ZodNumber;
@@ -165,12 +169,14 @@ export declare const assistantSessionEventSchema: z.ZodObject<{
165
169
  promptSource: z.ZodOptional<z.ZodString>;
166
170
  cwd: z.ZodOptional<z.ZodString>;
167
171
  gitBranch: z.ZodOptional<z.ZodString>;
168
- permissionMode: z.ZodOptional<z.ZodEnum<{
172
+ permissionMode: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
169
173
  default: "default";
174
+ auto: "auto";
170
175
  acceptEdits: "acceptEdits";
171
176
  bypassPermissions: "bypassPermissions";
172
177
  plan: "plan";
173
- }>>;
178
+ dontAsk: "dontAsk";
179
+ }>>>;
174
180
  rateLimits: z.ZodOptional<z.ZodObject<{
175
181
  primary: z.ZodOptional<z.ZodObject<{
176
182
  usedPercent: z.ZodNumber;
@@ -244,6 +250,7 @@ export declare const assistantSessionEventSchema: z.ZodObject<{
244
250
  }, z.core.$strip>;
245
251
  export declare const summarySessionEventSchema: z.ZodType<SummarySessionEvent>;
246
252
  export declare const systemSessionEventSchema: z.ZodObject<{
253
+ subtype: z.ZodCatch<z.ZodOptional<z.ZodString>>;
247
254
  timestamp: z.ZodString;
248
255
  entrypoint: z.ZodOptional<z.ZodString>;
249
256
  isMeta: z.ZodOptional<z.ZodBoolean>;
@@ -255,12 +262,14 @@ export declare const systemSessionEventSchema: z.ZodObject<{
255
262
  promptSource: z.ZodOptional<z.ZodString>;
256
263
  cwd: z.ZodOptional<z.ZodString>;
257
264
  gitBranch: z.ZodOptional<z.ZodString>;
258
- permissionMode: z.ZodOptional<z.ZodEnum<{
265
+ permissionMode: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
259
266
  default: "default";
267
+ auto: "auto";
260
268
  acceptEdits: "acceptEdits";
261
269
  bypassPermissions: "bypassPermissions";
262
270
  plan: "plan";
263
- }>>;
271
+ dontAsk: "dontAsk";
272
+ }>>>;
264
273
  rateLimits: z.ZodOptional<z.ZodObject<{
265
274
  primary: z.ZodOptional<z.ZodObject<{
266
275
  usedPercent: z.ZodNumber;
@@ -348,12 +357,14 @@ export declare const toolUseSessionEventSchema: z.ZodObject<{
348
357
  promptSource: z.ZodOptional<z.ZodString>;
349
358
  cwd: z.ZodOptional<z.ZodString>;
350
359
  gitBranch: z.ZodOptional<z.ZodString>;
351
- permissionMode: z.ZodOptional<z.ZodEnum<{
360
+ permissionMode: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
352
361
  default: "default";
362
+ auto: "auto";
353
363
  acceptEdits: "acceptEdits";
354
364
  bypassPermissions: "bypassPermissions";
355
365
  plan: "plan";
356
- }>>;
366
+ dontAsk: "dontAsk";
367
+ }>>>;
357
368
  rateLimits: z.ZodOptional<z.ZodObject<{
358
369
  primary: z.ZodOptional<z.ZodObject<{
359
370
  usedPercent: z.ZodNumber;
@@ -442,12 +453,14 @@ export declare const toolResultSessionEventSchema: z.ZodObject<{
442
453
  promptSource: z.ZodOptional<z.ZodString>;
443
454
  cwd: z.ZodOptional<z.ZodString>;
444
455
  gitBranch: z.ZodOptional<z.ZodString>;
445
- permissionMode: z.ZodOptional<z.ZodEnum<{
456
+ permissionMode: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
446
457
  default: "default";
458
+ auto: "auto";
447
459
  acceptEdits: "acceptEdits";
448
460
  bypassPermissions: "bypassPermissions";
449
461
  plan: "plan";
450
- }>>;
462
+ dontAsk: "dontAsk";
463
+ }>>>;
451
464
  rateLimits: z.ZodOptional<z.ZodObject<{
452
465
  primary: z.ZodOptional<z.ZodObject<{
453
466
  usedPercent: z.ZodNumber;
@@ -520,6 +533,30 @@ export declare const toolResultSessionEventSchema: z.ZodObject<{
520
533
  }, z.core.$strip>>;
521
534
  }, z.core.$strip>;
522
535
  export declare const sessionEventSchema: z.ZodType<SessionEvent>;
536
+ /** Options for {@link extractSessionEvents}. */
537
+ export interface ExtractSessionEventsOptions {
538
+ /**
539
+ * Also turn Claude Code's mid-turn task-notification attachments
540
+ * (`{ type: 'attachment', attachment: { type: 'queued_command',
541
+ * commandMode: 'task-notification', prompt } }`) into one `system` event
542
+ * with `origin: { kind: 'task-notification' }`, `message: { role: 'user',
543
+ * sourceLabel: 'task notification', content: <prompt> }`, and the line's
544
+ * timestamp. They report background agents finishing (or, as plain text,
545
+ * the user stopping them: see `parseAgentsStoppedNotice`).
546
+ *
547
+ * Also turns a background agent's `task_status` attachment with a final
548
+ * status (`{ type: 'attachment', attachment: { type: 'task_status',
549
+ * taskType: 'local_agent', taskId, status: 'completed', … } }`) into a
550
+ * `system` event with `origin: { kind: 'task-status' }` and `message: {
551
+ * role: 'system', sourceLabel: 'task status', content: [{ type:
552
+ * 'task_status', taskId, taskType, status, description }] }` (read it with
553
+ * `taskStatusFromEvent`). Default `false`: attachment lines yield no events.
554
+ *
555
+ * System lines (`agents_killed` among them) parse either way and keep
556
+ * their `subtype`.
557
+ */
558
+ includeTaskNotifications?: boolean;
559
+ }
523
560
  /**
524
561
  * Extracts canonical SessionEvents from a raw JSONL value.
525
562
  *
@@ -528,5 +565,9 @@ export declare const sessionEventSchema: z.ZodType<SessionEvent>;
528
565
  * `sessionEventSchema` alone rejects. This helper tries a direct parse,
529
566
  * then unwraps progress envelopes (recursively, in case of nesting).
530
567
  * Returns zero events for unrecognized input — never throws.
568
+ *
569
+ * The second argument is either the starting progress depth (the original
570
+ * signature) or an options object.
531
571
  */
532
572
  export declare function extractSessionEvents(raw: unknown, depth?: number): SessionEvent[];
573
+ export declare function extractSessionEvents(raw: unknown, options?: ExtractSessionEventsOptions): SessionEvent[];
@@ -12,6 +12,7 @@ exports.sessionEventSchema = exports.toolResultSessionEventSchema = exports.tool
12
12
  exports.extractSessionEvents = extractSessionEvents;
13
13
  const zod_1 = require("zod");
14
14
  const usageNormalization_1 = require("./usageNormalization");
15
+ const subagentSpawn_1 = require("../subagentSpawn");
15
16
  // ── MessageUsage ──
16
17
  exports.messageUsageSchema = zod_1.z.object({
17
18
  input_tokens: zod_1.z.number(),
@@ -44,6 +45,8 @@ exports.permissionModeSchema = zod_1.z.enum([
44
45
  'acceptEdits',
45
46
  'bypassPermissions',
46
47
  'plan',
48
+ 'auto',
49
+ 'dontAsk',
47
50
  ]);
48
51
  // ── SessionEvent ──
49
52
  const eventBaseShape = {
@@ -56,7 +59,9 @@ const eventBaseShape = {
56
59
  promptSource: zod_1.z.string().optional(),
57
60
  cwd: zod_1.z.string().optional(),
58
61
  gitBranch: zod_1.z.string().optional(),
59
- permissionMode: exports.permissionModeSchema.optional(),
62
+ // A mode this release doesn't know is dropped rather than rejecting the
63
+ // whole line with its prompt or tool results.
64
+ permissionMode: exports.permissionModeSchema.optional().catch(undefined),
60
65
  rateLimits: zod_1.z
61
66
  .object({
62
67
  primary: zod_1.z
@@ -145,6 +150,9 @@ exports.systemSessionEventSchema = zod_1.z.object({
145
150
  type: zod_1.z.literal('system'),
146
151
  message: exports.sessionMessageSchema.optional(),
147
152
  ...eventBaseShape,
153
+ // Claude Code's system-line subtype (`agents_killed`, `turn_duration`, …);
154
+ // a malformed one is dropped rather than rejecting the line.
155
+ subtype: zod_1.z.string().optional().catch(undefined),
148
156
  });
149
157
  exports.toolUseSessionEventSchema = zod_1.z.object({
150
158
  type: zod_1.z.literal('tool_use'),
@@ -173,22 +181,21 @@ exports.sessionEventSchema = zod_1.z.union([
173
181
  // ── Progress unwrapping ──
174
182
  /** Recursion bound for nested progress envelopes; real data nests 1 level. */
175
183
  const MAX_PROGRESS_DEPTH = 8;
176
- /**
177
- * Extracts canonical SessionEvents from a raw JSONL value.
178
- *
179
- * Claude Code wraps subagent/SDK events as
180
- * `{ type: 'progress', data: { message: <SessionEvent> } }`, which
181
- * `sessionEventSchema` alone rejects. This helper tries a direct parse,
182
- * then unwraps progress envelopes (recursively, in case of nesting).
183
- * Returns zero events for unrecognized input — never throws.
184
- */
185
- function extractSessionEvents(raw, depth = 0) {
186
- return extractSessionEventsWithProvenance(raw, depth, {});
184
+ function extractSessionEvents(raw, depthOrOptions = 0) {
185
+ if (typeof depthOrOptions === 'number') {
186
+ return extractSessionEventsWithProvenance(raw, depthOrOptions, {}, {});
187
+ }
188
+ return extractSessionEventsWithProvenance(raw, 0, {}, depthOrOptions ?? {});
187
189
  }
188
- function extractSessionEventsWithProvenance(raw, depth, inherited) {
190
+ function extractSessionEventsWithProvenance(raw, depth, inherited, options) {
189
191
  const direct = exports.sessionEventSchema.safeParse(raw);
190
192
  if (direct.success)
191
193
  return [{ ...inherited, ...direct.data }];
194
+ if (options.includeTaskNotifications) {
195
+ const notification = taskNotificationAttachmentEvent(raw) ?? taskStatusAttachmentEvent(raw);
196
+ if (notification)
197
+ return [{ ...inherited, ...notification }];
198
+ }
192
199
  if (depth >= MAX_PROGRESS_DEPTH)
193
200
  return [];
194
201
  if (typeof raw === 'object' && raw !== null && raw.type === 'progress') {
@@ -197,12 +204,54 @@ function extractSessionEventsWithProvenance(raw, depth, inherited) {
197
204
  if (typeof data === 'object' && data !== null) {
198
205
  const message = data.message;
199
206
  if (typeof message === 'object' && message !== null) {
200
- return extractSessionEventsWithProvenance(message, depth + 1, provenance);
207
+ return extractSessionEventsWithProvenance(message, depth + 1, provenance, options);
201
208
  }
202
209
  }
203
210
  }
204
211
  return [];
205
212
  }
213
+ /** The `system` event for a task-notification attachment line, or `null`. */
214
+ function taskNotificationAttachmentEvent(raw) {
215
+ const prompt = (0, subagentSpawn_1.taskNotificationPromptFromAttachment)(raw);
216
+ if (prompt === null)
217
+ return null;
218
+ const line = raw;
219
+ const candidate = {
220
+ type: 'system',
221
+ timestamp: line.timestamp,
222
+ origin: { kind: 'task-notification' },
223
+ message: { role: 'user', sourceLabel: 'task notification', content: prompt },
224
+ };
225
+ for (const key of ['entrypoint', 'isSidechain', 'cwd', 'gitBranch']) {
226
+ if (line[key] !== undefined)
227
+ candidate[key] = line[key];
228
+ }
229
+ const parsed = exports.systemSessionEventSchema.safeParse(candidate);
230
+ return parsed.success ? parsed.data : null;
231
+ }
232
+ /** The `system` event for a background agent's final `task_status` attachment, or `null`. */
233
+ function taskStatusAttachmentEvent(raw) {
234
+ const status = (0, subagentSpawn_1.taskStatusFromAttachment)(raw);
235
+ if (!status || !(0, subagentSpawn_1.isFinalTaskStatus)(status.status))
236
+ return null;
237
+ const line = raw;
238
+ const candidate = {
239
+ type: 'system',
240
+ timestamp: line.timestamp,
241
+ origin: { kind: subagentSpawn_1.TASK_STATUS_ORIGIN_KIND },
242
+ message: {
243
+ role: 'system',
244
+ sourceLabel: 'task status',
245
+ content: [{ type: subagentSpawn_1.TASK_STATUS_BLOCK_TYPE, ...status }],
246
+ },
247
+ };
248
+ for (const key of ['entrypoint', 'isSidechain', 'cwd', 'gitBranch']) {
249
+ if (line[key] !== undefined)
250
+ candidate[key] = line[key];
251
+ }
252
+ const parsed = exports.systemSessionEventSchema.safeParse(candidate);
253
+ return parsed.success ? parsed.data : null;
254
+ }
206
255
  function progressProvenance(raw) {
207
256
  const value = raw;
208
257
  const provenance = {};
@@ -25,6 +25,12 @@ export declare class SessionMonitor {
25
25
  constructor(provider: SessionProviderBase, options?: SessionMonitorOptions);
26
26
  attach(sessionPath: string, replay?: boolean): AggregatedMetrics;
27
27
  attachLatest(workspacePath: string, replay?: boolean): AggregatedMetrics | null;
28
+ /**
29
+ * Reads and aggregates what the session gained since the last call. When
30
+ * the reader had to start over (the file was truncated, rewritten, or
31
+ * replaced) the aggregator is reset first and the returned events are the
32
+ * session from the beginning.
33
+ */
28
34
  poll(): SessionEvent[];
29
35
  process(event: SessionEvent): void;
30
36
  onEvent(listener: (event: SessionEvent) => void): () => void;
@@ -67,12 +67,18 @@ class SessionMonitor {
67
67
  const sessionPath = this.provider.findActiveSession(workspacePath);
68
68
  return sessionPath ? this.attach(sessionPath, replay) : null;
69
69
  }
70
+ /**
71
+ * Reads and aggregates what the session gained since the last call. When
72
+ * the reader had to start over (the file was truncated, rewritten, or
73
+ * replaced) the aggregator is reset first and the returned events are the
74
+ * session from the beginning.
75
+ */
70
76
  poll() {
71
77
  if (!this.reader)
72
78
  return [];
79
+ const events = this.reader.readNew();
73
80
  if (this.reader.wasTruncated())
74
81
  this.aggregator.reset();
75
- const events = this.reader.readNew();
76
82
  this.consume(events);
77
83
  return events;
78
84
  }
@@ -57,6 +57,7 @@ exports.readSessionPreviewAsync = readSessionPreviewAsync;
57
57
  exports.listSessionPreviews = listSessionPreviews;
58
58
  exports.listSessionPreviewsAsync = listSessionPreviewsAsync;
59
59
  const fs = __importStar(require("fs"));
60
+ const compressedRollouts_1 = require("./providers/compressedRollouts");
60
61
  function emptyPrefixScan() {
61
62
  return { firstTimestamp: null, workspacePath: null };
62
63
  }
@@ -454,6 +455,12 @@ function scanPrefix(sessionPath, maxPrefixBytes) {
454
455
  const result = { firstTimestamp: null, workspacePath: null };
455
456
  let content;
456
457
  let sawWholeFile;
458
+ if ((0, compressedRollouts_1.isCompressedRolloutPath)(sessionPath)) {
459
+ // A compressed Codex rollout: scan its decompressed prefix.
460
+ const head = (0, compressedRollouts_1.readRolloutHead)(sessionPath, Math.max(1, maxPrefixBytes) + 1);
461
+ parsePrefixInto(result, head.subarray(0, Math.max(1, maxPrefixBytes)).toString('utf8'), head.length <= maxPrefixBytes);
462
+ return result;
463
+ }
457
464
  try {
458
465
  const descriptor = fs.openSync(sessionPath, 'r');
459
466
  try {
@@ -509,6 +516,8 @@ function scanPrefix(sessionPath, maxPrefixBytes) {
509
516
  }
510
517
  async function scanPrefixAsync(sessionPath, maxPrefixBytes) {
511
518
  const result = { firstTimestamp: null, workspacePath: null };
519
+ if ((0, compressedRollouts_1.isCompressedRolloutPath)(sessionPath))
520
+ return scanPrefix(sessionPath, maxPrefixBytes);
512
521
  let handle = null;
513
522
  try {
514
523
  handle = await fs.promises.open(sessionPath, 'r');
@@ -62,6 +62,11 @@ export interface CollectSessionPromptHistoryOptions {
62
62
  include?: SessionPromptHistoryInclude;
63
63
  bounds?: SessionPromptHistoryBounds;
64
64
  signal?: AbortSignal;
65
+ /**
66
+ * Codex: also read compressed rollouts (`….jsonl.zst`), as for
67
+ * `collectPromptHistory()`. Default false.
68
+ */
69
+ includeCompressedRollouts?: boolean;
65
70
  }
66
71
  export interface PromptHistorySessionPrompt extends Omit<PromptHistoryEntry, 'provider' | 'sessionId' | 'sessionKey'> {
67
72
  /** With `include.replies`: the agent's last text for this prompt's turn. */
@@ -14,42 +14,9 @@
14
14
  * `sessionIds` continues. Scope fails closed as in `collectPromptHistory()`,
15
15
  * and replies or signals that belong to an out-of-scope prompt are dropped.
16
16
  */
17
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
- if (k2 === undefined) k2 = k;
19
- var desc = Object.getOwnPropertyDescriptor(m, k);
20
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
- desc = { enumerable: true, get: function() { return m[k]; } };
22
- }
23
- Object.defineProperty(o, k2, desc);
24
- }) : (function(o, m, k, k2) {
25
- if (k2 === undefined) k2 = k;
26
- o[k2] = m[k];
27
- }));
28
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
- Object.defineProperty(o, "default", { enumerable: true, value: v });
30
- }) : function(o, v) {
31
- o["default"] = v;
32
- });
33
- var __importStar = (this && this.__importStar) || (function () {
34
- var ownKeys = function(o) {
35
- ownKeys = Object.getOwnPropertyNames || function (o) {
36
- var ar = [];
37
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
- return ar;
39
- };
40
- return ownKeys(o);
41
- };
42
- return function (mod) {
43
- if (mod && mod.__esModule) return mod;
44
- var result = {};
45
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
- __setModuleDefault(result, mod);
47
- return result;
48
- };
49
- })();
50
17
  Object.defineProperty(exports, "__esModule", { value: true });
51
18
  exports.collectSessionPromptHistory = collectSessionPromptHistory;
52
- const fs = __importStar(require("fs"));
19
+ const compressedRollouts_1 = require("./providers/compressedRollouts");
53
20
  const promptHistory_1 = require("./promptHistory");
54
21
  const sessionPromptSignals_1 = require("./sessionPromptSignals");
55
22
  const DEFAULT_SESSION_BOUNDS = {
@@ -224,7 +191,9 @@ function definedBounds(bounds) {
224
191
  async function selectCandidates(options, listingRoots) {
225
192
  const sinceMs = options.since ? options.since.getTime() : null;
226
193
  const providers = options.providers ?? ['claude-code', 'codex'];
227
- let candidates = await (0, promptHistory_1.listCandidates)(providers, listingRoots, sinceMs);
194
+ let candidates = await (0, promptHistory_1.listCandidates)(providers, listingRoots, sinceMs, {
195
+ includeCompressedRollouts: options.includeCompressedRollouts,
196
+ });
228
197
  if (options.sessionIds || options.sessionRefs) {
229
198
  const ids = new Set(options.sessionIds ?? []);
230
199
  const keys = new Set();
@@ -242,7 +211,7 @@ async function selectCandidates(options, listingRoots) {
242
211
  const selected = [];
243
212
  for (const candidate of candidates) {
244
213
  try {
245
- selected.push({ candidate, stat: await fs.promises.stat(candidate.filePath) });
214
+ selected.push({ candidate, stat: await (0, compressedRollouts_1.statRolloutContent)(candidate.filePath) });
246
215
  }
247
216
  catch {
248
217
  // Gone since it was listed.
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Subagent lifecycle records as `system` session events.
3
+ *
4
+ * Codex records its multi-agent lifecycle in the parent's rollout:
5
+ * `item_completed` → `SubAgentActivity` items link a `spawn_agent` call to the
6
+ * child thread it started (`started`), mark each finished child turn
7
+ * (`completed`, Codex 0.150+), and note `followup_task` / `send_message`
8
+ * calls (`interacted`) and `interrupt_agent` calls (`interrupted`); a child's
9
+ * report arrives as an `agent_message` whose text starts
10
+ * `Message Type: FINAL_ANSWER`. With
11
+ * `CodexRolloutParserOptions.includeSubagentActivity`, the parser turns each
12
+ * into one `system` event with `origin: { kind: 'subagent-activity' }` whose
13
+ * `message.content` is a single `{ type: 'subagent_activity', ... }` block.
14
+ *
15
+ * Those events are bookkeeping, not messages: transcripts, context
16
+ * attribution, and message counts skip them, as they do task notifications.
17
+ *
18
+ * Pure: no filesystem access. Browser-safe.
19
+ *
20
+ * @module subagentActivity
21
+ */
22
+ import type { SessionEvent } from './types/sessionEvent';
23
+ /** `origin.kind` of a subagent-activity `system` event. */
24
+ export declare const SUBAGENT_ACTIVITY_ORIGIN_KIND = "subagent-activity";
25
+ /** `type` of the content block that carries the activity. */
26
+ export declare const SUBAGENT_ACTIVITY_BLOCK_TYPE = "subagent_activity";
27
+ /**
28
+ * - `started`: a spawn call started the child thread (`callId` = the spawn
29
+ * call's id, `agentThreadId` = the child's rollout id).
30
+ * - `completed`: one child turn finished (`turnId` = that child turn).
31
+ * - `interacted`: the parent sent the child work or a message (`callId` =
32
+ * the `followup_task` or `send_message` call; `tool` says which, when the
33
+ * call was seen). After `followup_task` the child runs again.
34
+ * - `interrupted`: the parent interrupted the child (`interrupt_agent`).
35
+ * - `final-answer`: the child's final report reached the parent
36
+ * (`agentPath` = its author, `text` = the report).
37
+ */
38
+ export type SubagentActivityKind = 'started' | 'completed' | 'interacted' | 'interrupted' | 'final-answer';
39
+ export interface SubagentActivity {
40
+ kind: SubagentActivityKind;
41
+ /**
42
+ * The parent's tool call the record refers to: the spawn call for
43
+ * `started`, the `followup_task` / `send_message` call for `interacted`,
44
+ * the `interrupt_agent` call for `interrupted`.
45
+ */
46
+ callId?: string;
47
+ /**
48
+ * Raw name of the `callId` tool call (`spawn_agent`, `followup_task`,
49
+ * `send_message`, `interrupt_agent`) when the parser saw that call.
50
+ */
51
+ tool?: string;
52
+ /** `completed`: the child turn that finished. */
53
+ turnId?: string;
54
+ /** The child's thread id, which is its rollout's session id. */
55
+ agentThreadId?: string;
56
+ /** The child's agent path, e.g. `/root/review_builder` (`final-answer`: the author). */
57
+ agentPath?: string;
58
+ /** `final-answer`: the agent path the report went to, e.g. `/root`. */
59
+ recipient?: string;
60
+ /** `started`: the child's model and reasoning effort, when recorded. */
61
+ model?: string;
62
+ reasoningEffort?: string;
63
+ /** The thread and turn that recorded the activity (the parent's). */
64
+ parentThreadId?: string;
65
+ parentTurnId?: string;
66
+ /** `final-answer`: the report text (empty in metadata-only parsing). */
67
+ text?: string;
68
+ }
69
+ /** Whether an event is a subagent-activity `system` event (see the module docs). */
70
+ export declare function isSubagentActivitySystemEvent(event: SessionEvent): boolean;
71
+ /**
72
+ * The activity a subagent-activity `system` event carries, copied with only
73
+ * its known string fields; `null` for any other event or a malformed block.
74
+ */
75
+ export declare function subagentActivityFromEvent(event: SessionEvent): SubagentActivity | null;
76
+ /** A one-line, content-free description, e.g. `Subagent /root/review started`. */
77
+ export declare function describeSubagentActivity(activity: SubagentActivity): string;
78
+ /** Fields of a Codex inter-agent message text (`Message Type: … Payload:\n…`). */
79
+ export interface CodexAgentMessageText {
80
+ /** `MESSAGE`, `NEW_TASK`, `FINAL_ANSWER`, … */
81
+ messageType: string;
82
+ taskName?: string;
83
+ sender?: string;
84
+ /** Everything after the `Payload:` line. */
85
+ payload: string;
86
+ }
87
+ /**
88
+ * Parses a Codex inter-agent message text. Returns `null` unless it starts
89
+ * with a `Message Type:` line.
90
+ */
91
+ export declare function parseCodexAgentMessageText(text: unknown): CodexAgentMessageText | null;
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ /**
3
+ * Subagent lifecycle records as `system` session events.
4
+ *
5
+ * Codex records its multi-agent lifecycle in the parent's rollout:
6
+ * `item_completed` → `SubAgentActivity` items link a `spawn_agent` call to the
7
+ * child thread it started (`started`), mark each finished child turn
8
+ * (`completed`, Codex 0.150+), and note `followup_task` / `send_message`
9
+ * calls (`interacted`) and `interrupt_agent` calls (`interrupted`); a child's
10
+ * report arrives as an `agent_message` whose text starts
11
+ * `Message Type: FINAL_ANSWER`. With
12
+ * `CodexRolloutParserOptions.includeSubagentActivity`, the parser turns each
13
+ * into one `system` event with `origin: { kind: 'subagent-activity' }` whose
14
+ * `message.content` is a single `{ type: 'subagent_activity', ... }` block.
15
+ *
16
+ * Those events are bookkeeping, not messages: transcripts, context
17
+ * attribution, and message counts skip them, as they do task notifications.
18
+ *
19
+ * Pure: no filesystem access. Browser-safe.
20
+ *
21
+ * @module subagentActivity
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.SUBAGENT_ACTIVITY_BLOCK_TYPE = exports.SUBAGENT_ACTIVITY_ORIGIN_KIND = void 0;
25
+ exports.isSubagentActivitySystemEvent = isSubagentActivitySystemEvent;
26
+ exports.subagentActivityFromEvent = subagentActivityFromEvent;
27
+ exports.describeSubagentActivity = describeSubagentActivity;
28
+ exports.parseCodexAgentMessageText = parseCodexAgentMessageText;
29
+ /** `origin.kind` of a subagent-activity `system` event. */
30
+ exports.SUBAGENT_ACTIVITY_ORIGIN_KIND = 'subagent-activity';
31
+ /** `type` of the content block that carries the activity. */
32
+ exports.SUBAGENT_ACTIVITY_BLOCK_TYPE = 'subagent_activity';
33
+ const KINDS = new Set([
34
+ 'started',
35
+ 'completed',
36
+ 'interacted',
37
+ 'interrupted',
38
+ 'final-answer',
39
+ ]);
40
+ const STRING_FIELDS = [
41
+ 'callId',
42
+ 'tool',
43
+ 'turnId',
44
+ 'agentThreadId',
45
+ 'agentPath',
46
+ 'recipient',
47
+ 'model',
48
+ 'reasoningEffort',
49
+ 'parentThreadId',
50
+ 'parentTurnId',
51
+ 'text',
52
+ ];
53
+ /** Whether an event is a subagent-activity `system` event (see the module docs). */
54
+ function isSubagentActivitySystemEvent(event) {
55
+ return event.type === 'system' && event.origin?.kind === exports.SUBAGENT_ACTIVITY_ORIGIN_KIND;
56
+ }
57
+ /**
58
+ * The activity a subagent-activity `system` event carries, copied with only
59
+ * its known string fields; `null` for any other event or a malformed block.
60
+ */
61
+ function subagentActivityFromEvent(event) {
62
+ if (!isSubagentActivitySystemEvent(event))
63
+ return null;
64
+ const content = event.message?.content;
65
+ if (!Array.isArray(content))
66
+ return null;
67
+ for (const block of content) {
68
+ if (!block || typeof block !== 'object')
69
+ continue;
70
+ const raw = block;
71
+ if (raw.type !== exports.SUBAGENT_ACTIVITY_BLOCK_TYPE)
72
+ continue;
73
+ if (typeof raw.kind !== 'string' || !KINDS.has(raw.kind))
74
+ return null;
75
+ const activity = { kind: raw.kind };
76
+ for (const field of STRING_FIELDS) {
77
+ const value = raw[field];
78
+ if (typeof value === 'string' && value.length > 0)
79
+ activity[field] = value;
80
+ }
81
+ return activity;
82
+ }
83
+ return null;
84
+ }
85
+ /** A one-line, content-free description, e.g. `Subagent /root/review started`. */
86
+ function describeSubagentActivity(activity) {
87
+ const who = activity.agentPath ?? activity.agentThreadId ?? 'subagent';
88
+ const name = `Subagent ${who}`;
89
+ switch (activity.kind) {
90
+ case 'started':
91
+ return `${name} started`;
92
+ case 'completed':
93
+ return `${name} finished a turn`;
94
+ case 'interacted':
95
+ return activity.tool === 'send_message'
96
+ ? `Message sent to subagent ${who}`
97
+ : `${name} given a follow-up task`;
98
+ case 'interrupted':
99
+ return `${name} interrupted`;
100
+ case 'final-answer':
101
+ return `${name} reported its final answer`;
102
+ }
103
+ }
104
+ const MESSAGE_HEADER = /^Message Type:[ \t]*([A-Z_]+)[ \t]*(?:\r?\n|$)/;
105
+ /**
106
+ * Parses a Codex inter-agent message text. Returns `null` unless it starts
107
+ * with a `Message Type:` line.
108
+ */
109
+ function parseCodexAgentMessageText(text) {
110
+ if (typeof text !== 'string')
111
+ return null;
112
+ const header = MESSAGE_HEADER.exec(text);
113
+ if (!header)
114
+ return null;
115
+ const rest = text.slice(header[0].length);
116
+ const payloadAt = /(?:^|\n)Payload:[ \t]*(?:\r?\n|$)/.exec(rest);
117
+ const head = payloadAt ? rest.slice(0, payloadAt.index) : rest;
118
+ const payload = payloadAt ? rest.slice(payloadAt.index + payloadAt[0].length) : '';
119
+ const field = (name) => {
120
+ const match = new RegExp(`(?:^|\\n)${name}:[ \\t]*([^\\n]*)`).exec(head);
121
+ const value = match?.[1]?.trim();
122
+ return value ? value : undefined;
123
+ };
124
+ const taskName = field('Task name');
125
+ const sender = field('Sender');
126
+ return {
127
+ messageType: header[1],
128
+ ...(taskName ? { taskName } : {}),
129
+ ...(sender ? { sender } : {}),
130
+ payload,
131
+ };
132
+ }