mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-21 21:15:09 +00:00
fix(init): resolve Windows claude.exe only (#161)
* fix(init): resolve Windows claude.exe only Windows startup can resolve npm or Git Bash shims from PATH and then pass that path into shell-less child_process calls. Those .cmd, .bat, .ps1, or extensionless shim matches are not spawnable as the CLAUDE binary, so fail fast with a clear hint instead of returning an unusable path. No cli.js citation: this only changes local startup binary discovery and fatal diagnostics. It does not change any Class A/Class B endpoint, header, request field, response field, or wire behavior. Co-Authored-By: Codex <codex@openai.com> * fix(init): simplify Windows claude lookup Remove the redundant where.exe claude.exe probe and explain the intentional native .exe allow-list for shell-less Windows spawning. Alignment: no cli.js citation applies; this changes only local executable discovery and fatal diagnostics, not a Class A or Class B wire operation. Co-Authored-By: claude-flow <ruv@ruv.net> --------- Co-authored-by: nyxst4ck <289980115+nyxst4ck@users.noreply.github.com> Co-authored-by: Codex <codex@openai.com> Co-authored-by: nyxst4ck <nyxst4ck@users.noreply.github.com> Co-authored-by: claude-flow <ruv@ruv.net>
This commit is contained in:
co-authored by
nyxst4ck
Codex
nyxst4ck
claude-flow
parent
b7463a63f5
commit
d501e786b8
+51
-4
@@ -97,8 +97,40 @@ function _collectNodeManagerCandidates(home) {
|
|||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
function _joinIfBase(base, ...parts) {
|
||||||
|
return base ? join(base, ...parts) : null;
|
||||||
|
}
|
||||||
|
function _collectWindowsClaudeCandidates() {
|
||||||
|
const userProfile = process.env.USERPROFILE || process.env.HOME || "";
|
||||||
|
const localAppData = process.env.LOCALAPPDATA || "";
|
||||||
|
return [
|
||||||
|
_joinIfBase(userProfile, ".local", "bin", "claude.exe"),
|
||||||
|
_joinIfBase(localAppData, "Microsoft", "WinGet", "Links", "claude.exe"),
|
||||||
|
_joinIfBase(localAppData, "Microsoft", "WindowsApps", "claude.exe"),
|
||||||
|
].filter(Boolean);
|
||||||
|
}
|
||||||
|
function _isWindowsSpawnableBinary(path) {
|
||||||
|
return /\.exe$/i.test(path);
|
||||||
|
}
|
||||||
|
function _lookupLines(out) {
|
||||||
|
return out.split(/\r?\n/).map(line => line.trim()).filter(Boolean);
|
||||||
|
}
|
||||||
|
function _warnUnspawnableWindowsMatches(lines) {
|
||||||
|
const unspawnable = lines.filter(p => !/\.exe$/i.test(p));
|
||||||
|
if (unspawnable.length > 0) {
|
||||||
|
console.warn(`[init] Ignoring non-exe Windows claude command(s): ${unspawnable.join(", ")}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
function resolveClaude() {
|
function resolveClaude() {
|
||||||
|
const isWin = process.platform === "win32";
|
||||||
if (process.env.CLAUDE_BIN) {
|
if (process.env.CLAUDE_BIN) {
|
||||||
|
if (isWin && !_isWindowsSpawnableBinary(process.env.CLAUDE_BIN)) {
|
||||||
|
console.error(
|
||||||
|
`FATAL: CLAUDE_BIN="${process.env.CLAUDE_BIN}" is not a native Windows executable.\n` +
|
||||||
|
" Set CLAUDE_BIN to claude.exe; shell shims cannot be spawned without a shell."
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
accessSync(process.env.CLAUDE_BIN, constants.X_OK);
|
accessSync(process.env.CLAUDE_BIN, constants.X_OK);
|
||||||
return process.env.CLAUDE_BIN;
|
return process.env.CLAUDE_BIN;
|
||||||
@@ -108,8 +140,10 @@ function resolveClaude() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const home = process.env.HOME || "";
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
||||||
const candidates = [
|
const candidates = isWin
|
||||||
|
? _collectWindowsClaudeCandidates()
|
||||||
|
: [
|
||||||
"/opt/homebrew/bin/claude",
|
"/opt/homebrew/bin/claude",
|
||||||
"/usr/local/bin/claude",
|
"/usr/local/bin/claude",
|
||||||
"/usr/bin/claude",
|
"/usr/bin/claude",
|
||||||
@@ -120,16 +154,29 @@ function resolveClaude() {
|
|||||||
try { accessSync(p, constants.X_OK); console.warn(`[init] CLAUDE_BIN not set, resolved to ${p}`); return p; } catch {}
|
try { accessSync(p, constants.X_OK); console.warn(`[init] CLAUDE_BIN not set, resolved to ${p}`); return p; } catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isWin) {
|
||||||
|
try {
|
||||||
|
const lines = _lookupLines(execFileSync("where.exe", ["claude"], { encoding: "utf8", timeout: 5000 }));
|
||||||
|
const resolved = lines.find(_isWindowsSpawnableBinary);
|
||||||
|
if (resolved) { console.warn(`[init] CLAUDE_BIN not set, resolved via where.exe: ${resolved}`); return resolved; }
|
||||||
|
_warnUnspawnableWindowsMatches(lines);
|
||||||
|
} catch {}
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
const resolved = execFileSync("which", ["claude"], { encoding: "utf8", timeout: 5000 }).trim();
|
const resolved = execFileSync("which", ["claude"], { encoding: "utf8", timeout: 5000 }).trim();
|
||||||
if (resolved) { console.warn(`[init] CLAUDE_BIN not set, resolved via which: ${resolved}`); return resolved; }
|
if (resolved) { console.warn(`[init] CLAUDE_BIN not set, resolved via which: ${resolved}`); return resolved; }
|
||||||
} catch {}
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
console.error(
|
console.error(
|
||||||
"FATAL: claude binary not found.\n" +
|
"FATAL: claude binary not found.\n" +
|
||||||
" Set CLAUDE_BIN=/path/to/claude or ensure claude is in PATH.\n" +
|
(isWin
|
||||||
|
? " Set CLAUDE_BIN to the absolute path of claude.exe or ensure claude.exe is in PATH.\n" +
|
||||||
|
" Hint: npm .cmd/.bat/.ps1 shims cannot be spawned without a shell.\n" +
|
||||||
|
" The .exe requirement is an intentional allow-list for shell-less spawning.\n"
|
||||||
|
: " Set CLAUDE_BIN=/path/to/claude or ensure claude is in PATH.\n" +
|
||||||
" Hint: if you use nvm/fnm/asdf, set CLAUDE_BIN to the absolute path\n" +
|
" Hint: if you use nvm/fnm/asdf, set CLAUDE_BIN to the absolute path\n" +
|
||||||
" shown by `which claude` in your interactive shell.\n" +
|
" shown by `which claude` in your interactive shell.\n") +
|
||||||
" Checked: " + candidates.join(", ")
|
" Checked: " + candidates.join(", ")
|
||||||
);
|
);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user