@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,230 @@
|
|
|
1
|
+
export const DEVICE_PRESETS = {
|
|
2
|
+
'iPhone 15 Pro': {
|
|
3
|
+
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
|
|
4
|
+
viewport: { width: 393, height: 852 },
|
|
5
|
+
deviceScaleFactor: 3,
|
|
6
|
+
mobile: true,
|
|
7
|
+
hasTouch: true,
|
|
8
|
+
screenOrientation: 'portrait'
|
|
9
|
+
},
|
|
10
|
+
'iPhone 15 Pro Max': {
|
|
11
|
+
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
|
|
12
|
+
viewport: { width: 430, height: 932 },
|
|
13
|
+
deviceScaleFactor: 3,
|
|
14
|
+
mobile: true,
|
|
15
|
+
hasTouch: true,
|
|
16
|
+
screenOrientation: 'portrait'
|
|
17
|
+
},
|
|
18
|
+
'iPhone 14': {
|
|
19
|
+
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',
|
|
20
|
+
viewport: { width: 390, height: 844 },
|
|
21
|
+
deviceScaleFactor: 3,
|
|
22
|
+
mobile: true,
|
|
23
|
+
hasTouch: true,
|
|
24
|
+
screenOrientation: 'portrait'
|
|
25
|
+
},
|
|
26
|
+
'iPhone 14 Pro': {
|
|
27
|
+
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',
|
|
28
|
+
viewport: { width: 393, height: 852 },
|
|
29
|
+
deviceScaleFactor: 3,
|
|
30
|
+
mobile: true,
|
|
31
|
+
hasTouch: true,
|
|
32
|
+
screenOrientation: 'portrait'
|
|
33
|
+
},
|
|
34
|
+
'iPad Pro 12.9': {
|
|
35
|
+
userAgent: 'Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
|
|
36
|
+
viewport: { width: 1024, height: 1366 },
|
|
37
|
+
deviceScaleFactor: 2,
|
|
38
|
+
mobile: true,
|
|
39
|
+
hasTouch: true,
|
|
40
|
+
screenOrientation: 'portrait'
|
|
41
|
+
},
|
|
42
|
+
'Samsung Galaxy S24': {
|
|
43
|
+
userAgent: 'Mozilla/5.0 (Linux; Android 14; SM-S921B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',
|
|
44
|
+
viewport: { width: 360, height: 800 },
|
|
45
|
+
deviceScaleFactor: 3,
|
|
46
|
+
mobile: true,
|
|
47
|
+
hasTouch: true,
|
|
48
|
+
screenOrientation: 'portrait'
|
|
49
|
+
},
|
|
50
|
+
'Samsung Galaxy S24 Ultra': {
|
|
51
|
+
userAgent: 'Mozilla/5.0 (Linux; Android 14; SM-S928B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',
|
|
52
|
+
viewport: { width: 412, height: 915 },
|
|
53
|
+
deviceScaleFactor: 3,
|
|
54
|
+
mobile: true,
|
|
55
|
+
hasTouch: true,
|
|
56
|
+
screenOrientation: 'portrait'
|
|
57
|
+
},
|
|
58
|
+
'Pixel 8 Pro': {
|
|
59
|
+
userAgent: 'Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',
|
|
60
|
+
viewport: { width: 412, height: 892 },
|
|
61
|
+
deviceScaleFactor: 2.625,
|
|
62
|
+
mobile: true,
|
|
63
|
+
hasTouch: true,
|
|
64
|
+
screenOrientation: 'portrait'
|
|
65
|
+
},
|
|
66
|
+
'Desktop 1920x1080': {
|
|
67
|
+
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
68
|
+
viewport: { width: 1920, height: 1080 },
|
|
69
|
+
deviceScaleFactor: 1,
|
|
70
|
+
mobile: false,
|
|
71
|
+
hasTouch: false,
|
|
72
|
+
screenOrientation: 'landscape'
|
|
73
|
+
},
|
|
74
|
+
'Desktop 1366x768': {
|
|
75
|
+
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
76
|
+
viewport: { width: 1366, height: 768 },
|
|
77
|
+
deviceScaleFactor: 1,
|
|
78
|
+
mobile: false,
|
|
79
|
+
hasTouch: false,
|
|
80
|
+
screenOrientation: 'landscape'
|
|
81
|
+
},
|
|
82
|
+
'Laptop 1440x900': {
|
|
83
|
+
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
84
|
+
viewport: { width: 1440, height: 900 },
|
|
85
|
+
deviceScaleFactor: 1,
|
|
86
|
+
mobile: false,
|
|
87
|
+
hasTouch: false,
|
|
88
|
+
screenOrientation: 'landscape'
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
export async function browserViewport(session, options, _config) {
|
|
92
|
+
const { action, width, height, deviceScaleFactor = 1, mobile = false, devicePreset, userAgent, geolocation, locale, timezoneId, colorScheme, hasTouch, screenOrientation } = options;
|
|
93
|
+
if (action === "list") {
|
|
94
|
+
return {
|
|
95
|
+
success: true,
|
|
96
|
+
message: "Available device presets",
|
|
97
|
+
data: Object.keys(DEVICE_PRESETS).map(key => ({
|
|
98
|
+
devicePreset: key,
|
|
99
|
+
...DEVICE_PRESETS[key]
|
|
100
|
+
}))
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (action === "preset") {
|
|
104
|
+
if (!devicePreset) {
|
|
105
|
+
throw new Error("devicePreset is required for preset action");
|
|
106
|
+
}
|
|
107
|
+
const preset = DEVICE_PRESETS[devicePreset];
|
|
108
|
+
if (!preset) {
|
|
109
|
+
throw new Error(`Unknown device preset: ${devicePreset}. Available: ${Object.keys(DEVICE_PRESETS).join(', ')}`);
|
|
110
|
+
}
|
|
111
|
+
await applyViewportEmulation(session, {
|
|
112
|
+
width: preset.viewport.width,
|
|
113
|
+
height: preset.viewport.height,
|
|
114
|
+
deviceScaleFactor: preset.deviceScaleFactor,
|
|
115
|
+
mobile: preset.mobile,
|
|
116
|
+
hasTouch: preset.hasTouch,
|
|
117
|
+
screenOrientation: preset.screenOrientation,
|
|
118
|
+
userAgent: preset.userAgent,
|
|
119
|
+
geolocation,
|
|
120
|
+
locale,
|
|
121
|
+
timezoneId,
|
|
122
|
+
colorScheme
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
success: true,
|
|
126
|
+
message: `Applied device preset: ${devicePreset}`,
|
|
127
|
+
data: { devicePreset, ...preset }
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (action === "clear") {
|
|
131
|
+
await session.Emulation.clearDeviceMetricsOverride();
|
|
132
|
+
await session.Network.setUserAgentOverride({ userAgent: '' });
|
|
133
|
+
await session.Emulation.clearGeolocationOverride();
|
|
134
|
+
await session.Emulation.setTimezoneOverride({ timezoneId: '' });
|
|
135
|
+
return { success: true, message: "Cleared all viewport emulation" };
|
|
136
|
+
}
|
|
137
|
+
if (action === "set") {
|
|
138
|
+
const hasViewport = width !== undefined && height !== undefined;
|
|
139
|
+
const hasEmulation = geolocation !== undefined || timezoneId !== undefined || locale !== undefined || colorScheme !== undefined;
|
|
140
|
+
if (!hasViewport && !hasEmulation) {
|
|
141
|
+
throw new Error("Provide width/height for viewport, or geolocation/timezone/locale/colorScheme for emulation");
|
|
142
|
+
}
|
|
143
|
+
if (hasViewport) {
|
|
144
|
+
await applyViewportEmulation(session, {
|
|
145
|
+
width,
|
|
146
|
+
height,
|
|
147
|
+
deviceScaleFactor,
|
|
148
|
+
mobile,
|
|
149
|
+
hasTouch,
|
|
150
|
+
screenOrientation,
|
|
151
|
+
userAgent,
|
|
152
|
+
geolocation,
|
|
153
|
+
locale,
|
|
154
|
+
timezoneId,
|
|
155
|
+
colorScheme
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
success: true,
|
|
159
|
+
message: `Viewport set to ${width}x${height} (mobile: ${mobile}, dpr: ${deviceScaleFactor}, touch: ${hasTouch})`
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
// Emulation-only: apply geo/timezone/locale/colorScheme without touching viewport dimensions
|
|
163
|
+
const msg = [];
|
|
164
|
+
if (geolocation) {
|
|
165
|
+
await session.Emulation.setGeolocationOverride({
|
|
166
|
+
latitude: geolocation.latitude,
|
|
167
|
+
longitude: geolocation.longitude,
|
|
168
|
+
accuracy: geolocation.accuracy || 100
|
|
169
|
+
});
|
|
170
|
+
msg.push(`Geolocation set to ${geolocation.latitude}, ${geolocation.longitude}`);
|
|
171
|
+
}
|
|
172
|
+
if (timezoneId) {
|
|
173
|
+
await session.Emulation.setTimezoneOverride({ timezoneId });
|
|
174
|
+
msg.push(`Timezone set to ${timezoneId}`);
|
|
175
|
+
}
|
|
176
|
+
if (locale) {
|
|
177
|
+
await session.Emulation.setLocaleOverride({ locale });
|
|
178
|
+
msg.push(`Locale set to ${locale}`);
|
|
179
|
+
}
|
|
180
|
+
if (colorScheme && colorScheme !== 'no-preference') {
|
|
181
|
+
await session.Emulation.setEmulatedMedia({
|
|
182
|
+
features: [{ name: 'prefers-color-scheme', value: colorScheme }]
|
|
183
|
+
});
|
|
184
|
+
msg.push(`Color scheme set to ${colorScheme}`);
|
|
185
|
+
}
|
|
186
|
+
return { success: true, message: msg.join('. ') };
|
|
187
|
+
}
|
|
188
|
+
throw new Error("Unknown action");
|
|
189
|
+
}
|
|
190
|
+
async function applyViewportEmulation(session, options) {
|
|
191
|
+
const { width, height, deviceScaleFactor, mobile, hasTouch = mobile, screenOrientation, userAgent, geolocation, locale, timezoneId, colorScheme } = options;
|
|
192
|
+
// Set device metrics override
|
|
193
|
+
const orientation = screenOrientation === 'none' ? undefined :
|
|
194
|
+
screenOrientation === 'landscape'
|
|
195
|
+
? { type: 'landscapePrimary', angle: 90 }
|
|
196
|
+
: { type: 'portraitPrimary', angle: 0 };
|
|
197
|
+
await session.Emulation.setDeviceMetricsOverride({
|
|
198
|
+
width,
|
|
199
|
+
height,
|
|
200
|
+
deviceScaleFactor,
|
|
201
|
+
mobile,
|
|
202
|
+
screenOrientation: orientation
|
|
203
|
+
});
|
|
204
|
+
// Set user agent if provided
|
|
205
|
+
if (userAgent) {
|
|
206
|
+
await session.Network.setUserAgentOverride({ userAgent });
|
|
207
|
+
}
|
|
208
|
+
// Set geolocation if provided
|
|
209
|
+
if (geolocation) {
|
|
210
|
+
await session.Emulation.setGeolocationOverride({
|
|
211
|
+
latitude: geolocation.latitude,
|
|
212
|
+
longitude: geolocation.longitude,
|
|
213
|
+
accuracy: geolocation.accuracy || 100
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
// Set timezone if provided
|
|
217
|
+
if (timezoneId) {
|
|
218
|
+
await session.Emulation.setTimezoneOverride({ timezoneId });
|
|
219
|
+
}
|
|
220
|
+
// Set locale if provided
|
|
221
|
+
if (locale) {
|
|
222
|
+
await session.Emulation.setLocaleOverride({ locale });
|
|
223
|
+
}
|
|
224
|
+
// Set color scheme if provided
|
|
225
|
+
if (colorScheme && colorScheme !== 'no-preference') {
|
|
226
|
+
await session.Emulation.setEmulatedMedia({
|
|
227
|
+
features: [{ name: 'prefers-color-scheme', value: colorScheme }]
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab — tools/wait.ts
|
|
3
|
+
* Smart wait framework: polls/observes until condition is met or timeout expires.
|
|
4
|
+
* Supports: element, text, url, stable, network, auto
|
|
5
|
+
* Weavetab by fy2ne
|
|
6
|
+
*/
|
|
7
|
+
import CDP from "chrome-remote-interface";
|
|
8
|
+
import type { Config } from "../config/loader.js";
|
|
9
|
+
export interface WaitResult {
|
|
10
|
+
success: boolean;
|
|
11
|
+
found: boolean;
|
|
12
|
+
elapsed_ms: number;
|
|
13
|
+
matched_value: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function browserWait(session: CDP.Client, args: {
|
|
16
|
+
for: "element" | "text" | "url" | "stable" | "network" | "auto";
|
|
17
|
+
value?: string;
|
|
18
|
+
timeout?: number;
|
|
19
|
+
}, config: Config): Promise<WaitResult>;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { logDebug } from "../audit/logger.js";
|
|
2
|
+
import { sessionRegistry } from "../state/session.js";
|
|
3
|
+
import { logAction } from "../audit/logger.js";
|
|
4
|
+
import { sendToExtension } from "../cdp/helpers.js";
|
|
5
|
+
import { getConfigAgentId } from "../config/loader.js";
|
|
6
|
+
function sleep(ms) {
|
|
7
|
+
return new Promise(r => setTimeout(r, ms));
|
|
8
|
+
}
|
|
9
|
+
function globMatch(pattern, value) {
|
|
10
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
11
|
+
return new RegExp(`^${escaped}$`, "i").test(value);
|
|
12
|
+
}
|
|
13
|
+
// ── Auto-route: guess the best wait mode from the value string ─────────────
|
|
14
|
+
function autoDetectMode(value) {
|
|
15
|
+
if (/^https?:\/\//.test(value) || value.includes("://") || value.startsWith("*"))
|
|
16
|
+
return "url";
|
|
17
|
+
if (/^[.#\[]/.test(value) || /^[a-z]+\[/.test(value) || value.includes(" > "))
|
|
18
|
+
return "element";
|
|
19
|
+
return "text";
|
|
20
|
+
}
|
|
21
|
+
// ── Wait for element via MutationObserver injected into page ──────────────
|
|
22
|
+
async function waitForElement(session, selector, timeout) {
|
|
23
|
+
const start = Date.now();
|
|
24
|
+
const res = await session.Runtime.evaluate({
|
|
25
|
+
expression: `(function(sel, timeout) {
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
// Check immediately first
|
|
28
|
+
const existing = document.querySelector(sel) ||
|
|
29
|
+
(window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
30
|
+
if (existing) { return resolve({ found: true, tag: existing.tagName }); }
|
|
31
|
+
|
|
32
|
+
const obs = new MutationObserver(() => {
|
|
33
|
+
const el = document.querySelector(sel) ||
|
|
34
|
+
(window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
35
|
+
if (el) { obs.disconnect(); clearTimeout(tid); resolve({ found: true, tag: el.tagName }); }
|
|
36
|
+
});
|
|
37
|
+
obs.observe(document.documentElement, { childList: true, subtree: true, attributes: true });
|
|
38
|
+
const tid = setTimeout(() => { obs.disconnect(); resolve({ found: false }); }, timeout);
|
|
39
|
+
});
|
|
40
|
+
})(${JSON.stringify(selector)}, ${timeout})`,
|
|
41
|
+
awaitPromise: true,
|
|
42
|
+
returnByValue: true,
|
|
43
|
+
timeout: timeout + 2000,
|
|
44
|
+
}).catch(() => null);
|
|
45
|
+
const found = res?.result?.value?.found === true;
|
|
46
|
+
return { found, elapsed_ms: Date.now() - start };
|
|
47
|
+
}
|
|
48
|
+
// ── Wait for text via polling + MutationObserver ──────────────────────────
|
|
49
|
+
async function waitForText(session, text, timeout) {
|
|
50
|
+
const start = Date.now();
|
|
51
|
+
const res = await session.Runtime.evaluate({
|
|
52
|
+
expression: `(function(needle, timeout) {
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
const check = () => {
|
|
55
|
+
const body = document.body?.innerText ?? document.body?.textContent ?? '';
|
|
56
|
+
if (body.includes(needle)) return true;
|
|
57
|
+
// Also check visible value attributes
|
|
58
|
+
const inputs = document.querySelectorAll('input, textarea');
|
|
59
|
+
for (const inp of inputs) {
|
|
60
|
+
if ((inp.value || '').includes(needle)) return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
};
|
|
64
|
+
if (check()) return resolve({ found: true });
|
|
65
|
+
|
|
66
|
+
const obs = new MutationObserver(() => {
|
|
67
|
+
if (check()) { obs.disconnect(); clearTimeout(tid); resolve({ found: true }); }
|
|
68
|
+
});
|
|
69
|
+
obs.observe(document.documentElement, { childList: true, subtree: true, characterData: true });
|
|
70
|
+
const tid = setTimeout(() => { obs.disconnect(); resolve({ found: false }); }, timeout);
|
|
71
|
+
});
|
|
72
|
+
})(${JSON.stringify(text)}, ${timeout})`,
|
|
73
|
+
awaitPromise: true,
|
|
74
|
+
returnByValue: true,
|
|
75
|
+
timeout: timeout + 2000,
|
|
76
|
+
}).catch(() => null);
|
|
77
|
+
const found = res?.result?.value?.found === true;
|
|
78
|
+
return { found, elapsed_ms: Date.now() - start };
|
|
79
|
+
}
|
|
80
|
+
// ── Wait for URL via polling (Page.getFrameTree) ──────────────────────────
|
|
81
|
+
async function waitForUrl(session, pattern, timeout) {
|
|
82
|
+
const start = Date.now();
|
|
83
|
+
const interval = 150;
|
|
84
|
+
while (Date.now() - start < timeout) {
|
|
85
|
+
try {
|
|
86
|
+
const { frameTree } = await session.Page.getFrameTree();
|
|
87
|
+
const currentUrl = frameTree.frame.url;
|
|
88
|
+
if (globMatch(pattern, currentUrl) || currentUrl.includes(pattern)) {
|
|
89
|
+
return { found: true, elapsed_ms: Date.now() - start, matched_value: currentUrl };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch { /* navigation in progress, keep polling */ }
|
|
93
|
+
await sleep(interval);
|
|
94
|
+
}
|
|
95
|
+
return { found: false, elapsed_ms: Date.now() - start, matched_value: "" };
|
|
96
|
+
}
|
|
97
|
+
// ── Wait for network idle (no pending requests for quietMs) ───────────────
|
|
98
|
+
async function waitForNetwork(session, timeout, quietMs = 500) {
|
|
99
|
+
const start = Date.now();
|
|
100
|
+
try {
|
|
101
|
+
await session.Network.enable({});
|
|
102
|
+
}
|
|
103
|
+
catch { /* already enabled */ }
|
|
104
|
+
return new Promise((resolve) => {
|
|
105
|
+
let pending = 0;
|
|
106
|
+
let quietTimer = null;
|
|
107
|
+
let done = false;
|
|
108
|
+
const finish = (found) => {
|
|
109
|
+
if (done)
|
|
110
|
+
return;
|
|
111
|
+
done = true;
|
|
112
|
+
if (quietTimer)
|
|
113
|
+
clearTimeout(quietTimer);
|
|
114
|
+
try {
|
|
115
|
+
session.removeListener("Network.requestWillBeSent", onRequest);
|
|
116
|
+
session.removeListener("Network.loadingFinished", onComplete);
|
|
117
|
+
session.removeListener("Network.loadingFailed", onComplete);
|
|
118
|
+
}
|
|
119
|
+
catch { /* ignore */ }
|
|
120
|
+
resolve({ found, elapsed_ms: Date.now() - start });
|
|
121
|
+
};
|
|
122
|
+
const resetQuiet = () => {
|
|
123
|
+
if (quietTimer)
|
|
124
|
+
clearTimeout(quietTimer);
|
|
125
|
+
if (pending <= 0) {
|
|
126
|
+
quietTimer = setTimeout(() => finish(true), quietMs);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
resetQuiet();
|
|
130
|
+
const onRequest = () => {
|
|
131
|
+
pending++;
|
|
132
|
+
if (quietTimer)
|
|
133
|
+
clearTimeout(quietTimer);
|
|
134
|
+
quietTimer = null;
|
|
135
|
+
};
|
|
136
|
+
const onComplete = () => {
|
|
137
|
+
pending = Math.max(0, pending - 1);
|
|
138
|
+
resetQuiet();
|
|
139
|
+
};
|
|
140
|
+
session.on("Network.requestWillBeSent", onRequest);
|
|
141
|
+
session.on("Network.loadingFinished", onComplete);
|
|
142
|
+
session.on("Network.loadingFailed", onComplete);
|
|
143
|
+
// Overall timeout guard
|
|
144
|
+
setTimeout(() => finish(false), timeout);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// ── Main export ───────────────────────────────────────────────────────────
|
|
148
|
+
export async function browserWait(session, args, config) {
|
|
149
|
+
const { for: waitFor, value = "", timeout: rawTimeout = 8000 } = args;
|
|
150
|
+
const timeout = Math.max(1000, rawTimeout);
|
|
151
|
+
const start = Date.now();
|
|
152
|
+
let targetId = "default";
|
|
153
|
+
const active = sessionRegistry.getActive(getConfigAgentId(config));
|
|
154
|
+
if (active)
|
|
155
|
+
targetId = active.targetId;
|
|
156
|
+
sendToExtension(session, { type: 'Weavetab_STATE', hud: { action: `waiting for ${waitFor}...` } }).catch(() => { });
|
|
157
|
+
try {
|
|
158
|
+
// ── Auto-detect mode ─────────────────────────────────────────────────
|
|
159
|
+
if (waitFor === "auto") {
|
|
160
|
+
const detected = autoDetectMode(value);
|
|
161
|
+
return browserWait(session, { for: detected, value, timeout }, config);
|
|
162
|
+
}
|
|
163
|
+
// ── Element wait (MutationObserver) ───────────────────────────────────
|
|
164
|
+
if (waitFor === "element") {
|
|
165
|
+
const { found, elapsed_ms } = await waitForElement(session, value, timeout);
|
|
166
|
+
logAction("browser_wait", "element", found ? `found: ${value}` : `timeout after ${elapsed_ms}ms`);
|
|
167
|
+
return { success: found, found, elapsed_ms, matched_value: found ? value : "" };
|
|
168
|
+
}
|
|
169
|
+
// ── Text wait (MutationObserver) ──────────────────────────────────────
|
|
170
|
+
if (waitFor === "text") {
|
|
171
|
+
const { found, elapsed_ms } = await waitForText(session, value, timeout);
|
|
172
|
+
logAction("browser_wait", "text", found ? `found: "${value}"` : `timeout after ${elapsed_ms}ms`);
|
|
173
|
+
return { success: found, found, elapsed_ms, matched_value: found ? value : "" };
|
|
174
|
+
}
|
|
175
|
+
// ── URL wait (polling) ────────────────────────────────────────────────
|
|
176
|
+
if (waitFor === "url") {
|
|
177
|
+
const { found, elapsed_ms, matched_value } = await waitForUrl(session, value, timeout);
|
|
178
|
+
logAction("browser_wait", "url", found ? `matched: ${matched_value}` : `timeout after ${elapsed_ms}ms`);
|
|
179
|
+
return { success: found, found, elapsed_ms, matched_value };
|
|
180
|
+
}
|
|
181
|
+
// ── Stable DOM wait ───────────────────────────────────────────────────
|
|
182
|
+
if (waitFor === "stable") {
|
|
183
|
+
const { waitForDOMStable } = await import("../sensors/guard.js");
|
|
184
|
+
await waitForDOMStable(session, 500, timeout);
|
|
185
|
+
const elapsed = Date.now() - start;
|
|
186
|
+
logAction("browser_wait", "stable", `DOM settled after ${elapsed}ms`);
|
|
187
|
+
return { success: true, found: true, elapsed_ms: elapsed, matched_value: "stable" };
|
|
188
|
+
}
|
|
189
|
+
// ── Network idle wait ─────────────────────────────────────────────────
|
|
190
|
+
if (waitFor === "network") {
|
|
191
|
+
const { found, elapsed_ms } = await waitForNetwork(session, timeout);
|
|
192
|
+
logAction("browser_wait", "network", found ? `network idle after ${elapsed_ms}ms` : `timeout after ${elapsed_ms}ms`);
|
|
193
|
+
return { success: true, found, elapsed_ms, matched_value: found ? "network-idle" : "" };
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (e) {
|
|
197
|
+
logDebug(`[Weavetab] Error in browserWait(${waitFor}): ${e}`);
|
|
198
|
+
}
|
|
199
|
+
const elapsed = Date.now() - start;
|
|
200
|
+
logAction("browser_wait", waitFor, `timeout/error after ${elapsed}ms`);
|
|
201
|
+
return { success: false, found: false, elapsed_ms: elapsed, matched_value: "" };
|
|
202
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab — tools/wait_for.ts
|
|
3
|
+
* browser_wait_for: Poll the DOM for a CSS selector to appear.
|
|
4
|
+
*
|
|
5
|
+
* Use this to explicitly wait for an element to exist in the DOM instead of relying on
|
|
6
|
+
* hardcoded sleeps. It polls the document using querySelector.
|
|
7
|
+
* Returns the resolved backendNodeId if found before the timeout.
|
|
8
|
+
* Weavetab by fy2ne
|
|
9
|
+
*/
|
|
10
|
+
import CDP from "chrome-remote-interface";
|
|
11
|
+
import type { Config } from "../config/loader.js";
|
|
12
|
+
export interface WaitForOptions {
|
|
13
|
+
selector: string;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface WaitForResult {
|
|
17
|
+
success: boolean;
|
|
18
|
+
selector: string;
|
|
19
|
+
found: boolean;
|
|
20
|
+
elapsedMs: number;
|
|
21
|
+
nodeId?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function browserWaitFor(session: CDP.Client, options: WaitForOptions, _config: Config): Promise<WaitForResult>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export async function browserWaitFor(session, options, _config) {
|
|
2
|
+
const { selector, timeoutMs = 10000 } = options;
|
|
3
|
+
const pollInterval = 200;
|
|
4
|
+
const start = Date.now();
|
|
5
|
+
while (Date.now() - start < timeoutMs) {
|
|
6
|
+
try {
|
|
7
|
+
const { result } = await session.Runtime.evaluate({
|
|
8
|
+
expression: `document.querySelector('${selector.replace(/'/g, "\\'")}') !== null`,
|
|
9
|
+
returnByValue: true
|
|
10
|
+
});
|
|
11
|
+
if (result.value === true) {
|
|
12
|
+
// Find the node id
|
|
13
|
+
const { root } = await session.DOM.getDocument({ depth: -1 });
|
|
14
|
+
const { nodeId } = await session.DOM.querySelector({ nodeId: root.nodeId, selector });
|
|
15
|
+
const elapsed = Date.now() - start;
|
|
16
|
+
return { success: true, selector, found: true, elapsedMs: elapsed, nodeId };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Evaluation might fail if page is navigating, just retry
|
|
21
|
+
}
|
|
22
|
+
await new Promise(r => setTimeout(r, pollInterval));
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
success: false,
|
|
26
|
+
selector,
|
|
27
|
+
found: false,
|
|
28
|
+
elapsedMs: Date.now() - start
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab — tools/windows.ts
|
|
3
|
+
* Lists and focuses browser windows/popups opened via window.open().
|
|
4
|
+
* Weavetab by fy2ne
|
|
5
|
+
*/
|
|
6
|
+
import CDP from "chrome-remote-interface";
|
|
7
|
+
import type { Config } from "../config/loader.js";
|
|
8
|
+
export interface WindowInfo {
|
|
9
|
+
id: string;
|
|
10
|
+
url: string;
|
|
11
|
+
title: string;
|
|
12
|
+
type: string;
|
|
13
|
+
}
|
|
14
|
+
export interface WindowsResult {
|
|
15
|
+
success: true;
|
|
16
|
+
windows: WindowInfo[];
|
|
17
|
+
active_id: string | null;
|
|
18
|
+
}
|
|
19
|
+
export declare function browserWindows(session: CDP.Client, args: {
|
|
20
|
+
action: "list" | "focus";
|
|
21
|
+
windowId?: string;
|
|
22
|
+
}, config: Config): Promise<WindowsResult>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weavetab — tools/windows.ts
|
|
3
|
+
* Lists and focuses browser windows/popups opened via window.open().
|
|
4
|
+
* Weavetab by fy2ne
|
|
5
|
+
*/
|
|
6
|
+
import CDP from "chrome-remote-interface";
|
|
7
|
+
import { getPort } from "../cdp/connector.js";
|
|
8
|
+
import { connectToTab } from "../cdp/connector.js";
|
|
9
|
+
import { sessionRegistry } from "../state/session.js";
|
|
10
|
+
import { logAction } from "../audit/logger.js";
|
|
11
|
+
import { getConfigAgentId } from "../config/loader.js";
|
|
12
|
+
import { readLock } from "../cdp/lock.js";
|
|
13
|
+
/** Resolve active CDP port — live > lock file */
|
|
14
|
+
function resolvePort(_config) {
|
|
15
|
+
const port = getPort() || readLock()?.port;
|
|
16
|
+
if (!port)
|
|
17
|
+
throw new Error("[!] No active browser session. Run browser_go first.");
|
|
18
|
+
return port;
|
|
19
|
+
}
|
|
20
|
+
export async function browserWindows(session, args, config) {
|
|
21
|
+
const { action, windowId } = args;
|
|
22
|
+
const port = resolvePort(config);
|
|
23
|
+
const targets = await CDP.List({ host: "127.0.0.1", port });
|
|
24
|
+
// Include ALL target types — pages, popups, iframes
|
|
25
|
+
const windows = targets
|
|
26
|
+
.filter((t) => t.type === "page" || t.type === "popup")
|
|
27
|
+
.map((t) => ({
|
|
28
|
+
id: t.id,
|
|
29
|
+
url: t.url,
|
|
30
|
+
title: t.title,
|
|
31
|
+
type: t.type === "page" ? "tab/window" : t.type,
|
|
32
|
+
}));
|
|
33
|
+
// Auto-attach any popup that isn't in the session registry
|
|
34
|
+
for (const w of windows) {
|
|
35
|
+
const known = sessionRegistry.getAll().find((c) => c.targetId === w.id);
|
|
36
|
+
if (!known) {
|
|
37
|
+
connectToTab(w.id, port, getConfigAgentId(config)).catch(() => { });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (action === "focus" && windowId) {
|
|
41
|
+
const cleanId = windowId.trim();
|
|
42
|
+
// Short delay to let auto-attach (above) complete if it was just fired
|
|
43
|
+
await new Promise(r => setTimeout(r, 150));
|
|
44
|
+
const client = await connectToTab(cleanId, port, getConfigAgentId(config));
|
|
45
|
+
await client.session.Target.activateTarget({ targetId: cleanId });
|
|
46
|
+
sessionRegistry.setActive(cleanId, getConfigAgentId(config));
|
|
47
|
+
logAction("browser_windows", "focus", cleanId);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
logAction("browser_windows", "list", `${windows.length} windows`);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
success: true,
|
|
54
|
+
windows,
|
|
55
|
+
active_id: sessionRegistry.getActive(getConfigAgentId(config))?.targetId ?? null,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/ui/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
// src/ui/index.ts — DEPRECATED: All UI moved to ext-dist/content.js (Chrome extension)
|
|
3
|
+
// Legacy GhostOverlay (tactical overlay, ask modal) has been removed.
|
|
4
|
+
// The extension content script now handles:
|
|
5
|
+
// - WeaveCursor (canvas-based, shadow-DOM isolated)
|
|
6
|
+
// - Thought bubble (.wt-bubble with typewriter + hex icon)
|
|
7
|
+
// - Ask modal (.wt-chat input + Reply button)
|
|
8
|
+
// - HUD (token recorder, bottom-right)
|
|
9
|
+
// - X-Ray spotlight, controlled tab indicator, ripple effects
|
|
10
|
+
//
|
|
11
|
+
// This file is kept as a build stub so esbuild doesn't error.
|
|
12
|
+
// It exports nothing and does nothing.
|
package/docs/DEV_MODE.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Weavetab Developer Mode (devMode) & Plugin Profiling Guide
|
|
2
|
+
|
|
3
|
+
This guide explains Developer Mode (`devMode`), how tool execution timing (`execution_ms`) works, and how it empowers **`weavetab-plugin` developers** and AI agents to profile performance.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Enabling Developer Mode
|
|
8
|
+
|
|
9
|
+
Developer Mode can be enabled in two ways:
|
|
10
|
+
|
|
11
|
+
1. **Via Configuration (`~/.weavetab/config.json` or `.weavetab/config.json`)**:
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"devMode": true
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. **Via Environment Variable**:
|
|
19
|
+
```bash
|
|
20
|
+
WEAVETAB_DEV=1 node dist/index.js
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## What Does `devMode` Add?
|
|
26
|
+
|
|
27
|
+
When `devMode` is active, Weavetab exposes rich execution metadata, visual debugging tools, and mission logging without altering underlying tool execution behavior.
|
|
28
|
+
|
|
29
|
+
### 1. `execution_ms` & Tool Performance Profiling
|
|
30
|
+
|
|
31
|
+
In `devMode`, every tool response automatically includes an **`execution_ms`** field:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"success": true,
|
|
36
|
+
"execution_ms": 14,
|
|
37
|
+
"result": { ... }
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
* **Purpose**: Measures the exact millisecond duration required to process and complete that specific tool call.
|
|
42
|
+
* **Essential for Plugin Developers**: Allows community developers building custom Weavetab plugins to profile their handlers, measure bottleneck latency, and optimize tool responsiveness.
|
|
43
|
+
* **Agent Context Awareness**: AI agents and users reading tool outputs can monitor tool performance in real time.
|
|
44
|
+
|
|
45
|
+
### 2. Extension Visual Overlays & Tool Calls
|
|
46
|
+
|
|
47
|
+
* **Extension Visuals**: Renders real-time tool execution badges and `toolcalls` counters directly within the extension overlay.
|
|
48
|
+
* **Trajectory & Hitbox Inspection**: Visualizes pointer paths, click target bounding boxes, and action status badges during execution.
|
|
49
|
+
|
|
50
|
+
### 3. Mission Logs (`/logs/`)
|
|
51
|
+
|
|
52
|
+
* For every completed mission, Weavetab generates a structured mission log file inside `/logs/` (`~/.weavetab/logs/`).
|
|
53
|
+
* Contains full step-by-step tool traces, `execution_ms` timing distributions, and action histories for auditing and debugging.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Plugin Performance Profiling
|
|
58
|
+
|
|
59
|
+
Developer Mode is especially valuable for community developers creating Weavetab plugin packages.
|
|
60
|
+
|
|
61
|
+
* **Profiling Custom Tool Handlers**:
|
|
62
|
+
When developing a plugin, enabling `devMode` (`WEAVETAB_DEV=1`) allows you to inspect the `execution_ms` timer on every custom tool response to benchmark performance and optimize your code before publishing.
|
|
63
|
+
* **Manifest & Permissions**:
|
|
64
|
+
Plugins define their metadata, permissions, and entry points in a `weavetab.json` manifest.
|
|
65
|
+
* **Marketplace Screenshots (`/images/`)**:
|
|
66
|
+
Plugins can include an `/images` directory with screenshots and logos for display on the official Weavetab Marketplace website (`website/`).
|
|
67
|
+
|
|
68
|
+
> 📖 For full details on building, packaging, and publishing plugins, see [docs/PLUGINS.md](PLUGINS.md).
|