@elizaos/plugin-browser 2.0.0-alpha.9 → 2.0.11-beta.7

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.
Files changed (256) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -83
  3. package/auto-enable.ts +24 -0
  4. package/dist/actions/browser-autofill-login.d.ts +43 -0
  5. package/dist/actions/browser-autofill-login.d.ts.map +1 -0
  6. package/dist/actions/browser-autofill-login.js +278 -0
  7. package/dist/actions/browser-autofill-login.js.map +1 -0
  8. package/dist/actions/browser.d.ts +11 -0
  9. package/dist/actions/browser.d.ts.map +1 -0
  10. package/dist/actions/browser.js +412 -0
  11. package/dist/actions/browser.js.map +1 -0
  12. package/dist/actions/manage-browser-bridge.d.ts +34 -0
  13. package/dist/actions/manage-browser-bridge.d.ts.map +1 -0
  14. package/dist/actions/manage-browser-bridge.js +572 -0
  15. package/dist/actions/manage-browser-bridge.js.map +1 -0
  16. package/dist/bridge-policy.d.ts +10 -0
  17. package/dist/bridge-policy.d.ts.map +1 -0
  18. package/dist/bridge-policy.js +37 -0
  19. package/dist/bridge-policy.js.map +1 -0
  20. package/dist/bridge-readiness.d.ts +16 -0
  21. package/dist/bridge-readiness.d.ts.map +1 -0
  22. package/dist/bridge-readiness.js +82 -0
  23. package/dist/bridge-readiness.js.map +1 -0
  24. package/dist/bridge-records.d.ts +9 -0
  25. package/dist/bridge-records.d.ts.map +1 -0
  26. package/dist/bridge-records.js +37 -0
  27. package/dist/bridge-records.js.map +1 -0
  28. package/dist/browser-capture-hooks.d.ts +9 -0
  29. package/dist/browser-capture-hooks.d.ts.map +1 -0
  30. package/dist/browser-capture-hooks.js +15 -0
  31. package/dist/browser-capture-hooks.js.map +1 -0
  32. package/dist/browser-service.d.ts +103 -0
  33. package/dist/browser-service.d.ts.map +1 -0
  34. package/dist/browser-service.js +186 -0
  35. package/dist/browser-service.js.map +1 -0
  36. package/dist/browser-workspace-hooks.d.ts +14 -0
  37. package/dist/browser-workspace-hooks.d.ts.map +1 -0
  38. package/dist/browser-workspace-hooks.js +15 -0
  39. package/dist/browser-workspace-hooks.js.map +1 -0
  40. package/dist/companion-auth.d.ts +34 -0
  41. package/dist/companion-auth.d.ts.map +1 -0
  42. package/dist/companion-auth.js +98 -0
  43. package/dist/companion-auth.js.map +1 -0
  44. package/dist/contracts.d.ts +284 -0
  45. package/dist/contracts.d.ts.map +1 -0
  46. package/dist/contracts.js +56 -0
  47. package/dist/contracts.js.map +1 -0
  48. package/dist/index.d.ts +30 -16
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +76 -90
  51. package/dist/index.js.map +1 -1
  52. package/dist/lifeops-session-contracts.d.ts +46 -0
  53. package/dist/lifeops-session-contracts.d.ts.map +1 -0
  54. package/dist/lifeops-session-contracts.js +1 -0
  55. package/dist/lifeops-session-contracts.js.map +1 -0
  56. package/dist/message-adapter.d.ts +9 -0
  57. package/dist/message-adapter.d.ts.map +1 -0
  58. package/dist/message-adapter.js +104 -0
  59. package/dist/message-adapter.js.map +1 -0
  60. package/dist/packaging.d.ts +27 -0
  61. package/dist/packaging.d.ts.map +1 -0
  62. package/dist/packaging.js +571 -0
  63. package/dist/packaging.js.map +1 -0
  64. package/dist/password-manager-bridge.d.ts +50 -0
  65. package/dist/password-manager-bridge.d.ts.map +1 -0
  66. package/dist/password-manager-bridge.js +437 -0
  67. package/dist/password-manager-bridge.js.map +1 -0
  68. package/dist/plugin.d.ts +10 -0
  69. package/dist/plugin.d.ts.map +1 -0
  70. package/dist/plugin.js +168 -0
  71. package/dist/plugin.js.map +1 -0
  72. package/dist/providers/workspace.d.ts +13 -0
  73. package/dist/providers/workspace.d.ts.map +1 -0
  74. package/dist/providers/workspace.js +64 -0
  75. package/dist/providers/workspace.js.map +1 -0
  76. package/dist/routes/bridge.d.ts +37 -0
  77. package/dist/routes/bridge.d.ts.map +1 -0
  78. package/dist/routes/bridge.js +844 -0
  79. package/dist/routes/bridge.js.map +1 -0
  80. package/dist/routes/workspace-account-gate.d.ts +29 -0
  81. package/dist/routes/workspace-account-gate.d.ts.map +1 -0
  82. package/dist/routes/workspace-account-gate.js +147 -0
  83. package/dist/routes/workspace-account-gate.js.map +1 -0
  84. package/dist/routes/workspace-setup.d.ts +10 -0
  85. package/dist/routes/workspace-setup.d.ts.map +1 -0
  86. package/dist/routes/workspace-setup.js +65 -0
  87. package/dist/routes/workspace-setup.js.map +1 -0
  88. package/dist/routes/workspace.d.ts +20 -0
  89. package/dist/routes/workspace.d.ts.map +1 -0
  90. package/dist/routes/workspace.js +276 -0
  91. package/dist/routes/workspace.js.map +1 -0
  92. package/dist/schema.d.ts +2326 -0
  93. package/dist/schema.d.ts.map +1 -0
  94. package/dist/schema.js +133 -0
  95. package/dist/schema.js.map +1 -0
  96. package/dist/service.d.ts +30 -0
  97. package/dist/service.d.ts.map +1 -0
  98. package/dist/service.js +5 -0
  99. package/dist/service.js.map +1 -0
  100. package/dist/targets/bridge-target.d.ts +31 -0
  101. package/dist/targets/bridge-target.d.ts.map +1 -0
  102. package/dist/targets/bridge-target.js +98 -0
  103. package/dist/targets/bridge-target.js.map +1 -0
  104. package/dist/targets/stagehand-target.d.ts +3 -0
  105. package/dist/targets/stagehand-target.d.ts.map +1 -0
  106. package/dist/targets/stagehand-target.js +187 -0
  107. package/dist/targets/stagehand-target.js.map +1 -0
  108. package/dist/workspace/browser-capture.d.ts +41 -0
  109. package/dist/workspace/browser-capture.d.ts.map +1 -0
  110. package/dist/workspace/browser-capture.js +159 -0
  111. package/dist/workspace/browser-capture.js.map +1 -0
  112. package/dist/workspace/browser-workspace-desktop.d.ts +19 -0
  113. package/dist/workspace/browser-workspace-desktop.d.ts.map +1 -0
  114. package/dist/workspace/browser-workspace-desktop.js +1578 -0
  115. package/dist/workspace/browser-workspace-desktop.js.map +1 -0
  116. package/dist/workspace/browser-workspace-elements.d.ts +42 -0
  117. package/dist/workspace/browser-workspace-elements.d.ts.map +1 -0
  118. package/dist/workspace/browser-workspace-elements.js +547 -0
  119. package/dist/workspace/browser-workspace-elements.js.map +1 -0
  120. package/dist/workspace/browser-workspace-forms.d.ts +19 -0
  121. package/dist/workspace/browser-workspace-forms.d.ts.map +1 -0
  122. package/dist/workspace/browser-workspace-forms.js +277 -0
  123. package/dist/workspace/browser-workspace-forms.js.map +1 -0
  124. package/dist/workspace/browser-workspace-helpers.d.ts +32 -0
  125. package/dist/workspace/browser-workspace-helpers.d.ts.map +1 -0
  126. package/dist/workspace/browser-workspace-helpers.js +232 -0
  127. package/dist/workspace/browser-workspace-helpers.js.map +1 -0
  128. package/dist/workspace/browser-workspace-jsdom.d.ts +16 -0
  129. package/dist/workspace/browser-workspace-jsdom.d.ts.map +1 -0
  130. package/dist/workspace/browser-workspace-jsdom.js +233 -0
  131. package/dist/workspace/browser-workspace-jsdom.js.map +1 -0
  132. package/dist/workspace/browser-workspace-network.d.ts +7 -0
  133. package/dist/workspace/browser-workspace-network.d.ts.map +1 -0
  134. package/dist/workspace/browser-workspace-network.js +145 -0
  135. package/dist/workspace/browser-workspace-network.js.map +1 -0
  136. package/dist/workspace/browser-workspace-snapshots.d.ts +14 -0
  137. package/dist/workspace/browser-workspace-snapshots.d.ts.map +1 -0
  138. package/dist/workspace/browser-workspace-snapshots.js +144 -0
  139. package/dist/workspace/browser-workspace-snapshots.js.map +1 -0
  140. package/dist/workspace/browser-workspace-state.d.ts +24 -0
  141. package/dist/workspace/browser-workspace-state.d.ts.map +1 -0
  142. package/dist/workspace/browser-workspace-state.js +155 -0
  143. package/dist/workspace/browser-workspace-state.js.map +1 -0
  144. package/dist/workspace/browser-workspace-types.d.ts +345 -0
  145. package/dist/workspace/browser-workspace-types.d.ts.map +1 -0
  146. package/dist/workspace/browser-workspace-types.js +11 -0
  147. package/dist/workspace/browser-workspace-types.js.map +1 -0
  148. package/dist/workspace/browser-workspace-web.d.ts +8 -0
  149. package/dist/workspace/browser-workspace-web.d.ts.map +1 -0
  150. package/dist/workspace/browser-workspace-web.js +1342 -0
  151. package/dist/workspace/browser-workspace-web.js.map +1 -0
  152. package/dist/workspace/browser-workspace.d.ts +39 -0
  153. package/dist/workspace/browser-workspace.d.ts.map +1 -0
  154. package/dist/workspace/browser-workspace.js +958 -0
  155. package/dist/workspace/browser-workspace.js.map +1 -0
  156. package/dist/workspace/index.d.ts +26 -0
  157. package/dist/workspace/index.d.ts.map +1 -0
  158. package/dist/workspace/index.js +3 -0
  159. package/dist/workspace/index.js.map +1 -0
  160. package/dist/workspace.d.ts +2 -0
  161. package/dist/workspace.d.ts.map +1 -0
  162. package/dist/workspace.js +2 -0
  163. package/dist/workspace.js.map +1 -0
  164. package/package.json +71 -110
  165. package/dist/actions/click.d.ts +0 -3
  166. package/dist/actions/click.d.ts.map +0 -1
  167. package/dist/actions/click.js +0 -158
  168. package/dist/actions/click.js.map +0 -1
  169. package/dist/actions/extract.d.ts +0 -3
  170. package/dist/actions/extract.d.ts.map +0 -1
  171. package/dist/actions/extract.js +0 -168
  172. package/dist/actions/extract.js.map +0 -1
  173. package/dist/actions/index.d.ts +0 -7
  174. package/dist/actions/index.d.ts.map +0 -1
  175. package/dist/actions/index.js +0 -7
  176. package/dist/actions/index.js.map +0 -1
  177. package/dist/actions/navigate.d.ts +0 -3
  178. package/dist/actions/navigate.d.ts.map +0 -1
  179. package/dist/actions/navigate.js +0 -187
  180. package/dist/actions/navigate.js.map +0 -1
  181. package/dist/actions/screenshot.d.ts +0 -3
  182. package/dist/actions/screenshot.d.ts.map +0 -1
  183. package/dist/actions/screenshot.js +0 -167
  184. package/dist/actions/screenshot.js.map +0 -1
  185. package/dist/actions/select.d.ts +0 -3
  186. package/dist/actions/select.d.ts.map +0 -1
  187. package/dist/actions/select.js +0 -167
  188. package/dist/actions/select.js.map +0 -1
  189. package/dist/actions/type.d.ts +0 -3
  190. package/dist/actions/type.d.ts.map +0 -1
  191. package/dist/actions/type.js +0 -167
  192. package/dist/actions/type.js.map +0 -1
  193. package/dist/cli/index.d.ts +0 -8
  194. package/dist/cli/index.d.ts.map +0 -1
  195. package/dist/cli/index.js +0 -13
  196. package/dist/cli/index.js.map +0 -1
  197. package/dist/cli/register.d.ts +0 -20
  198. package/dist/cli/register.d.ts.map +0 -1
  199. package/dist/cli/register.js +0 -403
  200. package/dist/cli/register.js.map +0 -1
  201. package/dist/providerRelevance.d.ts +0 -4
  202. package/dist/providerRelevance.d.ts.map +0 -1
  203. package/dist/providerRelevance.js +0 -33
  204. package/dist/providerRelevance.js.map +0 -1
  205. package/dist/providers/browser-state.d.ts +0 -3
  206. package/dist/providers/browser-state.d.ts.map +0 -1
  207. package/dist/providers/browser-state.js +0 -72
  208. package/dist/providers/browser-state.js.map +0 -1
  209. package/dist/providers/index.d.ts +0 -2
  210. package/dist/providers/index.d.ts.map +0 -1
  211. package/dist/providers/index.js +0 -2
  212. package/dist/providers/index.js.map +0 -1
  213. package/dist/services/browser-service.d.ts +0 -32
  214. package/dist/services/browser-service.d.ts.map +0 -1
  215. package/dist/services/browser-service.js +0 -213
  216. package/dist/services/browser-service.js.map +0 -1
  217. package/dist/services/index.d.ts +0 -4
  218. package/dist/services/index.d.ts.map +0 -1
  219. package/dist/services/index.js +0 -4
  220. package/dist/services/index.js.map +0 -1
  221. package/dist/services/process-manager.d.ts +0 -24
  222. package/dist/services/process-manager.d.ts.map +0 -1
  223. package/dist/services/process-manager.js +0 -270
  224. package/dist/services/process-manager.js.map +0 -1
  225. package/dist/services/websocket-client.d.ts +0 -35
  226. package/dist/services/websocket-client.d.ts.map +0 -1
  227. package/dist/services/websocket-client.js +0 -221
  228. package/dist/services/websocket-client.js.map +0 -1
  229. package/dist/types.d.ts +0 -101
  230. package/dist/types.d.ts.map +0 -1
  231. package/dist/types.js +0 -2
  232. package/dist/types.js.map +0 -1
  233. package/dist/utils/captcha.d.ts +0 -33
  234. package/dist/utils/captcha.d.ts.map +0 -1
  235. package/dist/utils/captcha.js +0 -219
  236. package/dist/utils/captcha.js.map +0 -1
  237. package/dist/utils/errors.d.ts +0 -37
  238. package/dist/utils/errors.d.ts.map +0 -1
  239. package/dist/utils/errors.js +0 -81
  240. package/dist/utils/errors.js.map +0 -1
  241. package/dist/utils/index.d.ts +0 -5
  242. package/dist/utils/index.d.ts.map +0 -1
  243. package/dist/utils/index.js +0 -5
  244. package/dist/utils/index.js.map +0 -1
  245. package/dist/utils/retry.d.ts +0 -26
  246. package/dist/utils/retry.d.ts.map +0 -1
  247. package/dist/utils/retry.js +0 -55
  248. package/dist/utils/retry.js.map +0 -1
  249. package/dist/utils/security.d.ts +0 -27
  250. package/dist/utils/security.d.ts.map +0 -1
  251. package/dist/utils/security.js +0 -139
  252. package/dist/utils/security.js.map +0 -1
  253. package/dist/utils/url.d.ts +0 -12
  254. package/dist/utils/url.d.ts.map +0 -1
  255. package/dist/utils/url.js +0 -39
  256. 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"}