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
16pub mod 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
57exec /app/bin/systemprompt {services_serve_cmd} --foreground
58",
59 services_serve_cmd = CliPaths::services_serve_cmd(),
60 )
61}
62
63pub(super) fn execute(force: bool, _config: &CliConfig) -> Result<()> {
64 let project_root = std::env::current_dir().context("Failed to get current directory")?;
65 let ctx = ProjectContext::new(project_root.clone());
66 let systemprompt_dir = ctx.systemprompt_dir();
67 let services_dir = project_root.join("services");
68
69 let project_name = project_root
70 .file_name()
71 .and_then(|n| n.to_str())
72 .unwrap_or("systemprompt")
73 .to_owned();
74
75 CliService::section("Initialize Project");
76 CliService::key_value("Project", &project_name);
77 CliService::key_value("Root", &project_root.display().to_string());
78
79 if systemprompt_dir.exists() {
80 CliService::info(".systemprompt/ already exists");
81 } else {
82 create_systemprompt_dir(&systemprompt_dir, &project_root)?;
83 }
84
85 if !services_dir.exists() || force {
86 if force && services_dir.exists() {
87 CliService::warning("Removing existing services directory...");
88 std::fs::remove_dir_all(&services_dir)
89 .context("Failed to remove services directory")?;
90 }
91 generate_services_boilerplate(&project_root, &project_name)?;
92 } else {
93 CliService::info("services/ already exists (use --force to regenerate)");
94 }
95
96 CliService::section("Next Steps");
97 CliService::info("1. systemprompt cloud auth login # Authenticate");
98 CliService::info("2. systemprompt cloud tenant create # Create a tenant");
99 CliService::info("3. systemprompt cloud profile create local # Create a profile");
100
101 Ok(())
102}
103
104fn create_systemprompt_dir(dir: &Path, project_root: &Path) -> Result<()> {
105 std::fs::create_dir_all(dir).context("Failed to create .systemprompt directory")?;
106
107 std::fs::write(dir.join(".gitignore"), GITIGNORE_CONTENT)
108 .context("Failed to create .gitignore")?;
109 CliService::info(" Created .systemprompt/.gitignore");
110
111 std::fs::write(dir.join(".dockerignore"), DOCKERIGNORE_CONTENT)
112 .context("Failed to create .dockerignore")?;
113 CliService::info(" Created .systemprompt/.dockerignore");
114
115 let dockerfile_content = systemprompt_cloud::deploy::generate_dockerfile_content(project_root);
116 std::fs::write(dir.join("Dockerfile"), dockerfile_content)
117 .context("Failed to create Dockerfile")?;
118 CliService::info(" Created .systemprompt/Dockerfile");
119
120 std::fs::write(dir.join("entrypoint.sh"), entrypoint_content())
121 .context("Failed to create entrypoint.sh")?;
122 CliService::info(" Created .systemprompt/entrypoint.sh");
123
124 CliService::success("Created .systemprompt/");
125 Ok(())
126}
127
128pub(super) fn ensure_project_scaffolding(project_root: &Path) -> Result<()> {
129 let services_dir = project_root.join("services");
130 let web_dir = project_root.join("web");
131
132 if services_dir.exists() && web_dir.exists() {
133 return Ok(());
134 }
135
136 let project_name = project_root
137 .file_name()
138 .and_then(|n| n.to_str())
139 .unwrap_or("systemprompt")
140 .to_owned();
141
142 if !services_dir.exists() {
143 CliService::info("Scaffolding services/ directory...");
144 generate_services_boilerplate(project_root, &project_name)?;
145 }
146
147 if !web_dir.exists() {
148 std::fs::create_dir_all(&web_dir)
149 .with_context(|| format!("Failed to create directory: {}", web_dir.display()))?;
150 CliService::info("Created web/ directory");
151 }
152
153 Ok(())
154}