From 81a5efe935660edb6882c1d0cc3a007c23be881e Mon Sep 17 00:00:00 2001 From: BinBandit Date: Mon, 9 Mar 2026 14:24:25 +1100 Subject: [PATCH] fix(desktop): use filesystem-friendly userData directory name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Electron derives the userData path from productName in package.json, which produces directories with spaces and parentheses on all platforms (e.g. ~/.config/T3 Code (Alpha) on Linux). This is hostile to shell usage and violates Linux XDG naming conventions. Override the userData path via app.setPath() before the ready event to use a clean lowercase name (t3code). If the legacy directory already exists it is used as-is so existing users keep their Chromium profile data (localStorage, cookies, sessions, cache). This follows the same pattern VS Code uses — keeping productName for display purposes while explicitly setting the data directory path. Closes #578 --- apps/desktop/src/main.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index a23fc8e4a3..f39486902b 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -50,6 +50,8 @@ const ROOT_DIR = Path.resolve(__dirname, "../../.."); const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL); const APP_DISPLAY_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)"; const APP_USER_MODEL_ID = "com.t3tools.t3code"; +const USER_DATA_DIR_NAME = isDevelopment ? "t3code-dev" : "t3code"; +const LEGACY_USER_DATA_DIR_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)"; const COMMIT_HASH_PATTERN = /^[0-9a-f]{7,40}$/i; const COMMIT_HASH_DISPLAY_LENGTH = 12; const LOG_DIR = Path.join(STATE_DIR, "logs"); @@ -574,6 +576,34 @@ function resolveIconPath(ext: "ico" | "icns" | "png"): string | null { return resolveResourcePath(`icon.${ext}`); } +/** + * Resolve the Electron userData directory path. + * + * Electron derives the default userData path from `productName` in + * package.json, which currently produces directories with spaces and + * parentheses (e.g. `~/.config/T3 Code (Alpha)` on Linux). This is + * unfriendly for shell usage and violates Linux naming conventions. + * + * We override it to a clean lowercase name (`t3code`). If the legacy + * directory already exists we keep using it so existing users don't + * lose their Chromium profile data (localStorage, cookies, sessions). + */ +function resolveUserDataPath(): string { + const appDataBase = + process.platform === "win32" + ? process.env.APPDATA || Path.join(OS.homedir(), "AppData", "Roaming") + : process.platform === "darwin" + ? Path.join(OS.homedir(), "Library", "Application Support") + : process.env.XDG_CONFIG_HOME || Path.join(OS.homedir(), ".config"); + + const legacyPath = Path.join(appDataBase, LEGACY_USER_DATA_DIR_NAME); + if (FS.existsSync(legacyPath)) { + return legacyPath; + } + + return Path.join(appDataBase, USER_DATA_DIR_NAME); +} + function configureAppIdentity(): void { app.setName(APP_DISPLAY_NAME); const commitHash = resolveAboutCommitHash(); @@ -1171,6 +1201,11 @@ function createWindow(): BrowserWindow { return window; } +// Override Electron's userData path before the `ready` event so that +// Chromium session data uses a filesystem-friendly directory name. +// Must be called synchronously at the top level — before `app.whenReady()`. +app.setPath("userData", resolveUserDataPath()); + configureAppIdentity(); async function bootstrap(): Promise {