Files
rigdoctor/src/rigdoctor/core/reccontrol.py
T
jessey 5682878f22 feat: guided diagnostic session (CLI) — pick a game, capture, analyze — 0.11.0
The seed use case end to end, orchestrating M3 + M4 (ARCHITECTURE §7.1).

- core/diagnostic.py: start(game) runs a focused, game-tagged capture into a
  dedicated diagnostic log (window-scoped report, separate from the always-on
  crash log); finish() stops it and combines the capture summary (M3) with the
  health findings (M4). Game recorded as a log event so it survives crash+reboot.
- CLI: rigdoctor diagnose start --game/--appid | status | finish.
- recorder/record run gained an optional --game tag; reccontrol passes it through.
- Tests for game recovery + the finish() combination.

GUI/tray "Run Diagnostic" button and auto start/stop (D12 wrapper) come next.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 08:27:53 +02:00

76 lines
1.8 KiB
Python

"""Background-process control for the crash-capture recorder (shared by CLI + GUI).
Both front-ends start/stop/inspect the same `systemd`-style detached recorder via the
PID and status files, so behaviour is identical however you drive it.
"""
from __future__ import annotations
import json
import os
import signal
import subprocess
import sys
from .. import config
def pid_alive(pid: int) -> bool:
try:
os.kill(pid, 0)
except OSError:
return False
return True
def running_pid() -> int | None:
try:
pid = int(config.PID_FILE.read_text().strip())
except (OSError, ValueError):
return None
return pid if pid_alive(pid) else None
def read_status() -> dict | None:
try:
return json.loads(config.STATUS_FILE.read_text())
except (OSError, ValueError):
return None
def start_background(
interval: float | None = None, out: str | None = None, game: str | None = None
) -> int | None:
"""Spawn a detached `record run`. Returns the child pid, or None if already running."""
if running_pid():
return None
config.STATE_DIR.mkdir(parents=True, exist_ok=True)
cmd = [sys.executable, "-m", "rigdoctor", "record", "run"]
if interval:
cmd += ["--interval", str(interval)]
if out:
cmd += ["--out", out]
if game:
cmd += ["--game", game]
out_fh = open(config.SPAWN_LOG, "a")
proc = subprocess.Popen(
cmd,
stdout=out_fh,
stderr=subprocess.STDOUT,
stdin=subprocess.DEVNULL,
start_new_session=True,
)
return proc.pid
def stop_background() -> bool:
"""Signal the running recorder to stop. Returns False if it wasn't running."""
pid = running_pid()
if not pid:
return False
try:
os.kill(pid, signal.SIGTERM)
except OSError:
return False
return True