diff --git a/src/session_recall/providers/copilot_cli/_labels.py b/src/session_recall/providers/copilot_cli/_labels.py index 4da82b3..ac6dd81 100644 --- a/src/session_recall/providers/copilot_cli/_labels.py +++ b/src/session_recall/providers/copilot_cli/_labels.py @@ -2,12 +2,35 @@ from __future__ import annotations +import posixpath from pathlib import Path from ...util.detect_repo import detect_repo_for_cwd +def _is_posixish_path(path_str: str) -> bool: + """Return True for POSIX/WSL-style paths even when running on Windows.""" + return path_str.startswith(("/", "~/")) + + def _detect_repo_for_path(path_str: str) -> str | None: + """Detect a repository for a path without rewriting POSIX paths on Windows. + + Copilot CLI state can contain Linux/WSL-style paths even when this package is + executed by Windows Python. Passing those strings through pathlib.Path on + Windows rewrites separators (``/work`` -> ``\\work``), which breaks repo + detection and changes user-facing local workspace labels. + """ + if _is_posixish_path(path_str): + expanded = posixpath.expanduser(path_str) + for candidate in (expanded, posixpath.dirname(expanded)): + if not candidate: + continue + repo = detect_repo_for_cwd(candidate) + if repo: + return repo + return None + path = Path(path_str).expanduser() candidate = path if path.is_dir() else path.parent return detect_repo_for_cwd(str(candidate)) @@ -16,5 +39,6 @@ def _detect_repo_for_path(path_str: str) -> str | None: def _local_workspace_label(path_str: str | None) -> str | None: if not path_str: return None - expanded = Path(path_str).expanduser() - return f"local:{expanded}" + if _is_posixish_path(path_str): + return f"local:{posixpath.expanduser(path_str)}" + return f"local:{Path(path_str).expanduser()}" diff --git a/src/session_recall/tests/test_health_schema_multistorage.py b/src/session_recall/tests/test_health_schema_multistorage.py index de80403..57c9a2d 100644 --- a/src/session_recall/tests/test_health_schema_multistorage.py +++ b/src/session_recall/tests/test_health_schema_multistorage.py @@ -82,6 +82,64 @@ def test_health_provider_fallback_mode_json(monkeypatch, capsys): assert "Provider:vscode" in names +def test_health_discovers_cli_session_state_when_sqlite_db_is_missing( + monkeypatch, capsys, tmp_path +): + """Regression for issue #19: health should not require session-store.db. + + Newer Copilot CLI layouts may expose ~/.copilot/session-state/*/events.jsonl + without the legacy SQLite session-store.db file. + """ + from session_recall.commands import health + from session_recall.providers import discovery + + state_root = tmp_path / "session-state" + session_dir = state_root / "abcd1234-0000-0000-0000-000000000000" + session_dir.mkdir(parents=True) + (session_dir / "events.jsonl").write_text( + "\n".join( + [ + json.dumps( + { + "type": "session.start", + "data": { + "sessionId": "abcd1234-0000-0000-0000-000000000000", + "context": {"repository": "owner/repo"}, + }, + "timestamp": "2026-04-22T10:00:00.000Z", + } + ), + json.dumps( + { + "type": "user.message", + "data": {"content": "Investigate auth timeout"}, + "timestamp": "2026-04-22T10:01:00.000Z", + } + ), + ] + ) + + "\n", + encoding="utf-8", + ) + + missing_db = str(tmp_path / ".copilot" / "session-store.db") + monkeypatch.setattr(health, "DB_PATH", missing_db) + monkeypatch.setattr(discovery, "CLI_SESSION_STATE_ROOT", str(state_root)) + + args = argparse.Namespace(json=True, provider="all") + rc = health.run(args) + + captured = capsys.readouterr() + assert rc == 0 + assert "database not found" not in captured.err + out = json.loads(captured.out) + assert out["storage_mode"] == "provider-fallback" + assert out["providers"]["cli"]["available"] is True + names = [d["name"] for d in out["dims"]] + assert "SQLite Health Core" in names + assert "Provider:cli" in names + + # ── helpers for integration tests ──────────────────────────────────── diff --git a/src/session_recall/tests/test_provider_backends.py b/src/session_recall/tests/test_provider_backends.py index f04e541..4bef207 100644 --- a/src/session_recall/tests/test_provider_backends.py +++ b/src/session_recall/tests/test_provider_backends.py @@ -3,11 +3,8 @@ from __future__ import annotations import json -import sys from pathlib import Path -import pytest - from session_recall.providers.copilot_cli import CopilotCliProvider from session_recall.providers.file import ( VSCodeProvider, @@ -16,12 +13,6 @@ _is_wsl, ) -# Windows Python rewrites POSIX/WSL session paths (/home/x -> \home\x). -# Fixed by PR #29; strict so CI flags these once the fix lands. -posix_paths_on_windows = pytest.mark.xfail( - sys.platform == "win32", reason="POSIX paths rewritten on Windows (#29)", strict=True -) - def test_vscode_kind1_inputtext_extraction() -> None: row = { @@ -135,7 +126,6 @@ def test_cli_fallback_prefers_context_repository_field(tmp_path: Path) -> None: assert results[0]["repository"] == "dezgit2025/auto-memory" -@posix_paths_on_windows def test_cli_fallback_uses_tool_path_to_infer_repository( monkeypatch, tmp_path: Path ) -> None: @@ -186,7 +176,6 @@ def test_cli_fallback_uses_tool_path_to_infer_repository( assert sessions[0]["repository"] == "dezgit2025/auto-memory" -@posix_paths_on_windows def test_cli_fallback_labels_non_repo_session_as_local_workspace( tmp_path: Path, ) -> None: