@particle-academy/agent-integrations 0.46.0 → 0.47.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/CHANGELOG.md +835 -0
- package/LICENSE +21 -0
- package/README.md +44 -3
- package/dist/bridges/artboard.d.cts +3 -3
- package/dist/bridges/artboard.d.ts +3 -3
- package/dist/bridges/catalog.d.cts +3 -3
- package/dist/bridges/catalog.d.ts +3 -3
- package/dist/bridges/charts.d.cts +3 -3
- package/dist/bridges/charts.d.ts +3 -3
- package/dist/bridges/cms.d.cts +3 -3
- package/dist/bridges/cms.d.ts +3 -3
- package/dist/bridges/code.d.cts +3 -3
- package/dist/bridges/code.d.ts +3 -3
- package/dist/bridges/doc.d.cts +3 -3
- package/dist/bridges/doc.d.ts +3 -3
- package/dist/bridges/features.d.cts +3 -3
- package/dist/bridges/features.d.ts +3 -3
- package/dist/bridges/files.d.cts +3 -3
- package/dist/bridges/files.d.ts +3 -3
- package/dist/bridges/flow.d.cts +3 -3
- package/dist/bridges/flow.d.ts +3 -3
- package/dist/bridges/forms.d.cts +3 -3
- package/dist/bridges/forms.d.ts +3 -3
- package/dist/bridges/git.d.cts +3 -3
- package/dist/bridges/git.d.ts +3 -3
- package/dist/bridges/grid.d.cts +3 -3
- package/dist/bridges/grid.d.ts +3 -3
- package/dist/bridges/map.d.cts +3 -3
- package/dist/bridges/map.d.ts +3 -3
- package/dist/bridges/navigation.d.cts +127 -0
- package/dist/bridges/navigation.d.ts +127 -0
- package/dist/bridges/passkeys.d.cts +4 -4
- package/dist/bridges/passkeys.d.ts +4 -4
- package/dist/bridges/scene.d.cts +3 -3
- package/dist/bridges/scene.d.ts +3 -3
- package/dist/bridges/screens.d.cts +3 -3
- package/dist/bridges/screens.d.ts +3 -3
- package/dist/bridges/sheets.d.cts +3 -3
- package/dist/bridges/sheets.d.ts +3 -3
- package/dist/bridges/slides.d.cts +3 -3
- package/dist/bridges/slides.d.ts +3 -3
- package/dist/bridges/terminal.d.cts +3 -3
- package/dist/bridges/terminal.d.ts +3 -3
- package/dist/bridges/tui.d.cts +2 -2
- package/dist/bridges/tui.d.ts +2 -2
- package/dist/bridges/whiteboard.d.cts +3 -3
- package/dist/bridges/whiteboard.d.ts +3 -3
- package/dist/bridges-navigation.cjs +391 -0
- package/dist/bridges-navigation.cjs.map +1 -0
- package/dist/bridges-navigation.js +7 -0
- package/dist/bridges-navigation.js.map +1 -0
- package/dist/bridges-passkeys.cjs.map +1 -1
- package/dist/bridges-passkeys.js +1 -1
- package/dist/{chunk-PWYEW6NL.js → chunk-G6CRHFWU.js} +2 -2
- package/dist/{chunk-PWYEW6NL.js.map → chunk-G6CRHFWU.js.map} +1 -1
- package/dist/chunk-JGJHPH65.js +271 -0
- package/dist/chunk-JGJHPH65.js.map +1 -0
- package/dist/dom-navigation/index.d.cts +164 -0
- package/dist/dom-navigation/index.d.ts +164 -0
- package/dist/dom-navigation/script.d.cts +3 -0
- package/dist/dom-navigation/script.d.ts +3 -0
- package/dist/dom-navigation-script.cjs +11 -0
- package/dist/dom-navigation-script.cjs.map +1 -0
- package/dist/dom-navigation-script.js +9 -0
- package/dist/dom-navigation-script.js.map +1 -0
- package/dist/dom-navigation.cjs +387 -0
- package/dist/dom-navigation.cjs.map +1 -0
- package/dist/dom-navigation.js +370 -0
- package/dist/dom-navigation.js.map +1 -0
- package/dist/index.cjs +31 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -125
- package/dist/index.d.ts +10 -125
- package/dist/index.js +12 -275
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.cts +5 -5
- package/dist/mcp/index.d.ts +5 -5
- package/dist/mcp/stdio.d.cts +3 -3
- package/dist/mcp/stdio.d.ts +3 -3
- package/dist/presence/index.d.cts +1 -1
- package/dist/presence/index.d.ts +1 -1
- package/dist/{server-BIcA3ZtK.d.cts → server-1y0n61R5.d.cts} +2 -2
- package/dist/{server-DnUyeavY.d.ts → server-vq6qVl3T.d.ts} +2 -2
- package/dist/sharing/index.d.cts +3 -3
- package/dist/sharing/index.d.ts +3 -3
- package/dist/sheets-adapter.d.cts +3 -3
- package/dist/sheets-adapter.d.ts +3 -3
- package/dist/{tool-host-LVBgCN5m.d.cts → tool-host-D67N2a2h.d.cts} +1 -1
- package/dist/{tool-host-Wo0pkY83.d.ts → tool-host-LYfdPE8u.d.ts} +1 -1
- package/dist/{types-EcElKOlk.d.cts → types-DP5yQZQU.d.cts} +1 -1
- package/dist/{types-BxNRKSVd.d.ts → types-VX_9je7w.d.ts} +1 -1
- package/dist/{types-C2DtnHIn.d.cts → types-gzIpsUDE.d.cts} +1 -1
- package/dist/{types-C2DtnHIn.d.ts → types-gzIpsUDE.d.ts} +1 -1
- package/dist/undo/index.d.cts +2 -2
- package/dist/undo/index.d.ts +2 -2
- package/package.json +35 -3
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
// src/dom-navigation/agent.ts
|
|
2
|
+
var INTERACTIVE = "a[href], button, input, select, textarea, [role=button], [role=link], [role=checkbox], [role=tab], [data-co-handle]";
|
|
3
|
+
var DOM_NAVIGATION_METHODS = [
|
|
4
|
+
"getLocation",
|
|
5
|
+
"describe",
|
|
6
|
+
"read",
|
|
7
|
+
"visit",
|
|
8
|
+
"back",
|
|
9
|
+
"forward",
|
|
10
|
+
"scrollTo",
|
|
11
|
+
"scrollBy",
|
|
12
|
+
"setField",
|
|
13
|
+
"click",
|
|
14
|
+
"submit",
|
|
15
|
+
"rectFor"
|
|
16
|
+
];
|
|
17
|
+
var tag = (el) => el.tagName.toUpperCase();
|
|
18
|
+
function isVisible(el) {
|
|
19
|
+
const he = el;
|
|
20
|
+
if (el.type === "hidden") return false;
|
|
21
|
+
if (he.hidden || he.getAttribute("aria-hidden") === "true") return false;
|
|
22
|
+
return he.offsetParent !== null || he.getClientRects().length > 0;
|
|
23
|
+
}
|
|
24
|
+
function isSensitive(el) {
|
|
25
|
+
const input = el;
|
|
26
|
+
const ac = (el.getAttribute("autocomplete") ?? "").toLowerCase();
|
|
27
|
+
return input.type === "password" || ac.startsWith("cc-") || ac === "one-time-code" || el.hasAttribute("data-private");
|
|
28
|
+
}
|
|
29
|
+
function insideSensitive(node) {
|
|
30
|
+
for (let el = node.parentElement; el; el = el.parentElement) {
|
|
31
|
+
if (isSensitive(el)) return true;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
function safeText(root) {
|
|
36
|
+
const doc = root.ownerDocument ?? root;
|
|
37
|
+
const walker = doc.createTreeWalker(root, 4);
|
|
38
|
+
let out = "";
|
|
39
|
+
for (let n = walker.nextNode(); n; n = walker.nextNode()) {
|
|
40
|
+
if (!insideSensitive(n)) out += n.nodeValue ?? "";
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
function roleOf(el) {
|
|
45
|
+
const explicit = el.getAttribute("role");
|
|
46
|
+
if (explicit) return explicit;
|
|
47
|
+
const t = tag(el);
|
|
48
|
+
if (t === "A") return "link";
|
|
49
|
+
if (t === "BUTTON") return "button";
|
|
50
|
+
if (t === "SELECT") return "select";
|
|
51
|
+
if (t === "TEXTAREA") return "textbox";
|
|
52
|
+
if (t === "INPUT") {
|
|
53
|
+
const type = el.type;
|
|
54
|
+
if (type === "checkbox") return "checkbox";
|
|
55
|
+
if (type === "radio") return "radio";
|
|
56
|
+
if (type === "submit" || type === "button") return "button";
|
|
57
|
+
return "textbox";
|
|
58
|
+
}
|
|
59
|
+
return "generic";
|
|
60
|
+
}
|
|
61
|
+
function labelFor(doc, id) {
|
|
62
|
+
for (const lbl of Array.from(doc.querySelectorAll("label[for]"))) {
|
|
63
|
+
if (lbl.getAttribute("for") === id) return lbl;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
function accessibleName(el) {
|
|
68
|
+
const doc = el.ownerDocument;
|
|
69
|
+
const aria = el.getAttribute("aria-label");
|
|
70
|
+
if (aria) return aria.trim();
|
|
71
|
+
const labelledby = el.getAttribute("aria-labelledby");
|
|
72
|
+
if (labelledby) {
|
|
73
|
+
const txt = labelledby.split(/\s+/).map((id2) => doc.getElementById(id2)?.textContent ?? "").join(" ").trim();
|
|
74
|
+
if (txt) return txt;
|
|
75
|
+
}
|
|
76
|
+
const id = el.getAttribute("id");
|
|
77
|
+
if (id) {
|
|
78
|
+
const lbl = labelFor(doc, id);
|
|
79
|
+
if (lbl?.textContent?.trim()) return lbl.textContent.trim();
|
|
80
|
+
}
|
|
81
|
+
const wrapping = el.closest("label");
|
|
82
|
+
if (wrapping) {
|
|
83
|
+
const txt = safeText(wrapping).trim();
|
|
84
|
+
if (txt) return txt;
|
|
85
|
+
}
|
|
86
|
+
const placeholder = el.getAttribute("placeholder");
|
|
87
|
+
if (placeholder) return placeholder.trim();
|
|
88
|
+
const text = isSensitive(el) ? "" : el.textContent?.trim();
|
|
89
|
+
if (text) return text.replace(/\s+/g, " ").slice(0, 80);
|
|
90
|
+
return el.getAttribute("name") ?? el.getAttribute("id") ?? roleOf(el);
|
|
91
|
+
}
|
|
92
|
+
function isDestructive(el, label) {
|
|
93
|
+
if (el.hasAttribute("data-co-confirm")) return true;
|
|
94
|
+
if (el.type === "submit") return true;
|
|
95
|
+
if (tag(el) === "BUTTON" && el.type === "submit") return true;
|
|
96
|
+
return /\b(delete|remove|destroy|sign out|log ?out|cancel subscription|deactivate)\b/i.test(label);
|
|
97
|
+
}
|
|
98
|
+
function attributeHandle(el) {
|
|
99
|
+
return el.getAttribute("data-co-handle") || el.getAttribute("name") || el.getAttribute("id") || "";
|
|
100
|
+
}
|
|
101
|
+
function walk(doc = document) {
|
|
102
|
+
const registry = /* @__PURE__ */ new Map();
|
|
103
|
+
const actions = [];
|
|
104
|
+
const seen = /* @__PURE__ */ new Set();
|
|
105
|
+
let synthetic = 0;
|
|
106
|
+
for (const el of Array.from(doc.querySelectorAll(INTERACTIVE))) {
|
|
107
|
+
if (seen.has(el) || !isVisible(el)) continue;
|
|
108
|
+
seen.add(el);
|
|
109
|
+
const label = accessibleName(el);
|
|
110
|
+
const role = roleOf(el);
|
|
111
|
+
let handle = attributeHandle(el);
|
|
112
|
+
if (!handle || registry.has(handle)) handle = `${role}#${synthetic++}`;
|
|
113
|
+
registry.set(handle, el);
|
|
114
|
+
let value;
|
|
115
|
+
if (role === "textbox" || role === "select") {
|
|
116
|
+
value = isSensitive(el) ? void 0 : el.value;
|
|
117
|
+
} else if (role === "checkbox" || role === "radio") {
|
|
118
|
+
value = el.checked;
|
|
119
|
+
}
|
|
120
|
+
const action = { handle, role, label, destructive: isDestructive(el, label) };
|
|
121
|
+
if (value !== void 0) action.value = value;
|
|
122
|
+
actions.push(action);
|
|
123
|
+
}
|
|
124
|
+
const loc = doc.defaultView?.location;
|
|
125
|
+
return {
|
|
126
|
+
snapshot: { url: loc ? loc.pathname + loc.search : "", title: doc.title, actions },
|
|
127
|
+
registry
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function isField(el) {
|
|
131
|
+
const t = tag(el);
|
|
132
|
+
return t === "INPUT" || t === "TEXTAREA" || t === "SELECT";
|
|
133
|
+
}
|
|
134
|
+
function setNativeValue(el, value) {
|
|
135
|
+
const view = el.ownerDocument.defaultView ?? globalThis;
|
|
136
|
+
const fire = () => {
|
|
137
|
+
el.dispatchEvent(new view.Event("input", { bubbles: true }));
|
|
138
|
+
el.dispatchEvent(new view.Event("change", { bubbles: true }));
|
|
139
|
+
};
|
|
140
|
+
const t = tag(el);
|
|
141
|
+
if (t === "INPUT" && (el.type === "checkbox" || el.type === "radio")) {
|
|
142
|
+
const setter2 = Object.getOwnPropertyDescriptor(view.HTMLInputElement.prototype, "checked")?.set;
|
|
143
|
+
setter2?.call(el, Boolean(value));
|
|
144
|
+
fire();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const proto = t === "TEXTAREA" ? view.HTMLTextAreaElement.prototype : t === "SELECT" ? view.HTMLSelectElement.prototype : view.HTMLInputElement.prototype;
|
|
148
|
+
const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set;
|
|
149
|
+
setter?.call(el, String(value));
|
|
150
|
+
fire();
|
|
151
|
+
}
|
|
152
|
+
function readPage(doc = document) {
|
|
153
|
+
const main = doc.querySelector("main") ?? doc.body;
|
|
154
|
+
if (!main) return doc.title;
|
|
155
|
+
const heads = Array.from(main.querySelectorAll("h1, h2, h3")).map((h) => `${h.tagName}: ${safeText(h).trim()}`).filter(Boolean);
|
|
156
|
+
const text = safeText(main).replace(/\s+/g, " ").trim().slice(0, 4e3);
|
|
157
|
+
return [doc.title, ...heads, "", text].join("\n");
|
|
158
|
+
}
|
|
159
|
+
function findByAttribute(doc, attr, value) {
|
|
160
|
+
for (const el of Array.from(doc.querySelectorAll(`[${attr}]`))) {
|
|
161
|
+
if (el.getAttribute(attr) === value) return el;
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
var num = (v) => typeof v === "number" ? v : void 0;
|
|
166
|
+
function createDomNavigationAgent(options = {}) {
|
|
167
|
+
let registry = /* @__PURE__ */ new Map();
|
|
168
|
+
const doc = () => options.document ?? document;
|
|
169
|
+
const win = () => doc().defaultView ?? window;
|
|
170
|
+
const before = (action) => options.beforeAction?.(action);
|
|
171
|
+
const resolve = (handle) => {
|
|
172
|
+
const hit = registry.get(handle);
|
|
173
|
+
if (hit && hit.isConnected) return hit;
|
|
174
|
+
const d = doc();
|
|
175
|
+
return findByAttribute(d, "data-co-handle", handle) ?? findByAttribute(d, "name", handle) ?? d.getElementById(handle);
|
|
176
|
+
};
|
|
177
|
+
const agent = {
|
|
178
|
+
getLocation: () => {
|
|
179
|
+
const loc = win().location;
|
|
180
|
+
return { url: loc.pathname + loc.search, title: doc().title };
|
|
181
|
+
},
|
|
182
|
+
describe: () => {
|
|
183
|
+
const res = walk(doc());
|
|
184
|
+
registry = res.registry;
|
|
185
|
+
return res.snapshot;
|
|
186
|
+
},
|
|
187
|
+
read: () => readPage(doc()),
|
|
188
|
+
visit: (url) => {
|
|
189
|
+
const w = win();
|
|
190
|
+
const target = new URL(String(url), w.location.href);
|
|
191
|
+
if (target.protocol !== "http:" && target.protocol !== "https:") {
|
|
192
|
+
throw new Error(`Refusing to navigate to a '${target.protocol}' URL.`);
|
|
193
|
+
}
|
|
194
|
+
w.setTimeout(() => w.location.assign(target.href), 0);
|
|
195
|
+
},
|
|
196
|
+
back: () => win().history.back(),
|
|
197
|
+
forward: () => win().history.forward(),
|
|
198
|
+
scrollTo: ({ x, y, handle }) => {
|
|
199
|
+
const w = win();
|
|
200
|
+
if (handle) {
|
|
201
|
+
resolve(handle)?.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
w.scrollTo({ left: x ?? w.scrollX, top: y ?? w.scrollY, behavior: "smooth" });
|
|
205
|
+
},
|
|
206
|
+
scrollBy: (dy) => win().scrollBy({ top: dy, behavior: "smooth" }),
|
|
207
|
+
setField: (handle, value) => {
|
|
208
|
+
before("setField");
|
|
209
|
+
const el = resolve(handle);
|
|
210
|
+
if (!el) return { ok: false, error: `No element for handle "${handle}"` };
|
|
211
|
+
if (isField(el)) {
|
|
212
|
+
setNativeValue(el, value);
|
|
213
|
+
return { ok: true };
|
|
214
|
+
}
|
|
215
|
+
return { ok: false, error: `Handle "${handle}" is not a form field` };
|
|
216
|
+
},
|
|
217
|
+
click: (handle) => {
|
|
218
|
+
const el = resolve(handle);
|
|
219
|
+
if (!el) return { ok: false, error: `No element for handle "${handle}"` };
|
|
220
|
+
before("click");
|
|
221
|
+
el.click();
|
|
222
|
+
return { ok: true };
|
|
223
|
+
},
|
|
224
|
+
submit: (handle) => {
|
|
225
|
+
const el = resolve(handle);
|
|
226
|
+
if (!el) return { ok: false, error: `No element for handle "${handle}"` };
|
|
227
|
+
const form = tag(el) === "FORM" ? el : el.closest("form");
|
|
228
|
+
if (!form) return { ok: false, error: `Handle "${handle}" is not inside a form` };
|
|
229
|
+
before("submit");
|
|
230
|
+
if (typeof form.requestSubmit === "function") form.requestSubmit();
|
|
231
|
+
else form.submit();
|
|
232
|
+
return { ok: true };
|
|
233
|
+
},
|
|
234
|
+
rectFor: (handle) => {
|
|
235
|
+
const el = resolve(handle);
|
|
236
|
+
if (!el) return null;
|
|
237
|
+
const r = el.getBoundingClientRect();
|
|
238
|
+
return { x: r.left, y: r.top, width: r.width, height: r.height };
|
|
239
|
+
},
|
|
240
|
+
resolve,
|
|
241
|
+
call: (method, args = []) => {
|
|
242
|
+
const a = Array.isArray(args) ? args : [];
|
|
243
|
+
const handle = String(a[0] ?? "");
|
|
244
|
+
switch (method) {
|
|
245
|
+
case "getLocation":
|
|
246
|
+
return agent.getLocation();
|
|
247
|
+
case "describe":
|
|
248
|
+
return agent.describe();
|
|
249
|
+
case "read":
|
|
250
|
+
return agent.read();
|
|
251
|
+
case "visit":
|
|
252
|
+
agent.visit(String(a[0] ?? ""));
|
|
253
|
+
return void 0;
|
|
254
|
+
case "back":
|
|
255
|
+
agent.back();
|
|
256
|
+
return void 0;
|
|
257
|
+
case "forward":
|
|
258
|
+
agent.forward();
|
|
259
|
+
return void 0;
|
|
260
|
+
case "scrollTo": {
|
|
261
|
+
const o = a[0] && typeof a[0] === "object" ? a[0] : {};
|
|
262
|
+
agent.scrollTo({
|
|
263
|
+
x: num(o.x),
|
|
264
|
+
y: num(o.y),
|
|
265
|
+
handle: typeof o.handle === "string" ? o.handle : void 0
|
|
266
|
+
});
|
|
267
|
+
return void 0;
|
|
268
|
+
}
|
|
269
|
+
case "scrollBy":
|
|
270
|
+
agent.scrollBy(Number(a[0] ?? 0));
|
|
271
|
+
return void 0;
|
|
272
|
+
case "setField":
|
|
273
|
+
return agent.setField(handle, a[1]);
|
|
274
|
+
case "click":
|
|
275
|
+
return agent.click(handle);
|
|
276
|
+
case "submit":
|
|
277
|
+
return agent.submit(handle);
|
|
278
|
+
case "rectFor":
|
|
279
|
+
return agent.rectFor(handle);
|
|
280
|
+
default:
|
|
281
|
+
throw new Error(`Unknown dom-navigation method: ${String(method)}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
return agent;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// src/dom-navigation/remote.ts
|
|
289
|
+
var DOM_NAVIGATION_GLOBAL = "__fancyDomNavigation";
|
|
290
|
+
var DOM_NAVIGATION_PROTOCOL = 1;
|
|
291
|
+
var METHODS = new Set(DOM_NAVIGATION_METHODS);
|
|
292
|
+
function assertMethod(method) {
|
|
293
|
+
if (!METHODS.has(method)) throw new Error(`Unknown dom-navigation method: ${method}`);
|
|
294
|
+
}
|
|
295
|
+
function domNavigationCallScript(method, args = []) {
|
|
296
|
+
assertMethod(method);
|
|
297
|
+
const g = JSON.stringify(DOM_NAVIGATION_GLOBAL);
|
|
298
|
+
return `(function(){var n=globalThis[${g}];if(!n||typeof n.call!=="function")throw new Error("fancy dom-navigation is not injected in this world");return n.call(${JSON.stringify(method)},${JSON.stringify(args)});})()`;
|
|
299
|
+
}
|
|
300
|
+
var str = (v, fallback = "") => typeof v === "string" ? v : fallback;
|
|
301
|
+
var isObj = (v) => typeof v === "object" && v !== null;
|
|
302
|
+
function coerceAction(v) {
|
|
303
|
+
if (!isObj(v) || typeof v.handle !== "string" || v.handle === "") return null;
|
|
304
|
+
const action = {
|
|
305
|
+
handle: v.handle,
|
|
306
|
+
role: str(v.role, "generic"),
|
|
307
|
+
label: str(v.label),
|
|
308
|
+
destructive: v.destructive === true
|
|
309
|
+
};
|
|
310
|
+
const value = v.value;
|
|
311
|
+
if (typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) {
|
|
312
|
+
action.value = value;
|
|
313
|
+
}
|
|
314
|
+
return action;
|
|
315
|
+
}
|
|
316
|
+
function coerceSnapshot(v) {
|
|
317
|
+
const o = isObj(v) ? v : {};
|
|
318
|
+
const actions = Array.isArray(o.actions) ? o.actions.map(coerceAction).filter((a) => a !== null) : [];
|
|
319
|
+
return { url: str(o.url), title: str(o.title), actions };
|
|
320
|
+
}
|
|
321
|
+
function coerceResult(v) {
|
|
322
|
+
const o = isObj(v) ? v : {};
|
|
323
|
+
return { ok: o.ok === true, error: typeof o.error === "string" ? o.error : void 0 };
|
|
324
|
+
}
|
|
325
|
+
function coerceRect(v) {
|
|
326
|
+
if (!isObj(v)) return null;
|
|
327
|
+
const { x, y, width, height } = v;
|
|
328
|
+
const finite = (n) => typeof n === "number" && Number.isFinite(n);
|
|
329
|
+
return finite(x) && finite(y) && finite(width) && finite(height) ? { x, y, width, height } : null;
|
|
330
|
+
}
|
|
331
|
+
function createRemoteNavigationAdapter(options) {
|
|
332
|
+
const { transport } = options;
|
|
333
|
+
const call = (method, ...args) => transport.call(method, args);
|
|
334
|
+
const fail = (e) => ({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
335
|
+
return {
|
|
336
|
+
screenId: options.screenId,
|
|
337
|
+
getRevision: options.getRevision,
|
|
338
|
+
confirm: options.confirm,
|
|
339
|
+
getLocation: async () => {
|
|
340
|
+
const o = await call("getLocation");
|
|
341
|
+
const loc = isObj(o) ? o : {};
|
|
342
|
+
return { url: str(loc.url), title: str(loc.title) };
|
|
343
|
+
},
|
|
344
|
+
describe: async () => coerceSnapshot(await call("describe")),
|
|
345
|
+
read: async () => str(await call("read")),
|
|
346
|
+
visit: async (url) => {
|
|
347
|
+
await call("visit", url);
|
|
348
|
+
},
|
|
349
|
+
back: async () => {
|
|
350
|
+
await call("back");
|
|
351
|
+
},
|
|
352
|
+
forward: async () => {
|
|
353
|
+
await call("forward");
|
|
354
|
+
},
|
|
355
|
+
scrollTo: async (opts) => {
|
|
356
|
+
await call("scrollTo", { x: opts.x, y: opts.y, handle: opts.handle });
|
|
357
|
+
},
|
|
358
|
+
scrollBy: async (dy) => {
|
|
359
|
+
await call("scrollBy", dy);
|
|
360
|
+
},
|
|
361
|
+
setField: async (handle, value) => coerceResult(await call("setField", handle, value).catch(fail)),
|
|
362
|
+
click: async (handle) => coerceResult(await call("click", handle).catch(fail)),
|
|
363
|
+
submit: async (handle) => coerceResult(await call("submit", handle).catch(fail)),
|
|
364
|
+
rectFor: async (handle) => coerceRect(await call("rectFor", handle).catch(() => null))
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export { DOM_NAVIGATION_GLOBAL, DOM_NAVIGATION_METHODS, DOM_NAVIGATION_PROTOCOL, INTERACTIVE, accessibleName, attributeHandle, createDomNavigationAgent, createRemoteNavigationAdapter, domNavigationCallScript, isDestructive, isSensitive, isVisible, readPage, roleOf, setNativeValue, walk };
|
|
369
|
+
//# sourceMappingURL=dom-navigation.js.map
|
|
370
|
+
//# sourceMappingURL=dom-navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dom-navigation/agent.ts","../src/dom-navigation/remote.ts"],"names":["id","setter"],"mappings":"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","file":"dom-navigation.js","sourcesContent":["/**\n * The in-page half of DOM co-browsing: a framework-free walker that turns a\n * live document into a {@link PageSnapshot} of stable handles, and acts on\n * those handles.\n *\n * Extracted from px-ui-sandbox's CoBrowseProvider so a host that does NOT own\n * the page (Genie's browser, showing sites through an Electron\n * WebContentsView) can run the same walker, injected into an isolated world.\n *\n * Constraints this file holds, because the injected IIFE is built from it:\n *\n * - NO runtime imports. Type-only imports are erased; anything else would be\n * bundled into a script that must run with no module loader.\n * - Nothing touches `document` / `window` until a method is called, so the\n * script can be evaluated in a context with no DOM at all.\n * - Every result is plain, structured-cloneable data.\n *\n * Trust boundary: the page is hostile input. It controls every attribute,\n * label and text node read here. Two consequences:\n * - Sensitive values (passwords, card fields, one-time codes, anything marked\n * `data-private`) are masked HERE, before anything leaves the page — the host\n * cannot mask what it has already received.\n * - Handles are compared as plain strings, never spliced into a CSS selector,\n * so a crafted handle cannot change what a lookup matches.\n */\nimport type { PageAction, PageSnapshot } from \"../bridges/navigation\";\n\n/** Elements the walker considers actionable. */\nexport const INTERACTIVE =\n \"a[href], button, input, select, textarea, [role=button], [role=link], [role=checkbox], [role=tab], [data-co-handle]\";\n\n/** Every method the in-page agent answers. The wire protocol is exactly this list. */\nexport const DOM_NAVIGATION_METHODS = [\n \"getLocation\",\n \"describe\",\n \"read\",\n \"visit\",\n \"back\",\n \"forward\",\n \"scrollTo\",\n \"scrollBy\",\n \"setField\",\n \"click\",\n \"submit\",\n \"rectFor\",\n] as const;\n\nexport type DomNavigationMethod = (typeof DOM_NAVIGATION_METHODS)[number];\n\nexport type ActionResult = { ok: boolean; error?: string };\nexport type HandleRect = { x: number; y: number; width: number; height: number };\n\ntype FieldElement = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n\nconst tag = (el: Element) => el.tagName.toUpperCase();\n\nexport function isVisible(el: Element): boolean {\n const he = el as HTMLElement;\n if ((el as HTMLInputElement).type === \"hidden\") return false;\n if (he.hidden || he.getAttribute(\"aria-hidden\") === \"true\") return false;\n return he.offsetParent !== null || he.getClientRects().length > 0;\n}\n\n/** Sensitive fields whose value is never read into the snapshot. */\nexport function isSensitive(el: Element): boolean {\n const input = el as HTMLInputElement;\n const ac = (el.getAttribute(\"autocomplete\") ?? \"\").toLowerCase();\n return (\n input.type === \"password\" ||\n ac.startsWith(\"cc-\") ||\n ac === \"one-time-code\" ||\n el.hasAttribute(\"data-private\")\n );\n}\n\n/** True when this node, or any element containing it, is sensitive. */\nfunction insideSensitive(node: Node): boolean {\n for (let el = node.parentElement; el; el = el.parentElement) {\n if (isSensitive(el)) return true;\n }\n return false;\n}\n\n/** textContent, minus any text that sits inside a sensitive element. */\nfunction safeText(root: Node): string {\n const doc = root.ownerDocument ?? (root as Document);\n // NodeFilter.SHOW_TEXT === 4; the literal avoids depending on a NodeFilter global.\n const walker = doc.createTreeWalker(root, 4);\n let out = \"\";\n for (let n = walker.nextNode(); n; n = walker.nextNode()) {\n if (!insideSensitive(n)) out += n.nodeValue ?? \"\";\n }\n return out;\n}\n\nexport function roleOf(el: Element): string {\n const explicit = el.getAttribute(\"role\");\n if (explicit) return explicit;\n const t = tag(el);\n if (t === \"A\") return \"link\";\n if (t === \"BUTTON\") return \"button\";\n if (t === \"SELECT\") return \"select\";\n if (t === \"TEXTAREA\") return \"textbox\";\n if (t === \"INPUT\") {\n const type = (el as HTMLInputElement).type;\n if (type === \"checkbox\") return \"checkbox\";\n if (type === \"radio\") return \"radio\";\n if (type === \"submit\" || type === \"button\") return \"button\";\n return \"textbox\";\n }\n return \"generic\";\n}\n\nfunction labelFor(doc: Document, id: string): Element | null {\n // Equivalent to querySelector(`label[for=\"${CSS.escape(id)}\"]`) — first match\n // in document order — without building a selector from page-controlled text.\n for (const lbl of Array.from(doc.querySelectorAll(\"label[for]\"))) {\n if (lbl.getAttribute(\"for\") === id) return lbl;\n }\n return null;\n}\n\nexport function accessibleName(el: Element): string {\n const doc = el.ownerDocument;\n const aria = el.getAttribute(\"aria-label\");\n if (aria) return aria.trim();\n const labelledby = el.getAttribute(\"aria-labelledby\");\n if (labelledby) {\n const txt = labelledby\n .split(/\\s+/)\n .map((id) => doc.getElementById(id)?.textContent ?? \"\")\n .join(\" \")\n .trim();\n if (txt) return txt;\n }\n const id = el.getAttribute(\"id\");\n if (id) {\n const lbl = labelFor(doc, id);\n if (lbl?.textContent?.trim()) return lbl.textContent.trim();\n }\n const wrapping = el.closest(\"label\");\n if (wrapping) {\n const txt = safeText(wrapping).trim();\n if (txt) return txt;\n }\n const placeholder = el.getAttribute(\"placeholder\");\n if (placeholder) return placeholder.trim();\n // A sensitive field's own text is its value (a textarea's content), so it is\n // never used as its name.\n const text = isSensitive(el) ? \"\" : (el as HTMLElement).textContent?.trim();\n if (text) return text.replace(/\\s+/g, \" \").slice(0, 80);\n return el.getAttribute(\"name\") ?? el.getAttribute(\"id\") ?? roleOf(el);\n}\n\nexport function isDestructive(el: Element, label: string): boolean {\n if (el.hasAttribute(\"data-co-confirm\")) return true;\n if ((el as HTMLInputElement).type === \"submit\") return true;\n if (tag(el) === \"BUTTON\" && (el as HTMLButtonElement).type === \"submit\") return true;\n return /\\b(delete|remove|destroy|sign out|log ?out|cancel subscription|deactivate)\\b/i.test(label);\n}\n\n/**\n * The element's own stable handle: data-co-handle → name → id, or \"\" when it\n * has none. An EMPTY attribute counts as absent — `button.name` is `\"\"`, not\n * null, on every button, anchor and input without one, so a plain `??` chain\n * never reaches the id.\n */\nexport function attributeHandle(el: Element): string {\n return (\n el.getAttribute(\"data-co-handle\") ||\n el.getAttribute(\"name\") ||\n el.getAttribute(\"id\") ||\n \"\"\n );\n}\n\n/**\n * Build a fresh snapshot + a handle→element registry. Handle preference:\n * data-co-handle → name → id → `role#index` (stable within a snapshot).\n */\nexport function walk(doc: Document = document): { snapshot: PageSnapshot; registry: Map<string, Element> } {\n const registry = new Map<string, Element>();\n const actions: PageAction[] = [];\n const seen = new Set<Element>();\n let synthetic = 0;\n\n for (const el of Array.from(doc.querySelectorAll(INTERACTIVE))) {\n if (seen.has(el) || !isVisible(el)) continue;\n seen.add(el);\n const label = accessibleName(el);\n const role = roleOf(el);\n let handle = attributeHandle(el);\n if (!handle || registry.has(handle)) handle = `${role}#${synthetic++}`;\n registry.set(handle, el);\n\n let value: unknown;\n if (role === \"textbox\" || role === \"select\") {\n value = isSensitive(el) ? undefined : (el as HTMLInputElement).value;\n } else if (role === \"checkbox\" || role === \"radio\") {\n value = (el as HTMLInputElement).checked;\n }\n\n const action: PageAction = { handle, role, label, destructive: isDestructive(el, label) };\n if (value !== undefined) action.value = value;\n actions.push(action);\n }\n\n const loc = doc.defaultView?.location;\n return {\n snapshot: { url: loc ? loc.pathname + loc.search : \"\", title: doc.title, actions },\n registry,\n };\n}\n\nfunction isField(el: Element): el is FieldElement {\n const t = tag(el);\n return t === \"INPUT\" || t === \"TEXTAREA\" || t === \"SELECT\";\n}\n\n/**\n * Set a field's value so a React-controlled input sees the change: call the\n * PROTOTYPE setter (React shadows `value` on the instance with its value\n * tracker), then dispatch bubbling `input` + `change`.\n */\nexport function setNativeValue(el: FieldElement, value: unknown): void {\n const view = (el.ownerDocument.defaultView ?? globalThis) as typeof globalThis;\n const fire = () => {\n el.dispatchEvent(new view.Event(\"input\", { bubbles: true }));\n el.dispatchEvent(new view.Event(\"change\", { bubbles: true }));\n };\n const t = tag(el);\n if (t === \"INPUT\" && ((el as HTMLInputElement).type === \"checkbox\" || (el as HTMLInputElement).type === \"radio\")) {\n const setter = Object.getOwnPropertyDescriptor(view.HTMLInputElement.prototype, \"checked\")?.set;\n setter?.call(el, Boolean(value));\n fire();\n return;\n }\n const proto =\n t === \"TEXTAREA\"\n ? view.HTMLTextAreaElement.prototype\n : t === \"SELECT\"\n ? view.HTMLSelectElement.prototype\n : view.HTMLInputElement.prototype;\n const setter = Object.getOwnPropertyDescriptor(proto, \"value\")?.set;\n setter?.call(el, String(value));\n fire();\n}\n\n/** Visible text / heading outline, with sensitive text removed. */\nexport function readPage(doc: Document = document): string {\n const main = doc.querySelector(\"main\") ?? doc.body;\n if (!main) return doc.title;\n const heads = Array.from(main.querySelectorAll(\"h1, h2, h3\"))\n .map((h) => `${h.tagName}: ${safeText(h).trim()}`)\n .filter(Boolean);\n const text = safeText(main).replace(/\\s+/g, \" \").trim().slice(0, 4000);\n return [doc.title, ...heads, \"\", text].join(\"\\n\");\n}\n\nexport type DomNavigationAgentOptions = {\n /** Document to drive. Default: the global `document`, read lazily. */\n document?: Document;\n /**\n * Called just before the agent acts on the page — before resolving a field\n * for `setField`, and after resolving (only when the element exists) for\n * `click` / `submit`. The sandbox uses it to attribute the request an action\n * causes to the agent.\n */\n beforeAction?: (action: \"setField\" | \"click\" | \"submit\") => void;\n};\n\nexport type DomNavigationAgent = {\n getLocation(): { url: string; title: string };\n describe(): PageSnapshot;\n read(): string;\n /** Navigate. Only http(s) or same-site paths; deferred a tick so a remote call returns first. */\n visit(url: string): void;\n back(): void;\n forward(): void;\n scrollTo(opts: { x?: number; y?: number; handle?: string }): void;\n scrollBy(dy: number): void;\n setField(handle: string, value: unknown): ActionResult;\n click(handle: string): ActionResult;\n submit(handle: string): ActionResult;\n rectFor(handle: string): HandleRect | null;\n /** Element for a handle: this snapshot's registry, then a live attribute lookup. */\n resolve(handle: string): Element | null;\n /** Serialisable dispatch — what the injected script exposes to a host. */\n call(method: DomNavigationMethod, args?: unknown[]): unknown;\n};\n\nfunction findByAttribute(doc: Document, attr: string, value: string): Element | null {\n for (const el of Array.from(doc.querySelectorAll(`[${attr}]`))) {\n if (el.getAttribute(attr) === value) return el;\n }\n return null;\n}\n\nconst num = (v: unknown) => (typeof v === \"number\" ? v : undefined);\n\nexport function createDomNavigationAgent(options: DomNavigationAgentOptions = {}): DomNavigationAgent {\n let registry = new Map<string, Element>();\n const doc = () => options.document ?? document;\n const win = () => (doc().defaultView ?? window) as Window;\n const before = (action: \"setField\" | \"click\" | \"submit\") => options.beforeAction?.(action);\n\n const resolve = (handle: string): Element | null => {\n const hit = registry.get(handle);\n if (hit && hit.isConnected) return hit;\n // Fallback: a real attribute handle the agent may use before describe().\n const d = doc();\n return (\n findByAttribute(d, \"data-co-handle\", handle) ??\n findByAttribute(d, \"name\", handle) ??\n d.getElementById(handle)\n );\n };\n\n const agent: DomNavigationAgent = {\n getLocation: () => {\n const loc = win().location;\n return { url: loc.pathname + loc.search, title: doc().title };\n },\n describe: () => {\n const res = walk(doc());\n registry = res.registry;\n return res.snapshot;\n },\n read: () => readPage(doc()),\n visit: (url) => {\n const w = win();\n const target = new URL(String(url), w.location.href);\n if (target.protocol !== \"http:\" && target.protocol !== \"https:\") {\n throw new Error(`Refusing to navigate to a '${target.protocol}' URL.`);\n }\n w.setTimeout(() => w.location.assign(target.href), 0);\n },\n back: () => win().history.back(),\n forward: () => win().history.forward(),\n scrollTo: ({ x, y, handle }) => {\n const w = win();\n if (handle) {\n resolve(handle)?.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n return;\n }\n w.scrollTo({ left: x ?? w.scrollX, top: y ?? w.scrollY, behavior: \"smooth\" });\n },\n scrollBy: (dy) => win().scrollBy({ top: dy, behavior: \"smooth\" }),\n setField: (handle, value) => {\n before(\"setField\");\n const el = resolve(handle);\n if (!el) return { ok: false, error: `No element for handle \"${handle}\"` };\n if (isField(el)) {\n setNativeValue(el, value);\n return { ok: true };\n }\n return { ok: false, error: `Handle \"${handle}\" is not a form field` };\n },\n click: (handle) => {\n const el = resolve(handle);\n if (!el) return { ok: false, error: `No element for handle \"${handle}\"` };\n // Before the click: an Inertia link fires its visit synchronously inside click().\n before(\"click\");\n (el as HTMLElement).click();\n return { ok: true };\n },\n submit: (handle) => {\n const el = resolve(handle);\n if (!el) return { ok: false, error: `No element for handle \"${handle}\"` };\n const form = (tag(el) === \"FORM\" ? el : el.closest(\"form\")) as HTMLFormElement | null;\n if (!form) return { ok: false, error: `Handle \"${handle}\" is not inside a form` };\n before(\"submit\");\n if (typeof form.requestSubmit === \"function\") form.requestSubmit();\n else form.submit();\n return { ok: true };\n },\n rectFor: (handle) => {\n const el = resolve(handle);\n if (!el) return null;\n const r = el.getBoundingClientRect();\n return { x: r.left, y: r.top, width: r.width, height: r.height };\n },\n resolve,\n call: (method, args = []) => {\n const a = Array.isArray(args) ? args : [];\n const handle = String(a[0] ?? \"\");\n switch (method) {\n case \"getLocation\":\n return agent.getLocation();\n case \"describe\":\n return agent.describe();\n case \"read\":\n return agent.read();\n case \"visit\":\n agent.visit(String(a[0] ?? \"\"));\n return undefined;\n case \"back\":\n agent.back();\n return undefined;\n case \"forward\":\n agent.forward();\n return undefined;\n case \"scrollTo\": {\n const o = (a[0] && typeof a[0] === \"object\" ? a[0] : {}) as Record<string, unknown>;\n agent.scrollTo({\n x: num(o.x),\n y: num(o.y),\n handle: typeof o.handle === \"string\" ? o.handle : undefined,\n });\n return undefined;\n }\n case \"scrollBy\":\n agent.scrollBy(Number(a[0] ?? 0));\n return undefined;\n case \"setField\":\n return agent.setField(handle, a[1]);\n case \"click\":\n return agent.click(handle);\n case \"submit\":\n return agent.submit(handle);\n case \"rectFor\":\n return agent.rectFor(handle);\n default:\n throw new Error(`Unknown dom-navigation method: ${String(method)}`);\n }\n },\n };\n return agent;\n}\n","/**\n * The host half: a {@link NavigationBridgeAdapter} that drives a page it does\n * not run in, through any transport that can carry a method name and plain\n * arguments into the page and a plain result back — Electron's\n * `executeJavaScript` / `executeJavaScriptInIsolatedWorld`, a MessagePort, a\n * WebSocket to a remote browser.\n *\n * Every result is treated as hostile: the page owns the DOM the in-page walker\n * reads, and if the script was injected into the MAIN world the page can\n * replace the walker outright. So results are coerced to the declared shapes\n * here, and anything malformed is dropped rather than passed on to the agent.\n */\nimport type {\n NavigationBridgeAdapter,\n NavigationConfirmRequest,\n PageAction,\n PageSnapshot,\n} from \"../bridges/navigation\";\nimport { DOM_NAVIGATION_METHODS, type ActionResult, type DomNavigationMethod, type HandleRect } from \"./agent\";\n\n/** The global the injected script installs in the world it runs in. */\nexport const DOM_NAVIGATION_GLOBAL = \"__fancyDomNavigation\";\n\n/** Bumped only if the wire protocol changes incompatibly. */\nexport const DOM_NAVIGATION_PROTOCOL = 1;\n\n/**\n * Carries one call into the page. `args` and the resolved value are plain,\n * structured-cloneable data. Reject (or throw) when the call could not be\n * delivered — e.g. the page navigated and the script must be re-injected.\n */\nexport type DomNavigationTransport = {\n call(method: DomNavigationMethod, args: unknown[]): Promise<unknown>;\n};\n\nexport type RemoteNavigationAdapterOptions = {\n transport: DomNavigationTransport;\n /** Optional fancy-screens screen id for presence targeting. */\n screenId?: string;\n /** Human-control revision, if the host tracks one. Omit to disable stale-intent protection. */\n getRevision?: () => number | Promise<number>;\n /**\n * Trust-but-verify. Without it, `page_submit` and destructive `page_click`\n * are NOT staged — they run as soon as the agent asks. A host showing pages\n * it does not own should always supply one.\n */\n confirm?: (req: NavigationConfirmRequest) => Promise<boolean>;\n};\n\nconst METHODS = new Set<string>(DOM_NAVIGATION_METHODS);\n\nfunction assertMethod(method: string): asserts method is DomNavigationMethod {\n if (!METHODS.has(method)) throw new Error(`Unknown dom-navigation method: ${method}`);\n}\n\n/**\n * A JavaScript expression that performs one call against the injected global —\n * what a host passes to `executeJavaScript`. Arguments are embedded as JSON,\n * which is a valid JS expression, so no argument can break out of its literal.\n */\nexport function domNavigationCallScript(method: DomNavigationMethod, args: unknown[] = []): string {\n assertMethod(method);\n const g = JSON.stringify(DOM_NAVIGATION_GLOBAL);\n return (\n `(function(){var n=globalThis[${g}];` +\n `if(!n||typeof n.call!==\"function\")throw new Error(\"fancy dom-navigation is not injected in this world\");` +\n `return n.call(${JSON.stringify(method)},${JSON.stringify(args)});})()`\n );\n}\n\nconst str = (v: unknown, fallback = \"\") => (typeof v === \"string\" ? v : fallback);\nconst isObj = (v: unknown): v is Record<string, unknown> => typeof v === \"object\" && v !== null;\n\nfunction coerceAction(v: unknown): PageAction | null {\n if (!isObj(v) || typeof v.handle !== \"string\" || v.handle === \"\") return null;\n const action: PageAction = {\n handle: v.handle,\n role: str(v.role, \"generic\"),\n label: str(v.label),\n destructive: v.destructive === true,\n };\n const value = v.value;\n if (typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value))) {\n action.value = value;\n }\n return action;\n}\n\nfunction coerceSnapshot(v: unknown): PageSnapshot {\n const o = isObj(v) ? v : {};\n const actions = Array.isArray(o.actions)\n ? o.actions.map(coerceAction).filter((a): a is PageAction => a !== null)\n : [];\n return { url: str(o.url), title: str(o.title), actions };\n}\n\nfunction coerceResult(v: unknown): ActionResult {\n const o = isObj(v) ? v : {};\n return { ok: o.ok === true, error: typeof o.error === \"string\" ? o.error : undefined };\n}\n\nfunction coerceRect(v: unknown): HandleRect | null {\n if (!isObj(v)) return null;\n const { x, y, width, height } = v;\n const finite = (n: unknown): n is number => typeof n === \"number\" && Number.isFinite(n);\n return finite(x) && finite(y) && finite(width) && finite(height) ? { x, y, width, height } : null;\n}\n\n/** Build a NavigationBridgeAdapter backed by a transport into the page. */\nexport function createRemoteNavigationAdapter(options: RemoteNavigationAdapterOptions): NavigationBridgeAdapter {\n const { transport } = options;\n const call = (method: DomNavigationMethod, ...args: unknown[]) => transport.call(method, args);\n const fail = (e: unknown): ActionResult => ({ ok: false, error: e instanceof Error ? e.message : String(e) });\n\n return {\n screenId: options.screenId,\n getRevision: options.getRevision,\n confirm: options.confirm,\n getLocation: async () => {\n const o = await call(\"getLocation\");\n const loc = isObj(o) ? o : {};\n return { url: str(loc.url), title: str(loc.title) };\n },\n describe: async () => coerceSnapshot(await call(\"describe\")),\n read: async () => str(await call(\"read\")),\n visit: async (url) => {\n await call(\"visit\", url);\n },\n back: async () => {\n await call(\"back\");\n },\n forward: async () => {\n await call(\"forward\");\n },\n scrollTo: async (opts) => {\n await call(\"scrollTo\", { x: opts.x, y: opts.y, handle: opts.handle });\n },\n scrollBy: async (dy) => {\n await call(\"scrollBy\", dy);\n },\n setField: async (handle, value) => coerceResult(await call(\"setField\", handle, value).catch(fail)),\n click: async (handle) => coerceResult(await call(\"click\", handle).catch(fail)),\n submit: async (handle) => coerceResult(await call(\"submit\", handle).catch(fail)),\n rectFor: async (handle) => coerceRect(await call(\"rectFor\", handle).catch(() => null)),\n };\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -3422,8 +3422,8 @@ function registerNavigationBridge(host, options) {
|
|
|
3422
3422
|
const pendingMode = options.pendingMode ?? true;
|
|
3423
3423
|
const disposers = [];
|
|
3424
3424
|
let groundedRevision = null;
|
|
3425
|
-
const staleIntent = () => {
|
|
3426
|
-
const current = adapter.getRevision?.();
|
|
3425
|
+
const staleIntent = async () => {
|
|
3426
|
+
const current = await adapter.getRevision?.();
|
|
3427
3427
|
if (current === void 0) return null;
|
|
3428
3428
|
if (groundedRevision === null || groundedRevision !== current) {
|
|
3429
3429
|
return errorResult(
|
|
@@ -3470,9 +3470,9 @@ function registerNavigationBridge(host, options) {
|
|
|
3470
3470
|
"Describe the current page: its URL, title, and the interactive elements you can act on (each with a stable `handle`, role, and label). Call this first, and again after navigating.",
|
|
3471
3471
|
{},
|
|
3472
3472
|
[],
|
|
3473
|
-
() => {
|
|
3474
|
-
const snap = adapter.describe();
|
|
3475
|
-
const revision = adapter.getRevision?.();
|
|
3473
|
+
async () => {
|
|
3474
|
+
const snap = await adapter.describe();
|
|
3475
|
+
const revision = await adapter.getRevision?.();
|
|
3476
3476
|
if (revision !== void 0) {
|
|
3477
3477
|
snap.revision = revision;
|
|
3478
3478
|
groundedRevision = revision;
|
|
@@ -3492,7 +3492,7 @@ function registerNavigationBridge(host, options) {
|
|
|
3492
3492
|
"Read the page's visible text / heading outline for grounding.",
|
|
3493
3493
|
{},
|
|
3494
3494
|
[],
|
|
3495
|
-
() => textResult(adapter.read ? adapter.read() : "(host did not provide page text)"),
|
|
3495
|
+
async () => textResult(adapter.read ? await adapter.read() : "(host did not provide page text)"),
|
|
3496
3496
|
() => target("Read page")
|
|
3497
3497
|
);
|
|
3498
3498
|
reg(
|
|
@@ -3500,15 +3500,15 @@ function registerNavigationBridge(host, options) {
|
|
|
3500
3500
|
"Move the agent's visible focus to an interactive element by stable handle without activating it.",
|
|
3501
3501
|
{ handle: { type: "string" } },
|
|
3502
3502
|
["handle"],
|
|
3503
|
-
(args) => {
|
|
3504
|
-
const stale = staleIntent();
|
|
3503
|
+
async (args) => {
|
|
3504
|
+
const stale = await staleIntent();
|
|
3505
3505
|
if (stale) return stale;
|
|
3506
3506
|
const handle = String(args.handle ?? "");
|
|
3507
|
-
const action = adapter.describe().actions.find((candidate) => candidate.handle === handle);
|
|
3507
|
+
const action = (await adapter.describe()).actions.find((candidate) => candidate.handle === handle);
|
|
3508
3508
|
if (!action) return errorResult(`No element for handle "${handle}"`);
|
|
3509
3509
|
return textResult(`Focused ${handle}`, {
|
|
3510
3510
|
handle,
|
|
3511
|
-
rect: adapter.rectFor?.(handle) ?? void 0
|
|
3511
|
+
rect: await adapter.rectFor?.(handle) ?? void 0
|
|
3512
3512
|
});
|
|
3513
3513
|
},
|
|
3514
3514
|
(args) => target(`Focus ${String(args.handle ?? "")}`, String(args.handle ?? ""))
|
|
@@ -3519,7 +3519,7 @@ function registerNavigationBridge(host, options) {
|
|
|
3519
3519
|
{ url: { type: "string", description: "Path like /packages or an absolute URL." } },
|
|
3520
3520
|
["url"],
|
|
3521
3521
|
async (args) => {
|
|
3522
|
-
const stale = staleIntent();
|
|
3522
|
+
const stale = await staleIntent();
|
|
3523
3523
|
if (stale) return stale;
|
|
3524
3524
|
const url = String(args.url ?? "");
|
|
3525
3525
|
if (!url) return errorResult("url is required");
|
|
@@ -3529,7 +3529,7 @@ function registerNavigationBridge(host, options) {
|
|
|
3529
3529
|
`Refusing to navigate to a '${scheme}:' URL. Only http(s) URLs or same-site paths are allowed.`
|
|
3530
3530
|
);
|
|
3531
3531
|
}
|
|
3532
|
-
const from = adapter.getLocation().url;
|
|
3532
|
+
const from = (await adapter.getLocation()).url;
|
|
3533
3533
|
await adapter.visit(url);
|
|
3534
3534
|
fancyAutoCommon.pushUndoEntry(agent.id, {
|
|
3535
3535
|
timestamp: Date.now(),
|
|
@@ -3553,7 +3553,7 @@ function registerNavigationBridge(host, options) {
|
|
|
3553
3553
|
{},
|
|
3554
3554
|
[],
|
|
3555
3555
|
async () => {
|
|
3556
|
-
const stale = staleIntent();
|
|
3556
|
+
const stale = await staleIntent();
|
|
3557
3557
|
if (stale) return stale;
|
|
3558
3558
|
if (!adapter.back) return errorResult("Host did not provide back navigation.");
|
|
3559
3559
|
await adapter.back();
|
|
@@ -3567,7 +3567,7 @@ function registerNavigationBridge(host, options) {
|
|
|
3567
3567
|
{},
|
|
3568
3568
|
[],
|
|
3569
3569
|
async () => {
|
|
3570
|
-
const stale = staleIntent();
|
|
3570
|
+
const stale = await staleIntent();
|
|
3571
3571
|
if (stale) return stale;
|
|
3572
3572
|
if (!adapter.forward) return errorResult("Host did not provide forward navigation.");
|
|
3573
3573
|
await adapter.forward();
|
|
@@ -3584,16 +3584,16 @@ function registerNavigationBridge(host, options) {
|
|
|
3584
3584
|
y: { type: "number" }
|
|
3585
3585
|
},
|
|
3586
3586
|
[],
|
|
3587
|
-
(args) => {
|
|
3588
|
-
const stale = staleIntent();
|
|
3587
|
+
async (args) => {
|
|
3588
|
+
const stale = await staleIntent();
|
|
3589
3589
|
if (stale) return stale;
|
|
3590
3590
|
const handle = typeof args.handle === "string" ? args.handle : void 0;
|
|
3591
|
-
adapter.scrollTo({
|
|
3591
|
+
await adapter.scrollTo({
|
|
3592
3592
|
handle,
|
|
3593
3593
|
x: typeof args.x === "number" ? args.x : void 0,
|
|
3594
3594
|
y: typeof args.y === "number" ? args.y : void 0
|
|
3595
3595
|
});
|
|
3596
|
-
return textResult("Scrolled", handle ? { handle, rect: adapter.rectFor?.(handle) ?? void 0 } : void 0);
|
|
3596
|
+
return textResult("Scrolled", handle ? { handle, rect: await adapter.rectFor?.(handle) ?? void 0 } : void 0);
|
|
3597
3597
|
},
|
|
3598
3598
|
() => target("Scroll")
|
|
3599
3599
|
);
|
|
@@ -3602,10 +3602,10 @@ function registerNavigationBridge(host, options) {
|
|
|
3602
3602
|
"Scroll the page by a vertical delta in pixels (negative scrolls up).",
|
|
3603
3603
|
{ dy: { type: "number" } },
|
|
3604
3604
|
["dy"],
|
|
3605
|
-
(args) => {
|
|
3606
|
-
const stale = staleIntent();
|
|
3605
|
+
async (args) => {
|
|
3606
|
+
const stale = await staleIntent();
|
|
3607
3607
|
if (stale) return stale;
|
|
3608
|
-
adapter.scrollBy(Number(args.dy ?? 0));
|
|
3608
|
+
await adapter.scrollBy(Number(args.dy ?? 0));
|
|
3609
3609
|
return textResult(`Scrolled by ${Number(args.dy ?? 0)}px`);
|
|
3610
3610
|
},
|
|
3611
3611
|
() => target("Scroll")
|
|
@@ -3618,13 +3618,13 @@ function registerNavigationBridge(host, options) {
|
|
|
3618
3618
|
value: { description: "Value to set; type matches the field." }
|
|
3619
3619
|
},
|
|
3620
3620
|
["handle", "value"],
|
|
3621
|
-
(args) => {
|
|
3622
|
-
const stale = staleIntent();
|
|
3621
|
+
async (args) => {
|
|
3622
|
+
const stale = await staleIntent();
|
|
3623
3623
|
if (stale) return stale;
|
|
3624
3624
|
const handle = String(args.handle ?? "");
|
|
3625
|
-
const res = adapter.setField(handle, args.value);
|
|
3625
|
+
const res = await adapter.setField(handle, args.value);
|
|
3626
3626
|
if (!res.ok) return errorResult(res.error ?? `Could not set ${handle}`);
|
|
3627
|
-
return textResult(`${handle} \u2190 ${JSON.stringify(args.value)}`, { handle, value: args.value, rect: adapter.rectFor?.(handle) ?? void 0 });
|
|
3627
|
+
return textResult(`${handle} \u2190 ${JSON.stringify(args.value)}`, { handle, value: args.value, rect: await adapter.rectFor?.(handle) ?? void 0 });
|
|
3628
3628
|
},
|
|
3629
3629
|
(args) => target(`Set ${String(args.handle ?? "")}`, String(args.handle ?? ""))
|
|
3630
3630
|
);
|
|
@@ -3634,16 +3634,16 @@ function registerNavigationBridge(host, options) {
|
|
|
3634
3634
|
{ handle: { type: "string" } },
|
|
3635
3635
|
["handle"],
|
|
3636
3636
|
async (args) => {
|
|
3637
|
-
const stale = staleIntent();
|
|
3637
|
+
const stale = await staleIntent();
|
|
3638
3638
|
if (stale) return stale;
|
|
3639
3639
|
const handle = String(args.handle ?? "");
|
|
3640
|
-
const action = adapter.describe().actions.find((a) => a.handle === handle);
|
|
3641
|
-
const rect = adapter.rectFor?.(handle) ?? void 0;
|
|
3640
|
+
const action = (await adapter.describe()).actions.find((a) => a.handle === handle);
|
|
3641
|
+
const rect = await adapter.rectFor?.(handle) ?? void 0;
|
|
3642
3642
|
if (pendingMode && action?.destructive && adapter.confirm) {
|
|
3643
3643
|
const ok = await adapter.confirm({ action: "click", handle, label: action.label });
|
|
3644
3644
|
if (!ok) return errorResult("Declined by user");
|
|
3645
3645
|
}
|
|
3646
|
-
const res = adapter.click(handle);
|
|
3646
|
+
const res = await adapter.click(handle);
|
|
3647
3647
|
if (!res.ok) return errorResult(res.error ?? `Could not click ${handle}`);
|
|
3648
3648
|
return textResult(`Clicked ${handle}`, { handle, rect });
|
|
3649
3649
|
},
|
|
@@ -3655,10 +3655,10 @@ function registerNavigationBridge(host, options) {
|
|
|
3655
3655
|
{ handle: { type: "string" } },
|
|
3656
3656
|
["handle"],
|
|
3657
3657
|
async (args) => {
|
|
3658
|
-
const stale = staleIntent();
|
|
3658
|
+
const stale = await staleIntent();
|
|
3659
3659
|
if (stale) return stale;
|
|
3660
3660
|
const handle = String(args.handle ?? "");
|
|
3661
|
-
const rect = adapter.rectFor?.(handle) ?? void 0;
|
|
3661
|
+
const rect = await adapter.rectFor?.(handle) ?? void 0;
|
|
3662
3662
|
if (pendingMode && adapter.confirm) {
|
|
3663
3663
|
const ok = await adapter.confirm({ action: "submit", handle, label: handle });
|
|
3664
3664
|
if (!ok) return errorResult("Declined by user");
|