nothumanallowed
Advanced tools
+1
-1
| { | ||
| "name": "nothumanallowed", | ||
| "version": "16.0.57", | ||
| "version": "16.0.58", | ||
| "description": "Local AI assistant: 80 tools (Gmail, Calendar, Drive, GitHub, Slack, browser, code, files), 38 agents, visual workflows (Studio, AWF, WebCraft). Install with `npm i -g nothumanallowed`, run with `nha ui`. Free tier built-in (Liara), no API key required. Your data stays on your PC — OAuth tokens local, no cloud. Open-source MIT.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -8,3 +8,3 @@ import os from 'os'; | ||
| export const VERSION = '16.0.57'; | ||
| export const VERSION = '16.0.58'; | ||
| export const BASE_URL = 'https://nothumanallowed.com/cli'; | ||
@@ -11,0 +11,0 @@ export const API_BASE = 'https://nothumanallowed.com/api/v1'; |
@@ -128,2 +128,6 @@ /** | ||
| '/usr/bin/microsoft-edge', | ||
| // Termux on Android — chromium installed via "pkg install chromium" | ||
| '/data/data/com.termux/files/usr/bin/chromium', | ||
| '/data/data/com.termux/files/usr/bin/chromium-browser', | ||
| '/data/data/com.termux/files/usr/bin/google-chrome', | ||
| ], | ||
@@ -661,2 +665,100 @@ win32: [ | ||
| */ | ||
| /** | ||
| * Lightweight HTTP fallback when Chrome/Chromium is not available. | ||
| * Uses fetch() + regex-based HTML→text extraction. No JS rendering, no clicks. | ||
| * Good enough for: news sites, blog posts, static pages, API responses, | ||
| * documentation pages. NOT good for: SPAs, login flows, dynamic dashboards. | ||
| */ | ||
| async function browserOpenViaFetch(url, options = {}) { | ||
| const timeout = options.timeout || 15000; | ||
| try { | ||
| const ac = new AbortController(); | ||
| const timer = setTimeout(() => ac.abort(), timeout); | ||
| const res = await fetch(url, { | ||
| redirect: 'follow', | ||
| signal: ac.signal, | ||
| headers: { | ||
| 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', | ||
| 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', | ||
| 'Accept-Language': 'en-US,en;q=0.9,it;q=0.8', | ||
| }, | ||
| }); | ||
| clearTimeout(timer); | ||
| const status = res.status; | ||
| const finalUrl = res.url || url; | ||
| const ct = res.headers.get('content-type') || ''; | ||
| const isHtml = /html/i.test(ct); | ||
| const raw = await res.text(); | ||
| if (!isHtml) { | ||
| return { | ||
| title: finalUrl, | ||
| url: finalUrl, | ||
| status, | ||
| mode: 'fetch-fallback', | ||
| warning: 'Chrome not installed — used HTTP fetch. No JS rendering. Limited interactivity.', | ||
| content: raw.slice(0, 50_000), | ||
| }; | ||
| } | ||
| // Extract title | ||
| const titleMatch = raw.match(/<title[^>]*>([\s\S]*?)<\/title>/i); | ||
| const title = titleMatch ? titleMatch[1].replace(/\s+/g, ' ').trim() : finalUrl; | ||
| // Extract main text content: strip script/style/svg/comments, then strip tags | ||
| let textContent = raw | ||
| .replace(/<!--[\s\S]*?-->/g, '') | ||
| .replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, ' ') | ||
| .replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, ' ') | ||
| .replace(/<svg\b[^>]*>[\s\S]*?<\/svg>/gi, ' ') | ||
| .replace(/<noscript\b[^>]*>[\s\S]*?<\/noscript>/gi, ' ') | ||
| .replace(/<header\b[^>]*>[\s\S]*?<\/header>/gi, ' ') // strip nav/header noise | ||
| .replace(/<nav\b[^>]*>[\s\S]*?<\/nav>/gi, ' ') | ||
| .replace(/<footer\b[^>]*>[\s\S]*?<\/footer>/gi, ' ') | ||
| .replace(/<aside\b[^>]*>[\s\S]*?<\/aside>/gi, ' '); | ||
| // Extract headlines + links separately for news sites | ||
| const headlines = []; | ||
| const linkRe = /<a\b[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi; | ||
| let lm; | ||
| while ((lm = linkRe.exec(raw)) !== null && headlines.length < 50) { | ||
| const linkText = lm[2].replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim(); | ||
| const href = lm[1]; | ||
| if (linkText.length > 20 && linkText.length < 200 && !href.startsWith('#') && !href.startsWith('javascript:')) { | ||
| const absHref = href.startsWith('http') ? href : new URL(href, finalUrl).toString(); | ||
| headlines.push({ text: linkText, url: absHref }); | ||
| } | ||
| } | ||
| // Strip remaining tags to get plain text | ||
| textContent = textContent | ||
| .replace(/<[^>]+>/g, ' ') | ||
| .replace(/ /g, ' ') | ||
| .replace(/&/g, '&') | ||
| .replace(/</g, '<') | ||
| .replace(/>/g, '>') | ||
| .replace(/"/g, '"') | ||
| .replace(/'/g, "'") | ||
| .replace(/&#x?[0-9a-f]+;/gi, '') | ||
| .replace(/\s+/g, ' ') | ||
| .trim(); | ||
| return { | ||
| title, | ||
| url: finalUrl, | ||
| status, | ||
| mode: 'fetch-fallback', | ||
| warning: 'Chrome/Chromium not installed — used HTTP fetch fallback. No JS rendering, no interactive clicks/forms. To install: macOS use brew, Linux apt-get, Termux "pkg install chromium".', | ||
| headlines: headlines.slice(0, 30), | ||
| content: textContent.slice(0, 30_000), | ||
| }; | ||
| } catch (e) { | ||
| if (e.name === 'AbortError') { | ||
| return { error: true, message: `HTTP fetch timeout after ${timeout / 1000}s. The site may be slow or blocking the request.` }; | ||
| } | ||
| return { error: true, message: `HTTP fetch failed: ${e.message}. ${/ENOTFOUND|ECONNREFUSED/.test(e.message) ? 'Network or DNS issue.' : ''}` }; | ||
| } | ||
| } | ||
| export async function browserOpen(url, options = {}) { | ||
@@ -669,3 +771,19 @@ // SSRF check | ||
| const browser = await getBrowser(); | ||
| // Fast fallback: if Chrome/Chromium is not installed (e.g. Termux on Android), | ||
| // do a plain HTTP fetch and extract text content. Limited (no JS rendering, | ||
| // no clicks), but works for news sites / blog posts / static pages. | ||
| if (!findChromePath()) { | ||
| return browserOpenViaFetch(url, options); | ||
| } | ||
| let browser; | ||
| try { | ||
| browser = await getBrowser(); | ||
| } catch (e) { | ||
| // Chrome detection failed at launch — same fallback | ||
| if (/Chrome\/Chromium not found/i.test(e.message || '')) { | ||
| return browserOpenViaFetch(url, options); | ||
| } | ||
| throw e; | ||
| } | ||
| const timeout = options.timeout || NAV_TIMEOUT_MS; | ||
@@ -672,0 +790,0 @@ const waitForLoad = options.waitForLoad !== false; |
@@ -15,4 +15,9 @@ /** | ||
| // NHA published OAuth client (Desktop app type — client_id is not a secret) | ||
| const DEFAULT_CLIENT_ID = '516893094132-8u2jf6h6h3j6h8j9k0l1m2n3o4p5q6r7.apps.googleusercontent.com'; // NHA Official OAuth Client | ||
| // IMPORTANT: NHA does NOT ship a default Google OAuth client ID. | ||
| // The previous placeholder (516893094132-8u2jf...) was a fake-looking value | ||
| // that always returned `invalid_client` from Google. Each user must register | ||
| // their own OAuth client in Google Cloud Console — this is by design for | ||
| // privacy (no shared client app), and it's a one-time 3-minute setup. | ||
| // See https://nothumanallowed.com/docs/google for the full guide. | ||
| const DEFAULT_CLIENT_ID = ''; | ||
| const SCOPES = [ | ||
@@ -225,10 +230,23 @@ 'https://www.googleapis.com/auth/gmail.modify', | ||
| fail('Google OAuth client ID not configured.'); | ||
| info('Get credentials from Google Cloud Console:'); | ||
| info(' 1. Go to https://console.cloud.google.com/apis/credentials'); | ||
| info(' 2. Create an OAuth 2.0 Client ID (Desktop app type)'); | ||
| info(' 3. Enable Gmail API and Calendar API'); | ||
| info(' 4. Run:'); | ||
| info(''); | ||
| info('NHA does not ship a shared OAuth client (your data never goes through'); | ||
| info('our servers — Gmail/Calendar API calls go from your PC directly to'); | ||
| info('Google). You need a 3-minute one-time setup of your own OAuth client.'); | ||
| info(''); | ||
| info('STEPS:'); | ||
| info(' 1. Open https://console.cloud.google.com/apis/credentials'); | ||
| info(' 2. Click + CREATE CREDENTIALS → OAuth client ID'); | ||
| info(' 3. Application type: "Desktop app", give it a name (e.g. "NHA local")'); | ||
| info(' 4. Click CREATE. Google shows you Client ID + Client Secret.'); | ||
| info(' 5. Enable the APIs you need:'); | ||
| info(' - Gmail API: https://console.cloud.google.com/apis/library/gmail.googleapis.com'); | ||
| info(' - Calendar: https://console.cloud.google.com/apis/library/calendar-json.googleapis.com'); | ||
| info(' - Drive: https://console.cloud.google.com/apis/library/drive.googleapis.com'); | ||
| info(' - People API: https://console.cloud.google.com/apis/library/people.googleapis.com'); | ||
| info(' 6. Save the credentials in NHA:'); | ||
| info(' nha config set google-client-id YOUR_CLIENT_ID'); | ||
| info(' nha config set google-client-secret YOUR_CLIENT_SECRET'); | ||
| info(' 5. Run: nha google auth'); | ||
| info(' 7. Re-run: nha google auth'); | ||
| info(''); | ||
| info('Full guide with screenshots: https://nothumanallowed.com/docs/google'); | ||
| return false; | ||
@@ -235,0 +253,0 @@ } |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 4 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 4 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
4343865
0.14%45541
0.28%203
0.5%