@weavetab/mcp 2.5.0 → 2.5.1

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 (168) hide show
  1. package/AGENTS.md +49 -49
  2. package/ARCHITECTURE.md +590 -590
  3. package/LICENSE +216 -216
  4. package/README.md +269 -269
  5. package/SECURITY.md +207 -207
  6. package/TROUBLESHOOTING.md +373 -365
  7. package/dist/anticaptcha/detector.js +395 -395
  8. package/dist/anticaptcha/solver.js +130 -130
  9. package/dist/cdp/bridge.js +73 -73
  10. package/dist/cdp/connector.js +46 -22
  11. package/dist/cdp/extension.js +34 -34
  12. package/dist/cdp/helpers.js +174 -174
  13. package/dist/cdp/pruner.js +195 -195
  14. package/dist/cdp/ref_cache.js +66 -66
  15. package/dist/cdp/security.js +10 -10
  16. package/dist/cdp/verify.js +57 -57
  17. package/dist/cdp/walker.js +563 -525
  18. package/dist/cli/plugin.js +26 -3
  19. package/dist/config/loader.d.ts +0 -3
  20. package/dist/config/loader.js +0 -9
  21. package/dist/index.js +0 -4
  22. package/dist/intelligence/intent.js +81 -81
  23. package/dist/intelligence/sessionMemory.js +2 -2
  24. package/dist/overlay/ghost.js +22 -22
  25. package/dist/overlay/injector.js +89 -89
  26. package/dist/plugin/extension_bridge.js +54 -54
  27. package/dist/plugin/interface.d.ts +7 -0
  28. package/dist/plugin/loader.js +3 -4
  29. package/dist/plugin/schema.d.ts +11 -0
  30. package/dist/plugin/schema.js +59 -0
  31. package/dist/security/guard.js +18 -18
  32. package/dist/sensors/actionability.js +167 -167
  33. package/dist/sensors/guard.js +29 -29
  34. package/dist/sensors/network.js +15 -17
  35. package/dist/server.d.ts +1 -1
  36. package/dist/server.js +173 -144
  37. package/dist/state/delta.js +6 -7
  38. package/dist/tools/automation.js +85 -85
  39. package/dist/tools/canvas.js +48 -25
  40. package/dist/tools/checkpoint.js +94 -35
  41. package/dist/tools/click.js +52 -41
  42. package/dist/tools/clipboard.js +80 -74
  43. package/dist/tools/design_extract.js +441 -441
  44. package/dist/tools/dialog.js +13 -13
  45. package/dist/tools/emulation.d.ts +2 -0
  46. package/dist/tools/emulation.js +7 -0
  47. package/dist/tools/fill.js +344 -347
  48. package/dist/tools/find.js +78 -52
  49. package/dist/tools/highlight.js +67 -67
  50. package/dist/tools/inspect.js +54 -25
  51. package/dist/tools/key.js +42 -35
  52. package/dist/tools/navigate.d.ts +1 -1
  53. package/dist/tools/navigate.js +35 -35
  54. package/dist/tools/office/parse.js +62 -18
  55. package/dist/tools/pdf.d.ts +9 -0
  56. package/dist/tools/pdf.js +7 -4
  57. package/dist/tools/performance.d.ts +11 -4
  58. package/dist/tools/performance.js +94 -42
  59. package/dist/tools/performance_test.d.ts +2 -2
  60. package/dist/tools/performance_test.js +69 -69
  61. package/dist/tools/pointer.js +116 -116
  62. package/dist/tools/read.js +99 -67
  63. package/dist/tools/recording.js +9 -0
  64. package/dist/tools/scrape.js +146 -146
  65. package/dist/tools/screenshot.d.ts +2 -0
  66. package/dist/tools/screenshot.js +46 -4
  67. package/dist/tools/scroll.d.ts +3 -1
  68. package/dist/tools/scroll.js +13 -15
  69. package/dist/tools/select.d.ts +3 -0
  70. package/dist/tools/select.js +131 -124
  71. package/dist/tools/snapshot.js +8 -6
  72. package/dist/tools/storage.d.ts +5 -1
  73. package/dist/tools/storage.js +16 -0
  74. package/dist/tools/tabs.d.ts +7 -5
  75. package/dist/tools/tabs.js +79 -26
  76. package/dist/tools/thought.js +8 -8
  77. package/dist/tools/type.js +274 -274
  78. package/dist/tools/type_secret.js +23 -23
  79. package/dist/tools/upload.js +3 -3
  80. package/dist/tools/video_compiler.js +9 -0
  81. package/dist/tools/wait.js +35 -35
  82. package/dist/version.d.ts +1 -1
  83. package/dist/version.js +1 -1
  84. package/docs/DOCUMENTATION.md +583 -585
  85. package/docs/PLUGINS.md +139 -121
  86. package/docs/TOOLS.md +3 -4
  87. package/docs/architecture/blind-injection.md +83 -83
  88. package/docs/architecture/overview.md +49 -49
  89. package/docs/architecture/security.md +36 -36
  90. package/docs/architecture/transport.md +37 -37
  91. package/docs/cli/cli-commands.md +50 -50
  92. package/docs/cli/cli-flags.md +28 -28
  93. package/docs/cli/cli-scripting.md +35 -35
  94. package/docs/configuration/config-locations.md +23 -23
  95. package/docs/configuration/configuration.md +39 -27
  96. package/docs/configuration/env-variables.md +19 -19
  97. package/docs/configuration/folders.md +62 -55
  98. package/docs/desktop-automation/electron-apps.md +225 -214
  99. package/docs/get-started/installation.md +1 -1
  100. package/docs/get-started/introduction.md +60 -60
  101. package/docs/get-started/quickstart.md +2 -2
  102. package/docs/get-started/setup-wizard.md +27 -27
  103. package/docs/intelligence/site-profiles.md +151 -151
  104. package/docs/tools/tools.md +582 -631
  105. package/docs/troubleshooting/trouble-browser.md +27 -27
  106. package/docs/troubleshooting/trouble-loop.md +31 -31
  107. package/ext-dist/background.js +415 -415
  108. package/ext-dist/content.js +2527 -2527
  109. package/ext-dist/dashboard.html +583 -583
  110. package/ext-dist/hud/hud.js +3 -3
  111. package/ext-dist/hud/index.html +20 -20
  112. package/ext-dist/manifest.json +73 -73
  113. package/ext-dist/styles.css +223 -223
  114. package/mcp.json +796 -805
  115. package/package.json +118 -118
  116. package/server.json +23 -23
  117. package/dist/cdp/walker.test.d.ts +0 -2
  118. package/dist/cdp/walker.test.js +0 -172
  119. package/dist/intelligence/sessionMemory.test.d.ts +0 -2
  120. package/dist/intelligence/sessionMemory.test.js +0 -62
  121. package/dist/intelligence/trail.test.d.ts +0 -2
  122. package/dist/intelligence/trail.test.js +0 -110
  123. package/dist/state/cache.test.d.ts +0 -2
  124. package/dist/state/cache.test.js +0 -76
  125. package/dist/state/delta.test.d.ts +0 -2
  126. package/dist/state/delta.test.js +0 -279
  127. package/dist/state/groups.d.ts +0 -15
  128. package/dist/state/groups.js +0 -80
  129. package/dist/tools/accessibility.d.ts +0 -14
  130. package/dist/tools/accessibility.js +0 -32
  131. package/dist/tools/ask.d.ts +0 -14
  132. package/dist/tools/ask.js +0 -49
  133. package/dist/tools/click_and_wait.d.ts +0 -33
  134. package/dist/tools/click_and_wait.js +0 -149
  135. package/dist/tools/drag.d.ts +0 -15
  136. package/dist/tools/drag.js +0 -29
  137. package/dist/tools/geo.d.ts +0 -19
  138. package/dist/tools/geo.js +0 -29
  139. package/dist/tools/github/analyze.d.ts +0 -4
  140. package/dist/tools/github/analyze.js +0 -113
  141. package/dist/tools/github/cache.d.ts +0 -21
  142. package/dist/tools/github/cache.js +0 -28
  143. package/dist/tools/github/index.d.ts +0 -19
  144. package/dist/tools/github/index.js +0 -40
  145. package/dist/tools/github/issues.d.ts +0 -9
  146. package/dist/tools/github/issues.js +0 -88
  147. package/dist/tools/github/pr.d.ts +0 -5
  148. package/dist/tools/github/pr.js +0 -88
  149. package/dist/tools/github/rateLimiter.d.ts +0 -4
  150. package/dist/tools/github/rateLimiter.js +0 -46
  151. package/dist/tools/github/read.d.ts +0 -34
  152. package/dist/tools/github/read.js +0 -74
  153. package/dist/tools/github/repoContext.d.ts +0 -20
  154. package/dist/tools/github/repoContext.js +0 -129
  155. package/dist/tools/hover.d.ts +0 -19
  156. package/dist/tools/hover.js +0 -57
  157. package/dist/tools/integration.test.d.ts +0 -2
  158. package/dist/tools/integration.test.js +0 -96
  159. package/dist/tools/macro_compiler.d.ts +0 -7
  160. package/dist/tools/macro_compiler.js +0 -82
  161. package/dist/tools/mouse.d.ts +0 -21
  162. package/dist/tools/mouse.js +0 -62
  163. package/dist/tools/response.d.ts +0 -129
  164. package/dist/tools/response.js +0 -5
  165. package/dist/tools/wait_for.d.ts +0 -23
  166. package/dist/tools/wait_for.js +0 -30
  167. package/dist/tools/windows.d.ts +0 -22
  168. package/dist/tools/windows.js +0 -57
@@ -41,52 +41,52 @@ async function solveSliderDrag(session, detection, t0) {
41
41
  try {
42
42
  // Locate slider thumb and track
43
43
  const sliderInfo = await session.Runtime.evaluate({
44
- expression: `(function() {
45
- // Priority selectors for slider thumb
46
- var thumbSels = [
47
- '.geetest_slider_button', '.geetest_drag_thumb', '.geetest-slider-btn',
48
- '.slide-verify-slider', '[class*="slider-btn"]', '[class*="slider-thumb"]',
49
- '[class*="drag-btn"]', '[class*="slide-btn"]', '[class*="slider_button"]',
50
- '.nc-lang-cnt [class*="btn"]', '.btn_slide', '.handler',
51
- '[class*="verify"][class*="btn"]',
52
- ];
53
- var trackSels = [
54
- '.geetest_slider_bar', '.geetest_track', '.slide-verify-bar',
55
- '[class*="slider-bar"]', '[class*="track"]', '[class*="slider-wrap"]',
56
- '.nc-tpl [class*="bg"]', '[class*="verify"][class*="bar"]',
57
- ];
58
-
59
- var thumb = null, track = null;
60
-
61
- // Also try the provided selector
62
- ${detection.selector ? `thumb = document.querySelector(${JSON.stringify(detection.selector)});` : ''}
63
-
64
- if (!thumb) {
65
- for (var i = 0; i < thumbSels.length; i++) {
66
- var el = document.querySelector(thumbSels[i]);
67
- if (el && el.getBoundingClientRect().width > 0) {
68
- thumb = el;
69
- break;
70
- }
71
- }
72
- }
73
- for (var j = 0; j < trackSels.length; j++) {
74
- var el2 = document.querySelector(trackSels[j]);
75
- if (el2 && el2.getBoundingClientRect().width > 20) {
76
- track = el2;
77
- break;
78
- }
79
- }
80
-
81
- if (!thumb) return null;
82
- var tr = thumb.getBoundingClientRect();
83
- var trackWidth = track ? track.getBoundingClientRect().width : window.innerWidth * 0.6;
84
- return {
85
- thumbX: Math.round(tr.left + tr.width / 2),
86
- thumbY: Math.round(tr.top + tr.height / 2),
87
- thumbWidth: Math.round(tr.width),
88
- trackWidth: Math.round(trackWidth),
89
- };
44
+ expression: `(function() {
45
+ // Priority selectors for slider thumb
46
+ var thumbSels = [
47
+ '.geetest_slider_button', '.geetest_drag_thumb', '.geetest-slider-btn',
48
+ '.slide-verify-slider', '[class*="slider-btn"]', '[class*="slider-thumb"]',
49
+ '[class*="drag-btn"]', '[class*="slide-btn"]', '[class*="slider_button"]',
50
+ '.nc-lang-cnt [class*="btn"]', '.btn_slide', '.handler',
51
+ '[class*="verify"][class*="btn"]',
52
+ ];
53
+ var trackSels = [
54
+ '.geetest_slider_bar', '.geetest_track', '.slide-verify-bar',
55
+ '[class*="slider-bar"]', '[class*="track"]', '[class*="slider-wrap"]',
56
+ '.nc-tpl [class*="bg"]', '[class*="verify"][class*="bar"]',
57
+ ];
58
+
59
+ var thumb = null, track = null;
60
+
61
+ // Also try the provided selector
62
+ ${detection.selector ? `thumb = document.querySelector(${JSON.stringify(detection.selector)});` : ''}
63
+
64
+ if (!thumb) {
65
+ for (var i = 0; i < thumbSels.length; i++) {
66
+ var el = document.querySelector(thumbSels[i]);
67
+ if (el && el.getBoundingClientRect().width > 0) {
68
+ thumb = el;
69
+ break;
70
+ }
71
+ }
72
+ }
73
+ for (var j = 0; j < trackSels.length; j++) {
74
+ var el2 = document.querySelector(trackSels[j]);
75
+ if (el2 && el2.getBoundingClientRect().width > 20) {
76
+ track = el2;
77
+ break;
78
+ }
79
+ }
80
+
81
+ if (!thumb) return null;
82
+ var tr = thumb.getBoundingClientRect();
83
+ var trackWidth = track ? track.getBoundingClientRect().width : window.innerWidth * 0.6;
84
+ return {
85
+ thumbX: Math.round(tr.left + tr.width / 2),
86
+ thumbY: Math.round(tr.top + tr.height / 2),
87
+ thumbWidth: Math.round(tr.width),
88
+ trackWidth: Math.round(trackWidth),
89
+ };
90
90
  })()`,
91
91
  returnByValue: true,
92
92
  });
@@ -203,31 +203,31 @@ async function solvePressAndHold(session, detection, t0) {
203
203
  const holdMs = detection.holdDurationMs || 2500;
204
204
  // Locate the hold button
205
205
  const btnInfo = await session.Runtime.evaluate({
206
- expression: `(function() {
207
- var sels = [
208
- ${detection.selector ? JSON.stringify(detection.selector) + ',' : ''}
209
- '#px-captcha', '._pxCaptcha',
210
- '[class*="press-hold"]', '[class*="hold-btn"]', '[class*="presshold"]',
211
- 'button[class*="verify"]',
212
- ];
213
- for (var i = 0; i < sels.length; i++) {
214
- var el = document.querySelector(sels[i]);
215
- if (el) {
216
- var r = el.getBoundingClientRect();
217
- if (r.width > 0 && r.height > 0) {
218
- return { x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) };
219
- }
220
- }
221
- }
222
- // Last resort: find any visible button with "hold" in text
223
- var btns = document.querySelectorAll('button, [role="button"]');
224
- for (var j = 0; j < btns.length; j++) {
225
- if (/hold|press/i.test(btns[j].textContent || '')) {
226
- var br = btns[j].getBoundingClientRect();
227
- if (br.width > 0) return { x: Math.round(br.left+br.width/2), y: Math.round(br.top+br.height/2) };
228
- }
229
- }
230
- return null;
206
+ expression: `(function() {
207
+ var sels = [
208
+ ${detection.selector ? JSON.stringify(detection.selector) + ',' : ''}
209
+ '#px-captcha', '._pxCaptcha',
210
+ '[class*="press-hold"]', '[class*="hold-btn"]', '[class*="presshold"]',
211
+ 'button[class*="verify"]',
212
+ ];
213
+ for (var i = 0; i < sels.length; i++) {
214
+ var el = document.querySelector(sels[i]);
215
+ if (el) {
216
+ var r = el.getBoundingClientRect();
217
+ if (r.width > 0 && r.height > 0) {
218
+ return { x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) };
219
+ }
220
+ }
221
+ }
222
+ // Last resort: find any visible button with "hold" in text
223
+ var btns = document.querySelectorAll('button, [role="button"]');
224
+ for (var j = 0; j < btns.length; j++) {
225
+ if (/hold|press/i.test(btns[j].textContent || '')) {
226
+ var br = btns[j].getBoundingClientRect();
227
+ if (br.width > 0) return { x: Math.round(br.left+br.width/2), y: Math.round(br.top+br.height/2) };
228
+ }
229
+ }
230
+ return null;
231
231
  })()`,
232
232
  returnByValue: true,
233
233
  });
@@ -293,16 +293,16 @@ async function solveCheckbox(session, detection, t0) {
293
293
  try {
294
294
  // Find the iframe and click the checkbox inside it via coordinates
295
295
  const frameInfo = await session.Runtime.evaluate({
296
- expression: `(function() {
297
- var frames = document.querySelectorAll('iframe[src*="recaptcha"], iframe[src*="hcaptcha"]');
298
- for (var i = 0; i < frames.length; i++) {
299
- var r = frames[i].getBoundingClientRect();
300
- if (r.width > 0 && r.height > 0) {
301
- // Checkbox is typically at 20px from left, center vertically
302
- return { x: Math.round(r.left + 20), y: Math.round(r.top + r.height/2) };
303
- }
304
- }
305
- return null;
296
+ expression: `(function() {
297
+ var frames = document.querySelectorAll('iframe[src*="recaptcha"], iframe[src*="hcaptcha"]');
298
+ for (var i = 0; i < frames.length; i++) {
299
+ var r = frames[i].getBoundingClientRect();
300
+ if (r.width > 0 && r.height > 0) {
301
+ // Checkbox is typically at 20px from left, center vertically
302
+ return { x: Math.round(r.left + 20), y: Math.round(r.top + r.height/2) };
303
+ }
304
+ }
305
+ return null;
306
306
  })()`,
307
307
  returnByValue: true,
308
308
  });
@@ -351,17 +351,17 @@ async function solveInvisible(session, detection, t0) {
351
351
  // Invisible CAPTCHAs score based on user interaction signals.
352
352
  // Simulate natural page interaction to boost the score.
353
353
  await session.Runtime.evaluate({
354
- expression: `(function() {
355
- // Scroll slightly to simulate reading
356
- window.scrollBy({ top: 120, behavior: 'smooth' });
357
- // Move mouse (won't dispatch but registers user-intent in page context)
358
- document.dispatchEvent(new MouseEvent('mousemove', { bubbles: true, clientX: 400, clientY: 300 }));
359
- // Trigger focus/blur cycle on any form input
360
- var inputs = document.querySelectorAll('input:not([type="hidden"]), textarea');
361
- if (inputs.length > 0) {
362
- inputs[0].focus();
363
- setTimeout(function() { inputs[0].blur(); }, 200);
364
- }
354
+ expression: `(function() {
355
+ // Scroll slightly to simulate reading
356
+ window.scrollBy({ top: 120, behavior: 'smooth' });
357
+ // Move mouse (won't dispatch but registers user-intent in page context)
358
+ document.dispatchEvent(new MouseEvent('mousemove', { bubbles: true, clientX: 400, clientY: 300 }));
359
+ // Trigger focus/blur cycle on any form input
360
+ var inputs = document.querySelectorAll('input:not([type="hidden"]), textarea');
361
+ if (inputs.length > 0) {
362
+ inputs[0].focus();
363
+ setTimeout(function() { inputs[0].blur(); }, 200);
364
+ }
365
365
  })()`,
366
366
  returnByValue: false,
367
367
  });
@@ -369,14 +369,14 @@ async function solveInvisible(session, detection, t0) {
369
369
  // Try to programmatically trigger grecaptcha execute (v3)
370
370
  if (detection.type === "recaptcha_v3") {
371
371
  await session.Runtime.evaluate({
372
- expression: `(function() {
373
- try {
374
- if (window.grecaptcha && window.grecaptcha.execute) {
375
- window.grecaptcha.ready(function() {
376
- window.grecaptcha.execute().catch(function(){});
377
- });
378
- }
379
- } catch(e) {}
372
+ expression: `(function() {
373
+ try {
374
+ if (window.grecaptcha && window.grecaptcha.execute) {
375
+ window.grecaptcha.ready(function() {
376
+ window.grecaptcha.execute().catch(function(){});
377
+ });
378
+ }
379
+ } catch(e) {}
380
380
  })()`,
381
381
  returnByValue: false,
382
382
  });
@@ -400,31 +400,31 @@ async function solveInvisible(session, detection, t0) {
400
400
  async function solveMathCaptcha(session, detection, t0) {
401
401
  try {
402
402
  const result = await session.Runtime.evaluate({
403
- expression: `(function(sel) {
404
- var container = document.querySelector(sel) || document.body;
405
- var text = container.textContent || '';
406
- // Match expressions like "3 + 7 =", "12 - 4 =", "6 × 3", "8 ÷ 2"
407
- var m = text.match(/(\\d+)\\s*([+\\-*×x÷/])\\s*(\\d+)/);
408
- if (!m) return null;
409
- var a = parseInt(m[1]), op = m[2], b = parseInt(m[3]);
410
- var ans;
411
- if (op === '+') ans = a + b;
412
- else if (op === '-') ans = a - b;
413
- else if (op === '*' || op === '×' || op === 'x') ans = a * b;
414
- else if (op === '/' || op === '÷') ans = Math.floor(a / b);
415
- else return null;
416
- // Fill the answer input
417
- var inp = container.querySelector('input[type="text"], input[type="number"]');
418
- if (!inp) inp = document.querySelector('input[name*="captcha"], input[id*="captcha"]');
419
- if (inp) {
420
- inp.focus();
421
- var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
422
- if (nativeInputValueSetter) nativeInputValueSetter.call(inp, String(ans));
423
- inp.dispatchEvent(new Event('input', { bubbles: true }));
424
- inp.dispatchEvent(new Event('change', { bubbles: true }));
425
- return { solved: true, answer: ans };
426
- }
427
- return { solved: false, answer: ans };
403
+ expression: `(function(sel) {
404
+ var container = document.querySelector(sel) || document.body;
405
+ var text = container.textContent || '';
406
+ // Match expressions like "3 + 7 =", "12 - 4 =", "6 × 3", "8 ÷ 2"
407
+ var m = text.match(/(\\d+)\\s*([+\\-*×x÷/])\\s*(\\d+)/);
408
+ if (!m) return null;
409
+ var a = parseInt(m[1]), op = m[2], b = parseInt(m[3]);
410
+ var ans;
411
+ if (op === '+') ans = a + b;
412
+ else if (op === '-') ans = a - b;
413
+ else if (op === '*' || op === '×' || op === 'x') ans = a * b;
414
+ else if (op === '/' || op === '÷') ans = Math.floor(a / b);
415
+ else return null;
416
+ // Fill the answer input
417
+ var inp = container.querySelector('input[type="text"], input[type="number"]');
418
+ if (!inp) inp = document.querySelector('input[name*="captcha"], input[id*="captcha"]');
419
+ if (inp) {
420
+ inp.focus();
421
+ var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
422
+ if (nativeInputValueSetter) nativeInputValueSetter.call(inp, String(ans));
423
+ inp.dispatchEvent(new Event('input', { bubbles: true }));
424
+ inp.dispatchEvent(new Event('change', { bubbles: true }));
425
+ return { solved: true, answer: ans };
426
+ }
427
+ return { solved: false, answer: ans };
428
428
  })(${JSON.stringify(detection.selector || 'body')})`,
429
429
  returnByValue: true,
430
430
  });
@@ -493,11 +493,11 @@ async function checkCaptchaGone(session, detection) {
493
493
  if (!detection.selector)
494
494
  return null;
495
495
  const check = await session.Runtime.evaluate({
496
- expression: `(function(sel) {
497
- var el = document.querySelector(sel);
498
- if (!el) return false; // gone = solved
499
- var r = el.getBoundingClientRect();
500
- return r.width > 0 && r.height > 0 && r.top < window.innerHeight;
496
+ expression: `(function(sel) {
497
+ var el = document.querySelector(sel);
498
+ if (!el) return false; // gone = solved
499
+ var r = el.getBoundingClientRect();
500
+ return r.width > 0 && r.height > 0 && r.top < window.innerHeight;
501
501
  })(${JSON.stringify(detection.selector)})`,
502
502
  returnByValue: true,
503
503
  });
@@ -312,79 +312,79 @@ function recordLaunchSuccess(profileDir) {
312
312
  launchFailureCount.delete(`${profileDir}_time`);
313
313
  }
314
314
  // ─── Stealth script: injected before any page JS runs ─────────────────────────
315
- const STEALTH_SCRIPT = `
316
- (function() {
317
- 'use strict';
318
-
319
- // 1. Spoof navigator.webdriver
320
- Object.defineProperty(navigator, 'webdriver', {
321
- get: () => undefined,
322
- configurable: true,
323
- });
324
-
325
- // 2. Remove chrome automation props
326
- if (window.navigator.plugins.length === 0) {
327
- Object.defineProperty(navigator, 'plugins', {
328
- get: () => [1, 2, 3, 4, 5],
329
- configurable: true,
330
- });
331
- }
332
-
333
- // 3. Spoof navigator.languages (defaults to en-US if unset)
334
- if (!navigator.languages || navigator.languages.length === 0) {
335
- Object.defineProperty(navigator, 'languages', {
336
- get: () => ['en-US', 'en'],
337
- configurable: true,
338
- });
339
- }
340
-
341
- // 4. Spoof Chrome runtime
342
- window.chrome = window.chrome || {};
343
- window.chrome.runtime = window.chrome.runtime || {};
344
-
345
- // 5. Randomize hardwareConcurrency (4–8 cores)
346
- Object.defineProperty(navigator, 'hardwareConcurrency', {
347
- get: () => 4 + Math.floor(Math.random() * 4),
348
- configurable: true,
349
- });
350
-
351
- // 6. Randomize deviceMemory (4, 8, or 12 GB, weighted toward 8)
352
- Object.defineProperty(navigator, 'deviceMemory', {
353
- get: () => [4, 8, 8, 8, 12][Math.floor(Math.random() * 5)],
354
- configurable: true,
355
- });
356
-
357
- // 7. WebGL vendor/renderer spoofing — only spoof the two info params,
358
- // pass everything else through untouched. Wrapped in try/catch so a
359
- // missing WebGL context never breaks the page.
360
- try {
361
- var _origGetParam = WebGLRenderingContext.prototype.getParameter;
362
- WebGLRenderingContext.prototype.getParameter = function(p) {
363
- if (p === 37445) return 'Google Inc. (Intel)';
364
- if (p === 37446) {
365
- return navigator.platform.indexOf('Mac') === 0
366
- ? 'ANGLE (Intel, Intel(R) Iris(TM) Plus Graphics 640, OpenGL 4.1)'
367
- : 'ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)';
368
- }
369
- return _origGetParam.apply(this, arguments);
370
- };
371
- if (typeof WebGL2RenderingContext !== 'undefined') {
372
- var _origGetParam2 = WebGL2RenderingContext.prototype.getParameter;
373
- WebGL2RenderingContext.prototype.getParameter = function(p) {
374
- if (p === 37445) return 'Google Inc. (Intel)';
375
- if (p === 37446) {
376
- return navigator.platform.indexOf('Mac') === 0
377
- ? 'ANGLE (Intel, Intel(R) Iris(TM) Plus Graphics 640, OpenGL 4.1)'
378
- : 'ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)';
379
- }
380
- return _origGetParam2.apply(this, arguments);
381
- };
382
- }
383
- } catch(e) {}
384
-
385
- // NOTE: Function.prototype.toString proxy removed — it was wrapping
386
- // every toString call globally and could break page rendering.
387
- })();
315
+ const STEALTH_SCRIPT = `
316
+ (function() {
317
+ 'use strict';
318
+
319
+ // 1. Spoof navigator.webdriver
320
+ Object.defineProperty(navigator, 'webdriver', {
321
+ get: () => undefined,
322
+ configurable: true,
323
+ });
324
+
325
+ // 2. Remove chrome automation props
326
+ if (window.navigator.plugins.length === 0) {
327
+ Object.defineProperty(navigator, 'plugins', {
328
+ get: () => [1, 2, 3, 4, 5],
329
+ configurable: true,
330
+ });
331
+ }
332
+
333
+ // 3. Spoof navigator.languages (defaults to en-US if unset)
334
+ if (!navigator.languages || navigator.languages.length === 0) {
335
+ Object.defineProperty(navigator, 'languages', {
336
+ get: () => ['en-US', 'en'],
337
+ configurable: true,
338
+ });
339
+ }
340
+
341
+ // 4. Spoof Chrome runtime
342
+ window.chrome = window.chrome || {};
343
+ window.chrome.runtime = window.chrome.runtime || {};
344
+
345
+ // 5. Randomize hardwareConcurrency (4–8 cores)
346
+ Object.defineProperty(navigator, 'hardwareConcurrency', {
347
+ get: () => 4 + Math.floor(Math.random() * 4),
348
+ configurable: true,
349
+ });
350
+
351
+ // 6. Randomize deviceMemory (4, 8, or 12 GB, weighted toward 8)
352
+ Object.defineProperty(navigator, 'deviceMemory', {
353
+ get: () => [4, 8, 8, 8, 12][Math.floor(Math.random() * 5)],
354
+ configurable: true,
355
+ });
356
+
357
+ // 7. WebGL vendor/renderer spoofing — only spoof the two info params,
358
+ // pass everything else through untouched. Wrapped in try/catch so a
359
+ // missing WebGL context never breaks the page.
360
+ try {
361
+ var _origGetParam = WebGLRenderingContext.prototype.getParameter;
362
+ WebGLRenderingContext.prototype.getParameter = function(p) {
363
+ if (p === 37445) return 'Google Inc. (Intel)';
364
+ if (p === 37446) {
365
+ return navigator.platform.indexOf('Mac') === 0
366
+ ? 'ANGLE (Intel, Intel(R) Iris(TM) Plus Graphics 640, OpenGL 4.1)'
367
+ : 'ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)';
368
+ }
369
+ return _origGetParam.apply(this, arguments);
370
+ };
371
+ if (typeof WebGL2RenderingContext !== 'undefined') {
372
+ var _origGetParam2 = WebGL2RenderingContext.prototype.getParameter;
373
+ WebGL2RenderingContext.prototype.getParameter = function(p) {
374
+ if (p === 37445) return 'Google Inc. (Intel)';
375
+ if (p === 37446) {
376
+ return navigator.platform.indexOf('Mac') === 0
377
+ ? 'ANGLE (Intel, Intel(R) Iris(TM) Plus Graphics 640, OpenGL 4.1)'
378
+ : 'ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)';
379
+ }
380
+ return _origGetParam2.apply(this, arguments);
381
+ };
382
+ }
383
+ } catch(e) {}
384
+
385
+ // NOTE: Function.prototype.toString proxy removed — it was wrapping
386
+ // every toString call globally and could break page rendering.
387
+ })();
388
388
  `;
389
389
  // ─── Mandatory security flags (always applied, never overridable) ──────────────
390
390
  const MANDATORY_FLAGS = Object.freeze([
@@ -169,12 +169,12 @@ async function initSession(session, targetId, port, config, isElectron) {
169
169
  try {
170
170
  // Check for multiple indicators that extension is loaded
171
171
  const { result: extCheck } = await session.Runtime.evaluate({
172
- expression: `!!(
173
- document.querySelector('weavetab-host') ||
174
- document.getElementById('__Weavetab_cursor_host') ||
175
- document.getElementById('wt-ui-styles') ||
176
- document.querySelector('[data-wt-internal]') ||
177
- window.__wt_chat_queue
172
+ expression: `!!(
173
+ document.querySelector('weavetab-host') ||
174
+ document.getElementById('__Weavetab_cursor_host') ||
175
+ document.getElementById('wt-ui-styles') ||
176
+ document.querySelector('[data-wt-internal]') ||
177
+ window.__wt_chat_queue
178
178
  )`,
179
179
  returnByValue: true,
180
180
  });
@@ -288,14 +288,29 @@ export async function getOrConnect(config, targetApp) {
288
288
  for (let retry = 0; retry < 10; retry++) {
289
289
  try {
290
290
  targets = await withCDPTimeout(CDP.List({ host: "127.0.0.1", port }), 2000, "CDP.List Electron retry");
291
- if (targets.length > 0)
291
+ // Break early if we found a non-splash main window target
292
+ const hasMain = targets.some(t => {
293
+ const u = (t.url || "").toLowerCase();
294
+ const tit = (t.title || "").toLowerCase();
295
+ return !u.includes("splash") && !tit.includes("updater") && !u.startsWith("devtools://");
296
+ });
297
+ if (hasMain || (retry > 4 && targets.length > 0))
292
298
  break;
293
299
  }
294
300
  catch { /* wait */ }
295
301
  await new Promise(r => setTimeout(r, 500));
296
302
  }
297
303
  }
298
- let pageTarget = targets.find(t => t.type === "page" || t.type === "webview" || t.type === "app") ?? targets[0];
304
+ // Filter out splash screens, updater windows, and devtools targets
305
+ const isCandidate = (t) => {
306
+ const u = (t.url || "").toLowerCase();
307
+ const tit = (t.title || "").toLowerCase();
308
+ return !u.includes("splash") && !tit.includes("updater") && !u.startsWith("devtools://");
309
+ };
310
+ let pageTarget = targets.find(t => (t.type === "page" || t.type === "webview" || t.type === "app") && isCandidate(t))
311
+ ?? targets.find(isCandidate)
312
+ ?? targets.find(t => t.type === "page" || t.type === "webview" || t.type === "app")
313
+ ?? targets[0];
299
314
  if (!pageTarget) {
300
315
  throw new Error(`[Weavetab] ✗ No window or webview target found in Electron app "${targetApp}".`);
301
316
  }
@@ -622,7 +637,19 @@ export async function getTabList(agentId, targetApp) {
622
637
  const aid = agentId || getConfigAgentId(config);
623
638
  const bctxId = sessionRegistry.getBrowserContextIdForAgent(aid);
624
639
  return targetInfos
625
- .filter(t => (t.type === "page" || t.type === "webview" || t.type === "app" || t.type === "other" || t.type === "iframe") && (!bctxId || t.browserContextId === bctxId))
640
+ .filter(t => {
641
+ const matchType = (t.type === "page" || t.type === "webview" || t.type === "app" || t.type === "other" || t.type === "iframe");
642
+ const matchCtx = (!bctxId || t.browserContextId === bctxId);
643
+ if (!matchType || !matchCtx)
644
+ return false;
645
+ if (targetApp) {
646
+ const u = (t.url || "").toLowerCase();
647
+ const tit = (t.title || "").toLowerCase();
648
+ if (u.includes("splash") || tit.includes("updater") || u.startsWith("devtools://"))
649
+ return false;
650
+ }
651
+ return true;
652
+ })
626
653
  .map(t => ({
627
654
  id: t.targetId,
628
655
  title: t.title || t.url || t.type,
@@ -679,21 +706,18 @@ export async function connectToTab(targetId, port, agentId, browserContextId, ap
679
706
  }
680
707
  catch { }
681
708
  if (!t) {
682
- try {
683
- const metaSession = await withCDPTimeout(CDP({ host: "127.0.0.1", port: p }), 3000, "connectToTab meta CDP");
684
- const { targetInfos } = await withCDPTimeout(metaSession.Target.getTargets(), 3000, "connectToTab meta getTargets");
685
- await metaSession.close();
686
- const ti = targetInfos.find(item => item.targetId === targetId);
687
- if (ti) {
688
- t = { id: ti.targetId, targetId: ti.targetId, url: ti.url, title: ti.title, type: ti.type };
689
- }
690
- }
691
- catch { }
709
+ throw new Error(`Tab not found: "${targetId}". Check browser_tabs({ action: "list" }) for active IDs.`);
692
710
  }
693
- if (!t) {
694
- t = { id: targetId, targetId, url: "", title: appName || "Tab", type: "page" };
711
+ let session;
712
+ try {
713
+ session = await withCDPTimeout(CDP({ host: "127.0.0.1", port: p, target: targetId }), 5000, "connectToTab CDP");
714
+ }
715
+ catch (err) {
716
+ if (err?.message?.includes("webSocketDebuggerUrl") || err?.message?.includes("Cannot read propert")) {
717
+ throw new Error(`Tab not found or closed: "${targetId}".`);
718
+ }
719
+ throw err;
695
720
  }
696
- const session = await withCDPTimeout(CDP({ host: "127.0.0.1", port: p, target: targetId }), 5000, "connectToTab CDP");
697
721
  session.on("close", () => {
698
722
  logDebug(`[Weavetab CDP] connectToTab session closed (${appName || "browser"}) — unregistering.`);
699
723
  // Cancel this tab's analytics interval so it doesn't outlive the session