## ADDED Requirements

### Requirement: Parse CC JSONL files line by line
The system SHALL read Claude Code JSONL files line by line, parsing each line as a JSON object. It SHALL handle files of any size without loading the entire file into memory.

#### Scenario: Parse a valid JSONL file
- **WHEN** the system reads a JSONL file where each line is valid JSON
- **THEN** it SHALL yield each parsed JSON object in order

#### Scenario: Handle malformed lines
- **WHEN** a JSONL line cannot be parsed as valid JSON
- **THEN** the system SHALL skip that line, log a warning with the line number, and continue processing

### Requirement: Classify messages by type
The system SHALL classify each JSONL message using the `type` field into one of: `user`, `assistant`, `system`, `progress`, `file-history-snapshot`, `queue-operation`.

#### Scenario: Known message type
- **WHEN** a message has `type` set to one of the known values
- **THEN** the system SHALL classify it accordingly and parse type-specific fields

#### Scenario: Unknown message type
- **WHEN** a message has an unrecognized `type` value
- **THEN** the system SHALL skip it with a warning and continue processing

### Requirement: Reconstruct conversation tree from UUID links
The system SHALL build a conversation tree using `parentUuid` and `uuid` fields on each message. The root message has `parentUuid: null`.

#### Scenario: Linear conversation
- **WHEN** all messages form a single chain (each message's `parentUuid` points to the previous message's `uuid`)
- **THEN** the system SHALL produce a linear sequence matching the chain order

#### Scenario: Branching conversation with sidechains
- **WHEN** multiple messages share the same `parentUuid` (branching)
- **THEN** the system SHALL follow the branch where `isSidechain` is `false` for the main thread, and ignore sidechain branches (subagent messages are exported separately)

#### Scenario: Root message identification
- **WHEN** processing a JSONL file
- **THEN** the system SHALL identify the root message as the one with `parentUuid: null`

### Requirement: Reassemble streamed assistant responses
The system SHALL group consecutive assistant JSONL lines that share the same `message.id` (Anthropic API message ID) into a single logical response. Each JSONL line contains exactly one content block.

#### Scenario: Multi-block assistant response
- **WHEN** three consecutive assistant lines share `message.id: "msg_01Abc"` with content blocks of types `thinking`, `text`, and `tool_use` respectively
- **THEN** the system SHALL combine them into a single logical response containing all three content blocks in order

#### Scenario: Single-block assistant response
- **WHEN** an assistant line has a unique `message.id` not shared by adjacent lines
- **THEN** the system SHALL treat it as a complete single-block response

#### Scenario: Synthetic assistant messages
- **WHEN** an assistant line has `message.model: "<synthetic>"`
- **THEN** the system SHALL treat it as its own response regardless of `message.id`, and SHALL NOT group it with real API responses

### Requirement: Distinguish user message subtypes
The system SHALL distinguish between external user messages (human input) and tool result messages based on the content structure.

#### Scenario: External user message
- **WHEN** a user message has `message.content` as a string (not array) and no `sourceToolAssistantUUID` field
- **THEN** the system SHALL classify it as an external human message

#### Scenario: Tool result message
- **WHEN** a user message has `message.content` as an array containing objects with `type: "tool_result"`
- **THEN** the system SHALL classify it as a tool result and associate it with the originating assistant message via `sourceToolAssistantUUID`

#### Scenario: Context compaction summary
- **WHEN** a user message has `isCompactSummary: true`
- **THEN** the system SHALL classify it as a compaction summary (not a real user message)

### Requirement: Extract content blocks from assistant messages
The system SHALL extract and categorize content blocks from assistant messages. The three content block types are `thinking`, `text`, and `tool_use`.

#### Scenario: Thinking content block
- **WHEN** a content block has `type: "thinking"`
- **THEN** the system SHALL extract the `thinking` field as reasoning content

#### Scenario: Text content block
- **WHEN** a content block has `type: "text"`
- **THEN** the system SHALL extract the `text` field as the message content

#### Scenario: Tool use content block
- **WHEN** a content block has `type: "tool_use"`
- **THEN** the system SHALL extract `id`, `name`, and `input` as tool call information

### Requirement: Extract token usage from assistant messages
The system SHALL extract token usage data from the `message.usage` field on assistant messages.

#### Scenario: Standard usage fields
- **WHEN** an assistant message has `message.usage` with `input_tokens`, `output_tokens`, and `cache_read_input_tokens`
- **THEN** the system SHALL extract all three values

#### Scenario: Missing usage field
- **WHEN** an assistant message (including synthetic) has no `message.usage` or zero-valued fields
- **THEN** the system SHALL treat token counts as zero for that response
