fix: use realpathSync.native for session projectId hash on Windows (#1593) (#1601)

On Windows, path.resolve returns whatever case the caller supplied while
fs.realpathSync.native returns the OS-canonical case. These produce
different SHA-1 hashes and therefore different session tmpdir slots —
the test checks one slot while the implementation writes to another,
causing pointer lifecycle assertions to always fail.

Fix: use realpathSync.native with a fallback to path.resolve when the
planning directory does not yet exist.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-04-03 12:14:45 -04:00
committed by GitHub
parent b5dd886e15
commit 40fc681b28

View File

@@ -695,9 +695,20 @@ function getSessionScopedWorkstreamFile(cwd) {
const sessionKey = getWorkstreamSessionKey();
if (!sessionKey) return null;
// Use realpathSync.native so the hash is derived from the canonical filesystem
// path. On Windows, path.resolve returns whatever case the caller supplied,
// while realpathSync.native returns the case the OS recorded — they differ on
// case-insensitive NTFS, producing different hashes and different tmpdir slots.
// Fall back to path.resolve when the directory does not yet exist.
let planningAbs;
try {
planningAbs = fs.realpathSync.native(planningRoot(cwd));
} catch {
planningAbs = path.resolve(planningRoot(cwd));
}
const projectId = crypto
.createHash('sha1')
.update(path.resolve(planningRoot(cwd)))
.update(planningAbs)
.digest('hex')
.slice(0, 16);