use async_trait::async_trait; use crate::governed::command_trait::*; use crate::governed::session::{GovernedSession, Governed}; pub struct HistoryCommand; #[async_trait] impl ShellCommand for HistoryCommand { fn name(&self) -> &str { "history" } fn tier(&self) -> CommandTier { CommandTier::Analyst } fn required_scope(&self) -> RequiredScope { RequiredScope::ReadOnly } fn description(&self) -> &str { "Show mutation history for a registry" } fn usage(&self) -> &str { "history [artifact_id]" } async fn execute( &self, args: &[String], session: &mut GovernedSession, ) -> Result { if session.tenant_context().is_none() { return Err(CommandError::NoTenantContext); } if args.is_empty() { return Err(CommandError::InvalidArgs( "Usage: history [artifact_id]".to_string(), )); } let registry = &args[0]; let artifact_id = args.get(1); // Phase 1: stub — shows placeholder history. let scope = if let Some(id) = artifact_id { format!("{}:{}", registry, id) } else { registry.clone() }; let lines = vec![ OutputLine::Text(format!("Mutation history for: {}", scope)), OutputLine::Table { headers: vec![ "TIMESTAMP".to_string(), "VERB".to_string(), "ACTOR".to_string(), "CEREMONY".to_string(), ], rows: vec![ vec!["(no history loaded)".to_string(), "-".to_string(), "-".to_string(), "-".to_string()], ], }, ]; Ok(CommandOutput { lines }) } }