@riddledc/riddle-proof 0.7.173 → 0.7.174

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/README.md CHANGED
@@ -397,7 +397,7 @@ when body matching overrides sequence order.
397
397
  `target.setup_actions` is optional. Use it when the meaningful proof surface
398
398
  appears only after a picker, tab, login stub, storage seed, form fill,
399
399
  transport control, or other bounded interaction. Supported setup actions are
400
- `click`, `drag`, `press`, `fill`, `set_input_value`, `set_range_value`,
400
+ `click`, `tap`, `drag`, `press`, `fill`, `set_input_value`, `set_range_value`,
401
401
  `deterministic_runtime`, `canvas_signature`, `assert_text_visible`, `assert_text_absent`,
402
402
  `assert_selector_count`, `assert_window_value`, `assert_window_number`,
403
403
  `local_storage`, `session_storage`, `clear_storage`, `clear_console`,
@@ -416,6 +416,12 @@ Use `click_count` / `clickCount` / `clicks` from 1 to 10 on a single `click`
416
416
  action for atomic double-click or double-submit contracts where modeling the
417
417
  interaction as repeated setup actions would incorrectly require the target to
418
418
  remain in the DOM after the first click.
419
+ Use `tap` for touch-first controls, especially canvas regions where a mobile
420
+ tap should produce trusted touch events and the browser's synthesized click.
421
+ It requires `selector`, defaults to a touch tap at the target center, and
422
+ accepts `x` / `y` or `from_x` / `from_y` plus `coordinate_mode: "ratio"` for
423
+ element-relative coordinates. Set `pointer_type` to `mouse`, `touch`, or `pen`
424
+ when the proof must distinguish input modality.
419
425
  Use `set_range_value` for HTML range inputs and React-controlled sliders. It
420
426
  accepts aliases such as `set-slider-value`, requires `selector` plus `value`,
421
427
  uses the native input value setter, dispatches bubbling `input` and `change`
@@ -44,6 +44,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
44
44
  ];
45
45
  var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
46
46
  "click",
47
+ "tap",
47
48
  "drag",
48
49
  "press",
49
50
  "fill",
@@ -595,6 +596,21 @@ function profileSetupDragReceipts(results) {
595
596
  reason: result.reason ?? result.error ?? null
596
597
  }));
597
598
  }
599
+ function profileSetupTapReceipts(results) {
600
+ return results.filter((result) => profileSetupResultAction(result) === "tap").map((result) => ({
601
+ ordinal: result.ordinal ?? null,
602
+ ok: result.ok !== false,
603
+ selector: result.selector ?? null,
604
+ frame_selector: result.frame_selector ?? null,
605
+ pointer_type: result.pointer_type ?? null,
606
+ input_dispatch: result.input_dispatch ?? null,
607
+ coordinate_mode: result.coordinate_mode ?? null,
608
+ x: result.x ?? null,
609
+ y: result.y ?? null,
610
+ duration_ms: result.duration_ms ?? null,
611
+ reason: result.reason ?? result.error ?? null
612
+ }));
613
+ }
598
614
  function profileSetupCanvasSignatureReceipts(results) {
599
615
  return results.filter((result) => profileSetupResultAction(result) === "canvas_signature").map((result) => ({
600
616
  ordinal: result.ordinal ?? null,
@@ -756,6 +772,8 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
756
772
  const sampledRangeValueReceipts = sampleProfileSetupSummaryItems(rangeValueReceipts, 8);
757
773
  const dragReceipts = profileSetupDragReceipts(results);
758
774
  const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
775
+ const tapReceipts = profileSetupTapReceipts(results);
776
+ const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
759
777
  const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
760
778
  const sampledCanvasSignatureReceipts = sampleProfileSetupSummaryItems(canvasSignatureReceipts, 8);
761
779
  const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
@@ -820,6 +838,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
820
838
  drag_total: dragReceipts.length,
821
839
  drag_truncated: dragReceipts.length > sampledDragReceipts.length,
822
840
  drag: sampledDragReceipts,
841
+ tap_total: tapReceipts.length,
842
+ tap_truncated: tapReceipts.length > sampledTapReceipts.length,
843
+ tap: sampledTapReceipts,
823
844
  canvas_signature_total: canvasSignatureReceipts.length,
824
845
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
825
846
  canvas_signature: sampledCanvasSignatureReceipts,
@@ -876,7 +897,7 @@ function isSupportedCheckType(value) {
876
897
  }
877
898
  function normalizeSetupActionType(value, index) {
878
899
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
879
- 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 === "keyboard_press" || normalizedInput === "key_press" ? "press" : 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;
900
+ 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 === "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;
880
901
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
881
902
  return normalized;
882
903
  }
@@ -958,8 +979,8 @@ function normalizeSetupActionCoordinateMode(value, index) {
958
979
  }
959
980
  function normalizeSetupActionPointerType(value, type, index) {
960
981
  if (value === void 0 || value === null || value === "") return void 0;
961
- if (type !== "drag") {
962
- throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag actions.`);
982
+ if (type !== "drag" && type !== "tap") {
983
+ throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap actions.`);
963
984
  }
964
985
  const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
965
986
  if (normalized === "mouse") return "mouse";
@@ -1038,11 +1059,11 @@ function normalizeSetupAction(input, index) {
1038
1059
  if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
1039
1060
  throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
1040
1061
  }
1041
- if ((type === "click" || 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) {
1062
+ 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) {
1042
1063
  throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
1043
1064
  }
1044
- const fromX = type === "click" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
1045
- const fromY = type === "click" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
1065
+ const fromX = type === "click" || type === "tap" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
1066
+ const fromY = type === "click" || type === "tap" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
1046
1067
  const toX = numberValue(valueFromOwn(input, "to_x", "toX", "end_x", "endX", "x2"));
1047
1068
  const toY = numberValue(valueFromOwn(input, "to_y", "toY", "end_y", "endY", "y2"));
1048
1069
  const coordinateMode = normalizeSetupActionCoordinateMode(valueFromOwn(input, "coordinate_mode", "coordinateMode", "coords", "units"), index);
@@ -1062,6 +1083,21 @@ function normalizeSetupAction(input, index) {
1062
1083
  }
1063
1084
  }
1064
1085
  }
1086
+ if (type === "tap") {
1087
+ const hasTapCoordinate = fromX !== void 0 || fromY !== void 0;
1088
+ if (hasTapCoordinate && (fromX === void 0 || fromY === void 0)) {
1089
+ throw new Error(`target.setup_actions[${index}] tap coordinates require both x and y.`);
1090
+ }
1091
+ if (hasTapCoordinate && fromX !== void 0 && fromY !== void 0) {
1092
+ const tapCoordinates = [fromX, fromY];
1093
+ if (coordinateMode === "ratio" && tapCoordinates.some((value2) => value2 < 0 || value2 > 1)) {
1094
+ throw new Error(`target.setup_actions[${index}] tap ratio coordinates must be between 0 and 1.`);
1095
+ }
1096
+ if ((coordinateMode === void 0 || coordinateMode === "pixels") && tapCoordinates.some((value2) => value2 < 0)) {
1097
+ throw new Error(`target.setup_actions[${index}] tap pixel coordinates must be non-negative.`);
1098
+ }
1099
+ }
1100
+ }
1065
1101
  if (type === "drag") {
1066
1102
  if (fromX === void 0 || fromY === void 0 || toX === void 0 || toY === void 0) {
1067
1103
  throw new Error(`target.setup_actions[${index}] drag requires from_x, from_y, to_x, and to_y.`);
@@ -6057,6 +6093,96 @@ async function executeSetupAction(action, ordinal, viewport) {
6057
6093
  await waitForAnyVisibleSelector(scope.context, action.selector, timeout);
6058
6094
  return { ...base, ...setupScopeEvidence(scope), ok: true, timeout_ms: timeout };
6059
6095
  }
6096
+ if (type === "tap") {
6097
+ const scope = await setupActionScope(action, timeout);
6098
+ if (!scope.ok) return setupScopeFailure(base, scope);
6099
+ const locator = scope.context.locator(action.selector);
6100
+ const count = await locator.count();
6101
+ if (!count) return { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count };
6102
+ const targetIndex = Number.isInteger(action.index) ? action.index : 0;
6103
+ if (targetIndex < 0 || targetIndex >= count) return { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex };
6104
+ const target = locator.nth(targetIndex);
6105
+ await target.waitFor({ state: "visible", timeout });
6106
+ const box = await target.boundingBox();
6107
+ if (!box) return { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex };
6108
+ const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
6109
+ const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
6110
+ const hasTapPosition = fromX !== undefined || fromY !== undefined;
6111
+ if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex };
6112
+ const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
6113
+ if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex };
6114
+ if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex };
6115
+ const coordinate = (value, size) => mode === "ratio" ? value * size : value;
6116
+ const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
6117
+ const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
6118
+ const point = {
6119
+ x: box.x + coordinate(localX, box.width),
6120
+ y: box.y + coordinate(localY, box.height),
6121
+ };
6122
+ const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
6123
+ const pointerType = String(action.pointer_type || action.pointerType || "touch").trim().toLowerCase();
6124
+ if (pointerType === "touch" || pointerType === "pen") {
6125
+ const client = await page.context().newCDPSession(page);
6126
+ try {
6127
+ if (pointerType === "touch") {
6128
+ const touchPoint = {
6129
+ x: point.x,
6130
+ y: point.y,
6131
+ radiusX: 1,
6132
+ radiusY: 1,
6133
+ force: 1,
6134
+ id: 11,
6135
+ };
6136
+ await client.send("Input.dispatchTouchEvent", {
6137
+ type: "touchStart",
6138
+ touchPoints: [touchPoint],
6139
+ });
6140
+ if (durationMs) await page.waitForTimeout(durationMs);
6141
+ await client.send("Input.dispatchTouchEvent", {
6142
+ type: "touchEnd",
6143
+ touchPoints: [],
6144
+ });
6145
+ } else {
6146
+ await client.send("Input.dispatchMouseEvent", {
6147
+ type: "mousePressed",
6148
+ x: point.x,
6149
+ y: point.y,
6150
+ button: "left",
6151
+ buttons: 1,
6152
+ clickCount: 1,
6153
+ pointerType: "pen",
6154
+ });
6155
+ if (durationMs) await page.waitForTimeout(durationMs);
6156
+ await client.send("Input.dispatchMouseEvent", {
6157
+ type: "mouseReleased",
6158
+ x: point.x,
6159
+ y: point.y,
6160
+ button: "left",
6161
+ buttons: 0,
6162
+ clickCount: 1,
6163
+ pointerType: "pen",
6164
+ });
6165
+ }
6166
+ } finally {
6167
+ await client.detach().catch(() => {});
6168
+ }
6169
+ } else {
6170
+ await page.mouse.click(point.x, point.y);
6171
+ }
6172
+ return {
6173
+ ...base,
6174
+ ...setupScopeEvidence(scope),
6175
+ ok: true,
6176
+ count,
6177
+ target_index: targetIndex,
6178
+ coordinate_mode: hasTapPosition ? mode : undefined,
6179
+ x: hasTapPosition ? fromX : undefined,
6180
+ y: hasTapPosition ? fromY : undefined,
6181
+ pointer_type: pointerType,
6182
+ input_dispatch: pointerType === "touch" || pointerType === "pen" ? "cdp" : "playwright_mouse",
6183
+ duration_ms: durationMs || undefined,
6184
+ };
6185
+ }
6060
6186
  if (type === "drag") {
6061
6187
  const scope = await setupActionScope(action, timeout);
6062
6188
  if (!scope.ok) return setupScopeFailure(base, scope);
package/dist/cli.cjs CHANGED
@@ -7001,6 +7001,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
7001
7001
  ];
7002
7002
  var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
7003
7003
  "click",
7004
+ "tap",
7004
7005
  "drag",
7005
7006
  "press",
7006
7007
  "fill",
@@ -7552,6 +7553,21 @@ function profileSetupDragReceipts(results) {
7552
7553
  reason: result.reason ?? result.error ?? null
7553
7554
  }));
7554
7555
  }
7556
+ function profileSetupTapReceipts(results) {
7557
+ return results.filter((result) => profileSetupResultAction(result) === "tap").map((result) => ({
7558
+ ordinal: result.ordinal ?? null,
7559
+ ok: result.ok !== false,
7560
+ selector: result.selector ?? null,
7561
+ frame_selector: result.frame_selector ?? null,
7562
+ pointer_type: result.pointer_type ?? null,
7563
+ input_dispatch: result.input_dispatch ?? null,
7564
+ coordinate_mode: result.coordinate_mode ?? null,
7565
+ x: result.x ?? null,
7566
+ y: result.y ?? null,
7567
+ duration_ms: result.duration_ms ?? null,
7568
+ reason: result.reason ?? result.error ?? null
7569
+ }));
7570
+ }
7555
7571
  function profileSetupCanvasSignatureReceipts(results) {
7556
7572
  return results.filter((result) => profileSetupResultAction(result) === "canvas_signature").map((result) => ({
7557
7573
  ordinal: result.ordinal ?? null,
@@ -7713,6 +7729,8 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
7713
7729
  const sampledRangeValueReceipts = sampleProfileSetupSummaryItems(rangeValueReceipts, 8);
7714
7730
  const dragReceipts = profileSetupDragReceipts(results);
7715
7731
  const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
7732
+ const tapReceipts = profileSetupTapReceipts(results);
7733
+ const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
7716
7734
  const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
7717
7735
  const sampledCanvasSignatureReceipts = sampleProfileSetupSummaryItems(canvasSignatureReceipts, 8);
7718
7736
  const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
@@ -7777,6 +7795,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
7777
7795
  drag_total: dragReceipts.length,
7778
7796
  drag_truncated: dragReceipts.length > sampledDragReceipts.length,
7779
7797
  drag: sampledDragReceipts,
7798
+ tap_total: tapReceipts.length,
7799
+ tap_truncated: tapReceipts.length > sampledTapReceipts.length,
7800
+ tap: sampledTapReceipts,
7780
7801
  canvas_signature_total: canvasSignatureReceipts.length,
7781
7802
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
7782
7803
  canvas_signature: sampledCanvasSignatureReceipts,
@@ -7833,7 +7854,7 @@ function isSupportedCheckType(value) {
7833
7854
  }
7834
7855
  function normalizeSetupActionType(value, index) {
7835
7856
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
7836
- 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 === "keyboard_press" || normalizedInput === "key_press" ? "press" : 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;
7857
+ 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 === "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;
7837
7858
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
7838
7859
  return normalized;
7839
7860
  }
@@ -7915,8 +7936,8 @@ function normalizeSetupActionCoordinateMode(value, index) {
7915
7936
  }
7916
7937
  function normalizeSetupActionPointerType(value, type, index) {
7917
7938
  if (value === void 0 || value === null || value === "") return void 0;
7918
- if (type !== "drag") {
7919
- throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag actions.`);
7939
+ if (type !== "drag" && type !== "tap") {
7940
+ throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap actions.`);
7920
7941
  }
7921
7942
  const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
7922
7943
  if (normalized === "mouse") return "mouse";
@@ -7995,11 +8016,11 @@ function normalizeSetupAction(input, index) {
7995
8016
  if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
7996
8017
  throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
7997
8018
  }
7998
- if ((type === "click" || 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) {
8019
+ 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) {
7999
8020
  throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
8000
8021
  }
8001
- const fromX = type === "click" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
8002
- const fromY = type === "click" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
8022
+ const fromX = type === "click" || type === "tap" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
8023
+ const fromY = type === "click" || type === "tap" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
8003
8024
  const toX = numberValue(valueFromOwn(input, "to_x", "toX", "end_x", "endX", "x2"));
8004
8025
  const toY = numberValue(valueFromOwn(input, "to_y", "toY", "end_y", "endY", "y2"));
8005
8026
  const coordinateMode = normalizeSetupActionCoordinateMode(valueFromOwn(input, "coordinate_mode", "coordinateMode", "coords", "units"), index);
@@ -8019,6 +8040,21 @@ function normalizeSetupAction(input, index) {
8019
8040
  }
8020
8041
  }
8021
8042
  }
8043
+ if (type === "tap") {
8044
+ const hasTapCoordinate = fromX !== void 0 || fromY !== void 0;
8045
+ if (hasTapCoordinate && (fromX === void 0 || fromY === void 0)) {
8046
+ throw new Error(`target.setup_actions[${index}] tap coordinates require both x and y.`);
8047
+ }
8048
+ if (hasTapCoordinate && fromX !== void 0 && fromY !== void 0) {
8049
+ const tapCoordinates = [fromX, fromY];
8050
+ if (coordinateMode === "ratio" && tapCoordinates.some((value2) => value2 < 0 || value2 > 1)) {
8051
+ throw new Error(`target.setup_actions[${index}] tap ratio coordinates must be between 0 and 1.`);
8052
+ }
8053
+ if ((coordinateMode === void 0 || coordinateMode === "pixels") && tapCoordinates.some((value2) => value2 < 0)) {
8054
+ throw new Error(`target.setup_actions[${index}] tap pixel coordinates must be non-negative.`);
8055
+ }
8056
+ }
8057
+ }
8022
8058
  if (type === "drag") {
8023
8059
  if (fromX === void 0 || fromY === void 0 || toX === void 0 || toY === void 0) {
8024
8060
  throw new Error(`target.setup_actions[${index}] drag requires from_x, from_y, to_x, and to_y.`);
@@ -12998,6 +13034,96 @@ async function executeSetupAction(action, ordinal, viewport) {
12998
13034
  await waitForAnyVisibleSelector(scope.context, action.selector, timeout);
12999
13035
  return { ...base, ...setupScopeEvidence(scope), ok: true, timeout_ms: timeout };
13000
13036
  }
13037
+ if (type === "tap") {
13038
+ const scope = await setupActionScope(action, timeout);
13039
+ if (!scope.ok) return setupScopeFailure(base, scope);
13040
+ const locator = scope.context.locator(action.selector);
13041
+ const count = await locator.count();
13042
+ if (!count) return { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count };
13043
+ const targetIndex = Number.isInteger(action.index) ? action.index : 0;
13044
+ if (targetIndex < 0 || targetIndex >= count) return { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex };
13045
+ const target = locator.nth(targetIndex);
13046
+ await target.waitFor({ state: "visible", timeout });
13047
+ const box = await target.boundingBox();
13048
+ if (!box) return { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex };
13049
+ const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
13050
+ const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
13051
+ const hasTapPosition = fromX !== undefined || fromY !== undefined;
13052
+ if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex };
13053
+ const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
13054
+ if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex };
13055
+ if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex };
13056
+ const coordinate = (value, size) => mode === "ratio" ? value * size : value;
13057
+ const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
13058
+ const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
13059
+ const point = {
13060
+ x: box.x + coordinate(localX, box.width),
13061
+ y: box.y + coordinate(localY, box.height),
13062
+ };
13063
+ const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
13064
+ const pointerType = String(action.pointer_type || action.pointerType || "touch").trim().toLowerCase();
13065
+ if (pointerType === "touch" || pointerType === "pen") {
13066
+ const client = await page.context().newCDPSession(page);
13067
+ try {
13068
+ if (pointerType === "touch") {
13069
+ const touchPoint = {
13070
+ x: point.x,
13071
+ y: point.y,
13072
+ radiusX: 1,
13073
+ radiusY: 1,
13074
+ force: 1,
13075
+ id: 11,
13076
+ };
13077
+ await client.send("Input.dispatchTouchEvent", {
13078
+ type: "touchStart",
13079
+ touchPoints: [touchPoint],
13080
+ });
13081
+ if (durationMs) await page.waitForTimeout(durationMs);
13082
+ await client.send("Input.dispatchTouchEvent", {
13083
+ type: "touchEnd",
13084
+ touchPoints: [],
13085
+ });
13086
+ } else {
13087
+ await client.send("Input.dispatchMouseEvent", {
13088
+ type: "mousePressed",
13089
+ x: point.x,
13090
+ y: point.y,
13091
+ button: "left",
13092
+ buttons: 1,
13093
+ clickCount: 1,
13094
+ pointerType: "pen",
13095
+ });
13096
+ if (durationMs) await page.waitForTimeout(durationMs);
13097
+ await client.send("Input.dispatchMouseEvent", {
13098
+ type: "mouseReleased",
13099
+ x: point.x,
13100
+ y: point.y,
13101
+ button: "left",
13102
+ buttons: 0,
13103
+ clickCount: 1,
13104
+ pointerType: "pen",
13105
+ });
13106
+ }
13107
+ } finally {
13108
+ await client.detach().catch(() => {});
13109
+ }
13110
+ } else {
13111
+ await page.mouse.click(point.x, point.y);
13112
+ }
13113
+ return {
13114
+ ...base,
13115
+ ...setupScopeEvidence(scope),
13116
+ ok: true,
13117
+ count,
13118
+ target_index: targetIndex,
13119
+ coordinate_mode: hasTapPosition ? mode : undefined,
13120
+ x: hasTapPosition ? fromX : undefined,
13121
+ y: hasTapPosition ? fromY : undefined,
13122
+ pointer_type: pointerType,
13123
+ input_dispatch: pointerType === "touch" || pointerType === "pen" ? "cdp" : "playwright_mouse",
13124
+ duration_ms: durationMs || undefined,
13125
+ };
13126
+ }
13001
13127
  if (type === "drag") {
13002
13128
  const scope = await setupActionScope(action, timeout);
13003
13129
  if (!scope.ok) return setupScopeFailure(base, scope);
@@ -16279,6 +16405,7 @@ function profileSetupSummaryMarkdown(result) {
16279
16405
  const windowCallUntilCallTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.window_call_until_call_total) || 0), 0);
16280
16406
  const rangeValueTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.set_range_value_total) || 0), 0);
16281
16407
  const dragTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.drag_total) || 0), 0);
16408
+ const tapTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.tap_total) || 0), 0);
16282
16409
  const canvasSignatureTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.canvas_signature_total) || 0), 0);
16283
16410
  const failedTotal = viewports.reduce((sum, viewport) => sum + (Array.isArray(viewport.failed) ? viewport.failed.length : 0), 0);
16284
16411
  const lines = [
@@ -16311,6 +16438,9 @@ function profileSetupSummaryMarkdown(result) {
16311
16438
  if (dragTotal) {
16312
16439
  lines.push(`- drag: ${dragTotal} action(s)`);
16313
16440
  }
16441
+ if (tapTotal) {
16442
+ lines.push(`- tap: ${tapTotal} action(s)`);
16443
+ }
16314
16444
  if (canvasSignatureTotal) {
16315
16445
  lines.push(`- canvas_signature: ${canvasSignatureTotal} action(s)`);
16316
16446
  }
@@ -16333,9 +16463,10 @@ function profileSetupSummaryMarkdown(result) {
16333
16463
  const windowCallUntilCalls = cliFiniteNumber(viewport.window_call_until_call_total) || 0;
16334
16464
  const rangeValueActions = cliFiniteNumber(viewport.set_range_value_total) || 0;
16335
16465
  const dragActions = cliFiniteNumber(viewport.drag_total) || 0;
16466
+ const tapActions = cliFiniteNumber(viewport.tap_total) || 0;
16336
16467
  const canvasSignatureActions = cliFiniteNumber(viewport.canvas_signature_total) || 0;
16337
16468
  const observedPath = cliString(viewport.observed_path);
16338
- 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)` : ""}${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}` : ""}`);
16469
+ 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)` : ""}${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}` : ""}`);
16339
16470
  }
16340
16471
  const clickSequenceGroups = viewports.map((viewport) => {
16341
16472
  const name = cliString(viewport.name) || "viewport";
@@ -16381,6 +16512,27 @@ function profileSetupSummaryMarkdown(result) {
16381
16512
  lines.push(`- ${name} drag: ${ok}, ${markdownInlineCode(selector)}${pointerType ? ` ${markdownInlineCode(pointerType)}` : ""}${inputDispatch ? ` via ${markdownInlineCode(inputDispatch)}` : ""}${coordinateText}${steps === void 0 ? "" : `, steps ${steps}`}${durationMs === void 0 ? "" : `, duration ${durationMs}ms`}${reason ? `, reason ${markdownInlineCode(reason, 100)}` : ""}`);
16382
16513
  }
16383
16514
  if (dragDetails.length > sampledDragDetails.length) lines.push(`- ${dragDetails.length - sampledDragDetails.length} additional drag receipt(s) omitted.`);
16515
+ const tapGroups = viewports.map((viewport) => {
16516
+ const name = cliString(viewport.name) || "viewport";
16517
+ const receipts = Array.isArray(viewport.tap) ? viewport.tap.map(cliRecord).filter((item) => Boolean(item)) : [];
16518
+ return receipts.map((receipt) => ({ name, receipt }));
16519
+ });
16520
+ const tapDetails = tapGroups.flat();
16521
+ const sampledTapDetails = balancedSetupReceiptDetails(tapGroups, 12);
16522
+ for (const { name, receipt } of sampledTapDetails) {
16523
+ const selector = cliString(receipt.selector) || "target";
16524
+ const pointerType = cliString(receipt.pointer_type);
16525
+ const inputDispatch = cliString(receipt.input_dispatch);
16526
+ const coordinateMode = cliString(receipt.coordinate_mode);
16527
+ const x = cliValueLabel(receipt.x);
16528
+ const y = cliValueLabel(receipt.y);
16529
+ const durationMs = cliFiniteNumber(receipt.duration_ms);
16530
+ const ok = receipt.ok === false ? "failed" : "ok";
16531
+ const reason = cliString(receipt.reason);
16532
+ const coordinateText = x && y ? `, ${coordinateMode ? `${coordinateMode} ` : ""}${markdownInlineCode(`${x},${y}`)}` : "";
16533
+ 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)}` : ""}`);
16534
+ }
16535
+ if (tapDetails.length > sampledTapDetails.length) lines.push(`- ${tapDetails.length - sampledTapDetails.length} additional tap receipt(s) omitted.`);
16384
16536
  const canvasSignatureGroups = viewports.map((viewport) => {
16385
16537
  const name = cliString(viewport.name) || "viewport";
16386
16538
  const receipts = Array.isArray(viewport.canvas_signature) ? viewport.canvas_signature.map(cliRecord).filter((item) => Boolean(item)) : [];
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  profileStatusExitCode,
14
14
  resolveRiddleProofProfileTargetUrl,
15
15
  resolveRiddleProofProfileTimeoutSec
16
- } from "./chunk-JIAMASZX.js";
16
+ } from "./chunk-BD4RHTGW.js";
17
17
  import {
18
18
  createRiddleApiClient,
19
19
  isTerminalRiddleJobStatus,
@@ -790,6 +790,7 @@ function profileSetupSummaryMarkdown(result) {
790
790
  const windowCallUntilCallTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.window_call_until_call_total) || 0), 0);
791
791
  const rangeValueTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.set_range_value_total) || 0), 0);
792
792
  const dragTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.drag_total) || 0), 0);
793
+ const tapTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.tap_total) || 0), 0);
793
794
  const canvasSignatureTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.canvas_signature_total) || 0), 0);
794
795
  const failedTotal = viewports.reduce((sum, viewport) => sum + (Array.isArray(viewport.failed) ? viewport.failed.length : 0), 0);
795
796
  const lines = [
@@ -822,6 +823,9 @@ function profileSetupSummaryMarkdown(result) {
822
823
  if (dragTotal) {
823
824
  lines.push(`- drag: ${dragTotal} action(s)`);
824
825
  }
826
+ if (tapTotal) {
827
+ lines.push(`- tap: ${tapTotal} action(s)`);
828
+ }
825
829
  if (canvasSignatureTotal) {
826
830
  lines.push(`- canvas_signature: ${canvasSignatureTotal} action(s)`);
827
831
  }
@@ -844,9 +848,10 @@ function profileSetupSummaryMarkdown(result) {
844
848
  const windowCallUntilCalls = cliFiniteNumber(viewport.window_call_until_call_total) || 0;
845
849
  const rangeValueActions = cliFiniteNumber(viewport.set_range_value_total) || 0;
846
850
  const dragActions = cliFiniteNumber(viewport.drag_total) || 0;
851
+ const tapActions = cliFiniteNumber(viewport.tap_total) || 0;
847
852
  const canvasSignatureActions = cliFiniteNumber(viewport.canvas_signature_total) || 0;
848
853
  const observedPath = cliString(viewport.observed_path);
849
- 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)` : ""}${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}` : ""}`);
854
+ 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)` : ""}${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}` : ""}`);
850
855
  }
851
856
  const clickSequenceGroups = viewports.map((viewport) => {
852
857
  const name = cliString(viewport.name) || "viewport";
@@ -892,6 +897,27 @@ function profileSetupSummaryMarkdown(result) {
892
897
  lines.push(`- ${name} drag: ${ok}, ${markdownInlineCode(selector)}${pointerType ? ` ${markdownInlineCode(pointerType)}` : ""}${inputDispatch ? ` via ${markdownInlineCode(inputDispatch)}` : ""}${coordinateText}${steps === void 0 ? "" : `, steps ${steps}`}${durationMs === void 0 ? "" : `, duration ${durationMs}ms`}${reason ? `, reason ${markdownInlineCode(reason, 100)}` : ""}`);
893
898
  }
894
899
  if (dragDetails.length > sampledDragDetails.length) lines.push(`- ${dragDetails.length - sampledDragDetails.length} additional drag receipt(s) omitted.`);
900
+ const tapGroups = viewports.map((viewport) => {
901
+ const name = cliString(viewport.name) || "viewport";
902
+ const receipts = Array.isArray(viewport.tap) ? viewport.tap.map(cliRecord).filter((item) => Boolean(item)) : [];
903
+ return receipts.map((receipt) => ({ name, receipt }));
904
+ });
905
+ const tapDetails = tapGroups.flat();
906
+ const sampledTapDetails = balancedSetupReceiptDetails(tapGroups, 12);
907
+ for (const { name, receipt } of sampledTapDetails) {
908
+ const selector = cliString(receipt.selector) || "target";
909
+ const pointerType = cliString(receipt.pointer_type);
910
+ const inputDispatch = cliString(receipt.input_dispatch);
911
+ const coordinateMode = cliString(receipt.coordinate_mode);
912
+ const x = cliValueLabel(receipt.x);
913
+ const y = cliValueLabel(receipt.y);
914
+ const durationMs = cliFiniteNumber(receipt.duration_ms);
915
+ const ok = receipt.ok === false ? "failed" : "ok";
916
+ const reason = cliString(receipt.reason);
917
+ const coordinateText = x && y ? `, ${coordinateMode ? `${coordinateMode} ` : ""}${markdownInlineCode(`${x},${y}`)}` : "";
918
+ 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)}` : ""}`);
919
+ }
920
+ if (tapDetails.length > sampledTapDetails.length) lines.push(`- ${tapDetails.length - sampledTapDetails.length} additional tap receipt(s) omitted.`);
895
921
  const canvasSignatureGroups = viewports.map((viewport) => {
896
922
  const name = cliString(viewport.name) || "viewport";
897
923
  const receipts = Array.isArray(viewport.canvas_signature) ? viewport.canvas_signature.map(cliRecord).filter((item) => Boolean(item)) : [];
package/dist/index.cjs CHANGED
@@ -8777,6 +8777,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
8777
8777
  ];
8778
8778
  var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
8779
8779
  "click",
8780
+ "tap",
8780
8781
  "drag",
8781
8782
  "press",
8782
8783
  "fill",
@@ -9328,6 +9329,21 @@ function profileSetupDragReceipts(results) {
9328
9329
  reason: result.reason ?? result.error ?? null
9329
9330
  }));
9330
9331
  }
9332
+ function profileSetupTapReceipts(results) {
9333
+ return results.filter((result) => profileSetupResultAction(result) === "tap").map((result) => ({
9334
+ ordinal: result.ordinal ?? null,
9335
+ ok: result.ok !== false,
9336
+ selector: result.selector ?? null,
9337
+ frame_selector: result.frame_selector ?? null,
9338
+ pointer_type: result.pointer_type ?? null,
9339
+ input_dispatch: result.input_dispatch ?? null,
9340
+ coordinate_mode: result.coordinate_mode ?? null,
9341
+ x: result.x ?? null,
9342
+ y: result.y ?? null,
9343
+ duration_ms: result.duration_ms ?? null,
9344
+ reason: result.reason ?? result.error ?? null
9345
+ }));
9346
+ }
9331
9347
  function profileSetupCanvasSignatureReceipts(results) {
9332
9348
  return results.filter((result) => profileSetupResultAction(result) === "canvas_signature").map((result) => ({
9333
9349
  ordinal: result.ordinal ?? null,
@@ -9489,6 +9505,8 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
9489
9505
  const sampledRangeValueReceipts = sampleProfileSetupSummaryItems(rangeValueReceipts, 8);
9490
9506
  const dragReceipts = profileSetupDragReceipts(results);
9491
9507
  const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
9508
+ const tapReceipts = profileSetupTapReceipts(results);
9509
+ const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
9492
9510
  const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
9493
9511
  const sampledCanvasSignatureReceipts = sampleProfileSetupSummaryItems(canvasSignatureReceipts, 8);
9494
9512
  const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
@@ -9553,6 +9571,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
9553
9571
  drag_total: dragReceipts.length,
9554
9572
  drag_truncated: dragReceipts.length > sampledDragReceipts.length,
9555
9573
  drag: sampledDragReceipts,
9574
+ tap_total: tapReceipts.length,
9575
+ tap_truncated: tapReceipts.length > sampledTapReceipts.length,
9576
+ tap: sampledTapReceipts,
9556
9577
  canvas_signature_total: canvasSignatureReceipts.length,
9557
9578
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
9558
9579
  canvas_signature: sampledCanvasSignatureReceipts,
@@ -9609,7 +9630,7 @@ function isSupportedCheckType(value) {
9609
9630
  }
9610
9631
  function normalizeSetupActionType(value, index) {
9611
9632
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
9612
- 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 === "keyboard_press" || normalizedInput === "key_press" ? "press" : 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;
9633
+ 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 === "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;
9613
9634
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
9614
9635
  return normalized;
9615
9636
  }
@@ -9691,8 +9712,8 @@ function normalizeSetupActionCoordinateMode(value, index) {
9691
9712
  }
9692
9713
  function normalizeSetupActionPointerType(value, type, index) {
9693
9714
  if (value === void 0 || value === null || value === "") return void 0;
9694
- if (type !== "drag") {
9695
- throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag actions.`);
9715
+ if (type !== "drag" && type !== "tap") {
9716
+ throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap actions.`);
9696
9717
  }
9697
9718
  const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
9698
9719
  if (normalized === "mouse") return "mouse";
@@ -9771,11 +9792,11 @@ function normalizeSetupAction(input, index) {
9771
9792
  if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
9772
9793
  throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
9773
9794
  }
9774
- if ((type === "click" || 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) {
9795
+ 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) {
9775
9796
  throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
9776
9797
  }
9777
- const fromX = type === "click" ? numberValue3(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue3(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
9778
- const fromY = type === "click" ? numberValue3(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue3(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
9798
+ 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"));
9799
+ 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"));
9779
9800
  const toX = numberValue3(valueFromOwn(input, "to_x", "toX", "end_x", "endX", "x2"));
9780
9801
  const toY = numberValue3(valueFromOwn(input, "to_y", "toY", "end_y", "endY", "y2"));
9781
9802
  const coordinateMode = normalizeSetupActionCoordinateMode(valueFromOwn(input, "coordinate_mode", "coordinateMode", "coords", "units"), index);
@@ -9795,6 +9816,21 @@ function normalizeSetupAction(input, index) {
9795
9816
  }
9796
9817
  }
9797
9818
  }
9819
+ if (type === "tap") {
9820
+ const hasTapCoordinate = fromX !== void 0 || fromY !== void 0;
9821
+ if (hasTapCoordinate && (fromX === void 0 || fromY === void 0)) {
9822
+ throw new Error(`target.setup_actions[${index}] tap coordinates require both x and y.`);
9823
+ }
9824
+ if (hasTapCoordinate && fromX !== void 0 && fromY !== void 0) {
9825
+ const tapCoordinates = [fromX, fromY];
9826
+ if (coordinateMode === "ratio" && tapCoordinates.some((value2) => value2 < 0 || value2 > 1)) {
9827
+ throw new Error(`target.setup_actions[${index}] tap ratio coordinates must be between 0 and 1.`);
9828
+ }
9829
+ if ((coordinateMode === void 0 || coordinateMode === "pixels") && tapCoordinates.some((value2) => value2 < 0)) {
9830
+ throw new Error(`target.setup_actions[${index}] tap pixel coordinates must be non-negative.`);
9831
+ }
9832
+ }
9833
+ }
9798
9834
  if (type === "drag") {
9799
9835
  if (fromX === void 0 || fromY === void 0 || toX === void 0 || toY === void 0) {
9800
9836
  throw new Error(`target.setup_actions[${index}] drag requires from_x, from_y, to_x, and to_y.`);
@@ -14790,6 +14826,96 @@ async function executeSetupAction(action, ordinal, viewport) {
14790
14826
  await waitForAnyVisibleSelector(scope.context, action.selector, timeout);
14791
14827
  return { ...base, ...setupScopeEvidence(scope), ok: true, timeout_ms: timeout };
14792
14828
  }
14829
+ if (type === "tap") {
14830
+ const scope = await setupActionScope(action, timeout);
14831
+ if (!scope.ok) return setupScopeFailure(base, scope);
14832
+ const locator = scope.context.locator(action.selector);
14833
+ const count = await locator.count();
14834
+ if (!count) return { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count };
14835
+ const targetIndex = Number.isInteger(action.index) ? action.index : 0;
14836
+ if (targetIndex < 0 || targetIndex >= count) return { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex };
14837
+ const target = locator.nth(targetIndex);
14838
+ await target.waitFor({ state: "visible", timeout });
14839
+ const box = await target.boundingBox();
14840
+ if (!box) return { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex };
14841
+ const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
14842
+ const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
14843
+ const hasTapPosition = fromX !== undefined || fromY !== undefined;
14844
+ if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex };
14845
+ const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
14846
+ if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex };
14847
+ if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex };
14848
+ const coordinate = (value, size) => mode === "ratio" ? value * size : value;
14849
+ const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
14850
+ const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
14851
+ const point = {
14852
+ x: box.x + coordinate(localX, box.width),
14853
+ y: box.y + coordinate(localY, box.height),
14854
+ };
14855
+ const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
14856
+ const pointerType = String(action.pointer_type || action.pointerType || "touch").trim().toLowerCase();
14857
+ if (pointerType === "touch" || pointerType === "pen") {
14858
+ const client = await page.context().newCDPSession(page);
14859
+ try {
14860
+ if (pointerType === "touch") {
14861
+ const touchPoint = {
14862
+ x: point.x,
14863
+ y: point.y,
14864
+ radiusX: 1,
14865
+ radiusY: 1,
14866
+ force: 1,
14867
+ id: 11,
14868
+ };
14869
+ await client.send("Input.dispatchTouchEvent", {
14870
+ type: "touchStart",
14871
+ touchPoints: [touchPoint],
14872
+ });
14873
+ if (durationMs) await page.waitForTimeout(durationMs);
14874
+ await client.send("Input.dispatchTouchEvent", {
14875
+ type: "touchEnd",
14876
+ touchPoints: [],
14877
+ });
14878
+ } else {
14879
+ await client.send("Input.dispatchMouseEvent", {
14880
+ type: "mousePressed",
14881
+ x: point.x,
14882
+ y: point.y,
14883
+ button: "left",
14884
+ buttons: 1,
14885
+ clickCount: 1,
14886
+ pointerType: "pen",
14887
+ });
14888
+ if (durationMs) await page.waitForTimeout(durationMs);
14889
+ await client.send("Input.dispatchMouseEvent", {
14890
+ type: "mouseReleased",
14891
+ x: point.x,
14892
+ y: point.y,
14893
+ button: "left",
14894
+ buttons: 0,
14895
+ clickCount: 1,
14896
+ pointerType: "pen",
14897
+ });
14898
+ }
14899
+ } finally {
14900
+ await client.detach().catch(() => {});
14901
+ }
14902
+ } else {
14903
+ await page.mouse.click(point.x, point.y);
14904
+ }
14905
+ return {
14906
+ ...base,
14907
+ ...setupScopeEvidence(scope),
14908
+ ok: true,
14909
+ count,
14910
+ target_index: targetIndex,
14911
+ coordinate_mode: hasTapPosition ? mode : undefined,
14912
+ x: hasTapPosition ? fromX : undefined,
14913
+ y: hasTapPosition ? fromY : undefined,
14914
+ pointer_type: pointerType,
14915
+ input_dispatch: pointerType === "touch" || pointerType === "pen" ? "cdp" : "playwright_mouse",
14916
+ duration_ms: durationMs || undefined,
14917
+ };
14918
+ }
14793
14919
  if (type === "drag") {
14794
14920
  const scope = await setupActionScope(action, timeout);
14795
14921
  if (!scope.ok) return setupScopeFailure(base, scope);
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ import {
62
62
  resolveRiddleProofProfileTimeoutSec,
63
63
  slugifyRiddleProofProfileName,
64
64
  summarizeRiddleProofProfileResult
65
- } from "./chunk-JIAMASZX.js";
65
+ } from "./chunk-BD4RHTGW.js";
66
66
  import {
67
67
  DEFAULT_RIDDLE_API_BASE_URL,
68
68
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -91,6 +91,7 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
91
91
  ];
92
92
  var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
93
93
  "click",
94
+ "tap",
94
95
  "drag",
95
96
  "press",
96
97
  "fill",
@@ -642,6 +643,21 @@ function profileSetupDragReceipts(results) {
642
643
  reason: result.reason ?? result.error ?? null
643
644
  }));
644
645
  }
646
+ function profileSetupTapReceipts(results) {
647
+ return results.filter((result) => profileSetupResultAction(result) === "tap").map((result) => ({
648
+ ordinal: result.ordinal ?? null,
649
+ ok: result.ok !== false,
650
+ selector: result.selector ?? null,
651
+ frame_selector: result.frame_selector ?? null,
652
+ pointer_type: result.pointer_type ?? null,
653
+ input_dispatch: result.input_dispatch ?? null,
654
+ coordinate_mode: result.coordinate_mode ?? null,
655
+ x: result.x ?? null,
656
+ y: result.y ?? null,
657
+ duration_ms: result.duration_ms ?? null,
658
+ reason: result.reason ?? result.error ?? null
659
+ }));
660
+ }
645
661
  function profileSetupCanvasSignatureReceipts(results) {
646
662
  return results.filter((result) => profileSetupResultAction(result) === "canvas_signature").map((result) => ({
647
663
  ordinal: result.ordinal ?? null,
@@ -803,6 +819,8 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
803
819
  const sampledRangeValueReceipts = sampleProfileSetupSummaryItems(rangeValueReceipts, 8);
804
820
  const dragReceipts = profileSetupDragReceipts(results);
805
821
  const sampledDragReceipts = sampleProfileSetupSummaryItems(dragReceipts, 8);
822
+ const tapReceipts = profileSetupTapReceipts(results);
823
+ const sampledTapReceipts = sampleProfileSetupSummaryItems(tapReceipts, 8);
806
824
  const canvasSignatureReceipts = profileSetupCanvasSignatureReceipts(results);
807
825
  const sampledCanvasSignatureReceipts = sampleProfileSetupSummaryItems(canvasSignatureReceipts, 8);
808
826
  const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
@@ -867,6 +885,9 @@ function profileSetupSummary(viewports, actionCount, expectedActionCountByViewpo
867
885
  drag_total: dragReceipts.length,
868
886
  drag_truncated: dragReceipts.length > sampledDragReceipts.length,
869
887
  drag: sampledDragReceipts,
888
+ tap_total: tapReceipts.length,
889
+ tap_truncated: tapReceipts.length > sampledTapReceipts.length,
890
+ tap: sampledTapReceipts,
870
891
  canvas_signature_total: canvasSignatureReceipts.length,
871
892
  canvas_signature_truncated: canvasSignatureReceipts.length > sampledCanvasSignatureReceipts.length,
872
893
  canvas_signature: sampledCanvasSignatureReceipts,
@@ -923,7 +944,7 @@ function isSupportedCheckType(value) {
923
944
  }
924
945
  function normalizeSetupActionType(value, index) {
925
946
  const normalizedInput = String(value || "").trim().replace(/-/g, "_");
926
- 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 === "keyboard_press" || normalizedInput === "key_press" ? "press" : 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;
947
+ 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 === "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;
927
948
  if (RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES.includes(normalized)) {
928
949
  return normalized;
929
950
  }
@@ -1005,8 +1026,8 @@ function normalizeSetupActionCoordinateMode(value, index) {
1005
1026
  }
1006
1027
  function normalizeSetupActionPointerType(value, type, index) {
1007
1028
  if (value === void 0 || value === null || value === "") return void 0;
1008
- if (type !== "drag") {
1009
- throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag actions.`);
1029
+ if (type !== "drag" && type !== "tap") {
1030
+ throw new Error(`target.setup_actions[${index}].pointer_type is only supported for drag/tap actions.`);
1010
1031
  }
1011
1032
  const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
1012
1033
  if (normalized === "mouse") return "mouse";
@@ -1085,11 +1106,11 @@ function normalizeSetupAction(input, index) {
1085
1106
  if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
1086
1107
  throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
1087
1108
  }
1088
- if ((type === "click" || 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) {
1109
+ 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) {
1089
1110
  throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
1090
1111
  }
1091
- const fromX = type === "click" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
1092
- const fromY = type === "click" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
1112
+ const fromX = type === "click" || type === "tap" ? numberValue(valueFromOwn(input, "from_x", "fromX", "x", "click_x", "clickX", "start_x", "startX", "x1")) : numberValue(valueFromOwn(input, "from_x", "fromX", "start_x", "startX", "x1"));
1113
+ const fromY = type === "click" || type === "tap" ? numberValue(valueFromOwn(input, "from_y", "fromY", "y", "click_y", "clickY", "start_y", "startY", "y1")) : numberValue(valueFromOwn(input, "from_y", "fromY", "start_y", "startY", "y1"));
1093
1114
  const toX = numberValue(valueFromOwn(input, "to_x", "toX", "end_x", "endX", "x2"));
1094
1115
  const toY = numberValue(valueFromOwn(input, "to_y", "toY", "end_y", "endY", "y2"));
1095
1116
  const coordinateMode = normalizeSetupActionCoordinateMode(valueFromOwn(input, "coordinate_mode", "coordinateMode", "coords", "units"), index);
@@ -1109,6 +1130,21 @@ function normalizeSetupAction(input, index) {
1109
1130
  }
1110
1131
  }
1111
1132
  }
1133
+ if (type === "tap") {
1134
+ const hasTapCoordinate = fromX !== void 0 || fromY !== void 0;
1135
+ if (hasTapCoordinate && (fromX === void 0 || fromY === void 0)) {
1136
+ throw new Error(`target.setup_actions[${index}] tap coordinates require both x and y.`);
1137
+ }
1138
+ if (hasTapCoordinate && fromX !== void 0 && fromY !== void 0) {
1139
+ const tapCoordinates = [fromX, fromY];
1140
+ if (coordinateMode === "ratio" && tapCoordinates.some((value2) => value2 < 0 || value2 > 1)) {
1141
+ throw new Error(`target.setup_actions[${index}] tap ratio coordinates must be between 0 and 1.`);
1142
+ }
1143
+ if ((coordinateMode === void 0 || coordinateMode === "pixels") && tapCoordinates.some((value2) => value2 < 0)) {
1144
+ throw new Error(`target.setup_actions[${index}] tap pixel coordinates must be non-negative.`);
1145
+ }
1146
+ }
1147
+ }
1112
1148
  if (type === "drag") {
1113
1149
  if (fromX === void 0 || fromY === void 0 || toX === void 0 || toY === void 0) {
1114
1150
  throw new Error(`target.setup_actions[${index}] drag requires from_x, from_y, to_x, and to_y.`);
@@ -6104,6 +6140,96 @@ async function executeSetupAction(action, ordinal, viewport) {
6104
6140
  await waitForAnyVisibleSelector(scope.context, action.selector, timeout);
6105
6141
  return { ...base, ...setupScopeEvidence(scope), ok: true, timeout_ms: timeout };
6106
6142
  }
6143
+ if (type === "tap") {
6144
+ const scope = await setupActionScope(action, timeout);
6145
+ if (!scope.ok) return setupScopeFailure(base, scope);
6146
+ const locator = scope.context.locator(action.selector);
6147
+ const count = await locator.count();
6148
+ if (!count) return { ...base, ...setupScopeEvidence(scope), reason: "selector_not_found", count };
6149
+ const targetIndex = Number.isInteger(action.index) ? action.index : 0;
6150
+ if (targetIndex < 0 || targetIndex >= count) return { ...base, ...setupScopeEvidence(scope), reason: "index_out_of_range", count, target_index: targetIndex };
6151
+ const target = locator.nth(targetIndex);
6152
+ await target.waitFor({ state: "visible", timeout });
6153
+ const box = await target.boundingBox();
6154
+ if (!box) return { ...base, ...setupScopeEvidence(scope), reason: "bounding_box_unavailable", count, target_index: targetIndex };
6155
+ const fromX = setupFiniteNumber(action.from_x ?? action.fromX ?? action.x ?? action.click_x ?? action.clickX);
6156
+ const fromY = setupFiniteNumber(action.from_y ?? action.fromY ?? action.y ?? action.click_y ?? action.clickY);
6157
+ const hasTapPosition = fromX !== undefined || fromY !== undefined;
6158
+ if (hasTapPosition && (fromX === undefined || fromY === undefined)) return { ...base, ...setupScopeEvidence(scope), reason: "missing_tap_coordinates", count, target_index: targetIndex };
6159
+ const mode = String(action.coordinate_mode || action.coordinateMode || (hasTapPosition ? "pixels" : "ratio")).trim();
6160
+ if (hasTapPosition && mode === "ratio" && [fromX, fromY].some((value) => value < 0 || value > 1)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_ratio_coordinates", count, target_index: targetIndex };
6161
+ if (hasTapPosition && mode !== "ratio" && [fromX, fromY].some((value) => value < 0)) return { ...base, ...setupScopeEvidence(scope), reason: "invalid_pixel_coordinates", count, target_index: targetIndex };
6162
+ const coordinate = (value, size) => mode === "ratio" ? value * size : value;
6163
+ const localX = hasTapPosition && fromX !== undefined ? fromX : 0.5;
6164
+ const localY = hasTapPosition && fromY !== undefined ? fromY : 0.5;
6165
+ const point = {
6166
+ x: box.x + coordinate(localX, box.width),
6167
+ y: box.y + coordinate(localY, box.height),
6168
+ };
6169
+ const durationMs = setupNumber(action.duration_ms ?? action.durationMs, 0);
6170
+ const pointerType = String(action.pointer_type || action.pointerType || "touch").trim().toLowerCase();
6171
+ if (pointerType === "touch" || pointerType === "pen") {
6172
+ const client = await page.context().newCDPSession(page);
6173
+ try {
6174
+ if (pointerType === "touch") {
6175
+ const touchPoint = {
6176
+ x: point.x,
6177
+ y: point.y,
6178
+ radiusX: 1,
6179
+ radiusY: 1,
6180
+ force: 1,
6181
+ id: 11,
6182
+ };
6183
+ await client.send("Input.dispatchTouchEvent", {
6184
+ type: "touchStart",
6185
+ touchPoints: [touchPoint],
6186
+ });
6187
+ if (durationMs) await page.waitForTimeout(durationMs);
6188
+ await client.send("Input.dispatchTouchEvent", {
6189
+ type: "touchEnd",
6190
+ touchPoints: [],
6191
+ });
6192
+ } else {
6193
+ await client.send("Input.dispatchMouseEvent", {
6194
+ type: "mousePressed",
6195
+ x: point.x,
6196
+ y: point.y,
6197
+ button: "left",
6198
+ buttons: 1,
6199
+ clickCount: 1,
6200
+ pointerType: "pen",
6201
+ });
6202
+ if (durationMs) await page.waitForTimeout(durationMs);
6203
+ await client.send("Input.dispatchMouseEvent", {
6204
+ type: "mouseReleased",
6205
+ x: point.x,
6206
+ y: point.y,
6207
+ button: "left",
6208
+ buttons: 0,
6209
+ clickCount: 1,
6210
+ pointerType: "pen",
6211
+ });
6212
+ }
6213
+ } finally {
6214
+ await client.detach().catch(() => {});
6215
+ }
6216
+ } else {
6217
+ await page.mouse.click(point.x, point.y);
6218
+ }
6219
+ return {
6220
+ ...base,
6221
+ ...setupScopeEvidence(scope),
6222
+ ok: true,
6223
+ count,
6224
+ target_index: targetIndex,
6225
+ coordinate_mode: hasTapPosition ? mode : undefined,
6226
+ x: hasTapPosition ? fromX : undefined,
6227
+ y: hasTapPosition ? fromY : undefined,
6228
+ pointer_type: pointerType,
6229
+ input_dispatch: pointerType === "touch" || pointerType === "pen" ? "cdp" : "playwright_mouse",
6230
+ duration_ms: durationMs || undefined,
6231
+ };
6232
+ }
6107
6233
  if (type === "drag") {
6108
6234
  const scope = await setupActionScope(action, timeout);
6109
6235
  if (!scope.ok) return setupScopeFailure(base, scope);
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
5
5
  declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
6
6
  declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
7
7
  declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "observe_within", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
8
- declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "set_range_value", "deterministic_runtime", "canvas_signature", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_eval", "window_call", "window_call_until"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "tap", "drag", "press", "fill", "set_input_value", "set_range_value", "deterministic_runtime", "canvas_signature", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_eval", "window_call", "window_call_until"];
9
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
10
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
11
11
  type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
package/dist/profile.d.ts CHANGED
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
5
5
  declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
6
6
  declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
7
7
  declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "url_search_param_equals", "url_search_param_absent", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "dialog_count_equals", "dialog_accept_count_equals", "dialog_dismiss_count_equals", "selector_text_visible", "selector_text_absent", "selector_text_order", "observe_within", "frame_text_visible", "frame_url_equals", "frame_url_matches", "frame_no_horizontal_overflow", "text_visible", "text_absent", "http_status", "link_status", "artifact_link_status", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors", "no_console_warnings"];
8
- declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag", "press", "fill", "set_input_value", "set_range_value", "deterministic_runtime", "canvas_signature", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_eval", "window_call", "window_call_until"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "tap", "drag", "press", "fill", "set_input_value", "set_range_value", "deterministic_runtime", "canvas_signature", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "assert_window_number", "local_storage", "session_storage", "clear_storage", "clear_console", "dialog_response", "screenshot", "wait", "wait_for_selector", "wait_for_text", "window_eval", "window_call", "window_call_until"];
9
9
  type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
10
10
  type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
11
11
  type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
package/dist/profile.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  resolveRiddleProofProfileTimeoutSec,
24
24
  slugifyRiddleProofProfileName,
25
25
  summarizeRiddleProofProfileResult
26
- } from "./chunk-JIAMASZX.js";
26
+ } from "./chunk-BD4RHTGW.js";
27
27
  export {
28
28
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
29
29
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.173",
3
+ "version": "0.7.174",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",