agentstatedeveloper_cli/commands/trust.rs
1//! `asd trust` — emit the State Trust Score for the current workspace.
2//!
3//! Quick machine-readable answer to: "Can I rely on ASD for this task?"
4//!
5//! # Output (JSON)
6//!
7//! ```json
8//! {
9//! "score": 0.92,
10//! "level": "high",
11//! "reasons": ["fresh_index", "ledger_annotated", "sidecar_hydrated"],
12//! "blocking": false,
13//! "signals": { ... }
14//! }
15//! ```
16//!
17//! Exit code is 0 unless `--fail-blocked` is set and `blocking` is true.
18
19use anyhow::Result;
20use clap::Args;
21
22use agentstatedeveloper_core::compute_trust_score;
23
24use crate::config::Config;
25
26#[derive(Debug, Args)]
27pub struct TrustArgs {
28 /// Exit 1 when the trust score is in the "blocked" level.
29 /// Useful for CI pre-flight checks before expensive agent runs.
30 #[arg(long)]
31 pub fail_blocked: bool,
32
33 /// Suppress the human-readable summary and emit only the JSON object.
34 /// (JSON is always emitted; this suppresses the extra narrative line.)
35 #[arg(long)]
36 pub quiet: bool,
37}
38
39pub fn run(cfg: &Config, args: TrustArgs) -> Result<()> {
40 let trust = compute_trust_score(&cfg.db_path);
41
42 let json_str = serde_json::to_string_pretty(&trust.to_json())?;
43 println!("{json_str}");
44
45 if !args.quiet {
46 eprintln!(
47 "asd trust: {} ({:.0}%) — {}",
48 trust.level.to_uppercase(),
49 trust.score * 100.0,
50 trust.reasons.join(", ")
51 );
52 }
53
54 if args.fail_blocked && trust.blocking {
55 std::process::exit(1);
56 }
57
58 Ok(())
59}