cortex_runtime/cli/
compile_cmd.rs1use crate::cli::output;
4use crate::compiler::{codegen, schema};
5use crate::intelligence::cache::MapCache;
6use anyhow::{bail, Result};
7use std::path::PathBuf;
8
9pub async fn run(domain: &str, _all: bool, output_dir: Option<&str>) -> Result<()> {
11 let mut cache = MapCache::default_cache()?;
13 let site_map = match cache.load_map(domain)? {
14 Some(map) => map,
15 None => bail!("no cached map for '{domain}'. Run `cortex map {domain}` first."),
16 };
17
18 if !output::is_quiet() {
19 println!(" Compiling {domain}...\n");
20 println!(
21 " Analyzing map ({} nodes)...\n",
22 site_map.header.node_count
23 );
24 }
25
26 let compiled = schema::infer_schema(&site_map, domain);
28
29 if !output::is_quiet() {
30 println!(" Models:");
31 for model in &compiled.models {
32 println!(
33 " {:<16} {:>6} instances {:>2} fields {:>2} actions",
34 model.name,
35 model.instance_count,
36 model.fields.len(),
37 compiled
38 .actions
39 .iter()
40 .filter(|a| a.belongs_to == model.name)
41 .count()
42 );
43 }
44 println!();
45 }
46
47 if !compiled.relationships.is_empty() && !output::is_quiet() {
48 println!(" Relationships:");
49 for rel in &compiled.relationships {
50 println!(
51 " {} → {:<16} {:>12} {:>6} edges",
52 rel.from_model,
53 rel.to_model,
54 format!("{:?}", rel.cardinality).to_lowercase(),
55 rel.edge_count
56 );
57 }
58 println!();
59 }
60
61 let out_dir = if let Some(dir) = output_dir {
63 PathBuf::from(dir)
64 } else {
65 let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
66 home.join(".cortex").join("compiled").join(domain)
67 };
68
69 let files = codegen::generate_all(&compiled, &out_dir)?;
71
72 if !output::is_quiet() {
73 println!(" Generated:");
74 println!(" {}/", out_dir.display());
75 for file in &files.files {
76 println!(" ├── {:<24} {:>5} B", file.filename, file.size);
77 }
78 println!();
79 println!(" Usage:");
80
81 let domain_safe = domain.replace(['.', '-'], "_");
82 println!(" Python: from cortex.compiled.{domain_safe} import Product, Cart");
83 println!(
84 " TypeScript: import {{ searchProducts }} from '{}'",
85 out_dir.join("client").display()
86 );
87 println!(" OpenAPI: Point any REST client at the spec");
88 println!(" GraphQL: cortex graphql {domain} --port 7701");
89 }
90
91 if output::is_json() {
92 output::print_json(&serde_json::json!({
93 "domain": domain,
94 "models": compiled.stats.total_models,
95 "fields": compiled.stats.total_fields,
96 "actions": compiled.actions.len(),
97 "relationships": compiled.relationships.len(),
98 "output_dir": out_dir.display().to_string(),
99 }));
100 }
101
102 Ok(())
103}