sidekick-shared 0.29.1 → 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.
- package/CHANGELOG.md +26 -0
- package/README.md +171 -60
- package/dist/aggregation/EventAggregator.d.ts +79 -4
- package/dist/aggregation/EventAggregator.js +391 -37
- package/dist/aggregation/types.d.ts +27 -3
- package/dist/browser.d.ts +7 -3
- package/dist/browser.js +23 -3
- package/dist/context/sessionContext.js +5 -1
- package/dist/esm/aggregation/EventAggregator.js +392 -38
- package/dist/esm/browser.js +3 -1
- package/dist/esm/context/sessionContext.js +6 -2
- package/dist/esm/fileContinuity.js +149 -0
- package/dist/esm/index.js +5 -2
- package/dist/esm/node.js +2 -0
- package/dist/esm/parsers/codexParser.js +192 -3
- package/dist/esm/parsers/subagentEndState.js +61 -0
- package/dist/esm/parsers/subagentScanner.js +4 -0
- package/dist/esm/parsers/subagentTraceParser.js +6 -0
- package/dist/esm/promptHistory.js +22 -11
- package/dist/esm/providers/claudeCode.js +50 -27
- package/dist/esm/providers/codex.js +153 -163
- package/dist/esm/providers/codexCompressedReader.js +184 -0
- package/dist/esm/providers/codexDatabase.js +47 -2
- package/dist/esm/providers/codexRollouts.js +20 -2
- package/dist/esm/providers/codexSubagents.js +456 -0
- package/dist/esm/providers/compressedRollouts.js +330 -0
- package/dist/esm/providers/factory.js +4 -1
- package/dist/esm/providers/rolloutWalker.js +32 -4
- package/dist/esm/schemas/sessionEvent.js +32 -4
- package/dist/esm/sessionMonitor.js +7 -1
- package/dist/esm/sessionPreviews.js +9 -0
- package/dist/esm/sessionPromptHistory.js +5 -3
- package/dist/esm/subagentActivity.js +125 -0
- package/dist/esm/subagentDisplayState.js +81 -0
- package/dist/esm/subagentSpawn.js +206 -6
- package/dist/esm/testing/codexSubagentFixtures.js +336 -0
- package/dist/esm/toolCallOrigins.js +17 -10
- package/dist/esm/toolCategory.js +6 -2
- package/dist/esm/transcript.js +6 -2
- package/dist/esm/turns/assistantTurn.js +6 -3
- package/dist/esm/usage/usageEvents.js +4 -1
- package/dist/esm/watchers/eventBridge.js +31 -1
- package/dist/esm/watchers/jsonlTail.js +11 -42
- package/dist/esm/watchers/jsonlWatcher.js +19 -9
- package/dist/esm/watchers/providerReaderWatcher.js +5 -4
- package/dist/fileContinuity.d.ts +95 -0
- package/dist/fileContinuity.js +187 -0
- package/dist/index.d.ts +14 -7
- package/dist/index.js +39 -10
- package/dist/node.d.ts +4 -0
- package/dist/node.js +16 -2
- package/dist/parsers/codexParser.d.ts +44 -0
- package/dist/parsers/codexParser.js +192 -3
- package/dist/parsers/subagentEndState.d.ts +20 -0
- package/dist/parsers/subagentEndState.js +65 -0
- package/dist/parsers/subagentScanner.js +4 -0
- package/dist/parsers/subagentTraceParser.d.ts +8 -0
- package/dist/parsers/subagentTraceParser.js +6 -0
- package/dist/promptHistory.d.ts +13 -3
- package/dist/promptHistory.js +22 -11
- package/dist/providers/claudeCode.js +50 -27
- package/dist/providers/codex.d.ts +35 -5
- package/dist/providers/codex.js +150 -160
- package/dist/providers/codexCompressedReader.d.ts +58 -0
- package/dist/providers/codexCompressedReader.js +221 -0
- package/dist/providers/codexDatabase.d.ts +25 -0
- package/dist/providers/codexDatabase.js +48 -2
- package/dist/providers/codexRollouts.d.ts +16 -2
- package/dist/providers/codexRollouts.js +20 -2
- package/dist/providers/codexSubagents.d.ts +66 -0
- package/dist/providers/codexSubagents.js +495 -0
- package/dist/providers/compressedRollouts.d.ts +114 -0
- package/dist/providers/compressedRollouts.js +380 -0
- package/dist/providers/factory.d.ts +5 -0
- package/dist/providers/factory.js +4 -1
- package/dist/providers/rolloutWalker.d.ts +15 -2
- package/dist/providers/rolloutWalker.js +33 -4
- package/dist/providers/types.d.ts +22 -1
- package/dist/schemas/sessionEvent.d.ts +26 -2
- package/dist/schemas/sessionEvent.js +31 -3
- package/dist/sessionMonitor.d.ts +6 -0
- package/dist/sessionMonitor.js +7 -1
- package/dist/sessionPreviews.js +9 -0
- package/dist/sessionPromptHistory.d.ts +5 -0
- package/dist/sessionPromptHistory.js +5 -36
- package/dist/subagentActivity.d.ts +91 -0
- package/dist/subagentActivity.js +132 -0
- package/dist/subagentDisplayState.d.ts +81 -0
- package/dist/subagentDisplayState.js +86 -0
- package/dist/subagentSpawn.d.ts +100 -5
- package/dist/subagentSpawn.js +218 -7
- package/dist/testing/codexSubagentFixtures.d.ts +48 -0
- package/dist/testing/codexSubagentFixtures.js +344 -0
- package/dist/toolCallOrigins.d.ts +5 -0
- package/dist/toolCallOrigins.js +17 -10
- package/dist/toolCategory.js +6 -2
- package/dist/transcript.js +5 -1
- package/dist/turns/assistantTurn.d.ts +4 -1
- package/dist/turns/assistantTurn.js +5 -2
- package/dist/types/codex.d.ts +71 -2
- package/dist/types/sessionEvent.d.ts +38 -3
- package/dist/usage/usageEvents.d.ts +4 -1
- package/dist/usage/usageEvents.js +4 -1
- package/dist/watchers/eventBridge.js +30 -0
- package/dist/watchers/jsonlTail.js +11 -42
- package/dist/watchers/jsonlWatcher.d.ts +5 -1
- package/dist/watchers/jsonlWatcher.js +18 -8
- package/dist/watchers/providerReaderWatcher.js +5 -4
- 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;
|
|
@@ -78,9 +80,11 @@ export declare const userSessionEventSchema: z.ZodObject<{
|
|
|
78
80
|
gitBranch: z.ZodOptional<z.ZodString>;
|
|
79
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";
|
|
87
|
+
dontAsk: "dontAsk";
|
|
84
88
|
}>>>;
|
|
85
89
|
rateLimits: z.ZodOptional<z.ZodObject<{
|
|
86
90
|
primary: z.ZodOptional<z.ZodObject<{
|
|
@@ -167,9 +171,11 @@ export declare const assistantSessionEventSchema: z.ZodObject<{
|
|
|
167
171
|
gitBranch: z.ZodOptional<z.ZodString>;
|
|
168
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";
|
|
178
|
+
dontAsk: "dontAsk";
|
|
173
179
|
}>>>;
|
|
174
180
|
rateLimits: z.ZodOptional<z.ZodObject<{
|
|
175
181
|
primary: z.ZodOptional<z.ZodObject<{
|
|
@@ -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>;
|
|
@@ -257,9 +264,11 @@ export declare const systemSessionEventSchema: z.ZodObject<{
|
|
|
257
264
|
gitBranch: z.ZodOptional<z.ZodString>;
|
|
258
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";
|
|
271
|
+
dontAsk: "dontAsk";
|
|
263
272
|
}>>>;
|
|
264
273
|
rateLimits: z.ZodOptional<z.ZodObject<{
|
|
265
274
|
primary: z.ZodOptional<z.ZodObject<{
|
|
@@ -350,9 +359,11 @@ export declare const toolUseSessionEventSchema: z.ZodObject<{
|
|
|
350
359
|
gitBranch: z.ZodOptional<z.ZodString>;
|
|
351
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";
|
|
366
|
+
dontAsk: "dontAsk";
|
|
356
367
|
}>>>;
|
|
357
368
|
rateLimits: z.ZodOptional<z.ZodObject<{
|
|
358
369
|
primary: z.ZodOptional<z.ZodObject<{
|
|
@@ -444,9 +455,11 @@ export declare const toolResultSessionEventSchema: z.ZodObject<{
|
|
|
444
455
|
gitBranch: z.ZodOptional<z.ZodString>;
|
|
445
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";
|
|
462
|
+
dontAsk: "dontAsk";
|
|
450
463
|
}>>>;
|
|
451
464
|
rateLimits: z.ZodOptional<z.ZodObject<{
|
|
452
465
|
primary: z.ZodOptional<z.ZodObject<{
|
|
@@ -528,8 +541,19 @@ export interface ExtractSessionEventsOptions {
|
|
|
528
541
|
* commandMode: 'task-notification', prompt } }`) into one `system` event
|
|
529
542
|
* with `origin: { kind: 'task-notification' }`, `message: { role: 'user',
|
|
530
543
|
* sourceLabel: 'task notification', content: <prompt> }`, and the line's
|
|
531
|
-
* timestamp. They report background agents finishing
|
|
532
|
-
*
|
|
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`.
|
|
533
557
|
*/
|
|
534
558
|
includeTaskNotifications?: boolean;
|
|
535
559
|
}
|
|
@@ -45,6 +45,8 @@ exports.permissionModeSchema = zod_1.z.enum([
|
|
|
45
45
|
'acceptEdits',
|
|
46
46
|
'bypassPermissions',
|
|
47
47
|
'plan',
|
|
48
|
+
'auto',
|
|
49
|
+
'dontAsk',
|
|
48
50
|
]);
|
|
49
51
|
// ── SessionEvent ──
|
|
50
52
|
const eventBaseShape = {
|
|
@@ -57,8 +59,8 @@ const eventBaseShape = {
|
|
|
57
59
|
promptSource: zod_1.z.string().optional(),
|
|
58
60
|
cwd: zod_1.z.string().optional(),
|
|
59
61
|
gitBranch: zod_1.z.string().optional(),
|
|
60
|
-
// A mode this release doesn't know
|
|
61
|
-
//
|
|
62
|
+
// A mode this release doesn't know is dropped rather than rejecting the
|
|
63
|
+
// whole line with its prompt or tool results.
|
|
62
64
|
permissionMode: exports.permissionModeSchema.optional().catch(undefined),
|
|
63
65
|
rateLimits: zod_1.z
|
|
64
66
|
.object({
|
|
@@ -148,6 +150,9 @@ exports.systemSessionEventSchema = zod_1.z.object({
|
|
|
148
150
|
type: zod_1.z.literal('system'),
|
|
149
151
|
message: exports.sessionMessageSchema.optional(),
|
|
150
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),
|
|
151
156
|
});
|
|
152
157
|
exports.toolUseSessionEventSchema = zod_1.z.object({
|
|
153
158
|
type: zod_1.z.literal('tool_use'),
|
|
@@ -187,7 +192,7 @@ function extractSessionEventsWithProvenance(raw, depth, inherited, options) {
|
|
|
187
192
|
if (direct.success)
|
|
188
193
|
return [{ ...inherited, ...direct.data }];
|
|
189
194
|
if (options.includeTaskNotifications) {
|
|
190
|
-
const notification = taskNotificationAttachmentEvent(raw);
|
|
195
|
+
const notification = taskNotificationAttachmentEvent(raw) ?? taskStatusAttachmentEvent(raw);
|
|
191
196
|
if (notification)
|
|
192
197
|
return [{ ...inherited, ...notification }];
|
|
193
198
|
}
|
|
@@ -224,6 +229,29 @@ function taskNotificationAttachmentEvent(raw) {
|
|
|
224
229
|
const parsed = exports.systemSessionEventSchema.safeParse(candidate);
|
|
225
230
|
return parsed.success ? parsed.data : null;
|
|
226
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
|
+
}
|
|
227
255
|
function progressProvenance(raw) {
|
|
228
256
|
const value = raw;
|
|
229
257
|
const provenance = {};
|
package/dist/sessionMonitor.d.ts
CHANGED
|
@@ -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;
|
package/dist/sessionMonitor.js
CHANGED
|
@@ -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
|
}
|
package/dist/sessionPreviews.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How to show a subagent: its lifecycle's outcome once something settled
|
|
3
|
+
* it, otherwise `running`, unless its transcript or its parent says it has
|
|
4
|
+
* stopped in all but name.
|
|
5
|
+
*
|
|
6
|
+
* Some background agents never get a final notification (they stopped after
|
|
7
|
+
* an interim "may resume" notice, the user stopped them from the UI, or a
|
|
8
|
+
* restart killed them). Their lifecycles stay `running`. This rule reads
|
|
9
|
+
* them as:
|
|
10
|
+
*
|
|
11
|
+
* - `finished-unreported`: the transcript ended cleanly (last assistant turn
|
|
12
|
+
* `end_turn` / `stop_sequence`, no tool call unanswered) and has been quiet
|
|
13
|
+
* for {@link SUBAGENT_UNREPORTED_QUIET_MS}.
|
|
14
|
+
* - `ended`: neither the parent session nor the transcript has been active for
|
|
15
|
+
* {@link SUBAGENT_PARENT_IDLE_ENDED_MS}.
|
|
16
|
+
*
|
|
17
|
+
* Neither is stored: the state is recomputed from the latest data on every
|
|
18
|
+
* call, so an agent that resumes (its transcript grows, or a later
|
|
19
|
+
* notification reopens its lifecycle) reads as `running` again. Silence alone
|
|
20
|
+
* is never enough for `finished-unreported`: live agents can be quiet for
|
|
21
|
+
* hours.
|
|
22
|
+
*
|
|
23
|
+
* Pure: no filesystem access. Browser-safe.
|
|
24
|
+
*
|
|
25
|
+
* @module subagentDisplayState
|
|
26
|
+
*/
|
|
27
|
+
import type { SubagentLifecycle } from './aggregation/types';
|
|
28
|
+
/** Quiet time after a clean end before a running agent reads as finished without a report (2 min). */
|
|
29
|
+
export declare const SUBAGENT_UNREPORTED_QUIET_MS: number;
|
|
30
|
+
/** Parent and transcript idle time after which a running agent reads as ended (6 h). */
|
|
31
|
+
export declare const SUBAGENT_PARENT_IDLE_ENDED_MS: number;
|
|
32
|
+
/** How a subagent is shown. The last four are lifecycle outcomes. */
|
|
33
|
+
export type SubagentDisplayStateName = 'running' | 'finished-unreported' | 'ended' | 'completed' | 'failed' | 'stopped' | 'killed';
|
|
34
|
+
/** Why a subagent reads as it does. */
|
|
35
|
+
export type SubagentDisplayReason =
|
|
36
|
+
/** Its lifecycle is settled; the state is the outcome. */
|
|
37
|
+
'settled'
|
|
38
|
+
/** Claude Code's meta flags (`finished`, `stoppedByUser`) on a running lifecycle. */
|
|
39
|
+
| 'meta'
|
|
40
|
+
/** The transcript ended cleanly and has been quiet. */
|
|
41
|
+
| 'clean-end'
|
|
42
|
+
/** The parent session (and the transcript) has been idle. */
|
|
43
|
+
| 'parent-idle';
|
|
44
|
+
export interface SubagentDisplayState {
|
|
45
|
+
state: SubagentDisplayStateName;
|
|
46
|
+
/** Absent for a plain `running`. */
|
|
47
|
+
reason?: SubagentDisplayReason;
|
|
48
|
+
}
|
|
49
|
+
/** The lifecycle fields the rule reads. */
|
|
50
|
+
export type SubagentDisplayLifecycle = Pick<SubagentLifecycle, 'status' | 'outcome'>;
|
|
51
|
+
/**
|
|
52
|
+
* Transcript facts the rule reads; a `SubagentTrace`, or a `SubagentStats`
|
|
53
|
+
* mapped with `lastActivityAt: stats.endTime`.
|
|
54
|
+
*/
|
|
55
|
+
export interface SubagentDisplayTrace {
|
|
56
|
+
/** The transcript ended cleanly (see `SubagentTrace.endedCleanly`). */
|
|
57
|
+
endedCleanly?: boolean;
|
|
58
|
+
/** Time of the transcript's last record. */
|
|
59
|
+
lastActivityAt?: Date | string | number;
|
|
60
|
+
/** Claude Code meta `finished`. */
|
|
61
|
+
finished?: boolean;
|
|
62
|
+
/** Claude Code meta `stoppedByUser`. */
|
|
63
|
+
stoppedByUser?: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface SubagentDisplayOptions {
|
|
66
|
+
/** The current time (epoch ms or a Date). */
|
|
67
|
+
now: number | Date;
|
|
68
|
+
/** Time of the parent session's last event, when known. */
|
|
69
|
+
parentLastActivity?: Date | string | number | null;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolves how to show a subagent (see the module docs). Settled lifecycles
|
|
73
|
+
* map to their outcome (`completed` when none is recorded). A running one is
|
|
74
|
+
* `stopped` / `completed` when its meta flags say so, `finished-unreported`
|
|
75
|
+
* after a clean end and {@link SUBAGENT_UNREPORTED_QUIET_MS} of quiet,
|
|
76
|
+
* `ended` when the parent and transcript have both been idle for longer than
|
|
77
|
+
* {@link SUBAGENT_PARENT_IDLE_ENDED_MS}, and `running` otherwise.
|
|
78
|
+
*/
|
|
79
|
+
export declare function resolveSubagentDisplayState(lifecycle: SubagentDisplayLifecycle, trace: SubagentDisplayTrace | null | undefined, options: SubagentDisplayOptions): SubagentDisplayState;
|
|
80
|
+
/** A short label: `running`, `finished (no report)`, `ended`, `completed`, `failed`, `stopped`, `killed`. */
|
|
81
|
+
export declare function subagentDisplayLabel(state: SubagentDisplayStateName): string;
|