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.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
use anyhow::Result;
use clap::Args as ClapArgs;
/// Kill the running server, rebuild (if --build), restart it on the
/// same port + chip library, and reload the pup browser window.
/// One command replaces the 5-step restart cycle that kept tripping
/// up the AI: kill → build → start → confirm alive → reload browser.
#[derive(ClapArgs)]
pub struct Args {
/// Port (default 8872)
#[arg(long, default_value_t = 8872)]
port: u16,
/// Rebuild before restarting (`cargo build --release` + touch mod.rs)
#[arg(long)]
build: bool,
/// Pup session ID to reload after restart
#[arg(long, default_value = "chipsmith")]
session: String,
/// Max seconds to wait for the server to become healthy
#[arg(long, default_value_t = 30)]
timeout: u32,
}
pub fn run(args: Args) -> Result<()> {
let port = args.port;
// 1. Kill the running server
eprint!("stopping port {}... ", port);
let _ = ureq::post(&format!("http://127.0.0.1:{port}/shutdown"))
.call();
std::thread::sleep(std::time::Duration::from_secs(1));
eprintln!("done");
// 2. Optional rebuild
if args.build {
eprint!("building... ");
// Touch mod.rs to force include_bytes! re-embed of changed assets
let _ = std::fs::File::open("src/server/mod.rs")
.and_then(|f| f.set_modified(std::time::SystemTime::now()).map(|_| f));
let status = std::process::Command::new("cargo")
.args(["build", "--release"])
.status()?;
if !status.success() {
anyhow::bail!("cargo build failed");
}
eprintln!("done");
}
// 3. Read the last-known library dir from the server state (saved
// at /tmp/adom-chipsmith-last-library). Fall back to env var.
let state_file = std::path::PathBuf::from("/tmp/adom-chipsmith-last-library");
let lib_dir = if state_file.exists() {
std::fs::read_to_string(&state_file)?.trim().to_string()
} else if let Ok(d) = std::env::var("CHIPSMITH_LIBRARY") {
d
} else {
anyhow::bail!("no last-known library dir — pass CHIPSMITH_LIBRARY env or run view-library first");
};
// 4. Start the server in background
eprint!("starting on port {} with {}... ", port, lib_dir);
let exe = std::env::current_exe()?;
std::process::Command::new(&exe)
.args(["view-library", "--no-open", "--port", &port.to_string(), &lib_dir])
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn()?;
// 5. Wait for healthy
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(args.timeout as u64);
let url = format!("http://127.0.0.1:{port}/api/paths");
loop {
if std::time::Instant::now() > deadline {
anyhow::bail!("server did not become healthy within {}s", args.timeout);
}
std::thread::sleep(std::time::Duration::from_millis(500));
if ureq::get(&url).call().is_ok() {
break;
}
}
super::ok(format!("server alive on port {port}"));
// 6. Reload the pup browser window
let reload_result = std::process::Command::new("adom-desktop")
.args(["browser_reload", &format!("{{\"sessionId\":\"{}\"}}", args.session)])
.output();
match reload_result {
Ok(o) if o.status.success() => {
super::ok(format!("browser reloaded (session: {})", args.session));
}
_ => {
super::hint(format!("browser reload failed — manually reload session '{}'", args.session));
}
}
// 7. Wait for chipsmith JS to init (poll eval)
let eval_url = format!("http://127.0.0.1:{port}/eval");
let deadline2 = std::time::Instant::now() + std::time::Duration::from_secs(15);
loop {
if std::time::Instant::now() > deadline2 { break; }
std::thread::sleep(std::time::Duration::from_secs(1));
// Can't easily check the browser JS from here — the server's
// /eval endpoint doesn't exist. Just wait a reasonable time.
}
super::ok("restart complete — server + browser reloaded");
Ok(())
}