nothumanallowed 9.3.19 → 9.4.1
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 +29 -9
- package/src/constants.mjs +1 -1
- package/src/services/tool-executor.mjs +7 -1
- package/src/services/web-ui.mjs +57 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.4.1",
|
|
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
|
@@ -253,6 +253,13 @@ export async function cmdUI(args) {
|
|
|
253
253
|
return;
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
// GET /api/health — simple health check
|
|
257
|
+
if (method === 'GET' && pathname === '/api/health') {
|
|
258
|
+
sendJSON(res, 200, { ok: true, version: VERSION });
|
|
259
|
+
logRequest(method, pathname, 200, Date.now() - start);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
256
263
|
// GET /api/status
|
|
257
264
|
if (method === 'GET' && pathname === '/api/status') {
|
|
258
265
|
sendJSON(res, 200, {
|
|
@@ -1263,18 +1270,31 @@ export async function cmdUI(args) {
|
|
|
1263
1270
|
toolResults.push({ action, result: resultStr });
|
|
1264
1271
|
sendSSE('tool', { action, status: 'done', result: typeof resultStr === 'string' ? resultStr.slice(0, 500) : '' });
|
|
1265
1272
|
|
|
1266
|
-
//
|
|
1267
|
-
if (
|
|
1273
|
+
// Send live browser frame after browser actions (low-quality thumbnail for viewer)
|
|
1274
|
+
if (action.startsWith('browser_') && action !== 'browser_close') {
|
|
1268
1275
|
try {
|
|
1269
1276
|
const be = await import('../services/browser-engine.mjs');
|
|
1270
1277
|
if (be.isBrowserRunning()) {
|
|
1271
|
-
const
|
|
1272
|
-
if (!
|
|
1273
|
-
const
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
+
const frame = await be.browserScreenshot({ fullPage: false, format: 'jpeg', quality: 30 });
|
|
1279
|
+
if (!frame.error) {
|
|
1280
|
+
const info = await be.browserInfo();
|
|
1281
|
+
sendSSE('browser_frame', { base64: frame.base64, format: 'jpeg', url: (info.url || '').slice(0, 80) });
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
} catch { /* frame capture failed, non-critical */ }
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
// If the tool produced a screenshot (web_search with screenshot=true), send it via SSE
|
|
1288
|
+
if (resultStr.includes('[Screenshot of results captured')) {
|
|
1289
|
+
try {
|
|
1290
|
+
// Extract filename from result (tool-executor already saved it)
|
|
1291
|
+
const fileMatch = resultStr.match(/file:(ss-\d+\.jpg)/);
|
|
1292
|
+
if (fileMatch) {
|
|
1293
|
+
const ssFilename = fileMatch[1];
|
|
1294
|
+
const ssPath = path.join(NHA_DIR, 'screenshots', ssFilename);
|
|
1295
|
+
if (fs.existsSync(ssPath)) {
|
|
1296
|
+
const ssBase64 = fs.readFileSync(ssPath).toString('base64');
|
|
1297
|
+
sendSSE('screenshot', { base64: ssBase64, format: 'jpeg', filename: ssFilename });
|
|
1278
1298
|
if (!res._screenshotFiles) res._screenshotFiles = [];
|
|
1279
1299
|
res._screenshotFiles.push(ssFilename);
|
|
1280
1300
|
}
|
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.1';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -1337,7 +1337,13 @@ export async function executeTool(action, params, config) {
|
|
|
1337
1337
|
await new Promise(r => setTimeout(r, 300));
|
|
1338
1338
|
const ss = await be.browserScreenshot({ fullPage: false, format: 'jpeg', quality: 75 });
|
|
1339
1339
|
if (!ss.error) {
|
|
1340
|
-
|
|
1340
|
+
// Save to disk for persistence
|
|
1341
|
+
const ssDir = path.join(os.homedir(), '.nha', 'screenshots');
|
|
1342
|
+
const fsMod = await import('fs');
|
|
1343
|
+
fsMod.mkdirSync(ssDir, { recursive: true });
|
|
1344
|
+
const ssFilename = `ss-${Date.now()}.jpg`;
|
|
1345
|
+
fsMod.writeFileSync(path.join(ssDir, ssFilename), Buffer.from(ss.base64, 'base64'));
|
|
1346
|
+
return textResult + `\n\n[Screenshot of results captured (${Math.round(ss.size / 1024)}KB) file:${ssFilename}]`;
|
|
1341
1347
|
}
|
|
1342
1348
|
} catch { /* screenshot failed, return text only */ }
|
|
1343
1349
|
}
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -101,6 +101,19 @@ 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;top:12px;left:12px;width:440px;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:calc(100vw - 24px);top:8px;left:8px}}
|
|
116
|
+
@media(min-width:901px){.browser-viewer{left:232px}}
|
|
104
117
|
.chat__bar{display:flex;gap:8px;padding:10px 0 12px 0;border-top:1px solid var(--border);flex-shrink:0}
|
|
105
118
|
.chat__input{flex:1;resize:none;min-height:40px;max-height:100px;padding:10px 14px}
|
|
106
119
|
.chat__send{background:var(--green3);color:var(--bg);padding:10px 16px;border-radius:var(--r);font-weight:700;font-size:12px}
|
|
@@ -226,6 +239,24 @@ function stopChat(){
|
|
|
226
239
|
renderMessages();
|
|
227
240
|
}
|
|
228
241
|
|
|
242
|
+
// ---- BROWSER VIEWER (live preview of headless Chrome) ----
|
|
243
|
+
function showBrowserViewer(title,status){
|
|
244
|
+
var v=document.getElementById('browserViewer');if(!v)return;
|
|
245
|
+
v.classList.add('browser-viewer--open');
|
|
246
|
+
var t=document.getElementById('bvTitle');if(t)t.textContent=title||'Browser';
|
|
247
|
+
var s=document.getElementById('bvStatus');if(s)s.textContent=status||'Loading...';
|
|
248
|
+
}
|
|
249
|
+
function updateBrowserFrame(base64,format){
|
|
250
|
+
var f=document.getElementById('bvFrame');if(!f)return;
|
|
251
|
+
f.innerHTML='<img src="data:image/'+(format||'jpeg')+';base64,'+base64+'" alt="Browser view">';
|
|
252
|
+
}
|
|
253
|
+
function updateBrowserStatus(status){
|
|
254
|
+
var s=document.getElementById('bvStatus');if(s)s.textContent=status;
|
|
255
|
+
}
|
|
256
|
+
function closeBrowserViewer(){
|
|
257
|
+
var v=document.getElementById('browserViewer');if(v)v.classList.remove('browser-viewer--open');
|
|
258
|
+
}
|
|
259
|
+
|
|
229
260
|
function loadConvList(){return apiGet('/api/conversations').then(function(r){convList=(r&&r.conversations)||[];renderConvSidebar();})}
|
|
230
261
|
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
262
|
function createNewConv(){return apiPost('/api/conversations',{}).then(function(r){if(r&&r.conversation){activeConvId=r.conversation.id;chatHistory=[];renderMessages();loadConvList();}})}
|
|
@@ -533,6 +564,12 @@ function sendChat(){
|
|
|
533
564
|
var label=toolLabels[data.action]||data.action;
|
|
534
565
|
var indicator=data.status==='executing'?'\\u23f3 '+label+'...':'\\u2705 '+label;
|
|
535
566
|
if(data.status==='error')indicator='\\u274c '+label+' failed';
|
|
567
|
+
// Show browser viewer for browser actions
|
|
568
|
+
var isBrowserAction=data.action&&data.action.startsWith('browser_');
|
|
569
|
+
if(isBrowserAction&&data.status==='executing'){showBrowserViewer(label,'Executing...');}
|
|
570
|
+
if(isBrowserAction&&data.status==='done'){updateBrowserStatus('\\u2705 '+label);}
|
|
571
|
+
if(isBrowserAction&&data.status==='error'){updateBrowserStatus('\\u274c '+label);}
|
|
572
|
+
if(data.action==='browser_close'&&data.status==='done'){setTimeout(closeBrowserViewer,2000);}
|
|
536
573
|
// Strip JSON action blocks from streamed content (they are internal tool calls, not for the user)
|
|
537
574
|
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
575
|
chatHistory[streamIdx].content+=indicator+'\\n';
|
|
@@ -540,11 +577,18 @@ function sendChat(){
|
|
|
540
577
|
}
|
|
541
578
|
if(currentEvent==='screenshot'&&data.base64){
|
|
542
579
|
if(!chatHistory[streamIdx]._screenshots)chatHistory[streamIdx]._screenshots=[];
|
|
543
|
-
// Use file URL if available (persists across sessions), fall back to base64
|
|
544
580
|
var ssUrl=data.filename?'/api/screenshots/'+data.filename:'data:image/'+(data.format||'jpeg')+';base64,'+data.base64;
|
|
545
581
|
chatHistory[streamIdx]._screenshots.push(ssUrl);
|
|
546
582
|
chatHistory[streamIdx].content+='\\n\\n';
|
|
547
583
|
renderMessages();
|
|
584
|
+
// Update browser viewer with the screenshot
|
|
585
|
+
updateBrowserFrame(data.base64,data.format||'jpeg');
|
|
586
|
+
updateBrowserStatus('Screenshot captured');
|
|
587
|
+
}
|
|
588
|
+
if(currentEvent==='browser_frame'&&data.base64){
|
|
589
|
+
// Live frame update (thumbnail from browser during operations)
|
|
590
|
+
updateBrowserFrame(data.base64,data.format||'jpeg');
|
|
591
|
+
if(data.url)updateBrowserStatus(data.url);
|
|
548
592
|
}
|
|
549
593
|
if(currentEvent==='tool_synthesis'){chatHistory[streamIdx].content='';renderMessages();}
|
|
550
594
|
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 +1881,18 @@ init();
|
|
|
1837
1881
|
<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
1882
|
|
|
1839
1883
|
<div class="content" id="content"></div>
|
|
1884
|
+
|
|
1885
|
+
<div class="browser-viewer" id="browserViewer">
|
|
1886
|
+
<div class="browser-viewer__header">
|
|
1887
|
+
<span class="browser-viewer__dot"></span>
|
|
1888
|
+
<span class="browser-viewer__title" id="bvTitle">Browser</span>
|
|
1889
|
+
<button class="browser-viewer__close" onclick="closeBrowserViewer()">×</button>
|
|
1890
|
+
</div>
|
|
1891
|
+
<div class="browser-viewer__frame" id="bvFrame">
|
|
1892
|
+
<span style="color:var(--dim);font-size:11px">Waiting...</span>
|
|
1893
|
+
</div>
|
|
1894
|
+
<div class="browser-viewer__status" id="bvStatus">Idle</div>
|
|
1895
|
+
</div>
|
|
1840
1896
|
</div>
|
|
1841
1897
|
|
|
1842
1898
|
<div class="modal-overlay" id="agentModal">
|