mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-08-17 20:44:31 +00:00
fix(codex): read full first line for session validation
`readFirstLine` allocated a fixed 16 KB buffer, but Codex CLI 0.128+ embeds the entire base_instructions / system prompt in the `session_meta` line, pushing it past 20 KB. When the buffer doesn't catch a newline, `isValidCodexSession` rejects the session, so every recent Codex session is silently excluded from totals. Switch to a streaming readline read so the first line is captured regardless of length, and add a regression test that creates a 40 KB session_meta payload. Locally, this changes my 30-day Codex total from €267 (only ~half of sessions parsed) to €878 (all sessions parsed).
This commit is contained in:
parent
033da415c5
commit
945da9f0ba
2 changed files with 48 additions and 12 deletions
|
|
@ -1,4 +1,6 @@
|
|||
import { readdir, stat, open } from 'fs/promises'
|
||||
import { readdir, stat } from 'fs/promises'
|
||||
import { createReadStream } from 'fs'
|
||||
import { createInterface } from 'readline'
|
||||
import { basename, join } from 'path'
|
||||
import { homedir } from 'os'
|
||||
|
||||
|
|
@ -70,21 +72,29 @@ function sanitizeProject(cwd: string): string {
|
|||
}
|
||||
|
||||
async function readFirstLine(filePath: string): Promise<CodexEntry | null> {
|
||||
let fh
|
||||
// Codex CLI 0.128+ writes a session_meta line that can exceed 20 KB because
|
||||
// it embeds the full base_instructions / system prompt. A fixed-size buffer
|
||||
// would miss the trailing newline and reject the session as invalid.
|
||||
// Stream the file via readline to read the first line regardless of length.
|
||||
const stream = createReadStream(filePath, { encoding: 'utf-8' })
|
||||
const rl = createInterface({ input: stream, crlfDelay: Infinity })
|
||||
let firstLine: string | undefined
|
||||
try {
|
||||
fh = await open(filePath, 'r')
|
||||
const buf = Buffer.alloc(16384)
|
||||
const { bytesRead } = await fh.read(buf, 0, 16384, 0)
|
||||
if (bytesRead === 0) return null
|
||||
const text = buf.toString('utf-8', 0, bytesRead)
|
||||
const nl = text.indexOf('\n')
|
||||
const line = nl >= 0 ? text.slice(0, nl) : text
|
||||
if (!line.trim()) return null
|
||||
return JSON.parse(line) as CodexEntry
|
||||
for await (const line of rl) {
|
||||
firstLine = line
|
||||
break
|
||||
}
|
||||
} catch {
|
||||
return null
|
||||
} finally {
|
||||
await fh?.close()
|
||||
rl.close()
|
||||
stream.destroy()
|
||||
}
|
||||
if (!firstLine || !firstLine.trim()) return null
|
||||
try {
|
||||
return JSON.parse(firstLine) as CodexEntry
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,32 @@ describe('codex provider - session discovery', () => {
|
|||
expect(sessions).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('accepts session_meta lines larger than 16 KB (Codex CLI 0.128+)', async () => {
|
||||
// Codex CLI 0.128+ embeds the full base_instructions / system prompt in the
|
||||
// first session_meta line, often pushing it past 20 KB. Regression guard
|
||||
// against a fixed-size buffer in readFirstLine.
|
||||
const bigPayload = JSON.stringify({
|
||||
type: 'session_meta',
|
||||
timestamp: '2026-05-02T00:00:00Z',
|
||||
payload: {
|
||||
cwd: '/Users/test/big',
|
||||
originator: 'codex-tui',
|
||||
session_id: 'sess-big',
|
||||
model: 'gpt-5.5',
|
||||
base_instructions: { text: 'x'.repeat(40_000) },
|
||||
},
|
||||
})
|
||||
await writeSession(tmpDir, '2026-05-02', 'rollout-big.jsonl', [
|
||||
bigPayload,
|
||||
tokenCount({ last: { input: 100, output: 50 }, total: { total: 150 } }),
|
||||
])
|
||||
|
||||
const provider = createCodexProvider(tmpDir)
|
||||
const sessions = await provider.discoverSessions()
|
||||
expect(sessions).toHaveLength(1)
|
||||
expect(sessions[0]!.path).toContain('rollout-big.jsonl')
|
||||
})
|
||||
|
||||
it('skips files without codex session_meta', async () => {
|
||||
const [year, month, day] = '2026-04-14'.split('-')
|
||||
const sessionDir = join(tmpDir, 'sessions', year!, month!, day!)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue