oh-my-codex 0.21.13 → 0.21.14

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 (32) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +17 -0
  4. package/dist/cli/__tests__/session-timeline.test.d.ts +2 -0
  5. package/dist/cli/__tests__/session-timeline.test.d.ts.map +1 -0
  6. package/dist/cli/__tests__/session-timeline.test.js +155 -0
  7. package/dist/cli/__tests__/session-timeline.test.js.map +1 -0
  8. package/dist/cli/session-search.d.ts.map +1 -1
  9. package/dist/cli/session-search.js +7 -0
  10. package/dist/cli/session-search.js.map +1 -1
  11. package/dist/cli/session-timeline.d.ts +9 -0
  12. package/dist/cli/session-timeline.d.ts.map +1 -0
  13. package/dist/cli/session-timeline.js +174 -0
  14. package/dist/cli/session-timeline.js.map +1 -0
  15. package/dist/session-history/__tests__/timeline.test.d.ts +2 -0
  16. package/dist/session-history/__tests__/timeline.test.d.ts.map +1 -0
  17. package/dist/session-history/__tests__/timeline.test.js +459 -0
  18. package/dist/session-history/__tests__/timeline.test.js.map +1 -0
  19. package/dist/session-history/export.d.ts +2 -3
  20. package/dist/session-history/export.d.ts.map +1 -1
  21. package/dist/session-history/export.js +5 -66
  22. package/dist/session-history/export.js.map +1 -1
  23. package/dist/session-history/timeline.d.ts +97 -0
  24. package/dist/session-history/timeline.d.ts.map +1 -0
  25. package/dist/session-history/timeline.js +325 -0
  26. package/dist/session-history/timeline.js.map +1 -0
  27. package/dist/session-history/transcript.d.ts +16 -0
  28. package/dist/session-history/transcript.d.ts.map +1 -0
  29. package/dist/session-history/transcript.js +111 -0
  30. package/dist/session-history/transcript.js.map +1 -0
  31. package/package.json +1 -1
  32. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
@@ -0,0 +1,459 @@
1
+ import { afterEach, beforeEach, describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { appendFile, mkdir, mkdtemp, readFile, rename, rm, unlink, writeFile } from 'node:fs/promises';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { buildSessionTimeline } from '../timeline.js';
7
+ import { readResolvedSessionTranscriptLines, revalidateTranscriptMatches, resolveSessionTranscript } from '../transcript.js';
8
+ const START = '2026-10-14T10:00:00.000Z';
9
+ function time(seconds) { return new Date(Date.parse(START) + seconds * 1000).toISOString(); }
10
+ function record(type, payload, seconds = 0) { return { type, timestamp: time(seconds), payload }; }
11
+ function call(id, seconds, name = 'exec', namespace) {
12
+ return record('response_item', {
13
+ type: 'function_call', name, call_id: id, arguments: 'PRIVATE_ARGUMENTS',
14
+ ...(namespace === undefined ? {} : { namespace }),
15
+ }, seconds);
16
+ }
17
+ function output(id, seconds, result = { exit_code: 0 }) {
18
+ return record('response_item', { type: 'function_call_output', call_id: id, output: result }, seconds);
19
+ }
20
+ describe('buildSessionTimeline', () => {
21
+ let home;
22
+ beforeEach(async () => { home = await mkdtemp(join(tmpdir(), 'omx-timeline-')); });
23
+ afterEach(async () => { await rm(home, { recursive: true, force: true }); });
24
+ async function fixture(records, id = 'timeline-id', archived = false, directory = home) {
25
+ const root = join(directory, archived ? 'archived_sessions' : 'sessions/2026/10/14');
26
+ await mkdir(root, { recursive: true });
27
+ const path = join(root, `rollout-${id}.jsonl`);
28
+ await writeFile(path, [
29
+ record('session_meta', { id, timestamp: START, cwd: '/PRIVATE_PROJECT', instructions: 'PRIVATE_INSTRUCTIONS' }),
30
+ ...records,
31
+ ].map((row) => JSON.stringify(row)).join('\n') + '\n');
32
+ return path;
33
+ }
34
+ it('pairs interleaved calls by ID and summarizes the complete session in source order', async () => {
35
+ const path = await fixture([
36
+ record('event_msg', { type: 'task_started', turn_id: 'turn-1' }),
37
+ call('slow', 1), call('fast', 2, 'search'),
38
+ output('fast', 3), output('slow', 5, { exit_code: 2 }),
39
+ record('event_msg', { type: 'context_compacted' }, 6),
40
+ record('event_msg', { type: 'task_complete', turn_id: 'turn-1' }, 7),
41
+ record('event_msg', { type: 'task_started', turn_id: 'turn-2' }, 8),
42
+ call('pending', 9),
43
+ record('event_msg', { type: 'turn_aborted', turn_id: 'turn-2' }, 10),
44
+ ]);
45
+ const before = await readFile(path, 'utf-8');
46
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
47
+ assert.deepEqual(report.events.map((event) => event.kind), [
48
+ 'turn_start', 'tool', 'tool', 'compaction', 'turn_complete', 'turn_start', 'tool', 'turn_aborted',
49
+ ]);
50
+ assert.deepEqual(report.events[1], {
51
+ kind: 'tool', name: 'exec', namespace: null, call_id: 'slow', status: 'failed', line_number: 3,
52
+ timestamp: time(1), result_line_number: 6, completed_at: time(5), duration_ms: 4000, exit_code: 2,
53
+ });
54
+ assert.equal(report.duration_ms, 10_000);
55
+ assert.equal(report.last_activity_at, time(10));
56
+ assert.deepEqual(report.summary, {
57
+ events: 8, tool_calls: 3, completed: 1, failed: 1, incomplete: 1, orphan_outputs: 0,
58
+ turns_started: 2, turns_completed: 1, turns_aborted: 1, compactions: 1,
59
+ tools: [
60
+ { name: 'exec', namespace: null, calls: 2, completed: 0, failed: 1, incomplete: 1, measured_calls: 1, total_duration_ms: 4000, max_duration_ms: 4000 },
61
+ { name: 'search', namespace: null, calls: 1, completed: 1, failed: 0, incomplete: 0, measured_calls: 1, total_duration_ms: 1000, max_duration_ms: 1000 },
62
+ ],
63
+ });
64
+ assert.equal(await readFile(path, 'utf-8'), before);
65
+ });
66
+ it('retains only metadata, including for custom tools and compaction records', async () => {
67
+ await fixture([
68
+ record('response_item', { type: 'message', role: 'user', content: 'PRIVATE_MESSAGE' }),
69
+ record('response_item', { type: 'reasoning', summary: 'PRIVATE_REASONING' }),
70
+ record('response_item', { type: 'custom_tool_call', name: 'apply_patch', call_id: 'patch', input: 'PRIVATE_PATCH' }, 1),
71
+ record('response_item', { type: 'custom_tool_call_output', call_id: 'patch', output: 'PRIVATE_OUTPUT' }, 2),
72
+ record('compacted', { message: 'PRIVATE_COMPACTION', replacement_history: ['PRIVATE_HISTORY'] }, 3),
73
+ ]);
74
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
75
+ assert.doesNotMatch(JSON.stringify(report), /PRIVATE_|rollout-|codex_home|transcript_path/);
76
+ assert.equal(report.privacy.mode, 'metadata-only');
77
+ assert.equal(report.summary.completed, 1);
78
+ assert.equal(report.summary.compactions, 1);
79
+ assert.equal(report.events[0].duration_ms, 1000);
80
+ });
81
+ it('coalesces paired top-level and event-message compaction records', async () => {
82
+ await fixture([
83
+ record('compacted', { message: 'PRIVATE_COMPACTION' }, 1),
84
+ record('event_msg', { type: 'token_count', input_tokens: 1200, cached_input_tokens: 400 }, 2),
85
+ record('event_msg', { type: 'context_compacted', tokens_before: 1200, tokens_after: 300 }, 3),
86
+ ]);
87
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
88
+ assert.equal(report.summary.compactions, 1);
89
+ assert.deepEqual(report.events, [{ kind: 'compaction', line_number: 2, timestamp: time(1) }]);
90
+ assert.doesNotMatch(JSON.stringify(report), /PRIVATE_COMPACTION/);
91
+ });
92
+ it('does not coalesce unrelated compactions across turn boundaries', async () => {
93
+ await fixture([
94
+ record('compacted', {}, 1),
95
+ record('event_msg', { type: 'task_started', turn_id: 'turn-1' }, 2),
96
+ record('event_msg', { type: 'task_complete', turn_id: 'turn-1' }, 3),
97
+ record('event_msg', { type: 'context_compacted' }, 4),
98
+ ]);
99
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
100
+ assert.equal(report.summary.compactions, 2);
101
+ assert.deepEqual(report.events.filter((event) => event.kind === 'compaction').map((event) => event.timestamp), [time(1), time(4)]);
102
+ });
103
+ it('recognizes explicit failures without classifying arbitrary output text as errors', async () => {
104
+ const results = [
105
+ [{ exit_code: 1 }, 'failed', 1],
106
+ ['{"metadata":{"exit_code":-1},"output":"private"}', 'failed', -1],
107
+ [{ isError: true, exit_code: 0 }, 'failed', 0],
108
+ [{ is_error: true }, 'failed', null],
109
+ ['Chunk ID: abc\nWall time: 1 seconds\nProcess exited with code 7\nFinal output:\nprivate', 'failed', 7],
110
+ ['Process exited with code 1\nstderr:\nError: test suite failed', 'failed', 1],
111
+ ['Wall time: 0.1 seconds\r\nExit code: 3\r\nOutput:\r\nprivate', 'failed', 3],
112
+ ['Chunk ID: abc\nWall time: 1 seconds\nProcess exited with code 0\nFinal output:\nProcess exited with code 8', 'completed', 0],
113
+ ['Error: this is quoted program output, not a status', 'completed', null],
114
+ ['Wall time: this is ordinary text\nProcess exited with code 9', 'completed', null],
115
+ [{ output: { exit_code: 9 }, isError: false }, 'completed', null],
116
+ [{ exit_code: '1' }, 'completed', null],
117
+ [{ exit_code: 1.5 }, 'completed', null],
118
+ [null, 'completed', null],
119
+ ];
120
+ await fixture(results.flatMap(([result], index) => [call(`call-${index}`, index), output(`call-${index}`, index + 1, result)]));
121
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
122
+ assert.deepEqual(report.events.map((event) => {
123
+ assert.equal(event.kind, 'tool');
124
+ const tool = event;
125
+ return [tool.status, tool.exit_code];
126
+ }), results.map(([, status, code]) => [status, code]));
127
+ });
128
+ it('uses MCP lifecycle errors for paired and output-less calls', async () => {
129
+ await fixture([
130
+ call('mcp-failed', 1, 'read', 'mcp__filesystem'),
131
+ call('mcp-completed', 2, 'read', 'mcp__filesystem'),
132
+ call('mcp-transport-error', 3, 'read', 'mcp__filesystem'),
133
+ call('mcp-output-less', 4, 'read', 'mcp__filesystem'),
134
+ record('event_msg', {
135
+ type: 'mcp_tool_call_end', call_id: 'mcp-failed', result: { Ok: { isError: true } },
136
+ }, 3),
137
+ record('event_msg', {
138
+ type: 'mcp_tool_call_end', call_id: 'mcp-completed', result: { Ok: { isError: false } },
139
+ }, 4),
140
+ record('event_msg', {
141
+ type: 'mcp_tool_call_end', call_id: 'mcp-transport-error', result: { Err: 'PRIVATE_MCP_TRANSPORT_ERROR' },
142
+ }, 5),
143
+ record('event_msg', {
144
+ type: 'mcp_tool_call_end', call_id: 'mcp-output-less', result: { Ok: { isError: true } },
145
+ }, 6),
146
+ output('mcp-failed', 5, 'Wall time: 0.1 seconds\nOutput:\nPermission denied'),
147
+ output('mcp-completed', 6, 'Wall time: 0.1 seconds\nOutput:\nRead complete'),
148
+ output('mcp-transport-error', 7, 'Wall time: 0.1 seconds\nOutput:\nConnection failed'),
149
+ ]);
150
+ const options = { session: 'timeline-id', codexHomeDir: home };
151
+ const report = await buildSessionTimeline(options);
152
+ assert.deepEqual(report.events.map((event) => event.kind === 'tool' ? [event.call_id, event.status, event.exit_code] : null), [
153
+ ['mcp-failed', 'failed', null], ['mcp-completed', 'completed', null], ['mcp-transport-error', 'failed', null],
154
+ ['mcp-output-less', 'failed', null],
155
+ ]);
156
+ assert.equal(report.summary.failed, 3);
157
+ assert.equal(report.summary.completed, 1);
158
+ assert.equal(report.summary.incomplete, 0);
159
+ const outputLess = report.events.find((event) => event.kind === 'tool' && event.call_id === 'mcp-output-less');
160
+ assert.equal(outputLess?.kind === 'tool' ? outputLess.result_line_number : null, 9);
161
+ assert.equal(outputLess?.kind === 'tool' ? outputLess.completed_at : null, time(6));
162
+ assert.equal(outputLess?.kind === 'tool' ? outputLess.duration_ms : null, 2000);
163
+ assert.doesNotMatch(JSON.stringify(report), /PRIVATE_MCP_TRANSPORT_ERROR/);
164
+ const failures = await buildSessionTimeline({ ...options, status: 'failed' });
165
+ assert.deepEqual(failures.events.map((event) => event.kind === 'tool' ? event.call_id : null), [
166
+ 'mcp-failed', 'mcp-transport-error', 'mcp-output-less',
167
+ ]);
168
+ });
169
+ it('finalizes successful MCP lifecycle results without output and refines later output', async () => {
170
+ await fixture([
171
+ call('mcp-output-less', 1, 'read', 'mcp__filesystem'),
172
+ call('mcp-late-output', 2, 'read', 'mcp__filesystem'),
173
+ record('event_msg', {
174
+ type: 'mcp_tool_call_end', call_id: 'mcp-output-less', result: { Ok: { isError: false } },
175
+ }, 3),
176
+ record('event_msg', {
177
+ type: 'mcp_tool_call_end', call_id: 'mcp-late-output', result: { Ok: { isError: false } },
178
+ }, 4),
179
+ output('mcp-late-output', 5, { exit_code: 2 }),
180
+ ]);
181
+ const options = { session: 'timeline-id', codexHomeDir: home };
182
+ const report = await buildSessionTimeline(options);
183
+ assert.deepEqual(report.events.map((event) => event.kind === 'tool' ? [
184
+ event.call_id, event.status, event.result_line_number, event.duration_ms, event.exit_code,
185
+ ] : null), [
186
+ ['mcp-output-less', 'completed', 4, 2000, null],
187
+ ['mcp-late-output', 'failed', 6, 3000, 2],
188
+ ]);
189
+ assert.equal(report.summary.completed, 1);
190
+ assert.equal(report.summary.failed, 1);
191
+ assert.deepEqual((await buildSessionTimeline({ ...options, status: 'completed' })).events.map((event) => event.kind), ['tool']);
192
+ assert.deepEqual((await buildSessionTimeline({ ...options, status: 'failed' })).events.map((event) => event.kind), ['tool']);
193
+ });
194
+ it('allows call ID reuse after successful and failed MCP lifecycle results without output', async () => {
195
+ await fixture([
196
+ call('reused-after-lifecycle', 1, 'read', 'mcp__filesystem'),
197
+ call('reused-after-failure', 1, 'read', 'mcp__filesystem'),
198
+ record('event_msg', {
199
+ type: 'mcp_tool_call_end', call_id: 'reused-after-lifecycle', result: { Ok: { isError: false } },
200
+ }, 2),
201
+ record('event_msg', {
202
+ type: 'mcp_tool_call_end', call_id: 'reused-after-failure', result: { Err: 'PRIVATE_ERROR' },
203
+ }, 2),
204
+ call('reused-after-lifecycle', 3, 'read', 'mcp__filesystem'),
205
+ call('reused-after-failure', 3, 'read', 'mcp__filesystem'),
206
+ output('reused-after-lifecycle', 5, { exit_code: 2 }),
207
+ output('reused-after-failure', 5, { exit_code: 0 }),
208
+ ]);
209
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
210
+ assert.deepEqual(report.events.map((event) => event.kind === 'tool' ? [
211
+ event.call_id, event.status, event.result_line_number, event.duration_ms, event.exit_code,
212
+ ] : null), [
213
+ ['reused-after-lifecycle', 'completed', 4, 1000, null],
214
+ ['reused-after-failure', 'failed', 5, 1000, null],
215
+ ['reused-after-lifecycle', 'failed', 8, 2000, 2],
216
+ ['reused-after-failure', 'completed', 9, 2000, 0],
217
+ ]);
218
+ assert.equal(report.diagnostics.ambiguous_call_ids, 0);
219
+ assert.doesNotMatch(JSON.stringify(report), /PRIVATE_ERROR/);
220
+ });
221
+ it('retains unmatched MCP lifecycle results and coalesces a later orphan output', async () => {
222
+ await fixture([
223
+ record('event_msg', {
224
+ type: 'mcp_tool_call_end', call_id: 'orphan-with-output', result: { Err: 'PRIVATE_TRANSPORT_ERROR' },
225
+ }, 1),
226
+ { type: 'response_item', payload: { type: 'function_call_output', call_id: 'orphan-with-output', output: 'Connection failed' } },
227
+ record('event_msg', {
228
+ type: 'mcp_tool_call_end', call_id: 'orphan-without-output', result: { Ok: { isError: true } },
229
+ }, 3),
230
+ record('event_msg', { type: 'mcp_tool_call_end', result: { Ok: { isError: false } } }, 4),
231
+ ]);
232
+ const options = { session: 'timeline-id', codexHomeDir: home };
233
+ const report = await buildSessionTimeline(options);
234
+ assert.deepEqual(report.events.map((event) => event.kind === 'orphan_output' ? [
235
+ event.line_number, event.timestamp, event.call_id, event.status,
236
+ ] : null), [
237
+ [3, time(1), 'orphan-with-output', 'failed'],
238
+ [4, time(3), 'orphan-without-output', 'failed'],
239
+ [5, time(4), null, 'completed'],
240
+ ]);
241
+ assert.equal(report.summary.orphan_outputs, 3);
242
+ assert.equal(report.summary.tool_calls, 0);
243
+ assert.equal((await buildSessionTimeline({ ...options, status: 'failed' })).events.length, 2);
244
+ assert.equal((await buildSessionTimeline({ ...options, status: 'completed' })).events.length, 1);
245
+ assert.doesNotMatch(JSON.stringify(report), /PRIVATE_TRANSPORT_ERROR/);
246
+ });
247
+ it('preserves lifecycle timing when later output timestamps are missing or invalid', async () => {
248
+ await fixture([
249
+ call('missing-output-time', 1, 'read', 'mcp__filesystem'),
250
+ record('event_msg', {
251
+ type: 'mcp_tool_call_end', call_id: 'missing-output-time', result: { Ok: { isError: false } },
252
+ }, 2),
253
+ { type: 'response_item', payload: { type: 'function_call_output', call_id: 'missing-output-time', output: 'done' } },
254
+ call('invalid-output-time', 4, 'read', 'mcp__filesystem'),
255
+ record('event_msg', {
256
+ type: 'mcp_tool_call_end', call_id: 'invalid-output-time', result: { Ok: { isError: false } },
257
+ }, 5),
258
+ { ...output('invalid-output-time', 6), timestamp: 'PRIVATE_INVALID_TIMESTAMP' },
259
+ call('valid-output-time', 7, 'read', 'mcp__filesystem'),
260
+ record('event_msg', {
261
+ type: 'mcp_tool_call_end', call_id: 'valid-output-time', result: { Ok: { isError: false } },
262
+ }, 8),
263
+ output('valid-output-time', 10),
264
+ ]);
265
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
266
+ assert.deepEqual(report.events.map((event) => event.kind === 'tool' ? [
267
+ event.call_id, event.result_line_number, event.completed_at, event.duration_ms,
268
+ ] : null), [
269
+ ['missing-output-time', 4, time(2), 1000],
270
+ ['invalid-output-time', 7, time(5), 1000],
271
+ ['valid-output-time', 10, time(10), 3000],
272
+ ]);
273
+ assert.equal(report.summary.tools[0].measured_calls, 3);
274
+ assert.equal(report.summary.tools[0].total_duration_ms, 5000);
275
+ assert.equal((await buildSessionTimeline({
276
+ session: 'timeline-id', codexHomeDir: home, minDurationMs: 1000,
277
+ })).events.length, 3);
278
+ assert.equal(report.diagnostics.invalid_timestamps, 1);
279
+ assert.doesNotMatch(JSON.stringify(report), /PRIVATE_INVALID_TIMESTAMP/);
280
+ });
281
+ it('revalidates stale active transcript matches after an archive move', async () => {
282
+ const activePath = await fixture([], 'archive-race');
283
+ const archivedPath = join(home, 'archived_sessions', 'rollout-archive-race.jsonl');
284
+ await mkdir(join(home, 'archived_sessions'), { recursive: true });
285
+ const discovered = {
286
+ path: activePath, id: 'archive-race', startedAt: START, cwd: '/PRIVATE_PROJECT', archived: false,
287
+ };
288
+ await rename(activePath, archivedPath);
289
+ const matches = await revalidateTranscriptMatches([
290
+ discovered,
291
+ { ...discovered, path: archivedPath, archived: true },
292
+ ]);
293
+ assert.deepEqual(matches, [{ ...discovered, path: archivedPath, archived: true }]);
294
+ });
295
+ it('does not guess pairings for missing or duplicate outstanding call IDs', async () => {
296
+ await fixture([
297
+ output('orphan', 0, { isError: true }),
298
+ call(null, 1), output(null, 2),
299
+ call('duplicate', 3),
300
+ record('event_msg', { type: 'mcp_tool_call_end', call_id: 'duplicate', result: { Ok: { isError: true } } }, 4),
301
+ call('duplicate', 5), call('duplicate', 6),
302
+ record('event_msg', { type: 'mcp_tool_call_end', call_id: 'duplicate', result: { Ok: { isError: true } } }, 7),
303
+ output('duplicate', 8), output('duplicate', 9),
304
+ ]);
305
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
306
+ assert.equal(report.summary.incomplete, 3);
307
+ assert.equal(report.summary.orphan_outputs, 5);
308
+ assert.equal(report.summary.failed, 1); // The first call failed while its ID was still unique.
309
+ assert.equal(report.diagnostics.ambiguous_call_ids, 1);
310
+ assert.equal(report.summary.tools[0].total_duration_ms, 1000);
311
+ const failures = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home, status: 'failed' });
312
+ assert.equal(failures.events.length, 3);
313
+ assert.equal(failures.events[0].kind, 'orphan_output');
314
+ assert.equal(failures.events[1].kind, 'tool');
315
+ if (failures.events[1].kind === 'tool')
316
+ assert.equal(failures.events[1].call_id, 'duplicate');
317
+ assert.equal(failures.events[2].kind, 'orphan_output');
318
+ if (failures.events[2].kind === 'orphan_output')
319
+ assert.equal(failures.events[2].call_id, 'duplicate');
320
+ });
321
+ it('allows sequential ID reuse after a result without joining separate calls', async () => {
322
+ await fixture([call('reuse', 1), output('reuse', 2), call('reuse', 3), output('reuse', 5)]);
323
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
324
+ assert.deepEqual(report.events.map((event) => event.duration_ms), [1000, 2000]);
325
+ assert.equal(report.diagnostics.ambiguous_call_ids, 0);
326
+ });
327
+ it('keeps namespace as part of tool summary and filter identity', async () => {
328
+ await fixture([
329
+ call('server-a', 1, 'read', 'mcp__server-a'), call('server-b', 2, 'read', 'mcp__server-b'),
330
+ output('server-a', 3), output('server-b', 4),
331
+ ]);
332
+ const options = { session: 'timeline-id', codexHomeDir: home };
333
+ const report = await buildSessionTimeline(options);
334
+ assert.deepEqual(report.summary.tools.map(({ namespace, name, calls }) => ({ namespace, name, calls })), [
335
+ { namespace: 'mcp__server-a', name: 'read', calls: 1 },
336
+ { namespace: 'mcp__server-b', name: 'read', calls: 1 },
337
+ ]);
338
+ assert.equal((await buildSessionTimeline({ ...options, tool: 'read' })).events.length, 2);
339
+ const filtered = await buildSessionTimeline({ ...options, tool: 'read', namespace: 'mcp__server-b' });
340
+ assert.equal(filtered.selection.namespace, 'mcp__server-b');
341
+ assert.equal(filtered.events.length, 1);
342
+ assert.equal(filtered.events[0].kind, 'tool');
343
+ if (filtered.events[0].kind === 'tool')
344
+ assert.equal(filtered.events[0].namespace, 'mcp__server-b');
345
+ });
346
+ it('re-resolves a transcript moved to the archive before the timeline opens it', async () => {
347
+ const activePath = await fixture([call('archived-call', 1)], 'archive-race');
348
+ const options = { session: 'archive-race', codexHomeDir: home };
349
+ let transcript = await resolveSessionTranscript(options);
350
+ const archivedPath = join(home, 'archived_sessions', 'rollout-archive-race.jsonl');
351
+ await mkdir(join(home, 'archived_sessions'), { recursive: true });
352
+ await rename(activePath, archivedPath);
353
+ const lines = [];
354
+ for await (const line of readResolvedSessionTranscriptLines(options, transcript, (resolved) => {
355
+ transcript = resolved;
356
+ }))
357
+ lines.push(line);
358
+ assert.equal(transcript.archived, true);
359
+ assert.equal(transcript.path, archivedPath);
360
+ assert.equal(lines.length, 2);
361
+ const report = await buildSessionTimeline(options);
362
+ assert.equal(report.archived, true);
363
+ assert.equal(report.summary.tool_calls, 1);
364
+ });
365
+ it('does not replace a missing exact session with another prefix match during retry', async () => {
366
+ const selectedPath = await fixture([], 'abc');
367
+ await fixture([], 'abcd');
368
+ const options = { session: 'abc', codexHomeDir: home };
369
+ const transcript = await resolveSessionTranscript(options);
370
+ await unlink(selectedPath);
371
+ let resolvedAnotherTranscript = false;
372
+ const readLines = async () => {
373
+ for await (const _line of readResolvedSessionTranscriptLines(options, transcript, () => {
374
+ resolvedAnotherTranscript = true;
375
+ })) { /* drain the selected transcript */ }
376
+ };
377
+ await assert.rejects(readLines(), /selected transcript changed during inspection/);
378
+ assert.equal(resolvedAnotherTranscript, false);
379
+ });
380
+ it('keeps missing, invalid, and reversed timestamps unknown and reports gaps', async () => {
381
+ const noTime = call('missing', 0);
382
+ const invalid = { ...call('invalid', 0), timestamp: 'PRIVATE_INVALID_TIMESTAMP' };
383
+ const path = await fixture([
384
+ { type: noTime.type, payload: noTime.payload }, output('missing', 2),
385
+ invalid, output('invalid', 3),
386
+ call('reversed', 6), output('reversed', 4),
387
+ call('zero', 7), output('zero', 7),
388
+ ]);
389
+ await appendFile(path, '\ninvalid\nnull\n[]\n{"partial":');
390
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
391
+ assert.deepEqual(report.events.map((event) => event.duration_ms), [null, null, null, 0]);
392
+ assert.deepEqual(report.diagnostics, {
393
+ malformed_records: 4, invalid_timestamps: 1, reversed_tool_timestamps: 1, ambiguous_call_ids: 0,
394
+ });
395
+ assert.equal(report.summary.completed, 4);
396
+ assert.equal(report.summary.tools[0].measured_calls, 1);
397
+ assert.equal(report.summary.tools[0].total_duration_ms, 0);
398
+ assert.doesNotMatch(JSON.stringify(report), /PRIVATE_/);
399
+ });
400
+ it('uses record order for chronology even when timestamps go backwards', async () => {
401
+ await fixture([call('first', 4), output('first', 5), call('second', 1), output('second', 2)]);
402
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
403
+ assert.deepEqual(report.events.map((event) => event.call_id), ['first', 'second']);
404
+ assert.equal(report.last_activity_at, time(5));
405
+ });
406
+ it('filters and paginates after pairing while keeping whole-session summaries', async () => {
407
+ await fixture([
408
+ record('event_msg', { type: 'task_started' }),
409
+ call('short', 1), call('long', 2), call('other', 3, 'search'),
410
+ output('short', 2), output('long', 12, { exit_code: 1 }), output('other', 8),
411
+ call('unfinished', 13), record('compacted', {}, 14),
412
+ ]);
413
+ const options = { session: 'timeline-id', codexHomeDir: home };
414
+ const all = await buildSessionTimeline(options);
415
+ const first = await buildSessionTimeline({ ...options, kind: 'tools', sort: 'duration', limit: 1 });
416
+ assert.equal(first.events[0].call_id, 'long');
417
+ assert.equal(first.selection.matched_events, 4);
418
+ assert.equal(first.selection.has_more, true);
419
+ const second = await buildSessionTimeline({ ...options, kind: 'tools', sort: 'duration', offset: 1, limit: 1 });
420
+ assert.equal(second.events[0].call_id, 'other');
421
+ assert.deepEqual(second.summary, all.summary);
422
+ const filtered = await buildSessionTimeline({ ...options, tool: 'exec', minDurationMs: 1000, status: 'completed' });
423
+ assert.deepEqual(filtered.events.map((event) => event.call_id), ['short']);
424
+ const unknownDuration = await buildSessionTimeline({ ...options, status: 'incomplete', minDurationMs: 0 });
425
+ assert.equal(unknownDuration.events.length, 0);
426
+ const pastEnd = await buildSessionTimeline({ ...options, offset: 999 });
427
+ assert.equal(pastEnd.selection.has_more, false);
428
+ assert.equal(pastEnd.events.length, 0);
429
+ assert.deepEqual(pastEnd.summary, all.summary);
430
+ assert.equal((await buildSessionTimeline({ ...options, kind: 'turns' })).events[0].kind, 'turn_start');
431
+ assert.equal((await buildSessionTimeline({ ...options, kind: 'compactions' })).events[0].kind, 'compaction');
432
+ });
433
+ it('resolves archived prefixes, exact IDs, and source ambiguity consistently with export', async () => {
434
+ await fixture([call('active', 1)], 'abc');
435
+ await fixture([call('archived', 1)], 'abcd', true);
436
+ const exact = await buildSessionTimeline({ session: 'abc', codexHomeDir: home });
437
+ assert.equal(exact.archived, false);
438
+ const archived = await buildSessionTimeline({ session: 'abcd', codexHomeDir: home });
439
+ assert.equal(archived.archived, true);
440
+ await assert.rejects(buildSessionTimeline({ session: 'ab', codexHomeDir: home }), /Multiple transcripts/);
441
+ await assert.rejects(buildSessionTimeline({ session: 'missing', codexHomeDir: home }), /No local session/);
442
+ const other = join(home, 'other');
443
+ await fixture([], 'abc', false, other);
444
+ await assert.rejects(buildSessionTimeline({ session: 'abc', codexHomeDirs: [home, other] }), /--codex-home/);
445
+ });
446
+ it('reports empty and message-only histories without inventing turns or durations', async () => {
447
+ await fixture([record('event_msg', { type: 'user_message', message: 'private' }, 2)]);
448
+ const report = await buildSessionTimeline({ session: 'timeline-id', codexHomeDir: home });
449
+ assert.equal(report.events.length, 0);
450
+ assert.equal(report.summary.turns_started, 0);
451
+ assert.equal(report.last_activity_at, time(2));
452
+ });
453
+ it('validates numeric limits for programmatic callers before reading files', async () => {
454
+ for (const options of [{ limit: 0 }, { limit: 10_001 }, { offset: -1 }, { offset: 1.5 }, { minDurationMs: Infinity }]) {
455
+ await assert.rejects(buildSessionTimeline({ session: 'absent', codexHomeDir: home, ...options }), /Invalid --/);
456
+ }
457
+ });
458
+ });
459
+ //# sourceMappingURL=timeline.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline.test.js","sourceRoot":"","sources":["../../../src/session-history/__tests__/timeline.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvG,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAA0B,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,kCAAkC,EAAE,2BAA2B,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAE7H,MAAM,KAAK,GAAG,0BAA0B,CAAC;AACzC,SAAS,IAAI,CAAC,OAAe,IAAY,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AAC7G,SAAS,MAAM,CAAC,IAAY,EAAE,OAAgB,EAAE,OAAO,GAAG,CAAC,IAAI,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;AACpH,SAAS,IAAI,CAAC,EAAiB,EAAE,OAAe,EAAE,IAAI,GAAG,MAAM,EAAE,SAAkB;IACjF,OAAO,MAAM,CAAC,eAAe,EAAE;QAC7B,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,mBAAmB;QACxE,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;KAClD,EAAE,OAAO,CAAC,CAAC;AACd,CAAC;AACD,SAAS,MAAM,CAAC,EAAiB,EAAE,OAAe,EAAE,MAAM,GAAY,EAAE,SAAS,EAAE,CAAC,EAAE;IACpF,OAAO,MAAM,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,CAAC;AACzG,CAAC;AAED,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,IAAI,IAAY,CAAC;IACjB,UAAU,CAAC,KAAK,IAAI,EAAE,GAAG,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnF,SAAS,CAAC,KAAK,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7E,KAAK,UAAU,OAAO,CAAC,OAAkB,EAAE,EAAE,GAAG,aAAa,EAAE,QAAQ,GAAG,KAAK,EAAE,SAAS,GAAG,IAAI;QAC/F,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;QACrF,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,SAAS,CAAC,IAAI,EAAE;YACpB,MAAM,CAAC,cAAc,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,kBAAkB,EAAE,YAAY,EAAE,sBAAsB,EAAE,CAAC;YAC/G,GAAG,OAAO;SACX,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,EAAE,CAAC,mFAAmF,EAAE,KAAK,IAAI,EAAE;QACjG,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC;YACzB,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;YAChE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,QAAQ,CAAC;YAC1C,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;YACtD,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAC;YACrD,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACpE,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACnE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAClB,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;SACrE,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;YACzD,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,EAAE,cAAc;SAClG,CAAC,CAAC;QACH,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;YACjC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;YAC9F,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;SAClG,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE;YAC/B,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC;YACnF,aAAa,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC;YACtE,KAAK,EAAE;gBACL,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE;gBACtJ,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE;aACzJ;SACF,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,OAAO,CAAC;YACZ,MAAM,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;YACtF,MAAM,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;YAC5E,MAAM,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC;YACvH,MAAM,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,yBAAyB,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC;YAC3G,MAAM,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC,CAAC;SACpG,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,8CAA8C,CAAC,CAAC;QAC5F,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAuB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,OAAO,CAAC;YACZ,MAAM,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,oBAAoB,EAAE,EAAE,CAAC,CAAC;YACzD,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,mBAAmB,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YAC7F,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;SAC9F,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9F,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,OAAO,CAAC;YACZ,MAAM,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1B,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACnE,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACpE,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAC;SACtD,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrI,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;QAChG,MAAM,OAAO,GAA4C;YACvD,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC/B,CAAC,kDAAkD,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;YAClE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC9C,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC;YACpC,CAAC,yFAAyF,EAAE,QAAQ,EAAE,CAAC,CAAC;YACxG,CAAC,+DAA+D,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC9E,CAAC,8DAA8D,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC7E,CAAC,4GAA4G,EAAE,WAAW,EAAE,CAAC,CAAC;YAC9H,CAAC,oDAAoD,EAAE,WAAW,EAAE,IAAI,CAAC;YACzE,CAAC,8DAA8D,EAAE,WAAW,EAAE,IAAI,CAAC;YACnF,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC;YACjE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC;YACvC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC;YACvC,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC;SAC1B,CAAC;QACF,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,QAAQ,KAAK,EAAE,EAAE,KAAK,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChI,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YAC3C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACjC,MAAM,IAAI,GAAG,KAA0B,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACvC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,MAAM,OAAO,CAAC;YACZ,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YAChD,IAAI,CAAC,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YACnD,IAAI,CAAC,qBAAqB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YACzD,IAAI,CAAC,iBAAiB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YACrD,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;aACpF,EAAE,CAAC,CAAC;YACL,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;aACxF,EAAE,CAAC,CAAC;YACL,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,6BAA6B,EAAE;aAC1G,EAAE,CAAC,CAAC;YACL,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;aACzF,EAAE,CAAC,CAAC;YACL,MAAM,CAAC,YAAY,EAAE,CAAC,EAAE,oDAAoD,CAAC;YAC7E,MAAM,CAAC,eAAe,EAAE,CAAC,EAAE,gDAAgD,CAAC;YAC5E,MAAM,CAAC,qBAAqB,EAAE,CAAC,EAAE,oDAAoD,CAAC;SACvF,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QAC/D,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;YAC5H,CAAC,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,eAAe,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,qBAAqB,EAAE,QAAQ,EAAE,IAAI,CAAC;YAC7G,CAAC,iBAAiB,EAAE,QAAQ,EAAE,IAAI,CAAC;SACpC,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,iBAAiB,CAAC,CAAC;QAC/G,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACpF,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACpF,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAChF,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,6BAA6B,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9E,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;YAC7F,YAAY,EAAE,qBAAqB,EAAE,iBAAiB;SACvD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oFAAoF,EAAE,KAAK,IAAI,EAAE;QAClG,MAAM,OAAO,CAAC;YACZ,IAAI,CAAC,iBAAiB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YACrD,IAAI,CAAC,iBAAiB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YACrD,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;aAC1F,EAAE,CAAC,CAAC;YACL,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;aAC1F,EAAE,CAAC,CAAC;YACL,MAAM,CAAC,iBAAiB,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;SAC/C,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QAC/D,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC;YACpE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,SAAS;SAC1F,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;YACT,CAAC,iBAAiB,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC;YAC/C,CAAC,iBAAiB,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;SAC1C,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QAChI,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/H,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uFAAuF,EAAE,KAAK,IAAI,EAAE;QACrG,MAAM,OAAO,CAAC;YACZ,IAAI,CAAC,wBAAwB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YAC5D,IAAI,CAAC,sBAAsB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YAC1D,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,wBAAwB,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;aACjG,EAAE,CAAC,CAAC;YACL,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,sBAAsB,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,eAAe,EAAE;aAC7F,EAAE,CAAC,CAAC;YACL,IAAI,CAAC,wBAAwB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YAC5D,IAAI,CAAC,sBAAsB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YAC1D,MAAM,CAAC,wBAAwB,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;YACrD,MAAM,CAAC,sBAAsB,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC;YACpE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,SAAS;SAC1F,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;YACT,CAAC,wBAAwB,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC;YACtD,CAAC,sBAAsB,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC;YACjD,CAAC,wBAAwB,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YAChD,CAAC,sBAAsB,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;SAClD,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;QAC3F,MAAM,OAAO,CAAC;YACZ,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,yBAAyB,EAAE;aACrG,EAAE,CAAC,CAAC;YACL,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,EAAE,mBAAmB,EAAE,EAAE;YAChI,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,uBAAuB,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;aAC/F,EAAE,CAAC,CAAC;YACL,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;SAC1F,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QAC/D,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC;YAC7E,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM;SAChE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;YACT,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,QAAQ,CAAC;YAC5C,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,QAAQ,CAAC;YAC/C,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC;SAChC,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC9F,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACjG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,yBAAyB,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,KAAK,IAAI,EAAE;QAC9F,MAAM,OAAO,CAAC;YACZ,IAAI,CAAC,qBAAqB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YACzD,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;aAC9F,EAAE,CAAC,CAAC;YACL,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACpH,IAAI,CAAC,qBAAqB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YACzD,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;aAC9F,EAAE,CAAC,CAAC;YACL,EAAE,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,2BAA2B,EAAE;YAC/E,IAAI,CAAC,mBAAmB,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC;YACvD,MAAM,CAAC,WAAW,EAAE;gBAClB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;aAC5F,EAAE,CAAC,CAAC;YACL,MAAM,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC;YACpE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,WAAW;SAC/E,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;YACT,CAAC,qBAAqB,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;YACzC,CAAC,qBAAqB,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;YACzC,CAAC,mBAAmB,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;SAC1C,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,oBAAoB,CAAC;YACvC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI;SAChE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACtB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,2BAA2B,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC;QACrD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,mBAAmB,EAAE,4BAA4B,CAAC,CAAC;QACnF,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,MAAM,UAAU,GAAG;YACjB,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,kBAAkB,EAAE,QAAQ,EAAE,KAAK;SACjG,CAAC;QACF,MAAM,MAAM,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QAEvC,MAAM,OAAO,GAAG,MAAM,2BAA2B,CAAC;YAChD,UAAU;YACV,EAAE,GAAG,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE;SACtD,CAAC,CAAC;QACH,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,MAAM,OAAO,CAAC;YACZ,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9B,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YACpB,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YAC9G,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YAC1C,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YAC9G,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;SAC/C,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,uDAAuD;QAC/F,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9G,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM;YAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAC9F,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QACvD,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe;YAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACzG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5F,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAE,KAA2B,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACvG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,OAAO,CAAC;YACZ,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC;YAC1F,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;SAC7C,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QAC/D,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE;YACvG,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE;YACtD,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE;SACvD,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAE1F,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC;QACtG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM;YAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IACtG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;QAC1F,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;QAC7E,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QAChE,IAAI,UAAU,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,CAAC;QACzD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,mBAAmB,EAAE,4BAA4B,CAAC,CAAC;QACnF,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,MAAM,MAAM,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QAEvC,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,kCAAkC,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,QAAQ,EAAE,EAAE;YAC5F,UAAU,GAAG,QAAQ,CAAC;QACxB,CAAC,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAE9B,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iFAAiF,EAAE,KAAK,IAAI,EAAE;QAC/F,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC1B,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QACvD,MAAM,UAAU,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,CAAC;QAC3D,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAE3B,IAAI,yBAAyB,GAAG,KAAK,CAAC;QACtC,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE;YAC3B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,kCAAkC,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE;gBACrF,yBAAyB,GAAG,IAAI,CAAC;YACnC,CAAC,CAAC,EAAE,CAAC,CAAC,mCAAmC,CAAC,CAAC;QAC7C,CAAC,CAAC;QACF,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,+CAA+C,CAAC,CAAC;QACnF,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,2BAA2B,EAAE,CAAC;QAClF,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC;YACzB,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YACpE,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YAC7B,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;SACnC,CAAC,CAAC;QACH,MAAM,UAAU,CAAC,IAAI,EAAE,kCAAkC,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAE,KAA2B,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAChH,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE;YACnC,iBAAiB,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,wBAAwB,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC;SAChG,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;QAC3D,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9F,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAE,KAA2B,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC1G,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;QACzF,MAAM,OAAO,CAAC;YACZ,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;YAC7C,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,CAAC;YAC7D,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5E,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,CAAC;SACpD,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QAC/D,MAAM,GAAG,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACpG,MAAM,CAAC,KAAK,CAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAuB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACrE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QAChH,MAAM,CAAC,KAAK,CAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACvE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QACpH,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAE,KAA2B,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAClG,MAAM,eAAe,GAAG,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC,CAAC;QAC3G,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACxE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACvG,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC/G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;QACpG,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC1C,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACjF,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACtC,MAAM,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,EAAE,sBAAsB,CAAC,CAAC;QAC1G,MAAM,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,EAAE,kBAAkB,CAAC,CAAC;QAC3G,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAClC,MAAM,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QACvC,MAAM,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC;IAC/G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAC7F,MAAM,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACtF,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,KAAK,MAAM,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;YACtH,MAAM,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;QAClH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,6 +1,5 @@
1
- import { type SessionSearchOptions } from './search.js';
2
- export interface SessionExportOptions extends Pick<SessionSearchOptions, 'cwd' | 'codexHomeDir' | 'codexHomeDirs'> {
3
- session: string;
1
+ import { type SessionTranscriptOptions } from './transcript.js';
2
+ export interface SessionExportOptions extends SessionTranscriptOptions {
4
3
  includeTools?: boolean;
5
4
  }
6
5
  interface EntryLocation {
@@ -1 +1 @@
1
- {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/session-history/export.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuD,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAI7G,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,KAAK,GAAG,cAAc,GAAG,eAAe,CAAC;IAChH,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG,CAC7C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,WAAW,GAAG,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CACrF,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,CAAC,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAuGD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAkExG;AAaD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,CA4B7E"}
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/session-history/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgE,KAAK,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAI9H,MAAM,WAAW,oBAAqB,SAAQ,wBAAwB;IACpE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG,CAC7C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,WAAW,GAAG,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CACrF,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,CAAC,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAwCD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAoExG;AAaD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,CA4B7E"}
@@ -1,7 +1,4 @@
1
- import { createReadStream } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { createInterface } from 'node:readline';
4
- import { listRolloutFiles, resolveSessionSearchCodexHomeDirs } from './search.js';
1
+ import { readResolvedSessionTranscriptLines, resolveSessionTranscript } from './transcript.js';
5
2
  function asObject(value) {
6
3
  return value !== null && typeof value === 'object' && !Array.isArray(value)
7
4
  ? value : null;
@@ -17,66 +14,6 @@ function parseRecord(line) {
17
14
  return null;
18
15
  }
19
16
  }
20
- async function* readLines(path) {
21
- const stream = createReadStream(path, 'utf-8');
22
- const reader = createInterface({ input: stream, crlfDelay: Infinity });
23
- try {
24
- for await (const line of reader)
25
- yield line;
26
- }
27
- finally {
28
- reader.close();
29
- stream.destroy();
30
- }
31
- }
32
- async function readTranscriptMeta(path, archived) {
33
- try {
34
- for await (const line of readLines(path)) {
35
- const record = parseRecord(line);
36
- const payload = asObject(record?.payload);
37
- const id = asString(payload?.id);
38
- if (record?.type !== 'session_meta' || !id)
39
- return null;
40
- return {
41
- path, id, archived,
42
- startedAt: asString(payload?.timestamp) ?? asString(record.timestamp),
43
- cwd: asString(payload?.cwd),
44
- };
45
- }
46
- }
47
- catch (error) {
48
- // A running Codex instance can move a transcript into the archive during discovery.
49
- if (error.code !== 'ENOENT')
50
- throw error;
51
- }
52
- return null;
53
- }
54
- async function resolveTranscript(options) {
55
- const selector = options.session.trim();
56
- if (!selector)
57
- throw new Error('Missing session id. Use an exact id or a unique prefix.');
58
- const matches = [];
59
- const homes = await resolveSessionSearchCodexHomeDirs(options);
60
- for (const home of homes) {
61
- for (const archived of [false, true]) {
62
- const files = await listRolloutFiles(join(home, archived ? 'archived_sessions' : 'sessions'));
63
- for (const file of files) {
64
- const meta = await readTranscriptMeta(file, archived);
65
- if (meta?.id.startsWith(selector))
66
- matches.push(meta);
67
- }
68
- }
69
- }
70
- const exact = matches.filter((match) => match.id === selector);
71
- const candidates = exact.length > 0 ? exact : matches;
72
- if (candidates.length === 0)
73
- throw new Error(`No local session matches "${selector}".`);
74
- if (candidates.length > 1) {
75
- const ids = [...new Set(candidates.map((match) => match.id))].sort().join(', ');
76
- throw new Error(`Multiple transcripts match "${selector}" (${ids}). Use a full session id and --codex-home to narrow the source.`);
77
- }
78
- return candidates[0];
79
- }
80
17
  function messageText(content) {
81
18
  if (typeof content === 'string')
82
19
  return content;
@@ -104,14 +41,16 @@ function toolText(value) {
104
41
  return JSON.stringify(value, null, 2);
105
42
  }
106
43
  export async function exportSessionHistory(options) {
107
- const transcript = await resolveTranscript(options);
44
+ let transcript = await resolveSessionTranscript(options);
108
45
  const messages = [];
109
46
  const eventMessages = [];
110
47
  const tools = [];
111
48
  const toolNames = new Map();
112
49
  let lineNumber = 0;
113
50
  let skippedRecords = 0;
114
- for await (const line of readLines(transcript.path)) {
51
+ for await (const line of readResolvedSessionTranscriptLines(options, transcript, (resolved) => {
52
+ transcript = resolved;
53
+ })) {
115
54
  lineNumber += 1;
116
55
  if (line.trim() === '')
117
56
  continue;