1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use std::path::PathBuf;
use clap::Parser;
/// Subcommand args for `keyhog daemon {start, stop, status}`.
#[derive(Parser)]
pub struct DaemonArgs {
#[command(subcommand)]
pub action: DaemonAction,
}
#[derive(clap::Subcommand)]
pub enum DaemonAction {
/// Start a daemon process that holds a compiled scanner and
/// serves scan requests over a Unix socket. Blocks until
/// `daemon stop` is invoked.
Start {
/// Override the default socket path. KeyHog otherwise uses
/// $XDG_RUNTIME_DIR/keyhog.sock, then the OS user-cache directory,
/// then the OS temporary directory.
///
/// A daemon started here is reachable by `daemon stop`/`status --socket`
/// AND by scans via `keyhog scan --daemon --daemon-socket <same path>`.
/// Pass the matching path so a fixed-location daemon (e.g. a systemd
/// unit) actually serves scans, not just admin commands.
#[arg(long, value_name = "PATH")]
socket: Option<PathBuf>,
/// Detector directory (same default as `keyhog scan --detectors`).
#[arg(long, default_value = "detectors")]
detectors: PathBuf,
#[arg(skip)]
detectors_cli_explicit: bool,
/// Override the Hyperscan compiled-database cache directory.
#[arg(long, value_name = "DIR")]
cache_dir: Option<PathBuf>,
/// Force a daemon scan backend instead of using persisted autoroute.
///
/// The default `auto` mode requires persisted calibration. Missing or
/// invalid evidence prevents readiness. Use an explicit backend only
/// for diagnostics and hermetic daemon tests.
#[arg(
long,
value_name = "BACKEND",
value_parser = clap::builder::PossibleValuesParser::new(
keyhog_scanner::hw_probe::BACKEND_OVERRIDE_VALUES
)
)]
backend: Option<String>,
/// Enable bounded directory, Git, archive, binary, remote, and cloud
/// batches from `keyhog scan --daemon=mass`. Warm one-file requests
/// remain available on the same socket.
#[arg(long)]
mass: bool,
/// Require each completed mass transaction to prove that GPU processed
/// more than half of all non-empty payload bytes. The client validates
/// the terminal receipt and fails instead of accepting CPU-majority work.
#[arg(long, requires = "mass")]
mass_gpu_primary: bool,
/// Max seconds a client connection may sit without completing one
/// request frame before the daemon closes it and reclaims the slot.
#[arg(
long,
default_value_t = 300,
value_name = "SECS",
value_parser = crate::value_parsers::parse_daemon_request_timeout_secs
)]
request_timeout_secs: u64,
},
/// Stop the running daemon by sending it a `Shutdown` over the socket.
Stop {
#[arg(long, value_name = "PATH")]
socket: Option<PathBuf>,
},
/// Print uptime, scans served, active scans, detector count, and backend policy.
Status {
#[arg(long, value_name = "PATH")]
socket: Option<PathBuf>,
},
}