@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.
Files changed (281) hide show
  1. package/AGENTS.md +48 -0
  2. package/ARCHITECTURE.md +590 -0
  3. package/LICENSE +631 -0
  4. package/README.md +909 -0
  5. package/SECURITY.md +196 -0
  6. package/TROUBLESHOOTING.md +365 -0
  7. package/dist/anticaptcha/detector.d.ts +49 -0
  8. package/dist/anticaptcha/detector.js +465 -0
  9. package/dist/anticaptcha/integration.d.ts +36 -0
  10. package/dist/anticaptcha/integration.js +123 -0
  11. package/dist/anticaptcha/solver.d.ts +27 -0
  12. package/dist/anticaptcha/solver.js +552 -0
  13. package/dist/audit/logger.d.ts +13 -0
  14. package/dist/audit/logger.js +177 -0
  15. package/dist/audit/telemetry.d.ts +36 -0
  16. package/dist/audit/telemetry.js +162 -0
  17. package/dist/cdp/bridge.d.ts +16 -0
  18. package/dist/cdp/bridge.js +826 -0
  19. package/dist/cdp/confirm.d.ts +26 -0
  20. package/dist/cdp/confirm.js +79 -0
  21. package/dist/cdp/connector.d.ts +37 -0
  22. package/dist/cdp/connector.js +661 -0
  23. package/dist/cdp/extension.d.ts +36 -0
  24. package/dist/cdp/extension.js +118 -0
  25. package/dist/cdp/finder.d.ts +1 -0
  26. package/dist/cdp/finder.js +2 -0
  27. package/dist/cdp/helpers.d.ts +11 -0
  28. package/dist/cdp/helpers.js +195 -0
  29. package/dist/cdp/label_cache.d.ts +12 -0
  30. package/dist/cdp/label_cache.js +51 -0
  31. package/dist/cdp/lock.d.ts +33 -0
  32. package/dist/cdp/lock.js +206 -0
  33. package/dist/cdp/omni_broker.d.ts +17 -0
  34. package/dist/cdp/omni_broker.js +119 -0
  35. package/dist/cdp/profiles.d.ts +1 -0
  36. package/dist/cdp/profiles.js +87 -0
  37. package/dist/cdp/pruner.d.ts +41 -0
  38. package/dist/cdp/pruner.js +263 -0
  39. package/dist/cdp/ref_cache.d.ts +101 -0
  40. package/dist/cdp/ref_cache.js +234 -0
  41. package/dist/cdp/retry.d.ts +5 -0
  42. package/dist/cdp/retry.js +39 -0
  43. package/dist/cdp/retry_enhanced.d.ts +44 -0
  44. package/dist/cdp/retry_enhanced.js +102 -0
  45. package/dist/cdp/security.d.ts +50 -0
  46. package/dist/cdp/security.js +237 -0
  47. package/dist/cdp/verify.d.ts +39 -0
  48. package/dist/cdp/verify.js +143 -0
  49. package/dist/cdp/walker.d.ts +91 -0
  50. package/dist/cdp/walker.js +896 -0
  51. package/dist/cdp/walker.test.d.ts +2 -0
  52. package/dist/cdp/walker.test.js +172 -0
  53. package/dist/cdp/websocket_transport.d.ts +15 -0
  54. package/dist/cdp/websocket_transport.js +118 -0
  55. package/dist/cli/plugin.d.ts +9 -0
  56. package/dist/cli/plugin.js +1134 -0
  57. package/dist/cli/updater.d.ts +1 -0
  58. package/dist/cli/updater.js +72 -0
  59. package/dist/config/loader.d.ts +120 -0
  60. package/dist/config/loader.js +704 -0
  61. package/dist/index.d.ts +2 -0
  62. package/dist/index.js +1248 -0
  63. package/dist/intelligence/hints.d.ts +11 -0
  64. package/dist/intelligence/hints.js +39 -0
  65. package/dist/intelligence/intent.d.ts +33 -0
  66. package/dist/intelligence/intent.js +171 -0
  67. package/dist/intelligence/sessionMemory.d.ts +66 -0
  68. package/dist/intelligence/sessionMemory.js +284 -0
  69. package/dist/intelligence/sessionMemory.test.d.ts +2 -0
  70. package/dist/intelligence/sessionMemory.test.js +62 -0
  71. package/dist/intelligence/trail.d.ts +64 -0
  72. package/dist/intelligence/trail.js +233 -0
  73. package/dist/intelligence/trail.test.d.ts +2 -0
  74. package/dist/intelligence/trail.test.js +110 -0
  75. package/dist/intelligence/vision.d.ts +24 -0
  76. package/dist/intelligence/vision.js +151 -0
  77. package/dist/lifecycle/mission_manager.d.ts +16 -0
  78. package/dist/lifecycle/mission_manager.js +44 -0
  79. package/dist/overlay/bubble.d.ts +16 -0
  80. package/dist/overlay/bubble.js +37 -0
  81. package/dist/overlay/ghost.d.ts +35 -0
  82. package/dist/overlay/ghost.js +508 -0
  83. package/dist/overlay/injector.d.ts +22 -0
  84. package/dist/overlay/injector.js +198 -0
  85. package/dist/plugin/interface.d.ts +134 -0
  86. package/dist/plugin/interface.js +1 -0
  87. package/dist/plugin/loader.d.ts +18 -0
  88. package/dist/plugin/loader.js +155 -0
  89. package/dist/plugin/registry.d.ts +50 -0
  90. package/dist/plugin/registry.js +234 -0
  91. package/dist/security/blacklist.d.ts +24 -0
  92. package/dist/security/blacklist.js +80 -0
  93. package/dist/security/filter.d.ts +2 -0
  94. package/dist/security/filter.js +20 -0
  95. package/dist/security/guard.d.ts +8 -0
  96. package/dist/security/guard.js +35 -0
  97. package/dist/security/ratelimit.d.ts +11 -0
  98. package/dist/security/ratelimit.js +57 -0
  99. package/dist/security/secrets.d.ts +75 -0
  100. package/dist/security/secrets.js +365 -0
  101. package/dist/sensors/actionability.d.ts +81 -0
  102. package/dist/sensors/actionability.js +303 -0
  103. package/dist/sensors/guard.d.ts +25 -0
  104. package/dist/sensors/guard.js +168 -0
  105. package/dist/sensors/mutations.d.ts +23 -0
  106. package/dist/sensors/mutations.js +93 -0
  107. package/dist/sensors/network.d.ts +67 -0
  108. package/dist/sensors/network.js +193 -0
  109. package/dist/sensors/operation_monitor.d.ts +80 -0
  110. package/dist/sensors/operation_monitor.js +203 -0
  111. package/dist/sensors/pacing.d.ts +44 -0
  112. package/dist/sensors/pacing.js +111 -0
  113. package/dist/sensors/thoughts.d.ts +2 -0
  114. package/dist/sensors/thoughts.js +59 -0
  115. package/dist/sensors/wait.d.ts +12 -0
  116. package/dist/sensors/wait.js +44 -0
  117. package/dist/server.d.ts +7 -0
  118. package/dist/server.js +1687 -0
  119. package/dist/state/agent.d.ts +36 -0
  120. package/dist/state/agent.js +101 -0
  121. package/dist/state/cache.d.ts +16 -0
  122. package/dist/state/cache.js +92 -0
  123. package/dist/state/cache.test.d.ts +2 -0
  124. package/dist/state/cache.test.js +76 -0
  125. package/dist/state/delta.d.ts +71 -0
  126. package/dist/state/delta.js +234 -0
  127. package/dist/state/delta.test.d.ts +2 -0
  128. package/dist/state/delta.test.js +279 -0
  129. package/dist/state/groups.d.ts +15 -0
  130. package/dist/state/groups.js +80 -0
  131. package/dist/state/session.d.ts +30 -0
  132. package/dist/state/session.js +155 -0
  133. package/dist/tools/accessibility.d.ts +14 -0
  134. package/dist/tools/accessibility.js +32 -0
  135. package/dist/tools/ask.d.ts +14 -0
  136. package/dist/tools/ask.js +49 -0
  137. package/dist/tools/automation.d.ts +36 -0
  138. package/dist/tools/automation.js +218 -0
  139. package/dist/tools/browser_detect.d.ts +13 -0
  140. package/dist/tools/browser_detect.js +73 -0
  141. package/dist/tools/burst.d.ts +35 -0
  142. package/dist/tools/burst.js +344 -0
  143. package/dist/tools/canvas.d.ts +25 -0
  144. package/dist/tools/canvas.js +132 -0
  145. package/dist/tools/captcha.d.ts +38 -0
  146. package/dist/tools/captcha.js +209 -0
  147. package/dist/tools/click.d.ts +36 -0
  148. package/dist/tools/click.js +561 -0
  149. package/dist/tools/click_and_wait.d.ts +33 -0
  150. package/dist/tools/click_and_wait.js +149 -0
  151. package/dist/tools/clipboard.d.ts +29 -0
  152. package/dist/tools/clipboard.js +279 -0
  153. package/dist/tools/console.d.ts +21 -0
  154. package/dist/tools/console.js +107 -0
  155. package/dist/tools/cookies.d.ts +67 -0
  156. package/dist/tools/cookies.js +121 -0
  157. package/dist/tools/design_extract.d.ts +109 -0
  158. package/dist/tools/design_extract.js +641 -0
  159. package/dist/tools/dialog.d.ts +24 -0
  160. package/dist/tools/dialog.js +109 -0
  161. package/dist/tools/drag.d.ts +15 -0
  162. package/dist/tools/drag.js +29 -0
  163. package/dist/tools/emulation.d.ts +33 -0
  164. package/dist/tools/emulation.js +69 -0
  165. package/dist/tools/eval.d.ts +20 -0
  166. package/dist/tools/eval.js +92 -0
  167. package/dist/tools/fill.d.ts +41 -0
  168. package/dist/tools/fill.js +667 -0
  169. package/dist/tools/find.d.ts +30 -0
  170. package/dist/tools/find.js +60 -0
  171. package/dist/tools/geo.d.ts +19 -0
  172. package/dist/tools/geo.js +29 -0
  173. package/dist/tools/github/analyze.d.ts +4 -0
  174. package/dist/tools/github/analyze.js +113 -0
  175. package/dist/tools/github/cache.d.ts +21 -0
  176. package/dist/tools/github/cache.js +28 -0
  177. package/dist/tools/github/index.d.ts +4 -0
  178. package/dist/tools/github/index.js +4 -0
  179. package/dist/tools/github/issues.d.ts +9 -0
  180. package/dist/tools/github/issues.js +88 -0
  181. package/dist/tools/github/pr.d.ts +5 -0
  182. package/dist/tools/github/pr.js +88 -0
  183. package/dist/tools/github/rateLimiter.d.ts +4 -0
  184. package/dist/tools/github/rateLimiter.js +46 -0
  185. package/dist/tools/github/read.d.ts +34 -0
  186. package/dist/tools/github/read.js +74 -0
  187. package/dist/tools/github/repoContext.d.ts +20 -0
  188. package/dist/tools/github/repoContext.js +129 -0
  189. package/dist/tools/highlight.d.ts +20 -0
  190. package/dist/tools/highlight.js +140 -0
  191. package/dist/tools/hover.d.ts +19 -0
  192. package/dist/tools/hover.js +57 -0
  193. package/dist/tools/inspect.d.ts +17 -0
  194. package/dist/tools/inspect.js +125 -0
  195. package/dist/tools/integration.test.d.ts +2 -0
  196. package/dist/tools/integration.test.js +96 -0
  197. package/dist/tools/key.d.ts +25 -0
  198. package/dist/tools/key.js +173 -0
  199. package/dist/tools/macro_compiler.d.ts +7 -0
  200. package/dist/tools/macro_compiler.js +82 -0
  201. package/dist/tools/mouse.d.ts +21 -0
  202. package/dist/tools/mouse.js +62 -0
  203. package/dist/tools/navigate.d.ts +16 -0
  204. package/dist/tools/navigate.js +188 -0
  205. package/dist/tools/network_intercept.d.ts +17 -0
  206. package/dist/tools/network_intercept.js +151 -0
  207. package/dist/tools/office/index.d.ts +9 -0
  208. package/dist/tools/office/index.js +7 -0
  209. package/dist/tools/office/list.d.ts +15 -0
  210. package/dist/tools/office/list.js +41 -0
  211. package/dist/tools/office/parse.d.ts +20 -0
  212. package/dist/tools/office/parse.js +172 -0
  213. package/dist/tools/pdf.d.ts +22 -0
  214. package/dist/tools/pdf.js +42 -0
  215. package/dist/tools/performance.d.ts +12 -0
  216. package/dist/tools/performance.js +47 -0
  217. package/dist/tools/performance_test.d.ts +70 -0
  218. package/dist/tools/performance_test.js +128 -0
  219. package/dist/tools/plan.d.ts +39 -0
  220. package/dist/tools/plan.js +161 -0
  221. package/dist/tools/pointer.d.ts +35 -0
  222. package/dist/tools/pointer.js +522 -0
  223. package/dist/tools/read.d.ts +30 -0
  224. package/dist/tools/read.js +488 -0
  225. package/dist/tools/recording.d.ts +45 -0
  226. package/dist/tools/recording.js +124 -0
  227. package/dist/tools/response.d.ts +129 -0
  228. package/dist/tools/response.js +5 -0
  229. package/dist/tools/scrape.d.ts +24 -0
  230. package/dist/tools/scrape.js +140 -0
  231. package/dist/tools/screenshot.d.ts +40 -0
  232. package/dist/tools/screenshot.js +79 -0
  233. package/dist/tools/scroll.d.ts +23 -0
  234. package/dist/tools/scroll.js +196 -0
  235. package/dist/tools/select.d.ts +13 -0
  236. package/dist/tools/select.js +217 -0
  237. package/dist/tools/snapshot.d.ts +27 -0
  238. package/dist/tools/snapshot.js +99 -0
  239. package/dist/tools/storage.d.ts +18 -0
  240. package/dist/tools/storage.js +29 -0
  241. package/dist/tools/tabs.d.ts +77 -0
  242. package/dist/tools/tabs.js +342 -0
  243. package/dist/tools/thought.d.ts +16 -0
  244. package/dist/tools/thought.js +79 -0
  245. package/dist/tools/type.d.ts +65 -0
  246. package/dist/tools/type.js +1061 -0
  247. package/dist/tools/type_secret.d.ts +23 -0
  248. package/dist/tools/type_secret.js +229 -0
  249. package/dist/tools/upload.d.ts +19 -0
  250. package/dist/tools/upload.js +103 -0
  251. package/dist/tools/video_compiler.d.ts +24 -0
  252. package/dist/tools/video_compiler.js +199 -0
  253. package/dist/tools/viewport.d.ts +44 -0
  254. package/dist/tools/viewport.js +230 -0
  255. package/dist/tools/wait.d.ts +19 -0
  256. package/dist/tools/wait.js +202 -0
  257. package/dist/tools/wait_for.d.ts +23 -0
  258. package/dist/tools/wait_for.js +30 -0
  259. package/dist/tools/windows.d.ts +22 -0
  260. package/dist/tools/windows.js +57 -0
  261. package/dist/ui/index.d.ts +1 -0
  262. package/dist/ui/index.js +12 -0
  263. package/docs/DEV_MODE.md +68 -0
  264. package/docs/DOCUMENTATION.md +532 -0
  265. package/docs/PLUGINS.md +538 -0
  266. package/docs/TOOLS.md +104 -0
  267. package/docs/dev_plugin.md +310 -0
  268. package/ext-dist/background.js +467 -0
  269. package/ext-dist/content.js +3089 -0
  270. package/ext-dist/dashboard.html +583 -0
  271. package/ext-dist/hud/hud.js +73 -0
  272. package/ext-dist/hud/index.html +20 -0
  273. package/ext-dist/manifest.json +77 -0
  274. package/ext-dist/sidepanel/sidepanel.js +25 -0
  275. package/ext-dist/sidepanel.html +547 -0
  276. package/ext-dist/styles.css +218 -0
  277. package/icon.png +0 -0
  278. package/mcp.json +796 -0
  279. package/package.json +113 -0
  280. package/server.json +23 -0
  281. package/smithery.yaml +11 -0
@@ -0,0 +1,237 @@
1
+ import { logDebug } from "../audit/logger.js";
2
+ import * as path from "node:path";
3
+ import * as os from "node:os";
4
+ import { execSync, spawnSync } from "node:child_process";
5
+ import { getSessionProfile } from "./profiles.js";
6
+ import { getConfigCookies, getConfigProfileDir } from "../config/loader.js";
7
+ // ─── Profile Verification Cache ───────────────────────────────────────────────────
8
+ // Cap profileVerificationCache at 100 entries (evict oldest on overflow) and
9
+ // sweep entries for closed sessions every 5 minutes via an unref'd interval so
10
+ // the cache doesn't grow without bound across many tabs / reconnects.
11
+ const PROFILE_CACHE_MAX = 100;
12
+ let profileVerificationCache = new Map();
13
+ function profileCacheSet(key, value) {
14
+ if (profileVerificationCache.size >= PROFILE_CACHE_MAX && !profileVerificationCache.has(key)) {
15
+ const firstKey = profileVerificationCache.keys().next().value;
16
+ if (firstKey !== undefined)
17
+ profileVerificationCache.delete(firstKey);
18
+ }
19
+ profileVerificationCache.set(key, value);
20
+ }
21
+ // Periodic sweep: clear the whole cache every 5 min so stale session IDs don't persist
22
+ setInterval(() => { profileVerificationCache.clear(); }, 5 * 60_000).unref();
23
+ /**
24
+ * Verifies that the browser is actually using the isolated profile directory.
25
+ * Uses CDP to check the actual user data directory being used by the browser.
26
+ * Results are cached per session to avoid per-call overhead.
27
+ */
28
+ export async function verifyProfileIsolation(session, config, targetId) {
29
+ const cacheKey = targetId;
30
+ // Return cached result if available
31
+ if (profileVerificationCache.has(cacheKey)) {
32
+ const cached = profileVerificationCache.get(cacheKey);
33
+ const expectedProfile = getSessionProfile(getConfigCookies(config), getConfigProfileDir(config));
34
+ return { verified: cached, expectedProfile };
35
+ }
36
+ const expectedProfile = getSessionProfile(getConfigCookies(config), getConfigProfileDir(config));
37
+ try {
38
+ // Method 1: Check browser info via CDP (most reliable)
39
+ const browserInfo = await session.Browser.getVersion();
40
+ // Parse user agent to check for Weavetab session markers
41
+ // Weavetab adds custom flags that should be present in the browser
42
+ const userAgent = browserInfo.userAgent || "";
43
+ // Method 2: Check if browser has the Weavetab extension loaded
44
+ // This confirms it's our launched instance
45
+ const extensionCheck = await session.Runtime.evaluate({
46
+ expression: '!!(window.__wt_session_id || window.__wt_config)',
47
+ returnByValue: true,
48
+ });
49
+ // Method 3: Verify process command line contains the isolated profile path
50
+ // This requires OS-specific process inspection
51
+ const profileFromProcess = await getProfileFromProcess(session, config);
52
+ // Verification passes if:
53
+ // 1. Extension is loaded (we launched this browser)
54
+ // 2. OR we can verify the profile path from process info
55
+ const extensionLoaded = extensionCheck.result?.value === true;
56
+ const profileMatches = profileFromProcess ? normalizePath(profileFromProcess) === normalizePath(expectedProfile) : false;
57
+ const verified = extensionLoaded || profileMatches;
58
+ profileCacheSet(cacheKey, verified);
59
+ return {
60
+ verified,
61
+ actualProfile: profileFromProcess || undefined,
62
+ expectedProfile,
63
+ };
64
+ }
65
+ catch (error) {
66
+ logDebug(`[Weavetab Security] Profile verification failed: ${error}`);
67
+ // Fail closed: return verified:false and let the caller decide how to handle
68
+ // it. Verification errors — including a compromised or hijacked session —
69
+ // must never be treated as success.
70
+ profileCacheSet(cacheKey, false);
71
+ return { verified: false, expectedProfile };
72
+ }
73
+ }
74
+ /**
75
+ * Clears the profile verification cache for a specific session.
76
+ * Called when a session is closed or reconnected.
77
+ */
78
+ export function clearProfileVerificationCache(targetId) {
79
+ profileVerificationCache.delete(targetId);
80
+ }
81
+ let currentFingerprint = null;
82
+ /**
83
+ * Creates a unique fingerprint for the launched browser process.
84
+ * This is stored in the lock file and verified on reconnection.
85
+ */
86
+ export function createBrowserFingerprint(pid, port, profileDir, browserPath) {
87
+ return {
88
+ pid,
89
+ port,
90
+ profileDir,
91
+ browserPath,
92
+ launchTimestamp: Date.now(),
93
+ userAgent: "", // Will be filled after CDP connection
94
+ cdpVersion: "", // Will be filled after CDP connection
95
+ };
96
+ }
97
+ /**
98
+ * Verifies that the connected browser matches the expected fingerprint.
99
+ * Runs at CDP connect time only.
100
+ */
101
+ export async function verifyBrowserFingerprint(session, expectedFingerprint) {
102
+ try {
103
+ const browserInfo = await session.Browser.getVersion();
104
+ // Verify CDP version matches (or is compatible)
105
+ const currentCDPVersion = browserInfo.product || "";
106
+ // Verify user agent is from a Chromium-based browser
107
+ const userAgent = browserInfo.userAgent || "";
108
+ if (!userAgent.includes("Chrome") && !userAgent.includes("Edge") && !userAgent.includes("Brave")) {
109
+ return { valid: false, reason: "User agent does not match expected browser type" };
110
+ }
111
+ // Update fingerprint with runtime data
112
+ currentFingerprint = {
113
+ ...expectedFingerprint,
114
+ userAgent,
115
+ cdpVersion: currentCDPVersion,
116
+ };
117
+ return { valid: true };
118
+ }
119
+ catch (error) {
120
+ return { valid: false, reason: `Fingerprint verification failed: ${error}` };
121
+ }
122
+ }
123
+ export function getCurrentFingerprint() {
124
+ return currentFingerprint;
125
+ }
126
+ // ─── Process Killing Safety ────────────────────────────────────────────────────
127
+ /**
128
+ * Safely kills browser processes that were launched by Weavetab in the current session.
129
+ * Only kills processes that match the exact profile directory from the lock file.
130
+ * Never matches against processes that weren't launched by Weavetab.
131
+ */
132
+ const _killCooldown = new Map();
133
+ export function safelyKillWeavetabProcesses(profileDir, expectedPid) {
134
+ const now = Date.now();
135
+ const last = _killCooldown.get(profileDir) ?? 0;
136
+ if (now - last < 10_000) {
137
+ logDebug(`[Weavetab Security] safelyKillWeavetabProcesses: cooldown active, skipping.`);
138
+ return;
139
+ }
140
+ _killCooldown.set(profileDir, now);
141
+ const plat = os.platform();
142
+ const normalizedProfile = normalizePath(profileDir);
143
+ try {
144
+ if (plat === 'win32') {
145
+ // Windows: use tasklist with NO user data in the command string.
146
+ // Parse PIDs in JS, kill each with taskkill args array (no shell).
147
+ //
148
+ // Primary: PowerShell Get-WmiObject (works on all Win10+ without wmic.exe)
149
+ const psResult = spawnSync('powershell', [
150
+ '-NoProfile', '-NonInteractive', '-Command',
151
+ 'Get-WmiObject Win32_Process | Select-Object ProcessId,CommandLine | ConvertTo-Csv -NoTypeInformation'
152
+ ], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
153
+ if (psResult.status === 0 && psResult.stdout) {
154
+ const lines = psResult.stdout.split('\n').slice(1); // skip CSV header
155
+ for (const line of lines) {
156
+ const trimmed = line.trim();
157
+ if (!trimmed)
158
+ continue;
159
+ // CSV: "ProcessId","CommandLine"
160
+ const fields = trimmed.split(/,(?=(?:[^"]*"[^"]*")*[^"]*$)/).map(f => f.replace(/^"|"$/g, ''));
161
+ const pid = parseInt(fields[0] ?? '0', 10);
162
+ const cmdLine = (fields[1] ?? '').toLowerCase();
163
+ if (isNaN(pid) || pid <= 0)
164
+ continue;
165
+ if (expectedPid !== undefined && pid !== expectedPid)
166
+ continue;
167
+ // Filter in JS — no interpolation into any shell command
168
+ if (cmdLine.includes(normalizedProfile) && cmdLine.includes('--user-data-dir')) {
169
+ spawnSync('taskkill', ['/F', '/PID', String(pid)], { stdio: 'ignore' });
170
+ logDebug(`[Weavetab Security] Safely terminated Weavetab process: ${pid}`);
171
+ }
172
+ }
173
+ }
174
+ }
175
+ else {
176
+ // Unix: read ps output in JS, filter in JS, kill via process.kill — never interpolate into shell
177
+ const psResult = execSync('ps -ax -o pid= -o command=', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
178
+ for (const line of psResult.split('\n')) {
179
+ const trimmed = line.trim();
180
+ if (!trimmed)
181
+ continue;
182
+ const spaceIdx = trimmed.indexOf(' ');
183
+ if (spaceIdx === -1)
184
+ continue;
185
+ const pid = parseInt(trimmed.slice(0, spaceIdx), 10);
186
+ const cmd = trimmed.slice(spaceIdx + 1).toLowerCase();
187
+ if (isNaN(pid) || pid <= 0)
188
+ continue;
189
+ if (expectedPid !== undefined && pid !== expectedPid)
190
+ continue;
191
+ if (cmd.includes(normalizedProfile) && cmd.includes('--user-data-dir')) {
192
+ try {
193
+ process.kill(pid, 'SIGKILL');
194
+ logDebug(`[Weavetab Security] Safely terminated Weavetab process: ${pid}`);
195
+ }
196
+ catch { /* process already gone */ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ catch (error) {
202
+ logDebug(`[Weavetab Security] Process killing failed (non-critical): ${error}`);
203
+ }
204
+ }
205
+ /**
206
+ * Returns a normalized, platform-independent path for comparison.
207
+ */
208
+ function normalizePath(p) {
209
+ return path.resolve(p).toLowerCase();
210
+ }
211
+ /**
212
+ * Attempts to extract the profile directory from the browser process.
213
+ * This is a fallback method for profile verification.
214
+ */
215
+ async function getProfileFromProcess(session, config) {
216
+ try {
217
+ // Use extension-based method to check profile directory
218
+ const result = await session.Runtime.evaluate({
219
+ expression: `
220
+ (() => {
221
+ try {
222
+ // Check if we can read the user data directory from browser internals
223
+ if (window.__wt_profile_dir) return window.__wt_profile_dir;
224
+ return null;
225
+ } catch (e) {
226
+ return null;
227
+ }
228
+ })()
229
+ `,
230
+ returnByValue: true,
231
+ });
232
+ return result.result?.value || null;
233
+ }
234
+ catch {
235
+ return null;
236
+ }
237
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Verification helper functions for DOM state confirmation
3
+ * Provides utilities to verify element state, detect visible feedback, and infer next actions
4
+ */
5
+ import CDP from "chrome-remote-interface";
6
+ export interface ElementState {
7
+ exists: boolean;
8
+ tagName?: string;
9
+ value?: string;
10
+ textContent?: string;
11
+ checked?: boolean;
12
+ disabled?: boolean;
13
+ visible?: boolean;
14
+ attributes?: Record<string, string>;
15
+ className?: string;
16
+ }
17
+ export interface VisibleFeedback {
18
+ type: 'error' | 'warning' | 'success' | 'info';
19
+ text: string;
20
+ selector?: string;
21
+ }
22
+ /**
23
+ * Read full element state for verification
24
+ * Returns comprehensive state snapshot for before/after comparison
25
+ */
26
+ export declare function verifyElementState(session: CDP.Client, selector: string): Promise<ElementState>;
27
+ /**
28
+ * Detect visible feedback messages (toasts, errors, validation messages)
29
+ * Scans common selectors for feedback elements
30
+ */
31
+ export declare function detectVisibleFeedback(session: CDP.Client): Promise<VisibleFeedback[]>;
32
+ /**
33
+ * Infer likely next action based on page context
34
+ * Analyzes page state to suggest what the agent should do next
35
+ */
36
+ export declare function inferNextAction(session: CDP.Client, lastAction: string, context?: {
37
+ filledFields?: string[];
38
+ clickedElement?: string;
39
+ }): Promise<string | undefined>;
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Verification helper functions for DOM state confirmation
3
+ * Provides utilities to verify element state, detect visible feedback, and infer next actions
4
+ */
5
+ /**
6
+ * Read full element state for verification
7
+ * Returns comprehensive state snapshot for before/after comparison
8
+ */
9
+ export async function verifyElementState(session, selector) {
10
+ try {
11
+ const { result } = await session.Runtime.evaluate({
12
+ expression: `(function(sel) {
13
+ try {
14
+ var el = document.querySelector(sel);
15
+ if (!el) return JSON.stringify({ exists: false });
16
+
17
+ var rect = el.getBoundingClientRect();
18
+ var attrs = {};
19
+ for (var i = 0; i < el.attributes.length; i++) {
20
+ attrs[el.attributes[i].name] = el.attributes[i].value;
21
+ }
22
+
23
+ return JSON.stringify({
24
+ exists: true,
25
+ tagName: el.tagName.toLowerCase(),
26
+ value: (el as any).value !== undefined ? String((el as any).value) : undefined,
27
+ textContent: el.textContent ? el.textContent.slice(0, 200) : undefined,
28
+ checked: (el as any).checked,
29
+ disabled: (el as any).disabled,
30
+ visible: rect.width > 0 && rect.height > 0 && rect.bottom >= 0 && rect.top <= window.innerHeight,
31
+ attributes: attrs,
32
+ className: el.className
33
+ });
34
+ } catch(e) {
35
+ return JSON.stringify({ exists: false, error: (e as Error).message });
36
+ }
37
+ })(${JSON.stringify(selector)})`,
38
+ returnByValue: true,
39
+ });
40
+ return result?.value || { exists: false };
41
+ }
42
+ catch {
43
+ return { exists: false };
44
+ }
45
+ }
46
+ /**
47
+ * Detect visible feedback messages (toasts, errors, validation messages)
48
+ * Scans common selectors for feedback elements
49
+ */
50
+ export async function detectVisibleFeedback(session) {
51
+ try {
52
+ const { result } = await session.Runtime.evaluate({
53
+ expression: (function () {
54
+ var feedback = [];
55
+ var selectors = [
56
+ '[role="alert"]', '[role="status"]', '[role="error"]',
57
+ '.error', '.warning', '.success', '.info',
58
+ '[class*="error"]', '[class*="warning"]', '[class*="success"]',
59
+ '[class*="toast"]', '[class*="notification"]',
60
+ '[data-testid*="error"]', '[data-testid*="message"]'
61
+ ];
62
+ for (var i = 0; i < selectors.length; i++) {
63
+ var els = document.querySelectorAll(selectors[i]);
64
+ for (var j = 0; j < els.length; j++) {
65
+ var el = els[j];
66
+ var rect = el.getBoundingClientRect();
67
+ if (rect.width > 0 && rect.height > 0 && rect.bottom >= 0 && rect.top <= window.innerHeight) {
68
+ var text = el.textContent || el.innerText || '';
69
+ if (text.trim()) {
70
+ var type = 'info';
71
+ if (el.className.includes('error') || el.getAttribute('role') === 'error')
72
+ type = 'error';
73
+ else if (el.className.includes('warning'))
74
+ type = 'warning';
75
+ else if (el.className.includes('success'))
76
+ type = 'success';
77
+ feedback.push({
78
+ type: type,
79
+ text: text.trim().slice(0, 200),
80
+ selector: selectors[i]
81
+ });
82
+ }
83
+ }
84
+ }
85
+ }
86
+ return JSON.stringify(feedback.slice(0, 5)); // Limit to 5 most recent
87
+ })(),
88
+ returnByValue: true,
89
+ });
90
+ return result?.value || [];
91
+ }
92
+ catch {
93
+ return [];
94
+ }
95
+ }
96
+ /**
97
+ * Infer likely next action based on page context
98
+ * Analyzes page state to suggest what the agent should do next
99
+ */
100
+ export async function inferNextAction(session, lastAction, context) {
101
+ try {
102
+ const { result } = await session.Runtime.evaluate({
103
+ expression: `
104
+ (function(lastAction, ctx) {
105
+ try {
106
+ var suggestions = [];
107
+ if (lastAction === 'fill' || lastAction === 'type') {
108
+ var inputs = document.querySelectorAll('input:not([type="hidden"]):not([type="submit"]):not([type="button"]), textarea, select[required]');
109
+ var emptyRequired = [];
110
+ for (var i = 0; i < inputs.length; i++) {
111
+ var inp = inputs[i];
112
+ if ((inp.required || inp.getAttribute('aria-required') === 'true') && !inp.value) {
113
+ emptyRequired.push(inp.getAttribute('placeholder') || inp.getAttribute('name') || inp.getAttribute('aria-label') || 'field');
114
+ }
115
+ }
116
+ if (emptyRequired.length > 0) {
117
+ suggestions.push('Fill required field: ' + emptyRequired[0]);
118
+ }
119
+ var submitBtn = document.querySelector('button[type="submit"], input[type="submit"], [type="submit"]');
120
+ if (submitBtn) {
121
+ suggestions.push('Submit form');
122
+ }
123
+ }
124
+ if (lastAction === 'click') {
125
+ var modal = document.querySelector('[role="dialog"], .modal, [class*="modal"]');
126
+ if (modal) {
127
+ suggestions.push('Interact with modal dialog');
128
+ }
129
+ }
130
+ return JSON.stringify(suggestions[0] || undefined);
131
+ } catch(e) {
132
+ return JSON.stringify(undefined);
133
+ }
134
+ })(${JSON.stringify(lastAction)}, ${JSON.stringify(context)})
135
+ `,
136
+ returnByValue: true,
137
+ });
138
+ return result?.value;
139
+ }
140
+ catch {
141
+ return undefined;
142
+ }
143
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Weavetab — cdp/walker.ts
3
+ * Accessibility tree walker: builds w:N ref IDs, viewport culling, and heuristic pointer sweep.
4
+ * Weavetab by fy2ne
5
+ */
6
+ import CDP from "chrome-remote-interface";
7
+ import type { RefEntry } from "../state/delta.js";
8
+ export declare const WT_REGISTRY_INIT_EXPR = "\n window.__weavetab = window.__weavetab || {};\n window.__weavetab.registry = window.__weavetab.registry || new WeakMap();\n";
9
+ export type HrefType = "same-origin" | "external" | "anchor" | "email" | "unknown";
10
+ export interface ActionElement {
11
+ id: string;
12
+ role: string;
13
+ label: string;
14
+ value?: string;
15
+ backendNodeId?: number;
16
+ selector?: string;
17
+ group: "navigation" | "main_content" | "sidebar" | "form" | "modal" | "utility";
18
+ type?: string;
19
+ href?: string;
20
+ hrefType?: HrefType;
21
+ placeholder?: string;
22
+ testId?: string;
23
+ textContent?: string;
24
+ className?: string;
25
+ frameUrl?: string;
26
+ fingerprint: string;
27
+ isFixed?: boolean;
28
+ disabled?: boolean;
29
+ depth: number;
30
+ x?: number;
31
+ y?: number;
32
+ viewport?: string;
33
+ structuralIdiom?: string;
34
+ }
35
+ export interface ActionMap {
36
+ url: string;
37
+ title: string;
38
+ elements: ActionElement[];
39
+ pageType?: string;
40
+ targetId?: string;
41
+ domHash?: number;
42
+ }
43
+ export interface WalkerOptions {
44
+ scope?: ActionElement["group"];
45
+ query?: string;
46
+ limit?: number;
47
+ lite?: boolean;
48
+ fast?: boolean;
49
+ /** If true, returns delta info instead of full element list (caller handles) */
50
+ forDelta?: boolean;
51
+ /** Viewport dimensions — used for culling. Defaults fetched from browser if not passed. */
52
+ viewport?: {
53
+ width: number;
54
+ height: number;
55
+ scrollX: number;
56
+ scrollY: number;
57
+ };
58
+ /** If true, skip the flat-first optimization and go straight to deep shadow DOM traversal */
59
+ deep?: boolean;
60
+ /** Pre-resolved page URL — avoids redundant Page.getFrameTree() call */
61
+ url?: string;
62
+ /** Pre-resolved page title */
63
+ title?: string;
64
+ /**
65
+ * If true, run semantic DOM pruning before returning elements.
66
+ * Drops hidden elements with no interactive descendants and no known toggle-trigger.
67
+ * Replaces SVG icons with [SVG Icon: label] tokens.
68
+ * NOTE: distinct from delta (which diffs across time). Pruning compresses the
69
+ * current snapshot once, before it is returned.
70
+ */
71
+ prune?: boolean;
72
+ }
73
+ export declare function clearViewportCache(targetId: string): void;
74
+ export declare function resetFallbackIdCounter(): void;
75
+ export declare function setShadowDomCache(targetId: string, hasShadow: boolean): void;
76
+ export declare function clearShadowDomCache(targetId: string): void;
77
+ export declare function buildActionMap(session: CDP.Client, options?: WalkerOptions, targetId?: string): Promise<ActionMap>;
78
+ export declare function toRefEntries(elements: ActionElement[]): RefEntry[];
79
+ export declare function findAllMatches(elements: ActionElement[], query: string): ActionElement[];
80
+ export declare function findBestMatch(elements: ActionElement[], query: string): ActionElement | undefined;
81
+ export declare function toMarkdownTable(elements: ActionElement[], url: string, title: string, hint?: string): string;
82
+ export declare function safeSelector(el?: ActionElement): string | undefined;
83
+ export declare function resolveByAria(session: CDP.Client, query: string): Promise<{
84
+ id: string;
85
+ label: string;
86
+ x: number;
87
+ y: number;
88
+ selector: string;
89
+ } | null>;
90
+ export declare function clearAXTreeCache(targetId: string): void;
91
+ export declare function buildAXTreeMap(session: CDP.Client, _options?: WalkerOptions, targetId?: string): Promise<ActionMap>;