From de1d709b6116aa0330a11c1fa947270638f3a207 Mon Sep 17 00:00:00 2001 From: Tushar Date: Fri, 10 Apr 2026 12:29:00 +0530 Subject: [PATCH 1/3] fix(shell-plugin): use FORGE_BIN variable instead of hardcoded forge binary --- shell-plugin/lib/actions/config.zsh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell-plugin/lib/actions/config.zsh b/shell-plugin/lib/actions/config.zsh index 2c98a66ccf..5bf6d8f376 100644 --- a/shell-plugin/lib/actions/config.zsh +++ b/shell-plugin/lib/actions/config.zsh @@ -466,9 +466,9 @@ function _forge_action_config_edit() { # 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) + config_file=$($FORGE_BIN config path 2>/dev/null) if [[ -z "$config_file" ]]; then - _forge_log error "Failed to resolve config path from 'forge config path'" + _forge_log error "Failed to resolve config path from '$FORGE_BIN config path'" return 1 fi From 980ee3265171f20fce41e7d5f6d2125640054b0a Mon Sep 17 00:00:00 2001 From: Tushar Date: Fri, 10 Apr 2026 14:40:21 +0530 Subject: [PATCH 2/3] fix(config): prefer legacy ~/forge path while it exists to prevent silent base path switch --- crates/forge_app/src/fmt/fmt_input.rs | 2 +- crates/forge_config/src/reader.rs | 24 ++++++++++++++++++------ crates/forge_infra/src/env.rs | 10 ++++++++-- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/crates/forge_app/src/fmt/fmt_input.rs b/crates/forge_app/src/fmt/fmt_input.rs index 1dcf23cf2c..edc463f3ef 100644 --- a/crates/forge_app/src/fmt/fmt_input.rs +++ b/crates/forge_app/src/fmt/fmt_input.rs @@ -99,7 +99,7 @@ impl FormatContent for ToolCatalog { ToolCatalog::MultiPatch(input) => { let display_path = display_path_for(&input.file_path); Some( - TitleFormat::debug("Multi-patch") + TitleFormat::debug("Replace") .sub_title(format!("{} ({} edits)", display_path, input.edits.len())) .into(), ) diff --git a/crates/forge_config/src/reader.rs b/crates/forge_config/src/reader.rs index f0a6534c36..d0f144cc3a 100644 --- a/crates/forge_config/src/reader.rs +++ b/crates/forge_config/src/reader.rs @@ -53,8 +53,12 @@ impl ConfigReader { /// /// If the `FORGE_CONFIG` environment variable is set, its value is used /// directly as the base path. Otherwise defaults to `~/.forge`. - /// Falls back to the legacy `~/forge` path if it exists and `~/.forge` - /// does not. + /// Falls back to the legacy `~/forge` path if it exists, even if `~/.forge` + /// also exists. This prevents tools that eagerly create `~/.forge` (such as + /// the shell plugin's config-edit action) from silently switching the active + /// base path while the user's credentials and config still live in `~/forge`. + /// Once the user runs `forge config migrate` the `~/forge` directory is + /// removed, so this fallback naturally stops applying. pub fn base_path() -> PathBuf { if let Ok(path) = std::env::var("FORGE_CONFIG") { return PathBuf::from(path); @@ -64,8 +68,10 @@ impl ConfigReader { let path = home.join(".forge"); let legacy_path = home.join("forge"); - // Prefer the new dotfile path, but fall back to legacy if only it exists - if !path.exists() && legacy_path.exists() { + // Prefer the legacy ~/forge path while it still exists so that an + // empty ~/.forge directory (e.g. created by `mkdir -p` in the shell + // plugin) does not cause the base path to flip before migration. + if legacy_path.exists() { tracing::info!("Using legacy path"); return legacy_path; } @@ -195,8 +201,14 @@ mod tests { #[test] fn test_base_path_falls_back_to_home_dir_when_env_var_absent() { let actual = ConfigReader::base_path(); - // Without FORGE_CONFIG set the path must end with ".forge" - assert_eq!(actual.file_name().unwrap(), ".forge"); + // Without FORGE_CONFIG set the path must be either ".forge" (new) or + // "forge" (legacy fallback when ~/forge exists on this machine). + let name = actual.file_name().unwrap(); + assert!( + name == ".forge" || name == "forge", + "Expected base_path to end with '.forge' or 'forge', got: {:?}", + name + ); } #[test] diff --git a/crates/forge_infra/src/env.rs b/crates/forge_infra/src/env.rs index 1a89e7c965..d281eabd52 100644 --- a/crates/forge_infra/src/env.rs +++ b/crates/forge_infra/src/env.rs @@ -213,8 +213,14 @@ mod tests { #[test] fn test_to_environment_falls_back_to_home_dir_when_env_var_absent() { let actual = to_environment(PathBuf::from("/any/cwd")); - // Without FORGE_CONFIG the base_path must end with ".forge" - assert_eq!(actual.base_path.file_name().unwrap(), ".forge"); + // Without FORGE_CONFIG the base_path must be either ".forge" (new default) + // or "forge" (legacy fallback when ~/forge exists on this machine). + let name = actual.base_path.file_name().unwrap(); + assert!( + name == ".forge" || name == "forge", + "Expected base_path to end with '.forge' or 'forge', got: {:?}", + name + ); } #[test] From b8563c535a9092b097cba8bc94ae52187f4edfba Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:12:19 +0000 Subject: [PATCH 3/3] [autofix.ci] apply automated fixes --- crates/forge_config/src/reader.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/forge_config/src/reader.rs b/crates/forge_config/src/reader.rs index d0f144cc3a..aa77518347 100644 --- a/crates/forge_config/src/reader.rs +++ b/crates/forge_config/src/reader.rs @@ -55,10 +55,11 @@ impl ConfigReader { /// directly as the base path. Otherwise defaults to `~/.forge`. /// Falls back to the legacy `~/forge` path if it exists, even if `~/.forge` /// also exists. This prevents tools that eagerly create `~/.forge` (such as - /// the shell plugin's config-edit action) from silently switching the active - /// base path while the user's credentials and config still live in `~/forge`. - /// Once the user runs `forge config migrate` the `~/forge` directory is - /// removed, so this fallback naturally stops applying. + /// the shell plugin's config-edit action) from silently switching the + /// active base path while the user's credentials and config still live + /// in `~/forge`. Once the user runs `forge config migrate` the + /// `~/forge` directory is removed, so this fallback naturally stops + /// applying. pub fn base_path() -> PathBuf { if let Ok(path) = std::env::var("FORGE_CONFIG") { return PathBuf::from(path);