fix(learn): recover Claude project paths from session cwd

This commit is contained in:
Rod Boev 2026-07-08 23:05:09 -04:00
parent d0bdcb6302
commit ee720bb14f
2 changed files with 47 additions and 0 deletions

View file

@ -96,6 +96,11 @@ class ClaudeCodePlugin(LearnPlugin, ConversationScanner):
if not jsonl_files:
continue
session_project_path = self._project_path_from_session_cwd(jsonl_files)
if session_project_path is not None:
project_path = session_project_path
name = _project_display_name(project_path, entry.name)
projects.append(
ProjectInfo(
name=name,
@ -108,6 +113,28 @@ class ClaudeCodePlugin(LearnPlugin, ConversationScanner):
return projects
@staticmethod
def _project_path_from_session_cwd(jsonl_files: list[Path]) -> Path | None:
for jsonl_path in sorted(jsonl_files):
try:
with open(jsonl_path, encoding="utf-8", errors="replace") as f:
for line in f:
if not line.strip():
continue
try:
event = json.loads(line)
except json.JSONDecodeError:
continue
cwd = event.get("cwd")
if isinstance(cwd, str) and cwd:
project_path = Path(cwd)
if project_path.exists():
return project_path
except (OSError, UnicodeDecodeError):
continue
return None
def scan_project(
self, project: ProjectInfo, max_workers: int = 1, include_subagents: bool = True
) -> list[SessionData]:

View file

@ -8,6 +8,7 @@ making it impossible to reconstruct names formed from three or more tokens.
from __future__ import annotations
import json
from collections.abc import Generator
from pathlib import Path
from uuid import uuid4
@ -417,6 +418,25 @@ class TestDecodeProjectPath:
assert projects[0].name == "work"
assert str(projects[0].project_path).startswith("C:")
def test_discover_project_prefers_session_cwd_over_ambiguous_folder_name(
self, tmp_path: Path
) -> None:
nested = tmp_path / "vibe" / "remote"
hyphenated = tmp_path / "vibe-remote"
nested.mkdir(parents=True)
hyphenated.mkdir()
claude_dir = tmp_path / ".claude"
project_dir = claude_dir / "projects" / "C--Users-rod-work-vibe-remote"
project_dir.mkdir(parents=True)
(project_dir / "session.jsonl").write_text(json.dumps({"cwd": str(hyphenated)}) + "\n")
projects = ClaudeCodeScanner(claude_dir=claude_dir).discover_projects()
assert len(projects) == 1
assert projects[0].name == "vibe-remote"
assert projects[0].project_path == hyphenated
def test_windows_double_dash_encoding_decodes(self) -> None:
"""Real Claude Code encoding has no leading dash: C:\\Users\\x → C--Users-x (#1849).