consortium
Version:
Remote control and session sharing CLI for AI coding agents
60 lines (52 loc) • 2.06 kB
JavaScript
// Upstream `node-pty` publishes its per-platform `spawn-helper` binary as
// 0644 (no execute bit) and does not chmod it in any install hook. Its
// macOS PTY spawn path does posix_spawnp on that file, which the kernel
// refuses — the symptom is:
//
// Error: Failed to spawn process.
// binary: .../node-pty/prebuilds/<plat>/spawn-helper
// underlying error: posix_spawnp failed.
//
// This script runs as part of our postinstall and restores +x on every
// spawn-helper it can find inside the installed node-pty tree. Best-effort
// — we swallow errors so a partially-installed optional dep never breaks
// `npm install`.
const { existsSync, readdirSync, chmodSync, statSync } = require('node:fs');
const { dirname, join } = require('node:path');
function findNodePtyPrebuildsDir() {
try {
const pkgPath = require.resolve('node-pty/package.json');
return join(dirname(pkgPath), 'prebuilds');
} catch {
return null;
}
}
function fixSpawnHelperPerms() {
const prebuildsDir = findNodePtyPrebuildsDir();
if (!prebuildsDir || !existsSync(prebuildsDir)) return 0;
let fixed = 0;
for (const entry of readdirSync(prebuildsDir)) {
const helper = join(prebuildsDir, entry, 'spawn-helper');
if (!existsSync(helper)) continue;
try {
const mode = statSync(helper).mode & 0o777;
if ((mode & 0o111) === 0o111) continue; // already executable
chmodSync(helper, mode | 0o755);
fixed++;
} catch {
// Best-effort: read-only mounts, permission issues on a shared
// install, etc. Silent skip beats a failed `npm install`.
}
}
return fixed;
}
if (require.main === module) {
try {
const n = fixSpawnHelperPerms();
if (n > 0) console.log(`[consortium] Restored +x on ${n} node-pty spawn-helper binar${n === 1 ? 'y' : 'ies'}`);
} catch {
// Swallow — this must never fail a postinstall.
}
}
module.exports = { fixSpawnHelperPerms };