nothumanallowed 9.8.8 → 9.9.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 +13 -4
- package/src/constants.mjs +1 -1
- package/src/services/web-ui.mjs +38 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.9.0",
|
|
4
4
|
"description": "NotHumanAllowed — 38 AI agents, 53 tools. Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, GitHub, Notion, Slack, voice chat, 28 languages. Zero-dependency CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/commands/ui.mjs
CHANGED
|
@@ -1414,7 +1414,7 @@ export async function cmdUI(args) {
|
|
|
1414
1414
|
toolResults.push({ action, result: resultStr });
|
|
1415
1415
|
sendSSE('tool', { action, status: 'done', result: typeof resultStr === 'string' ? resultStr.slice(0, 500) : '' });
|
|
1416
1416
|
|
|
1417
|
-
// Send live browser frame after browser actions
|
|
1417
|
+
// Send live browser frame after browser actions — save as thumbnail file for persistence
|
|
1418
1418
|
if (action.startsWith('browser_') && action !== 'browser_close') {
|
|
1419
1419
|
try {
|
|
1420
1420
|
const be = await import('../services/browser-engine.mjs');
|
|
@@ -1422,7 +1422,15 @@ export async function cmdUI(args) {
|
|
|
1422
1422
|
const frame = await be.browserScreenshot({ fullPage: false, format: 'jpeg', quality: 30 });
|
|
1423
1423
|
if (!frame.error) {
|
|
1424
1424
|
const info = await be.browserInfo();
|
|
1425
|
-
|
|
1425
|
+
const pageUrl = (info.url || '').slice(0, 80);
|
|
1426
|
+
// Save thumbnail to disk for persistence
|
|
1427
|
+
const thumbDir = path.join(NHA_DIR, 'screenshots');
|
|
1428
|
+
fs.mkdirSync(thumbDir, { recursive: true });
|
|
1429
|
+
const thumbFile = `thumb-${Date.now()}.jpg`;
|
|
1430
|
+
fs.writeFileSync(path.join(thumbDir, thumbFile), Buffer.from(frame.base64, 'base64'));
|
|
1431
|
+
if (!res._browserThumbs) res._browserThumbs = [];
|
|
1432
|
+
res._browserThumbs.push({ file: thumbFile, url: pageUrl });
|
|
1433
|
+
sendSSE('browser_frame', { file: thumbFile, format: 'jpeg', url: pageUrl });
|
|
1426
1434
|
}
|
|
1427
1435
|
}
|
|
1428
1436
|
} catch { /* frame capture failed, non-critical */ }
|
|
@@ -1442,7 +1450,7 @@ export async function cmdUI(args) {
|
|
|
1442
1450
|
const ssBase64 = fs.readFileSync(ssPath).toString('base64');
|
|
1443
1451
|
console.log(` [screenshot] sending SSE, base64 size: ${ssBase64.length}`);
|
|
1444
1452
|
sendSSE('screenshot', { base64: ssBase64, format: 'jpeg', filename: ssFilename });
|
|
1445
|
-
sendSSE('browser_frame', {
|
|
1453
|
+
sendSSE('browser_frame', { file: ssFilename, format: 'jpeg', url: 'Search results' });
|
|
1446
1454
|
if (!res._screenshotFiles) res._screenshotFiles = [];
|
|
1447
1455
|
res._screenshotFiles.push(ssFilename);
|
|
1448
1456
|
}
|
|
@@ -1512,7 +1520,8 @@ export async function cmdUI(args) {
|
|
|
1512
1520
|
try { extractMemory('chat', msg, finalResponse); } catch {}
|
|
1513
1521
|
|
|
1514
1522
|
const ssFiles = res._screenshotFiles || [];
|
|
1515
|
-
|
|
1523
|
+
const browserThumbs = res._browserThumbs || [];
|
|
1524
|
+
sendSSE('done', { content: finalResponse, screenshotFiles: ssFiles, browserThumbs });
|
|
1516
1525
|
} catch (e) {
|
|
1517
1526
|
sendSSE('error', { message: e.message });
|
|
1518
1527
|
}
|
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.9.0';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -252,16 +252,24 @@ function stopChat(){
|
|
|
252
252
|
|
|
253
253
|
// ---- BROWSER VIEWER (live preview of headless Chrome) ----
|
|
254
254
|
function showBrowserViewer(title,status){
|
|
255
|
-
|
|
256
|
-
v.classList.add('browser-viewer--open');
|
|
255
|
+
// Update old monitor viewer
|
|
256
|
+
var v=document.getElementById('browserViewer');if(v)v.classList.add('browser-viewer--open');
|
|
257
257
|
var t=document.getElementById('bvTitle');if(t)t.textContent=title||'Browser';
|
|
258
258
|
var s=document.getElementById('bvStatus');if(s)s.textContent=status||'Loading...';
|
|
259
|
+
// Also auto-open canvas panel in browser tab
|
|
260
|
+
var p=document.getElementById('canvasPanel');
|
|
261
|
+
if(p&&!p.classList.contains('open')){canvasMode='browser';renderCanvasPanel();}
|
|
259
262
|
}
|
|
260
|
-
function updateBrowserFrame(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
+
function updateBrowserFrame(data){
|
|
264
|
+
// data = {base64?, file?, format, url}
|
|
265
|
+
var imgSrc=data.file?API+'/api/screenshots/'+data.file:'data:image/'+(data.format||'jpeg')+';base64,'+data.base64;
|
|
266
|
+
// Update old monitor viewer
|
|
267
|
+
var f=document.getElementById('bvFrame');if(f)f.innerHTML='<img src="'+imgSrc+'" alt="Browser view">';
|
|
263
268
|
// Save to per-conversation browser history for canvas Browser tab
|
|
264
|
-
addBrowserPage(base64,url);
|
|
269
|
+
addBrowserPage(data.file||null,data.base64||null,data.url);
|
|
270
|
+
// Update canvas browser tab live if open
|
|
271
|
+
var p=document.getElementById('canvasPanel');
|
|
272
|
+
if(p&&p.classList.contains('open')&&canvasMode==='browser'){renderCanvasPanel();}
|
|
265
273
|
}
|
|
266
274
|
function updateBrowserStatus(status){
|
|
267
275
|
var s=document.getElementById('bvStatus');if(s)s.textContent=status;
|
|
@@ -409,7 +417,7 @@ function renderChat(el){
|
|
|
409
417
|
'</div>'+
|
|
410
418
|
'<div class="chat"><div class="chat__messages" id="chatMessages"></div>'+
|
|
411
419
|
'<div id="chatAttachInfo" style="display:none;padding:4px 12px;font-size:11px;color:var(--cyan);background:var(--bg2);border-top:1px solid var(--border)"><span id="chatAttachName"></span> <button onclick="clearChatAttach()" style="background:none;border:none;color:#f44;cursor:pointer;font-size:14px;font-weight:700">×</button></div>'+
|
|
412
|
-
'<div class="chat__bar"><button class="chat__mic" id="chatMic" onclick="toggleVoiceInput()" title="Voice input">🎤</button><button onclick="document.getElementById(\\x27chatFileInput\\x27).click()" style="background:none;border:none;cursor:pointer;font-size:16px;padding:4px" title="Attach file">📎</button><button onclick="document.getElementById(\\x27chatImageInput\\x27).click()" style="background:none;border:none;cursor:pointer;font-size:16px;padding:4px" title="Attach image">📷</button><input type="file" id="chatFileInput" style="display:none" onchange="handleChatFile(this)"><input type="file" id="chatImageInput" accept="image/*" style="display:none" onchange="handleChatImage(this)"><textarea class="chat__input" id="chatInput" placeholder="Ask anything... (or attach file/image first)" rows="1"></textarea><button class="chat__send" id="chatSend">Send</button><button class="chat__stop" id="chatStop" onclick="stopChat()">Stop</button><button onclick="reopenCanvas()" style="background:none;border:1px solid var(--border2);border-radius:6px;cursor:pointer;font-size:11px;padding:4px 8px;color:var(--dim);font-family:var(--mono);display:flex;align-items:center;gap:4px" title="Open Canvas / Browser panel"><span style="font-size:
|
|
420
|
+
'<div class="chat__bar"><button class="chat__mic" id="chatMic" onclick="toggleVoiceInput()" title="Voice input">🎤</button><button onclick="document.getElementById(\\x27chatFileInput\\x27).click()" style="background:none;border:none;cursor:pointer;font-size:16px;padding:4px" title="Attach file">📎</button><button onclick="document.getElementById(\\x27chatImageInput\\x27).click()" style="background:none;border:none;cursor:pointer;font-size:16px;padding:4px" title="Attach image">📷</button><input type="file" id="chatFileInput" style="display:none" onchange="handleChatFile(this)"><input type="file" id="chatImageInput" accept="image/*" style="display:none" onchange="handleChatImage(this)"><textarea class="chat__input" id="chatInput" placeholder="Ask anything... (or attach file/image first)" rows="1"></textarea><button class="chat__send" id="chatSend">Send</button><button class="chat__stop" id="chatStop" onclick="stopChat()">Stop</button><button onclick="reopenCanvas()" style="background:none;border:1px solid var(--border2);border-radius:6px;cursor:pointer;font-size:11px;padding:4px 8px;color:var(--dim);font-family:var(--mono);display:flex;align-items:center;gap:4px" title="Open Canvas / Browser panel"><span style="font-size:13px">▣</span>Panel</button></div>'+
|
|
413
421
|
'</div>'+
|
|
414
422
|
'</div>'+
|
|
415
423
|
'</div>';
|
|
@@ -545,29 +553,33 @@ function showCanvas(html,title){
|
|
|
545
553
|
saveCanvasData();
|
|
546
554
|
}
|
|
547
555
|
|
|
548
|
-
function addBrowserPage(base64,url){
|
|
556
|
+
function addBrowserPage(file,base64,url){
|
|
549
557
|
var d=getConvCanvasData();
|
|
550
558
|
var cleanUrl=(url||'Browser').replace(/^https?:\\/\\//, '').slice(0,60);
|
|
551
559
|
// Only add if URL is different from the last entry (avoid frame duplicates)
|
|
552
560
|
if(d.browsers.length>0&&d.browsers[d.browsers.length-1].url===cleanUrl){
|
|
553
|
-
// Update the thumbnail
|
|
554
|
-
d.browsers[d.browsers.length-1].
|
|
561
|
+
// Update the thumbnail file ref
|
|
562
|
+
if(file)d.browsers[d.browsers.length-1].file=file;
|
|
563
|
+
if(base64)d.browsers[d.browsers.length-1].base64=base64;
|
|
555
564
|
return;
|
|
556
565
|
}
|
|
557
|
-
d.browsers.push({base64:base64,url:cleanUrl,ts:new Date().toLocaleTimeString()});
|
|
566
|
+
d.browsers.push({file:file,base64:base64,url:cleanUrl,ts:new Date().toLocaleTimeString()});
|
|
558
567
|
browserIdx=d.browsers.length-1;
|
|
559
|
-
//
|
|
560
|
-
|
|
561
|
-
if(p&&p.classList.contains('open')&&canvasMode==='browser'){renderCanvasPanel();}
|
|
568
|
+
// Persist file refs to localStorage (not base64)
|
|
569
|
+
saveCanvasData();
|
|
562
570
|
}
|
|
563
571
|
|
|
564
572
|
function saveCanvasData(){
|
|
565
|
-
// Save only canvas HTML (not browser base64 — too large) per conversation
|
|
566
573
|
try{
|
|
567
574
|
var save={};
|
|
568
575
|
for(var id in allCanvasData){
|
|
569
|
-
|
|
570
|
-
|
|
576
|
+
var d=allCanvasData[id];
|
|
577
|
+
if(d.canvases.length>0||d.browsers.length>0){
|
|
578
|
+
save[id]={
|
|
579
|
+
canvases:d.canvases.slice(-20),
|
|
580
|
+
// Save browser entries with file refs only (no base64)
|
|
581
|
+
browsers:d.browsers.slice(-30).map(function(b){return {file:b.file,url:b.url,ts:b.ts};})
|
|
582
|
+
};
|
|
571
583
|
}
|
|
572
584
|
}
|
|
573
585
|
localStorage.setItem('nha_canvas_data',JSON.stringify(save));
|
|
@@ -582,6 +594,7 @@ function loadCanvasData(){
|
|
|
582
594
|
for(var id in parsed){
|
|
583
595
|
if(!allCanvasData[id])allCanvasData[id]={canvases:[],browsers:[]};
|
|
584
596
|
allCanvasData[id].canvases=parsed[id].canvases||[];
|
|
597
|
+
allCanvasData[id].browsers=parsed[id].browsers||[];
|
|
585
598
|
}
|
|
586
599
|
}
|
|
587
600
|
}catch(e){}
|
|
@@ -620,11 +633,12 @@ function renderCanvasPanel(){
|
|
|
620
633
|
if(d.browsers.length===0){
|
|
621
634
|
doc.open();doc.write('<html><body style="margin:0;background:#111;display:flex;align-items:center;justify-content:center;height:100vh;font-family:monospace;color:#555"><div style="text-align:center"><div style="font-size:48px;margin-bottom:12px">🌐</div><div>No pages visited</div><div style="font-size:11px;margin-top:8px;color:#333">in this conversation</div></div></body></html>');doc.close();
|
|
622
635
|
} else {
|
|
623
|
-
var
|
|
636
|
+
var apiBase=window.API||'';
|
|
637
|
+
var gallery='<html><head><style>*{margin:0;padding:0;box-sizing:border-box}body{background:#111;padding:12px;font-family:monospace}h3{color:#00ff41;font-size:12px;margin-bottom:12px}.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}.card{background:#1a1a1a;border:1px solid #333;border-radius:8px;overflow:hidden;cursor:pointer;transition:border-color .2s}.card:hover{border-color:#00ff41}.card img{width:100%;height:120px;object-fit:cover;display:block;background:#222}.card .info{padding:6px 8px}.card .url{color:#8ab4f8;font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card .time{color:#555;font-size:9px;margin-top:2px}</style></head><body><h3>Pages visited ('+d.browsers.length+')</h3><div class="grid">';
|
|
624
638
|
for(var bi=0;bi<d.browsers.length;bi++){
|
|
625
639
|
var b=d.browsers[bi];
|
|
626
|
-
var
|
|
627
|
-
gallery+='<div class="card
|
|
640
|
+
var imgSrc=b.file?apiBase+'/api/screenshots/'+b.file:(b.base64?'data:image/jpeg;base64,'+b.base64:'');
|
|
641
|
+
gallery+='<div class="card" onclick="parent.selectBrowserPage('+bi+')">'+(imgSrc?'<img src="'+imgSrc+'" alt="'+b.url+'"/>':'<div style="height:120px;display:flex;align-items:center;justify-content:center;color:#555">No preview</div>')+'<div class="info"><div class="url">'+b.url+'</div><div class="time">'+(b.ts||'')+'</div></div></div>';
|
|
628
642
|
}
|
|
629
643
|
gallery+='</div></body></html>';
|
|
630
644
|
doc.open();doc.write(gallery);doc.close();
|
|
@@ -779,12 +793,12 @@ function sendChat(){
|
|
|
779
793
|
}
|
|
780
794
|
if(currentEvent==='screenshot'&&data.base64){
|
|
781
795
|
showBrowserViewer('Screenshot','Captured');
|
|
782
|
-
updateBrowserFrame(data.base64,data.format||'jpeg','Screenshot');
|
|
796
|
+
updateBrowserFrame({base64:data.base64,format:data.format||'jpeg',url:'Screenshot'});
|
|
783
797
|
updateBrowserStatus('Screenshot captured');
|
|
784
798
|
}
|
|
785
|
-
if(currentEvent==='browser_frame'&&data.base64){
|
|
799
|
+
if(currentEvent==='browser_frame'&&(data.base64||data.file)){
|
|
786
800
|
showBrowserViewer(data.url||'Browser','Live');
|
|
787
|
-
updateBrowserFrame(data
|
|
801
|
+
updateBrowserFrame(data);
|
|
788
802
|
if(data.url)updateBrowserStatus(data.url);
|
|
789
803
|
}
|
|
790
804
|
if(currentEvent==='canvas'&&data.markers){
|
|
@@ -794,7 +808,7 @@ function sendChat(){
|
|
|
794
808
|
if(data.markers.indexOf('[CANVAS_CLEAR]')!==-1)closeCanvas();
|
|
795
809
|
}
|
|
796
810
|
if(currentEvent==='tool_synthesis'){chatHistory[streamIdx].content='';renderMessages();}
|
|
797
|
-
if(currentEvent==='done'){endStreaming();if(data.content)chatHistory[streamIdx].content=data.content;var ssf=data.screenshotFiles||[];for(var fi=0;fi<ssf.length;fi++){chatHistory[streamIdx].content+='\\n\\n';}renderMessages();loadConvList();if(ssf.length>0)setTimeout(closeBrowserViewer,5000);}
|
|
811
|
+
if(currentEvent==='done'){endStreaming();if(data.content)chatHistory[streamIdx].content=data.content;var ssf=data.screenshotFiles||[];for(var fi=0;fi<ssf.length;fi++){chatHistory[streamIdx].content+='\\n\\n';}var bt=data.browserThumbs||[];if(bt.length>0){var cd=getConvCanvasData();for(var bti=0;bti<bt.length;bti++){var exists=cd.browsers.some(function(b){return b.file===bt[bti].file;});if(!exists)cd.browsers.push({file:bt[bti].file,url:bt[bti].url,ts:new Date().toLocaleTimeString()});}browserIdx=cd.browsers.length-1;saveCanvasData();}renderMessages();loadConvList();if(ssf.length>0)setTimeout(closeBrowserViewer,5000);}
|
|
798
812
|
if(currentEvent==='error'){endStreaming();chatHistory[streamIdx].content='Error: '+(data.message||'Unknown');renderMessages();}
|
|
799
813
|
}catch(e){}
|
|
800
814
|
}
|