diff --git a/walletkit-cli/src/commands/mod.rs b/walletkit-cli/src/commands/mod.rs index dcbb2ef7..81c7461b 100644 --- a/walletkit-cli/src/commands/mod.rs +++ b/walletkit-cli/src/commands/mod.rs @@ -3,6 +3,7 @@ mod auth; mod credential; mod proof; +mod recovery_agent; mod wallet; use std::path::PathBuf; @@ -97,6 +98,12 @@ pub enum Command { #[command(subcommand)] action: proof::ProofCommand, }, + /// Recovery agent management (initiate, execute, cancel updates). + #[command(name = "recovery-agent-update")] + RecoveryAgent { + #[command(subcommand)] + action: recovery_agent::RecoveryAgentCommand, + }, } /// Resolves the wallet root directory, defaulting to `~/.walletkit`. @@ -232,5 +239,6 @@ pub async fn run(cli: Cli) -> eyre::Result<()> { Command::Auth { action } => auth::run(&cli, action).await, Command::Credential { action } => credential::run(&cli, action).await, Command::Proof { action } => proof::run(&cli, action).await, + Command::RecoveryAgent { action } => recovery_agent::run(&cli, action).await, } } diff --git a/walletkit-cli/src/commands/recovery_agent.rs b/walletkit-cli/src/commands/recovery_agent.rs new file mode 100644 index 00000000..05b74d71 --- /dev/null +++ b/walletkit-cli/src/commands/recovery_agent.rs @@ -0,0 +1,69 @@ +//! `walletkit recovery-agent` subcommands — recovery agent management. + +use clap::Subcommand; +use eyre::WrapErr as _; + +use crate::output; + +use super::{init_authenticator, Cli}; + +#[derive(Subcommand)] +pub enum RecoveryAgentCommand { + /// Initiate a time-locked recovery agent update (14-day cooldown). + Initiate { + /// Checksummed hex address of the new recovery agent (e.g. "0x1234…"). + new_recovery_agent: String, + }, + /// Execute a pending recovery agent update after the cooldown has elapsed. + Execute, + /// Cancel a pending recovery agent update before the cooldown expires. + Cancel, +} + +pub async fn run(cli: &Cli, action: &RecoveryAgentCommand) -> eyre::Result<()> { + let (authenticator, _store) = init_authenticator(cli).await?; + + match action { + RecoveryAgentCommand::Initiate { new_recovery_agent } => { + let request_id = authenticator + .initiate_recovery_agent_update(new_recovery_agent.clone()) + .await + .wrap_err("initiate recovery agent update failed")?; + + let data = serde_json::json!({ "request_id": request_id }); + if cli.json { + output::print_json_data(&data, true); + } else { + println!("Recovery agent update initiated. Request ID: {request_id}"); + } + } + RecoveryAgentCommand::Execute => { + let request_id = authenticator + .execute_recovery_agent_update() + .await + .wrap_err("execute recovery agent update failed")?; + + let data = serde_json::json!({ "request_id": request_id }); + if cli.json { + output::print_json_data(&data, true); + } else { + println!("Recovery agent update executed. Request ID: {request_id}"); + } + } + RecoveryAgentCommand::Cancel => { + let request_id = authenticator + .cancel_recovery_agent_update() + .await + .wrap_err("cancel recovery agent update failed")?; + + let data = serde_json::json!({ "request_id": request_id }); + if cli.json { + output::print_json_data(&data, true); + } else { + println!("Recovery agent update cancelled. Request ID: {request_id}"); + } + } + } + + Ok(()) +}