use std::path::PathBuf;
use clap::Subcommand;
use khive_changeset::Envelope;
use serde::Serialize;
#[derive(Subcommand, Debug)]
pub enum KgCommand {
Validate(ValidateArgs),
Init(InitArgs),
#[command(visible_alias = "sync")]
Fetch(FetchArgs),
Export(ExportArgs),
Import(ImportArgs),
Status(StatusArgs),
#[command(subcommand)]
Hook(HookCommand),
Commit(CommitArgs),
Review(ReviewArgs),
}
#[derive(clap::Parser, Debug)]
pub struct ValidateArgs {
#[arg(long, default_value = ".")]
pub repo: PathBuf,
#[arg(long)]
pub fix: bool,
#[arg(long)]
pub strict: bool,
#[arg(long, default_value = "text")]
pub format: OutputFormat,
#[arg(long)]
pub verbose: bool,
#[arg(long)]
pub quiet: bool,
#[arg(long)]
pub rules: Option<PathBuf>,
#[arg(long)]
pub no_rules: bool,
}
#[derive(clap::ValueEnum, Debug, Clone, Copy)]
pub enum OutputFormat {
Text,
Json,
Github,
}
impl std::fmt::Display for OutputFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
OutputFormat::Text => write!(f, "text"),
OutputFormat::Json => write!(f, "json"),
OutputFormat::Github => write!(f, "github"),
}
}
}
#[derive(clap::Parser, Debug)]
pub struct InitArgs {
#[arg(long, default_value = ".")]
pub repo: PathBuf,
#[arg(long)]
pub ci: bool,
#[arg(long)]
pub add_hooks: bool,
}
#[derive(clap::Parser, Debug)]
pub struct FetchArgs {
pub remote: String,
#[arg(long, default_value = ".")]
pub repo: PathBuf,
#[arg(long)]
pub url: String,
#[arg(long = "ref", default_value = "main")]
pub git_ref: String,
#[arg(long, default_value = "local")]
pub namespace: String,
#[arg(long)]
pub pin: Option<String>,
#[arg(long)]
pub repin: bool,
}
#[derive(clap::Parser, Debug)]
pub struct ExportArgs {
pub output: PathBuf,
#[arg(long)]
pub db: PathBuf,
#[arg(long, default_value = "local")]
pub namespace: String,
}
#[derive(clap::Parser, Debug)]
pub struct ImportArgs {
pub source: PathBuf,
#[arg(long)]
pub db: PathBuf,
#[arg(long, default_value = "local")]
pub namespace: String,
#[arg(long, value_enum, default_value_t = ImportFormat::Archive)]
pub format: ImportFormat,
#[arg(long)]
pub verbose: bool,
}
#[derive(clap::ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ImportFormat {
Archive,
Json,
Ndjson,
}
#[derive(clap::Parser, Debug)]
pub struct StatusArgs {
#[arg(long, default_value = ".")]
pub repo: PathBuf,
#[arg(long)]
pub db: PathBuf,
#[arg(long, default_value = "local")]
pub namespace: String,
}
#[derive(clap::Parser, Debug)]
pub struct CommitArgs {
pub changeset: PathBuf,
#[arg(long)]
pub rules: PathBuf,
#[arg(long, default_value = ".")]
pub repo: PathBuf,
#[arg(short = 'm', long = "message")]
pub message: String,
#[arg(long, default_value = "text")]
pub format: OutputFormat,
}
#[derive(clap::Parser, Debug)]
pub struct ReviewArgs {
pub changeset: PathBuf,
#[arg(long)]
pub rules: PathBuf,
#[arg(long)]
pub reviewer_model_family: Option<String>,
#[arg(long, default_value = "text")]
pub format: OutputFormat,
}
#[derive(Debug, Serialize)]
pub struct CommitReport {
pub commit_sha: String,
pub changeset_path: String,
pub ops: usize,
pub producer: String,
pub producer_batch: String,
}
#[derive(Debug, Serialize)]
pub struct ReviewReport {
pub schema_version: &'static str,
pub review_kind: &'static str,
pub capability: ReviewCapability,
pub change_set: ReviewChangeSet,
pub tier_summary: ReviewTierSummary,
pub validation: ReviewValidationSummary,
pub findings: Vec<ReviewFinding>,
pub review_gate: ReviewGate,
}
#[derive(Debug, Serialize)]
pub struct ReviewChangeSet {
pub envelope: Envelope,
pub operations: Vec<ReviewOperation>,
}
#[derive(Debug, Serialize)]
pub struct ReviewOperation {
pub index: usize,
pub id: String,
pub op: String,
pub target: String,
pub tier: String,
pub summary: String,
pub reason: String,
pub tier_reasons: Vec<String>,
pub entity_ids: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub before: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after: Option<serde_json::Value>,
}
#[derive(Debug, Serialize)]
pub struct ReviewTierSummary {
pub operations: usize,
pub tier_1: usize,
pub tier_2: usize,
pub highest_tier: String,
pub requires_independent_review: bool,
pub policy: &'static str,
}
#[derive(Debug, Serialize)]
pub struct ReviewFinding {
pub rule_id: String,
pub severity: String,
pub message: String,
pub subject_id: Option<String>,
pub subject_name: Option<String>,
pub subject_kind: Option<String>,
pub fixable: bool,
}
#[derive(Debug, Serialize)]
pub struct ReviewValidationSummary {
pub scope: &'static str,
pub rules_evaluated: usize,
pub failed_rules: usize,
pub errors: usize,
pub warnings: usize,
pub info: usize,
pub passed: bool,
}
#[derive(Debug, Serialize)]
pub struct ReviewGate {
pub required: bool,
pub producer_model_family: String,
pub reviewer_model_family: Option<String>,
pub eligible: bool,
pub approval_ready: bool,
pub status: String,
pub reason: String,
pub persisted: bool,
}
#[derive(Debug, Serialize)]
pub struct ReviewCapability {
pub source: &'static str,
pub mutability: &'static str,
pub no_writes: bool,
pub git_reads: bool,
pub khive_reads: bool,
pub github_writes: bool,
pub wasm: bool,
pub persistence: bool,
pub unavailable_actions: [&'static str; 5],
}
#[derive(Subcommand, Debug)]
pub enum HookCommand {
Install {
#[arg(long, default_value = ".")]
repo: PathBuf,
},
Uninstall {
#[arg(long, default_value = ".")]
repo: PathBuf,
},
Status {
#[arg(long, default_value = ".")]
repo: PathBuf,
},
}
#[derive(Debug, Serialize)]
pub struct KgStatusReport {
pub db_hash: String,
pub ndjson_hash: String,
pub clean: bool,
}
#[derive(Debug, Serialize)]
pub struct ValidationReport {
pub rules: Vec<RuleResult>,
pub summary: ValidationSummary,
}
#[derive(Debug, Serialize)]
pub struct RuleResult {
pub id: String,
pub severity: &'static str,
pub passed: bool,
pub violations: Vec<Violation>,
}
#[derive(Debug, Serialize)]
pub struct Violation {
pub entity_id: Option<String>,
pub entity_name: Option<String>,
pub entity_kind: Option<String>,
pub rule_id: String,
pub severity: &'static str,
pub message: String,
pub fixable: bool,
}
#[derive(Debug, Serialize)]
pub struct ValidationSummary {
pub errors: usize,
pub warnings: usize,
pub info: usize,
pub entities: usize,
pub edges: usize,
pub empty: bool,
pub passed: bool,
}
#[derive(Debug, Serialize)]
pub struct HookStatus {
pub symlink_exists: bool,
pub symlink_target: Option<String>,
pub target_valid: bool,
}