nothumanallowed 13.2.18 → 13.2.19

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.19",
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": {
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.19';
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', '⚙', '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', '⚠', 'Unexpected error: ' + (e.message || String(e)), 'error');
2931
+ if (e.name !== 'AbortError') {
2932
+ studioLog('Studio', '⚠', '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>' +