app
Adom Chipsmith
Public Made by Adomby adom
STEP-native chip validator — 5-source cross-validation, OCCT-generated copyright-free 3D models with embedded signal annotations, datasheet-to-STEP pipeline.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
//! `adom-chipsmith detect <chip-fetcher-dir>` — run detection headlessly and
//! print a JSON report. Boots a transient server in --no-open mode, drives
//! the JS detection pipeline via /eval, then reports + shuts down. Useful
//! for batch validation across an entire chip-fetcher library.
use crate::cli::{err, ok, DEFAULT_PORT};
use crate::server::{self, convert, ServerConfig, ServerState};
use anyhow::{anyhow, Result};
use clap::Parser;
use std::path::PathBuf;
use std::time::Duration;
#[derive(Parser)]
pub struct Args {
/// Path to a chip-fetcher library directory.
pub dir: PathBuf,
/// Print JSON instead of human text.
#[arg(long)]
pub json: bool,
/// Port to bind during the headless run.
#[arg(long, default_value_t = DEFAULT_PORT)]
pub port: u16,
}
pub fn run(args: Args) -> Result<()> {
if !args.dir.is_dir() {
return Err(anyhow!("not a directory: {}", args.dir.display()));
}
let mpn = args.dir.file_name()
.and_then(|s| s.to_str())
.ok_or_else(|| anyhow!("can't derive MPN from dir: {}", args.dir.display()))?
.to_string();
let mut step_path = args.dir.join(format!("{mpn}.step"));
if !step_path.exists() { step_path = args.dir.join(format!("{mpn}.STEP")); }
if !step_path.exists() {
return Err(anyhow!("no .step file in {}", args.dir.display()));
}
let step_bytes = std::fs::read(&step_path).map_err(|e| anyhow!("read STEP: {e}"))?;
let result = convert::convert_step_bytes(&step_bytes)
.map_err(|e| anyhow!("conversion failed: {e}"))?;
let config = ServerConfig {
port: args.port,
initial_glb_path: Some(result.glb_path.clone()),
initial_source_label: Some(format!("{mpn}.step")),
initial_source_type: Some("chip-fetcher".to_string()),
};
let state = ServerState::new(config);
// Seed spec + footprint from the dir
let info_path = args.dir.join("info.json");
if info_path.exists() {
if let Ok(s) = std::fs::read_to_string(&info_path) {
if let Ok(v) = serde_json::from_str::<serde_json::Value>(&s) {
*state.spec.lock().unwrap() = v;
}
}
}
*state.signoff_dir.lock().unwrap() = Some(args.dir.clone());
*state.source_step_path.lock().unwrap() = Some(step_path.clone());
// Spawn server thread
let server_state = state.clone();
std::thread::spawn(move || {
let _ = server::run(server_state);
});
// Headless detection requires a JS context — for now, we report what the
// Rust side knows: GLB stats + spec + footprint pad count. Full live
// detection requires a webview running the JS. Future: bake detection
// into Rust once /step-meta delivers the structured B-rep.
std::thread::sleep(Duration::from_millis(800));
let spec = state.spec.lock().unwrap().clone();
let report = serde_json::json!({
"mpn": mpn,
"source": format!("{mpn}.step"),
"step_size_kb": step_bytes.len() / 1024,
"glb_size_kb": result.size_bytes / 1024,
"glb_meshes": result.meshes,
"glb_nodes": result.nodes,
"glb_cache_hit": result.cache_hit,
"spec": spec,
"step_meta_available": match convert::fetch_step_meta(&step_bytes) {
Ok(Some(_)) => true,
_ => false,
},
"headless_detect_status": "stub — full detection requires live webview; loads STEP + caches GLB + checks /step-meta availability",
});
if args.json {
println!("{}", serde_json::to_string_pretty(&report).unwrap());
} else {
ok(format!("MPN: {mpn}"));
ok(format!("STEP: {} KB → GLB: {} KB ({})", step_bytes.len() / 1024, result.size_bytes / 1024, if result.cache_hit { "cached" } else { "fresh" }));
if let Some(p) = spec.get("package_family") {
ok(format!("package: {p}"));
}
if let Some(p) = spec.get("pin_count") {
ok(format!("pin count: {p}"));
}
let step_meta_ok = match convert::fetch_step_meta(&step_bytes) {
Ok(Some(_)) => "yes",
Ok(None) => "no (service-step2glb /step-meta not deployed)",
Err(e) => { let _ = e; "error" }
};
ok(format!("step-meta available: {step_meta_ok}"));
}
Ok(())
}