use crate::services::template_service::{generate_template, scaffold_project, validate_template};
use crate::stateless_server::StatelessTemplateServer;
use anyhow::Result;
use serde_json::Value;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::io::AsyncWriteExt;
pub async fn handle_generate(
server: Arc<StatelessTemplateServer>,
category: String,
template: String,
params: Vec<(String, Value)>,
output: Option<PathBuf>,
create_dirs: bool,
) -> Result<()> {
let uri = format!("template://{category}/{template}");
let params_json = super::super::analysis_utilities::params_to_json(params);
let result = generate_template(server.as_ref(), &uri, params_json).await?;
if let Some(path) = output {
if create_dirs {
tokio::fs::create_dir_all(path.parent().unwrap()).await?;
}
tokio::fs::write(&path, &result.content).await?;
eprintln!("✅ Generated: {}", path.display());
} else {
tokio::io::stdout()
.write_all(result.content.as_bytes())
.await?;
}
Ok(())
}
pub async fn handle_scaffold(
server: Arc<StatelessTemplateServer>,
toolchain: String,
templates: Vec<String>,
params: Vec<(String, Value)>,
parallel: usize,
) -> Result<()> {
use futures::stream::{self, StreamExt};
let params_json = super::super::analysis_utilities::params_to_json(params);
let templates_to_use = resolve_scaffold_templates(&toolchain, templates);
let results = scaffold_project(
server.clone(),
&toolchain,
templates_to_use,
serde_json::Value::Object(params_json.clone()),
)
.await?;
if !results.errors.is_empty() {
eprintln!("⚠️ Some templates failed to generate:");
for error in &results.errors {
eprintln!(" - {}: {}", error.template, error.error);
}
}
let file_count = results.files.len();
let write_results: Vec<_> = stream::iter(results.files)
.map(|file| async move {
let path = PathBuf::from(&file.path);
if let Some(parent) = path.parent() {
tokio::fs::create_dir_all(parent).await?;
}
tokio::fs::write(&path, &file.content).await?;
eprintln!("✅ Created: {}", file.path);
Ok::<_, anyhow::Error>(())
})
.buffer_unordered(parallel)
.collect()
.await;
let mut any_failed = false;
for result in write_results {
if let Err(e) = result {
eprintln!("❌ Failed to write file: {e}");
any_failed = true;
}
}
if !any_failed && file_count > 0 {
eprintln!("\n🚀 Project scaffolded successfully!");
} else if file_count == 0 {
eprintln!("\n⚠️ No files were generated. Check your parameters and template availability.");
}
Ok(())
}
fn resolve_scaffold_templates(toolchain: &str, templates: Vec<String>) -> Vec<String> {
if templates.is_empty() {
get_default_scaffold_templates(toolchain)
} else {
templates
}
}
fn get_default_scaffold_templates(toolchain: &str) -> Vec<String> {
match toolchain {
"rust" | "deno" | "python-uv" => vec![
"makefile".to_string(),
"readme".to_string(),
"gitignore".to_string(),
],
_ => vec!["readme".to_string()],
}
}
pub async fn handle_validate(
server: Arc<StatelessTemplateServer>,
uri: String,
params: Vec<(String, Value)>,
) -> Result<()> {
let params_json = super::super::analysis_utilities::params_to_json(params);
let result = validate_template(
server.clone(),
&uri,
&serde_json::Value::Object(params_json),
)
.await?;
if result.valid {
eprintln!("✅ All parameters valid");
} else {
eprintln!("❌ Validation errors:");
for error in result.errors {
eprintln!(" - {}: {}", error.field, error.message);
}
std::process::exit(1);
}
Ok(())
}
pub struct ScaffoldAgentParams {
pub name: String,
pub template: String,
pub features: Vec<String>,
pub quality: String,
pub output: Option<PathBuf>,
pub force: bool,
pub dry_run: bool,
pub interactive: bool,
pub deterministic_core: Option<String>,
pub probabilistic_wrapper: Option<String>,
}
pub async fn handle_scaffold_agent(params: ScaffoldAgentParams) -> Result<()> {
let ScaffoldAgentParams {
name,
template,
features,
quality,
output,
force,
dry_run,
interactive,
deterministic_core,
probabilistic_wrapper,
} = params;
if interactive {
return handle_interactive_scaffold(output, dry_run, force).await;
}
let context = build_agent_context(
&name,
&template,
&features,
&quality,
deterministic_core,
probabilistic_wrapper,
)?;
let output_path = output.unwrap_or_else(|| PathBuf::from(&name));
execute_scaffold_operation(&context, &output_path, &name, dry_run, force).await
}
async fn handle_interactive_scaffold(
output: Option<PathBuf>,
dry_run: bool,
force: bool,
) -> Result<()> {
use crate::scaffold::agent::{scaffold_agent, InteractiveScaffolder};
let mut scaffolder = InteractiveScaffolder::new();
let context = scaffolder.run()?;
let output_path = output.unwrap_or_else(|| PathBuf::from(&context.name));
if dry_run {
eprintln!(
"🔍 Dry run - would generate agent '{}' at {}",
context.name,
output_path.display()
);
return Ok(());
}
validate_output_path(&output_path, force)?;
scaffold_agent(&context, &output_path).await?;
eprintln!(
"✅ Agent '{}' scaffolded successfully at {}",
context.name,
output_path.display()
);
Ok(())
}
fn build_agent_context(
name: &str,
template: &str,
features: &[String],
quality: &str,
deterministic_core: Option<String>,
probabilistic_wrapper: Option<String>,
) -> Result<crate::scaffold::agent::AgentContext> {
use crate::scaffold::agent::AgentContextBuilder;
let mut builder = AgentContextBuilder::new(name, template);
builder = add_features_to_builder(builder, features);
builder = add_quality_level_to_builder(builder, quality);
builder = add_hybrid_specs_to_builder(builder, deterministic_core, probabilistic_wrapper)?;
builder.build()
}
fn add_features_to_builder(
mut builder: crate::scaffold::agent::AgentContextBuilder,
features: &[String],
) -> crate::scaffold::agent::AgentContextBuilder {
use crate::scaffold::agent::AgentFeature;
for feature_str in features {
if let Ok(feature) = feature_str.parse::<AgentFeature>() {
builder = builder.with_feature(feature);
} else {
eprintln!("⚠️ Warning: Unknown feature '{feature_str}', skipping");
}
}
builder
}
fn add_quality_level_to_builder(
builder: crate::scaffold::agent::AgentContextBuilder,
quality: &str,
) -> crate::scaffold::agent::AgentContextBuilder {
use crate::scaffold::agent::QualityLevel;
let quality_level = match quality.to_lowercase().as_str() {
"standard" => QualityLevel::Standard,
"strict" => QualityLevel::Strict,
"extreme" => QualityLevel::Extreme,
_ => {
eprintln!("⚠️ Unknown quality level '{quality}', using 'strict'");
QualityLevel::Strict
}
};
builder.with_quality_level(quality_level)
}
fn add_hybrid_specs_to_builder(
mut builder: crate::scaffold::agent::AgentContextBuilder,
deterministic_core: Option<String>,
probabilistic_wrapper: Option<String>,
) -> Result<crate::scaffold::agent::AgentContextBuilder> {
if let Some(_core_spec) = deterministic_core {
builder = add_deterministic_core_spec(builder)?;
}
if let Some(_wrapper_spec) = probabilistic_wrapper {
builder = add_probabilistic_wrapper_spec(builder)?;
}
Ok(builder)
}
fn add_deterministic_core_spec(
builder: crate::scaffold::agent::AgentContextBuilder,
) -> Result<crate::scaffold::agent::AgentContextBuilder> {
use crate::scaffold::agent::hybrid::{CoreSpec, VerificationMethod};
let core = CoreSpec {
verification_method: VerificationMethod::PropertyTests,
max_complexity: 10,
invariants: Vec::new(),
};
Ok(builder.with_deterministic_core(core))
}
fn add_probabilistic_wrapper_spec(
builder: crate::scaffold::agent::AgentContextBuilder,
) -> Result<crate::scaffold::agent::AgentContextBuilder> {
use crate::scaffold::agent::hybrid::{FallbackStrategy, ModelType, WrapperSpec};
let wrapper = WrapperSpec {
model_type: ModelType::GPT4,
fallback_strategy: FallbackStrategy::Deterministic,
confidence_threshold: 0.95,
};
Ok(builder.with_probabilistic_wrapper(wrapper))
}
fn validate_output_path(output_path: &Path, force: bool) -> Result<()> {
if output_path.exists() && !force {
anyhow::bail!(
"Directory {} already exists. Use --force to overwrite.",
output_path.display()
);
}
Ok(())
}
async fn execute_scaffold_operation(
context: &crate::scaffold::agent::AgentContext,
output_path: &Path,
name: &str,
dry_run: bool,
force: bool,
) -> Result<()> {
use crate::scaffold::agent::scaffold_agent;
if dry_run {
print_dry_run_info(context, output_path);
return Ok(());
}
validate_output_path(output_path, force)?;
scaffold_agent(context, output_path).await?;
eprintln!(
"✅ Agent '{}' scaffolded successfully at {}",
name,
output_path.display()
);
Ok(())
}
fn print_dry_run_info(context: &crate::scaffold::agent::AgentContext, output_path: &Path) {
eprintln!("🔍 Dry run mode - would generate the following:");
eprintln!(" Agent: {}", context.name);
eprintln!(" Template: {:?}", context.template_type);
eprintln!(" Quality: {:?}", context.quality_level);
eprintln!(" Features: {} enabled", context.features.len());
eprintln!(" Output: {}", output_path.display());
}
pub async fn handle_list_agent_templates() -> Result<()> {
use crate::scaffold::agent::TemplateRegistry;
let registry = TemplateRegistry::new();
let templates = registry.list_available();
eprintln!("📦 Available Agent Templates:");
eprintln!();
for template in &templates {
if let Some(info) = registry.get_template_info(template) {
eprintln!(" • {} - {}", info.name, info.description);
}
}
eprintln!();
eprintln!("Total: {} templates available", templates.len());
Ok(())
}
pub async fn handle_validate_agent_template(path: PathBuf) -> Result<()> {
use crate::scaffold::agent::TemplateRegistry;
let registry = TemplateRegistry::new();
eprintln!("🔍 Validating template: {}", path.display());
match registry.validate_template_file(&path) {
Ok(()) => {
eprintln!("✅ Template is valid!");
}
Err(e) => {
eprintln!("❌ Template validation failed:");
eprintln!(" {e}");
let mut source = e.source();
while let Some(err) = source {
eprintln!(" Caused by: {err}");
source = err.source();
}
std::process::exit(1);
}
}
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
fn test_generation_handlers_basic() {
assert_eq!(1 + 1, 2);
}
}
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}