nothumanallowed 13.5.132 → 13.5.134

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/bin/nha ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * nha — NotHumanAllowed CLI
4
+ *
5
+ * Thin launcher for Legion (multi-agent deliberation) and PIF (agent social client).
6
+ * Zero dependencies. Downloads core files on first run to ~/.nha/.
7
+ *
8
+ * Usage:
9
+ * npx nha run "Compare React vs Vue for enterprise"
10
+ * npx nha agents
11
+ * npx nha pif register
12
+ * npx nha install nha-code-reviewer
13
+ * npx nha config set provider anthropic
14
+ * npx nha update
15
+ */
16
+
17
+ import { fileURLToPath, pathToFileURL } from 'url';
18
+ import path from 'path';
19
+
20
+ const __filename = fileURLToPath(import.meta.url);
21
+ const __dirname = path.dirname(__filename);
22
+
23
+ // ── Node.js version gate ────────────────────────────────────────────────────
24
+ const major = parseInt(process.version.slice(1), 10);
25
+ if (major < 20) {
26
+ console.error(`\x1b[31mError: nha requires Node.js 20 or later (found ${process.version}).\x1b[0m`);
27
+ console.error('Install from https://nodejs.org');
28
+ process.exit(1);
29
+ }
30
+
31
+ // ── Launch CLI ──────────────────────────────────────────────────────────────
32
+ // On Windows, dynamic import() requires file:// URLs, not raw paths like C:\...
33
+ const cliPath = path.join(__dirname, '..', 'src', 'cli.mjs');
34
+ const cliUrl = pathToFileURL(cliPath).href;
35
+ const { main } = await import(cliUrl);
36
+ await main(process.argv.slice(2));
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "13.5.132",
3
+ "version": "13.5.134",
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": {
7
- "nha": "./bin/nha.mjs",
8
- "nothumanallowed": "./bin/nha.mjs"
7
+ "nha": "bin/nha",
8
+ "nothumanallowed": "bin/nha"
9
9
  },
10
10
  "engines": {
11
11
  "node": ">=20.0.0"
@@ -50,7 +50,7 @@
50
50
  "license": "MIT",
51
51
  "repository": {
52
52
  "type": "git",
53
- "url": "https://github.com/adoslabsproject-gif/nothumanallowed"
53
+ "url": "git+https://github.com/adoslabsproject-gif/nothumanallowed.git"
54
54
  },
55
55
  "homepage": "https://nothumanallowed.com",
56
56
  "scripts": {
@@ -5708,12 +5708,49 @@ REGOLE CRITICHE:
5708
5708
  const { callLLMVision } = await import('../services/llm.mjs');
5709
5709
  const va = visionAttachments[0];
5710
5710
  fullResponse = await callLLMVision(config, systemPrompt, userMsg, { base64: va.base64, mimeType: va.mimeType });
5711
- sendEv({ type: 'text', token: fullResponse });
5711
+ // Strip <tool>...</tool> blocks before sending text to client
5712
+ const visibleText = fullResponse.replace(/<tool>[\s\S]*?<\/tool>/g, '').trim();
5713
+ if (visibleText) sendEv({ type: 'text', token: visibleText });
5712
5714
  } else {
5715
+ // Stream tokens but suppress <tool>...</tool> blocks from the visible text
5716
+ let _toolBuf = ''; // accumulates content inside a <tool> block
5717
+ let _inTool = false; // are we inside a <tool>...</tool>?
5713
5718
  await callLLMStream(config, systemPrompt, userMsg, (token) => {
5714
5719
  fullResponse += token;
5715
- sendEv({ type: 'text', token });
5720
+ // Feed token through tool-suppression filter
5721
+ let remaining = (_inTool ? '' : '') + token; // process token char by char via buffer
5722
+ // Simpler approach: buffer until we can decide
5723
+ _toolBuf += token;
5724
+ // Flush visible text up to next <tool> opening
5725
+ while (true) {
5726
+ if (!_inTool) {
5727
+ const toolStart = _toolBuf.indexOf('<tool>');
5728
+ if (toolStart === -1) {
5729
+ // No tool block opening — safe to send everything except possible partial '<tool' at end
5730
+ const safeEnd = _toolBuf.length - 6; // keep last 6 chars in case '<tool>' spans tokens
5731
+ if (safeEnd > 0) {
5732
+ sendEv({ type: 'text', token: _toolBuf.slice(0, safeEnd) });
5733
+ _toolBuf = _toolBuf.slice(safeEnd);
5734
+ }
5735
+ break;
5736
+ } else {
5737
+ // Flush text before the <tool>
5738
+ if (toolStart > 0) {
5739
+ sendEv({ type: 'text', token: _toolBuf.slice(0, toolStart) });
5740
+ }
5741
+ _toolBuf = _toolBuf.slice(toolStart);
5742
+ _inTool = true;
5743
+ }
5744
+ } else {
5745
+ const toolEnd = _toolBuf.indexOf('</tool>');
5746
+ if (toolEnd === -1) break; // still accumulating tool block
5747
+ _toolBuf = _toolBuf.slice(toolEnd + 7); // discard the </tool> and move on
5748
+ _inTool = false;
5749
+ }
5750
+ }
5716
5751
  }, { max_tokens: 4096 });
5752
+ // Flush any remaining visible text after stream ends
5753
+ if (!_inTool && _toolBuf.trim()) sendEv({ type: 'text', token: _toolBuf });
5717
5754
  }
5718
5755
  } catch (llmErr) {
5719
5756
  const errMsg = llmErr.message || String(llmErr);
@@ -5753,6 +5790,17 @@ REGOLE CRITICHE:
5753
5790
  return out;
5754
5791
  };
5755
5792
 
5793
+ // Second-pass JSON repair: fix missing commas between object properties
5794
+ // e.g. {"a":1\n"b":2} → {"a":1,"b":2}
5795
+ const repairJson = (raw) => {
5796
+ // Add missing commas between } or ] or "..." or number/bool/null and the next " or { or [
5797
+ return raw
5798
+ .replace(/([}\]"'0-9truefalsNullnull])\s*\n\s*(")/g, '$1,\n"') // after value, before next key
5799
+ .replace(/([}\]"'0-9truefalsNullnull])\s*\n\s*([{[])/g, '$1,\n$2') // after value, before { or [
5800
+ // Remove trailing commas before } or ]
5801
+ .replace(/,(\s*[}\]])/g, '$1');
5802
+ };
5803
+
5756
5804
  const toolRegex = /<tool>([\s\S]*?)<\/tool>/g;
5757
5805
  let toolMatch;
5758
5806
  const toolResults = [];
@@ -5760,7 +5808,13 @@ REGOLE CRITICHE:
5760
5808
  let toolCall;
5761
5809
  try {
5762
5810
  const raw = toolMatch[1].trim();
5763
- toolCall = JSON.parse(sanitizeToolJson(raw));
5811
+ const sanitized = sanitizeToolJson(raw);
5812
+ try {
5813
+ toolCall = JSON.parse(sanitized);
5814
+ } catch(_) {
5815
+ // Second attempt: repair missing commas
5816
+ toolCall = JSON.parse(repairJson(sanitized));
5817
+ }
5764
5818
  } catch(e) {
5765
5819
  sendEv({ type: 'tool', op: 'parse_error', path: '?', result: 'JSON malformato: ' + e.message.slice(0, 80) });
5766
5820
  continue;
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 = '13.5.132';
8
+ export const VERSION = '13.5.134';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -8371,7 +8371,7 @@ async function wcTriggerCrashFix(errorMsg) {
8371
8371
  });
8372
8372
  if (wcChatRunning) return;
8373
8373
  }
8374
- var fixMsg = 'AUTO-FIX: ' + errorMsg + String.fromCharCode(10) + 'Il server Express ha crashato con questo errore. Analizza tutti i file del progetto, individua la causa e correggi il codice. Modifica i file necessari usando i tool disponibili.';
8374
+ var fixMsg = 'CRASH FIX RICHIESTO.' + String.fromCharCode(10) + 'ERRORE:' + String.fromCharCode(10) + errorMsg + String.fromCharCode(10) + String.fromCharCode(10) + 'ISTRUZIONI OBBLIGATORIE:' + String.fromCharCode(10) + '1. Leggi i file coinvolti nello stack trace' + String.fromCharCode(10) + '2. Individua la riga esatta del problema' + String.fromCharCode(10) + '3. Usa OBBLIGATORIAMENTE il tool edit_file o write_file per correggere il codice' + String.fromCharCode(10) + '4. NON limitarti a spiegare il problema - DEVI modificare i file' + String.fromCharCode(10) + '5. Dopo aver modificato, il sandbox verrà riavviato automaticamente';
8375
8375
  wcChat.push({ role: 'user', text: '\uD83E\uDD16 Auto-fix crash: ' + errorMsg });
8376
8376
  wcChatRunning = true;
8377
8377
  renderWebCraft(document.getElementById('content'));
@@ -8403,7 +8403,7 @@ async function wcTriggerCrashFix(errorMsg) {
8403
8403
  var ev4 = JSON.parse(line4);
8404
8404
  if (ev4.type === 'text') { agentMsg.text += ev4.token; }
8405
8405
  else if (ev4.type === 'tool') { agentMsg.tools.push({ op: ev4.op, path: ev4.path, result: ev4.result, oldSnippet: ev4.oldSnippet || '', newSnippet: ev4.newSnippet || '' }); }
8406
- else if (ev4.type === 'done') { wcChatRunning = false; if (ev4.changed) { wcReloadProjectFiles(); } }
8406
+ else if (ev4.type === 'done') { wcChatRunning = false; if (ev4.changed) { wcReloadProjectFiles(); } if (agentMsg.tools.length > 0) { setTimeout(function(){ wcStartSandbox(); }, 500); } }
8407
8407
  else if (ev4.type === 'restart_sandbox') { wcStartSandbox(); }
8408
8408
  else if (ev4.type === 'error') { agentMsg.text += String.fromCharCode(10)+'Errore: '+ev4.msg; wcChatRunning = false; }
8409
8409
  } catch(_) {}
@@ -9387,7 +9387,7 @@ async function wcFixSandboxError() {
9387
9387
  try {
9388
9388
  var ev4 = JSON.parse(line4);
9389
9389
  if (ev4.type === 'text') { agentMsg.text += ev4.token; renderWebCraft(document.getElementById('content')); wcScrollChatToBottom(); }
9390
- else if (ev4.type === 'tool') { agentMsg.tools.push({ op: ev4.op, path: ev4.path, result: ev4.result }); renderWebCraft(document.getElementById('content')); }
9390
+ else if (ev4.type === 'tool') { agentMsg.tools.push({ op: ev4.op, path: ev4.path, result: ev4.result, oldSnippet: ev4.oldSnippet || '', newSnippet: ev4.newSnippet || '' }); renderWebCraft(document.getElementById('content')); }
9391
9391
  else if (ev4.type === 'done') {
9392
9392
  wcChatRunning = false;
9393
9393
  if (ev4.changed) {