nothumanallowed 13.5.60 → 13.5.62

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.60",
3
+ "version": "13.5.62",
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');
@@ -4687,7 +4690,9 @@ REGOLE CRITICHE:
4687
4690
  content = content.replace(toolCall.old, toolCall.new);
4688
4691
  fs.writeFileSync(fp, content, 'utf8');
4689
4692
  toolResults.push({ op: 'edit', path: toolCall.path, ok: true });
4690
- sendEv({ type: 'tool', op: 'edit', path: toolCall.path, result: 'ok' });
4693
+ sendEv({ type: 'tool', op: 'edit', path: toolCall.path, result: 'ok',
4694
+ oldSnippet: (toolCall.old || '').slice(0, 300),
4695
+ newSnippet: (toolCall.new || '').slice(0, 300) });
4691
4696
  } else {
4692
4697
  sendEv({ type: 'tool', op: 'edit', path: toolCall.path, result: 'old_string non trovato — patch fallita' });
4693
4698
  }
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.60';
8
+ export const VERSION = '13.5.62';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -6975,14 +6975,21 @@ 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>';
6983
6989
  }).join('') + '</div>';
6984
6990
  }
6985
6991
  } else {
6992
+ var diffBlocks = '';
6986
6993
  var toolBadges = (msg.tools || []).map(function(tool){
6987
6994
  var isOk = tool.result === 'ok';
6988
6995
  var isParseErr = tool.op === 'parse_error';
@@ -6990,6 +6997,17 @@ function wcChatPanelHtml() {
6990
6997
  var color = isOk ? 'var(--green)' : 'var(--red)';
6991
6998
  var label = isParseErr ? ('JSON err: ' + wcEsc(tool.result)) : wcEsc(tool.path);
6992
6999
  var title = isOk ? tool.op + ': ' + tool.path : (tool.result || '');
7000
+ // Build inline diff block for successful edits
7001
+ if (isOk && tool.op === 'edit' && tool.oldSnippet) {
7002
+ var oldLines = tool.oldSnippet.split(String.fromCharCode(10)).map(function(l){ return '<div style="background:#3f0f0f;color:#fca5a5;font-family:var(--mono);font-size:9px;padding:0 8px;white-space:pre-wrap;word-break:break-all">- '+wcEsc(l)+'</div>'; }).join('');
7003
+ var newLines = tool.newSnippet.split(String.fromCharCode(10)).map(function(l){ return '<div style="background:#0f2f0f;color:#86efac;font-family:var(--mono);font-size:9px;padding:0 8px;white-space:pre-wrap;word-break:break-all">+ '+wcEsc(l)+'</div>'; }).join('');
7004
+ diffBlocks += '<details style="margin:2px 0;border:1px solid rgba(255,255,255,0.08);border-radius:5px;overflow:hidden">' +
7005
+ '<summary style="padding:3px 8px;font-size:9px;font-family:var(--mono);color:var(--dim);cursor:pointer;list-style:none;display:flex;align-items:center;gap:4px">' +
7006
+ '<span style="color:var(--green)">&#9998;</span> '+wcEsc(tool.path)+' <span style="margin-left:auto;opacity:.5">&#9660;</span>' +
7007
+ '</summary>' +
7008
+ oldLines + newLines +
7009
+ '</details>';
7010
+ }
6993
7011
  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+'">' +
6994
7012
  icon + ' ' + label + '</span>';
6995
7013
  }).join(' ');
@@ -7000,6 +7018,7 @@ function wcChatPanelHtml() {
7000
7018
  '<span style="font-size:10px;font-weight:700;color:var(--green)">WebCraft Agent</span>' +
7001
7019
  '</div>' +
7002
7020
  '<div style="padding:8px 10px;font-size:11px;color:var(--text);line-height:1.6;white-space:pre-wrap">'+agentText+'</div>' +
7021
+ (diffBlocks ? '<div style="padding:4px 8px 6px;border-top:1px solid rgba(255,255,255,0.06)">'+diffBlocks+'</div>' : '') +
7003
7022
  (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>' : '') +
7004
7023
  '</div>';
7005
7024
  }
@@ -7184,7 +7203,7 @@ async function wcExecuteAgentCall(message, isPlanExec, planOrigMsg, attachments)
7184
7203
  if (typingEl) typingEl.textContent = '...';
7185
7204
  wcScrollChatToBottom();
7186
7205
  } else if (ev.type === 'tool') {
7187
- agentMsg.tools.push({ op: ev.op, path: ev.path, result: ev.result });
7206
+ agentMsg.tools.push({ op: ev.op, path: ev.path, result: ev.result, oldSnippet: ev.oldSnippet || '', newSnippet: ev.newSnippet || '' });
7188
7207
  if ((ev.op === 'edit' || ev.op === 'write') && ev.result === 'ok') {
7189
7208
  anyEdits = true;
7190
7209
  wcChat[wcChat.length-1] = agentMsg;
@@ -7304,7 +7323,7 @@ async function wcTriggerAutoFix(missingModule) {
7304
7323
  try {
7305
7324
  var ev2 = JSON.parse(line2);
7306
7325
  if (ev2.type === 'text') { agentMsg.text += ev2.token; }
7307
- else if (ev2.type === 'tool') { agentMsg.tools.push({ op: ev2.op, path: ev2.path, result: ev2.result }); }
7326
+ else if (ev2.type === 'tool') { agentMsg.tools.push({ op: ev2.op, path: ev2.path, result: ev2.result, oldSnippet: ev2.oldSnippet || '', newSnippet: ev2.newSnippet || '' }); }
7308
7327
  else if (ev2.type === 'done') { wcChatRunning = false; if (ev2.changed) { wcReloadProjectFiles(); } }
7309
7328
  else if (ev2.type === 'restart_sandbox') { wcStartSandbox(); }
7310
7329
  else if (ev2.type === 'error') { agentMsg.text += String.fromCharCode(10)+'Errore: '+ev2.msg; wcChatRunning = false; }
@@ -7631,7 +7650,7 @@ async function wcGenerate() {
7631
7650
 
7632
7651
  // Security rules always injected
7633
7652
  var SECURITY_RULES = [
7634
- 'ALWAYS use security headers: X-Content-Type-Options, X-Frame-Options: DENY, Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy: geolocation=(), microphone=(), camera=(), Strict-Transport-Security: max-age=31536000; includeSubDomains; preload.',
7653
+ 'ALWAYS use security headers: X-Content-Type-Options, Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy: geolocation=(), microphone=(), camera=(). NEVER set X-Frame-Options: DENY or frame-ancestors: none — the app runs in a sandbox iframe and must be embeddable. HSTS only in production (check NODE_ENV).',
7635
7654
  'NEVER put secrets, API keys, or DB credentials in frontend code. Only in .env server-side.',
7636
7655
  'ALWAYS use prepared statements / parameterized queries. NEVER string-concatenate SQL.',
7637
7656
  'ALWAYS hash passwords with bcrypt (cost factor 12+). NEVER store plain passwords.',
@@ -7651,7 +7670,7 @@ async function wcGenerate() {
7651
7670
  { name: 'package.json', lang: 'json', prompt: 'Generate package.json for an Express/PostgreSQL project named "'+projName+'". Dependencies: express, pg, bcryptjs, jsonwebtoken, nodemailer, helmet, express-rate-limit, cors, dotenv, express-validator, ioredis. DevDependencies: nodemon. Scripts: start, dev.' },
7652
7671
  { name: '.env.example', lang: 'bash', prompt: 'Generate .env.example with all required env vars: DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASS, JWT_SECRET, JWT_REFRESH_SECRET, SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM, SENDGRID_API_KEY (commented as optional fallback), REDIS_URL (default redis://localhost:6379, works with Dragonfly too), PORT, NODE_ENV, CORS_ORIGIN, BASE_URL. Add helpful comments for each. Note that REDIS_URL is optional — app falls back to in-memory LRU if Redis unavailable.' },
7653
7672
  { name: 'server/db.js', lang: 'javascript', prompt: 'Generate server/db.js: pg.Pool singleton (max:10, idleTimeoutMillis:30000, connectionTimeoutMillis:2000). Circuit breaker: if DB fails 5+ times in 60s, open circuit (throw immediately) for 30s, then half-open (try one query). Export pool, query(text, params) with circuit breaker, transaction(callback) helper (BEGIN/COMMIT/ROLLBACK). Graceful shutdown on SIGTERM/SIGINT.' },
7654
- { name: 'server/middleware/security.js', lang: 'javascript', prompt: 'Generate server/middleware/security.js: helmet with full CSP (defaultSrc self, scriptSrc self, styleSrc self unsafe-inline, imgSrc self data:, connectSrc self, frameSrc none, objectSrc none), HSTS, X-Frame-Options DENY, Referrer-Policy. Add express-rate-limit for general routes (100/15min) and strict limiter for auth (5/15min). Export { applySecurityMiddleware, authLimiter }.' },
7673
+ { name: 'server/middleware/security.js', lang: 'javascript', prompt: 'Generate server/middleware/security.js: detect sandbox via isSandbox = !process.env.NODE_ENV || process.env.NODE_ENV === "development". Use helmet CSP: defaultSrc self, scriptSrc self unsafe-inline, styleSrc self unsafe-inline, imgSrc self data:, connectSrc self, objectSrc none. frameAncestors: if isSandbox use ["self", "http://127.0.0.1:*", "http://localhost:*"] else ["none"]. NO X-Frame-Options DENY (conflicts with frameAncestors). NO HSTS in sandbox (HTTP only). Referrer-Policy strict-origin-when-cross-origin. Add express-rate-limit for general routes (100/15min) and strict limiter for auth (5/15min). Export { applySecurityMiddleware, authLimiter }.' },
7655
7674
  { name: 'server/middleware/validate.js', lang: 'javascript', prompt: 'Generate server/middleware/validate.js using express-validator. Export handleValidationErrors middleware. Export auth field validators: registerValidator (fields: '+authFieldsDef+'), loginValidator (email + password).' },
7656
7675
  { name: 'server/services/email.js', lang: 'javascript', prompt: 'Generate server/services/email.js: Nodemailer transporter using SMTP from env. Function sendVerificationEmail(to, token, baseUrl): sends HTML email with verification link. Function sendPasswordResetEmail(to, token, baseUrl). Add SendGrid fallback (commented out, predisposed with transporter swap). Never expose credentials.' },
7657
7676
  { name: 'server/routes/auth.js', lang: 'javascript', prompt: 'Generate server/routes/auth.js: POST /register (validate fields: '+authFieldsDef+', check duplicate email, bcrypt hash password cost 12, insert user, send verification email, return 201), POST /login (validate, check email verified, compare bcrypt, issue JWT access 15min + refresh 7d httpOnly cookie), POST /logout (clear refresh cookie), POST /refresh-token (validate refresh from httpOnly cookie, rotate token), GET /verify-email/:token (mark email verified). Use parameterized queries only. Apply authLimiter to register and login.' },
@@ -7857,7 +7876,12 @@ function wcSandboxPanelHtml() {
7857
7876
 
7858
7877
  return '<div style="display:flex;flex-direction:column;flex:1;min-height:0;overflow-y:auto">' +
7859
7878
  phasesHtml +
7860
- (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>' : '') +
7879
+ (sb.error ?
7880
+ '<div style="padding:10px 14px;border-top:1px solid var(--border);display:flex;align-items:flex-start;gap:10px;flex-wrap:wrap">' +
7881
+ '<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>' +
7882
+ '<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>' +
7883
+ '</div>'
7884
+ : '') +
7861
7885
  '</div>';
7862
7886
  }
7863
7887
 
@@ -7948,6 +7972,66 @@ async function wcStopSandbox() {
7948
7972
  renderWebCraft(document.getElementById('content'));
7949
7973
  }
7950
7974
 
7975
+ // "Correggi" button — sends full sandbox error to the agent for repair
7976
+ async function wcFixSandboxError() {
7977
+ var errText = wcState.sandbox.error || 'Errore sconosciuto avviando il server sandbox';
7978
+ // Put error in chat input so user can see it, then fire agent
7979
+ var fixMsg = 'ERRORE SANDBOX — il server Node.js non si avvia. Analizza tutti i file del progetto, trova la causa e correggi.' +
7980
+ String.fromCharCode(10) + String.fromCharCode(10) +
7981
+ 'STACKTRACE COMPLETO:' + String.fromCharCode(10) + errText;
7982
+ // Push as user message so it appears in chat
7983
+ wcChat.push({ role: 'user', text: '&#129302; Correggi errore sandbox' });
7984
+ wcScrollChatToBottom();
7985
+ wcChatRunning = true;
7986
+ renderWebCraft(document.getElementById('content'));
7987
+
7988
+ try {
7989
+ var r = await fetch(API + '/api/studio/webcraft/agent', {
7990
+ method: 'POST',
7991
+ headers: { 'Content-Type': 'application/json' },
7992
+ body: JSON.stringify({ projectName: wcState.projectName, message: fixMsg, autofix: true })
7993
+ });
7994
+ if (!r.ok) { wcChatRunning = false; renderWebCraft(document.getElementById('content')); return; }
7995
+ var agentMsg = { role: 'agent', text: '', tools: [] };
7996
+ wcChat.push(agentMsg);
7997
+ var reader4 = r.body.getReader();
7998
+ var dec4 = new TextDecoder();
7999
+ var buf4 = '';
8000
+ while (true) {
8001
+ var res4 = await reader4.read();
8002
+ if (res4.done) break;
8003
+ buf4 += dec4.decode(res4.value, { stream: true });
8004
+ var parts4 = buf4.split(String.fromCharCode(10) + String.fromCharCode(10));
8005
+ buf4 = parts4.pop();
8006
+ for (var pi4 = 0; pi4 < parts4.length; pi4++) {
8007
+ var line4 = parts4[pi4].replace(/^data: /, '').trim();
8008
+ if (!line4) continue;
8009
+ try {
8010
+ var ev4 = JSON.parse(line4);
8011
+ if (ev4.type === 'text') { agentMsg.text += ev4.token; renderWebCraft(document.getElementById('content')); wcScrollChatToBottom(); }
8012
+ else if (ev4.type === 'tool') { agentMsg.tools.push({ op: ev4.op, path: ev4.path, result: ev4.result }); renderWebCraft(document.getElementById('content')); }
8013
+ else if (ev4.type === 'done') {
8014
+ wcChatRunning = false;
8015
+ if (ev4.changed) {
8016
+ // Files changed — syntax check then offer to restart
8017
+ wcChat.push({ role: 'system', text: '&#9989; Fix applicato. Clicca &#9654; Avvia Sandbox per ritentare.' });
8018
+ }
8019
+ renderWebCraft(document.getElementById('content'));
8020
+ wcScrollChatToBottom();
8021
+ } else if (ev4.type === 'restart_sandbox') {
8022
+ wcState.sandbox = { running: false, port: null, dir: null, logs: [], error: null };
8023
+ setTimeout(function(){ wcStartSandbox(); }, 800);
8024
+ }
8025
+ } catch(_) {}
8026
+ }
8027
+ }
8028
+ } catch(e2) {
8029
+ wcChatRunning = false;
8030
+ wcChat.push({ role: 'system', text: '&#10060; Errore chiamata agente: ' + e2.message });
8031
+ renderWebCraft(document.getElementById('content'));
8032
+ }
8033
+ }
8034
+
7951
8035
  var _wcLastDownload = 0;
7952
8036
  function wcDownloadZip() {
7953
8037
  if (!wcState.generatedFiles.length) return;