Skip to main content

spec_driven_docs/commands/
ki.rs

1//! `ki` subcommand: runtime-shape.
2//!
3//! Resolves the target, asks the known-issues service, and renders text or
4//! JSON. The listing is a report: a record stating no axis is listed with
5//! the value missing, because judging it belongs to `ki-state` and
6//! `ki-filing`.
7
8use crate::cli::ki::{KiArgs, KiCommand, ListArgs};
9use crate::context::AppContext;
10use crate::error::AppError;
11use crate::output;
12use crate::services::known_issues::cases;
13
14/// Run one `sdd ki` verb.
15///
16/// # Errors
17///
18/// [`AppError::Usage`] when the target is neither absolute nor `.`, and
19/// [`AppError::Io`] when a record cannot be read.
20pub fn run(ctx: &AppContext, args: KiArgs) -> Result<(), AppError> {
21    match args.command {
22        KiCommand::List(args) => list(ctx, args),
23    }
24}
25
26fn list(ctx: &AppContext, args: ListArgs) -> Result<(), AppError> {
27    let target = if args.target.is_absolute() {
28        args.target
29    } else if args.target == "." {
30        ctx.cwd.clone()
31    } else {
32        return Err(AppError::Usage("target must be absolute or .".to_string()));
33    };
34    if !target.is_dir() {
35        return Err(AppError::Usage(format!("no directory at {target}")));
36    }
37    let cases = cases(&target)?;
38    if args.json {
39        return output::json(&cases);
40    }
41    let width = cases.iter().map(|case| case.id.len()).max().unwrap_or(0);
42    for case in &cases {
43        output::line(format!(
44            "{:width$}  {:<13}  {:<10}  {:<9}  {}",
45            case.id,
46            case.state.as_deref().unwrap_or("-"),
47            case.checked.as_deref().unwrap_or("-"),
48            case.filing.as_deref().unwrap_or("-"),
49            case.upstream.as_deref().unwrap_or("-"),
50        ));
51    }
52    Ok(())
53}