@farmslot/recipe-harness 0.4.2 → 0.5.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.
@@ -1,4 +1,4 @@
1
- import type { RecipeActionManifestDocument, RecipeArtifactManifestEntry } from '@farmslot/protocol';
1
+ import type { RecipeActionManifestDocument, RecipeArtifactManifestEntry, UiObserverRef } from '@farmslot/protocol';
2
2
  export type RecipeRunStatus = 'pass' | 'fail' | 'unknown';
3
3
  export type RecipeVideoRecordingMode = 'off' | 'full-run';
4
4
  export type RecipeRecordPolicy = 'none' | 'trace_only' | 'proof_window' | 'failure_only';
@@ -169,6 +169,8 @@ export interface ActionResult {
169
169
  case?: string;
170
170
  output?: unknown;
171
171
  artifacts?: RecipeArtifactManifestEntry[];
172
+ observations?: RecipeObservations;
173
+ observationWarnings?: RecipeObservationWarning[];
172
174
  }
173
175
  export interface ActionExecutionContext {
174
176
  nodeId: string;
@@ -188,6 +190,16 @@ export interface ActionAdapter {
188
190
  action: string;
189
191
  testOnly?: boolean;
190
192
  execute(node: Record<string, unknown>, context: ActionExecutionContext): Promise<ActionResult>;
193
+ observe?(refs: readonly UiObserverRef[], node: Record<string, unknown>, context: ActionExecutionContext): Promise<RecipeObservationResult>;
194
+ }
195
+ export type RecipeObservations = Partial<Record<UiObserverRef, unknown>>;
196
+ export interface RecipeObservationWarning {
197
+ ref: UiObserverRef;
198
+ message: string;
199
+ }
200
+ export interface RecipeObservationResult {
201
+ observations?: RecipeObservations;
202
+ warnings?: RecipeObservationWarning[];
191
203
  }
192
204
  export interface RecipePreconditionGate {
193
205
  id: string;
@@ -223,7 +235,10 @@ export interface TraceEntry {
223
235
  ok: boolean;
224
236
  next?: string;
225
237
  status?: RecipeRunStatus;
238
+ case?: string;
226
239
  output?: unknown;
240
+ observations?: RecipeObservations;
241
+ observationWarnings?: RecipeObservationWarning[];
227
242
  artifacts?: RecipeArtifactManifestEntry[];
228
243
  error?: string;
229
244
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
+ import type { UiObserverRef } from '@farmslot/protocol';
1
2
  import type { StandardUiAction, UiActionTransport } from '../adapters/ui.js';
2
- import type { ActionExecutionContext } from '../core/types.js';
3
+ import type { ActionExecutionContext, RecipeObservationResult } from '../core/types.js';
3
4
  export declare function sleep(ms: number): Promise<void>;
4
5
  export declare function dataTestId(testId: string): string;
5
6
  export interface CdpTargetInfo {
@@ -40,7 +41,12 @@ export declare class CdpWebPage {
40
41
  readonly session: CdpSession;
41
42
  constructor(session: CdpSession);
42
43
  static connectToTarget(target: CdpTargetInfo): Promise<CdpWebPage>;
43
- navigate(url: string): Promise<unknown>;
44
+ navigate(url: string, timeoutMs?: number): Promise<unknown>;
45
+ waitForDocumentReady(options: {
46
+ expectedUrl?: string;
47
+ timeoutMs?: number;
48
+ }): Promise<void>;
49
+ waitForDomSettled(timeoutMs?: number): Promise<void>;
44
50
  evaluate<T = unknown>(expression: string): Promise<T>;
45
51
  click(selector: string): Promise<unknown>;
46
52
  clickText(text: string): Promise<unknown>;
@@ -73,6 +79,7 @@ export declare class CdpWebPage {
73
79
  category?: string;
74
80
  mimeType: string;
75
81
  }>;
82
+ observe(refs: readonly UiObserverRef[]): Promise<RecipeObservationResult>;
76
83
  close(): void;
77
84
  }
78
85
  export interface CdpWebUiTransportInput {
@@ -1 +1 @@
1
- {"version":3,"file":"cdp.d.ts","sourceRoot":"","sources":["../../src/runtime/cdp.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAqB,MAAM,mBAAmB,CAAC;AAEhG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE/D,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC;CAChD;AAOD,wBAAsB,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAIlE;AAED,wBAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,EAC5C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,CAAC,CAAC,CAgBZ;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAEzF;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,aAAa,CAAC,CAsB7F;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;AAExE,qBAAa,UAAU;;IAMrB,OAAO;WAOM,OAAO,CAAC,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IASjE,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAczF,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,IAAI;IAUxD,KAAK,IAAI,IAAI;CAkCd;AAED,qBAAa,UAAU;IACrB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;gBAEjB,OAAO,EAAE,UAAU;WAIlB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC;IASlE,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIvC,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAerD,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAazC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAazC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA2B3D,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMvC,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB/C,MAAM,CAAC,OAAO,EAAE;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,GAAG,OAAO,CAAC,OAAO,CAAC;IAkBd,OAAO,CAAC,OAAO,EAAE;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,OAAO,CAAC;IAOd,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzF,iBAAiB,CACrB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACnC,OAAO,CAAC,OAAO,CAAC;IAOb,UAAU,CACd,OAAO,CAAC,EAAE,sBAAsB,EAChC,OAAO,CAAC,EAAE,MAAM,EAChB,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACrC,OAAO,CACN,MAAM,GACN;QACE,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KAClB,CACJ;IAyBD,KAAK,IAAI,IAAI;CAGd;AAYD,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,gBAAgB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,sBAAsB,CAAC;CACjC;AAED,MAAM,WAAW,8BAA8B;IAC7C,OAAO,CAAC,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7D,QAAQ,CAAC,CAAC,CAAC,EACT,KAAK,EAAE,sBAAsB,EAC7B,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GACzC,OAAO,CAAC,CAAC,CAAC,CAAC;CACf;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,8BAA8B,GACtC,iBAAiB,CA2DnB;AAiBD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CASpF"}
1
+ {"version":3,"file":"cdp.d.ts","sourceRoot":"","sources":["../../src/runtime/cdp.ts"],"names":[],"mappings":"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"}
@@ -145,8 +145,53 @@ export class CdpWebPage {
145
145
  await session.call('Page.enable');
146
146
  return new CdpWebPage(session);
147
147
  }
148
- async navigate(url) {
149
- return this.session.call('Page.navigate', { url });
148
+ async navigate(url, timeoutMs = 10_000) {
149
+ const deadline = Date.now() + timeoutMs;
150
+ const expectedUrl = await this.evaluate(`new URL(${JSON.stringify(url)}, location.href).href`);
151
+ let notifyLoaded;
152
+ const loaded = new Promise((resolve) => {
153
+ notifyLoaded = resolve;
154
+ });
155
+ const unsubscribe = this.session.on('Page.loadEventFired', () => notifyLoaded?.());
156
+ try {
157
+ const result = await this.session.call('Page.navigate', { url });
158
+ if (result.errorText)
159
+ throw new Error(`CDP navigation failed: ${result.errorText}`);
160
+ if (result.loaderId) {
161
+ await withTimeout(loaded, Math.max(1, deadline - Date.now()), `CDP navigation timed out after ${timeoutMs}ms`);
162
+ }
163
+ await this.waitForDocumentReady({
164
+ expectedUrl: result.loaderId ? undefined : expectedUrl,
165
+ timeoutMs: Math.max(1, deadline - Date.now()),
166
+ });
167
+ return result;
168
+ }
169
+ finally {
170
+ unsubscribe();
171
+ }
172
+ }
173
+ async waitForDocumentReady(options) {
174
+ const timeoutMs = options.timeoutMs ?? 10_000;
175
+ const deadline = Date.now() + timeoutMs;
176
+ let lastError;
177
+ while (Date.now() <= deadline) {
178
+ try {
179
+ const state = await this.evaluate(`(() => ({ ready: document.readyState === 'interactive' || document.readyState === 'complete', url: location.href }))()`);
180
+ if (state.ready && (!options.expectedUrl || state.url === options.expectedUrl))
181
+ return;
182
+ }
183
+ catch (error) {
184
+ // Runtime contexts can disappear briefly while a document navigation commits.
185
+ lastError = error;
186
+ }
187
+ await sleep(50);
188
+ }
189
+ const detail = lastError instanceof Error ? `: ${lastError.message}` : '';
190
+ throw new Error(`CDP document was not ready within ${timeoutMs}ms${detail}`);
191
+ }
192
+ async waitForDomSettled(timeoutMs = 10_000) {
193
+ const quietMs = Math.min(300, Math.max(1, Math.floor(timeoutMs / 2)));
194
+ await withTimeout(this.evaluate(`new Promise((resolve, reject) => { const quietMs = ${quietMs}; const observedRoots = new Set(); let quietTimer; let rootPoll; let timeout; let finished = false; const cleanup = () => { observer.disconnect(); clearTimeout(quietTimer); clearTimeout(timeout); clearInterval(rootPoll); }; const finish = () => { if (finished) return; const animations = typeof document.getAnimations === 'function' ? document.getAnimations({ subtree: true }) : []; const finiteAnimations = animations.filter((animation) => animation.effect?.getTiming().iterations !== Infinity); if (finiteAnimations.some((animation) => animation.playState === 'running' || animation.playState === 'pending')) { schedule(); return; } finished = true; cleanup(); resolve(true); }; const schedule = () => { clearTimeout(quietTimer); quietTimer = setTimeout(finish, quietMs); }; const observeRoot = (root) => { if (!observedRoots.has(root)) { observedRoots.add(root); observer.observe(root, { subtree: true, childList: true, attributes: true, characterData: true }); schedule(); } for (const element of root.querySelectorAll('*')) { if (element.shadowRoot) observeRoot(element.shadowRoot); } }; const discoverRoots = () => observeRoot(document); const observer = new MutationObserver(() => { discoverRoots(); schedule(); }); discoverRoots(); rootPoll = setInterval(discoverRoots, Math.min(25, quietMs)); requestAnimationFrame(() => requestAnimationFrame(schedule)); timeout = setTimeout(() => { if (finished) return; finished = true; cleanup(); reject(new Error('DOM remained active for ${timeoutMs}ms')); }, ${timeoutMs}); })`), timeoutMs + 50, `CDP document did not settle within ${timeoutMs}ms`);
150
195
  }
151
196
  async evaluate(expression) {
152
197
  const result = await this.session.call('Runtime.evaluate', { expression, awaitPromise: true, returnByValue: true });
@@ -158,22 +203,22 @@ export class CdpWebPage {
158
203
  return result.result?.value;
159
204
  }
160
205
  async click(selector) {
161
- const target = await this.evaluate(`(() => { const el = document.querySelector(${JSON.stringify(selector)}); if (!el) throw new Error('Selector not found: ${escapeForJsMessage(selector)}'); el.scrollIntoView({ block: 'center', inline: 'center' }); const rect = el.getBoundingClientRect(); if (rect.width <= 0 || rect.height <= 0) throw new Error('Selector has no clickable box: ${escapeForJsMessage(selector)}'); return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2, selector: ${JSON.stringify(selector)}, tagName: el.tagName }; })()`);
206
+ const target = await this.evaluate(`(() => { ${deepQueryHelpersExpression()} const el = querySelectorDeep(${JSON.stringify(selector)}); if (!el) throw new Error('Selector not found: ${escapeForJsMessage(selector)}'); el.scrollIntoView({ block: 'center', inline: 'center' }); const point = clickablePointDeep(el); return { ...point, selector: ${JSON.stringify(selector)}, tagName: el.tagName }; })()`);
162
207
  await this.clickPoint(target.x, target.y);
163
208
  return { clicked: true, selector: target.selector, tagName: target.tagName };
164
209
  }
165
210
  async clickText(text) {
166
- const target = await this.evaluate(`(() => { const expected = ${JSON.stringify(text)}; const candidates = Array.from(document.querySelectorAll('button, [role=button], a, label, input, textarea, [tabindex]')); const el = candidates.find((candidate) => (candidate.innerText || candidate.textContent || candidate.getAttribute('aria-label') || candidate.getAttribute('value') || '').trim().includes(expected)); if (!el) throw new Error('Text target not found: ${escapeForJsMessage(text)}'); el.scrollIntoView({ block: 'center', inline: 'center' }); const rect = el.getBoundingClientRect(); if (rect.width <= 0 || rect.height <= 0) throw new Error('Text target has no clickable box: ${escapeForJsMessage(text)}'); return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2, text: expected, tagName: el.tagName }; })()`);
211
+ const target = await this.evaluate(`(() => { ${deepQueryHelpersExpression()} const expected = ${JSON.stringify(text)}; const candidates = querySelectorAllDeep('button, [role=button], a, label, input, textarea, [tabindex]'); const el = candidates.find((candidate) => (candidate.innerText || candidate.textContent || candidate.getAttribute('aria-label') || candidate.getAttribute('value') || '').trim().includes(expected)); if (!el) throw new Error('Text target not found: ${escapeForJsMessage(text)}'); el.scrollIntoView({ block: 'center', inline: 'center' }); const point = clickablePointDeep(el); return { ...point, text: expected, tagName: el.tagName }; })()`);
167
212
  await this.clickPoint(target.x, target.y);
168
213
  return { clicked: true, text: target.text, tagName: target.tagName };
169
214
  }
170
215
  async setInput(selector, value) {
171
- const before = await this.evaluate(`(() => { const root = document.querySelector(${JSON.stringify(selector)}); if (!root) throw new Error('Selector not found: ${escapeForJsMessage(selector)}'); const el = root.matches('input, textarea, [contenteditable="true"], [contenteditable=""]') ? root : root.querySelector('input, textarea, [contenteditable="true"], [contenteditable=""]'); if (!el) throw new Error('Input target not found inside selector: ${escapeForJsMessage(selector)}'); if (el.disabled || el.getAttribute('aria-disabled') === 'true') throw new Error('Input target is disabled: ${escapeForJsMessage(selector)}'); el.scrollIntoView({ block: 'center', inline: 'nearest' }); el.focus(); if (typeof el.select === 'function') { el.select(); } else { const range = document.createRange(); range.selectNodeContents(el); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); } return { selector: ${JSON.stringify(selector)}, tagName: el.tagName, previousValue: el.value ?? el.textContent ?? '' }; })()`);
216
+ const before = await this.evaluate(`(() => { ${deepQueryHelpersExpression()} const root = querySelectorDeep(${JSON.stringify(selector)}); if (!root) throw new Error('Selector not found: ${escapeForJsMessage(selector)}'); const el = root.matches('input, textarea, [contenteditable="true"], [contenteditable=""]') ? root : querySelectorDeep('input, textarea, [contenteditable="true"], [contenteditable=""]', root); if (!el) throw new Error('Input target not found inside selector: ${escapeForJsMessage(selector)}'); if (el.disabled || el.getAttribute('aria-disabled') === 'true') throw new Error('Input target is disabled: ${escapeForJsMessage(selector)}'); el.scrollIntoView({ block: 'center', inline: 'nearest' }); el.focus(); if (typeof el.select === 'function') { el.select(); } else { const range = document.createRange(); range.selectNodeContents(el); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); } return { selector: ${JSON.stringify(selector)}, tagName: el.tagName, previousValue: el.value ?? el.textContent ?? '' }; })()`);
172
217
  await this.session.call('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Backspace' });
173
218
  await this.session.call('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Backspace' });
174
219
  if (value)
175
220
  await this.session.call('Input.insertText', { text: value });
176
- const after = await this.evaluate(`(() => { const root = document.querySelector(${JSON.stringify(selector)}); const el = root && (root.matches('input, textarea, [contenteditable="true"], [contenteditable=""]') ? root : root.querySelector('input, textarea, [contenteditable="true"], [contenteditable=""]')); if (!el) throw new Error('Input target disappeared after typing: ${escapeForJsMessage(selector)}'); el.dispatchEvent(new Event('change', { bubbles: true })); return { value: el.value ?? el.textContent ?? '' }; })()`);
221
+ const after = await this.evaluate(`(() => { ${deepQueryHelpersExpression()} const root = querySelectorDeep(${JSON.stringify(selector)}); const el = root && (root.matches('input, textarea, [contenteditable="true"], [contenteditable=""]') ? root : querySelectorDeep('input, textarea, [contenteditable="true"], [contenteditable=""]', root)); if (!el) throw new Error('Input target disappeared after typing: ${escapeForJsMessage(selector)}'); el.dispatchEvent(new Event('change', { bubbles: true })); return { value: el.value ?? el.textContent ?? '' }; })()`);
177
222
  if (after.value !== value) {
178
223
  throw new Error(`Input target value mismatch after typing ${selector}: expected ${JSON.stringify(value)}, got ${JSON.stringify(after.value)}.`);
179
224
  }
@@ -218,15 +263,15 @@ export class CdpWebPage {
218
263
  const deltaY = options.deltaY ?? 600;
219
264
  if (options.selector) {
220
265
  if (options.intoView) {
221
- return this.evaluate(`(() => { const el = document.querySelector(${JSON.stringify(options.selector)}); if (!el) throw new Error('Selector not found: ${escapeForJsMessage(options.selector)}'); el.scrollIntoView({ block: 'center', inline: 'nearest' }); return { scrolled: true, selector: ${JSON.stringify(options.selector)}, intoView: true }; })()`);
266
+ return this.evaluate(`(() => { ${deepQueryHelpersExpression()} const el = querySelectorDeep(${JSON.stringify(options.selector)}); if (!el) throw new Error('Selector not found: ${escapeForJsMessage(options.selector)}'); el.scrollIntoView({ block: 'center', inline: 'nearest' }); return { scrolled: true, selector: ${JSON.stringify(options.selector)}, intoView: true }; })()`);
222
267
  }
223
- return this.evaluate(`(() => { const el = document.querySelector(${JSON.stringify(options.selector)}); if (!el) throw new Error('Selector not found: ${escapeForJsMessage(options.selector)}'); el.scrollBy(${JSON.stringify(deltaX)}, ${JSON.stringify(deltaY)}); return { scrolled: true }; })()`);
268
+ return this.evaluate(`(() => { ${deepQueryHelpersExpression()} const el = querySelectorDeep(${JSON.stringify(options.selector)}); if (!el) throw new Error('Selector not found: ${escapeForJsMessage(options.selector)}'); el.scrollBy(${JSON.stringify(deltaX)}, ${JSON.stringify(deltaY)}); return { scrolled: true }; })()`);
224
269
  }
225
270
  return this.evaluate(`(() => { window.scrollBy(${JSON.stringify(deltaX)}, ${JSON.stringify(deltaY)}); return { scrolled: true }; })()`);
226
271
  }
227
272
  async waitFor(options) {
228
273
  const timeoutMs = options.timeoutMs ?? 5_000;
229
- return this.evaluate(`(async () => { const deadline = Date.now() + ${JSON.stringify(timeoutMs)}; while (Date.now() <= deadline) { const ok = ${waitForPredicateExpression(options)}; if (ok) return { matched: true }; await new Promise((resolve) => setTimeout(resolve, 100)); } throw new Error('ui.wait_for timed out'); })()`);
274
+ return this.evaluate(`(async () => { ${deepQueryHelpersExpression()} const deadline = Date.now() + ${JSON.stringify(timeoutMs)}; while (Date.now() <= deadline) { const ok = ${waitForPredicateExpression(options)}; if (ok) return { matched: true }; await new Promise((resolve) => setTimeout(resolve, 100)); } throw new Error('ui.wait_for timed out'); })()`);
230
275
  }
231
276
  async waitForSelector(selector, options = {}) {
232
277
  return this.waitFor({ selector, timeoutMs: options.timeoutMs });
@@ -257,6 +302,33 @@ export class CdpWebPage {
257
302
  mimeType: 'image/png',
258
303
  };
259
304
  }
305
+ async observe(refs) {
306
+ const observations = {};
307
+ const warnings = [];
308
+ for (const ref of refs) {
309
+ try {
310
+ if (ref === 'ui.screen') {
311
+ observations[ref] = await this.evaluate(`(() => { const hashPath = location.hash.split('?')[0]; const hashRoute = hashPath && !hashPath.includes('=') ? hashPath : undefined; return { provider: 'cdp-web', name: document.title || location.pathname || hashRoute || 'Browser', title: document.title || undefined, route: hashRoute || location.pathname || undefined, url: location.origin + location.pathname }; })()`);
312
+ }
313
+ else if (ref === 'ui.visible') {
314
+ observations[ref] = await this.evaluate(visibleTargetsExpression());
315
+ }
316
+ else {
317
+ warnings.push({ ref, message: `Unsupported UI observer: ${ref}.` });
318
+ }
319
+ }
320
+ catch (error) {
321
+ warnings.push({
322
+ ref,
323
+ message: error instanceof Error ? error.message : String(error),
324
+ });
325
+ }
326
+ }
327
+ return {
328
+ ...(Object.keys(observations).length ? { observations } : {}),
329
+ ...(warnings.length ? { warnings } : {}),
330
+ };
331
+ }
260
332
  close() {
261
333
  this.session.close();
262
334
  }
@@ -279,34 +351,36 @@ export function createCdpWebUiTransport(options) {
279
351
  switch (action) {
280
352
  case 'ui.navigate': {
281
353
  const url = asString(node.url ?? node.target, 'ui.navigate.url');
282
- return page.navigate(url);
354
+ return executeSettledCdpAction(page, page.navigate(url, node.timeout_ms == null
355
+ ? undefined
356
+ : asNumber(node.timeout_ms, 'ui.navigate.timeout_ms')), node);
283
357
  }
284
358
  case 'ui.press': {
285
359
  const selector = selectorForUiInput(node);
286
- if (selector)
287
- return page.click(selector);
288
- return page.clickText(asString(node.text ?? node.label, 'ui.press.text'));
360
+ return executeSettledCdpAction(page, selector
361
+ ? page.click(selector)
362
+ : page.clickText(asString(node.text ?? node.label, 'ui.press.text')), node);
289
363
  }
290
364
  case 'ui.key_press':
291
- return page.keyPress(asString(node.key, 'ui.key_press.key'));
365
+ return executeSettledCdpAction(page, page.keyPress(asString(node.key, 'ui.key_press.key')), node);
292
366
  case 'ui.set_input':
293
- return page.setInput(asString(selectorForUiInput(node), 'ui.set_input.selector'), asString(node.value ?? node.text, 'ui.set_input.value'));
367
+ return executeSettledCdpAction(page, page.setInput(asString(selectorForUiInput(node), 'ui.set_input.selector'), asString(node.value ?? node.text, 'ui.set_input.value')), node);
294
368
  case 'ui.scroll':
295
- return page.scroll({
369
+ return executeSettledCdpAction(page, page.scroll({
296
370
  selector: asOptionalString(selectorForUiInput(node), 'ui.scroll.selector'),
297
371
  intoView: node.scroll_into_view === true || node.into_view === true,
298
372
  deltaX: node.delta_x == null ? undefined : asNumber(node.delta_x, 'ui.scroll.delta_x'),
299
373
  deltaY: node.delta_y == null ? undefined : asNumber(node.delta_y, 'ui.scroll.delta_y'),
300
- });
374
+ }), node);
301
375
  case 'ui.wait_for':
302
- return page.waitFor({
376
+ return executeSettledCdpAction(page, page.waitFor({
303
377
  selector: asOptionalString(selectorForUiInput(node), 'ui.wait_for.selector'),
304
378
  text: asOptionalString(node.text, 'ui.wait_for.text'),
305
379
  expected: asOptionalString(node.expected, 'ui.wait_for.expected'),
306
380
  timeoutMs: node.timeout_ms == null
307
381
  ? undefined
308
382
  : asNumber(node.timeout_ms, 'ui.wait_for.timeout_ms'),
309
- });
383
+ }), node);
310
384
  case 'ui.screenshot':
311
385
  return captureCdpScreenshot(page, node, context);
312
386
  case 'app.status':
@@ -322,8 +396,136 @@ export function createCdpWebUiTransport(options) {
322
396
  }
323
397
  });
324
398
  },
399
+ async observe(refs, node, context) {
400
+ const input = { action: 'app.status', node, context };
401
+ return withCdpWebPage(options, input, async (page) => page.observe(refs));
402
+ },
325
403
  };
326
404
  }
405
+ async function executeSettledCdpAction(page, operation, node) {
406
+ const startedAt = Date.now();
407
+ const result = await operation;
408
+ if (node.settle === false)
409
+ return result;
410
+ // timeout_ms budgets the whole node: settlement only gets what the action left over.
411
+ const timeoutMs = node.timeout_ms == null
412
+ ? undefined
413
+ : Math.max(1, asNumber(node.timeout_ms, 'ui action timeout_ms') - (Date.now() - startedAt));
414
+ try {
415
+ await page.waitForDomSettled(timeoutMs);
416
+ return result;
417
+ }
418
+ catch (error) {
419
+ const settlementWarning = error instanceof Error ? error.message : String(error);
420
+ if (typeof result === 'object' && result !== null && !Array.isArray(result)) {
421
+ return { ...result, settlementWarning };
422
+ }
423
+ return { result, settlementWarning };
424
+ }
425
+ }
426
+ function visibleTargetsExpression() {
427
+ return `(() => {
428
+ const visibleLimit = 20;
429
+ const hiddenLimit = 10;
430
+ const selector = [
431
+ 'button',
432
+ 'a[href]',
433
+ 'input',
434
+ 'textarea',
435
+ 'select',
436
+ '[role="button"]',
437
+ '[role="link"]',
438
+ '[role="menuitem"]',
439
+ '[role="tab"]'
440
+ ].join(',');
441
+ ${deepQueryHelpersExpression()}
442
+ const nodes = querySelectorAllDeep(selector);
443
+ const textFor = (el) => {
444
+ const raw = el.getAttribute('aria-label') || el.getAttribute('title') || el.getAttribute('placeholder') || el.innerText || '';
445
+ return String(raw).replace(/\\s+/g, ' ').trim().slice(0, 120) || undefined;
446
+ };
447
+ const cssPath = (el) => {
448
+ if (el.id) return '#' + CSS.escape(el.id);
449
+ const testAttribute = ['data-testid', 'data-test-id', 'data-test'].find((attribute) => el.hasAttribute(attribute));
450
+ if (testAttribute) {
451
+ const testId = CSS.escape(String(el.getAttribute(testAttribute)));
452
+ return '[' + testAttribute + '="' + testId + '"]';
453
+ }
454
+ if (el.getRootNode() instanceof ShadowRoot) return undefined;
455
+ const parts = [];
456
+ let current = el;
457
+ while (current && current.nodeType === Node.ELEMENT_NODE) {
458
+ if (current.id) {
459
+ parts.unshift('#' + CSS.escape(current.id));
460
+ break;
461
+ }
462
+ const tag = current.tagName.toLowerCase();
463
+ const parent = current.parentElement;
464
+ if (!parent) {
465
+ parts.unshift(tag);
466
+ break;
467
+ }
468
+ const siblings = Array.from(parent.children).filter((child) => child.tagName === current.tagName);
469
+ parts.unshift(siblings.length > 1 ? tag + ':nth-of-type(' + (siblings.indexOf(current) + 1) + ')' : tag);
470
+ current = parent;
471
+ }
472
+ return parts.join(' > ');
473
+ };
474
+ const itemFor = (el, rect, includeLabel) => ({
475
+ role: el.getAttribute('role') || (el.tagName.toLowerCase() === 'a' ? 'link' : el.tagName.toLowerCase() === 'button' ? 'button' : undefined),
476
+ label: includeLabel ? textFor(el) : undefined,
477
+ test_id: el.getAttribute('data-testid') || el.getAttribute('data-test-id') || el.getAttribute('data-test') || undefined,
478
+ selector: cssPath(el),
479
+ enabled: !(el.disabled || el.getAttribute('aria-disabled') === 'true'),
480
+ selected: el.getAttribute('aria-selected') === 'true' || undefined,
481
+ focused: document.activeElement === el || undefined,
482
+ bounds: rect ? { x: Math.round(rect.left), y: Math.round(rect.top), width: Math.round(rect.width), height: Math.round(rect.height) } : undefined
483
+ });
484
+ const composedContains = (ancestor, descendant) => {
485
+ let current = descendant;
486
+ while (current) {
487
+ if (current === ancestor) return true;
488
+ const root = current.getRootNode();
489
+ current = current.parentElement || (root instanceof ShadowRoot ? root.host : null);
490
+ }
491
+ return false;
492
+ };
493
+ const isCoveredDeep = (el, rect) => {
494
+ const x = rect.left + rect.width / 2;
495
+ const y = rect.top + rect.height / 2;
496
+ if (x < 0 || y < 0 || x > window.innerWidth || y > window.innerHeight) return false;
497
+ let hit = document.elementFromPoint(x, y);
498
+ while (hit && hit.shadowRoot) {
499
+ const deeper = hit.shadowRoot.elementFromPoint(x, y);
500
+ if (!deeper || deeper === hit) break;
501
+ hit = deeper;
502
+ }
503
+ if (!hit) return false;
504
+ return !composedContains(el, hit);
505
+ };
506
+ const items = [];
507
+ const hidden_or_offscreen = [];
508
+ for (const el of nodes) {
509
+ const rect = el.getBoundingClientRect();
510
+ const hasBox = rect.width > 0 && rect.height > 0;
511
+ const rendered = hasBox && isRenderedDeep(el);
512
+ const visible = rendered && isVisibleDeep(el);
513
+ const covered = visible && isCoveredDeep(el, rect);
514
+ if (visible && !covered && items.length < visibleLimit) {
515
+ items.push(itemFor(el, rect, true));
516
+ } else if ((!visible || covered) && hidden_or_offscreen.length < hiddenLimit) {
517
+ hidden_or_offscreen.push({ ...itemFor(el, rendered ? rect : undefined, rendered), reason: covered ? 'covered' : rendered ? 'offscreen' : 'hidden_or_no_box' });
518
+ }
519
+ }
520
+ return {
521
+ provider: 'cdp-web',
522
+ items,
523
+ hidden_or_offscreen,
524
+ truncated: nodes.length > items.length + hidden_or_offscreen.length,
525
+ limits: { items: visibleLimit, hidden_or_offscreen: hiddenLimit }
526
+ };
527
+ })()`;
528
+ }
327
529
  async function withCdpWebPage(options, input, callback) {
328
530
  if (options.withPage)
329
531
  return options.withPage(input, callback);
@@ -544,15 +746,15 @@ function waitForPredicateExpression(options) {
544
746
  if (options.selector && options.text) {
545
747
  const selector = JSON.stringify(options.selector);
546
748
  const text = JSON.stringify(options.text);
547
- presentExpression = `Boolean(document.querySelector(${selector})) && document.body.innerText.includes(${text})`;
548
- visibleExpression = `${visibleSelectorExpression(options.selector)} && document.body.innerText.includes(${text})`;
749
+ presentExpression = `Boolean(querySelectorDeep(${selector})) && textIncludesDeep(${text})`;
750
+ visibleExpression = `${visibleSelectorExpression(options.selector)} && textIncludesDeep(${text})`;
549
751
  }
550
752
  else if (options.selector) {
551
- presentExpression = `Boolean(document.querySelector(${JSON.stringify(options.selector)}))`;
753
+ presentExpression = `Boolean(querySelectorDeep(${JSON.stringify(options.selector)}))`;
552
754
  visibleExpression = visibleSelectorExpression(options.selector);
553
755
  }
554
756
  else if (options.text) {
555
- presentExpression = `document.body.innerText.includes(${JSON.stringify(options.text)})`;
757
+ presentExpression = `textIncludesDeep(${JSON.stringify(options.text)})`;
556
758
  }
557
759
  else {
558
760
  throw new Error('ui.wait_for requires selector or text.');
@@ -573,7 +775,88 @@ function waitForPredicateExpression(options) {
573
775
  return presentExpression;
574
776
  }
575
777
  function visibleSelectorExpression(selector) {
576
- return `(() => { const el = document.querySelector(${JSON.stringify(selector)}); if (!el) return false; const rect = el.getBoundingClientRect(); const style = window.getComputedStyle(el); return rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'; })()`;
778
+ return `(() => { const el = querySelectorDeep(${JSON.stringify(selector)}); return Boolean(el && isVisibleDeep(el)); })()`;
779
+ }
780
+ function deepQueryHelpersExpression() {
781
+ return `
782
+ const querySelectorAllDeep = (selector, root = document) => {
783
+ const matches = Array.from(root.querySelectorAll(selector));
784
+ for (const element of root.querySelectorAll('*')) {
785
+ if (element.shadowRoot) matches.push(...querySelectorAllDeep(selector, element.shadowRoot));
786
+ }
787
+ return matches;
788
+ };
789
+ const querySelectorDeep = (selector, root = document) => querySelectorAllDeep(selector, root)[0] ?? null;
790
+ const isRenderedDeep = (element) => {
791
+ if (!element || element.getClientRects().length === 0) return false;
792
+ let current = element;
793
+ while (current) {
794
+ const style = getComputedStyle(current);
795
+ if (style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity || 1) <= 0) return false;
796
+ const root = current.getRootNode();
797
+ current = current.parentElement || (root instanceof ShadowRoot ? root.host : null);
798
+ }
799
+ return true;
800
+ };
801
+ const isVisibleDeep = (element) => {
802
+ if (!isRenderedDeep(element)) return false;
803
+ let rect = element.getBoundingClientRect();
804
+ let current = element;
805
+ while (current) {
806
+ const root = current.getRootNode();
807
+ const parent = current.parentElement || (root instanceof ShadowRoot ? root.host : null);
808
+ if (!parent) break;
809
+ const style = getComputedStyle(parent);
810
+ if (/(hidden|clip|scroll|auto)/.test(style.overflow + style.overflowX + style.overflowY)) {
811
+ const parentRect = parent.getBoundingClientRect();
812
+ rect = { left: Math.max(rect.left, parentRect.left), top: Math.max(rect.top, parentRect.top), right: Math.min(rect.right, parentRect.right), bottom: Math.min(rect.bottom, parentRect.bottom) };
813
+ if (rect.right <= rect.left || rect.bottom <= rect.top) return false;
814
+ }
815
+ current = parent;
816
+ }
817
+ return rect.right > 0 && rect.bottom > 0 && rect.left < window.innerWidth && rect.top < window.innerHeight;
818
+ };
819
+ const clickablePointDeep = (element) => {
820
+ if (!isVisibleDeep(element)) throw new Error('Target is not visible');
821
+ if (element.disabled || element.getAttribute('aria-disabled') === 'true') throw new Error('Target is disabled');
822
+ const rect = element.getBoundingClientRect();
823
+ const x = Math.max(0, Math.min(window.innerWidth - 1, rect.left + rect.width / 2));
824
+ const y = Math.max(0, Math.min(window.innerHeight - 1, rect.top + rect.height / 2));
825
+ let hit = document.elementFromPoint(x, y);
826
+ while (hit && hit.shadowRoot) {
827
+ const deeper = hit.shadowRoot.elementFromPoint(x, y);
828
+ if (!deeper || deeper === hit) break;
829
+ hit = deeper;
830
+ }
831
+ const composedContains = (ancestor, descendant) => {
832
+ let current = descendant;
833
+ while (current) {
834
+ if (current === ancestor) return true;
835
+ const root = current.getRootNode();
836
+ current = current.parentElement || (root instanceof ShadowRoot ? root.host : null);
837
+ }
838
+ return false;
839
+ };
840
+ if (!hit || !composedContains(element, hit)) throw new Error('Target is obscured');
841
+ return { x, y };
842
+ };
843
+ const renderedTextDeep = (root = document) => {
844
+ const chunks = [];
845
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
846
+ let node = walker.nextNode();
847
+ while (node) {
848
+ if (node.parentElement && isRenderedDeep(node.parentElement)) chunks.push(node.nodeValue || '');
849
+ node = walker.nextNode();
850
+ }
851
+ for (const element of root.querySelectorAll('*')) {
852
+ if (element.shadowRoot && isRenderedDeep(element)) {
853
+ chunks.push(renderedTextDeep(element.shadowRoot));
854
+ }
855
+ }
856
+ return chunks.join('\\n');
857
+ };
858
+ const textIncludesDeep = (text) => renderedTextDeep().includes(text);
859
+ `;
577
860
  }
578
861
  function escapeForJsMessage(value) {
579
862
  return value.replaceAll('\\', '\\\\').replaceAll("'", "\\'");