nothumanallowed 15.1.30 → 15.1.32

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": "nothumanallowed",
3
- "version": "15.1.30",
3
+ "version": "15.1.32",
4
4
  "description": "NotHumanAllowed — 38 AI agents, 80 tools, Studio (visual agentic workflows). Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, Alexandria E2E messaging, GitHub, Notion, Slack, voice chat, free AI (Liara), 28 languages. Zero-dependency CLI.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/constants.mjs CHANGED
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
7
 
8
- export const VERSION = '15.1.30';
8
+ export const VERSION = '15.1.32';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -14,9 +14,15 @@
14
14
 
15
15
  import fs from 'fs';
16
16
  import path from 'path';
17
- import { exec, spawn } from 'child_process';
18
- import { createServer } from 'net';
17
+ import { exec, spawn, execSync } from 'child_process';
18
+ import { createServer, Socket } from 'net';
19
19
  import { promisify } from 'util';
20
+ import { createRequire } from 'module';
21
+ // `require` shim for the rare spots where CJS-style require() was historically
22
+ // used in this ESM file. Without this, every `require(...)` here throws
23
+ // "ReferenceError: require is not defined" — which is exactly the bug that
24
+ // took 31 releases to diagnose because it surfaced in the SSE error channel.
25
+ const require = createRequire(import.meta.url);
20
26
  import { sendJSON, sendError, parseBody, sendSSE } from '../index.mjs';
21
27
  import { loadConfig } from '../../config.mjs';
22
28
  import { callLLM, callLLMStream, callLLMWithTools, getApiKey, fixQwen3BPE } from '../../services/llm.mjs';
@@ -227,6 +233,15 @@ class SandboxManager {
227
233
  if (line) emit({ type: 'log', msg: `[stderr] ${line}` });
228
234
  });
229
235
 
236
+ // Capture spawn-level errors (e.g. ENOENT on 'node', permission denied).
237
+ // Without this handler, Node would throw an unhandled 'error' event and
238
+ // the whole nha ui process could die silently. This is the missing path
239
+ // that produced the "[error] require is not defined" with no autofix flow.
240
+ proc.on('error', (err) => {
241
+ stderrBuf += `\n[spawn error] ${err.message}\n${err.stack || ''}\n`;
242
+ emit({ type: 'warn', msg: `[spawn error] ${err.code || ''} ${err.message}` });
243
+ });
244
+
230
245
  // Wait for exit or healthy
231
246
  const exitPromise = new Promise((resolve) => {
232
247
  proc.once('exit', (code) => {
@@ -266,14 +281,14 @@ class SandboxManager {
266
281
  emit({ type: 'warn', msg: 'Crash handling skipped: _stoppedByUser=true (user pressed Stop, or previous stop() leaked the flag). If this is unexpected, restart nha ui to pick up the latest fix.' });
267
282
  return;
268
283
  }
269
- emit({ type: 'status', msg: `Process exited with code ${exitCode}` });
284
+ emit({ type: 'status', msg: `Process exited with code ${exitCode} (attempt ${_attempt}/${MAX_RETRIES})` });
270
285
  // Surface the captured stderr right away so the user sees the REAL error
271
286
  // (not just the post-Tier-2 summary). This is the diagnostic gold.
272
287
  if (stderrBuf && stderrBuf.trim()) {
273
- const stderrSnippet = stderrBuf.split('\n').slice(0, 12).join('\n');
274
- emit({ type: 'log', msg: `[stderr captured]\n${stderrSnippet}` });
288
+ const stderrSnippet = stderrBuf.split('\n').slice(0, 20).join('\n');
289
+ emit({ type: 'log', msg: `[stderr full capture, ${stderrBuf.length} bytes]\n${stderrSnippet}` });
275
290
  } else {
276
- emit({ type: 'warn', msg: 'Process exited but no stderr was capturedexit may have been instant.' });
291
+ emit({ type: 'warn', msg: 'Process exited but stderr is EMPTYcould be: process killed by OS, spawn failed before any output, or stdio mis-routed. Run "node .nha-launcher.js" manually in the project dir to reproduce.' });
277
292
  }
278
293
 
279
294
  // ── Tier 1: missing module → npm install + retry ─────────────────────
@@ -318,6 +333,14 @@ class SandboxManager {
318
333
  ];
319
334
 
320
335
  const matchedPattern = runtimePatterns.find(p => p.re.test(stderrBuf));
336
+ // ALWAYS log the autofix decision, so the user can see why Tier 2 fires
337
+ // or doesn't fire. Previous versions emitted nothing when matchedPattern
338
+ // was undefined — leaving the user confused why no autofix ran.
339
+ if (!matchedPattern) {
340
+ emit({ type: 'warn', msg: `Auto-fix: no known runtime pattern matched in stderr. Patterns checked: ${runtimePatterns.map(p => p.name).join(', ')}. stderr starts with: "${stderrBuf.slice(0, 200).replace(/\n/g, ' ⏎ ')}"` });
341
+ } else if (_attempt >= MAX_RETRIES) {
342
+ emit({ type: 'warn', msg: `Auto-fix: pattern "${matchedPattern.name}" matched but MAX_RETRIES (${MAX_RETRIES}) reached. Stopping.` });
343
+ }
321
344
  if (matchedPattern && _attempt < MAX_RETRIES) {
322
345
  emit({ type: 'phase', phase: 'autofix', msg: `Runtime error detected: ${matchedPattern.name} — analyzing...` });
323
346
 
@@ -2393,9 +2416,9 @@ export function register(router) {
2393
2416
  path.resolve(__dir, '../../../node_modules/.bin/tsc'),
2394
2417
  path.resolve(__dir, '../../../../node_modules/.bin/tsc'),
2395
2418
  ];
2396
- // Also try global
2419
+ // Also try global — execSync imported at top of file (ESM).
2397
2420
  try {
2398
- const globalTsc = require('child_process').execSync('which tsc 2>/dev/null || where tsc 2>nul', { encoding: 'utf-8', timeout: 3000 }).trim();
2421
+ const globalTsc = execSync('which tsc 2>/dev/null || where tsc 2>nul', { encoding: 'utf-8', timeout: 3000 }).trim();
2399
2422
  if (globalTsc) candidates.push(globalTsc);
2400
2423
  } catch {}
2401
2424
  for (const c of candidates) {
@@ -3508,8 +3531,11 @@ function _waitForPort(port, timeoutMs) {
3508
3531
  return new Promise((resolve) => {
3509
3532
  const deadline = Date.now() + timeoutMs;
3510
3533
  const check = () => {
3511
- // Try to connect to the port if connection succeeds, the server is listening
3512
- const { Socket } = require('net');
3534
+ // Use the ESM-imported SocketNEVER `require('net')` here, this file
3535
+ // is .mjs and `require` is not defined in ESM. The require call here
3536
+ // was the single root cause of "[error] require is not defined" with
3537
+ // no autofix flow visible — the crash happened INSIDE the nha ui
3538
+ // server itself (in this exact function), not in the child sandbox.
3513
3539
  const sock = new Socket();
3514
3540
  sock.setTimeout(500);
3515
3541
  sock.once('connect', () => { sock.destroy(); resolve(true); });