fix(cli): find the session when the cache is stale or its cwd moved - #146
Merged
Conversation
`ccx refs` (and every other CLI subcommand) failed with "no session found matching project paths: ..." while the session plainly existed on disk. findSessionFile matched the tmux pane's path against LoadCachedSessions, which only reads ~/.claude/.ccx-cache.gob. Two problems: 1. Nothing in the CLI writes that cache — cache.save() runs only in ScanSessions, i.e. the TUI's full scan. A session started since the last TUI run is simply absent. 2. scanSessionStream sets sess.ProjectPath from every isMeta line it passes, so the cached value is whichever cwd the transcript's *last* isMeta line happened to carry at scan time. For a worktree with a nested Go module the cwd alternates between the two, so the cached path can be the submodule while the pane sits at the worktree root. Verified on a real transcript: truncated at 500 lines it caches .../build-civiz/ci-visibility, at 6100 lines .../build-civiz. Matching is now three passes: - exact match against the cache (unchanged); - ScanSessionsForPaths on the pane's project dirs. Its results are deliberately NOT re-filtered by ProjectPath — that field is the unreliable one; the directory, encoded from the pane path, is the actual link. This pass fixes both problems above; - a session at an ancestor of the pane path, for a pane inside a nested module, reported on stderr since it isn't an exact match. Only this direction: matching downward would let a pane in a broad parent like ~/src adopt an arbitrary deep session under it, which is worse than failing (observed while testing). The per-path loop is extracted into matchSessionsForPaths with a pluggable predicate, and ranks candidates by path distance before ModTime so a nearer ancestor beats a more recently touched distant one.
Kairo-Kim
approved these changes
Jul 28, 2026
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.
문제
ccx refs가 세션이 디스크에 멀쩡히 있는데도 실패했다:원인
findSessionFile은 tmux pane 경로를LoadCachedSessions(=~/.claude/.ccx-cache.gob만 읽음)의ProjectPath와 완전 일치로 비교한다. 두 가지가 겹쳐서 깨진다.1. CLI는 캐시를 절대 갱신하지 않는다.
cache.save()는ScanSessions(TUI 전체 스캔)에만 있다. 마지막 TUI 실행 이후 시작된 세션은 캐시에 아예 없다. 실측: 이 작업을 하던 세션 파일도 캐시에 없었다.2. 캐시된
ProjectPath가 신뢰할 수 없다.scanSessionStream은 지나가는isMeta라인마다sess.ProjectPath = cwd로 덮어쓴다 (scanner_stream.go:63). 즉 캐시에 남는 건 스캔 시점의 마지막isMetacwd다. nested Go module이 있는 worktree에서는 cwd가 두 경로를 오간다:실제 transcript를 잘라서 확인한 결과:
.../build-civiz/ci-visibility← 매칭 실패.../build-civiz/ci-visibility← 매칭 실패.../build-civizsubmodule이 마지막이었던 구간에서 TUI가 full scan을 돌리면 그 잘못된 경로가 캐시에 굳고, TUI를 다시 띄우기 전까지 CLI는 계속 실패한다.
수정
매칭을 3단계로 나눴다.
ScanSessionsForPaths로 직접 스캔 — pane 경로에서 인코딩한 프로젝트 디렉터리를 읽는다. 결과를ProjectPath로 재필터하지 않는다: 그 필드가 바로 신뢰할 수 없는 값이고, pane 경로로 인코딩한 디렉터리 자체가 실제 연결 고리다. 다시 걸면 이 폴백이 존재하는 이유인 바로 그 miss를 재현한다. 이 단계가 원인 1·2를 모두 해결한다.3단계는 의도적으로 단방향이다. 하위 방향도 매칭하면
~/src같은 넓은 상위에 있는 pane이 그 아래 아무 깊은 세션이나 주워 온다 — 테스트 중 실제로 관측했고, 실패보다 나쁘다.per-path 루프는
matchSessionsForPaths(sessions, paths, match)로 추출했고, 우선순위를 경로 거리 → ModTime 으로 잡았다. 먼 조상이 최근이라는 이유로 가까운 부모를 이기지 않는다.검증
실제 transcript로 원본 실패를 재현한 뒤 수정본과 비교했다 (캐시
ProjectPath가 nested module, pane은 worktree 루트):internal/cli/find_session_test.go에 테스트 8개 추가. 회귀 탐지력도 확인했다 — 거리 우선순위를 제거하니 의도대로 실패한다:go test ./...전체 통과.