Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions electron/gemini/projectTemp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,24 @@ describe("Gemini 项目临时目录解析", () => {
expect(tempRoot).toBe("\\\\wsl.localhost\\Ubuntu-24.04\\home\\lulu\\.gemini\\tmp\\demo");
expect(imageRoot).toBe("\\\\wsl.localhost\\Ubuntu-24.04\\home\\lulu\\.gemini\\tmp\\demo\\images");
});

it("Windows 主进程在 WSL 模式下会把 POSIX 版 GEMINI_CLI_HOME 转成 UNC", async () => {
vi.spyOn(os, "platform").mockReturnValue("win32" as any);
process.env.GEMINI_CLI_HOME = "/home/lulu/.gemini-custom";
const originalReadFile = fsp.readFile.bind(fsp);
vi.spyOn(fsp, "readFile").mockImplementation(async (targetPath: any, ...args: any[]) => {
const normalizedPath = String(targetPath || "");
if (normalizedPath === "\\\\wsl.localhost\\Ubuntu-24.04\\home\\lulu\\.gemini-custom\\projects.json")
return JSON.stringify({ projects: { "/home/lulu/demo": "demo" } }) as any;
return await (originalReadFile as any)(targetPath, ...args);
});

const tempRoot = await resolveGeminiProjectTempRootWinPath({
projectWslRoot: "/home/lulu/demo",
runtimeEnv: "wsl",
distro: "Ubuntu-24.04",
});

expect(tempRoot).toBe("\\\\wsl.localhost\\Ubuntu-24.04\\home\\lulu\\.gemini-custom\\tmp\\demo");
});
});
41 changes: 40 additions & 1 deletion electron/gemini/projectTemp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,21 +283,60 @@ function resolveGeminiHomeWindows(): string {
return path.win32.join(os.homedir(), ".gemini");
}

/**
* 中文说明:将 Windows 主进程中读取到的 `GEMINI_CLI_HOME` 转换为 WSL 运行时可直接访问的路径。
* - Windows/UNC 路径直接复用
* - WSL 绝对路径转成 `\\\\wsl.localhost\\<distro>\\...`
* - `~/...` 与相对路径按 `$HOME/<subPath>` 解析为 UNC
*/
async function resolveConfiguredGeminiHomeForWindowsWsl(
configuredHome: string,
distro: string,
): Promise<string | null> {
const value = tidyPathCandidate(configuredHome);
if (!value) return null;
if (isWindowsStylePath(value)) return value;

const normalized = value.replace(/\\/g, "/");
if (normalized.startsWith("/")) {
const tail = normalized.replace(/^\/+/, "").split("/").filter(Boolean).join("\\");
return tail
? `\\\\wsl.localhost\\${distro}\\${tail}`
: `\\\\wsl.localhost\\${distro}`;
}

const homeRelative = normalized === "~"
? "."
: normalized.startsWith("~/")
? normalized.slice(2)
: normalized.replace(/^\.\//, "");
const unc = await getDistroHomeSubPathUNCAsync(distro, homeRelative || ".");
const cleaned = tidyPathCandidate(unc || "");
return cleaned || null;
}

/**
* 中文说明:解析当前运行环境下、主进程可访问的 Gemini 根目录。
* - 非 WSL 场景优先直接使用 `GEMINI_CLI_HOME`
* - Windows 主进程 + WSL 运行时仅在路径可访问时复用 `GEMINI_CLI_HOME`;POSIX 路径会转成 UNC
* - WSL on Windows 返回 UNC 路径
* - WSL 单元测试/非 Windows 环境优先使用 `GEMINI_CLI_HOME`,否则返回 POSIX `~/.gemini`
* - Windows/Pwsh 返回本机 `%USERPROFILE%\\.gemini`
*/
async function resolveGeminiHomePath(
options: ResolveGeminiProjectTempOptions,
): Promise<string | null> {
const configuredHome = String(process.env.GEMINI_CLI_HOME || "").trim();
const runtimeEnv = options.runtimeEnv || "windows";
if (runtimeEnv !== "wsl") return resolveGeminiHomeWindows();
if (os.platform() !== "win32")
return String(process.env.GEMINI_CLI_HOME || "").trim() || path.posix.join(os.homedir(), ".gemini");
return configuredHome || path.posix.join(os.homedir(), ".gemini");
const distro = String(options.distro || "").trim();
if (!distro) return null;
if (configuredHome) {
const converted = await resolveConfiguredGeminiHomeForWindowsWsl(configuredHome, distro);
if (converted) return converted;
}
const uncBase = await getDistroHomeSubPathUNCAsync(distro, ".gemini");
return uncBase || null;
}
Expand Down
Loading