nothumanallowed 13.5.147 → 13.5.149

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.147",
3
+ "version": "13.5.149",
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": {
@@ -5869,39 +5869,61 @@ REGOLE CRITICHE:
5869
5869
  // Parse and execute tool calls from response
5870
5870
  // Sanitize JSON from LLM: replace literal newlines and invalid escape sequences inside JSON strings
5871
5871
  // Models often write multiline strings without escaping, or use \s \d \w in regex inside content
5872
- const sanitizeToolJson = (raw) => {
5873
- // Valid JSON escape chars after backslash: " \ / b f n r t u
5874
- const validEscapes = new Set(['"', '\\', '/', 'b', 'f', 'n', 'r', 't', 'u']);
5872
+ // Robust JSON string extractor: reads a JSON string value starting at position i (after the opening ")
5873
+ // Returns { value, end } where end is the index after the closing "
5874
+ const extractJsonString = (s, i) => {
5875
5875
  let out = '';
5876
- let inStr = false;
5877
- let escaped = false;
5878
- for (let ci = 0; ci < raw.length; ci++) {
5879
- const ch = raw[ci];
5880
- if (escaped) {
5881
- escaped = false;
5882
- // If this is not a valid JSON escape char, double the backslash
5883
- if (!validEscapes.has(ch)) {
5884
- out += '\\\\' + ch;
5885
- } else {
5886
- out += ch;
5887
- }
5888
- continue;
5889
- }
5876
+ const validEscapes = new Set(['"', '\\', '/', 'b', 'f', 'n', 'r', 't', 'u']);
5877
+ while (i < s.length) {
5878
+ const ch = s[i];
5890
5879
  if (ch === '\\') {
5891
- if (inStr) {
5892
- escaped = true;
5893
- out += ch;
5880
+ const next = s[i + 1];
5881
+ if (next === undefined) { out += '\\\\'; i++; break; }
5882
+ if (validEscapes.has(next)) {
5883
+ // valid escape — keep as-is, but handle \u specially
5884
+ if (next === 'u') {
5885
+ const hex = s.slice(i + 2, i + 6);
5886
+ if (/^[0-9a-fA-F]{4}$/.test(hex)) {
5887
+ out += s.slice(i, i + 6); i += 6;
5888
+ } else {
5889
+ out += '\\\\u'; i += 2;
5890
+ }
5891
+ } else {
5892
+ out += s.slice(i, i + 2); i += 2;
5893
+ }
5894
5894
  } else {
5895
- out += ch;
5895
+ // invalid escape (e.g. \s \d \w \( \. \n written as literal) — escape the backslash
5896
+ out += '\\\\' + next; i += 2;
5896
5897
  }
5897
5898
  continue;
5898
5899
  }
5899
- if (ch === '"') { inStr = !inStr; out += ch; continue; }
5900
- if (inStr && (ch === '\n' || ch === '\r')) {
5901
- out += ch === '\n' ? '\\n' : '\\r';
5902
- continue;
5900
+ if (ch === '"') { i++; break; } // closing quote
5901
+ if (ch === '\n') { out += '\\n'; i++; continue; }
5902
+ if (ch === '\r') { out += '\\r'; i++; continue; }
5903
+ if (ch === '\t') { out += '\\t'; i++; continue; }
5904
+ // other control chars
5905
+ if (ch.charCodeAt(0) < 0x20) { out += '\\u' + ch.charCodeAt(0).toString(16).padStart(4, '0'); i++; continue; }
5906
+ out += ch; i++;
5907
+ }
5908
+ return { value: out, end: i };
5909
+ };
5910
+
5911
+ const sanitizeToolJson = (raw) => {
5912
+ // Rebuild the JSON char-by-char, using extractJsonString for string values
5913
+ let out = '';
5914
+ let i = 0;
5915
+ let inStr = false;
5916
+ while (i < raw.length) {
5917
+ if (!inStr && raw[i] === '"') {
5918
+ // Start of a JSON string — extract it robustly
5919
+ out += '"';
5920
+ i++;
5921
+ const { value, end } = extractJsonString(raw, i);
5922
+ out += value + '"';
5923
+ i = end;
5924
+ } else {
5925
+ out += raw[i++];
5903
5926
  }
5904
- out += ch;
5905
5927
  }
5906
5928
  return out;
5907
5929
  };
@@ -5982,9 +6004,11 @@ Rispondi SOLO con il contenuto completo del file corretto, senza markdown fence,
5982
6004
  } else if (toolCall.op === 'write') {
5983
6005
  const fp = path.join(sandboxDir, toolCall.path.replace(/^\/+/, ''));
5984
6006
  fs.mkdirSync(path.dirname(fp), { recursive: true });
6007
+ const oldContent = fs.existsSync(fp) ? fs.readFileSync(fp, 'utf8') : '';
5985
6008
  fs.writeFileSync(fp, toolCall.content || '', 'utf8');
5986
6009
  toolResults.push({ op: 'write', path: toolCall.path, ok: true });
5987
- sendEv({ type: 'tool', op: 'write', path: toolCall.path, result: 'ok' });
6010
+ sendEv({ type: 'tool', op: 'write', path: toolCall.path, result: 'ok',
6011
+ oldSnippet: oldContent.slice(0, 300), newSnippet: (toolCall.content || '').slice(0, 300) });
5988
6012
  }
5989
6013
  }
5990
6014
 
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.147';
8
+ export const VERSION = '13.5.149';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -5276,6 +5276,21 @@ function downloadStudioPDF() {
5276
5276
  // ── Sections ─────────────────────────────────────────────────────────────
5277
5277
  sectionsHtml +
5278
5278
 
5279
+ // ── Charts / Canvas section (from CanvasAgent HTML) ──────────────────────
5280
+ (studioState.canvas ? (
5281
+ '<div class="section" style="page-break-before:always">' +
5282
+ '<div class="agent-header"><span class="agent-icon">&#128202;</span>' +
5283
+ '<div><div class="agent-name">Grafici e Dashboard</div>' +
5284
+ '<div class="agent-sub">CANVAS AGENT &nbsp;&#183;&nbsp; Visualizzazioni dati</div></div>' +
5285
+ '</div>' +
5286
+ '<div id="nha-canvas-charts" style="width:100%;overflow:hidden">' +
5287
+ studioState.canvas
5288
+ .replace(new RegExp('<script[^>]*>[\\s\\S]*?<\\/script>', 'gi'), '')
5289
+ .replace(new RegExp('<html[^>]*>|<\\/html>|<head[\\s\\S]*?<\\/head>|<body[^>]*>|<\\/body>', 'gi'), '') +
5290
+ '</div>' +
5291
+ '</div>'
5292
+ ) : '') +
5293
+
5279
5294
  // ── Footer ───────────────────────────────────────────────────────────────
5280
5295
  '<div class="footer-bar">' +
5281
5296
  '<span class="footer-left">NHA Studio &nbsp;&#183;&nbsp; nothumanallowed.com</span>' +
@@ -5283,6 +5298,32 @@ function downloadStudioPDF() {
5283
5298
  (totalTokensIn > 0 ? ' &nbsp;&#183;&nbsp; ' + totalTokensIn.toLocaleString() + ' token in / ' + totalTokensOut.toLocaleString() + ' out' : '') +
5284
5299
  '</span>' +
5285
5300
  '</div>' +
5301
+
5302
+ // ── Canvas-to-image script: converts <canvas> → <img> before printing ────
5303
+ // This runs inside the iframe, ensuring charts are visible in the PDF.
5304
+ '<script>' +
5305
+ 'window.addEventListener("load", function() {' +
5306
+ // Give Chart.js time to render all charts
5307
+ 'setTimeout(function() {' +
5308
+ 'function freezeCanvases() {' +
5309
+ 'var canvases = document.querySelectorAll("canvas");' +
5310
+ 'canvases.forEach(function(cv) {' +
5311
+ 'try {' +
5312
+ 'var img = document.createElement("img");' +
5313
+ 'img.src = cv.toDataURL("image/png");' +
5314
+ 'img.style.cssText = cv.style.cssText || "";' +
5315
+ 'img.style.maxWidth = "100%";' +
5316
+ 'img.style.display = "block";' +
5317
+ 'img.style.margin = "0 auto";' +
5318
+ 'if (cv.parentNode) cv.parentNode.replaceChild(img, cv);' +
5319
+ '} catch(e) {}' +
5320
+ '});' +
5321
+ '}' +
5322
+ 'window.addEventListener("beforeprint", freezeCanvases);' +
5323
+ '}, 1200);' +
5324
+ '});' +
5325
+ '<\/script>' +
5326
+
5286
5327
  '</body></html>';
5287
5328
 
5288
5329
  // ── Generate PDF via hidden in-page iframe ─────────────────────────────────
@@ -5310,7 +5351,8 @@ function downloadStudioPDF() {
5310
5351
 
5311
5352
  // Set up onload BEFORE appending — avoids WebKit race condition
5312
5353
  iframe.onload = function() {
5313
- // Wait for Chart.js to initialize all charts (needs ~800ms for animation frames)
5354
+ // Wait for Chart.js to initialize all charts and freezeCanvases to run (needs ~2s)
5355
+ var waitMs = studioState.canvas ? 2500 : 800;
5314
5356
  setTimeout(function() {
5315
5357
  try {
5316
5358
  iframe.contentWindow.focus();