Skip to content

fix: translate WSL mount paths to Windows drive-letter paths#127

Merged
matt1398 merged 2 commits intomainfrom
fix/wsl-path-translation
Mar 23, 2026
Merged

fix: translate WSL mount paths to Windows drive-letter paths#127
matt1398 merged 2 commits intomainfrom
fix/wsl-path-translation

Conversation

@matt1398
Copy link
Owner

@matt1398 matt1398 commented Mar 23, 2026

Sessions started from WSL encode POSIX paths (/mnt/d/...) in cwd, which aren't recognized as Windows paths (D:/...) by the app. Add translateWslMountPath() to convert /mnt/X/... → X:/... on Windows, applied in both decodePath() and extractCwd().

Fixes #118

Summary by CodeRabbit

  • Bug Fixes
    • Improved WSL path handling so mount-style POSIX paths are reliably converted to Windows drive-letter form, fixing incorrect CWD and decoded-path results.
  • Chores
    • Increased individual test timeout to 15 seconds to reduce flaky test failures.

Sessions started from WSL encode POSIX paths (/mnt/d/...) in cwd,
which aren't recognized as Windows paths (D:/...) by the app.
Add translateWslMountPath() to convert /mnt/X/... → X:/... on Windows,
applied in both decodePath() and extractCwd().

Fixes #118

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 23, 2026 04:10
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves an issue where paths originating from Windows Subsystem for Linux (WSL) sessions were not correctly interpreted by the application when running on Windows. By introducing a path translation mechanism, the application can now seamlessly handle POSIX-style WSL mount paths, converting them into native Windows drive-letter paths. This ensures proper functionality and compatibility for users working within WSL environments.

Highlights

  • WSL Path Translation: Implemented a new utility function, translateWslMountPath, to convert POSIX-style WSL mount paths (e.g., /mnt/d/) into Windows drive-letter paths (e.g., D:/).
  • Path Decoding Integration: Integrated the translateWslMountPath function into decodePath to ensure that all decoded paths originating from WSL are correctly formatted for Windows.
  • CWD Extraction Enhancement: Applied the translateWslMountPath function within extractCwd to ensure that the current working directory extracted from sessions started in WSL is correctly recognized by the application on Windows.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai coderabbitai bot added the bug Something isn't working label Mar 23, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Windows DevTools path handling for sessions/projects created under WSL by translating WSL mount-style POSIX paths (/mnt/d/...) into Windows drive-letter paths (D:/...) when running on Windows.

Changes:

  • Added translateWslMountPath() and applied it to decodePath() output on Windows.
  • Applied the same WSL mount translation to extractCwd() results before drive-letter normalization.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/main/utils/pathDecoder.ts Adds WSL mount path translation and applies it during encoded project path decoding.
src/main/utils/metadataExtraction.ts Uses shared WSL mount translation when extracting authoritative cwd from session JSONL.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const match = /^\/mnt\/([a-zA-Z])(\/.*)?$/.exec(posixPath);
if (match) {
const drive = match[1].toUpperCase();
const rest = match[2] ?? '';
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

translateWslMountPath() returns "D:" for an input like "/mnt/d" (no trailing slash). On Windows, "D:" is not an absolute path (path.isAbsolute('D:') is false), which can break downstream path resolution and cause fallbacks back to POSIX paths. Consider defaulting the "rest" portion to "/" when the mount path has no trailing segment so the result is "D:/".

Suggested change
const rest = match[2] ?? '';
const rest = match[2] ?? '/';

Copilot uses AI. Check for mistakes.
// Ensure leading slash for POSIX-style absolute paths
return decodedPath.startsWith('/') ? decodedPath : `/${decodedPath}`;
const absolutePath = decodedPath.startsWith('/') ? decodedPath : `/${decodedPath}`;

Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change introduces Windows-only behavior (WSL mount translation) in decodePath()/extractCwd(), but there are no unit tests covering the translation cases (e.g., "/mnt/d/repo" -> "D:/repo", and "/mnt/d" -> "D:/"), nor a non-Windows no-op assertion. Since CI runs on both Ubuntu and Windows, adding conditional tests would help prevent regressions.

Suggested change
// On non-Windows platforms, return the POSIX-style absolute path unchanged
if (os.platform() !== 'win32') {
return absolutePath;
}

Copilot uses AI. Check for mistakes.
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a fix to correctly handle WSL mount paths by translating them to Windows drive-letter paths. A new utility function translateWslMountPath is added for this conversion and is used in decodePath and extractCwd. The implementation is well-focused, but I've found a minor bug in the new function where it fails to correctly handle paths pointing to the root of a drive, which I've commented on with a suggestion for a fix.

Comment on lines +108 to +109
const rest = match[2] ?? '';
return `${drive}:${rest}`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

When translating a WSL path that points to the root of a drive (e.g., /mnt/c), match[2] is undefined, and rest becomes ''. This results in returning C:, which is not a valid absolute path and can cause issues with path joining later. The path should be C:/. You can handle this more concisely.

Suggested change
const rest = match[2] ?? '';
return `${drive}:${rest}`;
return `${drive}:${match[2] || '/'}`;

@coderabbitai
Copy link

coderabbitai bot commented Mar 23, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d6c970b2-36c6-41b6-86eb-ceb1b706098a

📥 Commits

Reviewing files that changed from the base of the PR and between c239cda and ad25f0f.

📒 Files selected for processing (1)
  • vitest.config.ts
✅ Files skipped from review due to trivial changes (1)
  • vitest.config.ts

📝 Walkthrough

Walkthrough

Adds WSL-to-Windows path translation and applies it to decoded and extracted paths: translateWslMountPath() converts /mnt/<letter>/... to X:/... on Windows; decodePath() and extractCwd() now call this translator (with extractCwd() calling it before normalizeDriveLetter()).

Changes

Cohort / File(s) Summary
WSL Path Translation
src/main/utils/pathDecoder.ts, src/main/utils/metadataExtraction.ts
Added exported translateWslMountPath(posixPath: string): string that rewrites /mnt/<letter>(/...) to X:/... when process.platform === 'win32'. decodePath() now returns translateWslMountPath(absolutePath). extractCwd() applies translateWslMountPath(entry.cwd) before normalizeDriveLetter().

Possibly related PRs

🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive The vitest.config.ts timeout increase is loosely justified by CI performance but is not directly required by issue #118. Clarify whether the test timeout change is necessary for the PR's primary objectives or if it should be split into a separate commit for CI infrastructure improvements.
✅ Passed checks (1 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR implements WSL mount path translation in both decodePath() and extractCwd() as specified, with matching regex patterns and Windows-gated logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c239cda6e6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

rl.close();
fileStream.destroy();
return normalizeDriveLetter(entry.cwd);
return normalizeDriveLetter(translateWslMountPath(entry.cwd));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate WSL path translation to local sessions

On Windows hosts this now rewrites every cwd read from a session file, including files coming from SshFileSystemProvider. ProjectPathResolver.resolveProjectPath() still calls extractCwd() for fsProvider.type === 'ssh', so a remote Linux project rooted at /mnt/d/repo will now be surfaced as D:/repo in ProjectScanner and session exports even though the session is remote. That loses the real remote path and can point path-based UI/actions at an unrelated local drive when someone SSHes into a WSL/Unix machine that uses /mnt/<drive> mounts.

Useful? React with 👍 / 👎.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/utils/pathDecoder.ts`:
- Around line 101-110: The translateWslMountPath function returns "C:" for input
"/mnt/c", which is not an absolute Windows path; update the logic in
translateWslMountPath to default the captured tail to '/' instead of '' (change
the rest assignment from match[2] ?? '' to match[2] ?? '/') so the function
returns "C:/" for mount-root inputs, and add a unit test for the "/mnt/c" case
to assert the output is "C:/" (or otherwise absolute per path.win32.isAbsolute)
to prevent regression.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b97b06a1-e6c6-427a-abe3-f1f7414fe362

📥 Commits

Reviewing files that changed from the base of the PR and between ccdd34a and c239cda.

📒 Files selected for processing (2)
  • src/main/utils/metadataExtraction.ts
  • src/main/utils/pathDecoder.ts

Comment on lines +101 to +110
export function translateWslMountPath(posixPath: string): string {
if (process.platform !== 'win32') {
return posixPath;
}
const match = /^\/mnt\/([a-zA-Z])(\/.*)?$/.exec(posixPath);
if (match) {
const drive = match[1].toUpperCase();
const rest = match[2] ?? '';
return `${drive}:${rest}`;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Node.js on Windows, what does path.win32.isAbsolute('C:') return, and what is the correct absolute drive-root format?

💡 Result:

In Node.js on Windows, path.win32.isAbsolute('C:') returns false. The correct absolute drive-root format is 'C:\' or 'C:/' (drive letter followed by colon and path separator).

Citations:


🏁 Script executed:

# Find the pathDecoder.ts file and examine the function
find . -name "pathDecoder.ts" -type f | head -5

Repository: matt1398/claude-devtools

Length of output: 99


🏁 Script executed:

# Get the full context of the function and surrounding code
cat -n src/main/utils/pathDecoder.ts | sed -n '95,115p'

Repository: matt1398/claude-devtools

Length of output: 796


🏁 Script executed:

# Search for usage of translateWslMountPath in the codebase
rg "translateWslMountPath" -n -A 3 -B 1

Repository: matt1398/claude-devtools

Length of output: 1353


🏁 Script executed:

# Look for tests related to this function
find . -name "*.test.ts" -o -name "*.spec.ts" | xargs grep -l "translateWslMountPath" 2>/dev/null

Repository: matt1398/claude-devtools

Length of output: 52


🏁 Script executed:

# Check path.isAbsolute usage in the codebase to understand downstream expectations
rg "isAbsolute|path\..*Absolute" --type ts --type tsx -n | grep -E "(src/main|src/renderer)" | head -20

Repository: matt1398/claude-devtools

Length of output: 95


🏁 Script executed:

# Search for normalizeDriveLetter function definition
rg "normalizeDriveLetter" -n -B 2 -A 5 --type ts

Repository: matt1398/claude-devtools

Length of output: 1182


🏁 Script executed:

# Search for tests more carefully with proper syntax
fd "\.(test|spec)\.ts$" -x grep -l "translateWslMountPath\|pathDecoder"

Repository: matt1398/claude-devtools

Length of output: 146


🏁 Script executed:

# Look at the full context in metadataExtraction.ts to understand how the result is used
cat -n src/main/utils/metadataExtraction.ts | sed -n '60,70p'

Repository: matt1398/claude-devtools

Length of output: 483


🏁 Script executed:

# Check if pathDecoder has any imports or exports related to normalization
cat -n src/main/utils/pathDecoder.ts | head -50

Repository: matt1398/claude-devtools

Length of output: 2112


🏁 Script executed:

# Examine the pathDecoder test file to see existing test coverage
cat -n test/main/utils/pathDecoder.test.ts

Repository: matt1398/claude-devtools

Length of output: 9427


🏁 Script executed:

# Check if normalizeDriveLetter handles the slash issue
rg "normalizeDriveLetter" -A 10 -B 5 src/main/utils/metadataExtraction.ts | head -30

Repository: matt1398/claude-devtools

Length of output: 913


Normalize mount-root paths to X:/ format.

For input like /mnt/c, this currently returns C:, which is not an absolute path on Windows (path.win32.isAbsolute('C:') returns false). The function's contract explicitly documents the output format as X:/..., and downstream consumers assume absolute paths. Change line 108 from const rest = match[2] ?? ''; to const rest = match[2] ?? '/'; to produce C:/ instead.

Proposed fix
 export function translateWslMountPath(posixPath: string): string {
   if (process.platform !== 'win32') {
     return posixPath;
   }
   const match = /^\/mnt\/([a-zA-Z])(\/.*)?$/.exec(posixPath);
   if (match) {
     const drive = match[1].toUpperCase();
-    const rest = match[2] ?? '';
+    const rest = match[2] ?? '/';
     return `${drive}:${rest}`;
   }
   return posixPath;
 }

Also add test coverage for the /mnt/c case to prevent regression.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function translateWslMountPath(posixPath: string): string {
if (process.platform !== 'win32') {
return posixPath;
}
const match = /^\/mnt\/([a-zA-Z])(\/.*)?$/.exec(posixPath);
if (match) {
const drive = match[1].toUpperCase();
const rest = match[2] ?? '';
return `${drive}:${rest}`;
}
export function translateWslMountPath(posixPath: string): string {
if (process.platform !== 'win32') {
return posixPath;
}
const match = /^\/mnt\/([a-zA-Z])(\/.*)?$/.exec(posixPath);
if (match) {
const drive = match[1].toUpperCase();
const rest = match[2] ?? '/';
return `${drive}:${rest}`;
}
return posixPath;
}
🧰 Tools
🪛 GitHub Check: validate

[warning] 105-105:
Unsafe Regular Expression

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/utils/pathDecoder.ts` around lines 101 - 110, The
translateWslMountPath function returns "C:" for input "/mnt/c", which is not an
absolute Windows path; update the logic in translateWslMountPath to default the
captured tail to '/' instead of '' (change the rest assignment from match[2] ??
'' to match[2] ?? '/') so the function returns "C:/" for mount-root inputs, and
add a unit test for the "/mnt/c" case to assert the output is "C:/" (or
otherwise absolute per path.win32.isAbsolute) to prevent regression.

The default 5s timeout is too tight for Windows CI runners where
module collection alone can take 20s+.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matt1398 matt1398 merged commit f23e881 into main Mar 23, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WSL project paths decode to /mnt/d/... instead of D:\ on Windows

2 participants