Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"server/",
"shared/",
"dist/",
"scripts/",
"README.md"
],
"homepage": "https://cloudcli.ai",
Expand All @@ -30,7 +31,8 @@
"preview": "vite preview",
"typecheck": "tsc --noEmit -p tsconfig.json",
"start": "npm run build && npm run server",
"release": "./release.sh"
"release": "./release.sh",
"postinstall": "node scripts/fix-node-pty.js"
},
"keywords": [
"claude code",
Expand Down
67 changes: 67 additions & 0 deletions scripts/fix-node-pty.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env node
/**
* Fix node-pty spawn-helper permissions on macOS
*
* This script fixes a known issue with node-pty where the spawn-helper
* binary is shipped without execute permissions, causing "posix_spawnp failed" errors.
*
* @see https://github.com/microsoft/node-pty/issues/850
* @module scripts/fix-node-pty
*/

import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

/**
* Fixes the spawn-helper binary permissions for node-pty on macOS.
*
* The node-pty package ships the spawn-helper binary without execute permissions
* (644 instead of 755), which causes "posix_spawnp failed" errors when trying
* to spawn terminal processes.
*
* This function:
* 1. Checks if running on macOS (darwin)
* 2. Locates spawn-helper binaries for both arm64 and x64 architectures
* 3. Sets execute permissions (755) on each binary found
*
* @async
* @function fixSpawnHelper
* @returns {Promise<void>} Resolves when permissions are fixed or skipped
* @example
* // Run as postinstall script
* await fixSpawnHelper();
*/
async function fixSpawnHelper() {
const nodeModulesPath = path.join(__dirname, '..', 'node_modules', 'node-pty', 'prebuilds');

// Only run on macOS
if (process.platform !== 'darwin') {
return;
}

const darwinDirs = ['darwin-arm64', 'darwin-x64'];

for (const dir of darwinDirs) {
const spawnHelperPath = path.join(nodeModulesPath, dir, 'spawn-helper');

try {
// Check if file exists
await fs.access(spawnHelperPath);

// Make it executable (755)
await fs.chmod(spawnHelperPath, 0o755);
console.log(`[postinstall] Fixed permissions for ${spawnHelperPath}`);
} catch (err) {
// File doesn't exist or other error - ignore
if (err.code !== 'ENOENT') {
console.warn(`[postinstall] Warning: Could not fix ${spawnHelperPath}: ${err.message}`);
}
}
}
}

fixSpawnHelper().catch(console.error);