@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,217 @@
1
+ import { recordAction } from "../intelligence/trail.js";
2
+ import { confirmChange } from "../cdp/confirm.js";
3
+ import { getCachedActionMap, cacheActionMap } from "../state/cache.js";
4
+ import { sessionRegistry } from "../state/session.js";
5
+ import { getConfigAgentId } from "../config/loader.js";
6
+ import { buildActionMap, safeSelector } from "../cdp/walker.js";
7
+ async function getSelector(session, options, config) {
8
+ if (options.selector)
9
+ return options.selector;
10
+ if (options.ref || options.id) {
11
+ const ref = (options.ref || options.id);
12
+ let targetId = "default";
13
+ const active = sessionRegistry.getActive(getConfigAgentId(config));
14
+ if (active)
15
+ targetId = active.targetId;
16
+ const { frameTree } = await session.Page.getFrameTree();
17
+ const url = frameTree.frame.url;
18
+ let map = getCachedActionMap(targetId, url);
19
+ if (!map) {
20
+ map = await buildActionMap(session, { lite: true }, targetId);
21
+ cacheActionMap(targetId, map);
22
+ }
23
+ const element = map.elements.find(el => el.id === ref || el.id.endsWith(ref.startsWith("w:") ? ref.slice(2) : ref));
24
+ if (element) {
25
+ const sel = safeSelector(element);
26
+ if (sel)
27
+ return sel;
28
+ }
29
+ throw new Error(`Could not resolve element for ref/id: ${ref}`);
30
+ }
31
+ if (options.nodeId) {
32
+ const { nodeIds } = await session.DOM.pushNodesByBackendIdsToFrontend({ backendNodeIds: [options.nodeId] });
33
+ if (!nodeIds[0])
34
+ throw new Error("Node not found");
35
+ const { object } = await session.DOM.resolveNode({ nodeId: nodeIds[0] });
36
+ if (!object?.objectId)
37
+ throw new Error("Could not resolve node");
38
+ const { result } = await session.Runtime.callFunctionOn({
39
+ objectId: object.objectId,
40
+ functionDeclaration: `function() {
41
+ if (this.id) return '#' + CSS.escape(this.id);
42
+ if (this.name) return 'select[name="' + CSS.escape(this.name) + '"]';
43
+ var idx = 0, el = this;
44
+ while (el.previousElementSibling) { idx++; el = el.previousElementSibling; }
45
+ var parent = this.parentElement;
46
+ if (!parent) return 'select:last-of-type';
47
+ var tag = this.tagName.toLowerCase();
48
+ return tag + ':nth-child(' + (idx + 1) + ')';
49
+ }()`,
50
+ returnByValue: true
51
+ });
52
+ return result.value;
53
+ }
54
+ throw new Error("browser_select requires either selector, nodeId, ref, or id");
55
+ }
56
+ function escapeSelector(sel) {
57
+ return JSON.stringify(sel);
58
+ }
59
+ export async function browserSelect(session, options, _config) {
60
+ if (!options.selector && !options.nodeId && !options.ref && !options.id) {
61
+ throw new Error("browser_select requires either selector, nodeId, ref, or id");
62
+ }
63
+ const selector = await getSelector(session, options, _config);
64
+ const value = options.value;
65
+ const getSelectState = async () => {
66
+ const { result } = await session.Runtime.evaluate({
67
+ expression: `(function() {
68
+ try {
69
+ var el = document.querySelector(${escapeSelector(selector)});
70
+ if (!el) return JSON.stringify({ exists: "false" });
71
+ if (el.tagName === "SELECT") {
72
+ var idx = el.selectedIndex;
73
+ var opt = idx >= 0 ? el.options[idx] : null;
74
+ return JSON.stringify({
75
+ exists: "true",
76
+ isNative: "true",
77
+ selectedIndex: String(idx),
78
+ value: el.value,
79
+ selectedText: opt ? opt.text : ""
80
+ });
81
+ }
82
+ // Custom UI Dropdown / Combobox / Popover
83
+ var text = (el.innerText || el.textContent || "").trim();
84
+ var val = el.getAttribute("data-value") || el.getAttribute("aria-valuenow") || text;
85
+ return JSON.stringify({
86
+ exists: "true",
87
+ isNative: "false",
88
+ value: val,
89
+ selectedText: text
90
+ });
91
+ } catch(e) {
92
+ return JSON.stringify({ exists: "false", error: e.message });
93
+ }
94
+ })()`,
95
+ returnByValue: true
96
+ });
97
+ return JSON.parse(result?.value || '{}');
98
+ };
99
+ const action = async () => {
100
+ const { result } = await session.Runtime.evaluate({
101
+ expression: `(function(selector, value) {
102
+ try {
103
+ const el = document.querySelector(selector);
104
+ if (!el) return 'Element not found';
105
+
106
+ // ── NATIVE <select> ELEMENT ──────────────────────────────────────
107
+ if (el.tagName === 'SELECT') {
108
+ let foundIndex = -1;
109
+ for (let i = 0; i < el.options.length; i++) {
110
+ const opt = el.options[i];
111
+ if (opt.value === value || opt.text === value || opt.text.trim() === value.trim()) {
112
+ foundIndex = i;
113
+ break;
114
+ }
115
+ }
116
+ if (foundIndex === -1) return 'Option not found in <select>: ' + value;
117
+
118
+ el.selectedIndex = foundIndex;
119
+
120
+ const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLSelectElement.prototype, 'value')?.set;
121
+ if (nativeSetter) nativeSetter.call(el, el.options[foundIndex].value);
122
+
123
+ el.dispatchEvent(new Event('input', { bubbles: true }));
124
+ el.dispatchEvent(new Event('change', { bubbles: true }));
125
+ el.options[foundIndex].dispatchEvent(new MouseEvent('click', { bubbles: true }));
126
+
127
+ return 'selected:' + el.selectedIndex;
128
+ }
129
+
130
+ // ── CUSTOM ARIA / REACT / RADIX / SHADCN DROPDOWN ────────────────
131
+ // 1. Open popover if closed
132
+ const isExpanded = el.getAttribute('aria-expanded') === 'true';
133
+ if (!isExpanded) {
134
+ el.click();
135
+ el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
136
+ el.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
137
+ }
138
+
139
+ // 2. Scan options in open popover / listbox
140
+ const targetText = value.toLowerCase().trim();
141
+ const optionSelectors = [
142
+ '[role="option"]',
143
+ '[role="menuitem"]',
144
+ '[role="treeitem"]',
145
+ '[data-radix-collection-item]',
146
+ 'li',
147
+ '.option',
148
+ '.select-option',
149
+ '[data-value]'
150
+ ];
151
+
152
+ let candidates = Array.from(document.querySelectorAll(optionSelectors.join(',')));
153
+ // Fallback to all visible clickable items inside active popovers/listboxes
154
+ if (candidates.length === 0) {
155
+ const containers = document.querySelectorAll('[role="listbox"], [role="menu"], [data-radix-popper-content-wrapper], .select-popover, .dropdown-menu');
156
+ containers.forEach(c => {
157
+ candidates.push(...Array.from(c.querySelectorAll('*')));
158
+ });
159
+ }
160
+
161
+ let matchedEl = null;
162
+ for (const cand of candidates) {
163
+ const text = (cand.innerText || cand.textContent || '').toLowerCase().trim();
164
+ const valAttr = (cand.getAttribute('data-value') || cand.getAttribute('value') || '').toLowerCase().trim();
165
+ if (text === targetText || valAttr === targetText || text.includes(targetText)) {
166
+ matchedEl = cand;
167
+ break;
168
+ }
169
+ }
170
+
171
+ if (!matchedEl) {
172
+ return 'Custom option not found: ' + value;
173
+ }
174
+
175
+ matchedEl.click();
176
+ matchedEl.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
177
+ matchedEl.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
178
+
179
+ return 'selected:custom';
180
+ } catch (e) {
181
+ return e.message || 'Unknown error';
182
+ }
183
+ })(${escapeSelector(selector)}, ${escapeSelector(value)})`,
184
+ returnByValue: true
185
+ });
186
+ const resultVal = result?.value;
187
+ if (!resultVal || (!resultVal.startsWith('selected:') && resultVal !== 'success')) {
188
+ throw new Error(resultVal || 'Selection failed');
189
+ }
190
+ };
191
+ const beforeState = await getSelectState();
192
+ if (beforeState.exists === "false") {
193
+ throw new Error("Element not found");
194
+ }
195
+ const confirm = await confirmChange(session, getSelectState, action, {
196
+ verifyPasses: [16, 50, 200, 400],
197
+ });
198
+ if (confirm.applied) {
199
+ recordAction({
200
+ timestamp: new Date().toISOString(),
201
+ tool: 'browser_select',
202
+ input: { ref: selector, value },
203
+ result: { success: true, stuck: false },
204
+ });
205
+ return { success: true, message: `Selected value "${value}" on ${beforeState.isNative === "true" ? "native <select>" : "custom UI dropdown"} (${confirm.attempts} attempts, settled ${confirm.settleMs}ms)` };
206
+ }
207
+ recordAction({
208
+ timestamp: new Date().toISOString(),
209
+ tool: 'browser_select',
210
+ input: { ref: selector, value },
211
+ result: { success: false, stuck: true },
212
+ });
213
+ return {
214
+ success: false,
215
+ message: `Selection did not take effect. Before: value="${beforeState.value}". After: value="${confirm.after.value}".`
216
+ };
217
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Weavetab — tools/snapshot.ts
3
+ * browser_snapshot: Create and restore MHTML snapshots of the DOM state.
4
+ *
5
+ * Secret containment: before capture, all elements marked data-wt-secret have
6
+ * their value blanked in the live DOM (then restored after capture). This prevents
7
+ * typed credential values from appearing in the MHTML archive.
8
+ *
9
+ * Weavetab by fy2ne
10
+ */
11
+ import CDP from "chrome-remote-interface";
12
+ import type { Config } from "../config/loader.js";
13
+ export interface SnapshotOptions {
14
+ action: "capture" | "restore";
15
+ /** Preferred parameter name. */
16
+ filename?: string;
17
+ /** Accepted alias for filename (sent by the MCP schema). */
18
+ filePath?: string;
19
+ /** If false, keeps the WeaveTab UI overlay visible in the MHTML snapshot.
20
+ * Default: true — overlay (cursor, thought bubble, HUD) is always hidden from snapshots. */
21
+ hideOverlay?: boolean;
22
+ }
23
+ export declare function browserSnapshot(session: CDP.Client, options: SnapshotOptions, config: Config): Promise<{
24
+ success: boolean;
25
+ message: string;
26
+ warning?: string;
27
+ }>;
@@ -0,0 +1,99 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import { getOutputDir, getConfigAgentId } from "../config/loader.js";
4
+ import { hideWeaveTabOverlay, restoreWeaveTabOverlay } from "../cdp/helpers.js";
5
+ import { clearTabCache } from "../state/cache.js";
6
+ import { clearSnapshot } from "../state/delta.js";
7
+ import { sessionRegistry } from "../state/session.js";
8
+ export async function browserSnapshot(session, options, config) {
9
+ const { action } = options;
10
+ // Accept both `filename` (original) and `filePath` (MCP schema alias)
11
+ let { filename } = options;
12
+ if (!filename)
13
+ filename = options.filePath;
14
+ if (!filename || !filename.trim()) {
15
+ throw new Error("browser_snapshot requires a filename.");
16
+ }
17
+ // Strip any absolute path provided by the caller — always save in the managed snapshot dir
18
+ filename = path.basename(filename);
19
+ if (!filename.endsWith(".mhtml"))
20
+ filename += ".mhtml";
21
+ const snapshotDir = getOutputDir("snapshots", config);
22
+ const filePath = path.join(snapshotDir, filename);
23
+ if (action === "capture") {
24
+ // Always hide overlay before capture (default true); set hideOverlay: false to skip.
25
+ const shouldHide = options.hideOverlay !== false;
26
+ if (shouldHide) {
27
+ await hideWeaveTabOverlay(session);
28
+ }
29
+ // ── Blank secret field values before capture ──────────────────────────
30
+ // Prevents credential values from being embedded in the MHTML archive.
31
+ // data-wt-secret is set by browser_type_secret at injection time.
32
+ await session.Runtime.evaluate({
33
+ expression: `(function() {
34
+ var els = document.querySelectorAll('[data-wt-secret], input[type="password"]');
35
+ for (var i = 0; i < els.length; i++) {
36
+ var el = els[i];
37
+ el.__wt_snap_backup = el.value;
38
+ try { el.value = ''; } catch(e) {}
39
+ if (el.isContentEditable) {
40
+ el.__wt_snap_text_backup = el.textContent;
41
+ try { el.textContent = ''; } catch(e) {}
42
+ }
43
+ }
44
+ })()`,
45
+ returnByValue: false,
46
+ }).catch(() => { });
47
+ let snapshotData;
48
+ try {
49
+ const res = await session.Page.captureSnapshot({ format: "mhtml" });
50
+ snapshotData = res.data;
51
+ }
52
+ finally {
53
+ // ── Restore secret field values after capture (always runs) ──────────
54
+ if (shouldHide) {
55
+ await restoreWeaveTabOverlay(session);
56
+ }
57
+ await session.Runtime.evaluate({
58
+ expression: `(function() {
59
+ var els = document.querySelectorAll('[data-wt-secret], input[type="password"]');
60
+ for (var i = 0; i < els.length; i++) {
61
+ var el = els[i];
62
+ if (el.__wt_snap_backup !== undefined) {
63
+ try { el.value = el.__wt_snap_backup; } catch(e) {}
64
+ delete el.__wt_snap_backup;
65
+ }
66
+ if (el.__wt_snap_text_backup !== undefined) {
67
+ try { el.textContent = el.__wt_snap_text_backup; } catch(e) {}
68
+ delete el.__wt_snap_text_backup;
69
+ }
70
+ }
71
+ })()`,
72
+ returnByValue: false,
73
+ }).catch(() => { });
74
+ }
75
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
76
+ await fs.writeFile(filePath, snapshotData, "utf8");
77
+ return { success: true, message: `Snapshot saved to ${filePath}` };
78
+ }
79
+ else if (action === "restore") {
80
+ // Navigate to the local MHTML file
81
+ // Note: Chrome must have access to the file path.
82
+ const fileUrl = `file:///${filePath.replace(/\\/g, '/')}`;
83
+ await session.Page.navigate({ url: fileUrl });
84
+ // Invalidate cached ref IDs after restore: the entire DOM is replaced, making
85
+ // all cached w:NN ref IDs stale. Clearing both the action-map cache and the
86
+ // delta snapshot forces the next browser_map / browser_inspect call to rebuild
87
+ // a fresh map with valid refs for the restored page.
88
+ const active = sessionRegistry.getActive(getConfigAgentId(config));
89
+ const targetId = active?.targetId ?? "default";
90
+ clearTabCache(targetId);
91
+ clearSnapshot(targetId);
92
+ return {
93
+ success: true,
94
+ message: `Restored snapshot from ${filePath}`,
95
+ warning: "Ref cache cleared — call browser_map to get fresh w:NN IDs for this restored page before using any ref-based tools.",
96
+ };
97
+ }
98
+ throw new Error("Unknown action");
99
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Weavetab — tools/storage.ts
3
+ * browser_storage: read/write localStorage and sessionStorage via Runtime.evaluate.
4
+ * Weavetab by fy2ne
5
+ */
6
+ import CDP from "chrome-remote-interface";
7
+ import type { Config } from "../config/loader.js";
8
+ export interface StorageOptions {
9
+ scope: "local" | "session";
10
+ action: "get" | "set" | "clear";
11
+ key?: string;
12
+ value?: string;
13
+ }
14
+ export declare function browserStorage(session: CDP.Client, options: StorageOptions, _config: Config): Promise<{
15
+ success: boolean;
16
+ result?: string | null;
17
+ message?: string;
18
+ }>;
@@ -0,0 +1,29 @@
1
+ export async function browserStorage(session, options, _config) {
2
+ const { scope, action, key, value } = options;
3
+ if (action === "get") {
4
+ if (!key)
5
+ throw new Error("browser_storage get requires a 'key'");
6
+ const { result } = await session.Runtime.evaluate({
7
+ // Use JSON.stringify to safely embed the key — no raw string interpolation
8
+ expression: `(function(k){ return ${scope}Storage.getItem(k); })(${JSON.stringify(key)})`,
9
+ returnByValue: true
10
+ });
11
+ return { success: true, result: result.value };
12
+ }
13
+ else if (action === "set") {
14
+ if (!key || value === undefined)
15
+ throw new Error("browser_storage set requires 'key' and 'value'");
16
+ await session.Runtime.evaluate({
17
+ // Use JSON.stringify to safely embed key and value — no raw string interpolation
18
+ expression: `(function(k,v){ ${scope}Storage.setItem(k,v); })(${JSON.stringify(key)}, ${JSON.stringify(value ?? "")})`
19
+ });
20
+ return { success: true, message: `Set ${scope}Storage key ${key}` };
21
+ }
22
+ else if (action === "clear") {
23
+ await session.Runtime.evaluate({
24
+ expression: `${scope}Storage.clear()`
25
+ });
26
+ return { success: true, message: `Cleared ${scope}Storage` };
27
+ }
28
+ throw new Error(`Unknown action: ${action}`);
29
+ }
@@ -0,0 +1,77 @@
1
+ import type { Config } from "../config/loader.js";
2
+ export declare function recordTabActivity(targetId: string): void;
3
+ export declare function lockTab(targetId: string): void;
4
+ export declare function unlockTab(targetId: string): void;
5
+ export declare function evaluateTabSemantics(targetId: string): Promise<void>;
6
+ export interface TabInfo {
7
+ id: string;
8
+ title: string;
9
+ url: string;
10
+ status: "active" | "idle" | "loading" | "locked" | "alive" | "dead" | "unreachable";
11
+ health: "alive" | "dead" | "unreachable";
12
+ score: number;
13
+ }
14
+ export declare function WeavetabOpen(url: string, config: Config, reuse?: boolean): Promise<{
15
+ success: true;
16
+ tabId: string;
17
+ url: string;
18
+ reused?: boolean;
19
+ }>;
20
+ export declare function WeavetabSwitch(tabId: string, config: Config): Promise<{
21
+ success: true;
22
+ tab_id: string;
23
+ title: string;
24
+ url: string;
25
+ contextSwitchCostMs: number;
26
+ }>;
27
+ export declare function WeavetabList(config: Config): Promise<{
28
+ tabs: TabInfo[];
29
+ }>;
30
+ export declare function WeavetabClose(tabId: string, config: Config, force?: boolean): Promise<{
31
+ success: true;
32
+ tab_id: string;
33
+ }>;
34
+ /**
35
+ * Batch close multiple tabs at once — saves multiple round-trips.
36
+ */
37
+ export declare function WeavetabCloseBatch(tabIds: string[], config: Config, force?: boolean): Promise<{
38
+ success: true;
39
+ closed: string[];
40
+ skipped: string[];
41
+ }>;
42
+ /**
43
+ * Consolidate: deduplicate tabs by URL, close duplicates.
44
+ */
45
+ export declare function WeavetabConsolidate(config: Config): Promise<{
46
+ success: true;
47
+ tabs_before: number;
48
+ tabs_after: number;
49
+ closed_duplicates: number;
50
+ }>;
51
+ /**
52
+ * Heal: check all tabs for crashed state and reload them.
53
+ */
54
+ export declare function WeavetabHeal(config: Config): Promise<{
55
+ success: true;
56
+ healed: number;
57
+ tabs_checked: number;
58
+ health_summary: Record<string, string>;
59
+ }>;
60
+ export interface WindowInfo {
61
+ windowId: number;
62
+ state: string;
63
+ bounds: {
64
+ left: number;
65
+ top: number;
66
+ width: number;
67
+ height: number;
68
+ };
69
+ focused: boolean;
70
+ }
71
+ export declare function weaveWindowList(config: Config): Promise<{
72
+ windows: WindowInfo[];
73
+ }>;
74
+ export declare function weaveFocusWindow(windowId: number, config: Config): Promise<{
75
+ success: true;
76
+ windowId: number;
77
+ }>;