mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
fix(cli/bin): stop delegating to system 'code' (VS Code) when invoked via npm/npx; always run bundled binary and show path\n\n- Remove fragile delegation heuristic that caused to open VS Code\n- Print a concise notice under npx showing the exact binary path in use\n- Keep postinstall collision handling for global installs unchanged\n\nThis restores expected behavior and makes collisions visible during npx runs.
This commit is contained in:
+31
-51
@@ -3,8 +3,6 @@
|
||||
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { realpathSync, accessSync, constants } from "fs";
|
||||
import { spawnSync } from "child_process";
|
||||
|
||||
// __dirname equivalent in ESM
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
@@ -12,55 +10,9 @@ const __dirname = path.dirname(__filename);
|
||||
|
||||
const { platform, arch } = process;
|
||||
|
||||
// If invoked as "code" and another "code" exists in PATH that is not
|
||||
// this package's launcher, delegate to it (e.g., VS Code's CLI).
|
||||
// This avoids hijacking users who already have VS Code installed.
|
||||
const maybeDelegateToOtherCode = () => {
|
||||
try {
|
||||
const invoked = process.env._ || "";
|
||||
const invokedBase = path.basename(invoked);
|
||||
if (invokedBase !== "code") return false;
|
||||
|
||||
const ourScriptReal = realpathSync(process.argv[1]);
|
||||
|
||||
const which = spawnSync("bash", ["-lc", "which -a code 2>/dev/null"], {
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
});
|
||||
if (which.status !== 0 || !which.stdout) return false;
|
||||
|
||||
const candidates = which.stdout
|
||||
.split(/\r?\n/)
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
for (const c of candidates) {
|
||||
// Skip the path that was used to invoke us
|
||||
if (c === invoked) continue;
|
||||
try {
|
||||
const real = realpathSync(c);
|
||||
// Skip if it resolves to our own script (same file inside our package)
|
||||
if (real === ourScriptReal) continue;
|
||||
|
||||
// Ensure it's executable; if so, exec and mirror exit code
|
||||
accessSync(c, constants.X_OK);
|
||||
const run = spawnSync(c, process.argv.slice(2), {
|
||||
stdio: "inherit",
|
||||
});
|
||||
// If it executed (even with non-zero), we consider delegation done.
|
||||
const code = run.status == null ? 1 : run.status;
|
||||
process.exit(code);
|
||||
} catch {
|
||||
// Try next candidate
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Fall through to our own binary
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
maybeDelegateToOtherCode();
|
||||
// Important: Never delegate to another system's `code` binary (e.g., VS Code).
|
||||
// When users run via `npx @just-every/code`, we must always execute our
|
||||
// packaged native binary by absolute path to avoid PATH collisions.
|
||||
|
||||
const isWSL = () => {
|
||||
if (platform !== "linux") return false;
|
||||
@@ -130,6 +82,7 @@ if (!existsSync(binaryPath)) {
|
||||
|
||||
// Check if binary exists and try to fix permissions if needed
|
||||
import { existsSync, chmodSync, statSync, openSync, readSync, closeSync } from "fs";
|
||||
import { spawnSync } from "child_process";
|
||||
if (existsSync(binaryPath)) {
|
||||
try {
|
||||
// Ensure binary is executable on Unix-like systems
|
||||
@@ -200,6 +153,33 @@ if (!validation.ok) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// If running under npx/npm, emit a concise notice about which binary path is used
|
||||
try {
|
||||
const ua = process.env.npm_config_user_agent || "";
|
||||
const isNpx = ua.includes("npx");
|
||||
if (isNpx && process.stderr && process.stderr.isTTY) {
|
||||
// Best-effort discovery of another 'code' on PATH for user clarity
|
||||
let otherCode = "";
|
||||
try {
|
||||
const cmd = process.platform === "win32" ? "where code" : "command -v code || which code || true";
|
||||
const out = spawnSync(process.platform === "win32" ? "cmd" : "bash", [
|
||||
process.platform === "win32" ? "/c" : "-lc",
|
||||
cmd,
|
||||
], { encoding: "utf8" });
|
||||
const line = (out.stdout || "").split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
|
||||
if (line && !line.includes("@just-every/code")) {
|
||||
otherCode = line;
|
||||
}
|
||||
} catch {}
|
||||
if (otherCode) {
|
||||
console.error(`@just-every/code: running bundled binary -> ${binaryPath}`);
|
||||
console.error(`Note: a different 'code' exists at ${otherCode}; not delegating.`);
|
||||
} else {
|
||||
console.error(`@just-every/code: running bundled binary -> ${binaryPath}`);
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
// Use an asynchronous spawn instead of spawnSync so that Node is able to
|
||||
// respond to signals (e.g. Ctrl-C / SIGINT) while the native binary is
|
||||
// executing. This allows us to forward those signals to the child process
|
||||
|
||||
+6
-6
@@ -5,14 +5,14 @@
|
||||
"scripts": {
|
||||
"format": "prettier --check *.json *.md .github/workflows/*.yml **/*.js",
|
||||
"format:fix": "prettier --write *.json *.md .github/workflows/*.yml **/*.js",
|
||||
"build": "cd codex-rs && cargo build --release --bin code --bin code-tui --bin code-exec",
|
||||
"build:dev": "cd codex-rs && cargo build --bin code --bin code-tui --bin code-exec",
|
||||
"build:quick": "cd codex-rs && cargo build --release --bin code",
|
||||
"test:local": "cd codex-cli && npm link && code --version",
|
||||
"fix": "cargo fmt && cargo fix --allow-dirty && cargo clippy --fix --allow-dirty"
|
||||
"build": "cd codex-rs && cargo build --release --bin code --bin code-tui --bin code-exec",
|
||||
"build:dev": "cd codex-rs && cargo build --bin code --bin code-tui --bin code-exec",
|
||||
"build:quick": "cd codex-rs && cargo build --release --bin code",
|
||||
"test:local": "cd codex-cli && npm link && code --version",
|
||||
"fix": "cargo fmt && cargo fix --allow-dirty && cargo clippy --fix --allow-dirty"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.5.3"
|
||||
"prettier": "^3.6.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"braces": "^3.0.3",
|
||||
|
||||
Generated
+5
-5
@@ -14,16 +14,16 @@ importers:
|
||||
.:
|
||||
devDependencies:
|
||||
prettier:
|
||||
specifier: ^3.5.3
|
||||
version: 3.5.3
|
||||
specifier: ^3.6.2
|
||||
version: 3.6.2
|
||||
|
||||
packages:
|
||||
|
||||
prettier@3.5.3:
|
||||
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
|
||||
prettier@3.6.2:
|
||||
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
snapshots:
|
||||
|
||||
prettier@3.5.3: {}
|
||||
prettier@3.6.2: {}
|
||||
|
||||
Reference in New Issue
Block a user