nothumanallowed 9.3.2 → 9.3.3
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.3.
|
|
3
|
+
"version": "9.3.3",
|
|
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/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.3.
|
|
8
|
+
export const VERSION = '9.3.3';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -532,12 +532,17 @@ async function launchBrowser() {
|
|
|
532
532
|
|
|
533
533
|
const port = await findFreePort();
|
|
534
534
|
|
|
535
|
+
// Realistic user agent to avoid bot detection on major sites
|
|
536
|
+
const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';
|
|
537
|
+
|
|
535
538
|
const chromeArgs = [
|
|
536
539
|
`--remote-debugging-port=${port}`,
|
|
537
540
|
'--headless=new',
|
|
538
541
|
`--user-data-dir=${userDataDir}`,
|
|
542
|
+
`--user-agent=${UA}`,
|
|
539
543
|
'--no-first-run',
|
|
540
544
|
'--no-default-browser-check',
|
|
545
|
+
'--disable-blink-features=AutomationControlled',
|
|
541
546
|
'--disable-background-networking',
|
|
542
547
|
'--disable-background-timer-throttling',
|
|
543
548
|
'--disable-backgrounding-occluded-windows',
|
|
@@ -603,6 +608,16 @@ async function launchBrowser() {
|
|
|
603
608
|
await ws.send('Network.enable');
|
|
604
609
|
await ws.send('DOM.enable');
|
|
605
610
|
|
|
611
|
+
// Anti-detection: remove navigator.webdriver flag and other headless indicators
|
|
612
|
+
await ws.send('Page.addScriptToEvaluateOnNewDocument', {
|
|
613
|
+
source: `
|
|
614
|
+
Object.defineProperty(navigator, 'webdriver', { get: () => false });
|
|
615
|
+
Object.defineProperty(navigator, 'languages', { get: () => ['it-IT', 'it', 'en-US', 'en'] });
|
|
616
|
+
Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] });
|
|
617
|
+
window.chrome = { runtime: {} };
|
|
618
|
+
`,
|
|
619
|
+
});
|
|
620
|
+
|
|
606
621
|
_browser = { process: proc, ws, wsUrl, userDataDir, port };
|
|
607
622
|
|
|
608
623
|
// Cleanup on process exit
|
|
@@ -756,10 +771,11 @@ export async function browserScreenshot(options = {}) {
|
|
|
756
771
|
}
|
|
757
772
|
|
|
758
773
|
/**
|
|
759
|
-
* Click an element by CSS selector or coordinates.
|
|
774
|
+
* Click an element by CSS selector, visible text, or coordinates.
|
|
760
775
|
*
|
|
761
776
|
* @param {object} target
|
|
762
777
|
* @param {string} [target.selector] - CSS selector to click
|
|
778
|
+
* @param {string} [target.text] - Visible text of a button/link/element to click (case-insensitive partial match)
|
|
763
779
|
* @param {number} [target.x] - X coordinate
|
|
764
780
|
* @param {number} [target.y] - Y coordinate
|
|
765
781
|
* @returns {Promise<{ clicked: boolean, selector?: string }>}
|
|
@@ -768,9 +784,44 @@ export async function browserClick(target) {
|
|
|
768
784
|
const browser = await getBrowser();
|
|
769
785
|
|
|
770
786
|
let x, y;
|
|
787
|
+
let label = '';
|
|
788
|
+
|
|
789
|
+
if (target.text) {
|
|
790
|
+
// Find element by visible text — searches buttons, links, and all clickable elements
|
|
791
|
+
const searchText = target.text;
|
|
792
|
+
const result = await browser.ws.send('Runtime.evaluate', {
|
|
793
|
+
expression: `(() => {
|
|
794
|
+
const searchText = ${JSON.stringify(searchText)}.toLowerCase();
|
|
795
|
+
// Search in priority order: buttons, links, then any visible element
|
|
796
|
+
const candidates = [
|
|
797
|
+
...document.querySelectorAll('button, [role="button"], input[type="submit"], input[type="button"]'),
|
|
798
|
+
...document.querySelectorAll('a'),
|
|
799
|
+
...document.querySelectorAll('[onclick], [tabindex]'),
|
|
800
|
+
];
|
|
801
|
+
for (const el of candidates) {
|
|
802
|
+
const text = (el.textContent || el.value || el.getAttribute('aria-label') || '').trim();
|
|
803
|
+
if (text.toLowerCase().includes(searchText) && el.offsetHeight > 0 && el.offsetWidth > 0) {
|
|
804
|
+
const rect = el.getBoundingClientRect();
|
|
805
|
+
if (rect.width > 0 && rect.height > 0) {
|
|
806
|
+
return { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2, tag: el.tagName, text: text.slice(0, 60) };
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
return null;
|
|
811
|
+
})()`,
|
|
812
|
+
returnByValue: true,
|
|
813
|
+
});
|
|
771
814
|
|
|
772
|
-
|
|
773
|
-
|
|
815
|
+
const info = result.result?.value;
|
|
816
|
+
if (!info) {
|
|
817
|
+
return { error: true, message: `No clickable element found with text "${searchText}". Try browser_extract to see visible buttons.` };
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
x = Math.round(info.x);
|
|
821
|
+
y = Math.round(info.y);
|
|
822
|
+
label = `"${info.text}" (${info.tag})`;
|
|
823
|
+
} else if (target.selector) {
|
|
824
|
+
// Find element by CSS selector and get its center point
|
|
774
825
|
const result = await browser.ws.send('Runtime.evaluate', {
|
|
775
826
|
expression: `(() => {
|
|
776
827
|
const el = document.querySelector(${JSON.stringify(target.selector)});
|
|
@@ -789,11 +840,13 @@ export async function browserClick(target) {
|
|
|
789
840
|
|
|
790
841
|
x = Math.round(info.x);
|
|
791
842
|
y = Math.round(info.y);
|
|
843
|
+
label = target.selector;
|
|
792
844
|
} else if (target.x !== undefined && target.y !== undefined) {
|
|
793
845
|
x = target.x;
|
|
794
846
|
y = target.y;
|
|
847
|
+
label = `(${x}, ${y})`;
|
|
795
848
|
} else {
|
|
796
|
-
return { error: true, message: 'Provide
|
|
849
|
+
return { error: true, message: 'Provide text, CSS selector, or x/y coordinates' };
|
|
797
850
|
}
|
|
798
851
|
|
|
799
852
|
// Dispatch mouse events: move → down → up (simulates real click)
|
|
@@ -807,10 +860,25 @@ export async function browserClick(target) {
|
|
|
807
860
|
type: 'mouseReleased', x, y, button: 'left', clickCount: 1,
|
|
808
861
|
});
|
|
809
862
|
|
|
810
|
-
//
|
|
811
|
-
await new Promise(r => setTimeout(r,
|
|
863
|
+
// Wait for any navigation or JS handlers triggered by the click
|
|
864
|
+
await new Promise(r => setTimeout(r, 500));
|
|
865
|
+
|
|
866
|
+
// Check if the click triggered a navigation — wait for it
|
|
867
|
+
try {
|
|
868
|
+
const navCheck = await browser.ws.send('Runtime.evaluate', {
|
|
869
|
+
expression: 'document.readyState',
|
|
870
|
+
returnByValue: true,
|
|
871
|
+
});
|
|
872
|
+
if (navCheck.result?.value === 'loading') {
|
|
873
|
+
// Page is navigating — wait for load
|
|
874
|
+
try {
|
|
875
|
+
await browser.ws.waitForEvent('Page.loadEventFired', 10000);
|
|
876
|
+
await new Promise(r => setTimeout(r, 500));
|
|
877
|
+
} catch { /* timeout ok */ }
|
|
878
|
+
}
|
|
879
|
+
} catch { /* evaluation failed during navigation, that's fine */ }
|
|
812
880
|
|
|
813
|
-
return { error: false, clicked: true, x, y, selector: target.selector || `(${x}, ${y})` };
|
|
881
|
+
return { error: false, clicked: true, x, y, selector: label || target.selector || `(${x}, ${y})` };
|
|
814
882
|
}
|
|
815
883
|
|
|
816
884
|
/**
|
|
@@ -290,10 +290,12 @@ TOOLS:
|
|
|
290
290
|
fullPage=true captures the entire scrollable page. saveTo saves to a file path (e.g. "~/screenshot.png").
|
|
291
291
|
Returns base64-encoded image data. Use after browser_open to see what's on screen.
|
|
292
292
|
|
|
293
|
-
51. browser_click(selector?: string, x?: number, y?: number)
|
|
294
|
-
Click an element on the page by CSS selector or x/y coordinates.
|
|
295
|
-
|
|
296
|
-
|
|
293
|
+
51. browser_click(text?: string, selector?: string, x?: number, y?: number)
|
|
294
|
+
Click an element on the page by visible text, CSS selector, or x/y coordinates.
|
|
295
|
+
PREFERRED: use text="Rifiuta tutto" or text="Submit" to click buttons/links by their visible label (case-insensitive partial match).
|
|
296
|
+
CSS selector: selector="#submit-btn", selector="a.nav-link"
|
|
297
|
+
Coordinates: x=500, y=300 for precise clicking.
|
|
298
|
+
Always try text first — it works for buttons, links, and any clickable element regardless of CSS structure.
|
|
297
299
|
|
|
298
300
|
52. browser_type(text: string, selector?: string, clear?: boolean, delay?: number)
|
|
299
301
|
Type text into an input field. If selector is provided, clicks the element first to focus it.
|
|
@@ -1129,6 +1131,7 @@ export async function executeTool(action, params, config) {
|
|
|
1129
1131
|
if (!be.isBrowserRunning()) return 'No browser open. Use browser_open first.';
|
|
1130
1132
|
|
|
1131
1133
|
const result = await be.browserClick({
|
|
1134
|
+
text: params.text,
|
|
1132
1135
|
selector: params.selector,
|
|
1133
1136
|
x: params.x,
|
|
1134
1137
|
y: params.y,
|