@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/state/delta.test.js
DELETED
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* delta.test.ts — Phase 1.1
|
|
3
|
-
* Unit tests for snapshot diffing and delta computation.
|
|
4
|
-
*/
|
|
5
|
-
import { test } from "node:test";
|
|
6
|
-
import assert from "node:assert/strict";
|
|
7
|
-
import { storeSnapshot, computeDelta, seedRichSnapshot, computeRichDelta, clearAllSnapshots, } from "./delta.js";
|
|
8
|
-
test("delta: first visit returns null (no baseline)", () => {
|
|
9
|
-
const targetId = "tab-1";
|
|
10
|
-
clearAllSnapshots();
|
|
11
|
-
const refs = [
|
|
12
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
13
|
-
];
|
|
14
|
-
const result = computeDelta(targetId, 'http://test.com', refs);
|
|
15
|
-
assert.equal(result, null, "First visit should return null");
|
|
16
|
-
});
|
|
17
|
-
test("delta: detects added elements", () => {
|
|
18
|
-
const targetId = "tab-2";
|
|
19
|
-
clearAllSnapshots();
|
|
20
|
-
const initial = [
|
|
21
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
22
|
-
];
|
|
23
|
-
storeSnapshot(targetId, 'http://test.com', initial);
|
|
24
|
-
const updated = [
|
|
25
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
26
|
-
{ id: "w:2", role: "link", label: "Home", fingerprint: "link:home:nav:1" },
|
|
27
|
-
];
|
|
28
|
-
const result = computeDelta(targetId, 'http://test.com', updated);
|
|
29
|
-
assert.ok(result !== null);
|
|
30
|
-
assert.equal(result?.added.length, 1, "One element added");
|
|
31
|
-
assert.equal(result?.added[0]?.id, "w:2");
|
|
32
|
-
assert.equal(result?.removed.length, 0);
|
|
33
|
-
assert.equal(result?.changed.length, 0);
|
|
34
|
-
});
|
|
35
|
-
test("delta: detects removed elements", () => {
|
|
36
|
-
const targetId = "tab-3";
|
|
37
|
-
clearAllSnapshots();
|
|
38
|
-
const initial = [
|
|
39
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
40
|
-
{ id: "w:2", role: "link", label: "Home", fingerprint: "link:home:nav:1" },
|
|
41
|
-
];
|
|
42
|
-
storeSnapshot(targetId, 'http://test.com', initial);
|
|
43
|
-
const updated = [
|
|
44
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
45
|
-
];
|
|
46
|
-
const result = computeDelta(targetId, 'http://test.com', updated);
|
|
47
|
-
assert.ok(result !== null);
|
|
48
|
-
assert.equal(result?.added.length, 0);
|
|
49
|
-
assert.equal(result?.removed.length, 1, "One element removed");
|
|
50
|
-
assert.equal(result?.removed[0], "w:2");
|
|
51
|
-
assert.equal(result?.changed.length, 0);
|
|
52
|
-
});
|
|
53
|
-
test("delta: detects changed elements (label)", () => {
|
|
54
|
-
const targetId = "tab-4";
|
|
55
|
-
clearAllSnapshots();
|
|
56
|
-
const initial = [
|
|
57
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
58
|
-
];
|
|
59
|
-
storeSnapshot(targetId, 'http://test.com', initial);
|
|
60
|
-
const updated = [
|
|
61
|
-
{ id: "w:1", role: "button", label: "Cancel", fingerprint: "button:cancel:div:0" },
|
|
62
|
-
];
|
|
63
|
-
const result = computeDelta(targetId, 'http://test.com', updated);
|
|
64
|
-
assert.ok(result !== null);
|
|
65
|
-
assert.equal(result?.added.length, 0);
|
|
66
|
-
assert.equal(result?.removed.length, 0);
|
|
67
|
-
assert.equal(result?.changed.length, 1, "One element changed");
|
|
68
|
-
assert.equal(result?.changed[0]?.id, "w:1");
|
|
69
|
-
assert.equal(result?.changed[0]?.label, "Cancel");
|
|
70
|
-
});
|
|
71
|
-
test("delta: detects changed elements (disabled)", () => {
|
|
72
|
-
const targetId = "tab-5";
|
|
73
|
-
clearAllSnapshots();
|
|
74
|
-
const initial = [
|
|
75
|
-
{ id: "w:1", role: "button", label: "Submit", disabled: false, fingerprint: "button:submit:div:0" },
|
|
76
|
-
];
|
|
77
|
-
storeSnapshot(targetId, 'http://test.com', initial);
|
|
78
|
-
const updated = [
|
|
79
|
-
{ id: "w:1", role: "button", label: "Submit", disabled: true, fingerprint: "button:submit:div:0" },
|
|
80
|
-
];
|
|
81
|
-
const result = computeDelta(targetId, 'http://test.com', updated);
|
|
82
|
-
assert.ok(result !== null);
|
|
83
|
-
assert.equal(result?.changed.length, 1, "Disabled state change detected");
|
|
84
|
-
assert.equal(result?.changed[0]?.disabled, true);
|
|
85
|
-
});
|
|
86
|
-
test("delta: detects changed elements (value)", () => {
|
|
87
|
-
const targetId = "tab-6";
|
|
88
|
-
clearAllSnapshots();
|
|
89
|
-
const initial = [
|
|
90
|
-
{ id: "w:1", role: "textbox", label: "Email", value: "", fingerprint: "textbox:email:form:0" },
|
|
91
|
-
];
|
|
92
|
-
storeSnapshot(targetId, 'http://test.com', initial);
|
|
93
|
-
const updated = [
|
|
94
|
-
{ id: "w:1", role: "textbox", label: "Email", value: "test@example.com", fingerprint: "textbox:email:form:0" },
|
|
95
|
-
];
|
|
96
|
-
const result = computeDelta(targetId, 'http://test.com', updated);
|
|
97
|
-
assert.ok(result !== null);
|
|
98
|
-
assert.equal(result?.changed.length, 1, "Value change detected");
|
|
99
|
-
assert.equal(result?.changed[0]?.value, "test@example.com");
|
|
100
|
-
});
|
|
101
|
-
test("delta: counts stable elements", () => {
|
|
102
|
-
const targetId = "tab-7";
|
|
103
|
-
clearAllSnapshots();
|
|
104
|
-
const initial = [
|
|
105
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
106
|
-
{ id: "w:2", role: "link", label: "Home", fingerprint: "link:home:nav:1" },
|
|
107
|
-
{ id: "w:3", role: "textbox", label: "Email", fingerprint: "textbox:email:form:0" },
|
|
108
|
-
];
|
|
109
|
-
storeSnapshot(targetId, 'http://test.com', initial);
|
|
110
|
-
const updated = [
|
|
111
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
112
|
-
{ id: "w:2", role: "link", label: "Home", fingerprint: "link:home:nav:1" },
|
|
113
|
-
{ id: "w:3", role: "textbox", label: "Email", value: "test@example.com", fingerprint: "textbox:email:form:0" },
|
|
114
|
-
];
|
|
115
|
-
const result = computeDelta(targetId, 'http://test.com', updated);
|
|
116
|
-
assert.ok(result !== null);
|
|
117
|
-
assert.equal(result?.stable_count, 2, "Two stable elements");
|
|
118
|
-
assert.equal(result?.changed.length, 1);
|
|
119
|
-
});
|
|
120
|
-
test("delta: updates stored snapshot", () => {
|
|
121
|
-
const targetId = "tab-8";
|
|
122
|
-
clearAllSnapshots();
|
|
123
|
-
const initial = [
|
|
124
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
125
|
-
];
|
|
126
|
-
storeSnapshot(targetId, 'http://test.com', initial);
|
|
127
|
-
const updated = [
|
|
128
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
129
|
-
{ id: "w:2", role: "link", label: "Home", fingerprint: "link:home:nav:1" },
|
|
130
|
-
];
|
|
131
|
-
computeDelta(targetId, 'http://test.com', updated);
|
|
132
|
-
// Second call should see no changes since snapshot was updated
|
|
133
|
-
const secondCall = computeDelta(targetId, 'http://test.com', updated);
|
|
134
|
-
assert.ok(secondCall !== null);
|
|
135
|
-
assert.equal(secondCall?.added.length, 0);
|
|
136
|
-
assert.equal(secondCall?.removed.length, 0);
|
|
137
|
-
assert.equal(secondCall?.changed.length, 0);
|
|
138
|
-
assert.equal(secondCall?.stable_count, 2);
|
|
139
|
-
});
|
|
140
|
-
test("delta: rich delta - first visit returns null", async () => {
|
|
141
|
-
const targetId = "tab-9";
|
|
142
|
-
clearAllSnapshots();
|
|
143
|
-
const elements = [
|
|
144
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0", group: "utility", depth: 0 },
|
|
145
|
-
];
|
|
146
|
-
const result = await computeRichDelta(targetId, 'http://test.com', elements);
|
|
147
|
-
assert.equal(result, null, "First visit rich delta returns null");
|
|
148
|
-
});
|
|
149
|
-
test("delta: rich delta - basic changed properties", async () => {
|
|
150
|
-
const targetId = "tab-10";
|
|
151
|
-
clearAllSnapshots();
|
|
152
|
-
const initial = [
|
|
153
|
-
{
|
|
154
|
-
id: "w:1",
|
|
155
|
-
role: "button",
|
|
156
|
-
label: "Submit",
|
|
157
|
-
value: "",
|
|
158
|
-
disabled: false,
|
|
159
|
-
fingerprint: "button:submit:div:0",
|
|
160
|
-
group: "utility",
|
|
161
|
-
depth: 0
|
|
162
|
-
},
|
|
163
|
-
];
|
|
164
|
-
// Seed the snapshot first
|
|
165
|
-
seedRichSnapshot(targetId, 'http://test.com', initial);
|
|
166
|
-
const updated = [
|
|
167
|
-
{
|
|
168
|
-
id: "w:1",
|
|
169
|
-
role: "button",
|
|
170
|
-
label: "Submit",
|
|
171
|
-
value: "",
|
|
172
|
-
disabled: true,
|
|
173
|
-
fingerprint: "button:submit:div:0",
|
|
174
|
-
group: "utility",
|
|
175
|
-
depth: 0
|
|
176
|
-
},
|
|
177
|
-
];
|
|
178
|
-
const result = await computeRichDelta(targetId, 'http://test.com', updated);
|
|
179
|
-
assert.ok(result !== null);
|
|
180
|
-
assert.ok(!("delta_timeout" in result));
|
|
181
|
-
const diff = result;
|
|
182
|
-
assert.equal(diff.changed.length, 1);
|
|
183
|
-
assert.equal(diff.changed[0]?.ref, "w:1");
|
|
184
|
-
assert.ok("disabled" in diff.changed[0]?.changes);
|
|
185
|
-
assert.equal(diff.changed[0]?.changes?.disabled?.from, "false");
|
|
186
|
-
assert.equal(diff.changed[0]?.changes?.disabled?.to, "true");
|
|
187
|
-
});
|
|
188
|
-
test("delta: rich delta - marks interactive elements as actionable", async () => {
|
|
189
|
-
const targetId = "tab-11";
|
|
190
|
-
clearAllSnapshots();
|
|
191
|
-
const initial = [
|
|
192
|
-
{
|
|
193
|
-
id: "w:1",
|
|
194
|
-
role: "button",
|
|
195
|
-
label: "Submit",
|
|
196
|
-
fingerprint: "button:submit:div:0",
|
|
197
|
-
group: "utility",
|
|
198
|
-
depth: 0
|
|
199
|
-
},
|
|
200
|
-
];
|
|
201
|
-
// Seed the snapshot first
|
|
202
|
-
seedRichSnapshot(targetId, 'http://test.com', initial);
|
|
203
|
-
const updated = [
|
|
204
|
-
{
|
|
205
|
-
id: "w:1",
|
|
206
|
-
role: "button",
|
|
207
|
-
label: "Submit",
|
|
208
|
-
value: "",
|
|
209
|
-
disabled: false, // Changed from undefined/missing to false
|
|
210
|
-
fingerprint: "button:submit:div:0",
|
|
211
|
-
group: "utility",
|
|
212
|
-
depth: 0
|
|
213
|
-
},
|
|
214
|
-
];
|
|
215
|
-
const result = await computeRichDelta(targetId, 'http://test.com', updated);
|
|
216
|
-
assert.ok(result !== null);
|
|
217
|
-
assert.ok(!("delta_timeout" in result));
|
|
218
|
-
const diff = result;
|
|
219
|
-
assert.equal(diff.changed.length, 1);
|
|
220
|
-
assert.equal(diff.changed[0]?.actionable, true);
|
|
221
|
-
assert.equal(diff.changed[0]?.recommended_action, "click");
|
|
222
|
-
});
|
|
223
|
-
test("delta: rich delta - iframe tracking", async () => {
|
|
224
|
-
const targetId = "tab-12";
|
|
225
|
-
clearAllSnapshots();
|
|
226
|
-
const initial = [
|
|
227
|
-
{
|
|
228
|
-
id: "w:1",
|
|
229
|
-
role: "button",
|
|
230
|
-
label: "Submit",
|
|
231
|
-
frameUrl: "https://example.com",
|
|
232
|
-
fingerprint: "button:submit:div:0",
|
|
233
|
-
group: "utility",
|
|
234
|
-
depth: 0
|
|
235
|
-
},
|
|
236
|
-
];
|
|
237
|
-
// Seed the snapshot first
|
|
238
|
-
seedRichSnapshot(targetId, 'http://test.com', initial);
|
|
239
|
-
const updated = [
|
|
240
|
-
{
|
|
241
|
-
id: "w:1",
|
|
242
|
-
role: "button",
|
|
243
|
-
label: "Submit",
|
|
244
|
-
frameUrl: "https://example.com",
|
|
245
|
-
fingerprint: "button:submit:div:0",
|
|
246
|
-
group: "utility",
|
|
247
|
-
depth: 0
|
|
248
|
-
},
|
|
249
|
-
{
|
|
250
|
-
id: "w:2",
|
|
251
|
-
role: "link",
|
|
252
|
-
label: "Home",
|
|
253
|
-
frameUrl: "https://iframe.com",
|
|
254
|
-
fingerprint: "link:home:nav:1",
|
|
255
|
-
group: "navigation",
|
|
256
|
-
depth: 1
|
|
257
|
-
},
|
|
258
|
-
];
|
|
259
|
-
const result = await computeRichDelta(targetId, 'http://test.com', updated);
|
|
260
|
-
assert.ok(result !== null);
|
|
261
|
-
assert.ok(!("delta_timeout" in result));
|
|
262
|
-
const diff = result;
|
|
263
|
-
assert.ok(diff.iframes !== undefined);
|
|
264
|
-
assert.equal(diff.iframes?.length, 1);
|
|
265
|
-
assert.equal(diff.iframes?.[0]?.status, "added");
|
|
266
|
-
assert.equal(diff.iframes?.[0]?.frameUrl, "https://iframe.com");
|
|
267
|
-
});
|
|
268
|
-
test("delta: clearSnapshot removes all data", () => {
|
|
269
|
-
const targetId = "tab-13";
|
|
270
|
-
const refs = [
|
|
271
|
-
{ id: "w:1", role: "button", label: "Submit", fingerprint: "button:submit:div:0" },
|
|
272
|
-
];
|
|
273
|
-
storeSnapshot(targetId, 'http://test.com', refs);
|
|
274
|
-
seedRichSnapshot(targetId, 'http://test.com', []);
|
|
275
|
-
clearAllSnapshots();
|
|
276
|
-
const result = computeDelta(targetId, 'http://test.com', refs);
|
|
277
|
-
assert.equal(result, null, "Cache cleared");
|
|
278
|
-
});
|
|
279
|
-
//# sourceMappingURL=delta.test.js.map
|
package/dist/state/groups.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import CDP from "chrome-remote-interface";
|
|
2
|
-
interface GroupEntry {
|
|
3
|
-
groupName: string;
|
|
4
|
-
tabIds: string[];
|
|
5
|
-
}
|
|
6
|
-
interface GroupStore {
|
|
7
|
-
[windowId: number]: GroupEntry[];
|
|
8
|
-
}
|
|
9
|
-
export declare function saveGroup(windowId: number, groupName: string, tabIds: string[]): void;
|
|
10
|
-
export declare function removeTabFromGroups(tabId: string): void;
|
|
11
|
-
export declare function clearStore(): void;
|
|
12
|
-
export declare function getStore(): GroupStore;
|
|
13
|
-
export declare function restoreGroups(session: CDP.Client): Promise<void>;
|
|
14
|
-
export {};
|
|
15
|
-
//# sourceMappingURL=groups.d.ts.map
|
package/dist/state/groups.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import * as os from "node:os";
|
|
4
|
-
const GROUPS_DIR = path.join(os.homedir(), ".Weavetab-system", "groups");
|
|
5
|
-
const GROUPS_FILE = path.join(GROUPS_DIR, "groups.json");
|
|
6
|
-
function ensureDir() {
|
|
7
|
-
if (!fs.existsSync(GROUPS_DIR)) {
|
|
8
|
-
fs.mkdirSync(GROUPS_DIR, { recursive: true });
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
function readStore() {
|
|
12
|
-
try {
|
|
13
|
-
if (fs.existsSync(GROUPS_FILE)) {
|
|
14
|
-
return JSON.parse(fs.readFileSync(GROUPS_FILE, "utf-8"));
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
// corrupted — reset
|
|
19
|
-
}
|
|
20
|
-
return {};
|
|
21
|
-
}
|
|
22
|
-
function writeStore(store) {
|
|
23
|
-
ensureDir();
|
|
24
|
-
fs.writeFileSync(GROUPS_FILE, JSON.stringify(store), "utf-8");
|
|
25
|
-
}
|
|
26
|
-
export function saveGroup(windowId, groupName, tabIds) {
|
|
27
|
-
const store = readStore();
|
|
28
|
-
if (!store[windowId])
|
|
29
|
-
store[windowId] = [];
|
|
30
|
-
const existing = store[windowId].find(g => g.groupName === groupName);
|
|
31
|
-
if (existing) {
|
|
32
|
-
existing.tabIds = tabIds;
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
store[windowId].push({ groupName, tabIds });
|
|
36
|
-
}
|
|
37
|
-
writeStore(store);
|
|
38
|
-
}
|
|
39
|
-
export function removeTabFromGroups(tabId) {
|
|
40
|
-
const store = readStore();
|
|
41
|
-
let changed = false;
|
|
42
|
-
for (const windowId of Object.keys(store)) {
|
|
43
|
-
const groups = store[Number(windowId)];
|
|
44
|
-
for (const group of groups) {
|
|
45
|
-
const idx = group.tabIds.indexOf(tabId);
|
|
46
|
-
if (idx !== -1) {
|
|
47
|
-
group.tabIds.splice(idx, 1);
|
|
48
|
-
changed = true;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
store[Number(windowId)] = groups.filter(g => g.tabIds.length > 0);
|
|
52
|
-
}
|
|
53
|
-
if (changed)
|
|
54
|
-
writeStore(store);
|
|
55
|
-
}
|
|
56
|
-
export function clearStore() {
|
|
57
|
-
try {
|
|
58
|
-
if (fs.existsSync(GROUPS_FILE))
|
|
59
|
-
fs.unlinkSync(GROUPS_FILE);
|
|
60
|
-
}
|
|
61
|
-
catch { /* ignore */ }
|
|
62
|
-
}
|
|
63
|
-
export function getStore() {
|
|
64
|
-
return readStore();
|
|
65
|
-
}
|
|
66
|
-
export async function restoreGroups(session) {
|
|
67
|
-
const store = readStore();
|
|
68
|
-
const entries = Object.entries(store).flatMap(([windowId, groups]) => groups.map(g => ({ windowId: Number(windowId), groupName: g.groupName, tabIds: g.tabIds })));
|
|
69
|
-
if (entries.length === 0)
|
|
70
|
-
return;
|
|
71
|
-
try {
|
|
72
|
-
const { sendToExtension } = await import("../cdp/helpers.js");
|
|
73
|
-
await sendToExtension(session, {
|
|
74
|
-
type: "Weavetab_RESTORE_GROUPS",
|
|
75
|
-
groups: entries,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
catch { /* best-effort */ }
|
|
79
|
-
}
|
|
80
|
-
//# sourceMappingURL=groups.js.map
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Weavetab — tools/accessibility.ts
|
|
3
|
-
* browser_accessibility: returns the full Chrome accessibility tree via Accessibility.getFullAXTree.
|
|
4
|
-
*
|
|
5
|
-
* Use this to understand ARIA-heavy UIs when the standard DOM map is insufficient.
|
|
6
|
-
* Weavetab by fy2ne
|
|
7
|
-
*/
|
|
8
|
-
import CDP from "chrome-remote-interface";
|
|
9
|
-
import type { Config } from "../config/loader.js";
|
|
10
|
-
export interface AccessibilityResult {
|
|
11
|
-
success: boolean;
|
|
12
|
-
tree: any;
|
|
13
|
-
}
|
|
14
|
-
export declare function browserAccessibility(session: CDP.Client, _config: Config): Promise<AccessibilityResult>;
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export async function browserAccessibility(session, _config) {
|
|
2
|
-
try {
|
|
3
|
-
// Enable Accessibility domain
|
|
4
|
-
await session.Accessibility.enable();
|
|
5
|
-
const tree = await session.Accessibility.getFullAXTree();
|
|
6
|
-
// Simplify tree for LLM consumption
|
|
7
|
-
const simplify = (node) => {
|
|
8
|
-
if (node.ignored)
|
|
9
|
-
return null;
|
|
10
|
-
const role = node.role?.value;
|
|
11
|
-
const name = node.name?.value;
|
|
12
|
-
const value = node.value?.value;
|
|
13
|
-
const children = (node.children || []).map(simplify).filter(Boolean);
|
|
14
|
-
if (!name && children.length === 0 && !value)
|
|
15
|
-
return null; // skip noise
|
|
16
|
-
return {
|
|
17
|
-
role,
|
|
18
|
-
name: name || undefined,
|
|
19
|
-
value: value || undefined,
|
|
20
|
-
nodeId: node.nodeId,
|
|
21
|
-
backendDOMNodeId: node.backendDOMNodeId,
|
|
22
|
-
children: children.length > 0 ? children : undefined
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
const root = tree.nodes.find((n) => !n.parentId);
|
|
26
|
-
const simplifiedTree = simplify(root);
|
|
27
|
-
return { success: true, tree: simplifiedTree };
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
throw new Error(`Failed to get accessibility tree: ${error}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
package/dist/tools/ask.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import CDP from "chrome-remote-interface";
|
|
2
|
-
export interface AskResult {
|
|
3
|
-
success: true;
|
|
4
|
-
response: string;
|
|
5
|
-
timeout?: boolean;
|
|
6
|
-
}
|
|
7
|
-
export declare function browserAsk(session: CDP.Client, args: {
|
|
8
|
-
question: string;
|
|
9
|
-
}): Promise<AskResult | {
|
|
10
|
-
success: false;
|
|
11
|
-
error_code: string;
|
|
12
|
-
message: string;
|
|
13
|
-
}>;
|
|
14
|
-
//# sourceMappingURL=ask.d.ts.map
|
package/dist/tools/ask.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// src/tools/ask.ts
|
|
2
|
-
// browser_ask — renders ask UI in content.js via sendToExtension, polls result
|
|
3
|
-
import { logAction } from "../audit/logger.js";
|
|
4
|
-
import { sendToExtension } from "../cdp/helpers.js";
|
|
5
|
-
function sleep(ms) {
|
|
6
|
-
return new Promise(r => setTimeout(r, ms));
|
|
7
|
-
}
|
|
8
|
-
export async function browserAsk(session, args) {
|
|
9
|
-
const { question } = args;
|
|
10
|
-
const ASK_TIMEOUT_MS = 300000;
|
|
11
|
-
const COUNTDOWN_SEC = 300;
|
|
12
|
-
logAction("browser_ask", "prompting", question);
|
|
13
|
-
// Show HUD hint + waiting state
|
|
14
|
-
await sendToExtension(session, { type: 'Weavetab_STATE', state: 'waiting', hud: { action: question.slice(0, 40) + (question.length > 40 ? '...' : '') } });
|
|
15
|
-
// Show ask UI via content.js
|
|
16
|
-
await sendToExtension(session, { type: 'Weavetab_ASK', question }).catch(() => { });
|
|
17
|
-
// Poll for result via DOM bridge (shared between isolated & main worlds)
|
|
18
|
-
const start = Date.now();
|
|
19
|
-
while (Date.now() - start < ASK_TIMEOUT_MS) {
|
|
20
|
-
await sleep(500);
|
|
21
|
-
try {
|
|
22
|
-
const { result } = await session.Runtime.evaluate({
|
|
23
|
-
expression: `(() => { try {
|
|
24
|
-
var el = document.getElementById('__wt_ask_bridge');
|
|
25
|
-
if (!el || el.dataset.status === 'pending') return null;
|
|
26
|
-
return JSON.stringify({ status: el.dataset.status, result: el.dataset.result });
|
|
27
|
-
} catch(e) { return null; } })()`,
|
|
28
|
-
returnByValue: true,
|
|
29
|
-
});
|
|
30
|
-
if (result?.value) {
|
|
31
|
-
const data = JSON.parse(result.value);
|
|
32
|
-
if (data.status === 'submitted') {
|
|
33
|
-
logAction("browser_ask", "answered", data.result);
|
|
34
|
-
return { success: true, response: data.result };
|
|
35
|
-
}
|
|
36
|
-
if (data.status === 'cancelled' || data.status === 'timeout') {
|
|
37
|
-
logAction("browser_ask", data.status, "");
|
|
38
|
-
return { success: true, response: "", timeout: true };
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
// polling error — retry
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
logAction("browser_ask", "timeout", "");
|
|
47
|
-
return { success: true, response: "", timeout: true };
|
|
48
|
-
}
|
|
49
|
-
//# sourceMappingURL=ask.js.map
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import CDP from "chrome-remote-interface";
|
|
2
|
-
import type { Config } from "../config/loader.js";
|
|
3
|
-
import type { ClickResult, WeaveError } from "./click.js";
|
|
4
|
-
export interface ClickAndWaitOptions {
|
|
5
|
-
/** Element identifier - can be id, label, intent, or selector */
|
|
6
|
-
id?: string;
|
|
7
|
-
label?: string;
|
|
8
|
-
intent?: string;
|
|
9
|
-
/** Direct coordinates bypass */
|
|
10
|
-
x?: number;
|
|
11
|
-
y?: number;
|
|
12
|
-
/** Time to wait after click for page response (ms) */
|
|
13
|
-
waitAfter?: number;
|
|
14
|
-
/** Whether to wait for network idle after click */
|
|
15
|
-
waitForNetwork?: boolean;
|
|
16
|
-
/** Whether to return the page map after click */
|
|
17
|
-
includeMap?: boolean;
|
|
18
|
-
/** Fast mode - skip stability checks */
|
|
19
|
-
fast?: boolean;
|
|
20
|
-
/** Execute in a specific tab instead of active */
|
|
21
|
-
tab_id?: string;
|
|
22
|
-
}
|
|
23
|
-
export interface ClickAndWaitResult extends ClickResult {
|
|
24
|
-
/** Time waited after click */
|
|
25
|
-
waited_ms: number;
|
|
26
|
-
/** Whether network was idle after wait */
|
|
27
|
-
network_idle?: boolean;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Consolidated tool that combines element resolution, clicking, and waiting.
|
|
31
|
-
* Eliminates 2-3 tool calls in the common pattern: find → click → wait
|
|
32
|
-
*/
|
|
33
|
-
export declare function weaveClickAndWait(session: CDP.Client, args: ClickAndWaitOptions, config: Config): Promise<ClickAndWaitResult | WeaveError>;
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
// src/tools/click_and_wait.ts
|
|
2
|
-
// Consolidated tool: find element + click + wait for response in one CDP round-trip
|
|
3
|
-
// Eliminates the common pattern: browser_map → browser_click → browser_wait
|
|
4
|
-
import { buildActionMap, findBestMatch, safeSelector, toMarkdownTable } from "../cdp/walker.js";
|
|
5
|
-
import { recordAction, trackToolCall, detectStuckLoop } from "../intelligence/trail.js";
|
|
6
|
-
import { waitForDOMStable } from "../sensors/guard.js";
|
|
7
|
-
import { waitForNetworkIdle } from "../sensors/wait.js";
|
|
8
|
-
import { ghostMove, ghostClick } from "../overlay/ghost.js";
|
|
9
|
-
import { cacheActionMap, getCachedActionMap } from "../state/cache.js";
|
|
10
|
-
import { storeSnapshot, computeDelta } from "../state/delta.js";
|
|
11
|
-
import { sessionRegistry } from "../state/session.js";
|
|
12
|
-
import { getConfigAgentId } from "../config/loader.js";
|
|
13
|
-
import { operationMonitor } from "../sensors/operation_monitor.js";
|
|
14
|
-
/**
|
|
15
|
-
* Consolidated tool that combines element resolution, clicking, and waiting.
|
|
16
|
-
* Eliminates 2-3 tool calls in the common pattern: find → click → wait
|
|
17
|
-
*/
|
|
18
|
-
export async function weaveClickAndWait(session, args, config) {
|
|
19
|
-
const { id, label, intent, x, y, waitAfter = 500, waitForNetwork = true, includeMap = false, fast = false, tab_id } = args;
|
|
20
|
-
const { Page, DOM, Input } = session;
|
|
21
|
-
const startMs = Date.now();
|
|
22
|
-
const targetId = sessionRegistry.getActive(getConfigAgentId(config))?.targetId ?? "default";
|
|
23
|
-
const operationId = `clickAndWait-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
24
|
-
operationMonitor.startOperation(operationId, 'browser_click_and_wait');
|
|
25
|
-
// Handle tab switching if tab_id is provided
|
|
26
|
-
let targetSession = session;
|
|
27
|
-
if (tab_id) {
|
|
28
|
-
const { connectToTab } = await import("../cdp/connector.js");
|
|
29
|
-
const client = await connectToTab(tab_id);
|
|
30
|
-
targetSession = client.session;
|
|
31
|
-
}
|
|
32
|
-
// Check for stuck loop before processing
|
|
33
|
-
const stuckCheck = detectStuckLoop();
|
|
34
|
-
if (stuckCheck.stuck) {
|
|
35
|
-
return {
|
|
36
|
-
success: false,
|
|
37
|
-
error_code: "STUCK_LOOP",
|
|
38
|
-
message: stuckCheck.diagnosis || "Agent is stuck in a loop",
|
|
39
|
-
suggestion: "Try a different approach or reset the loop counter",
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
// Get initial URL
|
|
43
|
-
const initialUrl = (await targetSession.Page.getFrameTree()).frameTree.frame.url;
|
|
44
|
-
// Build or get cached action map
|
|
45
|
-
let map = getCachedActionMap(targetId, initialUrl);
|
|
46
|
-
if (!map) {
|
|
47
|
-
map = await buildActionMap(targetSession, { lite: true }, targetId);
|
|
48
|
-
cacheActionMap(targetId, map);
|
|
49
|
-
}
|
|
50
|
-
await storeSnapshot(targetId, initialUrl, map.elements);
|
|
51
|
-
// Resolve element
|
|
52
|
-
let element;
|
|
53
|
-
if (id) {
|
|
54
|
-
element = map.elements.find((el) => el.id === id || el.id.endsWith(id));
|
|
55
|
-
}
|
|
56
|
-
if (!element && label) {
|
|
57
|
-
element = findBestMatch(map.elements, label);
|
|
58
|
-
}
|
|
59
|
-
if (!element && intent) {
|
|
60
|
-
element = findBestMatch(map.elements, intent);
|
|
61
|
-
}
|
|
62
|
-
if (!element && !x && !y) {
|
|
63
|
-
return {
|
|
64
|
-
success: false,
|
|
65
|
-
error_code: "ELEMENT_NOT_FOUND",
|
|
66
|
-
message: `Element not found with id="${id}", label="${label}", or intent="${intent}"`,
|
|
67
|
-
suggestion: "Try browser_map to see available elements, or use x/y coordinates",
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
const clickX = x ?? element?.x;
|
|
71
|
-
const clickY = y ?? element?.y;
|
|
72
|
-
const selector = element ? safeSelector(element) : undefined;
|
|
73
|
-
if (!clickX || !clickY) {
|
|
74
|
-
return {
|
|
75
|
-
success: false,
|
|
76
|
-
error_code: "NO_COORDINATES",
|
|
77
|
-
message: "Could not determine click coordinates",
|
|
78
|
-
suggestion: "Provide explicit x/y coordinates or ensure element has position data",
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
// Perform click with ghost move
|
|
82
|
-
await ghostMove(targetSession, clickX, clickY, config, element?.label || "target");
|
|
83
|
-
await ghostClick(targetSession, clickX, clickY, { pointerType: 'mouse' });
|
|
84
|
-
await new Promise(r => setTimeout(r, 30 + Math.random() * 40));
|
|
85
|
-
await targetSession.Input.dispatchMouseEvent({
|
|
86
|
-
type: 'mouseReleased',
|
|
87
|
-
x: clickX,
|
|
88
|
-
y: clickY,
|
|
89
|
-
button: 'left',
|
|
90
|
-
clickCount: 1,
|
|
91
|
-
pointerType: 'mouse'
|
|
92
|
-
});
|
|
93
|
-
// Wait for response
|
|
94
|
-
const waitStart = Date.now();
|
|
95
|
-
if (waitForNetwork) {
|
|
96
|
-
await Promise.all([
|
|
97
|
-
waitForDOMStable(targetSession, 50, 300),
|
|
98
|
-
waitForNetworkIdle(targetSession, waitAfter, waitAfter * 2).catch(() => { })
|
|
99
|
-
]);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
await new Promise(r => setTimeout(r, waitAfter));
|
|
103
|
-
}
|
|
104
|
-
const waitedMs = Date.now() - waitStart;
|
|
105
|
-
// Check result
|
|
106
|
-
const finalUrl = (await targetSession.Page.getFrameTree()).frameTree.frame.url;
|
|
107
|
-
const urlChanged = finalUrl !== initialUrl;
|
|
108
|
-
let newMap = map;
|
|
109
|
-
let domChanged = false;
|
|
110
|
-
if (urlChanged || includeMap) {
|
|
111
|
-
newMap = await buildActionMap(targetSession, { lite: true }, targetId);
|
|
112
|
-
cacheActionMap(targetId, newMap);
|
|
113
|
-
const delta = computeDelta(targetId, initialUrl, newMap.elements);
|
|
114
|
-
domChanged = delta ? delta.added.length + delta.removed.length + delta.changed.length > 0 : urlChanged;
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
const delta = computeDelta(targetId, initialUrl, map.elements);
|
|
118
|
-
domChanged = delta ? delta.added.length + delta.removed.length + delta.changed.length > 0 : false;
|
|
119
|
-
}
|
|
120
|
-
const executionMs = Date.now() - startMs;
|
|
121
|
-
// Track tool call
|
|
122
|
-
trackToolCall("browser_click_and_wait", element?.id || id || label || "coordinates", {
|
|
123
|
-
success: true,
|
|
124
|
-
urlChanged
|
|
125
|
-
});
|
|
126
|
-
recordAction({
|
|
127
|
-
timestamp: new Date().toISOString(),
|
|
128
|
-
tool: "browser_click_and_wait",
|
|
129
|
-
input: { ref: element?.id || id || label, waitAfter, waitForNetwork },
|
|
130
|
-
result: { success: true, urlChanged, domChanged, waitedMs },
|
|
131
|
-
});
|
|
132
|
-
operationMonitor.endOperation(operationId);
|
|
133
|
-
const result = {
|
|
134
|
-
success: true,
|
|
135
|
-
clicked: element?.label || "coordinates",
|
|
136
|
-
ref: element?.id || id || "coordinates",
|
|
137
|
-
execution_ms: executionMs,
|
|
138
|
-
tab_id: targetId,
|
|
139
|
-
url: finalUrl,
|
|
140
|
-
title: newMap?.title || "",
|
|
141
|
-
url_changed: urlChanged,
|
|
142
|
-
...(includeMap ? { page_map: newMap ? toMarkdownTable(newMap.elements, finalUrl, newMap.title) : "" } : {}),
|
|
143
|
-
dom_changed: domChanged,
|
|
144
|
-
stuck_warning: false,
|
|
145
|
-
waited_ms: waitedMs,
|
|
146
|
-
network_idle: waitForNetwork,
|
|
147
|
-
};
|
|
148
|
-
return result;
|
|
149
|
-
}
|