@claudecollab/cli 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claudecollab/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -10,8 +10,45 @@
10
10
  // node-pty is a native module and is imported lazily inside startPty, so this
11
11
  // file (and FrameSplitter's tests) load fine even where node-pty isn't built.
12
12
 
13
+ import fs from 'node:fs';
14
+ import path from 'node:path';
15
+ import { createRequire } from 'node:module';
16
+
13
17
  /** Synchronized-update END marker. Claude ends every repaint frame with this. */
14
18
  export const SU_END = '\x1b[?2026l';
19
+
20
+ // node-pty forks a small `spawn-helper` binary to launch the child, and that file
21
+ // must be executable. Installers that skip package build scripts (npm's
22
+ // allow-scripts / ignore-scripts policies, pnpm by default) ship it WITHOUT the
23
+ // execute bit, so the very first spawn dies with "posix_spawnp failed". A
24
+ // postinstall script can't fix this — those same policies block it — so we restore
25
+ // the bit at RUNTIME, right before spawning. Best-effort and idempotent: if the
26
+ // bit is already set (or we can't touch the file) we do nothing and let spawn
27
+ // surface the real error. macOS/Linux only; Windows has no such helper.
28
+ export function ensureSpawnHelperExecutable(requireFn) {
29
+ if (process.platform === 'win32') return;
30
+ try {
31
+ const req = requireFn ?? createRequire(import.meta.url);
32
+ const ptyDir = path.dirname(req.resolve('node-pty/package.json'));
33
+ const candidates = [path.join(ptyDir, 'build', 'Release', 'spawn-helper')];
34
+ const prebuilds = path.join(ptyDir, 'prebuilds');
35
+ try {
36
+ for (const d of fs.readdirSync(prebuilds)) candidates.push(path.join(prebuilds, d, 'spawn-helper'));
37
+ } catch {
38
+ /* no prebuilds dir on this layout */
39
+ }
40
+ for (const f of candidates) {
41
+ try {
42
+ const { mode } = fs.statSync(f);
43
+ if (!(mode & 0o111)) fs.chmodSync(f, mode | 0o111); // add u+g+o execute
44
+ } catch {
45
+ /* not present here, or not ours to chmod — skip */
46
+ }
47
+ }
48
+ } catch {
49
+ /* couldn't even resolve node-pty — the import below throws the real error */
50
+ }
51
+ }
15
52
  /** Synchronized-update BEGIN marker (exported for reference / future use). */
16
53
  export const SU_BEGIN = '\x1b[?2026h';
17
54
 
@@ -78,6 +115,7 @@ export async function startPty({
78
115
  cwd,
79
116
  flushMs = 8,
80
117
  } = {}) {
118
+ ensureSpawnHelperExecutable(); // fix node-pty's spawn-helper exec bit before spawning
81
119
  const mod = await import('node-pty');
82
120
  const spawn = mod.spawn ?? mod.default?.spawn;
83
121
  if (typeof spawn !== 'function') {