Add native Windows host daemon (bleak/WinRT)
Adds a Windows port of the host daemon so the Clawdmeter stays connected on Windows independent of WSL. Mirrors the macOS daemon and speaks the existing GATT data service unchanged — no firmware changes. - claude_usage_daemon_windows.py: Windows-local OAuth token read + Anthropic poll + BLE scan/connect/write, with auto-reconnect (connect-retry wrapper, zombie-link break, split fast/slow backoff) - tray_windows.py: pystray login-startup tray app (status icon + Quit) - autostart_windows.py: winreg HKCU\Run autostart via pythonw.exe - icon_assets.py: per-state tray icons composited from logo.h - install-windows.ps1 + daemon/README-windows.md: turnkey setup - pytest suite: token / poll / reconnect / tray / autostart / no-WSL guard
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Static no-WSL-paths regression guard — APP-02 / D-10.
|
||||
|
||||
Asserts that the daemon, tray, and autostart sources reference no WSL-specific
|
||||
paths. This is a CI-surviving regression lock that needs no hardware: if a
|
||||
future edit accidentally introduces a ``\\wsl$``, ``wsl.exe``, ``/home/``, or
|
||||
``/mnt/`` reference into any of the three core Windows daemon source files, this
|
||||
test will fail with a message that names the offending pattern and file.
|
||||
|
||||
Run: python -m pytest daemon/tests/test_windows_no_wsl.py -x -q
|
||||
"""
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
# The four WSL-path patterns that must never appear in the daemon sources.
|
||||
FORBIDDEN = [r"\\wsl\$", r"wsl\.exe", r"/home/", r"/mnt/"]
|
||||
|
||||
# The three Windows-daemon source files covered by the guard.
|
||||
SOURCES = [
|
||||
Path("daemon/claude_usage_daemon_windows.py"),
|
||||
Path("daemon/tray_windows.py"),
|
||||
Path("daemon/autostart_windows.py"),
|
||||
]
|
||||
|
||||
|
||||
def test_no_wsl_paths_in_daemon():
|
||||
"""daemon/claude_usage_daemon_windows.py references no WSL paths."""
|
||||
_assert_clean(Path("daemon/claude_usage_daemon_windows.py"))
|
||||
|
||||
|
||||
def test_no_wsl_paths_in_tray():
|
||||
"""daemon/tray_windows.py references no WSL paths."""
|
||||
_assert_clean(Path("daemon/tray_windows.py"))
|
||||
|
||||
|
||||
def test_no_wsl_paths_in_autostart():
|
||||
"""daemon/autostart_windows.py references no WSL paths."""
|
||||
_assert_clean(Path("daemon/autostart_windows.py"))
|
||||
|
||||
|
||||
def _assert_clean(source: Path) -> None:
|
||||
"""Assert that none of the FORBIDDEN patterns appear in the given source file.
|
||||
|
||||
Reads the file relative to the repository root (the cwd pytest is invoked
|
||||
from). Fails with a descriptive message naming the leaked pattern and file
|
||||
so the regression is immediately actionable.
|
||||
"""
|
||||
text = source.read_text(encoding="utf-8")
|
||||
for pat in FORBIDDEN:
|
||||
match = re.search(pat, text)
|
||||
assert match is None, (
|
||||
f"WSL path leaked into {source}: pattern {pat!r} found at "
|
||||
f"position {match.start()} — "
|
||||
f"context: {text[max(0, match.start()-20):match.end()+20]!r}"
|
||||
)
|
||||
Reference in New Issue
Block a user