Investigation revealed that Claude Code now appends synthetic error messages to transcript files when API errors occur (rate limits, authentication failures, etc.).
These synthetic messages have:
- model: "<synthetic>"
- isApiErrorMessage: true
- All token usage fields set to 0
The getTokenMetrics() function in src/utils/jsonl.ts calculates the current context length by finding the most recent main chain entry(isSidechain !== true) sorted by timestamp. When an API error occurs, the synthetic error message becomes the "most recent entry", causing contextLength to be calculated as 0.
* revert 798b637
* Fix#88: Fix Block Timer showing incorrect elapsed time due to flawed block calculation
\## Problem
The Block Timer widget was displaying incorrect elapsed times when multiple work sessions occurred on the same day with gaps between them. For example, with work sessions at:
- Morning: 11:00-16:00 (first message at 11:42, last at 14:52)
- Evening: 17:00-22:00 (first message at 17:44)
At 20:10, the Block Timer showed **4hr 10m** instead of the expected **3hr 10m**.
\## Root Cause
The existing algorithm in `findMostRecentBlockStartTime()` had a fundamental flaw in how it calculated block start times:
1. It correctly identified continuous work by finding gaps ≥ 5 hours
2. It floored the continuous work start to the hour
3. **But then it used `Math.floor(totalWorkTime / sessionDurationMs)` to calculate the current block**
This division-based approach assumed continuous 5-hour blocks without gaps:
```
[Block 0: 11:00-16:00][Block 1: 16:00-21:00]...
```
In reality, blocks have gaps between them:
```
[Block 0: 11:00-16:00]--gap--[Block 1: 17:00-22:00]...
```
\### Incorrectly Identified Cases
The algorithm failed in scenarios where:
- **Multiple work sessions with small gaps** (< 5 hours): Treated them as one continuous session and calculated wrong block boundaries
- **Current time in a gap**: Could incorrectly show elapsed time from a previous block
- **Messages spanning multiple days**: Division logic ignored actual message timestamps and gaps
\### Example of the Bug
With messages at 11:42 and 17:44, gap of ~2h 52m:
1. No 5-hour gap found → continuous work from 11:00
2. At 20:10: `totalWorkTime = 9h 10m`
3. `completedBlocks = floor(9.17 / 5) = 1`
4. `blockStart = 11:00 + (1 × 5h) = 16:00`
5. Elapsed = 20:10 - 16:00 = **4h 10m** (wrong!)
Correct calculation should be:
- Block 1: 11:00-16:00 (ended)
- Gap: 16:00-17:44
- Block 2: 17:00-22:00 (current)
- Elapsed = 20:10 - 17:00 = **3h 10m** ✓
\## Solution
Replaced the flawed division-based calculation with a proper block-building algorithm:
1. **Find definitive boundary**: Look back for 5+ hour gap (or start of data)
2. **Build blocks forward from timestamps**:
- Sort timestamps chronologically
- For each timestamp after the boundary:
- If no current block OR timestamp is after current block end: start new block (floor to hour, add 5h for end)
- Otherwise: timestamp is within current block
3. **Find current block**: Check if `now` falls within any constructed block's timespan
4. **Return block start** if found and has activity, otherwise null
This correctly handles gaps of any size and builds the actual block structure from message timestamps.
\## Tests Added
Created comprehensive unit tests in `src/utils/__tests__/jsonl.test.ts` covering:
\### Real Scenarios
- **Morning and evening blocks with gap**: Messages at 11:42 and 17:44 → correctly identifies 17:00 block start at 20:10
- **Multiple messages in single block**: Messages within 5 hours → single block with floored start time
- **Multi-block scenario**: Messages at 00:13, 05:56, 06:01, 14:33, 20:01 → correctly identifies 20:00 block at 22:43
\### Edge Cases
- **Current time in gap between blocks**: Returns null (no active block)
- **No messages within 5 hours**: Returns null (session expired)
- **Block boundary timing**: Correctly handles time exactly at 5-hour boundary
- **5+ hour gap detection**: Properly detects boundary when gap ≥ 5 hours
- **Messages at exact hour boundaries**: Handles flooring when message is already at :00
\### Invalid Inputs
- **Empty content**: Returns null
- **Invalid JSON**: Returns null gracefully
All tests pass with the corrected algorithm, ensuring the Block Timer and Five Hour Moons widgets now display accurate elapsed times.
---------
Co-authored-by: alexander.buyanov <alexander.buyanov@konux.de>
Detect block boundaries after 60 minutes of inactivity instead of requiring a 5-hour gap.
This prevents block start times from carrying over into short midday breaks and ensures elapsed time matches ccusage.
Co-authored-by: alexander.buyanov <alexander.buyanov@konux.de>
* feat: Add fish-style path abbreviation to CurrentWorkingDir widget
- Added new toggle option for fish-style path abbreviation
- Keeps home directory as ~, first and last directories complete
- Abbreviates middle directories to first letter only
- Preserves dot for hidden directories (e.g. .config → .c)
- Maintains backward compatibility with segments feature
- Both options are mutually exclusive (fish-style takes precedence)
Example: ~/Documents/Projects/my-project → ~/D/P/my-project
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Modify cwd widget fish-style code to use handleEditorAction instead of renderEditor, misc lint fixes
---------
Co-authored-by: Jishuai <aqianlikuaizaifeng@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
Block windows were staying “active” after multiple hours with no token usage, so the block timer kept counting even though ccusage reported the session closed.
Aligning the activity detection with actual token usage prevents those phantom sessions and keeps the timer in sync with the upstream report.
Co-authored-by: alexander.buyanov <alexander.buyanov@konux.de>
- Enhanced separator rendering to check all previous widgets for actual content
- Prevents separators from being skipped when there are widgets that don't render but others before them do
- Improves status line layout consistency by properly detecting content presence
* chore(settings): support more than 3 lines
* chore: add confirm dialog
* chore: update example script
* chore: rm config override
* Fix spacing issues, disallow deletion of last line, fix issue where deleting lines 2 and 3 would keep them in the list, cleanup onDelete and onAppend method locations
* Initialize default settings with two empty lines
---------
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>