nothumanallowed 12.1.3 → 12.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "12.1.3",
3
+ "version": "12.2.0",
4
4
  "description": "NotHumanAllowed — 38 AI agents, 80 tools. 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": {
@@ -1904,8 +1904,44 @@ export async function cmdUI(args) {
1904
1904
  toolResults.push({ action, result: resultStr });
1905
1905
  sendSSE('tool', { action, status: 'done', result: typeof resultStr === 'string' ? resultStr.slice(0, 500) : '' });
1906
1906
 
1907
+ // After web_search: open first result in browser + send canvas with results
1908
+ if (action === 'web_search' && resultStr.length > 50) {
1909
+ try {
1910
+ // Extract first URL from results
1911
+ const urlMatch = resultStr.match(/https?:\/\/[^\s)<]+/);
1912
+ if (urlMatch) {
1913
+ const be = await import('../services/browser-engine.mjs');
1914
+ sendSSE('tool', { action: 'browser_open', status: 'executing' });
1915
+ await be.browserOpen(urlMatch[0]);
1916
+ sendSSE('tool', { action: 'browser_open', status: 'done', result: 'Opened ' + urlMatch[0] });
1917
+ // Capture frame for monitor
1918
+ await new Promise(r => setTimeout(r, 1500));
1919
+ const frame = await be.browserScreenshot({ fullPage: false, format: 'jpeg', quality: 40 });
1920
+ if (!frame.error) {
1921
+ const info = await be.browserInfo();
1922
+ const thumbDir = path.join(NHA_DIR, 'screenshots');
1923
+ fs.mkdirSync(thumbDir, { recursive: true });
1924
+ const thumbFile = `thumb-${Date.now()}.jpg`;
1925
+ fs.writeFileSync(path.join(thumbDir, thumbFile), Buffer.from(frame.base64, 'base64'));
1926
+ if (!res._browserThumbs) res._browserThumbs = [];
1927
+ res._browserThumbs.push({ file: thumbFile, url: (info.url || '').slice(0, 80) });
1928
+ sendSSE('browser_frame', { file: thumbFile, format: 'jpeg', url: (info.url || '').slice(0, 80) });
1929
+ }
1930
+ }
1931
+
1932
+ // Send canvas with structured search results
1933
+ const lines = resultStr.split('\n').filter(l => l.trim());
1934
+ const canvasHtml = `<html><head><meta charset="utf-8"><style>body{font-family:system-ui;background:#0a0a0a;color:#ccc;padding:20px;margin:0}h2{color:#00ff41;font-size:16px;margin:0 0 16px}a{color:#00e5ff;text-decoration:none}.r{padding:12px;border:1px solid #222;border-radius:8px;margin-bottom:8px;background:#111}.r:hover{border-color:#00ff41}.t{font-size:14px;margin-bottom:4px}.s{font-size:11px;color:#666}</style></head><body><h2>🔍 Search Results</h2>${lines.slice(0, 8).map(l => {
1935
+ const um = l.match(/https?:\/\/[^\s)]+/);
1936
+ const title = l.replace(/^\d+\.\s*/, '').replace(/https?:\/\/\S+/g, '').trim();
1937
+ return '<div class="r">' + (um ? '<a href="' + um[0] + '" target="_blank">' : '') + '<div class="t">' + title.replace(/</g, '&lt;') + '</div>' + (um ? '<div class="s">' + um[0] + '</div></a>' : '') + '</div>';
1938
+ }).join('')}</body></html>`;
1939
+ sendSSE('canvas', { markers: `[CANVAS_RENDER]${JSON.stringify({ html: canvasHtml, title: 'Search Results' })}[/CANVAS_RENDER]` });
1940
+ } catch { /* non-critical: search results still shown as text */ }
1941
+ }
1942
+
1907
1943
  // Send live browser frame after browser/search/fetch actions — save as thumbnail file for persistence
1908
- if ((action.startsWith('browser_') && action !== 'browser_close') || action === 'web_search' || action === 'fetch_url') {
1944
+ if ((action.startsWith('browser_') && action !== 'browser_close') || action === 'fetch_url') {
1909
1945
  try {
1910
1946
  const be = await import('../services/browser-engine.mjs');
1911
1947
  if (be.isBrowserRunning()) {
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 = '12.1.3';
8
+ export const VERSION = '12.2.0';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11