@elizaos/plugin-browser 2.0.0-alpha.9 → 2.0.3-beta.2
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/LICENSE +21 -0
- package/README.md +98 -83
- package/auto-enable.ts +24 -0
- package/dist/actions/browser-autofill-login.d.ts +43 -0
- package/dist/actions/browser-autofill-login.d.ts.map +1 -0
- package/dist/actions/browser-autofill-login.js +278 -0
- package/dist/actions/browser-autofill-login.js.map +1 -0
- package/dist/actions/browser.d.ts +11 -0
- package/dist/actions/browser.d.ts.map +1 -0
- package/dist/actions/browser.js +412 -0
- package/dist/actions/browser.js.map +1 -0
- package/dist/actions/manage-browser-bridge.d.ts +34 -0
- package/dist/actions/manage-browser-bridge.d.ts.map +1 -0
- package/dist/actions/manage-browser-bridge.js +572 -0
- package/dist/actions/manage-browser-bridge.js.map +1 -0
- package/dist/bridge-policy.d.ts +10 -0
- package/dist/bridge-policy.d.ts.map +1 -0
- package/dist/bridge-policy.js +37 -0
- package/dist/bridge-policy.js.map +1 -0
- package/dist/bridge-readiness.d.ts +16 -0
- package/dist/bridge-readiness.d.ts.map +1 -0
- package/dist/bridge-readiness.js +82 -0
- package/dist/bridge-readiness.js.map +1 -0
- package/dist/bridge-records.d.ts +9 -0
- package/dist/bridge-records.d.ts.map +1 -0
- package/dist/bridge-records.js +37 -0
- package/dist/bridge-records.js.map +1 -0
- package/dist/browser-capture-hooks.d.ts +9 -0
- package/dist/browser-capture-hooks.d.ts.map +1 -0
- package/dist/browser-capture-hooks.js +15 -0
- package/dist/browser-capture-hooks.js.map +1 -0
- package/dist/browser-service.d.ts +103 -0
- package/dist/browser-service.d.ts.map +1 -0
- package/dist/browser-service.js +186 -0
- package/dist/browser-service.js.map +1 -0
- package/dist/browser-workspace-hooks.d.ts +14 -0
- package/dist/browser-workspace-hooks.d.ts.map +1 -0
- package/dist/browser-workspace-hooks.js +15 -0
- package/dist/browser-workspace-hooks.js.map +1 -0
- package/dist/companion-auth.d.ts +34 -0
- package/dist/companion-auth.d.ts.map +1 -0
- package/dist/companion-auth.js +98 -0
- package/dist/companion-auth.js.map +1 -0
- package/dist/contracts.d.ts +284 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +56 -0
- package/dist/contracts.js.map +1 -0
- package/dist/index.d.ts +30 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +76 -90
- package/dist/index.js.map +1 -1
- package/dist/lifeops-session-contracts.d.ts +46 -0
- package/dist/lifeops-session-contracts.d.ts.map +1 -0
- package/dist/lifeops-session-contracts.js +1 -0
- package/dist/lifeops-session-contracts.js.map +1 -0
- package/dist/message-adapter.d.ts +9 -0
- package/dist/message-adapter.d.ts.map +1 -0
- package/dist/message-adapter.js +104 -0
- package/dist/message-adapter.js.map +1 -0
- package/dist/packaging.d.ts +27 -0
- package/dist/packaging.d.ts.map +1 -0
- package/dist/packaging.js +571 -0
- package/dist/packaging.js.map +1 -0
- package/dist/password-manager-bridge.d.ts +50 -0
- package/dist/password-manager-bridge.d.ts.map +1 -0
- package/dist/password-manager-bridge.js +437 -0
- package/dist/password-manager-bridge.js.map +1 -0
- package/dist/plugin.d.ts +10 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +168 -0
- package/dist/plugin.js.map +1 -0
- package/dist/providers/workspace.d.ts +13 -0
- package/dist/providers/workspace.d.ts.map +1 -0
- package/dist/providers/workspace.js +64 -0
- package/dist/providers/workspace.js.map +1 -0
- package/dist/routes/bridge.d.ts +37 -0
- package/dist/routes/bridge.d.ts.map +1 -0
- package/dist/routes/bridge.js +844 -0
- package/dist/routes/bridge.js.map +1 -0
- package/dist/routes/workspace-account-gate.d.ts +29 -0
- package/dist/routes/workspace-account-gate.d.ts.map +1 -0
- package/dist/routes/workspace-account-gate.js +147 -0
- package/dist/routes/workspace-account-gate.js.map +1 -0
- package/dist/routes/workspace-setup.d.ts +10 -0
- package/dist/routes/workspace-setup.d.ts.map +1 -0
- package/dist/routes/workspace-setup.js +65 -0
- package/dist/routes/workspace-setup.js.map +1 -0
- package/dist/routes/workspace.d.ts +20 -0
- package/dist/routes/workspace.d.ts.map +1 -0
- package/dist/routes/workspace.js +276 -0
- package/dist/routes/workspace.js.map +1 -0
- package/dist/schema.d.ts +2326 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +133 -0
- package/dist/schema.js.map +1 -0
- package/dist/service.d.ts +30 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +5 -0
- package/dist/service.js.map +1 -0
- package/dist/targets/bridge-target.d.ts +31 -0
- package/dist/targets/bridge-target.d.ts.map +1 -0
- package/dist/targets/bridge-target.js +98 -0
- package/dist/targets/bridge-target.js.map +1 -0
- package/dist/targets/stagehand-target.d.ts +3 -0
- package/dist/targets/stagehand-target.d.ts.map +1 -0
- package/dist/targets/stagehand-target.js +187 -0
- package/dist/targets/stagehand-target.js.map +1 -0
- package/dist/workspace/browser-capture.d.ts +41 -0
- package/dist/workspace/browser-capture.d.ts.map +1 -0
- package/dist/workspace/browser-capture.js +159 -0
- package/dist/workspace/browser-capture.js.map +1 -0
- package/dist/workspace/browser-workspace-desktop.d.ts +19 -0
- package/dist/workspace/browser-workspace-desktop.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-desktop.js +1578 -0
- package/dist/workspace/browser-workspace-desktop.js.map +1 -0
- package/dist/workspace/browser-workspace-elements.d.ts +42 -0
- package/dist/workspace/browser-workspace-elements.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-elements.js +547 -0
- package/dist/workspace/browser-workspace-elements.js.map +1 -0
- package/dist/workspace/browser-workspace-forms.d.ts +19 -0
- package/dist/workspace/browser-workspace-forms.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-forms.js +277 -0
- package/dist/workspace/browser-workspace-forms.js.map +1 -0
- package/dist/workspace/browser-workspace-helpers.d.ts +32 -0
- package/dist/workspace/browser-workspace-helpers.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-helpers.js +232 -0
- package/dist/workspace/browser-workspace-helpers.js.map +1 -0
- package/dist/workspace/browser-workspace-jsdom.d.ts +16 -0
- package/dist/workspace/browser-workspace-jsdom.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-jsdom.js +233 -0
- package/dist/workspace/browser-workspace-jsdom.js.map +1 -0
- package/dist/workspace/browser-workspace-network.d.ts +7 -0
- package/dist/workspace/browser-workspace-network.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-network.js +145 -0
- package/dist/workspace/browser-workspace-network.js.map +1 -0
- package/dist/workspace/browser-workspace-snapshots.d.ts +14 -0
- package/dist/workspace/browser-workspace-snapshots.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-snapshots.js +144 -0
- package/dist/workspace/browser-workspace-snapshots.js.map +1 -0
- package/dist/workspace/browser-workspace-state.d.ts +24 -0
- package/dist/workspace/browser-workspace-state.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-state.js +155 -0
- package/dist/workspace/browser-workspace-state.js.map +1 -0
- package/dist/workspace/browser-workspace-types.d.ts +345 -0
- package/dist/workspace/browser-workspace-types.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-types.js +11 -0
- package/dist/workspace/browser-workspace-types.js.map +1 -0
- package/dist/workspace/browser-workspace-web.d.ts +8 -0
- package/dist/workspace/browser-workspace-web.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-web.js +1342 -0
- package/dist/workspace/browser-workspace-web.js.map +1 -0
- package/dist/workspace/browser-workspace.d.ts +39 -0
- package/dist/workspace/browser-workspace.d.ts.map +1 -0
- package/dist/workspace/browser-workspace.js +958 -0
- package/dist/workspace/browser-workspace.js.map +1 -0
- package/dist/workspace/index.d.ts +26 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +3 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace.d.ts +2 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +2 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +71 -110
- package/dist/actions/click.d.ts +0 -3
- package/dist/actions/click.d.ts.map +0 -1
- package/dist/actions/click.js +0 -158
- package/dist/actions/click.js.map +0 -1
- package/dist/actions/extract.d.ts +0 -3
- package/dist/actions/extract.d.ts.map +0 -1
- package/dist/actions/extract.js +0 -168
- package/dist/actions/extract.js.map +0 -1
- package/dist/actions/index.d.ts +0 -7
- package/dist/actions/index.d.ts.map +0 -1
- package/dist/actions/index.js +0 -7
- package/dist/actions/index.js.map +0 -1
- package/dist/actions/navigate.d.ts +0 -3
- package/dist/actions/navigate.d.ts.map +0 -1
- package/dist/actions/navigate.js +0 -187
- package/dist/actions/navigate.js.map +0 -1
- package/dist/actions/screenshot.d.ts +0 -3
- package/dist/actions/screenshot.d.ts.map +0 -1
- package/dist/actions/screenshot.js +0 -167
- package/dist/actions/screenshot.js.map +0 -1
- package/dist/actions/select.d.ts +0 -3
- package/dist/actions/select.d.ts.map +0 -1
- package/dist/actions/select.js +0 -167
- package/dist/actions/select.js.map +0 -1
- package/dist/actions/type.d.ts +0 -3
- package/dist/actions/type.d.ts.map +0 -1
- package/dist/actions/type.js +0 -167
- package/dist/actions/type.js.map +0 -1
- package/dist/cli/index.d.ts +0 -8
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -13
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/register.d.ts +0 -20
- package/dist/cli/register.d.ts.map +0 -1
- package/dist/cli/register.js +0 -403
- package/dist/cli/register.js.map +0 -1
- package/dist/providerRelevance.d.ts +0 -4
- package/dist/providerRelevance.d.ts.map +0 -1
- package/dist/providerRelevance.js +0 -33
- package/dist/providerRelevance.js.map +0 -1
- package/dist/providers/browser-state.d.ts +0 -3
- package/dist/providers/browser-state.d.ts.map +0 -1
- package/dist/providers/browser-state.js +0 -72
- package/dist/providers/browser-state.js.map +0 -1
- package/dist/providers/index.d.ts +0 -2
- package/dist/providers/index.d.ts.map +0 -1
- package/dist/providers/index.js +0 -2
- package/dist/providers/index.js.map +0 -1
- package/dist/services/browser-service.d.ts +0 -32
- package/dist/services/browser-service.d.ts.map +0 -1
- package/dist/services/browser-service.js +0 -213
- package/dist/services/browser-service.js.map +0 -1
- package/dist/services/index.d.ts +0 -4
- package/dist/services/index.d.ts.map +0 -1
- package/dist/services/index.js +0 -4
- package/dist/services/index.js.map +0 -1
- package/dist/services/process-manager.d.ts +0 -24
- package/dist/services/process-manager.d.ts.map +0 -1
- package/dist/services/process-manager.js +0 -270
- package/dist/services/process-manager.js.map +0 -1
- package/dist/services/websocket-client.d.ts +0 -35
- package/dist/services/websocket-client.d.ts.map +0 -1
- package/dist/services/websocket-client.js +0 -221
- package/dist/services/websocket-client.js.map +0 -1
- package/dist/types.d.ts +0 -101
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/utils/captcha.d.ts +0 -33
- package/dist/utils/captcha.d.ts.map +0 -1
- package/dist/utils/captcha.js +0 -219
- package/dist/utils/captcha.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -37
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/errors.js +0 -81
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/index.d.ts +0 -5
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -5
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/retry.d.ts +0 -26
- package/dist/utils/retry.d.ts.map +0 -1
- package/dist/utils/retry.js +0 -55
- package/dist/utils/retry.js.map +0 -1
- package/dist/utils/security.d.ts +0 -27
- package/dist/utils/security.d.ts.map +0 -1
- package/dist/utils/security.js +0 -139
- package/dist/utils/security.js.map +0 -1
- package/dist/utils/url.d.ts +0 -12
- package/dist/utils/url.d.ts.map +0 -1
- package/dist/utils/url.js +0 -39
- package/dist/utils/url.js.map +0 -1
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildBrowserWorkspaceCssStringLiteral,
|
|
3
|
+
normalizeBrowserWorkspaceText
|
|
4
|
+
} from "./browser-workspace-helpers.js";
|
|
5
|
+
import { getJSDOMClass } from "./browser-workspace-jsdom.js";
|
|
6
|
+
function buildBrowserWorkspaceElementSelector(element) {
|
|
7
|
+
const escapeFn = globalThis.CSS?.escape;
|
|
8
|
+
const escapedId = typeof escapeFn === "function" ? escapeFn(element.id) : element.id.replace(/[^a-zA-Z0-9_-]/g, "\\$&");
|
|
9
|
+
if (element.id) {
|
|
10
|
+
return `#${escapedId}`;
|
|
11
|
+
}
|
|
12
|
+
const testId = element.getAttribute("data-testid")?.trim();
|
|
13
|
+
if (testId) {
|
|
14
|
+
return `[data-testid=${buildBrowserWorkspaceCssStringLiteral(testId)}]`;
|
|
15
|
+
}
|
|
16
|
+
const name = element.getAttribute("name")?.trim();
|
|
17
|
+
if (name) {
|
|
18
|
+
return `${element.tagName.toLowerCase()}[name=${buildBrowserWorkspaceCssStringLiteral(name)}]`;
|
|
19
|
+
}
|
|
20
|
+
const type = element.getAttribute("type")?.trim();
|
|
21
|
+
if (type) {
|
|
22
|
+
return `${element.tagName.toLowerCase()}[type=${buildBrowserWorkspaceCssStringLiteral(type)}]`;
|
|
23
|
+
}
|
|
24
|
+
const parent = element.parentElement;
|
|
25
|
+
if (!parent) {
|
|
26
|
+
return element.tagName.toLowerCase();
|
|
27
|
+
}
|
|
28
|
+
const siblings = parent.children;
|
|
29
|
+
let index = 1;
|
|
30
|
+
for (let cursor = 0; cursor < siblings.length; cursor += 1) {
|
|
31
|
+
const sibling = siblings.item(cursor);
|
|
32
|
+
if (!sibling || sibling.tagName !== element.tagName) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (sibling === element) {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
index += 1;
|
|
39
|
+
}
|
|
40
|
+
return `${element.tagName.toLowerCase()}:nth-of-type(${index})`;
|
|
41
|
+
}
|
|
42
|
+
function createBrowserWorkspaceElementSummary(element) {
|
|
43
|
+
const inputLike = element.tagName === "INPUT" || element.tagName === "TEXTAREA" || element.tagName === "SELECT";
|
|
44
|
+
const elementValue = inputLike ? element.value ?? null : null;
|
|
45
|
+
return {
|
|
46
|
+
selector: buildBrowserWorkspaceElementSelector(element),
|
|
47
|
+
tag: element.tagName.toLowerCase(),
|
|
48
|
+
text: normalizeBrowserWorkspaceText(
|
|
49
|
+
inputLike ? elementValue : element.textContent
|
|
50
|
+
),
|
|
51
|
+
type: element.getAttribute("type"),
|
|
52
|
+
name: element.getAttribute("name"),
|
|
53
|
+
href: element.getAttribute("href"),
|
|
54
|
+
value: typeof elementValue === "string" ? elementValue : null
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function collectBrowserWorkspaceInspectElements(document) {
|
|
58
|
+
const elements = Array.from(
|
|
59
|
+
document.querySelectorAll(
|
|
60
|
+
"a, button, input, textarea, select, form, [role='button'], [data-testid]"
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
const summaries = [];
|
|
64
|
+
const seenSelectors = /* @__PURE__ */ new Set();
|
|
65
|
+
for (const element of elements) {
|
|
66
|
+
const summary = createBrowserWorkspaceElementSummary(element);
|
|
67
|
+
if (seenSelectors.has(summary.selector)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
seenSelectors.add(summary.selector);
|
|
71
|
+
summaries.push(summary);
|
|
72
|
+
if (summaries.length >= 40) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return summaries;
|
|
77
|
+
}
|
|
78
|
+
function resolveBrowserWorkspaceIframeDocument(runtime, frameElement, baseUrl) {
|
|
79
|
+
if (!frameElement || frameElement.tagName !== "IFRAME") {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
const iframe = frameElement;
|
|
83
|
+
const srcdoc = iframe.getAttribute("srcdoc");
|
|
84
|
+
if (srcdoc?.trim()) {
|
|
85
|
+
const selector = buildBrowserWorkspaceElementSelector(frameElement);
|
|
86
|
+
const cached = runtime.frameDoms.get(selector);
|
|
87
|
+
if (cached) {
|
|
88
|
+
return cached.window.document;
|
|
89
|
+
}
|
|
90
|
+
if (iframe.contentDocument && normalizeBrowserWorkspaceText(iframe.contentDocument.body?.textContent).length > 0) {
|
|
91
|
+
return iframe.contentDocument;
|
|
92
|
+
}
|
|
93
|
+
const parsed = new (getJSDOMClass())(srcdoc, {
|
|
94
|
+
pretendToBeVisual: true,
|
|
95
|
+
url: baseUrl
|
|
96
|
+
});
|
|
97
|
+
runtime.frameDoms.set(selector, parsed);
|
|
98
|
+
return parsed.window.document;
|
|
99
|
+
}
|
|
100
|
+
if (iframe.contentDocument) {
|
|
101
|
+
return iframe.contentDocument;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
function resolveWebBrowserWorkspaceCommandDocument(tab, dom, runtimeState) {
|
|
106
|
+
const state = runtimeState;
|
|
107
|
+
const frameSelector = state.currentFrame?.trim() || null;
|
|
108
|
+
if (!frameSelector) {
|
|
109
|
+
return { document: dom.window.document, frameSelector: null };
|
|
110
|
+
}
|
|
111
|
+
const frameElement = resolveBrowserWorkspaceElement(
|
|
112
|
+
dom.window.document,
|
|
113
|
+
frameSelector
|
|
114
|
+
);
|
|
115
|
+
const frameDocument = resolveBrowserWorkspaceIframeDocument(
|
|
116
|
+
state,
|
|
117
|
+
frameElement,
|
|
118
|
+
tab.url
|
|
119
|
+
);
|
|
120
|
+
if (!frameDocument) {
|
|
121
|
+
return { document: dom.window.document, frameSelector: null };
|
|
122
|
+
}
|
|
123
|
+
return { document: frameDocument, frameSelector };
|
|
124
|
+
}
|
|
125
|
+
function getBrowserWorkspaceElementSearchTexts(element) {
|
|
126
|
+
const labelText = element.id && element.ownerDocument ? Array.from(
|
|
127
|
+
element.ownerDocument.querySelectorAll(`label[for="${element.id}"]`)
|
|
128
|
+
).map((label) => label.textContent).join(" ") : "";
|
|
129
|
+
return [
|
|
130
|
+
element.textContent,
|
|
131
|
+
element.getAttribute("aria-label"),
|
|
132
|
+
element.getAttribute("placeholder"),
|
|
133
|
+
element.getAttribute("title"),
|
|
134
|
+
element.getAttribute("name"),
|
|
135
|
+
element.getAttribute("alt"),
|
|
136
|
+
element.getAttribute("data-testid"),
|
|
137
|
+
labelText,
|
|
138
|
+
element.value
|
|
139
|
+
].map((value) => normalizeBrowserWorkspaceText(value)).filter(Boolean);
|
|
140
|
+
}
|
|
141
|
+
function browserWorkspaceTextMatches(candidate, wanted, exact = false) {
|
|
142
|
+
const normalizedCandidate = normalizeBrowserWorkspaceText(candidate).toLowerCase();
|
|
143
|
+
const normalizedWanted = normalizeBrowserWorkspaceText(wanted).toLowerCase();
|
|
144
|
+
if (!normalizedCandidate || !normalizedWanted) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
return exact ? normalizedCandidate === normalizedWanted : normalizedCandidate.includes(normalizedWanted);
|
|
148
|
+
}
|
|
149
|
+
function isBrowserWorkspaceElementVisible(element) {
|
|
150
|
+
if (element.hasAttribute("hidden") || element.getAttribute("aria-hidden") === "true") {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
const htmlElement = element;
|
|
154
|
+
const inlineDisplay = htmlElement.style?.display?.trim().toLowerCase();
|
|
155
|
+
const inlineVisibility = htmlElement.style?.visibility?.trim().toLowerCase();
|
|
156
|
+
if (inlineDisplay === "none" || inlineVisibility === "hidden") {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
function findBrowserWorkspaceElementByLabel(document, labelText, exact = false) {
|
|
162
|
+
const labels = Array.from(document.querySelectorAll("label"));
|
|
163
|
+
for (const label of labels) {
|
|
164
|
+
if (!browserWorkspaceTextMatches(label.textContent ?? "", labelText, exact)) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const forId = label.getAttribute("for")?.trim();
|
|
168
|
+
if (forId) {
|
|
169
|
+
const explicit = document.getElementById(forId);
|
|
170
|
+
if (explicit) {
|
|
171
|
+
return explicit;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const nested = label.querySelector("input, textarea, select, button");
|
|
175
|
+
if (nested) {
|
|
176
|
+
return nested;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
function getBrowserWorkspaceNativeRole(element) {
|
|
182
|
+
const explicitRole = element.getAttribute("role")?.trim().toLowerCase();
|
|
183
|
+
if (explicitRole) {
|
|
184
|
+
return explicitRole;
|
|
185
|
+
}
|
|
186
|
+
const tag = element.tagName.toLowerCase();
|
|
187
|
+
if (tag === "a" && element.getAttribute("href")) return "link";
|
|
188
|
+
if (tag === "button") return "button";
|
|
189
|
+
if (tag === "select") return "combobox";
|
|
190
|
+
if (tag === "option") return "option";
|
|
191
|
+
if (tag === "textarea") return "textbox";
|
|
192
|
+
if (tag === "form") return "form";
|
|
193
|
+
if (/^h[1-6]$/.test(tag)) return "heading";
|
|
194
|
+
if (tag === "input") {
|
|
195
|
+
const input = element;
|
|
196
|
+
const type = (input.type || "text").toLowerCase();
|
|
197
|
+
if (type === "checkbox") return "checkbox";
|
|
198
|
+
if (type === "radio") return "radio";
|
|
199
|
+
if (["button", "submit", "reset", "image"].includes(type)) {
|
|
200
|
+
return "button";
|
|
201
|
+
}
|
|
202
|
+
return "textbox";
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
function findBrowserWorkspaceElementByRole(document, role, name, exact = false) {
|
|
207
|
+
const wantedRole = role.trim().toLowerCase();
|
|
208
|
+
if (!wantedRole) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
const candidates = Array.from(
|
|
212
|
+
document.querySelectorAll(
|
|
213
|
+
"a, button, input, textarea, select, option, form, h1, h2, h3, h4, h5, h6, [role], [data-testid]"
|
|
214
|
+
)
|
|
215
|
+
);
|
|
216
|
+
for (const candidate of candidates) {
|
|
217
|
+
if (getBrowserWorkspaceNativeRole(candidate) !== wantedRole) {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (!name?.trim()) {
|
|
221
|
+
return candidate;
|
|
222
|
+
}
|
|
223
|
+
const haystacks = getBrowserWorkspaceElementSearchTexts(candidate);
|
|
224
|
+
if (haystacks.some((value) => browserWorkspaceTextMatches(value, name, exact))) {
|
|
225
|
+
return candidate;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
function trimBrowserWorkspaceQuotedValue(value) {
|
|
231
|
+
const trimmed = value.trim();
|
|
232
|
+
const hasTextMatch = trimmed.match(/^has-text\((['"])([\s\S]*?)\1\)$/i);
|
|
233
|
+
if (hasTextMatch?.[2]) {
|
|
234
|
+
return hasTextMatch[2].trim();
|
|
235
|
+
}
|
|
236
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
237
|
+
return trimmed.slice(1, -1).trim();
|
|
238
|
+
}
|
|
239
|
+
return trimmed;
|
|
240
|
+
}
|
|
241
|
+
function normalizeBrowserWorkspaceSelectorSyntax(selector) {
|
|
242
|
+
let normalized = selector.trim();
|
|
243
|
+
normalized = normalized.replace(
|
|
244
|
+
/^role\s*[:=]\s*([a-z0-9_-]+)\s+name\s*[:=]\s*(.+)$/i,
|
|
245
|
+
"role=$1[name=$2]"
|
|
246
|
+
);
|
|
247
|
+
normalized = normalized.replace(
|
|
248
|
+
/^((?:label|text|placeholder|alt|title|testid|data-testid)\s*[:=]\s*(?:has-text\((['"])[\s\S]*?\2\)|"[^"]+"|'[^']+'|[^>]+?))\s+((?:input|textarea|select)[\s\S]*)$/i,
|
|
249
|
+
"$1 >> $3"
|
|
250
|
+
);
|
|
251
|
+
return normalized;
|
|
252
|
+
}
|
|
253
|
+
function parseBrowserWorkspaceSemanticSelector(selector) {
|
|
254
|
+
const trimmed = normalizeBrowserWorkspaceSelectorSyntax(selector);
|
|
255
|
+
const match = trimmed.match(/^([a-z-]+)\s*[:=]\s*(.+)$/i);
|
|
256
|
+
if (!match) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
const kind = match[1]?.trim().toLowerCase();
|
|
260
|
+
const rawValue = match[2]?.trim() ?? "";
|
|
261
|
+
if (!kind || !rawValue) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
switch (kind) {
|
|
265
|
+
case "alt":
|
|
266
|
+
return { findBy: "alt", text: trimBrowserWorkspaceQuotedValue(rawValue) };
|
|
267
|
+
case "css":
|
|
268
|
+
return { selector: trimBrowserWorkspaceQuotedValue(rawValue) };
|
|
269
|
+
case "data-testid":
|
|
270
|
+
case "testid":
|
|
271
|
+
return {
|
|
272
|
+
findBy: "testid",
|
|
273
|
+
text: trimBrowserWorkspaceQuotedValue(rawValue)
|
|
274
|
+
};
|
|
275
|
+
case "label":
|
|
276
|
+
return {
|
|
277
|
+
findBy: "label",
|
|
278
|
+
text: trimBrowserWorkspaceQuotedValue(rawValue)
|
|
279
|
+
};
|
|
280
|
+
case "placeholder":
|
|
281
|
+
return {
|
|
282
|
+
findBy: "placeholder",
|
|
283
|
+
text: trimBrowserWorkspaceQuotedValue(rawValue)
|
|
284
|
+
};
|
|
285
|
+
case "role": {
|
|
286
|
+
const roleMatch = rawValue.match(
|
|
287
|
+
/^([a-z0-9_-]+)(?:\s*\[\s*name\s*[:=]\s*(.+?)\s*\])?$/i
|
|
288
|
+
);
|
|
289
|
+
if (!roleMatch?.[1]) {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
findBy: "role",
|
|
294
|
+
name: roleMatch[2] ? trimBrowserWorkspaceQuotedValue(roleMatch[2]) : void 0,
|
|
295
|
+
role: roleMatch[1].trim().toLowerCase()
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
case "text":
|
|
299
|
+
return {
|
|
300
|
+
findBy: "text",
|
|
301
|
+
text: trimBrowserWorkspaceQuotedValue(rawValue)
|
|
302
|
+
};
|
|
303
|
+
case "title":
|
|
304
|
+
return {
|
|
305
|
+
findBy: "title",
|
|
306
|
+
text: trimBrowserWorkspaceQuotedValue(rawValue)
|
|
307
|
+
};
|
|
308
|
+
default:
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function mergeBrowserWorkspaceSelectorCommand(command, selector) {
|
|
313
|
+
const parsed = parseBrowserWorkspaceSemanticSelector(selector);
|
|
314
|
+
if (!parsed) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
return {
|
|
318
|
+
...command,
|
|
319
|
+
...parsed,
|
|
320
|
+
selector: parsed.selector
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function queryBrowserWorkspaceSelector(root, selector) {
|
|
324
|
+
try {
|
|
325
|
+
return root.querySelector(selector);
|
|
326
|
+
} catch {
|
|
327
|
+
throw new Error(`Invalid selector ${selector}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function queryAllBrowserWorkspaceSelector(root, selector) {
|
|
331
|
+
try {
|
|
332
|
+
return Array.from(root.querySelectorAll(selector));
|
|
333
|
+
} catch {
|
|
334
|
+
throw new Error(`Invalid selector ${selector}`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function findBrowserWorkspaceElementByText(document, needle) {
|
|
338
|
+
const wanted = normalizeBrowserWorkspaceText(needle).toLowerCase();
|
|
339
|
+
if (!wanted) {
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
const candidates = Array.from(
|
|
343
|
+
document.querySelectorAll(
|
|
344
|
+
"a, button, input, textarea, select, option, label, h1, h2, h3, [role='button'], [data-testid]"
|
|
345
|
+
)
|
|
346
|
+
);
|
|
347
|
+
for (const element of candidates) {
|
|
348
|
+
const haystacks = [
|
|
349
|
+
element.textContent,
|
|
350
|
+
element.getAttribute("aria-label"),
|
|
351
|
+
element.getAttribute("placeholder"),
|
|
352
|
+
element.getAttribute("title"),
|
|
353
|
+
element.getAttribute("name"),
|
|
354
|
+
element.value
|
|
355
|
+
].map((value) => normalizeBrowserWorkspaceText(value)).filter(Boolean).map((value) => value.toLowerCase());
|
|
356
|
+
if (haystacks.some((value) => value.includes(wanted))) {
|
|
357
|
+
return element;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
function resolveBrowserWorkspaceFindElement(document, command) {
|
|
363
|
+
switch (command.findBy) {
|
|
364
|
+
case "alt":
|
|
365
|
+
return Array.from(document.querySelectorAll("[alt]")).find(
|
|
366
|
+
(element) => browserWorkspaceTextMatches(
|
|
367
|
+
element.getAttribute("alt") ?? "",
|
|
368
|
+
command.text ?? "",
|
|
369
|
+
command.exact
|
|
370
|
+
)
|
|
371
|
+
) ?? null;
|
|
372
|
+
case "first":
|
|
373
|
+
return command.selector?.trim() ? queryBrowserWorkspaceSelector(document, command.selector) : null;
|
|
374
|
+
case "label":
|
|
375
|
+
return command.text?.trim() ? findBrowserWorkspaceElementByLabel(
|
|
376
|
+
document,
|
|
377
|
+
command.text,
|
|
378
|
+
command.exact
|
|
379
|
+
) : null;
|
|
380
|
+
case "last":
|
|
381
|
+
return command.selector?.trim() ? queryAllBrowserWorkspaceSelector(document, command.selector).at(
|
|
382
|
+
-1
|
|
383
|
+
) ?? null : null;
|
|
384
|
+
case "nth":
|
|
385
|
+
if (!command.selector?.trim()) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
if (typeof command.index !== "number" || !Number.isInteger(command.index)) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
return queryAllBrowserWorkspaceSelector(document, command.selector).at(
|
|
392
|
+
command.index
|
|
393
|
+
) ?? null;
|
|
394
|
+
case "placeholder":
|
|
395
|
+
return Array.from(document.querySelectorAll("[placeholder]")).find(
|
|
396
|
+
(element) => browserWorkspaceTextMatches(
|
|
397
|
+
element.getAttribute("placeholder") ?? "",
|
|
398
|
+
command.text ?? "",
|
|
399
|
+
command.exact
|
|
400
|
+
)
|
|
401
|
+
) ?? null;
|
|
402
|
+
case "role":
|
|
403
|
+
return command.role?.trim() ? findBrowserWorkspaceElementByRole(
|
|
404
|
+
document,
|
|
405
|
+
command.role,
|
|
406
|
+
command.name,
|
|
407
|
+
command.exact
|
|
408
|
+
) : null;
|
|
409
|
+
case "testid":
|
|
410
|
+
return command.text?.trim() ? document.querySelector(
|
|
411
|
+
`[data-testid=${buildBrowserWorkspaceCssStringLiteral(command.text)}]`
|
|
412
|
+
) : null;
|
|
413
|
+
case "text":
|
|
414
|
+
return command.text?.trim() ? findBrowserWorkspaceElementByText(document, command.text) : null;
|
|
415
|
+
case "title":
|
|
416
|
+
return Array.from(document.querySelectorAll("[title]")).find(
|
|
417
|
+
(element) => browserWorkspaceTextMatches(
|
|
418
|
+
element.getAttribute("title") ?? "",
|
|
419
|
+
command.text ?? "",
|
|
420
|
+
command.exact
|
|
421
|
+
)
|
|
422
|
+
) ?? null;
|
|
423
|
+
default:
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function resolveBrowserWorkspaceElement(document, selector, text, command) {
|
|
428
|
+
const normalizedSelector = selector ? normalizeBrowserWorkspaceSelectorSyntax(selector) : void 0;
|
|
429
|
+
if (normalizedSelector) {
|
|
430
|
+
const selectorChain = normalizedSelector.split(/\s*>>\s*/).map((segment) => segment.trim()).filter(Boolean);
|
|
431
|
+
if (selectorChain.length > 1) {
|
|
432
|
+
let current = resolveBrowserWorkspaceElement(
|
|
433
|
+
document,
|
|
434
|
+
selectorChain[0],
|
|
435
|
+
void 0,
|
|
436
|
+
command
|
|
437
|
+
);
|
|
438
|
+
for (let index = 1; current && index < selectorChain.length; index += 1) {
|
|
439
|
+
const segment = selectorChain[index];
|
|
440
|
+
if (!segment) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
if (typeof current.matches === "function" && current.matches(segment)) {
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
if (/^(input|textarea|select)(?:\[[^\]]+\])?$/i.test(segment) && (current.tagName === "INPUT" || current.tagName === "TEXTAREA" || current.tagName === "SELECT")) {
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
current = queryBrowserWorkspaceSelector(current, segment);
|
|
450
|
+
}
|
|
451
|
+
return current;
|
|
452
|
+
}
|
|
453
|
+
const semanticCommand = mergeBrowserWorkspaceSelectorCommand(
|
|
454
|
+
command,
|
|
455
|
+
normalizedSelector
|
|
456
|
+
);
|
|
457
|
+
if (semanticCommand) {
|
|
458
|
+
return resolveBrowserWorkspaceFindElement(document, semanticCommand);
|
|
459
|
+
}
|
|
460
|
+
return queryBrowserWorkspaceSelector(document, normalizedSelector);
|
|
461
|
+
}
|
|
462
|
+
if (command?.findBy) {
|
|
463
|
+
return resolveBrowserWorkspaceFindElement(document, command);
|
|
464
|
+
}
|
|
465
|
+
const normalizedText = text?.trim();
|
|
466
|
+
if (normalizedText) {
|
|
467
|
+
return findBrowserWorkspaceElementByText(document, normalizedText);
|
|
468
|
+
}
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
function getBrowserWorkspaceElementBox(element) {
|
|
472
|
+
const box = typeof element.getBoundingClientRect === "function" ? element.getBoundingClientRect() : {
|
|
473
|
+
bottom: 0,
|
|
474
|
+
height: 0,
|
|
475
|
+
left: 0,
|
|
476
|
+
right: 0,
|
|
477
|
+
top: 0,
|
|
478
|
+
width: 0,
|
|
479
|
+
x: 0,
|
|
480
|
+
y: 0
|
|
481
|
+
};
|
|
482
|
+
return {
|
|
483
|
+
bottom: box.bottom,
|
|
484
|
+
height: box.height,
|
|
485
|
+
left: box.left,
|
|
486
|
+
right: box.right,
|
|
487
|
+
top: box.top,
|
|
488
|
+
width: box.width,
|
|
489
|
+
x: box.x,
|
|
490
|
+
y: box.y
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
function getBrowserWorkspaceElementValue(element) {
|
|
494
|
+
if (element.tagName === "INPUT" || element.tagName === "TEXTAREA" || element.tagName === "SELECT") {
|
|
495
|
+
const control = element;
|
|
496
|
+
if (element.tagName === "INPUT") {
|
|
497
|
+
const input = control;
|
|
498
|
+
const type = input.type.trim().toLowerCase();
|
|
499
|
+
if (type === "checkbox" || type === "radio") {
|
|
500
|
+
return input.checked;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return control.value;
|
|
504
|
+
}
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
507
|
+
function getBrowserWorkspaceElementStyles(element, window) {
|
|
508
|
+
const computed = window.getComputedStyle(element);
|
|
509
|
+
return {
|
|
510
|
+
display: computed.display || null,
|
|
511
|
+
visibility: computed.visibility || null,
|
|
512
|
+
opacity: computed.opacity || null
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
function findClosestBrowserWorkspaceForm(element) {
|
|
516
|
+
if (!element) {
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
return element.tagName === "FORM" ? element : element.closest("form");
|
|
520
|
+
}
|
|
521
|
+
export {
|
|
522
|
+
browserWorkspaceTextMatches,
|
|
523
|
+
buildBrowserWorkspaceElementSelector,
|
|
524
|
+
collectBrowserWorkspaceInspectElements,
|
|
525
|
+
createBrowserWorkspaceElementSummary,
|
|
526
|
+
findBrowserWorkspaceElementByLabel,
|
|
527
|
+
findBrowserWorkspaceElementByRole,
|
|
528
|
+
findBrowserWorkspaceElementByText,
|
|
529
|
+
findClosestBrowserWorkspaceForm,
|
|
530
|
+
getBrowserWorkspaceElementBox,
|
|
531
|
+
getBrowserWorkspaceElementSearchTexts,
|
|
532
|
+
getBrowserWorkspaceElementStyles,
|
|
533
|
+
getBrowserWorkspaceElementValue,
|
|
534
|
+
getBrowserWorkspaceNativeRole,
|
|
535
|
+
isBrowserWorkspaceElementVisible,
|
|
536
|
+
mergeBrowserWorkspaceSelectorCommand,
|
|
537
|
+
normalizeBrowserWorkspaceSelectorSyntax,
|
|
538
|
+
parseBrowserWorkspaceSemanticSelector,
|
|
539
|
+
queryAllBrowserWorkspaceSelector,
|
|
540
|
+
queryBrowserWorkspaceSelector,
|
|
541
|
+
resolveBrowserWorkspaceElement,
|
|
542
|
+
resolveBrowserWorkspaceFindElement,
|
|
543
|
+
resolveBrowserWorkspaceIframeDocument,
|
|
544
|
+
resolveWebBrowserWorkspaceCommandDocument,
|
|
545
|
+
trimBrowserWorkspaceQuotedValue
|
|
546
|
+
};
|
|
547
|
+
//# sourceMappingURL=browser-workspace-elements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/workspace/browser-workspace-elements.ts"],"sourcesContent":["import type { JSDOM } from \"jsdom\";\nimport {\n buildBrowserWorkspaceCssStringLiteral,\n normalizeBrowserWorkspaceText,\n} from \"./browser-workspace-helpers.js\";\nimport { getJSDOMClass } from \"./browser-workspace-jsdom.js\";\nimport type {\n BrowserWorkspaceCommand,\n BrowserWorkspaceDomElementSummary,\n BrowserWorkspaceRuntimeState,\n} from \"./browser-workspace-types.js\";\n\nexport function buildBrowserWorkspaceElementSelector(element: Element): string {\n const escapeFn = (\n globalThis as { CSS?: { escape?: (value: string) => string } }\n ).CSS?.escape;\n const escapedId =\n typeof escapeFn === \"function\"\n ? escapeFn(element.id)\n : element.id.replace(/[^a-zA-Z0-9_-]/g, \"\\\\$&\");\n\n if (element.id) {\n return `#${escapedId}`;\n }\n\n const testId = element.getAttribute(\"data-testid\")?.trim();\n if (testId) {\n return `[data-testid=${buildBrowserWorkspaceCssStringLiteral(testId)}]`;\n }\n\n const name = element.getAttribute(\"name\")?.trim();\n if (name) {\n return `${element.tagName.toLowerCase()}[name=${buildBrowserWorkspaceCssStringLiteral(name)}]`;\n }\n\n const type = element.getAttribute(\"type\")?.trim();\n if (type) {\n return `${element.tagName.toLowerCase()}[type=${buildBrowserWorkspaceCssStringLiteral(type)}]`;\n }\n\n const parent = element.parentElement;\n if (!parent) {\n return element.tagName.toLowerCase();\n }\n\n const siblings = parent.children;\n let index = 1;\n for (let cursor = 0; cursor < siblings.length; cursor += 1) {\n const sibling = siblings.item(cursor);\n if (!sibling || sibling.tagName !== element.tagName) {\n continue;\n }\n if (sibling === element) {\n break;\n }\n index += 1;\n }\n\n return `${element.tagName.toLowerCase()}:nth-of-type(${index})`;\n}\n\nexport function createBrowserWorkspaceElementSummary(\n element: Element,\n): BrowserWorkspaceDomElementSummary {\n const inputLike =\n element.tagName === \"INPUT\" ||\n element.tagName === \"TEXTAREA\" ||\n element.tagName === \"SELECT\";\n\n const elementValue = inputLike\n ? ((element as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement)\n .value ?? null)\n : null;\n\n return {\n selector: buildBrowserWorkspaceElementSelector(element),\n tag: element.tagName.toLowerCase(),\n text: normalizeBrowserWorkspaceText(\n inputLike ? elementValue : element.textContent,\n ),\n type: element.getAttribute(\"type\"),\n name: element.getAttribute(\"name\"),\n href: element.getAttribute(\"href\"),\n value: typeof elementValue === \"string\" ? elementValue : null,\n };\n}\n\nexport function collectBrowserWorkspaceInspectElements(\n document: Document,\n): BrowserWorkspaceDomElementSummary[] {\n const elements = Array.from(\n document.querySelectorAll(\n \"a, button, input, textarea, select, form, [role='button'], [data-testid]\",\n ),\n );\n const summaries: BrowserWorkspaceDomElementSummary[] = [];\n const seenSelectors = new Set<string>();\n\n for (const element of elements) {\n const summary = createBrowserWorkspaceElementSummary(element);\n if (seenSelectors.has(summary.selector)) {\n continue;\n }\n seenSelectors.add(summary.selector);\n summaries.push(summary);\n if (summaries.length >= 40) {\n break;\n }\n }\n\n return summaries;\n}\n\nexport function resolveBrowserWorkspaceIframeDocument(\n runtime: BrowserWorkspaceRuntimeState,\n frameElement: Element | null,\n baseUrl: string,\n): Document | null {\n if (!frameElement || frameElement.tagName !== \"IFRAME\") {\n return null;\n }\n\n const iframe = frameElement as HTMLIFrameElement;\n const srcdoc = iframe.getAttribute(\"srcdoc\");\n if (srcdoc?.trim()) {\n const selector = buildBrowserWorkspaceElementSelector(frameElement);\n const cached = runtime.frameDoms.get(selector);\n if (cached) {\n return cached.window.document;\n }\n if (\n iframe.contentDocument &&\n normalizeBrowserWorkspaceText(iframe.contentDocument.body?.textContent)\n .length > 0\n ) {\n return iframe.contentDocument;\n }\n const parsed = new (getJSDOMClass())(srcdoc, {\n pretendToBeVisual: true,\n url: baseUrl,\n });\n runtime.frameDoms.set(selector, parsed);\n return parsed.window.document;\n }\n\n if (iframe.contentDocument) {\n return iframe.contentDocument;\n }\n\n return null;\n}\n\nexport function resolveWebBrowserWorkspaceCommandDocument(\n tab: { id: string; url: string },\n dom: JSDOM,\n runtimeState: import(\"./browser-workspace-types.js\").BrowserWorkspaceRuntimeState,\n): { document: Document; frameSelector: string | null } {\n const state = runtimeState;\n const frameSelector = state.currentFrame?.trim() || null;\n if (!frameSelector) {\n return { document: dom.window.document, frameSelector: null };\n }\n\n const frameElement = resolveBrowserWorkspaceElement(\n dom.window.document,\n frameSelector,\n );\n const frameDocument = resolveBrowserWorkspaceIframeDocument(\n state,\n frameElement,\n tab.url,\n );\n if (!frameDocument) {\n return { document: dom.window.document, frameSelector: null };\n }\n\n return { document: frameDocument, frameSelector };\n}\n\nexport function getBrowserWorkspaceElementSearchTexts(\n element: Element,\n): string[] {\n const labelText =\n element.id && element.ownerDocument\n ? Array.from(\n element.ownerDocument.querySelectorAll(`label[for=\"${element.id}\"]`),\n )\n .map((label) => label.textContent)\n .join(\" \")\n : \"\";\n return [\n element.textContent,\n element.getAttribute(\"aria-label\"),\n element.getAttribute(\"placeholder\"),\n element.getAttribute(\"title\"),\n element.getAttribute(\"name\"),\n element.getAttribute(\"alt\"),\n element.getAttribute(\"data-testid\"),\n labelText,\n (element as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement)\n .value,\n ]\n .map((value) => normalizeBrowserWorkspaceText(value))\n .filter(Boolean);\n}\n\nexport function browserWorkspaceTextMatches(\n candidate: string,\n wanted: string,\n exact = false,\n): boolean {\n const normalizedCandidate =\n normalizeBrowserWorkspaceText(candidate).toLowerCase();\n const normalizedWanted = normalizeBrowserWorkspaceText(wanted).toLowerCase();\n if (!normalizedCandidate || !normalizedWanted) {\n return false;\n }\n return exact\n ? normalizedCandidate === normalizedWanted\n : normalizedCandidate.includes(normalizedWanted);\n}\n\nexport function isBrowserWorkspaceElementVisible(element: Element): boolean {\n if (\n element.hasAttribute(\"hidden\") ||\n element.getAttribute(\"aria-hidden\") === \"true\"\n ) {\n return false;\n }\n\n const htmlElement = element as HTMLElement;\n const inlineDisplay = htmlElement.style?.display?.trim().toLowerCase();\n const inlineVisibility = htmlElement.style?.visibility?.trim().toLowerCase();\n if (inlineDisplay === \"none\" || inlineVisibility === \"hidden\") {\n return false;\n }\n\n return true;\n}\n\nexport function findBrowserWorkspaceElementByLabel(\n document: Document,\n labelText: string,\n exact = false,\n): Element | null {\n const labels = Array.from(document.querySelectorAll(\"label\"));\n for (const label of labels) {\n if (\n !browserWorkspaceTextMatches(label.textContent ?? \"\", labelText, exact)\n ) {\n continue;\n }\n\n const forId = label.getAttribute(\"for\")?.trim();\n if (forId) {\n const explicit = document.getElementById(forId);\n if (explicit) {\n return explicit;\n }\n }\n\n const nested = label.querySelector(\"input, textarea, select, button\");\n if (nested) {\n return nested;\n }\n }\n return null;\n}\n\nexport function getBrowserWorkspaceNativeRole(element: Element): string | null {\n const explicitRole = element.getAttribute(\"role\")?.trim().toLowerCase();\n if (explicitRole) {\n return explicitRole;\n }\n\n const tag = element.tagName.toLowerCase();\n if (tag === \"a\" && element.getAttribute(\"href\")) return \"link\";\n if (tag === \"button\") return \"button\";\n if (tag === \"select\") return \"combobox\";\n if (tag === \"option\") return \"option\";\n if (tag === \"textarea\") return \"textbox\";\n if (tag === \"form\") return \"form\";\n if (/^h[1-6]$/.test(tag)) return \"heading\";\n if (tag === \"input\") {\n const input = element as HTMLInputElement;\n const type = (input.type || \"text\").toLowerCase();\n if (type === \"checkbox\") return \"checkbox\";\n if (type === \"radio\") return \"radio\";\n if ([\"button\", \"submit\", \"reset\", \"image\"].includes(type)) {\n return \"button\";\n }\n return \"textbox\";\n }\n return null;\n}\n\nexport function findBrowserWorkspaceElementByRole(\n document: Document,\n role: string,\n name?: string,\n exact = false,\n): Element | null {\n const wantedRole = role.trim().toLowerCase();\n if (!wantedRole) {\n return null;\n }\n\n const candidates = Array.from(\n document.querySelectorAll(\n \"a, button, input, textarea, select, option, form, h1, h2, h3, h4, h5, h6, [role], [data-testid]\",\n ),\n );\n for (const candidate of candidates) {\n if (getBrowserWorkspaceNativeRole(candidate) !== wantedRole) {\n continue;\n }\n if (!name?.trim()) {\n return candidate;\n }\n const haystacks = getBrowserWorkspaceElementSearchTexts(candidate);\n if (\n haystacks.some((value) => browserWorkspaceTextMatches(value, name, exact))\n ) {\n return candidate;\n }\n }\n return null;\n}\n\nexport function trimBrowserWorkspaceQuotedValue(value: string): string {\n const trimmed = value.trim();\n const hasTextMatch = trimmed.match(/^has-text\\((['\"])([\\s\\S]*?)\\1\\)$/i);\n if (hasTextMatch?.[2]) {\n return hasTextMatch[2].trim();\n }\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1).trim();\n }\n return trimmed;\n}\n\nexport function normalizeBrowserWorkspaceSelectorSyntax(\n selector: string,\n): string {\n let normalized = selector.trim();\n normalized = normalized.replace(\n /^role\\s*[:=]\\s*([a-z0-9_-]+)\\s+name\\s*[:=]\\s*(.+)$/i,\n \"role=$1[name=$2]\",\n );\n normalized = normalized.replace(\n /^((?:label|text|placeholder|alt|title|testid|data-testid)\\s*[:=]\\s*(?:has-text\\((['\"])[\\s\\S]*?\\2\\)|\"[^\"]+\"|'[^']+'|[^>]+?))\\s+((?:input|textarea|select)[\\s\\S]*)$/i,\n \"$1 >> $3\",\n );\n return normalized;\n}\n\nexport function parseBrowserWorkspaceSemanticSelector(\n selector: string,\n): Pick<\n BrowserWorkspaceCommand,\n \"findBy\" | \"name\" | \"role\" | \"selector\" | \"text\"\n> | null {\n const trimmed = normalizeBrowserWorkspaceSelectorSyntax(selector);\n const match = trimmed.match(/^([a-z-]+)\\s*[:=]\\s*(.+)$/i);\n if (!match) {\n return null;\n }\n\n const kind = match[1]?.trim().toLowerCase();\n const rawValue = match[2]?.trim() ?? \"\";\n if (!kind || !rawValue) {\n return null;\n }\n\n switch (kind) {\n case \"alt\":\n return { findBy: \"alt\", text: trimBrowserWorkspaceQuotedValue(rawValue) };\n case \"css\":\n return { selector: trimBrowserWorkspaceQuotedValue(rawValue) };\n case \"data-testid\":\n case \"testid\":\n return {\n findBy: \"testid\",\n text: trimBrowserWorkspaceQuotedValue(rawValue),\n };\n case \"label\":\n return {\n findBy: \"label\",\n text: trimBrowserWorkspaceQuotedValue(rawValue),\n };\n case \"placeholder\":\n return {\n findBy: \"placeholder\",\n text: trimBrowserWorkspaceQuotedValue(rawValue),\n };\n case \"role\": {\n const roleMatch = rawValue.match(\n /^([a-z0-9_-]+)(?:\\s*\\[\\s*name\\s*[:=]\\s*(.+?)\\s*\\])?$/i,\n );\n if (!roleMatch?.[1]) {\n return null;\n }\n return {\n findBy: \"role\",\n name: roleMatch[2]\n ? trimBrowserWorkspaceQuotedValue(roleMatch[2])\n : undefined,\n role: roleMatch[1].trim().toLowerCase(),\n };\n }\n case \"text\":\n return {\n findBy: \"text\",\n text: trimBrowserWorkspaceQuotedValue(rawValue),\n };\n case \"title\":\n return {\n findBy: \"title\",\n text: trimBrowserWorkspaceQuotedValue(rawValue),\n };\n default:\n return null;\n }\n}\n\nexport function mergeBrowserWorkspaceSelectorCommand(\n command: BrowserWorkspaceCommand | undefined,\n selector: string,\n): BrowserWorkspaceCommand | null {\n const parsed = parseBrowserWorkspaceSemanticSelector(selector);\n if (!parsed) {\n return null;\n }\n\n return {\n ...command,\n ...parsed,\n selector: parsed.selector,\n } as BrowserWorkspaceCommand;\n}\n\nexport function queryBrowserWorkspaceSelector(\n root: Document | Element,\n selector: string,\n): Element | null {\n try {\n return root.querySelector(selector);\n } catch {\n throw new Error(`Invalid selector ${selector}`);\n }\n}\n\nexport function queryAllBrowserWorkspaceSelector(\n root: Document | Element,\n selector: string,\n): Element[] {\n try {\n return Array.from(root.querySelectorAll(selector));\n } catch {\n throw new Error(`Invalid selector ${selector}`);\n }\n}\n\nexport function findBrowserWorkspaceElementByText(\n document: Document,\n needle: string,\n): Element | null {\n const wanted = normalizeBrowserWorkspaceText(needle).toLowerCase();\n if (!wanted) {\n return null;\n }\n\n const candidates = Array.from(\n document.querySelectorAll(\n \"a, button, input, textarea, select, option, label, h1, h2, h3, [role='button'], [data-testid]\",\n ),\n );\n\n for (const element of candidates) {\n const haystacks = [\n element.textContent,\n element.getAttribute(\"aria-label\"),\n element.getAttribute(\"placeholder\"),\n element.getAttribute(\"title\"),\n element.getAttribute(\"name\"),\n (element as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement)\n .value,\n ]\n .map((value) => normalizeBrowserWorkspaceText(value))\n .filter(Boolean)\n .map((value) => value.toLowerCase());\n\n if (haystacks.some((value) => value.includes(wanted))) {\n return element;\n }\n }\n\n return null;\n}\n\nexport function resolveBrowserWorkspaceFindElement(\n document: Document,\n command: BrowserWorkspaceCommand,\n): Element | null {\n switch (command.findBy) {\n case \"alt\":\n return (\n Array.from(document.querySelectorAll(\"[alt]\")).find((element) =>\n browserWorkspaceTextMatches(\n element.getAttribute(\"alt\") ?? \"\",\n command.text ?? \"\",\n command.exact,\n ),\n ) ?? null\n );\n case \"first\":\n return command.selector?.trim()\n ? queryBrowserWorkspaceSelector(document, command.selector)\n : null;\n case \"label\":\n return command.text?.trim()\n ? findBrowserWorkspaceElementByLabel(\n document,\n command.text,\n command.exact,\n )\n : null;\n case \"last\":\n return command.selector?.trim()\n ? (queryAllBrowserWorkspaceSelector(document, command.selector).at(\n -1,\n ) ?? null)\n : null;\n case \"nth\":\n if (!command.selector?.trim()) {\n return null;\n }\n if (\n typeof command.index !== \"number\" ||\n !Number.isInteger(command.index)\n ) {\n return null;\n }\n return (\n queryAllBrowserWorkspaceSelector(document, command.selector).at(\n command.index,\n ) ?? null\n );\n case \"placeholder\":\n return (\n Array.from(document.querySelectorAll(\"[placeholder]\")).find((element) =>\n browserWorkspaceTextMatches(\n element.getAttribute(\"placeholder\") ?? \"\",\n command.text ?? \"\",\n command.exact,\n ),\n ) ?? null\n );\n case \"role\":\n return command.role?.trim()\n ? findBrowserWorkspaceElementByRole(\n document,\n command.role,\n command.name,\n command.exact,\n )\n : null;\n case \"testid\":\n return command.text?.trim()\n ? document.querySelector(\n `[data-testid=${buildBrowserWorkspaceCssStringLiteral(command.text)}]`,\n )\n : null;\n case \"text\":\n return command.text?.trim()\n ? findBrowserWorkspaceElementByText(document, command.text)\n : null;\n case \"title\":\n return (\n Array.from(document.querySelectorAll(\"[title]\")).find((element) =>\n browserWorkspaceTextMatches(\n element.getAttribute(\"title\") ?? \"\",\n command.text ?? \"\",\n command.exact,\n ),\n ) ?? null\n );\n default:\n return null;\n }\n}\n\nexport function resolveBrowserWorkspaceElement(\n document: Document,\n selector?: string,\n text?: string,\n command?: BrowserWorkspaceCommand,\n): Element | null {\n const normalizedSelector = selector\n ? normalizeBrowserWorkspaceSelectorSyntax(selector)\n : undefined;\n if (normalizedSelector) {\n const selectorChain = normalizedSelector\n .split(/\\s*>>\\s*/)\n .map((segment) => segment.trim())\n .filter(Boolean);\n if (selectorChain.length > 1) {\n let current = resolveBrowserWorkspaceElement(\n document,\n selectorChain[0],\n undefined,\n command,\n );\n for (let index = 1; current && index < selectorChain.length; index += 1) {\n const segment = selectorChain[index];\n if (!segment) {\n continue;\n }\n if (\n typeof (current as Element).matches === \"function\" &&\n (current as Element).matches(segment)\n ) {\n continue;\n }\n if (\n /^(input|textarea|select)(?:\\[[^\\]]+\\])?$/i.test(segment) &&\n (current.tagName === \"INPUT\" ||\n current.tagName === \"TEXTAREA\" ||\n current.tagName === \"SELECT\")\n ) {\n continue;\n }\n current = queryBrowserWorkspaceSelector(current, segment);\n }\n return current;\n }\n const semanticCommand = mergeBrowserWorkspaceSelectorCommand(\n command,\n normalizedSelector,\n );\n if (semanticCommand) {\n return resolveBrowserWorkspaceFindElement(document, semanticCommand);\n }\n return queryBrowserWorkspaceSelector(document, normalizedSelector);\n }\n\n if (command?.findBy) {\n return resolveBrowserWorkspaceFindElement(document, command);\n }\n\n const normalizedText = text?.trim();\n if (normalizedText) {\n return findBrowserWorkspaceElementByText(document, normalizedText);\n }\n\n return null;\n}\n\nexport function getBrowserWorkspaceElementBox(element: Element): {\n bottom: number;\n height: number;\n left: number;\n right: number;\n top: number;\n width: number;\n x: number;\n y: number;\n} {\n const box =\n typeof (element as HTMLElement).getBoundingClientRect === \"function\"\n ? (element as HTMLElement).getBoundingClientRect()\n : {\n bottom: 0,\n height: 0,\n left: 0,\n right: 0,\n top: 0,\n width: 0,\n x: 0,\n y: 0,\n };\n return {\n bottom: box.bottom,\n height: box.height,\n left: box.left,\n right: box.right,\n top: box.top,\n width: box.width,\n x: box.x,\n y: box.y,\n };\n}\n\nexport function getBrowserWorkspaceElementValue(\n element: Element,\n): string | boolean | null {\n if (\n element.tagName === \"INPUT\" ||\n element.tagName === \"TEXTAREA\" ||\n element.tagName === \"SELECT\"\n ) {\n const control = element as\n | HTMLInputElement\n | HTMLTextAreaElement\n | HTMLSelectElement;\n if (element.tagName === \"INPUT\") {\n const input = control as HTMLInputElement;\n const type = input.type.trim().toLowerCase();\n if (type === \"checkbox\" || type === \"radio\") {\n return input.checked;\n }\n }\n return control.value;\n }\n return null;\n}\n\nexport function getBrowserWorkspaceElementStyles(\n element: Element,\n window: Pick<Window, \"getComputedStyle\">,\n): Record<string, string | null> {\n const computed = window.getComputedStyle(element);\n return {\n display: computed.display || null,\n visibility: computed.visibility || null,\n opacity: computed.opacity || null,\n };\n}\n\nexport function findClosestBrowserWorkspaceForm(\n element: Element | null,\n): HTMLFormElement | null {\n if (!element) {\n return null;\n }\n return (\n element.tagName === \"FORM\" ? element : element.closest(\"form\")\n ) as HTMLFormElement | null;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { JSDOM } from "jsdom";
|
|
2
|
+
import type { BrowserWorkspaceCommandResult, BrowserWorkspaceScrollDirection, WebBrowserWorkspaceTabState } from "./browser-workspace-types.js";
|
|
3
|
+
export declare function ensureBrowserWorkspaceFormControlElement(element: Element, subaction: "clipboard" | "fill" | "keyboardinserttext" | "keyboardtype" | "select" | "type"): HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
|
4
|
+
export declare function ensureBrowserWorkspaceCheckboxElement(element: Element, subaction: "check" | "uncheck"): HTMLInputElement;
|
|
5
|
+
export declare function setBrowserWorkspaceControlValue(control: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, nextValue: string): void;
|
|
6
|
+
export declare function activateWebBrowserWorkspaceElement(tab: WebBrowserWorkspaceTabState, element: Element, subaction: "click" | "dblclick"): Promise<BrowserWorkspaceCommandResult>;
|
|
7
|
+
export declare function scrollWebBrowserWorkspaceTarget(dom: JSDOM, element: Element | null, direction: BrowserWorkspaceScrollDirection, pixels: number): {
|
|
8
|
+
axis: "x" | "y";
|
|
9
|
+
selector: string | null;
|
|
10
|
+
value: number;
|
|
11
|
+
};
|
|
12
|
+
export declare function submitWebBrowserWorkspaceForm(tab: WebBrowserWorkspaceTabState, form: HTMLFormElement): Promise<void>;
|
|
13
|
+
import type { BrowserWorkspaceTab } from "./browser-workspace-types.js";
|
|
14
|
+
export declare function clearWebBrowserWorkspaceTabElementRefs(tabId: string): void;
|
|
15
|
+
export declare function cloneWebBrowserWorkspaceTabState(tab: WebBrowserWorkspaceTabState): BrowserWorkspaceTab;
|
|
16
|
+
export declare function pushWebBrowserWorkspaceHistory(tab: WebBrowserWorkspaceTabState, nextUrl: string): void;
|
|
17
|
+
export declare function loadWebBrowserWorkspaceTabDocument(tab: WebBrowserWorkspaceTabState): Promise<void>;
|
|
18
|
+
export declare function ensureLoadedWebBrowserWorkspaceTabDocument(tab: WebBrowserWorkspaceTabState): Promise<JSDOM>;
|
|
19
|
+
//# sourceMappingURL=browser-workspace-forms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-workspace-forms.d.ts","sourceRoot":"","sources":["../../src/workspace/browser-workspace-forms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAsBnC,OAAO,KAAK,EACV,6BAA6B,EAC7B,+BAA+B,EAC/B,2BAA2B,EAC5B,MAAM,8BAA8B,CAAC;AAEtC,wBAAgB,wCAAwC,CACtD,OAAO,EAAE,OAAO,EAChB,SAAS,EACL,WAAW,GACX,MAAM,GACN,oBAAoB,GACpB,cAAc,GACd,QAAQ,GACR,MAAM,GACT,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,CAe5D;AAED,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,OAAO,GAAG,SAAS,GAC7B,gBAAgB,CAYlB;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,EACnE,SAAS,EAAE,MAAM,GAChB,IAAI,CAMN;AAED,wBAAsB,kCAAkC,CACtD,GAAG,EAAE,2BAA2B,EAChC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,OAAO,GAAG,UAAU,GAC9B,OAAO,CAAC,6BAA6B,CAAC,CAwExC;AAED,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,KAAK,EACV,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,SAAS,EAAE,+BAA+B,EAC1C,MAAM,EAAE,MAAM,GACb;IACD,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf,CAoCA;AAED,wBAAsB,6BAA6B,CACjD,GAAG,EAAE,2BAA2B,EAChC,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,IAAI,CAAC,CA8Df;AAKD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,wBAAgB,sCAAsC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE1E;AAED,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,2BAA2B,GAC/B,mBAAmB,CAYrB;AAED,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,2BAA2B,EAChC,OAAO,EAAE,MAAM,GACd,IAAI,CAKN;AAED,wBAAsB,kCAAkC,CACtD,GAAG,EAAE,2BAA2B,GAC/B,OAAO,CAAC,IAAI,CAAC,CAwCf;AAED,wBAAsB,0CAA0C,CAC9D,GAAG,EAAE,2BAA2B,GAC/B,OAAO,CAAC,KAAK,CAAC,CAKhB"}
|