systemprompt_cli/commands/cloud/init/
mod.rs1use anyhow::{Context, Result};
11use std::path::Path;
12use systemprompt_cloud::ProjectContext;
13use systemprompt_logging::CliService;
14use systemprompt_models::CliPaths;
15
16mod scaffolding;
17pub mod templates;
18
19use crate::cli_settings::CliConfig;
20use scaffolding::generate_services_boilerplate;
21
22const GITIGNORE_CONTENT: &str = "# Ignore sensitive files
23credentials.json
24tenants.json
25**/secrets.json
26docker/
27storage/
28";
29
30const DOCKERIGNORE_CONTENT: &str = ".git
31.gitignore
32.gitmodules
33target/debug
34.cargo
35.systemprompt/credentials.json
36.systemprompt/tenants.json
37.systemprompt/**/secrets.json
38.systemprompt/docker
39.systemprompt/storage
40.env*
41backup
42docs
43instructions
44*.md
45web/node_modules
46.vscode
47.idea
48logs
49*.log
50";
51
52fn entrypoint_content() -> String {
53 format!(
54 r#"#!/bin/sh
55set -e
56
57echo "Running database migrations..."
58/app/bin/systemprompt {db_migrate_cmd}
59
60echo "Starting services..."
61exec /app/bin/systemprompt {services_serve_cmd} --foreground
62"#,
63 db_migrate_cmd = CliPaths::db_migrate_cmd(),
64 services_serve_cmd = CliPaths::services_serve_cmd(),
65 )
66}
67
68pub(super) fn execute(force: bool, _config: &CliConfig) -> Result<()> {
69 let project_root = std::env::current_dir().context("Failed to get current directory")?;
70 let ctx = ProjectContext::new(project_root.clone());
71 let systemprompt_dir = ctx.systemprompt_dir();
72 let services_dir = project_root.join("services");
73
74 let project_name = project_root
75 .file_name()
76 .and_then(|n| n.to_str())
77 .unwrap_or("systemprompt")
78 .to_owned();
79
80 CliService::section("Initialize Project");
81 CliService::key_value("Project", &project_name);
82 CliService::key_value("Root", &project_root.display().to_string());
83
84 if systemprompt_dir.exists() {
85 CliService::info(".systemprompt/ already exists");
86 } else {
87 create_systemprompt_dir(&systemprompt_dir, &project_root)?;
88 }
89
90 if !services_dir.exists() || force {
91 if force && services_dir.exists() {
92 CliService::warning("Removing existing services directory...");
93 std::fs::remove_dir_all(&services_dir)
94 .context("Failed to remove services directory")?;
95 }
96 generate_services_boilerplate(&project_root, &project_name)?;
97 } else {
98 CliService::info("services/ already exists (use --force to regenerate)");
99 }
100
101 CliService::section("Next Steps");
102 CliService::info("1. systemprompt cloud auth login # Authenticate");
103 CliService::info("2. systemprompt cloud tenant create # Create a tenant");
104 CliService::info("3. systemprompt cloud profile create local # Create a profile");
105
106 Ok(())
107}
108
109fn create_systemprompt_dir(dir: &Path, project_root: &Path) -> Result<()> {
110 std::fs::create_dir_all(dir).context("Failed to create .systemprompt directory")?;
111
112 std::fs::write(dir.join(".gitignore"), GITIGNORE_CONTENT)
113 .context("Failed to create .gitignore")?;
114 CliService::info(" Created .systemprompt/.gitignore");
115
116 std::fs::write(dir.join(".dockerignore"), DOCKERIGNORE_CONTENT)
117 .context("Failed to create .dockerignore")?;
118 CliService::info(" Created .systemprompt/.dockerignore");
119
120 let dockerfile_content = systemprompt_cloud::deploy::generate_dockerfile_content(project_root);
121 std::fs::write(dir.join("Dockerfile"), dockerfile_content)
122 .context("Failed to create Dockerfile")?;
123 CliService::info(" Created .systemprompt/Dockerfile");
124
125 std::fs::write(dir.join("entrypoint.sh"), entrypoint_content())
126 .context("Failed to create entrypoint.sh")?;
127 CliService::info(" Created .systemprompt/entrypoint.sh");
128
129 CliService::success("Created .systemprompt/");
130 Ok(())
131}
132
133pub(super) fn ensure_project_scaffolding(project_root: &Path) -> Result<()> {
134 let services_dir = project_root.join("services");
135 let web_dir = project_root.join("web");
136
137 if services_dir.exists() && web_dir.exists() {
138 return Ok(());
139 }
140
141 let project_name = project_root
142 .file_name()
143 .and_then(|n| n.to_str())
144 .unwrap_or("systemprompt")
145 .to_owned();
146
147 if !services_dir.exists() {
148 CliService::info("Scaffolding services/ directory...");
149 generate_services_boilerplate(project_root, &project_name)?;
150 }
151
152 if !web_dir.exists() {
153 std::fs::create_dir_all(&web_dir)
154 .with_context(|| format!("Failed to create directory: {}", web_dir.display()))?;
155 CliService::info("Created web/ directory");
156 }
157
158 Ok(())
159}