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 +1 -1
- package/src/constants.mjs +1 -1
- package/src/server/routes/webcraft.mjs +36 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "15.1.
|
|
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.
|
|
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,
|
|
274
|
-
emit({ type: 'log', msg: `[stderr
|
|
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
|
|
291
|
+
emit({ type: 'warn', msg: 'Process exited but stderr is EMPTY — could 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 =
|
|
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
|
-
//
|
|
3512
|
-
|
|
3534
|
+
// Use the ESM-imported Socket — NEVER `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); });
|