codeburn/tests/parser-subagent-collection.test.ts
iamtoruk f1bf7a197b
Some checks are pending
CI / semgrep (push) Waiting to run
feat(report): Claude-scoped agent-type breakdown
Surfaces real subagent-transcript spend grouped by agentType
(workflow-subagent / Explore / general-purpose / …), read from each agent's
sibling .meta.json (cached on CachedFile; session cache bumped 3→4). This makes
ultra/workflow usage visible — the existing Task-input-based "subagents" section
never sees workflow agents. Shown in `report --format json` (claudeAgentTypes)
and a "Claude Agent Types" dashboard panel that renders only when Claude agent
transcripts exist, so it never appears for the other providers.
2026-06-10 11:45:28 +02:00

61 lines
2.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { mkdtemp, mkdir, rm, writeFile } from 'fs/promises'
import { tmpdir } from 'os'
import { join, basename } from 'path'
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { collectJsonlFiles, readAgentType } from '../src/parser.js'
let root: string
beforeEach(async () => { root = await mkdtemp(join(tmpdir(), 'codeburn-collect-')) })
afterEach(async () => { await rm(root, { recursive: true, force: true }) })
describe('collectJsonlFiles', () => {
// Regression for #470: workflow/ultracode subagent transcripts live nested at
// `<session>/subagents/workflows/<wf>/agent-*.jsonl`. A flat scan dropped them,
// so usage went uncounted whenever the workflow feature was on.
it('collects nested workflow subagent transcripts, not just top-level subagent files', async () => {
const sessionDir = join(root, 'session-1')
const wfDir = join(sessionDir, 'subagents', 'workflows', 'wf_abc')
await mkdir(wfDir, { recursive: true })
await writeFile(join(root, 'session-1.jsonl'), '{}\n')
await writeFile(join(sessionDir, 'subagents', 'agent-direct.jsonl'), '{}\n')
await writeFile(join(wfDir, 'agent-nested.jsonl'), '{}\n')
// Sidecar metadata must never be picked up as a transcript.
await writeFile(join(wfDir, 'agent-nested.meta.json'), '{}\n')
const found = (await collectJsonlFiles(root)).map(f => basename(f)).sort()
expect(found).toContain('session-1.jsonl')
expect(found).toContain('agent-direct.jsonl')
expect(found).toContain('agent-nested.jsonl')
expect(found).not.toContain('agent-nested.meta.json')
})
it('returns an empty list for a missing directory without throwing', async () => {
await expect(collectJsonlFiles(join(root, 'does-not-exist'))).resolves.toEqual([])
})
})
describe('readAgentType (Claude-scoped agent-type detection)', () => {
it('reads agentType from a subagent transcripts sibling .meta.json', async () => {
const dir = join(root, 'session', 'subagents')
await mkdir(dir, { recursive: true })
await writeFile(join(dir, 'agent-x.jsonl'), '{}\n')
await writeFile(join(dir, 'agent-x.meta.json'), JSON.stringify({ agentType: 'Explore' }))
expect(await readAgentType(join(dir, 'agent-x.jsonl'))).toBe('Explore')
})
it('falls back to workflow-subagent for nested workflow agents without a meta', async () => {
const dir = join(root, 'session', 'subagents', 'workflows', 'wf_1')
await mkdir(dir, { recursive: true })
await writeFile(join(dir, 'agent-y.jsonl'), '{}\n')
expect(await readAgentType(join(dir, 'agent-y.jsonl'))).toBe('workflow-subagent')
})
it('returns undefined for an ordinary (non-subagent) session file', async () => {
await writeFile(join(root, 'session.jsonl'), '{}\n')
expect(await readAgentType(join(root, 'session.jsonl'))).toBeUndefined()
})
})