@riddledc/riddle-proof 0.7.197 → 0.7.198

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  profileStatusExitCode,
14
14
  resolveRiddleProofProfileTargetUrl,
15
15
  resolveRiddleProofProfileTimeoutSec
16
- } from "./chunk-EYLIXKE2.js";
16
+ } from "./chunk-DL6UB4N6.js";
17
17
  import {
18
18
  createRiddleApiClient,
19
19
  isTerminalRiddleJobStatus,
@@ -848,10 +848,11 @@ function profilePackReceiptStatus(result, metadata, receipt) {
848
848
  clickFallbackTapKeys.add(`${ordinal === void 0 ? `idx:${index}` : `ord:${ordinal}`}:${frameSelector}:${selector}`);
849
849
  });
850
850
  const clickFallbackTapCount = clickFallbackTapKeys.size;
851
- const visibleUiActionCount = clickCount + profileSetupReceiptTotal(setupViewports, "tap");
851
+ const tapUntilCount = profileSetupReceiptTotal(setupViewports, "tap_until");
852
+ const visibleUiActionCount = clickCount + profileSetupReceiptTotal(setupViewports, "tap") + tapUntilCount;
852
853
  const setupFailureCount = profileSetupFailureCount(setupViewports);
853
854
  const setupObstructionCount = profileSetupObstructionCount(setupViewports);
854
- const inputDispatchCount = profileSetupReceiptTotal(setupViewports, "drag") + profileSetupReceiptTotal(setupViewports, "tap") + profileSetupReceiptTotal(setupViewports, "press") + profileSetupReceiptTotal(setupViewports, "keyboard_sequence");
855
+ const inputDispatchCount = profileSetupReceiptTotal(setupViewports, "drag") + profileSetupReceiptTotal(setupViewports, "tap") + tapUntilCount + profileSetupReceiptTotal(setupViewports, "press") + profileSetupReceiptTotal(setupViewports, "keyboard_sequence");
855
856
  const canvasReceipts = setupViewports.flatMap((viewport) => setupReceiptArray(viewport, "canvas_signature"));
856
857
  const hasCanvasChange = canvasReceipts.some((item) => item.ok !== false && item.changed === true);
857
858
  const canvasSignatureHashes = canvasReceipts.filter((item) => item.ok !== false).map((item) => cliString(item.hash)).filter(Boolean);
@@ -918,6 +919,13 @@ function profilePackReceiptStatus(result, metadata, receipt) {
918
919
  "click fallback tap evidence missing"
919
920
  );
920
921
  }
922
+ if (text.includes("tap_until") || text.includes("tap until") || text.includes("tap-until")) {
923
+ return profileReceiptSignalStatus(
924
+ tapUntilCount > 0,
925
+ `tap_until receipt present (${tapUntilCount})`,
926
+ "tap_until receipt missing"
927
+ );
928
+ }
921
929
  if (text.includes("active") && (text.includes("route-local") || text.includes("route local")) && (text.includes("proof helper") || text.includes("proof api") || text.includes("proof state"))) {
922
930
  return profileReceiptSignalStatus(
923
931
  hasActiveRouteLocalProofReceipt,
@@ -1353,6 +1361,7 @@ function setupNaturalInputSummaryMarkdown(viewports) {
1353
1361
  const inputReceipts = [
1354
1362
  ...setupReceiptArray(viewport, "drag").map((receipt) => ({ kind: "drag", receipt })),
1355
1363
  ...setupReceiptArray(viewport, "tap").map((receipt) => ({ kind: "tap", receipt })),
1364
+ ...setupReceiptArray(viewport, "tap_until").map((receipt) => ({ kind: "tap_until", receipt })),
1356
1365
  ...setupReceiptArray(viewport, "press").map((receipt) => ({ kind: "press", receipt }))
1357
1366
  ].filter(({ receipt }) => receipt.ok !== false);
1358
1367
  if (!inputReceipts.length) continue;
@@ -1747,6 +1756,8 @@ function profileSetupSummaryMarkdown(result) {
1747
1756
  const rangeValueTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.set_range_value_total) || 0), 0);
1748
1757
  const dragTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.drag_total) || 0), 0);
1749
1758
  const tapTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.tap_total) || 0), 0);
1759
+ const tapUntilTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.tap_until_total) || 0), 0);
1760
+ const tapUntilTapTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.tap_until_tap_total) || 0), 0);
1750
1761
  const keyboardTotal = viewports.reduce((sum, viewport) => {
1751
1762
  const total = cliFiniteNumber(viewport.keyboard_total);
1752
1763
  return sum + (total === void 0 ? cliFiniteNumber(viewport.press_total) || 0 : total);
@@ -1786,6 +1797,9 @@ function profileSetupSummaryMarkdown(result) {
1786
1797
  if (tapTotal) {
1787
1798
  lines.push(`- tap: ${tapTotal} action(s)`);
1788
1799
  }
1800
+ if (tapUntilTotal) {
1801
+ lines.push(`- tap_until: ${tapUntilTotal} action(s), tap_count total ${tapUntilTapTotal}`);
1802
+ }
1789
1803
  if (keyboardTotal) {
1790
1804
  lines.push(`- keyboard: ${keyboardTotal} action(s)`);
1791
1805
  }
@@ -1813,10 +1827,12 @@ function profileSetupSummaryMarkdown(result) {
1813
1827
  const rangeValueActions = cliFiniteNumber(viewport.set_range_value_total) || 0;
1814
1828
  const dragActions = cliFiniteNumber(viewport.drag_total) || 0;
1815
1829
  const tapActions = cliFiniteNumber(viewport.tap_total) || 0;
1830
+ const tapUntilActions = cliFiniteNumber(viewport.tap_until_total) || 0;
1831
+ const tapUntilTaps = cliFiniteNumber(viewport.tap_until_tap_total) || 0;
1816
1832
  const keyboardActions = cliFiniteNumber(viewport.keyboard_total) ?? cliFiniteNumber(viewport.press_total) ?? 0;
1817
1833
  const canvasSignatureActions = cliFiniteNumber(viewport.canvas_signature_total) || 0;
1818
1834
  const observedPath = cliString(viewport.observed_path);
1819
- lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${clickSequenceCount ? `, ${clickSequenceCount} click sequence(s)` : ""}${clickCountActions ? `, ${clickCountActions} click_count action(s)` : ""}${rangeValueActions ? `, ${rangeValueActions} set_range_value action(s)` : ""}${dragActions ? `, ${dragActions} drag action(s)` : ""}${tapActions ? `, ${tapActions} tap action(s)` : ""}${keyboardActions ? `, ${keyboardActions} keyboard action(s)` : ""}${canvasSignatureActions ? `, ${canvasSignatureActions} canvas_signature action(s)` : ""}${deterministicRuntimeActions ? `, ${deterministicRuntimeActions} deterministic_runtime action(s)` : ""}${windowCallActions ? `, ${windowCallActions} window_call action(s), ${windowCallStored} stored return(s), ${windowCallCaptured} captured return(s)` : ""}${windowEvalActions ? `, ${windowEvalActions} window_eval action(s), ${windowEvalStored} stored return(s), ${windowEvalCaptured} captured return(s)` : ""}${windowCallUntilActions ? `, ${windowCallUntilActions} window_call_until action(s), ${windowCallUntilCalls} call(s)` : ""}${observedPath ? `, path ${observedPath}` : ""}`);
1835
+ lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${clickSequenceCount ? `, ${clickSequenceCount} click sequence(s)` : ""}${clickCountActions ? `, ${clickCountActions} click_count action(s)` : ""}${rangeValueActions ? `, ${rangeValueActions} set_range_value action(s)` : ""}${dragActions ? `, ${dragActions} drag action(s)` : ""}${tapActions ? `, ${tapActions} tap action(s)` : ""}${tapUntilActions ? `, ${tapUntilActions} tap_until action(s), ${tapUntilTaps} tap(s)` : ""}${keyboardActions ? `, ${keyboardActions} keyboard action(s)` : ""}${canvasSignatureActions ? `, ${canvasSignatureActions} canvas_signature action(s)` : ""}${deterministicRuntimeActions ? `, ${deterministicRuntimeActions} deterministic_runtime action(s)` : ""}${windowCallActions ? `, ${windowCallActions} window_call action(s), ${windowCallStored} stored return(s), ${windowCallCaptured} captured return(s)` : ""}${windowEvalActions ? `, ${windowEvalActions} window_eval action(s), ${windowEvalStored} stored return(s), ${windowEvalCaptured} captured return(s)` : ""}${windowCallUntilActions ? `, ${windowCallUntilActions} window_call_until action(s), ${windowCallUntilCalls} call(s)` : ""}${observedPath ? `, path ${observedPath}` : ""}`);
1820
1836
  }
1821
1837
  const clickSequenceGroups = viewports.map((viewport) => {
1822
1838
  const name = cliString(viewport.name) || "viewport";
@@ -1883,6 +1899,33 @@ function profileSetupSummaryMarkdown(result) {
1883
1899
  lines.push(`- ${name} tap: ${ok}, ${markdownInlineCode(selector)}${pointerType ? ` ${markdownInlineCode(pointerType)}` : ""}${inputDispatch ? ` via ${markdownInlineCode(inputDispatch)}` : ""}${coordinateText}${durationMs === void 0 ? "" : `, duration ${durationMs}ms`}${reason ? `, reason ${markdownInlineCode(reason, 100)}` : ""}`);
1884
1900
  }
1885
1901
  if (tapDetails.length > sampledTapDetails.length) lines.push(`- ${tapDetails.length - sampledTapDetails.length} additional tap receipt(s) omitted.`);
1902
+ const tapUntilGroups = viewports.map((viewport) => {
1903
+ const name = cliString(viewport.name) || "viewport";
1904
+ const receipts = Array.isArray(viewport.tap_until) ? viewport.tap_until.map(cliRecord).filter((item) => Boolean(item)) : [];
1905
+ return receipts.map((receipt) => ({ name, receipt }));
1906
+ });
1907
+ const tapUntilDetails = tapUntilGroups.flat();
1908
+ const sampledTapUntilDetails = balancedSetupReceiptDetails(tapUntilGroups, 12);
1909
+ for (const { name, receipt } of sampledTapUntilDetails) {
1910
+ const selector = cliString(receipt.selector) || "target";
1911
+ const pointerType = cliString(receipt.pointer_type);
1912
+ const inputDispatch = cliString(receipt.input_dispatch);
1913
+ const coordinateMode = cliString(receipt.coordinate_mode);
1914
+ const x = cliValueLabel(receipt.x);
1915
+ const y = cliValueLabel(receipt.y);
1916
+ const durationMs = cliFiniteNumber(receipt.duration_ms);
1917
+ const untilPath = cliString(receipt.until_path) || "until_path";
1918
+ const expected = cliValueLabel(receipt.until_expected_value);
1919
+ const actual = cliValueLabel(receipt.until_value);
1920
+ const tapCount = cliFiniteNumber(receipt.tap_count);
1921
+ const maxTaps = cliFiniteNumber(receipt.max_taps) ?? cliFiniteNumber(receipt.max_calls);
1922
+ const ok = receipt.ok === false ? "failed" : "ok";
1923
+ const reason = cliString(receipt.reason);
1924
+ const coordinateText = x && y ? `, ${coordinateMode ? `${coordinateMode} ` : ""}${markdownInlineCode(`${x},${y}`)}` : "";
1925
+ const tapText = tapCount === void 0 ? "" : ` in ${tapCount}${maxTaps === void 0 ? "" : `/${maxTaps}`} tap(s)`;
1926
+ lines.push(`- ${name} tap_until: ${ok}, ${markdownInlineCode(selector)}${pointerType ? ` ${markdownInlineCode(pointerType)}` : ""}${inputDispatch ? ` via ${markdownInlineCode(inputDispatch)}` : ""}${coordinateText}${durationMs === void 0 ? "" : `, duration ${durationMs}ms`} until ${markdownInlineCode(untilPath)}${expected === void 0 ? "" : ` == ${markdownInlineCode(expected, 80)}`}${tapText}${actual === void 0 ? "" : `, observed ${markdownInlineCode(actual, 80)}`}${reason ? `, reason ${markdownInlineCode(reason, 100)}` : ""}`);
1927
+ }
1928
+ if (tapUntilDetails.length > sampledTapUntilDetails.length) lines.push(`- ${tapUntilDetails.length - sampledTapUntilDetails.length} additional tap_until receipt(s) omitted.`);
1886
1929
  const keyboardGroups = viewports.map((viewport) => {
1887
1930
  const name = cliString(viewport.name) || "viewport";
1888
1931
  const rawReceipts = Array.isArray(viewport.keyboard) ? viewport.keyboard : viewport.press;
package/dist/index.cjs CHANGED
@@ -8778,6 +8778,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
8778
8778
  var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
8779
8779
  "click",
8780
8780
  "tap",
8781
+ "tap_until",
8781
8782
  "drag",
8782
8783
  "press",
8783
8784
  "key_down",
@@ -9348,6 +9349,28 @@ function profileSetupTapReceipts(results) {
9348
9349
  reason: result.reason ?? result.error ?? null
9349
9350
  }));
9350
9351
  }
9352
+ function profileSetupTapUntilReceipts(results) {
9353
+ return results.filter((result) => profileSetupResultAction(result) === "tap_until").map((result) => ({
9354
+ ordinal: result.ordinal ?? null,
9355
+ ok: result.ok !== false,
9356
+ selector: result.selector ?? null,
9357
+ frame_selector: result.frame_selector ?? null,
9358
+ pointer_type: result.pointer_type ?? null,
9359
+ input_dispatch: result.input_dispatch ?? null,
9360
+ coordinate_mode: result.coordinate_mode ?? null,
9361
+ x: result.x ?? null,
9362
+ y: result.y ?? null,
9363
+ duration_ms: result.duration_ms ?? null,
9364
+ until_path: result.until_path ?? null,
9365
+ until_value: result.until_value ?? null,
9366
+ until_expected_value: result.until_expected_value ?? null,
9367
+ tap_count: result.tap_count ?? null,
9368
+ max_taps: result.max_taps ?? result.max_calls ?? null,
9369
+ interval_ms: result.interval_ms ?? null,
9370
+ timeout_ms: result.timeout_ms ?? null,
9371
+ reason: result.reason ?? result.error ?? null
9372
+ }));
9373
+ }
9351
9374
  function profileSetupKeyboardReceipts(results) {
9352
9375
  return results.filter((result) => ["press", "key_down", "key_up"].includes(profileSetupResultAction(result))).map((result) => ({
9353
9376
  action: profileSetupResultAction(result),
@@ -9523,6 +9546,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
9523
9546
  const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
9524
9547
  const tapReceipts = profileSetupTapReceipts(results);
9525
9548
  const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
9549
+ const tapUntilReceipts = profileSetupTapUntilReceipts(results);
9550
+ const tapUntilTapCounts = tapUntilReceipts.map((result) => typeof result.tap_count === "number" && Number.isFinite(result.tap_count) ? result.tap_count : void 0).filter((value) => value !== void 0);
9551
+ const sampledTapUntilReceipts = sampleProfileSetupSummaryItems(tapUntilReceipts, 8);
9526
9552
  const keyboardReceipts = profileSetupKeyboardReceipts(results);
9527
9553
  const sampledKeyboardReceipts = sampleProfileSetupSummaryItems(keyboardReceipts, 8);
9528
9554
  const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
@@ -9595,6 +9621,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
9595
9621
  tap_total: tapReceipts.length,
9596
9622
  tap_truncated: tapReceipts.length > sampledTapReceipts.length,
9597
9623
  tap: sampledTapReceipts,
9624
+ tap_until_total: tapUntilReceipts.length,
9625
+ tap_until_tap_total: tapUntilTapCounts.reduce((sum, value) => sum + value, 0),
9626
+ tap_until_truncated: tapUntilReceipts.length > sampledTapUntilReceipts.length,
9627
+ tap_until: sampledTapUntilReceipts,
9598
9628
  keyboard_total: keyboardReceipts.length,
9599
9629
  keyboard_truncated: keyboardReceipts.length > sampledKeyboardReceipts.length,
9600
9630
  keyboard: sampledKeyboardReceipts,
@@ -9656,7 +9686,7 @@ function isSupportedCheckType(value) {
9656
9686
  }
9657
9687
  function normalizeSetupActionType(value, index) {
9658
9688
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
9659
- const normalized = normalizedInput === "clear_browser_storage" ? "clear_storage" : normalizedInput === "reset_console" || normalizedInput === "clear_browser_console" || normalizedInput === "reset_browser_console" ? "clear_console" : normalizedInput === "pointer_drag" || normalizedInput === "mouse_drag" || normalizedInput === "drag_to" ? "drag" : normalizedInput === "pointer_tap" || normalizedInput === "touch_tap" || normalizedInput === "canvas_tap" ? "tap" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "keyboard_down" || normalizedInput === "key_down" || normalizedInput === "keydown" || normalizedInput === "press_down" ? "key_down" : normalizedInput === "keyboard_up" || normalizedInput === "key_up" || normalizedInput === "keyup" || normalizedInput === "press_up" || normalizedInput === "release_key" || normalizedInput === "key_release" ? "key_up" : normalizedInput === "set_slider_value" || normalizedInput === "slider_value" || normalizedInput === "set_slider" || normalizedInput === "set_range" || normalizedInput === "range_value" || normalizedInput === "range_input" || normalizedInput === "set_range_input" ? "set_range_value" : normalizedInput === "deterministic_runtime" || normalizedInput === "mock_runtime" || normalizedInput === "mock_random" || normalizedInput === "mock_random_queue" || normalizedInput === "seed_random_queue" || normalizedInput === "set_random_queue" || normalizedInput === "mock_clock" || normalizedInput === "set_mock_clock" || normalizedInput === "set_runtime_determinism" || normalizedInput === "runtime_determinism" ? "deterministic_runtime" : normalizedInput === "canvas_hash" || normalizedInput === "capture_canvas_hash" || normalizedInput === "capture_canvas_signature" || normalizedInput === "canvas_state_signature" ? "canvas_signature" : normalizedInput === "capture_screenshot" || normalizedInput === "save_screenshot" || normalizedInput === "setup_screenshot" ? "screenshot" : normalizedInput === "accept_dialog" || normalizedInput === "accept_dialogs" || normalizedInput === "confirm_dialog" || normalizedInput === "set_dialog_response" ? "dialog_response" : normalizedInput === "dismiss_dialog" || normalizedInput === "dismiss_dialogs" || normalizedInput === "cancel_dialog" ? "dialog_response" : normalizedInput === "window_call_until" || normalizedInput === "call_until" || normalizedInput === "window_call_repeat_until" || normalizedInput === "repeat_window_call_until" ? "window_call_until" : normalizedInput === "window_evaluate" || normalizedInput === "browser_eval" || normalizedInput === "browser_evaluate" || normalizedInput === "evaluate_script" || normalizedInput === "profile_script" ? "window_eval" : normalizedInput;
9689
+ const normalized = normalizedInput === "clear_browser_storage" ? "clear_storage" : normalizedInput === "reset_console" || normalizedInput === "clear_browser_console" || normalizedInput === "reset_browser_console" ? "clear_console" : normalizedInput === "pointer_drag" || normalizedInput === "mouse_drag" || normalizedInput === "drag_to" ? "drag" : normalizedInput === "pointer_tap" || normalizedInput === "touch_tap" || normalizedInput === "canvas_tap" ? "tap" : normalizedInput === "tap_until" || normalizedInput === "pointer_tap_until" || normalizedInput === "touch_tap_until" || normalizedInput === "canvas_tap_until" || normalizedInput === "tap_repeat_until" || normalizedInput === "repeat_tap_until" ? "tap_until" : normalizedInput === "keyboard_press" || normalizedInput === "key_press" ? "press" : normalizedInput === "keyboard_down" || normalizedInput === "key_down" || normalizedInput === "keydown" || normalizedInput === "press_down" ? "key_down" : normalizedInput === "keyboard_up" || normalizedInput === "key_up" || normalizedInput === "keyup" || normalizedInput === "press_up" || normalizedInput === "release_key" || normalizedInput === "key_release" ? "key_up" : normalizedInput === "set_slider_value" || normalizedInput === "slider_value" || normalizedInput === "set_slider" || normalizedInput === "set_range" || normalizedInput === "range_value" || normalizedInput === "range_input" || normalizedInput === "set_range_input" ? "set_range_value" : normalizedInput === "deterministic_runtime" || normalizedInput === "mock_runtime" || normalizedInput === "mock_random" || normalizedInput === "mock_random_queue" || normalizedInput === "seed_random_queue" || normalizedInput === "set_random_queue" || normalizedInput === "mock_clock" || normalizedInput === "set_mock_clock" || normalizedInput === "set_runtime_determinism" || normalizedInput === "runtime_determinism" ? "deterministic_runtime" : normalizedInput === "canvas_hash" || normalizedInput === "capture_canvas_hash" || normalizedInput === "capture_canvas_signature" || normalizedInput === "canvas_state_signature" ? "canvas_signature" : normalizedInput === "capture_screenshot" || normalizedInput === "save_screenshot" || normalizedInput === "setup_screenshot" ? "screenshot" : normalizedInput === "accept_dialog" || normalizedInput === "accept_dialogs" || normalizedInput === "confirm_dialog" || normalizedInput === "set_dialog_response" ? "dialog_response" : normalizedInput === "dismiss_dialog" || normalizedInput === "dismiss_dialogs" || normalizedInput === "cancel_dialog" ? "dialog_response" : normalizedInput === "window_call_until" || normalizedInput === "call_until" || normalizedInput === "window_call_repeat_until" || normalizedInput === "repeat_window_call_until" ? "window_call_until" : normalizedInput === "window_evaluate" || normalizedInput === "browser_eval" || normalizedInput === "browser_evaluate" || normalizedInput === "evaluate_script" || normalizedInput === "profile_script" ? "window_eval" : normalizedInput;
9660
9690
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
9661
9691
  return normalized;
9662
9692
  }
@@ -9738,8 +9768,8 @@ function normalizeSetupActionCoordinateMode(value, index) {
9738
9768
  }
9739
9769
  function normalizeSetupActionPointerType(value, type, index) {
9740
9770
  if (value === void 0 || value === null || value === "") return void 0;
9741
- if (type !== "drag" && type !== "tap") {
9742
- throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap actions.`);
9771
+ if (type !== "drag" && type !== "tap" && type !== "tap_until") {
9772
+ throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap/tap_until actions.`);
9743
9773
  }
9744
9774
  const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
9745
9775
  if (normalized === "mouse") return "mouse";
@@ -9818,11 +9848,11 @@ function normalizeSetupAction(input, index) {
9818
9848
  if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
9819
9849
  throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
9820
9850
  }
9821
- if ((type === "click" || type === "tap" || type === "drag" || type === "fill" || type === "set_input_value" || type === "set_range_value" || type === "canvas_signature" || type === "wait_for_selector" || type === "wait_for_text" || type === "assert_text_visible" || type === "assert_text_absent" || type === "assert_selector_count") && !selector) {
9851
+ if ((type === "click" || type === "tap" || type === "tap_until" || type === "drag" || type === "fill" || type === "set_input_value" || type === "set_range_value" || type === "canvas_signature" || type === "wait_for_selector" || type === "wait_for_text" || type === "assert_text_visible" || type === "assert_text_absent" || type === "assert_selector_count") && !selector) {
9822
9852
  throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
9823
9853
  }
9824
- const fromX = type === "click" || type === "tap" ? numberValue3(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue3(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
9825
- const fromY = type === "click" || type === "tap" ? numberValue3(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue3(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
9854
+ const fromX = type === "click" || type === "tap" || type === "tap_until" ? numberValue3(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue3(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
9855
+ const fromY = type === "click" || type === "tap" || type === "tap_until" ? numberValue3(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue3(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
9826
9856
  const toX = numberValue3(valueFromOwn(input, "to_x", "toX", "end_x", "endX", "x2"));
9827
9857
  const toY = numberValue3(valueFromOwn(input, "to_y", "toY", "end_y", "endY", "y2"));
9828
9858
  const coordinateMode = normalizeSetupActionCoordinateMode(valueFromOwn(input, "coordinate_mode", "coordinateMode", "coords", "units"), index);
@@ -9847,18 +9877,18 @@ function normalizeSetupAction(input, index) {
9847
9877
  }
9848
9878
  }
9849
9879
  }
9850
- if (type === "tap") {
9880
+ if (type === "tap" || type === "tap_until") {
9851
9881
  const hasTapCoordinate = fromX !== void 0 || fromY !== void 0;
9852
9882
  if (hasTapCoordinate && (fromX === void 0 || fromY === void 0)) {
9853
- throw new Error(`target.setup_actions[${index}] tap coordinates require both x and y.`);
9883
+ throw new Error(`target.setup_actions[${index}] ${type} coordinates require both x and y.`);
9854
9884
  }
9855
9885
  if (hasTapCoordinate && fromX !== void 0 && fromY !== void 0) {
9856
9886
  const tapCoordinates = [fromX, fromY];
9857
9887
  if (coordinateMode === "ratio" && tapCoordinates.some((value2) => value2 < 0 || value2 > 1)) {
9858
- throw new Error(`target.setup_actions[${index}] tap ratio coordinates must be between 0 and 1.`);
9888
+ throw new Error(`target.setup_actions[${index}] ${type} ratio coordinates must be between 0 and 1.`);
9859
9889
  }
9860
9890
  if ((coordinateMode === void 0 || coordinateMode === "pixels") && tapCoordinates.some((value2) => value2 < 0)) {
9861
- throw new Error(`target.setup_actions[${index}] tap pixel coordinates must be non-negative.`);
9891
+ throw new Error(`target.setup_actions[${index}] ${type} pixel coordinates must be non-negative.`);
9862
9892
  }
9863
9893
  }
9864
9894
  }
@@ -9964,7 +9994,7 @@ function normalizeSetupAction(input, index) {
9964
9994
  const captureReturn = input.capture_return === false || input.captureReturn === false || input.include_return === false || input.includeReturn === false || input.omit_return === true || input.omitReturn === true ? false : void 0;
9965
9995
  const untilPath = stringFromOwn(input, "until_path", "untilPath", "until_state_path", "untilStatePath", "until_window_path", "untilWindowPath", "until");
9966
9996
  const hasUntilExpectedValue = hasOwn(input, "until_expected_value") || hasOwn(input, "untilExpectedValue") || hasOwn(input, "until_expected") || hasOwn(input, "untilExpected") || hasOwn(input, "until_value") || hasOwn(input, "untilValue") || hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected");
9967
- if (type === "window_call_until") {
9997
+ if (type === "window_call_until" || type === "tap_until") {
9968
9998
  if (!untilPath) {
9969
9999
  throw new Error(`target.setup_actions[${index}] ${type} requires until_path.`);
9970
10000
  }
@@ -9972,12 +10002,12 @@ function normalizeSetupAction(input, index) {
9972
10002
  throw new Error(`target.setup_actions[${index}] ${type} requires until_expected_value.`);
9973
10003
  }
9974
10004
  }
9975
- const maxCalls = numberValue3(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts"));
9976
- if (type === "window_call_until" && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
10005
+ const maxCalls = numberValue3(valueFromOwn(input, "max_calls", "maxCalls", "max_attempts", "maxAttempts", "attempts", "max_taps", "maxTaps", "tap_limit", "tapLimit"));
10006
+ if ((type === "window_call_until" || type === "tap_until") && (maxCalls === void 0 || !Number.isInteger(maxCalls) || maxCalls < 1 || maxCalls > 100)) {
9977
10007
  throw new Error(`target.setup_actions[${index}].max_calls must be an integer from 1 to 100.`);
9978
10008
  }
9979
10009
  const intervalMs = numberValue3(valueFromOwn(input, "interval_ms", "intervalMs", "poll_ms", "pollMs", "call_interval_ms", "callIntervalMs"));
9980
- if (type === "window_call_until" && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
10010
+ if ((type === "window_call_until" || type === "tap_until") && intervalMs !== void 0 && (!Number.isInteger(intervalMs) || intervalMs < 0 || intervalMs > 5e3)) {
9981
10011
  throw new Error(`target.setup_actions[${index}].interval_ms must be an integer from 0 to 5000.`);
9982
10012
  }
9983
10013
  const steps = numberValue3(input.steps);
@@ -13243,6 +13273,30 @@ function profileSetupTapReceipts(results) {
13243
13273
  reason: result.reason || result.error || null,
13244
13274
  }));
13245
13275
  }
13276
+ function profileSetupTapUntilReceipts(results) {
13277
+ return (results || [])
13278
+ .filter((result) => result && profileSetupResultAction(result) === "tap_until")
13279
+ .map((result) => ({
13280
+ ordinal: result.ordinal ?? null,
13281
+ ok: result.ok !== false,
13282
+ selector: result.selector ?? null,
13283
+ frame_selector: result.frame_selector ?? null,
13284
+ pointer_type: result.pointer_type ?? null,
13285
+ input_dispatch: result.input_dispatch ?? null,
13286
+ coordinate_mode: result.coordinate_mode ?? null,
13287
+ x: result.x ?? null,
13288
+ y: result.y ?? null,
13289
+ duration_ms: result.duration_ms ?? null,
13290
+ until_path: result.until_path ?? null,
13291
+ until_value: result.until_value ?? null,
13292
+ until_expected_value: result.until_expected_value ?? null,
13293
+ tap_count: result.tap_count ?? null,
13294
+ max_taps: result.max_taps ?? result.max_calls ?? null,
13295
+ interval_ms: result.interval_ms ?? null,
13296
+ timeout_ms: result.timeout_ms ?? null,
13297
+ reason: result.reason || result.error || null,
13298
+ }));
13299
+ }
13246
13300
  function profileSetupKeyboardReceipts(results) {
13247
13301
  return (results || [])
13248
13302
  .filter((result) => result && ["press", "key_down", "key_up"].includes(profileSetupResultAction(result)))
@@ -13445,6 +13499,11 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
13445
13499
  const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
13446
13500
  const tapReceipts = profileSetupTapReceipts(results);
13447
13501
  const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
13502
+ const tapUntilReceipts = profileSetupTapUntilReceipts(results);
13503
+ const tapUntilTapCounts = tapUntilReceipts
13504
+ .map((result) => typeof result.tap_count === "number" && Number.isFinite(result.tap_count) ? result.tap_count : undefined)
13505
+ .filter((value) => value !== undefined);
13506
+ const sampledTapUntilReceipts = sampleProfileSetupSummaryItems(tapUntilReceipts, 8);
13448
13507
  const keyboardReceipts = profileSetupKeyboardReceipts(results);
13449
13508
  const sampledKeyboardReceipts = sampleProfileSetupSummaryItems(keyboardReceipts, 8);
13450
13509
  const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
@@ -13527,6 +13586,10 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountsByViewp
13527
13586
  tap_total: tapReceipts.length,
13528
13587
  tap_truncated: tapReceipts.length > sampledTapReceipts.length,
13529
13588
  tap: sampledTapReceipts,
13589
+ tap_until_total: tapUntilReceipts.length,
13590
+ tap_until_tap_total: tapUntilTapCounts.reduce((sum, value) => sum + value, 0),
13591
+ tap_until_truncated: tapUntilReceipts.length > sampledTapUntilReceipts.length,
13592
+ tap_until: sampledTapUntilReceipts,
13530
13593
  keyboard_total: keyboardReceipts.length,
13531
13594
  keyboard_truncated: keyboardReceipts.length > sampledKeyboardReceipts.length,
13532
13595
  keyboard: sampledKeyboardReceipts,
@@ -14473,6 +14536,108 @@ async function waitForAnyVisibleSelector(context, selector, timeout) {
14473
14536
  }
14474
14537
  throw new Error("No visible match for selector " + selector + ": " + lastReason);
14475
14538
  }
14539
+ async function dispatchSetupTapPoint(point, pointerType, durationMs) {
14540
+ if (pointerType === "touch" || pointerType === "pen") {
14541
+ const client = await page.context().newCDPSession(page);
14542
+ try {
14543
+ if (pointerType === "touch") {
14544
+ const touchPoint = {
14545
+ x: point.x,
14546
+ y: point.y,
14547
+ radiusX: 1,
14548
+ radiusY: 1,
14549
+ force: 1,
14550
+ id: 11,
14551
+ };
14552
+ await client.send("Input.dispatchTouchEvent", {
14553
+ type: "touchStart",
14554
+ touchPoints: [touchPoint],
14555
+ });
14556
+ if (durationMs) await page.waitForTimeout(durationMs);
14557
+ await client.send("Input.dispatchTouchEvent", {
14558
+ type: "touchEnd",
14559
+ touchPoints: [],
14560
+ });
14561
+ } else {
14562
+ await client.send("Input.dispatchMouseEvent", {
14563
+ type: "mousePressed",
14564
+ x: point.x,
14565
+ y: point.y,
14566
+ button: "left",
14567
+ buttons: 1,
14568
+ clickCount: 1,
14569
+ pointerType: "pen",
14570
+ });
14571
+ if (durationMs) await page.waitForTimeout(durationMs);
14572
+ await client.send("Input.dispatchMouseEvent", {
14573
+ type: "mouseReleased",
14574
+ x: point.x,
14575
+ y: point.y,
14576
+ button: "left",
14577
+ buttons: 0,
14578
+ clickCount: 1,
14579
+ pointerType: "pen",
14580
+ });
14581
+ }
14582
+ } finally {
14583
+ await client.detach().catch(() => {});
14584
+ }
14585
+ } else {
14586
+ await page.mouse.click(point.x, point.y);
14587
+ }
14588
+ }
14589
+ async function resolveSetupTapTarget(action, base, scope, timeout) {
14590
+ const locator = scope.context.locator(action.selector);
14591
+ const count = await locator.count();
14592
+ if (!count) return { result: { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count } };
14593
+ const targetIndex = Number.isInteger(action.index) ? action.index : 0;
14594
+ if (targetIndex < 0 || targetIndex >= count) return { result: { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex } };
14595
+ const target = locator.nth(targetIndex);
14596
+ await target.waitFor({ state: "visible", timeout });
14597
+ const box = await target.boundingBox();
14598
+ if (!box) return { result: { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex } };
14599
+ const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
14600
+ const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
14601
+ const hasTapPosition = fromX !== undefined || fromY !== undefined;
14602
+ if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { result: { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex } };
14603
+ const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
14604
+ if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { result: { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex } };
14605
+ if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { result: { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex } };
14606
+ const coordinate = (value, size) => mode === "ratio" ? value * size : value;
14607
+ const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
14608
+ const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
14609
+ const point = {
14610
+ x: box.x + coordinate(localX, box.width),
14611
+ y: box.y + coordinate(localY, box.height),
14612
+ };
14613
+ const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
14614
+ const pointerType = String(action.pointer_type || action.pointerType || "touch").trim().toLowerCase();
14615
+ return {
14616
+ target: {
14617
+ count,
14618
+ targetIndex,
14619
+ point,
14620
+ mode,
14621
+ fromX,
14622
+ fromY,
14623
+ hasTapPosition,
14624
+ pointerType,
14625
+ durationMs,
14626
+ },
14627
+ };
14628
+ }
14629
+ function setupTapTargetEvidence(tapTarget) {
14630
+ return {
14631
+ count: tapTarget.count,
14632
+ target_index: tapTarget.targetIndex,
14633
+ coordinate_mode: tapTarget.hasTapPosition ? tapTarget.mode : undefined,
14634
+ x: tapTarget.hasTapPosition ? tapTarget.fromX : undefined,
14635
+ y: tapTarget.hasTapPosition ? tapTarget.fromY : undefined,
14636
+ pointer_type: tapTarget.pointerType,
14637
+ input_dispatch: tapTarget.pointerType === "touch" || tapTarget.pointerType === "pen" ? "cdp" : "playwright_mouse",
14638
+ duration_ms: tapTarget.durationMs || undefined,
14639
+ };
14640
+ }
14476
14641
  function setupHasOwn(action, key) {
14477
14642
  return Boolean(action) && Object.keys(action).includes(key);
14478
14643
  }
@@ -15075,91 +15240,108 @@ async function executeSetupAction(action, ordinal, viewport) {
15075
15240
  if (type === "tap") {
15076
15241
  const scope = await setupActionScope(action, timeout);
15077
15242
  if (!scope.ok) return setupScopeFailure(base, scope);
15078
- const locator = scope.context.locator(action.selector);
15079
- const count = await locator.count();
15080
- if (!count) return { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count };
15081
- const targetIndex = Number.isInteger(action.index) ? action.index : 0;
15082
- if (targetIndex < 0 || targetIndex >= count) return { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex };
15083
- const target = locator.nth(targetIndex);
15084
- await target.waitFor({ state: "visible", timeout });
15085
- const box = await target.boundingBox();
15086
- if (!box) return { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex };
15087
- const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
15088
- const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
15089
- const hasTapPosition = fromX !== undefined || fromY !== undefined;
15090
- if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex };
15091
- const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
15092
- if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex };
15093
- if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex };
15094
- const coordinate = (value, size) => mode === "ratio" ? value * size : value;
15095
- const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
15096
- const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
15097
- const point = {
15098
- x: box.x + coordinate(localX, box.width),
15099
- y: box.y + coordinate(localY, box.height),
15243
+ const prepared = await resolveSetupTapTarget(action, base, scope, timeout);
15244
+ if (prepared.result) return prepared.result;
15245
+ await dispatchSetupTapPoint(prepared.target.point, prepared.target.pointerType, prepared.target.durationMs);
15246
+ return {
15247
+ ...base,
15248
+ ...setupScopeEvidence(scope),
15249
+ ok: true,
15250
+ ...setupTapTargetEvidence(prepared.target),
15100
15251
  };
15101
- const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
15102
- const pointerType = String(action.pointer_type || action.pointerType || "touch").trim().toLowerCase();
15103
- if (pointerType === "touch" || pointerType === "pen") {
15104
- const client = await page.context().newCDPSession(page);
15105
- try {
15106
- if (pointerType === "touch") {
15107
- const touchPoint = {
15108
- x: point.x,
15109
- y: point.y,
15110
- radiusX: 1,
15111
- radiusY: 1,
15112
- force: 1,
15113
- id: 11,
15114
- };
15115
- await client.send("Input.dispatchTouchEvent", {
15116
- type: "touchStart",
15117
- touchPoints: [touchPoint],
15118
- });
15119
- if (durationMs) await page.waitForTimeout(durationMs);
15120
- await client.send("Input.dispatchTouchEvent", {
15121
- type: "touchEnd",
15122
- touchPoints: [],
15123
- });
15124
- } else {
15125
- await client.send("Input.dispatchMouseEvent", {
15126
- type: "mousePressed",
15127
- x: point.x,
15128
- y: point.y,
15129
- button: "left",
15130
- buttons: 1,
15131
- clickCount: 1,
15132
- pointerType: "pen",
15133
- });
15134
- if (durationMs) await page.waitForTimeout(durationMs);
15135
- await client.send("Input.dispatchMouseEvent", {
15136
- type: "mouseReleased",
15137
- x: point.x,
15138
- y: point.y,
15139
- button: "left",
15140
- buttons: 0,
15141
- clickCount: 1,
15142
- pointerType: "pen",
15143
- });
15144
- }
15145
- } finally {
15146
- await client.detach().catch(() => {});
15252
+ }
15253
+ if (type === "tap_until") {
15254
+ const untilPath = String(action.until_path || action.untilPath || action.until_state_path || action.untilStatePath || action.until_window_path || action.untilWindowPath || action.until || "");
15255
+ const hasUntilExpected = setupHasOwn(action, "until_expected_value")
15256
+ || setupHasOwn(action, "untilExpectedValue")
15257
+ || setupHasOwn(action, "until_expected")
15258
+ || setupHasOwn(action, "untilExpected")
15259
+ || setupHasOwn(action, "until_value")
15260
+ || setupHasOwn(action, "untilValue")
15261
+ || setupHasOwn(action, "expected_value")
15262
+ || setupHasOwn(action, "expectedValue")
15263
+ || setupHasOwn(action, "expected");
15264
+ const untilExpected = setupHasOwn(action, "until_expected_value")
15265
+ ? action.until_expected_value
15266
+ : setupHasOwn(action, "untilExpectedValue")
15267
+ ? action.untilExpectedValue
15268
+ : setupHasOwn(action, "until_expected")
15269
+ ? action.until_expected
15270
+ : setupHasOwn(action, "untilExpected")
15271
+ ? action.untilExpected
15272
+ : setupHasOwn(action, "until_value")
15273
+ ? action.until_value
15274
+ : setupHasOwn(action, "untilValue")
15275
+ ? action.untilValue
15276
+ : setupHasOwn(action, "expected_value")
15277
+ ? action.expected_value
15278
+ : setupHasOwn(action, "expectedValue")
15279
+ ? action.expectedValue
15280
+ : action.expected;
15281
+ if (!untilPath) return { ...base, reason: "missing_until_path" };
15282
+ if (!hasUntilExpected) return { ...base, until_path: untilPath, reason: "missing_until_expected_value" };
15283
+ const maxTaps = Math.min(100, Math.max(1, Math.floor(setupNumber(action.max_taps ?? action.maxTaps ?? action.tap_limit ?? action.tapLimit ?? action.max_calls ?? action.maxCalls ?? action.max_attempts ?? action.maxAttempts ?? action.attempts, 1) || 1)));
15284
+ const intervalMs = Math.min(5000, Math.max(0, Math.floor(setupNumber(action.interval_ms ?? action.intervalMs ?? action.poll_ms ?? action.pollMs ?? action.tap_interval_ms ?? action.tapIntervalMs, 100) || 0)));
15285
+ const scope = await setupActionScope(action, timeout);
15286
+ if (!scope.ok) return setupScopeFailure(base, scope);
15287
+ const prepared = await resolveSetupTapTarget(action, base, scope, timeout);
15288
+ if (prepared.result) return prepared.result;
15289
+ const startedAt = Date.now();
15290
+ let tapCount = 0;
15291
+ let lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
15292
+ const targetEvidence = setupTapTargetEvidence(prepared.target);
15293
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
15294
+ return {
15295
+ ...base,
15296
+ ...setupScopeEvidence(scope),
15297
+ ok: true,
15298
+ ...targetEvidence,
15299
+ until_path: untilPath,
15300
+ until_value: setupJsonValue(lastPredicateResult.value),
15301
+ until_expected_value: setupJsonValue(untilExpected),
15302
+ tap_count: tapCount,
15303
+ max_taps: maxTaps,
15304
+ max_calls: maxTaps,
15305
+ interval_ms: intervalMs,
15306
+ timeout_ms: timeout,
15307
+ };
15308
+ }
15309
+ while (tapCount < maxTaps && Date.now() - startedAt <= timeout) {
15310
+ await dispatchSetupTapPoint(prepared.target.point, prepared.target.pointerType, prepared.target.durationMs);
15311
+ tapCount += 1;
15312
+ lastPredicateResult = await setupReadWindowValue(scope.context, untilPath);
15313
+ if (lastPredicateResult.ok && setupValuesEqual(lastPredicateResult.value, untilExpected)) {
15314
+ return {
15315
+ ...base,
15316
+ ...setupScopeEvidence(scope),
15317
+ ok: true,
15318
+ ...targetEvidence,
15319
+ until_path: untilPath,
15320
+ until_value: setupJsonValue(lastPredicateResult.value),
15321
+ until_expected_value: setupJsonValue(untilExpected),
15322
+ tap_count: tapCount,
15323
+ max_taps: maxTaps,
15324
+ max_calls: maxTaps,
15325
+ interval_ms: intervalMs,
15326
+ timeout_ms: timeout,
15327
+ };
15147
15328
  }
15148
- } else {
15149
- await page.mouse.click(point.x, point.y);
15329
+ if (tapCount < maxTaps && intervalMs) await page.waitForTimeout(intervalMs);
15150
15330
  }
15151
15331
  return {
15152
15332
  ...base,
15153
15333
  ...setupScopeEvidence(scope),
15154
- ok: true,
15155
- count,
15156
- target_index: targetIndex,
15157
- coordinate_mode: hasTapPosition ? mode : undefined,
15158
- x: hasTapPosition ? fromX : undefined,
15159
- y: hasTapPosition ? fromY : undefined,
15160
- pointer_type: pointerType,
15161
- input_dispatch: pointerType === "touch" || pointerType === "pen" ? "cdp" : "playwright_mouse",
15162
- duration_ms: durationMs || undefined,
15334
+ ...targetEvidence,
15335
+ until_path: untilPath,
15336
+ until_value: setupJsonValue(lastPredicateResult?.value),
15337
+ until_expected_value: setupJsonValue(untilExpected),
15338
+ tap_count: tapCount,
15339
+ max_taps: maxTaps,
15340
+ max_calls: maxTaps,
15341
+ interval_ms: intervalMs,
15342
+ timeout_ms: timeout,
15343
+ reason: Date.now() - startedAt > timeout ? "timeout" : "until_condition_not_met",
15344
+ missing_part: lastPredicateResult?.missing_part || undefined,
15163
15345
  };
15164
15346
  }
15165
15347
  if (type === "drag") {
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ import {
62
62
  resolveRiddleProofProfileTimeoutSec,
63
63
  slugifyRiddleProofProfileName,
64
64
  summarizeRiddleProofProfileResult
65
- } from "./chunk-EYLIXKE2.js";
65
+ } from "./chunk-DL6UB4N6.js";
66
66
  import {
67
67
  DEFAULT_RIDDLE_API_BASE_URL,
68
68
  DEFAULT_RIDDLE_API_KEY_FILE,