@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
@@ -3,58 +3,84 @@ export async function browserFind(session, options, _config) {
3
3
  if (!query)
4
4
  throw new Error("browser_find requires a query string");
5
5
  const { result } = await session.Runtime.evaluate({
6
- expression: `(function(q, returnAll, maxMatches) {
7
- function norm(s) { return (s || '').toLowerCase().replace(/[.\\u2026\\s]+/g, ' ').trim(); }
8
- var qLow = norm(q);
9
- var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, null, false);
10
- var matchedNodes = [];
11
- var seenElements = new Set();
12
-
13
- while (walker.nextNode()) {
14
- var node = walker.currentNode;
15
- var el = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
16
- if (!el || seenElements.has(el)) continue;
17
-
18
- var text = norm(node.textContent);
19
- var aria = norm(el.getAttribute('aria-label') || el.getAttribute('title') || el.getAttribute('placeholder') || '');
20
-
21
- if ((text && text.includes(qLow)) || (aria && aria.includes(qLow))) {
22
- seenElements.add(el);
23
- matchedNodes.push(el);
24
- if (!returnAll && matchedNodes.length >= 1) break;
25
- if (matchedNodes.length >= maxMatches) break;
26
- }
27
- }
28
-
29
- if (matchedNodes.length === 0) return null;
30
-
31
- var out = matchedNodes.map(function(match, i) {
32
- var r = match.getBoundingClientRect();
33
- var wtId = match.getAttribute('data-wt-id');
34
- var sel = '';
35
- if (wtId) {
36
- sel = '[data-wt-id="' + wtId + '"]';
37
- } else if (match.id) {
38
- sel = '#' + CSS.escape(match.id);
39
- } else {
40
- var tmp = 'wt-find-' + i + '-' + Math.random().toString(36).slice(2,6);
41
- match.setAttribute('data-wt-id', tmp);
42
- sel = '[data-wt-id="' + tmp + '"]';
43
- wtId = tmp;
44
- }
45
- return {
46
- ref: 'w:' + wtId,
47
- label: match.getAttribute('aria-label') || (match.textContent||'').trim().slice(0,80) || q,
48
- tag: match.tagName.toLowerCase(),
49
- x: Math.round(r.left),
50
- y: Math.round(r.top),
51
- width: Math.round(r.width),
52
- height: Math.round(r.height),
53
- selector: sel
54
- };
55
- });
56
-
57
- return JSON.stringify(out);
6
+ expression: `(function(q, returnAll, maxMatches) {
7
+ function norm(s) { return (s || '').toLowerCase().replace(/[.\\u2026\\s]+/g, ' ').trim(); }
8
+ var qLow = norm(q);
9
+ var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, null, false);
10
+ var matchedNodes = [];
11
+ var seenElements = new Set();
12
+
13
+ while (walker.nextNode()) {
14
+ var node = walker.currentNode;
15
+ if (node.nodeType === Node.TEXT_NODE) {
16
+ var t = norm(node.nodeValue);
17
+ if (t && t.includes(qLow)) {
18
+ var p = node.parentElement;
19
+ if (p && !seenElements.has(p)) {
20
+ seenElements.add(p);
21
+ matchedNodes.push(p);
22
+ if (!returnAll && matchedNodes.length >= 1) break;
23
+ if (matchedNodes.length >= maxMatches) break;
24
+ }
25
+ }
26
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
27
+ var el = node;
28
+ if (seenElements.has(el)) continue;
29
+ var aria = norm(el.getAttribute('aria-label') || el.getAttribute('title') || el.getAttribute('placeholder') || el.getAttribute('data-placeholder') || '');
30
+ if (aria && aria.includes(qLow)) {
31
+ seenElements.add(el);
32
+ matchedNodes.push(el);
33
+ if (!returnAll && matchedNodes.length >= 1) break;
34
+ if (matchedNodes.length >= maxMatches) break;
35
+ }
36
+ }
37
+ }
38
+
39
+ if (matchedNodes.length === 0) return null;
40
+
41
+ var out = matchedNodes.map(function(match, i) {
42
+ var r = match.getBoundingClientRect();
43
+ var wtId = match.getAttribute('data-wt-id');
44
+ var sel = '';
45
+ if (wtId) {
46
+ sel = '[data-wt-id="' + wtId + '"]';
47
+ } else if (match.id) {
48
+ sel = '#' + CSS.escape(match.id);
49
+ } else {
50
+ // Construct clean selector path without dirtying the DOM
51
+ var path = [];
52
+ var curr = match;
53
+ while (curr && curr.nodeType === Node.ELEMENT_NODE && curr !== document.body && curr !== document.documentElement) {
54
+ var tag = curr.tagName.toLowerCase();
55
+ if (curr.id) {
56
+ path.unshift('#' + CSS.escape(curr.id));
57
+ break;
58
+ }
59
+ var p = curr.parentElement;
60
+ if (p) {
61
+ var sibs = Array.from(p.children).filter(function(c) { return c.tagName === curr.tagName; });
62
+ if (sibs.length > 1) {
63
+ tag += ':nth-of-type(' + (sibs.indexOf(curr) + 1) + ')';
64
+ }
65
+ }
66
+ path.unshift(tag);
67
+ curr = p;
68
+ }
69
+ sel = path.join(' > ') || match.tagName.toLowerCase();
70
+ }
71
+ return {
72
+ ref: wtId ? ('w:' + wtId) : undefined,
73
+ label: match.getAttribute('aria-label') || (match.textContent||'').trim().slice(0,80) || q,
74
+ tag: match.tagName.toLowerCase(),
75
+ x: Math.round(r.left),
76
+ y: Math.round(r.top),
77
+ width: Math.round(r.width),
78
+ height: Math.round(r.height),
79
+ selector: sel
80
+ };
81
+ });
82
+
83
+ return JSON.stringify(out);
58
84
  })(${JSON.stringify(query)}, ${JSON.stringify(all)}, ${JSON.stringify(limit)})`,
59
85
  returnByValue: true
60
86
  }).catch(() => ({ result: { value: null } }));
@@ -7,37 +7,37 @@ export async function browserHighlight(session, options, _config) {
7
7
  const customColor = options.color;
8
8
  // Inject required keyframes once
9
9
  await session.Runtime.evaluate({
10
- expression: `(function(){
11
- if (!document.getElementById('wt-highlight-styles')) {
12
- var s = document.createElement('style');
13
- s.id = 'wt-highlight-styles';
14
- s.textContent = \`
15
- @keyframes wt-shimmer {
16
- 0% { opacity: 0; background-position: -200% 0; }
17
- 15% { opacity: 0.9; }
18
- 40% { opacity: 0.7; }
19
- 85% { opacity: 0.3; }
20
- 100% { opacity: 0; background-position: 200% 0; }
21
- }
22
- @keyframes wt-consider-pulse {
23
- 0%, 100% { box-shadow: 0 0 0 1px rgba(56,189,248,0.7), 0 0 14px rgba(56,189,248,0.35); opacity: 0.92; }
24
- 50% { box-shadow: 0 0 0 2px rgba(56,189,248,0.95), 0 0 22px rgba(56,189,248,0.6); opacity: 1; }
25
- }
26
- @keyframes wt-target-lock {
27
- 0% { transform: scale(1.05); opacity: 0.5; }
28
- 100% { transform: scale(1); opacity: 1; }
29
- }
30
- @keyframes wt-danger-pulse {
31
- 0%, 100% { box-shadow: 0 0 0 1px rgba(239,68,68,0.7), 0 0 14px rgba(239,68,68,0.35); opacity: 0.92; }
32
- 50% { box-shadow: 0 0 0 2px rgba(239,68,68,0.95), 0 0 22px rgba(239,68,68,0.6); opacity: 1; }
33
- }
34
- @keyframes wt-success-glow {
35
- 0% { opacity: 0.6; box-shadow: 0 0 0 1px rgba(16,185,129,0.7); }
36
- 100% { opacity: 1; box-shadow: 0 0 0 2px rgba(16,185,129,0.9), 0 0 18px rgba(16,185,129,0.45); }
37
- }
38
- \`;
39
- (document.head || document.documentElement).appendChild(s);
40
- }
10
+ expression: `(function(){
11
+ if (!document.getElementById('wt-highlight-styles')) {
12
+ var s = document.createElement('style');
13
+ s.id = 'wt-highlight-styles';
14
+ s.textContent = \`
15
+ @keyframes wt-shimmer {
16
+ 0% { opacity: 0; background-position: -200% 0; }
17
+ 15% { opacity: 0.9; }
18
+ 40% { opacity: 0.7; }
19
+ 85% { opacity: 0.3; }
20
+ 100% { opacity: 0; background-position: 200% 0; }
21
+ }
22
+ @keyframes wt-consider-pulse {
23
+ 0%, 100% { box-shadow: 0 0 0 1px rgba(56,189,248,0.7), 0 0 14px rgba(56,189,248,0.35); opacity: 0.92; }
24
+ 50% { box-shadow: 0 0 0 2px rgba(56,189,248,0.95), 0 0 22px rgba(56,189,248,0.6); opacity: 1; }
25
+ }
26
+ @keyframes wt-target-lock {
27
+ 0% { transform: scale(1.05); opacity: 0.5; }
28
+ 100% { transform: scale(1); opacity: 1; }
29
+ }
30
+ @keyframes wt-danger-pulse {
31
+ 0%, 100% { box-shadow: 0 0 0 1px rgba(239,68,68,0.7), 0 0 14px rgba(239,68,68,0.35); opacity: 0.92; }
32
+ 50% { box-shadow: 0 0 0 2px rgba(239,68,68,0.95), 0 0 22px rgba(239,68,68,0.6); opacity: 1; }
33
+ }
34
+ @keyframes wt-success-glow {
35
+ 0% { opacity: 0.6; box-shadow: 0 0 0 1px rgba(16,185,129,0.7); }
36
+ 100% { opacity: 1; box-shadow: 0 0 0 2px rgba(16,185,129,0.9), 0 0 18px rgba(16,185,129,0.45); }
37
+ }
38
+ \`;
39
+ (document.head || document.documentElement).appendChild(s);
40
+ }
41
41
  })()`,
42
42
  returnByValue: true,
43
43
  }).catch(() => { });
@@ -66,20 +66,20 @@ export async function browserHighlight(session, options, _config) {
66
66
  const badgeHtml = escapedBadge
67
67
  ? `<span style="position:absolute;top:-20px;left:0;background:#09090b;border:1px solid #27272a;color:#f4f4f5;font-size:10px;font-family:-apple-system,BlinkMacSystemFont,\\'Segoe UI\\',sans-serif;font-weight:500;padding:1px 6px;border-radius:4px;white-space:nowrap;pointer-events:none;box-shadow:0 2px 6px rgba(0,0,0,0.5);">${escapedBadge}</span>`
68
68
  : '';
69
- return `(function(){
70
- var div = document.createElement('div');
71
- div.setAttribute('data-wt-ignore', 'true');
72
- div.style.cssText = 'position:fixed;left:${x}px;top:${y}px;width:${w}px;height:${h}px;z-index:2147483647;pointer-events:none;${styleCss}';
73
- if (${JSON.stringify(badgeHtml)}) {
74
- div.innerHTML = ${JSON.stringify(badgeHtml)};
75
- }
76
- (document.getElementById('Weavetab-root')?.shadowRoot || document.getElementById('Weavetab-root') || document.body).appendChild(div);
77
- setTimeout(function(){
78
- div.style.transition = 'opacity 0.2s ease-out';
79
- div.style.opacity = '0';
80
- setTimeout(function(){ if(div.parentNode) div.parentNode.removeChild(div); }, 220);
81
- }, ${duration});
82
- return true;
69
+ return `(function(){
70
+ var div = document.createElement('div');
71
+ div.setAttribute('data-wt-ignore', 'true');
72
+ div.style.cssText = 'position:fixed;left:${x}px;top:${y}px;width:${w}px;height:${h}px;z-index:2147483647;pointer-events:none;${styleCss}';
73
+ if (${JSON.stringify(badgeHtml)}) {
74
+ div.innerHTML = ${JSON.stringify(badgeHtml)};
75
+ }
76
+ (document.getElementById('Weavetab-root')?.shadowRoot || document.getElementById('Weavetab-root') || document.body).appendChild(div);
77
+ setTimeout(function(){
78
+ div.style.transition = 'opacity 0.2s ease-out';
79
+ div.style.opacity = '0';
80
+ setTimeout(function(){ if(div.parentNode) div.parentNode.removeChild(div); }, 220);
81
+ }, ${duration});
82
+ return true;
83
83
  })()`;
84
84
  }
85
85
  // Draw overlay by querying selector
@@ -90,28 +90,28 @@ export async function browserHighlight(session, options, _config) {
90
90
  const badgeHtml = escapedBadge
91
91
  ? `<span style="position:absolute;top:-20px;left:0;background:#09090b;border:1px solid #27272a;color:#f4f4f5;font-size:10px;font-family:-apple-system,BlinkMacSystemFont,\\'Segoe UI\\',sans-serif;font-weight:500;padding:1px 6px;border-radius:4px;white-space:nowrap;pointer-events:none;box-shadow:0 2px 6px rgba(0,0,0,0.5);">${escapedBadge}</span>`
92
92
  : '';
93
- return `(function(){
94
- var el;
95
- try { el = document.querySelector('${escaped}'); } catch(e) {}
96
- if (!el && window.__Weavetab_shadowQuery) {
97
- try { el = window.__Weavetab_shadowQuery('${escaped}'); } catch(e) {}
98
- }
99
- if (!el) return false;
100
- var r = el.getBoundingClientRect();
101
- if (r.width === 0 && r.height === 0) return false;
102
- var div = document.createElement('div');
103
- div.setAttribute('data-wt-ignore', 'true');
104
- div.style.cssText = 'position:fixed;left:'+r.left+'px;top:'+r.top+'px;width:'+r.width+'px;height:'+r.height+'px;z-index:2147483647;pointer-events:none;${styleCss}';
105
- if (${JSON.stringify(badgeHtml)}) {
106
- div.innerHTML = ${JSON.stringify(badgeHtml)};
107
- }
108
- (document.getElementById('Weavetab-root')?.shadowRoot || document.getElementById('Weavetab-root') || document.body).appendChild(div);
109
- setTimeout(function(){
110
- div.style.transition = 'opacity 0.2s ease-out';
111
- div.style.opacity = '0';
112
- setTimeout(function(){ if(div.parentNode) div.parentNode.removeChild(div); }, 220);
113
- }, ${duration});
114
- return true;
93
+ return `(function(){
94
+ var el;
95
+ try { el = document.querySelector('${escaped}'); } catch(e) {}
96
+ if (!el && window.__Weavetab_shadowQuery) {
97
+ try { el = window.__Weavetab_shadowQuery('${escaped}'); } catch(e) {}
98
+ }
99
+ if (!el) return false;
100
+ var r = el.getBoundingClientRect();
101
+ if (r.width === 0 && r.height === 0) return false;
102
+ var div = document.createElement('div');
103
+ div.setAttribute('data-wt-ignore', 'true');
104
+ div.style.cssText = 'position:fixed;left:'+r.left+'px;top:'+r.top+'px;width:'+r.width+'px;height:'+r.height+'px;z-index:2147483647;pointer-events:none;${styleCss}';
105
+ if (${JSON.stringify(badgeHtml)}) {
106
+ div.innerHTML = ${JSON.stringify(badgeHtml)};
107
+ }
108
+ (document.getElementById('Weavetab-root')?.shadowRoot || document.getElementById('Weavetab-root') || document.body).appendChild(div);
109
+ setTimeout(function(){
110
+ div.style.transition = 'opacity 0.2s ease-out';
111
+ div.style.opacity = '0';
112
+ setTimeout(function(){ if(div.parentNode) div.parentNode.removeChild(div); }, 220);
113
+ }, ${duration});
114
+ return true;
115
115
  })()`;
116
116
  }
117
117
  async function trySelector(sel, badgeLabel) {
@@ -9,24 +9,20 @@ export async function browserInspect(session, options, _config) {
9
9
  }
10
10
  const { DOM, CSS, DOMDebugger } = session;
11
11
  await DOM.enable();
12
- const doc = await DOM.getDocument({ depth: -1 }).catch(() => null);
12
+ await DOM.getDocument({ depth: 0 }).catch(() => null);
13
13
  await CSS.enable().catch(() => { });
14
14
  let resolvedNodeId = nodeId || null;
15
15
  // Step 1: Resolve a live nodeId from any input
16
16
  if (!resolvedNodeId && ref) {
17
17
  const active = sessionRegistry.getActive(getConfigAgentId(_config));
18
18
  if (active) {
19
- // getCachedActionMap returns null when the DOM has mutated since the last
20
- // read (lastMutationTime > lastReadTime). On a cache miss, rebuild the map
21
- // so ref IDs remain resolvable after any DOM change instead of silently
22
- // falling through to "Could not resolve element to a node ID".
23
19
  let map = getCachedActionMap(active.targetId);
24
20
  if (!map) {
25
21
  try {
26
22
  map = await buildActionMap(session, { lite: true }, active.targetId);
27
23
  cacheActionMap(active.targetId, map);
28
24
  }
29
- catch { /* best-effort; will fall through to selector strategies */ }
25
+ catch { /* best-effort */ }
30
26
  }
31
27
  if (map) {
32
28
  const el = map.elements.find((e) => e.id === ref || e.id.endsWith(ref.startsWith("w:") ? ref.slice(2) : ref));
@@ -38,7 +34,6 @@ export async function browserInspect(session, options, _config) {
38
34
  if (!resolvedNodeId && el?.selector) {
39
35
  selector = el.selector;
40
36
  }
41
- // Also try data-wt-id selector directly when backendNodeId lookup fails
42
37
  if (!resolvedNodeId && ref) {
43
38
  const rawId = ref.startsWith("w:") ? ref.slice(2) : ref;
44
39
  selector = selector || `[data-wt-id="${rawId}"]`;
@@ -48,14 +43,14 @@ export async function browserInspect(session, options, _config) {
48
43
  }
49
44
  if (!resolvedNodeId && selector) {
50
45
  const res = await session.Runtime.evaluate({
51
- expression: `(function(sel) {
52
- var els = document.querySelectorAll(sel);
53
- for (var i = 0; i < els.length; i++) {
54
- if (!els[i].closest('#wt-shadow-host, [data-wt-ignore]')) {
55
- return els[i];
56
- }
57
- }
58
- return els[0] || null;
46
+ expression: `(function(sel) {
47
+ var els = document.querySelectorAll(sel);
48
+ for (var i = 0; i < els.length; i++) {
49
+ if (!els[i].closest('#wt-shadow-host, [data-wt-ignore]')) {
50
+ return els[i];
51
+ }
52
+ }
53
+ return els[0] || null;
59
54
  })(${JSON.stringify(selector)})`,
60
55
  });
61
56
  if (res.result?.objectId) {
@@ -69,26 +64,60 @@ export async function browserInspect(session, options, _config) {
69
64
  }
70
65
  // Step 2: Fetch box model, computed styles, and event listeners in parallel
71
66
  const boxModel = await DOM.getBoxModel({ nodeId: resolvedNodeId }).catch(() => null);
67
+ function reconstructShorthand(prefix, styles) {
68
+ const t = styles[`${prefix}-top`];
69
+ const r = styles[`${prefix}-right`];
70
+ const b = styles[`${prefix}-bottom`];
71
+ const l = styles[`${prefix}-left`];
72
+ if (t === undefined && r === undefined && b === undefined && l === undefined)
73
+ return undefined;
74
+ if (t === b && r === l)
75
+ return t === r ? t : `${t} ${r}`;
76
+ if (r === l)
77
+ return `${t} ${r} ${b}`;
78
+ return `${t} ${r} ${b} ${l}`;
79
+ }
72
80
  // Try CSS.getComputedStyleForNode first (CDP-native), fall back to Runtime.evaluate
73
81
  let computedStylesData = null;
74
82
  const cssResult = await CSS.getComputedStyleForNode({ nodeId: resolvedNodeId }).catch(() => null);
75
83
  if (cssResult?.computedStyle) {
76
- const INTERESTING = ['display', 'position', 'width', 'height', 'margin', 'padding', 'color', 'background-color', 'font-size', 'visibility', 'opacity', 'z-index', 'pointer-events'];
77
- computedStylesData = cssResult.computedStyle
84
+ const INTERESTING = [
85
+ 'display', 'position', 'width', 'height', 'color', 'background-color', 'font-size', 'visibility', 'opacity', 'z-index', 'pointer-events',
86
+ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
87
+ 'padding-top', 'padding-right', 'padding-bottom', 'padding-left'
88
+ ];
89
+ const rawStyles = cssResult.computedStyle
78
90
  .filter((s) => INTERESTING.includes(s.name))
79
91
  .reduce((acc, curr) => ({ ...acc, [curr.name]: curr.value }), {});
92
+ const margin = reconstructShorthand('margin', rawStyles);
93
+ const padding = reconstructShorthand('padding', rawStyles);
94
+ computedStylesData = {
95
+ display: rawStyles.display,
96
+ position: rawStyles.position,
97
+ width: rawStyles.width,
98
+ height: rawStyles.height,
99
+ ...(margin ? { margin } : {}),
100
+ ...(padding ? { padding } : {}),
101
+ color: rawStyles.color,
102
+ 'background-color': rawStyles['background-color'],
103
+ 'font-size': rawStyles['font-size'],
104
+ visibility: rawStyles.visibility,
105
+ opacity: rawStyles.opacity,
106
+ 'z-index': rawStyles['z-index'],
107
+ 'pointer-events': rawStyles['pointer-events']
108
+ };
80
109
  }
81
110
  if (!computedStylesData && selector) {
82
111
  // Fallback: use window.getComputedStyle via Runtime.evaluate
83
112
  const { result: fallbackRes } = await session.Runtime.evaluate({
84
- expression: `(function(sel) {
85
- var el = document.querySelector(sel);
86
- if (!el) return null;
87
- var s = window.getComputedStyle(el);
88
- var KEYS = ['display','position','width','height','margin','padding','color','background-color','font-size','visibility','opacity','z-index','pointer-events'];
89
- var r = {};
90
- for (var i = 0; i < KEYS.length; i++) r[KEYS[i]] = s.getPropertyValue(KEYS[i]);
91
- return JSON.stringify(r);
113
+ expression: `(function(sel) {
114
+ var el = document.querySelector(sel);
115
+ if (!el) return null;
116
+ var s = window.getComputedStyle(el);
117
+ var KEYS = ['display','position','width','height','margin','padding','color','background-color','font-size','visibility','opacity','z-index','pointer-events'];
118
+ var r = {};
119
+ for (var i = 0; i < KEYS.length; i++) r[KEYS[i]] = s.getPropertyValue(KEYS[i]);
120
+ return JSON.stringify(r);
92
121
  })(${JSON.stringify(selector)})`,
93
122
  returnByValue: true,
94
123
  }).catch(() => ({ result: { value: null } }));
package/dist/tools/key.js CHANGED
@@ -90,41 +90,41 @@ export async function weaveKey(session, args, _config) {
90
90
  if (key === "Enter") {
91
91
  // SPA Fallback: direct form submit + submit button click for React/Vue/Google
92
92
  // This is needed because Input.dispatchKeyEvent alone doesn't trigger SPA form submission
93
- await session.Runtime.evaluate({ expression: `
94
- (function(){
95
- try {
96
- var el = document.activeElement;
97
- if (!el || !el.tagName) return;
98
-
99
- // Focus the element first to make sure it's active
100
- if (typeof el.focus === 'function') el.focus();
101
-
102
- // 1. Try native form submit (Google search, DuckDuckGo, etc.)
103
- var form = el.closest('form');
104
- if (form) {
105
- var submitBtn = form.querySelector('input[type="submit"], button[type="submit"]');
106
- if (submitBtn && submitBtn.offsetParent !== null) { submitBtn.click(); return; }
107
- try { form.submit(); return; } catch(e) {}
108
- }
109
-
110
- // 2. Google-specific: find name="q" input and submit its form
111
- var q = document.querySelector('input[name="q"], textarea[name="q"]');
112
- if (q) {
113
- var qForm = q.closest('form');
114
- if (qForm) { try { qForm.submit(); return; } catch(e) {} }
115
- }
116
-
117
- // 3. Last resort: find any visible submit/search button near the active element
118
- var parent = el.parentElement;
119
- while (parent && parent.tagName !== 'BODY') {
120
- var btns = parent.querySelectorAll('button, input[type="submit"], input[type="button"]');
121
- for (var i = 0; i < btns.length; i++) {
122
- if (btns[i].offsetParent !== null && btns[i].getBoundingClientRect().width > 0) { btns[i].click(); return; }
123
- }
124
- parent = parent.parentElement;
125
- }
126
- } catch(e) {}
127
- })();
93
+ await session.Runtime.evaluate({ expression: `
94
+ (function(){
95
+ try {
96
+ var el = document.activeElement;
97
+ if (!el || !el.tagName) return;
98
+
99
+ // Focus the element first to make sure it's active
100
+ if (typeof el.focus === 'function') el.focus();
101
+
102
+ // 1. Try native form submit (Google search, DuckDuckGo, etc.)
103
+ var form = el.closest('form');
104
+ if (form) {
105
+ var submitBtn = form.querySelector('input[type="submit"], button[type="submit"]');
106
+ if (submitBtn && submitBtn.offsetParent !== null) { submitBtn.click(); return; }
107
+ try { form.submit(); return; } catch(e) {}
108
+ }
109
+
110
+ // 2. Google-specific: find name="q" input and submit its form
111
+ var q = document.querySelector('input[name="q"], textarea[name="q"]');
112
+ if (q) {
113
+ var qForm = q.closest('form');
114
+ if (qForm) { try { qForm.submit(); return; } catch(e) {} }
115
+ }
116
+
117
+ // 3. Last resort: find any visible submit/search button near the active element
118
+ var parent = el.parentElement;
119
+ while (parent && parent.tagName !== 'BODY') {
120
+ var btns = parent.querySelectorAll('button, input[type="submit"], input[type="button"]');
121
+ for (var i = 0; i < btns.length; i++) {
122
+ if (btns[i].offsetParent !== null && btns[i].getBoundingClientRect().width > 0) { btns[i].click(); return; }
123
+ }
124
+ parent = parent.parentElement;
125
+ }
126
+ } catch(e) {}
127
+ })();
128
128
  ` }).catch(() => { });
129
129
  }
130
130
  await session.Input.dispatchKeyEvent({ type: "keyUp", key: effectiveKey, modifiers: modMask, windowsVirtualKeyCode: effectiveKey === "Enter" ? 13 : undefined, nativeVirtualKeyCode: effectiveKey === "Enter" ? 13 : undefined });
@@ -144,6 +144,13 @@ export async function weaveKey(session, args, _config) {
144
144
  const activeSession = sessionRegistry.getActive(getConfigAgentId(_config));
145
145
  if (activeSession)
146
146
  activeSession.url = postUrl;
147
+ const titleRes = await session.Runtime.evaluate({ expression: "document.title", returnByValue: true }).catch(() => null);
148
+ if (titleRes?.result?.value) {
149
+ postTitle = String(titleRes.result.value);
150
+ }
151
+ else if (activeSession?.title) {
152
+ postTitle = activeSession.title;
153
+ }
147
154
  }
148
155
  catch { /* ignore */ }
149
156
  const urlChanged = postUrl !== urlBefore;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Weavetab — tools/navigate.ts
2
+ * Weavetab — tools/navigate.ts
3
3
  * URL navigation with domain blocklist enforcement and post-navigation DOM stability wait.
4
4
  * Weavetab by fy2ne
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Weavetab — tools/navigate.ts
2
+ * Weavetab — tools/navigate.ts
3
3
  * URL navigation with domain blocklist enforcement and post-navigation DOM stability wait.
4
4
  * Weavetab by fy2ne
5
5
  */
@@ -15,8 +15,8 @@ import { sessionRegistry } from "../state/session.js";
15
15
  export async function weaveNavigate(session, url, config, targetId = "default", force = false, fast = false, appName) {
16
16
  logDebug(`[weaveNavigate] Attempting navigation to: ${url}`);
17
17
  let parsed;
18
- if (url.startsWith('Weavetab://')) {
19
- const page = url.replace('Weavetab://', '').split('?')[0] || 'dashboard';
18
+ if (url.toLowerCase().startsWith('weavetab://')) {
19
+ const page = url.slice('weavetab://'.length).split('?')[0] || 'dashboard';
20
20
  try {
21
21
  const { getFromExtension } = await import("../cdp/helpers.js");
22
22
  const extUrl = await getFromExtension(session, { type: 'RESOLVE_EXTENSION_URL', page });
@@ -24,11 +24,11 @@ export async function weaveNavigate(session, url, config, targetId = "default",
24
24
  parsed = new URL(extUrl);
25
25
  }
26
26
  else {
27
- return { success: false, error_code: "EXTENSION_URL_FAILED", message: `Could not resolve Weavetab://${page}` };
27
+ return { success: false, error_code: "EXTENSION_URL_FAILED", message: `Could not resolve weavetab://${page}` };
28
28
  }
29
29
  }
30
30
  catch {
31
- return { success: false, error_code: "EXTENSION_NOT_AVAILABLE", message: "Extension runtime not available for Weavetab:// navigation" };
31
+ return { success: false, error_code: "EXTENSION_NOT_AVAILABLE", message: "Extension runtime not available for weavetab:// navigation" };
32
32
  }
33
33
  }
34
34
  else {
@@ -71,10 +71,10 @@ export async function weaveNavigate(session, url, config, targetId = "default",
71
71
  }
72
72
  }
73
73
  // Extension pages: open in new tab instead of navigating current tab
74
- // (chrome-extension:// pages use a different process context — Page.navigate
74
+ // (chrome-extension:// pages use a different process context — Page.navigate
75
75
  // can break the CDP session or not fire loadEventFired properly)
76
76
  if (parsed.protocol === 'chrome-extension:') {
77
- logDebug(`[weaveNavigate] Extension URL detected — opening in new tab: ${parsed.href}`);
77
+ logDebug(`[weaveNavigate] Extension URL detected — opening in new tab: ${parsed.href}`);
78
78
  const { sendToExtension } = await import("../cdp/helpers.js");
79
79
  await sendToExtension(session, { type: 'Weavetab_STATE', hud: { action: `opening extension page...` } });
80
80
  const { WeavetabOpen } = await import("./tabs.js");
@@ -112,20 +112,20 @@ export async function weaveNavigate(session, url, config, targetId = "default",
112
112
  let isAnchor = false;
113
113
  try {
114
114
  const res = await session.Runtime.evaluate({
115
- expression: `new Promise((resolve) => {
116
- let done = false;
117
- const finish = (val) => { if (!done) { done = true; resolve(val); } };
118
- setTimeout(() => finish(false), 30);
119
- try {
120
- const browserAPI = typeof browser !== 'undefined' ? browser : (typeof chrome !== 'undefined' ? chrome : null);
121
- if (browserAPI && browserAPI.runtime && browserAPI.runtime.id) {
122
- browserAPI.runtime.sendMessage({ type: 'GET_ANCHOR_STATUS' }, (response) => {
123
- finish(response?.isAnchor || false);
124
- });
125
- } else {
126
- finish(false);
127
- }
128
- } catch(e) { finish(false); }
115
+ expression: `new Promise((resolve) => {
116
+ let done = false;
117
+ const finish = (val) => { if (!done) { done = true; resolve(val); } };
118
+ setTimeout(() => finish(false), 30);
119
+ try {
120
+ const browserAPI = typeof browser !== 'undefined' ? browser : (typeof chrome !== 'undefined' ? chrome : null);
121
+ if (browserAPI && browserAPI.runtime && browserAPI.runtime.id) {
122
+ browserAPI.runtime.sendMessage({ type: 'GET_ANCHOR_STATUS' }, (response) => {
123
+ finish(response?.isAnchor || false);
124
+ });
125
+ } else {
126
+ finish(false);
127
+ }
128
+ } catch(e) { finish(false); }
129
129
  })`,
130
130
  awaitPromise: true,
131
131
  returnByValue: true
@@ -171,20 +171,20 @@ export async function weaveNavigate(session, url, config, targetId = "default",
171
171
  session.Page.getFrameTree().catch(() => ({ frameTree: { frame: { url: parsed.href } } })),
172
172
  session.Runtime.evaluate({ expression: 'document.title', returnByValue: true }).catch(() => null),
173
173
  session.Runtime.evaluate({
174
- expression: `
175
- (function(){
176
- var selectors = [
177
- '[id*="cookie"] button','[class*="cookie"] button',
178
- '[id*="consent"] button','[class*="consent"] button',
179
- '[id*="gdpr"] button','[class*="gdpr"] button',
180
- '[aria-label*="Accept"]','[aria-label*="Agree"]',
181
- 'button[data-cookiebanner]'
182
- ];
183
- for(var i=0;i<selectors.length;i++){
184
- var el=document.querySelector(selectors[i]);
185
- if(el){try{el.click();}catch(e){}break;}
186
- }
187
- })()
174
+ expression: `
175
+ (function(){
176
+ var selectors = [
177
+ '[id*="cookie"] button','[class*="cookie"] button',
178
+ '[id*="consent"] button','[class*="consent"] button',
179
+ '[id*="gdpr"] button','[class*="gdpr"] button',
180
+ '[aria-label*="Accept"]','[aria-label*="Agree"]',
181
+ 'button[data-cookiebanner]'
182
+ ];
183
+ for(var i=0;i<selectors.length;i++){
184
+ var el=document.querySelector(selectors[i]);
185
+ if(el){try{el.click();}catch(e){}break;}
186
+ }
187
+ })()
188
188
  `
189
189
  }).catch(() => { })
190
190
  ]);