nothumanallowed 13.5.81 → 13.5.83

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.81",
3
+ "version": "13.5.83",
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": {
@@ -266,7 +266,7 @@ export async function callNHA(apiKey, model, systemPrompt, userMessage, stream =
266
266
 
267
267
  const body = {
268
268
  model: model || '/opt/models/qwen3-32b',
269
- max_tokens: thinkingEnabled ? 8192 : 4096,
269
+ max_tokens: thinkingEnabled ? 16384 : 8192,
270
270
  messages: [
271
271
  { role: 'system', content: sanitizeForSentinel(systemPrompt) },
272
272
  { role: 'user', content: sanitizeForSentinel(userMessage) },
@@ -6568,7 +6568,7 @@ function renderWebCraft(el) {
6568
6568
  ? '<div id="wcFileTabsRow" style="display:flex;gap:0;overflow-x:auto;border-bottom:1px solid var(--border);margin-bottom:0;flex-shrink:0;scrollbar-width:none">' +
6569
6569
  wcState.generatedFiles.map(function(f,i){
6570
6570
  var active = i === wcState.activeFile;
6571
- var hasErr = !!f._error;
6571
+ var hasErr = !!f._error || !!f._syntaxError;
6572
6572
  var tabColor = hasErr ? (active ? '#f87171' : '#7f4040') : (active ? 'var(--green)' : 'var(--dim)');
6573
6573
  var tabBorder = hasErr ? (active ? '#f87171' : 'transparent') : (active ? 'var(--green3)' : 'transparent');
6574
6574
  return '<button id="wcTab'+i+'" onclick="wcSetFile('+i+')" style="padding:6px 14px;font-size:11px;font-family:var(--mono);font-weight:'+(active?'700':'400')+';background:'+(active?'var(--bg3)':'transparent')+';border:none;border-bottom:2px solid '+tabBorder+';color:'+tabColor+';cursor:pointer;white-space:nowrap;flex-shrink:0">'+(hasErr?'&#9888; ':'')+wcEsc(f.name)+'</button>';
@@ -6579,8 +6579,8 @@ function renderWebCraft(el) {
6579
6579
  var _activeFile = wcState.generatedFiles[wcState.activeFile];
6580
6580
  var codeHtml = wcState.generatedFiles.length > 0 && _activeFile
6581
6581
  ? '<div id="wcCodeWrap" style="flex:1;overflow:auto;background:var(--bg3);border-radius:0 0 8px 8px">' +
6582
- (_activeFile._error ? '<div style="padding:8px 14px;background:rgba(239,68,68,0.12);border-bottom:1px solid rgba(239,68,68,0.3);font-size:11px;color:#f87171;display:flex;align-items:center;gap:6px">&#9888; Generazione fallita — chiedi al modello di rigenerare questo file</div>' : '') +
6583
- '<pre style="margin:0;padding:14px 16px;font-size:11px;line-height:1.6;color:'+(_activeFile._error?'#f87171':'var(--text)')+';font-family:var(--mono);white-space:pre-wrap;word-break:break-all">'+wcEsc(_activeFile.content)+'</pre>' +
6582
+ (_activeFile._error ? '<div style="padding:8px 14px;background:rgba(239,68,68,0.12);border-bottom:1px solid rgba(239,68,68,0.3);font-size:11px;color:#f87171;display:flex;align-items:center;gap:6px">&#9888; Generazione fallita — chiedi al modello di rigenerare questo file</div>' : (_activeFile._syntaxError ? '<div style="padding:8px 14px;background:rgba(234,179,8,0.1);border-bottom:1px solid rgba(234,179,8,0.3);font-size:11px;color:#facc15;display:flex;align-items:center;gap:6px">&#9888; Syntax error: '+wcEsc(_activeFile._syntaxError)+'</div>' : '')) +
6583
+ '<pre style="margin:0;padding:14px 16px;font-size:11px;line-height:1.6;color:'+(_activeFile._error?'#f87171':_activeFile._syntaxError?'#fde68a':'var(--text)')+';font-family:var(--mono);white-space:pre-wrap;word-break:break-all">'+wcEsc(_activeFile.content)+'</pre>' +
6584
6584
  '</div>'
6585
6585
  : '<div style="flex:1;display:flex;align-items:center;justify-content:center;color:var(--dim);font-size:12px;flex-direction:column;gap:8px">' +
6586
6586
  '<span style="font-size:36px;opacity:.25">&#128736;</span>' +
@@ -7942,6 +7942,62 @@ async function wcGenerate() {
7942
7942
  }
7943
7943
  }
7944
7944
 
7945
+ // ── Post-generation syntax scan ──────────────────────────────────────────
7946
+ // Zero LLM calls — pure structural check on every generated file
7947
+ // Files with syntax errors get _syntaxError set and are re-queued for retry
7948
+ var syntaxFailedNames = [];
7949
+ wcState.generatedFiles.forEach(function(f) {
7950
+ if (f._error) return; // already failed at LLM level
7951
+ var lang = f.lang || (f.name.endsWith('.css') ? 'css' : f.name.endsWith('.js') ? 'javascript' : f.name.endsWith('.html') ? 'html' : f.name.endsWith('.json') ? 'json' : 'text');
7952
+ var check = wcSyntaxCheck(f.content, lang);
7953
+ if (!check.ok) {
7954
+ f._syntaxError = check.reason;
7955
+ syntaxFailedNames.push(f.name);
7956
+ } else {
7957
+ delete f._syntaxError;
7958
+ }
7959
+ });
7960
+
7961
+ // Re-fix syntax-broken files — continue/patch, do NOT regenerate from scratch
7962
+ if (syntaxFailedNames.length > 0 && !(_wcGenAbortCtrl && _wcGenAbortCtrl.signal.aborted)) {
7963
+ var syntaxRetryPlan = filePlan.filter(function(fp2){ return syntaxFailedNames.indexOf(fp2.name) !== -1; });
7964
+ for (var si2 = 0; si2 < syntaxRetryPlan.length; si2++) {
7965
+ var sfp = syntaxRetryPlan[si2];
7966
+ var brokenFile = wcState.generatedFiles.filter(function(f){ return f.name === sfp.name; })[0];
7967
+ if (!brokenFile) continue;
7968
+ wcUpdateGenOverlay(si2, syntaxRetryPlan.length, 'Fix: ' + sfp.name);
7969
+ if (_wcGenAbortCtrl && _wcGenAbortCtrl.signal.aborted) break;
7970
+ await new Promise(function(resolve){ setTimeout(resolve, 1500); });
7971
+ try {
7972
+ var _nl3 = String.fromCharCode(10);
7973
+ // Build a targeted fix prompt — pass the broken file and ask only for the fix/completion
7974
+ var fixSys = sysPreamble + _nl3 + 'You are fixing a truncated or broken file. Output ONLY the corrected complete file content. No explanations, no markdown fences.';
7975
+ var fixUser = 'File: ' + sfp.name + _nl3 +
7976
+ 'Syntax error: ' + (brokenFile._syntaxError || 'truncated') + _nl3 + _nl3 +
7977
+ 'Current (broken) content:' + _nl3 + brokenFile.content + _nl3 + _nl3 +
7978
+ 'Output the complete corrected file. If it was truncated, continue from where it stopped and output the FULL file from the beginning.';
7979
+ var fixedContent = await wcCallLLM(fixSys, fixUser, _wcGenAbortCtrl ? _wcGenAbortCtrl.signal : null, sfp.lang);
7980
+ // Strip fences if model added them
7981
+ var _fence2 = String.fromCharCode(96,96,96);
7982
+ var fixLines = fixedContent.split(_nl3);
7983
+ if (fixLines.length > 0 && fixLines[0].indexOf(_fence2) === 0) fixLines.shift();
7984
+ if (fixLines.length > 0 && fixLines[fixLines.length-1].trim() === _fence2) fixLines.pop();
7985
+ fixedContent = fixLines.join(_nl3).trim();
7986
+ var fixCheck = wcSyntaxCheck(fixedContent, sfp.lang);
7987
+ for (var gi2 = 0; gi2 < wcState.generatedFiles.length; gi2++) {
7988
+ if (wcState.generatedFiles[gi2].name === sfp.name) {
7989
+ wcState.generatedFiles[gi2] = { name: sfp.name, content: fixedContent, lang: sfp.lang };
7990
+ if (!fixCheck.ok) wcState.generatedFiles[gi2]._syntaxError = fixCheck.reason;
7991
+ break;
7992
+ }
7993
+ }
7994
+ renderWebCraft(document.getElementById('content'));
7995
+ } catch(se) {
7996
+ if (se && se.name === 'AbortError') break;
7997
+ }
7998
+ }
7999
+ }
8000
+
7945
8001
  wcState.running = false;
7946
8002
  _wcGenAbortCtrl = null;
7947
8003
  _wcOverlayMinimized = false;
@@ -7958,27 +8014,68 @@ async function wcGenerate() {
7958
8014
  renderWebCraft(document.getElementById('content'));
7959
8015
  }
7960
8016
 
7961
- // Returns true if content looks truncated (unbalanced braces or ends mid-rule)
7962
- function wcIsTruncated(content, lang) {
7963
- if (!content || content.length < 100) return false;
8017
+ // Quick structural check returns {ok, reason} without calling the LLM
8018
+ // Reads only structure (braces, tags) — does NOT add content to any context
8019
+ function wcSyntaxCheck(content, lang) {
8020
+ if (!content || content.length < 20) return { ok: false, reason: 'empty' };
7964
8021
  var trimmed = content.trimEnd();
7965
- // CSS/SCSS: count { vs } — if open > closed, truncated
8022
+
7966
8023
  if (lang === 'css' || lang === 'scss') {
8024
+ // Strip comments and strings to avoid false brace counts
8025
+ var stripped = trimmed
8026
+ .replace(new RegExp('/[*][\\s\\S]*?[*]/', 'g'), '')
8027
+ .replace(new RegExp('"[^"]*"', 'g'), '""')
8028
+ .replace(new RegExp("['][^']*[']", 'g'), "''");
7967
8029
  var open = 0, close = 0;
7968
- for (var ci = 0; ci < trimmed.length; ci++) {
7969
- if (trimmed[ci] === '{') open++;
7970
- else if (trimmed[ci] === '}') close++;
8030
+ for (var i = 0; i < stripped.length; i++) {
8031
+ if (stripped[i] === '{') open++;
8032
+ else if (stripped[i] === '}') close++;
7971
8033
  }
7972
- return open > close;
8034
+ if (open !== close) return { ok: false, reason: 'unbalanced braces (' + open + ' open, ' + close + ' close)' };
8035
+ if (open === 0) return { ok: false, reason: 'no CSS rules found' };
8036
+ return { ok: true };
7973
8037
  }
7974
- // JS: ends without closing brace/semicolon — rough heuristic
8038
+
7975
8039
  if (lang === 'javascript') {
7976
- var last = trimmed[trimmed.length - 1];
7977
- return last !== '}' && last !== ';' && last !== ')';
8040
+ // Use Function constructor as a zero-overhead parse check (no eval, just syntax)
8041
+ try { new Function(content); return { ok: true }; }
8042
+ catch(e) { return { ok: false, reason: e.message.split(String.fromCharCode(10))[0] }; }
7978
8043
  }
7979
- // HTML: doesn't end with closing tag
8044
+
7980
8045
  if (lang === 'html') {
7981
- return trimmed.slice(-7).indexOf('</html>') === -1 && trimmed.slice(-8).indexOf('</body>') === -1;
8046
+ var lower = trimmed.toLowerCase();
8047
+ if (lower.indexOf('</html>') === -1 && lower.indexOf('</body>') === -1)
8048
+ return { ok: false, reason: 'missing </html> or </body>' };
8049
+ // DOMParser check for well-formedness
8050
+ try {
8051
+ var doc = new DOMParser().parseFromString(trimmed, 'text/html');
8052
+ var pe = doc.querySelector('parseerror');
8053
+ if (pe) return { ok: false, reason: pe.textContent.slice(0, 80) };
8054
+ } catch(_) {}
8055
+ return { ok: true };
8056
+ }
8057
+
8058
+ if (lang === 'json') {
8059
+ try { JSON.parse(trimmed); return { ok: true }; }
8060
+ catch(e) { return { ok: false, reason: e.message }; }
8061
+ }
8062
+
8063
+ // For markdown, nginx.conf, sql, bash — just check not truncated mid-line
8064
+ var last = trimmed[trimmed.length - 1];
8065
+ if (last === undefined) return { ok: false, reason: 'empty' };
8066
+ return { ok: true };
8067
+ }
8068
+
8069
+ // Returns true if content looks truncated (unbalanced braces or ends mid-rule)
8070
+ function wcIsTruncated(content, lang) {
8071
+ if (!content || content.length < 100) return false;
8072
+ var check = wcSyntaxCheck(content, lang);
8073
+ if (!check.ok) return true;
8074
+ // Also check raw ending for langs not fully covered above
8075
+ var trimmed = content.trimEnd();
8076
+ if (lang === 'javascript') {
8077
+ var last = trimmed[trimmed.length - 1];
8078
+ return last !== '}' && last !== ';' && last !== ')';
7982
8079
  }
7983
8080
  return false;
7984
8081
  }
@@ -7987,7 +8084,7 @@ async function wcCallLLMRaw(sys, user, signal) {
7987
8084
  var fetchOpts = {
7988
8085
  method: 'POST',
7989
8086
  headers: {'Content-Type':'application/json'},
7990
- body: JSON.stringify({system: sys, user: user, max_tokens: 4096})
8087
+ body: JSON.stringify({system: sys, user: user, max_tokens: 8192})
7991
8088
  };
7992
8089
  if (signal) fetchOpts.signal = signal;
7993
8090
  for (var attempt = 0; attempt < 3; attempt++) {