From ca2a91a42c93c2fe070a44048886598290fc03f5 Mon Sep 17 00:00:00 2001 From: ziyaad-mallick Date: Tue, 22 Sep 2026 12:16:37 +0500 Subject: [PATCH] fix(account): fold the Windows profile directory to one separator style ProfileDirectory() joins "/RunAnywhere/Wally" onto LOCALAPPDATA (or USERPROFILE) as the environment hands it over, backslash-separated, so `wally account login` reports "cloud session stored in C:\Users\...\AppData\Local/RunAnywhere/Wally" and `wally uninstall` lists the same mixed path. Run the base through paths::normalize_dir, the fold cli_paths already applies to resolve_home and state_dir (#58). Win32 accepts either separator and every consumer goes through std::filesystem, so the directory on disk is unchanged. A WALLY_PROFILE_DIR override is still returned as given. Co-Authored-By: Claude Opus 5 --- src/account/credentials.cpp | 5 ++++- tests/test_wally_account.cpp | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/account/credentials.cpp b/src/account/credentials.cpp index 49f38f4e..420a76fe 100644 --- a/src/account/credentials.cpp +++ b/src/account/credentials.cpp @@ -1,6 +1,7 @@ #include "account/credentials.h" #include "account/baked_endpoints.h" +#include "config/cli_paths.h" #include #include @@ -669,7 +670,9 @@ std::string ProfileDirectory() { return override_dir; } #if defined(_WIN32) - const std::string home = HomeDirectory(); + // LOCALAPPDATA is backslash-separated and the suffix is not; fold it the way + // paths::normalize_dir does so `wally account login` prints one style. + const std::string home = paths::normalize_dir(HomeDirectory()); return home.empty() ? std::string() : home + "/RunAnywhere/Wally"; #else const std::string xdg = Env("XDG_CONFIG_HOME"); diff --git a/tests/test_wally_account.cpp b/tests/test_wally_account.cpp index efb9a1e4..6ddb2931 100644 --- a/tests/test_wally_account.cpp +++ b/tests/test_wally_account.cpp @@ -309,6 +309,26 @@ TestResult test_credentials_reject_a_document_they_cannot_unlock() { result.passed = true; return result; } + +// A real LOCALAPPDATA is backslash-separated while the suffix appended to it is +// not. `wally account login` prints this directory, so the join must not mix them. +TestResult test_profile_directory_uses_one_separator_style() { + TestResult result; + result.test_name = "profile_directory_uses_one_separator_style"; + EnvVar profile("WALLY_PROFILE_DIR", nullptr); + EnvVar legacy("RCLI_PROFILE_DIR", nullptr); + EnvVar local("LOCALAPPDATA", "C:\\wally-local"); + + const std::string directory = wally::account::ProfileDirectory(); + if (directory != "C:/wally-local/RunAnywhere/Wally") { + result.expected = "C:/wally-local/RunAnywhere/Wally"; + result.actual = directory; + result.details = "the profile directory must not mix separators"; + return result; + } + result.passed = true; + return result; +} #endif #if !defined(_WIN32) @@ -1190,6 +1210,8 @@ int main(int argc, char** argv) { #else suite.add("credentials_reject_a_document_they_cannot_unlock", test_credentials_reject_a_document_they_cannot_unlock); + suite.add("profile_directory_uses_one_separator_style", + test_profile_directory_uses_one_separator_style); #endif suite.add("console_client_contract", test_console_client_contract); suite.add("console_errors_do_not_echo_secrets", test_console_errors_do_not_echo_secrets);