@weavetab/mcp 2.5.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +48 -0
- package/ARCHITECTURE.md +590 -0
- package/LICENSE +631 -0
- package/README.md +909 -0
- package/SECURITY.md +196 -0
- package/TROUBLESHOOTING.md +365 -0
- package/dist/anticaptcha/detector.d.ts +49 -0
- package/dist/anticaptcha/detector.js +465 -0
- package/dist/anticaptcha/integration.d.ts +36 -0
- package/dist/anticaptcha/integration.js +123 -0
- package/dist/anticaptcha/solver.d.ts +27 -0
- package/dist/anticaptcha/solver.js +552 -0
- package/dist/audit/logger.d.ts +13 -0
- package/dist/audit/logger.js +177 -0
- package/dist/audit/telemetry.d.ts +36 -0
- package/dist/audit/telemetry.js +162 -0
- package/dist/cdp/bridge.d.ts +16 -0
- package/dist/cdp/bridge.js +826 -0
- package/dist/cdp/confirm.d.ts +26 -0
- package/dist/cdp/confirm.js +79 -0
- package/dist/cdp/connector.d.ts +37 -0
- package/dist/cdp/connector.js +661 -0
- package/dist/cdp/extension.d.ts +36 -0
- package/dist/cdp/extension.js +118 -0
- package/dist/cdp/finder.d.ts +1 -0
- package/dist/cdp/finder.js +2 -0
- package/dist/cdp/helpers.d.ts +11 -0
- package/dist/cdp/helpers.js +195 -0
- package/dist/cdp/label_cache.d.ts +12 -0
- package/dist/cdp/label_cache.js +51 -0
- package/dist/cdp/lock.d.ts +33 -0
- package/dist/cdp/lock.js +206 -0
- package/dist/cdp/omni_broker.d.ts +17 -0
- package/dist/cdp/omni_broker.js +119 -0
- package/dist/cdp/profiles.d.ts +1 -0
- package/dist/cdp/profiles.js +87 -0
- package/dist/cdp/pruner.d.ts +41 -0
- package/dist/cdp/pruner.js +263 -0
- package/dist/cdp/ref_cache.d.ts +101 -0
- package/dist/cdp/ref_cache.js +234 -0
- package/dist/cdp/retry.d.ts +5 -0
- package/dist/cdp/retry.js +39 -0
- package/dist/cdp/retry_enhanced.d.ts +44 -0
- package/dist/cdp/retry_enhanced.js +102 -0
- package/dist/cdp/security.d.ts +50 -0
- package/dist/cdp/security.js +237 -0
- package/dist/cdp/verify.d.ts +39 -0
- package/dist/cdp/verify.js +143 -0
- package/dist/cdp/walker.d.ts +91 -0
- package/dist/cdp/walker.js +896 -0
- package/dist/cdp/walker.test.d.ts +2 -0
- package/dist/cdp/walker.test.js +172 -0
- package/dist/cdp/websocket_transport.d.ts +15 -0
- package/dist/cdp/websocket_transport.js +118 -0
- package/dist/cli/plugin.d.ts +9 -0
- package/dist/cli/plugin.js +1134 -0
- package/dist/cli/updater.d.ts +1 -0
- package/dist/cli/updater.js +72 -0
- package/dist/config/loader.d.ts +120 -0
- package/dist/config/loader.js +704 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1248 -0
- package/dist/intelligence/hints.d.ts +11 -0
- package/dist/intelligence/hints.js +39 -0
- package/dist/intelligence/intent.d.ts +33 -0
- package/dist/intelligence/intent.js +171 -0
- package/dist/intelligence/sessionMemory.d.ts +66 -0
- package/dist/intelligence/sessionMemory.js +284 -0
- package/dist/intelligence/sessionMemory.test.d.ts +2 -0
- package/dist/intelligence/sessionMemory.test.js +62 -0
- package/dist/intelligence/trail.d.ts +64 -0
- package/dist/intelligence/trail.js +233 -0
- package/dist/intelligence/trail.test.d.ts +2 -0
- package/dist/intelligence/trail.test.js +110 -0
- package/dist/intelligence/vision.d.ts +24 -0
- package/dist/intelligence/vision.js +151 -0
- package/dist/lifecycle/mission_manager.d.ts +16 -0
- package/dist/lifecycle/mission_manager.js +44 -0
- package/dist/overlay/bubble.d.ts +16 -0
- package/dist/overlay/bubble.js +37 -0
- package/dist/overlay/ghost.d.ts +35 -0
- package/dist/overlay/ghost.js +508 -0
- package/dist/overlay/injector.d.ts +22 -0
- package/dist/overlay/injector.js +198 -0
- package/dist/plugin/interface.d.ts +134 -0
- package/dist/plugin/interface.js +1 -0
- package/dist/plugin/loader.d.ts +18 -0
- package/dist/plugin/loader.js +155 -0
- package/dist/plugin/registry.d.ts +50 -0
- package/dist/plugin/registry.js +234 -0
- package/dist/security/blacklist.d.ts +24 -0
- package/dist/security/blacklist.js +80 -0
- package/dist/security/filter.d.ts +2 -0
- package/dist/security/filter.js +20 -0
- package/dist/security/guard.d.ts +8 -0
- package/dist/security/guard.js +35 -0
- package/dist/security/ratelimit.d.ts +11 -0
- package/dist/security/ratelimit.js +57 -0
- package/dist/security/secrets.d.ts +75 -0
- package/dist/security/secrets.js +365 -0
- package/dist/sensors/actionability.d.ts +81 -0
- package/dist/sensors/actionability.js +303 -0
- package/dist/sensors/guard.d.ts +25 -0
- package/dist/sensors/guard.js +168 -0
- package/dist/sensors/mutations.d.ts +23 -0
- package/dist/sensors/mutations.js +93 -0
- package/dist/sensors/network.d.ts +67 -0
- package/dist/sensors/network.js +193 -0
- package/dist/sensors/operation_monitor.d.ts +80 -0
- package/dist/sensors/operation_monitor.js +203 -0
- package/dist/sensors/pacing.d.ts +44 -0
- package/dist/sensors/pacing.js +111 -0
- package/dist/sensors/thoughts.d.ts +2 -0
- package/dist/sensors/thoughts.js +59 -0
- package/dist/sensors/wait.d.ts +12 -0
- package/dist/sensors/wait.js +44 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +1687 -0
- package/dist/state/agent.d.ts +36 -0
- package/dist/state/agent.js +101 -0
- package/dist/state/cache.d.ts +16 -0
- package/dist/state/cache.js +92 -0
- package/dist/state/cache.test.d.ts +2 -0
- package/dist/state/cache.test.js +76 -0
- package/dist/state/delta.d.ts +71 -0
- package/dist/state/delta.js +234 -0
- package/dist/state/delta.test.d.ts +2 -0
- package/dist/state/delta.test.js +279 -0
- package/dist/state/groups.d.ts +15 -0
- package/dist/state/groups.js +80 -0
- package/dist/state/session.d.ts +30 -0
- package/dist/state/session.js +155 -0
- package/dist/tools/accessibility.d.ts +14 -0
- package/dist/tools/accessibility.js +32 -0
- package/dist/tools/ask.d.ts +14 -0
- package/dist/tools/ask.js +49 -0
- package/dist/tools/automation.d.ts +36 -0
- package/dist/tools/automation.js +218 -0
- package/dist/tools/browser_detect.d.ts +13 -0
- package/dist/tools/browser_detect.js +73 -0
- package/dist/tools/burst.d.ts +35 -0
- package/dist/tools/burst.js +344 -0
- package/dist/tools/canvas.d.ts +25 -0
- package/dist/tools/canvas.js +132 -0
- package/dist/tools/captcha.d.ts +38 -0
- package/dist/tools/captcha.js +209 -0
- package/dist/tools/click.d.ts +36 -0
- package/dist/tools/click.js +561 -0
- package/dist/tools/click_and_wait.d.ts +33 -0
- package/dist/tools/click_and_wait.js +149 -0
- package/dist/tools/clipboard.d.ts +29 -0
- package/dist/tools/clipboard.js +279 -0
- package/dist/tools/console.d.ts +21 -0
- package/dist/tools/console.js +107 -0
- package/dist/tools/cookies.d.ts +67 -0
- package/dist/tools/cookies.js +121 -0
- package/dist/tools/design_extract.d.ts +109 -0
- package/dist/tools/design_extract.js +641 -0
- package/dist/tools/dialog.d.ts +24 -0
- package/dist/tools/dialog.js +109 -0
- package/dist/tools/drag.d.ts +15 -0
- package/dist/tools/drag.js +29 -0
- package/dist/tools/emulation.d.ts +33 -0
- package/dist/tools/emulation.js +69 -0
- package/dist/tools/eval.d.ts +20 -0
- package/dist/tools/eval.js +92 -0
- package/dist/tools/fill.d.ts +41 -0
- package/dist/tools/fill.js +667 -0
- package/dist/tools/find.d.ts +30 -0
- package/dist/tools/find.js +60 -0
- package/dist/tools/geo.d.ts +19 -0
- package/dist/tools/geo.js +29 -0
- package/dist/tools/github/analyze.d.ts +4 -0
- package/dist/tools/github/analyze.js +113 -0
- package/dist/tools/github/cache.d.ts +21 -0
- package/dist/tools/github/cache.js +28 -0
- package/dist/tools/github/index.d.ts +4 -0
- package/dist/tools/github/index.js +4 -0
- package/dist/tools/github/issues.d.ts +9 -0
- package/dist/tools/github/issues.js +88 -0
- package/dist/tools/github/pr.d.ts +5 -0
- package/dist/tools/github/pr.js +88 -0
- package/dist/tools/github/rateLimiter.d.ts +4 -0
- package/dist/tools/github/rateLimiter.js +46 -0
- package/dist/tools/github/read.d.ts +34 -0
- package/dist/tools/github/read.js +74 -0
- package/dist/tools/github/repoContext.d.ts +20 -0
- package/dist/tools/github/repoContext.js +129 -0
- package/dist/tools/highlight.d.ts +20 -0
- package/dist/tools/highlight.js +140 -0
- package/dist/tools/hover.d.ts +19 -0
- package/dist/tools/hover.js +57 -0
- package/dist/tools/inspect.d.ts +17 -0
- package/dist/tools/inspect.js +125 -0
- package/dist/tools/integration.test.d.ts +2 -0
- package/dist/tools/integration.test.js +96 -0
- package/dist/tools/key.d.ts +25 -0
- package/dist/tools/key.js +173 -0
- package/dist/tools/macro_compiler.d.ts +7 -0
- package/dist/tools/macro_compiler.js +82 -0
- package/dist/tools/mouse.d.ts +21 -0
- package/dist/tools/mouse.js +62 -0
- package/dist/tools/navigate.d.ts +16 -0
- package/dist/tools/navigate.js +188 -0
- package/dist/tools/network_intercept.d.ts +17 -0
- package/dist/tools/network_intercept.js +151 -0
- package/dist/tools/office/index.d.ts +9 -0
- package/dist/tools/office/index.js +7 -0
- package/dist/tools/office/list.d.ts +15 -0
- package/dist/tools/office/list.js +41 -0
- package/dist/tools/office/parse.d.ts +20 -0
- package/dist/tools/office/parse.js +172 -0
- package/dist/tools/pdf.d.ts +22 -0
- package/dist/tools/pdf.js +42 -0
- package/dist/tools/performance.d.ts +12 -0
- package/dist/tools/performance.js +47 -0
- package/dist/tools/performance_test.d.ts +70 -0
- package/dist/tools/performance_test.js +128 -0
- package/dist/tools/plan.d.ts +39 -0
- package/dist/tools/plan.js +161 -0
- package/dist/tools/pointer.d.ts +35 -0
- package/dist/tools/pointer.js +522 -0
- package/dist/tools/read.d.ts +30 -0
- package/dist/tools/read.js +488 -0
- package/dist/tools/recording.d.ts +45 -0
- package/dist/tools/recording.js +124 -0
- package/dist/tools/response.d.ts +129 -0
- package/dist/tools/response.js +5 -0
- package/dist/tools/scrape.d.ts +24 -0
- package/dist/tools/scrape.js +140 -0
- package/dist/tools/screenshot.d.ts +40 -0
- package/dist/tools/screenshot.js +79 -0
- package/dist/tools/scroll.d.ts +23 -0
- package/dist/tools/scroll.js +196 -0
- package/dist/tools/select.d.ts +13 -0
- package/dist/tools/select.js +217 -0
- package/dist/tools/snapshot.d.ts +27 -0
- package/dist/tools/snapshot.js +99 -0
- package/dist/tools/storage.d.ts +18 -0
- package/dist/tools/storage.js +29 -0
- package/dist/tools/tabs.d.ts +77 -0
- package/dist/tools/tabs.js +342 -0
- package/dist/tools/thought.d.ts +16 -0
- package/dist/tools/thought.js +79 -0
- package/dist/tools/type.d.ts +65 -0
- package/dist/tools/type.js +1061 -0
- package/dist/tools/type_secret.d.ts +23 -0
- package/dist/tools/type_secret.js +229 -0
- package/dist/tools/upload.d.ts +19 -0
- package/dist/tools/upload.js +103 -0
- package/dist/tools/video_compiler.d.ts +24 -0
- package/dist/tools/video_compiler.js +199 -0
- package/dist/tools/viewport.d.ts +44 -0
- package/dist/tools/viewport.js +230 -0
- package/dist/tools/wait.d.ts +19 -0
- package/dist/tools/wait.js +202 -0
- package/dist/tools/wait_for.d.ts +23 -0
- package/dist/tools/wait_for.js +30 -0
- package/dist/tools/windows.d.ts +22 -0
- package/dist/tools/windows.js +57 -0
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +12 -0
- package/docs/DEV_MODE.md +68 -0
- package/docs/DOCUMENTATION.md +532 -0
- package/docs/PLUGINS.md +538 -0
- package/docs/TOOLS.md +104 -0
- package/docs/dev_plugin.md +310 -0
- package/ext-dist/background.js +467 -0
- package/ext-dist/content.js +3089 -0
- package/ext-dist/dashboard.html +583 -0
- package/ext-dist/hud/hud.js +73 -0
- package/ext-dist/hud/index.html +20 -0
- package/ext-dist/manifest.json +77 -0
- package/ext-dist/sidepanel/sidepanel.js +25 -0
- package/ext-dist/sidepanel.html +547 -0
- package/ext-dist/styles.css +218 -0
- package/icon.png +0 -0
- package/mcp.json +796 -0
- package/package.json +113 -0
- package/server.json +23 -0
- package/smithery.yaml +11 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// src/overlay/bubble.ts
|
|
2
|
+
// Phase 3.7.3: Thought bubble — categorized progress, step tracking, time estimates.
|
|
3
|
+
// Sends structured messages to content.js via sendToExtension.
|
|
4
|
+
import { sendToExtension } from "../cdp/helpers.js";
|
|
5
|
+
export async function showBubble(session, icon, text, durationMs, opts) {
|
|
6
|
+
const payload = {
|
|
7
|
+
type: 'Weavetab_THOUGHT',
|
|
8
|
+
text,
|
|
9
|
+
icon,
|
|
10
|
+
active: true,
|
|
11
|
+
};
|
|
12
|
+
if (opts?.category)
|
|
13
|
+
payload.category = opts.category;
|
|
14
|
+
if (opts?.step !== undefined)
|
|
15
|
+
payload.step = opts.step;
|
|
16
|
+
if (opts?.stepTotal !== undefined)
|
|
17
|
+
payload.stepTotal = opts.stepTotal;
|
|
18
|
+
if (opts?.estimatedMs !== undefined)
|
|
19
|
+
payload.estimatedMs = opts.estimatedMs;
|
|
20
|
+
await sendToExtension(session, payload).catch(() => { });
|
|
21
|
+
}
|
|
22
|
+
export async function showProgress(session, text, step, stepTotal, category = "acting", estimatedMs) {
|
|
23
|
+
await showBubble(session, "→", text, undefined, {
|
|
24
|
+
category,
|
|
25
|
+
step,
|
|
26
|
+
stepTotal,
|
|
27
|
+
estimatedMs,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export async function hideBubble(session) {
|
|
31
|
+
await sendToExtension(session, {
|
|
32
|
+
type: 'Weavetab_CLEAR_THOUGHT',
|
|
33
|
+
}).catch(() => { });
|
|
34
|
+
}
|
|
35
|
+
export async function injectBubbleScripts(_session) { }
|
|
36
|
+
export async function openOverlayTab(_session) { }
|
|
37
|
+
export function startBubbleProcess(_humanMode) { }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import CDP from "chrome-remote-interface";
|
|
2
|
+
import type { Config } from "../config/loader.js";
|
|
3
|
+
export interface CursorOptions {
|
|
4
|
+
trail?: "off" | "subtle" | "full";
|
|
5
|
+
opacity?: number;
|
|
6
|
+
speed?: "human" | "fast" | "instant";
|
|
7
|
+
}
|
|
8
|
+
export interface BurstProfile {
|
|
9
|
+
groupSize: [number, number];
|
|
10
|
+
interCharMin: number;
|
|
11
|
+
interCharMax: number;
|
|
12
|
+
interGroupMin: number;
|
|
13
|
+
interGroupMax: number;
|
|
14
|
+
}
|
|
15
|
+
export declare const BURST_PROFILES: Record<"fast" | "normal" | "deliberate", BurstProfile>;
|
|
16
|
+
export type GhostProfile = "human" | "fast" | "instant";
|
|
17
|
+
export declare function ghostType(session: CDP.Client, rawText: string, config: Config,
|
|
18
|
+
/** CSS selector of the target field — used to re-verify focus every N chars */
|
|
19
|
+
targetSelector?: string, profileName?: "fast" | "normal" | "deliberate"): Promise<void>;
|
|
20
|
+
export declare function ghostMove(session: CDP.Client, targetX: number, targetY: number, config: Config, label?: string, profile?: GhostProfile, cursorOpts?: Pick<CursorOptions, "trail" | "opacity">): Promise<void>;
|
|
21
|
+
/** Cancel simulated reading so actions don't wait 15s. */
|
|
22
|
+
export declare function cancelReading(): void;
|
|
23
|
+
export declare function startReadingSimulation(session: CDP.Client, wordCount: number, config: Config): void;
|
|
24
|
+
export declare function waitForReading(): Promise<void>;
|
|
25
|
+
export declare function ghostResult(session: CDP.Client, success: boolean, actionType: string, detail?: string): Promise<void>;
|
|
26
|
+
export declare function recordCursorPosition(x: number, y: number): void;
|
|
27
|
+
export declare function getCursorTrail(length?: number): {
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
t: number;
|
|
31
|
+
}[];
|
|
32
|
+
export declare function clearCursorTrail(): void;
|
|
33
|
+
export declare function ghostClick(session: CDP.Client, x: number, y: number, options?: any): Promise<void>;
|
|
34
|
+
export declare function ghostWait(session: CDP.Client): void;
|
|
35
|
+
export declare function ghostIdle(session: CDP.Client): void;
|
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
import { logDebug } from "../audit/logger.js";
|
|
2
|
+
import { getConfigHeadless, getConfigVisuals } from "../config/loader.js";
|
|
3
|
+
function sleep(ms) {
|
|
4
|
+
return new Promise(r => setTimeout(r, ms));
|
|
5
|
+
}
|
|
6
|
+
// Gaussian random generator (Box-Muller transform)
|
|
7
|
+
function randomGaussian(mean, stdDev) {
|
|
8
|
+
let u = 0, v = 0;
|
|
9
|
+
while (u === 0)
|
|
10
|
+
u = Math.random();
|
|
11
|
+
while (v === 0)
|
|
12
|
+
v = Math.random();
|
|
13
|
+
let num = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
|
|
14
|
+
num = num / 10.0 + 0.5;
|
|
15
|
+
if (num > 1 || num < 0)
|
|
16
|
+
return randomGaussian(mean, stdDev);
|
|
17
|
+
return mean + (num - 0.5) * 2 * stdDev;
|
|
18
|
+
}
|
|
19
|
+
import { sendToExtension } from "../cdp/helpers.js";
|
|
20
|
+
function wtCursor(session, x, y, state, opts) {
|
|
21
|
+
recordCursorPosition(x, y);
|
|
22
|
+
const trail = opts?.trail && opts.trail !== "off" ? getCursorTrail(opts.trail === "full" ? 20 : 8) : undefined;
|
|
23
|
+
sendToExtension(session, { type: 'Weavetab_STATE', cursor: { x, y, trail }, state }).catch(() => { });
|
|
24
|
+
}
|
|
25
|
+
async function wtThought(session, text) {
|
|
26
|
+
await sendToExtension(session, { type: 'Weavetab_STATE', hud: { action: text } }).catch(() => { });
|
|
27
|
+
// Add realistic wandering movement connected to thoughts
|
|
28
|
+
if (currentX > 0 && currentY > 0 && Math.random() > 0.2) {
|
|
29
|
+
const wanderDistance = 15 + Math.random() * 35;
|
|
30
|
+
const angle = Math.random() * Math.PI * 2;
|
|
31
|
+
const tx = Math.max(0, currentX + Math.cos(angle) * wanderDistance);
|
|
32
|
+
const ty = Math.max(0, currentY + Math.sin(angle) * wanderDistance);
|
|
33
|
+
const steps = 15;
|
|
34
|
+
const waypoints = [];
|
|
35
|
+
const cp1X = currentX + (tx - currentX) * 0.3 + (Math.random() - 0.5) * 15;
|
|
36
|
+
const cp1Y = currentY + (ty - currentY) * 0.3 + (Math.random() - 0.5) * 15;
|
|
37
|
+
const cp2X = currentX + (tx - currentX) * 0.7 + (Math.random() - 0.5) * 15;
|
|
38
|
+
const cp2Y = currentY + (ty - currentY) * 0.7 + (Math.random() - 0.5) * 15;
|
|
39
|
+
for (let i = 1; i <= steps; i++) {
|
|
40
|
+
let t = i / steps;
|
|
41
|
+
t = 1 - Math.pow(1 - t, 3);
|
|
42
|
+
waypoints.push({
|
|
43
|
+
x: cubicBezier(t, currentX, cp1X, cp2X, tx),
|
|
44
|
+
y: cubicBezier(t, currentY, cp1Y, cp2Y, ty)
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
sendToExtension(session, {
|
|
48
|
+
type: 'Weavetab_STATE',
|
|
49
|
+
cursor: { waypoints, duration_ms: steps * 20, x: currentX, y: currentY },
|
|
50
|
+
state: "thinking"
|
|
51
|
+
}).catch(() => { });
|
|
52
|
+
// Async physical dispatch to not block the main logic flow
|
|
53
|
+
(async () => {
|
|
54
|
+
for (let i = 1; i <= steps; i++) {
|
|
55
|
+
const x = waypoints[i - 1].x;
|
|
56
|
+
const y = waypoints[i - 1].y;
|
|
57
|
+
await session.Input.dispatchMouseEvent({ type: "mouseMoved", x, y, button: "none" }).catch(() => { });
|
|
58
|
+
currentX = x;
|
|
59
|
+
currentY = y;
|
|
60
|
+
await new Promise(r => setTimeout(r, 20));
|
|
61
|
+
}
|
|
62
|
+
})();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function wtClearThought(session) {
|
|
66
|
+
await sendToExtension(session, { type: 'Weavetab_STATE', hud: { action: '' } }).catch(() => { });
|
|
67
|
+
}
|
|
68
|
+
export const BURST_PROFILES = {
|
|
69
|
+
fast: {
|
|
70
|
+
groupSize: [3, 5],
|
|
71
|
+
interCharMin: 15,
|
|
72
|
+
interCharMax: 30,
|
|
73
|
+
interGroupMin: 40,
|
|
74
|
+
interGroupMax: 80,
|
|
75
|
+
},
|
|
76
|
+
normal: {
|
|
77
|
+
groupSize: [2, 4],
|
|
78
|
+
interCharMin: 40,
|
|
79
|
+
interCharMax: 70,
|
|
80
|
+
interGroupMin: 60,
|
|
81
|
+
interGroupMax: 150,
|
|
82
|
+
},
|
|
83
|
+
deliberate: {
|
|
84
|
+
groupSize: [1, 2],
|
|
85
|
+
interCharMin: 80,
|
|
86
|
+
interCharMax: 140,
|
|
87
|
+
interGroupMin: 100,
|
|
88
|
+
interGroupMax: 250,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
// Common bigrams typed ~35% faster (muscle memory)
|
|
92
|
+
const FAST_BIGRAMS = new Set([
|
|
93
|
+
'th', 'he', 'in', 'er', 'an', 're', 'on', 'at', 'en', 'nd', 'ti', 'es', 'or', 'te',
|
|
94
|
+
'of', 'ed', 'is', 'it', 'al', 'ar', 'st', 'to', 'nt', 'ng', 'se', 'ha', 'as', 'ou',
|
|
95
|
+
'io', 'le', 've', 'co', 'me', 'de', 'hi', 'ri', 'ro', 'ic', 'ne', 'ea', 'ra', 'ce',
|
|
96
|
+
]);
|
|
97
|
+
// Gaussian sample — Box-Muller, clamped to reasonable range
|
|
98
|
+
function gaussianDelay(mean, sd) {
|
|
99
|
+
let u = 0, v = 0;
|
|
100
|
+
while (u === 0)
|
|
101
|
+
u = Math.random();
|
|
102
|
+
while (v === 0)
|
|
103
|
+
v = Math.random();
|
|
104
|
+
const n = Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
|
|
105
|
+
return Math.max(20, Math.min(mean * 4.5, mean + n * sd));
|
|
106
|
+
}
|
|
107
|
+
export async function ghostType(session, rawText, config,
|
|
108
|
+
/** CSS selector of the target field — used to re-verify focus every N chars */
|
|
109
|
+
targetSelector, profileName) {
|
|
110
|
+
if (!rawText)
|
|
111
|
+
return;
|
|
112
|
+
const resolvedProfile = profileName || "normal";
|
|
113
|
+
if (getConfigHeadless(config)) {
|
|
114
|
+
// Non-human: fast insertText line by line, no simulation
|
|
115
|
+
const lines = rawText.split(/\r?\n/);
|
|
116
|
+
for (let li = 0; li < lines.length; li++) {
|
|
117
|
+
const line = lines[li];
|
|
118
|
+
if (line) {
|
|
119
|
+
await session.Input.insertText({ text: line }).catch(async () => {
|
|
120
|
+
for (const ch of line) {
|
|
121
|
+
await session.Input.dispatchKeyEvent({ type: "keyDown", text: ch });
|
|
122
|
+
await session.Input.dispatchKeyEvent({ type: "keyUp" });
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
if (li < lines.length - 1) {
|
|
127
|
+
await session.Input.dispatchKeyEvent({ type: "keyDown", key: "Enter", windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13 });
|
|
128
|
+
await session.Input.dispatchKeyEvent({ type: "keyUp", key: "Enter", windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13 });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// ── Realistic human burst-typing ───────────────────────────────────────────
|
|
134
|
+
// Use Input.insertText per burst group instead of per-character
|
|
135
|
+
// dispatchKeyEvent pairs. This eliminates character dropping caused by
|
|
136
|
+
// Chrome's event coalescing on Windows while preserving all human-like
|
|
137
|
+
// timing simulation (delays, pauses, cursor jitter, bigram speedup).
|
|
138
|
+
const p = BURST_PROFILES[resolvedProfile];
|
|
139
|
+
let wordsSinceBreak = 0;
|
|
140
|
+
let wordCharCount = 0;
|
|
141
|
+
let prevChar = '';
|
|
142
|
+
wtCursor(session, currentX, currentY, "typing");
|
|
143
|
+
let currentGroupSize = Math.floor(Math.random() * (p.groupSize[1] - p.groupSize[0] + 1)) + p.groupSize[0];
|
|
144
|
+
let charsTypedInGroup = 0;
|
|
145
|
+
let groupBuffer = '';
|
|
146
|
+
async function flushGroup() {
|
|
147
|
+
if (!groupBuffer)
|
|
148
|
+
return;
|
|
149
|
+
await session.Input.insertText({ text: groupBuffer });
|
|
150
|
+
groupBuffer = '';
|
|
151
|
+
}
|
|
152
|
+
for (let i = 0; i < rawText.length; i++) {
|
|
153
|
+
const char = rawText[i];
|
|
154
|
+
// ── Newline: flush buffer + dispatch Enter key ───────────────────────
|
|
155
|
+
if (char === '\n' || char === '\r') {
|
|
156
|
+
await flushGroup();
|
|
157
|
+
await session.Input.dispatchKeyEvent({ type: "keyDown", key: "Enter", windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13 });
|
|
158
|
+
await session.Input.dispatchKeyEvent({ type: "keyUp", key: "Enter", windowsVirtualKeyCode: 13, nativeVirtualKeyCode: 13 });
|
|
159
|
+
prevChar = char;
|
|
160
|
+
wordCharCount = 0;
|
|
161
|
+
charsTypedInGroup = 0;
|
|
162
|
+
currentGroupSize = Math.floor(Math.random() * (p.groupSize[1] - p.groupSize[0] + 1)) + p.groupSize[0];
|
|
163
|
+
await sleep(gaussianDelay(190, 65));
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
// ── Cursor jitter while typing (moved to content.js) ───────────────────
|
|
167
|
+
// ── Typo-and-correct (flush + dispatchKeyEvent ────────────────────────
|
|
168
|
+
const typoRate = typeof config.typoRate === 'number' ? config.typoRate : 0;
|
|
169
|
+
if (typoRate > 0 && Math.random() < typoRate && /[a-zA-Z]/.test(char)) {
|
|
170
|
+
await flushGroup();
|
|
171
|
+
const offset = Math.random() > 0.5 ? 1 : -1;
|
|
172
|
+
const typoChar = String.fromCharCode(char.toLowerCase().charCodeAt(0) + offset);
|
|
173
|
+
if (/[a-z]/.test(typoChar)) {
|
|
174
|
+
await session.Input.dispatchKeyEvent({ type: "keyDown", text: typoChar });
|
|
175
|
+
await session.Input.dispatchKeyEvent({ type: "keyUp" });
|
|
176
|
+
await sleep(gaussianDelay(115, 38));
|
|
177
|
+
await session.Input.dispatchKeyEvent({ type: "keyDown", key: "Backspace", windowsVirtualKeyCode: 8, nativeVirtualKeyCode: 8 });
|
|
178
|
+
await session.Input.dispatchKeyEvent({ type: "keyUp", key: "Backspace", windowsVirtualKeyCode: 8, nativeVirtualKeyCode: 8 });
|
|
179
|
+
await sleep(gaussianDelay(75, 22));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// ── Add character to burst buffer ──────────────────────────────────────
|
|
183
|
+
groupBuffer += char;
|
|
184
|
+
charsTypedInGroup++;
|
|
185
|
+
// ── Compute delay ──────────────────────────────────────────────────────
|
|
186
|
+
let charDelay = Math.random() * (p.interCharMax - p.interCharMin) + p.interCharMin;
|
|
187
|
+
const bigram = (prevChar + char).toLowerCase();
|
|
188
|
+
if (FAST_BIGRAMS.has(bigram))
|
|
189
|
+
charDelay *= 0.62;
|
|
190
|
+
// ── Word boundary: flush group + pause ─────────────────────────────────
|
|
191
|
+
if (char === ' ' || char === '\t') {
|
|
192
|
+
await flushGroup();
|
|
193
|
+
wordCharCount = 0;
|
|
194
|
+
wordsSinceBreak++;
|
|
195
|
+
await sleep(charDelay + (Math.random() * 50 + 20));
|
|
196
|
+
if (rawText.length > 80 && wordsSinceBreak >= 12 && Math.random() < 0.20) {
|
|
197
|
+
wtThought(session, `typing ${rawText.slice(0, 18).trim()}...`);
|
|
198
|
+
await sleep(380 + Math.random() * 520);
|
|
199
|
+
wordsSinceBreak = 0;
|
|
200
|
+
}
|
|
201
|
+
prevChar = char;
|
|
202
|
+
charsTypedInGroup = 0;
|
|
203
|
+
currentGroupSize = Math.floor(Math.random() * (p.groupSize[1] - p.groupSize[0] + 1)) + p.groupSize[0];
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
// ── Punctuation: flush group + pause ────────────────────────────────────
|
|
207
|
+
if (/[.,!?;:]/.test(char)) {
|
|
208
|
+
await flushGroup();
|
|
209
|
+
wordCharCount = 0;
|
|
210
|
+
await sleep(charDelay + (Math.random() * 150 + 100));
|
|
211
|
+
prevChar = char;
|
|
212
|
+
charsTypedInGroup = 0;
|
|
213
|
+
currentGroupSize = Math.floor(Math.random() * (p.groupSize[1] - p.groupSize[0] + 1)) + p.groupSize[0];
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
// ── Group boundary: flush buffer + pause ────────────────────────────────
|
|
217
|
+
if (charsTypedInGroup >= currentGroupSize) {
|
|
218
|
+
await flushGroup();
|
|
219
|
+
const groupPause = Math.random() * (p.interGroupMax - p.interGroupMin) + p.interGroupMin;
|
|
220
|
+
await sleep(groupPause);
|
|
221
|
+
charsTypedInGroup = 0;
|
|
222
|
+
currentGroupSize = Math.floor(Math.random() * (p.groupSize[1] - p.groupSize[0] + 1)) + p.groupSize[0];
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
await sleep(charDelay);
|
|
226
|
+
}
|
|
227
|
+
// ── Periodic focus verification (every 5 chars) ───────────────────────
|
|
228
|
+
if (targetSelector && i > 0 && i % 5 === 0) {
|
|
229
|
+
const focusOk = await session.Runtime.evaluate({
|
|
230
|
+
expression: `(function(sel) {
|
|
231
|
+
try {
|
|
232
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
233
|
+
return el ? document.activeElement === el || el.contains(document.activeElement) : true;
|
|
234
|
+
} catch(e) { return true; }
|
|
235
|
+
})(${JSON.stringify(targetSelector)})`,
|
|
236
|
+
returnByValue: true,
|
|
237
|
+
}).catch(() => ({ result: { value: true } }));
|
|
238
|
+
if (focusOk?.result?.value === false) {
|
|
239
|
+
await flushGroup();
|
|
240
|
+
const coords = await session.Runtime.evaluate({
|
|
241
|
+
expression: `(function(sel){
|
|
242
|
+
const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
|
|
243
|
+
if (!el) return null;
|
|
244
|
+
const r = el.getBoundingClientRect();
|
|
245
|
+
return { x: Math.round(r.left + r.width/2), y: Math.round(r.top + r.height/2) };
|
|
246
|
+
})(${JSON.stringify(targetSelector)})`,
|
|
247
|
+
returnByValue: true,
|
|
248
|
+
}).catch(() => null);
|
|
249
|
+
const c = coords?.result?.value;
|
|
250
|
+
if (c) {
|
|
251
|
+
await session.Input.dispatchMouseEvent({ type: 'mousePressed', x: c.x, y: c.y, button: 'left', clickCount: 1 });
|
|
252
|
+
await session.Input.dispatchMouseEvent({ type: 'mouseReleased', x: c.x, y: c.y, button: 'left', clickCount: 1 });
|
|
253
|
+
await sleep(60);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
prevChar = char;
|
|
258
|
+
}
|
|
259
|
+
// Flush any remaining buffered characters
|
|
260
|
+
await flushGroup();
|
|
261
|
+
wtCursor(session, currentX, currentY, "idle");
|
|
262
|
+
// Short pause after typing (human reviews what they typed)
|
|
263
|
+
await sleep(180 + Math.random() * 280);
|
|
264
|
+
}
|
|
265
|
+
// ─── 2. Ghost Cursor (Bezier Paths & Overshoot) ──────────────────────────────
|
|
266
|
+
let currentX = -1;
|
|
267
|
+
let currentY = -1;
|
|
268
|
+
function cubicBezier(t, p0, p1, p2, p3) {
|
|
269
|
+
const u = 1 - t;
|
|
270
|
+
return (u * u * u * p0) + (3 * u * u * t * p1) + (3 * u * t * t * p2) + (t * t * t * p3);
|
|
271
|
+
}
|
|
272
|
+
let _firstMoveDone = false;
|
|
273
|
+
export async function ghostMove(session, targetX, targetY, config, label, profile, cursorOpts) {
|
|
274
|
+
const resolvedProfile = profile || (getConfigHeadless(config) ? "instant" : "human");
|
|
275
|
+
if (resolvedProfile === "instant") {
|
|
276
|
+
await session.Input.dispatchMouseEvent({ type: "mouseMoved", x: targetX, y: targetY, button: "none" });
|
|
277
|
+
currentX = targetX;
|
|
278
|
+
currentY = targetY;
|
|
279
|
+
wtCursor(session, targetX, targetY, "hover", cursorOpts);
|
|
280
|
+
recordCursorPosition(targetX, targetY);
|
|
281
|
+
await session.Runtime.evaluate({
|
|
282
|
+
expression: `(function(){
|
|
283
|
+
var el = document.elementFromPoint(${targetX}, ${targetY});
|
|
284
|
+
if (el) {
|
|
285
|
+
el.dispatchEvent(new MouseEvent('mouseover', {bubbles:true,cancelable:true,clientX:${targetX},clientY:${targetY}}));
|
|
286
|
+
el.dispatchEvent(new MouseEvent('mouseenter', {bubbles:false,cancelable:true,clientX:${targetX},clientY:${targetY}}));
|
|
287
|
+
}
|
|
288
|
+
})()`
|
|
289
|
+
}).catch(() => { });
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (resolvedProfile === "fast") {
|
|
293
|
+
const steps = 4;
|
|
294
|
+
const startX = currentX === -1 ? targetX : currentX;
|
|
295
|
+
const startY = currentY === -1 ? targetY : currentY;
|
|
296
|
+
for (let i = 1; i <= steps; i++) {
|
|
297
|
+
const t = i / steps;
|
|
298
|
+
const x = Math.round(startX + (targetX - startX) * t);
|
|
299
|
+
const y = Math.round(startY + (targetY - startY) * t);
|
|
300
|
+
await session.Input.dispatchMouseEvent({ type: "mouseMoved", x, y, button: "none" });
|
|
301
|
+
currentX = x;
|
|
302
|
+
currentY = y;
|
|
303
|
+
wtCursor(session, x, y, "moving", cursorOpts);
|
|
304
|
+
await sleep(5);
|
|
305
|
+
}
|
|
306
|
+
currentX = targetX;
|
|
307
|
+
currentY = targetY;
|
|
308
|
+
wtCursor(session, targetX, targetY, "hover", cursorOpts);
|
|
309
|
+
recordCursorPosition(targetX, targetY);
|
|
310
|
+
await session.Input.dispatchMouseEvent({ type: "mouseMoved", x: targetX, y: targetY, button: "none" });
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (!_firstMoveDone) {
|
|
314
|
+
logDebug(`[Weavetab Ghost] First mouse move → (${targetX}, ${targetY}) — CDP session active`);
|
|
315
|
+
_firstMoveDone = true;
|
|
316
|
+
}
|
|
317
|
+
// Don't fake-init cursor position — injector.ts hides cursor until first real move
|
|
318
|
+
if (currentX === -1 && currentY === -1) {
|
|
319
|
+
currentX = targetX;
|
|
320
|
+
currentY = targetY;
|
|
321
|
+
wtCursor(session, targetX, targetY, "hover", cursorOpts);
|
|
322
|
+
recordCursorPosition(targetX, targetY);
|
|
323
|
+
await session.Input.dispatchMouseEvent({ type: "mouseMoved", x: targetX, y: targetY, button: "none" });
|
|
324
|
+
await session.Runtime.evaluate({
|
|
325
|
+
expression: `(function(){
|
|
326
|
+
var el = document.elementFromPoint(${targetX}, ${targetY});
|
|
327
|
+
if (el) {
|
|
328
|
+
el.dispatchEvent(new MouseEvent('mouseover', {bubbles:true,cancelable:true,clientX:${targetX},clientY:${targetY}}));
|
|
329
|
+
el.dispatchEvent(new MouseEvent('mouseenter', {bubbles:false,cancelable:true,clientX:${targetX},clientY:${targetY}}));
|
|
330
|
+
}
|
|
331
|
+
})()`
|
|
332
|
+
}).catch(() => { });
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const dx = targetX - currentX;
|
|
336
|
+
const dy = targetY - currentY;
|
|
337
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
338
|
+
wtCursor(session, currentX, currentY, label && distance >= 150 ? "searching" : "idle", cursorOpts);
|
|
339
|
+
if (label && distance >= 150 && getConfigVisuals(config) !== false) {
|
|
340
|
+
wtThought(session, `moving to ${label.slice(0, 40)}...`);
|
|
341
|
+
await sleep(80 + Math.random() * 120);
|
|
342
|
+
}
|
|
343
|
+
if (distance < 150) {
|
|
344
|
+
currentX = targetX;
|
|
345
|
+
currentY = targetY;
|
|
346
|
+
await session.Input.dispatchMouseEvent({ type: "mouseMoved", x: targetX, y: targetY, button: "none" });
|
|
347
|
+
wtCursor(session, targetX, targetY, "hover", cursorOpts);
|
|
348
|
+
recordCursorPosition(targetX, targetY);
|
|
349
|
+
await session.Runtime.evaluate({
|
|
350
|
+
expression: `(function(){
|
|
351
|
+
var el = document.elementFromPoint(${targetX}, ${targetY});
|
|
352
|
+
if (el) {
|
|
353
|
+
el.dispatchEvent(new MouseEvent('mouseover', {bubbles:true,cancelable:true,clientX:${targetX},clientY:${targetY}}));
|
|
354
|
+
el.dispatchEvent(new MouseEvent('mouseenter', {bubbles:false,cancelable:true,clientX:${targetX},clientY:${targetY}}));
|
|
355
|
+
}
|
|
356
|
+
})()`
|
|
357
|
+
}).catch(() => { });
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
const duration = Math.max(80, Math.min(300, distance * 0.6));
|
|
361
|
+
let steps = Math.floor(duration / 16);
|
|
362
|
+
if (steps > 10)
|
|
363
|
+
steps = 10;
|
|
364
|
+
if (steps < 3)
|
|
365
|
+
steps = 3;
|
|
366
|
+
const cp1X = currentX + dx * 0.2 + randomGaussian(0, distance * 0.2);
|
|
367
|
+
const cp1Y = currentY + dy * 0.2 + randomGaussian(0, distance * 0.2);
|
|
368
|
+
const cp2X = currentX + dx * 0.8 + randomGaussian(0, distance * 0.2);
|
|
369
|
+
const cp2Y = currentY + dy * 0.8 + randomGaussian(0, distance * 0.2);
|
|
370
|
+
const doOvershoot = distance >= 300 && Math.random() > 0.3;
|
|
371
|
+
const overshootAmount = doOvershoot ? randomGaussian(10, 5) : 0;
|
|
372
|
+
const angle = Math.atan2(dy, dx);
|
|
373
|
+
const overshootX = targetX + Math.cos(angle) * overshootAmount;
|
|
374
|
+
const overshootY = targetY + Math.sin(angle) * overshootAmount;
|
|
375
|
+
wtCursor(session, targetX, targetY, "idle", cursorOpts);
|
|
376
|
+
const waypoints = [];
|
|
377
|
+
for (let i = 1; i <= steps; i++) {
|
|
378
|
+
let t = i / steps;
|
|
379
|
+
t = 1 - Math.pow(1 - t, 4);
|
|
380
|
+
const actualTargetX = doOvershoot && i < steps * 0.8 ? overshootX : targetX;
|
|
381
|
+
const actualTargetY = doOvershoot && i < steps * 0.8 ? overshootY : targetY;
|
|
382
|
+
waypoints.push({
|
|
383
|
+
x: cubicBezier(t, currentX, cp1X, cp2X, actualTargetX),
|
|
384
|
+
y: cubicBezier(t, currentY, cp1Y, cp2Y, actualTargetY)
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
// Pre-announce the move
|
|
388
|
+
sendToExtension(session, {
|
|
389
|
+
type: 'Weavetab_STATE',
|
|
390
|
+
cursor: { waypoints, duration_ms: steps * 8, x: currentX, y: currentY },
|
|
391
|
+
state: "moving"
|
|
392
|
+
}).catch(() => { });
|
|
393
|
+
for (let i = 1; i <= steps; i++) {
|
|
394
|
+
const x = waypoints[i - 1].x;
|
|
395
|
+
const y = waypoints[i - 1].y;
|
|
396
|
+
await session.Input.dispatchMouseEvent({ type: "mouseMoved", x, y, button: "none" });
|
|
397
|
+
currentX = x;
|
|
398
|
+
currentY = y;
|
|
399
|
+
wtCursor(session, x, y, "moving", cursorOpts);
|
|
400
|
+
await sleep(8);
|
|
401
|
+
}
|
|
402
|
+
currentX = targetX;
|
|
403
|
+
currentY = targetY;
|
|
404
|
+
wtCursor(session, targetX, targetY, "hover", cursorOpts);
|
|
405
|
+
recordCursorPosition(targetX, targetY);
|
|
406
|
+
if (label)
|
|
407
|
+
wtClearThought(session);
|
|
408
|
+
await session.Input.dispatchMouseEvent({ type: "mouseMoved", x: targetX, y: targetY, button: "none" });
|
|
409
|
+
await session.Runtime.evaluate({
|
|
410
|
+
expression: `(function(){
|
|
411
|
+
var el = document.elementFromPoint(${targetX}, ${targetY});
|
|
412
|
+
if (el) {
|
|
413
|
+
el.dispatchEvent(new MouseEvent('mouseover', {bubbles:true,cancelable:true,view:window,clientX:${targetX},clientY:${targetY}}));
|
|
414
|
+
el.dispatchEvent(new MouseEvent('mouseenter', {bubbles:false,cancelable:true,view:window,clientX:${targetX},clientY:${targetY}}));
|
|
415
|
+
}
|
|
416
|
+
})()`
|
|
417
|
+
}).catch(() => { });
|
|
418
|
+
}
|
|
419
|
+
// ─── 3. Reading Simulation ───────────────────────────────────────────────────
|
|
420
|
+
let readingPromise = null;
|
|
421
|
+
/** Cancel simulated reading so actions don't wait 15s. */
|
|
422
|
+
export function cancelReading() {
|
|
423
|
+
readingPromise = null;
|
|
424
|
+
}
|
|
425
|
+
export function startReadingSimulation(session, wordCount, config) {
|
|
426
|
+
if (getConfigHeadless(config))
|
|
427
|
+
return;
|
|
428
|
+
const readTimeMs = Math.min((wordCount / 200) * 60000, 3000);
|
|
429
|
+
if (readTimeMs < 300)
|
|
430
|
+
return;
|
|
431
|
+
readingPromise = (async () => {
|
|
432
|
+
const startTime = Date.now();
|
|
433
|
+
let lastScrollTime = startTime;
|
|
434
|
+
wtThought(session, "reading the page...");
|
|
435
|
+
while (Date.now() - startTime < readTimeMs) {
|
|
436
|
+
const now = Date.now();
|
|
437
|
+
if (Math.random() < 0.1) {
|
|
438
|
+
currentX += randomGaussian(0, 3);
|
|
439
|
+
currentY += randomGaussian(0, 3);
|
|
440
|
+
await session.Input.dispatchMouseEvent({ type: "mouseMoved", x: currentX, y: currentY, button: "none" }).catch(() => { });
|
|
441
|
+
wtCursor(session, currentX, currentY, "reading");
|
|
442
|
+
}
|
|
443
|
+
if (now - lastScrollTime > 1500 && Math.random() < 0.5) {
|
|
444
|
+
const totalScroll = randomGaussian(150, 50);
|
|
445
|
+
const scrollSteps = Math.floor(totalScroll / 5);
|
|
446
|
+
for (let i = 0; i < scrollSteps; i++) {
|
|
447
|
+
await session.Input.dispatchMouseEvent({
|
|
448
|
+
type: "mouseWheel",
|
|
449
|
+
x: currentX, y: currentY,
|
|
450
|
+
deltaX: 0, deltaY: 5
|
|
451
|
+
}).catch(() => { });
|
|
452
|
+
await sleep(16);
|
|
453
|
+
}
|
|
454
|
+
lastScrollTime = Date.now();
|
|
455
|
+
}
|
|
456
|
+
await sleep(100);
|
|
457
|
+
}
|
|
458
|
+
readingPromise = null;
|
|
459
|
+
wtClearThought(session);
|
|
460
|
+
})();
|
|
461
|
+
}
|
|
462
|
+
export async function waitForReading() {
|
|
463
|
+
// Never block actions on reading simulation — it made clicks/types feel frozen
|
|
464
|
+
cancelReading();
|
|
465
|
+
}
|
|
466
|
+
// ─── 4. Visual Feedback for Action Results ─────────────────────────────────────
|
|
467
|
+
// Shows a brief visual indicator (success checkmark / failure X) via the HUD.
|
|
468
|
+
export async function ghostResult(session, success, actionType, detail) {
|
|
469
|
+
const icon = success ? "✓" : "✗";
|
|
470
|
+
const label = detail ? `${icon} ${actionType}: ${detail}` : `${icon} ${actionType}`;
|
|
471
|
+
await wtThought(session, label);
|
|
472
|
+
await sleep(success ? 400 : 800);
|
|
473
|
+
if (success) {
|
|
474
|
+
await wtClearThought(session);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
// ─── 5. Cursor Trail Customization ─────────────────────────────────────────────
|
|
478
|
+
// Stores the last N cursor positions so the extension can render a trail.
|
|
479
|
+
const cursorHistory = [];
|
|
480
|
+
const MAX_TRAIL_LENGTH = 20;
|
|
481
|
+
export function recordCursorPosition(x, y) {
|
|
482
|
+
cursorHistory.push({ x, y, t: Date.now() });
|
|
483
|
+
if (cursorHistory.length > MAX_TRAIL_LENGTH) {
|
|
484
|
+
cursorHistory.shift();
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
export function getCursorTrail(length) {
|
|
488
|
+
const n = length ?? cursorHistory.length;
|
|
489
|
+
return cursorHistory.slice(-n);
|
|
490
|
+
}
|
|
491
|
+
export function clearCursorTrail() {
|
|
492
|
+
cursorHistory.length = 0;
|
|
493
|
+
}
|
|
494
|
+
// ─── 6. Action and Lifecycle Hooks ─────────────────────────────────────────────
|
|
495
|
+
export async function ghostClick(session, x, y, options) {
|
|
496
|
+
await session.Input.dispatchMouseEvent({ type: 'mousePressed', x, y, button: 'left', clickCount: options?.clickCount || 1, ...options });
|
|
497
|
+
sendToExtension(session, {
|
|
498
|
+
type: 'Weavetab_STATE',
|
|
499
|
+
ripple: { x, y },
|
|
500
|
+
state: 'clicking'
|
|
501
|
+
}).catch(() => { });
|
|
502
|
+
}
|
|
503
|
+
export function ghostWait(session) {
|
|
504
|
+
wtCursor(session, currentX, currentY, "waiting");
|
|
505
|
+
}
|
|
506
|
+
export function ghostIdle(session) {
|
|
507
|
+
wtCursor(session, currentX, currentY, "idle");
|
|
508
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/overlay/injector.ts
|
|
3
|
+
* Weavetab — Browser Presence Layer v3 (stripped)
|
|
4
|
+
*
|
|
5
|
+
* Kept: __wt_plan (mission dashboard), SPA nav detection,
|
|
6
|
+
* __wt_setConfig, __wt_status, favicon state.
|
|
7
|
+
* Removed: cursor (moved to content.js), chat panel, thought bubble,
|
|
8
|
+
* ask modal, screen glow, CSS keyframes, emoji system.
|
|
9
|
+
*
|
|
10
|
+
* @module overlay/injector
|
|
11
|
+
*/
|
|
12
|
+
import CDP from "chrome-remote-interface";
|
|
13
|
+
import type { Config } from "../config/loader.js";
|
|
14
|
+
export type CursorState = "idle" | "hover" | "clicking" | "typing" | "thinking" | "searching" | "reading" | "navigating" | "scrolling" | "dragging" | "burst" | "waiting" | "github" | "stuck" | "eval" | "clear";
|
|
15
|
+
export declare function getMinimalOverlayScript(): string;
|
|
16
|
+
export declare const INSTALL_EXPR = "if(window.__wt_install_minimal)window.__wt_install_minimal();";
|
|
17
|
+
export declare function ensureVisualLayer(session: CDP.Client, config: Config, client?: import("../cdp/connector.js").BrowserClient): Promise<void>;
|
|
18
|
+
export declare function setupOverlay(session: CDP.Client, config: Config): Promise<void>;
|
|
19
|
+
export declare function setFaviconState(_session: CDP.Client, _state: CursorState): Promise<void>;
|
|
20
|
+
export declare function removeTitleBadge(_session: CDP.Client): Promise<void>;
|
|
21
|
+
export declare function hideCursor(session: CDP.Client): Promise<void>;
|
|
22
|
+
export declare function setCursorState(session: CDP.Client, state: CursorState): Promise<void>;
|