| | @@ -2593,6 +2593,31 @@ test('--each writes one report bundle per session plus index manifests', async ( |
| | } |
| | }); |
| | |
| + | test('--each skips a session with no prompts instead of aborting the batch', async () => { |
| + | const dir = mkdtempSync(join(tmpdir(), 'tt-each-empty-')); |
| + | const here = dirname(fileURLToPath(import.meta.url)); |
| + | const claudeFix = join(here, 'fixtures', 'synthetic-session.jsonl'); |
| + | // a title-only Claude session (abandoned before the first prompt): one summary line, no turns |
| + | const empty = join(dir, 'title-only.jsonl'); |
| + | writeFileSync(empty, '{"type":"summary","summary":"abandoned session","leafUuid":"11111111-2222-3333-4444-555555555555"}\n'); |
| + | const outDir = join(dir, 'reports'); |
| + | try { |
| + | // good session first, then empty: pre-fix this aborted after writing the first |
| + | // bundle (err.code vs err.exitCode), leaving no INDEX and a non-zero exit |
| + | await main(['--each', '--from', 'claude', '--file', claudeFix, empty, '--out-dir', outDir, '--dir', dir, '--quiet']); |
| + | assert.ok(existsSync(join(outDir, 'INDEX.md')), 'INDEX.md written despite the empty session'); |
| + | const index = JSON.parse(readFileSync(join(outDir, 'index.json'), 'utf8')); |
| + | assert.equal(index.sessionCount, 1, 'only the real session lands in the manifest'); |
| + | // same batch with the empty session FIRST must behave identically |
| + | const outDir2 = join(dir, 'reports2'); |
| + | await main(['--each', '--from', 'claude', '--file', empty, claudeFix, '--out-dir', outDir2, '--dir', dir, '--quiet']); |
| + | const index2 = JSON.parse(readFileSync(join(outDir2, 'index.json'), 'utf8')); |
| + | assert.equal(index2.sessionCount, 1, 'order-independent: empty-first batch still completes'); |
| + | } finally { |
| + | rmSync(dir, { recursive: true, force: true }); |
| + | } |
| + | }); |
| + | |
| | test('--each collides labels safely when session ids repeat', async () => { |
| | const dir = mkdtempSync(join(tmpdir(), 'tt-each-dup-')); |
| | // two plain transcripts with the SAME basename in different subdirs -> same sessionId label |