From 53b35687bee0374796e8ebc8141d8eefb9699e4e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:38:25 +0000 Subject: [PATCH 1/3] Initial plan From 3c52c1376d6ade2e53fdba85850fcc3634fc6da4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:41:51 +0000 Subject: [PATCH 2/3] fix windows path handling for state location and folder hyperlinks Co-authored-by: LIU-Yinyi <43030043+LIU-Yinyi@users.noreply.github.com> --- src/state/discovery.ts | 8 +++++++- src/terminal/style.ts | 10 +++++++++- test/unit/state-discovery.test.ts | 17 +++++++++++++++++ test/unit/terminal-style.test.ts | 10 +++++++++- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/state/discovery.ts b/src/state/discovery.ts index 4d71d24..7989dde 100644 --- a/src/state/discovery.ts +++ b/src/state/discovery.ts @@ -20,6 +20,10 @@ function nativePlatform(): PathPlatform { return process.platform === "win32" ? "win32" : "posix"; } +function isAbsolutePath(value: string): boolean { + return path.posix.isAbsolute(value) || path.win32.isAbsolute(value); +} + export function resolveStateLocation( options: StateLocationOptions = {}, ): StateLocation { @@ -38,7 +42,9 @@ export function resolveStateLocation( throw new Error("Codex home must not be empty"); } - const codexHome = parser.resolve(cwd, configuredHome); + const codexHome = isAbsolutePath(configuredHome) + ? configuredHome + : parser.resolve(cwd, configuredHome); return { codexHome, configDirectory: parser.join(userHome, ".config", "codex-project"), diff --git a/src/terminal/style.ts b/src/terminal/style.ts index a8026f8..efcb287 100644 --- a/src/terminal/style.ts +++ b/src/terminal/style.ts @@ -106,7 +106,15 @@ export function folderLink( { tone: "folder", underline: options.hyperlinks === true }, options, ); - return hyperlink(text, pathToFileURL(folder).href, options); + const normalized = folder.replaceAll("\\", "/"); + const uri = /^[A-Za-z]:\//.test(normalized) + ? `file:///${encodeURI(normalized)}` + : normalized.startsWith("//") + ? `file:${encodeURI(normalized)}` + : normalized.startsWith("/") + ? `file://${encodeURI(normalized)}` + : pathToFileURL(folder).href; + return hyperlink(text, uri, options); } export interface DetectTerminalStyleOptions { diff --git a/test/unit/state-discovery.test.ts b/test/unit/state-discovery.test.ts index ea5a0bb..5b7d06c 100644 --- a/test/unit/state-discovery.test.ts +++ b/test/unit/state-discovery.test.ts @@ -54,4 +54,21 @@ describe("state discovery", () => { "C:\\work\\tests\\fixture-home\\.codex-global-state.json", }); }); + + it("keeps absolute Windows Codex home unchanged in posix-mode resolution", () => { + expect( + resolveStateLocation({ + codexHome: "C:\\Users\\Example\\AppData\\Local\\Temp\\codex-home", + cwd: "D:\\work\\repo", + env: {}, + platform: "posix", + userHome: "/Users/example", + }), + ).toEqual({ + codexHome: "C:\\Users\\Example\\AppData\\Local\\Temp\\codex-home", + configDirectory: "/Users/example/.config/codex-project", + stateFile: + "C:\\Users\\Example\\AppData\\Local\\Temp\\codex-home/.codex-global-state.json", + }); + }); }); diff --git a/test/unit/terminal-style.test.ts b/test/unit/terminal-style.test.ts index d14bc8e..6a0704e 100644 --- a/test/unit/terminal-style.test.ts +++ b/test/unit/terminal-style.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { detectTerminalStyle } from "../../src/terminal/style.js"; +import { detectTerminalStyle, folderLink } from "../../src/terminal/style.js"; describe("terminal style detection", () => { it("enables colors and hyperlinks for an interactive terminal", () => { @@ -46,4 +46,12 @@ describe("terminal style detection", () => { }), ).toEqual({ colors: true, hyperlinks: true }); }); + + it("formats absolute paths into stable file hyperlinks", () => { + const linked = folderLink("/work/rose garden", { + colors: false, + hyperlinks: true, + }); + expect(linked).toContain("\u001B]8;;file:///work/rose%20garden\u001B\\"); + }); }); From 2acf8ad1bac2c7a022968fb05b74fb6f8c9b5927 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 12 Aug 2026 07:04:35 +0000 Subject: [PATCH 3/3] Fix mixed-platform absolute path normalization in path adapter Co-authored-by: LIU-Yinyi <43030043+LIU-Yinyi@users.noreply.github.com> --- src/platform/path-adapter.ts | 10 +++++++--- test/unit/path-adapter.test.ts | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/platform/path-adapter.ts b/src/platform/path-adapter.ts index a55f8ff..6c6aeab 100644 --- a/src/platform/path-adapter.ts +++ b/src/platform/path-adapter.ts @@ -23,10 +23,14 @@ function removeTrailingSeparators( value: string, parser: typeof path.posix | typeof path.win32, ): string { - const root = parser.parse(value).root; + const root = Math.max( + parser.parse(value).root.length, + path.posix.parse(value).root.length, + path.win32.parse(value).root.length, + ); let end = value.length; while ( - end > root.length && + end > root && (value[end - 1] === "/" || value[end - 1] === "\\") ) { end -= 1; @@ -65,7 +69,7 @@ export function createPathAdapter(options: PathAdapterOptions): PathAdapter { options.platform, options.homeDirectory, ); - const normalized = parser.isAbsolute(expanded) + const normalized = path.posix.isAbsolute(expanded) || path.win32.isAbsolute(expanded) ? parser.normalize(expanded) : parser.resolve(normalizedCwd, expanded); return removeTrailingSeparators(normalized, parser); diff --git a/test/unit/path-adapter.test.ts b/test/unit/path-adapter.test.ts index 9d1b967..9c0e275 100644 --- a/test/unit/path-adapter.test.ts +++ b/test/unit/path-adapter.test.ts @@ -25,6 +25,10 @@ describe("POSIX path adapter", () => { expect(paths.normalize("/")).toBe("/"); }); + it("preserves absolute Windows paths in POSIX mode", () => { + expect(paths.normalize("C:\\Work\\Alpha\\")).toBe("C:\\Work\\Alpha"); + }); + it("keeps POSIX comparisons case-sensitive", () => { expect(paths.equals("/Work/Alpha", "/Work/Alpha/")).toBe(true); expect(paths.equals("/Work/Alpha", "/work/alpha")).toBe(false);