From 7f4a6f6699ca59a2826d2cd65e72fe6b61c4884f Mon Sep 17 00:00:00 2001 From: disqualifier Date: Thu, 25 Jun 2026 18:42:17 -0400 Subject: [PATCH] style: drop inline comments, trim docstring periods remove inline comments (CLAUDE.md: docstrings only), strip trailing periods from single-line docstrings, and fix a PulseArmy->PulseAudio typo. no behavior change. Signed-off-by: disqualifier --- src/claudedo/__init__.py | 2 +- src/claudedo/__main__.py | 4 ++-- src/claudedo/audio.py | 8 ++++---- src/claudedo/config.py | 12 ++++++------ src/claudedo/daemon.py | 14 +++++++------- src/claudedo/grammar.py | 8 ++++---- src/claudedo/stt.py | 2 +- src/claudedo/target.py | 25 +++++++++++-------------- 8 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/claudedo/__init__.py b/src/claudedo/__init__.py index 6392e52..ce0d4d9 100644 --- a/src/claudedo/__init__.py +++ b/src/claudedo/__init__.py @@ -1,3 +1,3 @@ -"""claudedo — voice-control daemon for claude code (local STT -> tmux send-keys).""" +"""claudedo — voice-control daemon for claude code (local STT -> tmux send-keys)""" __version__ = "0.1.0" diff --git a/src/claudedo/__main__.py b/src/claudedo/__main__.py index 730c04c..675f3ea 100644 --- a/src/claudedo/__main__.py +++ b/src/claudedo/__main__.py @@ -1,4 +1,4 @@ -"""claudedo CLI: start | stop | status | test-audio | install.""" +"""claudedo CLI: start | stop | status | test-audio | install""" from __future__ import annotations @@ -95,7 +95,7 @@ def cmd_test_audio(args: argparse.Namespace) -> int: config.samplerate, config.channels, device, held=_timed_hold(2.0), max_utterance=3.0, min_utterance=0.0, ) - except Exception as exc: # noqa: BLE001 — surface any capture failure to the user + except Exception as exc: print(f"\naudio capture FAILED: {exc}", file=sys.stderr) print("fix-chain: install.sh apt deps + ~/.asoundrc pulse shim + Windows mic permission", file=sys.stderr) diff --git a/src/claudedo/audio.py b/src/claudedo/audio.py index 0339b8d..291ab26 100644 --- a/src/claudedo/audio.py +++ b/src/claudedo/audio.py @@ -6,7 +6,7 @@ a concrete sounddevice input device. two capture paths: utterance (no streaming STT; chunk-on-silence is enough for commands). - record_while(predicate): ptt mode — capture while predicate() is true (key held). -the WSLg/PulseArmy path is verified separately by `claudedo test-audio`; if capture +the WSLg/PulseAudio path is verified separately by `claudedo test-audio`; if capture fails here the fix-chain is the apt deps + ~/.asoundrc + Windows mic permission. """ @@ -23,11 +23,11 @@ log = logging.getLogger(__name__) class AudioError(Exception): - """raised when no usable input device is found or capture fails.""" + """raised when no usable input device is found or capture fails""" def list_devices() -> list[dict]: - """return sounddevice's device table (for test-audio / debugging).""" + """return sounddevice's device table (for test-audio / debugging)""" import sounddevice as sd return list(sd.query_devices()) @@ -121,7 +121,7 @@ def record_until_silence(samplerate: int, channels: int, device: int | None, def record_while(samplerate: int, channels: int, device: int | None, held: Callable[[], bool], max_utterance: float, min_utterance: float) -> np.ndarray | None: - """capture while held() is true (push-to-talk). returns mono float32 or None.""" + """capture while held() is true (push-to-talk). returns mono float32 or None""" import sounddevice as sd block_dur = 0.05 diff --git a/src/claudedo/config.py b/src/claudedo/config.py index 5baff95..4671464 100644 --- a/src/claudedo/config.py +++ b/src/claudedo/config.py @@ -1,4 +1,4 @@ -"""load and validate config.toml into a typed Config object with clear errors.""" +"""load and validate config.toml into a typed Config object with clear errors""" from __future__ import annotations @@ -10,7 +10,7 @@ from pathlib import Path try: import tomllib as _toml _TOML_BINARY = True -except ModuleNotFoundError: # python < 3.11 +except ModuleNotFoundError: import tomli as _toml _TOML_BINARY = True @@ -27,12 +27,12 @@ DEFAULT_CONFIG_PATHS = ( class ConfigError(Exception): - """raised on a missing or invalid configuration value.""" + """raised on a missing or invalid configuration value""" @dataclass class Config: - """validated claudedo configuration.""" + """validated claudedo configuration""" wake_phrases: list[str] mode: str @@ -53,7 +53,7 @@ class Config: def find_config_path(explicit: str | os.PathLike | None = None) -> Path: - """resolve the config file path, raising ConfigError if none is found.""" + """resolve the config file path, raising ConfigError if none is found""" candidates: list[Path] = [] if explicit: candidates.append(Path(explicit)) @@ -79,7 +79,7 @@ def _require(table: dict, section: str, key: str, types: tuple, default=None): def load_config(explicit: str | os.PathLike | None = None) -> Config: - """load config.toml from the first existing default path (or an explicit one).""" + """load config.toml from the first existing default path (or an explicit one)""" path = find_config_path(explicit) try: with open(path, "rb") as fh: diff --git a/src/claudedo/daemon.py b/src/claudedo/daemon.py index c1fa749..eecccac 100644 --- a/src/claudedo/daemon.py +++ b/src/claudedo/daemon.py @@ -32,7 +32,7 @@ def _ensure_state_dir() -> None: def write_state(pid: int, mode: str, target_session: str | None) -> None: - """write the running daemon's status for `claudedo status` to read.""" + """write the running daemon's status for `claudedo status` to read""" _ensure_state_dir() STATEFILE.write_text(json.dumps({ "pid": pid, @@ -43,7 +43,7 @@ def write_state(pid: int, mode: str, target_session: str | None) -> None: def read_state() -> dict | None: - """read the daemon status file, or None if absent/unreadable.""" + """read the daemon status file, or None if absent/unreadable""" try: return json.loads(STATEFILE.read_text(encoding="utf-8")) except (FileNotFoundError, json.JSONDecodeError, OSError): @@ -51,7 +51,7 @@ def read_state() -> dict | None: def read_pid() -> int | None: - """return the pid of a running daemon, or None (also clears stale pidfiles).""" + """return the pid of a running daemon, or None (also clears stale pidfiles)""" try: pid = int(PIDFILE.read_text(encoding="utf-8").strip()) except (FileNotFoundError, ValueError, OSError): @@ -67,7 +67,7 @@ def read_pid() -> int | None: def stop_running() -> bool: - """signal a running daemon to stop. returns whether one was found.""" + """signal a running daemon to stop. returns whether one was found""" pid = read_pid() if pid is None: return False @@ -105,7 +105,7 @@ class _PTTKey: class Daemon: - """owns the capture/transcribe/inject loop and runtime mode switching.""" + """owns the capture/transcribe/inject loop and runtime mode switching""" def __init__(self, config: Config) -> None: self.config = config @@ -186,7 +186,7 @@ class Daemon: write_state(os.getpid(), self.mode, target.read_active()) def run(self) -> None: - """run the daemon loop until a stop signal arrives.""" + """run the daemon loop until a stop signal arrives""" _ensure_state_dir() PIDFILE.write_text(str(os.getpid()), encoding="utf-8") self._install_signals() @@ -213,7 +213,7 @@ class Daemon: def run_daemon(config: Config) -> None: - """entry point used by the CLI ``start`` command.""" + """entry point used by the CLI ``start`` command""" if read_pid() is not None: raise RuntimeError("claudedo is already running (see `claudedo status`)") Daemon(config).run() diff --git a/src/claudedo/grammar.py b/src/claudedo/grammar.py index f66e46e..5069e76 100644 --- a/src/claudedo/grammar.py +++ b/src/claudedo/grammar.py @@ -42,7 +42,7 @@ class Action: def normalize(text: str) -> str: - """lowercase, strip punctuation, collapse whitespace, map number words to digits.""" + """lowercase, strip punctuation, collapse whitespace, map number words to digits""" text = text.lower().strip() text = _PUNCT.sub(" ", text) text = _WS.sub(" ", text).strip() @@ -57,7 +57,7 @@ def _ratio(a: str, b: str) -> float: def _wake_variants(phrase: str) -> set[str]: - """spaced and despaced forms of a wake phrase for lenient matching.""" + """spaced and despaced forms of a wake phrase for lenient matching""" norm = normalize(phrase) return {norm, norm.replace(" ", "")} @@ -104,7 +104,7 @@ def _fuzzy_in(token: str, options: tuple[str, ...], threshold: float) -> bool: def match_command(remainder: str, threshold: float) -> Action | None: - """map a normalized command remainder to an Action, or None if unrecognized.""" + """map a normalized command remainder to an Action, or None if unrecognized""" remainder = remainder.strip() if not remainder: return None @@ -152,7 +152,7 @@ def match_command(remainder: str, threshold: float) -> Action | None: def parse(transcript: str, wake_phrases: list[str], threshold: float, require_wake: bool) -> Action | None: - """full parse: wake gate then command match. None means discard.""" + """full parse: wake gate then command match. None means discard""" remainder = strip_wake(transcript, wake_phrases, threshold, require_wake) if remainder is None: return None diff --git a/src/claudedo/stt.py b/src/claudedo/stt.py index 1a6c076..35e94e8 100644 --- a/src/claudedo/stt.py +++ b/src/claudedo/stt.py @@ -14,7 +14,7 @@ log = logging.getLogger(__name__) class Transcriber: - """a loaded faster-whisper model that transcribes float32 mono audio chunks.""" + """a loaded faster-whisper model that transcribes float32 mono audio chunks""" def __init__(self, model: str = "small", language: str = "en", device: str = "auto", compute_type: str = "auto") -> None: diff --git a/src/claudedo/target.py b/src/claudedo/target.py index ebd7386..6650622 100644 --- a/src/claudedo/target.py +++ b/src/claudedo/target.py @@ -1,4 +1,4 @@ -"""resolve the active claude code tmux session from ~/.claude-active.""" +"""resolve the active claude code tmux session from ~/.claude-active""" from __future__ import annotations @@ -26,7 +26,7 @@ def session_name(name: str) -> str: def read_active() -> str | None: - """return the target session name from ~/.claude-active, or None if unset.""" + """return the target session name from ~/.claude-active, or None if unset""" try: name = ACTIVE_FILE.read_text(encoding="utf-8").strip() except FileNotFoundError: @@ -38,7 +38,7 @@ def read_active() -> str | None: def write_active(name: str) -> None: - """overwrite ~/.claude-active with a session name (used by ``switch``).""" + """overwrite ~/.claude-active with a session name (used by ``switch``)""" ACTIVE_FILE.write_text(name + "\n", encoding="utf-8") @@ -51,7 +51,7 @@ def set_target(name: str) -> str: def session_exists(name: str) -> bool: - """true if a tmux session with this name currently exists.""" + """true if a tmux session with this name currently exists""" if not name: return False result = subprocess.run( @@ -67,6 +67,13 @@ def resolve_target() -> str | None: never guesses a target: on a missing/empty ~/.claude-active or a stale session name, this logs a clear warning and returns None so the caller injects nothing. + + TODO: most-recently-active targeting (preferred over attached). today the target + is the project most recently ATTACHED to (the cc kit writes ~/.claude-active on + attach); upgrade to the session claude most recently asked a question in, via + tmux session_activity timestamps (list-sessions -F '#{session_name} + #{session_activity}', pick the highest-activity claude-* session) or by scraping + panes (capture-pane) for a waiting-prompt UI. """ name = read_active() if not name: @@ -76,13 +83,3 @@ def resolve_target() -> str | None: log.warning("target session %r no longer exists — skipping injection", name) return None return name - - -# TODO: most-recently-active targeting (preferred over attached). today the target -# is "the project most recently ATTACHED to" (the cc kit writes ~/.claude-active on -# attach). upgrade to "the session claude most recently asked a question / produced -# output in" via tmux session_activity timestamps: -# tmux list-sessions -F '#{session_name} #{session_activity}' -# pick the highest-activity claude-* session; or scrape panes -# (tmux capture-pane -p -t ) for a waiting-prompt UI and target the session whose -# pane currently shows one.