scan method
Scans lines (the session file's raw lines, header included).
Implementation
UsageChainScan scan(Iterable<String> lines) {
final state = _ScanState();
for (final raw in lines) {
final line = raw.trimRight();
if (line.isEmpty) continue;
// Cheap pre-check for the giant blob records: hashed, counted, never
// decoded.
final skippedDecode = _isBlobRecord(line);
final decoded = skippedDecode ? <String, dynamic>{} : _decode(line);
if (decoded == null) continue; // torn line: contributes nothing
final type = decoded['type'];
if (type == 'session') continue; // header line
state.noteRecord(line);
if (skippedDecode) continue;
final timestamp = DateTime.tryParse(
decoded['timestamp'] as String? ?? '',
);
if (type == 'custom' &&
decoded['customType'] == usageSegmentStartCustomType) {
_handleMarker(timestamp, state);
continue;
}
// Every other consumed record contributes its timestamp to the
// current segment (its closedAt, or firstRecordAt fallback).
state.current().noteRecordAt(timestamp);
if (type == 'custom') {
_handleSummary(decoded, state);
continue;
}
if (type != 'message') continue;
_handleAssistantMessage(decoded, state);
}
return state.finish();
}