Skip to content

Instantly share code, notes, and snippets.

@you06
Created June 15, 2026 03:29
Show Gist options
  • Select an option

  • Save you06/a73648e6f9ff027235e4ff8a987dda35 to your computer and use it in GitHub Desktop.

Select an option

Save you06/a73648e6f9ff027235e4ff8a987dda35 to your computer and use it in GitHub Desktop.
claude.js
#!/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