nothumanallowed 13.5.65 → 13.5.67

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.65",
3
+ "version": "13.5.67",
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": {
@@ -4313,6 +4313,13 @@ module.exports = { get, set, del, exists };
4313
4313
  [/require\(['"]\.\.\/\.\.\/config['"]\)/g, "{env:process.env}"],
4314
4314
  [/require\(['"]\.\.\/config['"]\)/g, "{env:process.env}"],
4315
4315
  [/require\(['"]\.\/config['"]\)/g, "{env:process.env}"],
4316
+ // rateLimiter: LLM sometimes creates a separate file instead of importing from security.js
4317
+ [/require\(['"]\.\.\/middleware\/rateLimiter['"]\)/g, "require('../middleware/security')"],
4318
+ [/require\(['"]\.\/middleware\/rateLimiter['"]\)/g, "require('./middleware/security')"],
4319
+ [/require\(['"]\.\.\/middleware\/rateLimit['"]\)/g, "require('../middleware/security')"],
4320
+ [/require\(['"]\.\/middleware\/rateLimit['"]\)/g, "require('./middleware/security')"],
4321
+ [/require\(['"]\.\.\/middleware\/limiter['"]\)/g, "require('../middleware/security')"],
4322
+ [/require\(['"]\.\/middleware\/limiter['"]\)/g, "require('./middleware/security')"],
4316
4323
  ];
4317
4324
  function patchJsFiles(dir) {
4318
4325
  if (!fs.existsSync(dir)) return;
@@ -6544,6 +6544,9 @@ var _wcDiffQueue = []; // [{file, before, after}] diffs from last agent ru
6544
6544
  var _wcGrepOpen = false; // grep panel visible
6545
6545
  var _wcGrepQuery = '';
6546
6546
  var _wcGrepResults = [];
6547
+ var _wcOverlayMinimized = false; // overlay minimized by user click
6548
+ var _wcOverlayTimer = null; // inactivity timer to restore overlay
6549
+ var _wcGenAbortCtrl = null; // AbortController for generation stop
6547
6550
  var _wcSyntaxResults = []; // [{file, ok, error}]
6548
6551
  var _wcSnapshots = []; // [{ts, fileCount}]
6549
6552
  // Skills state
@@ -6657,7 +6660,22 @@ function renderWebCraft(el) {
6657
6660
  : '') +
6658
6661
  '</div>' +
6659
6662
  '<div data-wc-files style="position:relative;flex:1;min-width:0;background:var(--bg2);border:1px solid var(--border);border-radius:10px;display:flex;flex-direction:column;height:100%;overflow:hidden">' +
6660
- (wcState.running ? '<div id="wcGenOverlay" style="position:absolute;inset:0;background:rgba(0,0,0,0.75);backdrop-filter:blur(4px);border-radius:10px;z-index:50;display:flex;flex-direction:column;align-items:center;justify-content:center;animation:wcBubbleIn .3s ease"><div style="font-size:38px;animation:wcRobotBob 1s ease-in-out infinite">&#129302;</div><div style="font-size:13px;font-weight:700;color:var(--green);margin-top:12px">Avvio generazione...</div><div style="display:flex;gap:4px;margin-top:16px">'+[0,1,2,3,4].map(function(_,idx){ return '<div style="width:6px;height:6px;border-radius:50%;background:var(--green);animation:wcDot 1.1s ease-in-out infinite '+(idx*0.14)+'s"></div>'; }).join('')+'</div></div>' : '') +
6663
+ (wcState.running ? (
6664
+ _wcOverlayMinimized
6665
+ // Minimized: small pill in bottom-right corner
6666
+ ? '<div id="wcGenOverlay" onclick="wcOverlayRestore()" style="position:absolute;bottom:12px;right:12px;z-index:50;background:rgba(0,0,0,0.85);border:1px solid var(--green3);border-radius:20px;padding:5px 12px;display:flex;align-items:center;gap:7px;cursor:pointer;animation:wcBubbleIn .2s ease;backdrop-filter:blur(4px)">'
6667
+ +'<span style="font-size:16px;animation:wcRobotBob .9s ease-in-out infinite">&#129302;</span>'
6668
+ +'<span style="font-size:10px;color:var(--green);font-weight:700">Generando...</span>'
6669
+ +'<span style="display:flex;gap:3px">'+[0,1,2].map(function(_,idx){ return '<span style="width:4px;height:4px;border-radius:50%;background:var(--green);animation:wcDot 1.1s ease-in-out infinite '+(idx*0.18)+'s"></span>'; }).join('')+'</span>'
6670
+ +'</div>'
6671
+ // Full overlay
6672
+ : '<div id="wcGenOverlay" onclick="wcOverlayMinimize()" title="Clicca per nascondere e navigare i file" style="position:absolute;inset:0;background:rgba(0,0,0,0.75);backdrop-filter:blur(4px);border-radius:10px;z-index:50;display:flex;flex-direction:column;align-items:center;justify-content:center;animation:wcBubbleIn .3s ease;cursor:pointer">'
6673
+ +'<div style="font-size:38px;animation:wcRobotBob 1s ease-in-out infinite">&#129302;</div>'
6674
+ +'<div style="font-size:13px;font-weight:700;color:var(--green);margin-top:12px">Generazione in corso...</div>'
6675
+ +'<div style="font-size:10px;color:var(--dim);margin-top:4px">Clicca per navigare i file</div>'
6676
+ +'<div style="display:flex;gap:4px;margin-top:16px">'+[0,1,2,3,4].map(function(_,idx){ return '<div style="width:6px;height:6px;border-radius:50%;background:var(--green);animation:wcDot 1.1s ease-in-out infinite '+(idx*0.14)+'s"></div>'; }).join('')+'</div>'
6677
+ +'</div>'
6678
+ ) : '') +
6661
6679
  '<div style="display:flex;border-bottom:1px solid var(--border);flex-shrink:0">' +
6662
6680
  '<button onclick="wcTabFiles()" style="padding:8px 16px;background:'+(wcRightTab==='preview'?'transparent':'var(--bg3)')+';border:none;border-right:1px solid var(--border);color:'+(wcRightTab==='preview'?'var(--dim)':'var(--text)')+';font-size:11px;font-weight:600;cursor:pointer">&#128196; File</button>' +
6663
6681
  '<button onclick="wcTabPreview()" style="padding:8px 16px;background:'+(wcRightTab==='preview'?'var(--bg3)':'transparent')+';border:none;color:'+(wcRightTab==='preview'?'var(--text)':'var(--dim)')+';font-size:11px;font-weight:600;cursor:pointer">&#127760; Sandbox</button>' +
@@ -7087,7 +7105,10 @@ function wcChatPanelHtml() {
7087
7105
  '<input type="file" id="wcFileInput" multiple accept="image/*,.pdf" style="display:none" onchange="wcHandleFileAttach(this)">' +
7088
7106
  '</label>' +
7089
7107
  '<textarea id="wcChatInput" rows="4" placeholder="'+placeholder+'" '+(inputDisabled?'disabled':'')+' style="flex:1;padding:8px 10px;font-size:12px;border-radius:8px;border:1px solid var(--border2);background:var(--bg3);color:var(--text);resize:vertical;min-height:80px;line-height:1.5;font-family:inherit" onkeydown="wcChatKeydown(event)"></textarea>' +
7090
- '<button onclick="wcChatSend()" '+(inputDisabled?'disabled':'')+' style="padding:8px 14px;background:var(--green3);border:none;border-radius:8px;color:var(--bg);font-size:13px;font-weight:700;cursor:pointer;flex-shrink:0;height:38px">'+sendBtnLabel+'</button>' +
7108
+ '<div style="display:flex;flex-direction:column;gap:5px;flex-shrink:0">' +
7109
+ '<button onclick="wcChatSend()" '+(inputDisabled?'disabled':'')+' style="padding:8px 14px;background:var(--green3);border:none;border-radius:8px;color:var(--bg);font-size:13px;font-weight:700;cursor:pointer;height:38px;white-space:nowrap">'+sendBtnLabel+'</button>' +
7110
+ (inputDisabled ? '<button onclick="wcStopAll()" style="padding:5px 10px;background:rgba(239,68,68,0.12);border:1px solid rgba(239,68,68,0.4);border-radius:7px;color:#f87171;font-size:11px;font-weight:700;cursor:pointer;white-space:nowrap">&#9632; Stop</button>' : '') +
7111
+ '</div>' +
7091
7112
  '</div>' +
7092
7113
  '</div>';
7093
7114
  }
@@ -7096,6 +7117,17 @@ function wcChatKeydown(e) {
7096
7117
  if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); wcChatSend(); }
7097
7118
  }
7098
7119
 
7120
+ function wcStopAll() {
7121
+ // Abort ongoing generation
7122
+ if (_wcGenAbortCtrl) { _wcGenAbortCtrl.abort(); _wcGenAbortCtrl = null; }
7123
+ wcState.running = false;
7124
+ wcChatRunning = false;
7125
+ _wcOverlayMinimized = false;
7126
+ if (_wcOverlayTimer) { clearTimeout(_wcOverlayTimer); _wcOverlayTimer = null; }
7127
+ wcChat.push({ role: 'system', text: '&#9632; Generazione interrotta.' });
7128
+ renderWebCraft(document.getElementById('content'));
7129
+ }
7130
+
7099
7131
  function wcRemoveAttachment(ai) {
7100
7132
  wcChatAttachments.splice(ai, 1);
7101
7133
  renderWebCraft(document.getElementById('content'));
@@ -7671,6 +7703,8 @@ async function wcGenerate() {
7671
7703
  wcState.running = true;
7672
7704
  wcState.generatedFiles = [];
7673
7705
  wcState.activeFile = 0;
7706
+ _wcOverlayMinimized = false;
7707
+ _wcGenAbortCtrl = new AbortController();
7674
7708
  renderWebCraft(document.getElementById('content'));
7675
7709
 
7676
7710
  // Security rules always injected
@@ -7698,7 +7732,7 @@ async function wcGenerate() {
7698
7732
  { 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 }.' },
7699
7733
  { 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).' },
7700
7734
  { 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.' },
7701
- { 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.' },
7735
+ { 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. Import authLimiter EXACTLY like this: const { authLimiter } = require("../middleware/security"); — do NOT create or import from ../middleware/rateLimiter (that file does not exist). Apply authLimiter to register and login.' },
7702
7736
  { name: 'server/routes/api.js', lang: 'javascript', prompt: 'Generate server/routes/api.js: Express router with a verifyToken middleware (validates JWT Bearer). GET /api/me returns authenticated user profile (no password hash). GET /api/health returns {status: ok, timestamp}. Structure ready for adding more routes.' },
7703
7737
  { name: 'server/index.js', lang: 'javascript', prompt: 'Generate server/index.js: Express app entry point. Apply applySecurityMiddleware first. Then apply sentinelMiddleware (import from ./middleware/sentinel.js). Use CORS with env CORS_ORIGIN. Parse JSON body (limit 10kb). Mount /api/auth → auth.js, /api → api.js. Serve public/ as static. 404 handler and global error handler (never leak stack traces in production). Start on PORT from env.' },
7704
7738
  { name: 'db/migrations/001_init.sql', lang: 'sql', prompt: 'Generate PostgreSQL migration 001_init.sql: CREATE TABLE users with id UUID default gen_random_uuid(), fields for '+authFieldsDef+', email_verified BOOLEAN default false, verification_token VARCHAR, reset_token VARCHAR, reset_token_expires TIMESTAMPTZ, refresh_token_hash VARCHAR, created_at TIMESTAMPTZ default now(), updated_at TIMESTAMPTZ default now(). CREATE INDEX on email. CREATE TABLE refresh_tokens (id, user_id FK, token_hash, expires_at, created_at). Add updated_at trigger function.' },
@@ -7731,30 +7765,46 @@ async function wcGenerate() {
7731
7765
  var sysPreamble = 'You are an expert full-stack engineer generating production-quality code.' + _nl + _nl + 'SECURITY RULES (non-negotiable):' + _nl + SECURITY_RULES + _nl + _nl + 'Project: ' + projName + _nl + 'Description: ' + desc + _nl + 'Enabled blocks: ' + blocksEnabled + _nl + _nl + 'Generate ONLY the file content requested. No explanations, no markdown code fences, no comments like "here is the file". Output raw file content only.';
7732
7766
 
7733
7767
  function wcUpdateGenOverlay(fi2, total, name) {
7768
+ if (_wcOverlayMinimized) return; // don't touch minimized pill
7734
7769
  var ov = document.getElementById('wcGenOverlay');
7735
7770
  if (!ov) return;
7736
7771
  var pct = Math.round((fi2 / total) * 100);
7737
7772
  ov.innerHTML =
7738
- '<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:16px;padding:24px">' +
7739
- '<div style="font-size:38px;animation:wcRobotBob 1s ease-in-out infinite">&#129302;</div>' +
7740
- '<div style="font-size:13px;font-weight:700;color:var(--green)">Generazione in corso...</div>' +
7741
- '<div style="font-size:11px;color:var(--dim);font-family:var(--mono);max-width:300px;text-align:center;word-break:break-all">'+wcEsc(name)+'</div>' +
7742
- '<div style="width:220px;height:4px;background:var(--bg3);border-radius:2px;overflow:hidden">' +
7743
- '<div style="height:100%;width:'+pct+'%;background:var(--green);border-radius:2px;transition:width .4s ease;animation:wcBarPulse 1.5s ease-in-out infinite"></div>' +
7744
- '</div>' +
7745
- '<div style="font-size:10px;color:var(--dim)">'+fi2+' / '+total+' file</div>' +
7746
- '<div style="display:flex;gap:4px;margin-top:4px">' +
7747
- [0,1,2,3,4].map(function(_,idx){ return '<div style="width:6px;height:6px;border-radius:50%;background:var(--green);animation:wcDot 1.1s ease-in-out infinite '+(idx*0.14)+'s"></div>'; }).join('') +
7748
- '</div>' +
7749
- '</div>';
7773
+ '<div style="font-size:38px;animation:wcRobotBob 1s ease-in-out infinite">&#129302;</div>' +
7774
+ '<div style="font-size:13px;font-weight:700;color:var(--green);margin-top:12px">Generazione in corso...</div>' +
7775
+ '<div style="font-size:10px;color:var(--dim);margin-top:2px">Clicca per navigare i file</div>' +
7776
+ '<div style="font-size:11px;color:var(--dim);font-family:var(--mono);max-width:300px;text-align:center;word-break:break-all;margin-top:8px">'+wcEsc(name)+'</div>' +
7777
+ '<div style="width:220px;height:4px;background:rgba(255,255,255,0.1);border-radius:2px;overflow:hidden;margin-top:12px">' +
7778
+ '<div style="height:100%;width:'+pct+'%;background:var(--green);border-radius:2px;transition:width .4s ease;animation:wcBarPulse 1.5s ease-in-out infinite"></div>' +
7779
+ '</div>' +
7780
+ '<div style="font-size:10px;color:var(--dim);margin-top:6px">'+fi2+' / '+total+' file</div>' +
7781
+ '<div style="display:flex;gap:4px;margin-top:10px">'+[0,1,2,3,4].map(function(_,idx){ return '<div style="width:6px;height:6px;border-radius:50%;background:var(--green);animation:wcDot 1.1s ease-in-out infinite '+(idx*0.14)+'s"></div>'; }).join('')+'</div>';
7782
+ }
7783
+
7784
+ function wcOverlayMinimize() {
7785
+ _wcOverlayMinimized = true;
7786
+ renderWebCraft(document.getElementById('content'));
7787
+ // Restore after 10s of inactivity
7788
+ if (_wcOverlayTimer) clearTimeout(_wcOverlayTimer);
7789
+ _wcOverlayTimer = setTimeout(function() {
7790
+ if (wcState.running) { _wcOverlayMinimized = false; renderWebCraft(document.getElementById('content')); }
7791
+ }, 10000);
7792
+ }
7793
+
7794
+ function wcOverlayRestore() {
7795
+ if (_wcOverlayTimer) { clearTimeout(_wcOverlayTimer); _wcOverlayTimer = null; }
7796
+ _wcOverlayMinimized = false;
7797
+ renderWebCraft(document.getElementById('content'));
7750
7798
  }
7751
7799
 
7752
7800
  for (var fi = 0; fi < filePlan.length; fi++) {
7753
7801
  var fp = filePlan[fi];
7754
7802
  wcUpdateGenOverlay(fi, filePlan.length, fp.name);
7803
+ // Check if aborted
7804
+ if (_wcGenAbortCtrl && _wcGenAbortCtrl.signal.aborted) break;
7755
7805
  try {
7756
7806
  var _nl2 = String.fromCharCode(10);
7757
- var content = await wcCallLLM(sysPreamble, fp.prompt + _nl2 + _nl2 + 'File to generate: ' + fp.name);
7807
+ var content = await wcCallLLM(sysPreamble, fp.prompt + _nl2 + _nl2 + 'File to generate: ' + fp.name, _wcGenAbortCtrl ? _wcGenAbortCtrl.signal : null);
7758
7808
  // Strip markdown code fences if model added them anyway
7759
7809
  var _fence = String.fromCharCode(96,96,96);
7760
7810
  var wcLines = content.split(_nl2);
@@ -7765,11 +7815,14 @@ async function wcGenerate() {
7765
7815
  if (fi === 0) wcState.activeFile = 0;
7766
7816
  renderWebCraft(document.getElementById('content'));
7767
7817
  } catch(e) {
7818
+ if (e && e.name === 'AbortError') break;
7768
7819
  wcState.generatedFiles.push({ name: fp.name, content: '// Error generating this file: ' + e.message, lang: fp.lang });
7769
7820
  }
7770
7821
  }
7771
7822
 
7772
7823
  wcState.running = false;
7824
+ _wcGenAbortCtrl = null;
7825
+ _wcOverlayMinimized = false;
7773
7826
 
7774
7827
  // Auto-save project to ~/.nha/webcraft/<projectName>/
7775
7828
  try {
@@ -7783,12 +7836,14 @@ async function wcGenerate() {
7783
7836
  renderWebCraft(document.getElementById('content'));
7784
7837
  }
7785
7838
 
7786
- async function wcCallLLM(sys, user) {
7787
- var r = await fetch(API + '/api/studio/webcraft', {
7839
+ async function wcCallLLM(sys, user, signal) {
7840
+ var fetchOpts = {
7788
7841
  method: 'POST',
7789
7842
  headers: {'Content-Type':'application/json'},
7790
7843
  body: JSON.stringify({system: sys, user: user, max_tokens: 4096})
7791
- });
7844
+ };
7845
+ if (signal) fetchOpts.signal = signal;
7846
+ var r = await fetch(API + '/api/studio/webcraft', fetchOpts);
7792
7847
  if (!r.ok) throw new Error('LLM error ' + r.status);
7793
7848
  var d = await r.json();
7794
7849
  return (d && (d.text || d.content || d.result)) || '';