Skip to content

fix: self-heal node-pty spawn-helper permissions at runtime - #3

Open
samwei12 wants to merge 1 commit into
cloudcli-ai:mainfrom
samwei12:fix/runtime-spawn-helper-permissions
Open

samwei12 wants to merge 1 commit into
cloudcli-ai:mainfrom
samwei12:fix/runtime-spawn-helper-permissions

Conversation

@samwei12

@samwei12 samwei12 commented Apr 14, 2026 •

Copy link
Copy Markdown

Summary

On macOS, new terminal sessions disconnect immediately after the plugin is installed, because node-pty cannot spawn its spawn-helper. This restores the execute bit on the helper of the node-pty copy the plugin actually loads.

Closes #1.

Root cause

  • The node-pty@1.1.0 npm tarball ships prebuilds/darwin-*/spawn-helper as -rw-r--r--.
  • CloudCLI installs plugins with npm install --ignore-scripts, so node-pty's own post-install step that sets the bit never runs.
  • pty.spawn() then throws posix_spawnp failed, and the websocket closes right after connecting.

What changed

  • src/shell.ts: new side-effect-free ensureSpawnHelperExecutable(root, platform, arch). It only acts on darwin, only touches the helper for the current architecture, only adds the owner execute bit, and does nothing when the helper is absent (source build, other layouts).
  • src/server.ts: findModule() calls it right after node-pty loads successfully, using the package root of the specifier that was loaded, so a host-provided copy is repaired as well. The repair is best effort and never makes the module load fail.
  • test/shell.test.mjs: two tests covering darwin-only behaviour, current-architecture-only, idempotence, and a missing helper.

Verification

  • npm run typecheck passes; node --test test/shell.test.mjs passes (13 tests).
  • On macOS arm64 with npm install --ignore-scripts and the helper left non-executable, test/server.test.mjs fails 9 tests on current main (every test that spawns a PTY). With this change it fails 3.
  • Those 3 (init chooses the working directory…, a dropped connection keeps the shell alive…, resize reaches the PTY) also fail on main when the helper is executable, so they are not caused by this change. The first compares /var/… with its /private/var/… realpath; the other two depend on how the local shell echoes input.

Related: #12 addresses the same symptom with a different approach.

@dfface

dfface commented Jun 11, 2026

Copy link
Copy Markdown

I encountered the same issue. Thank you very much, your code solved it~

Co-authored-by: Cursor <cursoragent@cursor.com>
@samwei12
samwei12 force-pushed the fix/runtime-spawn-helper-permissions branch from 29adb2e to 9dae8e0 Compare October 28, 2026 11:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Terminal plugin disconnects immediately on macOS after install

2 participants