@weavetab/mcp 2.5.0-beta.0
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 +48 -0
- package/ARCHITECTURE.md +590 -0
- package/LICENSE +631 -0
- package/README.md +909 -0
- package/SECURITY.md +196 -0
- package/TROUBLESHOOTING.md +365 -0
- package/dist/anticaptcha/detector.d.ts +49 -0
- package/dist/anticaptcha/detector.js +465 -0
- package/dist/anticaptcha/integration.d.ts +36 -0
- package/dist/anticaptcha/integration.js +123 -0
- package/dist/anticaptcha/solver.d.ts +27 -0
- package/dist/anticaptcha/solver.js +552 -0
- package/dist/audit/logger.d.ts +13 -0
- package/dist/audit/logger.js +177 -0
- package/dist/audit/telemetry.d.ts +36 -0
- package/dist/audit/telemetry.js +162 -0
- package/dist/cdp/bridge.d.ts +16 -0
- package/dist/cdp/bridge.js +826 -0
- package/dist/cdp/confirm.d.ts +26 -0
- package/dist/cdp/confirm.js +79 -0
- package/dist/cdp/connector.d.ts +37 -0
- package/dist/cdp/connector.js +661 -0
- package/dist/cdp/extension.d.ts +36 -0
- package/dist/cdp/extension.js +118 -0
- package/dist/cdp/finder.d.ts +1 -0
- package/dist/cdp/finder.js +2 -0
- package/dist/cdp/helpers.d.ts +11 -0
- package/dist/cdp/helpers.js +195 -0
- package/dist/cdp/label_cache.d.ts +12 -0
- package/dist/cdp/label_cache.js +51 -0
- package/dist/cdp/lock.d.ts +33 -0
- package/dist/cdp/lock.js +206 -0
- package/dist/cdp/omni_broker.d.ts +17 -0
- package/dist/cdp/omni_broker.js +119 -0
- package/dist/cdp/profiles.d.ts +1 -0
- package/dist/cdp/profiles.js +87 -0
- package/dist/cdp/pruner.d.ts +41 -0
- package/dist/cdp/pruner.js +263 -0
- package/dist/cdp/ref_cache.d.ts +101 -0
- package/dist/cdp/ref_cache.js +234 -0
- package/dist/cdp/retry.d.ts +5 -0
- package/dist/cdp/retry.js +39 -0
- package/dist/cdp/retry_enhanced.d.ts +44 -0
- package/dist/cdp/retry_enhanced.js +102 -0
- package/dist/cdp/security.d.ts +50 -0
- package/dist/cdp/security.js +237 -0
- package/dist/cdp/verify.d.ts +39 -0
- package/dist/cdp/verify.js +143 -0
- package/dist/cdp/walker.d.ts +91 -0
- package/dist/cdp/walker.js +896 -0
- package/dist/cdp/walker.test.d.ts +2 -0
- package/dist/cdp/walker.test.js +172 -0
- package/dist/cdp/websocket_transport.d.ts +15 -0
- package/dist/cdp/websocket_transport.js +118 -0
- package/dist/cli/plugin.d.ts +9 -0
- package/dist/cli/plugin.js +1134 -0
- package/dist/cli/updater.d.ts +1 -0
- package/dist/cli/updater.js +72 -0
- package/dist/config/loader.d.ts +120 -0
- package/dist/config/loader.js +704 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1248 -0
- package/dist/intelligence/hints.d.ts +11 -0
- package/dist/intelligence/hints.js +39 -0
- package/dist/intelligence/intent.d.ts +33 -0
- package/dist/intelligence/intent.js +171 -0
- package/dist/intelligence/sessionMemory.d.ts +66 -0
- package/dist/intelligence/sessionMemory.js +284 -0
- package/dist/intelligence/sessionMemory.test.d.ts +2 -0
- package/dist/intelligence/sessionMemory.test.js +62 -0
- package/dist/intelligence/trail.d.ts +64 -0
- package/dist/intelligence/trail.js +233 -0
- package/dist/intelligence/trail.test.d.ts +2 -0
- package/dist/intelligence/trail.test.js +110 -0
- package/dist/intelligence/vision.d.ts +24 -0
- package/dist/intelligence/vision.js +151 -0
- package/dist/lifecycle/mission_manager.d.ts +16 -0
- package/dist/lifecycle/mission_manager.js +44 -0
- package/dist/overlay/bubble.d.ts +16 -0
- package/dist/overlay/bubble.js +37 -0
- package/dist/overlay/ghost.d.ts +35 -0
- package/dist/overlay/ghost.js +508 -0
- package/dist/overlay/injector.d.ts +22 -0
- package/dist/overlay/injector.js +198 -0
- package/dist/plugin/interface.d.ts +134 -0
- package/dist/plugin/interface.js +1 -0
- package/dist/plugin/loader.d.ts +18 -0
- package/dist/plugin/loader.js +155 -0
- package/dist/plugin/registry.d.ts +50 -0
- package/dist/plugin/registry.js +234 -0
- package/dist/security/blacklist.d.ts +24 -0
- package/dist/security/blacklist.js +80 -0
- package/dist/security/filter.d.ts +2 -0
- package/dist/security/filter.js +20 -0
- package/dist/security/guard.d.ts +8 -0
- package/dist/security/guard.js +35 -0
- package/dist/security/ratelimit.d.ts +11 -0
- package/dist/security/ratelimit.js +57 -0
- package/dist/security/secrets.d.ts +75 -0
- package/dist/security/secrets.js +365 -0
- package/dist/sensors/actionability.d.ts +81 -0
- package/dist/sensors/actionability.js +303 -0
- package/dist/sensors/guard.d.ts +25 -0
- package/dist/sensors/guard.js +168 -0
- package/dist/sensors/mutations.d.ts +23 -0
- package/dist/sensors/mutations.js +93 -0
- package/dist/sensors/network.d.ts +67 -0
- package/dist/sensors/network.js +193 -0
- package/dist/sensors/operation_monitor.d.ts +80 -0
- package/dist/sensors/operation_monitor.js +203 -0
- package/dist/sensors/pacing.d.ts +44 -0
- package/dist/sensors/pacing.js +111 -0
- package/dist/sensors/thoughts.d.ts +2 -0
- package/dist/sensors/thoughts.js +59 -0
- package/dist/sensors/wait.d.ts +12 -0
- package/dist/sensors/wait.js +44 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +1687 -0
- package/dist/state/agent.d.ts +36 -0
- package/dist/state/agent.js +101 -0
- package/dist/state/cache.d.ts +16 -0
- package/dist/state/cache.js +92 -0
- package/dist/state/cache.test.d.ts +2 -0
- package/dist/state/cache.test.js +76 -0
- package/dist/state/delta.d.ts +71 -0
- package/dist/state/delta.js +234 -0
- package/dist/state/delta.test.d.ts +2 -0
- package/dist/state/delta.test.js +279 -0
- package/dist/state/groups.d.ts +15 -0
- package/dist/state/groups.js +80 -0
- package/dist/state/session.d.ts +30 -0
- package/dist/state/session.js +155 -0
- package/dist/tools/accessibility.d.ts +14 -0
- package/dist/tools/accessibility.js +32 -0
- package/dist/tools/ask.d.ts +14 -0
- package/dist/tools/ask.js +49 -0
- package/dist/tools/automation.d.ts +36 -0
- package/dist/tools/automation.js +218 -0
- package/dist/tools/browser_detect.d.ts +13 -0
- package/dist/tools/browser_detect.js +73 -0
- package/dist/tools/burst.d.ts +35 -0
- package/dist/tools/burst.js +344 -0
- package/dist/tools/canvas.d.ts +25 -0
- package/dist/tools/canvas.js +132 -0
- package/dist/tools/captcha.d.ts +38 -0
- package/dist/tools/captcha.js +209 -0
- package/dist/tools/click.d.ts +36 -0
- package/dist/tools/click.js +561 -0
- package/dist/tools/click_and_wait.d.ts +33 -0
- package/dist/tools/click_and_wait.js +149 -0
- package/dist/tools/clipboard.d.ts +29 -0
- package/dist/tools/clipboard.js +279 -0
- package/dist/tools/console.d.ts +21 -0
- package/dist/tools/console.js +107 -0
- package/dist/tools/cookies.d.ts +67 -0
- package/dist/tools/cookies.js +121 -0
- package/dist/tools/design_extract.d.ts +109 -0
- package/dist/tools/design_extract.js +641 -0
- package/dist/tools/dialog.d.ts +24 -0
- package/dist/tools/dialog.js +109 -0
- package/dist/tools/drag.d.ts +15 -0
- package/dist/tools/drag.js +29 -0
- package/dist/tools/emulation.d.ts +33 -0
- package/dist/tools/emulation.js +69 -0
- package/dist/tools/eval.d.ts +20 -0
- package/dist/tools/eval.js +92 -0
- package/dist/tools/fill.d.ts +41 -0
- package/dist/tools/fill.js +667 -0
- package/dist/tools/find.d.ts +30 -0
- package/dist/tools/find.js +60 -0
- package/dist/tools/geo.d.ts +19 -0
- package/dist/tools/geo.js +29 -0
- package/dist/tools/github/analyze.d.ts +4 -0
- package/dist/tools/github/analyze.js +113 -0
- package/dist/tools/github/cache.d.ts +21 -0
- package/dist/tools/github/cache.js +28 -0
- package/dist/tools/github/index.d.ts +4 -0
- package/dist/tools/github/index.js +4 -0
- package/dist/tools/github/issues.d.ts +9 -0
- package/dist/tools/github/issues.js +88 -0
- package/dist/tools/github/pr.d.ts +5 -0
- package/dist/tools/github/pr.js +88 -0
- package/dist/tools/github/rateLimiter.d.ts +4 -0
- package/dist/tools/github/rateLimiter.js +46 -0
- package/dist/tools/github/read.d.ts +34 -0
- package/dist/tools/github/read.js +74 -0
- package/dist/tools/github/repoContext.d.ts +20 -0
- package/dist/tools/github/repoContext.js +129 -0
- package/dist/tools/highlight.d.ts +20 -0
- package/dist/tools/highlight.js +140 -0
- package/dist/tools/hover.d.ts +19 -0
- package/dist/tools/hover.js +57 -0
- package/dist/tools/inspect.d.ts +17 -0
- package/dist/tools/inspect.js +125 -0
- package/dist/tools/integration.test.d.ts +2 -0
- package/dist/tools/integration.test.js +96 -0
- package/dist/tools/key.d.ts +25 -0
- package/dist/tools/key.js +173 -0
- package/dist/tools/macro_compiler.d.ts +7 -0
- package/dist/tools/macro_compiler.js +82 -0
- package/dist/tools/mouse.d.ts +21 -0
- package/dist/tools/mouse.js +62 -0
- package/dist/tools/navigate.d.ts +16 -0
- package/dist/tools/navigate.js +188 -0
- package/dist/tools/network_intercept.d.ts +17 -0
- package/dist/tools/network_intercept.js +151 -0
- package/dist/tools/office/index.d.ts +9 -0
- package/dist/tools/office/index.js +7 -0
- package/dist/tools/office/list.d.ts +15 -0
- package/dist/tools/office/list.js +41 -0
- package/dist/tools/office/parse.d.ts +20 -0
- package/dist/tools/office/parse.js +172 -0
- package/dist/tools/pdf.d.ts +22 -0
- package/dist/tools/pdf.js +42 -0
- package/dist/tools/performance.d.ts +12 -0
- package/dist/tools/performance.js +47 -0
- package/dist/tools/performance_test.d.ts +70 -0
- package/dist/tools/performance_test.js +128 -0
- package/dist/tools/plan.d.ts +39 -0
- package/dist/tools/plan.js +161 -0
- package/dist/tools/pointer.d.ts +35 -0
- package/dist/tools/pointer.js +522 -0
- package/dist/tools/read.d.ts +30 -0
- package/dist/tools/read.js +488 -0
- package/dist/tools/recording.d.ts +45 -0
- package/dist/tools/recording.js +124 -0
- package/dist/tools/response.d.ts +129 -0
- package/dist/tools/response.js +5 -0
- package/dist/tools/scrape.d.ts +24 -0
- package/dist/tools/scrape.js +140 -0
- package/dist/tools/screenshot.d.ts +40 -0
- package/dist/tools/screenshot.js +79 -0
- package/dist/tools/scroll.d.ts +23 -0
- package/dist/tools/scroll.js +196 -0
- package/dist/tools/select.d.ts +13 -0
- package/dist/tools/select.js +217 -0
- package/dist/tools/snapshot.d.ts +27 -0
- package/dist/tools/snapshot.js +99 -0
- package/dist/tools/storage.d.ts +18 -0
- package/dist/tools/storage.js +29 -0
- package/dist/tools/tabs.d.ts +77 -0
- package/dist/tools/tabs.js +342 -0
- package/dist/tools/thought.d.ts +16 -0
- package/dist/tools/thought.js +79 -0
- package/dist/tools/type.d.ts +65 -0
- package/dist/tools/type.js +1061 -0
- package/dist/tools/type_secret.d.ts +23 -0
- package/dist/tools/type_secret.js +229 -0
- package/dist/tools/upload.d.ts +19 -0
- package/dist/tools/upload.js +103 -0
- package/dist/tools/video_compiler.d.ts +24 -0
- package/dist/tools/video_compiler.js +199 -0
- package/dist/tools/viewport.d.ts +44 -0
- package/dist/tools/viewport.js +230 -0
- package/dist/tools/wait.d.ts +19 -0
- package/dist/tools/wait.js +202 -0
- package/dist/tools/wait_for.d.ts +23 -0
- package/dist/tools/wait_for.js +30 -0
- package/dist/tools/windows.d.ts +22 -0
- package/dist/tools/windows.js +57 -0
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +12 -0
- package/docs/DEV_MODE.md +68 -0
- package/docs/DOCUMENTATION.md +532 -0
- package/docs/PLUGINS.md +538 -0
- package/docs/TOOLS.md +104 -0
- package/docs/dev_plugin.md +310 -0
- package/ext-dist/background.js +467 -0
- package/ext-dist/content.js +3089 -0
- package/ext-dist/dashboard.html +583 -0
- package/ext-dist/hud/hud.js +73 -0
- package/ext-dist/hud/index.html +20 -0
- package/ext-dist/manifest.json +77 -0
- package/ext-dist/sidepanel/sidepanel.js +25 -0
- package/ext-dist/sidepanel.html +547 -0
- package/ext-dist/styles.css +218 -0
- package/icon.png +0 -0
- package/mcp.json +796 -0
- package/package.json +113 -0
- package/server.json +23 -0
- package/smithery.yaml +11 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* integration.test.ts — Phase 1.1
|
|
3
|
+
* Integration tests for click, type, and browser_map against real pages.
|
|
4
|
+
* Run: npx tsx src/tools/integration.test.ts
|
|
5
|
+
*/
|
|
6
|
+
import { loadConfigSync } from "../config/loader.js";
|
|
7
|
+
import { getOrConnect } from "../cdp/connector.js";
|
|
8
|
+
import { weaveClick } from "./click.js";
|
|
9
|
+
import { weaveType } from "./type.js";
|
|
10
|
+
import { browserMap } from "./read.js";
|
|
11
|
+
import { buildActionMap } from "../cdp/walker.js";
|
|
12
|
+
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
13
|
+
let passed = 0, failed = 0;
|
|
14
|
+
const assert = (cond, msg) => {
|
|
15
|
+
if (cond) {
|
|
16
|
+
console.error(` ✅ ${msg}`);
|
|
17
|
+
passed++;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.error(` ❌ ${msg}`);
|
|
21
|
+
failed++;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
async function main() {
|
|
25
|
+
const config = loadConfigSync();
|
|
26
|
+
const client = await getOrConnect(config);
|
|
27
|
+
const session = client.session;
|
|
28
|
+
// ── Test 1: browser_map returns ref IDs ────────────
|
|
29
|
+
console.error("\n── Test 1: browser_map returns ref IDs ──");
|
|
30
|
+
await session.Page.navigate({ url: "https://httpbin.org/forms/post" });
|
|
31
|
+
await sleep(3000);
|
|
32
|
+
const mapStr = await browserMap(session, { prune: true }, "default", config);
|
|
33
|
+
assert(typeof mapStr === "string" && mapStr.length > 80, "map returned markdown content");
|
|
34
|
+
const rawMap = await buildActionMap(session, { prune: true }, "default");
|
|
35
|
+
assert(rawMap.elements.length >= 3, "map has >= 3 elements");
|
|
36
|
+
const allValid = rawMap.elements.filter(Boolean).every(el => el.id && String(el.id).startsWith("w:"));
|
|
37
|
+
assert(allValid, "all elements have w: ref IDs");
|
|
38
|
+
// ── Test 2: weaveClick by label ────────────────────
|
|
39
|
+
console.error("\n── Test 2: weaveClick by label ──");
|
|
40
|
+
await session.Page.navigate({ url: "https://httpbin.org/forms/post" });
|
|
41
|
+
await sleep(3000);
|
|
42
|
+
const clickR = await weaveClick(session, { label: "Submit order" }, config);
|
|
43
|
+
assert(clickR.success === true, "click returned success");
|
|
44
|
+
assert(typeof clickR.clicked === "string" && clickR.clicked.length > 0, "clicked field set");
|
|
45
|
+
assert(typeof clickR.ref === "string" && clickR.ref.startsWith("w:"), "ref is w:NN format");
|
|
46
|
+
assert(typeof clickR.execution_ms === "number" && clickR.execution_ms > 0, "execution_ms > 0");
|
|
47
|
+
// ── Test 3: weaveType by ref ID ────────────────────
|
|
48
|
+
console.error("\n── Test 3: weaveType by ref ID ──");
|
|
49
|
+
await session.Page.navigate({ url: "https://httpbin.org/forms/post" });
|
|
50
|
+
await sleep(3000);
|
|
51
|
+
const elems = await buildActionMap(session, { prune: true }, "default");
|
|
52
|
+
const textbox = elems.elements.find(el => el.role === "textbox" || (el.role === "input" && !el.type));
|
|
53
|
+
if (textbox?.id) {
|
|
54
|
+
const typeR = await weaveType(session, { id: textbox.id, text: "Hello" }, config);
|
|
55
|
+
assert(typeR.success === true, "type returned success");
|
|
56
|
+
assert(typeof typeR.length === "number" && typeR.length > 0, "length > 0");
|
|
57
|
+
assert(typeof typeR.typed_into === "string", "typed_into is string");
|
|
58
|
+
assert(typeof typeR.execution_ms === "number" && typeR.execution_ms > 0, "execution_ms > 0");
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
assert(true, "no text input found (skip)");
|
|
62
|
+
}
|
|
63
|
+
// ── Test 4: weaveClick by ref ID ───────────────────
|
|
64
|
+
console.error("\n── Test 4: weaveClick by ref ID ──");
|
|
65
|
+
await session.Page.navigate({ url: "https://httpbin.org/forms/post" });
|
|
66
|
+
await sleep(3000);
|
|
67
|
+
const map2 = await buildActionMap(session, { prune: true }, "default");
|
|
68
|
+
const btn = map2.elements.find(r => r.role === "button");
|
|
69
|
+
if (btn?.id) {
|
|
70
|
+
const refR = await weaveClick(session, { id: btn.id }, config);
|
|
71
|
+
assert(refR.success === true, "ref-ID click returned success");
|
|
72
|
+
assert(refR.ref === btn.id, "click.ref matches input ref");
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
assert(true, "no button found (skip)");
|
|
76
|
+
}
|
|
77
|
+
// ── Test 5: Stuck detection on nonexistent element ─
|
|
78
|
+
console.error("\n── Test 5: Stuck detection ──");
|
|
79
|
+
const stuckR = await weaveClick(session, { label: "__nonexistent__" }, config);
|
|
80
|
+
if (stuckR.success) {
|
|
81
|
+
assert(stuckR.stuck_warning === true, "nonexistent click reports stuck_warning");
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
assert(true, "nonexistent click correctly fails");
|
|
85
|
+
}
|
|
86
|
+
// ── Summary ────────────────────────────────────────
|
|
87
|
+
console.error(`\nResults: ${passed} passed, ${failed} failed`);
|
|
88
|
+
await session.close().catch(() => { });
|
|
89
|
+
if (failed > 0)
|
|
90
|
+
process.exit(1);
|
|
91
|
+
else
|
|
92
|
+
console.error("ALL INTEGRATION TESTS PASSED");
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
main();
|
|
96
|
+
//# sourceMappingURL=integration.test.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab — tools/key.ts
|
|
3
|
+
* Keyboard event dispatcher with allowlisted control keys and modifier support.
|
|
4
|
+
* Weavetab by fy2ne
|
|
5
|
+
*/
|
|
6
|
+
import CDP from "chrome-remote-interface";
|
|
7
|
+
import type { Config } from "../config/loader.js";
|
|
8
|
+
import type { WeaveError } from "./click.js";
|
|
9
|
+
type Modifier = "Alt" | "Ctrl" | "Meta" | "Shift";
|
|
10
|
+
interface KeyResult {
|
|
11
|
+
success: true;
|
|
12
|
+
pressed: string;
|
|
13
|
+
tab_id: string;
|
|
14
|
+
url: string;
|
|
15
|
+
title: string;
|
|
16
|
+
url_changed?: boolean;
|
|
17
|
+
dom_changed?: boolean;
|
|
18
|
+
stuck_warning?: boolean;
|
|
19
|
+
stuck_hint?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function weaveKey(session: CDP.Client, args: {
|
|
22
|
+
key: string;
|
|
23
|
+
modifiers?: Modifier[];
|
|
24
|
+
}, _config: Config): Promise<KeyResult | WeaveError>;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab — tools/key.ts
|
|
3
|
+
* Keyboard event dispatcher with allowlisted control keys and modifier support.
|
|
4
|
+
* Weavetab by fy2ne
|
|
5
|
+
*/
|
|
6
|
+
import { recordAction } from "../intelligence/trail.js";
|
|
7
|
+
import { waitForDOMStable } from "../sensors/guard.js";
|
|
8
|
+
import { waitForNetworkIdle } from "../sensors/wait.js";
|
|
9
|
+
import { buildActionMap, toRefEntries } from "../cdp/walker.js";
|
|
10
|
+
import { cacheActionMap, cacheBoxModel } from "../state/cache.js";
|
|
11
|
+
import { computeDelta, storeSnapshot } from "../state/delta.js";
|
|
12
|
+
import { sessionRegistry } from "../state/session.js";
|
|
13
|
+
import { getConfigAgentId } from "../config/loader.js";
|
|
14
|
+
import { sendToExtension } from "../cdp/helpers.js";
|
|
15
|
+
const ALLOWED_KEYS = new Set([
|
|
16
|
+
"Enter", "Escape", "Tab", "Backspace", "Delete", "Space",
|
|
17
|
+
"ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight",
|
|
18
|
+
"Home", "End", "PageUp", "PageDown",
|
|
19
|
+
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
|
|
20
|
+
]);
|
|
21
|
+
export async function weaveKey(session, args, _config) {
|
|
22
|
+
const { key, modifiers } = args;
|
|
23
|
+
// Allow single printable chars or control keys from the allowlist
|
|
24
|
+
if (key.length > 1 && !ALLOWED_KEYS.has(key)) {
|
|
25
|
+
return {
|
|
26
|
+
success: false,
|
|
27
|
+
error_code: "INVALID_KEY",
|
|
28
|
+
message: `[!] Key "${key}" is not a valid control key. Use single characters or: ${[...ALLOWED_KEYS].join(", ")}`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
let modMask = 0;
|
|
32
|
+
if (modifiers) {
|
|
33
|
+
if (modifiers.includes("Alt"))
|
|
34
|
+
modMask |= 1;
|
|
35
|
+
if (modifiers.includes("Ctrl"))
|
|
36
|
+
modMask |= 2;
|
|
37
|
+
if (modifiers.includes("Meta"))
|
|
38
|
+
modMask |= 4;
|
|
39
|
+
if (modifiers.includes("Shift"))
|
|
40
|
+
modMask |= 8;
|
|
41
|
+
}
|
|
42
|
+
const label = modifiers && modifiers.length > 0 ? `${modifiers.join("+")}+${key}` : key;
|
|
43
|
+
await sendToExtension(session, { type: 'Weavetab_STATE', hud: { action: `pressing ${label}` } });
|
|
44
|
+
const { frameTree: beforeFrameTree } = await session.Page.getFrameTree();
|
|
45
|
+
const urlBefore = beforeFrameTree.frame.url;
|
|
46
|
+
// Track map before for delta if Enter is pressed
|
|
47
|
+
let targetId = "default";
|
|
48
|
+
const active = sessionRegistry.getActive(getConfigAgentId(_config));
|
|
49
|
+
if (active)
|
|
50
|
+
targetId = active.targetId;
|
|
51
|
+
const mapBefore = await buildActionMap(session, { lite: true }, targetId);
|
|
52
|
+
storeSnapshot(targetId, urlBefore, toRefEntries(mapBefore.elements));
|
|
53
|
+
// We removed the direct toast injection here because the extension handles HUD display via Weavetab_STATE (line 66)
|
|
54
|
+
await session.Input.dispatchKeyEvent({ type: "rawKeyDown", key, modifiers: modMask, windowsVirtualKeyCode: key === "Enter" ? 13 : undefined, nativeVirtualKeyCode: key === "Enter" ? 13 : undefined });
|
|
55
|
+
if (key === "Enter") {
|
|
56
|
+
// SPA Fallback: direct form submit + submit button click for React/Vue/Google
|
|
57
|
+
// This is needed because Input.dispatchKeyEvent alone doesn't trigger SPA form submission
|
|
58
|
+
await session.Runtime.evaluate({ expression: `
|
|
59
|
+
(function(){
|
|
60
|
+
try {
|
|
61
|
+
var el = document.activeElement;
|
|
62
|
+
if (!el || !el.tagName) return;
|
|
63
|
+
|
|
64
|
+
// Focus the element first to make sure it's active
|
|
65
|
+
if (typeof el.focus === 'function') el.focus();
|
|
66
|
+
|
|
67
|
+
// 1. Try native form submit (Google search, DuckDuckGo, etc.)
|
|
68
|
+
var form = el.closest('form');
|
|
69
|
+
if (form) {
|
|
70
|
+
var submitBtn = form.querySelector('input[type="submit"], button[type="submit"]');
|
|
71
|
+
if (submitBtn && submitBtn.offsetParent !== null) { submitBtn.click(); return; }
|
|
72
|
+
try { form.submit(); return; } catch(e) {}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 2. Google-specific: find name="q" input and submit its form
|
|
76
|
+
var q = document.querySelector('input[name="q"], textarea[name="q"]');
|
|
77
|
+
if (q) {
|
|
78
|
+
var qForm = q.closest('form');
|
|
79
|
+
if (qForm) { try { qForm.submit(); return; } catch(e) {} }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 3. Last resort: find any visible submit/search button near the active element
|
|
83
|
+
var parent = el.parentElement;
|
|
84
|
+
while (parent && parent.tagName !== 'BODY') {
|
|
85
|
+
var btns = parent.querySelectorAll('button, input[type="submit"], input[type="button"]');
|
|
86
|
+
for (var i = 0; i < btns.length; i++) {
|
|
87
|
+
if (btns[i].offsetParent !== null && btns[i].getBoundingClientRect().width > 0) { btns[i].click(); return; }
|
|
88
|
+
}
|
|
89
|
+
parent = parent.parentElement;
|
|
90
|
+
}
|
|
91
|
+
} catch(e) {}
|
|
92
|
+
})();
|
|
93
|
+
` }).catch(() => { });
|
|
94
|
+
}
|
|
95
|
+
await session.Input.dispatchKeyEvent({ type: "keyUp", key, modifiers: modMask, windowsVirtualKeyCode: key === "Enter" ? 13 : undefined, nativeVirtualKeyCode: key === "Enter" ? 13 : undefined });
|
|
96
|
+
// ── Post-Action Pipeline & Predictive Action Queue ────────────────────────
|
|
97
|
+
const predictiveQueue = async () => {
|
|
98
|
+
try {
|
|
99
|
+
const nextMap = await buildActionMap(session, { lite: true }, targetId);
|
|
100
|
+
cacheActionMap(targetId, nextMap);
|
|
101
|
+
for (const el of nextMap.elements.slice(0, 10)) {
|
|
102
|
+
if (el.backendNodeId) {
|
|
103
|
+
const { nodeIds } = await session.DOM.pushNodesByBackendIdsToFrontend({ backendNodeIds: [el.backendNodeId] }).catch(() => ({ nodeIds: [] }));
|
|
104
|
+
if (nodeIds[0]) {
|
|
105
|
+
const box = await session.DOM.getBoxModel({ nodeId: nodeIds[0] }).catch(() => null);
|
|
106
|
+
if (box)
|
|
107
|
+
cacheBoxModel(targetId, el.backendNodeId, box.model);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch { /* ignore pre-fetch errors */ }
|
|
113
|
+
};
|
|
114
|
+
const settleTimeout = key === "Enter" ? 5000 : 2500;
|
|
115
|
+
await Promise.all([
|
|
116
|
+
waitForDOMStable(session, 50, settleTimeout),
|
|
117
|
+
waitForNetworkIdle(session, 50, settleTimeout).catch(() => { }),
|
|
118
|
+
predictiveQueue()
|
|
119
|
+
]);
|
|
120
|
+
// Post-key location context
|
|
121
|
+
let postUrl = "";
|
|
122
|
+
let postTitle = "";
|
|
123
|
+
try {
|
|
124
|
+
const { frameTree } = await session.Page.getFrameTree();
|
|
125
|
+
postUrl = frameTree.frame.url;
|
|
126
|
+
try {
|
|
127
|
+
const titleRes = await session.Runtime.evaluate({ expression: 'document.title', returnByValue: true });
|
|
128
|
+
postTitle = titleRes?.result?.value || postUrl;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
postTitle = postUrl;
|
|
132
|
+
}
|
|
133
|
+
const activeSession = sessionRegistry.getActive(getConfigAgentId(_config));
|
|
134
|
+
if (activeSession) {
|
|
135
|
+
activeSession.url = postUrl;
|
|
136
|
+
activeSession.title = postTitle;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch { /* ignore */ }
|
|
140
|
+
const urlChanged = postUrl !== urlBefore;
|
|
141
|
+
let domChanged = false;
|
|
142
|
+
let stuckWarning = false;
|
|
143
|
+
let stuckHint;
|
|
144
|
+
if (key === "Enter") {
|
|
145
|
+
const nextMap = await buildActionMap(session, { lite: true }, targetId);
|
|
146
|
+
const newRefs = toRefEntries(nextMap.elements);
|
|
147
|
+
const diff = computeDelta(targetId, urlBefore, newRefs);
|
|
148
|
+
const changedRefs = diff ? [...diff.added, ...diff.changed] : [];
|
|
149
|
+
domChanged = changedRefs.length > 0 || (diff?.removed.length ?? 0) > 0;
|
|
150
|
+
stuckWarning = !domChanged && !urlChanged;
|
|
151
|
+
if (stuckWarning) {
|
|
152
|
+
await sendToExtension(session, { type: 'Weavetab_STATE', hud: { action: 'hmm, no response. reassessing...' } });
|
|
153
|
+
stuckHint = "Page did not respond to Enter key. You might need to find the actual submit button and use browser_click instead.";
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
recordAction({
|
|
157
|
+
timestamp: new Date().toISOString(),
|
|
158
|
+
tool: "browser_key",
|
|
159
|
+
input: { key, modifiers },
|
|
160
|
+
result: { success: true, pressed: label },
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
success: true,
|
|
164
|
+
pressed: label,
|
|
165
|
+
tab_id: targetId,
|
|
166
|
+
url: postUrl,
|
|
167
|
+
title: postTitle,
|
|
168
|
+
url_changed: urlChanged,
|
|
169
|
+
dom_changed: domChanged,
|
|
170
|
+
stuck_warning: stuckWarning,
|
|
171
|
+
...(stuckHint ? { stuck_hint: stuckHint } : {})
|
|
172
|
+
};
|
|
173
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TrailEntry as TrailStep } from "../intelligence/trail.js";
|
|
2
|
+
import type { AnyBurstStep } from "./burst.js";
|
|
3
|
+
/**
|
|
4
|
+
* Compiles a sequence of successful trail steps into a single burst macro.
|
|
5
|
+
* This skips intermediate DOM reads for faster execution.
|
|
6
|
+
*/
|
|
7
|
+
export declare function compileTraceToMacro(steps: TrailStep[]): AnyBurstStep[];
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { logDebug } from "../audit/logger.js";
|
|
2
|
+
/**
|
|
3
|
+
* Universal parameter extractor — tries ALL known parameter key patterns plus
|
|
4
|
+
* runtime introspection to find the args container regardless of the source
|
|
5
|
+
* code path that produced the trail entry.
|
|
6
|
+
*/
|
|
7
|
+
function extractArgs(step) {
|
|
8
|
+
const s = step;
|
|
9
|
+
// 1. Known parameter key patterns (ordered by specificity)
|
|
10
|
+
const knownKeys = [
|
|
11
|
+
'arguments', 'args', 'mcp_arguments', 'input',
|
|
12
|
+
'params', 'parameters', 'tool_args', 'toolInput',
|
|
13
|
+
'data', 'payload', 'options',
|
|
14
|
+
];
|
|
15
|
+
for (const key of knownKeys) {
|
|
16
|
+
const val = s[key];
|
|
17
|
+
if (val !== null && val !== undefined && typeof val === 'object' && !Array.isArray(val)) {
|
|
18
|
+
return val;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// 2. Runtime introspection: find the first own property that looks like
|
|
22
|
+
// a params container (non-null object, not a standard metadata key).
|
|
23
|
+
const metaKeys = new Set([
|
|
24
|
+
'tool', 'result', 'timestamp', 'type', 'id',
|
|
25
|
+
'status', 'error', 'duration', 'startTime', 'endTime',
|
|
26
|
+
'session', 'tabId', 'targetId',
|
|
27
|
+
]);
|
|
28
|
+
for (const key of Object.keys(s)) {
|
|
29
|
+
if (metaKeys.has(key))
|
|
30
|
+
continue;
|
|
31
|
+
const val = s[key];
|
|
32
|
+
if (val !== null && val !== undefined && typeof val === 'object' && !Array.isArray(val)) {
|
|
33
|
+
logDebug(`[macro_compiler] Found unknown param key "${key}" on step ${step.tool}`);
|
|
34
|
+
return val;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// 3. Totally empty — log the shape for debugging
|
|
38
|
+
logDebug(`[macro_compiler] Could not extract args from step ${step.tool}, shape: ${Object.keys(s).join(',')}`);
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Compiles a sequence of successful trail steps into a single burst macro.
|
|
43
|
+
* This skips intermediate DOM reads for faster execution.
|
|
44
|
+
*/
|
|
45
|
+
export function compileTraceToMacro(steps) {
|
|
46
|
+
const macro = [];
|
|
47
|
+
let lastKey = "";
|
|
48
|
+
const BURST_TOOLS = new Set([
|
|
49
|
+
"browser_click", "browser_type", "browser_navigate", "browser_go",
|
|
50
|
+
"browser_key", "browser_scroll", "browser_wait", "browser_select",
|
|
51
|
+
"browser_pointer", "browser_eval", "browser_console", "browser_find",
|
|
52
|
+
"browser_fill", "browser_type_secret", "browser_inspect",
|
|
53
|
+
"browser_screenshot", "browser_storage", "browser_cookies",
|
|
54
|
+
"browser_highlight", "browser_scrape",
|
|
55
|
+
"browser_canvas", "browser_performance", "browser_snapshot",
|
|
56
|
+
"browser_pdf", "browser_dialog", "browser_upload", "browser_automation",
|
|
57
|
+
"browser_viewport", "browser_clipboard", "browser_detect",
|
|
58
|
+
"browser_macro_compile", "browser_reset_loop_counter", "browser_recording",
|
|
59
|
+
"browser_fill", "type_and_send", "navigate_and_read",
|
|
60
|
+
"click_and_wait", "scroll_and_read",
|
|
61
|
+
]);
|
|
62
|
+
steps.forEach((step, idx) => {
|
|
63
|
+
if (step.result && !step.result.success)
|
|
64
|
+
return;
|
|
65
|
+
if (step.tool === "browser_map") {
|
|
66
|
+
if (idx === steps.length - 1) {
|
|
67
|
+
macro.push({ tool: "browser_map", args: step.input || {} });
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (BURST_TOOLS.has(step.tool)) {
|
|
72
|
+
const args = extractArgs(step);
|
|
73
|
+
// Dedupe consecutive identical steps (same tool + same args)
|
|
74
|
+
const key = `${step.tool}:${JSON.stringify(args)}`;
|
|
75
|
+
if (key !== lastKey) {
|
|
76
|
+
macro.push({ tool: step.tool, args });
|
|
77
|
+
lastKey = key;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return macro;
|
|
82
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import CDP from "chrome-remote-interface";
|
|
2
|
+
import type { Config } from "../config/loader.js";
|
|
3
|
+
export interface MouseResult {
|
|
4
|
+
success: true;
|
|
5
|
+
action: string;
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
end_x?: number;
|
|
9
|
+
end_y?: number;
|
|
10
|
+
execution_ms: number;
|
|
11
|
+
tab_id: string;
|
|
12
|
+
url: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function browserMouse(session: CDP.Client, args: {
|
|
15
|
+
action: "hover" | "click" | "double_click" | "drag_and_drop";
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
end_x?: number;
|
|
19
|
+
end_y?: number;
|
|
20
|
+
}, config: Config): Promise<MouseResult>;
|
|
21
|
+
//# sourceMappingURL=mouse.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { logAction } from "../audit/logger.js";
|
|
2
|
+
import { recordAction } from "../intelligence/trail.js";
|
|
3
|
+
import { ghostMove } from "../overlay/ghost.js";
|
|
4
|
+
import { waitForDOMStable } from "../sensors/guard.js";
|
|
5
|
+
export async function browserMouse(session, args, config) {
|
|
6
|
+
const { action, x, y, end_x, end_y } = args;
|
|
7
|
+
const startMs = Date.now();
|
|
8
|
+
const { Page, Input } = session;
|
|
9
|
+
const { frameTree } = await Page.getFrameTree();
|
|
10
|
+
const url = frameTree.frame.url;
|
|
11
|
+
let targetId = "default";
|
|
12
|
+
const { sessionRegistry } = await import("../state/session.js");
|
|
13
|
+
const active = sessionRegistry.getActive();
|
|
14
|
+
if (active)
|
|
15
|
+
targetId = active.targetId;
|
|
16
|
+
// Move to target using human-like motion (no label — avoids fake "scanning" delay)
|
|
17
|
+
await ghostMove(session, x, y, config);
|
|
18
|
+
if (action === "click") {
|
|
19
|
+
await Input.dispatchMouseEvent({ type: "mousePressed", x, y, button: "left", clickCount: 1 });
|
|
20
|
+
await Input.dispatchMouseEvent({ type: "mouseReleased", x, y, button: "left", clickCount: 1 });
|
|
21
|
+
}
|
|
22
|
+
else if (action === "double_click") {
|
|
23
|
+
await Input.dispatchMouseEvent({ type: "mousePressed", x, y, button: "left", clickCount: 1 });
|
|
24
|
+
await Input.dispatchMouseEvent({ type: "mouseReleased", x, y, button: "left", clickCount: 1 });
|
|
25
|
+
await new Promise(r => setTimeout(r, 100));
|
|
26
|
+
await Input.dispatchMouseEvent({ type: "mousePressed", x, y, button: "left", clickCount: 2 });
|
|
27
|
+
await Input.dispatchMouseEvent({ type: "mouseReleased", x, y, button: "left", clickCount: 2 });
|
|
28
|
+
}
|
|
29
|
+
else if (action === "drag_and_drop") {
|
|
30
|
+
if (end_x === undefined || end_y === undefined) {
|
|
31
|
+
throw new Error("drag_and_drop requires end_x and end_y");
|
|
32
|
+
}
|
|
33
|
+
await Input.dispatchMouseEvent({ type: "mousePressed", x, y, button: "left", clickCount: 1 });
|
|
34
|
+
await new Promise(r => setTimeout(r, 200));
|
|
35
|
+
// Drag to destination
|
|
36
|
+
await ghostMove(session, end_x, end_y, config);
|
|
37
|
+
await new Promise(r => setTimeout(r, 200));
|
|
38
|
+
await Input.dispatchMouseEvent({ type: "mouseReleased", x: end_x, y: end_y, button: "left", clickCount: 1 });
|
|
39
|
+
}
|
|
40
|
+
// Settle
|
|
41
|
+
await waitForDOMStable(session, 50, 1500).catch(() => { });
|
|
42
|
+
const executionMs = Date.now() - startMs;
|
|
43
|
+
logAction("browser_mouse", action, `(${x}, ${y}) (exec: ${executionMs}ms)`);
|
|
44
|
+
recordAction({
|
|
45
|
+
timestamp: new Date().toISOString(),
|
|
46
|
+
tool: "browser_mouse",
|
|
47
|
+
input: args,
|
|
48
|
+
result: { success: true },
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
success: true,
|
|
52
|
+
action,
|
|
53
|
+
x,
|
|
54
|
+
y,
|
|
55
|
+
end_x,
|
|
56
|
+
end_y,
|
|
57
|
+
execution_ms: executionMs,
|
|
58
|
+
tab_id: targetId,
|
|
59
|
+
url,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=mouse.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab — tools/navigate.ts
|
|
3
|
+
* URL navigation with domain blocklist enforcement and post-navigation DOM stability wait.
|
|
4
|
+
* Weavetab by fy2ne
|
|
5
|
+
*/
|
|
6
|
+
import CDP from "chrome-remote-interface";
|
|
7
|
+
import type { Config } from "../config/loader.js";
|
|
8
|
+
import type { WeaveError } from "./click.js";
|
|
9
|
+
interface NavigateResult {
|
|
10
|
+
success: true;
|
|
11
|
+
url: string;
|
|
12
|
+
title: string;
|
|
13
|
+
tab_id: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function weaveNavigate(session: CDP.Client, url: string, config: Config, targetId?: string, force?: boolean, fast?: boolean): Promise<NavigateResult | WeaveError>;
|
|
16
|
+
export {};
|