@riddledc/riddle-proof 0.7.68 → 0.7.70

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
@@ -272,6 +272,10 @@ stable enough for Playwright's default click actionability checks. Use `press`
272
272
  with a Playwright key name, such as `Enter`, `Space`, or `ArrowLeft`,
273
273
  when a route's intended browser control is keyboard-driven; omit `selector` for
274
274
  a page-level key press, or provide `selector` to press against a focused element.
275
+ Use `click_count` / `clickCount` / `clicks` from 1 to 10 on a single `click`
276
+ action for atomic double-click or double-submit contracts where modeling the
277
+ interaction as repeated setup actions would incorrectly require the target to
278
+ remain in the DOM after the first click.
275
279
  Use `drag` for pointer-driven controls such as canvas launch areas, sliders, or
276
280
  drag-to-aim games. Provide `selector`, `from_x`, `from_y`, `to_x`, and `to_y`;
277
281
  coordinates are element-relative pixels by default. Set `coordinate_mode:
@@ -314,7 +318,9 @@ setup screenshots, compact text samples, and failures so setup-heavy clickthroug
314
318
  can be reviewed without reading every raw setup-action result. Long click
315
319
  sequences include `clicked_total` and `clicked_truncated`; the compact `clicked`
316
320
  list keeps the first and last clicked targets so later route switches and reset
317
- actions stay visible.
321
+ actions stay visible. Click actions with `click_count` greater than `1` are
322
+ included in clicked-target evidence and rolled up as `click_count_action_total`
323
+ and `click_count_value_total`.
318
324
 
319
325
  `target.timeout_sec` is optional. Use it for known-heavy profile targets so the
320
326
  profile carries its own hosted Riddle worker budget; an explicit CLI `--timeout`
@@ -231,12 +231,18 @@ function profileSetupSummary(viewports, actionCount) {
231
231
  viewports: viewports.map((viewport) => {
232
232
  const results = viewport.setup_action_results || [];
233
233
  const failed = results.filter((result) => result.ok === false);
234
- const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => ({
235
- ordinal: result.ordinal ?? null,
236
- selector: result.selector ?? null,
237
- frame_selector: result.frame_selector ?? null,
238
- text: compactProfileSetupSummaryText(result.text)
239
- }));
234
+ const successfulClicks = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false);
235
+ const clickCountValues = successfulClicks.map((result) => typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0).filter((value) => value !== void 0);
236
+ const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
237
+ const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0;
238
+ return {
239
+ ordinal: result.ordinal ?? null,
240
+ selector: result.selector ?? null,
241
+ frame_selector: result.frame_selector ?? null,
242
+ text: compactProfileSetupSummaryText(result.text),
243
+ ...clickCount ? { click_count: clickCount } : {}
244
+ };
245
+ });
240
246
  const clicked = sampleProfileSetupSummaryItems(clickedItems, 8);
241
247
  const text_samples = results.filter((result) => result.ok !== false && typeof result.text === "string" && (profileSetupResultAction(result) === "assert_text_visible" || profileSetupResultAction(result) === "assert_text_absent" || profileSetupResultAction(result) === "wait_for_text")).map((result) => ({
242
248
  ordinal: result.ordinal ?? null,
@@ -256,6 +262,8 @@ function profileSetupSummary(viewports, actionCount) {
256
262
  setup_screenshots: profileSetupScreenshotLabels(results),
257
263
  clicked_total: clickedItems.length,
258
264
  clicked_truncated: clickedItems.length > clicked.length,
265
+ click_count_action_total: clickCountValues.length,
266
+ click_count_value_total: clickCountValues.reduce((sum, value) => sum + value, 0),
259
267
  clicked,
260
268
  text_samples,
261
269
  failed: failed.map((result) => ({
@@ -329,6 +337,18 @@ function normalizeSetupActionRepeat(input, index) {
329
337
  }
330
338
  return repeat;
331
339
  }
340
+ function normalizeSetupActionClickCount(input, type, index) {
341
+ const clickCountInput = valueFromOwn(input, "click_count", "clickCount", "clicks");
342
+ if (clickCountInput === void 0) return void 0;
343
+ if (type !== "click") {
344
+ throw new Error(`target.setup_actions[${index}].click_count is only supported for click actions.`);
345
+ }
346
+ const clickCount = numberValue(clickCountInput);
347
+ if (clickCount === void 0 || !Number.isInteger(clickCount) || clickCount < 1 || clickCount > 10) {
348
+ throw new Error(`target.setup_actions[${index}].click_count must be an integer from 1 to 10.`);
349
+ }
350
+ return clickCount;
351
+ }
332
352
  function normalizeSetupActionCoordinateMode(value, index) {
333
353
  if (value === void 0 || value === null || value === "") return void 0;
334
354
  const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
@@ -420,6 +440,7 @@ function normalizeSetupAction(input, index) {
420
440
  frame_selector: frameSelector,
421
441
  frame_index: frameIndex,
422
442
  force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
443
+ click_count: normalizeSetupActionClickCount(input, type, index),
423
444
  coordinate_mode: coordinateMode,
424
445
  from_x: fromX,
425
446
  from_y: fromY,
@@ -1883,14 +1904,22 @@ function profileSetupSummary(viewports, actionCount) {
1883
1904
  viewports: (viewports || []).map((viewport) => {
1884
1905
  const results = viewport.setup_action_results || [];
1885
1906
  const failed = results.filter((result) => result && result.ok === false);
1907
+ const successfulClicks = results.filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false);
1908
+ const clickCountValues = successfulClicks
1909
+ .map((result) => typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : undefined)
1910
+ .filter((value) => value !== undefined);
1886
1911
  const clickedItems = results
1887
1912
  .filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false)
1888
- .map((result) => ({
1889
- ordinal: result.ordinal ?? null,
1890
- selector: result.selector ?? null,
1891
- frame_selector: result.frame_selector ?? null,
1892
- text: compactProfileSetupSummaryText(result.text),
1893
- }));
1913
+ .map((result) => {
1914
+ const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : undefined;
1915
+ return {
1916
+ ordinal: result.ordinal ?? null,
1917
+ selector: result.selector ?? null,
1918
+ frame_selector: result.frame_selector ?? null,
1919
+ text: compactProfileSetupSummaryText(result.text),
1920
+ ...(clickCount ? { click_count: clickCount } : {}),
1921
+ };
1922
+ });
1894
1923
  const clicked = sampleProfileSetupSummaryItems(clickedItems, 8);
1895
1924
  const textSamples = results
1896
1925
  .filter((result) => result && result.ok !== false && typeof result.text === "string" && (
@@ -1918,6 +1947,8 @@ function profileSetupSummary(viewports, actionCount) {
1918
1947
  setup_screenshots: profileSetupScreenshotLabels(results),
1919
1948
  clicked_total: clickedItems.length,
1920
1949
  clicked_truncated: clickedItems.length > clicked.length,
1950
+ click_count_action_total: clickCountValues.length,
1951
+ click_count_value_total: clickCountValues.reduce((sum, value) => sum + value, 0),
1921
1952
  clicked,
1922
1953
  text_samples: textSamples,
1923
1954
  failed: failed.map((result) => ({
@@ -3118,8 +3149,10 @@ async function executeSetupAction(action, ordinal, viewport) {
3118
3149
  const clickOptions = action.force === true
3119
3150
  ? { timeout, noWaitAfter: true, force: true }
3120
3151
  : { timeout, noWaitAfter: true };
3152
+ const clickCount = setupNumber(action.click_count, 1);
3153
+ if (Number.isInteger(clickCount) && clickCount > 1) clickOptions.clickCount = clickCount;
3121
3154
  await locator.nth(targetIndex).click(clickOptions);
3122
- return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
3155
+ return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined, click_count: clickCount > 1 ? clickCount : undefined };
3123
3156
  }
3124
3157
  if (type === "fill" || type === "set_input_value") {
3125
3158
  const scope = await setupActionScope(action, timeout);
package/dist/cli.cjs CHANGED
@@ -7104,12 +7104,18 @@ function profileSetupSummary(viewports, actionCount) {
7104
7104
  viewports: viewports.map((viewport) => {
7105
7105
  const results = viewport.setup_action_results || [];
7106
7106
  const failed = results.filter((result) => result.ok === false);
7107
- const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => ({
7108
- ordinal: result.ordinal ?? null,
7109
- selector: result.selector ?? null,
7110
- frame_selector: result.frame_selector ?? null,
7111
- text: compactProfileSetupSummaryText(result.text)
7112
- }));
7107
+ const successfulClicks = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false);
7108
+ const clickCountValues = successfulClicks.map((result) => typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0).filter((value) => value !== void 0);
7109
+ const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
7110
+ const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0;
7111
+ return {
7112
+ ordinal: result.ordinal ?? null,
7113
+ selector: result.selector ?? null,
7114
+ frame_selector: result.frame_selector ?? null,
7115
+ text: compactProfileSetupSummaryText(result.text),
7116
+ ...clickCount ? { click_count: clickCount } : {}
7117
+ };
7118
+ });
7113
7119
  const clicked = sampleProfileSetupSummaryItems(clickedItems, 8);
7114
7120
  const text_samples = results.filter((result) => result.ok !== false && typeof result.text === "string" && (profileSetupResultAction(result) === "assert_text_visible" || profileSetupResultAction(result) === "assert_text_absent" || profileSetupResultAction(result) === "wait_for_text")).map((result) => ({
7115
7121
  ordinal: result.ordinal ?? null,
@@ -7129,6 +7135,8 @@ function profileSetupSummary(viewports, actionCount) {
7129
7135
  setup_screenshots: profileSetupScreenshotLabels(results),
7130
7136
  clicked_total: clickedItems.length,
7131
7137
  clicked_truncated: clickedItems.length > clicked.length,
7138
+ click_count_action_total: clickCountValues.length,
7139
+ click_count_value_total: clickCountValues.reduce((sum, value) => sum + value, 0),
7132
7140
  clicked,
7133
7141
  text_samples,
7134
7142
  failed: failed.map((result) => ({
@@ -7202,6 +7210,18 @@ function normalizeSetupActionRepeat(input, index) {
7202
7210
  }
7203
7211
  return repeat;
7204
7212
  }
7213
+ function normalizeSetupActionClickCount(input, type, index) {
7214
+ const clickCountInput = valueFromOwn(input, "click_count", "clickCount", "clicks");
7215
+ if (clickCountInput === void 0) return void 0;
7216
+ if (type !== "click") {
7217
+ throw new Error(`target.setup_actions[${index}].click_count is only supported for click actions.`);
7218
+ }
7219
+ const clickCount = numberValue(clickCountInput);
7220
+ if (clickCount === void 0 || !Number.isInteger(clickCount) || clickCount < 1 || clickCount > 10) {
7221
+ throw new Error(`target.setup_actions[${index}].click_count must be an integer from 1 to 10.`);
7222
+ }
7223
+ return clickCount;
7224
+ }
7205
7225
  function normalizeSetupActionCoordinateMode(value, index) {
7206
7226
  if (value === void 0 || value === null || value === "") return void 0;
7207
7227
  const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
@@ -7293,6 +7313,7 @@ function normalizeSetupAction(input, index) {
7293
7313
  frame_selector: frameSelector,
7294
7314
  frame_index: frameIndex,
7295
7315
  force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
7316
+ click_count: normalizeSetupActionClickCount(input, type, index),
7296
7317
  coordinate_mode: coordinateMode,
7297
7318
  from_x: fromX,
7298
7319
  from_y: fromY,
@@ -8740,14 +8761,22 @@ function profileSetupSummary(viewports, actionCount) {
8740
8761
  viewports: (viewports || []).map((viewport) => {
8741
8762
  const results = viewport.setup_action_results || [];
8742
8763
  const failed = results.filter((result) => result && result.ok === false);
8764
+ const successfulClicks = results.filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false);
8765
+ const clickCountValues = successfulClicks
8766
+ .map((result) => typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : undefined)
8767
+ .filter((value) => value !== undefined);
8743
8768
  const clickedItems = results
8744
8769
  .filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false)
8745
- .map((result) => ({
8746
- ordinal: result.ordinal ?? null,
8747
- selector: result.selector ?? null,
8748
- frame_selector: result.frame_selector ?? null,
8749
- text: compactProfileSetupSummaryText(result.text),
8750
- }));
8770
+ .map((result) => {
8771
+ const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : undefined;
8772
+ return {
8773
+ ordinal: result.ordinal ?? null,
8774
+ selector: result.selector ?? null,
8775
+ frame_selector: result.frame_selector ?? null,
8776
+ text: compactProfileSetupSummaryText(result.text),
8777
+ ...(clickCount ? { click_count: clickCount } : {}),
8778
+ };
8779
+ });
8751
8780
  const clicked = sampleProfileSetupSummaryItems(clickedItems, 8);
8752
8781
  const textSamples = results
8753
8782
  .filter((result) => result && result.ok !== false && typeof result.text === "string" && (
@@ -8775,6 +8804,8 @@ function profileSetupSummary(viewports, actionCount) {
8775
8804
  setup_screenshots: profileSetupScreenshotLabels(results),
8776
8805
  clicked_total: clickedItems.length,
8777
8806
  clicked_truncated: clickedItems.length > clicked.length,
8807
+ click_count_action_total: clickCountValues.length,
8808
+ click_count_value_total: clickCountValues.reduce((sum, value) => sum + value, 0),
8778
8809
  clicked,
8779
8810
  text_samples: textSamples,
8780
8811
  failed: failed.map((result) => ({
@@ -9975,8 +10006,10 @@ async function executeSetupAction(action, ordinal, viewport) {
9975
10006
  const clickOptions = action.force === true
9976
10007
  ? { timeout, noWaitAfter: true, force: true }
9977
10008
  : { timeout, noWaitAfter: true };
10009
+ const clickCount = setupNumber(action.click_count, 1);
10010
+ if (Number.isInteger(clickCount) && clickCount > 1) clickOptions.clickCount = clickCount;
9978
10011
  await locator.nth(targetIndex).click(clickOptions);
9979
- return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
10012
+ return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined, click_count: clickCount > 1 ? clickCount : undefined };
9980
10013
  }
9981
10014
  if (type === "fill" || type === "set_input_value") {
9982
10015
  const scope = await setupActionScope(action, timeout);
@@ -11229,20 +11262,26 @@ function profileSetupSummaryMarkdown(result) {
11229
11262
  return sum + labels.filter((label) => typeof label === "string" && label.trim()).length;
11230
11263
  }, 0);
11231
11264
  const clickedTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.clicked_total) || 0), 0);
11265
+ const clickCountActionTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.click_count_action_total) || 0), 0);
11266
+ const clickCountValueTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.click_count_value_total) || 0), 0);
11232
11267
  const failedTotal = viewports.reduce((sum, viewport) => sum + (Array.isArray(viewport.failed) ? viewport.failed.length : 0), 0);
11233
11268
  const lines = [
11234
11269
  `- setup actions: ${declaredActions === void 0 ? "unknown" : declaredActions} declared, ${totalResults} recorded result(s) across ${viewports.length} viewport(s)`,
11235
11270
  `- setup screenshots: ${setupScreenshots}`,
11236
11271
  `- clicked targets: ${clickedTotal}${failedTotal ? `; failed setup actions: ${failedTotal}` : ""}`
11237
11272
  ];
11273
+ if (clickCountActionTotal) {
11274
+ lines.push(`- click counts: ${clickCountActionTotal} action(s), click_count total ${clickCountValueTotal}`);
11275
+ }
11238
11276
  for (const viewport of viewports.slice(0, 8)) {
11239
11277
  const name = cliString(viewport.name) || "viewport";
11240
11278
  const ok = viewport.ok === false ? "failed" : "ok";
11241
11279
  const resultCount = cliFiniteNumber(viewport.result_count) || 0;
11242
11280
  const screenshotCount = Array.isArray(viewport.setup_screenshots) ? viewport.setup_screenshots.filter((label) => typeof label === "string" && label.trim()).length : 0;
11243
11281
  const clicked = cliFiniteNumber(viewport.clicked_total) || 0;
11282
+ const clickCountActions = cliFiniteNumber(viewport.click_count_action_total) || 0;
11244
11283
  const observedPath = cliString(viewport.observed_path);
11245
- lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${observedPath ? `, path ${observedPath}` : ""}`);
11284
+ lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${clickCountActions ? `, ${clickCountActions} click_count action(s)` : ""}${observedPath ? `, path ${observedPath}` : ""}`);
11246
11285
  }
11247
11286
  if (viewports.length > 8) lines.push(`- ${viewports.length - 8} additional viewport(s) omitted from setup summary.`);
11248
11287
  return lines;
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-376FPGFA.js";
13
+ } from "./chunk-KMJBTFLI.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
@@ -351,20 +351,26 @@ function profileSetupSummaryMarkdown(result) {
351
351
  return sum + labels.filter((label) => typeof label === "string" && label.trim()).length;
352
352
  }, 0);
353
353
  const clickedTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.clicked_total) || 0), 0);
354
+ const clickCountActionTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.click_count_action_total) || 0), 0);
355
+ const clickCountValueTotal = viewports.reduce((sum, viewport) => sum + (cliFiniteNumber(viewport.click_count_value_total) || 0), 0);
354
356
  const failedTotal = viewports.reduce((sum, viewport) => sum + (Array.isArray(viewport.failed) ? viewport.failed.length : 0), 0);
355
357
  const lines = [
356
358
  `- setup actions: ${declaredActions === void 0 ? "unknown" : declaredActions} declared, ${totalResults} recorded result(s) across ${viewports.length} viewport(s)`,
357
359
  `- setup screenshots: ${setupScreenshots}`,
358
360
  `- clicked targets: ${clickedTotal}${failedTotal ? `; failed setup actions: ${failedTotal}` : ""}`
359
361
  ];
362
+ if (clickCountActionTotal) {
363
+ lines.push(`- click counts: ${clickCountActionTotal} action(s), click_count total ${clickCountValueTotal}`);
364
+ }
360
365
  for (const viewport of viewports.slice(0, 8)) {
361
366
  const name = cliString(viewport.name) || "viewport";
362
367
  const ok = viewport.ok === false ? "failed" : "ok";
363
368
  const resultCount = cliFiniteNumber(viewport.result_count) || 0;
364
369
  const screenshotCount = Array.isArray(viewport.setup_screenshots) ? viewport.setup_screenshots.filter((label) => typeof label === "string" && label.trim()).length : 0;
365
370
  const clicked = cliFiniteNumber(viewport.clicked_total) || 0;
371
+ const clickCountActions = cliFiniteNumber(viewport.click_count_action_total) || 0;
366
372
  const observedPath = cliString(viewport.observed_path);
367
- lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${observedPath ? `, path ${observedPath}` : ""}`);
373
+ lines.push(`- ${name}: ${ok}, ${resultCount} result(s), ${screenshotCount} setup screenshot(s), ${clicked} click(s)${clickCountActions ? `, ${clickCountActions} click_count action(s)` : ""}${observedPath ? `, path ${observedPath}` : ""}`);
368
374
  }
369
375
  if (viewports.length > 8) lines.push(`- ${viewports.length - 8} additional viewport(s) omitted from setup summary.`);
370
376
  return lines;
package/dist/index.cjs CHANGED
@@ -8945,12 +8945,18 @@ function profileSetupSummary(viewports, actionCount) {
8945
8945
  viewports: viewports.map((viewport) => {
8946
8946
  const results = viewport.setup_action_results || [];
8947
8947
  const failed = results.filter((result) => result.ok === false);
8948
- const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => ({
8949
- ordinal: result.ordinal ?? null,
8950
- selector: result.selector ?? null,
8951
- frame_selector: result.frame_selector ?? null,
8952
- text: compactProfileSetupSummaryText(result.text)
8953
- }));
8948
+ const successfulClicks = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false);
8949
+ const clickCountValues = successfulClicks.map((result) => typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0).filter((value) => value !== void 0);
8950
+ const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
8951
+ const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0;
8952
+ return {
8953
+ ordinal: result.ordinal ?? null,
8954
+ selector: result.selector ?? null,
8955
+ frame_selector: result.frame_selector ?? null,
8956
+ text: compactProfileSetupSummaryText(result.text),
8957
+ ...clickCount ? { click_count: clickCount } : {}
8958
+ };
8959
+ });
8954
8960
  const clicked = sampleProfileSetupSummaryItems(clickedItems, 8);
8955
8961
  const text_samples = results.filter((result) => result.ok !== false && typeof result.text === "string" && (profileSetupResultAction(result) === "assert_text_visible" || profileSetupResultAction(result) === "assert_text_absent" || profileSetupResultAction(result) === "wait_for_text")).map((result) => ({
8956
8962
  ordinal: result.ordinal ?? null,
@@ -8970,6 +8976,8 @@ function profileSetupSummary(viewports, actionCount) {
8970
8976
  setup_screenshots: profileSetupScreenshotLabels(results),
8971
8977
  clicked_total: clickedItems.length,
8972
8978
  clicked_truncated: clickedItems.length > clicked.length,
8979
+ click_count_action_total: clickCountValues.length,
8980
+ click_count_value_total: clickCountValues.reduce((sum, value) => sum + value, 0),
8973
8981
  clicked,
8974
8982
  text_samples,
8975
8983
  failed: failed.map((result) => ({
@@ -9043,6 +9051,18 @@ function normalizeSetupActionRepeat(input, index) {
9043
9051
  }
9044
9052
  return repeat;
9045
9053
  }
9054
+ function normalizeSetupActionClickCount(input, type, index) {
9055
+ const clickCountInput = valueFromOwn(input, "click_count", "clickCount", "clicks");
9056
+ if (clickCountInput === void 0) return void 0;
9057
+ if (type !== "click") {
9058
+ throw new Error(`target.setup_actions[${index}].click_count is only supported for click actions.`);
9059
+ }
9060
+ const clickCount = numberValue3(clickCountInput);
9061
+ if (clickCount === void 0 || !Number.isInteger(clickCount) || clickCount < 1 || clickCount > 10) {
9062
+ throw new Error(`target.setup_actions[${index}].click_count must be an integer from 1 to 10.`);
9063
+ }
9064
+ return clickCount;
9065
+ }
9046
9066
  function normalizeSetupActionCoordinateMode(value, index) {
9047
9067
  if (value === void 0 || value === null || value === "") return void 0;
9048
9068
  const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
@@ -9134,6 +9154,7 @@ function normalizeSetupAction(input, index) {
9134
9154
  frame_selector: frameSelector,
9135
9155
  frame_index: frameIndex,
9136
9156
  force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
9157
+ click_count: normalizeSetupActionClickCount(input, type, index),
9137
9158
  coordinate_mode: coordinateMode,
9138
9159
  from_x: fromX,
9139
9160
  from_y: fromY,
@@ -10597,14 +10618,22 @@ function profileSetupSummary(viewports, actionCount) {
10597
10618
  viewports: (viewports || []).map((viewport) => {
10598
10619
  const results = viewport.setup_action_results || [];
10599
10620
  const failed = results.filter((result) => result && result.ok === false);
10621
+ const successfulClicks = results.filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false);
10622
+ const clickCountValues = successfulClicks
10623
+ .map((result) => typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : undefined)
10624
+ .filter((value) => value !== undefined);
10600
10625
  const clickedItems = results
10601
10626
  .filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false)
10602
- .map((result) => ({
10603
- ordinal: result.ordinal ?? null,
10604
- selector: result.selector ?? null,
10605
- frame_selector: result.frame_selector ?? null,
10606
- text: compactProfileSetupSummaryText(result.text),
10607
- }));
10627
+ .map((result) => {
10628
+ const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : undefined;
10629
+ return {
10630
+ ordinal: result.ordinal ?? null,
10631
+ selector: result.selector ?? null,
10632
+ frame_selector: result.frame_selector ?? null,
10633
+ text: compactProfileSetupSummaryText(result.text),
10634
+ ...(clickCount ? { click_count: clickCount } : {}),
10635
+ };
10636
+ });
10608
10637
  const clicked = sampleProfileSetupSummaryItems(clickedItems, 8);
10609
10638
  const textSamples = results
10610
10639
  .filter((result) => result && result.ok !== false && typeof result.text === "string" && (
@@ -10632,6 +10661,8 @@ function profileSetupSummary(viewports, actionCount) {
10632
10661
  setup_screenshots: profileSetupScreenshotLabels(results),
10633
10662
  clicked_total: clickedItems.length,
10634
10663
  clicked_truncated: clickedItems.length > clicked.length,
10664
+ click_count_action_total: clickCountValues.length,
10665
+ click_count_value_total: clickCountValues.reduce((sum, value) => sum + value, 0),
10635
10666
  clicked,
10636
10667
  text_samples: textSamples,
10637
10668
  failed: failed.map((result) => ({
@@ -11832,8 +11863,10 @@ async function executeSetupAction(action, ordinal, viewport) {
11832
11863
  const clickOptions = action.force === true
11833
11864
  ? { timeout, noWaitAfter: true, force: true }
11834
11865
  : { timeout, noWaitAfter: true };
11866
+ const clickCount = setupNumber(action.click_count, 1);
11867
+ if (Number.isInteger(clickCount) && clickCount > 1) clickOptions.clickCount = clickCount;
11835
11868
  await locator.nth(targetIndex).click(clickOptions);
11836
- return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
11869
+ return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined, click_count: clickCount > 1 ? clickCount : undefined };
11837
11870
  }
11838
11871
  if (type === "fill" || type === "set_input_value") {
11839
11872
  const scope = await setupActionScope(action, timeout);
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-376FPGFA.js";
61
+ } from "./chunk-KMJBTFLI.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -274,12 +274,18 @@ function profileSetupSummary(viewports, actionCount) {
274
274
  viewports: viewports.map((viewport) => {
275
275
  const results = viewport.setup_action_results || [];
276
276
  const failed = results.filter((result) => result.ok === false);
277
- const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => ({
278
- ordinal: result.ordinal ?? null,
279
- selector: result.selector ?? null,
280
- frame_selector: result.frame_selector ?? null,
281
- text: compactProfileSetupSummaryText(result.text)
282
- }));
277
+ const successfulClicks = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false);
278
+ const clickCountValues = successfulClicks.map((result) => typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0).filter((value) => value !== void 0);
279
+ const clickedItems = results.filter((result) => profileSetupResultAction(result) === "click" && result.ok !== false).map((result) => {
280
+ const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : void 0;
281
+ return {
282
+ ordinal: result.ordinal ?? null,
283
+ selector: result.selector ?? null,
284
+ frame_selector: result.frame_selector ?? null,
285
+ text: compactProfileSetupSummaryText(result.text),
286
+ ...clickCount ? { click_count: clickCount } : {}
287
+ };
288
+ });
283
289
  const clicked = sampleProfileSetupSummaryItems(clickedItems, 8);
284
290
  const text_samples = results.filter((result) => result.ok !== false && typeof result.text === "string" && (profileSetupResultAction(result) === "assert_text_visible" || profileSetupResultAction(result) === "assert_text_absent" || profileSetupResultAction(result) === "wait_for_text")).map((result) => ({
285
291
  ordinal: result.ordinal ?? null,
@@ -299,6 +305,8 @@ function profileSetupSummary(viewports, actionCount) {
299
305
  setup_screenshots: profileSetupScreenshotLabels(results),
300
306
  clicked_total: clickedItems.length,
301
307
  clicked_truncated: clickedItems.length > clicked.length,
308
+ click_count_action_total: clickCountValues.length,
309
+ click_count_value_total: clickCountValues.reduce((sum, value) => sum + value, 0),
302
310
  clicked,
303
311
  text_samples,
304
312
  failed: failed.map((result) => ({
@@ -372,6 +380,18 @@ function normalizeSetupActionRepeat(input, index) {
372
380
  }
373
381
  return repeat;
374
382
  }
383
+ function normalizeSetupActionClickCount(input, type, index) {
384
+ const clickCountInput = valueFromOwn(input, "click_count", "clickCount", "clicks");
385
+ if (clickCountInput === void 0) return void 0;
386
+ if (type !== "click") {
387
+ throw new Error(`target.setup_actions[${index}].click_count is only supported for click actions.`);
388
+ }
389
+ const clickCount = numberValue(clickCountInput);
390
+ if (clickCount === void 0 || !Number.isInteger(clickCount) || clickCount < 1 || clickCount > 10) {
391
+ throw new Error(`target.setup_actions[${index}].click_count must be an integer from 1 to 10.`);
392
+ }
393
+ return clickCount;
394
+ }
375
395
  function normalizeSetupActionCoordinateMode(value, index) {
376
396
  if (value === void 0 || value === null || value === "") return void 0;
377
397
  const normalized = String(value).trim().replace(/-/g, "_").toLowerCase();
@@ -463,6 +483,7 @@ function normalizeSetupAction(input, index) {
463
483
  frame_selector: frameSelector,
464
484
  frame_index: frameIndex,
465
485
  force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
486
+ click_count: normalizeSetupActionClickCount(input, type, index),
466
487
  coordinate_mode: coordinateMode,
467
488
  from_x: fromX,
468
489
  from_y: fromY,
@@ -1926,14 +1947,22 @@ function profileSetupSummary(viewports, actionCount) {
1926
1947
  viewports: (viewports || []).map((viewport) => {
1927
1948
  const results = viewport.setup_action_results || [];
1928
1949
  const failed = results.filter((result) => result && result.ok === false);
1950
+ const successfulClicks = results.filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false);
1951
+ const clickCountValues = successfulClicks
1952
+ .map((result) => typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : undefined)
1953
+ .filter((value) => value !== undefined);
1929
1954
  const clickedItems = results
1930
1955
  .filter((result) => result && profileSetupResultAction(result) === "click" && result.ok !== false)
1931
- .map((result) => ({
1932
- ordinal: result.ordinal ?? null,
1933
- selector: result.selector ?? null,
1934
- frame_selector: result.frame_selector ?? null,
1935
- text: compactProfileSetupSummaryText(result.text),
1936
- }));
1956
+ .map((result) => {
1957
+ const clickCount = typeof result.click_count === "number" && Number.isFinite(result.click_count) && result.click_count > 1 ? result.click_count : undefined;
1958
+ return {
1959
+ ordinal: result.ordinal ?? null,
1960
+ selector: result.selector ?? null,
1961
+ frame_selector: result.frame_selector ?? null,
1962
+ text: compactProfileSetupSummaryText(result.text),
1963
+ ...(clickCount ? { click_count: clickCount } : {}),
1964
+ };
1965
+ });
1937
1966
  const clicked = sampleProfileSetupSummaryItems(clickedItems, 8);
1938
1967
  const textSamples = results
1939
1968
  .filter((result) => result && result.ok !== false && typeof result.text === "string" && (
@@ -1961,6 +1990,8 @@ function profileSetupSummary(viewports, actionCount) {
1961
1990
  setup_screenshots: profileSetupScreenshotLabels(results),
1962
1991
  clicked_total: clickedItems.length,
1963
1992
  clicked_truncated: clickedItems.length > clicked.length,
1993
+ click_count_action_total: clickCountValues.length,
1994
+ click_count_value_total: clickCountValues.reduce((sum, value) => sum + value, 0),
1964
1995
  clicked,
1965
1996
  text_samples: textSamples,
1966
1997
  failed: failed.map((result) => ({
@@ -3161,8 +3192,10 @@ async function executeSetupAction(action, ordinal, viewport) {
3161
3192
  const clickOptions = action.force === true
3162
3193
  ? { timeout, noWaitAfter: true, force: true }
3163
3194
  : { timeout, noWaitAfter: true };
3195
+ const clickCount = setupNumber(action.click_count, 1);
3196
+ if (Number.isInteger(clickCount) && clickCount > 1) clickOptions.clickCount = clickCount;
3164
3197
  await locator.nth(targetIndex).click(clickOptions);
3165
- return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
3198
+ return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined, click_count: clickCount > 1 ? clickCount : undefined };
3166
3199
  }
3167
3200
  if (type === "fill" || type === "set_input_value") {
3168
3201
  const scope = await setupActionScope(action, timeout);
@@ -23,6 +23,7 @@ interface RiddleProofProfileSetupAction {
23
23
  frame_selector?: string;
24
24
  frame_index?: number;
25
25
  force?: boolean;
26
+ click_count?: number;
26
27
  coordinate_mode?: "pixels" | "ratio";
27
28
  from_x?: number;
28
29
  from_y?: number;
package/dist/profile.d.ts CHANGED
@@ -23,6 +23,7 @@ interface RiddleProofProfileSetupAction {
23
23
  frame_selector?: string;
24
24
  frame_index?: number;
25
25
  force?: boolean;
26
+ click_count?: number;
26
27
  coordinate_mode?: "pixels" | "ratio";
27
28
  from_x?: number;
28
29
  from_y?: number;
package/dist/profile.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  resolveRiddleProofProfileTimeoutSec,
20
20
  slugifyRiddleProofProfileName,
21
21
  summarizeRiddleProofProfileResult
22
- } from "./chunk-376FPGFA.js";
22
+ } from "./chunk-KMJBTFLI.js";
23
23
  export {
24
24
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
25
25
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
295
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
385
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
662
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
295
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
385
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
662
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.68",
3
+ "version": "0.7.70",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",