-
Notifications
You must be signed in to change notification settings - Fork 11
Description
Bug Description
When Claude Code exits plan mode (e.g., "clear context and implement"), it creates a new JSONL session file with a new filename UUID, but the internal sessionId in the file content still references the original pre-plan session. Freshell's session indexer resolves session IDs by preferring content IDs over filename IDs, causing both files to map to the same session key. The second file silently overwrites the first in sessionKeyToFilePath, and only one of the two sessions is ever visible in the sidebar.
The result: all conversation history after plan mode exit is invisible to the user in Freshell, even though the JSONL file exists on disk with valid content.
Steps to Reproduce
- Start a Claude Code session in a project directory (or worktree)
- Have a conversation (generates
<session-A>.jsonlwith internal sessionIdA) - Enter plan mode, write a plan
- Exit plan mode using one of the "clear context" options
- Continue chatting — Claude Code creates a new file
<session-B>.jsonl, but the internal sessionId is stillA - Open Freshell sidebar — only the original session (pre-plan) is visible
- The continuation session (
<session-B>.jsonl) is not shown, despite existing on disk
Root Cause
In server/coding-cli/session-indexer.ts, the processFile() method resolves the canonical session ID at line 418:
const sessionId = meta.sessionId || provider.extractSessionId(filePath, meta)meta.sessionId comes from parsing the JSONL content (parseSessionContent() in server/coding-cli/providers/claude.ts), which extracts the sessionId field from message objects (lines 266-277). Since the continuation file's content still contains the original session's ID, both files resolve to the same sessionId.
At line 444, the session key is set without collision detection:
this.sessionKeyToFilePath.set(makeSessionKey(provider.name, sessionId), filePath)Whichever file is processed last wins; the other becomes invisible.
Observed Example
- Original session file:
136767ac-590b-416c-8cd4-7022e2cfb5df.jsonl— 980 lines, ends at plan mode exit - Continuation file:
361f4f46-af04-4c1c-8e2e-f94fee0fae2e.jsonl— 743 lines, contains post-plan implementation work - Both are in the same project directory (
~/.claude/projects/...-worktrees-pane-extension-system/) - Content of the continuation file has
sessionId: "136767ac-590b-416c-8cd4-7022e2cfb5df"(the original ID) - Only the original shows in the sidebar; the continuation is invisible
Possible Fix Approaches
-
Prefer filename UUID as canonical ID — When the filename is a valid UUID and differs from the content sessionId, use the filename. Claude Code intentionally assigned a new UUID to the continuation file.
-
Detect collisions and keep both — When
sessionKeyToFilePathalready has an entry for a session key pointing to a different file, treat them as separate sessions (e.g., use a composite key likeprovider:sessionId:filePath). -
Session chaining — Detect that the continuation file references a parent sessionId and link them in the UI as a continuation chain, showing both in the sidebar (possibly grouped).
Environment
- Freshell v0.6.0
- Claude Code v2.1.63
- Commit: 940db3f