@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/type.js
CHANGED
|
@@ -22,12 +22,12 @@ import { verifyActionability, quickHitCheck } from "../sensors/actionability.js"
|
|
|
22
22
|
export async function detectFramework(session) {
|
|
23
23
|
try {
|
|
24
24
|
const { result } = await session.Runtime.evaluate({
|
|
25
|
-
expression: `(function() {
|
|
26
|
-
const root = document.documentElement;
|
|
27
|
-
if (root.__reactFiber || root._reactRootContainer || window.React || window.react) return 'react';
|
|
28
|
-
if (root.__vue__ || document.querySelector('[data-v-]') || window.Vue || window.vue) return 'vue';
|
|
29
|
-
if (root.ng || document.querySelector('[ng-version]') || window.angular || window.ng) return 'angular';
|
|
30
|
-
return 'vanilla';
|
|
25
|
+
expression: `(function() {
|
|
26
|
+
const root = document.documentElement;
|
|
27
|
+
if (root.__reactFiber || root._reactRootContainer || window.React || window.react) return 'react';
|
|
28
|
+
if (root.__vue__ || document.querySelector('[data-v-]') || window.Vue || window.vue) return 'vue';
|
|
29
|
+
if (root.ng || document.querySelector('[ng-version]') || window.angular || window.ng) return 'angular';
|
|
30
|
+
return 'vanilla';
|
|
31
31
|
})()`,
|
|
32
32
|
returnByValue: true,
|
|
33
33
|
});
|
|
@@ -40,14 +40,14 @@ export async function detectFramework(session) {
|
|
|
40
40
|
async function focusEditable(session, objectId, clearFirst, fast = false) {
|
|
41
41
|
const { Input } = session;
|
|
42
42
|
await session.Runtime.callFunctionOn({
|
|
43
|
-
functionDeclaration: `async function() {
|
|
44
|
-
if (this.scrollIntoViewIfNeeded) this.scrollIntoViewIfNeeded();
|
|
45
|
-
else {
|
|
46
|
-
this.scrollIntoView({behavior:'smooth',block:'center'});
|
|
47
|
-
await new Promise(r => setTimeout(r, ${fast ? 50 : 400}));
|
|
48
|
-
}
|
|
49
|
-
this.focus();
|
|
50
|
-
this.click();
|
|
43
|
+
functionDeclaration: `async function() {
|
|
44
|
+
if (this.scrollIntoViewIfNeeded) this.scrollIntoViewIfNeeded();
|
|
45
|
+
else {
|
|
46
|
+
this.scrollIntoView({behavior:'smooth',block:'center'});
|
|
47
|
+
await new Promise(r => setTimeout(r, ${fast ? 50 : 400}));
|
|
48
|
+
}
|
|
49
|
+
this.focus();
|
|
50
|
+
this.click();
|
|
51
51
|
}`,
|
|
52
52
|
objectId,
|
|
53
53
|
silent: true,
|
|
@@ -55,15 +55,15 @@ async function focusEditable(session, objectId, clearFirst, fast = false) {
|
|
|
55
55
|
});
|
|
56
56
|
if (clearFirst) {
|
|
57
57
|
await session.Runtime.callFunctionOn({
|
|
58
|
-
functionDeclaration: `function() {
|
|
59
|
-
if (typeof this.select === 'function') this.select();
|
|
60
|
-
else if (this.isContentEditable) {
|
|
61
|
-
this.textContent = '';
|
|
62
|
-
this.dispatchEvent(new Event('input', { bubbles: true }));
|
|
63
|
-
} else {
|
|
64
|
-
this.value = '';
|
|
65
|
-
this.dispatchEvent(new Event('input', { bubbles: true }));
|
|
66
|
-
}
|
|
58
|
+
functionDeclaration: `function() {
|
|
59
|
+
if (typeof this.select === 'function') this.select();
|
|
60
|
+
else if (this.isContentEditable) {
|
|
61
|
+
this.textContent = '';
|
|
62
|
+
this.dispatchEvent(new Event('input', { bubbles: true }));
|
|
63
|
+
} else {
|
|
64
|
+
this.value = '';
|
|
65
|
+
this.dispatchEvent(new Event('input', { bubbles: true }));
|
|
66
|
+
}
|
|
67
67
|
}`,
|
|
68
68
|
objectId,
|
|
69
69
|
silent: true,
|
|
@@ -90,34 +90,34 @@ export async function frameworkAwareType(session, objectId, text, framework) {
|
|
|
90
90
|
// for — the old `.simulated = true` trick only worked in React <16 and is a
|
|
91
91
|
// no-op in modern React (Event properties are frozen after construction).
|
|
92
92
|
await Runtime.callFunctionOn({
|
|
93
|
-
functionDeclaration: `function(text) {
|
|
94
|
-
const nativeInputSetter = Object.getOwnPropertyDescriptor(
|
|
95
|
-
window.HTMLInputElement.prototype, 'value'
|
|
96
|
-
)?.set;
|
|
97
|
-
const nativeTextAreaSetter = Object.getOwnPropertyDescriptor(
|
|
98
|
-
window.HTMLTextAreaElement.prototype, 'value'
|
|
99
|
-
)?.set;
|
|
100
|
-
|
|
101
|
-
if (this.tagName === 'INPUT' && nativeInputSetter) {
|
|
102
|
-
nativeInputSetter.call(this, text);
|
|
103
|
-
} else if (this.tagName === 'TEXTAREA' && nativeTextAreaSetter) {
|
|
104
|
-
nativeTextAreaSetter.call(this, text);
|
|
105
|
-
} else if (this.isContentEditable) {
|
|
106
|
-
this.textContent = text;
|
|
107
|
-
} else {
|
|
108
|
-
this.value = text;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Single InputEvent with inputType:'insertText' — React 16/17/18 SyntheticEvent
|
|
112
|
-
// source. Do NOT also dispatch a plain Event('input') here; that would
|
|
113
|
-
// fire the onChange handler a second time and duplicate the value.
|
|
114
|
-
this.dispatchEvent(new InputEvent('input', {
|
|
115
|
-
bubbles: true,
|
|
116
|
-
cancelable: true,
|
|
117
|
-
inputType: 'insertText',
|
|
118
|
-
data: text,
|
|
119
|
-
}));
|
|
120
|
-
this.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));
|
|
93
|
+
functionDeclaration: `function(text) {
|
|
94
|
+
const nativeInputSetter = Object.getOwnPropertyDescriptor(
|
|
95
|
+
window.HTMLInputElement.prototype, 'value'
|
|
96
|
+
)?.set;
|
|
97
|
+
const nativeTextAreaSetter = Object.getOwnPropertyDescriptor(
|
|
98
|
+
window.HTMLTextAreaElement.prototype, 'value'
|
|
99
|
+
)?.set;
|
|
100
|
+
|
|
101
|
+
if (this.tagName === 'INPUT' && nativeInputSetter) {
|
|
102
|
+
nativeInputSetter.call(this, text);
|
|
103
|
+
} else if (this.tagName === 'TEXTAREA' && nativeTextAreaSetter) {
|
|
104
|
+
nativeTextAreaSetter.call(this, text);
|
|
105
|
+
} else if (this.isContentEditable) {
|
|
106
|
+
this.textContent = text;
|
|
107
|
+
} else {
|
|
108
|
+
this.value = text;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Single InputEvent with inputType:'insertText' — React 16/17/18 SyntheticEvent
|
|
112
|
+
// source. Do NOT also dispatch a plain Event('input') here; that would
|
|
113
|
+
// fire the onChange handler a second time and duplicate the value.
|
|
114
|
+
this.dispatchEvent(new InputEvent('input', {
|
|
115
|
+
bubbles: true,
|
|
116
|
+
cancelable: true,
|
|
117
|
+
inputType: 'insertText',
|
|
118
|
+
data: text,
|
|
119
|
+
}));
|
|
120
|
+
this.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));
|
|
121
121
|
}`,
|
|
122
122
|
objectId,
|
|
123
123
|
arguments: [{ value: text }],
|
|
@@ -165,15 +165,15 @@ async function resolveTypingTarget(session, map, args, _targetId) {
|
|
|
165
165
|
if (!element && id && !id.startsWith("w:")) {
|
|
166
166
|
try {
|
|
167
167
|
const checkEl = await session.Runtime.evaluate({
|
|
168
|
-
expression: `(function(){
|
|
169
|
-
const el = document.querySelector(${JSON.stringify(id)}) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(${JSON.stringify(id)}) : null);
|
|
170
|
-
if (!el) return null;
|
|
171
|
-
const r = el.getBoundingClientRect();
|
|
172
|
-
return {
|
|
173
|
-
label: el.getAttribute('aria-label') || el.getAttribute('placeholder') || el.getAttribute('name') || 'selector-match',
|
|
174
|
-
x: Math.round(r.left + r.width / 2),
|
|
175
|
-
y: Math.round(r.top + r.height / 2)
|
|
176
|
-
};
|
|
168
|
+
expression: `(function(){
|
|
169
|
+
const el = document.querySelector(${JSON.stringify(id)}) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(${JSON.stringify(id)}) : null);
|
|
170
|
+
if (!el) return null;
|
|
171
|
+
const r = el.getBoundingClientRect();
|
|
172
|
+
return {
|
|
173
|
+
label: el.getAttribute('aria-label') || el.getAttribute('placeholder') || el.getAttribute('name') || 'selector-match',
|
|
174
|
+
x: Math.round(r.left + r.width / 2),
|
|
175
|
+
y: Math.round(r.top + r.height / 2)
|
|
176
|
+
};
|
|
177
177
|
})()`,
|
|
178
178
|
returnByValue: true
|
|
179
179
|
});
|
|
@@ -248,48 +248,48 @@ async function resolveTypingTarget(session, map, args, _targetId) {
|
|
|
248
248
|
return null;
|
|
249
249
|
}
|
|
250
250
|
const active = await session.Runtime.evaluate({
|
|
251
|
-
expression: `(function(){
|
|
252
|
-
const pick = (el) => {
|
|
253
|
-
if (!el) return null;
|
|
254
|
-
const r = el.getBoundingClientRect();
|
|
255
|
-
if (r.width < 20 || r.height < 10) return null;
|
|
256
|
-
if (r.bottom < 0 || r.top > innerHeight) return null;
|
|
257
|
-
return {
|
|
258
|
-
label: el.getAttribute('aria-label') || el.getAttribute('placeholder') || el.getAttribute('name') || (el.textContent||'').trim().slice(0,40) || 'input',
|
|
259
|
-
selector: ['textarea[name="q"]','input[name="q"]','[aria-label="Search"]','[title="Search"]','input[type="search"]','textarea','input[type="text"]','input:not([type])','[role="combobox"]','[role="textbox"]','[contenteditable="true"]','[contenteditable=""]'].find(function(s){try{return el.matches(s)}catch(e){return false}}) || '',
|
|
260
|
-
x: Math.round(r.left + r.width/2),
|
|
261
|
-
y: Math.round(r.top + r.height/2)
|
|
262
|
-
};
|
|
263
|
-
};
|
|
264
|
-
var el = document.activeElement;
|
|
265
|
-
var isEditable = el && el !== document.body && (
|
|
266
|
-
el.isContentEditable ||
|
|
267
|
-
el.tagName === 'TEXTAREA' ||
|
|
268
|
-
(el.tagName === 'INPUT' && !['button','submit','checkbox','radio','hidden','file'].includes((el.type||'').toLowerCase())) ||
|
|
269
|
-
el.getAttribute('role') === 'textbox' || el.getAttribute('role') === 'searchbox' || el.getAttribute('role') === 'combobox'
|
|
270
|
-
);
|
|
271
|
-
if (isEditable) {
|
|
272
|
-
var fromActive = pick(el);
|
|
273
|
-
if (fromActive) return JSON.stringify(fromActive);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
var sel = 'textarea[name="q"], input[name="q"], [aria-label="Search"], [title="Search"]';
|
|
277
|
-
var q = document.querySelector(sel);
|
|
278
|
-
var fromQ = pick(q);
|
|
279
|
-
if (fromQ) return JSON.stringify(fromQ);
|
|
280
|
-
|
|
281
|
-
var sels = ['[contenteditable="true"]','[contenteditable=""]','textarea','input[type="search"]','input[type="text"]','input:not([type])','[role="textbox"]','[role="combobox"]','input[name="q"]'];
|
|
282
|
-
var best = null, bestArea = 0;
|
|
283
|
-
for (var si = 0; si < sels.length; si++) {
|
|
284
|
-
var nodes = document.querySelectorAll(sels[si]);
|
|
285
|
-
for (var ni = 0; ni < nodes.length; ni++) {
|
|
286
|
-
var r = nodes[ni].getBoundingClientRect();
|
|
287
|
-
var area = r.width * r.height;
|
|
288
|
-
if (area > bestArea && r.top >= 0 && r.top < innerHeight) { bestArea = area; best = nodes[ni]; }
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
if (!best) return null;
|
|
292
|
-
return JSON.stringify(pick(best));
|
|
251
|
+
expression: `(function(){
|
|
252
|
+
const pick = (el) => {
|
|
253
|
+
if (!el) return null;
|
|
254
|
+
const r = el.getBoundingClientRect();
|
|
255
|
+
if (r.width < 20 || r.height < 10) return null;
|
|
256
|
+
if (r.bottom < 0 || r.top > innerHeight) return null;
|
|
257
|
+
return {
|
|
258
|
+
label: el.getAttribute('aria-label') || el.getAttribute('placeholder') || el.getAttribute('name') || (el.textContent||'').trim().slice(0,40) || 'input',
|
|
259
|
+
selector: ['textarea[name="q"]','input[name="q"]','[aria-label="Search"]','[title="Search"]','input[type="search"]','textarea','input[type="text"]','input:not([type])','[role="combobox"]','[role="textbox"]','[contenteditable="true"]','[contenteditable=""]'].find(function(s){try{return el.matches(s)}catch(e){return false}}) || '',
|
|
260
|
+
x: Math.round(r.left + r.width/2),
|
|
261
|
+
y: Math.round(r.top + r.height/2)
|
|
262
|
+
};
|
|
263
|
+
};
|
|
264
|
+
var el = document.activeElement;
|
|
265
|
+
var isEditable = el && el !== document.body && (
|
|
266
|
+
el.isContentEditable ||
|
|
267
|
+
el.tagName === 'TEXTAREA' ||
|
|
268
|
+
(el.tagName === 'INPUT' && !['button','submit','checkbox','radio','hidden','file'].includes((el.type||'').toLowerCase())) ||
|
|
269
|
+
el.getAttribute('role') === 'textbox' || el.getAttribute('role') === 'searchbox' || el.getAttribute('role') === 'combobox'
|
|
270
|
+
);
|
|
271
|
+
if (isEditable) {
|
|
272
|
+
var fromActive = pick(el);
|
|
273
|
+
if (fromActive) return JSON.stringify(fromActive);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
var sel = 'textarea[name="q"], input[name="q"], [aria-label="Search"], [title="Search"]';
|
|
277
|
+
var q = document.querySelector(sel);
|
|
278
|
+
var fromQ = pick(q);
|
|
279
|
+
if (fromQ) return JSON.stringify(fromQ);
|
|
280
|
+
|
|
281
|
+
var sels = ['[contenteditable="true"]','[contenteditable=""]','textarea','input[type="search"]','input[type="text"]','input:not([type])','[role="textbox"]','[role="combobox"]','input[name="q"]'];
|
|
282
|
+
var best = null, bestArea = 0;
|
|
283
|
+
for (var si = 0; si < sels.length; si++) {
|
|
284
|
+
var nodes = document.querySelectorAll(sels[si]);
|
|
285
|
+
for (var ni = 0; ni < nodes.length; ni++) {
|
|
286
|
+
var r = nodes[ni].getBoundingClientRect();
|
|
287
|
+
var area = r.width * r.height;
|
|
288
|
+
if (area > bestArea && r.top >= 0 && r.top < innerHeight) { bestArea = area; best = nodes[ni]; }
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (!best) return null;
|
|
292
|
+
return JSON.stringify(pick(best));
|
|
293
293
|
})()`,
|
|
294
294
|
returnByValue: true,
|
|
295
295
|
}).catch(() => null);
|
|
@@ -434,21 +434,21 @@ export async function weaveType(session, args, config) {
|
|
|
434
434
|
}
|
|
435
435
|
if (target && target.selector) {
|
|
436
436
|
const isEditableRes = await session.Runtime.evaluate({
|
|
437
|
-
expression: `(function(sel) {
|
|
438
|
-
const el = document.querySelector(sel);
|
|
439
|
-
if (!el) return true; // optimistic: let it try
|
|
440
|
-
const tag = el.tagName.toLowerCase();
|
|
441
|
-
const t = (el.getAttribute('type') || '').toLowerCase();
|
|
442
|
-
const role = (el.getAttribute('role') || '').toLowerCase();
|
|
443
|
-
// Standard editable
|
|
444
|
-
if (el.isContentEditable) return true;
|
|
445
|
-
if (tag === 'textarea') return true;
|
|
446
|
-
if (tag === 'input' && !['button','submit','checkbox','radio','hidden','file','image','reset'].includes(t)) return true;
|
|
447
|
-
// ARIA editable roles — many custom widgets use these
|
|
448
|
-
if (role === 'textbox' || role === 'combobox' || role === 'searchbox' || role === 'spinbutton') return true;
|
|
449
|
-
// Custom div/span inputs often have no role — check for contenteditable ancestors
|
|
450
|
-
if (el.closest('[contenteditable]')) return true;
|
|
451
|
-
return false;
|
|
437
|
+
expression: `(function(sel) {
|
|
438
|
+
const el = document.querySelector(sel);
|
|
439
|
+
if (!el) return true; // optimistic: let it try
|
|
440
|
+
const tag = el.tagName.toLowerCase();
|
|
441
|
+
const t = (el.getAttribute('type') || '').toLowerCase();
|
|
442
|
+
const role = (el.getAttribute('role') || '').toLowerCase();
|
|
443
|
+
// Standard editable
|
|
444
|
+
if (el.isContentEditable) return true;
|
|
445
|
+
if (tag === 'textarea') return true;
|
|
446
|
+
if (tag === 'input' && !['button','submit','checkbox','radio','hidden','file','image','reset'].includes(t)) return true;
|
|
447
|
+
// ARIA editable roles — many custom widgets use these
|
|
448
|
+
if (role === 'textbox' || role === 'combobox' || role === 'searchbox' || role === 'spinbutton') return true;
|
|
449
|
+
// Custom div/span inputs often have no role — check for contenteditable ancestors
|
|
450
|
+
if (el.closest('[contenteditable]')) return true;
|
|
451
|
+
return false;
|
|
452
452
|
})(${JSON.stringify(target.selector)})`,
|
|
453
453
|
returnByValue: true
|
|
454
454
|
}).catch(() => null);
|
|
@@ -483,14 +483,14 @@ export async function weaveType(session, args, config) {
|
|
|
483
483
|
let frameUrl = null;
|
|
484
484
|
try {
|
|
485
485
|
const res = await session.Runtime.evaluate({
|
|
486
|
-
expression: `(function(sel) {
|
|
487
|
-
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
488
|
-
if (!el) return null;
|
|
489
|
-
return {
|
|
490
|
-
coords: window.__Weavetab_getCoords(sel),
|
|
491
|
-
inIframe: el.ownerDocument.defaultView !== window,
|
|
492
|
-
frameUrl: el.ownerDocument.defaultView.location.href
|
|
493
|
-
};
|
|
486
|
+
expression: `(function(sel) {
|
|
487
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
488
|
+
if (!el) return null;
|
|
489
|
+
return {
|
|
490
|
+
coords: window.__Weavetab_getCoords(sel),
|
|
491
|
+
inIframe: el.ownerDocument.defaultView !== window,
|
|
492
|
+
frameUrl: el.ownerDocument.defaultView.location.href
|
|
493
|
+
};
|
|
494
494
|
})(${JSON.stringify(selector)})`,
|
|
495
495
|
returnByValue: true
|
|
496
496
|
});
|
|
@@ -550,17 +550,17 @@ export async function weaveType(session, args, config) {
|
|
|
550
550
|
// Detect password / secret fields early to protect HUD, logs, and register secret
|
|
551
551
|
const isSecretParam = !!args.isSecret || !!args.secret;
|
|
552
552
|
const isPassword = isSecretParam || await session.Runtime.evaluate({
|
|
553
|
-
expression: `(function(sel) {
|
|
554
|
-
const el = (sel === 'document.activeElement') ? document.activeElement : (document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null));
|
|
555
|
-
if (!el) return false;
|
|
556
|
-
const t = (el.getAttribute('type') || '').toLowerCase();
|
|
557
|
-
const ac = (el.getAttribute('autocomplete') || '').toLowerCase();
|
|
558
|
-
const name = (el.getAttribute('name') || '').toLowerCase();
|
|
559
|
-
const id = (el.getAttribute('id') || '').toLowerCase();
|
|
560
|
-
const aria = (el.getAttribute('aria-label') || '').toLowerCase();
|
|
561
|
-
const isSecAttr = el.hasAttribute('data-wt-secret');
|
|
562
|
-
const secretRegex = /password|passcode|pin|passphrase|secret|token|auth.?key|access.?code|mot.?de.?passe|contrase[nñ]a|kennwort|senha/i;
|
|
563
|
-
return isSecAttr || t === 'password' || ac.includes('password') || secretRegex.test(name) || secretRegex.test(id) || secretRegex.test(aria);
|
|
553
|
+
expression: `(function(sel) {
|
|
554
|
+
const el = (sel === 'document.activeElement') ? document.activeElement : (document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null));
|
|
555
|
+
if (!el) return false;
|
|
556
|
+
const t = (el.getAttribute('type') || '').toLowerCase();
|
|
557
|
+
const ac = (el.getAttribute('autocomplete') || '').toLowerCase();
|
|
558
|
+
const name = (el.getAttribute('name') || '').toLowerCase();
|
|
559
|
+
const id = (el.getAttribute('id') || '').toLowerCase();
|
|
560
|
+
const aria = (el.getAttribute('aria-label') || '').toLowerCase();
|
|
561
|
+
const isSecAttr = el.hasAttribute('data-wt-secret');
|
|
562
|
+
const secretRegex = /password|passcode|pin|passphrase|secret|token|auth.?key|access.?code|mot.?de.?passe|contrase[nñ]a|kennwort|senha/i;
|
|
563
|
+
return isSecAttr || t === 'password' || ac.includes('password') || secretRegex.test(name) || secretRegex.test(id) || secretRegex.test(aria);
|
|
564
564
|
})(${JSON.stringify(selector)})`,
|
|
565
565
|
returnByValue: true
|
|
566
566
|
}).then(r => r.result?.value === true).catch(() => false);
|
|
@@ -602,10 +602,10 @@ export async function weaveType(session, args, config) {
|
|
|
602
602
|
}
|
|
603
603
|
// Check if element is ALREADY focused before clicking it to prevent unfocusing or toggling
|
|
604
604
|
const alreadyFocusedRes = await session.Runtime.evaluate({
|
|
605
|
-
expression: `(function(sel) {
|
|
606
|
-
if (!sel || sel === 'document.activeElement') return true;
|
|
607
|
-
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
608
|
-
return el ? (document.activeElement === el || el.contains(document.activeElement)) : false;
|
|
605
|
+
expression: `(function(sel) {
|
|
606
|
+
if (!sel || sel === 'document.activeElement') return true;
|
|
607
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
608
|
+
return el ? (document.activeElement === el || el.contains(document.activeElement)) : false;
|
|
609
609
|
})(${JSON.stringify(selector)})`,
|
|
610
610
|
returnByValue: true
|
|
611
611
|
}).catch(() => null);
|
|
@@ -618,10 +618,10 @@ export async function weaveType(session, args, config) {
|
|
|
618
618
|
else if (isAlreadyFocused) {
|
|
619
619
|
// Ensure focus without hardware click re-trigger
|
|
620
620
|
await session.Runtime.evaluate({
|
|
621
|
-
expression: `(function(sel) {
|
|
622
|
-
if (!sel || sel === 'document.activeElement') return;
|
|
623
|
-
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
624
|
-
if (el && typeof el.focus === 'function') el.focus();
|
|
621
|
+
expression: `(function(sel) {
|
|
622
|
+
if (!sel || sel === 'document.activeElement') return;
|
|
623
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
624
|
+
if (el && typeof el.focus === 'function') el.focus();
|
|
625
625
|
})(${JSON.stringify(selector)})`,
|
|
626
626
|
returnByValue: false
|
|
627
627
|
}).catch(() => { });
|
|
@@ -630,20 +630,20 @@ export async function weaveType(session, args, config) {
|
|
|
630
630
|
const shouldPaste = args.paste || text.length > 8;
|
|
631
631
|
if (clearFirst === true && !shouldPaste) {
|
|
632
632
|
await session.Runtime.evaluate({
|
|
633
|
-
expression: `(function(sel) {
|
|
634
|
-
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
635
|
-
if (!el) return;
|
|
636
|
-
if (el.isContentEditable) {
|
|
637
|
-
el.textContent = '';
|
|
638
|
-
} else {
|
|
639
|
-
el.value = '';
|
|
640
|
-
const nativeSetter = el.tagName === 'TEXTAREA'
|
|
641
|
-
? Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set
|
|
642
|
-
: Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
|
|
643
|
-
if (nativeSetter) nativeSetter.call(el, '');
|
|
644
|
-
}
|
|
645
|
-
el.dispatchEvent(new Event('input',{bubbles:true}));
|
|
646
|
-
el.dispatchEvent(new Event('change',{bubbles:true}));
|
|
633
|
+
expression: `(function(sel) {
|
|
634
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
635
|
+
if (!el) return;
|
|
636
|
+
if (el.isContentEditable) {
|
|
637
|
+
el.textContent = '';
|
|
638
|
+
} else {
|
|
639
|
+
el.value = '';
|
|
640
|
+
const nativeSetter = el.tagName === 'TEXTAREA'
|
|
641
|
+
? Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set
|
|
642
|
+
: Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
|
|
643
|
+
if (nativeSetter) nativeSetter.call(el, '');
|
|
644
|
+
}
|
|
645
|
+
el.dispatchEvent(new Event('input',{bubbles:true}));
|
|
646
|
+
el.dispatchEvent(new Event('change',{bubbles:true}));
|
|
647
647
|
})(${JSON.stringify(selector)})`,
|
|
648
648
|
returnByValue: false,
|
|
649
649
|
}).catch(() => { });
|
|
@@ -652,9 +652,9 @@ export async function weaveType(session, args, config) {
|
|
|
652
652
|
}
|
|
653
653
|
// Verify focus landed correctly
|
|
654
654
|
const focusCheck = await session.Runtime.evaluate({
|
|
655
|
-
expression: `(function(sel) {
|
|
656
|
-
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
657
|
-
return document.activeElement === el || (el ? el.contains(document.activeElement) : false);
|
|
655
|
+
expression: `(function(sel) {
|
|
656
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
657
|
+
return document.activeElement === el || (el ? el.contains(document.activeElement) : false);
|
|
658
658
|
})(${JSON.stringify(selector)})`,
|
|
659
659
|
returnByValue: true
|
|
660
660
|
}).catch(() => null);
|
|
@@ -703,12 +703,12 @@ export async function weaveType(session, args, config) {
|
|
|
703
703
|
// fallback to Input.insertText which targets the currently-focused element.
|
|
704
704
|
if (selector) {
|
|
705
705
|
const pasteCheck = await session.Runtime.evaluate({
|
|
706
|
-
expression: `(function(sel) {
|
|
707
|
-
var el = (sel === 'document.activeElement') ? document.activeElement : (document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null));
|
|
708
|
-
if (!el) return null;
|
|
709
|
-
var isSec = el.hasAttribute('data-wt-secret') || (el.tagName === 'INPUT' && el.type === 'password');
|
|
710
|
-
if (isSec) return (el.value && el.value.length > 0) ? '__HAS_CONTENT__' : '';
|
|
711
|
-
return el.value !== undefined ? el.value : (el.textContent || null);
|
|
706
|
+
expression: `(function(sel) {
|
|
707
|
+
var el = (sel === 'document.activeElement') ? document.activeElement : (document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null));
|
|
708
|
+
if (!el) return null;
|
|
709
|
+
var isSec = el.hasAttribute('data-wt-secret') || (el.tagName === 'INPUT' && el.type === 'password');
|
|
710
|
+
if (isSec) return (el.value && el.value.length > 0) ? '__HAS_CONTENT__' : '';
|
|
711
|
+
return el.value !== undefined ? el.value : (el.textContent || null);
|
|
712
712
|
})(${JSON.stringify(selector)})`,
|
|
713
713
|
returnByValue: true,
|
|
714
714
|
}).catch(() => null);
|
|
@@ -739,33 +739,33 @@ export async function weaveType(session, args, config) {
|
|
|
739
739
|
else {
|
|
740
740
|
// Selector-based fallback — same native-setter logic, single InputEvent only
|
|
741
741
|
await session.Runtime.evaluate({
|
|
742
|
-
expression: `(function(sel, txt) {
|
|
743
|
-
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
744
|
-
if (!el) return;
|
|
745
|
-
|
|
746
|
-
const nativeInputSetter = Object.getOwnPropertyDescriptor(
|
|
747
|
-
window.HTMLInputElement.prototype, 'value'
|
|
748
|
-
)?.set;
|
|
749
|
-
const nativeTextAreaSetter = Object.getOwnPropertyDescriptor(
|
|
750
|
-
window.HTMLTextAreaElement.prototype, 'value'
|
|
751
|
-
)?.set;
|
|
752
|
-
|
|
753
|
-
if (el.tagName === 'INPUT' && nativeInputSetter) {
|
|
754
|
-
nativeInputSetter.call(el, txt);
|
|
755
|
-
} else if (el.tagName === 'TEXTAREA' && nativeTextAreaSetter) {
|
|
756
|
-
nativeTextAreaSetter.call(el, txt);
|
|
757
|
-
} else if (el.isContentEditable) {
|
|
758
|
-
el.textContent = txt;
|
|
759
|
-
} else {
|
|
760
|
-
el.value = txt;
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
// Single InputEvent — React 16/17/18 SyntheticEvent source.
|
|
764
|
-
// Do NOT also dispatch plain Event('input') — that fires onChange twice.
|
|
765
|
-
el.dispatchEvent(new InputEvent('input', {
|
|
766
|
-
bubbles: true, cancelable: true, inputType: 'insertText', data: txt
|
|
767
|
-
}));
|
|
768
|
-
el.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));
|
|
742
|
+
expression: `(function(sel, txt) {
|
|
743
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
744
|
+
if (!el) return;
|
|
745
|
+
|
|
746
|
+
const nativeInputSetter = Object.getOwnPropertyDescriptor(
|
|
747
|
+
window.HTMLInputElement.prototype, 'value'
|
|
748
|
+
)?.set;
|
|
749
|
+
const nativeTextAreaSetter = Object.getOwnPropertyDescriptor(
|
|
750
|
+
window.HTMLTextAreaElement.prototype, 'value'
|
|
751
|
+
)?.set;
|
|
752
|
+
|
|
753
|
+
if (el.tagName === 'INPUT' && nativeInputSetter) {
|
|
754
|
+
nativeInputSetter.call(el, txt);
|
|
755
|
+
} else if (el.tagName === 'TEXTAREA' && nativeTextAreaSetter) {
|
|
756
|
+
nativeTextAreaSetter.call(el, txt);
|
|
757
|
+
} else if (el.isContentEditable) {
|
|
758
|
+
el.textContent = txt;
|
|
759
|
+
} else {
|
|
760
|
+
el.value = txt;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Single InputEvent — React 16/17/18 SyntheticEvent source.
|
|
764
|
+
// Do NOT also dispatch plain Event('input') — that fires onChange twice.
|
|
765
|
+
el.dispatchEvent(new InputEvent('input', {
|
|
766
|
+
bubbles: true, cancelable: true, inputType: 'insertText', data: txt
|
|
767
|
+
}));
|
|
768
|
+
el.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));
|
|
769
769
|
})(${JSON.stringify(selector)}, ${JSON.stringify(text)})`,
|
|
770
770
|
returnByValue: false,
|
|
771
771
|
awaitPromise: true,
|
|
@@ -783,11 +783,11 @@ export async function weaveType(session, args, config) {
|
|
|
783
783
|
// Firing again here would trigger a second onChange and duplicate the value.
|
|
784
784
|
if (!nativeSetterUsed) {
|
|
785
785
|
await session.Runtime.evaluate({
|
|
786
|
-
expression: `(function(sel) {
|
|
787
|
-
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
788
|
-
if (!el) return;
|
|
789
|
-
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
790
|
-
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
786
|
+
expression: `(function(sel) {
|
|
787
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
788
|
+
if (!el) return;
|
|
789
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
790
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
791
791
|
})(${JSON.stringify(selector)})`,
|
|
792
792
|
returnByValue: false,
|
|
793
793
|
}).catch(() => { });
|
|
@@ -830,21 +830,21 @@ export async function weaveType(session, args, config) {
|
|
|
830
830
|
const isActiveElementRef = selector === "document.activeElement";
|
|
831
831
|
const checkFieldValue = async () => {
|
|
832
832
|
const expression = isActiveElementRef
|
|
833
|
-
? `(function(expected) {
|
|
834
|
-
var el = document.activeElement;
|
|
835
|
-
if (!el) return false;
|
|
836
|
-
var val = el.value !== undefined ? el.value : (el.textContent || '');
|
|
837
|
-
return val === expected || (typeof val === 'string' && val.trim() === expected.trim())
|
|
838
|
-
|| (typeof val === 'string' && typeof expected === 'string' &&
|
|
839
|
-
val.replace(/\\D/g, '') === expected.replace(/\\D/g, '') && expected.length > 3);
|
|
833
|
+
? `(function(expected) {
|
|
834
|
+
var el = document.activeElement;
|
|
835
|
+
if (!el) return false;
|
|
836
|
+
var val = el.value !== undefined ? el.value : (el.textContent || '');
|
|
837
|
+
return val === expected || (typeof val === 'string' && val.trim() === expected.trim())
|
|
838
|
+
|| (typeof val === 'string' && typeof expected === 'string' &&
|
|
839
|
+
val.replace(/\\D/g, '') === expected.replace(/\\D/g, '') && expected.length > 3);
|
|
840
840
|
})(${JSON.stringify(text)})`
|
|
841
|
-
: `(function(sel, expected) {
|
|
842
|
-
var el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
843
|
-
if (!el) return false;
|
|
844
|
-
var val = el.value !== undefined ? el.value : (el.textContent || '');
|
|
845
|
-
return val === expected || (typeof val === 'string' && val.trim() === expected.trim())
|
|
846
|
-
|| (typeof val === 'string' && typeof expected === 'string' &&
|
|
847
|
-
val.replace(/\\D/g, '') === expected.replace(/\\D/g, '') && expected.length > 3);
|
|
841
|
+
: `(function(sel, expected) {
|
|
842
|
+
var el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
843
|
+
if (!el) return false;
|
|
844
|
+
var val = el.value !== undefined ? el.value : (el.textContent || '');
|
|
845
|
+
return val === expected || (typeof val === 'string' && val.trim() === expected.trim())
|
|
846
|
+
|| (typeof val === 'string' && typeof expected === 'string' &&
|
|
847
|
+
val.replace(/\\D/g, '') === expected.replace(/\\D/g, '') && expected.length > 3);
|
|
848
848
|
})(${JSON.stringify(selector)}, ${JSON.stringify(text)})`;
|
|
849
849
|
const { result } = await session.Runtime.evaluate({ expression, returnByValue: true }).catch(() => ({ result: { value: false } }));
|
|
850
850
|
return result?.value === true;
|
|
@@ -890,12 +890,12 @@ export async function weaveType(session, args, config) {
|
|
|
890
890
|
let detectedFramework = profileFramework;
|
|
891
891
|
if (!detectedFramework) {
|
|
892
892
|
const fwCheck = await session.Runtime.evaluate({
|
|
893
|
-
expression: `(function(){
|
|
894
|
-
var r=document.documentElement;
|
|
895
|
-
if(r.__reactFiber||r._reactRootContainer) return 'react';
|
|
896
|
-
if(r.__vue__||document.querySelector('[data-v-]')) return 'vue';
|
|
897
|
-
if(r.ng||document.querySelector('[ng-version]')) return 'angular';
|
|
898
|
-
return '';
|
|
893
|
+
expression: `(function(){
|
|
894
|
+
var r=document.documentElement;
|
|
895
|
+
if(r.__reactFiber||r._reactRootContainer) return 'react';
|
|
896
|
+
if(r.__vue__||document.querySelector('[data-v-]')) return 'vue';
|
|
897
|
+
if(r.ng||document.querySelector('[ng-version]')) return 'angular';
|
|
898
|
+
return '';
|
|
899
899
|
})()`,
|
|
900
900
|
returnByValue: true,
|
|
901
901
|
}).catch(() => null);
|
|
@@ -907,42 +907,42 @@ export async function weaveType(session, args, config) {
|
|
|
907
907
|
if (isSpa) {
|
|
908
908
|
const { omniEvaluate } = await import("../cdp/omni_broker.js");
|
|
909
909
|
// Single Runtime.evaluate — nativeInputValueSetter + InputEvent dispatch
|
|
910
|
-
const rawRes = await omniEvaluate(session, targetId, `(function(sel, value) {
|
|
911
|
-
try {
|
|
912
|
-
var el = document.querySelector(sel) ||
|
|
913
|
-
(window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
914
|
-
if (!el) return JSON.stringify({ ok: false, strategy: 'NOT_FOUND', exists: false });
|
|
915
|
-
|
|
916
|
-
// Strategy A: React's internal nativeInputValueSetter override
|
|
917
|
-
var nativeSetter =
|
|
918
|
-
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set ||
|
|
919
|
-
Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set;
|
|
920
|
-
|
|
921
|
-
if (nativeSetter) {
|
|
922
|
-
nativeSetter.call(el, value);
|
|
923
|
-
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
924
|
-
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
925
|
-
el.dispatchEvent(new InputEvent('input', {
|
|
926
|
-
bubbles: true, data: value, inputType: 'insertText'
|
|
927
|
-
}));
|
|
928
|
-
return JSON.stringify({ ok: el.value === value, strategy: 'native-setter', value: el.value, exists: true });
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
// Strategy B: contenteditable with InputEvent
|
|
932
|
-
if (el.isContentEditable) {
|
|
933
|
-
el.textContent = value;
|
|
934
|
-
el.dispatchEvent(new InputEvent('input', { bubbles: true, data: value }));
|
|
935
|
-
return JSON.stringify({ ok: el.textContent === value, strategy: 'contenteditable', value: el.textContent, exists: true });
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
// Strategy C: direct value + dispatchEvent fallback
|
|
939
|
-
el.value = value;
|
|
940
|
-
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
941
|
-
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
942
|
-
return JSON.stringify({ ok: el.value === value, strategy: 'direct-event', value: el.value, exists: true });
|
|
943
|
-
} catch(e) {
|
|
944
|
-
return JSON.stringify({ ok: false, strategy: 'ERROR', error: e.message, exists: false });
|
|
945
|
-
}
|
|
910
|
+
const rawRes = await omniEvaluate(session, targetId, `(function(sel, value) {
|
|
911
|
+
try {
|
|
912
|
+
var el = document.querySelector(sel) ||
|
|
913
|
+
(window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
914
|
+
if (!el) return JSON.stringify({ ok: false, strategy: 'NOT_FOUND', exists: false });
|
|
915
|
+
|
|
916
|
+
// Strategy A: React's internal nativeInputValueSetter override
|
|
917
|
+
var nativeSetter =
|
|
918
|
+
Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set ||
|
|
919
|
+
Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set;
|
|
920
|
+
|
|
921
|
+
if (nativeSetter) {
|
|
922
|
+
nativeSetter.call(el, value);
|
|
923
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
924
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
925
|
+
el.dispatchEvent(new InputEvent('input', {
|
|
926
|
+
bubbles: true, data: value, inputType: 'insertText'
|
|
927
|
+
}));
|
|
928
|
+
return JSON.stringify({ ok: el.value === value, strategy: 'native-setter', value: el.value, exists: true });
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// Strategy B: contenteditable with InputEvent
|
|
932
|
+
if (el.isContentEditable) {
|
|
933
|
+
el.textContent = value;
|
|
934
|
+
el.dispatchEvent(new InputEvent('input', { bubbles: true, data: value }));
|
|
935
|
+
return JSON.stringify({ ok: el.textContent === value, strategy: 'contenteditable', value: el.textContent, exists: true });
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// Strategy C: direct value + dispatchEvent fallback
|
|
939
|
+
el.value = value;
|
|
940
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
941
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
942
|
+
return JSON.stringify({ ok: el.value === value, strategy: 'direct-event', value: el.value, exists: true });
|
|
943
|
+
} catch(e) {
|
|
944
|
+
return JSON.stringify({ ok: false, strategy: 'ERROR', error: e.message, exists: false });
|
|
945
|
+
}
|
|
946
946
|
})(${JSON.stringify(selector)}, ${JSON.stringify(text)})`);
|
|
947
947
|
if (rawRes) {
|
|
948
948
|
try {
|
|
@@ -1019,18 +1019,18 @@ export async function weaveType(session, args, config) {
|
|
|
1019
1019
|
if (selector) {
|
|
1020
1020
|
try {
|
|
1021
1021
|
const { result: stateResult } = await session.Runtime.evaluate({
|
|
1022
|
-
expression: `(function(sel) {
|
|
1023
|
-
var el = document.querySelector(sel);
|
|
1024
|
-
if (!el) return null;
|
|
1025
|
-
var isSecret = el.hasAttribute('data-wt-secret') || (el.tagName === 'INPUT' && el.type === 'password');
|
|
1026
|
-
return {
|
|
1027
|
-
tag: el.tagName.toLowerCase(),
|
|
1028
|
-
visible: el.offsetParent !== null,
|
|
1029
|
-
disabled: el.disabled,
|
|
1030
|
-
value: isSecret ? '[REDACTED]' : el.value,
|
|
1031
|
-
label: el.getAttribute('aria-label') || el.getAttribute('placeholder') || el.getAttribute('name') || (el.textContent||'').trim().slice(0,40),
|
|
1032
|
-
textContent: isSecret ? '[REDACTED]' : (el.isContentEditable ? el.textContent?.slice(0, 100) : undefined)
|
|
1033
|
-
};
|
|
1022
|
+
expression: `(function(sel) {
|
|
1023
|
+
var el = document.querySelector(sel);
|
|
1024
|
+
if (!el) return null;
|
|
1025
|
+
var isSecret = el.hasAttribute('data-wt-secret') || (el.tagName === 'INPUT' && el.type === 'password');
|
|
1026
|
+
return {
|
|
1027
|
+
tag: el.tagName.toLowerCase(),
|
|
1028
|
+
visible: el.offsetParent !== null,
|
|
1029
|
+
disabled: el.disabled,
|
|
1030
|
+
value: isSecret ? '[REDACTED]' : el.value,
|
|
1031
|
+
label: el.getAttribute('aria-label') || el.getAttribute('placeholder') || el.getAttribute('name') || (el.textContent||'').trim().slice(0,40),
|
|
1032
|
+
textContent: isSecret ? '[REDACTED]' : (el.isContentEditable ? el.textContent?.slice(0, 100) : undefined)
|
|
1033
|
+
};
|
|
1034
1034
|
})(${JSON.stringify(selector)})`,
|
|
1035
1035
|
returnByValue: true,
|
|
1036
1036
|
});
|
|
@@ -1060,13 +1060,13 @@ export async function weaveType(session, args, config) {
|
|
|
1060
1060
|
if (!isPassword && selector && selector !== 'document.activeElement') {
|
|
1061
1061
|
try {
|
|
1062
1062
|
const { result: vlRes } = await session.Runtime.evaluate({
|
|
1063
|
-
expression: `(function(sel) {
|
|
1064
|
-
var el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
1065
|
-
if (!el) return -1;
|
|
1066
|
-
var isSec = el.hasAttribute('data-wt-secret') || (el.tagName === 'INPUT' && el.type === 'password');
|
|
1067
|
-
if (isSec) return -1;
|
|
1068
|
-
var v = el.value !== undefined ? el.value : (el.textContent || '');
|
|
1069
|
-
return (v || '').length;
|
|
1063
|
+
expression: `(function(sel) {
|
|
1064
|
+
var el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
1065
|
+
if (!el) return -1;
|
|
1066
|
+
var isSec = el.hasAttribute('data-wt-secret') || (el.tagName === 'INPUT' && el.type === 'password');
|
|
1067
|
+
if (isSec) return -1;
|
|
1068
|
+
var v = el.value !== undefined ? el.value : (el.textContent || '');
|
|
1069
|
+
return (v || '').length;
|
|
1070
1070
|
})(${JSON.stringify(selector)})`,
|
|
1071
1071
|
returnByValue: true,
|
|
1072
1072
|
});
|