Skip to main content

qualia_cli/
service.rs

1use crate::daemon::{self, DaemonOpts, DEFAULT_DAEMON_PORT};
2use crate::mcp::{self, DEFAULT_MCP_BIND};
3use clap::Subcommand;
4
5#[derive(Subcommand, Debug)]
6pub enum ServiceAction {
7    /// Start detached daemon (4242) and MCP (4244) services for local WASM/native tests
8    Start {
9        /// Replace stale service records if needed
10        #[arg(long)]
11        force: bool,
12        /// Daemon loopback port
13        #[arg(long, default_value_t = DEFAULT_DAEMON_PORT)]
14        daemon_port: u16,
15        /// MCP TCP bind address
16        #[arg(long, default_value = DEFAULT_MCP_BIND)]
17        mcp_bind: String,
18    },
19    /// Stop both daemon and MCP background services
20    Stop,
21    /// Report status of daemon and MCP background services
22    Status,
23    /// Inspect daemon + MCP health and list MCP tools
24    Doctor,
25}
26
27pub async fn handle(action: &ServiceAction, qpu_enabled: bool) {
28    match action {
29        ServiceAction::Start {
30            force,
31            daemon_port,
32            mcp_bind,
33        } => {
34            let daemon_opts = DaemonOpts {
35                dev: true,
36                port: *daemon_port,
37                net_mode: "unmetered".to_string(),
38                energy_mode: "unlimited".to_string(),
39                workers: 1,
40                compute_swarm: false,
41                empty_graph: true,
42            };
43
44            println!("Starting Qualia local dev stack...");
45            if let Err(err) = daemon::start_service(&daemon_opts, *force) {
46                eprintln!("Daemon start failed: {err}");
47                std::process::exit(1);
48            }
49
50            if let Err(err) = mcp::start_background(mcp_bind, qpu_enabled, *force) {
51                eprintln!("MCP start failed: {err}");
52                let _ = daemon::stop_service();
53                std::process::exit(1);
54            }
55
56            println!("Local dev stack ready:");
57            println!("  graph daemon : http://127.0.0.1:{daemon_port}");
58            println!("  MCP surface  : tcp://{mcp_bind}");
59            println!("  run tests    : node docs/tests/run-headless.mjs --mode both");
60        }
61        ServiceAction::Stop => {
62            let daemon_err = daemon::stop_service().err();
63            let mcp_err = mcp::stop_background().err();
64            if let Some(err) = daemon_err {
65                eprintln!("Daemon stop: {err}");
66            }
67            if let Some(err) = mcp_err {
68                eprintln!("MCP stop: {err}");
69            }
70        }
71        ServiceAction::Status => {
72            println!("daemon:");
73            let _ = daemon::print_status();
74            println!("mcp:");
75            let _ = mcp::print_status();
76        }
77        ServiceAction::Doctor => {
78            println!("=== daemon ===");
79            let _ = daemon::print_doctor(DEFAULT_DAEMON_PORT);
80            println!();
81            println!("=== mcp ===");
82            let _ = mcp::print_doctor();
83            println!();
84            println!("=== quick start ===");
85            println!("  qualia-cli service start");
86            println!("  qualia-cli mcp serve --transport stdio   # for IDE MCP clients");
87            println!("  node docs/tests/run-headless.mjs --mode both");
88        }
89    }
90}