Skip to main content

systemprompt_cli/commands/infrastructure/services/
dispatch.rs

1//! `infra services` start/stop/restart dispatch.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use anyhow::Result;
7
8use super::{RestartTarget, ServicesCommands, StartTarget, StopTarget, restart, start, stop};
9use crate::context::CommandContext;
10use crate::shared::render_result;
11
12pub async fn execute(command: ServicesCommands, ctx: &CommandContext) -> Result<()> {
13    let config = &ctx.cli;
14    match command {
15        ServicesCommands::Start {
16            target,
17            all,
18            api,
19            agents,
20            mcp,
21            foreground: _,
22            skip_migrate,
23            kill_port_process,
24        } => {
25            let flags = start::ServiceFlags {
26                all,
27                targets: start::ServiceTargetFlags { api, agents, mcp },
28            };
29            let options = start::StartupOptions {
30                skip_migrate,
31                kill_port_process,
32            };
33            execute_start(target, flags, options, ctx).await
34        },
35
36        ServicesCommands::Stop {
37            target,
38            all,
39            api,
40            agents,
41            mcp,
42            force,
43        } => {
44            let flags = start::ServiceFlags {
45                all,
46                targets: start::ServiceTargetFlags { api, agents, mcp },
47            };
48            execute_stop(target, flags, force, ctx).await
49        },
50
51        ServicesCommands::Restart {
52            target,
53            failed,
54            agents,
55            mcp,
56        } => execute_restart(target, failed, agents, mcp, ctx).await,
57
58        ServicesCommands::Status {
59            detailed,
60            json,
61            health,
62        } => {
63            let result = super::status::execute(detailed, json, health, config).await?;
64            render_result(&result, config);
65            Ok(())
66        },
67
68        ServicesCommands::Cleanup { yes, dry_run } => {
69            let result = super::cleanup::execute(yes, dry_run, ctx).await?;
70            render_result(&result, config);
71            Ok(())
72        },
73
74        ServicesCommands::Serve {
75            foreground,
76            kill_port_process,
77        } => super::serve::execute(ctx.prompter(), foreground, kill_port_process, config).await,
78    }
79}
80
81async fn execute_start(
82    target: Option<StartTarget>,
83    flags: start::ServiceFlags,
84    options: start::StartupOptions,
85    ctx: &CommandContext,
86) -> Result<()> {
87    if let Some(individual) = target {
88        let app = ctx.app_context().await?;
89        return match individual {
90            StartTarget::Agent { agent } => {
91                start::execute_individual_agent(app, &agent, &ctx.cli).await
92            },
93            StartTarget::Mcp { server_name } => {
94                start::execute_individual_mcp(app, &server_name, &ctx.cli).await
95            },
96        };
97    }
98
99    let service_target = start::ServiceTarget::from_flags(flags);
100    start::execute(service_target, options, ctx).await
101}
102
103async fn execute_stop(
104    target: Option<StopTarget>,
105    flags: start::ServiceFlags,
106    force: bool,
107    ctx: &CommandContext,
108) -> Result<()> {
109    let config = &ctx.cli;
110    if let Some(individual) = target {
111        let app = ctx.app_context().await?;
112        return match individual {
113            StopTarget::Agent { agent, force } => {
114                let result = stop::execute_individual_agent(app, &agent, force, config).await?;
115                render_result(&result, config);
116                Ok(())
117            },
118            StopTarget::Mcp { server_name, force } => {
119                let result = stop::execute_individual_mcp(app, &server_name, force, config).await?;
120                render_result(&result, config);
121                Ok(())
122            },
123        };
124    }
125
126    let service_target = start::ServiceTarget::from_flags(flags);
127    let result = stop::execute(service_target, force, ctx).await?;
128    render_result(&result, config);
129    Ok(())
130}
131
132async fn execute_restart(
133    target: Option<RestartTarget>,
134    failed: bool,
135    agents: bool,
136    mcp: bool,
137    ctx: &CommandContext,
138) -> Result<()> {
139    let config = &ctx.cli;
140    let app = ctx.app_context().await?;
141
142    let result = if failed {
143        restart::execute_failed(app, config).await?
144    } else if agents {
145        restart::execute_all_agents(app, config).await?
146    } else if mcp {
147        restart::execute_all_mcp(app, config).await?
148    } else {
149        match target {
150            Some(RestartTarget::Api) => restart::execute_api(ctx.prompter(), config).await?,
151            Some(RestartTarget::Agent { agent }) => {
152                restart::execute_agent(app, &agent, config).await?
153            },
154            Some(RestartTarget::Mcp { server_name, build }) => {
155                restart::execute_mcp(app, &server_name, build, config).await?
156            },
157            None => {
158                return Err(anyhow::anyhow!(
159                    "Must specify target (api, agent, mcp) or use --failed/--agents/--mcp flag"
160                ));
161            },
162        }
163    };
164    render_result(&result, config);
165    Ok(())
166}
167
168pub fn load_service_configs() -> Result<Vec<systemprompt_scheduler::ServiceConfig>> {
169    let services_config = systemprompt_loader::ConfigLoader::load()?;
170    Ok(systemprompt_scheduler::ServiceConfig::list_from_manifest(
171        &services_config,
172    ))
173}