@weavetab/mcp 2.5.0-beta.5 → 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 (160) hide show
  1. package/AGENTS.md +49 -49
  2. package/ARCHITECTURE.md +590 -590
  3. package/README.md +216 -100
  4. package/SECURITY.md +207 -207
  5. package/TROUBLESHOOTING.md +373 -365
  6. package/dist/anticaptcha/detector.js +395 -395
  7. package/dist/anticaptcha/solver.js +130 -130
  8. package/dist/cdp/bridge.js +73 -73
  9. package/dist/cdp/connector.js +46 -22
  10. package/dist/cdp/extension.js +34 -34
  11. package/dist/cdp/helpers.js +174 -174
  12. package/dist/cdp/pruner.js +195 -195
  13. package/dist/cdp/ref_cache.js +66 -66
  14. package/dist/cdp/security.js +10 -10
  15. package/dist/cdp/verify.js +57 -57
  16. package/dist/cdp/walker.js +563 -525
  17. package/dist/cli/plugin.js +26 -3
  18. package/dist/config/loader.d.ts +0 -3
  19. package/dist/config/loader.js +0 -9
  20. package/dist/index.js +0 -4
  21. package/dist/intelligence/intent.js +81 -81
  22. package/dist/intelligence/sessionMemory.js +2 -2
  23. package/dist/overlay/ghost.js +22 -22
  24. package/dist/overlay/injector.js +89 -89
  25. package/dist/plugin/extension_bridge.js +54 -54
  26. package/dist/plugin/interface.d.ts +7 -0
  27. package/dist/plugin/loader.js +3 -4
  28. package/dist/plugin/schema.d.ts +11 -0
  29. package/dist/plugin/schema.js +59 -0
  30. package/dist/security/guard.js +18 -18
  31. package/dist/sensors/actionability.js +167 -167
  32. package/dist/sensors/guard.js +29 -29
  33. package/dist/sensors/network.js +15 -17
  34. package/dist/server.d.ts +1 -1
  35. package/dist/server.js +173 -144
  36. package/dist/state/delta.js +6 -7
  37. package/dist/tools/automation.js +85 -85
  38. package/dist/tools/canvas.js +48 -25
  39. package/dist/tools/checkpoint.js +94 -35
  40. package/dist/tools/click.js +52 -41
  41. package/dist/tools/clipboard.js +80 -74
  42. package/dist/tools/design_extract.js +441 -441
  43. package/dist/tools/dialog.js +13 -13
  44. package/dist/tools/emulation.d.ts +2 -0
  45. package/dist/tools/emulation.js +7 -0
  46. package/dist/tools/fill.js +344 -347
  47. package/dist/tools/find.js +78 -52
  48. package/dist/tools/highlight.js +67 -67
  49. package/dist/tools/inspect.js +54 -25
  50. package/dist/tools/key.js +42 -35
  51. package/dist/tools/navigate.d.ts +1 -1
  52. package/dist/tools/navigate.js +35 -35
  53. package/dist/tools/office/parse.js +62 -18
  54. package/dist/tools/pdf.d.ts +9 -0
  55. package/dist/tools/pdf.js +7 -4
  56. package/dist/tools/performance.d.ts +11 -4
  57. package/dist/tools/performance.js +94 -42
  58. package/dist/tools/performance_test.d.ts +2 -2
  59. package/dist/tools/performance_test.js +69 -69
  60. package/dist/tools/pointer.js +116 -116
  61. package/dist/tools/read.js +99 -67
  62. package/dist/tools/recording.js +9 -0
  63. package/dist/tools/scrape.js +146 -146
  64. package/dist/tools/screenshot.d.ts +2 -0
  65. package/dist/tools/screenshot.js +46 -4
  66. package/dist/tools/scroll.d.ts +3 -1
  67. package/dist/tools/scroll.js +13 -15
  68. package/dist/tools/select.d.ts +3 -0
  69. package/dist/tools/select.js +131 -124
  70. package/dist/tools/snapshot.js +8 -6
  71. package/dist/tools/storage.d.ts +5 -1
  72. package/dist/tools/storage.js +16 -0
  73. package/dist/tools/tabs.d.ts +7 -5
  74. package/dist/tools/tabs.js +79 -26
  75. package/dist/tools/thought.js +8 -8
  76. package/dist/tools/type.js +274 -274
  77. package/dist/tools/type_secret.js +23 -23
  78. package/dist/tools/upload.js +3 -3
  79. package/dist/tools/video_compiler.js +9 -0
  80. package/dist/tools/wait.js +35 -35
  81. package/dist/version.d.ts +1 -1
  82. package/dist/version.js +1 -1
  83. package/docs/DOCUMENTATION.md +583 -585
  84. package/docs/PLUGINS.md +139 -121
  85. package/docs/TOOLS.md +3 -4
  86. package/docs/architecture/blind-injection.md +83 -83
  87. package/docs/architecture/overview.md +49 -49
  88. package/docs/configuration/configuration.md +39 -27
  89. package/docs/configuration/folders.md +62 -55
  90. package/docs/desktop-automation/electron-apps.md +225 -214
  91. package/docs/get-started/installation.md +1 -1
  92. package/docs/get-started/introduction.md +60 -60
  93. package/docs/get-started/quickstart.md +2 -2
  94. package/docs/get-started/setup-wizard.md +1 -1
  95. package/docs/intelligence/site-profiles.md +151 -151
  96. package/docs/tools/tools.md +582 -631
  97. package/docs/troubleshooting/trouble-loop.md +31 -31
  98. package/ext-dist/background.js +415 -415
  99. package/ext-dist/content.js +2527 -2527
  100. package/ext-dist/dashboard.html +583 -583
  101. package/ext-dist/hud/hud.js +3 -3
  102. package/ext-dist/hud/index.html +20 -20
  103. package/ext-dist/manifest.json +73 -73
  104. package/ext-dist/styles.css +223 -223
  105. package/mcp.json +796 -805
  106. package/package.json +8 -8
  107. package/server.json +23 -23
  108. package/smithery.yaml +7 -11
  109. package/dist/cdp/walker.test.d.ts +0 -2
  110. package/dist/cdp/walker.test.js +0 -172
  111. package/dist/intelligence/sessionMemory.test.d.ts +0 -2
  112. package/dist/intelligence/sessionMemory.test.js +0 -62
  113. package/dist/intelligence/trail.test.d.ts +0 -2
  114. package/dist/intelligence/trail.test.js +0 -110
  115. package/dist/state/cache.test.d.ts +0 -2
  116. package/dist/state/cache.test.js +0 -76
  117. package/dist/state/delta.test.d.ts +0 -2
  118. package/dist/state/delta.test.js +0 -279
  119. package/dist/state/groups.d.ts +0 -15
  120. package/dist/state/groups.js +0 -80
  121. package/dist/tools/accessibility.d.ts +0 -14
  122. package/dist/tools/accessibility.js +0 -32
  123. package/dist/tools/ask.d.ts +0 -14
  124. package/dist/tools/ask.js +0 -49
  125. package/dist/tools/click_and_wait.d.ts +0 -33
  126. package/dist/tools/click_and_wait.js +0 -149
  127. package/dist/tools/drag.d.ts +0 -15
  128. package/dist/tools/drag.js +0 -29
  129. package/dist/tools/geo.d.ts +0 -19
  130. package/dist/tools/geo.js +0 -29
  131. package/dist/tools/github/analyze.d.ts +0 -4
  132. package/dist/tools/github/analyze.js +0 -113
  133. package/dist/tools/github/cache.d.ts +0 -21
  134. package/dist/tools/github/cache.js +0 -28
  135. package/dist/tools/github/index.d.ts +0 -19
  136. package/dist/tools/github/index.js +0 -40
  137. package/dist/tools/github/issues.d.ts +0 -9
  138. package/dist/tools/github/issues.js +0 -88
  139. package/dist/tools/github/pr.d.ts +0 -5
  140. package/dist/tools/github/pr.js +0 -88
  141. package/dist/tools/github/rateLimiter.d.ts +0 -4
  142. package/dist/tools/github/rateLimiter.js +0 -46
  143. package/dist/tools/github/read.d.ts +0 -34
  144. package/dist/tools/github/read.js +0 -74
  145. package/dist/tools/github/repoContext.d.ts +0 -20
  146. package/dist/tools/github/repoContext.js +0 -129
  147. package/dist/tools/hover.d.ts +0 -19
  148. package/dist/tools/hover.js +0 -57
  149. package/dist/tools/integration.test.d.ts +0 -2
  150. package/dist/tools/integration.test.js +0 -96
  151. package/dist/tools/macro_compiler.d.ts +0 -7
  152. package/dist/tools/macro_compiler.js +0 -82
  153. package/dist/tools/mouse.d.ts +0 -21
  154. package/dist/tools/mouse.js +0 -62
  155. package/dist/tools/response.d.ts +0 -129
  156. package/dist/tools/response.js +0 -5
  157. package/dist/tools/wait_for.d.ts +0 -23
  158. package/dist/tools/wait_for.js +0 -30
  159. package/dist/tools/windows.d.ts +0 -22
  160. package/dist/tools/windows.js +0 -57
@@ -43,6 +43,29 @@ function runCommand(cmd, cmdArgs, cwd = process.cwd()) {
43
43
  function runNpmCommand(cmdArgs, cwd = process.cwd()) {
44
44
  return runCommand("npm", cmdArgs, cwd);
45
45
  }
46
+ /**
47
+ * Resolve a human-readable author from a manifest. Handles every shape the
48
+ * schema allows: a plain `author` string, an `author` object, an `author`
49
+ * array, or the richer `authors[]` array of strings/objects.
50
+ */
51
+ function resolveManifestAuthor(manifest, fallback) {
52
+ const pick = (value) => {
53
+ if (typeof value === "string" && value.trim())
54
+ return value.trim();
55
+ if (Array.isArray(value)) {
56
+ for (const entry of value) {
57
+ const name = pick(entry);
58
+ if (name)
59
+ return name;
60
+ }
61
+ }
62
+ else if (value && typeof value === "object" && typeof value.name === "string" && value.name.trim()) {
63
+ return value.name.trim();
64
+ }
65
+ return null;
66
+ };
67
+ return pick(manifest?.author) || pick(manifest?.authors) || fallback;
68
+ }
46
69
  // ---------------------------------------------------------------------------
47
70
  // 1. ADD / INSTALL PLUGIN WITH DISAMBIGUATION
48
71
  // ---------------------------------------------------------------------------
@@ -193,7 +216,7 @@ export async function runPluginAdd(inputName, args = []) {
193
216
  `${pc.bold("Plugin Details:")}`,
194
217
  ` ${pc.dim("Name:")} ${manifest.name || selectedPkg}`,
195
218
  ` ${pc.dim("Version:")} ${manifest.version || "1.0.0"}`,
196
- ` ${pc.dim("Author:")} ${manifest.author || "Community"}`,
219
+ ` ${pc.dim("Author:")} ${resolveManifestAuthor(manifest, "Community")}`,
197
220
  ` ${pc.dim("Trust Tier:")} ${trust.badge}`,
198
221
  ` ${pc.dim("Description:")} ${manifest.description || "No description provided"}`,
199
222
  ];
@@ -298,7 +321,7 @@ export async function runPluginList() {
298
321
  const m = pInfo.manifest;
299
322
  const toolCount = m.tools?.length ?? 0;
300
323
  console.log(`${trust.badge} ${pc.bold(pc.cyan(pInfo.packageName))} ${pc.dim(`v${m.version || "1.0.0"}`)}`);
301
- console.log(` ${pc.dim("Author:")} ${m.author || "Unknown"}`);
324
+ console.log(` ${pc.dim("Author:")} ${resolveManifestAuthor(m, "Unknown")}`);
302
325
  console.log(` ${pc.dim("Description:")} ${m.description || "(none)"}`);
303
326
  console.log(` ${pc.dim("Tools:")} ${toolCount} tool(s) registered`);
304
327
  if (m.tools && m.tools.length > 0) {
@@ -490,7 +513,7 @@ export async function runPluginCli(args) {
490
513
  console.log(` weavetab plugin <command> [options]`);
491
514
  console.log();
492
515
  console.log(pc.bold("COMMANDS"));
493
- console.log(` ${pc.cyan("add <pkg|path>")} Install a plugin by npm name or local path (e.g. @fy2ne/wt-youtube, ./my-plugin)`);
516
+ console.log(` ${pc.cyan("add <pkg|path>")} Install a plugin by npm name or local path (e.g. @acme/weavetab-plugin, ./my-plugin)`);
494
517
  console.log(` ${pc.cyan("browse")} Interactive terminal explorer to browse & 1-click install`);
495
518
  console.log(` ${pc.cyan("search [query]")} Search plugins across official registry & npm`);
496
519
  console.log(` ${pc.cyan("list")} List all installed plugins and their registered tools`);
@@ -39,7 +39,6 @@ export interface Config {
39
39
  actionabilityTimeoutMs: number;
40
40
  maxTabs: number;
41
41
  maxActionsPerMinute: number;
42
- githubCacheTtlMs: number;
43
42
  refCacheTtlMs: number;
44
43
  downloadDir: string;
45
44
  pdfDir: string;
@@ -115,7 +114,6 @@ export declare function getConfigSessionTimeout(config: Config): number;
115
114
  export declare function getConfigNavigationTimeout(config: Config): number;
116
115
  export declare function getConfigIdleTimeout(config: Config): number;
117
116
  export declare function getConfigActionabilityTimeoutMs(config: Config): number;
118
- export declare function getConfigGithubCacheTtl(config: Config): number;
119
117
  export declare function getConfigRefCacheTtl(config: Config): number;
120
118
  export declare function getConfigDevMode(config: Config): boolean;
121
119
  export declare function getConfigApps(config: Config): Record<string, ElectronAppConfig> | undefined;
@@ -127,7 +125,6 @@ export declare function getElectronAppNames(config?: Config): string[];
127
125
  export declare function getApps(config?: Config): Record<string, ElectronAppConfig>;
128
126
  export declare function getElectronApps(config?: Config): Record<string, ElectronAppConfig>;
129
127
  export declare function getConfigNavigationTimeoutMs(config: Config): number;
130
- export declare function getConfigGithubCacheTtlMs(config: Config): number;
131
128
  export declare function getConfigRefCacheTtlMs(config: Config): number;
132
129
  export declare function getSystemDir(subdir: string): string;
133
130
  export declare function getSystemAppDir(appName: string): string;
@@ -47,7 +47,6 @@ export const DEFAULT_CONFIG = {
47
47
  actionabilityTimeoutMs: 300,
48
48
  maxTabs: 10,
49
49
  maxActionsPerMinute: 60,
50
- githubCacheTtlMs: 30 * 60 * 1000,
51
50
  refCacheTtlMs: 30_000,
52
51
  downloadDir: "",
53
52
  pdfDir: "",
@@ -103,7 +102,6 @@ export function migrateToSimple(sectioned) {
103
102
  actionabilityTimeoutMs: sectioned.performance?.timeouts?.actionability || 500,
104
103
  maxTabs: sectioned.performance?.limits?.maxTabs || 10,
105
104
  maxActionsPerMinute: sectioned.performance?.limits?.maxActionsPerMinute || 60,
106
- githubCacheTtlMs: sectioned.performance?.cache?.githubTtlMs || 30 * 60 * 1000,
107
105
  refCacheTtlMs: sectioned.performance?.cache?.refCacheTtlMs || 30_000,
108
106
  downloadDir: sectioned.paths?.downloads || "",
109
107
  pdfDir: sectioned.paths?.pdfs || "",
@@ -307,7 +305,6 @@ export function validateConfigInternal(raw) {
307
305
  actionabilityTimeoutMs: validateField("actionabilityTimeoutMs", raw.actionabilityTimeoutMs, isNum, d.actionabilityTimeoutMs, v => v >= 50 && v <= 15000),
308
306
  maxTabs: validateField("maxTabs", raw.maxTabs, isNum, d.maxTabs, v => v >= 1 && v <= 100),
309
307
  maxActionsPerMinute: validateField("maxActionsPerMinute", raw.maxActionsPerMinute, isNum, d.maxActionsPerMinute, v => v >= 1 && v <= 600),
310
- githubCacheTtlMs: validateField("githubCacheTtlMs", raw.githubCacheTtlMs, isNum, d.githubCacheTtlMs, v => v >= 0),
311
308
  refCacheTtlMs: validateField("refCacheTtlMs", raw.refCacheTtlMs, isNum, d.refCacheTtlMs, v => v >= 1000 && v <= 300_000),
312
309
  downloadDir,
313
310
  pdfDir: safePathField("pdfDir", raw.pdfDir),
@@ -676,9 +673,6 @@ export function getConfigIdleTimeout(config) {
676
673
  export function getConfigActionabilityTimeoutMs(config) {
677
674
  return config.actionabilityTimeoutMs;
678
675
  }
679
- export function getConfigGithubCacheTtl(config) {
680
- return config.githubCacheTtlMs;
681
- }
682
676
  export function getConfigRefCacheTtl(config) {
683
677
  return config.refCacheTtlMs;
684
678
  }
@@ -723,9 +717,6 @@ export function getElectronApps(config) {
723
717
  export function getConfigNavigationTimeoutMs(config) {
724
718
  return config.navigationTimeout;
725
719
  }
726
- export function getConfigGithubCacheTtlMs(config) {
727
- return config.githubCacheTtlMs;
728
- }
729
720
  export function getConfigRefCacheTtlMs(config) {
730
721
  return config.refCacheTtlMs;
731
722
  }
package/dist/index.js CHANGED
@@ -208,7 +208,6 @@ async function main() {
208
208
  }
209
209
  getSystemDir("logs");
210
210
  getSystemDir("memory");
211
- getSystemDir("profiles");
212
211
  }
213
212
  catch (err) {
214
213
  process.stderr.write("[Weavetab] Warning: Failed to lazily initialize directories " + err + "\n");
@@ -493,8 +492,6 @@ async function main() {
493
492
  console.log(boxen(pc.cyan("SECTION C: DEVELOPER & TELEMETRY"), { padding: 1, borderStyle: 'round', borderColor: 'cyan' }));
494
493
  if ((await run([
495
494
  S.cf("Send anonymous telemetry?", "telemetry", false),
496
- S.tx("GitHub cache TTL (ms)", "githubCacheTtlMs", "1800000", (v) => { const n = parseInt(v ?? ""); if (isNaN(n) || n < 0)
497
- return "Positive integer."; }),
498
495
  ])) === "back")
499
496
  process.exit(0);
500
497
  }
@@ -564,7 +561,6 @@ async function main() {
564
561
  actionabilityTimeout: parseInt(a.actionabilityTimeout) || 500,
565
562
  refCacheTtlMs: parseInt(a.refCacheTtlMs) || 30000,
566
563
  telemetry: a.telemetry || false,
567
- githubCacheTtlMs: parseInt(a.githubCacheTtlMs) || 1800000,
568
564
  downloadDir: a.downloadDir || "",
569
565
  pdfDir: a.pdfDir || "",
570
566
  snapshotDir: a.snapshotDir || "",
@@ -35,87 +35,87 @@ export async function classifyTarget(session, selector) {
35
35
  }
36
36
  try {
37
37
  const { result } = await session.Runtime.evaluate({
38
- expression: `(function(sel) {
39
- try {
40
- var el = document.querySelector(sel);
41
- if (!el) return JSON.stringify({ error: 'not_found' });
42
-
43
- var tag = el.tagName.toLowerCase();
44
- var typeAttr = (el.getAttribute('type') || 'text').toLowerCase();
45
- var role = el.getAttribute('role') || '';
46
- var isControlled = false;
47
-
48
- // Detect React/Vue controlled components
49
- if ((el as any)._reactInternalFiber || (el as any)._reactRootContainer ||
50
- (el as any).__vueApp__ || (el as any).__VUE__ ||
51
- el.hasAttribute('data-reactroot')) {
52
- isControlled = true;
53
- }
54
-
55
- var classification: any = {
56
- type: tag,
57
- interactionExpected: 'click',
58
- successCondition: 'element_clicked',
59
- fallbackStrategies: [],
60
- isControlled: isControlled,
61
- complexity: 'simple'
62
- };
63
-
64
- // Determine interaction type based on element
65
- if (tag === 'input') {
66
- if (typeAttr === 'checkbox' || typeAttr === 'radio') {
67
- classification.interactionExpected = 'check';
68
- classification.successCondition = 'checked_state_changed';
69
- classification.fallbackStrategies = ['click', 'property_set'];
70
- } else if (typeAttr === 'file') {
71
- classification.interactionExpected = 'upload';
72
- classification.successCondition = 'file_selected';
73
- classification.fallbackStrategies = ['click', 'direct_upload'];
74
- } else if (typeAttr === 'submit' || typeAttr === 'button') {
75
- classification.interactionExpected = 'click';
76
- classification.successCondition = 'form_submitted_or_clicked';
77
- classification.fallbackStrategies = ['click', 'form_submit'];
78
- } else {
79
- classification.interactionExpected = 'type';
80
- classification.successCondition = 'value_changed';
81
- classification.fallbackStrategies = ['native_setter', 'react_setter', 'dispatch_events'];
82
- classification.complexity = isControlled ? 'complex' : 'simple';
83
- }
84
- } else if (tag === 'textarea') {
85
- classification.interactionExpected = 'type';
86
- classification.successCondition = 'value_changed';
87
- classification.fallbackStrategies = ['native_setter', 'react_setter', 'dispatch_events'];
88
- classification.complexity = isControlled ? 'complex' : 'simple';
89
- } else if (tag === 'select') {
90
- classification.interactionExpected = 'select';
91
- classification.successCondition = 'selection_changed';
92
- classification.fallbackStrategies = ['property_set', 'click_option'];
93
- classification.complexity = isControlled ? 'complex' : 'simple';
94
- } else if (tag === 'button' || role === 'button') {
95
- classification.interactionExpected = 'click';
96
- classification.successCondition = 'clicked';
97
- classification.fallbackStrategies = ['click', 'keyboard_enter'];
98
- } else if (tag === 'a') {
99
- classification.interactionExpected = 'click';
100
- classification.successCondition = 'navigated';
101
- classification.fallbackStrategies = ['click', 'direct_navigate'];
102
- } else if (tag === 'div' || tag === 'span') {
103
- if (role === 'textbox' || role === 'combobox' || (el as any).isContentEditable) {
104
- classification.interactionExpected = 'type';
105
- classification.successCondition = 'text_changed';
106
- classification.fallbackStrategies = ['text_content_set', 'dispatch_events'];
107
- classification.complexity = 'complex';
108
- } else {
109
- classification.interactionExpected = 'click';
110
- classification.successCondition = 'clicked';
111
- classification.fallbackStrategies = ['click'];
112
- }
113
- }
114
-
115
- return JSON.stringify(classification);
116
- } catch(e) {
117
- return JSON.stringify({ error: (e as Error).message });
118
- }
38
+ expression: `(function(sel) {
39
+ try {
40
+ var el = document.querySelector(sel);
41
+ if (!el) return JSON.stringify({ error: 'not_found' });
42
+
43
+ var tag = el.tagName.toLowerCase();
44
+ var typeAttr = (el.getAttribute('type') || 'text').toLowerCase();
45
+ var role = el.getAttribute('role') || '';
46
+ var isControlled = false;
47
+
48
+ // Detect React/Vue controlled components
49
+ if ((el as any)._reactInternalFiber || (el as any)._reactRootContainer ||
50
+ (el as any).__vueApp__ || (el as any).__VUE__ ||
51
+ el.hasAttribute('data-reactroot')) {
52
+ isControlled = true;
53
+ }
54
+
55
+ var classification: any = {
56
+ type: tag,
57
+ interactionExpected: 'click',
58
+ successCondition: 'element_clicked',
59
+ fallbackStrategies: [],
60
+ isControlled: isControlled,
61
+ complexity: 'simple'
62
+ };
63
+
64
+ // Determine interaction type based on element
65
+ if (tag === 'input') {
66
+ if (typeAttr === 'checkbox' || typeAttr === 'radio') {
67
+ classification.interactionExpected = 'check';
68
+ classification.successCondition = 'checked_state_changed';
69
+ classification.fallbackStrategies = ['click', 'property_set'];
70
+ } else if (typeAttr === 'file') {
71
+ classification.interactionExpected = 'upload';
72
+ classification.successCondition = 'file_selected';
73
+ classification.fallbackStrategies = ['click', 'direct_upload'];
74
+ } else if (typeAttr === 'submit' || typeAttr === 'button') {
75
+ classification.interactionExpected = 'click';
76
+ classification.successCondition = 'form_submitted_or_clicked';
77
+ classification.fallbackStrategies = ['click', 'form_submit'];
78
+ } else {
79
+ classification.interactionExpected = 'type';
80
+ classification.successCondition = 'value_changed';
81
+ classification.fallbackStrategies = ['native_setter', 'react_setter', 'dispatch_events'];
82
+ classification.complexity = isControlled ? 'complex' : 'simple';
83
+ }
84
+ } else if (tag === 'textarea') {
85
+ classification.interactionExpected = 'type';
86
+ classification.successCondition = 'value_changed';
87
+ classification.fallbackStrategies = ['native_setter', 'react_setter', 'dispatch_events'];
88
+ classification.complexity = isControlled ? 'complex' : 'simple';
89
+ } else if (tag === 'select') {
90
+ classification.interactionExpected = 'select';
91
+ classification.successCondition = 'selection_changed';
92
+ classification.fallbackStrategies = ['property_set', 'click_option'];
93
+ classification.complexity = isControlled ? 'complex' : 'simple';
94
+ } else if (tag === 'button' || role === 'button') {
95
+ classification.interactionExpected = 'click';
96
+ classification.successCondition = 'clicked';
97
+ classification.fallbackStrategies = ['click', 'keyboard_enter'];
98
+ } else if (tag === 'a') {
99
+ classification.interactionExpected = 'click';
100
+ classification.successCondition = 'navigated';
101
+ classification.fallbackStrategies = ['click', 'direct_navigate'];
102
+ } else if (tag === 'div' || tag === 'span') {
103
+ if (role === 'textbox' || role === 'combobox' || (el as any).isContentEditable) {
104
+ classification.interactionExpected = 'type';
105
+ classification.successCondition = 'text_changed';
106
+ classification.fallbackStrategies = ['text_content_set', 'dispatch_events'];
107
+ classification.complexity = 'complex';
108
+ } else {
109
+ classification.interactionExpected = 'click';
110
+ classification.successCondition = 'clicked';
111
+ classification.fallbackStrategies = ['click'];
112
+ }
113
+ }
114
+
115
+ return JSON.stringify(classification);
116
+ } catch(e) {
117
+ return JSON.stringify({ error: (e as Error).message });
118
+ }
119
119
  })(${JSON.stringify(selector)})`,
120
120
  returnByValue: true,
121
121
  });
@@ -256,8 +256,8 @@ export async function detectFramework(session) {
256
256
  export async function detectShadowDom(session) {
257
257
  try {
258
258
  const resp = await session.Runtime.evaluate({
259
- expression: `(function() {
260
- return document.querySelectorAll('*').some(el => el.shadowRoot !== null);
259
+ expression: `(function() {
260
+ return document.querySelectorAll('*').some(el => el.shadowRoot !== null);
261
261
  })()`,
262
262
  returnByValue: true,
263
263
  });
@@ -275,22 +275,22 @@ targetSelector, profileName) {
275
275
  // ── Periodic focus verification (every 5 chars) ───────────────────────
276
276
  if (targetSelector && i > 0 && i % 5 === 0) {
277
277
  const focusOk = await session.Runtime.evaluate({
278
- expression: `(function(sel) {
279
- try {
280
- const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
281
- return el ? document.activeElement === el || el.contains(document.activeElement) : true;
282
- } catch(e) { return true; }
278
+ expression: `(function(sel) {
279
+ try {
280
+ const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
281
+ return el ? document.activeElement === el || el.contains(document.activeElement) : true;
282
+ } catch(e) { return true; }
283
283
  })(${JSON.stringify(targetSelector)})`,
284
284
  returnByValue: true,
285
285
  }).catch(() => ({ result: { value: true } }));
286
286
  if (focusOk?.result?.value === false) {
287
287
  await flushGroup();
288
288
  const coords = await session.Runtime.evaluate({
289
- expression: `(function(sel){
290
- const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
291
- if (!el) return null;
292
- const r = el.getBoundingClientRect();
293
- return { x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) };
289
+ expression: `(function(sel){
290
+ const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
291
+ if (!el) return null;
292
+ const r = el.getBoundingClientRect();
293
+ return { x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) };
294
294
  })(${JSON.stringify(targetSelector)})`,
295
295
  returnByValue: true,
296
296
  }).catch(() => null);
@@ -331,12 +331,12 @@ export async function ghostMove(session, targetX, targetY, config, label, profil
331
331
  wtCursor(session, targetX, targetY, "hover", cursorOpts);
332
332
  recordCursorPosition(targetX, targetY);
333
333
  await session.Runtime.evaluate({
334
- expression: `(function(){
335
- var el = document.elementFromPoint(${targetX}, ${targetY});
336
- if (el) {
337
- el.dispatchEvent(new MouseEvent('mouseover', {bubbles:true,cancelable:true,clientX:${targetX},clientY:${targetY}}));
338
- el.dispatchEvent(new MouseEvent('mouseenter', {bubbles:false,cancelable:true,clientX:${targetX},clientY:${targetY}}));
339
- }
334
+ expression: `(function(){
335
+ var el = document.elementFromPoint(${targetX}, ${targetY});
336
+ if (el) {
337
+ el.dispatchEvent(new MouseEvent('mouseover', {bubbles:true,cancelable:true,clientX:${targetX},clientY:${targetY}}));
338
+ el.dispatchEvent(new MouseEvent('mouseenter', {bubbles:false,cancelable:true,clientX:${targetX},clientY:${targetY}}));
339
+ }
340
340
  })()`
341
341
  }).catch(() => { });
342
342
  return;
@@ -427,12 +427,12 @@ export async function ghostMove(session, targetX, targetY, config, label, profil
427
427
  wtClearThought(session);
428
428
  await session.Input.dispatchMouseEvent({ type: "mouseMoved", x: targetX, y: targetY, button: "none" }).catch(() => { });
429
429
  await session.Runtime.evaluate({
430
- expression: `(function(){
431
- var el = document.elementFromPoint(${targetX}, ${targetY});
432
- if (el) {
433
- el.dispatchEvent(new MouseEvent('mouseover', {bubbles:true,cancelable:true,view:window,clientX:${targetX},clientY:${targetY}}));
434
- el.dispatchEvent(new MouseEvent('mouseenter', {bubbles:false,cancelable:true,view:window,clientX:${targetX},clientY:${targetY}}));
435
- }
430
+ expression: `(function(){
431
+ var el = document.elementFromPoint(${targetX}, ${targetY});
432
+ if (el) {
433
+ el.dispatchEvent(new MouseEvent('mouseover', {bubbles:true,cancelable:true,view:window,clientX:${targetX},clientY:${targetY}}));
434
+ el.dispatchEvent(new MouseEvent('mouseenter', {bubbles:false,cancelable:true,view:window,clientX:${targetX},clientY:${targetY}}));
435
+ }
436
436
  })()`
437
437
  }).catch(() => { });
438
438
  }
@@ -2,92 +2,92 @@ import { logDebug } from "../audit/logger.js";
2
2
  import { getConfigDevMode } from "../config/loader.js";
3
3
  // ─── Minimal Overlay Script ───────────────────────────────────────────────────
4
4
  export function getMinimalOverlayScript() {
5
- return `(function(){
6
- 'use strict';
7
-
8
- // ── Persistent shadow container ────────────────────────────────────────────
9
- var __wt_sr = null;
10
- function ec() {
11
- if (__wt_sr && __wt_sr.host && __wt_sr.host.isConnected) return __wt_sr;
12
- var h = document.getElementById('Weavetab-root');
13
- if (h && h.shadowRoot) { __wt_sr = h.shadowRoot; return __wt_sr; }
14
- if (!h) {
15
- var root = document.body || document.head || document.documentElement;
16
- if (root) {
17
- h = document.createElement('weavetab-host');
18
- h.id = 'Weavetab-root';
19
- h.setAttribute('data-wt-ignore', '');
20
- h.style.cssText = 'all:initial !important;position:fixed !important;left:0 !important;top:0 !important;width:0 !important;height:0 !important;z-index:2147483647 !important;pointer-events:none !important;touch-action:none !important;background:transparent !important;opacity:1 !important;transform:none !important;filter:none !important;';
21
- root.appendChild(h);
22
- } else {
23
- return null;
24
- }
25
- }
26
- __wt_sr = h.shadowRoot || h.attachShadow({ mode: 'open' });
27
- return __wt_sr;
28
- }
29
-
30
- // ── Install ─────────────────────────────────────────────────────────────────
31
- window.__wt_install_minimal = function() {
32
- var s = ec();
33
- if (!s) return false;
34
- var $ = function(id) { return s.getElementById(id) || document.getElementById(id); };
35
-
36
- // Cleanup old UI elements (pre-overlay-rewrite)
37
- var oldEls = ['wt-chat-icon','wt-chat-tooltip','wt-shadow-host','Weavetab-tactical-overlay','wt-ghost-cursor','wt-ghost-bubble','wt-ask-panel','wt-cur-canvas'];
38
- for (var oi = 0; oi < oldEls.length; oi++) { var oe = document.getElementById(oldEls[oi]); if (oe) oe.remove(); }
39
-
40
- // SPA navigation
41
- if (!window.__wt_nav_installed) {
42
- window.__wt_nav_installed = true;
43
- var em = function(type, url) {
44
- window.__wt_nav_event = { type: type, url: url, ts: Date.now() };
45
- document.dispatchEvent(new CustomEvent('__wt_navigation', { detail: { type: type, url: url } }));
46
- };
47
- var ps = history.pushState.bind(history);
48
- var rs = history.replaceState.bind(history);
49
- history.pushState = function() { ps.apply(history, arguments); em('pushState', arguments.length > 2 ? arguments[2] : null); };
50
- history.replaceState = function() { rs.apply(history, arguments); em('replaceState', arguments.length > 2 ? arguments[2] : null); };
51
- window.addEventListener('popstate', function() { em('popstate', location.href); });
52
- document.addEventListener('NavigationEnd', function() { em('angular', location.href); });
53
- }
54
-
55
- // The message listeners below are guarded so they are registered exactly once
56
- // per page, even when __wt_install_minimal() is called repeatedly (e.g. SPAs
57
- // with frequent navigations).
58
- if (!window.__wt_msg_installed) {
59
- window.__wt_msg_installed = true;
60
- window.__wt_chat_queue = window.__wt_chat_queue || [];
61
- window.addEventListener("message", function(e) {
62
- if (e.data && e.data.type === "__WT_FEEDBACK") {
63
- window.__wt_chat_queue.push(e.data.text);
64
- }
65
- });
66
- }
67
-
68
- window.__wt_setConfig = function(c) {
69
- if (c && c.devMode) window.__wt_devMode = true;
70
- };
71
-
72
- window.__wt_status = function() { return JSON.stringify({ rootInjected: true }); };
73
-
74
- // ── Fallback relay (works w/out extension) ───────────────────────
75
- // Cursor + HUD handled by content.js (extension). This is a no-op relay.
76
- window.__wt_fallback_handle = function(e) {
77
- if (window.__Weavetab && window.__Weavetab.version) return;
78
- };
79
- window.addEventListener('Weavetab-msg-in', window.__wt_fallback_handle);
80
-
81
- return true;
82
- };
83
-
84
- try {
85
- if (document.readyState === 'loading') {
86
- document.addEventListener('DOMContentLoaded', window.__wt_install_minimal);
87
- } else {
88
- window.__wt_install_minimal();
89
- }
90
- } catch(e) { logDebug('[Weavetab] Overlay init error:', e?.message || e); }
5
+ return `(function(){
6
+ 'use strict';
7
+
8
+ // ── Persistent shadow container ────────────────────────────────────────────
9
+ var __wt_sr = null;
10
+ function ec() {
11
+ if (__wt_sr && __wt_sr.host && __wt_sr.host.isConnected) return __wt_sr;
12
+ var h = document.getElementById('Weavetab-root');
13
+ if (h && h.shadowRoot) { __wt_sr = h.shadowRoot; return __wt_sr; }
14
+ if (!h) {
15
+ var root = document.body || document.head || document.documentElement;
16
+ if (root) {
17
+ h = document.createElement('weavetab-host');
18
+ h.id = 'Weavetab-root';
19
+ h.setAttribute('data-wt-ignore', '');
20
+ h.style.cssText = 'all:initial !important;position:fixed !important;left:0 !important;top:0 !important;width:0 !important;height:0 !important;z-index:2147483647 !important;pointer-events:none !important;touch-action:none !important;background:transparent !important;opacity:1 !important;transform:none !important;filter:none !important;';
21
+ root.appendChild(h);
22
+ } else {
23
+ return null;
24
+ }
25
+ }
26
+ __wt_sr = h.shadowRoot || h.attachShadow({ mode: 'open' });
27
+ return __wt_sr;
28
+ }
29
+
30
+ // ── Install ─────────────────────────────────────────────────────────────────
31
+ window.__wt_install_minimal = function() {
32
+ var s = ec();
33
+ if (!s) return false;
34
+ var $ = function(id) { return s.getElementById(id) || document.getElementById(id); };
35
+
36
+ // Cleanup old UI elements (pre-overlay-rewrite)
37
+ var oldEls = ['wt-chat-icon','wt-chat-tooltip','wt-shadow-host','Weavetab-tactical-overlay','wt-ghost-cursor','wt-ghost-bubble','wt-ask-panel','wt-cur-canvas'];
38
+ for (var oi = 0; oi < oldEls.length; oi++) { var oe = document.getElementById(oldEls[oi]); if (oe) oe.remove(); }
39
+
40
+ // SPA navigation
41
+ if (!window.__wt_nav_installed) {
42
+ window.__wt_nav_installed = true;
43
+ var em = function(type, url) {
44
+ window.__wt_nav_event = { type: type, url: url, ts: Date.now() };
45
+ document.dispatchEvent(new CustomEvent('__wt_navigation', { detail: { type: type, url: url } }));
46
+ };
47
+ var ps = history.pushState.bind(history);
48
+ var rs = history.replaceState.bind(history);
49
+ history.pushState = function() { ps.apply(history, arguments); em('pushState', arguments.length > 2 ? arguments[2] : null); };
50
+ history.replaceState = function() { rs.apply(history, arguments); em('replaceState', arguments.length > 2 ? arguments[2] : null); };
51
+ window.addEventListener('popstate', function() { em('popstate', location.href); });
52
+ document.addEventListener('NavigationEnd', function() { em('angular', location.href); });
53
+ }
54
+
55
+ // The message listeners below are guarded so they are registered exactly once
56
+ // per page, even when __wt_install_minimal() is called repeatedly (e.g. SPAs
57
+ // with frequent navigations).
58
+ if (!window.__wt_msg_installed) {
59
+ window.__wt_msg_installed = true;
60
+ window.__wt_chat_queue = window.__wt_chat_queue || [];
61
+ window.addEventListener("message", function(e) {
62
+ if (e.data && e.data.type === "__WT_FEEDBACK") {
63
+ window.__wt_chat_queue.push(e.data.text);
64
+ }
65
+ });
66
+ }
67
+
68
+ window.__wt_setConfig = function(c) {
69
+ if (c && c.devMode) window.__wt_devMode = true;
70
+ };
71
+
72
+ window.__wt_status = function() { return JSON.stringify({ rootInjected: true }); };
73
+
74
+ // ── Fallback relay (works w/out extension) ───────────────────────
75
+ // Cursor + HUD handled by content.js (extension). This is a no-op relay.
76
+ window.__wt_fallback_handle = function(e) {
77
+ if (window.__Weavetab && window.__Weavetab.version) return;
78
+ };
79
+ window.addEventListener('Weavetab-msg-in', window.__wt_fallback_handle);
80
+
81
+ return true;
82
+ };
83
+
84
+ try {
85
+ if (document.readyState === 'loading') {
86
+ document.addEventListener('DOMContentLoaded', window.__wt_install_minimal);
87
+ } else {
88
+ window.__wt_install_minimal();
89
+ }
90
+ } catch(e) { logDebug('[Weavetab] Overlay init error:', e?.message || e); }
91
91
  })();`;
92
92
  }
93
93
  // ─── Script reinstall expression ─────────────────────────────────────────────
@@ -117,11 +117,11 @@ async function evalInPage(session, expression) {
117
117
  }
118
118
  function buildConfigExpr(config) {
119
119
  const msg = { type: 'Weavetab_CONFIG', devMode: getConfigDevMode(config) };
120
- return `
120
+ return `
121
121
  if(window.__wt_setConfig)window.__wt_setConfig(${JSON.stringify({
122
122
  ...config,
123
- })});
124
- window.postMessage({type:'Weavetab-msg-in',data:${JSON.stringify(msg)}},'*');
123
+ })});
124
+ window.postMessage({type:'Weavetab-msg-in',data:${JSON.stringify(msg)}},'*');
125
125
  `;
126
126
  }
127
127
  // ─── Public surface ───────────────────────────────────────────────────────────