myrlin-workbook 0.9.29 → 0.9.30

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": "myrlin-workbook",
3
- "version": "0.9.29",
3
+ "version": "0.9.30",
4
4
  "description": "Browser-based project manager for Claude Code sessions - session discovery, multi-terminal, cost tracking, docs, and kanban board",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -1,37 +1,77 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Postinstall script: fix node-pty spawn-helper permissions on macOS/Linux.
4
- * The prebuilt spawn-helper binary ships without execute permission (644),
5
- * causing posix_spawnp failures. This sets it to 755.
6
- * See: https://github.com/therealarthur/myrlin-workbook/issues/4
7
- */
8
- 'use strict';
9
-
10
- if (process.platform === 'win32') {
11
- process.exit(0);
12
- }
13
-
14
- const { execSync } = require('child_process');
15
- const path = require('path');
16
- const fs = require('fs');
17
-
18
- const prebuildsDir = path.join(__dirname, '..', 'node_modules', 'node-pty', 'prebuilds');
19
-
20
- if (!fs.existsSync(prebuildsDir)) {
21
- process.exit(0);
22
- }
23
-
24
- try {
25
- // Find all spawn-helper binaries across platform dirs and chmod +x them
26
- const dirs = fs.readdirSync(prebuildsDir, { withFileTypes: true })
27
- .filter(d => d.isDirectory());
28
-
29
- for (const dir of dirs) {
30
- const helper = path.join(prebuildsDir, dir.name, 'spawn-helper');
31
- if (fs.existsSync(helper)) {
32
- execSync(`chmod +x "${helper}"`, { stdio: 'ignore' });
33
- }
34
- }
35
- } catch (_) {
36
- // Non-fatal: if chmod fails, user can still manually fix
37
- }
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Postinstall script: fix node-pty spawn-helper permissions on macOS/Linux.
4
+ *
5
+ * The prebuilt spawn-helper binary in node-pty's package ships without
6
+ * execute permission (mode 644 instead of 755), causing posix_spawnp to
7
+ * fail with "posix_spawnp failed" on first PTY spawn.
8
+ *
9
+ * This is a known node-pty packaging issue. We work around it here by
10
+ * locating node-pty (wherever npm/npx hoisted it), finding all prebuilt
11
+ * spawn-helper binaries across platform dirs, and setting them to 755.
12
+ *
13
+ * See: https://github.com/therealarthur/myrlin-workbook/issues/4
14
+ */
15
+ 'use strict';
16
+
17
+ if (process.platform === 'win32') {
18
+ process.exit(0);
19
+ }
20
+
21
+ const path = require('path');
22
+ const fs = require('fs');
23
+
24
+ /**
25
+ * Locate node-pty's package directory using require.resolve.
26
+ * Works regardless of where npm/npx/yarn placed it (hoisted, nested,
27
+ * pnp-virtual, etc.). Returns null if node-pty isn't installed.
28
+ */
29
+ function findNodePtyDir() {
30
+ try {
31
+ const ptyMain = require.resolve('node-pty', { paths: [path.join(__dirname, '..')] });
32
+ let dir = path.dirname(ptyMain);
33
+ // Walk up until we find package.json with "name": "node-pty"
34
+ for (let i = 0; i < 8; i++) {
35
+ const pkg = path.join(dir, 'package.json');
36
+ if (fs.existsSync(pkg)) {
37
+ try {
38
+ const json = JSON.parse(fs.readFileSync(pkg, 'utf8'));
39
+ if (json && json.name === 'node-pty') return dir;
40
+ } catch (_) {}
41
+ }
42
+ const parent = path.dirname(dir);
43
+ if (parent === dir) break;
44
+ dir = parent;
45
+ }
46
+ } catch (_) {}
47
+ return null;
48
+ }
49
+
50
+ const ptyDir = findNodePtyDir();
51
+ if (!ptyDir) {
52
+ // node-pty not installed yet (rare during postinstall); skip silently.
53
+ process.exit(0);
54
+ }
55
+
56
+ const prebuildsDir = path.join(ptyDir, 'prebuilds');
57
+ if (!fs.existsSync(prebuildsDir)) {
58
+ process.exit(0);
59
+ }
60
+
61
+ try {
62
+ const platforms = fs.readdirSync(prebuildsDir, { withFileTypes: true })
63
+ .filter(d => d.isDirectory());
64
+
65
+ for (const platform of platforms) {
66
+ const helper = path.join(prebuildsDir, platform.name, 'spawn-helper');
67
+ if (fs.existsSync(helper)) {
68
+ try {
69
+ fs.chmodSync(helper, 0o755);
70
+ } catch (_) {
71
+ // Non-fatal: runtime fix will catch this on first PTY spawn
72
+ }
73
+ }
74
+ }
75
+ } catch (_) {
76
+ // Non-fatal
77
+ }
@@ -11,10 +11,52 @@
11
11
  * - Scrollback is capped at ~100KB total characters
12
12
  */
13
13
 
14
- const pty = require('node-pty');
15
14
  const fs = require('fs');
16
15
  const os = require('os');
17
16
  const path = require('path');
17
+
18
+ // Ensure node-pty's prebuilt spawn-helper is executable BEFORE requiring node-pty.
19
+ // node-pty's prebuild ships with mode 644 instead of 755, causing posix_spawnp
20
+ // to fail on macOS/Linux. The postinstall script handles this in normal installs
21
+ // but doesn't run with --ignore-scripts or in some npx caches. This runtime
22
+ // fallback covers those cases. See: https://github.com/therealarthur/myrlin-workbook/issues/4
23
+ if (process.platform !== 'win32') {
24
+ try {
25
+ const ptyMain = require.resolve('node-pty');
26
+ let dir = path.dirname(ptyMain);
27
+ for (let i = 0; i < 8; i++) {
28
+ const pkg = path.join(dir, 'package.json');
29
+ if (fs.existsSync(pkg)) {
30
+ try {
31
+ const json = JSON.parse(fs.readFileSync(pkg, 'utf8'));
32
+ if (json && json.name === 'node-pty') break;
33
+ } catch (_) {}
34
+ }
35
+ const parent = path.dirname(dir);
36
+ if (parent === dir) { dir = null; break; }
37
+ dir = parent;
38
+ }
39
+ if (dir) {
40
+ const prebuildsDir = path.join(dir, 'prebuilds');
41
+ if (fs.existsSync(prebuildsDir)) {
42
+ for (const p of fs.readdirSync(prebuildsDir)) {
43
+ const helper = path.join(prebuildsDir, p, 'spawn-helper');
44
+ if (fs.existsSync(helper)) {
45
+ try {
46
+ const stat = fs.statSync(helper);
47
+ // Only chmod if not already executable, avoids unnecessary syscalls
48
+ if ((stat.mode & 0o111) === 0) fs.chmodSync(helper, 0o755);
49
+ } catch (_) {}
50
+ }
51
+ }
52
+ }
53
+ }
54
+ } catch (_) {
55
+ // node-pty not yet resolvable; require() below will throw with a clearer error
56
+ }
57
+ }
58
+
59
+ const pty = require('node-pty');
18
60
  const { getStore } = require('../state/store');
19
61
 
20
62
  /**