fix(claude): honor CLAUDE_CONFIG_DIR when resolving the resume session id - #85
Merged
Conversation
…n id Restored Claude sessions failed with "No conversation found with session ID: <uuid>", leaving a bare shell prompt behind (the pwsh wrapper runs with -NoExit, so claude's exit is visible rather than closing the pane). ClaudeSessionService hardcoded ~/.claude as Claude's data directory. Claude Code honors CLAUDE_CONFIG_DIR, and when that is set its conversations live under $CLAUDE_CONFIG_DIR/projects/ instead. A machine that has ever run without the env var keeps a stale ~/.claude/projects/ tree, so GetLastSessionId returned the newest id from the *wrong* store - a real, valid-looking UUID that current Claude has no record of. Reproduced on the reporting machine: CLAUDE_CONFIG_DIR is set at User scope, so CodeShellManager.exe inherits it. For one project folder the stale ~/.claude tree resolved to 6270d0e9-... (last written two months earlier) - exactly the id in the error - while the live store resolved to 8eaf0a22-..., modified that day. ResolveClaudeHome(configDir, userProfile) now picks CLAUDE_CONFIG_DIR when set and falls back to ~/.claude otherwise. GetLastSessionId gains an internal overload taking the resolved home so the lookup is testable without touching process environment or the real user profile; the public signature is unchanged. Note this deliberately does NOT fall back to the legacy directory when the resolved one has no session: returning null starts a fresh conversation, which is correct, whereas falling back reintroduces the bogus-id failure. Does not address issue #75 (the same-folder resume race) - that is a separate root cause in the same code path. Verified: 9 new unit tests (env resolution, stale-vs-live store selection, the real on-disk layout where a <session-id>/ subdirectory sits next to <session-id>.jsonl); 215/215 tests pass; app builds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes restored Claude sessions failing with
No conversation found with session ID: <uuid>, leaving a bare shell prompt behind.Root cause
ClaudeSessionServicehardcoded~/.claudeas Claude's data directory:Claude Code honors
CLAUDE_CONFIG_DIR, and when it's set, conversations live under$CLAUDE_CONFIG_DIR/projects/instead. A machine that has ever run without the env var keeps a stale~/.claude/projects/tree — soGetLastSessionIdreturned the newest id from the wrong store: a real, valid-looking UUID that current Claude has no record of.This is why it looked like Claude had changed how
--resumeworks. It hasn't; only where conversations are stored moved.Evidence from the reporting machine
CLAUDE_CONFIG_DIRis set at User scope, soCodeShellManager.exeinherits it. For one project folder:.jsonl~/.claude(stale, frozen ~2 months)6270d0e9-971a-44ad-81b9-cf89434ab1cf← exactly the id in the error~/.claude-work(live)8eaf0a22-4f5d-45a4-a579-0ccf20553e27, modified same dayChange
ResolveClaudeHome(configDir, userProfile)—CLAUDE_CONFIG_DIRwhen set, else~/.claude.GetLastSessionIdgains aninternaloverload taking the resolved home, so the lookup is testable without mutating process environment or depending on the real user profile. Public signature unchanged.This deliberately does not fall back to the legacy directory when the resolved one has no session — returning
nullstarts a fresh conversation, which is correct. Falling back would reintroduce the bogus-id failure.Scope
Does not fix #75 (the same-folder resume race, where two sessions in one folder both resolve to the same id and the first session's own write poisons the lookup for the second). That's a separate root cause in the same code path; the durable fix there is persisting a
ClaudeSessionIdper session and launching with--session-id. This PR only ensures we read the right directory.Verification
<session-id>/subdirectory and amemory/dir sit next to<session-id>.jsonlManual check worth doing before merge: restart CodeShellManager and confirm sessions resume rather than erroring. I verified the id resolution against the real filesystem but did not perform a live
--resume(that would have written into an in-use conversation).🤖 Generated with Claude Code