Skip to content

Conversation

@nielpattin
Copy link

@nielpattin nielpattin commented Dec 24, 2025

Fix MSYS/Git Bash path handling on Windows

Summary

  • Add toNativePath() to convert MSYS/Git Bash/Cygwin paths (/c/Users/...) to Windows paths (C:\Users\...)
  • Add safeRelative() to handle cross-drive paths and deep parent traversals
  • Fix TUI path display with Locale.truncateMiddle for long paths

Details

When running opencode in Git Bash on Windows, the shell uses POSIX-style paths (/f/test/file.txt) but Node.js/Bun APIs expect Windows paths (F:\test\file.txt). This caused:

  1. File operations failing - ENOENT: no such file or directory because Node can't resolve /f/... paths
  2. Garbage display - path.relative() across different drives produced ..\..\..\..\..\..\f\test
  3. Long paths unreadable - No truncation for deeply nested paths

Before

→ Read ..\..\..\..\..\..\..\f\test\file.txt
Error: ENOENT: no such file or directory

After

→ Read F:\test\file.txt

Files Changed

  • packages/opencode/src/util/filesystem.ts - Added toNativePath() and safeRelative()
  • packages/opencode/src/tool/*.ts - Applied path conversion at entry points (read, write, edit, glob, grep, ls, patch)
  • packages/opencode/src/cli/cmd/tui/routes/session/index.tsx - Fixed TUI display with path abbreviation

Test Cases

Setup (run once in Git Bash)

# Cross-drive test files (F: drive)
mkdir -p /f/test
echo "hello world foo bar" > /f/test/test.txt
echo "another hello" > /f/test/test2.txt

# Long nested path on different drive
mkdir -p /f/test/very/deeply/nested/folder/structure/that/is/really/long
echo "deeply nested content" > /f/test/very/deeply/nested/folder/structure/that/is/really/long/file.txt

# Parent traversal test files (same drive, different depths)
mkdir -p /c/Users/<user_name>/repo/sst/testdir
echo "2 levels up" > /c/Users/<user_name>/repo/sst/testdir/two-up.txt

mkdir -p /c/Users/<user_name>/repo/testdir
echo "3 levels up" > /c/Users/<user_name>/repo/testdir/three-up.txt

# Long nested path inside worktree
mkdir -p /c/Users/<user_name>/repo/sst/opencode/very/deeply/nested/folder/structure/that/is/really/long
echo "deep test" > /c/Users/<user_name>/repo/sst/opencode/very/deeply/nested/folder/structure/that/is/really/long/file.txt

I don't touch LSP or MultipleEdit tools because unsure about those. (But it's working by default)

Feature 1: MSYS/Git Bash Path Conversion

Tests that /c/... and /f/... paths are converted to C:\... and F:\....

LIST Tool

Use the LIST tool to show all files in /f/test/

Expected: → List F:\test (not ..\..\..\..\f\test)

READ Tool

Use the READ tool to read /f/test/test.txt

Expected: → Read F:\test\test.txt

WRITE Tool

Use the WRITE tool to create /f/test/write-test.txt with content "written by opencode"

Expected: → Wrote F:\test\write-test.txt

EDIT Tool

Use the EDIT tool to replace "hello" with "goodbye" in /f/test/test.txt

Expected: → Edit F:\test\test.txt

GLOB Tool

Use the GLOB tool to find all *.txt files in /f/test/

Expected: → ✱ Glob "*.txt" in F:\test\ (4 matches)

GREP Tool

Use the GREP tool to search for "hello" in /f/test/

Expected: → ✱ Grep "hello" in F:\test\ (1 matches)


Feature 2: Parent Traversal Threshold (3+)

Paths with 3+ parent traversals (../../..) show absolute path. Paths with 0-2 show relative.

2 levels up - shows RELATIVE

Use the READ tool to read /c/Users/<user_name>/repo/sst/opencode/PR.md

Expected: → Read ..\..\.PR.md (relative path)

3+ levels up - shows ABSOLUTE

Use the READ tool to read /c/Users/<user_name>/repo/testdir/three-up.txt

Expected: → Read C:\Users\<user_name>\repo\testdir\three-up.txt (absolute path)

Use the READ tool to read /c/Users/<user_name>/.config/opencode/opencode.jsonc

Expected: → Read C:\Users\<user_name>\.config\opencode\opencode.jsonc (absolute path)


Feature 3: Long Path Truncation

Long paths are truncated with ... in the middle, using Locale.truncateMiddle.

Long path on different drive

Use the READ tool to read /f/test/very/deeply/nested/folder/structure/that/is/really/long/file.txt

Expected: → Read F:\test\very\deeply\…\that\is\really\long\file.txt (truncated)

Long path inside worktree

Use the READ tool to read /c/Users/<user_name>/repo/sst/opencode/very/deeply/nested/folder/structure/that/is/really/long/file.txt

Expected: → Read ..\..\very\deeply\ne…\that\is\really\long\file.txt (truncated relative path)


Checklist

  • No-op on non-Windows platforms for toNativePath() (gated by process.platform === "win32")
  • Parent traversal check (3+) applies to ALL platforms
  • Uses existing Locale.truncateMiddle for path abbreviation (consistent with sidebar)
  • No breaking changes for normal Windows or Unix paths

- Add safeRelative() for cross-drive and deep parent traversal paths
- Fix TUI path display with truncation for long paths
@nielpattin nielpattin mentioned this pull request Dec 24, 2025
@rekram1-node
Copy link
Collaborator

/review

@nielpattin
Copy link
Author

@rekram1-node lgtm after refactor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants