@jini-ai/agentic 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/LICENSE +201 -0
  2. package/dist/ag-ui.d.ts +82 -0
  3. package/dist/ag-ui.d.ts.map +1 -0
  4. package/dist/ag-ui.js +56 -0
  5. package/dist/ag-ui.js.map +1 -0
  6. package/dist/agui/encoder.d.ts +50 -0
  7. package/dist/agui/encoder.d.ts.map +1 -0
  8. package/dist/agui/encoder.js +97 -0
  9. package/dist/agui/encoder.js.map +1 -0
  10. package/dist/agui/events.d.ts +59 -0
  11. package/dist/agui/events.d.ts.map +1 -0
  12. package/dist/agui/events.js +15 -0
  13. package/dist/agui/events.js.map +1 -0
  14. package/dist/capability.d.ts +81 -0
  15. package/dist/capability.d.ts.map +1 -0
  16. package/dist/capability.js +79 -0
  17. package/dist/capability.js.map +1 -0
  18. package/dist/dom/dom-page-driver.d.ts +29 -0
  19. package/dist/dom/dom-page-driver.d.ts.map +1 -0
  20. package/dist/dom/dom-page-driver.js +557 -0
  21. package/dist/dom/dom-page-driver.js.map +1 -0
  22. package/dist/dom/index.d.ts +17 -0
  23. package/dist/dom/index.d.ts.map +1 -0
  24. package/dist/dom/index.js +17 -0
  25. package/dist/dom/index.js.map +1 -0
  26. package/dist/dom/model-context.d.ts +54 -0
  27. package/dist/dom/model-context.d.ts.map +1 -0
  28. package/dist/dom/model-context.js +36 -0
  29. package/dist/dom/model-context.js.map +1 -0
  30. package/dist/element-handles.d.ts +99 -0
  31. package/dist/element-handles.d.ts.map +1 -0
  32. package/dist/element-handles.js +39 -0
  33. package/dist/element-handles.js.map +1 -0
  34. package/dist/gen-ui/encoder.d.ts +50 -0
  35. package/dist/gen-ui/encoder.d.ts.map +1 -0
  36. package/dist/gen-ui/encoder.js +97 -0
  37. package/dist/gen-ui/encoder.js.map +1 -0
  38. package/dist/gen-ui/events.d.ts +59 -0
  39. package/dist/gen-ui/events.d.ts.map +1 -0
  40. package/dist/gen-ui/events.js +15 -0
  41. package/dist/gen-ui/events.js.map +1 -0
  42. package/dist/gen-ui/index.d.ts +18 -0
  43. package/dist/gen-ui/index.d.ts.map +1 -0
  44. package/dist/gen-ui/index.js +17 -0
  45. package/dist/gen-ui/index.js.map +1 -0
  46. package/dist/guards.d.ts +91 -0
  47. package/dist/guards.d.ts.map +1 -0
  48. package/dist/guards.js +181 -0
  49. package/dist/guards.js.map +1 -0
  50. package/dist/handle.d.ts +41 -0
  51. package/dist/handle.d.ts.map +1 -0
  52. package/dist/handle.js +41 -0
  53. package/dist/handle.js.map +1 -0
  54. package/dist/index.d.ts +65 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +64 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/mcp-ui-apps.d.ts +133 -0
  59. package/dist/mcp-ui-apps.d.ts.map +1 -0
  60. package/dist/mcp-ui-apps.js +134 -0
  61. package/dist/mcp-ui-apps.js.map +1 -0
  62. package/dist/mcp-ui.d.ts +133 -0
  63. package/dist/mcp-ui.d.ts.map +1 -0
  64. package/dist/mcp-ui.js +134 -0
  65. package/dist/mcp-ui.js.map +1 -0
  66. package/dist/page-capabilities.d.ts +14 -0
  67. package/dist/page-capabilities.d.ts.map +1 -0
  68. package/dist/page-capabilities.js +129 -0
  69. package/dist/page-capabilities.js.map +1 -0
  70. package/dist/page-driver.d.ts +107 -0
  71. package/dist/page-driver.d.ts.map +1 -0
  72. package/dist/page-driver.js +2 -0
  73. package/dist/page-driver.js.map +1 -0
  74. package/dist/page-executor.d.ts +87 -0
  75. package/dist/page-executor.d.ts.map +1 -0
  76. package/dist/page-executor.js +288 -0
  77. package/dist/page-executor.js.map +1 -0
  78. package/dist/webmcp.d.ts +81 -0
  79. package/dist/webmcp.d.ts.map +1 -0
  80. package/dist/webmcp.js +67 -0
  81. package/dist/webmcp.js.map +1 -0
  82. package/package.json +56 -0
@@ -0,0 +1,557 @@
1
+ import { AGENT_ELEMENT_ATTRIBUTE, AGENT_LABEL_ATTRIBUTE, AGENT_PAGE_ATTRIBUTE, AGENT_ROLE_ATTRIBUTE, AGENT_ELEMENT_ROLES, resolveHandleSelector, } from '../element-handles.js';
2
+ import { normalizeAgentLabel } from '../guards.js';
3
+ /**
4
+ * A {@link PageDriver} over a real DOM subtree.
5
+ *
6
+ * Deliberately mechanical: every refusal — handle validation, the credential-field guard, the
7
+ * page allowlist, highlight clamping — already ran in `executePageCapability` before anything
8
+ * here is called. Re-checking would duplicate policy in a place that will drift from it.
9
+ *
10
+ * Scoped to a `root` the host names, never `document`. Scanning the whole document would make
11
+ * any markup anywhere — including rendered user content — an authorization decision, which
12
+ * inverts the point of an explicit allowlist.
13
+ */
14
+ /** How the marker is drawn. Inline styles, so no stylesheet or CSP allowance is needed. */
15
+ const HIGHLIGHT_STYLE = {
16
+ outline: '3px solid #e11d48',
17
+ outlineOffset: '2px',
18
+ borderRadius: '4px',
19
+ };
20
+ /**
21
+ * Upper bound on {@link createDomPageDriver}'s `settle`.
22
+ *
23
+ * A hidden tab stops delivering animation frames, so waiting for one never returns — and a
24
+ * background tab is exactly where an agent-driven page ends up while the user works elsewhere.
25
+ * This is the ceiling that keeps every write bounded regardless.
26
+ */
27
+ const SETTLE_TIMEOUT_MS = 120;
28
+ function isAgentElementRole(value) {
29
+ return value !== null && AGENT_ELEMENT_ROLES.includes(value);
30
+ }
31
+ /**
32
+ * Whether the element is a rich-text surface — a `contenteditable` region rather than a form
33
+ * control. Rich-text editors are built this way, so treating one as unfillable makes every
34
+ * comment box, description field and document editor unreachable.
35
+ */
36
+ function isEditableRegion(element) {
37
+ if (!(element instanceof HTMLElement))
38
+ return false;
39
+ // A control embedded in a rich-text document is still that control. Without this, a real
40
+ // browser — which, unlike jsdom, propagates `isContentEditable` to every descendant — reports
41
+ // the Save button inside an editor as a fillable text region, and `fill` overwrites its label
42
+ // instead of refusing. The type-based refusals in `findFieldFillRefusal` cannot catch that
43
+ // either, because the descriptor would say `contenteditable` rather than `button`.
44
+ if (element.matches('input, textarea, select, button, a[href], summary, option'))
45
+ return false;
46
+ // The attribute is checked before `isContentEditable` because a headless DOM does not compute
47
+ // the latter — relying on it alone makes every one of these tests pass vacuously while the real
48
+ // browser behaves differently. `contenteditable=""` and `"plaintext-only"` are both editable;
49
+ // only an explicit `"false"` is not.
50
+ const attribute = element.getAttribute('contenteditable');
51
+ if (attribute !== null)
52
+ return attribute !== 'false';
53
+ // Editability inherited from an ancestor, which only a real layout engine can tell us about.
54
+ return element.isContentEditable === true;
55
+ }
56
+ /** Every `<label>` associated with `control` by whichever relationship resolves first. */
57
+ function labelTextOf(control) {
58
+ // Real form controls carry `.labels` — every associated <label>, both for-linked and wrapping.
59
+ const associated = 'labels' in control
60
+ ? Array.from(control.labels ?? [])
61
+ : [];
62
+ for (const label of associated) {
63
+ const text = label.textContent?.trim();
64
+ if (text)
65
+ return text;
66
+ }
67
+ // A contenteditable region is not a form control and has no `.labels`; resolve the same two
68
+ // relationships by hand — an ancestor <label> (implicit wrapping) and a for-linked one (explicit).
69
+ const wrapping = control.closest('label');
70
+ if (wrapping) {
71
+ const text = wrapping.textContent?.trim();
72
+ if (text)
73
+ return text;
74
+ }
75
+ if (control.id) {
76
+ for (const label of Array.from(control.ownerDocument.querySelectorAll('label'))) {
77
+ if (label.htmlFor === control.id) {
78
+ const text = label.textContent?.trim();
79
+ if (text)
80
+ return text;
81
+ }
82
+ }
83
+ }
84
+ return undefined;
85
+ }
86
+ /**
87
+ * The field's human-visible label, for the guard's benefit: `name`/`id` are the machine names, and
88
+ * a CMS emitting `name="field_47"` next to a visibly-labelled "Card number" leaves every guard here
89
+ * nothing to judge unless this is populated. Resolution order: `aria-label`, then `placeholder`,
90
+ * then the text of an associated `<label>` (for-linked or wrapping) — whichever the driver can
91
+ * resolve first.
92
+ */
93
+ function accessibleLabelOf(control) {
94
+ const ariaLabel = control.getAttribute('aria-label')?.trim();
95
+ if (ariaLabel)
96
+ return ariaLabel;
97
+ const placeholder = control.getAttribute('placeholder')?.trim();
98
+ if (placeholder)
99
+ return placeholder;
100
+ return labelTextOf(control);
101
+ }
102
+ /** The field attributes the guards need, or `null` when the control is not a text-bearing input. */
103
+ function fieldDescriptorOf(control) {
104
+ if (isEditableRegion(control)) {
105
+ // Reported as a field so the same guards run: a contenteditable div named `card-number` is
106
+ // no more fillable than an input would be. `type` is not a real HTML input type, and is not
107
+ // in any denied set, which is correct — the guard should judge it by name and attributes.
108
+ return {
109
+ type: 'contenteditable',
110
+ // Read for the same reason `name` is: neither attribute is standard on a div, but a page
111
+ // that bothers to set one is telling the guard what the field holds, and honouring `name`
112
+ // while ignoring `autocomplete` would refuse `name="card_number"` and accept the
113
+ // `autocomplete="cc-number"` spelling of the same field.
114
+ autocomplete: control.getAttribute('autocomplete')?.toLowerCase() || undefined,
115
+ name: control.getAttribute('name') || undefined,
116
+ id: control.id || undefined,
117
+ accessibleLabel: accessibleLabelOf(control),
118
+ readOnly: control.getAttribute('aria-readonly') === 'true',
119
+ disabled: control.getAttribute('aria-disabled') === 'true',
120
+ };
121
+ }
122
+ if (!(control instanceof HTMLInputElement) && !(control instanceof HTMLTextAreaElement)) {
123
+ return null;
124
+ }
125
+ return {
126
+ type: control instanceof HTMLInputElement ? control.type.toLowerCase() : 'textarea',
127
+ autocomplete: control.getAttribute('autocomplete')?.toLowerCase() ?? undefined,
128
+ name: control.name || undefined,
129
+ id: control.id || undefined,
130
+ accessibleLabel: accessibleLabelOf(control),
131
+ readOnly: control.readOnly,
132
+ // `.disabled` reflects only this element's own attribute — not the "actually disabled" state
133
+ // a control gets from an ancestor `<fieldset disabled>`. `:disabled` is the platform's own
134
+ // answer for both, and is what decides whether the value even reaches form submission.
135
+ disabled: control.matches(':disabled'),
136
+ };
137
+ }
138
+ /**
139
+ * Whether the element is actually rendered, or `undefined` when the platform cannot say.
140
+ *
141
+ * `checkVisibility` is the only answer that accounts for `display:none` on an ancestor, `hidden`,
142
+ * `content-visibility` and an empty box at once. Where it is missing, this reports nothing rather
143
+ * than falling back to a layout measurement — a headless DOM has no layout, so that fallback would
144
+ * confidently declare every element invisible.
145
+ *
146
+ * The options are passed explicitly rather than relying on the method's defaults: per spec every
147
+ * option defaults to `false`, so a bare `checkVisibility()` misses `visibility:hidden` and
148
+ * `opacity:0` ancestors — two of the most common real ways to hide interactive UI (fade
149
+ * transitions, visually-hidden-but-focusable patterns) — while still correctly reporting
150
+ * `display:none`. Confirmed in real Chromium: `checkOpacity`/`checkVisibilityCSS` (this build's
151
+ * spelling) turn a false `visible: true` on a `visibility:hidden`/`opacity:0` ancestor into the
152
+ * correct `false`; jsdom does not implement the method at all, so no unit test can show this.
153
+ */
154
+ function visibilityOf(element) {
155
+ const check = element.checkVisibility;
156
+ return typeof check === 'function'
157
+ ? check.call(element, { checkOpacity: true, checkVisibilityCSS: true })
158
+ : undefined;
159
+ }
160
+ /**
161
+ * `disabled` for the controls that have one; `undefined` for everything else, which is not the
162
+ * same as `false`.
163
+ *
164
+ * `:disabled` rather than the `.disabled` IDL property: the property only reflects the element's
165
+ * own attribute, so a control disabled solely by an ancestor `<fieldset disabled>` reads as
166
+ * enabled even though a real user cannot type into or click it, and its value is excluded from
167
+ * form submission entirely. `:disabled` is the platform's own answer and covers both cases.
168
+ */
169
+ function disabledOf(control) {
170
+ return control instanceof HTMLInputElement
171
+ || control instanceof HTMLTextAreaElement
172
+ || control instanceof HTMLButtonElement
173
+ || control instanceof HTMLSelectElement
174
+ ? control.matches(':disabled')
175
+ : undefined;
176
+ }
177
+ function describe(element, page) {
178
+ const role = element.getAttribute(AGENT_ROLE_ATTRIBUTE);
179
+ /* c8 ignore next -- `Node.textContent` is typed nullable for the abstract node; on an Element it is always a string, so the `?? ''` satisfies the type and is not a reachable path. */
180
+ const text = element.textContent ?? '';
181
+ const label = element.getAttribute(AGENT_LABEL_ATTRIBUTE) ?? text;
182
+ /* c8 ignore next -- only ever called on a `[data-agent-element]` match, so the attribute is present by construction. */
183
+ const handle = element.getAttribute(AGENT_ELEMENT_ATTRIBUTE) ?? '';
184
+ return {
185
+ handle,
186
+ role: isAgentElementRole(role) ? role : undefined,
187
+ // The executor normalizes and bounds this; raw here on purpose so the guard is applied in
188
+ // exactly one place rather than half-applied in two.
189
+ label,
190
+ labelTruncated: false,
191
+ page,
192
+ };
193
+ }
194
+ /**
195
+ * Builds a driver over `root`.
196
+ *
197
+ * @param options - The subtree, the navigable pages, and the current page id.
198
+ * @returns A driver ready to hand to `executePageCapability`.
199
+ */
200
+ export function createDomPageDriver(options) {
201
+ const { root, pages } = options;
202
+ /**
203
+ * The page a specific element belongs to — its own nearest `[data-agent-page]` ancestor, not a
204
+ * single document-wide guess.
205
+ *
206
+ * A host that keeps more than one `[data-agent-page]` section mounted at once (tabs, wizard
207
+ * steps toggled with CSS rather than unmounted — the kind of SPA this driver's own options doc
208
+ * anticipates) previously had every element attributed to whichever section happened to be
209
+ * first in the DOM, regardless of which one it actually lived in. `closest` answers per element
210
+ * instead of once for the whole call.
211
+ *
212
+ * Still overridden by a pinned `currentPage`, unchanged: that value is the host's own claim
213
+ * about what is showing, taking precedence over whatever the DOM happens to say.
214
+ */
215
+ const pageOf = (element) => options.currentPage ?? element.closest(`[${AGENT_PAGE_ATTRIBUTE}]`)?.getAttribute(AGENT_PAGE_ATTRIBUTE) ?? undefined;
216
+ /**
217
+ * Active markers keyed by handle, so re-highlighting the same element restarts rather than
218
+ * stacks — and carrying the styling to put back, which must be captured once, on the first
219
+ * highlight. Re-reading the element on a restart would snapshot the marker itself, and the
220
+ * element would keep it forever: a capability classified `read` precisely because it is
221
+ * transient would permanently change how someone's page looks.
222
+ */
223
+ const highlights = new Map();
224
+ /**
225
+ * Every element published under `handle`. A page that (accidentally, or via a templating bug)
226
+ * publishes the same handle twice makes `find`'s single-match resolution ambiguous — surfaced
227
+ * here so both callers below can refuse rather than silently pick one.
228
+ */
229
+ const findAll = (handle) => Array.from(root.querySelectorAll(resolveHandleSelector(handle)));
230
+ /**
231
+ * More than one element answers to the same handle — a page-authoring bug (duplicate
232
+ * `data-agent-element`), not something a caller passing that handle can resolve on its own.
233
+ *
234
+ * `findElements` still lists every one of them, so the collision is discoverable; resolving a
235
+ * single handle to act on refuses instead of silently taking the first DOM match and leaving the
236
+ * others permanently unreachable with no signal that they were ever unreachable at all.
237
+ */
238
+ const ambiguousHandleError = (handle, count) => new Error(`"${handle}" is published on ${count} elements on this page, so which one it addresses is `
239
+ + 'ambiguous — this is a page-authoring bug (duplicate data-agent-element), not something a '
240
+ + 'caller can resolve; publish a unique handle per element');
241
+ const find = (handle) => {
242
+ const matches = findAll(handle);
243
+ if (matches.length === 0)
244
+ throw new Error(`no element published as "${handle}" on this page`);
245
+ if (matches.length > 1)
246
+ throw ambiguousHandleError(handle, matches.length);
247
+ return matches[0];
248
+ };
249
+ /**
250
+ * The control a handle addresses — for a wrapper like `<li><label><input>`, the input.
251
+ *
252
+ * `<details>` is called out because its interactive part is the `<summary>`: clicking the
253
+ * `<details>` element itself dispatches an event the platform ignores, so a disclosure widget
254
+ * would never open and the caller would be told the click landed.
255
+ */
256
+ const controlOf = (element) => {
257
+ // An editable region IS the control. Descending would find a link inside a rich-text document
258
+ // and address that instead of the text the caller meant to write.
259
+ if (isEditableRegion(element))
260
+ return element;
261
+ // `:scope >` because only a *direct child* `<summary>` is the disclosure control. An
262
+ // unscoped query returns the first summary anywhere in the subtree, so a `<details>`
263
+ // containing another one would toggle the inner disclosure while reporting that the outer
264
+ // handle was clicked — the false success this whole suite exists to catch.
265
+ if (element instanceof HTMLDetailsElement) {
266
+ return element.querySelector(':scope > summary') ?? element;
267
+ }
268
+ if (element.matches('input, textarea, select, button, a'))
269
+ return element;
270
+ // A descendant that is itself independently published (its own `[data-agent-element]`) must
271
+ // never be silently adopted as this handle's control — it is a distinct, separately
272
+ // addressable target with its own label, not unhandled wrapper markup like the plain
273
+ // `<li><label><input>` this descent exists for. Filtering to descendants whose nearest
274
+ // published ancestor is still `element` itself excludes exactly that case while leaving
275
+ // ordinary wrapper descent untouched.
276
+ const owned = (node) => node.closest(`[${AGENT_ELEMENT_ATTRIBUTE}]`) === element;
277
+ const candidate = Array.from(element.querySelectorAll('input, textarea, select, button, a, summary'))
278
+ .find(owned);
279
+ return candidate ?? element;
280
+ };
281
+ return {
282
+ async findElements(filter) {
283
+ const found = Array.from(root.querySelectorAll(`[${AGENT_ELEMENT_ATTRIBUTE}]`))
284
+ .map((element) => describe(element, pageOf(element)))
285
+ .filter((element) => element.handle.length > 0);
286
+ const query = filter.query?.toLowerCase();
287
+ return found.filter((element) => {
288
+ if (filter.role !== undefined && element.role !== filter.role)
289
+ return false;
290
+ if (query === undefined)
291
+ return true;
292
+ return element.handle.toLowerCase().includes(query)
293
+ || element.label.toLowerCase().includes(query);
294
+ });
295
+ },
296
+ async listPages() {
297
+ return Object.keys(pages);
298
+ },
299
+ async describeField(handle) {
300
+ return fieldDescriptorOf(controlOf(find(handle)));
301
+ },
302
+ async describeState(handle) {
303
+ // Unlike every other method here, a handle that no longer resolves is an answer rather than
304
+ // an error: an element that a click removed is exactly what the caller is asking about. A
305
+ // handle resolving to *more than one* element is a different situation entirely — not an
306
+ // absence but an ambiguity — so that case still refuses, same as `find`.
307
+ const matches = findAll(handle);
308
+ if (matches.length === 0)
309
+ return null;
310
+ if (matches.length > 1)
311
+ throw ambiguousHandleError(handle, matches.length);
312
+ const element = matches[0];
313
+ const control = controlOf(element);
314
+ const field = fieldDescriptorOf(control);
315
+ const checkable = control instanceof HTMLInputElement
316
+ && (control.type === 'checkbox' || control.type === 'radio');
317
+ // A dropdown reports its option texts alongside its value. Without them a caller can only
318
+ // guess what to pass to `page.select_option`, and a wrong guess is a refusal it could have
319
+ // avoided by looking. It carries a descriptor too, so the read guard still runs — a
320
+ // `<select name="secret_token">` is no more readable than an input of the same name.
321
+ const dropdown = control instanceof HTMLSelectElement ? control : undefined;
322
+ const readable = field ?? (dropdown === undefined ? null : {
323
+ type: 'select',
324
+ name: dropdown.name || undefined,
325
+ id: dropdown.id || undefined,
326
+ // Same `:disabled` reasoning as `disabledOf` — a `<select>` inside a disabled `<fieldset>`
327
+ // is not itself flagged by the `.disabled` IDL property.
328
+ disabled: dropdown.matches(':disabled'),
329
+ });
330
+ const value = field !== null
331
+ ? control.value
332
+ : dropdown?.value;
333
+ /* c8 ignore next -- as in `describe`: an Element's textContent is always a string. */
334
+ const text = element.textContent ?? '';
335
+ return {
336
+ text,
337
+ // Reported raw and unconditionally; `projectElementState` applies the read guard. A
338
+ // driver deciding here which values are secret is a driver holding policy.
339
+ ...(value !== undefined ? { value } : {}),
340
+ ...(checkable ? { checked: control.checked } : {}),
341
+ ...(disabledOf(control) !== undefined ? { disabled: disabledOf(control) } : {}),
342
+ ...(visibilityOf(element) !== undefined ? { visible: visibilityOf(element) } : {}),
343
+ ...(readable !== null ? { field: readable } : {}),
344
+ ...(dropdown !== undefined
345
+ ? {
346
+ options: Array.from(dropdown.options)
347
+ .map((entry) => entry.text.trim())
348
+ .filter((entry) => entry.length > 0),
349
+ }
350
+ : {}),
351
+ };
352
+ },
353
+ /**
354
+ * Two animation frames — long enough for a framework to have re-rendered and the browser to
355
+ * have painted — or {@link SETTLE_TIMEOUT_MS}, whichever lands first. Without the timeout this
356
+ * would hang for the whole life of a backgrounded tab; without the frames every write would
357
+ * report its own target unchanged, because the read would beat the render.
358
+ */
359
+ async settle() {
360
+ await new Promise((resolve) => {
361
+ let timer;
362
+ // No re-entry guard: whichever side loses the race calls this again, and both of its
363
+ // effects are already idempotent — clearing an elapsed timer is a no-op, and a second
364
+ // `resolve` on a settled promise is ignored. A flag here would only be a branch nothing
365
+ // can distinguish.
366
+ const finish = () => {
367
+ if (timer !== undefined)
368
+ clearTimeout(timer);
369
+ resolve();
370
+ };
371
+ const raf = globalThis.requestAnimationFrame;
372
+ // With no animation frames to wait for, one macrotask is the whole mechanism, and waiting
373
+ // the full ceiling on every write would be pure latency.
374
+ timer = setTimeout(finish, typeof raf === 'function' ? SETTLE_TIMEOUT_MS : 0);
375
+ if (typeof raf === 'function')
376
+ raf(() => raf(finish));
377
+ });
378
+ },
379
+ async highlight(handle, durationMs) {
380
+ const element = find(handle);
381
+ // Same refusal as `click()`, for the same reason: an SVG (or other non-HTMLElement) target
382
+ // has no `.style` to draw an outline on, so silently returning here drew nothing while
383
+ // `page-executor.ts` unconditionally reports the highlight as successful — a guaranteed
384
+ // false positive with no way for the caller to tell. Refusing makes that visible instead.
385
+ if (!(element instanceof HTMLElement))
386
+ throw new Error(`"${handle}" is not highlightable`);
387
+ const active = highlights.get(handle);
388
+ if (active !== undefined)
389
+ clearTimeout(active.timer);
390
+ // Reuse the first capture on a restart; see the map's own doc for what re-reading would cost.
391
+ const restore = active?.restore ?? {
392
+ outline: element.style.outline,
393
+ outlineOffset: element.style.outlineOffset,
394
+ borderRadius: element.style.borderRadius,
395
+ };
396
+ Object.assign(element.style, HIGHLIGHT_STYLE);
397
+ element.scrollIntoView({ behavior: 'smooth', block: 'center' });
398
+ const timer = setTimeout(() => {
399
+ // Restore what was there rather than clearing: the element may have had its own outline.
400
+ Object.assign(element.style, restore);
401
+ highlights.delete(handle);
402
+ }, durationMs);
403
+ highlights.set(handle, { timer, restore });
404
+ },
405
+ async scrollTo(handle) {
406
+ find(handle).scrollIntoView({ behavior: 'smooth', block: 'center' });
407
+ },
408
+ async click(handle) {
409
+ const control = controlOf(find(handle));
410
+ if (!(control instanceof HTMLElement))
411
+ throw new Error(`"${handle}" is not clickable`);
412
+ control.click();
413
+ },
414
+ async fill(handle, text) {
415
+ const control = controlOf(find(handle));
416
+ if (isEditableRegion(control)) {
417
+ // A contenteditable region has no `value`; its content *is* its children, and a real
418
+ // editor owns that subtree. See `fillEditableRegion` for why this drives it through
419
+ // selection + `execCommand` rather than replacing `textContent` directly.
420
+ fillEditableRegion(control, text);
421
+ return;
422
+ }
423
+ if (!(control instanceof HTMLInputElement) && !(control instanceof HTMLTextAreaElement)) {
424
+ throw new Error(`"${handle}" is not a fillable field`);
425
+ }
426
+ // Assign through the prototype setter, then dispatch: React tracks the previous value on
427
+ // the node and ignores an input event whose value it believes it already has, so a plain
428
+ // `control.value = text` updates the DOM but leaves React state stale.
429
+ const prototype = control instanceof HTMLInputElement
430
+ ? HTMLInputElement.prototype
431
+ : HTMLTextAreaElement.prototype;
432
+ const setter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set;
433
+ if (setter)
434
+ setter.call(control, text);
435
+ else
436
+ control.value = text;
437
+ control.dispatchEvent(new Event('input', { bubbles: true }));
438
+ control.dispatchEvent(new Event('change', { bubbles: true }));
439
+ },
440
+ async selectOption(handle, option, selected = true) {
441
+ const control = controlOf(find(handle));
442
+ if (!(control instanceof HTMLSelectElement)) {
443
+ throw new Error(`"${handle}" is not a dropdown`);
444
+ }
445
+ // Visible text first, then value: the text is what a caller saw in `find_elements`, and
446
+ // matching value first would make an option whose value collides with another's label
447
+ // resolve to the wrong entry.
448
+ // A disabled option is not selectable by the user either, so offering it to an agent would
449
+ // be a way around the page's own rule — and the resulting selection cannot be submitted.
450
+ const options = Array.from(control.options).filter((entry) => !entry.disabled);
451
+ const match = options.find((entry) => entry.text.trim() === option)
452
+ ?? options.find((entry) => entry.value === option);
453
+ if (match === undefined) {
454
+ // Every other piece of page-authored text this system hands to a model goes through
455
+ // normalizeAgentLabel first — bounded, control- and bidi-stripped. `available` is exactly
456
+ // that: the page's own <option> texts, read verbatim with no length bound of their own.
457
+ // The caller's `option` is sanitized too, for the same reason page.navigate's caller-
458
+ // supplied `page` now is — an unbounded value reaching a thrown message a model reads is
459
+ // the same shape of problem regardless of which side authored it. `handle` needs no
460
+ // treatment: it is already validated ASCII, length-capped by isValidElementHandle before
461
+ // this driver is ever called.
462
+ const safeOption = normalizeAgentLabel(option).text;
463
+ const available = options.map((entry) => normalizeAgentLabel(entry.text.trim()).text)
464
+ .filter((text) => text.length > 0);
465
+ throw new Error(`"${safeOption}" is not an option of "${handle}". Available: ${available.length > 0 ? available.join(', ') : '(none)'}`);
466
+ }
467
+ if (control.multiple) {
468
+ // A multi-select accumulates by default. Assigning `value` would silently clear every
469
+ // prior choice, so a caller building up a selection would end with only its last call's
470
+ // option — and setting `.selected` directly is also how a caller narrows one back off
471
+ // without disturbing the rest.
472
+ match.selected = selected;
473
+ }
474
+ else if (!selected) {
475
+ // A single-select's one option IS its value; there is no "off" state to put it in. Silently
476
+ // ignoring this would tell the caller a deselect happened when nothing changed, and clearing
477
+ // the control would invent a third state (no selection) that a native <select> cannot hold.
478
+ throw new Error(`"${handle}" is a single-select; its choice cannot be removed, only replaced — `
479
+ + `select a different option instead of deselecting "${normalizeAgentLabel(option).text}"`);
480
+ }
481
+ else {
482
+ // Same prototype-setter dance as `fill`, for the same reason: React tracks the previous
483
+ // value on the node and ignores a change event whose value it believes it already has.
484
+ const setter = Object.getOwnPropertyDescriptor(HTMLSelectElement.prototype, 'value')?.set;
485
+ if (setter)
486
+ setter.call(control, match.value);
487
+ else
488
+ control.value = match.value;
489
+ }
490
+ control.dispatchEvent(new Event('input', { bubbles: true }));
491
+ control.dispatchEvent(new Event('change', { bubbles: true }));
492
+ },
493
+ async navigate(page) {
494
+ const go = pages[page];
495
+ // The executor already checked the allowlist and sanitizes this same message before this
496
+ // driver-level check would ever be reached through it; this is the belt on the braces. But
497
+ // `PageDriver` is a public interface — a caller that reaches this method directly, bypassing
498
+ // the executor entirely, hands `page` in unsanitized, so the same bound-and-strip treatment
499
+ // applies here too rather than assuming the only caller is the one that already checked.
500
+ if (go === undefined)
501
+ throw new Error(`"${normalizeAgentLabel(page).text}" is not a published page`);
502
+ go();
503
+ },
504
+ };
505
+ }
506
+ /**
507
+ * Writes into a contenteditable region the way a real user typing would, rather than by replacing
508
+ * its DOM directly.
509
+ *
510
+ * A framework rich-text editor (Lexical, ProseMirror, Quill, CodeMirror) owns its subtree: it
511
+ * keeps its own model and reconciles the DOM to match it, so a direct `textContent =` write is
512
+ * either invisible to that model or gets reverted on the editor's next render — and it always
513
+ * destroys whatever node structure the editor had built (a mention's `<span>`, a paragraph's `<p>`)
514
+ * in favour of one bare text node. Selecting the existing contents and issuing a real editing
515
+ * command instead is what Playwright's own `fill` does against a contenteditable, for the same
516
+ * reason: `execCommand('insertText'|'delete')` is the platform's own command, so the browser fires
517
+ * `beforeinput`/`input` itself with the correct `inputType` — the exact signal these editors
518
+ * listen for — rather than this driver guessing at a contract it does not own by hand-rolling one.
519
+ *
520
+ * jsdom implements neither a real editing host nor `execCommand`, so every unit test here exercises
521
+ * the fallback: the previous `textContent` + synthetic `input` behaviour, kept for exactly that
522
+ * case and for a real browser that reports the command did not run.
523
+ *
524
+ * Verified 2026-07-26 in Chromium against real Lexical 0.36.2 — the editor
525
+ * `packages/ui/src/features/rich-text-input/` is built on — driving both paths at one editor each
526
+ * and reading back Lexical's own `EditorState`, not the DOM. The `textContent` write left the
527
+ * model at its seed value and was reverted in the DOM too; the `execCommand` path landed in the
528
+ * model. That is the whole reason this function exists, and no unit test in this repo can show it.
529
+ */
530
+ function fillEditableRegion(control, text) {
531
+ control.focus();
532
+ const selection = globalThis.getSelection?.();
533
+ if (selection) {
534
+ const range = control.ownerDocument.createRange();
535
+ range.selectNodeContents(control);
536
+ selection.removeAllRanges();
537
+ selection.addRange(range);
538
+ }
539
+ const execCommand = control.ownerDocument.execCommand?.bind(control.ownerDocument);
540
+ if (typeof execCommand === 'function') {
541
+ // An empty replacement has no text to insert; `delete` removes the just-selected contents,
542
+ // which `insertText` with an empty string is not guaranteed to do in every engine.
543
+ const ran = text.length > 0 ? execCommand('insertText', false, text) : execCommand('delete');
544
+ if (ran)
545
+ return;
546
+ }
547
+ control.textContent = text;
548
+ // Editors listen for `input`, not `change`; `change` is a form-control event and firing it here
549
+ // would be inventing an event the platform never sends for this element.
550
+ control.dispatchEvent(new Event('input', { bubbles: true }));
551
+ }
552
+ /** Reads the current page's `data-agent-page`, for hosts that tag the body. */
553
+ export function currentAgentPage(root) {
554
+ const tagged = root.querySelector(`[${AGENT_PAGE_ATTRIBUTE}]`);
555
+ return tagged?.getAttribute(AGENT_PAGE_ATTRIBUTE) ?? undefined;
556
+ }
557
+ //# sourceMappingURL=dom-page-driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-page-driver.js","sourceRoot":"","sources":["../../src/dom/dom-page-driver.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GAItB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAwB,MAAM,cAAc,CAAC;AAGzE;;;;;;;;;;GAUG;AAEH,2FAA2F;AAC3F,MAAM,eAAe,GAAG;IACtB,OAAO,EAAE,mBAAmB;IAC5B,aAAa,EAAE,KAAK;IACpB,YAAY,EAAE,KAAK;CACX,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,SAAS,kBAAkB,CAAC,KAAoB;IAC9C,OAAO,KAAK,KAAK,IAAI,IAAK,mBAAyC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACtF,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,OAAgB;IACxC,IAAI,CAAC,CAAC,OAAO,YAAY,WAAW,CAAC;QAAE,OAAO,KAAK,CAAC;IACpD,yFAAyF;IACzF,8FAA8F;IAC9F,8FAA8F;IAC9F,2FAA2F;IAC3F,mFAAmF;IACnF,IAAI,OAAO,CAAC,OAAO,CAAC,2DAA2D,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/F,8FAA8F;IAC9F,gGAAgG;IAChG,8FAA8F;IAC9F,qCAAqC;IACrC,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAC1D,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,SAAS,KAAK,OAAO,CAAC;IACrD,6FAA6F;IAC7F,OAAO,OAAO,CAAC,iBAAiB,KAAK,IAAI,CAAC;AAC5C,CAAC;AAED,0FAA0F;AAC1F,SAAS,WAAW,CAAC,OAAgB;IACnC,+FAA+F;IAC/F,MAAM,UAAU,GAAG,QAAQ,IAAI,OAAO;QACpC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAE,OAAqD,CAAC,MAAM,IAAI,EAAE,CAAC;QACjF,CAAC,CAAC,EAAE,CAAC;IACP,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC;QACvC,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;IACxB,CAAC;IACD,4FAA4F;IAC5F,mGAAmG;IACnG,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC;QAC1C,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;IACxB,CAAC;IACD,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;QACf,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YAChF,IAAK,KAA0B,CAAC,OAAO,KAAK,OAAO,CAAC,EAAE,EAAE,CAAC;gBACvD,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC;gBACvC,IAAI,IAAI;oBAAE,OAAO,IAAI,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,iBAAiB,CAAC,OAAgB;IACzC,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC;IAC7D,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAChC,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,CAAC;IAChE,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IACpC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,oGAAoG;AACpG,SAAS,iBAAiB,CAAC,OAAgB;IACzC,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,2FAA2F;QAC3F,4FAA4F;QAC5F,0FAA0F;QAC1F,OAAO;YACL,IAAI,EAAE,iBAAiB;YACvB,yFAAyF;YACzF,0FAA0F;YAC1F,iFAAiF;YACjF,yDAAyD;YACzD,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,WAAW,EAAE,IAAI,SAAS;YAC9E,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,SAAS;YAC/C,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,SAAS;YAC3B,eAAe,EAAE,iBAAiB,CAAC,OAAO,CAAC;YAC3C,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,KAAK,MAAM;YAC1D,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,KAAK,MAAM;SACjC,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC,CAAC,OAAO,YAAY,gBAAgB,CAAC,IAAI,CAAC,CAAC,OAAO,YAAY,mBAAmB,CAAC,EAAE,CAAC;QACxF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO;QACL,IAAI,EAAE,OAAO,YAAY,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,UAAU;QACnF,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,WAAW,EAAE,IAAI,SAAS;QAC9E,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,SAAS;QAC/B,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,SAAS;QAC3B,eAAe,EAAE,iBAAiB,CAAC,OAAO,CAAC;QAC3C,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,6FAA6F;QAC7F,2FAA2F;QAC3F,uFAAuF;QACvF,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC;KACb,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAS,YAAY,CAAC,OAAgB;IACpC,MAAM,KAAK,GAAI,OAA+E,CAAC,eAAe,CAAC;IAC/G,OAAO,OAAO,KAAK,KAAK,UAAU;QAChC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC;QACvE,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,UAAU,CAAC,OAAgB;IAClC,OAAO,OAAO,YAAY,gBAAgB;WACrC,OAAO,YAAY,mBAAmB;WACtC,OAAO,YAAY,iBAAiB;WACpC,OAAO,YAAY,iBAAiB;QACvC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC;QAC9B,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,SAAS,QAAQ,CAAC,OAAgB,EAAE,IAAwB;IAC1D,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAC;IACxD,uLAAuL;IACvL,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,qBAAqB,CAAC,IAAI,IAAI,CAAC;IAClE,wHAAwH;IACxH,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,uBAAuB,CAAC,IAAI,EAAE,CAAC;IACnE,OAAO;QACL,MAAM;QACN,IAAI,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACjD,0FAA0F;QAC1F,qDAAqD;QACrD,KAAK;QACL,cAAc,EAAE,KAAK;QACrB,IAAI;KACL,CAAC;AACJ,CAAC;AAmBD;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAChC;;;;;;;;;;;;OAYG;IACH,MAAM,MAAM,GAAG,CAAC,OAAgB,EAAsB,EAAE,CACtD,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,oBAAoB,GAAG,CAAC,EAAE,YAAY,CAAC,oBAAoB,CAAC,IAAI,SAAS,CAAC;IACvH;;;;;;OAMG;IACH,MAAM,UAAU,GAAG,IAAI,GAAG,EAGtB,CAAC;IAEL;;;;OAIG;IACH,MAAM,OAAO,GAAG,CAAC,MAAc,EAAa,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAEhH;;;;;;;OAOG;IACH,MAAM,oBAAoB,GAAG,CAAC,MAAc,EAAE,KAAa,EAAS,EAAE,CAAC,IAAI,KAAK,CAC9E,IAAI,MAAM,qBAAqB,KAAK,uDAAuD;UACzF,2FAA2F;UAC3F,yDAAyD,CAC5D,CAAC;IAEF,MAAM,IAAI,GAAG,CAAC,MAAc,EAAW,EAAE;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAChC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,MAAM,gBAAgB,CAAC,CAAC;QAC9F,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,oBAAoB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3E,OAAO,OAAO,CAAC,CAAC,CAAE,CAAC;IACrB,CAAC,CAAC;IAEF;;;;;;OAMG;IACH,MAAM,SAAS,GAAG,CAAC,OAAgB,EAAW,EAAE;QAC9C,8FAA8F;QAC9F,kEAAkE;QAClE,IAAI,gBAAgB,CAAC,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC;QAC9C,qFAAqF;QACrF,qFAAqF;QACrF,0FAA0F;QAC1F,2EAA2E;QAC3E,IAAI,OAAO,YAAY,kBAAkB,EAAE,CAAC;YAC1C,OAAO,OAAO,CAAC,aAAa,CAAC,kBAAkB,CAAC,IAAI,OAAO,CAAC;QAC9D,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,CAAC,oCAAoC,CAAC;YAAE,OAAO,OAAO,CAAC;QAC1E,4FAA4F;QAC5F,oFAAoF;QACpF,qFAAqF;QACrF,uFAAuF;QACvF,wFAAwF;QACxF,sCAAsC;QACtC,MAAM,KAAK,GAAG,CAAC,IAAa,EAAW,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,uBAAuB,GAAG,CAAC,KAAK,OAAO,CAAC;QACnG,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,6CAA6C,CAAC,CAAC;aAClG,IAAI,CAAC,KAAK,CAAC,CAAC;QACf,OAAO,SAAS,IAAI,OAAO,CAAC;IAC9B,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,YAAY,CAAC,MAA0B;YAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,uBAAuB,GAAG,CAAC,CAAC;iBAC5E,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;iBACpD,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC;YAC1C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI;oBAAE,OAAO,KAAK,CAAC;gBAC5E,IAAI,KAAK,KAAK,SAAS;oBAAE,OAAO,IAAI,CAAC;gBACrC,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;uBAC9C,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACnD,CAAC,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,SAAS;YACb,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,MAAM;YACxB,OAAO,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,MAAM;YACxB,4FAA4F;YAC5F,0FAA0F;YAC1F,yFAAyF;YACzF,yEAAyE;YACzE,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YACtC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM,oBAAoB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAC3E,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;YACnC,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;YACzC,MAAM,SAAS,GAAG,OAAO,YAAY,gBAAgB;mBAChD,CAAC,OAAO,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;YAC/D,0FAA0F;YAC1F,2FAA2F;YAC3F,oFAAoF;YACpF,qFAAqF;YACrF,MAAM,QAAQ,GAAG,OAAO,YAAY,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;YAC5E,MAAM,QAAQ,GAAG,KAAK,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;gBACzD,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,SAAS;gBAChC,EAAE,EAAE,QAAQ,CAAC,EAAE,IAAI,SAAS;gBAC5B,2FAA2F;gBAC3F,yDAAyD;gBACzD,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC;aACd,CAAC,CAAC;YAC7B,MAAM,KAAK,GAAG,KAAK,KAAK,IAAI;gBAC1B,CAAC,CAAE,OAAkD,CAAC,KAAK;gBAC3D,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC;YACpB,sFAAsF;YACtF,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;YACvC,OAAO;gBACL,IAAI;gBACJ,oFAAoF;gBACpF,2EAA2E;gBAC3E,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAG,OAA4B,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/E,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClF,GAAG,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjD,GAAG,CAAC,QAAQ,KAAK,SAAS;oBACxB,CAAC,CAAC;wBACE,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;6BAClC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;6BACjC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;qBACvC;oBACH,CAAC,CAAC,EAAE,CAAC;aACuB,CAAC;QACnC,CAAC;QAED;;;;;WAKG;QACH,KAAK,CAAC,MAAM;YACV,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAClC,IAAI,KAAgD,CAAC;gBACrD,qFAAqF;gBACrF,sFAAsF;gBACtF,wFAAwF;gBACxF,mBAAmB;gBACnB,MAAM,MAAM,GAAG,GAAS,EAAE;oBACxB,IAAI,KAAK,KAAK,SAAS;wBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;oBAC7C,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC;gBACF,MAAM,GAAG,GAAG,UAAU,CAAC,qBAAqB,CAAC;gBAC7C,0FAA0F;gBAC1F,yDAAyD;gBACzD,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,KAAK,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC9E,IAAI,OAAO,GAAG,KAAK,UAAU;oBAAE,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU;YAChC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7B,2FAA2F;YAC3F,uFAAuF;YACvF,wFAAwF;YACxF,0FAA0F;YAC1F,IAAI,CAAC,CAAC,OAAO,YAAY,WAAW,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,IAAI,MAAM,wBAAwB,CAAC,CAAC;YAC3F,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACtC,IAAI,MAAM,KAAK,SAAS;gBAAE,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAErD,8FAA8F;YAC9F,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI;gBACjC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO;gBAC9B,aAAa,EAAE,OAAO,CAAC,KAAK,CAAC,aAAa;gBAC1C,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,YAAY;aACzC,CAAC;YACF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;YAC9C,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YAEhE,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,yFAAyF;gBACzF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBACtC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC5B,CAAC,EAAE,UAAU,CAAC,CAAC;YACf,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7C,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,MAAM;YACnB,IAAI,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,KAAK,CAAC,KAAK,CAAC,MAAM;YAChB,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACxC,IAAI,CAAC,CAAC,OAAO,YAAY,WAAW,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,IAAI,MAAM,oBAAoB,CAAC,CAAC;YACvF,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI;YACrB,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACxC,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC9B,qFAAqF;gBACrF,oFAAoF;gBACpF,0EAA0E;gBAC1E,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBAClC,OAAO;YACT,CAAC;YACD,IAAI,CAAC,CAAC,OAAO,YAAY,gBAAgB,CAAC,IAAI,CAAC,CAAC,OAAO,YAAY,mBAAmB,CAAC,EAAE,CAAC;gBACxF,MAAM,IAAI,KAAK,CAAC,IAAI,MAAM,2BAA2B,CAAC,CAAC;YACzD,CAAC;YACD,yFAAyF;YACzF,yFAAyF;YACzF,uEAAuE;YACvE,MAAM,SAAS,GAAG,OAAO,YAAY,gBAAgB;gBACnD,CAAC,CAAC,gBAAgB,CAAC,SAAS;gBAC5B,CAAC,CAAC,mBAAmB,CAAC,SAAS,CAAC;YAClC,MAAM,MAAM,GAAG,MAAM,CAAC,wBAAwB,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC;YACxE,IAAI,MAAM;gBAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;;gBAClC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;YAC1B,OAAO,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAChE,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI;YAChD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACxC,IAAI,CAAC,CAAC,OAAO,YAAY,iBAAiB,CAAC,EAAE,CAAC;gBAC5C,MAAM,IAAI,KAAK,CAAC,IAAI,MAAM,qBAAqB,CAAC,CAAC;YACnD,CAAC;YACD,wFAAwF;YACxF,sFAAsF;YACtF,8BAA8B;YAC9B,2FAA2F;YAC3F,yFAAyF;YACzF,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC/E,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,MAAM,CAAC;mBAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;YACrD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,oFAAoF;gBACpF,0FAA0F;gBAC1F,wFAAwF;gBACxF,sFAAsF;gBACtF,yFAAyF;gBACzF,oFAAoF;gBACpF,yFAAyF;gBACzF,8BAA8B;gBAC9B,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;gBACpD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;qBAClF,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBACrC,MAAM,IAAI,KAAK,CACb,IAAI,UAAU,0BAA0B,MAAM,iBAAiB,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CACxH,CAAC;YACJ,CAAC;YACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,sFAAsF;gBACtF,wFAAwF;gBACxF,sFAAsF;gBACtF,+BAA+B;gBAC/B,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAC5B,CAAC;iBAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACrB,4FAA4F;gBAC5F,6FAA6F;gBAC7F,4FAA4F;gBAC5F,MAAM,IAAI,KAAK,CACb,IAAI,MAAM,sEAAsE;sBAC9E,qDAAqD,mBAAmB,CAAC,MAAM,CAAC,CAAC,IAAI,GAAG,CAC3F,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,wFAAwF;gBACxF,uFAAuF;gBACvF,MAAM,MAAM,GAAG,MAAM,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC;gBAC1F,IAAI,MAAM;oBAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;;oBACzC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;YACnC,CAAC;YACD,OAAO,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAChE,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,IAAI;YACjB,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YACvB,yFAAyF;YACzF,2FAA2F;YAC3F,6FAA6F;YAC7F,4FAA4F;YAC5F,yFAAyF;YACzF,IAAI,EAAE,KAAK,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,2BAA2B,CAAC,CAAC;YACrG,EAAE,EAAE,CAAC;QACP,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAS,kBAAkB,CAAC,OAAoB,EAAE,IAAY;IAC5D,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,EAAE,EAAE,CAAC;IAC9C,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;QAClD,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAClC,SAAS,CAAC,eAAe,EAAE,CAAC;QAC5B,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACnF,IAAI,OAAO,WAAW,KAAK,UAAU,EAAE,CAAC;QACtC,2FAA2F;QAC3F,mFAAmF;QACnF,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC7F,IAAI,GAAG;YAAE,OAAO;IAClB,CAAC;IACD,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAC3B,gGAAgG;IAChG,yEAAyE;IACzE,OAAO,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,IAAgB;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,oBAAoB,GAAG,CAAC,CAAC;IAC/D,OAAO,MAAM,EAAE,YAAY,CAAC,oBAAoB,CAAC,IAAI,SAAS,CAAC;AACjE,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @jini-ai/agentic/dom — the browser half of agent control.
3
+ *
4
+ * The one `PageDriver` (see `@jini-ai/agentic`'s `page-driver.ts`) that reads and writes a real DOM
5
+ * subtree. Split into its own entry point, compiled under its own `DOM`-lib `tsconfig.dom.json`,
6
+ * so the rest of this package can stay provably DOM-free — see source-map.md's "The DOM split".
7
+ *
8
+ * `@jini-ai/chat-react` is this package's one in-repo consumer today.
9
+ */
10
+ export { createDomPageDriver, currentAgentPage, type DomPageDriverOptions } from './dom-page-driver.js';
11
+ /**
12
+ * WebMCP feature detection — moved 2026-07-26 from `@jini-ai/ui`'s `agent-tools/model-context.ts`
13
+ * (plan §8 step 6). See `model-context.ts`'s module doc for why it lives here rather than
14
+ * alongside `../webmcp.ts`'s DOM-free projection.
15
+ */
16
+ export { getAgentModelContext, type AgentModelContextLike, type AgentModelContextToolRegistration, } from './model-context.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dom/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAExG;;;;GAIG;AACH,OAAO,EACL,oBAAoB,EACpB,KAAK,qBAAqB,EAC1B,KAAK,iCAAiC,GACvC,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @jini-ai/agentic/dom — the browser half of agent control.
3
+ *
4
+ * The one `PageDriver` (see `@jini-ai/agentic`'s `page-driver.ts`) that reads and writes a real DOM
5
+ * subtree. Split into its own entry point, compiled under its own `DOM`-lib `tsconfig.dom.json`,
6
+ * so the rest of this package can stay provably DOM-free — see source-map.md's "The DOM split".
7
+ *
8
+ * `@jini-ai/chat-react` is this package's one in-repo consumer today.
9
+ */
10
+ export { createDomPageDriver, currentAgentPage } from './dom-page-driver.js';
11
+ /**
12
+ * WebMCP feature detection — moved 2026-07-26 from `@jini-ai/ui`'s `agent-tools/model-context.ts`
13
+ * (plan §8 step 6). See `model-context.ts`'s module doc for why it lives here rather than
14
+ * alongside `../webmcp.ts`'s DOM-free projection.
15
+ */
16
+ export { getAgentModelContext, } from './model-context.js';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dom/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAA6B,MAAM,sBAAsB,CAAC;AAExG;;;;GAIG;AACH,OAAO,EACL,oBAAoB,GAGrB,MAAM,oBAAoB,CAAC"}