fix(hooks): derive project wing from non-macOS transcript paths (#1145)
_wing_from_transcript_path only matched '-Projects-<name>' segments, so Linux users with code under ~/dev/, ~/code/, or ~/src/ fell through to the wing_sessions fallback and lost the per-project diary scoping introduced in #659. Broaden the heuristic to derive the project from the final dash-separated token of the encoded project-folder name under .claude/projects/. Keeps the legacy -Projects- regex as a secondary match for transcripts living outside the standard Claude Code path. Covers macOS Users layout, Linux dev/code layouts, and deeper nested source paths while preserving existing Projects/ behavior.
This commit is contained in:
+19
-4
@@ -490,14 +490,29 @@ def _parse_harness_input(data: dict, harness: str) -> dict:
|
|||||||
def _wing_from_transcript_path(transcript_path: str) -> str:
|
def _wing_from_transcript_path(transcript_path: str) -> str:
|
||||||
"""Derive a project wing name from a Claude Code transcript path.
|
"""Derive a project wing name from a Claude Code transcript path.
|
||||||
|
|
||||||
Claude Code stores transcripts at:
|
Claude Code encodes the project's source directory by replacing path
|
||||||
|
separators with dashes, producing folders like:
|
||||||
~/.claude/projects/-home-<user>-Projects-<project>/session.jsonl
|
~/.claude/projects/-home-<user>-Projects-<project>/session.jsonl
|
||||||
We extract <project> and return ``wing_<project>`` to match the
|
~/.claude/projects/-home-<user>-dev-<parent>-<project>/session.jsonl
|
||||||
AAAK_SPEC convention (``wing_user``, ``wing_agent``, ``wing_code``,
|
~/.claude/projects/-Users-<user>-<folder>-<project>/session.jsonl
|
||||||
``wing_<project>``…). Falls back to ``wing_sessions``.
|
|
||||||
|
The project directory name is the final dash-separated token of the
|
||||||
|
encoded folder. Returns ``wing_<project>`` (lowercased, spaces → ``_``).
|
||||||
|
Falls back to ``wing_sessions`` if the path does not match a Claude Code
|
||||||
|
project-folder layout.
|
||||||
"""
|
"""
|
||||||
# Normalize path separators for cross-platform (Windows backslashes)
|
# Normalize path separators for cross-platform (Windows backslashes)
|
||||||
normalized = transcript_path.replace("\\", "/")
|
normalized = transcript_path.replace("\\", "/")
|
||||||
|
# Primary: pull the encoded project folder out of ``.claude/projects/``
|
||||||
|
# and take its last dash-separated token.
|
||||||
|
match = re.search(r"/\.claude/projects/-([^/]+)", normalized)
|
||||||
|
if match:
|
||||||
|
encoded = match.group(1)
|
||||||
|
project = encoded.rsplit("-", 1)[-1]
|
||||||
|
if project:
|
||||||
|
return f"wing_{project.lower().replace(' ', '_')}"
|
||||||
|
# Legacy fallback: explicit ``-Projects-<name>`` segment, useful for
|
||||||
|
# transcripts not under the standard Claude Code projects dir.
|
||||||
match = re.search(r"-Projects-([^/]+?)(?:/|$)", normalized)
|
match = re.search(r"-Projects-([^/]+?)(?:/|$)", normalized)
|
||||||
if match:
|
if match:
|
||||||
project = match.group(1).lower().replace(" ", "_")
|
project = match.group(1).lower().replace(" ", "_")
|
||||||
|
|||||||
@@ -324,6 +324,24 @@ def test_wing_from_transcript_path_lowercases():
|
|||||||
assert _wing_from_transcript_path(path) == "wing_myproject"
|
assert _wing_from_transcript_path(path) == "wing_myproject"
|
||||||
|
|
||||||
|
|
||||||
|
def test_wing_from_transcript_path_non_projects_layout():
|
||||||
|
# Linux users with code under ~/dev/, ~/src/, ~/code/ — no -Projects- segment.
|
||||||
|
# Project name is the final dash-separated token of the encoded folder.
|
||||||
|
path = "/home/igor/.claude/projects/-home-igor-dev-MemPalace-mempalace/session.jsonl"
|
||||||
|
assert _wing_from_transcript_path(path) == "wing_mempalace"
|
||||||
|
|
||||||
|
|
||||||
|
def test_wing_from_transcript_path_macos_users_layout():
|
||||||
|
# macOS ~/ layout without a Projects/ segment.
|
||||||
|
path = "/Users/alice/.claude/projects/-Users-alice-code-MyApp/session.jsonl"
|
||||||
|
assert _wing_from_transcript_path(path) == "wing_myapp"
|
||||||
|
|
||||||
|
|
||||||
|
def test_wing_from_transcript_path_nested_deep():
|
||||||
|
path = "/home/bob/.claude/projects/-home-bob-work-clients-acme-frontend/session.jsonl"
|
||||||
|
assert _wing_from_transcript_path(path) == "wing_frontend"
|
||||||
|
|
||||||
|
|
||||||
# --- _log ---
|
# --- _log ---
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user