From e911840dda143b2b06944c673ee075c6008b81b6 Mon Sep 17 00:00:00 2001 From: kerwin612 Date: Tue, 3 Feb 2026 15:47:18 +0800 Subject: [PATCH] Fix Windows path resolution for claude-trace and claude-bridge --- apps/claude-bridge/src/cli.ts | 98 +++++++++++++++++--- apps/claude-trace/package.json | 2 +- apps/claude-trace/src/cli.ts | 98 +++++++++++++++++--- package-lock.json | 165 ++++++++++++++++++++++++++++++++- 4 files changed, 333 insertions(+), 30 deletions(-) diff --git a/apps/claude-bridge/src/cli.ts b/apps/claude-bridge/src/cli.ts index 5213ff4..c676ac1 100644 --- a/apps/claude-bridge/src/cli.ts +++ b/apps/claude-bridge/src/cli.ts @@ -410,6 +410,60 @@ function validateProviderAndModel(provider?: string, model?: string): { provider return { provider, model }; } +/** + * Convert MSYS2/Git Bash style paths to Windows paths + * E.g., /c/Users/name/path -> C:\Users\name\path + */ +function convertMsys2Path(inputPath: string): string { + // Check if it's a MSYS2/Git Bash style path (e.g., /c/users/...) + const msys2Match = inputPath.match(/^\/([a-zA-Z])\/(.*)/); + if (msys2Match) { + const drive = msys2Match[1].toUpperCase(); + const rest = msys2Match[2]; + return `${drive}:\\${rest.replace(/\//g, "\\")}`; + } + return inputPath; +} + +/** + * Extract JS file path from npm bash shim script + * Looks for patterns like: $basedir/...cli.js or "path/to/cli.js" + */ +function extractJsFromBashScript(scriptContent: string, baseDir: string): string | null { + // Try to find JS file reference patterns + const patterns = [ + // Pattern 1: basedir/node_modules/.../cli.js + /\$basedir\/(.+?\.js)/, + // Pattern 2: Direct quoted paths + /"([^"]+\.js)"/, + // Pattern 3: Unquoted paths + /([a-zA-Z]:\/[^\s]+\.js)/, + /([a-zA-Z]:\\[^\s]+\.js)/, + ]; + + for (const pattern of patterns) { + const match = scriptContent.match(pattern); + if (match && match[1]) { + let jsPath = match[1]; + + // If it's a basedir reference, resolve it + if (jsPath.includes("$basedir")) { + jsPath = jsPath.replace(/\$basedir/, baseDir); + } + + // Convert to Windows path if needed + jsPath = convertMsys2Path(jsPath); + + // Verify the file exists + if (fs.existsSync(jsPath)) { + return jsPath; + } + } + } + + return null; +} + function resolveToJsFile(filePath: string): string { try { // First, resolve any symlinks @@ -470,22 +524,41 @@ function findClaudeExecutable(customPath?: string): string { encoding: "utf-8", }).trim(); + // Convert MSYS2/Git Bash style paths to Windows paths if necessary + claudePath = convertMsys2Path(claudePath); + // Handle shell aliases (e.g., "claude: aliased to /path/to/claude") const aliasMatch = claudePath.match(/:\s*aliased to\s+(.+)$/); if (aliasMatch && aliasMatch[1]) { - claudePath = aliasMatch[1]; + claudePath = convertMsys2Path(aliasMatch[1]); } // Check if the path is a bash wrapper if (fs.existsSync(claudePath)) { const content = fs.readFileSync(claudePath, "utf-8"); - if (content.startsWith("#!/bin/bash")) { - // Parse bash wrapper to find actual executable - const execMatch = content.match(/exec\s+"([^"]+)"/); - if (execMatch && execMatch[1]) { - const actualPath = execMatch[1]; - // Resolve any symlinks to get the final JS file - return resolveToJsFile(actualPath); + if (content.startsWith("#!/bin/bash") || content.startsWith("#!/bin/sh")) { + // Extract the base directory from the bash script + const baseDir = path.dirname(claudePath); + + // Try to extract JS file path from bash script + const jsPath = extractJsFromBashScript(content, baseDir); + if (jsPath && fs.existsSync(jsPath)) { + return resolveToJsFile(jsPath); + } + + // Fallback: look for common npm locations + const npmGlobalDir = baseDir; + const possiblePaths = [ + path.join(npmGlobalDir, "node_modules", "@anthropic-ai", "claude-code", "dist", "cli.js"), + path.join(npmGlobalDir, "node_modules", "@anthropic-ai", "claude-code", "cli.js"), + path.join(npmGlobalDir, "node_modules", "claude", "bin", "cli.js"), + path.join(npmGlobalDir, "node_modules", "claude", "dist", "cli.js"), + ]; + + for (const possiblePath of possiblePaths) { + if (fs.existsSync(possiblePath)) { + return resolveToJsFile(possiblePath); + } } } } @@ -497,10 +570,11 @@ function findClaudeExecutable(customPath?: string): string { if (fs.existsSync(localClaudeWrapper)) { const content = fs.readFileSync(localClaudeWrapper, "utf-8"); - if (content.startsWith("#!/bin/bash")) { - const execMatch = content.match(/exec\s+"([^"]+)"/); - if (execMatch && execMatch[1]) { - return resolveToJsFile(execMatch[1]); + if (content.startsWith("#!/bin/bash") || content.startsWith("#!/bin/sh")) { + const baseDir = path.dirname(localClaudeWrapper); + const jsPath = extractJsFromBashScript(content, baseDir); + if (jsPath && fs.existsSync(jsPath)) { + return resolveToJsFile(jsPath); } } } diff --git a/apps/claude-trace/package.json b/apps/claude-trace/package.json index a3a90fc..8e9e4a3 100644 --- a/apps/claude-trace/package.json +++ b/apps/claude-trace/package.json @@ -49,7 +49,7 @@ "typescript": "^5.0.0" }, "dependencies": { - "@anthropic-ai/claude-code": "^1.0.0", + "@anthropic-ai/claude-code": "^2.1.29", "@anthropic-ai/sdk": "^0.52.0", "@mariozechner/claude-trace": "^1.0.3" }, diff --git a/apps/claude-trace/src/cli.ts b/apps/claude-trace/src/cli.ts index ad13e33..6dfa7e2 100644 --- a/apps/claude-trace/src/cli.ts +++ b/apps/claude-trace/src/cli.ts @@ -104,6 +104,60 @@ For more information, visit: https://github.com/mariozechner/claude-trace `); } +/** + * Convert MSYS2/Git Bash style paths to Windows paths + * E.g., /c/Users/name/path -> C:\Users\name\path + */ +function convertMsys2Path(inputPath: string): string { + // Check if it's a MSYS2/Git Bash style path (e.g., /c/users/...) + const msys2Match = inputPath.match(/^\/([a-zA-Z])\/(.*)/); + if (msys2Match) { + const drive = msys2Match[1].toUpperCase(); + const rest = msys2Match[2]; + return `${drive}:\\${rest.replace(/\//g, "\\")}`; + } + return inputPath; +} + +/** + * Extract JS file path from npm bash shim script + * Looks for patterns like: $basedir/...cli.js or "path/to/cli.js" + */ +function extractJsFromBashScript(scriptContent: string, baseDir: string): string | null { + // Try to find JS file reference patterns + const patterns = [ + // Pattern 1: basedir/node_modules/.../cli.js + /\$basedir\/(.+?\.js)/, + // Pattern 2: Direct quoted paths + /"([^"]+\.js)"/, + // Pattern 3: Unquoted paths + /([a-zA-Z]:\/[^\s]+\.js)/, + /([a-zA-Z]:\\[^\s]+\.js)/, + ]; + + for (const pattern of patterns) { + const match = scriptContent.match(pattern); + if (match && match[1]) { + let jsPath = match[1]; + + // If it's a basedir reference, resolve it + if (jsPath.includes("$basedir")) { + jsPath = jsPath.replace(/\$basedir/, baseDir); + } + + // Convert to Windows path if needed + jsPath = convertMsys2Path(jsPath); + + // Verify the file exists + if (fs.existsSync(jsPath)) { + return jsPath; + } + } + } + + return null; +} + function resolveToJsFile(filePath: string): string { try { // First, resolve any symlinks @@ -167,22 +221,41 @@ function getClaudeAbsolutePath(customPath?: string): string { }) .trim(); + // Convert MSYS2/Git Bash style paths to Windows paths if necessary + claudePath = convertMsys2Path(claudePath); + // Handle shell aliases (e.g., "claude: aliased to /path/to/claude") const aliasMatch = claudePath.match(/:\s*aliased to\s+(.+)$/); if (aliasMatch && aliasMatch[1]) { - claudePath = aliasMatch[1]; + claudePath = convertMsys2Path(aliasMatch[1]); } // Check if the path is a bash wrapper if (fs.existsSync(claudePath)) { const content = fs.readFileSync(claudePath, "utf-8"); - if (content.startsWith("#!/bin/bash")) { - // Parse bash wrapper to find actual executable - const execMatch = content.match(/exec\s+"([^"]+)"/); - if (execMatch && execMatch[1]) { - const actualPath = execMatch[1]; - // Resolve any symlinks to get the final JS file - return resolveToJsFile(actualPath); + if (content.startsWith("#!/bin/bash") || content.startsWith("#!/bin/sh")) { + // Extract the base directory from the bash script + const baseDir = path.dirname(claudePath); + + // Try to extract JS file path from bash script + const jsPath = extractJsFromBashScript(content, baseDir); + if (jsPath && fs.existsSync(jsPath)) { + return resolveToJsFile(jsPath); + } + + // Fallback: look for common npm locations + const npmGlobalDir = baseDir; + const possiblePaths = [ + path.join(npmGlobalDir, "node_modules", "@anthropic-ai", "claude-code", "dist", "cli.js"), + path.join(npmGlobalDir, "node_modules", "@anthropic-ai", "claude-code", "cli.js"), + path.join(npmGlobalDir, "node_modules", "claude", "bin", "cli.js"), + path.join(npmGlobalDir, "node_modules", "claude", "dist", "cli.js"), + ]; + + for (const possiblePath of possiblePaths) { + if (fs.existsSync(possiblePath)) { + return resolveToJsFile(possiblePath); + } } } } @@ -195,10 +268,11 @@ function getClaudeAbsolutePath(customPath?: string): string { if (fs.existsSync(localClaudeWrapper)) { const content = fs.readFileSync(localClaudeWrapper, "utf-8"); - if (content.startsWith("#!/bin/bash")) { - const execMatch = content.match(/exec\s+"([^"]+)"/); - if (execMatch && execMatch[1]) { - return resolveToJsFile(execMatch[1]); + if (content.startsWith("#!/bin/bash") || content.startsWith("#!/bin/sh")) { + const baseDir = path.dirname(localClaudeWrapper); + const jsPath = extractJsFromBashScript(content, baseDir); + if (jsPath && fs.existsSync(jsPath)) { + return resolveToJsFile(jsPath); } } } diff --git a/package-lock.json b/package-lock.json index 06b7288..45deab6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -77,7 +77,7 @@ "version": "1.0.8", "license": "MIT", "dependencies": { - "@anthropic-ai/claude-code": "^1.0.0", + "@anthropic-ai/claude-code": "^2.1.29", "@anthropic-ai/sdk": "^0.52.0", "@mariozechner/claude-trace": "^1.0.3" }, @@ -381,10 +381,9 @@ } }, "node_modules/@anthropic-ai/claude-code": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-1.0.0.tgz", - "integrity": "sha512-5+FV9oNtV3sZ8rq1pw3B6KX24Ib+qs9FoLR1ghxOAzk4ZXKzCSSHhW4GOWJy+6N9926KHN2wFNVcuZC9NW75Xg==", - "hasInstallScript": true, + "version": "2.1.29", + "resolved": "https://registry.npmmirror.com/@anthropic-ai/claude-code/-/claude-code-2.1.29.tgz", + "integrity": "sha512-vMHTOXrYdnreGtKUsWdd3Bwx5fKprTyNG7shrvbx3L2/jU9jexkOJrEKmN5loeR5jrE54LSB38QpaIj8pVM6eQ==", "license": "SEE LICENSE IN README.md", "bin": { "claude": "cli.js" @@ -394,8 +393,12 @@ }, "optionalDependencies": { "@img/sharp-darwin-arm64": "^0.33.5", + "@img/sharp-darwin-x64": "^0.33.5", "@img/sharp-linux-arm": "^0.33.5", + "@img/sharp-linux-arm64": "^0.33.5", "@img/sharp-linux-x64": "^0.33.5", + "@img/sharp-linuxmusl-arm64": "^0.33.5", + "@img/sharp-linuxmusl-x64": "^0.33.5", "@img/sharp-win32-x64": "^0.33.5" } }, @@ -873,6 +876,28 @@ "@img/sharp-libvips-darwin-arm64": "1.0.4" } }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, "node_modules/@img/sharp-libvips-darwin-arm64": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", @@ -889,6 +914,22 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-libvips-linux-arm": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", @@ -905,6 +946,22 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-libvips-linux-x64": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", @@ -921,6 +978,38 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-linux-arm": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", @@ -943,6 +1032,28 @@ "@img/sharp-libvips-linux-arm": "1.0.5" } }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, "node_modules/@img/sharp-linux-x64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", @@ -965,6 +1076,50 @@ "@img/sharp-libvips-linux-x64": "1.0.4" } }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, "node_modules/@img/sharp-win32-x64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",