nothumanallowed 13.5.58 → 13.5.60

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # NotHumanAllowed
2
2
 
3
- **38 specialized AI agents, 81 tools, Studio visual workflows — all local, all free.** Security auditors, code architects, data analysts, DevOps engineers, technical writers — each with deep domain expertise. Use them individually, run complex multi-agent workflows in Studio, or let them deliberate together with Parliament mode.
3
+ **38 specialized AI agents, 80 tools, Studio visual workflows, WebCraft full-stack builder — all local, all free.** Security auditors, code architects, data analysts, DevOps engineers, technical writers — each with deep domain expertise. Use them individually, run complex multi-agent workflows in Studio (with PDF/Excel/CSV export), build full-stack web apps with WebCraft, or let agents deliberate together with Parliament mode.
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -40,6 +40,83 @@ EmailAgent → WebSearchAgent → WriterAgent
40
40
  - **Parliament mode** — enable for 2+ specialist agents to cross-read and deliberate: R1 (independent), R2 (agents read each other), R3 (HERALD mediation), convergence score
41
41
  - Open `nha ui` → click **Studio** in the sidebar
42
42
 
43
+ ### Studio Export
44
+
45
+ When a workflow completes, Studio provides three export formats:
46
+
47
+ - **PDF** — full structured report with all agent outputs, typography, token counters
48
+ - **Excel (XLSX)** — professional multi-sheet workbook via SheetJS: one sheet per agent, auto-detected numeric columns with formatting, alternating row colors, freeze panes, auto-column widths, index sheet with token summary. Data tables are extracted from Markdown output automatically.
49
+ - **CSV** — all Markdown tables from the report merged into a single file
50
+
51
+ Export buttons appear in the result panel and in the toolbar after each run.
52
+
53
+ ---
54
+
55
+ ## WebCraft — Full-Stack Web Apps from a Chat
56
+
57
+ WebCraft is a full-stack web app builder embedded in `nha ui`. Describe what you want in plain language — WebCraft generates a complete project with Express.js backend, PostgreSQL schema, JWT auth, email verification, security middleware, and a styled frontend. Everything runs locally with a live sandbox.
58
+
59
+ ```
60
+ Open nha ui → click WebCraft in the sidebar
61
+ ```
62
+
63
+ ### How it works
64
+
65
+ 1. **Describe your project** in the chat (or pick an example: MySaaS, MyShop, MyBlog, MyPortfolio...)
66
+ 2. **WebCraft generates** all files: `server/`, `public/`, `db/migrations/`, `.env.example`, `package.json`, nginx config
67
+ 3. **Click ▶ Sandbox** — runs `npm install && node server/index.js` in an isolated process, live on a local port
68
+ 4. **Chat with the agent** to modify, fix, or extend anything — the agent edits files directly on disk, you see diffs in real time
69
+
70
+ ### WebCraft Agent
71
+
72
+ An AI assistant permanently available in the chat panel. Powered by Liara (Qwen3 32B, free) or your own API key.
73
+
74
+ **What it can do:**
75
+ - Edit files surgically (old → new string replace) or rewrite them completely
76
+ - Read any project file for context
77
+ - Auto-fix `MODULE_NOT_FOUND` and common require() path errors
78
+ - Restart the sandbox after fixes
79
+ - Process attached screenshots or PDFs (vision) to debug visual issues
80
+
81
+ **Context files** (created automatically for every project, editable via sidebar):
82
+ | File | Type | Purpose |
83
+ |---|---|---|
84
+ | `skills/memory.md` | memory | Architecture decisions, stack choices, developer preferences |
85
+ | `skills/liara.md` | provider | Calibrate AI tone, code style, constraints |
86
+ | `skills/skills.md` | skill | Reusable patterns, snippets, API integrations |
87
+
88
+ Add more skill files (unlimited) for specific integrations (Stripe, email templates, etc.).
89
+
90
+ ### Developer Tools (sidebar toolbar)
91
+
92
+ | Tool | Description |
93
+ |---|---|
94
+ | **Diff viewer** | After every agent edit, see before/after for each changed file — color-coded, collapsible |
95
+ | **Syntax check** ✅ | Runs `node --check` on all JS files, reports errors instantly |
96
+ | **Search** 🔍 | Grep across all project files — click a result to jump to that file |
97
+ | **Snapshot** 💾 | Save a full point-in-time backup of all files. Restore any snapshot with one click |
98
+ | **Plan mode** | Type `/plan your request` — agent proposes a plan first, you approve before any file is touched |
99
+ | **Auto-fix** | Sandbox errors (MODULE_NOT_FOUND etc.) trigger automatic Liara fix attempts (3 free, unlimited with own key) |
100
+
101
+ ### Example session
102
+
103
+ ```
104
+ You: "Add a contact form with SMTP email and honeypot spam protection"
105
+ Agent: → edits server/routes/api.js (add /contact POST route)
106
+ → edits server/services/email.js (add sendContactEmail)
107
+ → edits public/index.html (add form HTML)
108
+ → edits public/js/main.js (add form JS with honeypot)
109
+ [Diff viewer shows 4 files changed]
110
+ [Syntax check: ✅ all files valid]
111
+ [Sandbox restarted automatically]
112
+ ```
113
+
114
+ ```
115
+ You: "/plan refactor auth to use refresh token rotation"
116
+ Agent: → proposes plan (3 files, 6 changes) — no edits yet
117
+ → you click Approve → agent executes
118
+ ```
119
+
43
120
  ## Daily Operations (PAO)
44
121
 
45
122
  Connect Gmail + Calendar. 5 specialist agents analyze your day.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "13.5.58",
3
+ "version": "13.5.60",
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": {
@@ -4632,12 +4632,40 @@ REGOLE CRITICHE:
4632
4632
  }
4633
4633
 
4634
4634
  // Parse and execute tool calls from response
4635
+ // Sanitize JSON from LLM: replace literal newlines inside JSON strings with \n
4636
+ // Models often write multiline strings without escaping, which breaks JSON.parse
4637
+ const sanitizeToolJson = (raw) => {
4638
+ // Replace literal CR/LF inside JSON string values with escaped versions
4639
+ // Strategy: walk char by char, track if we're inside a JSON string
4640
+ let out = '';
4641
+ let inStr = false;
4642
+ let escaped = false;
4643
+ for (let ci = 0; ci < raw.length; ci++) {
4644
+ const ch = raw[ci];
4645
+ if (escaped) { out += ch; escaped = false; continue; }
4646
+ if (ch === '\\') { out += ch; escaped = true; continue; }
4647
+ if (ch === '"') { inStr = !inStr; out += ch; continue; }
4648
+ if (inStr && (ch === '\n' || ch === '\r')) {
4649
+ out += ch === '\n' ? '\\n' : '\\r';
4650
+ continue;
4651
+ }
4652
+ out += ch;
4653
+ }
4654
+ return out;
4655
+ };
4656
+
4635
4657
  const toolRegex = /<tool>([\s\S]*?)<\/tool>/g;
4636
4658
  let toolMatch;
4637
4659
  const toolResults = [];
4638
4660
  while ((toolMatch = toolRegex.exec(fullResponse)) !== null) {
4639
4661
  let toolCall;
4640
- try { toolCall = JSON.parse(toolMatch[1]); } catch(e) { continue; }
4662
+ try {
4663
+ const raw = toolMatch[1].trim();
4664
+ toolCall = JSON.parse(sanitizeToolJson(raw));
4665
+ } catch(e) {
4666
+ sendEv({ type: 'tool', op: 'parse_error', path: '?', result: 'JSON malformato: ' + e.message.slice(0, 80) });
4667
+ continue;
4668
+ }
4641
4669
 
4642
4670
  if (toolCall.op === 'read') {
4643
4671
  const fp = path.join(sandboxDir, toolCall.path.replace(/^\/+/, ''));
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.58';
8
+ export const VERSION = '13.5.60';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -6984,16 +6984,23 @@ function wcChatPanelHtml() {
6984
6984
  }
6985
6985
  } else {
6986
6986
  var toolBadges = (msg.tools || []).map(function(tool){
6987
- var icon = tool.op === 'edit' ? '&#9998;' : (tool.op === 'write' ? '&#10133;' : '&#128065;');
6988
- var color = tool.result === 'ok' ? 'var(--green)' : 'var(--red)';
6989
- return '<span style="display:inline-flex;align-items:center;gap:3px;background:var(--bg3);border:1px solid var(--border);border-radius:4px;padding:2px 6px;font-size:9px;font-family:var(--mono);color:'+color+'">'+icon+' '+wcEsc(tool.path)+'</span>';
6987
+ var isOk = tool.result === 'ok';
6988
+ var isParseErr = tool.op === 'parse_error';
6989
+ var icon = isParseErr ? '&#10067;' : (tool.op === 'edit' ? '&#9998;' : (tool.op === 'write' ? '&#10133;' : '&#128065;'));
6990
+ var color = isOk ? 'var(--green)' : 'var(--red)';
6991
+ var label = isParseErr ? ('JSON err: ' + wcEsc(tool.result)) : wcEsc(tool.path);
6992
+ var title = isOk ? tool.op + ': ' + tool.path : (tool.result || '');
6993
+ return '<span title="'+wcEsc(title)+'" style="display:inline-flex;align-items:center;gap:3px;background:var(--bg3);border:1px solid '+(isOk?'var(--green3)':'var(--red)')+';border-radius:4px;padding:2px 6px;font-size:9px;font-family:var(--mono);color:'+color+'">' +
6994
+ icon + ' ' + label + '</span>';
6990
6995
  }).join(' ');
6991
- messagesHtml += '<div style="margin:4px 12px">' +
6992
- '<div style="display:flex;align-items:center;gap:6px;margin-bottom:3px">' +
6993
- '<span style="font-size:10px;font-weight:700;color:var(--green)">&#129302; WebCraft Agent</span>' +
6996
+ var agentText = wcEsc(msg.text.replace(new RegExp('<tool>[\\s\\S]*?<\\/tool>', 'g'), '').trim());
6997
+ messagesHtml += '<div style="margin:6px 12px;border:1px solid rgba(255,255,255,0.12);border-radius:10px;background:var(--bg3);overflow:hidden">' +
6998
+ '<div style="display:flex;align-items:center;gap:6px;padding:6px 10px;border-bottom:1px solid rgba(255,255,255,0.06);background:rgba(255,255,255,0.03)">' +
6999
+ '<span style="font-size:13px">&#129302;</span>' +
7000
+ '<span style="font-size:10px;font-weight:700;color:var(--green)">WebCraft Agent</span>' +
6994
7001
  '</div>' +
6995
- '<div style="font-size:11px;color:var(--text);line-height:1.6;white-space:pre-wrap;max-width:85%">'+wcEsc(msg.text.replace(new RegExp('<tool>[\\s\\S]*?<\\/tool>', 'g'), '').trim())+'</div>' +
6996
- (toolBadges ? '<div style="display:flex;flex-wrap:wrap;gap:4px;margin-top:5px">'+toolBadges+'</div>' : '') +
7002
+ '<div style="padding:8px 10px;font-size:11px;color:var(--text);line-height:1.6;white-space:pre-wrap">'+agentText+'</div>' +
7003
+ (toolBadges ? '<div style="display:flex;flex-wrap:wrap;gap:4px;padding:6px 10px;border-top:1px solid rgba(255,255,255,0.06)">'+toolBadges+'</div>' : '') +
6997
7004
  '</div>';
6998
7005
  }
6999
7006
  }
@@ -7024,9 +7031,9 @@ function wcChatPanelHtml() {
7024
7031
  '</div>'
7025
7032
  : '<div style="padding:4px 12px 0;font-size:10px;color:var(--dim)">&#128196; <strong style="color:var(--green)">'+wcEsc(wcState.projectName)+'</strong> &mdash; scrivi per modificare o migliorare il progetto</div>';
7026
7033
 
7027
- return '<div style="border-top:1px solid var(--border);background:var(--bg2);flex-shrink:0;display:flex;flex-direction:column">' +
7034
+ return '<div style="border-top:1px solid var(--border);background:var(--bg2);flex-shrink:0;display:flex;flex-direction:column;min-height:220px">' +
7028
7035
  // Messages
7029
- '<div id="wcChatMessages" style="max-height:160px;overflow-y:auto;padding:6px 0">' +
7036
+ '<div id="wcChatMessages" style="max-height:240px;overflow-y:auto;padding:6px 0">' +
7030
7037
  messagesHtml +
7031
7038
  '</div>' +
7032
7039
  // Attachments
@@ -7039,7 +7046,7 @@ function wcChatPanelHtml() {
7039
7046
  '&#128206;' +
7040
7047
  '<input type="file" id="wcFileInput" multiple accept="image/*,.pdf" style="display:none" onchange="wcHandleFileAttach(this)">' +
7041
7048
  '</label>' +
7042
- '<textarea id="wcChatInput" rows="2" 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:none;line-height:1.5;font-family:inherit" onkeydown="wcChatKeydown(event)"></textarea>' +
7049
+ '<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>' +
7043
7050
  '<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>' +
7044
7051
  '</div>' +
7045
7052
  '</div>';
@@ -7909,6 +7916,20 @@ async function wcStartSandbox() {
7909
7916
  wcState.sandbox.running = false;
7910
7917
  wcState.sandbox.error = evt.msg;
7911
7918
  renderWebCraft(document.getElementById('content'));
7919
+ // Auto-fix: try to detect MODULE_NOT_FOUND in crash message and fix it
7920
+ var errMsg = evt.msg || '';
7921
+ var modMatch = errMsg.match(new RegExp("Cannot find module '([^']+)'")) ||
7922
+ errMsg.match(new RegExp('Cannot find module "([^"]+)"'));
7923
+ if (modMatch && _wcAutoFixAttempts < 3) {
7924
+ _wcAutoFixAttempts++;
7925
+ wcTriggerAutoFix(modMatch[1]);
7926
+ } else if (errMsg && !modMatch && _wcAutoFixAttempts < 3) {
7927
+ // Generic crash: post error to chat so agent can see it
7928
+ _wcAutoFixAttempts++;
7929
+ wcChat.push({ role: 'system', text: '&#10060; Errore sandbox: ' + errMsg });
7930
+ renderWebCraft(document.getElementById('content'));
7931
+ wcScrollChatToBottom();
7932
+ }
7912
7933
  }
7913
7934
  } catch(_) {}
7914
7935
  }