quilltap 4.5.1 → 4.6.0-dev.22

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.
Files changed (2) hide show
  1. package/bin/quilltap.js +60 -18
  2. package/package.json +1 -1
package/bin/quilltap.js CHANGED
@@ -266,25 +266,67 @@ function linkNativeModules(standaloneDir) {
266
266
  || resolveModuleDir('better-sqlite3');
267
267
  linkModule('better-sqlite3', betterSqlite3Dir);
268
268
 
269
- // Link node-pty — the standalone tarball strips it (platform-specific),
270
- // and pty-manager loads it via a dynamic require, so it needs to resolve
271
- // from standaloneDir/node_modules.
272
- const nodePtyDir = resolveModuleDir('node-pty');
273
- linkModule('node-pty', nodePtyDir);
274
- if (nodePtyDir) {
275
- // Some npm cache extractions strip the executable bit on spawn-helper,
276
- // causing pty.spawn() to fail with `posix_spawnp failed`. Restore it.
277
- const prebuildsDir = path.join(nodePtyDir, 'prebuilds');
278
- if (fs.existsSync(prebuildsDir)) {
279
- try {
280
- for (const entry of fs.readdirSync(prebuildsDir, { withFileTypes: true })) {
281
- if (!entry.isDirectory()) continue;
282
- const helper = path.join(prebuildsDir, entry.name, 'spawn-helper');
283
- if (fs.existsSync(helper)) {
284
- try { fs.chmodSync(helper, 0o755); } catch { /* best-effort */ }
269
+ // Link node-pty — but only when we have to. The standalone tarball ships
270
+ // node-pty intact with cross-platform prebuilds (darwin-arm64, darwin-x64,
271
+ // win32-arm64, win32-x64). On those platforms the tarball-shipped copy is
272
+ // already correct, and we MUST NOT replace it with a symlink to the
273
+ // npm-installed copy: `sudo npm install -g quilltap` on macOS can strip the
274
+ // executable bit off `spawn-helper`, and we can't chmod a root-owned file
275
+ // back as a non-root runtime user pty.spawn() then fails with
276
+ // `posix_spawnp failed`. Only Linux (which has no node-pty prebuild) and
277
+ // rebuild-failure cases need the symlink.
278
+ const standaloneNodePtyPath = path.join(standaloneNodeModules, 'node-pty');
279
+ const standaloneHasUsablePty = (() => {
280
+ try {
281
+ const stat = fs.lstatSync(standaloneNodePtyPath);
282
+ if (stat.isSymbolicLink()) return false; // prior broken-symlink state — replace it
283
+ if (!stat.isDirectory()) return false;
284
+ } catch {
285
+ return false;
286
+ }
287
+ const platformPrebuildDir = path.join(
288
+ standaloneNodePtyPath,
289
+ 'prebuilds',
290
+ `${process.platform}-${process.arch}`,
291
+ );
292
+ return fs.existsSync(platformPrebuildDir);
293
+ })();
294
+
295
+ if (!standaloneHasUsablePty) {
296
+ const nodePtyDir = resolveModuleDir('node-pty');
297
+ linkModule('node-pty', nodePtyDir);
298
+ if (nodePtyDir) {
299
+ // Some npm cache extractions (notably `sudo npm install -g`) strip the
300
+ // executable bit on spawn-helper. Restore it where we can. If chmod
301
+ // fails because we don't own the file (typical when the CLI was
302
+ // installed with sudo and is run as a non-root user), warn loudly —
303
+ // silent failure here produces the `posix_spawnp failed` runtime error
304
+ // with no actionable hint.
305
+ const prebuildsDir = path.join(nodePtyDir, 'prebuilds');
306
+ if (fs.existsSync(prebuildsDir)) {
307
+ try {
308
+ for (const entry of fs.readdirSync(prebuildsDir, { withFileTypes: true })) {
309
+ if (!entry.isDirectory()) continue;
310
+ const helper = path.join(prebuildsDir, entry.name, 'spawn-helper');
311
+ if (!fs.existsSync(helper)) continue;
312
+ try {
313
+ fs.chmodSync(helper, 0o755);
314
+ } catch (err) {
315
+ if (err && err.code === 'EPERM') {
316
+ console.error('');
317
+ console.error(` Warning: Could not make node-pty spawn-helper executable:`);
318
+ console.error(` ${helper}`);
319
+ console.error(` The file is owned by another user (likely root from a sudo'd`);
320
+ console.error(` global install). Terminal sessions will fail to spawn with`);
321
+ console.error(` "posix_spawnp failed" until this is fixed. Run:`);
322
+ console.error(` sudo chmod 755 "${helper}"`);
323
+ console.error('');
324
+ }
325
+ // Other errors are non-fatal — node-pty may still work if the bit was already set.
326
+ }
285
327
  }
286
- }
287
- } catch { /* best-effort */ }
328
+ } catch { /* best-effort */ }
329
+ }
288
330
  }
289
331
  }
290
332
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quilltap",
3
- "version": "4.5.1",
3
+ "version": "4.6.0-dev.22",
4
4
  "description": "Self-hosted AI workspace for writers, worldbuilders, and roleplayers. Run with npx quilltap.",
5
5
  "author": {
6
6
  "name": "Charles Sebold",