Skip to content

fix(settings): prefer canonical codewhale settings path#2730

Open
xyuai wants to merge 1 commit into
Hmbown:mainfrom
xyuai:cw2664
Open

fix(settings): prefer canonical codewhale settings path#2730
xyuai wants to merge 1 commit into
Hmbown:mainfrom
xyuai:cw2664

Conversation

@xyuai
Copy link
Copy Markdown
Contributor

@xyuai xyuai commented Jun 3, 2026

Summary

  • keep /config and other settings surfaces pointed at the canonical ~/.codewhale/settings.toml path
  • continue reading legacy DeepSeek-branded settings paths as fallbacks, then copy them into the CodeWhale home on load
  • add regression tests covering legacy-home and platform-config fallback migration

Testing

  • cargo fmt --all
  • cargo test -p codewhale-tui --bin codewhale-tui settings_ -- --nocapture
  • cargo test -p codewhale-tui --bin codewhale-tui display_localizes_header_and_config_file_label -- --nocapture

Closes #2664.

Greptile Summary

This PR refactors Settings::path() to always return the canonical ~/.codewhale/settings.toml path for display and writes, while preserving backward-compatible reading from legacy DeepSeek-branded locations (~/.deepseek/ and the platform config_dir/deepseek/). A new migrate_settings_file_to_primary_if_needed helper silently copies any legacy settings file into the canonical home on the first load().

  • settings_path_candidates() extracts the shared logic for building the three candidate paths, replacing duplicated env-var and directory-resolution code that was scattered across path(), load(), and auto_compact_explicitly_configured().
  • Settings::path() now skips legacy_home entirely, returning primary (or legacy_config_dir when codewhale_home() fails) so the /config surface always advertises the canonical write target.
  • Migration is performed inside load() after a successful read: if settings were read from any legacy location and the primary path doesn't yet exist, the raw file is copied to ~/.codewhale/settings.toml, with failures degraded to tracing::warn so a transient I/O error cannot crash the TUI.

Confidence Score: 5/5

Safe to merge — the refactor is narrowly scoped to path resolution and the migration helper, with no changes to how settings are parsed, normalized, or persisted beyond directing writes to the canonical location.

The logic in settings_path_candidates, Settings::path, and migrate_settings_file_to_primary_if_needed is internally consistent: reads still fall through all three candidate locations in priority order, writes always target the canonical path, and migration is gated on the primary not yet existing so it cannot overwrite user-intentional edits. Migration failures are soft-degraded to warnings rather than propagated as errors, which is appropriate for a first-run copy.

No files require special attention beyond the single note on the platform-config migration test.

Important Files Changed

Filename Overview
crates/tui/src/settings.rs Core settings path and migration logic refactored; new helpers settings_path_candidates() and migrate_settings_file_to_primary_if_needed() extracted; tests updated to exercise Settings::load() end-to-end for both legacy-home and platform-config migration paths.

Fix All in Codex Fix All in Claude Code Fix All in Cursor

Reviews (2): Last reviewed commit: "fix(settings): tighten legacy path migra..." | Re-trigger Greptile

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

Thanks @xyuai for taking the time to contribute.

This repository is currently observing a maintainer-managed contribution gate in dry-run mode, so this pull request is staying open. When enforcement is enabled, pull requests from contributors who are not listed in .github/APPROVED_CONTRIBUTORS will be closed automatically.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant PR access by commenting /lgtm on a pull request.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors settings path resolution and introduces automatic migration of legacy settings files to the new canonical primary path (~/.codewhale/settings.toml). The feedback suggests minor code improvements to avoid redundant cloning of the primary path variable in both Settings::load() and auto_compact_explicitly_configured(), as well as removing a redundant fallback in the latter.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +383 to +385
let read_path =
resolve_settings_path_from_candidates(primary.clone(), legacy_home, legacy_config_dir)
.unwrap_or_else(|_| write_path.clone());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In Settings::load(), primary is not used after the call to resolve_settings_path_from_candidates. Therefore, cloning it is redundant and we can directly move it, avoiding an unnecessary allocation.

        let read_path =
            resolve_settings_path_from_candidates(primary, legacy_home, legacy_config_dir)
                .unwrap_or_else(|_| write_path.clone());

Comment on lines +423 to 428
let Ok(path) =
resolve_settings_path_from_candidates(primary.clone(), legacy_home, legacy_config_dir)
.or_else(|_| primary.ok_or_else(|| anyhow::anyhow!("missing primary path")))
else {
return false;
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In auto_compact_explicitly_configured(), the .or_else(...) fallback is completely redundant because resolve_settings_path_from_candidates already falls back to primary.or(legacy_config_dir) when none of the candidate paths exist on disk. If both are None, it returns an Err, which means primary is None and the .or_else block would also return Err anyway. Additionally, primary does not need to be cloned since it is not used after this call.

        let Ok(path) =
            resolve_settings_path_from_candidates(primary, legacy_home, legacy_config_dir)
        else {
            return false;
        };

Comment thread crates/tui/src/settings.rs Outdated
Comment thread crates/tui/src/settings.rs
@Hmbown
Copy link
Copy Markdown
Owner

Hmbown commented Jun 4, 2026

ah - thank you so much!! @xyuai I've been struggling to get this finally done - super helpful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

settings: TUI still surfaces legacy Application Support/deepseek/settings.toml path

2 participants