(filePath: string)
| 491 | } |
| 492 | |
| 493 | function parseCodexSessionFile(filePath: string): Session | null { |
| 494 | assertTrustedPath(filePath); |
| 495 | const meta: CodexSessionMeta = { sessionId: '', cwd: '', source: '', model: '' }; |
| 496 | const state = createCodexState(''); |
| 497 | let parsedLineCount = 0; |
| 498 | |
| 499 | try { |
| 500 | readCodexJsonlStreaming(filePath, (line) => { |
| 501 | parsedLineCount++; |
| 502 | handleCodexLine(line, state, meta); |
| 503 | }); |
| 504 | } catch { |
| 505 | return null; |
| 506 | } |
| 507 | |
| 508 | if (parsedLineCount === 0) return null; |
| 509 | if (!meta.sessionId) meta.sessionId = path.basename(filePath, '.jsonl'); |
| 510 | |
| 511 | const wsName = projectNameFromCwd(meta.cwd); |
| 512 | const wsId = `codex-${wsName}-${meta.sessionId.slice(0, 8)}`; |
| 513 | |
| 514 | flushCodexTurn(state, meta.model); |
| 515 | if (state.requests.length === 0) return null; |
| 516 | |
| 517 | const modelUsage = computeModelUsage(state, meta.model); |
| 518 | const endReason = computeEndReason(modelUsage, state.requests); |
| 519 | |
| 520 | return createSession({ |
| 521 | sessionId: meta.sessionId, |
| 522 | workspaceId: wsId, |
| 523 | workspaceName: wsName, |
| 524 | location: meta.source || 'terminal', |
| 525 | harness: 'Codex', |
| 526 | creationDate: state.firstTs, |
| 527 | lastMessageDate: state.lastTs, |
| 528 | requests: state.requests, |
| 529 | modelUsage, |
| 530 | endReason, |
| 531 | hasDevcontainer: detectDevcontainerFromRequests(state.requests, meta.cwd), |
| 532 | workspaceRootPath: meta.cwd || undefined, |
| 533 | }); |
| 534 | } |
no test coverage detected