@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,193 @@
1
+ export class TelemetryCapture {
2
+ session;
3
+ requests = new Map();
4
+ toastMessages = [];
5
+ errors = [];
6
+ navigationOccurred = false;
7
+ newUrl;
8
+ active = false;
9
+ // Store each CDP event listener reference so stop() can remove them.
10
+ // Multiple TelemetryCapture instances per session must not accumulate listeners.
11
+ _onRequestWillBeSent = null;
12
+ _onResponseReceived = null;
13
+ _onLoadingFinished = null;
14
+ _onLoadingFailed = null;
15
+ _onFrameNavigated = null;
16
+ _onChildNodeInserted = null;
17
+ _onConsoleAPICalled = null;
18
+ constructor(session) {
19
+ this.session = session;
20
+ this.setupListeners();
21
+ }
22
+ setupListeners() {
23
+ this._onRequestWillBeSent = (params) => {
24
+ if (!this.active)
25
+ return;
26
+ this.requests.set(params.requestId, {
27
+ url: params.request.url,
28
+ method: params.request.method,
29
+ isApi: params.request.url.includes('/api/') || params.request.headers?.['Accept']?.includes('application/json'),
30
+ timestamp: params.wallTime ? params.wallTime * 1000 : Date.now(),
31
+ _startTimeMonotonic: params.timestamp
32
+ });
33
+ };
34
+ this.session.Network.requestWillBeSent(this._onRequestWillBeSent);
35
+ this._onResponseReceived = (params) => {
36
+ if (!this.active)
37
+ return;
38
+ const req = this.requests.get(params.requestId);
39
+ if (req) {
40
+ req.status = params.response.status;
41
+ if (params.response.mimeType?.includes('application/json')) {
42
+ req.isApi = true;
43
+ }
44
+ // 1. Capture TLS/SSL Certificate Metadata
45
+ if (params.response.securityDetails) {
46
+ const sec = params.response.securityDetails;
47
+ req.securityDetails = {
48
+ protocol: sec.protocol,
49
+ issuer: sec.issuer,
50
+ subjectName: sec.subjectName,
51
+ validFrom: sec.validFrom,
52
+ validTo: sec.validTo,
53
+ cipher: sec.cipher,
54
+ keyExchange: sec.keyExchange,
55
+ sanList: sec.sanList,
56
+ certificateId: sec.certificateId
57
+ };
58
+ }
59
+ // 2. Capture Network Timing Breakdown (DNS, TCP, SSL, Send, Wait)
60
+ if (params.response.timing) {
61
+ const t = params.response.timing;
62
+ const dnsMs = (t.dnsEnd > 0 && t.dnsStart >= 0) ? Math.max(0, t.dnsEnd - t.dnsStart) : 0;
63
+ const connectMs = (t.connectEnd > 0 && t.connectStart >= 0) ? Math.max(0, t.connectEnd - t.connectStart) : 0;
64
+ const sslMs = (t.sslEnd > 0 && t.sslStart >= 0) ? Math.max(0, t.sslEnd - t.sslStart) : 0;
65
+ const sendMs = (t.sendEnd > 0 && t.sendStart >= 0) ? Math.max(0, t.sendEnd - t.sendStart) : 0;
66
+ const waitMs = (t.receiveHeadersStart > 0 && t.sendEnd >= 0) ? Math.max(0, t.receiveHeadersStart - t.sendEnd) : 0;
67
+ req.timing = {
68
+ dnsMs: Number(dnsMs.toFixed(3)),
69
+ connectMs: Number(connectMs.toFixed(3)),
70
+ sslMs: Number(sslMs.toFixed(3)),
71
+ sendMs: Number(sendMs.toFixed(3)),
72
+ waitMs: Number(waitMs.toFixed(3)),
73
+ };
74
+ if (t.requestTime && t.receiveHeadersStart > 0) {
75
+ req._responseHeadersMonotonic = t.requestTime + (t.receiveHeadersStart / 1000);
76
+ }
77
+ }
78
+ }
79
+ };
80
+ this.session.Network.responseReceived(this._onResponseReceived);
81
+ this._onLoadingFinished = (params) => {
82
+ if (!this.active)
83
+ return;
84
+ const req = this.requests.get(params.requestId);
85
+ if (req) {
86
+ const finishTimeMonotonic = params.timestamp;
87
+ if (req._startTimeMonotonic && finishTimeMonotonic) {
88
+ const totalMs = (finishTimeMonotonic - req._startTimeMonotonic) * 1000;
89
+ if (!req.timing)
90
+ req.timing = {};
91
+ req.timing.totalMs = Number(Math.max(0, totalMs).toFixed(3));
92
+ if (req._responseHeadersMonotonic) {
93
+ const downloadMs = (finishTimeMonotonic - req._responseHeadersMonotonic) * 1000;
94
+ req.timing.downloadMs = Number(Math.max(0, downloadMs).toFixed(3));
95
+ }
96
+ else {
97
+ req.timing.downloadMs = 0;
98
+ }
99
+ }
100
+ }
101
+ };
102
+ this.session.Network.loadingFinished(this._onLoadingFinished);
103
+ this._onLoadingFailed = (params) => {
104
+ if (!this.active)
105
+ return;
106
+ const req = this.requests.get(params.requestId);
107
+ if (req) {
108
+ req.failure = {
109
+ errorText: params.errorText || "net::ERR_FAILED",
110
+ canceled: params.canceled,
111
+ blockedReason: params.blockedReason
112
+ };
113
+ this.errors.push(`[Network Error] ${req.url} failed: ${params.errorText || 'net::ERR_FAILED'}`);
114
+ }
115
+ };
116
+ this.session.Network.loadingFailed(this._onLoadingFailed);
117
+ this._onFrameNavigated = (params) => {
118
+ if (!this.active)
119
+ return;
120
+ if (!params.frame.parentId) { // Main frame
121
+ this.navigationOccurred = true;
122
+ this.newUrl = params.frame.url;
123
+ }
124
+ };
125
+ this.session.Page.frameNavigated(this._onFrameNavigated);
126
+ this._onChildNodeInserted = (params) => {
127
+ if (!this.active)
128
+ return;
129
+ const attrs = params.node.attributes || [];
130
+ const isToast = attrs.some((a) => typeof a === 'string' && a.toLowerCase().match(/toast|snackbar|notification|alert/));
131
+ if (isToast) {
132
+ this.toastMessages.push("Toast or banner detected");
133
+ }
134
+ };
135
+ this.session.DOM.childNodeInserted(this._onChildNodeInserted);
136
+ this._onConsoleAPICalled = (params) => {
137
+ if (!this.active)
138
+ return;
139
+ if (params.type === 'error' || params.type === 'warning') {
140
+ const text = params.args.map((a) => a.value || a.description).join(' ');
141
+ this.errors.push(`[${params.type}] ${text}`);
142
+ }
143
+ };
144
+ this.session.Runtime.consoleAPICalled(this._onConsoleAPICalled);
145
+ }
146
+ async start() {
147
+ this.requests.clear();
148
+ this.toastMessages = [];
149
+ this.errors = [];
150
+ this.navigationOccurred = false;
151
+ this.newUrl = undefined;
152
+ await this.session.Network.enable();
153
+ await this.session.Page.enable();
154
+ await this.session.DOM.enable();
155
+ await this.session.Runtime.enable();
156
+ this.active = true;
157
+ }
158
+ async stop() {
159
+ this.active = false;
160
+ // Remove all listeners to prevent accumulation
161
+ try {
162
+ if (this._onRequestWillBeSent)
163
+ this.session.Network.removeListener('requestWillBeSent', this._onRequestWillBeSent);
164
+ if (this._onResponseReceived)
165
+ this.session.Network.removeListener('responseReceived', this._onResponseReceived);
166
+ if (this._onLoadingFinished)
167
+ this.session.Network.removeListener('loadingFinished', this._onLoadingFinished);
168
+ if (this._onLoadingFailed)
169
+ this.session.Network.removeListener('loadingFailed', this._onLoadingFailed);
170
+ if (this._onFrameNavigated)
171
+ this.session.Page.removeListener('frameNavigated', this._onFrameNavigated);
172
+ if (this._onChildNodeInserted)
173
+ this.session.DOM.removeListener('childNodeInserted', this._onChildNodeInserted);
174
+ if (this._onConsoleAPICalled)
175
+ this.session.Runtime.removeListener('consoleAPICalled', this._onConsoleAPICalled);
176
+ }
177
+ catch { /* ignore */ }
178
+ this._onRequestWillBeSent = this._onResponseReceived = this._onLoadingFinished = this._onLoadingFailed =
179
+ this._onFrameNavigated = this._onChildNodeInserted = this._onConsoleAPICalled = null;
180
+ const requestsClean = Array.from(this.requests.values()).map(r => {
181
+ const { _startTimeMonotonic, _responseHeadersMonotonic, ...publicReq } = r;
182
+ return publicReq;
183
+ });
184
+ return {
185
+ networkRequests: requestsClean,
186
+ domMutations: this.toastMessages.length > 0 ? ["Toasts appeared"] : [], // simplified DOM mutations for now
187
+ navigationOccurred: this.navigationOccurred,
188
+ newUrl: this.newUrl,
189
+ toastMessages: this.toastMessages,
190
+ errors: this.errors
191
+ };
192
+ }
193
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Weavetab — sensors/operation_monitor.ts
3
+ * Intelligent operation monitoring for detecting and resolving tool execution lag.
4
+ * Detects when operations hang inside tool execution and provides adaptive bail-out.
5
+ * Weavetab by fy2ne
6
+ */
7
+ export interface OperationPhase {
8
+ name: string;
9
+ startTime: number;
10
+ endTime?: number;
11
+ duration?: number;
12
+ completed: boolean;
13
+ warning?: string;
14
+ }
15
+ export interface OperationDiagnostics {
16
+ toolName: string;
17
+ totalDuration: number;
18
+ phases: OperationPhase[];
19
+ bottlenecks: string[];
20
+ health: "healthy" | "degraded" | "critical";
21
+ bailOutReason?: string;
22
+ }
23
+ declare class OperationMonitor {
24
+ private activeOperations;
25
+ private readonly PHASE_THRESHOLDS;
26
+ private readonly BAIL_OUT_THRESHOLDS;
27
+ private readonly TOTAL_OPERATION_TIMEOUT;
28
+ /**
29
+ * Start monitoring a new tool operation
30
+ */
31
+ startOperation(operationId: string, toolName: string): void;
32
+ /**
33
+ * Record the start of a specific phase within an operation
34
+ */
35
+ startPhase(operationId: string, phaseName: string): void;
36
+ /**
37
+ * Record the completion of a specific phase
38
+ */
39
+ endPhase(operationId: string, phaseName: string, warning?: string): void;
40
+ /**
41
+ * End operation monitoring and return diagnostics
42
+ */
43
+ endOperation(operationId: string): OperationDiagnostics | null;
44
+ /**
45
+ * Check if an operation should bail out with degraded results
46
+ */
47
+ shouldBailOut(operationId: string): {
48
+ shouldBail: boolean;
49
+ reason?: string;
50
+ };
51
+ /**
52
+ * Get current operation status for diagnostics
53
+ */
54
+ getOperationStatus(operationId: string): {
55
+ toolName: string;
56
+ duration: number;
57
+ currentPhase: string;
58
+ health: "healthy" | "degraded" | "critical";
59
+ } | null;
60
+ /**
61
+ * Periodic health check for active operations
62
+ */
63
+ private checkOperationHealth;
64
+ /**
65
+ * Identify bottlenecks in operation phases
66
+ */
67
+ private identifyBottlenecks;
68
+ /**
69
+ * Determine overall operation health
70
+ */
71
+ private determineHealth;
72
+ /**
73
+ * Clear every active diagnostics timer. Registered on process exit events so
74
+ * that a tool crashing before endOperation() can't leave an interval firing
75
+ * every second and pinning the Node.js event loop.
76
+ */
77
+ cleanupAll(): void;
78
+ }
79
+ export declare const operationMonitor: OperationMonitor;
80
+ export {};
@@ -0,0 +1,203 @@
1
+ import { logDebug } from "../audit/logger.js";
2
+ class OperationMonitor {
3
+ activeOperations = new Map();
4
+ PHASE_THRESHOLDS = {
5
+ // Expected maximum duration for each phase (in ms)
6
+ setup: 500, // Security checks, session setup
7
+ element_resolution: 1000, // Finding elements in DOM
8
+ actionability_check: 800, // Checking if element is clickable
9
+ ghost_move: 500, // Ghost cursor movement
10
+ action_dispatch: 300, // Actual click/type dispatch
11
+ stuck_check: 1000, // Post-action stuck detection
12
+ network_wait: 3000, // Network idle waiting
13
+ dom_stability: 1500, // DOM stability checks
14
+ };
15
+ BAIL_OUT_THRESHOLDS = {
16
+ // When to bail out with degraded results (in ms)
17
+ element_resolution: 2500,
18
+ actionability_check: 2000,
19
+ network_wait: 6000,
20
+ dom_stability: 4000,
21
+ };
22
+ TOTAL_OPERATION_TIMEOUT = 15000; // 15s max for any operation
23
+ /**
24
+ * Start monitoring a new tool operation
25
+ */
26
+ startOperation(operationId, toolName) {
27
+ this.activeOperations.set(operationId, {
28
+ toolName,
29
+ startTime: Date.now(),
30
+ phases: [],
31
+ });
32
+ // Start periodic health check
33
+ const diagnosticsTimer = setInterval(() => {
34
+ this.checkOperationHealth(operationId);
35
+ }, 1000); // Check every 1 second (reduced from 2s for faster detection)
36
+ this.activeOperations.get(operationId).diagnosticsTimer = diagnosticsTimer;
37
+ }
38
+ /**
39
+ * Record the start of a specific phase within an operation
40
+ */
41
+ startPhase(operationId, phaseName) {
42
+ const op = this.activeOperations.get(operationId);
43
+ if (!op)
44
+ return;
45
+ op.phases.push({
46
+ name: phaseName,
47
+ startTime: Date.now(),
48
+ completed: false,
49
+ });
50
+ }
51
+ /**
52
+ * Record the completion of a specific phase
53
+ */
54
+ endPhase(operationId, phaseName, warning) {
55
+ const op = this.activeOperations.get(operationId);
56
+ if (!op)
57
+ return;
58
+ const phase = op.phases.find(p => p.name === phaseName && !p.completed);
59
+ if (phase) {
60
+ phase.endTime = Date.now();
61
+ phase.duration = phase.endTime - phase.startTime;
62
+ phase.completed = true;
63
+ phase.warning = warning;
64
+ }
65
+ }
66
+ /**
67
+ * End operation monitoring and return diagnostics
68
+ */
69
+ endOperation(operationId) {
70
+ const op = this.activeOperations.get(operationId);
71
+ if (!op)
72
+ return null;
73
+ // Clear diagnostics timer
74
+ if (op.diagnosticsTimer) {
75
+ clearInterval(op.diagnosticsTimer);
76
+ }
77
+ const totalDuration = Date.now() - op.startTime;
78
+ const bottlenecks = this.identifyBottlenecks(op.phases);
79
+ const health = this.determineHealth(totalDuration, bottlenecks);
80
+ const diagnostics = {
81
+ toolName: op.toolName,
82
+ totalDuration,
83
+ phases: op.phases,
84
+ bottlenecks,
85
+ health,
86
+ };
87
+ this.activeOperations.delete(operationId);
88
+ return diagnostics;
89
+ }
90
+ /**
91
+ * Check if an operation should bail out with degraded results
92
+ */
93
+ shouldBailOut(operationId) {
94
+ const op = this.activeOperations.get(operationId);
95
+ if (!op)
96
+ return { shouldBail: false };
97
+ const totalDuration = Date.now() - op.startTime;
98
+ // Check total operation timeout
99
+ if (totalDuration > this.TOTAL_OPERATION_TIMEOUT) {
100
+ return { shouldBail: true, reason: `Total operation timeout (${totalDuration}ms > ${this.TOTAL_OPERATION_TIMEOUT}ms)` };
101
+ }
102
+ // Check specific phase timeouts
103
+ const currentPhase = op.phases.find(p => !p.completed);
104
+ if (currentPhase) {
105
+ const phaseDuration = Date.now() - currentPhase.startTime;
106
+ const bailOutThreshold = this.BAIL_OUT_THRESHOLDS[currentPhase.name];
107
+ if (bailOutThreshold && phaseDuration > bailOutThreshold) {
108
+ return {
109
+ shouldBail: true,
110
+ reason: `Phase '${currentPhase.name}' timeout (${phaseDuration}ms > ${bailOutThreshold}ms)`
111
+ };
112
+ }
113
+ }
114
+ return { shouldBail: false };
115
+ }
116
+ /**
117
+ * Get current operation status for diagnostics
118
+ */
119
+ getOperationStatus(operationId) {
120
+ const op = this.activeOperations.get(operationId);
121
+ if (!op)
122
+ return null;
123
+ const duration = Date.now() - op.startTime;
124
+ const currentPhase = op.phases.find(p => !p.completed)?.name || "idle";
125
+ const health = this.determineHealth(duration, []);
126
+ return {
127
+ toolName: op.toolName,
128
+ duration,
129
+ currentPhase,
130
+ health,
131
+ };
132
+ }
133
+ /**
134
+ * Periodic health check for active operations
135
+ */
136
+ checkOperationHealth(operationId) {
137
+ const op = this.activeOperations.get(operationId);
138
+ if (!op)
139
+ return;
140
+ const duration = Date.now() - op.startTime;
141
+ const currentPhase = op.phases.find(p => !p.completed);
142
+ if (currentPhase) {
143
+ const phaseDuration = Date.now() - currentPhase.startTime;
144
+ const threshold = this.PHASE_THRESHOLDS[currentPhase.name];
145
+ if (threshold && phaseDuration > threshold) {
146
+ // Phase is taking longer than expected
147
+ logDebug(`[Weavetab Monitor] Phase '${currentPhase.name}' taking longer than expected: ${phaseDuration}ms (threshold: ${threshold}ms)`);
148
+ // Add warning to phase
149
+ currentPhase.warning = `Exceeded threshold by ${phaseDuration - threshold}ms`;
150
+ }
151
+ }
152
+ if (duration > this.TOTAL_OPERATION_TIMEOUT * 0.7) {
153
+ // Operation is approaching timeout
154
+ logDebug(`[Weavetab Monitor] Operation '${op.toolName}' approaching timeout: ${duration}ms / ${this.TOTAL_OPERATION_TIMEOUT}ms`);
155
+ }
156
+ }
157
+ /**
158
+ * Identify bottlenecks in operation phases
159
+ */
160
+ identifyBottlenecks(phases) {
161
+ const bottlenecks = [];
162
+ for (const phase of phases) {
163
+ if (!phase.completed || !phase.duration)
164
+ continue;
165
+ const threshold = this.PHASE_THRESHOLDS[phase.name];
166
+ if (threshold && phase.duration > threshold) {
167
+ bottlenecks.push(`${phase.name}: ${phase.duration}ms (threshold: ${threshold}ms)`);
168
+ }
169
+ }
170
+ return bottlenecks;
171
+ }
172
+ /**
173
+ * Determine overall operation health
174
+ */
175
+ determineHealth(duration, bottlenecks) {
176
+ if (bottlenecks.length > 2 || duration > this.TOTAL_OPERATION_TIMEOUT * 0.8) {
177
+ return "critical";
178
+ }
179
+ if (bottlenecks.length > 0 || duration > this.TOTAL_OPERATION_TIMEOUT * 0.5) {
180
+ return "degraded";
181
+ }
182
+ return "healthy";
183
+ }
184
+ /**
185
+ * Clear every active diagnostics timer. Registered on process exit events so
186
+ * that a tool crashing before endOperation() can't leave an interval firing
187
+ * every second and pinning the Node.js event loop.
188
+ */
189
+ cleanupAll() {
190
+ for (const [id, op] of this.activeOperations.entries()) {
191
+ if (op.diagnosticsTimer) {
192
+ clearInterval(op.diagnosticsTimer);
193
+ }
194
+ this.activeOperations.delete(id);
195
+ }
196
+ }
197
+ }
198
+ export const operationMonitor = new OperationMonitor();
199
+ // Register shutdown hooks so timers are always cleared, even on crashes
200
+ process.on('exit', () => operationMonitor.cleanupAll());
201
+ process.on('SIGINT', () => { operationMonitor.cleanupAll(); });
202
+ process.on('SIGTERM', () => { operationMonitor.cleanupAll(); });
203
+ process.on('uncaughtException', () => { operationMonitor.cleanupAll(); });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Weavetab — src/sensors/pacing.ts
3
+ * Human Pacing System — pass-through wrapper that records timing telemetry.
4
+ * All human-like delays live in ghost.ts (ghostMove, ghostType).
5
+ * This file does NOT add its own delays — eliminates the "double pacing" bug.
6
+ * Weavetab by fy2ne
7
+ */
8
+ import CDP from "chrome-remote-interface";
9
+ export declare const HumanPace: {
10
+ afterRead: () => Promise<unknown>;
11
+ betweenClicks: () => Promise<unknown>;
12
+ afterNavigate: () => Promise<unknown>;
13
+ thinkingPause: () => Promise<unknown>;
14
+ fieldToField: () => Promise<unknown>;
15
+ beforeSubmit: () => Promise<unknown>;
16
+ };
17
+ export interface ToolCallMetrics {
18
+ tool: string;
19
+ inputTokens: number;
20
+ outputTokens: number;
21
+ totalTokens: number;
22
+ latencyMs: number;
23
+ timestamp: number;
24
+ }
25
+ /**
26
+ * Returns a session-level usage summary.
27
+ * Exposed to browser_eval via window.__wt_get_usage().
28
+ */
29
+ export declare function getUsageStats(): {
30
+ totalCalls: number;
31
+ totalTokens: number;
32
+ byTool: {
33
+ tool: string;
34
+ calls: number;
35
+ tokens: number;
36
+ avgLatencyMs: number;
37
+ }[];
38
+ topSlowest: string[];
39
+ };
40
+ /**
41
+ * Wraps a tool action — records timing + updates HUD state.
42
+ * No artificial delays added here; ghost.ts handles human-like pacing.
43
+ */
44
+ export declare function agentAction(session: CDP.Client, type: 'clicking' | 'typing' | 'reading' | 'thinking' | 'navigating', fn: () => Promise<any>, toolName?: string): Promise<any>;
@@ -0,0 +1,111 @@
1
+ import { sendToExtension } from "../cdp/helpers.js";
2
+ import { agentState } from "../state/agent.js";
3
+ import { getRandomThought } from "./thoughts.js";
4
+ export const HumanPace = {
5
+ afterRead: () => sleep(randomBetween(800, 2500)),
6
+ betweenClicks: () => sleep(randomBetween(300, 800)),
7
+ afterNavigate: () => sleep(randomBetween(1500, 3500)),
8
+ thinkingPause: () => sleep(randomBetween(2000, 5000)),
9
+ fieldToField: () => sleep(randomBetween(400, 900)),
10
+ beforeSubmit: () => sleep(randomBetween(500, 1500)),
11
+ };
12
+ function sleep(ms) {
13
+ return new Promise(r => setTimeout(r, ms));
14
+ }
15
+ function randomBetween(min, max) {
16
+ return Math.random() * (max - min) + min;
17
+ }
18
+ /** Rolling log of the last 100 tool calls for devMode HUD and usage() queries. */
19
+ const toolCallLog = [];
20
+ const MAX_LOG_SIZE = 100;
21
+ function estimateTokens(obj) {
22
+ try {
23
+ return Math.ceil(JSON.stringify(obj).length / 4);
24
+ }
25
+ catch {
26
+ return 0;
27
+ }
28
+ }
29
+ function recordMetrics(metrics) {
30
+ toolCallLog.push(metrics);
31
+ if (toolCallLog.length > MAX_LOG_SIZE)
32
+ toolCallLog.shift();
33
+ }
34
+ /**
35
+ * Returns a session-level usage summary.
36
+ * Exposed to browser_eval via window.__wt_get_usage().
37
+ */
38
+ export function getUsageStats() {
39
+ const byTool = new Map();
40
+ for (const entry of toolCallLog) {
41
+ const existing = byTool.get(entry.tool) ?? { calls: 0, tokens: 0, totalLatencyMs: 0 };
42
+ existing.calls++;
43
+ existing.tokens += entry.totalTokens;
44
+ existing.totalLatencyMs += entry.latencyMs;
45
+ byTool.set(entry.tool, existing);
46
+ }
47
+ const totalCalls = toolCallLog.length;
48
+ const totalTokens = toolCallLog.reduce((s, e) => s + e.totalTokens, 0);
49
+ const toolEntries = [...byTool.entries()].map(([tool, data]) => ({
50
+ tool,
51
+ calls: data.calls,
52
+ tokens: data.tokens,
53
+ avgLatencyMs: Math.round(data.totalLatencyMs / data.calls),
54
+ }));
55
+ const topSlowest = [...toolCallLog]
56
+ .sort((a, b) => b.latencyMs - a.latencyMs)
57
+ .slice(0, 5)
58
+ .map(e => `${e.tool} (${e.latencyMs}ms)`);
59
+ return { totalCalls, totalTokens, byTool: toolEntries, topSlowest };
60
+ }
61
+ /**
62
+ * Wraps a tool action — records timing + updates HUD state.
63
+ * No artificial delays added here; ghost.ts handles human-like pacing.
64
+ */
65
+ export async function agentAction(session, type, fn, toolName) {
66
+ // Report tool activity to agent state manager
67
+ agentState.reportToolCall();
68
+ // Update state indicator with a varied thought (no cursor position — ghost.ts handles real cursor)
69
+ const thought = getRandomThought(type);
70
+ sendToExtension(session, {
71
+ type: 'Weavetab_STATE',
72
+ state: type,
73
+ ...(thought ? { hud: { action: thought } } : {}),
74
+ }).catch(() => { });
75
+ const start = Date.now();
76
+ const result = await fn();
77
+ const elapsed = Date.now() - start;
78
+ // Record execution timing for telemetry
79
+ if (result && typeof result === 'object') {
80
+ result.execution_ms = elapsed;
81
+ }
82
+ // Token telemetry — approximate via JSON length / 4
83
+ if (toolName) {
84
+ const inputTokens = estimateTokens(result); // args not captured here, output used as proxy
85
+ const outputTokens = estimateTokens(result);
86
+ const metrics = {
87
+ tool: toolName,
88
+ inputTokens,
89
+ outputTokens,
90
+ totalTokens: inputTokens + outputTokens,
91
+ latencyMs: elapsed,
92
+ timestamp: start,
93
+ };
94
+ recordMetrics(metrics);
95
+ // DevMode HUD console output
96
+ const liveConfig = global.__wt_live_config;
97
+ const devMode = liveConfig?.devMode;
98
+ const devEnabled = devMode === true;
99
+ if (devEnabled) {
100
+ const stats = getUsageStats();
101
+ process.stderr.write(`\n┌─ Tool Call ──────────────────────────────────────────┐\n` +
102
+ `│ ${toolName.padEnd(50)} │\n` +
103
+ `│ Input: ${String(inputTokens).padStart(4)} tokens │ Latency: ${String(elapsed).padStart(6)}ms │\n` +
104
+ `│ Output: ${String(outputTokens).padStart(4)} tokens │ Total: ${String(metrics.totalTokens).padStart(4)} tokens │\n` +
105
+ `│ ──────────────────────────────────────────────────── │\n` +
106
+ `│ Session total: ${stats.totalTokens} tokens (${stats.totalCalls} calls)`.padEnd(53) + `│\n` +
107
+ `└──────────────────────────────────────────────────────┘\n`);
108
+ }
109
+ }
110
+ return result;
111
+ }
@@ -0,0 +1,2 @@
1
+ export declare const THOUGHT_POOLS: Record<string, string[]>;
2
+ export declare function getRandomThought(state: string): string | null;