nothumanallowed 13.5.83 → 13.5.85

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.83",
3
+ "version": "13.5.85",
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": {
@@ -6527,7 +6527,8 @@ var wcState = {
6527
6527
  dir: null,
6528
6528
  logs: [],
6529
6529
  error: null
6530
- }
6530
+ },
6531
+ lastGenStats: null
6531
6532
  };
6532
6533
  var wcRightTab = 'files';
6533
6534
  var wcMainTab = 'new'; // 'new' | 'projects'
@@ -6569,9 +6570,11 @@ function renderWebCraft(el) {
6569
6570
  wcState.generatedFiles.map(function(f,i){
6570
6571
  var active = i === wcState.activeFile;
6571
6572
  var hasErr = !!f._error || !!f._syntaxError;
6572
- var tabColor = hasErr ? (active ? '#f87171' : '#7f4040') : (active ? 'var(--green)' : 'var(--dim)');
6573
+ var isPending = !!f._pending;
6574
+ var tabColor = hasErr ? (active ? '#f87171' : '#7f4040') : isPending ? (active ? '#9ca3af' : '#4b5563') : (active ? 'var(--green)' : 'var(--dim)');
6573
6575
  var tabBorder = hasErr ? (active ? '#f87171' : 'transparent') : (active ? 'var(--green3)' : 'transparent');
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>';
6576
+ var tabPrefix = hasErr ? '&#9888; ' : isPending ? '&#8987; ' : '';
6577
+ 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">'+tabPrefix+wcEsc(f.name)+'</button>';
6575
6578
  }).join('') +
6576
6579
  '</div>'
6577
6580
  : '';
@@ -6661,7 +6664,13 @@ function renderWebCraft(el) {
6661
6664
  '<button onclick="wcToggleGrep()" title="Cerca nel codice" style="padding:9px 10px;background:'+(_wcGrepOpen?'var(--greendim)':'var(--bg3)')+';border:1px solid '+(_wcGrepOpen?'var(--green3)':'var(--border2)')+';border-radius:8px;color:'+(_wcGrepOpen?'var(--green)':'var(--dim)')+';font-size:11px;cursor:pointer">&#128269;</button>' +
6662
6665
  '<button onclick="wcManualSnapshot()" title="Salva snapshot" style="padding:9px 10px;background:var(--bg3);border:1px solid var(--border2);border-radius:8px;color:var(--dim);font-size:11px;cursor:pointer">&#128190;</button>' +
6663
6666
  '</div>' +
6664
- '<button onclick="wcStartSandbox()" id="wcSandboxBtn" style="width:100%;padding:10px;background:var(--bg3);border:1px solid var(--green3);border-radius:8px;color:var(--green);font-size:12px;font-weight:600;cursor:pointer">&#9654; '+t('wc_sandbox_start')+'</button>'
6667
+ '<button onclick="wcStartSandbox()" id="wcSandboxBtn" style="width:100%;padding:10px;background:var(--bg3);border:1px solid var(--green3);border-radius:8px;color:var(--green);font-size:12px;font-weight:600;cursor:pointer">&#9654; '+t('wc_sandbox_start')+'</button>' +
6668
+ (wcState.lastGenStats ? '<div style="padding:6px 8px;background:var(--bg3);border:1px solid var(--border);border-radius:6px;font-size:10px;color:var(--dim);font-family:var(--mono);display:flex;flex-wrap:wrap;gap:6px">' +
6669
+ '<span>&#9201; '+(wcState.lastGenStats.seconds >= 60 ? Math.floor(wcState.lastGenStats.seconds/60)+'m '+(wcState.lastGenStats.seconds%60)+'s' : wcState.lastGenStats.seconds+'s')+'</span>' +
6670
+ '<span>&#8679; '+wcState.lastGenStats.tokIn.toLocaleString()+' tok in</span>' +
6671
+ '<span>&#8681; '+wcState.lastGenStats.tokOut.toLocaleString()+' tok out</span>' +
6672
+ '<span>&#128196; '+wcState.lastGenStats.files+' file</span>' +
6673
+ '</div>' : '')
6665
6674
  : '') +
6666
6675
  '</div>' +
6667
6676
  '<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">' +
@@ -7870,11 +7879,35 @@ async function wcGenerate() {
7870
7879
  var _nl = String.fromCharCode(10);
7871
7880
  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.';
7872
7881
 
7882
+ var _wcGenStartTime = Date.now();
7883
+ var _wcTokIn = 0, _wcTokOut = 0;
7884
+ var _wcTimerInterval = null;
7885
+
7886
+ function wcGenElapsed() {
7887
+ var s = Math.floor((Date.now() - _wcGenStartTime) / 1000);
7888
+ var m = Math.floor(s / 60); s = s % 60;
7889
+ return (m > 0 ? m + 'm ' : '') + s + 's';
7890
+ }
7891
+
7892
+ function wcStartGenTimer() {
7893
+ if (_wcTimerInterval) clearInterval(_wcTimerInterval);
7894
+ _wcTimerInterval = setInterval(function() {
7895
+ if (!wcState.running) { clearInterval(_wcTimerInterval); _wcTimerInterval = null; return; }
7896
+ wcUpdateGenOverlay(_wcGenOverlayState.fi, _wcGenOverlayState.total, _wcGenOverlayState.name);
7897
+ }, 1000);
7898
+ }
7899
+
7900
+ var _wcGenOverlayState = { fi: 0, total: 0, name: '' };
7901
+
7873
7902
  function wcUpdateGenOverlay(fi2, total, name) {
7874
- if (_wcOverlayMinimized) return; // don't touch minimized pill
7903
+ _wcGenOverlayState = { fi: fi2, total: total, name: name };
7904
+ if (_wcOverlayMinimized) return;
7875
7905
  var ov = document.getElementById('wcGenOverlay');
7876
7906
  if (!ov) return;
7877
7907
  var pct = Math.round((fi2 / total) * 100);
7908
+ var tokLabel = (_wcTokIn + _wcTokOut) > 0
7909
+ ? '<div style="font-size:10px;color:var(--dim);margin-top:4px;font-family:var(--mono)">&#8679;' + _wcTokIn.toLocaleString() + ' &#8681;' + _wcTokOut.toLocaleString() + ' tok</div>'
7910
+ : '';
7878
7911
  ov.innerHTML =
7879
7912
  '<div style="font-size:38px;animation:wcRobotBob 1s ease-in-out infinite">&#129302;</div>' +
7880
7913
  '<div style="font-size:13px;font-weight:700;color:var(--green);margin-top:12px">Generazione in corso...</div>' +
@@ -7883,11 +7916,12 @@ async function wcGenerate() {
7883
7916
  '<div style="width:220px;height:4px;background:rgba(255,255,255,0.1);border-radius:2px;overflow:hidden;margin-top:12px">' +
7884
7917
  '<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>' +
7885
7918
  '</div>' +
7886
- '<div style="font-size:10px;color:var(--dim);margin-top:6px">'+fi2+' / '+total+' file</div>' +
7919
+ '<div style="font-size:10px;color:var(--dim);margin-top:6px">'+fi2+' / '+total+' file &nbsp;&#183;&nbsp; '+wcGenElapsed()+'</div>' +
7920
+ tokLabel +
7887
7921
  '<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>';
7888
7922
  }
7889
7923
 
7890
- // Helper: generate one file, returns {ok, content} or {ok:false, err}
7924
+ // Helper: generate one file
7891
7925
  async function wcGenOneFile(fp, signal) {
7892
7926
  var _nl2 = String.fromCharCode(10);
7893
7927
  var content = await wcCallLLM(sysPreamble, fp.prompt + _nl2 + _nl2 + 'File to generate: ' + fp.name, signal, fp.lang);
@@ -7898,21 +7932,49 @@ async function wcGenerate() {
7898
7932
  return wcLines.join(_nl2).trim();
7899
7933
  }
7900
7934
 
7901
- for (var fi = 0; fi < filePlan.length; fi++) {
7902
- var fp = filePlan[fi];
7903
- wcUpdateGenOverlay(fi, filePlan.length, fp.name);
7935
+ wcStartGenTimer();
7936
+
7937
+ // Pre-populate generatedFiles in order so tabs appear immediately
7938
+ filePlan.forEach(function(fp) {
7939
+ wcState.generatedFiles.push({ name: fp.name, content: '', lang: fp.lang, _pending: true });
7940
+ });
7941
+ wcState.activeFile = 0;
7942
+ renderWebCraft(document.getElementById('content'));
7943
+
7944
+ // Generate in parallel batches of 4 — each call is independent/fresh to Liara
7945
+ var BATCH = 4;
7946
+ var doneCount = 0;
7947
+ for (var bi = 0; bi < filePlan.length; bi += BATCH) {
7904
7948
  if (_wcGenAbortCtrl && _wcGenAbortCtrl.signal.aborted) break;
7905
- try {
7906
- var content = await wcGenOneFile(fp, _wcGenAbortCtrl ? _wcGenAbortCtrl.signal : null);
7907
- wcState.generatedFiles.push({ name: fp.name, content: content, lang: fp.lang });
7908
- if (fi === 0) wcState.activeFile = 0;
7909
- renderWebCraft(document.getElementById('content'));
7910
- } catch(e) {
7911
- if (e && e.name === 'AbortError') break;
7912
- wcState.generatedFiles.push({ name: fp.name, content: '// Error generating this file: ' + (e.message || 'unknown error'), lang: fp.lang, _error: true });
7913
- if (fi === 0) wcState.activeFile = 0;
7914
- renderWebCraft(document.getElementById('content'));
7915
- }
7949
+ var batch = filePlan.slice(bi, bi + BATCH);
7950
+ wcUpdateGenOverlay(doneCount, filePlan.length, batch.map(function(f){ return f.name; }).join(', '));
7951
+ var results = await Promise.allSettled(batch.map(function(fp) {
7952
+ return wcGenOneFile(fp, _wcGenAbortCtrl ? _wcGenAbortCtrl.signal : null).then(function(c){ return { fp: fp, content: c }; });
7953
+ }));
7954
+ results.forEach(function(r) {
7955
+ if (r.status === 'fulfilled') {
7956
+ var fp = r.value.fp;
7957
+ for (var gi = 0; gi < wcState.generatedFiles.length; gi++) {
7958
+ if (wcState.generatedFiles[gi].name === fp.name) {
7959
+ wcState.generatedFiles[gi] = { name: fp.name, content: r.value.content, lang: fp.lang };
7960
+ break;
7961
+ }
7962
+ }
7963
+ } else if (r.reason && r.reason.name !== 'AbortError') {
7964
+ var fpName = batch[results.indexOf(r)] ? batch[results.indexOf(r)].name : '?';
7965
+ // find by matching position
7966
+ var batchIdx = results.indexOf(r);
7967
+ if (batch[batchIdx]) fpName = batch[batchIdx].name;
7968
+ for (var gi2 = 0; gi2 < wcState.generatedFiles.length; gi2++) {
7969
+ if (wcState.generatedFiles[gi2].name === fpName) {
7970
+ wcState.generatedFiles[gi2] = { name: fpName, content: '// Error generating this file: ' + (r.reason.message || 'unknown error'), lang: (batch[batchIdx] || {}).lang || '', _error: true };
7971
+ break;
7972
+ }
7973
+ }
7974
+ }
7975
+ doneCount++;
7976
+ });
7977
+ renderWebCraft(document.getElementById('content'));
7916
7978
  }
7917
7979
 
7918
7980
  // ── Retry pass: regenerate files that failed ──────────────────────────────
@@ -7998,9 +8060,14 @@ async function wcGenerate() {
7998
8060
  }
7999
8061
  }
8000
8062
 
8063
+ if (_wcTimerInterval) { clearInterval(_wcTimerInterval); _wcTimerInterval = null; }
8064
+ var _wcGenTotalTime = Math.floor((Date.now() - _wcGenStartTime) / 1000);
8065
+
8001
8066
  wcState.running = false;
8002
8067
  _wcGenAbortCtrl = null;
8003
8068
  _wcOverlayMinimized = false;
8069
+ // Store final stats for display after generation
8070
+ wcState.lastGenStats = { tokIn: _wcTokIn, tokOut: _wcTokOut, seconds: _wcGenTotalTime, files: wcState.generatedFiles.length };
8004
8071
 
8005
8072
  // Auto-save project to ~/.nha/webcraft/<projectName>/
8006
8073
  try {
@@ -8092,6 +8159,15 @@ async function wcCallLLMRaw(sys, user, signal) {
8092
8159
  var r = await fetch(API + '/api/studio/webcraft', fetchOpts);
8093
8160
  if (r.ok) {
8094
8161
  var d = await r.json();
8162
+ // Accumulate token counts if the server returns usage data
8163
+ if (d && d.usage) {
8164
+ if (typeof _wcTokIn !== 'undefined') _wcTokIn += (d.usage.prompt_tokens || d.usage.input_tokens || 0);
8165
+ if (typeof _wcTokOut !== 'undefined') _wcTokOut += (d.usage.completion_tokens || d.usage.output_tokens || 0);
8166
+ } else if (d && d.text) {
8167
+ // Estimate from char count (4 chars ≈ 1 token)
8168
+ if (typeof _wcTokIn !== 'undefined') _wcTokIn += Math.round((sys.length + user.length) / 4);
8169
+ if (typeof _wcTokOut !== 'undefined') _wcTokOut += Math.round((d.text || '').length / 4);
8170
+ }
8095
8171
  return (d && (d.text || d.content || d.result)) || '';
8096
8172
  }
8097
8173
  if (r.status < 500 || attempt === 2) {
@@ -8267,7 +8343,7 @@ async function wcStartSandbox() {
8267
8343
  headers: {'Content-Type':'application/json'},
8268
8344
  body: JSON.stringify({
8269
8345
  projectName: wcState.projectName || 'webcraft-sandbox',
8270
- files: wcState.generatedFiles.filter(function(f){ return !f._error; })
8346
+ files: wcState.generatedFiles.filter(function(f){ return !f._error && !f._pending; })
8271
8347
  })
8272
8348
  });
8273
8349
  if (!r.ok || !r.body) throw new Error('Sandbox error ' + r.status);