1use anyhow::Result;
7#[cfg(feature = "api")]
8use axum::{
9 extract::{Json, State},
10 http::StatusCode,
11 response::IntoResponse,
12 routing::post,
13 Router,
14};
15use serde::{Deserialize, Serialize};
16use std::path::PathBuf;
17#[cfg(feature = "api")]
18use tower_http::cors::CorsLayer;
19
20use crate::unified_pipeline::analyze_repository;
21
22#[derive(Debug, Clone, Deserialize)]
23pub struct AnalyzeRequest {
24 pub repo_path: String,
26 pub s3_bucket: String,
28 pub s3_key: String,
30 pub workers: Option<usize>,
32}
33
34#[derive(Debug, Clone, Serialize)]
35pub struct AnalyzeResponse {
36 pub s3_url: String,
38 pub summary: String,
40}
41
42#[derive(Clone)]
43pub struct ApiState {
44 llm_api_key: String,
45}
46
47#[cfg(feature = "api")]
48pub async fn create_api_router(llm_api_key: String) -> axum::Router {
49 let state = ApiState { llm_api_key };
50
51 Router::new()
52 .route("/analyze", post(analyze_handler))
53 .layer(CorsLayer::permissive())
54 .with_state(state)
55}
56
57#[cfg(feature = "api")]
58async fn analyze_handler(
59 State(state): State<ApiState>,
60 Json(request): Json<AnalyzeRequest>,
61) -> impl IntoResponse {
62 let repo_path = PathBuf::from(&request.repo_path);
63
64 if !repo_path.exists() {
65 return (
66 StatusCode::BAD_REQUEST,
67 Json(serde_json::json!({
68 "error": "Repository path does not exist"
69 })),
70 )
71 .into_response();
72 }
73
74 match analyze_repository(
75 &repo_path,
76 &request.s3_bucket,
77 &request.s3_key,
78 state.llm_api_key.clone(),
79 request.workers,
80 )
81 .await
82 {
83 Ok(s3_url) => {
84 let response = AnalyzeResponse {
85 s3_url: s3_url.clone(),
86 summary: format!(
87 "Successfully analyzed {} and published first-principles instructions to {}",
88 request.repo_path, s3_url
89 ),
90 };
91 (StatusCode::OK, Json(response)).into_response()
92 }
93 Err(e) => (
94 StatusCode::INTERNAL_SERVER_ERROR,
95 Json(serde_json::json!({
96 "error": format!("Analysis failed: {}", e)
97 })),
98 )
99 .into_response(),
100 }
101}
102
103pub async fn run_cli_analysis(
105 repo_path: &str,
106 s3_bucket: &str,
107 s3_key: &str,
108 llm_api_key: &str,
109) -> Result<()> {
110 std::env::set_var("RUST_LOG", "concept_analyzer=info");
112 env_logger::init();
113
114 println!("\nšÆ CONCEPT ANALYZER - First Principles Extractor");
115 println!("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā");
116 println!("\nThis tool will:");
117 println!(" 1. Scan your repository for source files");
118 println!(" 2. Extract high-level concepts using AI");
119 println!(" 3. Analyze relationships between concepts");
120 println!(" 4. Identify critical gaps in functionality");
121 println!(" 5. Generate rebuild instructions from first principles");
122 println!(" 6. Publish results to S3 for agent consumption");
123 println!("\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā");
124
125 let s3_url = analyze_repository(
126 &PathBuf::from(repo_path),
127 s3_bucket,
128 s3_key,
129 llm_api_key.to_string(),
130 None,
131 )
132 .await?;
133
134 println!("\n\nš SUCCESS! Your first-principles blueprint is ready!");
135 println!("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā");
136 println!("\nš Output Summary:");
137 println!(" ā Essential concepts extracted");
138 println!(" ā Core relationships mapped");
139 println!(" ā Build order optimized");
140 println!(" ā Critical gaps identified");
141 println!(" ā Rebuild instructions generated");
142 println!("\nš Location: {}", s3_url);
143 println!("\nš” An AI agent can now use this blueprint to:");
144 println!(" ⢠Understand the system's core purpose");
145 println!(" ⢠Rebuild it from scratch");
146 println!(" ⢠Fill in the identified gaps");
147 println!(" ⢠Maintain architectural consistency");
148 println!("\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
149
150 Ok(())
151}