nothumanallowed 13.2.18 → 13.2.20

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.2.18",
3
+ "version": "13.2.20",
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": {
@@ -2758,14 +2758,92 @@ Respond with ONLY valid JSON, no markdown:
2758
2758
  // Tool-data agents: fetch real live data and use buildSystemPrompt (tool calls allowed)
2759
2759
  const isLiveDataAgent = ['CalendarAgent','EmailAgent','GitHubAgent','NotionAgent','SlackAgent','DriveAgent','BrowserAgent','WebSearchAgent','ResearchAgent'].includes(agent);
2760
2760
 
2761
- const canvasSystemPrompt = `You are an HTML report generator. Output a single complete HTML document in ${language}. No preamble, no explanation.
2762
- RULES:
2763
- - First character of your response must be < (start of <!DOCTYPE html>)
2764
- - Do NOT use markdown code blocks, JSON, or any wrapper
2765
- - All text content must be in ${language}
2766
- - Use clean design: white background, Inter/system-ui font, #6366f1 accent color
2767
- - Structure: gradient header, then card sections with the content
2768
- - Make it complete and self-contained`;
2761
+ const canvasSystemPrompt = `You are an HTML report generator. Output ONLY a single complete HTML document in ${language}. No preamble, no explanation, no markdown.
2762
+ STRICT RULES:
2763
+ - Your ENTIRE response must be valid HTML starting with <!DOCTYPE html>
2764
+ - Do NOT output markdown code blocks, JSON, or any wrapper text
2765
+ - ALL text content (titles, descriptions, labels, body text) must be in ${language}
2766
+ - Use EXACTLY this CSS template structure — only change the content inside, never the style
2767
+
2768
+ USE THIS EXACT HTML STRUCTURE (replace placeholders with real content):
2769
+ <!DOCTYPE html>
2770
+ <html lang="${language.slice(0,2).toLowerCase()}">
2771
+ <head>
2772
+ <meta charset="UTF-8">
2773
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
2774
+ <title>REPORT TITLE HERE</title>
2775
+ <style>
2776
+ *{margin:0;padding:0;box-sizing:border-box}
2777
+ body{font-family:'Inter',system-ui,sans-serif;background:#0d0d14;color:#f0f0f5;min-height:100vh;padding:24px}
2778
+ .header{background:linear-gradient(135deg,#6366f1 0%,#22d3ee 100%);border-radius:16px;padding:32px 40px;margin-bottom:24px}
2779
+ .header h1{font-size:28px;font-weight:700;color:#fff;margin-bottom:8px}
2780
+ .header p{font-size:14px;color:rgba(255,255,255,0.8)}
2781
+ .meta{display:flex;gap:16px;margin-top:16px;flex-wrap:wrap}
2782
+ .meta span{background:rgba(255,255,255,0.2);border-radius:20px;padding:4px 12px;font-size:12px;color:#fff}
2783
+ .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px;margin-bottom:24px}
2784
+ .card{background:#15151f;border:1px solid #2a2a38;border-radius:12px;padding:20px}
2785
+ .card h2{font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:#6366f1;margin-bottom:12px;font-weight:600}
2786
+ .card h3{font-size:16px;font-weight:600;color:#f0f0f5;margin-bottom:8px}
2787
+ .card p{font-size:13px;color:#8b8b9e;line-height:1.6}
2788
+ .card ul{list-style:none;padding:0}
2789
+ .card ul li{font-size:13px;color:#8b8b9e;line-height:1.8;padding-left:16px;position:relative}
2790
+ .card ul li::before{content:'›';position:absolute;left:0;color:#6366f1}
2791
+ .badge{display:inline-block;padding:3px 10px;border-radius:20px;font-size:11px;font-weight:600;margin-right:6px;margin-bottom:4px}
2792
+ .badge-high{background:#7f1d1d;color:#ef4444}
2793
+ .badge-med{background:#713f12;color:#f59e0b}
2794
+ .badge-low{background:#14532d;color:#34d399}
2795
+ .badge-info{background:#1e1b4b;color:#6366f1}
2796
+ .section{background:#15151f;border:1px solid #2a2a38;border-radius:12px;padding:24px;margin-bottom:16px}
2797
+ .section h2{font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:#22d3ee;margin-bottom:16px;font-weight:600}
2798
+ .section h3{font-size:15px;font-weight:600;color:#f0f0f5;margin-bottom:6px}
2799
+ .section p{font-size:13px;color:#8b8b9e;line-height:1.7;margin-bottom:12px}
2800
+ .priority-list{display:flex;flex-direction:column;gap:10px}
2801
+ .priority-item{display:flex;align-items:flex-start;gap:12px;padding:12px;background:#1c1c28;border-radius:8px}
2802
+ .priority-num{width:28px;height:28px;border-radius:50%;background:#6366f1;color:#fff;font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}
2803
+ .priority-item h4{font-size:13px;font-weight:600;color:#f0f0f5;margin-bottom:2px}
2804
+ .priority-item p{font-size:12px;color:#8b8b9e;line-height:1.5;margin:0}
2805
+ .footer{text-align:center;padding:20px;font-size:11px;color:#4a4a5e;margin-top:8px}
2806
+ </style>
2807
+ </head>
2808
+ <body>
2809
+ <!-- HEADER: put report title, subtitle, date, and 2-3 meta tags -->
2810
+ <div class="header">
2811
+ <h1>REPLACE WITH REPORT TITLE</h1>
2812
+ <p>REPLACE WITH SUBTITLE/DESCRIPTION</p>
2813
+ <div class="meta">
2814
+ <span>📅 ${today}</span>
2815
+ <span>META TAG 2</span>
2816
+ <span>META TAG 3</span>
2817
+ </div>
2818
+ </div>
2819
+
2820
+ <!-- STATS GRID: 3-4 cards with key numbers/stats -->
2821
+ <div class="grid">
2822
+ <div class="card">
2823
+ <h2>LABEL 1</h2>
2824
+ <h3>STAT OR TITLE</h3>
2825
+ <p>DESCRIPTION</p>
2826
+ </div>
2827
+ <!-- Add more cards for other stats -->
2828
+ </div>
2829
+
2830
+ <!-- MAIN SECTIONS: 2-4 sections with content -->
2831
+ <div class="section">
2832
+ <h2>SECTION LABEL</h2>
2833
+ <div class="priority-list">
2834
+ <div class="priority-item">
2835
+ <div class="priority-num">1</div>
2836
+ <div><h4>ITEM TITLE</h4><p>ITEM DESCRIPTION</p></div>
2837
+ </div>
2838
+ <!-- Add more priority items -->
2839
+ </div>
2840
+ </div>
2841
+
2842
+ <div class="footer">Generated by NHA Studio · ${today}</div>
2843
+ </body>
2844
+ </html>
2845
+
2846
+ Fill ALL placeholder text with the actual content from the data provided. Keep ALL CSS exactly as above. Output ONLY the HTML.`;
2769
2847
 
2770
2848
  let sysPrompt, userMsg;
2771
2849
 
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.2.18';
8
+ export const VERSION = '13.2.20';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -2715,6 +2715,22 @@ var studioState = {
2715
2715
  planned: false
2716
2716
  };
2717
2717
 
2718
+ var studioAbortController = null;
2719
+
2720
+ function stopStudio() {
2721
+ if (!studioState.running) return;
2722
+ if (studioAbortController) { try { studioAbortController.abort(); } catch(e) {} studioAbortController = null; }
2723
+ studioState.running = false;
2724
+ var btn = document.getElementById('studioRunBtn');
2725
+ if (btn) { btn.disabled = false; btn.textContent = '▶ Run'; }
2726
+ var stopBtn = document.getElementById('studioStopBtn');
2727
+ if (stopBtn) stopBtn.style.display = 'none';
2728
+ studioLog('Studio', '⬛', 'Workflow stopped by user.', 'system');
2729
+ // Mark any still-running nodes as error
2730
+ studioState.nodes.forEach(function(n) { if (n.status === 'running') n.status = 'error'; });
2731
+ renderStudioNodes();
2732
+ }
2733
+
2718
2734
  function studioReset() {
2719
2735
  if (studioState.running) return;
2720
2736
  studioState.task = '';
@@ -2840,8 +2856,12 @@ async function runStudio() {
2840
2856
  renderStudioLog();
2841
2857
  renderStudioResult();
2842
2858
 
2859
+ studioAbortController = new AbortController();
2860
+
2843
2861
  var btn = document.getElementById('studioRunBtn');
2844
2862
  if (btn) { btn.disabled = true; btn.textContent = 'Planning...'; }
2863
+ var stopBtn = document.getElementById('studioStopBtn');
2864
+ if (stopBtn) stopBtn.style.display = '';
2845
2865
 
2846
2866
  studioLog('Studio', '&#9881;', 'Planning workflow for: "' + task + '"', 'system');
2847
2867
  // Show a temporary planning indicator in the nodes area
@@ -2871,7 +2891,12 @@ async function runStudio() {
2871
2891
  studioSetNodeStatus(i, 'running');
2872
2892
  studioLog(node.label, node.icon, 'Starting...', 'agent');
2873
2893
 
2874
- var stepResult = await runStudioStep(i, node, task, context, planRes.steps[i]);
2894
+ if (!studioState.running) break; // stopped by user
2895
+ var stepResult = await runStudioStep(i, node, task, context, planRes.steps[i], studioAbortController ? studioAbortController.signal : null);
2896
+ if (stepResult.aborted) {
2897
+ studioSetNodeStatus(i, 'error');
2898
+ break;
2899
+ }
2875
2900
  if (stepResult.error) {
2876
2901
  studioSetNodeStatus(i, 'error');
2877
2902
  studioLog(node.label, node.icon, 'Error: ' + stepResult.error, 'error');
@@ -2903,11 +2928,15 @@ async function runStudio() {
2903
2928
  renderStudioSessionsBar();
2904
2929
 
2905
2930
  } catch(e) {
2906
- studioLog('Studio', '&#9888;', 'Unexpected error: ' + (e.message || String(e)), 'error');
2931
+ if (e.name !== 'AbortError') {
2932
+ studioLog('Studio', '&#9888;', 'Unexpected error: ' + (e.message || String(e)), 'error');
2933
+ }
2907
2934
  }
2908
2935
 
2909
2936
  studioState.running = false;
2910
- if (btn) { btn.disabled = false; btn.textContent = 'Run'; }
2937
+ studioAbortController = null;
2938
+ if (btn) { btn.disabled = false; btn.textContent = '▶ Run'; }
2939
+ if (stopBtn) stopBtn.style.display = 'none';
2911
2940
  }
2912
2941
 
2913
2942
  // ---- STUDIO SESSIONS ----
@@ -2966,7 +2995,7 @@ function restoreStudioSession(idx) {
2966
2995
  var ta = document.getElementById('studioTaskInput');
2967
2996
  if (ta) ta.value = s.task;
2968
2997
  renderStudioNodes(); renderStudioLog(); renderStudioResult();
2969
- toast('Session restored');
2998
+ showToast('success', 'Session restored', s.task.slice(0, 60), 3000);
2970
2999
  }
2971
3000
 
2972
3001
  function importStudioToChat(idx) {
@@ -3007,17 +3036,15 @@ function studioAddTokens(inp, out) {
3007
3036
  if (el) el.textContent = 'Tokens: ' + studioTokens.in + ' in / ' + studioTokens.out + ' out';
3008
3037
  }
3009
3038
 
3010
- function runStudioStep(idx, node, task, context, stepDef) {
3039
+ function runStudioStep(idx, node, task, context, stepDef, signal) {
3011
3040
  return new Promise(function(resolve) {
3012
3041
  var output = '';
3013
3042
  var canvasHtml = null;
3014
3043
  var body = JSON.stringify({stepIdx: idx, agent: node.agent, task: task, context: context, stepDef: stepDef});
3044
+ var fetchOpts = {method: 'POST', headers: {'Content-Type': 'application/json'}, body: body};
3045
+ if (signal) fetchOpts.signal = signal;
3015
3046
 
3016
- fetch('/api/studio/run', {
3017
- method: 'POST',
3018
- headers: {'Content-Type': 'application/json'},
3019
- body: body
3020
- }).then(function(res) {
3047
+ fetch('/api/studio/run', fetchOpts).then(function(res) {
3021
3048
  if (!res.ok) { resolve({error: 'HTTP ' + res.status}); return; }
3022
3049
  var reader = res.body.getReader();
3023
3050
  var decoder = new TextDecoder();
@@ -3072,10 +3099,14 @@ function runStudioStep(idx, node, task, context, stepDef) {
3072
3099
  } catch(e) {}
3073
3100
  });
3074
3101
  pump();
3075
- }).catch(function(e) { resolve({error: e.message}); });
3102
+ }).catch(function(e) {
3103
+ if (e.name === 'AbortError') { resolve({aborted: true}); } else { resolve({error: e.message}); }
3104
+ });
3076
3105
  }
3077
3106
  pump();
3078
- }).catch(function(e) { resolve({error: e.message}); });
3107
+ }).catch(function(e) {
3108
+ if (e.name === 'AbortError') { resolve({aborted: true}); } else { resolve({error: e.message}); }
3109
+ });
3079
3110
  });
3080
3111
  }
3081
3112
 
@@ -3184,6 +3215,7 @@ function renderStudio(el) {
3184
3215
  '<textarea id="studioTaskInput" placeholder="Describe what you want to accomplish... (Ctrl+Enter to run)" onkeydown="if(event.key===\\x27Enter\\x27&&(event.ctrlKey||event.metaKey)){runStudio();event.preventDefault()}">' + esc(studioState.task) + '</textarea>' +
3185
3216
  '<div style="display:flex;gap:6px">' +
3186
3217
  '<button id="studioRunBtn" class="studio-run-btn" onclick="runStudio()" style="flex:1" ' + (studioState.running ? 'disabled' : '') + '>&#9654; Run</button>' +
3218
+ '<button id="studioStopBtn" onclick="stopStudio()" title="Stop workflow" style="padding:8px 14px;background:#7f1d1d;border:1px solid #ef4444;border-radius:8px;color:#ef4444;cursor:pointer;font-size:13px;font-weight:700;white-space:nowrap;' + (studioState.running ? '' : 'display:none') + '">&#9632; Stop</button>' +
3187
3219
  '<button onclick="studioReset()" title="New workflow" style="padding:8px 12px;background:none;border:1px solid var(--border);border-radius:8px;color:var(--dim);cursor:pointer;font-size:16px;line-height:1" ' + (studioState.running ? 'disabled' : '') + '>&#8635;</button>' +
3188
3220
  '</div>' +
3189
3221
  '</div>' +