systemprompt_cli/commands/admin/setup/
mod.rs1pub mod ai_config;
9mod catalog;
10mod common;
11mod docker;
12mod docker_compose;
13mod docker_database;
14mod postgres;
15mod profile;
16mod profile_sections;
17mod secrets;
18mod types;
19mod wizard;
20mod wizard_dry_run;
21mod wizard_prompts;
22
23use crate::shared::CommandOutput;
24use anyhow::Result;
25use clap::Args;
26
27pub use types::*;
28
29#[derive(Debug, Args)]
30#[expect(
31 clippy::struct_excessive_bools,
32 reason = "each bool is an independent clap CLI flag, not a state machine"
33)]
34pub struct SetupArgs {
35 #[arg(
36 short,
37 long,
38 help = "Target environment name (e.g., dev, staging, prod)"
39 )]
40 pub environment: Option<String>,
41
42 #[arg(
43 long,
44 help = "Use Docker for PostgreSQL (default: use existing installation)"
45 )]
46 pub docker: bool,
47
48 #[arg(
49 long,
50 env = "SYSTEMPROMPT_DB_HOST",
51 default_value = "localhost",
52 help = "PostgreSQL host"
53 )]
54 pub db_host: String,
55
56 #[arg(
57 long,
58 env = "SYSTEMPROMPT_DB_PORT",
59 default_value = "5432",
60 help = "PostgreSQL port"
61 )]
62 pub db_port: u16,
63
64 #[arg(
65 long,
66 env = "SYSTEMPROMPT_DB_USER",
67 help = "PostgreSQL user (default: systemprompt_`<env>`)"
68 )]
69 pub db_user: Option<String>,
70
71 #[arg(
72 long,
73 env = "SYSTEMPROMPT_DB_PASSWORD",
74 help = "PostgreSQL password (auto-generated if not provided)"
75 )]
76 pub db_password: Option<String>,
77
78 #[arg(
79 long,
80 env = "SYSTEMPROMPT_DB_NAME",
81 help = "PostgreSQL database name (default: systemprompt_`<env>`)"
82 )]
83 pub db_name: Option<String>,
84
85 #[arg(long, env = "GEMINI_API_KEY", help = "Google AI (Gemini) API key")]
86 pub gemini_key: Option<String>,
87
88 #[arg(long, env = "ANTHROPIC_API_KEY", help = "Anthropic (Claude) API key")]
89 pub anthropic_key: Option<String>,
90
91 #[arg(long, env = "OPENAI_API_KEY", help = "OpenAI (GPT) API key")]
92 pub openai_key: Option<String>,
93
94 #[arg(long, env = "GITHUB_TOKEN", help = "GitHub token (optional)")]
95 pub github_token: Option<String>,
96
97 #[arg(
98 long,
99 env = "SYSTEMPROMPT_DEFAULT_PROVIDER",
100 help = "Provider to make the default (gemini | anthropic | openai); must have a key. \
101 In interactive mode the selected provider is used instead."
102 )]
103 pub default_provider: Option<String>,
104
105 #[arg(long, help = "Run database migrations after setup")]
106 pub migrate: bool,
107
108 #[arg(
109 long,
110 conflicts_with = "migrate",
111 help = "Skip migrations (non-interactive default)"
112 )]
113 pub no_migrate: bool,
114
115 #[arg(long, help = "Preview setup without creating files or making changes")]
116 pub dry_run: bool,
117
118 #[arg(short = 'y', long, help = "Skip confirmation prompts")]
119 pub yes: bool,
120
121 #[arg(
122 long,
123 help = "Overwrite existing profile/secrets files (default: preserve them)"
124 )]
125 pub force: bool,
126}
127
128impl SetupArgs {
129 pub fn effective_db_user(&self, env_name: &str) -> String {
130 self.db_user
131 .clone()
132 .unwrap_or_else(|| format!("systemprompt_{}", env_name))
133 }
134
135 pub fn effective_db_name(&self, env_name: &str) -> String {
136 self.db_name
137 .clone()
138 .unwrap_or_else(|| format!("systemprompt_{}", env_name))
139 }
140
141 pub const fn has_ai_provider(&self) -> bool {
142 self.gemini_key.is_some() || self.anthropic_key.is_some() || self.openai_key.is_some()
143 }
144}
145
146pub async fn execute(args: SetupArgs, config: &crate::CliConfig) -> Result<CommandOutput> {
147 wizard::execute(args, config).await
148}