From 55f4f9fdfd1eca5bee8b4f4493f86ddb20a51f19 Mon Sep 17 00:00:00 2001 From: AndrewAvery7 <204509720+AndrewAvery7@users.noreply.github.com> Date: Fri, 24 Jul 2026 15:04:29 -0500 Subject: [PATCH] fix: normalize Windows extended-length paths in import ledger lookup importedThreadIdForSource compared fs.realpathSync output against ledger source_path records with strict equality. On Windows, Codex writes ledger paths with the \?\ extended-length prefix while realpathSync returns the plain form, so the comparison never matched: every successful transfer was reported as 'did not record an imported thread' (#513). Normalize both sides before comparing: strip \?\ (and \?\UNC\), and compare case-insensitively on win32. Fixes #513 Co-Authored-By: Claude Fable 5 --- plugins/codex/scripts/lib/codex.mjs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/plugins/codex/scripts/lib/codex.mjs b/plugins/codex/scripts/lib/codex.mjs index fead00cc4..e15ca0c0d 100644 --- a/plugins/codex/scripts/lib/codex.mjs +++ b/plugins/codex/scripts/lib/codex.mjs @@ -658,6 +658,23 @@ function sourceContentSha256(sourcePath) { return crypto.createHash("sha256").update(fs.readFileSync(sourcePath)).digest("hex"); } +function normalizeLedgerPath(sourcePath) { + // On Windows, Codex records ledger paths with the \\?\ extended-length + // prefix (e.g. \\?\C:\Users\...), while fs.realpathSync returns the plain + // form. Strip the prefix (including the \\?\UNC\ variant) and compare + // case-insensitively so ledger records match realpath output. + let normalized = String(sourcePath); + if (process.platform === "win32") { + if (normalized.startsWith("\\\\?\\UNC\\")) { + normalized = `\\\\${normalized.slice(8)}`; + } else if (normalized.startsWith("\\\\?\\")) { + normalized = normalized.slice(4); + } + return normalized.toLowerCase(); + } + return normalized; +} + function importedThreadIdForSource(sourcePath) { const ledgerPath = path.join(resolveCodexHome(), "external_agent_session_imports.json"); if (!fs.existsSync(ledgerPath)) { @@ -665,12 +682,13 @@ function importedThreadIdForSource(sourcePath) { } const ledger = readJsonFile(ledgerPath); const canonicalSource = fs.realpathSync(sourcePath); + const normalizedSource = normalizeLedgerPath(canonicalSource); const contentSha256 = sourceContentSha256(canonicalSource); const records = Array.isArray(ledger?.records) ? ledger.records : []; const match = records .filter( (record) => - record?.source_path === canonicalSource && + normalizeLedgerPath(record?.source_path) === normalizedSource && record?.content_sha256 === contentSha256 && typeof record?.imported_thread_id === "string" )