@weavetab/mcp 2.5.0 → 2.5.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/AGENTS.md +49 -49
- package/ARCHITECTURE.md +590 -590
- package/LICENSE +216 -216
- package/README.md +269 -269
- package/SECURITY.md +207 -207
- package/TROUBLESHOOTING.md +373 -365
- package/dist/anticaptcha/detector.js +395 -395
- package/dist/anticaptcha/solver.js +130 -130
- package/dist/cdp/bridge.js +73 -73
- package/dist/cdp/connector.js +46 -22
- package/dist/cdp/extension.js +34 -34
- package/dist/cdp/helpers.js +174 -174
- package/dist/cdp/pruner.js +195 -195
- package/dist/cdp/ref_cache.js +66 -66
- package/dist/cdp/security.js +10 -10
- package/dist/cdp/verify.js +57 -57
- package/dist/cdp/walker.js +563 -525
- package/dist/cli/plugin.js +26 -3
- package/dist/config/loader.d.ts +0 -3
- package/dist/config/loader.js +0 -9
- package/dist/index.js +0 -4
- package/dist/intelligence/intent.js +81 -81
- package/dist/intelligence/sessionMemory.js +2 -2
- package/dist/overlay/ghost.js +22 -22
- package/dist/overlay/injector.js +89 -89
- package/dist/plugin/extension_bridge.js +54 -54
- package/dist/plugin/interface.d.ts +7 -0
- package/dist/plugin/loader.js +3 -4
- package/dist/plugin/schema.d.ts +11 -0
- package/dist/plugin/schema.js +59 -0
- package/dist/security/guard.js +18 -18
- package/dist/sensors/actionability.js +167 -167
- package/dist/sensors/guard.js +29 -29
- package/dist/sensors/network.js +15 -17
- package/dist/server.d.ts +1 -1
- package/dist/server.js +173 -144
- package/dist/state/delta.js +6 -7
- package/dist/tools/automation.js +85 -85
- package/dist/tools/canvas.js +48 -25
- package/dist/tools/checkpoint.js +94 -35
- package/dist/tools/click.js +52 -41
- package/dist/tools/clipboard.js +80 -74
- package/dist/tools/design_extract.js +441 -441
- package/dist/tools/dialog.js +13 -13
- package/dist/tools/emulation.d.ts +2 -0
- package/dist/tools/emulation.js +7 -0
- package/dist/tools/fill.js +344 -347
- package/dist/tools/find.js +78 -52
- package/dist/tools/highlight.js +67 -67
- package/dist/tools/inspect.js +54 -25
- package/dist/tools/key.js +42 -35
- package/dist/tools/navigate.d.ts +1 -1
- package/dist/tools/navigate.js +35 -35
- package/dist/tools/office/parse.js +62 -18
- package/dist/tools/pdf.d.ts +9 -0
- package/dist/tools/pdf.js +7 -4
- package/dist/tools/performance.d.ts +11 -4
- package/dist/tools/performance.js +94 -42
- package/dist/tools/performance_test.d.ts +2 -2
- package/dist/tools/performance_test.js +69 -69
- package/dist/tools/pointer.js +116 -116
- package/dist/tools/read.js +99 -67
- package/dist/tools/recording.js +9 -0
- package/dist/tools/scrape.js +146 -146
- package/dist/tools/screenshot.d.ts +2 -0
- package/dist/tools/screenshot.js +46 -4
- package/dist/tools/scroll.d.ts +3 -1
- package/dist/tools/scroll.js +13 -15
- package/dist/tools/select.d.ts +3 -0
- package/dist/tools/select.js +131 -124
- package/dist/tools/snapshot.js +8 -6
- package/dist/tools/storage.d.ts +5 -1
- package/dist/tools/storage.js +16 -0
- package/dist/tools/tabs.d.ts +7 -5
- package/dist/tools/tabs.js +79 -26
- package/dist/tools/thought.js +8 -8
- package/dist/tools/type.js +274 -274
- package/dist/tools/type_secret.js +23 -23
- package/dist/tools/upload.js +3 -3
- package/dist/tools/video_compiler.js +9 -0
- package/dist/tools/wait.js +35 -35
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/DOCUMENTATION.md +583 -585
- package/docs/PLUGINS.md +139 -121
- package/docs/TOOLS.md +3 -4
- package/docs/architecture/blind-injection.md +83 -83
- package/docs/architecture/overview.md +49 -49
- package/docs/architecture/security.md +36 -36
- package/docs/architecture/transport.md +37 -37
- package/docs/cli/cli-commands.md +50 -50
- package/docs/cli/cli-flags.md +28 -28
- package/docs/cli/cli-scripting.md +35 -35
- package/docs/configuration/config-locations.md +23 -23
- package/docs/configuration/configuration.md +39 -27
- package/docs/configuration/env-variables.md +19 -19
- package/docs/configuration/folders.md +62 -55
- package/docs/desktop-automation/electron-apps.md +225 -214
- package/docs/get-started/installation.md +1 -1
- package/docs/get-started/introduction.md +60 -60
- package/docs/get-started/quickstart.md +2 -2
- package/docs/get-started/setup-wizard.md +27 -27
- package/docs/intelligence/site-profiles.md +151 -151
- package/docs/tools/tools.md +582 -631
- package/docs/troubleshooting/trouble-browser.md +27 -27
- package/docs/troubleshooting/trouble-loop.md +31 -31
- package/ext-dist/background.js +415 -415
- package/ext-dist/content.js +2527 -2527
- package/ext-dist/dashboard.html +583 -583
- package/ext-dist/hud/hud.js +3 -3
- package/ext-dist/hud/index.html +20 -20
- package/ext-dist/manifest.json +73 -73
- package/ext-dist/styles.css +223 -223
- package/mcp.json +796 -805
- package/package.json +118 -118
- package/server.json +23 -23
- package/dist/cdp/walker.test.d.ts +0 -2
- package/dist/cdp/walker.test.js +0 -172
- package/dist/intelligence/sessionMemory.test.d.ts +0 -2
- package/dist/intelligence/sessionMemory.test.js +0 -62
- package/dist/intelligence/trail.test.d.ts +0 -2
- package/dist/intelligence/trail.test.js +0 -110
- package/dist/state/cache.test.d.ts +0 -2
- package/dist/state/cache.test.js +0 -76
- package/dist/state/delta.test.d.ts +0 -2
- package/dist/state/delta.test.js +0 -279
- package/dist/state/groups.d.ts +0 -15
- package/dist/state/groups.js +0 -80
- package/dist/tools/accessibility.d.ts +0 -14
- package/dist/tools/accessibility.js +0 -32
- package/dist/tools/ask.d.ts +0 -14
- package/dist/tools/ask.js +0 -49
- package/dist/tools/click_and_wait.d.ts +0 -33
- package/dist/tools/click_and_wait.js +0 -149
- package/dist/tools/drag.d.ts +0 -15
- package/dist/tools/drag.js +0 -29
- package/dist/tools/geo.d.ts +0 -19
- package/dist/tools/geo.js +0 -29
- package/dist/tools/github/analyze.d.ts +0 -4
- package/dist/tools/github/analyze.js +0 -113
- package/dist/tools/github/cache.d.ts +0 -21
- package/dist/tools/github/cache.js +0 -28
- package/dist/tools/github/index.d.ts +0 -19
- package/dist/tools/github/index.js +0 -40
- package/dist/tools/github/issues.d.ts +0 -9
- package/dist/tools/github/issues.js +0 -88
- package/dist/tools/github/pr.d.ts +0 -5
- package/dist/tools/github/pr.js +0 -88
- package/dist/tools/github/rateLimiter.d.ts +0 -4
- package/dist/tools/github/rateLimiter.js +0 -46
- package/dist/tools/github/read.d.ts +0 -34
- package/dist/tools/github/read.js +0 -74
- package/dist/tools/github/repoContext.d.ts +0 -20
- package/dist/tools/github/repoContext.js +0 -129
- package/dist/tools/hover.d.ts +0 -19
- package/dist/tools/hover.js +0 -57
- package/dist/tools/integration.test.d.ts +0 -2
- package/dist/tools/integration.test.js +0 -96
- package/dist/tools/macro_compiler.d.ts +0 -7
- package/dist/tools/macro_compiler.js +0 -82
- package/dist/tools/mouse.d.ts +0 -21
- package/dist/tools/mouse.js +0 -62
- package/dist/tools/response.d.ts +0 -129
- package/dist/tools/response.js +0 -5
- package/dist/tools/wait_for.d.ts +0 -23
- package/dist/tools/wait_for.js +0 -30
- package/dist/tools/windows.d.ts +0 -22
- package/dist/tools/windows.js +0 -57
package/dist/tools/scrape.js
CHANGED
|
@@ -4,79 +4,79 @@ import { sessionRegistry } from "../state/session.js";
|
|
|
4
4
|
export async function browserScrape(session, options, _config) {
|
|
5
5
|
const { query, type = "css", attributes = ["textContent"], multiple = true } = options;
|
|
6
6
|
const res = await session.Runtime.evaluate({
|
|
7
|
-
expression: `(function() {
|
|
8
|
-
const results = [];
|
|
9
|
-
let nodes = [];
|
|
10
|
-
|
|
11
|
-
try {
|
|
12
|
-
if (${JSON.stringify(type)} === 'css') {
|
|
13
|
-
if (${multiple}) {
|
|
14
|
-
nodes = Array.from(document.querySelectorAll(${JSON.stringify(query)}));
|
|
15
|
-
// Shadow DOM fallback: if nothing found, try the extension's deep-shadow query helper.
|
|
16
|
-
// This handles Vue/React components that attach to shadow roots.
|
|
17
|
-
if (nodes.length === 0 && window.__Weavetab_shadowQuery_all) {
|
|
18
|
-
try { nodes = Array.from(window.__Weavetab_shadowQuery_all(${JSON.stringify(query)})); } catch (_) {}
|
|
19
|
-
}
|
|
20
|
-
} else {
|
|
21
|
-
const node = document.querySelector(${JSON.stringify(query)})
|
|
22
|
-
|| (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(${JSON.stringify(query)}) : null);
|
|
23
|
-
if (node) nodes = [node];
|
|
24
|
-
}
|
|
25
|
-
} else if (${JSON.stringify(type)} === 'xpath') {
|
|
26
|
-
// Use SNAPSHOT type — immune to DOM mutations that would invalidate an ITERATOR mid-walk.
|
|
27
|
-
const snap = document.evaluate(${JSON.stringify(query)}, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
28
|
-
const limit = ${multiple} ? snap.snapshotLength : Math.min(snap.snapshotLength, 1);
|
|
29
|
-
for (let i = 0; i < limit; i++) {
|
|
30
|
-
const n = snap.snapshotItem(i);
|
|
31
|
-
// Only Element nodes expose getAttribute / tagName / outerHTML safely.
|
|
32
|
-
if (n && n.nodeType === 1) nodes.push(n);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
} catch (e) {
|
|
36
|
-
return { error: e.message };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const attrs = ${JSON.stringify(attributes)};
|
|
40
|
-
var secretRegex = /password|passcode|pin|passphrase|secret|token|auth.?key|access.?code|mot.?de.?passe|contrase[nñ]a|kennwort|senha/i;
|
|
41
|
-
nodes.forEach(node => {
|
|
42
|
-
const item = {};
|
|
43
|
-
|
|
44
|
-
// Secret containment: redact any element marked as sensitive.
|
|
45
|
-
const isSecret = node.hasAttribute && (
|
|
46
|
-
node.hasAttribute('data-wt-secret') ||
|
|
47
|
-
(node.tagName === 'INPUT' && (
|
|
48
|
-
node.type === 'password' ||
|
|
49
|
-
secretRegex.test(node.getAttribute('autocomplete') || '') ||
|
|
50
|
-
secretRegex.test(node.getAttribute('name') || '') ||
|
|
51
|
-
secretRegex.test(node.getAttribute('id') || '') ||
|
|
52
|
-
secretRegex.test(node.getAttribute('aria-label') || '')
|
|
53
|
-
))
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
if (isSecret) {
|
|
57
|
-
// Replace ALL requested attributes with [REDACTED] — value never crosses boundary
|
|
58
|
-
attrs.forEach(attr => { item[attr] = '[REDACTED]'; });
|
|
59
|
-
} else {
|
|
60
|
-
attrs.forEach(attr => {
|
|
61
|
-
if (attr === 'textContent' || attr === 'innerText') {
|
|
62
|
-
item[attr] = node[attr]?.trim() || '';
|
|
63
|
-
} else if (attr === 'outerHTML') {
|
|
64
|
-
item[attr] = node.outerHTML;
|
|
65
|
-
} else if (attr === 'value') {
|
|
66
|
-
// Read live DOM property (not HTML attribute) so getter overrides work
|
|
67
|
-
item[attr] = node.value !== undefined ? String(node.value) : '';
|
|
68
|
-
} else {
|
|
69
|
-
item[attr] = node.getAttribute(attr) || node[attr] || '';
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
results.push(item);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const isXpath = ${JSON.stringify(type)} === 'xpath';
|
|
78
|
-
const shadowFallback = !isXpath && nodes.length > 0 && !document.querySelector(${JSON.stringify(query)});
|
|
79
|
-
return { data: results, usedShadowFallback: shadowFallback };
|
|
7
|
+
expression: `(function() {
|
|
8
|
+
const results = [];
|
|
9
|
+
let nodes = [];
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
if (${JSON.stringify(type)} === 'css') {
|
|
13
|
+
if (${multiple}) {
|
|
14
|
+
nodes = Array.from(document.querySelectorAll(${JSON.stringify(query)}));
|
|
15
|
+
// Shadow DOM fallback: if nothing found, try the extension's deep-shadow query helper.
|
|
16
|
+
// This handles Vue/React components that attach to shadow roots.
|
|
17
|
+
if (nodes.length === 0 && window.__Weavetab_shadowQuery_all) {
|
|
18
|
+
try { nodes = Array.from(window.__Weavetab_shadowQuery_all(${JSON.stringify(query)})); } catch (_) {}
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
const node = document.querySelector(${JSON.stringify(query)})
|
|
22
|
+
|| (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(${JSON.stringify(query)}) : null);
|
|
23
|
+
if (node) nodes = [node];
|
|
24
|
+
}
|
|
25
|
+
} else if (${JSON.stringify(type)} === 'xpath') {
|
|
26
|
+
// Use SNAPSHOT type — immune to DOM mutations that would invalidate an ITERATOR mid-walk.
|
|
27
|
+
const snap = document.evaluate(${JSON.stringify(query)}, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
28
|
+
const limit = ${multiple} ? snap.snapshotLength : Math.min(snap.snapshotLength, 1);
|
|
29
|
+
for (let i = 0; i < limit; i++) {
|
|
30
|
+
const n = snap.snapshotItem(i);
|
|
31
|
+
// Only Element nodes expose getAttribute / tagName / outerHTML safely.
|
|
32
|
+
if (n && n.nodeType === 1) nodes.push(n);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
} catch (e) {
|
|
36
|
+
return { error: e.message };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const attrs = ${JSON.stringify(attributes)};
|
|
40
|
+
var secretRegex = /password|passcode|pin|passphrase|secret|token|auth.?key|access.?code|mot.?de.?passe|contrase[nñ]a|kennwort|senha/i;
|
|
41
|
+
nodes.forEach(node => {
|
|
42
|
+
const item = {};
|
|
43
|
+
|
|
44
|
+
// Secret containment: redact any element marked as sensitive.
|
|
45
|
+
const isSecret = node.hasAttribute && (
|
|
46
|
+
node.hasAttribute('data-wt-secret') ||
|
|
47
|
+
(node.tagName === 'INPUT' && (
|
|
48
|
+
node.type === 'password' ||
|
|
49
|
+
secretRegex.test(node.getAttribute('autocomplete') || '') ||
|
|
50
|
+
secretRegex.test(node.getAttribute('name') || '') ||
|
|
51
|
+
secretRegex.test(node.getAttribute('id') || '') ||
|
|
52
|
+
secretRegex.test(node.getAttribute('aria-label') || '')
|
|
53
|
+
))
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (isSecret) {
|
|
57
|
+
// Replace ALL requested attributes with [REDACTED] — value never crosses boundary
|
|
58
|
+
attrs.forEach(attr => { item[attr] = '[REDACTED]'; });
|
|
59
|
+
} else {
|
|
60
|
+
attrs.forEach(attr => {
|
|
61
|
+
if (attr === 'textContent' || attr === 'innerText') {
|
|
62
|
+
item[attr] = node[attr]?.trim() || '';
|
|
63
|
+
} else if (attr === 'outerHTML') {
|
|
64
|
+
item[attr] = node.outerHTML;
|
|
65
|
+
} else if (attr === 'value') {
|
|
66
|
+
// Read live DOM property (not HTML attribute) so getter overrides work
|
|
67
|
+
item[attr] = node.value !== undefined ? String(node.value) : '';
|
|
68
|
+
} else {
|
|
69
|
+
item[attr] = node.getAttribute(attr) || node[attr] || '';
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
results.push(item);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const isXpath = ${JSON.stringify(type)} === 'xpath';
|
|
78
|
+
const shadowFallback = !isXpath && nodes.length > 0 && !document.querySelector(${JSON.stringify(query)});
|
|
79
|
+
return { data: results, usedShadowFallback: shadowFallback };
|
|
80
80
|
})()`,
|
|
81
81
|
returnByValue: true
|
|
82
82
|
});
|
|
@@ -90,87 +90,87 @@ export async function browserScrape(session, options, _config) {
|
|
|
90
90
|
await new Promise(r => setTimeout(r, 300));
|
|
91
91
|
// Build a fresh count expression depending on selector type.
|
|
92
92
|
const countExpr = type === 'xpath'
|
|
93
|
-
? `(function(){
|
|
94
|
-
try {
|
|
95
|
-
var s = document.evaluate(${JSON.stringify(query)}, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
96
|
-
return s.snapshotLength;
|
|
97
|
-
} catch(e) { return 0; }
|
|
93
|
+
? `(function(){
|
|
94
|
+
try {
|
|
95
|
+
var s = document.evaluate(${JSON.stringify(query)}, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
96
|
+
return s.snapshotLength;
|
|
97
|
+
} catch(e) { return 0; }
|
|
98
98
|
})()`
|
|
99
|
-
: `(function(){
|
|
100
|
-
var n = Array.from(document.querySelectorAll(${JSON.stringify(query)}));
|
|
101
|
-
if (n.length === 0 && window.__Weavetab_shadowQuery_all) {
|
|
102
|
-
try { n = Array.from(window.__Weavetab_shadowQuery_all(${JSON.stringify(query)})); } catch(_){}
|
|
103
|
-
}
|
|
104
|
-
return n.length;
|
|
99
|
+
: `(function(){
|
|
100
|
+
var n = Array.from(document.querySelectorAll(${JSON.stringify(query)}));
|
|
101
|
+
if (n.length === 0 && window.__Weavetab_shadowQuery_all) {
|
|
102
|
+
try { n = Array.from(window.__Weavetab_shadowQuery_all(${JSON.stringify(query)})); } catch(_){}
|
|
103
|
+
}
|
|
104
|
+
return n.length;
|
|
105
105
|
})()`;
|
|
106
106
|
const retry = await session.Runtime.evaluate({ expression: countExpr, returnByValue: true }).catch(() => null);
|
|
107
107
|
if (retry?.result?.value && retry.result.value > 0) {
|
|
108
108
|
// Re-run full scrape now that elements exist.
|
|
109
109
|
// XPath path uses snapshot; CSS path uses querySelectorAll + shadow fallback.
|
|
110
110
|
const fullExpr = type === 'xpath'
|
|
111
|
-
? `(function(){
|
|
112
|
-
var attrs = ${JSON.stringify(attributes)};
|
|
113
|
-
var secretRegex = /password|passcode|pin|passphrase|secret|token|auth.?key|access.?code|mot.?de.?passe|contrase[nñ]a|kennwort|senha/i;
|
|
114
|
-
var snap = document.evaluate(${JSON.stringify(query)}, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
115
|
-
var limit = ${multiple} ? snap.snapshotLength : Math.min(snap.snapshotLength, 1);
|
|
116
|
-
var results = [];
|
|
117
|
-
for (var i = 0; i < limit; i++) {
|
|
118
|
-
var node = snap.snapshotItem(i);
|
|
119
|
-
if (!node || node.nodeType !== 1) continue;
|
|
120
|
-
var item = {};
|
|
121
|
-
var isSecret = node.hasAttribute && (
|
|
122
|
-
node.hasAttribute('data-wt-secret') ||
|
|
123
|
-
(node.tagName === 'INPUT' && (
|
|
124
|
-
node.type === 'password' ||
|
|
125
|
-
secretRegex.test(node.getAttribute('autocomplete') || '') ||
|
|
126
|
-
secretRegex.test(node.getAttribute('name') || '') ||
|
|
127
|
-
secretRegex.test(node.getAttribute('id') || '') ||
|
|
128
|
-
secretRegex.test(node.getAttribute('aria-label') || '')
|
|
129
|
-
))
|
|
130
|
-
);
|
|
131
|
-
if (isSecret) {
|
|
132
|
-
attrs.forEach(function(attr) { item[attr] = '[REDACTED]'; });
|
|
133
|
-
} else {
|
|
134
|
-
attrs.forEach(function(attr) {
|
|
135
|
-
if (attr === 'textContent' || attr === 'innerText') { item[attr] = (node[attr] || '').trim(); }
|
|
136
|
-
else if (attr === 'outerHTML') { item[attr] = node.outerHTML; }
|
|
137
|
-
else { item[attr] = node.getAttribute ? (node.getAttribute(attr) || node[attr] || '') : ''; }
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
results.push(item);
|
|
141
|
-
}
|
|
142
|
-
return { data: results };
|
|
111
|
+
? `(function(){
|
|
112
|
+
var attrs = ${JSON.stringify(attributes)};
|
|
113
|
+
var secretRegex = /password|passcode|pin|passphrase|secret|token|auth.?key|access.?code|mot.?de.?passe|contrase[nñ]a|kennwort|senha/i;
|
|
114
|
+
var snap = document.evaluate(${JSON.stringify(query)}, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
115
|
+
var limit = ${multiple} ? snap.snapshotLength : Math.min(snap.snapshotLength, 1);
|
|
116
|
+
var results = [];
|
|
117
|
+
for (var i = 0; i < limit; i++) {
|
|
118
|
+
var node = snap.snapshotItem(i);
|
|
119
|
+
if (!node || node.nodeType !== 1) continue;
|
|
120
|
+
var item = {};
|
|
121
|
+
var isSecret = node.hasAttribute && (
|
|
122
|
+
node.hasAttribute('data-wt-secret') ||
|
|
123
|
+
(node.tagName === 'INPUT' && (
|
|
124
|
+
node.type === 'password' ||
|
|
125
|
+
secretRegex.test(node.getAttribute('autocomplete') || '') ||
|
|
126
|
+
secretRegex.test(node.getAttribute('name') || '') ||
|
|
127
|
+
secretRegex.test(node.getAttribute('id') || '') ||
|
|
128
|
+
secretRegex.test(node.getAttribute('aria-label') || '')
|
|
129
|
+
))
|
|
130
|
+
);
|
|
131
|
+
if (isSecret) {
|
|
132
|
+
attrs.forEach(function(attr) { item[attr] = '[REDACTED]'; });
|
|
133
|
+
} else {
|
|
134
|
+
attrs.forEach(function(attr) {
|
|
135
|
+
if (attr === 'textContent' || attr === 'innerText') { item[attr] = (node[attr] || '').trim(); }
|
|
136
|
+
else if (attr === 'outerHTML') { item[attr] = node.outerHTML; }
|
|
137
|
+
else { item[attr] = node.getAttribute ? (node.getAttribute(attr) || node[attr] || '') : ''; }
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
results.push(item);
|
|
141
|
+
}
|
|
142
|
+
return { data: results };
|
|
143
143
|
})()`
|
|
144
|
-
: `(function(){
|
|
145
|
-
var nodes = Array.from(document.querySelectorAll(${JSON.stringify(query)}));
|
|
146
|
-
if (nodes.length === 0 && window.__Weavetab_shadowQuery_all) {
|
|
147
|
-
try { nodes = Array.from(window.__Weavetab_shadowQuery_all(${JSON.stringify(query)})); } catch(_){}
|
|
148
|
-
}
|
|
149
|
-
var attrs = ${JSON.stringify(attributes)};
|
|
150
|
-
var secretRegex = /password|passcode|pin|passphrase|secret|token|auth.?key|access.?code|mot.?de.?passe|contrase[nñ]a|kennwort|senha/i;
|
|
151
|
-
return { data: nodes.map(function(node) {
|
|
152
|
-
var item = {};
|
|
153
|
-
var isSecret = node.hasAttribute && (
|
|
154
|
-
node.hasAttribute('data-wt-secret') ||
|
|
155
|
-
(node.tagName === 'INPUT' && (
|
|
156
|
-
node.type === 'password' ||
|
|
157
|
-
secretRegex.test(node.getAttribute('autocomplete') || '') ||
|
|
158
|
-
secretRegex.test(node.getAttribute('name') || '') ||
|
|
159
|
-
secretRegex.test(node.getAttribute('id') || '') ||
|
|
160
|
-
secretRegex.test(node.getAttribute('aria-label') || '')
|
|
161
|
-
))
|
|
162
|
-
);
|
|
163
|
-
if (isSecret) {
|
|
164
|
-
attrs.forEach(function(attr) { item[attr] = '[REDACTED]'; });
|
|
165
|
-
} else {
|
|
166
|
-
attrs.forEach(function(attr) {
|
|
167
|
-
if (attr === 'textContent' || attr === 'innerText') { item[attr] = (node[attr] || '').trim(); }
|
|
168
|
-
else if (attr === 'outerHTML') { item[attr] = node.outerHTML; }
|
|
169
|
-
else { item[attr] = node.getAttribute(attr) || node[attr] || ''; }
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
return item;
|
|
173
|
-
})};
|
|
144
|
+
: `(function(){
|
|
145
|
+
var nodes = Array.from(document.querySelectorAll(${JSON.stringify(query)}));
|
|
146
|
+
if (nodes.length === 0 && window.__Weavetab_shadowQuery_all) {
|
|
147
|
+
try { nodes = Array.from(window.__Weavetab_shadowQuery_all(${JSON.stringify(query)})); } catch(_){}
|
|
148
|
+
}
|
|
149
|
+
var attrs = ${JSON.stringify(attributes)};
|
|
150
|
+
var secretRegex = /password|passcode|pin|passphrase|secret|token|auth.?key|access.?code|mot.?de.?passe|contrase[nñ]a|kennwort|senha/i;
|
|
151
|
+
return { data: nodes.map(function(node) {
|
|
152
|
+
var item = {};
|
|
153
|
+
var isSecret = node.hasAttribute && (
|
|
154
|
+
node.hasAttribute('data-wt-secret') ||
|
|
155
|
+
(node.tagName === 'INPUT' && (
|
|
156
|
+
node.type === 'password' ||
|
|
157
|
+
secretRegex.test(node.getAttribute('autocomplete') || '') ||
|
|
158
|
+
secretRegex.test(node.getAttribute('name') || '') ||
|
|
159
|
+
secretRegex.test(node.getAttribute('id') || '') ||
|
|
160
|
+
secretRegex.test(node.getAttribute('aria-label') || '')
|
|
161
|
+
))
|
|
162
|
+
);
|
|
163
|
+
if (isSecret) {
|
|
164
|
+
attrs.forEach(function(attr) { item[attr] = '[REDACTED]'; });
|
|
165
|
+
} else {
|
|
166
|
+
attrs.forEach(function(attr) {
|
|
167
|
+
if (attr === 'textContent' || attr === 'innerText') { item[attr] = (node[attr] || '').trim(); }
|
|
168
|
+
else if (attr === 'outerHTML') { item[attr] = node.outerHTML; }
|
|
169
|
+
else { item[attr] = node.getAttribute(attr) || node[attr] || ''; }
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return item;
|
|
173
|
+
})};
|
|
174
174
|
})()`;
|
|
175
175
|
const res2 = await session.Runtime.evaluate({ expression: fullExpr, returnByValue: true }).catch(() => null);
|
|
176
176
|
if (res2?.result?.value?.data) {
|
|
@@ -26,6 +26,8 @@ export interface ScreenshotOptions {
|
|
|
26
26
|
width: number;
|
|
27
27
|
height: number;
|
|
28
28
|
};
|
|
29
|
+
/** CSS selector of an element — capture is cropped to its bounding rect. */
|
|
30
|
+
selector?: string;
|
|
29
31
|
/** If false, keeps the WeaveTab UI overlay visible during capture.
|
|
30
32
|
* Default: true — overlay is always hidden from agent captures. */
|
|
31
33
|
hideOverlay?: boolean;
|
package/dist/tools/screenshot.js
CHANGED
|
@@ -9,14 +9,42 @@ export async function browserScreenshot(session, options = {}, _config) {
|
|
|
9
9
|
});
|
|
10
10
|
const vp = JSON.parse(vpResult.value);
|
|
11
11
|
let clip;
|
|
12
|
+
let beyondViewport = !!options.fullPage;
|
|
12
13
|
if (options.clip) {
|
|
13
14
|
clip = { ...options.clip, scale: 1 };
|
|
14
15
|
}
|
|
16
|
+
else if (options.selector) {
|
|
17
|
+
const { result: selResult } = await session.Runtime.evaluate({
|
|
18
|
+
expression: `(() => {
|
|
19
|
+
try {
|
|
20
|
+
const el = document.querySelector(${JSON.stringify(options.selector)});
|
|
21
|
+
if (!el) return JSON.stringify({ notFound: true });
|
|
22
|
+
const r = el.getBoundingClientRect();
|
|
23
|
+
return JSON.stringify({ x: r.x, y: r.y, width: r.width, height: r.height, docX: r.x + window.scrollX, docY: r.y + window.scrollY });
|
|
24
|
+
} catch (e) {
|
|
25
|
+
return JSON.stringify({ error: String(e && e.message || e) });
|
|
26
|
+
}
|
|
27
|
+
})()`,
|
|
28
|
+
returnByValue: true,
|
|
29
|
+
});
|
|
30
|
+
const sel = selResult?.value ? JSON.parse(selResult.value) : { notFound: true };
|
|
31
|
+
if (sel.error) {
|
|
32
|
+
throw new Error(`browser_screenshot selector failed: ${sel.error}`);
|
|
33
|
+
}
|
|
34
|
+
if (sel.notFound || !selResult?.value) {
|
|
35
|
+
throw new Error(`browser_screenshot: no element found for selector '${options.selector}'`);
|
|
36
|
+
}
|
|
37
|
+
if (sel.width === 0 || sel.height === 0) {
|
|
38
|
+
throw new Error(`browser_screenshot: element matched by '${options.selector}' has no size (display: none or not laid out)`);
|
|
39
|
+
}
|
|
40
|
+
clip = { x: sel.docX, y: sel.docY, width: sel.width, height: sel.height, scale: 1 };
|
|
41
|
+
beyondViewport = true;
|
|
42
|
+
}
|
|
15
43
|
else if (options.fullPage) {
|
|
16
44
|
const { result: scrollResult } = await session.Runtime.evaluate({
|
|
17
|
-
expression: `JSON.stringify({
|
|
18
|
-
w: Math.max(document.documentElement.scrollWidth, document.body.scrollWidth),
|
|
19
|
-
h: Math.max(document.documentElement.scrollHeight, document.body.scrollHeight)
|
|
45
|
+
expression: `JSON.stringify({
|
|
46
|
+
w: Math.max(document.documentElement.scrollWidth, document.body.scrollWidth),
|
|
47
|
+
h: Math.max(document.documentElement.scrollHeight, document.body.scrollHeight)
|
|
20
48
|
})`,
|
|
21
49
|
returnByValue: true,
|
|
22
50
|
});
|
|
@@ -26,7 +54,7 @@ export async function browserScreenshot(session, options = {}, _config) {
|
|
|
26
54
|
// ── Auto-compress: if viewport is wide, downscale to 1280px wide as JPEG 75% ──
|
|
27
55
|
// This cuts token cost by 40-60% with no quality loss for text content.
|
|
28
56
|
// Only applies when no explicit format/clip was requested.
|
|
29
|
-
const params = { format, captureBeyondViewport:
|
|
57
|
+
const params = { format, captureBeyondViewport: beyondViewport };
|
|
30
58
|
if (!options.clip && !options.format && vp.w > 1280) {
|
|
31
59
|
const scale = 1280 / vp.w;
|
|
32
60
|
params.format = 'jpeg';
|
|
@@ -67,6 +95,20 @@ export async function browserScreenshot(session, options = {}, _config) {
|
|
|
67
95
|
throw e;
|
|
68
96
|
}
|
|
69
97
|
}
|
|
98
|
+
const MAX_BASE64 = 2 * 1024 * 1024;
|
|
99
|
+
for (const q of [70, 40]) {
|
|
100
|
+
if (data.length <= MAX_BASE64)
|
|
101
|
+
break;
|
|
102
|
+
if (params.format === "jpeg" && (params.quality ?? 90) <= q)
|
|
103
|
+
break;
|
|
104
|
+
params.format = "jpeg";
|
|
105
|
+
params.quality = q;
|
|
106
|
+
const res = await session.Page.captureScreenshot(params);
|
|
107
|
+
data = res.data;
|
|
108
|
+
}
|
|
109
|
+
if (data.length > MAX_BASE64) {
|
|
110
|
+
throw new Error(`Screenshot payload exceeds the 2MB MCP size limit even at JPEG quality 40. Narrow the capture with clip or selector.`);
|
|
111
|
+
}
|
|
70
112
|
}
|
|
71
113
|
finally {
|
|
72
114
|
// Restore secret fields and overlay visibility immediately after capture
|
package/dist/tools/scroll.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface ScrollResult {
|
|
|
11
11
|
scrolled: string;
|
|
12
12
|
direction: string;
|
|
13
13
|
distance: number;
|
|
14
|
-
new_visible_count
|
|
14
|
+
new_visible_count?: number;
|
|
15
15
|
dom_changed: boolean;
|
|
16
16
|
}
|
|
17
17
|
export declare function browserScroll(session: CDP.Client, args: {
|
|
@@ -19,5 +19,7 @@ export declare function browserScroll(session: CDP.Client, args: {
|
|
|
19
19
|
label?: string;
|
|
20
20
|
direction: "up" | "down" | "left" | "right";
|
|
21
21
|
distance?: number;
|
|
22
|
+
pixels?: number;
|
|
23
|
+
amount?: number;
|
|
22
24
|
speed?: "human" | "read" | "fast";
|
|
23
25
|
}, config: Config): Promise<ScrollResult | WeaveError>;
|
package/dist/tools/scroll.js
CHANGED
|
@@ -30,7 +30,8 @@ function applyEasing(t, type) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
export async function browserScroll(session, args, config) {
|
|
33
|
-
let { id, label, direction,
|
|
33
|
+
let { id, label, direction, speed = "human" } = args;
|
|
34
|
+
let distance = args.distance ?? args.pixels ?? args.amount ?? 400;
|
|
34
35
|
if (distance < 0) {
|
|
35
36
|
distance = Math.abs(distance);
|
|
36
37
|
if (direction === "down")
|
|
@@ -111,14 +112,14 @@ export async function browserScroll(session, args, config) {
|
|
|
111
112
|
let elementFound = false;
|
|
112
113
|
try {
|
|
113
114
|
const res = await session.Runtime.evaluate({
|
|
114
|
-
expression: `(function(sel) {
|
|
115
|
-
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
116
|
-
if (!el) return null;
|
|
117
|
-
const rect = el.getBoundingClientRect();
|
|
118
|
-
return {
|
|
119
|
-
x: rect.left + rect.width / 2,
|
|
120
|
-
y: rect.top + rect.height / 2
|
|
121
|
-
};
|
|
115
|
+
expression: `(function(sel) {
|
|
116
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
117
|
+
if (!el) return null;
|
|
118
|
+
const rect = el.getBoundingClientRect();
|
|
119
|
+
return {
|
|
120
|
+
x: rect.left + rect.width / 2,
|
|
121
|
+
y: rect.top + rect.height / 2
|
|
122
|
+
};
|
|
122
123
|
})(${JSON.stringify(scrollSelector)})`,
|
|
123
124
|
returnByValue: true
|
|
124
125
|
});
|
|
@@ -151,12 +152,10 @@ export async function browserScroll(session, args, config) {
|
|
|
151
152
|
const profile = profiles[speed];
|
|
152
153
|
const totalPx = direction === 'down' ? distance : direction === 'up' ? -distance : 0;
|
|
153
154
|
const totalPxX = direction === 'right' ? distance : direction === 'left' ? -distance : 0;
|
|
154
|
-
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
cacheActionMap(targetId, map);
|
|
155
|
+
const map = getCachedActionMap(targetId, url);
|
|
156
|
+
if (map) {
|
|
157
|
+
storeSnapshot(targetId, map.url, map.elements);
|
|
158
158
|
}
|
|
159
|
-
storeSnapshot(targetId, map.url, map.elements);
|
|
160
159
|
const viewportRes = await session.Runtime.evaluate({
|
|
161
160
|
expression: `JSON.stringify({ x: window.innerWidth / 2, y: window.innerHeight / 2 })`,
|
|
162
161
|
returnByValue: true
|
|
@@ -185,7 +184,6 @@ export async function browserScroll(session, args, config) {
|
|
|
185
184
|
scrolled: id ?? label ?? "window",
|
|
186
185
|
direction,
|
|
187
186
|
distance,
|
|
188
|
-
new_visible_count: 0,
|
|
189
187
|
dom_changed: true,
|
|
190
188
|
};
|
|
191
189
|
}
|
package/dist/tools/select.d.ts
CHANGED
|
@@ -5,9 +5,12 @@ export interface SelectOptions {
|
|
|
5
5
|
selector?: string;
|
|
6
6
|
ref?: string;
|
|
7
7
|
id?: string;
|
|
8
|
+
target?: string;
|
|
8
9
|
value: string;
|
|
9
10
|
}
|
|
10
11
|
export declare function browserSelect(session: CDP.Client, options: SelectOptions, _config: Config): Promise<{
|
|
11
12
|
success: boolean;
|
|
12
13
|
message: string;
|
|
14
|
+
value?: string;
|
|
15
|
+
selected?: string;
|
|
13
16
|
}>;
|