nothumanallowed 13.5.59 → 13.5.61

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": "13.5.59",
3
+ "version": "13.5.61",
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": {
@@ -4225,7 +4225,10 @@ function sentinelMiddleware(req, res, next) {
4225
4225
  }
4226
4226
  next();
4227
4227
  }
4228
- module.exports = { sentinelMiddleware };
4228
+ // Export both ways: default function (for require('./middleware/sentinel'))
4229
+ // and named export (for require('./middleware/sentinel').sentinelMiddleware)
4230
+ module.exports = sentinelMiddleware;
4231
+ module.exports.sentinelMiddleware = sentinelMiddleware;
4229
4232
  `;
4230
4233
  fs.mkdirSync(path.join(sandboxDir, 'server', 'middleware'), { recursive: true });
4231
4234
  fs.writeFileSync(path.join(sandboxDir, 'server', 'middleware', 'sentinel.js'), sentinelShim, 'utf8');
@@ -4632,12 +4635,40 @@ REGOLE CRITICHE:
4632
4635
  }
4633
4636
 
4634
4637
  // Parse and execute tool calls from response
4638
+ // Sanitize JSON from LLM: replace literal newlines inside JSON strings with \n
4639
+ // Models often write multiline strings without escaping, which breaks JSON.parse
4640
+ const sanitizeToolJson = (raw) => {
4641
+ // Replace literal CR/LF inside JSON string values with escaped versions
4642
+ // Strategy: walk char by char, track if we're inside a JSON string
4643
+ let out = '';
4644
+ let inStr = false;
4645
+ let escaped = false;
4646
+ for (let ci = 0; ci < raw.length; ci++) {
4647
+ const ch = raw[ci];
4648
+ if (escaped) { out += ch; escaped = false; continue; }
4649
+ if (ch === '\\') { out += ch; escaped = true; continue; }
4650
+ if (ch === '"') { inStr = !inStr; out += ch; continue; }
4651
+ if (inStr && (ch === '\n' || ch === '\r')) {
4652
+ out += ch === '\n' ? '\\n' : '\\r';
4653
+ continue;
4654
+ }
4655
+ out += ch;
4656
+ }
4657
+ return out;
4658
+ };
4659
+
4635
4660
  const toolRegex = /<tool>([\s\S]*?)<\/tool>/g;
4636
4661
  let toolMatch;
4637
4662
  const toolResults = [];
4638
4663
  while ((toolMatch = toolRegex.exec(fullResponse)) !== null) {
4639
4664
  let toolCall;
4640
- try { toolCall = JSON.parse(toolMatch[1]); } catch(e) { continue; }
4665
+ try {
4666
+ const raw = toolMatch[1].trim();
4667
+ toolCall = JSON.parse(sanitizeToolJson(raw));
4668
+ } catch(e) {
4669
+ sendEv({ type: 'tool', op: 'parse_error', path: '?', result: 'JSON malformato: ' + e.message.slice(0, 80) });
4670
+ continue;
4671
+ }
4641
4672
 
4642
4673
  if (toolCall.op === 'read') {
4643
4674
  const fp = path.join(sandboxDir, toolCall.path.replace(/^\/+/, ''));
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.59';
8
+ export const VERSION = '13.5.61';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -6975,8 +6975,14 @@ function wcChatPanelHtml() {
6975
6975
  '</div>';
6976
6976
  }
6977
6977
  } else if (msg.role === 'system') {
6978
- // System messages: compact notices (snapshot, syntax check, etc.)
6979
- messagesHtml += '<div style="margin:2px 12px;padding:4px 10px;background:var(--bg3);border-left:2px solid var(--border2);border-radius:4px;font-size:10px;color:var(--dim)">' + (msg.text||'') + '</div>';
6978
+ // System messages: compact notices (snapshot, syntax check, error with fix button)
6979
+ var isSandboxErr = (msg.text || '').indexOf('Errore sandbox') !== -1;
6980
+ var borderColor = isSandboxErr ? '#ef4444' : 'var(--border2)';
6981
+ var textColor = isSandboxErr ? '#fca5a5' : 'var(--dim)';
6982
+ messagesHtml += '<div style="margin:4px 12px;padding:6px 10px;background:var(--bg3);border-left:2px solid '+borderColor+';border-radius:4px;font-size:10px;color:'+textColor+';display:flex;align-items:center;gap:8px">' +
6983
+ '<span style="flex:1">' + (msg.text||'') + '</span>' +
6984
+ (isSandboxErr ? '<button onclick="wcFixSandboxError()" style="flex-shrink:0;padding:4px 10px;background:#7f1d1d;border:1px solid #ef4444;border-radius:5px;color:#fca5a5;font-size:10px;font-weight:700;cursor:pointer">&#129302; Correggi</button>' : '') +
6985
+ '</div>';
6980
6986
  if (msg.syntaxErrors && msg.syntaxErrors.length) {
6981
6987
  messagesHtml += '<div style="margin:2px 12px">' + msg.syntaxErrors.map(function(e2){
6982
6988
  return '<div style="font-size:10px;font-family:var(--mono);color:#f87171;padding:2px 0">&#10005; ' + wcEsc(e2.file) + ': ' + wcEsc(e2.error) + '</div>';
@@ -6984,16 +6990,23 @@ function wcChatPanelHtml() {
6984
6990
  }
6985
6991
  } else {
6986
6992
  var toolBadges = (msg.tools || []).map(function(tool){
6987
- var icon = tool.op === 'edit' ? '&#9998;' : (tool.op === 'write' ? '&#10133;' : '&#128065;');
6988
- var color = tool.result === 'ok' ? 'var(--green)' : 'var(--red)';
6989
- return '<span style="display:inline-flex;align-items:center;gap:3px;background:var(--bg3);border:1px solid var(--border);border-radius:4px;padding:2px 6px;font-size:9px;font-family:var(--mono);color:'+color+'">'+icon+' '+wcEsc(tool.path)+'</span>';
6993
+ var isOk = tool.result === 'ok';
6994
+ var isParseErr = tool.op === 'parse_error';
6995
+ var icon = isParseErr ? '&#10067;' : (tool.op === 'edit' ? '&#9998;' : (tool.op === 'write' ? '&#10133;' : '&#128065;'));
6996
+ var color = isOk ? 'var(--green)' : 'var(--red)';
6997
+ var label = isParseErr ? ('JSON err: ' + wcEsc(tool.result)) : wcEsc(tool.path);
6998
+ var title = isOk ? tool.op + ': ' + tool.path : (tool.result || '');
6999
+ return '<span title="'+wcEsc(title)+'" style="display:inline-flex;align-items:center;gap:3px;background:var(--bg3);border:1px solid '+(isOk?'var(--green3)':'var(--red)')+';border-radius:4px;padding:2px 6px;font-size:9px;font-family:var(--mono);color:'+color+'">' +
7000
+ icon + ' ' + label + '</span>';
6990
7001
  }).join(' ');
6991
- messagesHtml += '<div style="margin:4px 12px">' +
6992
- '<div style="display:flex;align-items:center;gap:6px;margin-bottom:3px">' +
6993
- '<span style="font-size:10px;font-weight:700;color:var(--green)">&#129302; WebCraft Agent</span>' +
7002
+ var agentText = wcEsc(msg.text.replace(new RegExp('<tool>[\\s\\S]*?<\\/tool>', 'g'), '').trim());
7003
+ messagesHtml += '<div style="margin:6px 12px;border:1px solid rgba(255,255,255,0.12);border-radius:10px;background:var(--bg3);overflow:hidden">' +
7004
+ '<div style="display:flex;align-items:center;gap:6px;padding:6px 10px;border-bottom:1px solid rgba(255,255,255,0.06);background:rgba(255,255,255,0.03)">' +
7005
+ '<span style="font-size:13px">&#129302;</span>' +
7006
+ '<span style="font-size:10px;font-weight:700;color:var(--green)">WebCraft Agent</span>' +
6994
7007
  '</div>' +
6995
- '<div style="font-size:11px;color:var(--text);line-height:1.6;white-space:pre-wrap;max-width:85%">'+wcEsc(msg.text.replace(new RegExp('<tool>[\\s\\S]*?<\\/tool>', 'g'), '').trim())+'</div>' +
6996
- (toolBadges ? '<div style="display:flex;flex-wrap:wrap;gap:4px;margin-top:5px">'+toolBadges+'</div>' : '') +
7008
+ '<div style="padding:8px 10px;font-size:11px;color:var(--text);line-height:1.6;white-space:pre-wrap">'+agentText+'</div>' +
7009
+ (toolBadges ? '<div style="display:flex;flex-wrap:wrap;gap:4px;padding:6px 10px;border-top:1px solid rgba(255,255,255,0.06)">'+toolBadges+'</div>' : '') +
6997
7010
  '</div>';
6998
7011
  }
6999
7012
  }
@@ -7850,7 +7863,12 @@ function wcSandboxPanelHtml() {
7850
7863
 
7851
7864
  return '<div style="display:flex;flex-direction:column;flex:1;min-height:0;overflow-y:auto">' +
7852
7865
  phasesHtml +
7853
- (sb.error ? '<div style="padding:10px 14px;color:var(--red);font-size:11px;font-family:var(--mono);border-top:1px solid var(--border)">&#10060; '+wcEsc(sb.error)+'</div>' : '') +
7866
+ (sb.error ?
7867
+ '<div style="padding:10px 14px;border-top:1px solid var(--border);display:flex;align-items:flex-start;gap:10px;flex-wrap:wrap">' +
7868
+ '<div style="flex:1;min-width:0;font-size:11px;font-family:var(--mono);color:var(--red);white-space:pre-wrap;word-break:break-all">&#10060; '+wcEsc(sb.error)+'</div>' +
7869
+ '<button onclick="wcFixSandboxError()" style="flex-shrink:0;padding:6px 14px;background:#7f1d1d;border:1px solid #ef4444;border-radius:6px;color:#fca5a5;font-size:11px;font-weight:700;cursor:pointer;white-space:nowrap">&#129302; Correggi</button>' +
7870
+ '</div>'
7871
+ : '') +
7854
7872
  '</div>';
7855
7873
  }
7856
7874
 
@@ -7941,6 +7959,66 @@ async function wcStopSandbox() {
7941
7959
  renderWebCraft(document.getElementById('content'));
7942
7960
  }
7943
7961
 
7962
+ // "Correggi" button — sends full sandbox error to the agent for repair
7963
+ async function wcFixSandboxError() {
7964
+ var errText = wcState.sandbox.error || 'Errore sconosciuto avviando il server sandbox';
7965
+ // Put error in chat input so user can see it, then fire agent
7966
+ var fixMsg = 'ERRORE SANDBOX — il server Node.js non si avvia. Analizza tutti i file del progetto, trova la causa e correggi.' +
7967
+ String.fromCharCode(10) + String.fromCharCode(10) +
7968
+ 'STACKTRACE COMPLETO:' + String.fromCharCode(10) + errText;
7969
+ // Push as user message so it appears in chat
7970
+ wcChat.push({ role: 'user', text: '&#129302; Correggi errore sandbox' });
7971
+ wcScrollChatToBottom();
7972
+ wcChatRunning = true;
7973
+ renderWebCraft(document.getElementById('content'));
7974
+
7975
+ try {
7976
+ var r = await fetch(API + '/api/studio/webcraft/agent', {
7977
+ method: 'POST',
7978
+ headers: { 'Content-Type': 'application/json' },
7979
+ body: JSON.stringify({ projectName: wcState.projectName, message: fixMsg, autofix: true })
7980
+ });
7981
+ if (!r.ok) { wcChatRunning = false; renderWebCraft(document.getElementById('content')); return; }
7982
+ var agentMsg = { role: 'agent', text: '', tools: [] };
7983
+ wcChat.push(agentMsg);
7984
+ var reader4 = r.body.getReader();
7985
+ var dec4 = new TextDecoder();
7986
+ var buf4 = '';
7987
+ while (true) {
7988
+ var res4 = await reader4.read();
7989
+ if (res4.done) break;
7990
+ buf4 += dec4.decode(res4.value, { stream: true });
7991
+ var parts4 = buf4.split(String.fromCharCode(10) + String.fromCharCode(10));
7992
+ buf4 = parts4.pop();
7993
+ for (var pi4 = 0; pi4 < parts4.length; pi4++) {
7994
+ var line4 = parts4[pi4].replace(/^data: /, '').trim();
7995
+ if (!line4) continue;
7996
+ try {
7997
+ var ev4 = JSON.parse(line4);
7998
+ if (ev4.type === 'text') { agentMsg.text += ev4.token; renderWebCraft(document.getElementById('content')); wcScrollChatToBottom(); }
7999
+ else if (ev4.type === 'tool') { agentMsg.tools.push({ op: ev4.op, path: ev4.path, result: ev4.result }); renderWebCraft(document.getElementById('content')); }
8000
+ else if (ev4.type === 'done') {
8001
+ wcChatRunning = false;
8002
+ if (ev4.changed) {
8003
+ // Files changed — syntax check then offer to restart
8004
+ wcChat.push({ role: 'system', text: '&#9989; Fix applicato. Clicca &#9654; Avvia Sandbox per ritentare.' });
8005
+ }
8006
+ renderWebCraft(document.getElementById('content'));
8007
+ wcScrollChatToBottom();
8008
+ } else if (ev4.type === 'restart_sandbox') {
8009
+ wcState.sandbox = { running: false, port: null, dir: null, logs: [], error: null };
8010
+ setTimeout(function(){ wcStartSandbox(); }, 800);
8011
+ }
8012
+ } catch(_) {}
8013
+ }
8014
+ }
8015
+ } catch(e2) {
8016
+ wcChatRunning = false;
8017
+ wcChat.push({ role: 'system', text: '&#10060; Errore chiamata agente: ' + e2.message });
8018
+ renderWebCraft(document.getElementById('content'));
8019
+ }
8020
+ }
8021
+
7944
8022
  var _wcLastDownload = 0;
7945
8023
  function wcDownloadZip() {
7946
8024
  if (!wcState.generatedFiles.length) return;