@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.
- package/AGENTS.md +49 -49
- package/ARCHITECTURE.md +590 -590
- package/README.md +216 -100
- package/SECURITY.md +207 -207
- package/TROUBLESHOOTING.md +373 -365
- package/dist/anticaptcha/detector.js +395 -395
- package/dist/anticaptcha/solver.js +130 -130
- package/dist/cdp/bridge.js +73 -73
- package/dist/cdp/connector.js +46 -22
- package/dist/cdp/extension.js +34 -34
- package/dist/cdp/helpers.js +174 -174
- package/dist/cdp/pruner.js +195 -195
- package/dist/cdp/ref_cache.js +66 -66
- package/dist/cdp/security.js +10 -10
- package/dist/cdp/verify.js +57 -57
- package/dist/cdp/walker.js +563 -525
- package/dist/cli/plugin.js +26 -3
- package/dist/config/loader.d.ts +0 -3
- package/dist/config/loader.js +0 -9
- package/dist/index.js +0 -4
- package/dist/intelligence/intent.js +81 -81
- package/dist/intelligence/sessionMemory.js +2 -2
- package/dist/overlay/ghost.js +22 -22
- package/dist/overlay/injector.js +89 -89
- package/dist/plugin/extension_bridge.js +54 -54
- package/dist/plugin/interface.d.ts +7 -0
- package/dist/plugin/loader.js +3 -4
- package/dist/plugin/schema.d.ts +11 -0
- package/dist/plugin/schema.js +59 -0
- package/dist/security/guard.js +18 -18
- package/dist/sensors/actionability.js +167 -167
- package/dist/sensors/guard.js +29 -29
- package/dist/sensors/network.js +15 -17
- package/dist/server.d.ts +1 -1
- package/dist/server.js +173 -144
- package/dist/state/delta.js +6 -7
- package/dist/tools/automation.js +85 -85
- package/dist/tools/canvas.js +48 -25
- package/dist/tools/checkpoint.js +94 -35
- package/dist/tools/click.js +52 -41
- package/dist/tools/clipboard.js +80 -74
- package/dist/tools/design_extract.js +441 -441
- package/dist/tools/dialog.js +13 -13
- package/dist/tools/emulation.d.ts +2 -0
- package/dist/tools/emulation.js +7 -0
- package/dist/tools/fill.js +344 -347
- package/dist/tools/find.js +78 -52
- package/dist/tools/highlight.js +67 -67
- package/dist/tools/inspect.js +54 -25
- package/dist/tools/key.js +42 -35
- package/dist/tools/navigate.d.ts +1 -1
- package/dist/tools/navigate.js +35 -35
- package/dist/tools/office/parse.js +62 -18
- package/dist/tools/pdf.d.ts +9 -0
- package/dist/tools/pdf.js +7 -4
- package/dist/tools/performance.d.ts +11 -4
- package/dist/tools/performance.js +94 -42
- package/dist/tools/performance_test.d.ts +2 -2
- package/dist/tools/performance_test.js +69 -69
- package/dist/tools/pointer.js +116 -116
- package/dist/tools/read.js +99 -67
- package/dist/tools/recording.js +9 -0
- package/dist/tools/scrape.js +146 -146
- package/dist/tools/screenshot.d.ts +2 -0
- package/dist/tools/screenshot.js +46 -4
- package/dist/tools/scroll.d.ts +3 -1
- package/dist/tools/scroll.js +13 -15
- package/dist/tools/select.d.ts +3 -0
- package/dist/tools/select.js +131 -124
- package/dist/tools/snapshot.js +8 -6
- package/dist/tools/storage.d.ts +5 -1
- package/dist/tools/storage.js +16 -0
- package/dist/tools/tabs.d.ts +7 -5
- package/dist/tools/tabs.js +79 -26
- package/dist/tools/thought.js +8 -8
- package/dist/tools/type.js +274 -274
- package/dist/tools/type_secret.js +23 -23
- package/dist/tools/upload.js +3 -3
- package/dist/tools/video_compiler.js +9 -0
- package/dist/tools/wait.js +35 -35
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/DOCUMENTATION.md +583 -585
- package/docs/PLUGINS.md +139 -121
- package/docs/TOOLS.md +3 -4
- package/docs/architecture/blind-injection.md +83 -83
- package/docs/architecture/overview.md +49 -49
- package/docs/configuration/configuration.md +39 -27
- package/docs/configuration/folders.md +62 -55
- package/docs/desktop-automation/electron-apps.md +225 -214
- package/docs/get-started/installation.md +1 -1
- package/docs/get-started/introduction.md +60 -60
- package/docs/get-started/quickstart.md +2 -2
- package/docs/get-started/setup-wizard.md +1 -1
- package/docs/intelligence/site-profiles.md +151 -151
- package/docs/tools/tools.md +582 -631
- package/docs/troubleshooting/trouble-loop.md +31 -31
- package/ext-dist/background.js +415 -415
- package/ext-dist/content.js +2527 -2527
- package/ext-dist/dashboard.html +583 -583
- package/ext-dist/hud/hud.js +3 -3
- package/ext-dist/hud/index.html +20 -20
- package/ext-dist/manifest.json +73 -73
- package/ext-dist/styles.css +223 -223
- package/mcp.json +796 -805
- package/package.json +8 -8
- package/server.json +23 -23
- package/smithery.yaml +7 -11
- package/dist/cdp/walker.test.d.ts +0 -2
- package/dist/cdp/walker.test.js +0 -172
- package/dist/intelligence/sessionMemory.test.d.ts +0 -2
- package/dist/intelligence/sessionMemory.test.js +0 -62
- package/dist/intelligence/trail.test.d.ts +0 -2
- package/dist/intelligence/trail.test.js +0 -110
- package/dist/state/cache.test.d.ts +0 -2
- package/dist/state/cache.test.js +0 -76
- package/dist/state/delta.test.d.ts +0 -2
- package/dist/state/delta.test.js +0 -279
- package/dist/state/groups.d.ts +0 -15
- package/dist/state/groups.js +0 -80
- package/dist/tools/accessibility.d.ts +0 -14
- package/dist/tools/accessibility.js +0 -32
- package/dist/tools/ask.d.ts +0 -14
- package/dist/tools/ask.js +0 -49
- package/dist/tools/click_and_wait.d.ts +0 -33
- package/dist/tools/click_and_wait.js +0 -149
- package/dist/tools/drag.d.ts +0 -15
- package/dist/tools/drag.js +0 -29
- package/dist/tools/geo.d.ts +0 -19
- package/dist/tools/geo.js +0 -29
- package/dist/tools/github/analyze.d.ts +0 -4
- package/dist/tools/github/analyze.js +0 -113
- package/dist/tools/github/cache.d.ts +0 -21
- package/dist/tools/github/cache.js +0 -28
- package/dist/tools/github/index.d.ts +0 -19
- package/dist/tools/github/index.js +0 -40
- package/dist/tools/github/issues.d.ts +0 -9
- package/dist/tools/github/issues.js +0 -88
- package/dist/tools/github/pr.d.ts +0 -5
- package/dist/tools/github/pr.js +0 -88
- package/dist/tools/github/rateLimiter.d.ts +0 -4
- package/dist/tools/github/rateLimiter.js +0 -46
- package/dist/tools/github/read.d.ts +0 -34
- package/dist/tools/github/read.js +0 -74
- package/dist/tools/github/repoContext.d.ts +0 -20
- package/dist/tools/github/repoContext.js +0 -129
- package/dist/tools/hover.d.ts +0 -19
- package/dist/tools/hover.js +0 -57
- package/dist/tools/integration.test.d.ts +0 -2
- package/dist/tools/integration.test.js +0 -96
- package/dist/tools/macro_compiler.d.ts +0 -7
- package/dist/tools/macro_compiler.js +0 -82
- package/dist/tools/mouse.d.ts +0 -21
- package/dist/tools/mouse.js +0 -62
- package/dist/tools/response.d.ts +0 -129
- package/dist/tools/response.js +0 -5
- package/dist/tools/wait_for.d.ts +0 -23
- package/dist/tools/wait_for.js +0 -30
- package/dist/tools/windows.d.ts +0 -22
- package/dist/tools/windows.js +0 -57
package/dist/cli/plugin.js
CHANGED
|
@@ -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
|
|
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
|
|
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. @
|
|
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`);
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -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;
|
package/dist/config/loader.js
CHANGED
|
@@ -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
|
});
|
package/dist/overlay/ghost.js
CHANGED
|
@@ -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
|
}
|
package/dist/overlay/injector.js
CHANGED
|
@@ -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 ───────────────────────────────────────────────────────────
|