claude-code-pathfix 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +129 -0
- package/index.js +60 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 fnrhombus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# claude-code-pathfix
|
|
2
|
+
|
|
3
|
+
**Stop burning tokens on Windows path errors.**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/claude-code-pathfix)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
Every time Claude Code generates a Bash command on Windows, there's a coin flip: will it use `D:\Users\Tom\file.txt` or `/d/Users/Tom/file.txt`? The wrong one fails, Claude reasons about the error, retries, sometimes fails again — and you pay for every token.
|
|
9
|
+
|
|
10
|
+
**`claude-code-pathfix` makes the problem disappear.** It's a zero-config [PreToolUse hook](https://docs.anthropic.com/en/docs/claude-code/hooks) that silently rewrites Windows paths to POSIX format before Bash commands execute. No errors. No retries. No wasted tokens.
|
|
11
|
+
|
|
12
|
+
## The problem
|
|
13
|
+
|
|
14
|
+
Claude Code runs Bash (Git Bash / MSYS2) on Windows, but the AI constantly generates Windows-style paths:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# What Claude generates
|
|
18
|
+
cat D:\Users\Tom\.claude\settings.json
|
|
19
|
+
git -C C:\dev\myproject status
|
|
20
|
+
ls "C:\Program Files\Git\bin"
|
|
21
|
+
|
|
22
|
+
# What Git Bash actually needs
|
|
23
|
+
cat /d/Users/Tom/.claude/settings.json
|
|
24
|
+
git -C /c/dev/myproject status
|
|
25
|
+
ls "/c/Program Files/Git/bin"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Each failure triggers a retry loop:
|
|
29
|
+
|
|
30
|
+
1. Command fails → error message (tokens spent)
|
|
31
|
+
2. Claude reasons about the error (more tokens spent)
|
|
32
|
+
3. Claude retries with a corrected path (even more tokens)
|
|
33
|
+
4. Sometimes repeats 3-4 times before succeeding
|
|
34
|
+
|
|
35
|
+
This is **the most common source of wasted tokens on Windows.** There are [15+ open issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue+windows+path) about it in the Claude Code repo.
|
|
36
|
+
|
|
37
|
+
## The fix
|
|
38
|
+
|
|
39
|
+
Install `claude-code-pathfix` and add two lines to your settings. Every Bash command is silently intercepted, paths are converted, and the corrected command executes on the first try.
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
Before: 3-4 attempts per path error × multiple errors per session = hundreds of wasted tokens
|
|
43
|
+
After: zero failures, zero retries, zero wasted tokens
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Prior art
|
|
47
|
+
|
|
48
|
+
The blog post [*Fixing Claude Code's PowerShell Problem with Hooks*](https://blog.netnerds.net/2026/02/claude-code-powershell-hooks/) pioneered the idea of using hooks to catch Windows path errors. That approach **blocks** commands with bad paths and forces Claude to retry with the correct format — a "block-and-correct" pattern. The author reported going from *"three attempts per PowerShell operation"* to *"zero failures."*
|
|
49
|
+
|
|
50
|
+
`claude-code-pathfix` takes this further:
|
|
51
|
+
|
|
52
|
+
| | netnerds.net approach | claude-code-pathfix |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| **Mechanism** | Block the command, force a retry | Transparently rewrite the command |
|
|
55
|
+
| **Retries needed** | 1 (Claude must resubmit) | 0 (fixed before execution) |
|
|
56
|
+
| **Tokens saved** | ~60% of retry cost | ~100% of retry cost |
|
|
57
|
+
| **Claude awareness** | Claude sees the block, reasons about it | Claude never knows — command just works |
|
|
58
|
+
| **Scope** | PowerShell commands | All Bash commands |
|
|
59
|
+
|
|
60
|
+
The key difference: blocking still costs a round-trip. Claude sees the error, thinks about it, and resubmits — that's tokens spent on reasoning about a problem that could have been silently fixed. `claude-code-pathfix` uses Claude Code's [`updatedInput`](https://docs.anthropic.com/en/docs/claude-code/hooks) feature (shipped in v2.0.10) to rewrite the command in-flight. The AI never sees an error because there isn't one.
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
Add this to your Claude Code settings (`~/.claude/settings.json`):
|
|
65
|
+
|
|
66
|
+
```jsonc
|
|
67
|
+
{
|
|
68
|
+
"hooks": {
|
|
69
|
+
"PreToolUse": [
|
|
70
|
+
{
|
|
71
|
+
"matcher": "Bash",
|
|
72
|
+
"hooks": [
|
|
73
|
+
{
|
|
74
|
+
"type": "command",
|
|
75
|
+
"command": "npx -y claude-code-pathfix"
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
That's it. One step. `npx` downloads and caches the package automatically on first run — no global install needed.
|
|
85
|
+
|
|
86
|
+
## What it converts
|
|
87
|
+
|
|
88
|
+
| Input | Output |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `D:\Users\Tom\file.txt` | `/d/Users/Tom/file.txt` |
|
|
91
|
+
| `C:\dev\myproject\src\index.ts` | `/c/dev/myproject/src/index.ts` |
|
|
92
|
+
| `"C:\Program Files\Git\bin"` | `"/c/Program Files/Git/bin"` |
|
|
93
|
+
| `E:\data\export\` | `/e/data/export/` |
|
|
94
|
+
|
|
95
|
+
### What it doesn't touch
|
|
96
|
+
|
|
97
|
+
- Paths that are already POSIX (`/d/Users/Tom/...`)
|
|
98
|
+
- Relative paths (`../src/file.ts`)
|
|
99
|
+
- URLs (`https://example.com`)
|
|
100
|
+
- Escape sequences (`\n`, `\t`)
|
|
101
|
+
- Non-path backslash usage (`grep 'foo\|bar'`)
|
|
102
|
+
|
|
103
|
+
## Cross-platform safe
|
|
104
|
+
|
|
105
|
+
**If your Claude Code settings are symlinked across Windows and WSL** (a common setup), `claude-code-pathfix` detects the platform at startup and silently exits on non-Windows systems. It will never interfere with native Linux or macOS Bash commands.
|
|
106
|
+
|
|
107
|
+
## Performance
|
|
108
|
+
|
|
109
|
+
The hook is a single Node.js script with **zero dependencies**. It starts in under 10ms — compared to 200-500ms for hooks that spawn a Bash subshell ([#34457](https://github.com/anthropics/claude-code/issues/34457)). You won't notice it's there.
|
|
110
|
+
|
|
111
|
+
## How it works
|
|
112
|
+
|
|
113
|
+
1. Claude Code's `PreToolUse` event fires before every Bash command
|
|
114
|
+
2. `claude-code-pathfix` reads the command from stdin
|
|
115
|
+
3. A two-pass regex converts Windows absolute paths to POSIX format:
|
|
116
|
+
- Pass 1: quoted paths (handles spaces in paths like `"C:\Program Files\..."`)
|
|
117
|
+
- Pass 2: unquoted paths
|
|
118
|
+
4. If any paths were converted, the fixed command is returned via `updatedInput`
|
|
119
|
+
5. If nothing changed, the hook exits silently (no output = no modification)
|
|
120
|
+
|
|
121
|
+
## Requirements
|
|
122
|
+
|
|
123
|
+
- **Claude Code** v2.0.10+ (for `updatedInput` hook support)
|
|
124
|
+
- **Node.js** 14+ (any version that ships with Claude Code works)
|
|
125
|
+
- **Windows** with Git Bash or MSYS2
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// claude-code-pathfix
|
|
4
|
+
// PreToolUse hook: transparently converts Windows paths to POSIX in Bash commands
|
|
5
|
+
// https://github.com/fnrhombus/claude-code-pathfix
|
|
6
|
+
|
|
7
|
+
// No-op on non-Windows platforms (safe for symlinked settings across WSL/Windows)
|
|
8
|
+
if (process.platform !== 'win32') process.exit(0);
|
|
9
|
+
|
|
10
|
+
let input = '';
|
|
11
|
+
process.stdin.setEncoding('utf8');
|
|
12
|
+
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
13
|
+
process.stdin.on('end', () => {
|
|
14
|
+
try {
|
|
15
|
+
const data = JSON.parse(input);
|
|
16
|
+
|
|
17
|
+
if (data.tool_name !== 'Bash') return;
|
|
18
|
+
|
|
19
|
+
const command = data.tool_input?.command;
|
|
20
|
+
if (!command) return;
|
|
21
|
+
|
|
22
|
+
const fixed = fixWindowsPaths(command);
|
|
23
|
+
|
|
24
|
+
if (fixed === command) return;
|
|
25
|
+
|
|
26
|
+
process.stdout.write(JSON.stringify({
|
|
27
|
+
hookSpecificOutput: {
|
|
28
|
+
hookEventName: 'PreToolUse',
|
|
29
|
+
updatedInput: { ...data.tool_input, command: fixed },
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
} catch {
|
|
33
|
+
// Silent failure — never block the command
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Convert Windows-style absolute paths to POSIX (Git Bash / MSYS2) format.
|
|
39
|
+
*
|
|
40
|
+
* D:\Users\Tom\file.txt → /d/Users/Tom/file.txt
|
|
41
|
+
* "C:\Program Files\Git\bin" → "/c/Program Files/Git/bin"
|
|
42
|
+
* C:\repo\src\index.ts → /c/repo/src/index.ts
|
|
43
|
+
*/
|
|
44
|
+
function fixWindowsPaths(command) {
|
|
45
|
+
// Pass 1: paths inside double quotes (may contain spaces)
|
|
46
|
+
let result = command.replace(
|
|
47
|
+
/"([A-Za-z]):((?:\\[^"*?<>|\n\r]+?)+\\?)"/g,
|
|
48
|
+
(_, drive, tail) => '"/' + drive.toLowerCase() + tail.replace(/\\/g, '/') + '"',
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// Pass 2: unquoted paths (no spaces)
|
|
52
|
+
result = result.replace(
|
|
53
|
+
/(?<![/\w])([A-Za-z]):((?:\\[^\s\\*?"<>|]+)+\\?)/g,
|
|
54
|
+
(_, drive, tail) => '/' + drive.toLowerCase() + tail.replace(/\\/g, '/'),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = { fixWindowsPaths };
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-code-pathfix",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Claude Code hook that transparently converts Windows paths to POSIX in Bash commands — eliminating retry loops and saving tokens",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"claude-code-pathfix": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"claude-code",
|
|
14
|
+
"claude",
|
|
15
|
+
"hook",
|
|
16
|
+
"windows",
|
|
17
|
+
"path",
|
|
18
|
+
"posix",
|
|
19
|
+
"git-bash",
|
|
20
|
+
"msys2",
|
|
21
|
+
"wsl",
|
|
22
|
+
"token-saving",
|
|
23
|
+
"developer-tools",
|
|
24
|
+
"ai-coding",
|
|
25
|
+
"mcp"
|
|
26
|
+
],
|
|
27
|
+
"author": "fnrhombus",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/fnrhombus/claude-code-pathfix.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/fnrhombus/claude-code-pathfix/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/fnrhombus/claude-code-pathfix#readme",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=14.0.0"
|
|
39
|
+
}
|
|
40
|
+
}
|