1use std::env;
12use std::path::PathBuf;
13use std::process::Command;
14use context_bar::context_engine;
15use context_bar::git_signal::{
16 self, ChangeSummary, CommitSummary, GitSignals,
17};
18use context_bar::state_writer;
19
20fn main() {
21 if let Err(error) = run() {
22 eprintln!("snapshot failed: {error}");
23 std::process::exit(1);
24 }
25}
26
27fn run() -> Result<(), String> {
28 let root = env::args()
29 .nth(1)
30 .map(PathBuf::from)
31 .unwrap_or_else(|| env::current_dir().expect("cwd"));
32 let root = root
33 .canonicalize()
34 .map_err(|error| format!("cannot canonicalize {}: {error}", root.display()))?;
35
36 let git = collect_git(&root)?;
37 let files = context_engine::collect_files(&root)?;
38 let snapshot = context_engine::assemble(root.clone(), git, files)?;
39 let result = state_writer::write(&root, &snapshot)?;
40
41 println!("Wrote:");
42 println!(" {}", result.state_path.display());
43 println!(" {}", result.now_brief_path.display());
44 println!(" {}", result.session_brief_path.display());
45 println!(" {}", result.week_brief_path.display());
46 println!(" {} <- primary agent surface", result.agent_brief_path.display());
47 println!(" {} <- Claude Code surface", result.claude_brief_path.display());
48 Ok(())
49}
50
51fn collect_git(root: &PathBuf) -> Result<GitSignals, String> {
52 let branch = run_git(root, &["rev-parse", "--abbrev-ref", "HEAD"])?
53 .trim()
54 .to_string();
55 let log = run_git(
56 root,
57 &["log", "--since=7 days ago", "--max-count=40", "--format=%H%x09%ct%x09%s"],
58 )?;
59 let recent_commits: Vec<CommitSummary> = git_signal::parse_commits(&log);
60 let status = run_git(root, &["status", "--short"])?;
61 let (staged, unstaged): (Vec<ChangeSummary>, Vec<ChangeSummary>) =
62 git_signal::parse_status_public(&status);
63 let clean = staged.is_empty() && unstaged.is_empty();
64 Ok(GitSignals {
65 branch,
66 recent_commits,
67 staged_changes: staged,
68 unstaged_changes: unstaged,
69 clean_worktree: clean,
70 })
71}
72
73fn run_git(root: &PathBuf, args: &[&str]) -> Result<String, String> {
74 let output = Command::new("git")
75 .arg("-C")
76 .arg(root)
77 .args(args)
78 .output()
79 .map_err(|error| format!("git spawn failed: {error}"))?;
80 if !output.status.success() {
81 return Err(format!(
82 "git {:?} failed: {}",
83 args,
84 String::from_utf8_lossy(&output.stderr).trim()
85 ));
86 }
87 String::from_utf8(output.stdout).map_err(|error| format!("git utf8: {error}"))
88}