@weavetab/mcp 2.5.0-beta.1 → 2.5.0-beta.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/AGENTS.md +2 -1
- package/ARCHITECTURE.md +6 -6
- package/LICENSE +1 -1
- package/README.md +164 -802
- package/SECURITY.md +33 -22
- package/TROUBLESHOOTING.md +3 -3
- package/dist/cdp/bridge.d.ts +10 -0
- package/dist/cdp/bridge.js +285 -78
- package/dist/cdp/connector.d.ts +7 -3
- package/dist/cdp/connector.js +196 -75
- package/dist/cdp/helpers.d.ts +4 -0
- package/dist/cdp/helpers.js +181 -0
- package/dist/cdp/lock.d.ts +9 -6
- package/dist/cdp/lock.js +72 -59
- package/dist/cdp/omni_broker.d.ts +2 -1
- package/dist/cdp/omni_broker.js +13 -7
- package/dist/cdp/profiles.d.ts +10 -0
- package/dist/cdp/profiles.js +65 -0
- package/dist/cdp/walker.d.ts +25 -1
- package/dist/cdp/walker.js +354 -7
- package/dist/cli/plugin.d.ts +0 -2
- package/dist/cli/plugin.js +51 -696
- package/dist/cli/updater.d.ts +1 -1
- package/dist/cli/updater.js +27 -7
- package/dist/config/loader.d.ts +33 -6
- package/dist/config/loader.js +174 -22
- package/dist/desktop/discovery.d.ts +44 -0
- package/dist/desktop/discovery.js +364 -0
- package/dist/index.js +140 -64
- package/dist/intelligence/marks.d.ts +36 -0
- package/dist/intelligence/marks.js +30 -0
- package/dist/intelligence/patternCompiler.d.ts +118 -0
- package/dist/intelligence/patternCompiler.js +259 -0
- package/dist/intelligence/sessionMemory.d.ts +2 -0
- package/dist/intelligence/sessionMemory.js +18 -8
- package/dist/overlay/ghost.js +2 -2
- package/dist/overlay/injector.js +3 -5
- package/dist/plugin/extension_bridge.d.ts +40 -0
- package/dist/plugin/extension_bridge.js +158 -0
- package/dist/plugin/interface.d.ts +151 -15
- package/dist/plugin/loader.d.ts +19 -1
- package/dist/plugin/loader.js +331 -63
- package/dist/plugin/pipeline.d.ts +75 -0
- package/dist/plugin/pipeline.js +183 -0
- package/dist/plugin/registry.js +12 -1
- package/dist/plugin/storage.d.ts +51 -0
- package/dist/plugin/storage.js +164 -0
- package/dist/security/secrets.d.ts +1 -0
- package/dist/security/secrets.js +13 -0
- package/dist/sensors/actionability.js +1 -2
- package/dist/sensors/guard.js +4 -10
- package/dist/sensors/mutations.js +12 -0
- package/dist/sensors/operation_monitor.js +1 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +600 -236
- package/dist/state/agent.d.ts +1 -0
- package/dist/state/agent.js +3 -0
- package/dist/state/delta.d.ts +12 -4
- package/dist/state/delta.js +67 -14
- package/dist/state/session.d.ts +8 -2
- package/dist/state/session.js +60 -13
- package/dist/tools/browser_detect.d.ts +16 -2
- package/dist/tools/browser_detect.js +54 -6
- package/dist/tools/burst.d.ts +17 -7
- package/dist/tools/burst.js +240 -83
- package/dist/tools/checkpoint.d.ts +38 -0
- package/dist/tools/checkpoint.js +271 -0
- package/dist/tools/click.d.ts +1 -0
- package/dist/tools/click.js +97 -98
- package/dist/tools/clipboard.js +31 -24
- package/dist/tools/design_extract.js +1 -1
- package/dist/tools/eval.js +1 -1
- package/dist/tools/fill.d.ts +20 -1
- package/dist/tools/fill.js +199 -40
- package/dist/tools/find.d.ts +16 -0
- package/dist/tools/find.js +67 -44
- package/dist/tools/github/index.d.ts +19 -4
- package/dist/tools/github/index.js +40 -4
- package/dist/tools/highlight.d.ts +6 -2
- package/dist/tools/highlight.js +158 -72
- package/dist/tools/inspect.js +1 -1
- package/dist/tools/key.js +65 -56
- package/dist/tools/navigate.d.ts +1 -1
- package/dist/tools/navigate.js +57 -44
- package/dist/tools/pdf.js +21 -13
- package/dist/tools/pointer.d.ts +18 -3
- package/dist/tools/pointer.js +89 -1
- package/dist/tools/read.d.ts +28 -8
- package/dist/tools/read.js +230 -56
- package/dist/tools/scrape.js +67 -13
- package/dist/tools/screenshot.js +21 -16
- package/dist/tools/scroll.js +6 -11
- package/dist/tools/select.js +8 -2
- package/dist/tools/snapshot.js +3 -34
- package/dist/tools/tabs.d.ts +10 -10
- package/dist/tools/tabs.js +55 -39
- package/dist/tools/thought.d.ts +2 -0
- package/dist/tools/thought.js +13 -14
- package/dist/tools/type.d.ts +2 -0
- package/dist/tools/type.js +109 -60
- package/dist/tools/type_secret.js +42 -76
- package/dist/tools/upload.js +1 -1
- package/dist/tools/video_compiler.d.ts +1 -1
- package/dist/tools/video_compiler.js +11 -12
- package/dist/version.d.ts +5 -0
- package/dist/version.js +5 -0
- package/docs/DOCUMENTATION.md +82 -36
- package/docs/PLUGINS.md +82 -499
- package/docs/TOOLS.md +51 -99
- package/docs/architecture/blind-injection.md +83 -0
- package/docs/architecture/dual-injection.md +32 -0
- package/docs/architecture/overview.md +49 -0
- package/docs/architecture/security.md +35 -0
- package/docs/architecture/transport.md +37 -0
- package/docs/captcha-stealth/captcha-solver.md +75 -0
- package/docs/captcha-stealth/stealth-physics.md +60 -0
- package/docs/cli/cli-commands.md +44 -0
- package/docs/cli/cli-flags.md +20 -0
- package/docs/cli/cli-introduction.md +20 -0
- package/docs/cli/cli-scripting.md +32 -0
- package/docs/cli/g-ide/ide-antigravity.md +24 -0
- package/docs/cli/g-ide/ide-claude-code.md +24 -0
- package/docs/cli/g-ide/ide-claude-desktop.md +32 -0
- package/docs/cli/g-ide/ide-cursor.md +31 -0
- package/docs/cli/g-ide/ide-generic.md +34 -0
- package/docs/cli/g-ide/ide-opencode.md +24 -0
- package/docs/cli/g-ide/ide-vscode-copilot.md +24 -0
- package/docs/cli/g-ide/ide-windsurf.md +24 -0
- package/docs/configuration/config-locations.md +24 -0
- package/docs/configuration/configuration.md +73 -0
- package/docs/configuration/env-variables.md +19 -0
- package/docs/configuration/folders.md +55 -0
- package/docs/desktop-automation/electron-apps.md +217 -0
- package/docs/get-started/installation.md +47 -0
- package/docs/get-started/introduction.md +60 -0
- package/docs/get-started/quickstart.md +54 -0
- package/docs/get-started/setup-wizard.md +26 -0
- package/docs/intelligence/site-profiles.md +151 -0
- package/docs/skills-ecosystem/skills-overview.md +35 -0
- package/docs/skills-ecosystem/skills-recipes.md +36 -0
- package/docs/tools/tools.md +631 -0
- package/docs/troubleshooting/trouble-browser.md +27 -0
- package/docs/troubleshooting/trouble-config.md +20 -0
- package/docs/troubleshooting/trouble-loop.md +31 -0
- package/ext-dist/background.js +10 -62
- package/ext-dist/content.js +333 -921
- package/ext-dist/hud/hud.js +9 -9
- package/ext-dist/manifest.json +2 -6
- package/ext-dist/styles.css +6 -1
- package/mcp.json +108 -72
- package/package.json +14 -9
- package/server.json +3 -3
- package/docs/DEV_MODE.md +0 -68
- package/docs/dev_plugin.md +0 -310
- package/ext-dist/sidepanel/sidepanel.js +0 -25
- package/ext-dist/sidepanel.html +0 -547
package/dist/tools/navigate.js
CHANGED
|
@@ -12,7 +12,7 @@ import { resetFallbackIdCounter, clearShadowDomCache, clearAXTreeCache } from ".
|
|
|
12
12
|
import { clearTabCache } from "../state/cache.js";
|
|
13
13
|
import { bumpVisitCount } from "../intelligence/sessionMemory.js";
|
|
14
14
|
import { sessionRegistry } from "../state/session.js";
|
|
15
|
-
export async function weaveNavigate(session, url, config, targetId = "default", force = false, fast = false) {
|
|
15
|
+
export async function weaveNavigate(session, url, config, targetId = "default", force = false, fast = false, appName) {
|
|
16
16
|
logDebug(`[weaveNavigate] Attempting navigation to: ${url}`);
|
|
17
17
|
let parsed;
|
|
18
18
|
if (url.startsWith('Weavetab://')) {
|
|
@@ -40,16 +40,35 @@ export async function weaveNavigate(session, url, config, targetId = "default",
|
|
|
40
40
|
return { success: false, error_code: "INVALID_URL", message: `[!] Invalid URL: ${url}` };
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
const active = sessionRegistry.getActive(config.agentId, appName);
|
|
44
|
+
const isElectron = !!(appName || active?.isElectron);
|
|
45
|
+
// Allowed web and desktop application protocols.
|
|
46
|
+
// Block script-execution protocols (javascript:, data:) that bypass safety policies.
|
|
45
47
|
const proto = parsed.protocol.toLowerCase();
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
const allowedProtocols = new Set([
|
|
49
|
+
"http:",
|
|
50
|
+
"https:",
|
|
51
|
+
"file:",
|
|
52
|
+
"chrome-extension:",
|
|
53
|
+
"app:",
|
|
54
|
+
"vscode-webview:",
|
|
55
|
+
"vscode-file:",
|
|
56
|
+
"discord:",
|
|
57
|
+
"slack:",
|
|
58
|
+
"devtools:",
|
|
59
|
+
"chrome:",
|
|
60
|
+
"about:",
|
|
61
|
+
]);
|
|
62
|
+
if (!allowedProtocols.has(proto)) {
|
|
63
|
+
return { success: false, error_code: "BLOCKED_PROTOCOL", message: `[!] Blocked protocol '${proto}'. Only web, file, and desktop app protocols are allowed.` };
|
|
48
64
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
65
|
+
// Domain policy check only applies to standard web navigations
|
|
66
|
+
if (!isElectron && (proto === "http:" || proto === "https:")) {
|
|
67
|
+
const domainCheck = checkDomain(parsed.href, config);
|
|
68
|
+
logDebug(`[weaveNavigate] Domain check for ${parsed.hostname}: ${JSON.stringify(domainCheck)}`);
|
|
69
|
+
if (!domainCheck.allowed) {
|
|
70
|
+
return { success: false, error_code: "DOMAIN_BLOCKED", message: `[!] Weave blocked: ${domainCheck.reason}` };
|
|
71
|
+
}
|
|
53
72
|
}
|
|
54
73
|
// Extension pages: open in new tab instead of navigating current tab
|
|
55
74
|
// (chrome-extension:// pages use a different process context — Page.navigate
|
|
@@ -88,7 +107,6 @@ export async function weaveNavigate(session, url, config, targetId = "default",
|
|
|
88
107
|
};
|
|
89
108
|
}
|
|
90
109
|
// Resolve active tab id
|
|
91
|
-
const active = sessionRegistry.getActive(config.agentId);
|
|
92
110
|
const resolvedTargetId = active?.targetId ?? targetId;
|
|
93
111
|
// 1. Anchor Tab Protection
|
|
94
112
|
let isAnchor = false;
|
|
@@ -97,7 +115,7 @@ export async function weaveNavigate(session, url, config, targetId = "default",
|
|
|
97
115
|
expression: `new Promise((resolve) => {
|
|
98
116
|
let done = false;
|
|
99
117
|
const finish = (val) => { if (!done) { done = true; resolve(val); } };
|
|
100
|
-
setTimeout(() => finish(false),
|
|
118
|
+
setTimeout(() => finish(false), 30);
|
|
101
119
|
try {
|
|
102
120
|
const browserAPI = typeof browser !== 'undefined' ? browser : (typeof chrome !== 'undefined' ? chrome : null);
|
|
103
121
|
if (browserAPI && browserAPI.runtime && browserAPI.runtime.id) {
|
|
@@ -111,7 +129,7 @@ export async function weaveNavigate(session, url, config, targetId = "default",
|
|
|
111
129
|
})`,
|
|
112
130
|
awaitPromise: true,
|
|
113
131
|
returnByValue: true
|
|
114
|
-
});
|
|
132
|
+
}).catch(() => null);
|
|
115
133
|
isAnchor = res?.result?.value === true;
|
|
116
134
|
}
|
|
117
135
|
catch (e) {
|
|
@@ -133,50 +151,45 @@ export async function weaveNavigate(session, url, config, targetId = "default",
|
|
|
133
151
|
sendToExtension(session, { type: 'Weavetab_STATE', hud: { action: `navigating to ${parsed.hostname}...` } }).catch(() => { });
|
|
134
152
|
sendToExtension(session, { type: 'Weavetab_STATE', cursor: { x: 10, y: 10 }, state: 'thinking' }).catch(() => { });
|
|
135
153
|
await session.Page.navigate({ url: parsed.href });
|
|
136
|
-
//
|
|
154
|
+
// Fast navigation wait
|
|
137
155
|
try {
|
|
138
156
|
await awaitNavigation(session, config.navigationTimeout || 30000);
|
|
139
157
|
}
|
|
140
158
|
catch (navErr) {
|
|
141
159
|
logDebug(`[weaveNavigate] Navigation timeout: ${navErr}`);
|
|
142
|
-
// Continue — page may be partially loaded
|
|
143
160
|
}
|
|
144
|
-
// Clear delta snapshot
|
|
161
|
+
// Clear delta snapshot & caches
|
|
145
162
|
clearSnapshot(resolvedTargetId);
|
|
146
163
|
resetLoopCounter("navigation");
|
|
147
|
-
clearToolCallWindow();
|
|
164
|
+
clearToolCallWindow();
|
|
148
165
|
resetFallbackIdCounter();
|
|
149
166
|
clearShadowDomCache(resolvedTargetId);
|
|
150
167
|
clearAXTreeCache(resolvedTargetId);
|
|
151
168
|
clearTabCache(resolvedTargetId);
|
|
152
|
-
//
|
|
153
|
-
await
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
title = titleRes.result.value;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
catch { }
|
|
169
|
+
// Parallelize post-navigation metadata & cookie banner dismissal
|
|
170
|
+
const [frameRes, titleRes] = await Promise.all([
|
|
171
|
+
session.Page.getFrameTree().catch(() => ({ frameTree: { frame: { url: parsed.href } } })),
|
|
172
|
+
session.Runtime.evaluate({ expression: 'document.title', returnByValue: true }).catch(() => null),
|
|
173
|
+
session.Runtime.evaluate({
|
|
174
|
+
expression: `
|
|
175
|
+
(function(){
|
|
176
|
+
var selectors = [
|
|
177
|
+
'[id*="cookie"] button','[class*="cookie"] button',
|
|
178
|
+
'[id*="consent"] button','[class*="consent"] button',
|
|
179
|
+
'[id*="gdpr"] button','[class*="gdpr"] button',
|
|
180
|
+
'[aria-label*="Accept"]','[aria-label*="Agree"]',
|
|
181
|
+
'button[data-cookiebanner]'
|
|
182
|
+
];
|
|
183
|
+
for(var i=0;i<selectors.length;i++){
|
|
184
|
+
var el=document.querySelector(selectors[i]);
|
|
185
|
+
if(el){try{el.click();}catch(e){}break;}
|
|
186
|
+
}
|
|
187
|
+
})()
|
|
188
|
+
`
|
|
189
|
+
}).catch(() => { })
|
|
190
|
+
]);
|
|
191
|
+
const finalUrl = frameRes?.frameTree?.frame?.url || parsed.href;
|
|
192
|
+
const title = titleRes?.result?.value || parsed.hostname;
|
|
180
193
|
// Keep session registry in sync with the new URL
|
|
181
194
|
if (active)
|
|
182
195
|
active.url = finalUrl;
|
package/dist/tools/pdf.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getOutputDir } from "../config/loader.js";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { hideWeaveTabOverlay, restoreWeaveTabOverlay } from "../cdp/helpers.js";
|
|
4
|
+
import { hideWeaveTabOverlay, restoreWeaveTabOverlay, maskSecretFieldsForCapture, restoreSecretFieldsAfterCapture } from "../cdp/helpers.js";
|
|
5
5
|
export async function browserPdf(session, options, config) {
|
|
6
6
|
// Always hide the overlay before generating PDF (agent must never see it).
|
|
7
7
|
// Set hideOverlay: false explicitly to keep overlays visible.
|
|
@@ -9,18 +9,26 @@ export async function browserPdf(session, options, config) {
|
|
|
9
9
|
if (shouldHide) {
|
|
10
10
|
await hideWeaveTabOverlay(session);
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
await maskSecretFieldsForCapture(session);
|
|
13
|
+
let data;
|
|
14
|
+
try {
|
|
15
|
+
const pdfRes = await session.Page.printToPDF({
|
|
16
|
+
landscape: options.landscape ?? false,
|
|
17
|
+
scale: options.scale ?? 1.0,
|
|
18
|
+
pageRanges: options.pageRanges ?? "",
|
|
19
|
+
marginTop: 0.4, // 1cm ish
|
|
20
|
+
marginBottom: 0.4,
|
|
21
|
+
marginLeft: 0.4,
|
|
22
|
+
marginRight: 0.4,
|
|
23
|
+
printBackground: true
|
|
24
|
+
});
|
|
25
|
+
data = pdfRes.data;
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
await restoreSecretFieldsAfterCapture(session);
|
|
29
|
+
if (shouldHide) {
|
|
30
|
+
await restoreWeaveTabOverlay(session);
|
|
31
|
+
}
|
|
24
32
|
}
|
|
25
33
|
// Use configured PDF directory or default
|
|
26
34
|
const pdfsDir = getOutputDir("pdfs", config);
|
package/dist/tools/pointer.d.ts
CHANGED
|
@@ -19,8 +19,18 @@ export interface PointerResult {
|
|
|
19
19
|
url: string;
|
|
20
20
|
dom_changed?: boolean;
|
|
21
21
|
}
|
|
22
|
-
export
|
|
23
|
-
action
|
|
22
|
+
export interface PointerStep {
|
|
23
|
+
action?: "hover" | "click" | "double_click";
|
|
24
|
+
ref?: string;
|
|
25
|
+
selector?: string;
|
|
26
|
+
target?: string;
|
|
27
|
+
label?: string;
|
|
28
|
+
x?: number;
|
|
29
|
+
y?: number;
|
|
30
|
+
holdMs?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface PointerArgs {
|
|
33
|
+
action?: "click" | "double_click" | "hover" | "drag_and_drop" | "hover_chain";
|
|
24
34
|
ref?: string;
|
|
25
35
|
selector?: string;
|
|
26
36
|
target?: string;
|
|
@@ -32,4 +42,9 @@ export declare function browserPointer(session: CDP.Client, args: {
|
|
|
32
42
|
end_y?: number;
|
|
33
43
|
waitForChild?: string;
|
|
34
44
|
holdMs?: number;
|
|
35
|
-
|
|
45
|
+
hover_chain?: Array<string | PointerStep>;
|
|
46
|
+
chain?: Array<string | PointerStep>;
|
|
47
|
+
clickFinal?: boolean;
|
|
48
|
+
[key: string]: unknown;
|
|
49
|
+
}
|
|
50
|
+
export declare function browserPointer(session: CDP.Client, args: PointerArgs, config: Config): Promise<PointerResult>;
|
package/dist/tools/pointer.js
CHANGED
|
@@ -117,7 +117,95 @@ async function resolveRefToCoords(session, targetId, ref, currentUrl) {
|
|
|
117
117
|
return null;
|
|
118
118
|
}
|
|
119
119
|
export async function browserPointer(session, args, config) {
|
|
120
|
-
let { action, ref, selector, label, x, y, end_ref, end_x, end_y, waitForChild, holdMs =
|
|
120
|
+
let { action = "click", ref, selector, label, x, y, end_ref, end_x, end_y, waitForChild, holdMs = 200 } = args;
|
|
121
|
+
// ── HOVER CHAIN / SUBMENU NAVIGATION (Photopea, Figma, Photoshop, Flyout Menus) ──
|
|
122
|
+
const rawChain = args.hover_chain || args.chain;
|
|
123
|
+
if (action === "hover_chain" || (rawChain && rawChain.length > 0)) {
|
|
124
|
+
const chainItems = (rawChain || []).map((step, idx, arr) => {
|
|
125
|
+
if (typeof step === "string") {
|
|
126
|
+
const isLast = idx === arr.length - 1;
|
|
127
|
+
return {
|
|
128
|
+
action: isLast && args.clickFinal !== false ? "click" : "hover",
|
|
129
|
+
ref: step,
|
|
130
|
+
label: step,
|
|
131
|
+
target: step
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return step;
|
|
135
|
+
});
|
|
136
|
+
const startMs = Date.now();
|
|
137
|
+
const { Page, Input } = session;
|
|
138
|
+
let targetId = "default";
|
|
139
|
+
const active = sessionRegistry.getActive(getConfigAgentId(config));
|
|
140
|
+
if (active)
|
|
141
|
+
targetId = active.targetId;
|
|
142
|
+
let lastX = 0, lastY = 0;
|
|
143
|
+
for (let i = 0; i < chainItems.length; i++) {
|
|
144
|
+
const step = chainItems[i];
|
|
145
|
+
const stepTarget = step.ref || step.selector || step.target || step.label;
|
|
146
|
+
let stepCoords = null;
|
|
147
|
+
if (step.x !== undefined && step.y !== undefined) {
|
|
148
|
+
stepCoords = { x: step.x, y: step.y, selector: step.selector || '' };
|
|
149
|
+
}
|
|
150
|
+
else if (stepTarget) {
|
|
151
|
+
stepCoords = await resolveRefToCoords(session, targetId, stepTarget).catch(() => null);
|
|
152
|
+
if (!stepCoords) {
|
|
153
|
+
// Submenu might have rendered after previous hover; quick retry with fresh map
|
|
154
|
+
await new Promise(r => setTimeout(r, 80));
|
|
155
|
+
await buildActionMap(session, { lite: true }, targetId).then(m => cacheActionMap(targetId, m)).catch(() => { });
|
|
156
|
+
stepCoords = await resolveRefToCoords(session, targetId, stepTarget).catch(() => null);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (!stepCoords) {
|
|
160
|
+
throw new Error(`[browser_pointer hover_chain] Could not resolve coordinates for chain step [${i}]: '${stepTarget}'`);
|
|
161
|
+
}
|
|
162
|
+
lastX = stepCoords.x;
|
|
163
|
+
lastY = stepCoords.y;
|
|
164
|
+
// Move pointer smoothly to element
|
|
165
|
+
await ghostMove(session, stepCoords.x, stepCoords.y, config, step.label, "fast");
|
|
166
|
+
await Input.dispatchMouseEvent({ type: "mouseMoved", x: stepCoords.x, y: stepCoords.y, pointerType: "mouse" });
|
|
167
|
+
// Dispatch mouseenter/mouseover events for dynamic flyout/hover menus
|
|
168
|
+
if (stepCoords.selector) {
|
|
169
|
+
await session.Runtime.evaluate({
|
|
170
|
+
expression: `(function(sel, cx, cy) {
|
|
171
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
172
|
+
if (!el) return;
|
|
173
|
+
el.dispatchEvent(new MouseEvent('mouseenter', { bubbles: false, cancelable: true, clientX: cx, clientY: cy }));
|
|
174
|
+
el.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, cancelable: true, clientX: cx, clientY: cy }));
|
|
175
|
+
el.dispatchEvent(new MouseEvent('mousemove', { bubbles: true, cancelable: true, clientX: cx, clientY: cy }));
|
|
176
|
+
})(${JSON.stringify(stepCoords.selector)}, ${stepCoords.x}, ${stepCoords.y})`,
|
|
177
|
+
returnByValue: false
|
|
178
|
+
}).catch(() => { });
|
|
179
|
+
}
|
|
180
|
+
const stepHold = step.holdMs ?? (i === chainItems.length - 1 ? 40 : 100);
|
|
181
|
+
await new Promise(r => setTimeout(r, stepHold));
|
|
182
|
+
// If action is click (e.g. final step in chain)
|
|
183
|
+
if (step.action === "click") {
|
|
184
|
+
await Input.dispatchMouseEvent({ type: "mousePressed", x: stepCoords.x, y: stepCoords.y, button: "left", clickCount: 1, pointerType: "mouse" });
|
|
185
|
+
await new Promise(r => setTimeout(r, 40));
|
|
186
|
+
await Input.dispatchMouseEvent({ type: "mouseReleased", x: stepCoords.x, y: stepCoords.y, button: "left", clickCount: 1, pointerType: "mouse" });
|
|
187
|
+
}
|
|
188
|
+
else if (step.action === "double_click") {
|
|
189
|
+
await Input.dispatchMouseEvent({ type: "mousePressed", x: stepCoords.x, y: stepCoords.y, button: "left", clickCount: 1, pointerType: "mouse" });
|
|
190
|
+
await Input.dispatchMouseEvent({ type: "mouseReleased", x: stepCoords.x, y: stepCoords.y, button: "left", clickCount: 1, pointerType: "mouse" });
|
|
191
|
+
await new Promise(r => setTimeout(r, 60));
|
|
192
|
+
await Input.dispatchMouseEvent({ type: "mousePressed", x: stepCoords.x, y: stepCoords.y, button: "left", clickCount: 2, pointerType: "mouse" });
|
|
193
|
+
await Input.dispatchMouseEvent({ type: "mouseReleased", x: stepCoords.x, y: stepCoords.y, button: "left", clickCount: 2, pointerType: "mouse" });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const execMs = Date.now() - startMs;
|
|
197
|
+
const { frameTree: postFrameTree } = await Page.getFrameTree().catch(() => ({ frameTree: { frame: { url: '' } } }));
|
|
198
|
+
return {
|
|
199
|
+
success: true,
|
|
200
|
+
action: "hover_chain",
|
|
201
|
+
x: lastX,
|
|
202
|
+
y: lastY,
|
|
203
|
+
execution_ms: execMs,
|
|
204
|
+
tab_id: targetId,
|
|
205
|
+
url: postFrameTree.frame.url,
|
|
206
|
+
dom_changed: true,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
121
209
|
if (selector && !ref) {
|
|
122
210
|
ref = selector;
|
|
123
211
|
}
|
package/dist/tools/read.d.ts
CHANGED
|
@@ -4,7 +4,25 @@
|
|
|
4
4
|
* Weavetab by fy2ne
|
|
5
5
|
*/
|
|
6
6
|
import CDP from "chrome-remote-interface";
|
|
7
|
+
import { type MarkEntry } from "../intelligence/marks.js";
|
|
7
8
|
import type { Config } from "../config/loader.js";
|
|
9
|
+
export interface VisualMark {
|
|
10
|
+
mark: number;
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
ref?: string;
|
|
16
|
+
label?: string;
|
|
17
|
+
type?: MarkEntry["type"];
|
|
18
|
+
}
|
|
19
|
+
export interface BrowserMapResult {
|
|
20
|
+
text: string;
|
|
21
|
+
/** Base64 JPEG of the page annotated with numbered SoM badges. Only present in visual mode. */
|
|
22
|
+
imageBase64?: string;
|
|
23
|
+
/** Structured mark list — numbers match badges visible on the screenshot. */
|
|
24
|
+
marks?: VisualMark[];
|
|
25
|
+
}
|
|
8
26
|
export interface ReadOptions {
|
|
9
27
|
lite?: boolean;
|
|
10
28
|
full?: boolean;
|
|
@@ -14,17 +32,19 @@ export interface ReadOptions {
|
|
|
14
32
|
delta?: boolean;
|
|
15
33
|
intent?: string;
|
|
16
34
|
ax_tree?: boolean;
|
|
17
|
-
/** Debug: draws colored element borders via extension.
|
|
35
|
+
/** Debug: draws colored element borders via extension. */
|
|
18
36
|
show_overlays?: boolean;
|
|
19
|
-
/** Force deep shadow DOM traversal
|
|
37
|
+
/** Force deep shadow DOM traversal. */
|
|
20
38
|
deep?: boolean;
|
|
39
|
+
/** Semantic DOM pruning. Defaults to true to drop non-interactive noise and SVGs. */
|
|
40
|
+
prune?: boolean;
|
|
21
41
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
42
|
+
* Visual grounding mode (Set-of-Marks).
|
|
43
|
+
* - true → always inject numbered badges + screenshot.
|
|
44
|
+
* - "auto" → activate only when DOM interactive count < 5 (canvas/WebGL pages).
|
|
45
|
+
* Use browser_click({ mark: N }) to interact with numbered marks.
|
|
26
46
|
*/
|
|
27
|
-
|
|
47
|
+
visual?: boolean | "auto";
|
|
28
48
|
}
|
|
29
|
-
export declare function browserMap(session: CDP.Client, options: ReadOptions | undefined, targetId: string | undefined, config: Config): Promise<string>;
|
|
49
|
+
export declare function browserMap(session: CDP.Client, options: ReadOptions | undefined, targetId: string | undefined, config: Config): Promise<string | BrowserMapResult>;
|
|
30
50
|
export { browserMap as weaveRead };
|