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