@riddledc/riddle-proof 0.7.50 → 0.7.52

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
@@ -238,16 +238,21 @@ where the second request must carry newer state.
238
238
  appears only after a picker, tab, login stub, storage seed, form fill,
239
239
  transport control, or other bounded interaction. Supported setup actions are
240
240
  `click`, `fill`, `set_input_value`, `assert_text_visible`,
241
- `assert_text_absent`, `assert_selector_count`, `local_storage`,
242
- `session_storage`, `clear_storage`, `wait`, `wait_for_selector`, and
243
- `wait_for_text`; a failed setup action is recorded as a failed
244
- `setup_actions_succeeded` check so the profile cannot pass without reaching
245
- the intended state. Text-matched `click` actions prefer visible matching
246
- elements, which keeps responsive layouts from selecting hidden desktop or
247
- mobile-only links. Use setup assertions when the pre-click or pre-navigation
248
- state is part of the contract, for example a fresh row must be present, stale
249
- copy must be absent, or exactly one source link must exist before clicking into
250
- the final route. `assert_selector_count` accepts `expected_count`.
241
+ `assert_text_absent`, `assert_selector_count`, `assert_window_value`,
242
+ `local_storage`, `session_storage`, `clear_storage`, `wait`,
243
+ `wait_for_selector`, `wait_for_text`, and `window_call`; a failed setup action
244
+ is recorded as a failed `setup_actions_succeeded` check so the profile cannot
245
+ pass without reaching the intended state. Text-matched `click` actions prefer
246
+ visible matching elements, which keeps responsive layouts from selecting hidden
247
+ desktop or mobile-only links. Add `force: true` to a click action only when the
248
+ matched visible element is intentionally animated or otherwise never becomes
249
+ stable enough for Playwright's default click actionability checks. Use setup
250
+ assertions when the pre-click or pre-navigation state is part of the contract,
251
+ for example a fresh row must be present, stale copy must be absent, exactly one
252
+ source link must exist before clicking into the final route, or a canvas app's
253
+ proof state must expose a terminal flag. `assert_selector_count` accepts
254
+ `expected_count`; `assert_window_value` accepts `path` / `state_path` plus
255
+ `expected_value` / `expected` and compares JSON-safe values exactly.
251
256
  `local_storage` and `session_storage` accept a `key` plus string `value` or
252
257
  JSON `json` / `value_json`, and can reload the page with `reload: true`.
253
258
  `clear_storage` clears `local`, `session`, or `both` browser storage scopes,
@@ -35,6 +35,7 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
35
35
  "assert_text_visible",
36
36
  "assert_text_absent",
37
37
  "assert_selector_count",
38
+ "assert_window_value",
38
39
  "local_storage",
39
40
  "session_storage",
40
41
  "clear_storage",
@@ -248,21 +249,27 @@ function normalizeSetupAction(input, index) {
248
249
  if ((type === "local_storage" || type === "session_storage") && value === void 0 && !hasJsonValue) {
249
250
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
250
251
  }
251
- const path = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath");
252
- if (type === "window_call" && !path) {
252
+ const path = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
253
+ if ((type === "window_call" || type === "assert_window_value") && !path) {
253
254
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
254
255
  }
255
256
  const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
257
+ const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
258
+ if (type === "assert_window_value" && !hasExpectedValue) {
259
+ throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
260
+ }
256
261
  const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
257
262
  return {
258
263
  type,
259
264
  selector,
265
+ force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
260
266
  key,
261
267
  value,
262
268
  value_json: hasJsonValue ? toJsonValue(input.value_json ?? input.valueJson ?? input.json) : void 0,
263
269
  path,
264
270
  args,
265
271
  expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
272
+ expected_value: hasExpectedValue ? toJsonValue(valueFromOwn(input, "expected_value", "expectedValue", "expected", "expect_value", "expectValue", "expect")) : void 0,
266
273
  text: stringValue(input.text),
267
274
  pattern: stringValue(input.pattern),
268
275
  flags: stringValue(input.flags),
@@ -1976,6 +1983,29 @@ function setupJsonValue(value) {
1976
1983
  function setupValuesEqual(left, right) {
1977
1984
  return JSON.stringify(setupJsonValue(left)) === JSON.stringify(setupJsonValue(right));
1978
1985
  }
1986
+ async function setupReadWindowValue(path) {
1987
+ return await page.evaluate(({ path }) => {
1988
+ const toJsonValue = (value) => {
1989
+ if (value === null || value === undefined) return null;
1990
+ if (typeof value === "string" || typeof value === "boolean") return value;
1991
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
1992
+ if (Array.isArray(value)) return value.map(toJsonValue);
1993
+ if (typeof value === "object") {
1994
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
1995
+ }
1996
+ return String(value);
1997
+ };
1998
+ const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
1999
+ if (!pathParts.length) return { ok: false, reason: "missing_path" };
2000
+ let current = window;
2001
+ for (const part of pathParts) {
2002
+ if (current === null || current === undefined) return { ok: false, reason: "path_not_found", missing_part: part };
2003
+ current = current[part];
2004
+ if (current === undefined) return { ok: false, reason: "path_not_found", missing_part: part };
2005
+ }
2006
+ return { ok: true, value: toJsonValue(current) };
2007
+ }, { path });
2008
+ }
1979
2009
  async function setupLocatorText(locator, index) {
1980
2010
  return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
1981
2011
  }
@@ -2224,6 +2254,53 @@ async function executeSetupAction(action, ordinal) {
2224
2254
  error: result.error || undefined,
2225
2255
  };
2226
2256
  }
2257
+ if (type === "assert_window_value") {
2258
+ const path = String(action.path || action.window_path || action.windowPath || "");
2259
+ const hasExpected = setupHasOwn(action, "expected_value")
2260
+ || setupHasOwn(action, "expectedValue")
2261
+ || setupHasOwn(action, "expected")
2262
+ || setupHasOwn(action, "expect_value")
2263
+ || setupHasOwn(action, "expectValue")
2264
+ || setupHasOwn(action, "expect");
2265
+ const expected = setupHasOwn(action, "expected_value")
2266
+ ? action.expected_value
2267
+ : setupHasOwn(action, "expectedValue")
2268
+ ? action.expectedValue
2269
+ : setupHasOwn(action, "expected")
2270
+ ? action.expected
2271
+ : setupHasOwn(action, "expect_value")
2272
+ ? action.expect_value
2273
+ : setupHasOwn(action, "expectValue")
2274
+ ? action.expectValue
2275
+ : action.expect;
2276
+ if (!path) return { ...base, path, reason: "missing_path" };
2277
+ if (!hasExpected) return { ...base, path, reason: "missing_expected_value" };
2278
+ const startedAt = Date.now();
2279
+ let result = null;
2280
+ while (Date.now() - startedAt <= timeout) {
2281
+ result = await setupReadWindowValue(path);
2282
+ if (result.ok && setupValuesEqual(result.value, expected)) {
2283
+ return {
2284
+ ...base,
2285
+ ok: true,
2286
+ path,
2287
+ value: setupJsonValue(result.value),
2288
+ expected_value: setupJsonValue(expected),
2289
+ timeout_ms: timeout,
2290
+ };
2291
+ }
2292
+ await page.waitForTimeout(100);
2293
+ }
2294
+ return {
2295
+ ...base,
2296
+ path,
2297
+ reason: result?.ok ? "unexpected_value" : result?.reason || "path_not_found",
2298
+ missing_part: result?.missing_part || undefined,
2299
+ value: setupJsonValue(result?.value),
2300
+ expected_value: setupJsonValue(expected),
2301
+ timeout_ms: timeout,
2302
+ };
2303
+ }
2227
2304
  if (type === "click") {
2228
2305
  const locator = page.locator(action.selector);
2229
2306
  const count = await locator.count();
@@ -2253,8 +2330,11 @@ async function executeSetupAction(action, ordinal) {
2253
2330
  if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
2254
2331
  }
2255
2332
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
2256
- await locator.nth(targetIndex).click({ timeout, noWaitAfter: true });
2257
- return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
2333
+ const clickOptions = action.force === true
2334
+ ? { timeout, noWaitAfter: true, force: true }
2335
+ : { timeout, noWaitAfter: true };
2336
+ await locator.nth(targetIndex).click(clickOptions);
2337
+ return { ...base, ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
2258
2338
  }
2259
2339
  if (type === "fill" || type === "set_input_value") {
2260
2340
  const locator = page.locator(action.selector);
package/dist/cli.cjs CHANGED
@@ -6908,6 +6908,7 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
6908
6908
  "assert_text_visible",
6909
6909
  "assert_text_absent",
6910
6910
  "assert_selector_count",
6911
+ "assert_window_value",
6911
6912
  "local_storage",
6912
6913
  "session_storage",
6913
6914
  "clear_storage",
@@ -7121,21 +7122,27 @@ function normalizeSetupAction(input, index) {
7121
7122
  if ((type === "local_storage" || type === "session_storage") && value === void 0 && !hasJsonValue) {
7122
7123
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
7123
7124
  }
7124
- const path7 = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath");
7125
- if (type === "window_call" && !path7) {
7125
+ const path7 = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
7126
+ if ((type === "window_call" || type === "assert_window_value") && !path7) {
7126
7127
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
7127
7128
  }
7128
7129
  const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
7130
+ const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
7131
+ if (type === "assert_window_value" && !hasExpectedValue) {
7132
+ throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
7133
+ }
7129
7134
  const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
7130
7135
  return {
7131
7136
  type,
7132
7137
  selector,
7138
+ force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
7133
7139
  key,
7134
7140
  value,
7135
7141
  value_json: hasJsonValue ? toJsonValue(input.value_json ?? input.valueJson ?? input.json) : void 0,
7136
7142
  path: path7,
7137
7143
  args,
7138
7144
  expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
7145
+ expected_value: hasExpectedValue ? toJsonValue(valueFromOwn(input, "expected_value", "expectedValue", "expected", "expect_value", "expectValue", "expect")) : void 0,
7139
7146
  text: stringValue2(input.text),
7140
7147
  pattern: stringValue2(input.pattern),
7141
7148
  flags: stringValue2(input.flags),
@@ -8833,6 +8840,29 @@ function setupJsonValue(value) {
8833
8840
  function setupValuesEqual(left, right) {
8834
8841
  return JSON.stringify(setupJsonValue(left)) === JSON.stringify(setupJsonValue(right));
8835
8842
  }
8843
+ async function setupReadWindowValue(path) {
8844
+ return await page.evaluate(({ path }) => {
8845
+ const toJsonValue = (value) => {
8846
+ if (value === null || value === undefined) return null;
8847
+ if (typeof value === "string" || typeof value === "boolean") return value;
8848
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
8849
+ if (Array.isArray(value)) return value.map(toJsonValue);
8850
+ if (typeof value === "object") {
8851
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
8852
+ }
8853
+ return String(value);
8854
+ };
8855
+ const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
8856
+ if (!pathParts.length) return { ok: false, reason: "missing_path" };
8857
+ let current = window;
8858
+ for (const part of pathParts) {
8859
+ if (current === null || current === undefined) return { ok: false, reason: "path_not_found", missing_part: part };
8860
+ current = current[part];
8861
+ if (current === undefined) return { ok: false, reason: "path_not_found", missing_part: part };
8862
+ }
8863
+ return { ok: true, value: toJsonValue(current) };
8864
+ }, { path });
8865
+ }
8836
8866
  async function setupLocatorText(locator, index) {
8837
8867
  return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
8838
8868
  }
@@ -9081,6 +9111,53 @@ async function executeSetupAction(action, ordinal) {
9081
9111
  error: result.error || undefined,
9082
9112
  };
9083
9113
  }
9114
+ if (type === "assert_window_value") {
9115
+ const path = String(action.path || action.window_path || action.windowPath || "");
9116
+ const hasExpected = setupHasOwn(action, "expected_value")
9117
+ || setupHasOwn(action, "expectedValue")
9118
+ || setupHasOwn(action, "expected")
9119
+ || setupHasOwn(action, "expect_value")
9120
+ || setupHasOwn(action, "expectValue")
9121
+ || setupHasOwn(action, "expect");
9122
+ const expected = setupHasOwn(action, "expected_value")
9123
+ ? action.expected_value
9124
+ : setupHasOwn(action, "expectedValue")
9125
+ ? action.expectedValue
9126
+ : setupHasOwn(action, "expected")
9127
+ ? action.expected
9128
+ : setupHasOwn(action, "expect_value")
9129
+ ? action.expect_value
9130
+ : setupHasOwn(action, "expectValue")
9131
+ ? action.expectValue
9132
+ : action.expect;
9133
+ if (!path) return { ...base, path, reason: "missing_path" };
9134
+ if (!hasExpected) return { ...base, path, reason: "missing_expected_value" };
9135
+ const startedAt = Date.now();
9136
+ let result = null;
9137
+ while (Date.now() - startedAt <= timeout) {
9138
+ result = await setupReadWindowValue(path);
9139
+ if (result.ok && setupValuesEqual(result.value, expected)) {
9140
+ return {
9141
+ ...base,
9142
+ ok: true,
9143
+ path,
9144
+ value: setupJsonValue(result.value),
9145
+ expected_value: setupJsonValue(expected),
9146
+ timeout_ms: timeout,
9147
+ };
9148
+ }
9149
+ await page.waitForTimeout(100);
9150
+ }
9151
+ return {
9152
+ ...base,
9153
+ path,
9154
+ reason: result?.ok ? "unexpected_value" : result?.reason || "path_not_found",
9155
+ missing_part: result?.missing_part || undefined,
9156
+ value: setupJsonValue(result?.value),
9157
+ expected_value: setupJsonValue(expected),
9158
+ timeout_ms: timeout,
9159
+ };
9160
+ }
9084
9161
  if (type === "click") {
9085
9162
  const locator = page.locator(action.selector);
9086
9163
  const count = await locator.count();
@@ -9110,8 +9187,11 @@ async function executeSetupAction(action, ordinal) {
9110
9187
  if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
9111
9188
  }
9112
9189
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
9113
- await locator.nth(targetIndex).click({ timeout, noWaitAfter: true });
9114
- return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
9190
+ const clickOptions = action.force === true
9191
+ ? { timeout, noWaitAfter: true, force: true }
9192
+ : { timeout, noWaitAfter: true };
9193
+ await locator.nth(targetIndex).click(clickOptions);
9194
+ return { ...base, ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
9115
9195
  }
9116
9196
  if (type === "fill" || type === "set_input_value") {
9117
9197
  const locator = page.locator(action.selector);
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-5FHHNCX4.js";
13
+ } from "./chunk-4S6RC5IJ.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -8749,6 +8749,7 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
8749
8749
  "assert_text_visible",
8750
8750
  "assert_text_absent",
8751
8751
  "assert_selector_count",
8752
+ "assert_window_value",
8752
8753
  "local_storage",
8753
8754
  "session_storage",
8754
8755
  "clear_storage",
@@ -8962,21 +8963,27 @@ function normalizeSetupAction(input, index) {
8962
8963
  if ((type === "local_storage" || type === "session_storage") && value === void 0 && !hasJsonValue) {
8963
8964
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
8964
8965
  }
8965
- const path6 = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath");
8966
- if (type === "window_call" && !path6) {
8966
+ const path6 = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
8967
+ if ((type === "window_call" || type === "assert_window_value") && !path6) {
8967
8968
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
8968
8969
  }
8969
8970
  const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
8971
+ const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
8972
+ if (type === "assert_window_value" && !hasExpectedValue) {
8973
+ throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
8974
+ }
8970
8975
  const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
8971
8976
  return {
8972
8977
  type,
8973
8978
  selector,
8979
+ force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
8974
8980
  key,
8975
8981
  value,
8976
8982
  value_json: hasJsonValue ? toJsonValue(input.value_json ?? input.valueJson ?? input.json) : void 0,
8977
8983
  path: path6,
8978
8984
  args,
8979
8985
  expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
8986
+ expected_value: hasExpectedValue ? toJsonValue(valueFromOwn(input, "expected_value", "expectedValue", "expected", "expect_value", "expectValue", "expect")) : void 0,
8980
8987
  text: stringValue5(input.text),
8981
8988
  pattern: stringValue5(input.pattern),
8982
8989
  flags: stringValue5(input.flags),
@@ -10690,6 +10697,29 @@ function setupJsonValue(value) {
10690
10697
  function setupValuesEqual(left, right) {
10691
10698
  return JSON.stringify(setupJsonValue(left)) === JSON.stringify(setupJsonValue(right));
10692
10699
  }
10700
+ async function setupReadWindowValue(path) {
10701
+ return await page.evaluate(({ path }) => {
10702
+ const toJsonValue = (value) => {
10703
+ if (value === null || value === undefined) return null;
10704
+ if (typeof value === "string" || typeof value === "boolean") return value;
10705
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
10706
+ if (Array.isArray(value)) return value.map(toJsonValue);
10707
+ if (typeof value === "object") {
10708
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
10709
+ }
10710
+ return String(value);
10711
+ };
10712
+ const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
10713
+ if (!pathParts.length) return { ok: false, reason: "missing_path" };
10714
+ let current = window;
10715
+ for (const part of pathParts) {
10716
+ if (current === null || current === undefined) return { ok: false, reason: "path_not_found", missing_part: part };
10717
+ current = current[part];
10718
+ if (current === undefined) return { ok: false, reason: "path_not_found", missing_part: part };
10719
+ }
10720
+ return { ok: true, value: toJsonValue(current) };
10721
+ }, { path });
10722
+ }
10693
10723
  async function setupLocatorText(locator, index) {
10694
10724
  return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
10695
10725
  }
@@ -10938,6 +10968,53 @@ async function executeSetupAction(action, ordinal) {
10938
10968
  error: result.error || undefined,
10939
10969
  };
10940
10970
  }
10971
+ if (type === "assert_window_value") {
10972
+ const path = String(action.path || action.window_path || action.windowPath || "");
10973
+ const hasExpected = setupHasOwn(action, "expected_value")
10974
+ || setupHasOwn(action, "expectedValue")
10975
+ || setupHasOwn(action, "expected")
10976
+ || setupHasOwn(action, "expect_value")
10977
+ || setupHasOwn(action, "expectValue")
10978
+ || setupHasOwn(action, "expect");
10979
+ const expected = setupHasOwn(action, "expected_value")
10980
+ ? action.expected_value
10981
+ : setupHasOwn(action, "expectedValue")
10982
+ ? action.expectedValue
10983
+ : setupHasOwn(action, "expected")
10984
+ ? action.expected
10985
+ : setupHasOwn(action, "expect_value")
10986
+ ? action.expect_value
10987
+ : setupHasOwn(action, "expectValue")
10988
+ ? action.expectValue
10989
+ : action.expect;
10990
+ if (!path) return { ...base, path, reason: "missing_path" };
10991
+ if (!hasExpected) return { ...base, path, reason: "missing_expected_value" };
10992
+ const startedAt = Date.now();
10993
+ let result = null;
10994
+ while (Date.now() - startedAt <= timeout) {
10995
+ result = await setupReadWindowValue(path);
10996
+ if (result.ok && setupValuesEqual(result.value, expected)) {
10997
+ return {
10998
+ ...base,
10999
+ ok: true,
11000
+ path,
11001
+ value: setupJsonValue(result.value),
11002
+ expected_value: setupJsonValue(expected),
11003
+ timeout_ms: timeout,
11004
+ };
11005
+ }
11006
+ await page.waitForTimeout(100);
11007
+ }
11008
+ return {
11009
+ ...base,
11010
+ path,
11011
+ reason: result?.ok ? "unexpected_value" : result?.reason || "path_not_found",
11012
+ missing_part: result?.missing_part || undefined,
11013
+ value: setupJsonValue(result?.value),
11014
+ expected_value: setupJsonValue(expected),
11015
+ timeout_ms: timeout,
11016
+ };
11017
+ }
10941
11018
  if (type === "click") {
10942
11019
  const locator = page.locator(action.selector);
10943
11020
  const count = await locator.count();
@@ -10967,8 +11044,11 @@ async function executeSetupAction(action, ordinal) {
10967
11044
  if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
10968
11045
  }
10969
11046
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
10970
- await locator.nth(targetIndex).click({ timeout, noWaitAfter: true });
10971
- return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
11047
+ const clickOptions = action.force === true
11048
+ ? { timeout, noWaitAfter: true, force: true }
11049
+ : { timeout, noWaitAfter: true };
11050
+ await locator.nth(targetIndex).click(clickOptions);
11051
+ return { ...base, ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
10972
11052
  }
10973
11053
  if (type === "fill" || type === "set_input_value") {
10974
11054
  const locator = page.locator(action.selector);
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-5FHHNCX4.js";
61
+ } from "./chunk-4S6RC5IJ.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -78,6 +78,7 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
78
78
  "assert_text_visible",
79
79
  "assert_text_absent",
80
80
  "assert_selector_count",
81
+ "assert_window_value",
81
82
  "local_storage",
82
83
  "session_storage",
83
84
  "clear_storage",
@@ -291,21 +292,27 @@ function normalizeSetupAction(input, index) {
291
292
  if ((type === "local_storage" || type === "session_storage") && value === void 0 && !hasJsonValue) {
292
293
  throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
293
294
  }
294
- const path = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath");
295
- if (type === "window_call" && !path) {
295
+ const path = stringFromOwn(input, "path", "function_path", "functionPath", "window_path", "windowPath", "state_path", "statePath");
296
+ if ((type === "window_call" || type === "assert_window_value") && !path) {
296
297
  throw new Error(`target.setup_actions[${index}] ${type} requires path.`);
297
298
  }
298
299
  const args = type === "window_call" ? normalizeSetupActionArgs(input, index) : void 0;
300
+ const hasExpectedValue = hasOwn(input, "expected_value") || hasOwn(input, "expectedValue") || hasOwn(input, "expected") || hasOwn(input, "expect_value") || hasOwn(input, "expectValue") || hasOwn(input, "expect");
301
+ if (type === "assert_window_value" && !hasExpectedValue) {
302
+ throw new Error(`target.setup_actions[${index}] ${type} requires expected_value.`);
303
+ }
299
304
  const hasExpectedReturn = hasOwn(input, "expect_return") || hasOwn(input, "expectReturn") || hasOwn(input, "expected_return") || hasOwn(input, "expectedReturn");
300
305
  return {
301
306
  type,
302
307
  selector,
308
+ force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
303
309
  key,
304
310
  value,
305
311
  value_json: hasJsonValue ? toJsonValue(input.value_json ?? input.valueJson ?? input.json) : void 0,
306
312
  path,
307
313
  args,
308
314
  expect_return: hasExpectedReturn ? toJsonValue(valueFromOwn(input, "expect_return", "expectReturn", "expected_return", "expectedReturn")) : void 0,
315
+ expected_value: hasExpectedValue ? toJsonValue(valueFromOwn(input, "expected_value", "expectedValue", "expected", "expect_value", "expectValue", "expect")) : void 0,
309
316
  text: stringValue(input.text),
310
317
  pattern: stringValue(input.pattern),
311
318
  flags: stringValue(input.flags),
@@ -2019,6 +2026,29 @@ function setupJsonValue(value) {
2019
2026
  function setupValuesEqual(left, right) {
2020
2027
  return JSON.stringify(setupJsonValue(left)) === JSON.stringify(setupJsonValue(right));
2021
2028
  }
2029
+ async function setupReadWindowValue(path) {
2030
+ return await page.evaluate(({ path }) => {
2031
+ const toJsonValue = (value) => {
2032
+ if (value === null || value === undefined) return null;
2033
+ if (typeof value === "string" || typeof value === "boolean") return value;
2034
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
2035
+ if (Array.isArray(value)) return value.map(toJsonValue);
2036
+ if (typeof value === "object") {
2037
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, toJsonValue(child)]));
2038
+ }
2039
+ return String(value);
2040
+ };
2041
+ const pathParts = String(path || "").split(".").map((part) => part.trim()).filter(Boolean);
2042
+ if (!pathParts.length) return { ok: false, reason: "missing_path" };
2043
+ let current = window;
2044
+ for (const part of pathParts) {
2045
+ if (current === null || current === undefined) return { ok: false, reason: "path_not_found", missing_part: part };
2046
+ current = current[part];
2047
+ if (current === undefined) return { ok: false, reason: "path_not_found", missing_part: part };
2048
+ }
2049
+ return { ok: true, value: toJsonValue(current) };
2050
+ }, { path });
2051
+ }
2022
2052
  async function setupLocatorText(locator, index) {
2023
2053
  return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
2024
2054
  }
@@ -2267,6 +2297,53 @@ async function executeSetupAction(action, ordinal) {
2267
2297
  error: result.error || undefined,
2268
2298
  };
2269
2299
  }
2300
+ if (type === "assert_window_value") {
2301
+ const path = String(action.path || action.window_path || action.windowPath || "");
2302
+ const hasExpected = setupHasOwn(action, "expected_value")
2303
+ || setupHasOwn(action, "expectedValue")
2304
+ || setupHasOwn(action, "expected")
2305
+ || setupHasOwn(action, "expect_value")
2306
+ || setupHasOwn(action, "expectValue")
2307
+ || setupHasOwn(action, "expect");
2308
+ const expected = setupHasOwn(action, "expected_value")
2309
+ ? action.expected_value
2310
+ : setupHasOwn(action, "expectedValue")
2311
+ ? action.expectedValue
2312
+ : setupHasOwn(action, "expected")
2313
+ ? action.expected
2314
+ : setupHasOwn(action, "expect_value")
2315
+ ? action.expect_value
2316
+ : setupHasOwn(action, "expectValue")
2317
+ ? action.expectValue
2318
+ : action.expect;
2319
+ if (!path) return { ...base, path, reason: "missing_path" };
2320
+ if (!hasExpected) return { ...base, path, reason: "missing_expected_value" };
2321
+ const startedAt = Date.now();
2322
+ let result = null;
2323
+ while (Date.now() - startedAt <= timeout) {
2324
+ result = await setupReadWindowValue(path);
2325
+ if (result.ok && setupValuesEqual(result.value, expected)) {
2326
+ return {
2327
+ ...base,
2328
+ ok: true,
2329
+ path,
2330
+ value: setupJsonValue(result.value),
2331
+ expected_value: setupJsonValue(expected),
2332
+ timeout_ms: timeout,
2333
+ };
2334
+ }
2335
+ await page.waitForTimeout(100);
2336
+ }
2337
+ return {
2338
+ ...base,
2339
+ path,
2340
+ reason: result?.ok ? "unexpected_value" : result?.reason || "path_not_found",
2341
+ missing_part: result?.missing_part || undefined,
2342
+ value: setupJsonValue(result?.value),
2343
+ expected_value: setupJsonValue(expected),
2344
+ timeout_ms: timeout,
2345
+ };
2346
+ }
2270
2347
  if (type === "click") {
2271
2348
  const locator = page.locator(action.selector);
2272
2349
  const count = await locator.count();
@@ -2296,8 +2373,11 @@ async function executeSetupAction(action, ordinal) {
2296
2373
  if (targetIndex < 0) return { ...base, reason: "text_not_found", count };
2297
2374
  }
2298
2375
  if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
2299
- await locator.nth(targetIndex).click({ timeout, noWaitAfter: true });
2300
- return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
2376
+ const clickOptions = action.force === true
2377
+ ? { timeout, noWaitAfter: true, force: true }
2378
+ : { timeout, noWaitAfter: true };
2379
+ await locator.nth(targetIndex).click(clickOptions);
2380
+ return { ...base, ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
2301
2381
  }
2302
2382
  if (type === "fill" || type === "set_input_value") {
2303
2383
  const locator = page.locator(action.selector);
@@ -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", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
8
- declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "local_storage", "session_storage", "clear_storage", "wait", "wait_for_selector", "wait_for_text", "window_call"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "local_storage", "session_storage", "clear_storage", "wait", "wait_for_selector", "wait_for_text", "window_call"];
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];
@@ -20,12 +20,14 @@ interface RiddleProofProfileViewport {
20
20
  interface RiddleProofProfileSetupAction {
21
21
  type: RiddleProofProfileSetupActionType;
22
22
  selector?: string;
23
+ force?: boolean;
23
24
  key?: string;
24
25
  value?: string;
25
26
  value_json?: JsonValue;
26
27
  path?: string;
27
28
  args?: JsonValue[];
28
29
  expect_return?: JsonValue;
30
+ expected_value?: JsonValue;
29
31
  text?: string;
30
32
  pattern?: string;
31
33
  flags?: string;
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", "selector_visible", "selector_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
8
- declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "local_storage", "session_storage", "clear_storage", "wait", "wait_for_selector", "wait_for_text", "window_call"];
8
+ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "assert_window_value", "local_storage", "session_storage", "clear_storage", "wait", "wait_for_selector", "wait_for_text", "window_call"];
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];
@@ -20,12 +20,14 @@ interface RiddleProofProfileViewport {
20
20
  interface RiddleProofProfileSetupAction {
21
21
  type: RiddleProofProfileSetupActionType;
22
22
  selector?: string;
23
+ force?: boolean;
23
24
  key?: string;
24
25
  value?: string;
25
26
  value_json?: JsonValue;
26
27
  path?: string;
27
28
  args?: JsonValue[];
28
29
  expect_return?: JsonValue;
30
+ expected_value?: JsonValue;
29
31
  text?: string;
30
32
  pattern?: string;
31
33
  flags?: string;
package/dist/profile.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  resolveRiddleProofProfileTimeoutSec,
20
20
  slugifyRiddleProofProfileName,
21
21
  summarizeRiddleProofProfileResult
22
- } from "./chunk-5FHHNCX4.js";
22
+ } from "./chunk-4S6RC5IJ.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.50",
3
+ "version": "0.7.52",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",