Created
June 15, 2026 03:29
-
-
Save you06/a73648e6f9ff027235e4ff8a987dda35 to your computer and use it in GitHub Desktop.
claude.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env node | |
| // Transparent `claude` wrapper. `claude -p` is handled by claude-p; all | |
| // other invocations fall through to the real Claude CLI on PATH. | |
| /* | |
| # Quick Start | |
| ``` | |
| npm install -g claude-p | |
| # add this script to your PATH as `claude` (e.g. by symlinking it from /usr/local/bin) | |
| claude.js -p "Who are you" # proxy to claude-p | |
| claude.js -h # proxy to real Claude CLI on PATH | |
| ``` | |
| */ | |
| const { spawnSync } = require("node:child_process"); | |
| const fs = require("node:fs"); | |
| const path = require("node:path"); | |
| function platformDir() { | |
| return `${process.platform}-${process.arch}`; | |
| } | |
| function claudePBinaryName() { | |
| return process.platform === "win32" ? "claude-p.exe" : "claude-p"; | |
| } | |
| function stripPrintFlags(argv) { | |
| let sawPrint = false; | |
| const stripped = []; | |
| for (let i = 0; i < argv.length; i += 1) { | |
| const arg = argv[i]; | |
| if (arg === "--") { | |
| stripped.push(...argv.slice(i)); | |
| break; | |
| } | |
| if (arg === "-p" || arg === "--print") { | |
| sawPrint = true; | |
| continue; | |
| } | |
| stripped.push(arg); | |
| } | |
| return { sawPrint, argv: stripped }; | |
| } | |
| function sameFile(a, b) { | |
| try { | |
| return fs.realpathSync(a) === fs.realpathSync(b); | |
| } catch { | |
| return path.resolve(a) === path.resolve(b); | |
| } | |
| } | |
| function isExecutable(file) { | |
| try { | |
| fs.accessSync(file, fs.constants.X_OK); | |
| return fs.statSync(file).isFile(); | |
| } catch { | |
| return false; | |
| } | |
| } | |
| function pathEntries() { | |
| return (process.env.PATH || "").split(path.delimiter).filter(Boolean); | |
| } | |
| function findOnPath(names) { | |
| const seen = new Set(); | |
| for (const dir of pathEntries()) { | |
| for (const name of names) { | |
| const candidate = path.join(dir, name); | |
| if (seen.has(candidate)) continue; | |
| seen.add(candidate); | |
| if (isExecutable(candidate)) return candidate; | |
| } | |
| } | |
| return null; | |
| } | |
| function realScriptDir() { | |
| try { | |
| return path.dirname(fs.realpathSync(__filename)); | |
| } catch { | |
| return __dirname; | |
| } | |
| } | |
| function localClaudePBinary(root) { | |
| return path.join(root, "prebuilt", platformDir(), claudePBinaryName()); | |
| } | |
| function findClaudePBinary() { | |
| if (process.env.CLAUDE_P_BIN && isExecutable(process.env.CLAUDE_P_BIN)) { | |
| return process.env.CLAUDE_P_BIN; | |
| } | |
| const localCandidates = [ | |
| localClaudePBinary(path.join(realScriptDir(), "..")), | |
| localClaudePBinary(path.join(__dirname, "..")), | |
| ]; | |
| for (const candidate of localCandidates) { | |
| if (isExecutable(candidate)) return candidate; | |
| } | |
| return findOnPath([claudePBinaryName()]); | |
| } | |
| function findRealClaude() { | |
| const seen = new Set(); | |
| const selfPaths = [__filename]; | |
| if (process.argv[1]) selfPaths.push(process.argv[1]); | |
| for (const dir of pathEntries()) { | |
| const candidate = path.join(dir, "claude"); | |
| if (seen.has(candidate)) continue; | |
| seen.add(candidate); | |
| if (!isExecutable(candidate)) continue; | |
| if (selfPaths.some((self) => sameFile(candidate, self))) continue; | |
| return candidate; | |
| } | |
| return null; | |
| } | |
| function run(command, argv) { | |
| const result = spawnSync(command, argv, { stdio: "inherit" }); | |
| if (result.error) { | |
| console.error("claude:", result.error.message); | |
| process.exit(2); | |
| } | |
| if (result.signal) { | |
| process.kill(process.pid, result.signal); | |
| return; | |
| } | |
| process.exit(result.status ?? 0); | |
| } | |
| function main() { | |
| const parsed = stripPrintFlags(process.argv.slice(2)); | |
| if (parsed.sawPrint) { | |
| const claudeP = findClaudePBinary(); | |
| if (!claudeP) { | |
| console.error( | |
| "claude: claude-p binary not found for print invocation\n" + | |
| "Re-run `npm install claude-p` or build from source with `zig build`.", | |
| ); | |
| process.exit(2); | |
| } | |
| run(claudeP, parsed.argv); | |
| return; | |
| } | |
| const realClaude = findRealClaude(); | |
| if (!realClaude) { | |
| console.error( | |
| "claude: real Claude CLI not found on PATH for non-print invocation", | |
| ); | |
| process.exit(2); | |
| } | |
| run(realClaude, process.argv.slice(2)); | |
| } | |
| main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment