nothumanallowed 9.8.5 → 9.8.7

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": "9.8.5",
3
+ "version": "9.8.7",
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/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.5';
8
+ export const VERSION = '9.8.7';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -257,11 +257,11 @@ function showBrowserViewer(title,status){
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
259
  }
260
- function updateBrowserFrame(base64,format){
260
+ function updateBrowserFrame(base64,format,url){
261
261
  var f=document.getElementById('bvFrame');if(!f)return;
262
262
  f.innerHTML='<img src="data:image/'+(format||'jpeg')+';base64,'+base64+'" alt="Browser view">';
263
- // Also save to canvas browser tab
264
- lastBrowserFrame=base64;
263
+ // Save to per-conversation browser history for canvas Browser tab
264
+ addBrowserPage(base64,url);
265
265
  }
266
266
  function updateBrowserStatus(status){
267
267
  var s=document.getElementById('bvStatus');if(s)s.textContent=status;
@@ -271,7 +271,7 @@ function closeBrowserViewer(){
271
271
  }
272
272
 
273
273
  function loadConvList(){return apiGet('/api/conversations').then(function(r){convList=(r&&r.conversations)||[];renderConvSidebar();})}
274
- 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();}})}
274
+ 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();onConversationSwitch();}})}
275
275
  function createNewConv(){return apiPost('/api/conversations',{}).then(function(r){if(r&&r.conversation){activeConvId=r.conversation.id;chatHistory=[];renderMessages();loadConvList();}})}
276
276
  function deleteConv(id){return fetch(API+'/api/conversations/'+id,{method:'DELETE'}).then(function(){loadConvList();if(id===activeConvId)createNewConv();})}
277
277
  function clearChatHistory(){createNewConv()}
@@ -409,7 +409,7 @@ function renderChat(el){
409
409
  '</div>'+
410
410
  '<div class="chat"><div class="chat__messages" id="chatMessages"></div>'+
411
411
  '<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">&times;</button></div>'+
412
- '<div class="chat__bar"><button class="chat__mic" id="chatMic" onclick="toggleVoiceInput()" title="Voice input">&#127908;</button><button onclick="document.getElementById(\\x27chatFileInput\\x27).click()" style="background:none;border:none;cursor:pointer;font-size:16px;padding:4px" title="Attach file">&#128206;</button><button onclick="document.getElementById(\\x27chatImageInput\\x27).click()" style="background:none;border:none;cursor:pointer;font-size:16px;padding:4px" title="Attach image">&#128247;</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:none;cursor:pointer;font-size:14px;padding:4px;color:var(--dim)" title="Open Canvas panel">&#x25A3;</button></div>'+
412
+ '<div class="chat__bar"><button class="chat__mic" id="chatMic" onclick="toggleVoiceInput()" title="Voice input">&#127908;</button><button onclick="document.getElementById(\\x27chatFileInput\\x27).click()" style="background:none;border:none;cursor:pointer;font-size:16px;padding:4px" title="Attach file">&#128206;</button><button onclick="document.getElementById(\\x27chatImageInput\\x27).click()" style="background:none;border:none;cursor:pointer;font-size:16px;padding:4px" title="Attach image">&#128247;</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:14px">&#x25A3;</span>Canvas</button></div>'+
413
413
  '</div>'+
414
414
  '</div>'+
415
415
  '</div>';
@@ -524,68 +524,152 @@ function clearChatAttach(){
524
524
  document.getElementById('chatImageInput').value='';
525
525
  }
526
526
 
527
- // ---- CANVAS (with history + browser viewer) ----
528
- var canvasHistory=[]; // [{html,title,timestamp}]
529
- var canvasIdx=-1; // current index in history
530
- var canvasMode='canvas'; // 'canvas' or 'browser'
531
- var lastBrowserFrame=null;
527
+ // ---- CANVAS + BROWSER (per-conversation history) ----
528
+ var allCanvasData={}; // {convId: {canvases:[{html,title,ts}], browsers:[{base64,url,ts}]}}
529
+ var canvasIdx=-1;
530
+ var browserIdx=-1;
531
+ var canvasMode='canvas';
532
+
533
+ function getConvCanvasData(){
534
+ var id=activeConvId||'_default';
535
+ if(!allCanvasData[id])allCanvasData[id]={canvases:[],browsers:[]};
536
+ return allCanvasData[id];
537
+ }
532
538
 
533
539
  function showCanvas(html,title){
534
- // Save to history
535
- canvasHistory.push({html:html,title:title||'Canvas',timestamp:new Date().toLocaleTimeString()});
536
- canvasIdx=canvasHistory.length-1;
540
+ var d=getConvCanvasData();
541
+ d.canvases.push({html:html,title:title||'Canvas',ts:new Date().toLocaleTimeString()});
542
+ canvasIdx=d.canvases.length-1;
537
543
  canvasMode='canvas';
538
544
  renderCanvasPanel();
539
- // Persist canvas history to localStorage
540
- try{localStorage.setItem('nha_canvas_history',JSON.stringify(canvasHistory.slice(-20)));}catch(e){}
545
+ saveCanvasData();
546
+ }
547
+
548
+ function addBrowserPage(base64,url){
549
+ var d=getConvCanvasData();
550
+ var cleanUrl=(url||'Browser').replace(/^https?:\\/\\//, '').slice(0,60);
551
+ // Only add if URL is different from the last entry (avoid frame duplicates)
552
+ if(d.browsers.length>0&&d.browsers[d.browsers.length-1].url===cleanUrl){
553
+ // Update the thumbnail with the latest frame
554
+ d.browsers[d.browsers.length-1].base64=base64;
555
+ return;
556
+ }
557
+ d.browsers.push({base64:base64,url:cleanUrl,ts:new Date().toLocaleTimeString()});
558
+ browserIdx=d.browsers.length-1;
559
+ // Auto-update canvas panel if browser tab is open
560
+ var p=document.getElementById('canvasPanel');
561
+ if(p&&p.classList.contains('open')&&canvasMode==='browser'){renderCanvasPanel();}
541
562
  }
542
563
 
564
+ function saveCanvasData(){
565
+ // Save only canvas HTML (not browser base64 — too large) per conversation
566
+ try{
567
+ var save={};
568
+ for(var id in allCanvasData){
569
+ if(allCanvasData[id].canvases.length>0){
570
+ save[id]={canvases:allCanvasData[id].canvases.slice(-20)};
571
+ }
572
+ }
573
+ localStorage.setItem('nha_canvas_data',JSON.stringify(save));
574
+ }catch(e){}
575
+ }
576
+
577
+ function loadCanvasData(){
578
+ try{
579
+ var saved=localStorage.getItem('nha_canvas_data');
580
+ if(saved){
581
+ var parsed=JSON.parse(saved);
582
+ for(var id in parsed){
583
+ if(!allCanvasData[id])allCanvasData[id]={canvases:[],browsers:[]};
584
+ allCanvasData[id].canvases=parsed[id].canvases||[];
585
+ }
586
+ }
587
+ }catch(e){}
588
+ }
589
+ loadCanvasData();
590
+
543
591
  function renderCanvasPanel(){
544
592
  var p=document.getElementById('canvasPanel');
545
593
  if(!p)return;
546
594
  p.classList.add('open');
547
- var item=canvasMode==='browser'?null:canvasHistory[canvasIdx];
548
- // Update header
595
+ var d=getConvCanvasData();
596
+ var list=canvasMode==='browser'?d.browsers:d.canvases;
597
+ var idx=canvasMode==='browser'?browserIdx:canvasIdx;
598
+ var item=list[idx];
599
+ // Header title
549
600
  var t=document.getElementById('canvasTitle');
550
601
  if(t){
551
- if(canvasMode==='browser'){t.textContent='Browser';}
552
- else if(item){t.textContent=item.title+(canvasHistory.length>1?' ('+(canvasIdx+1)+'/'+canvasHistory.length+')':'');}
553
- else{t.textContent='Canvas';}
602
+ if(canvasMode==='browser'){t.textContent=d.browsers.length>0?d.browsers.length+' pages visited':'No pages visited';}
603
+ else if(!item){t.textContent='Empty canvas';}
604
+ else{t.textContent=(item.title||'Canvas')+(d.canvases.length>1?' ('+(canvasIdx+1)+'/'+d.canvases.length+')':'');}
554
605
  }
555
- // Update nav buttons visibility
606
+ // Nav arrows only for canvas mode (browser uses gallery grid)
556
607
  var navEl=document.getElementById('canvasNav');
557
- if(navEl){navEl.style.display=canvasHistory.length>1&&canvasMode==='canvas'?'flex':'none';}
558
- // Update tab buttons
608
+ if(navEl){navEl.style.display=d.canvases.length>1&&canvasMode==='canvas'?'flex':'none';}
609
+ // Tab highlight
559
610
  var tabC=document.getElementById('canvasTabC');
560
611
  var tabB=document.getElementById('canvasTabB');
561
612
  if(tabC)tabC.style.borderBottom=canvasMode==='canvas'?'2px solid var(--green)':'none';
562
613
  if(tabB)tabB.style.borderBottom=canvasMode==='browser'?'2px solid var(--green)':'none';
563
- // Render content
564
- var f=document.getElementById('canvasFrame');
565
- if(!f)return;
566
- if(canvasMode==='browser'&&lastBrowserFrame){
567
- var doc=f.contentDocument||f.contentWindow.document;
568
- doc.open();doc.write('<html><body style="margin:0;background:#1a1a1a;display:flex;align-items:center;justify-content:center;height:100vh"><img src="data:image/jpeg;base64,'+lastBrowserFrame+'" style="max-width:100%;max-height:100%"/></body></html>');doc.close();
569
- } else if(item){
570
- var doc=f.contentDocument||f.contentWindow.document;
614
+ // Render iframe content
615
+ var f=document.getElementById('canvasFrame');if(!f)return;
616
+ var doc=f.contentDocument||f.contentWindow.document;
617
+ if(canvasMode==='browser'){
618
+ // Browser tab: gallery of visited page thumbnails
619
+ var d=getConvCanvasData();
620
+ if(d.browsers.length===0){
621
+ 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">&#x1F310;</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
+ } else {
623
+ 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}.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}.selected{border-color:#00ff41;box-shadow:0 0 10px rgba(0,255,65,0.2)}</style></head><body><h3>Pages visited ('+d.browsers.length+')</h3><div class="grid">';
624
+ for(var bi=0;bi<d.browsers.length;bi++){
625
+ var b=d.browsers[bi];
626
+ var sel=bi===browserIdx?' selected':'';
627
+ gallery+='<div class="card'+sel+'" onclick="parent.selectBrowserPage('+bi+')"><img src="data:image/jpeg;base64,'+b.base64+'" alt="'+b.url+'"/><div class="info"><div class="url">'+b.url+'</div><div class="time">'+b.ts+'</div></div></div>';
628
+ }
629
+ gallery+='</div></body></html>';
630
+ doc.open();doc.write(gallery);doc.close();
631
+ }
632
+ } else if(!item){
633
+ 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">&#x25A3;</div><div>No canvas content</div><div style="font-size:11px;margin-top:8px;color:#333">in this conversation</div></div></body></html>');doc.close();
634
+ } else {
571
635
  doc.open();doc.write(item.html);doc.close();
572
636
  }
573
637
  }
574
638
 
575
- function canvasPrev(){if(canvasIdx>0){canvasIdx--;canvasMode='canvas';renderCanvasPanel();}}
576
- function canvasNext(){if(canvasIdx<canvasHistory.length-1){canvasIdx++;canvasMode='canvas';renderCanvasPanel();}}
577
- function canvasShowBrowser(){canvasMode='browser';renderCanvasPanel();}
578
- function canvasShowCanvas(){canvasMode='canvas';renderCanvasPanel();}
639
+ function canvasPrev(){
640
+ var d=getConvCanvasData();
641
+ if(canvasMode==='browser'){if(browserIdx>0){browserIdx--;renderCanvasPanel();}}
642
+ else{if(canvasIdx>0){canvasIdx--;renderCanvasPanel();}}
643
+ }
644
+ function canvasNext(){
645
+ var d=getConvCanvasData();
646
+ if(canvasMode==='browser'){if(browserIdx<d.browsers.length-1){browserIdx++;renderCanvasPanel();}}
647
+ else{if(canvasIdx<d.canvases.length-1){canvasIdx++;renderCanvasPanel();}}
648
+ }
649
+ function selectBrowserPage(i){browserIdx=i;canvasMode='browser';renderCanvasPanel();}
650
+ function canvasShowBrowser(){var d=getConvCanvasData();browserIdx=d.browsers.length-1;canvasMode='browser';renderCanvasPanel();}
651
+ function canvasShowCanvas(){var d=getConvCanvasData();canvasIdx=d.canvases.length-1;canvasMode='canvas';renderCanvasPanel();}
579
652
 
580
- function reopenCanvas(){
581
- if(canvasHistory.length===0){
582
- // Try restore from localStorage
583
- try{var saved=localStorage.getItem('nha_canvas_history');if(saved){canvasHistory=JSON.parse(saved);canvasIdx=canvasHistory.length-1;}}catch(e){}
653
+ function onConversationSwitch(){
654
+ // Called when user switches conversation — update canvas panel
655
+ var p=document.getElementById('canvasPanel');
656
+ if(p&&p.classList.contains('open')){
657
+ var d=getConvCanvasData();
658
+ canvasIdx=d.canvases.length-1;
659
+ browserIdx=d.browsers.length-1;
660
+ renderCanvasPanel();
584
661
  }
585
- if(canvasHistory.length>0){canvasIdx=canvasHistory.length-1;canvasMode='canvas';renderCanvasPanel();}
586
- else if(lastBrowserFrame){canvasMode='browser';renderCanvasPanel();}
587
662
  }
588
663
 
664
+ function reopenCanvas(){
665
+ var d=getConvCanvasData();
666
+ canvasIdx=d.canvases.length-1;
667
+ browserIdx=d.browsers.length-1;
668
+ if(d.canvases.length>0){canvasMode='canvas';}
669
+ else if(d.browsers.length>0){canvasMode='browser';}
670
+ else{canvasMode='canvas';} // show empty state
671
+ renderCanvasPanel();
672
+ }
589
673
  function closeCanvas(){var p=document.getElementById('canvasPanel');if(p)p.classList.remove('open');}
590
674
  function toggleCanvasSize(){
591
675
  var p=document.getElementById('canvasPanel');if(!p)return;
@@ -694,15 +778,13 @@ function sendChat(){
694
778
  renderMessages();
695
779
  }
696
780
  if(currentEvent==='screenshot'&&data.base64){
697
- // Only update the browser viewer — the actual image in chat is handled by the 'done' event via screenshotFiles
698
781
  showBrowserViewer('Screenshot','Captured');
699
- updateBrowserFrame(data.base64,data.format||'jpeg');
782
+ updateBrowserFrame(data.base64,data.format||'jpeg','Screenshot');
700
783
  updateBrowserStatus('Screenshot captured');
701
784
  }
702
785
  if(currentEvent==='browser_frame'&&data.base64){
703
- // Live frame update — also ensure viewer is open
704
786
  showBrowserViewer(data.url||'Browser','Live');
705
- updateBrowserFrame(data.base64,data.format||'jpeg');
787
+ updateBrowserFrame(data.base64,data.format||'jpeg',data.url||'Browser');
706
788
  if(data.url)updateBrowserStatus(data.url);
707
789
  }
708
790
  if(currentEvent==='canvas'&&data.markers){