From d66be73237f4b063e8f4870fa621efcc6c04b382 Mon Sep 17 00:00:00 2001 From: Alton Johnson Date: Sun, 19 Apr 2026 13:51:11 -0400 Subject: [PATCH 1/2] Expand leading ~ in provider home paths before exporting as env vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spawned processes don't inherit shell tilde expansion, so a Codex homePath of ~/.codex-work was being passed to the child verbatim as CODEX_HOME=~/.codex-work. The receiver then treats ~ as a relative directory name rather than $HOME, so state ends up in the wrong place (or fails to load existing config). Add an expandHomePath() helper that turns a leading ~ or ~/… into the current user's home directory, and apply it everywhere the Codex homePath setting flows into CODEX_HOME: the text-generation spawn, the discovery probe, the app-server manager spawn and version check, and the Codex provider health check. Leaves other-user (~alice) expansion out — only ~ and ~/… are handled. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/server/src/codexAppServerManager.ts | 5 +++-- .../src/git/Layers/CodexTextGeneration.ts | 5 ++++- apps/server/src/pathExpansion.ts | 18 ++++++++++++++++++ .../src/provider/Layers/CodexProvider.ts | 3 ++- apps/server/src/provider/codexAppServer.ts | 3 ++- 5 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 apps/server/src/pathExpansion.ts diff --git a/apps/server/src/codexAppServerManager.ts b/apps/server/src/codexAppServerManager.ts index 6d98264c910..ba776890ee5 100644 --- a/apps/server/src/codexAppServerManager.ts +++ b/apps/server/src/codexAppServerManager.ts @@ -32,6 +32,7 @@ import { type CodexAccountSnapshot, } from "./provider/codexAccount.ts"; import { buildCodexInitializeParams, killCodexChildProcess } from "./provider/codexAppServer.ts"; +import { expandHomePath } from "./pathExpansion.ts"; export { buildCodexInitializeParams } from "./provider/codexAppServer.ts"; export { readCodexAccountSnapshot, resolveCodexModelForAccount } from "./provider/codexAccount.ts"; @@ -493,7 +494,7 @@ export class CodexAppServerManager extends EventEmitter Date: Sun, 19 Apr 2026 19:33:03 -0400 Subject: [PATCH 2/2] Handle ~\ on Windows and cover expandHomePath with unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The other three expandHomePath helpers in this repo (os-jank.ts, WorkspaceEntries.ts, WorkspacePaths.ts) accept both `~/` and `~\` prefixes. Match that behavior in the new pathExpansion helper so a Windows user who types `~\.codex` into provider settings gets the same expansion as `~/.codex`. Also add a small test file covering the shape of the helper (empty, unchanged, `~`, `~/…`, `~\…`, and `~user` pass-through). Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/server/src/pathExpansion.test.ts | 33 +++++++++++++++++++++++++++ apps/server/src/pathExpansion.ts | 19 +++++++++------ 2 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 apps/server/src/pathExpansion.test.ts diff --git a/apps/server/src/pathExpansion.test.ts b/apps/server/src/pathExpansion.test.ts new file mode 100644 index 00000000000..40ca25e6c8f --- /dev/null +++ b/apps/server/src/pathExpansion.test.ts @@ -0,0 +1,33 @@ +import { homedir } from "node:os"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; + +import { expandHomePath } from "./pathExpansion.ts"; + +describe("expandHomePath", () => { + it("returns an empty string unchanged", () => { + expect(expandHomePath("")).toBe(""); + }); + + it("returns paths without a leading tilde unchanged", () => { + expect(expandHomePath("/absolute/path")).toBe("/absolute/path"); + expect(expandHomePath("relative/path")).toBe("relative/path"); + expect(expandHomePath("some~weird~path")).toBe("some~weird~path"); + }); + + it("expands a lone tilde to the home directory", () => { + expect(expandHomePath("~")).toBe(homedir()); + }); + + it("expands ~/ to a subpath of the home directory", () => { + expect(expandHomePath("~/.codex-work")).toBe(join(homedir(), ".codex-work")); + }); + + it("expands a Windows-style ~\\ prefix", () => { + expect(expandHomePath("~\\.codex")).toBe(join(homedir(), ".codex")); + }); + + it("does not expand ~user paths", () => { + expect(expandHomePath("~alice/foo")).toBe("~alice/foo"); + }); +}); diff --git a/apps/server/src/pathExpansion.ts b/apps/server/src/pathExpansion.ts index 2adb89ffba8..18060c3e554 100644 --- a/apps/server/src/pathExpansion.ts +++ b/apps/server/src/pathExpansion.ts @@ -2,17 +2,22 @@ import { homedir } from "node:os"; import { join } from "node:path"; /** - * Expand a leading `~` (or `~/…`) in a user-supplied path to the current - * user's home directory. Spawned processes don't get shell expansion, so - * env vars like `CODEX_HOME=~/.codex-work` or `CLAUDE_CONFIG_DIR=~/.claude` - * would be passed verbatim and treated as relative paths by the receiver. + * Expand a leading `~` (or `~/…`, `~\…`) in a user-supplied path to the + * current user's home directory. Spawned processes don't get shell + * expansion, so env vars like `CODEX_HOME=~/.codex-work` would be passed + * verbatim and treated as relative paths by the receiver. * - * Returns the input unchanged if it doesn't start with `~` or is empty. - * Does not handle `~user` (other-user) expansion — only `~` and `~/…`. + * Matches the behavior of the other `expandHomePath` helpers in the + * workspace layers and CLI bootstrap: `~` alone and both `~/` and `~\` + * separators are handled. Returns the input unchanged if it doesn't + * start with `~` or is empty. Does not handle `~user` (other-user) + * expansion. */ export function expandHomePath(value: string): string { if (!value) return value; if (value === "~") return homedir(); - if (value.startsWith("~/")) return join(homedir(), value.slice(2)); + if (value.startsWith("~/") || value.startsWith("~\\")) { + return join(homedir(), value.slice(2)); + } return value; }