systemprompt_cli/commands/cloud/
mod.rs1pub mod auth;
11pub mod backup;
12pub mod deploy;
13pub mod doctor;
14pub mod init;
15pub mod profile;
16mod status;
17pub mod templates;
18pub mod tenant;
19pub mod types;
20
21pub use systemprompt_cloud::{Environment, OAuthProvider};
22
23use crate::cli_settings::CliConfig;
24use crate::context::CommandContext;
25use crate::descriptor::{CommandDescriptor, DescribeCommand};
26use anyhow::Result;
27use clap::Subcommand;
28
29#[derive(Debug, Subcommand)]
30pub enum CloudCommands {
31 #[command(subcommand, about = "Authentication (login, logout, whoami)")]
32 Auth(auth::AuthCommands),
33
34 #[command(about = "Initialize project structure")]
35 Init {
36 #[arg(long)]
37 force: bool,
38 },
39
40 #[command(subcommand_required = false, about = "Manage tenants (local or cloud)")]
41 Tenant {
42 #[command(subcommand)]
43 command: Option<tenant::TenantCommands>,
44 },
45
46 #[command(subcommand_required = false, about = "Manage profiles")]
47 Profile {
48 #[command(subcommand)]
49 command: Option<profile::ProfileCommands>,
50 },
51
52 #[command(about = "Deploy to systemprompt.io Cloud")]
53 Deploy {
54 #[arg(long)]
55 skip_push: bool,
56
57 #[arg(long, short = 'p', help = "Profile name to deploy")]
58 profile: Option<String>,
59
60 #[arg(long, help = "Run the pre-deploy preflight only, without deploying")]
61 check: bool,
62 },
63
64 #[command(about = "Download the tenant's runtime services/ tree to a local directory")]
65 Backup {
66 #[arg(long, short = 'p', help = "Profile name to back up")]
67 profile: Option<String>,
68
69 #[arg(
70 long,
71 short = 'o',
72 help = "Output directory (default: ./systemprompt-backup-<timestamp>)"
73 )]
74 output: Option<std::path::PathBuf>,
75
76 #[arg(long, help = "List remote files without downloading")]
77 list: bool,
78 },
79
80 #[command(about = "Run the pre-deploy preflight for a profile without deploying")]
81 Doctor {
82 #[arg(long, short = 'p', help = "Profile name to check")]
83 profile: Option<String>,
84 },
85
86 #[command(about = "Check cloud deployment status")]
87 Status,
88
89 #[command(about = "Generate Dockerfile based on discovered extensions")]
90 Dockerfile,
91}
92
93impl DescribeCommand for CloudCommands {
94 fn descriptor(&self) -> CommandDescriptor {
95 match self {
96 Self::Deploy { .. } => CommandDescriptor::PROFILE_AND_SECRETS,
97 Self::Backup { .. } | Self::Status => CommandDescriptor::PROFILE_ONLY,
98 _ => CommandDescriptor::NONE,
99 }
100 }
101}
102
103pub async fn execute(cmd: CloudCommands, ctx: &CommandContext) -> Result<()> {
104 match cmd {
105 CloudCommands::Auth(cmd) => auth::execute(cmd, ctx).await,
106 CloudCommands::Init { force } => init::execute(force, &ctx.cli),
107 CloudCommands::Tenant { command } => tenant::execute(command, ctx).await,
108 CloudCommands::Profile { command } => profile::execute(command, ctx).await,
109 CloudCommands::Deploy {
110 skip_push,
111 profile,
112 check,
113 } => {
114 deploy::execute(
115 deploy::DeployArgs {
116 skip_push,
117 profile_name: profile,
118 check,
119 },
120 ctx.prompter(),
121 &ctx.cli,
122 )
123 .await
124 },
125 CloudCommands::Backup {
126 profile,
127 output,
128 list,
129 } => {
130 backup::execute(
131 backup::BackupArgs {
132 profile_name: profile,
133 output,
134 list,
135 },
136 ctx.prompter(),
137 &ctx.cli,
138 )
139 .await
140 },
141 CloudCommands::Doctor { profile } => {
142 doctor::execute(profile, ctx.prompter(), &ctx.cli).await
143 },
144 CloudCommands::Status => {
145 let result = status::execute(&ctx.cli).await?;
146 crate::shared::render_result(&result, &ctx.cli);
147 Ok(())
148 },
149 CloudCommands::Dockerfile => execute_dockerfile(&ctx.cli),
150 }
151}
152
153fn execute_dockerfile(config: &CliConfig) -> Result<()> {
154 use crate::shared::project::ProjectRoot;
155 use types::DockerfileOutput;
156
157 let project = ProjectRoot::discover().map_err(|e| anyhow::anyhow!("{}", e))?;
158 let content = systemprompt_cloud::deploy::generate_dockerfile_content(project.as_path());
159
160 let output = DockerfileOutput {
161 content: content.clone(),
162 };
163
164 if config.is_json_output() {
165 crate::shared::render_result(
166 &crate::shared::CommandOutput::copy_paste_titled("Dockerfile", output.content),
167 config,
168 );
169 } else {
170 systemprompt_logging::CliService::output(&content);
171 }
172
173 Ok(())
174}