nothumanallowed 13.5.69 → 13.5.71

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.69",
3
+ "version": "13.5.71",
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": {
@@ -4086,7 +4086,11 @@ ${completedHeadings ? `## SECTIONS ALREADY WRITTEN (headings only):\n${completed
4086
4086
  'Connection': 'keep-alive',
4087
4087
  'Access-Control-Allow-Origin': '*',
4088
4088
  });
4089
- const sendLog = (msg) => res.write(`data: ${JSON.stringify({ type: 'log', msg })}\n\n`);
4089
+ const _sbLogLines = [];
4090
+ const sendLog = (msg) => {
4091
+ _sbLogLines.push(msg);
4092
+ res.write(`data: ${JSON.stringify({ type: 'log', msg })}\n\n`);
4093
+ };
4090
4094
  const sendReady = (port, dir) => res.write(`data: ${JSON.stringify({ type: 'ready', port, dir })}\n\n`);
4091
4095
  const sendError = (msg) => res.write(`data: ${JSON.stringify({ type: 'error', msg })}\n\n`);
4092
4096
 
@@ -4274,6 +4278,21 @@ module.exports = { get, set, del, exists };
4274
4278
  fs.mkdirSync(path.join(sandboxDir, 'server', 'services'), { recursive: true });
4275
4279
  fs.writeFileSync(path.join(sandboxDir, 'server', 'services', 'cache.js'), cacheShim, 'utf8');
4276
4280
 
4281
+ // Validators shim — LLM often generates require('../utils/validators') with helpers that don't exist
4282
+ const validatorsShim = `
4283
+ // NHA WebCraft Sandbox — utils/validators shim
4284
+ function validateEmail(email) { return typeof email === 'string' && /^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(email.trim()); }
4285
+ function sanitizeText(str) { return typeof str === 'string' ? str.replace(/<[^>]*>/g, '').trim() : ''; }
4286
+ function validatePassword(pwd) { return typeof pwd === 'string' && pwd.length >= 8; }
4287
+ function validateUsername(u) { return typeof u === 'string' && u.length >= 2 && u.length <= 50; }
4288
+ function validatePhone(p) { return typeof p === 'string' && /^[+]?[\\d\\s\\-().]{7,20}$/.test(p.trim()); }
4289
+ module.exports = { validateEmail, sanitizeText, validatePassword, validateUsername, validatePhone };
4290
+ `;
4291
+ fs.mkdirSync(path.join(sandboxDir, 'server', 'utils'), { recursive: true });
4292
+ if (!fs.existsSync(path.join(sandboxDir, 'server', 'utils', 'validators.js'))) {
4293
+ fs.writeFileSync(path.join(sandboxDir, 'server', 'utils', 'validators.js'), validatorsShim, 'utf8');
4294
+ }
4295
+
4277
4296
  // Patch all generated JS files: fix known wrong require() names
4278
4297
  // The LLM often uses 'bcrypt' instead of 'bcryptjs', 'pg' instead of nothing, etc.
4279
4298
  const requireFixes = [
@@ -4293,6 +4312,21 @@ module.exports = { get, set, del, exists };
4293
4312
  [/require\(['"]winston['"]\)/g, "{createLogger:()=>({info:()=>{},error:()=>{},warn:()=>{}}),transports:{Console:function(){}},format:{combine:()=>{},timestamp:()=>{},json:()=>{}}}"],
4294
4313
  [/require\(['"]morgan['"]\)/g, "(()=>(r,s,n)=>n())"],
4295
4314
  [/require\(['"]compression['"]\)/g, "(()=>(r,s,n)=>n())"],
4315
+ [/require\(['"]express-validator['"]\)/g, "{body:()=>({isEmail:()=>({normalizeEmail:()=>({run:async()=>{}})}),isLength:()=>({run:async()=>{}}),trim:()=>({escape:()=>({run:async()=>{}})}),notEmpty:()=>({run:async()=>{}})}),validationResult:()=>({isEmpty:()=>true,array:()=>[]})}"],
4316
+ [/require\(['"]validator['"]\)/g, "{isEmail:(s)=>/^[^@\\s]+@[^@\\s]+[.][^@\\s]+$/.test(s),escape:(s)=>String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'),trim:(s)=>String(s).trim(),isEmpty:(s)=>!s||!String(s).trim(),isLength:(s,o)=>{ var l=String(s).length; return (!o.min||l>=o.min)&&(!o.max||l<=o.max); }}"],
4317
+ [/require\(['"]handlebars['"]\)/g, "{compile:(t)=>(d)=>t.replace(/\\{\\{([^}]+)\\}\\}/g,(_,k)=>d[k.trim()]||''),registerHelper:()=>{},registerPartial:()=>{}}"],
4318
+ [/require\(['"]express-handlebars['"]\)/g, "{engine:()=>(p,o,cb)=>cb(null,'<html>'+JSON.stringify(o)+'</html>')}"],
4319
+ [/require\(['"]hbs['"]\)/g, "{registerHelper:()=>{},registerPartial:()=>{}}"],
4320
+ [/require\(['"]ejs['"]\)/g, "{render:(t,d)=>t.replace(/<%=([^%]+)%>/g,(_,k)=>d[k.trim()]||''),renderFile:(f,d,o,cb)=>{ if(typeof o==='function'){o(null,'');}else if(cb){cb(null,'');} }}"],
4321
+ [/require\(['"]pug['"]\)/g, "{compile:()=>(d)=>'',renderFile:(f,d,cb)=>cb&&cb(null,'')}"],
4322
+ [/require\(['"]nunjucks['"]\)/g, "{configure:()=>({}),render:(t,d)=>JSON.stringify(d),renderString:(t,d)=>JSON.stringify(d)}"],
4323
+ [/require\(['"]mustache['"]\)/g, "{render:(t,d)=>t.replace(/\\{\\{([^}]+)\\}\\}/g,(_,k)=>d[k.trim()]||'')}"],
4324
+ [/require\(['"]marked['"]\)/g, "{marked:(s)=>s,parse:(s)=>s}"],
4325
+ [/require\(['"]highlight\.js['"]\)/g, "{highlight:(c)=>({value:c}),highlightAuto:(c)=>({value:c})}"],
4326
+ [/require\(['"]nodemailer['"]\)/g, "{createTransport:()=>({sendMail:(o,cb)=>{ if(cb)cb(null,{messageId:'sandbox-'+Date.now()}); return Promise.resolve({messageId:'sandbox'}); }})}"],
4327
+ [/require\(['"]stripe['"]\)/g, "(()=>({customers:{create:async()=>({id:'cus_sandbox'})},paymentIntents:{create:async()=>({id:'pi_sandbox',client_secret:'sandbox_secret'})}}))()"],
4328
+ [/require\(['"]@sendgrid\/mail['"]\)/g, "{setApiKey:()=>{},send:async()=>({statusCode:202})}"],
4329
+ [/require\(['"]twilio['"]\)/g, "(()=>({messages:{create:async()=>({sid:'SM_sandbox'})}}))()"],
4296
4330
  [/require\(['"]cookie-parser['"]\)/g, "(()=>(r,s,n)=>{r.cookies=r.cookies||{};n()})"],
4297
4331
  [/require\(['"]passport['"]\)/g, "{initialize:()=>(r,s,n)=>n(),session:()=>(r,s,n)=>n(),authenticate:()=>(r,s,n)=>n&&n()}"],
4298
4332
  [/require\(['"]express-session['"]\)/g, "(()=>(r,s,n)=>{r.session=r.session||{};n()})"],
@@ -4313,6 +4347,14 @@ module.exports = { get, set, del, exists };
4313
4347
  [/require\(['"]\.\.\/\.\.\/config['"]\)/g, "{env:process.env}"],
4314
4348
  [/require\(['"]\.\.\/config['"]\)/g, "{env:process.env}"],
4315
4349
  [/require\(['"]\.\/config['"]\)/g, "{env:process.env}"],
4350
+ // utils/* — LLM generates helpers that don't exist; redirect to shim
4351
+ [/require\(['"]\.\.\/utils\/validators['"]\)/g, "require('../utils/validators')"],
4352
+ [/require\(['"]\.\/utils\/validators['"]\)/g, "require('./utils/validators')"],
4353
+ [/require\(['"]\.\.\/utils\/validation['"]\)/g, "require('../utils/validators')"],
4354
+ [/require\(['"]\.\.\/helpers\/validators['"]\)/g, "require('../utils/validators')"],
4355
+ [/require\(['"]\.\.\/utils\/helpers['"]\)/g, "{sanitize:(s)=>String(s).trim(),escape:(s)=>String(s).replace(/</g,'&lt;')}"],
4356
+ [/require\(['"]\.\.\/utils\/logger['"]\)/g, "{info:()=>{},error:()=>{},warn:()=>{},debug:()=>{}}"],
4357
+ [/require\(['"]\.\.\/utils\/errors['"]\)/g, "{AppError:class AppError extends Error{constructor(m,s){super(m);this.statusCode=s||500;}}}"],
4316
4358
  // rateLimiter: LLM sometimes creates a separate file instead of importing from security.js
4317
4359
  [/require\(['"]\.\.\/middleware\/rateLimiter['"]\)/g, "require('../middleware/security')"],
4318
4360
  [/require\(['"]\.\/middleware\/rateLimiter['"]\)/g, "require('./middleware/security')"],
@@ -4468,8 +4510,44 @@ module.exports = { get, set, del, exists };
4468
4510
  });
4469
4511
 
4470
4512
  sendLog(`✅ Sandbox pronta!`);
4513
+
4514
+ // Write sandbox log to skills/ so the agent can read it as context
4515
+ try {
4516
+ const _nl = '\n';
4517
+ const logTs = new Date().toISOString().replace('T', ' ').slice(0, 19);
4518
+ const logName = projName + '-' + logTs.replace(/[: ]/g, '-') + '.log';
4519
+ const logsDir = path.join(sandboxDir, 'skills');
4520
+ fs.mkdirSync(logsDir, { recursive: true });
4521
+ // Keep only last 3 log files to avoid bloat
4522
+ const existing = fs.readdirSync(logsDir).filter(f => f.endsWith('.log') && f.startsWith(projName + '-'));
4523
+ existing.sort().slice(0, -2).forEach(f => { try { fs.unlinkSync(path.join(logsDir, f)); } catch(_) {} });
4524
+ const logContent = '# Sandbox Log — ' + projName + _nl + 'Avviato: ' + logTs + _nl + 'Porta: ' + freePort + _nl + _nl + _sbLogLines.join(_nl);
4525
+ fs.writeFileSync(path.join(logsDir, logName), logContent, 'utf8');
4526
+ // Also update _index.json so the UI knows the type
4527
+ const idxPath = path.join(logsDir, '_index.json');
4528
+ let idx = {};
4529
+ try { idx = JSON.parse(fs.readFileSync(idxPath, 'utf8')); } catch(_) {}
4530
+ idx[logName] = 'log';
4531
+ fs.writeFileSync(idxPath, JSON.stringify(idx), 'utf8');
4532
+ } catch(_) {}
4533
+
4471
4534
  sendReady(freePort, sandboxDir);
4472
4535
  } catch (e) {
4536
+ // Write error log too
4537
+ try {
4538
+ const _nl = '\n';
4539
+ const logTs = new Date().toISOString().replace('T', ' ').slice(0, 19);
4540
+ const logName = projName + '-' + logTs.replace(/[: ]/g, '-') + '-ERROR.log';
4541
+ const logsDir = path.join(sandboxDir, 'skills');
4542
+ fs.mkdirSync(logsDir, { recursive: true });
4543
+ const logContent = '# Sandbox Log — ' + projName + ' [ERRORE]' + _nl + 'Avviato: ' + logTs + _nl + _nl + _sbLogLines.join(_nl) + _nl + _nl + '❌ ERRORE: ' + e.message;
4544
+ fs.writeFileSync(path.join(logsDir, logName), logContent, 'utf8');
4545
+ const idxPath = path.join(logsDir, '_index.json');
4546
+ let idx = {};
4547
+ try { idx = JSON.parse(fs.readFileSync(idxPath, 'utf8')); } catch(_) {}
4548
+ idx[logName] = 'log';
4549
+ fs.writeFileSync(idxPath, JSON.stringify(idx), 'utf8');
4550
+ } catch(_) {}
4473
4551
  sendError(e.message);
4474
4552
  }
4475
4553
  res.end();
@@ -4548,7 +4626,7 @@ module.exports = { get, set, del, exists };
4548
4626
  let typeIndex = {};
4549
4627
  if (fs.existsSync(indexPath)) { try { typeIndex = JSON.parse(fs.readFileSync(indexPath, 'utf8')); } catch(_) {} }
4550
4628
  const defaultType = (n) => n === 'memory.md' ? 'memory' : n === 'liara.md' ? 'provider' : 'skill';
4551
- const sections = { memory: [], provider: [], skill: [] };
4629
+ const sections = { memory: [], provider: [], skill: [], log: [] };
4552
4630
  for (const fname of fs.readdirSync(skillsDir)) {
4553
4631
  if (!fname.endsWith('.md')) continue;
4554
4632
  try {
@@ -4563,6 +4641,7 @@ module.exports = { get, set, del, exists };
4563
4641
  if (sections.memory.length) parts.push('MEMORIA PROGETTO:\n' + sections.memory.join('\n\n'));
4564
4642
  if (sections.provider.length) parts.push('ISTRUZIONI MODELLO AI:\n' + sections.provider.join('\n\n'));
4565
4643
  if (sections.skill.length) parts.push('SKILLS & PATTERN:\n' + sections.skill.join('\n\n'));
4644
+ if (sections.log && sections.log.length) parts.push('LOG AVVIO SANDBOX (ultimo):\n' + sections.log[sections.log.length - 1]);
4566
4645
  if (parts.length) skillsContext = '\n' + parts.join('\n\n') + '\n';
4567
4646
  }
4568
4647
 
@@ -6727,11 +6727,11 @@ function wcOpenSandbox() { if (wcState.sandbox.port) window.open('http://127.0.0
6727
6727
  // ── WebCraft Context Files (Skills / Memory / Provider) ───────────────────────
6728
6728
 
6729
6729
  function wcFileTypeIcon(type) {
6730
- return type === 'memory' ? '&#129504;' : type === 'provider' ? '&#129302;' : '&#128203;';
6730
+ return type === 'memory' ? '&#129504;' : type === 'provider' ? '&#129302;' : type === 'log' ? '&#128196;' : '&#128203;';
6731
6731
  }
6732
6732
  function wcFileTypeBadge(type) {
6733
- var colors = { memory: '#7c5cbf', provider: '#2a7fff', skill: '#1a7a4a' };
6734
- var labels = { memory: 'memory', provider: 'provider', skill: 'skill' };
6733
+ var colors = { memory: '#7c5cbf', provider: '#2a7fff', skill: '#1a7a4a', log: '#555' };
6734
+ var labels = { memory: 'memory', provider: 'provider', skill: 'skill', log: 'log' };
6735
6735
  return '<span style="font-size:9px;padding:1px 5px;border-radius:3px;background:' + (colors[type]||'#444') + ';color:#fff;margin-left:4px;flex-shrink:0">' + (labels[type]||type) + '</span>';
6736
6736
  }
6737
6737
 
@@ -6756,14 +6756,16 @@ function wcSkillsPanelHtml() {
6756
6756
  // Can add new skill only (memory + provider are singletons already in defaults)
6757
6757
  var rows = wcSkills.map(function(s, si) {
6758
6758
  var isSingleton = s.type === 'memory' || s.type === 'provider';
6759
+ var isLog = s.type === 'log';
6759
6760
  var isEmpty = !s.content || s.content.trim() === '';
6760
6761
  return '<div style="display:flex;align-items:center;gap:4px;padding:5px 0;border-bottom:1px solid var(--border)">' +
6761
6762
  '<span style="font-size:13px;flex-shrink:0">' + wcFileTypeIcon(s.type) + '</span>' +
6762
- '<span style="font-size:11px;color:var(--text);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + wcEsc(s.name) + '</span>' +
6763
+ '<span style="font-size:11px;color:'+(isLog?'var(--dim)':'var(--text)')+';flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="'+wcEsc(s.name)+'">' + wcEsc(s.name) + '</span>' +
6763
6764
  wcFileTypeBadge(s.type) +
6764
- (isEmpty ? '<span title="Vuoto" style="font-size:9px;color:#e09020;flex-shrink:0">&#9888;</span>' : '') +
6765
- '<button onclick="wcOpenSkill('+si+')" title="Modifica" style="background:none;border:none;color:var(--dim);cursor:pointer;font-size:12px;padding:2px 4px;flex-shrink:0">&#9998;</button>' +
6766
- (!isSingleton ? '<button onclick="wcClearSkill('+si+')" title="Svuota" style="background:none;border:none;color:var(--dim);cursor:pointer;font-size:11px;padding:2px 4px;flex-shrink:0">&#128465;</button>' : '') +
6765
+ (!isLog && isEmpty ? '<span title="Vuoto" style="font-size:9px;color:#e09020;flex-shrink:0">&#9888;</span>' : '') +
6766
+ '<button onclick="wcOpenSkill('+si+')" title="'+(isLog?'Visualizza log':'Modifica')+'" style="background:none;border:none;color:var(--dim);cursor:pointer;font-size:12px;padding:2px 4px;flex-shrink:0">'+(isLog?'&#128065;':'&#9998;')+'</button>' +
6767
+ (!isSingleton && !isLog ? '<button onclick="wcClearSkill('+si+')" title="Svuota" style="background:none;border:none;color:var(--dim);cursor:pointer;font-size:11px;padding:2px 4px;flex-shrink:0">&#128465;</button>' : '') +
6768
+ (isLog ? '<button onclick="wcDeleteSkill('+si+')" title="Elimina log" style="background:none;border:none;color:var(--dim);cursor:pointer;font-size:11px;padding:2px 4px;flex-shrink:0">&#128465;</button>' : '') +
6767
6769
  '</div>';
6768
6770
  }).join('');
6769
6771
  return '<div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px">' +