nothumanallowed 15.1.19 → 15.1.21

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.19",
3
+ "version": "15.1.21",
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/cli.mjs CHANGED
@@ -521,7 +521,7 @@ function cmdConfig(args) {
521
521
  if (!key || !value) {
522
522
  fail('Usage: nha config set <key> <value>');
523
523
  console.log('');
524
- info('Keys: provider, key, openai-key, gemini-key, deepseek-key, grok-key, model, timeout');
524
+ info('Keys: provider, key, openai-key, gemini-key, deepseek-key, grok-key, groq-key (voice/Whisper), model, timeout');
525
525
  info(' verbose, immersive, deliberation, rounds, convergence, tribunal, knowledge');
526
526
  info(' google-client-id, google-client-secret');
527
527
  info(' microsoft-client-id, microsoft-client-secret, microsoft-tenant');
@@ -553,7 +553,10 @@ function cmdConfig(args) {
553
553
  if (config.llm.openaiKey) console.log(` OpenAI Key: ${G}${config.llm.openaiKey.slice(0, 12)}...${NC}`);
554
554
  if (config.llm.geminiKey) console.log(` Gemini Key: ${G}${config.llm.geminiKey.slice(0, 12)}...${NC}`);
555
555
  if (config.llm.deepseekKey) console.log(` DeepSeek Key: ${G}${config.llm.deepseekKey.slice(0, 12)}...${NC}`);
556
- if (config.llm.grokKey) console.log(` Grok Key: ${G}${config.llm.grokKey.slice(0, 12)}...${NC}`);
556
+ if (config.llm.grokKey) console.log(` Grok Key: ${G}${config.llm.grokKey.slice(0, 12)}...${NC} ${D}(X.AI Grok LLM)${NC}`);
557
+ // Groq is for voice transcription (Whisper). ALWAYS show so users can see
558
+ // whether it's configured — voice in Telegram needs this when NHA proxy is down.
559
+ console.log(` Groq Key: ${config.llm.groqKey ? G + config.llm.groqKey.slice(0, 12) + '...' : R + '(not set)'}${NC} ${D}(voice transcription, free at https://console.groq.com/keys)${NC}`);
557
560
  if (config.llm.model) console.log(` Model: ${W}${config.llm.model}${NC}`);
558
561
  console.log(` Timeout: ${D}${config.llm.timeout}ms${NC}`);
559
562
 
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.19';
8
+ export const VERSION = '15.1.21';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -289,19 +289,99 @@ class SandboxManager {
289
289
 
290
290
  const matchedPattern = runtimePatterns.find(p => p.re.test(stderrBuf));
291
291
  if (matchedPattern && _attempt < MAX_RETRIES) {
292
- // Extract the file path from the stack trace.
293
- // Patterns: "at /abs/path/file.js:N:M", "at file:///abs/path/file.js:N:M",
294
- // "at Object.<anonymous> (/path/file.js:N:M)", or simply at start of stderr.
295
- const fileMatches = [...stderrBuf.matchAll(/(?:at\s+(?:[\w<>\.\s]+\s+)?\(?)?(?:file:\/\/)?(\/[^\s:()'"]+\.(?:m?js|cjs|jsx?|tsx?)):\d+(?::\d+)?/g)];
296
- const projectFiles = fileMatches
297
- .map(m => m[1])
298
- .filter(p => p && p.startsWith(projectDir))
299
- .map(p => path.relative(projectDir, p))
292
+ emit({ type: 'phase', phase: 'autofix', msg: `Runtime error detected: ${matchedPattern.name} — analyzing...` });
293
+
294
+ // ── Special pre-fix for require/import mismatches ──
295
+ // For "require is not defined" the project is ESM but uses CJS syntax.
296
+ // Easiest fix: flip package.json — REMOVE "type":"module" so CJS works,
297
+ // OR rewrite files. We try the package.json toggle FIRST (cheaper) only
298
+ // when the failing files clearly use `require()`. For the inverse case
299
+ // ("Cannot use import statement outside a module") we ADD "type":"module".
300
+ const pkgPath = path.join(projectDir, 'package.json');
301
+ const isRequireError = /require is not defined/i.test(stderrBuf);
302
+ const isImportError = /Cannot use import statement outside a module/i.test(stderrBuf);
303
+
304
+ if ((isRequireError || isImportError) && fs.existsSync(pkgPath)) {
305
+ try {
306
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
307
+ if (isImportError && pkg.type !== 'module') {
308
+ pkg.type = 'module';
309
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
310
+ emit({ type: 'status', msg: 'Auto-fix: added "type":"module" to package.json — retrying...' });
311
+ return this.start(projectName, projectDir, emit, _attempt + 1);
312
+ }
313
+ if (isRequireError && pkg.type === 'module') {
314
+ // Flip OFF "type":"module" so require() works again
315
+ delete pkg.type;
316
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
317
+ emit({ type: 'status', msg: 'Auto-fix: removed "type":"module" from package.json — retrying...' });
318
+ return this.start(projectName, projectDir, emit, _attempt + 1);
319
+ }
320
+ } catch (e) {
321
+ emit({ type: 'warn', msg: `package.json toggle failed: ${e.message.slice(0, 200)}` });
322
+ }
323
+ }
324
+
325
+ // ── Extract file path from stack trace (multiple patterns) ──
326
+ // Try several regex forms to be robust against various Node stack formats.
327
+ const allPaths = new Set();
328
+ // Form A: "at /abs/path/file.js:N:M" or "at file:///abs/path/file.js:N:M"
329
+ for (const m of stderrBuf.matchAll(/(?:file:\/\/)?(\/[^\s:()'"]+\.(?:m?js|cjs|jsx?|tsx?)):\d+(?::\d+)?/g)) {
330
+ allPaths.add(m[1]);
331
+ }
332
+ // Form B: ESM error header "file:///path/file.js:N"
333
+ for (const m of stderrBuf.matchAll(/file:\/\/(\/[^\s:'"]+\.(?:m?js|cjs|jsx?|tsx?)):?\d*/g)) {
334
+ allPaths.add(m[1]);
335
+ }
336
+ // Form C: bare absolute path at start of line (Node prints this for CJS syntax)
337
+ for (const m of stderrBuf.matchAll(/^(\/[^\s:'"]+\.(?:m?js|cjs|jsx?|tsx?))(?::\d+)?$/gm)) {
338
+ allPaths.add(m[1]);
339
+ }
340
+
341
+ // First filter: paths that look like they live in this project
342
+ let projectFiles = [...allPaths]
343
+ .filter(p => p.startsWith(projectDir) || p.includes('/' + path.basename(projectDir) + '/'))
344
+ .map(p => p.startsWith(projectDir) ? path.relative(projectDir, p) : null)
345
+ .filter(Boolean)
300
346
  .filter((v, i, a) => a.indexOf(v) === i)
301
- .slice(0, 3);
347
+ .slice(0, 5);
348
+
349
+ // FALLBACK: if no stack-trace files matched, scan the project directory
350
+ // for all .js / .mjs / .cjs files (excluding node_modules) and pick the
351
+ // ones that contain `require(` or `import` — those are the candidates.
352
+ if (projectFiles.length === 0) {
353
+ emit({ type: 'status', msg: `Stack trace did not reveal a file in project — scanning project files...` });
354
+ try {
355
+ const _walk = (dir, out = []) => {
356
+ for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
357
+ if (ent.name === 'node_modules' || ent.name.startsWith('.')) continue;
358
+ const abs = path.join(dir, ent.name);
359
+ if (ent.isDirectory()) _walk(abs, out);
360
+ else if (/\.(m?js|cjs)$/.test(ent.name)) out.push(abs);
361
+ }
362
+ return out;
363
+ };
364
+ const allJs = _walk(projectDir);
365
+ // Heuristic — pick files matching the error semantics
366
+ const triggers = isRequireError
367
+ ? /\brequire\s*\(/
368
+ : isImportError ? /^\s*import\s+/m
369
+ : /\brequire\s*\(|^\s*import\s+/m;
370
+ const candidates = allJs
371
+ .filter(abs => {
372
+ try { return triggers.test(fs.readFileSync(abs, 'utf-8')); } catch { return false; }
373
+ })
374
+ .slice(0, 3);
375
+ projectFiles = candidates.map(abs => path.relative(projectDir, abs));
376
+ } catch (e) {
377
+ emit({ type: 'warn', msg: `Project scan failed: ${e.message.slice(0, 200)}` });
378
+ }
379
+ }
302
380
 
303
- if (projectFiles.length > 0) {
304
- emit({ type: 'phase', phase: 'autofix', msg: `Runtime error (${matchedPattern.name}) repairing ${projectFiles.length} file(s)...` });
381
+ if (projectFiles.length === 0) {
382
+ emit({ type: 'warn', msg: `Auto-fix: could not identify a target file to repair. Stack trace shown above.` });
383
+ } else {
384
+ emit({ type: 'phase', phase: 'autofix', msg: `Auto-fix repairing ${projectFiles.length} file(s): ${projectFiles.join(', ')}` });
305
385
  let anyFixed = false;
306
386
  for (const rel of projectFiles) {
307
387
  const abs = path.join(projectDir, rel);
@@ -309,8 +389,6 @@ class SandboxManager {
309
389
  try { original = fs.readFileSync(abs, 'utf-8'); } catch { continue; }
310
390
  if (!original) continue;
311
391
 
312
- // Build a focused repair prompt — include the runtime error so the
313
- // model knows exactly what to fix.
314
392
  const errSnippet = stderrBuf.split('\n').slice(0, 30).join('\n');
315
393
  const fixPrompt =
316
394
  `A Node.js sandbox crashed with this runtime error:
@@ -327,40 +405,26 @@ Current file content:
327
405
  ${original.slice(0, 12_000)}`;
328
406
 
329
407
  try {
408
+ emit({ type: 'status', msg: `Auto-fix: rewriting ${rel}...` });
330
409
  let fixed = '';
331
410
  await callLLMStream(loadConfig(), 'You are a precise code repair assistant. Output only the corrected file, no explanation.', fixPrompt, (c) => { fixed += c; }, { max_tokens: 16384 });
332
411
  fixed = fixed.replace(/^```[\w]*\n/, '').replace(/\n```$/, '').trim();
333
412
  if (fixed.length > 20 && fixed !== original) {
334
413
  fs.writeFileSync(abs, fixed, 'utf-8');
335
- emit({ type: 'status', msg: `Repaired ${rel} (${fixed.length} chars)` });
414
+ emit({ type: 'status', msg: `Auto-fix: ✓ repaired ${rel} (${fixed.length} chars)` });
336
415
  anyFixed = true;
416
+ } else {
417
+ emit({ type: 'warn', msg: `Auto-fix: LLM returned no useful change for ${rel}` });
337
418
  }
338
419
  } catch (e) {
339
- emit({ type: 'warn', msg: `LLM repair of ${rel} failed: ${(e.message || '').slice(0, 200)}` });
420
+ emit({ type: 'warn', msg: `Auto-fix: LLM repair of ${rel} failed ${(e.message || '').slice(0, 200)}` });
340
421
  }
341
422
  }
342
423
  if (anyFixed) {
343
- emit({ type: 'status', msg: `Restarting sandbox (attempt ${_attempt + 1}/${MAX_RETRIES})...` });
424
+ emit({ type: 'status', msg: `Auto-fix: restarting sandbox (attempt ${_attempt + 1}/${MAX_RETRIES})...` });
344
425
  return this.start(projectName, projectDir, emit, _attempt + 1);
345
426
  }
346
427
  }
347
-
348
- // Special fallback for CJS/ESM mismatches: try flipping package.json "type"
349
- if (matchedPattern.name.includes('CJS/ESM') || matchedPattern.name.includes('ESM/CJS')) {
350
- const pkgPath = path.join(projectDir, 'package.json');
351
- if (fs.existsSync(pkgPath)) {
352
- try {
353
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
354
- const isCjsError = /Cannot use import statement outside a module/i.test(stderrBuf);
355
- if (isCjsError && pkg.type !== 'module') {
356
- pkg.type = 'module';
357
- fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
358
- emit({ type: 'status', msg: 'Added "type":"module" to package.json — retrying...' });
359
- return this.start(projectName, projectDir, emit, _attempt + 1);
360
- }
361
- } catch { /* ignore */ }
362
- }
363
- }
364
428
  }
365
429
 
366
430
  // Show the actual error from stderr — include full trace for debugging