real-browser-mcp-server 2.0.0 → 2.0.4
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/README.md +2 -2
- package/dist/lib/cjs/index.d.ts +2 -13
- package/dist/lib/cjs/index.d.ts.map +1 -1
- package/dist/lib/cjs/index.js.map +1 -1
- package/dist/lib/esm/index.d.mjs +2 -9
- package/dist/src/mcp/handlers/browser.d.ts +1 -1
- package/dist/src/mcp/handlers/browser.d.ts.map +1 -1
- package/dist/src/mcp/handlers/browser.js +62 -109
- package/dist/src/mcp/handlers/browser.js.map +1 -1
- package/dist/src/mcp/handlers/dom.d.ts +1 -1
- package/dist/src/mcp/handlers/dom.d.ts.map +1 -1
- package/dist/src/mcp/handlers/dom.js +90 -11
- package/dist/src/mcp/handlers/dom.js.map +1 -1
- package/dist/src/mcp/handlers/index.d.ts +2 -2
- package/dist/src/mcp/handlers/index.d.ts.map +1 -1
- package/dist/src/mcp/handlers/index.js +1 -14
- package/dist/src/mcp/handlers/index.js.map +1 -1
- package/dist/src/mcp/handlers/network.d.ts.map +1 -1
- package/dist/src/mcp/handlers/network.js +16 -3
- package/dist/src/mcp/handlers/network.js.map +1 -1
- package/dist/src/mcp/handlers/state.d.ts +0 -2
- package/dist/src/mcp/handlers/state.d.ts.map +1 -1
- package/dist/src/mcp/handlers/state.js +1 -8
- package/dist/src/mcp/handlers/state.js.map +1 -1
- package/dist/src/mcp/handlers/utility-handlers.d.ts +1 -4
- package/dist/src/mcp/handlers/utility-handlers.d.ts.map +1 -1
- package/dist/src/mcp/handlers/utility-handlers.js +12 -2
- package/dist/src/mcp/handlers/utility-handlers.js.map +1 -1
- package/dist/src/shared/activity-logger.d.ts +1 -2
- package/dist/src/shared/activity-logger.d.ts.map +1 -1
- package/dist/src/shared/activity-logger.js +1 -2
- package/dist/src/shared/activity-logger.js.map +1 -1
- package/dist/src/shared/lib-core.d.ts +18 -11
- package/dist/src/shared/lib-core.d.ts.map +1 -1
- package/dist/src/shared/lib-core.js +14 -34
- package/dist/src/shared/lib-core.js.map +1 -1
- package/dist/src/types.d.ts +8 -89
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +5 -7
- package/dist/src/shared/cache-manager.d.ts +0 -78
- package/dist/src/shared/cache-manager.d.ts.map +0 -1
- package/dist/src/shared/cache-manager.js +0 -219
- package/dist/src/shared/cache-manager.js.map +0 -1
- package/dist/test/cjs/test.d.ts +0 -11
- package/dist/test/cjs/test.d.ts.map +0 -1
- package/dist/test/cjs/test.js +0 -242
- package/dist/test/cjs/test.js.map +0 -1
- package/dist/test/mcp/smoke-test.d.ts +0 -29
- package/dist/test/mcp/smoke-test.d.ts.map +0 -1
- package/dist/test/mcp/smoke-test.js +0 -144
- package/dist/test/mcp/smoke-test.js.map +0 -1
- package/dist/test/unit/handler-test.d.ts +0 -3
- package/dist/test/unit/handler-test.d.ts.map +0 -1
- package/dist/test/unit/handler-test.js +0 -133
- package/dist/test/unit/handler-test.js.map +0 -1
package/README.md
CHANGED
|
@@ -92,7 +92,7 @@ docker run -i --rm ghcr.io/codeiva4u/real-browser-mcp-server:latest
|
|
|
92
92
|
* **Turnstile Auto-Solver**: Seamlessly detects and bypasses Cloudflare Turnstile widgets.
|
|
93
93
|
* **Anti-Race Condition Guards**: Robust state-guards ensure popup blockers, shims, and adblockers attach exactly once per page, preventing context destruction.
|
|
94
94
|
* **TypeScript**: Entire codebase is written in TypeScript for type safety and maintainability.
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
|
|
97
97
|
---
|
|
98
98
|
|
|
@@ -355,7 +355,7 @@ Run these scripts from the project root directory:
|
|
|
355
355
|
- **MCP-first**: every tool is defined in `src/shared/tools.ts` and dispatched through a single `executeTool()` router.
|
|
356
356
|
- **Handler modules**: `src/mcp/handlers/` contains focused helper files (`network-recorder.ts`, `network-extractors.ts`, `vision-captcha.ts`, `vision-see-page.ts`) with thin wrapper files (`network.ts`, `vision.ts`) for the tool-facing API.
|
|
357
357
|
- **Browser state**: a single global `state` object in `src/mcp/handlers/state.ts` holds the current browser/page instance and network recorder data. `createSessionContext()` provides a typed accessor pattern for handlers.
|
|
358
|
-
- **Persistent
|
|
358
|
+
- **Persistent activity log**: `src/shared/activity-logger.ts` survives server restarts via a JSON file on disk.
|
|
359
359
|
|
|
360
360
|
### Known Limitations
|
|
361
361
|
|
package/dist/lib/cjs/index.d.ts
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
headless?: boolean | undefined;
|
|
4
|
-
proxy?: any;
|
|
5
|
-
contextOptions?: {} | undefined;
|
|
6
|
-
turnstile?: boolean | undefined;
|
|
7
|
-
executablePath?: undefined;
|
|
8
|
-
}) => Promise<{
|
|
9
|
-
browser: import("patchright-core").Browser;
|
|
10
|
-
page: import("patchright-core").Page;
|
|
11
|
-
blocker: any;
|
|
12
|
-
setupPage: (p: any) => Promise<void>;
|
|
13
|
-
}>;
|
|
1
|
+
import { createConnect } from '../../src/shared/lib-core';
|
|
2
|
+
declare const connect: ReturnType<typeof createConnect>;
|
|
14
3
|
export { connect };
|
|
15
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/cjs/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/cjs/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,QAAA,MAAM,OAAO,EAAE,UAAU,CAAC,OAAO,aAAa,CAAiC,CAAC;AAEhF,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/cjs/index.ts"],"names":[],"mappings":";;;AAAA,4DAAyD;AACzD,wDAA0D;AAE1D,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/cjs/index.ts"],"names":[],"mappings":";;;AAAA,4DAAyD;AACzD,wDAA0D;AAE1D,MAAM,OAAO,GAAqC,IAAA,wBAAa,EAAC,+BAAc,CAAC,CAAC;AAEvE,0BAAO;AAChB,MAAM,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,CAAC"}
|
package/dist/lib/esm/index.d.mjs
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
executablePath?;
|
|
4
|
-
}) => Promise<{
|
|
5
|
-
browser: import("patchright-core").Browser;
|
|
6
|
-
page: import("patchright-core").Page;
|
|
7
|
-
blocker;
|
|
8
|
-
setupPage: (p) => Promise<void>;
|
|
9
|
-
}>;
|
|
1
|
+
import { createConnect } from '../../src/shared/lib-core.mjs';
|
|
2
|
+
declare const connect: ReturnType<typeof createConnect>;
|
|
10
3
|
|
|
11
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -23,7 +23,7 @@ export declare const browserHandlers: {
|
|
|
23
23
|
type: "navigation" | "networkidle" | "selector" | "timeout";
|
|
24
24
|
value: string | undefined;
|
|
25
25
|
}>;
|
|
26
|
-
browser_close(params?:
|
|
26
|
+
browser_close(params?: Record<string, unknown>): Promise<{
|
|
27
27
|
success: boolean;
|
|
28
28
|
message: string;
|
|
29
29
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../../src/mcp/handlers/browser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../../src/mcp/handlers/browser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAkB,MAAM,aAAa,CAAC;AAEjG,eAAO,MAAM,eAAe;0BACC,iBAAiB;;;;;;;qBAqFrB,cAAc;;;;;;;;;;;iBA2FlB,UAAU;;;;;2BA0BD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;CA6BpD,CAAC"}
|
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// @ts-nocheck
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
3
|
exports.browserHandlers = void 0;
|
|
5
4
|
const state_1 = require("./state");
|
|
6
|
-
// Auto-generated browser handlers
|
|
7
5
|
exports.browserHandlers = {
|
|
8
6
|
async browser_init(params = {}) {
|
|
9
7
|
(0, state_1.notifyProgress)('browser_init', 'started', 'Initializing browser...');
|
|
10
8
|
const { connect } = require('../../../lib/cjs/index.js');
|
|
11
|
-
// Get headless from params OR environment variable
|
|
12
9
|
const envHeadless = (0, state_1.getHeadlessFromEnv)();
|
|
13
10
|
const headless = params.headless !== undefined ? params.headless : envHeadless;
|
|
14
11
|
const { proxy = {}, contextOptions = {}, turnstile = false, enableBlocker = true, recordVideo = false } = params;
|
|
15
12
|
(0, state_1.notifyProgress)('browser_init', 'progress', `Mode: ${headless ? 'Headless' : 'GUI (Visible)'}`, { headless });
|
|
16
|
-
|
|
17
|
-
const savedStorage = state_1.globalCache.get('storage_state');
|
|
18
|
-
const mergedContextOptions = savedStorage
|
|
19
|
-
? { ...contextOptions, storageState: savedStorage }
|
|
20
|
-
: contextOptions;
|
|
13
|
+
const mergedContextOptions = contextOptions;
|
|
21
14
|
const result = await connect({
|
|
22
15
|
headless,
|
|
23
16
|
proxy,
|
|
@@ -28,59 +21,42 @@ exports.browserHandlers = {
|
|
|
28
21
|
state_1.state.browserInstance = result.browser;
|
|
29
22
|
state_1.state.pageInstance = result.page;
|
|
30
23
|
state_1.state.blockerInstance = result.blocker;
|
|
31
|
-
state_1.state.setupPageFn = result.setupPage;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
await dialog.dismiss(); // Simulate clicking 'Cancel'
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
// Auto-accept other dialogs (like alerts or simple confirmations)
|
|
49
|
-
await dialog.accept(); // Simulate clicking 'OK'
|
|
24
|
+
state_1.state.setupPageFn = result.setupPage;
|
|
25
|
+
if (state_1.state.pageInstance) {
|
|
26
|
+
state_1.state.pageInstance.on('dialog', async (dialog) => {
|
|
27
|
+
const dialogType = dialog.type();
|
|
28
|
+
const msg = dialog.message().toLowerCase();
|
|
29
|
+
(0, state_1.notifyProgress)('browser_init', 'progress', `🔔 Handling dialog: ${dialogType} - ${dialog.message().substring(0, 100)}...`);
|
|
30
|
+
try {
|
|
31
|
+
if (msg.includes('redirect') || msg.includes('external') || msg.includes('leaving')) {
|
|
32
|
+
console.error('🚫 Blocking redirect dialog (Dismiss)');
|
|
33
|
+
await dialog.dismiss();
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
await dialog.accept();
|
|
37
|
+
}
|
|
50
38
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// Ignore errors (dialog might be closed by injected script)
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
// ═══════════════════════════════════════════════════════════════
|
|
57
|
-
// INJECTED SCRIPT - Silent Handling of Popups
|
|
58
|
-
// Override window.confirm/alert to handle them inside the page context
|
|
59
|
-
// Note: Using addInitScript (Playwright) to intercept popups early
|
|
60
|
-
// ═══════════════════════════════════════════════════════════════
|
|
61
|
-
await state_1.state.pageInstance.addInitScript(() => {
|
|
62
|
-
window.originalConfirm = window.confirm;
|
|
63
|
-
window.originalAlert = window.alert;
|
|
64
|
-
// Smart Confirm Handler
|
|
65
|
-
window.confirm = (msg) => {
|
|
66
|
-
console.log('Intercepted Confirm Dialog:', msg);
|
|
67
|
-
if (msg && (msg.toLowerCase().includes('redirect') || msg.toLowerCase().includes('external'))) {
|
|
68
|
-
console.log('🚫 Blocking redirect confirmation inside page');
|
|
69
|
-
return false; // Return FALSE = Click Cancel
|
|
39
|
+
catch (e) {
|
|
40
|
+
// Ignore errors (dialog might be closed by injected script)
|
|
70
41
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
42
|
+
});
|
|
43
|
+
await state_1.state.pageInstance.addInitScript(() => {
|
|
44
|
+
window.originalConfirm = window.confirm;
|
|
45
|
+
window.originalAlert = window.alert;
|
|
46
|
+
window.confirm = (msg) => {
|
|
47
|
+
if (msg && (msg.toLowerCase().includes('redirect') || msg.toLowerCase().includes('external'))) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
52
|
+
window.alert = (_msg) => {
|
|
53
|
+
return undefined;
|
|
54
|
+
};
|
|
55
|
+
window.prompt = (_msg, _default) => {
|
|
56
|
+
return null;
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}
|
|
84
60
|
const pid = (typeof state_1.state.browserInstance.process === 'function') ? state_1.state.browserInstance.process()?.pid : null;
|
|
85
61
|
(0, state_1.notifyProgress)('browser_init', 'completed', `Browser started (PID: ${pid})`, {
|
|
86
62
|
headless,
|
|
@@ -97,82 +73,72 @@ exports.browserHandlers = {
|
|
|
97
73
|
},
|
|
98
74
|
async navigate(params) {
|
|
99
75
|
const { page } = (0, state_1.requireBrowser)();
|
|
100
|
-
let { url, waitUntil = 'networkidle', timeout = 30000, retries = 2 } = params;
|
|
101
|
-
// Playwright/Patchright wait states: load | domcontentloaded | networkidle | commit
|
|
76
|
+
let { url, waitUntil = 'networkidle', timeout = 30000, retries = 2, smartWait = true } = params;
|
|
102
77
|
waitUntil = (0, state_1.resolveWaitUntil)(waitUntil);
|
|
103
78
|
(0, state_1.notifyProgress)('navigate', 'started', `Navigating to: ${url}`);
|
|
104
|
-
// ═══════════════════════════════════════════════════════════════
|
|
105
|
-
// CDP EARLY INJECTION - Setup BEFORE navigation for better ad blocking
|
|
106
|
-
// This ensures CSS and scripts are injected before page scripts run
|
|
107
|
-
// ═══════════════════════════════════════════════════════════════
|
|
108
79
|
console.error('[Navigate] state.setupPageFn available:', !!state_1.state.setupPageFn);
|
|
109
80
|
if (state_1.state.setupPageFn) {
|
|
110
81
|
try {
|
|
111
82
|
await state_1.state.setupPageFn(page);
|
|
112
83
|
(0, state_1.notifyProgress)('navigate', 'progress', 'CDP early injection setup complete');
|
|
113
|
-
console.error('[Navigate] CDP early injection SUCCESS');
|
|
114
84
|
}
|
|
115
85
|
catch (e) {
|
|
116
|
-
|
|
117
|
-
console.error('[Navigate] CDP early injection failed:',
|
|
86
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
87
|
+
console.error('[Navigate] CDP early injection failed:', msg);
|
|
118
88
|
}
|
|
119
89
|
}
|
|
120
|
-
else {
|
|
121
|
-
console.error('[Navigate] No state.setupPageFn available - CDP early injection skipped');
|
|
122
|
-
}
|
|
123
90
|
let lastError = null;
|
|
124
91
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
125
92
|
try {
|
|
126
|
-
// Wait a bit if this is a retry
|
|
127
93
|
if (attempt > 0) {
|
|
128
94
|
(0, state_1.notifyProgress)('navigate', 'progress', `Retry attempt ${attempt}...`);
|
|
129
95
|
await new Promise(r => setTimeout(r, 1000));
|
|
130
96
|
}
|
|
131
97
|
await page.goto(url, { waitUntil, timeout });
|
|
132
|
-
|
|
98
|
+
if (smartWait) {
|
|
99
|
+
try {
|
|
100
|
+
await page.waitForFunction(() => {
|
|
101
|
+
const body = document.body;
|
|
102
|
+
if (!body)
|
|
103
|
+
return false;
|
|
104
|
+
const text = body.innerText || '';
|
|
105
|
+
return text.length > 50 && !body.querySelector('.loading, .spinner, [class*="loading"]');
|
|
106
|
+
}, { timeout: 5000 });
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Smart wait timeout — page may still be loading, continue
|
|
110
|
+
}
|
|
111
|
+
}
|
|
133
112
|
await new Promise(r => setTimeout(r, 500));
|
|
134
|
-
// Try to get title with error handling
|
|
135
113
|
let title = '';
|
|
136
114
|
try {
|
|
137
115
|
title = await page.title();
|
|
138
116
|
}
|
|
139
117
|
catch (e) {
|
|
140
|
-
// Title might fail if page is still loading
|
|
141
118
|
title = 'Loading...';
|
|
142
119
|
}
|
|
143
120
|
(0, state_1.notifyProgress)('navigate', 'completed', `Loaded: ${title}`, { url: page.url(), title });
|
|
144
|
-
return {
|
|
145
|
-
success: true,
|
|
146
|
-
url: page.url(),
|
|
147
|
-
title
|
|
148
|
-
};
|
|
121
|
+
return { success: true, url: page.url(), title };
|
|
149
122
|
}
|
|
150
123
|
catch (error) {
|
|
151
124
|
lastError = error;
|
|
152
|
-
|
|
153
|
-
if (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
(0, state_1.notifyProgress)('navigate', 'progress', `Navigation interrupted (${
|
|
157
|
-
// Wait for any ongoing navigation to complete
|
|
125
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
126
|
+
if (errMsg.includes('Execution context was destroyed') ||
|
|
127
|
+
errMsg.includes('context') ||
|
|
128
|
+
errMsg.includes('Target closed')) {
|
|
129
|
+
(0, state_1.notifyProgress)('navigate', 'progress', `Navigation interrupted (${errMsg.substring(0, 50)}...), waiting for page...`);
|
|
158
130
|
try {
|
|
159
131
|
await page.waitForNavigation({ timeout: 5000, waitUntil: 'domcontentloaded' }).catch(() => { });
|
|
160
132
|
}
|
|
161
133
|
catch (e) {
|
|
162
134
|
// Ignore timeout
|
|
163
135
|
}
|
|
164
|
-
// Check if we actually landed on the page
|
|
165
136
|
try {
|
|
166
137
|
const currentUrl = page.url();
|
|
167
138
|
if (currentUrl && currentUrl !== 'about:blank') {
|
|
168
139
|
const title = await page.title().catch(() => 'Unknown');
|
|
169
140
|
(0, state_1.notifyProgress)('navigate', 'completed', `Loaded after recovery: ${title}`, { url: currentUrl, title });
|
|
170
|
-
return {
|
|
171
|
-
success: true,
|
|
172
|
-
url: currentUrl,
|
|
173
|
-
title,
|
|
174
|
-
recovered: true
|
|
175
|
-
};
|
|
141
|
+
return { success: true, url: currentUrl, title, recovered: true };
|
|
176
142
|
}
|
|
177
143
|
}
|
|
178
144
|
catch (e) {
|
|
@@ -180,13 +146,12 @@ exports.browserHandlers = {
|
|
|
180
146
|
}
|
|
181
147
|
}
|
|
182
148
|
else {
|
|
183
|
-
// Non-recoverable error, throw immediately
|
|
184
149
|
throw error;
|
|
185
150
|
}
|
|
186
151
|
}
|
|
187
152
|
}
|
|
188
|
-
|
|
189
|
-
(0, state_1.notifyProgress)('navigate', 'error', `Navigation failed after ${retries + 1} attempts: ${
|
|
153
|
+
const lastErrMsg = lastError instanceof Error ? lastError.message : String(lastError);
|
|
154
|
+
(0, state_1.notifyProgress)('navigate', 'error', `Navigation failed after ${retries + 1} attempts: ${lastErrMsg}`);
|
|
190
155
|
throw lastError || new Error('Navigation failed');
|
|
191
156
|
},
|
|
192
157
|
async wait(params) {
|
|
@@ -205,7 +170,7 @@ exports.browserHandlers = {
|
|
|
205
170
|
break;
|
|
206
171
|
case 'timeout':
|
|
207
172
|
default:
|
|
208
|
-
await new Promise(r => setTimeout(r, parseInt(value) || 1000));
|
|
173
|
+
await new Promise(r => setTimeout(r, parseInt(value || '1000') || 1000));
|
|
209
174
|
}
|
|
210
175
|
(0, state_1.notifyProgress)('wait', 'completed', `Wait completed: ${type}`, { type, value });
|
|
211
176
|
return { success: true, type, value };
|
|
@@ -214,18 +179,6 @@ exports.browserHandlers = {
|
|
|
214
179
|
const { force = false, saveSession = false } = params;
|
|
215
180
|
(0, state_1.notifyProgress)('browser_close', 'started', 'Closing browser...');
|
|
216
181
|
if (state_1.state.browserInstance) {
|
|
217
|
-
// Save storage state to globalCache before closing (only if saveSession is true)
|
|
218
|
-
if (state_1.state.pageInstance && saveSession) {
|
|
219
|
-
try {
|
|
220
|
-
const storageState = await state_1.state.pageInstance.context().storageState();
|
|
221
|
-
state_1.globalCache.set('storage_state', storageState);
|
|
222
|
-
state_1.globalCache.saveToDisk();
|
|
223
|
-
(0, state_1.notifyProgress)('browser_close', 'progress', 'Session state saved');
|
|
224
|
-
}
|
|
225
|
-
catch (e) {
|
|
226
|
-
// ignore error
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
182
|
try {
|
|
230
183
|
await state_1.state.browserInstance.close();
|
|
231
184
|
(0, state_1.notifyProgress)('browser_close', 'progress', 'Browser closed gracefully');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../../../src/mcp/handlers/browser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../../../src/mcp/handlers/browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../../../src/mcp/handlers/dom.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIzF,eAAO,MAAM,WAAW;kBACF,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../../../src/mcp/handlers/dom.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIzF,eAAO,MAAM,WAAW;kBACF,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsXZ,UAAU;;;;;;;;;;;;;2BAwGD,YAAY;;;;;sBAkDhB,cAAc;;;;;;CAmBvC,CAAC"}
|
|
@@ -14,7 +14,7 @@ exports.domHandlers = {
|
|
|
14
14
|
// iframe support
|
|
15
15
|
iframe, iframeSelector,
|
|
16
16
|
// Additional options
|
|
17
|
-
scrollIntoView = true, forceClick = false,
|
|
17
|
+
scrollIntoView = true, forceClick = false, aiHeal = true,
|
|
18
18
|
// NEW: Auto Video Player Detection & Control
|
|
19
19
|
autoDetectPlayer = false, usePlayerAPI = true, waitForPlay = false, playerTimeout = 15000 } = params;
|
|
20
20
|
let selector = providedSelector;
|
|
@@ -154,7 +154,7 @@ exports.domHandlers = {
|
|
|
154
154
|
const startTime = Date.now();
|
|
155
155
|
let isPlaying = false;
|
|
156
156
|
while (Date.now() - startTime < playerTimeout) {
|
|
157
|
-
const
|
|
157
|
+
const videoState = await context.evaluate(() => {
|
|
158
158
|
const video = document.querySelector('video');
|
|
159
159
|
if (video) {
|
|
160
160
|
return {
|
|
@@ -169,9 +169,9 @@ exports.domHandlers = {
|
|
|
169
169
|
}
|
|
170
170
|
return { playing: false };
|
|
171
171
|
}).catch(() => ({ playing: false }));
|
|
172
|
-
if (
|
|
172
|
+
if (videoState.playing || videoState.currentTime > 0) {
|
|
173
173
|
isPlaying = true;
|
|
174
|
-
(0, state_1.notifyProgress)('click', 'progress', `▶️ Video is now playing (${
|
|
174
|
+
(0, state_1.notifyProgress)('click', 'progress', `▶️ Video is now playing (${videoState.currentTime?.toFixed(1) || 0}s)`);
|
|
175
175
|
break;
|
|
176
176
|
}
|
|
177
177
|
await new Promise(r => setTimeout(r, 500));
|
|
@@ -208,6 +208,36 @@ exports.domHandlers = {
|
|
|
208
208
|
await context.waitForSelector(selector, { timeout: Math.min(timeout / retries, 10000) });
|
|
209
209
|
}
|
|
210
210
|
catch (e) {
|
|
211
|
+
if (aiHeal && attempt === 1) {
|
|
212
|
+
const healed = await page.evaluate((sel) => {
|
|
213
|
+
const parts = sel.replace(/[#.[\]]/g, ' ').trim().split(/\s+/).filter(Boolean);
|
|
214
|
+
const candidates = document.querySelectorAll('a, button, input, [role="button"], [onclick]');
|
|
215
|
+
for (const el of candidates) {
|
|
216
|
+
const text = (el.textContent || '').toLowerCase();
|
|
217
|
+
const id = (el.id || '').toLowerCase();
|
|
218
|
+
const cls = (el.className || '').toLowerCase();
|
|
219
|
+
for (const part of parts) {
|
|
220
|
+
if (text.includes(part.toLowerCase()) || id.includes(part.toLowerCase()) || cls.includes(part.toLowerCase())) {
|
|
221
|
+
if (el.id)
|
|
222
|
+
return `#${el.id}`;
|
|
223
|
+
if (el.className)
|
|
224
|
+
return `${el.tagName.toLowerCase()}.${el.className.split(' ')[0]}`;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return null;
|
|
229
|
+
}, selector).catch(() => null);
|
|
230
|
+
if (healed) {
|
|
231
|
+
(0, state_1.notifyProgress)('click', 'progress', `🔧 AI Healed: ${selector} → ${healed}`);
|
|
232
|
+
selector = healed;
|
|
233
|
+
try {
|
|
234
|
+
await context.waitForSelector(selector, { timeout: 5000 });
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// healed selector also not found
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
211
241
|
if (attempt < retries) {
|
|
212
242
|
(0, state_1.notifyProgress)('click', 'progress', `Selector not found, retry ${attempt}/${retries}...`);
|
|
213
243
|
await new Promise(r => setTimeout(r, 1000));
|
|
@@ -313,11 +343,11 @@ exports.domHandlers = {
|
|
|
313
343
|
},
|
|
314
344
|
async type(params) {
|
|
315
345
|
const { page } = (0, state_1.requireBrowser)();
|
|
316
|
-
const { selector: providedSelector, annotationId, text, delay = 50, clear =
|
|
346
|
+
const { selector: providedSelector, annotationId, text, delay = 50, clear = true,
|
|
317
347
|
// NEW: iframe support
|
|
318
348
|
iframe, iframeSelector,
|
|
319
349
|
// NEW: Additional options
|
|
320
|
-
pressEnter = false, waitForSelector = true } = params;
|
|
350
|
+
pressEnter = false, waitForSelector = true, aiHeal = true } = params;
|
|
321
351
|
let selector = providedSelector;
|
|
322
352
|
if (annotationId !== undefined) {
|
|
323
353
|
if (state_1.state.activeAnnotations && state_1.state.activeAnnotations[annotationId]) {
|
|
@@ -348,6 +378,31 @@ exports.domHandlers = {
|
|
|
348
378
|
await context.waitForSelector(selector, { timeout: 10000 });
|
|
349
379
|
}
|
|
350
380
|
catch (e) {
|
|
381
|
+
if (aiHeal) {
|
|
382
|
+
const healed = await page.evaluate((sel) => {
|
|
383
|
+
const parts = sel.replace(/[#.[\]]/g, ' ').trim().split(/\s+/).filter(Boolean);
|
|
384
|
+
const candidates = document.querySelectorAll('input, textarea, select');
|
|
385
|
+
for (const el of candidates) {
|
|
386
|
+
const name = (el.getAttribute('name') || '').toLowerCase();
|
|
387
|
+
const id = (el.id || '').toLowerCase();
|
|
388
|
+
const placeholder = (el.getAttribute('placeholder') || '').toLowerCase();
|
|
389
|
+
for (const part of parts) {
|
|
390
|
+
const p = part.toLowerCase();
|
|
391
|
+
if (name.includes(p) || id.includes(p) || placeholder.includes(p)) {
|
|
392
|
+
if (el.id)
|
|
393
|
+
return `#${el.id}`;
|
|
394
|
+
if (el.getAttribute('name'))
|
|
395
|
+
return `[name="${el.getAttribute('name')}"]`;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return null;
|
|
400
|
+
}, selector).catch(() => null);
|
|
401
|
+
if (healed) {
|
|
402
|
+
(0, state_1.notifyProgress)('type', 'progress', `🔧 AI Healed: ${selector} → ${healed}`);
|
|
403
|
+
selector = healed;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
351
406
|
(0, state_1.notifyProgress)('type', 'error', `Selector not found: ${selector}`);
|
|
352
407
|
return { success: false, error: `Selector not found: ${selector}. 💡 AI HINT: The element might be hidden, inside an iframe, or the selector is wrong. Run see_page(annotate: true) to verify and get an annotationId.` };
|
|
353
408
|
}
|
|
@@ -374,11 +429,35 @@ exports.domHandlers = {
|
|
|
374
429
|
},
|
|
375
430
|
async random_scroll(params = {}) {
|
|
376
431
|
const { page } = (0, state_1.requireBrowser)();
|
|
377
|
-
const { direction = 'down', amount = 0, smooth = true } = params;
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
432
|
+
const { direction = 'down', amount = 0, smooth = true, aiDetectLazyLoad = true } = params;
|
|
433
|
+
let scrollAmount = amount || Math.floor(Math.random() * 500) + 200;
|
|
434
|
+
if (aiDetectLazyLoad) {
|
|
435
|
+
const lazyInfo = await page.evaluate(() => {
|
|
436
|
+
const lazyImages = document.querySelectorAll('img[loading="lazy"], img[data-src], [data-lazy]');
|
|
437
|
+
const infiniteScroll = !!document.querySelector('[class*="infinite"], [class*="load-more"]');
|
|
438
|
+
return { lazyImages: lazyImages.length, infiniteScroll };
|
|
439
|
+
}).catch(() => ({ lazyImages: 0, infiniteScroll: false }));
|
|
440
|
+
if (lazyInfo.lazyImages > 0) {
|
|
441
|
+
scrollAmount = Math.min(scrollAmount, 300);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
let scrollDirection;
|
|
445
|
+
if (direction === 'random') {
|
|
446
|
+
scrollDirection = Math.random() > 0.5 ? 'down' : 'up';
|
|
447
|
+
}
|
|
448
|
+
else if (direction === 'smart') {
|
|
449
|
+
const scrollInfo = await page.evaluate(() => ({
|
|
450
|
+
scrollY: window.scrollY,
|
|
451
|
+
scrollHeight: document.body.scrollHeight,
|
|
452
|
+
innerHeight: window.innerHeight
|
|
453
|
+
}));
|
|
454
|
+
const atBottom = scrollInfo.scrollY + scrollInfo.innerHeight >= scrollInfo.scrollHeight - 100;
|
|
455
|
+
const atTop = scrollInfo.scrollY <= 10;
|
|
456
|
+
scrollDirection = atBottom ? 'up' : atTop ? 'down' : (Math.random() > 0.5 ? 'down' : 'up');
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
scrollDirection = direction;
|
|
460
|
+
}
|
|
382
461
|
(0, state_1.notifyProgress)('random_scroll', 'started', `Scrolling ${scrollDirection} ${scrollAmount}px`);
|
|
383
462
|
const y = scrollDirection === 'down' ? scrollAmount : -scrollAmount;
|
|
384
463
|
if (smooth && page.realScroll) {
|