From 055e2c4a72e3b2331a18fdc9f8132ef990af7e38 Mon Sep 17 00:00:00 2001 From: soryu Date: Tue, 20 Jan 2026 17:23:34 +0000 Subject: Update CLI to show log history as well --- makima/src/daemon/cli/config.rs | 128 ++++++++++++++++++++++++++++++++++++++++ makima/src/daemon/cli/mod.rs | 29 +++++++++ makima/src/daemon/cli/view.rs | 10 +++- 3 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 makima/src/daemon/cli/config.rs (limited to 'makima/src/daemon/cli') diff --git a/makima/src/daemon/cli/config.rs b/makima/src/daemon/cli/config.rs new file mode 100644 index 0000000..8199b88 --- /dev/null +++ b/makima/src/daemon/cli/config.rs @@ -0,0 +1,128 @@ +//! CLI configuration management. +//! +//! Handles loading and saving CLI configuration from ~/.makima/config.toml. +//! This is separate from daemon configuration and is used for interactive CLI commands. + +use clap::Args; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::path::PathBuf; + +/// Arguments for setting the API key +#[derive(Args, Debug, Clone)] +pub struct SetKeyArgs { + /// The API key to save + pub api_key: String, +} + +/// Arguments for setting the API URL +#[derive(Args, Debug, Clone)] +pub struct SetUrlArgs { + /// The API URL to save + pub api_url: String, +} + +/// CLI configuration stored in ~/.makima/config.toml +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct CliConfig { + /// API URL for the makima server + #[serde(default = "default_api_url")] + pub api_url: String, + + /// API key for authentication + #[serde(default)] + pub api_key: Option, +} + +fn default_api_url() -> String { + "https://api.makima.jp".to_string() +} + +impl CliConfig { + /// Get the config directory path (~/.makima) + pub fn config_dir() -> Option { + dirs::home_dir().map(|h| h.join(".makima")) + } + + /// Get the config file path (~/.makima/config.toml) + pub fn config_path() -> Option { + Self::config_dir().map(|d| d.join("config.toml")) + } + + /// Load CLI config from ~/.makima/config.toml + /// Returns default config if file doesn't exist + pub fn load() -> Self { + let Some(path) = Self::config_path() else { + return Self::default(); + }; + + if !path.exists() { + return Self::default(); + } + + match fs::read_to_string(&path) { + Ok(contents) => { + toml::from_str(&contents).unwrap_or_else(|e| { + eprintln!("Warning: Failed to parse {}: {}", path.display(), e); + Self::default() + }) + } + Err(e) => { + eprintln!("Warning: Failed to read {}: {}", path.display(), e); + Self::default() + } + } + } + + /// Save CLI config to ~/.makima/config.toml + pub fn save(&self) -> Result<(), Box> { + let Some(dir) = Self::config_dir() else { + return Err("Could not determine home directory".into()); + }; + + let Some(path) = Self::config_path() else { + return Err("Could not determine config path".into()); + }; + + // Create config directory if it doesn't exist + if !dir.exists() { + fs::create_dir_all(&dir)?; + } + + let contents = toml::to_string_pretty(self) + .map_err(|e| format!("Failed to serialize config: {}", e))?; + fs::write(&path, contents)?; + + Ok(()) + } + + /// Get API key, preferring environment variable over config file + pub fn get_api_key(&self) -> Option { + // Environment variable takes precedence + if let Ok(key) = std::env::var("MAKIMA_API_KEY") { + if !key.is_empty() { + return Some(key); + } + } + + // Fall back to config file + self.api_key.clone() + } + + /// Get API URL, preferring environment variable over config file + pub fn get_api_url(&self) -> String { + // Environment variable takes precedence + if let Ok(url) = std::env::var("MAKIMA_API_URL") { + if !url.is_empty() { + return url; + } + } + + // Fall back to config file, or default if empty + if self.api_url.is_empty() { + default_api_url() + } else { + self.api_url.clone() + } + } +} diff --git a/makima/src/daemon/cli/mod.rs b/makima/src/daemon/cli/mod.rs index 3394b35..216f281 100644 --- a/makima/src/daemon/cli/mod.rs +++ b/makima/src/daemon/cli/mod.rs @@ -1,5 +1,6 @@ //! Command-line interface for the makima CLI. +pub mod config; pub mod contract; pub mod daemon; pub mod server; @@ -8,6 +9,7 @@ pub mod view; use clap::{Parser, Subcommand}; +pub use config::CliConfig; pub use contract::ContractArgs; pub use daemon::DaemonArgs; pub use server::ServerArgs; @@ -48,7 +50,34 @@ pub enum Commands { /// ↑/k: Move up ↓/j: Move down Enter/l: Drill in /// Esc/h: Go back /: Search q: Quit /// e: Edit d: Delete c: cd to worktree + /// n: New contract View(ViewArgs), + + /// Configure CLI settings (API key, server URL) + /// + /// Saves configuration to ~/.makima/config.toml for use by CLI commands. + #[command(subcommand)] + Config(ConfigCommand), +} + +/// Config subcommands for CLI configuration. +#[derive(Subcommand, Debug)] +pub enum ConfigCommand { + /// Set the API key + /// + /// Saves the API key to ~/.makima/config.toml + SetKey(config::SetKeyArgs), + + /// Set the API URL + /// + /// Saves the API URL to ~/.makima/config.toml + SetUrl(config::SetUrlArgs), + + /// Show current configuration + Show, + + /// Show the config file path + Path, } /// Supervisor subcommands for contract orchestration. diff --git a/makima/src/daemon/cli/view.rs b/makima/src/daemon/cli/view.rs index b5b516f..b9fa82f 100644 --- a/makima/src/daemon/cli/view.rs +++ b/makima/src/daemon/cli/view.rs @@ -67,12 +67,16 @@ use clap::Args; #[derive(Args, Debug, Clone)] pub struct ViewArgs { /// API URL for the makima server - #[arg(long, env = "MAKIMA_API_URL", default_value = "https://api.makima.jp")] - pub api_url: String, + /// + /// If not provided, uses MAKIMA_API_URL env var or ~/.makima/config.toml + #[arg(long, env = "MAKIMA_API_URL")] + pub api_url: Option, /// API key for authentication + /// + /// If not provided, uses MAKIMA_API_KEY env var or ~/.makima/config.toml #[arg(long, env = "MAKIMA_API_KEY")] - pub api_key: String, + pub api_key: Option, /// Initial search query /// -- cgit v1.2.3