feat: add CLI with start/stop/status commands
Made-with: Cursor
This commit is contained in:
103
src/cursor_flasher/cli.py
Normal file
103
src/cursor_flasher/cli.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
"""CLI for starting/stopping the cursor-flasher daemon."""
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from cursor_flasher.daemon import run_daemon
|
||||||
|
|
||||||
|
PID_FILE = Path.home() / ".cursor-flasher" / "daemon.pid"
|
||||||
|
|
||||||
|
|
||||||
|
def _write_pid() -> None:
|
||||||
|
PID_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
PID_FILE.write_text(str(os.getpid()))
|
||||||
|
|
||||||
|
|
||||||
|
def _read_pid() -> int | None:
|
||||||
|
if not PID_FILE.exists():
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
pid = int(PID_FILE.read_text().strip())
|
||||||
|
os.kill(pid, 0)
|
||||||
|
return pid
|
||||||
|
except (ValueError, ProcessLookupError, PermissionError):
|
||||||
|
PID_FILE.unlink(missing_ok=True)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _remove_pid() -> None:
|
||||||
|
PID_FILE.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_start(args: argparse.Namespace) -> None:
|
||||||
|
existing = _read_pid()
|
||||||
|
if existing is not None:
|
||||||
|
print(f"Daemon already running (PID {existing})")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if args.foreground:
|
||||||
|
_write_pid()
|
||||||
|
try:
|
||||||
|
run_daemon()
|
||||||
|
finally:
|
||||||
|
_remove_pid()
|
||||||
|
else:
|
||||||
|
pid = os.fork()
|
||||||
|
if pid > 0:
|
||||||
|
print(f"Daemon started (PID {pid})")
|
||||||
|
return
|
||||||
|
os.setsid()
|
||||||
|
_write_pid()
|
||||||
|
try:
|
||||||
|
run_daemon()
|
||||||
|
finally:
|
||||||
|
_remove_pid()
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_stop(args: argparse.Namespace) -> None:
|
||||||
|
pid = _read_pid()
|
||||||
|
if pid is None:
|
||||||
|
print("Daemon is not running")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
os.kill(pid, signal.SIGTERM)
|
||||||
|
_remove_pid()
|
||||||
|
print(f"Daemon stopped (PID {pid})")
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_status(args: argparse.Namespace) -> None:
|
||||||
|
pid = _read_pid()
|
||||||
|
if pid is None:
|
||||||
|
print("Daemon is not running")
|
||||||
|
else:
|
||||||
|
print(f"Daemon is running (PID {pid})")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
prog="cursor-flasher",
|
||||||
|
description="Flash the Cursor window when the AI agent is waiting for input",
|
||||||
|
)
|
||||||
|
sub = parser.add_subparsers(dest="command")
|
||||||
|
|
||||||
|
start_parser = sub.add_parser("start", help="Start the daemon")
|
||||||
|
start_parser.add_argument(
|
||||||
|
"--foreground", "-f", action="store_true",
|
||||||
|
help="Run in the foreground (don't daemonize)",
|
||||||
|
)
|
||||||
|
start_parser.set_defaults(func=cmd_start)
|
||||||
|
|
||||||
|
stop_parser = sub.add_parser("stop", help="Stop the daemon")
|
||||||
|
stop_parser.set_defaults(func=cmd_stop)
|
||||||
|
|
||||||
|
status_parser = sub.add_parser("status", help="Check daemon status")
|
||||||
|
status_parser.set_defaults(func=cmd_status)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
if not hasattr(args, "func"):
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
args.func(args)
|
||||||
Reference in New Issue
Block a user