use std::path::PathBuf;
const SURFACES: &[&str] = &["server_instructions", "onboarding_prompt"];
fn main() {
bake_git_sha();
emit_prompt_surfaces();
}
fn bake_git_sha() {
let sha = std::process::Command::new("git")
.args(["rev-parse", "--short", "HEAD"])
.output()
.ok()
.filter(|o| o.status.success())
.and_then(|o| String::from_utf8(o.stdout).ok())
.map(|s| s.trim().to_string())
.unwrap_or_else(|| "unknown".to_string());
let sha_full = std::process::Command::new("git")
.args(["rev-parse", "HEAD"])
.output()
.ok()
.filter(|o| o.status.success())
.and_then(|o| String::from_utf8(o.stdout).ok())
.map(|s| s.trim().to_string())
.unwrap_or_else(|| "unknown".to_string());
let dirty = std::process::Command::new("git")
.args(["status", "--porcelain"])
.output()
.ok()
.filter(|o| o.status.success())
.map(|o| if o.stdout.is_empty() { "0" } else { "1" })
.unwrap_or("unknown");
println!("cargo:rustc-env=CODESCOUT_GIT_SHA={sha}");
println!("cargo:rustc-env=CODESCOUT_GIT_SHA_FULL={sha_full}");
println!("cargo:rustc-env=CODESCOUT_GIT_DIRTY={dirty}");
println!("cargo:rerun-if-changed=.git/HEAD");
println!("cargo:rerun-if-changed=.git/index");
println!("cargo:rerun-if-changed=.git/refs/heads/");
}
fn emit_prompt_surfaces() {
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let source_path = manifest.join("src/prompts/source.md");
let source = std::fs::read_to_string(&source_path)
.unwrap_or_else(|e| panic!("read {}: {e}", source_path.display()));
let out_dir: PathBuf = std::env::var_os("OUT_DIR")
.expect("OUT_DIR set by cargo")
.into();
for surface in SURFACES {
let content = extract_surface(&source, surface).unwrap_or_else(|| {
panic!(
"surface `{surface}` not found in {} — every entry in build.rs SURFACES \
must have a `<!-- @surface NAME -->` block in source.md",
source_path.display()
)
});
let dest = out_dir.join(format!("{surface}.md"));
std::fs::write(&dest, content).unwrap_or_else(|e| panic!("write {}: {e}", dest.display()));
}
println!("cargo:rerun-if-changed=src/prompts/source.md");
println!("cargo:rerun-if-changed=build.rs");
}
fn extract_surface<'a>(source: &'a str, surface: &str) -> Option<&'a str> {
let open = format!("<!-- @surface {surface} -->");
let marker_end = source.find(&open)? + open.len();
let bytes = source.as_bytes();
let mut start = marker_end;
if bytes.get(start) == Some(&b'\r') {
start += 1;
}
if bytes.get(start) == Some(&b'\n') {
start += 1;
}
let rest = &source[start..];
let end_offset = rest.find("<!-- @end -->")?;
Some(&rest[..end_offset])
}