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.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +17 -0
- package/dist/cli/__tests__/session-timeline.test.d.ts +2 -0
- package/dist/cli/__tests__/session-timeline.test.d.ts.map +1 -0
- package/dist/cli/__tests__/session-timeline.test.js +155 -0
- package/dist/cli/__tests__/session-timeline.test.js.map +1 -0
- package/dist/cli/session-search.d.ts.map +1 -1
- package/dist/cli/session-search.js +7 -0
- package/dist/cli/session-search.js.map +1 -1
- package/dist/cli/session-timeline.d.ts +9 -0
- package/dist/cli/session-timeline.d.ts.map +1 -0
- package/dist/cli/session-timeline.js +174 -0
- package/dist/cli/session-timeline.js.map +1 -0
- package/dist/session-history/__tests__/timeline.test.d.ts +2 -0
- package/dist/session-history/__tests__/timeline.test.d.ts.map +1 -0
- package/dist/session-history/__tests__/timeline.test.js +459 -0
- package/dist/session-history/__tests__/timeline.test.js.map +1 -0
- package/dist/session-history/export.d.ts +2 -3
- package/dist/session-history/export.d.ts.map +1 -1
- package/dist/session-history/export.js +5 -66
- package/dist/session-history/export.js.map +1 -1
- package/dist/session-history/timeline.d.ts +97 -0
- package/dist/session-history/timeline.d.ts.map +1 -0
- package/dist/session-history/timeline.js +325 -0
- package/dist/session-history/timeline.js.map +1 -0
- package/dist/session-history/transcript.d.ts +16 -0
- package/dist/session-history/transcript.d.ts.map +1 -0
- package/dist/session-history/transcript.js +111 -0
- package/dist/session-history/transcript.js.map +1 -0
- package/package.json +1 -1
- 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":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
export interface SessionExportOptions extends
|
|
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":"
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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;
|