From 9e741cfe871a197a04532126d5162bbb080949a4 Mon Sep 17 00:00:00 2001 From: Tushar Date: Fri, 10 Apr 2026 07:50:24 +0530 Subject: [PATCH 1/3] feat(cli): add config path subcommand to print global config file path --- crates/forge_main/src/cli.rs | 3 +++ crates/forge_main/src/ui.rs | 4 ++++ shell-plugin/lib/actions/config.zsh | 18 ++++++++++++++---- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/crates/forge_main/src/cli.rs b/crates/forge_main/src/cli.rs index 01d5b56f77..08c77434b1 100644 --- a/crates/forge_main/src/cli.rs +++ b/crates/forge_main/src/cli.rs @@ -510,6 +510,9 @@ pub enum ConfigCommand { /// List configuration values. List, + + /// Print the path to the global config file. + Path, } /// Arguments for `forge config set`. diff --git a/crates/forge_main/src/ui.rs b/crates/forge_main/src/ui.rs index ca01a0b657..548dd2d32d 100644 --- a/crates/forge_main/src/ui.rs +++ b/crates/forge_main/src/ui.rs @@ -3595,6 +3595,10 @@ impl A + Send + Sync> UI crate::cli::ConfigCommand::List => { self.on_show_config(porcelain).await?; } + crate::cli::ConfigCommand::Path => { + let path = forge_config::ConfigReader::config_path(); + self.writeln(path.display().to_string())?; + } } Ok(()) } diff --git a/shell-plugin/lib/actions/config.zsh b/shell-plugin/lib/actions/config.zsh index a6d5f51479..2c98a66ccf 100644 --- a/shell-plugin/lib/actions/config.zsh +++ b/shell-plugin/lib/actions/config.zsh @@ -463,12 +463,22 @@ function _forge_action_config_edit() { return 1 fi - local config_file="${HOME}/forge/.forge.toml" + # Resolve config file path via the forge binary (honours FORGE_CONFIG, + # new ~/.forge path, and legacy ~/forge fallback automatically) + local config_file + config_file=$(forge config path 2>/dev/null) + if [[ -z "$config_file" ]]; then + _forge_log error "Failed to resolve config path from 'forge config path'" + return 1 + fi + + local config_dir + config_dir=$(dirname "$config_file") # Ensure the config directory exists - if [[ ! -d "${HOME}/forge" ]]; then - mkdir -p "${HOME}/forge" || { - _forge_log error "Failed to create ~/forge directory" + if [[ ! -d "$config_dir" ]]; then + mkdir -p "$config_dir" || { + _forge_log error "Failed to create $config_dir directory" return 1 } fi From 2349f4e0a242bd7743bef95862a8150957725550 Mon Sep 17 00:00:00 2001 From: Tushar Date: Fri, 10 Apr 2026 07:54:30 +0530 Subject: [PATCH 2/3] feat(cli): add config migrate subcommand to rename ~/forge to ~/.forge --- Cargo.lock | 1 + crates/forge_main/Cargo.toml | 1 + crates/forge_main/src/cli.rs | 3 +++ crates/forge_main/src/ui.rs | 37 ++++++++++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 0bbd367a95..f77d1be63d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2165,6 +2165,7 @@ dependencies = [ "console", "convert_case 0.11.0", "derive_setters", + "dirs", "enable-ansi-support", "fake", "forge_api", diff --git a/crates/forge_main/Cargo.toml b/crates/forge_main/Cargo.toml index d3d4d472f8..8eec3efd6f 100644 --- a/crates/forge_main/Cargo.toml +++ b/crates/forge_main/Cargo.toml @@ -52,6 +52,7 @@ update-informer = { version = "1.2.0", default-features = false, features = [ "ureq", "rustls-tls", ] } +dirs.workspace = true open.workspace = true humantime.workspace = true num-format.workspace = true diff --git a/crates/forge_main/src/cli.rs b/crates/forge_main/src/cli.rs index 08c77434b1..6e4bc5d77d 100644 --- a/crates/forge_main/src/cli.rs +++ b/crates/forge_main/src/cli.rs @@ -513,6 +513,9 @@ pub enum ConfigCommand { /// Print the path to the global config file. Path, + + /// Migrate the legacy ~/forge directory to ~/.forge. + Migrate, } /// Arguments for `forge config set`. diff --git a/crates/forge_main/src/ui.rs b/crates/forge_main/src/ui.rs index 548dd2d32d..ac61d6e571 100644 --- a/crates/forge_main/src/ui.rs +++ b/crates/forge_main/src/ui.rs @@ -3599,7 +3599,44 @@ impl A + Send + Sync> UI let path = forge_config::ConfigReader::config_path(); self.writeln(path.display().to_string())?; } + crate::cli::ConfigCommand::Migrate => { + self.handle_config_migrate()?; + } + } + Ok(()) + } + + /// Rename `~/forge` to `~/.forge`. + /// + /// Errors if the legacy directory does not exist, if the new directory + /// already exists, or if the rename fails. + fn handle_config_migrate(&mut self) -> Result<()> { + let home = dirs::home_dir() + .ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?; + let legacy = home.join("forge"); + let new = home.join(".forge"); + + if !legacy.exists() { + anyhow::bail!("Legacy directory {} does not exist — nothing to migrate", legacy.display()); + } + + if new.exists() { + anyhow::bail!( + "Target directory {} already exists — remove it first or migrate manually", + new.display() + ); } + + std::fs::rename(&legacy, &new).map_err(|e| { + anyhow::anyhow!("Failed to rename {} to {}: {}", legacy.display(), new.display(), e) + })?; + + self.writeln(format!( + "Migrated {} → {}", + legacy.display(), + new.display() + ))?; + Ok(()) } From a595f6d1d88df42512e2dabaafdb2d5903df71d0 Mon Sep 17 00:00:00 2001 From: Tushar Date: Fri, 10 Apr 2026 07:56:28 +0530 Subject: [PATCH 3/3] style(ui): reformat anyhow macros and use writeln_title for migration output --- crates/forge_main/src/ui.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/crates/forge_main/src/ui.rs b/crates/forge_main/src/ui.rs index ac61d6e571..2cbce1d3b5 100644 --- a/crates/forge_main/src/ui.rs +++ b/crates/forge_main/src/ui.rs @@ -3617,7 +3617,10 @@ impl A + Send + Sync> UI let new = home.join(".forge"); if !legacy.exists() { - anyhow::bail!("Legacy directory {} does not exist — nothing to migrate", legacy.display()); + anyhow::bail!( + "Legacy directory {} does not exist — nothing to migrate", + legacy.display() + ); } if new.exists() { @@ -3628,14 +3631,19 @@ impl A + Send + Sync> UI } std::fs::rename(&legacy, &new).map_err(|e| { - anyhow::anyhow!("Failed to rename {} to {}: {}", legacy.display(), new.display(), e) + anyhow::anyhow!( + "Failed to rename {} to {}: {}", + legacy.display(), + new.display(), + e + ) })?; - self.writeln(format!( - "Migrated {} → {}", + self.writeln_title(TitleFormat::info("Migration Completed").sub_title(format!( + "{} → {}", legacy.display(), new.display() - ))?; + )))?; Ok(()) }