nothumanallowed 9.3.18 → 9.4.0
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 +1 -1
- package/src/commands/ui.mjs +14 -0
- package/src/constants.mjs +1 -1
- package/src/services/browser-engine.mjs +18 -2
- package/src/services/web-ui.mjs +56 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.4.0",
|
|
4
4
|
"description": "NotHumanAllowed — 38 AI agents + 58 tools + browser automation + web search. Streaming chat, headless Chrome CDP, multi-conversation, export. Gmail, Calendar, Drive, GitHub, Notion, Slack. Zero-dependency CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/commands/ui.mjs
CHANGED
|
@@ -1263,6 +1263,20 @@ export async function cmdUI(args) {
|
|
|
1263
1263
|
toolResults.push({ action, result: resultStr });
|
|
1264
1264
|
sendSSE('tool', { action, status: 'done', result: typeof resultStr === 'string' ? resultStr.slice(0, 500) : '' });
|
|
1265
1265
|
|
|
1266
|
+
// Send live browser frame after browser actions (low-quality thumbnail for viewer)
|
|
1267
|
+
if (action.startsWith('browser_') && action !== 'browser_close') {
|
|
1268
|
+
try {
|
|
1269
|
+
const be = await import('../services/browser-engine.mjs');
|
|
1270
|
+
if (be.isBrowserRunning()) {
|
|
1271
|
+
const frame = await be.browserScreenshot({ fullPage: false, format: 'jpeg', quality: 30 });
|
|
1272
|
+
if (!frame.error) {
|
|
1273
|
+
const info = await be.browserInfo();
|
|
1274
|
+
sendSSE('browser_frame', { base64: frame.base64, format: 'jpeg', url: (info.url || '').slice(0, 80) });
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
} catch { /* frame capture failed, non-critical */ }
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1266
1280
|
// If the tool produced a screenshot (web_search with screenshot=true), send it via SSE and save to disk
|
|
1267
1281
|
if (resultStr.includes('[Screenshot of results captured')) {
|
|
1268
1282
|
try {
|
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 = '9.
|
|
8
|
+
export const VERSION = '9.4.0';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -1014,13 +1014,29 @@ export async function browserExtract(options = {}) {
|
|
|
1014
1014
|
export async function browserEval(code, options = {}) {
|
|
1015
1015
|
const browser = await getBrowser();
|
|
1016
1016
|
|
|
1017
|
-
|
|
1018
|
-
|
|
1017
|
+
// Auto-wrap object literals: {key: val} → ({key: val}) to avoid block/label ambiguity
|
|
1018
|
+
let expression = code.trim();
|
|
1019
|
+
if (expression.startsWith('{') && !expression.startsWith('{(')) {
|
|
1020
|
+
expression = `(${expression})`;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
let result = await browser.ws.send('Runtime.evaluate', {
|
|
1024
|
+
expression,
|
|
1019
1025
|
returnByValue: true,
|
|
1020
1026
|
awaitPromise: options.awaitPromise !== false,
|
|
1021
1027
|
generatePreview: true,
|
|
1022
1028
|
}, COMMAND_TIMEOUT_MS);
|
|
1023
1029
|
|
|
1030
|
+
// If SyntaxError, retry with IIFE wrapper
|
|
1031
|
+
if (result.exceptionDetails?.exception?.description?.includes('SyntaxError')) {
|
|
1032
|
+
result = await browser.ws.send('Runtime.evaluate', {
|
|
1033
|
+
expression: `(() => { return (${code.trim()}); })()`,
|
|
1034
|
+
returnByValue: true,
|
|
1035
|
+
awaitPromise: options.awaitPromise !== false,
|
|
1036
|
+
generatePreview: true,
|
|
1037
|
+
}, COMMAND_TIMEOUT_MS);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1024
1040
|
if (result.exceptionDetails) {
|
|
1025
1041
|
const errMsg = result.exceptionDetails.exception?.description
|
|
1026
1042
|
|| result.exceptionDetails.text
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -101,6 +101,18 @@ input:focus,textarea:focus{border-color:var(--green3)}
|
|
|
101
101
|
.tool-indicator--web{border-color:var(--cyan);color:var(--cyan)}
|
|
102
102
|
.tool-indicator--email{border-color:var(--green3);color:var(--green)}
|
|
103
103
|
.screenshot-preview{max-width:100%;border-radius:var(--r);margin:8px 0;border:1px solid var(--border)}
|
|
104
|
+
.browser-viewer{position:fixed;bottom:16px;right:16px;width:380px;background:var(--bg2);border:2px solid #9c27b0;border-radius:8px;box-shadow:0 8px 32px rgba(0,0,0,0.6);z-index:300;overflow:hidden;display:none;transition:all .3s ease}
|
|
105
|
+
.browser-viewer--open{display:block}
|
|
106
|
+
.browser-viewer__header{display:flex;align-items:center;gap:6px;padding:6px 10px;background:#1a1a2e;border-bottom:1px solid #9c27b0;font-size:10px;color:#ce93d8}
|
|
107
|
+
.browser-viewer__dot{width:6px;height:6px;border-radius:50%;background:#9c27b0;animation:bvpulse 1.5s infinite}
|
|
108
|
+
@keyframes bvpulse{0%,100%{opacity:1}50%{opacity:.3}}
|
|
109
|
+
.browser-viewer__title{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
110
|
+
.browser-viewer__close{background:none;border:none;color:#666;cursor:pointer;font-size:14px;padding:0 4px}
|
|
111
|
+
.browser-viewer__close:hover{color:#fff}
|
|
112
|
+
.browser-viewer__frame{width:100%;aspect-ratio:16/9;background:#000;display:flex;align-items:center;justify-content:center}
|
|
113
|
+
.browser-viewer__frame img{width:100%;height:100%;object-fit:contain}
|
|
114
|
+
.browser-viewer__status{padding:4px 10px;font-size:9px;color:var(--dim);border-top:1px solid var(--border)}
|
|
115
|
+
@media(max-width:600px){.browser-viewer{width:280px;bottom:70px}}
|
|
104
116
|
.chat__bar{display:flex;gap:8px;padding:10px 0 12px 0;border-top:1px solid var(--border);flex-shrink:0}
|
|
105
117
|
.chat__input{flex:1;resize:none;min-height:40px;max-height:100px;padding:10px 14px}
|
|
106
118
|
.chat__send{background:var(--green3);color:var(--bg);padding:10px 16px;border-radius:var(--r);font-weight:700;font-size:12px}
|
|
@@ -226,6 +238,24 @@ function stopChat(){
|
|
|
226
238
|
renderMessages();
|
|
227
239
|
}
|
|
228
240
|
|
|
241
|
+
// ---- BROWSER VIEWER (live preview of headless Chrome) ----
|
|
242
|
+
function showBrowserViewer(title,status){
|
|
243
|
+
var v=document.getElementById('browserViewer');if(!v)return;
|
|
244
|
+
v.classList.add('browser-viewer--open');
|
|
245
|
+
var t=document.getElementById('bvTitle');if(t)t.textContent=title||'Browser';
|
|
246
|
+
var s=document.getElementById('bvStatus');if(s)s.textContent=status||'Loading...';
|
|
247
|
+
}
|
|
248
|
+
function updateBrowserFrame(base64,format){
|
|
249
|
+
var f=document.getElementById('bvFrame');if(!f)return;
|
|
250
|
+
f.innerHTML='<img src="data:image/'+(format||'jpeg')+';base64,'+base64+'" alt="Browser view">';
|
|
251
|
+
}
|
|
252
|
+
function updateBrowserStatus(status){
|
|
253
|
+
var s=document.getElementById('bvStatus');if(s)s.textContent=status;
|
|
254
|
+
}
|
|
255
|
+
function closeBrowserViewer(){
|
|
256
|
+
var v=document.getElementById('browserViewer');if(v)v.classList.remove('browser-viewer--open');
|
|
257
|
+
}
|
|
258
|
+
|
|
229
259
|
function loadConvList(){return apiGet('/api/conversations').then(function(r){convList=(r&&r.conversations)||[];renderConvSidebar();})}
|
|
230
260
|
function loadConv(id){return apiGet('/api/conversations/'+id).then(function(r){if(r&&r.conversation){activeConvId=r.conversation.id;chatHistory=r.conversation.messages||[];renderMessages();renderConvSidebar();}})}
|
|
231
261
|
function createNewConv(){return apiPost('/api/conversations',{}).then(function(r){if(r&&r.conversation){activeConvId=r.conversation.id;chatHistory=[];renderMessages();loadConvList();}})}
|
|
@@ -533,6 +563,12 @@ function sendChat(){
|
|
|
533
563
|
var label=toolLabels[data.action]||data.action;
|
|
534
564
|
var indicator=data.status==='executing'?'\\u23f3 '+label+'...':'\\u2705 '+label;
|
|
535
565
|
if(data.status==='error')indicator='\\u274c '+label+' failed';
|
|
566
|
+
// Show browser viewer for browser actions
|
|
567
|
+
var isBrowserAction=data.action&&data.action.startsWith('browser_');
|
|
568
|
+
if(isBrowserAction&&data.status==='executing'){showBrowserViewer(label,'Executing...');}
|
|
569
|
+
if(isBrowserAction&&data.status==='done'){updateBrowserStatus('\\u2705 '+label);}
|
|
570
|
+
if(isBrowserAction&&data.status==='error'){updateBrowserStatus('\\u274c '+label);}
|
|
571
|
+
if(data.action==='browser_close'&&data.status==='done'){setTimeout(closeBrowserViewer,2000);}
|
|
536
572
|
// Strip JSON action blocks from streamed content (they are internal tool calls, not for the user)
|
|
537
573
|
if(data.status==='executing'){chatHistory[streamIdx].content=chatHistory[streamIdx].content.replace(new RegExp('\\x60\\x60\\x60json[\\\\s\\\\S]*?\\x60\\x60\\x60','g'),'').trim()+'\\n';}
|
|
538
574
|
chatHistory[streamIdx].content+=indicator+'\\n';
|
|
@@ -540,11 +576,18 @@ function sendChat(){
|
|
|
540
576
|
}
|
|
541
577
|
if(currentEvent==='screenshot'&&data.base64){
|
|
542
578
|
if(!chatHistory[streamIdx]._screenshots)chatHistory[streamIdx]._screenshots=[];
|
|
543
|
-
// Use file URL if available (persists across sessions), fall back to base64
|
|
544
579
|
var ssUrl=data.filename?'/api/screenshots/'+data.filename:'data:image/'+(data.format||'jpeg')+';base64,'+data.base64;
|
|
545
580
|
chatHistory[streamIdx]._screenshots.push(ssUrl);
|
|
546
581
|
chatHistory[streamIdx].content+='\\n\\n';
|
|
547
582
|
renderMessages();
|
|
583
|
+
// Update browser viewer with the screenshot
|
|
584
|
+
updateBrowserFrame(data.base64,data.format||'jpeg');
|
|
585
|
+
updateBrowserStatus('Screenshot captured');
|
|
586
|
+
}
|
|
587
|
+
if(currentEvent==='browser_frame'&&data.base64){
|
|
588
|
+
// Live frame update (thumbnail from browser during operations)
|
|
589
|
+
updateBrowserFrame(data.base64,data.format||'jpeg');
|
|
590
|
+
if(data.url)updateBrowserStatus(data.url);
|
|
548
591
|
}
|
|
549
592
|
if(currentEvent==='tool_synthesis'){chatHistory[streamIdx].content='';renderMessages();}
|
|
550
593
|
if(currentEvent==='done'){endStreaming();if(data.content)chatHistory[streamIdx].content=data.content;var ss=chatHistory[streamIdx]._screenshots;if(ss&&ss.length>0){for(var si=0;si<ss.length;si++){chatHistory[streamIdx].content+='\\n\\n';}}renderMessages();loadConvList();}
|
|
@@ -1837,6 +1880,18 @@ init();
|
|
|
1837
1880
|
<button onclick="openSidebar()" style="position:fixed;top:8px;left:8px;z-index:100;background:var(--bg2);border:1px solid var(--border);border-radius:var(--r);color:var(--green);font-size:20px;padding:4px 10px;cursor:pointer;line-height:1" id="mobileBurger">☰</button>
|
|
1838
1881
|
|
|
1839
1882
|
<div class="content" id="content"></div>
|
|
1883
|
+
|
|
1884
|
+
<div class="browser-viewer" id="browserViewer">
|
|
1885
|
+
<div class="browser-viewer__header">
|
|
1886
|
+
<span class="browser-viewer__dot"></span>
|
|
1887
|
+
<span class="browser-viewer__title" id="bvTitle">Browser</span>
|
|
1888
|
+
<button class="browser-viewer__close" onclick="closeBrowserViewer()">×</button>
|
|
1889
|
+
</div>
|
|
1890
|
+
<div class="browser-viewer__frame" id="bvFrame">
|
|
1891
|
+
<span style="color:var(--dim);font-size:11px">Waiting...</span>
|
|
1892
|
+
</div>
|
|
1893
|
+
<div class="browser-viewer__status" id="bvStatus">Idle</div>
|
|
1894
|
+
</div>
|
|
1840
1895
|
</div>
|
|
1841
1896
|
|
|
1842
1897
|
<div class="modal-overlay" id="agentModal">
|