@validate.qa/runner 1.0.100 → 1.0.101

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.
@@ -52692,7 +52692,7 @@ var require_he = __commonJS({
52692
52692
  var stringFromCharCode2 = String.fromCharCode;
52693
52693
  var object = {};
52694
52694
  var hasOwnProperty = object.hasOwnProperty;
52695
- var has = function(object2, propertyName) {
52695
+ var has2 = function(object2, propertyName) {
52696
52696
  return hasOwnProperty.call(object2, propertyName);
52697
52697
  };
52698
52698
  var contains = function(array, value) {
@@ -52712,7 +52712,7 @@ var require_he = __commonJS({
52712
52712
  var result = {};
52713
52713
  var key2;
52714
52714
  for (key2 in defaults) {
52715
- result[key2] = has(options, key2) ? options[key2] : defaults[key2];
52715
+ result[key2] = has2(options, key2) ? options[key2] : defaults[key2];
52716
52716
  }
52717
52717
  return result;
52718
52718
  };
@@ -52724,7 +52724,7 @@ var require_he = __commonJS({
52724
52724
  }
52725
52725
  return "\uFFFD";
52726
52726
  }
52727
- if (has(decodeMapNumeric, codePoint)) {
52727
+ if (has2(decodeMapNumeric, codePoint)) {
52728
52728
  if (strict) {
52729
52729
  parseError("disallowed character reference");
52730
52730
  }
@@ -52765,7 +52765,7 @@ var require_he = __commonJS({
52765
52765
  };
52766
52766
  if (encodeEverything) {
52767
52767
  string = string.replace(regexAsciiWhitelist, function(symbol) {
52768
- if (useNamedReferences && has(encodeMap, symbol)) {
52768
+ if (useNamedReferences && has2(encodeMap, symbol)) {
52769
52769
  return "&" + encodeMap[symbol] + ";";
52770
52770
  }
52771
52771
  return escapeBmpSymbol(symbol);
@@ -52890,7 +52890,7 @@ var require_he = __commonJS({
52890
52890
  freeModule.exports = he;
52891
52891
  } else {
52892
52892
  for (var key in he) {
52893
- has(he, key) && (freeExports[key] = he[key]);
52893
+ has2(he, key) && (freeExports[key] = he[key]);
52894
52894
  }
52895
52895
  }
52896
52896
  } else {
@@ -70679,7 +70679,7 @@ function unescapeQuotedBody(raw) {
70679
70679
  return raw.replace(/\\(['"`\\])/g, "$1");
70680
70680
  }
70681
70681
  function extractRoleNameValue(line) {
70682
- const m = line.match(new RegExp(`getByRole\\s*\\([^,]+,\\s*\\{[^}]*name\\s*:\\s*(?:${QUOTED_BODY}|\\/([^/]*?)\\/)`, "i"));
70682
+ const m = line.match(new RegExp(`getByRole\\s*\\([^,]{1,200},\\s*\\{[^}]{0,200}?name\\s*:\\s*(?:${QUOTED_BODY}|\\/([^/]*?)\\/)`, "i"));
70683
70683
  if (!m)
70684
70684
  return null;
70685
70685
  const raw = m[1] ?? m[2] ?? m[3];
@@ -71387,6 +71387,8 @@ function stripCoverageComments(code) {
71387
71387
  let copyFrom = 0;
71388
71388
  let i = 0;
71389
71389
  let quote = null;
71390
+ let prev = "";
71391
+ let noRegexBefore = 0;
71390
71392
  while (i < code.length) {
71391
71393
  const ch = code[i];
71392
71394
  if (quote) {
@@ -71394,12 +71396,24 @@ function stripCoverageComments(code) {
71394
71396
  i += 2;
71395
71397
  continue;
71396
71398
  }
71397
- if (ch === quote || ch === "\n" && quote !== "`")
71399
+ if (ch === quote || ch === "\n" && quote !== "`") {
71398
71400
  quote = null;
71401
+ prev = ch === "\n" ? prev : ch;
71402
+ }
71399
71403
  i++;
71400
71404
  continue;
71401
71405
  }
71402
71406
  const next = code[i + 1];
71407
+ if (ch === "/" && next !== "*" && next !== "/" && i >= noRegexBefore && (prev === "" || REGEX_PRECEDER2.includes(prev))) {
71408
+ const end = regexLiteralEnd3(code, i);
71409
+ if (end > 0) {
71410
+ i = end;
71411
+ prev = "a";
71412
+ continue;
71413
+ }
71414
+ const eol = code.indexOf("\n", i);
71415
+ noRegexBefore = eol === -1 ? code.length : eol;
71416
+ }
71403
71417
  if (ch === "/" && next === "*") {
71404
71418
  const end = code.indexOf("*/", i + 2);
71405
71419
  const stop = end === -1 ? code.length : end + 2;
@@ -71418,11 +71432,39 @@ function stripCoverageComments(code) {
71418
71432
  }
71419
71433
  if (ch === '"' || ch === "'" || ch === "`")
71420
71434
  quote = ch;
71435
+ if (ch !== " " && ch !== " " && ch !== "\n" && ch !== "\r")
71436
+ prev = ch;
71421
71437
  i++;
71422
71438
  }
71423
71439
  out.push(code.slice(copyFrom));
71424
71440
  return out.join("");
71425
71441
  }
71442
+ function regexLiteralEnd3(code, start) {
71443
+ let inClass = false;
71444
+ for (let j = start + 1; j < code.length; j++) {
71445
+ const c = code[j];
71446
+ if (c === "\n")
71447
+ return -1;
71448
+ if (c === "\\") {
71449
+ j++;
71450
+ continue;
71451
+ }
71452
+ if (inClass) {
71453
+ if (c === "]")
71454
+ inClass = false;
71455
+ continue;
71456
+ }
71457
+ if (c === "[")
71458
+ inClass = true;
71459
+ else if (c === "/") {
71460
+ let k = j + 1;
71461
+ while (k < code.length && isIdentChar(code[k]))
71462
+ k++;
71463
+ return k;
71464
+ }
71465
+ }
71466
+ return -1;
71467
+ }
71426
71468
  function isIdentChar(ch) {
71427
71469
  if (!ch)
71428
71470
  return false;
@@ -72080,7 +72122,7 @@ function assessTitleCoverage(title, code) {
72080
72122
  const repeatedHit = [...repeated].some((term) => hay.includes(term));
72081
72123
  return { covered: hit >= needed || repeatedHit, missingTerms };
72082
72124
  }
72083
- var COVERAGE_STOP_WORDS, MAX_ASSERTION_JOIN_CHARS, MAX_COVERAGE_LINE_CHARS, BLOCK_SCAFFOLD, cachedAssertionInput, cachedAssertionSource, LOCAL_BINDING, ASSERTED_STATUS_RE, MAX_RESOLVED_NAMES_PER_LINE, WORD_CHAR_RE, NOT_CONTAIN_TEXT_RE, PLACE_PHRASE_RE, PLACE_WORD_MIN_CHARS, PLACE_FUNCTION_WORDS, HIDDEN_STATE_TERMS, HIDDEN_ELEMENT_LINE_RE, HIDDEN_LINE_RE, MAX_SHOWN_EARLIER_LINES, SHOWN_EARLIER_LITERAL_RE, SHARED_PREFIX_MIN_CHARS, MAX_SHOWN_EARLIER_LITERALS, VALUE_SHAPE_RE, VALUE_SHAPE_ALL_RE, TITLE_TERM_MIN;
72125
+ var COVERAGE_STOP_WORDS, MAX_ASSERTION_JOIN_CHARS, MAX_COVERAGE_LINE_CHARS, REGEX_PRECEDER2, BLOCK_SCAFFOLD, cachedAssertionInput, cachedAssertionSource, LOCAL_BINDING, ASSERTED_STATUS_RE, MAX_RESOLVED_NAMES_PER_LINE, WORD_CHAR_RE, NOT_CONTAIN_TEXT_RE, PLACE_PHRASE_RE, PLACE_WORD_MIN_CHARS, PLACE_FUNCTION_WORDS, HIDDEN_STATE_TERMS, HIDDEN_ELEMENT_LINE_RE, HIDDEN_LINE_RE, MAX_SHOWN_EARLIER_LINES, SHOWN_EARLIER_LITERAL_RE, SHARED_PREFIX_MIN_CHARS, MAX_SHOWN_EARLIER_LITERALS, VALUE_SHAPE_RE, VALUE_SHAPE_ALL_RE, TITLE_TERM_MIN;
72084
72126
  var init_expected_outcome_coverage = __esm({
72085
72127
  "../shared/dist/expected-outcome-coverage.js"() {
72086
72128
  "use strict";
@@ -72117,6 +72159,7 @@ var init_expected_outcome_coverage = __esm({
72117
72159
  ]);
72118
72160
  MAX_ASSERTION_JOIN_CHARS = 8e3;
72119
72161
  MAX_COVERAGE_LINE_CHARS = 2e3;
72162
+ REGEX_PRECEDER2 = "(,=:[!&|?{};+-*%<>~^";
72120
72163
  BLOCK_SCAFFOLD = /=>|\b(?:test|describe|it|beforeEach|afterEach|beforeAll|afterAll|function)\b/;
72121
72164
  cachedAssertionInput = null;
72122
72165
  cachedAssertionSource = { raw: "", normalized: "", bindings: /* @__PURE__ */ new Map(), bindingRefs: /* @__PURE__ */ new Map() };
@@ -72567,7 +72610,7 @@ function detectsErrorBannerAssertion(code) {
72567
72610
  const cleaned = stripCommentsAndLogs(stripLoginScaffolding(code));
72568
72611
  const lines = cleaned.split("\n");
72569
72612
  const candidates = [];
72570
- const positive = (stmt) => !NEGATED_ASSERT.test(stmt) && !ABSENCE_MATCHER.test(stmt);
72613
+ const positive = (stmt) => !claimsAbsence(stmt);
72571
72614
  const statements = liveExpectStatements(cleaned).map((s) => s.stmt);
72572
72615
  for (const stmt of statements) {
72573
72616
  if (positive(stmt))
@@ -72696,6 +72739,12 @@ function detectsObservedFailureAsExpected(code) {
72696
72739
  return FAILURE_STATUS_ASSERT.some((re) => re.test(stmt)) || hasFailedListener && FAILED_LIST_ASSERT.test(stmt);
72697
72740
  });
72698
72741
  }
72742
+ function claimsAbsence(stmt) {
72743
+ const negated = NEGATED_ASSERT_NOT.test(stmt);
72744
+ const bare = negated ? stmt.replace(NOT_BEFORE_MATCHER, ".") : stmt;
72745
+ const absenceMatcher = /\.toBeHidden\s*\(|\.toHaveCount\s*\(\s*0\s*\)/.test(bare) || VALUE_ABSENCE.test(bare) || OPTION_ABSENCE.test(bare);
72746
+ return negated !== absenceMatcher;
72747
+ }
72699
72748
  function isVacuousErrorAbsence(stmt, presence) {
72700
72749
  if (!ABSENCE_MATCHER.test(stmt))
72701
72750
  return false;
@@ -72711,19 +72760,53 @@ function isChromeTarget(stmt) {
72711
72760
  return CHROME_LOCATOR.test(stmt) && !CONTENT_ROLE.test(stmt) && !/getByText\s*\(/.test(stmt);
72712
72761
  }
72713
72762
  function countsAsContentText(stmt) {
72714
- if (!TEXT_CONTENT_MATCHER.test(stmt))
72763
+ if (!TEXT_CONTENT_MATCHER.test(stmt) || NEGATED_ASSERT.test(stmt))
72715
72764
  return false;
72716
72765
  if (isSymbolOnlyArgument(stmt, TEXT_CONTENT_MATCHER))
72717
72766
  return false;
72718
- if (!isChromeTarget(stmt))
72767
+ return onContentTarget(stmt);
72768
+ }
72769
+ function onContentTarget(stmt) {
72770
+ return !isChromeTarget(stmt) || /getByRole\s*\(\s*['"`]main['"`]/i.test(stmt);
72771
+ }
72772
+ function provesTextRemoved(stmt, presence) {
72773
+ const m = stmt.match(NEGATED_TEXT);
72774
+ if (!m || !onContentTarget(stmt))
72775
+ return false;
72776
+ const text = m[1] ?? m[2];
72777
+ if (text === void 0)
72719
72778
  return true;
72720
- return /getByRole\s*\(\s*['"`]main['"`]/i.test(stmt);
72779
+ if (!/[\p{L}\p{N}]/u.test(text))
72780
+ return false;
72781
+ return !ERROR_TEXT_WORDS.test(text) || presence().includes(text);
72721
72782
  }
72722
72783
  function isDataContentRole(stmt) {
72723
72784
  return CONTENT_ROLE.test(stmt) && !ANNOUNCE_ROLE.test(stmt);
72724
72785
  }
72786
+ function destructuresRequest(code) {
72787
+ let readTo = -1;
72788
+ for (const m of code.matchAll(ASYNC_DESTRUCTURE_OPEN)) {
72789
+ const start = m.index + m[0].length;
72790
+ if (start <= readTo)
72791
+ continue;
72792
+ let end = start;
72793
+ while (end < code.length && code[end] !== "}" && code[end] !== ")")
72794
+ end++;
72795
+ readTo = end;
72796
+ if (end === code.length)
72797
+ return false;
72798
+ if (code[end] !== "}" || !REQUEST_WORD.test(code.slice(start, end)))
72799
+ continue;
72800
+ let close = end + 1;
72801
+ while (close < code.length && /\s/.test(code[close]))
72802
+ close++;
72803
+ if (code[close] === ")")
72804
+ return true;
72805
+ }
72806
+ return false;
72807
+ }
72725
72808
  function isApiTest(code) {
72726
- const usesRequestFixture = /async\s*\(\s*\{[^})]*\brequest\b[^})]*\}\s*\)/.test(code) || /\brequest\.(get|post|put|patch|delete|head|fetch)\s*\(/.test(code);
72809
+ const usesRequestFixture = destructuresRequest(code) || /\brequest\.(get|post|put|patch|delete|head|fetch)\s*\(/.test(code);
72727
72810
  if (!usesRequestFixture)
72728
72811
  return false;
72729
72812
  const drivesUi = /\bpage\.(getBy\w+|locator|click|fill|goto|waitForURL|reload)\s*\(/.test(code) || /\.(click|fill|check|uncheck|selectOption|pressSequentially)\s*\(/.test(code);
@@ -72982,6 +73065,9 @@ function hasOnlyConstantAssertions(code) {
72982
73065
  const { constant, real } = constantAssertions(code);
72983
73066
  return constant.length > 0 && real === 0;
72984
73067
  }
73068
+ function envValueKey(name) {
73069
+ return `\0env:${name}`;
73070
+ }
72985
73071
  function enteredValues(stmts) {
72986
73072
  const values = /* @__PURE__ */ new Map();
72987
73073
  const navLines = [];
@@ -72990,24 +73076,55 @@ function enteredValues(stmts) {
72990
73076
  navLines.push(startLine);
72991
73077
  let m;
72992
73078
  ENTERED_VALUE.lastIndex = 0;
72993
- while (m = ENTERED_VALUE.exec(stmt)) {
72994
- const value = (m[1] ?? m[2] ?? m[3]).toLowerCase();
72995
- if (!values.has(value))
72996
- values.set(value, startLine);
72997
- }
73079
+ const add = (value) => {
73080
+ const lines = values.get(value);
73081
+ if (!lines)
73082
+ values.set(value, [startLine]);
73083
+ else if (lines[lines.length - 1] !== startLine)
73084
+ lines.push(startLine);
73085
+ };
73086
+ while (m = ENTERED_VALUE.exec(stmt))
73087
+ add((m[1] ?? m[2] ?? m[3]).toLowerCase());
73088
+ ENTERED_ENV.lastIndex = 0;
73089
+ while (m = ENTERED_ENV.exec(stmt))
73090
+ add(envValueKey(m[1] ?? m[2] ?? m[3] ?? m[4]));
72998
73091
  }
72999
73092
  return { values, navLines };
73000
73093
  }
73001
- function isEnteredValueEcho(stmt, entered, startLine) {
73094
+ function countBelow(lines, line) {
73095
+ let lo = 0;
73096
+ let hi = lines.length;
73097
+ while (lo < hi) {
73098
+ const mid = lo + hi >> 1;
73099
+ if (lines[mid] < line)
73100
+ lo = mid + 1;
73101
+ else
73102
+ hi = mid;
73103
+ }
73104
+ return lo;
73105
+ }
73106
+ function enteredLinesOf(stmt, entered) {
73002
73107
  const m = stmt.match(/\.toHaveValue\s*\(\s*(['"`])((?:(?!\1).)+)\1/);
73003
- if (!m)
73108
+ if (m)
73109
+ return entered.values.get(m[2].toLowerCase());
73110
+ const env = stmt.match(HAVE_VALUE_ENV);
73111
+ return env ? entered.values.get(envValueKey(env[1] ?? env[2])) : void 0;
73112
+ }
73113
+ function typedSinceLastNav(stmt, entered, startLine, lines = enteredLinesOf(stmt, entered)) {
73114
+ if (!lines || startLine === void 0)
73115
+ return false;
73116
+ const before = countBelow(lines, startLine);
73117
+ if (before === 0)
73004
73118
  return false;
73005
- const enteredAt = entered.values.get(m[2].toLowerCase());
73006
- if (enteredAt === void 0)
73119
+ return countBelow(entered.navLines, startLine) === countBelow(entered.navLines, lines[before - 1] + 1);
73120
+ }
73121
+ function isEnteredValueEcho(stmt, entered, startLine) {
73122
+ const lines = enteredLinesOf(stmt, entered);
73123
+ if (!lines)
73007
73124
  return false;
73008
- if (startLine === void 0)
73125
+ if (startLine === void 0 || lines[0] >= startLine)
73009
73126
  return true;
73010
- return !entered.navLines.some((n) => n > enteredAt && n < startLine);
73127
+ return typedSinceLastNav(stmt, entered, startLine, lines);
73011
73128
  }
73012
73129
  function isAnyValueMatcher(stmt) {
73013
73130
  if (/\.not\.toHaveValue\s*\(\s*(?:['"`]{2}|\/\^?\$?\/)/.test(stmt))
@@ -73097,6 +73214,43 @@ function hasAttributeTransition(stmts) {
73097
73214
  return true;
73098
73215
  return false;
73099
73216
  }
73217
+ function comparesWithItself(subject, tail) {
73218
+ const m = SELF_COMPARE_MATCHER.exec(tail);
73219
+ if (!m)
73220
+ return false;
73221
+ const args = balancedArguments(tail, m[0].length, MATCHER_ARGS_MAX);
73222
+ if (args === null)
73223
+ return false;
73224
+ const squash2 = (x) => x.replace(/^\s*await\s+/, "").replace(/\s+/g, "");
73225
+ const expected = squash2(args);
73226
+ return expected === squash2(m[1] === "toHaveCount" ? `${subject}.count()` : subject);
73227
+ }
73228
+ function asPlainAssertion(s) {
73229
+ const { stmt } = s;
73230
+ if (COUNT_AT_LEAST_ZERO.test(stmt))
73231
+ return [];
73232
+ const subject = extractExpectSubject(stmt);
73233
+ if (subject === null)
73234
+ return [s];
73235
+ const plain = subject.replace(/^await\s+/, "").trim();
73236
+ const subjectAt = stmt.indexOf(subject, stmt.search(EXPECT_CALL_RE));
73237
+ const tail = stmt.slice(subjectAt + subject.length).trimStart();
73238
+ const as = (rewritten) => [{ ...s, stmt: rewritten }];
73239
+ if (LOCATOR_EXPR.test(plain) && !LOCATOR_VALUE_READ.test(plain) && ALWAYS_TRUE_ON_OBJECT.test(tail))
73240
+ return [];
73241
+ if (DEFINED_VALUE_READ.test(plain) && ALWAYS_DEFINED.test(tail))
73242
+ return [];
73243
+ if (comparesWithItself(plain, tail))
73244
+ return [];
73245
+ const visible = /^(.+)\.\s*isVisible\s*\(\s*\)$/s.exec(plain);
73246
+ if (visible && IS_VISIBLE_TRUE.test(tail))
73247
+ return as(`await expect(${visible[1]}).toBeVisible();`);
73248
+ if (/^page\s*\.\s*(?:url|title)\s*\(\s*\)$/.test(plain) && PAGE_VALUE_MATCHER.test(tail)) {
73249
+ const matcher = plain.includes("url") ? "toHaveURL" : "toHaveTitle";
73250
+ return as(`await expect(page)${tail.replace(/^\)\s*\.\s*\w+\s*\(/, `.${matcher}(`)}`);
73251
+ }
73252
+ return [s];
73253
+ }
73100
73254
  function creditsOutcomeAlways(stmt, entered, startLine) {
73101
73255
  if (!OUTCOME_ALWAYS.some((re) => re.test(stmt)))
73102
73256
  return false;
@@ -73170,6 +73324,8 @@ function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstM
73170
73324
  continue;
73171
73325
  if (isVacuousErrorAbsence(stmt, presence))
73172
73326
  continue;
73327
+ if (COUNT_ONE.test(stmt) && quotedAssertedStrings(stmt).some((t) => clicked.has(t.toLowerCase())))
73328
+ continue;
73173
73329
  if (creditsOutcomeAlways(stmt, entered, startLine))
73174
73330
  return { kind: "durable" };
73175
73331
  if (mutated && !NEGATED_ASSERT.test(stmt) && MESSAGE_SURFACE.test(stmt) && OUTCOME_TEXT.test(assertedText(stmt))) {
@@ -73179,12 +73335,15 @@ function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstM
73179
73335
  else
73180
73336
  return { kind: "durable" };
73181
73337
  }
73182
- if (STATE_MATCHER.test(stmt) && (persistence && startLine !== void 0 ? reopenedAfterSave(startLine, persistence, persistence.reloadCalls) : reloaded))
73338
+ const retyped = typedSinceLastNav(stmt, entered, startLine);
73339
+ if (!retyped && STATE_MATCHER.test(stmt) && (persistence && startLine !== void 0 ? reopenedAfterSave(startLine, persistence, persistence.reloadCalls) : reloaded))
73183
73340
  return { kind: "durable" };
73184
- if (provesStoredControlValue(stmt, startLine, persistence))
73341
+ if (!retyped && provesStoredControlValue(stmt, startLine, persistence))
73185
73342
  return { kind: "durable" };
73186
73343
  if (countsAsContentText(stmt))
73187
73344
  return { kind: "durable" };
73345
+ if (provesTextRemoved(stmt, presence))
73346
+ return { kind: "durable" };
73188
73347
  if (mutated && VISIBILITY_MATCHER.test(stmt)) {
73189
73348
  const revealsText = GET_BY_TEXT.test(stmt) || HAS_TEXT_FILTER.test(stmt) || CONTENT_ROLE.test(stmt);
73190
73349
  if (revealsText && !isChromeTarget(stmt)) {
@@ -73251,7 +73410,7 @@ function detectOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMut
73251
73410
  function validateAssertionStrength(code, opts = {}) {
73252
73411
  const body = stripLoginScaffolding(code);
73253
73412
  const lines = body.split("\n");
73254
- const stmts = liveExpectStatements(stripCoverageComments(body));
73413
+ const stmts = liveExpectStatements(stripCoverageComments(body)).flatMap(asPlainAssertion);
73255
73414
  const base2 = (extra) => ({
73256
73415
  apiTest: false,
73257
73416
  interacted: false,
@@ -73457,7 +73616,7 @@ function validateAssertionStrength(code, opts = {}) {
73457
73616
  signals
73458
73617
  };
73459
73618
  }
73460
- var ERROR_BANNER, OUTCOME_ALWAYS, FORM_INPUT, ANY_CLICK, NAV_LOCATOR, URL_PROOF, RELOAD, EXPECT_STMT, BLOCK_SCAFFOLD2, TEST_BLOCK_OPEN, LOCATOR_BINDING, EXPECT_OPEN, STATE_MATCHER, CHROME_LOCATOR, CONTENT_ROLE, GET_BY_TEXT, BARE_CONTAINER_ROLE, HAS_TEXT_FILTER, OUTCOME_TEXT, SUCCESS_NOTICE_TEXT, NOT_A_SUCCESS_NOTICE, ANNOUNCE_ROLE, MESSAGE_SURFACE, TEXT_CONTENT_MATCHER, VISIBILITY_MATCHER, ADDITIVE_AFFORDANCE, EXCLUDE_AFFORDANCE, EMPTY_STATE_TEXT, AUTH_START, AUTH_END, LOGIN_CALL_LINE, INBOX_START, INBOX_END, NEGATED_ASSERT, CONST_CHAIN_MAX_DEPTH, TYPED_INPUT, TITLE_LINE, FAILURE_STATUS_ASSERT, FAILED_LIST_ASSERT, ENDPOINT_DOWN, NAVIGATION_RESPONSE_VAR, DIRECT_REQUEST_VAR, CATCH_ALL_PATTERN, GUARD_HANDLER, ABSENCE_MATCHER, ERROR_TEXT_WORDS, TEXT_REGEX_ARG, ROLE_NAME_RE, INTERACT_VERB, ROLE_SIG_RE, TRANSIENT_CONTROL_ROLES, POLL_CALLBACK, CONSTANT_WORD, CONSTANT_GLUE_CHARS, WORD_CHAR, MATCHER_ARGS_MAX, MATCHER_OPEN, ENTERED_VALUE, PAGE_NAV, IN_FLIGHT_TEXT, FORM_CONTROL_LOCATOR, CONTROL_VALUE_MATCHER, COPY_CONTROL, COPIED_NOTICE, SEND_CONTROL, SEND_NOTICE, MARK_READ_CONTROL, APP_DATA_FIELD;
73619
+ var ERROR_BANNER, OUTCOME_ALWAYS, FORM_INPUT, ANY_CLICK, NAV_LOCATOR, URL_PROOF, RELOAD, EXPECT_STMT, BLOCK_SCAFFOLD2, TEST_BLOCK_OPEN, LOCATOR_BINDING, EXPECT_OPEN, STATE_MATCHER, CHROME_LOCATOR, CONTENT_ROLE, GET_BY_TEXT, BARE_CONTAINER_ROLE, HAS_TEXT_FILTER, OUTCOME_TEXT, SUCCESS_NOTICE_TEXT, NOT_A_SUCCESS_NOTICE, ANNOUNCE_ROLE, MESSAGE_SURFACE, TEXT_CONTENT_MATCHER, VISIBILITY_MATCHER, ADDITIVE_AFFORDANCE, EXCLUDE_AFFORDANCE, EMPTY_STATE_TEXT, AUTH_START, AUTH_END, LOGIN_CALL_LINE, INBOX_START, INBOX_END, NEGATED_ASSERT, NEGATED_ASSERT_NOT, CONST_CHAIN_MAX_DEPTH, TYPED_INPUT, TITLE_LINE, FAILURE_STATUS_ASSERT, FAILED_LIST_ASSERT, ENDPOINT_DOWN, NAVIGATION_RESPONSE_VAR, DIRECT_REQUEST_VAR, CATCH_ALL_PATTERN, GUARD_HANDLER, ABSENCE_MATCHER, VALUE_ABSENCE, OPTION_ABSENCE, NOT_BEFORE_MATCHER, ERROR_TEXT_WORDS, TEXT_REGEX_ARG, NEGATED_TEXT, ASYNC_DESTRUCTURE_OPEN, REQUEST_WORD, ROLE_NAME_RE, INTERACT_VERB, ROLE_SIG_RE, TRANSIENT_CONTROL_ROLES, POLL_CALLBACK, CONSTANT_WORD, CONSTANT_GLUE_CHARS, WORD_CHAR, MATCHER_ARGS_MAX, MATCHER_OPEN, ENTERED_VALUE, PAGE_NAV, ENV_READ, ENTERED_ENV, HAVE_VALUE_ENV, IN_FLIGHT_TEXT, LOCATOR_VALUE_READ, LOCATOR_EXPR, ALWAYS_TRUE_ON_OBJECT, COUNT_AT_LEAST_ZERO, DEFINED_VALUE_READ, ALWAYS_DEFINED, SELF_COMPARE_MATCHER, IS_VISIBLE_TRUE, PAGE_VALUE_MATCHER, COUNT_ONE, FORM_CONTROL_LOCATOR, CONTROL_VALUE_MATCHER, COPY_CONTROL, COPIED_NOTICE, SEND_CONTROL, SEND_NOTICE, MARK_READ_CONTROL, APP_DATA_FIELD;
73461
73620
  var init_assertion_strength = __esm({
73462
73621
  "../shared/dist/assertion-strength.js"() {
73463
73622
  "use strict";
@@ -73482,8 +73641,8 @@ var init_assertion_strength = __esm({
73482
73641
  // form field value
73483
73642
  /\.toMatch\s*\(/,
73484
73643
  // string/regex content match (e.g. textContent() vs /[2-9] selected/)
73485
- /\.toBeDisabled\s*\(/,
73486
- // a control became DISABLED — a gating/validation outcome
73644
+ /(?<!\.not\s*)\.\s*toBeDisabled\s*\(/,
73645
+ // a control became DISABLED — a gating/validation outcome (not.toBeDisabled is the toBeEnabled twin)
73487
73646
  /\.not\.toBeVisible\s*\(/,
73488
73647
  /\.toBeHidden\s*\(/
73489
73648
  // something the action removed/closed (disappearance proof)
@@ -73491,7 +73650,7 @@ var init_assertion_strength = __esm({
73491
73650
  FORM_INPUT = /\.(fill|selectOption|setInputFiles|check|uncheck|setChecked|pressSequentially)\s*\(|keyboard\.type\s*\(/;
73492
73651
  ANY_CLICK = /\.click\s*\(/;
73493
73652
  NAV_LOCATOR = /getByRole\s*\(\s*['"`](?:link|menuitem)['"`]/i;
73494
- URL_PROOF = /\.toHaveURL\s*\(|\.waitForURL\s*\(/;
73653
+ URL_PROOF = /\.toHaveURL\s*\(|\.waitForURL\s*\(|\bexpect\s*\(\s*(?:await\s+)?page\s*\.\s*url\s*\(\s*\)\s*\)|\bexpect\s*\.\s*poll\s*\(\s*(?:async\s*)?\(\s*\)\s*=>\s*(?:\{\s*return\s+)?page\s*\.\s*url\s*\(\s*\)/;
73495
73654
  RELOAD = /\.reload\s*\(/;
73496
73655
  EXPECT_STMT = /\bexpect\s*[.(]/;
73497
73656
  BLOCK_SCAFFOLD2 = /=>|\b(?:test|describe|it|beforeEach|afterEach|beforeAll|afterAll|function)\b/;
@@ -73520,6 +73679,7 @@ var init_assertion_strength = __esm({
73520
73679
  INBOX_START = /^\s*\/\/\s*>>>\s*VALIDATE_QA_INBOX/;
73521
73680
  INBOX_END = /^\s*\/\/\s*<<<\s*VALIDATE_QA_INBOX/;
73522
73681
  NEGATED_ASSERT = /\.not\s*\.\s*to[A-Z]\w*|\.toBeHidden\s*\(/;
73682
+ NEGATED_ASSERT_NOT = /\.not\s*\.\s*to[A-Z]/;
73523
73683
  CONST_CHAIN_MAX_DEPTH = 5;
73524
73684
  TYPED_INPUT = /\.(fill|type|pressSequentially|setInputFiles)\s*\(/;
73525
73685
  TITLE_LINE = /^\s*(?:test|describe)(?:\.\w+)?\s*\(/;
@@ -73535,8 +73695,14 @@ var init_assertion_strength = __esm({
73535
73695
  CATCH_ALL_PATTERN = /^(['"`])\*\*(?:\/\*)?\1$|^\/\.\*\/[a-z]*$/;
73536
73696
  GUARD_HANDLER = /\bMUTATING\.has\s*\(|blockedbyclient|Read-only guard/;
73537
73697
  ABSENCE_MATCHER = /\.not\.toBeVisible\s*\(|\.toBeHidden\s*\(|\.toHaveCount\s*\(\s*0\s*\)/;
73698
+ VALUE_ABSENCE = /\.(?:count\s*\(\s*\)[\s)]{0,10}\.(?:(?:toBe|toEqual|toStrictEqual)\s*\(\s*0\s*\)|toBeLessThan\s*\(\s*1\s*\))|isVisible\s*\(\s*\)[\s)]{0,10}\.(?:(?:toBe|toEqual|toStrictEqual)\s*\(\s*false\s*\)|toBeFalsy\s*\()|isHidden\s*\(\s*\)[\s)]{0,10}\.(?:(?:toBe|toEqual|toStrictEqual)\s*\(\s*true\s*\)|toBeTruthy\s*\())/;
73699
+ OPTION_ABSENCE = /\.(?:toBeVisible\s*\(\s*\{[^{}()]{0,200}\bvisible|toBeAttached\s*\(\s*\{[^{}()]{0,200}\battached)\s*:\s*false\b/;
73700
+ NOT_BEFORE_MATCHER = /\.not\s*\.\s*(?=to[A-Z])/g;
73538
73701
  ERROR_TEXT_WORDS = /error|fail|wrong|try again|unable|could ?n.?t|can.?t|problem|invalid|unavailable/i;
73539
73702
  TEXT_REGEX_ARG = /(?:getByText|hasText|getByRole\([^)]{0,200}name)\s*[:(]\s*(\/(?:\\.|[^/\\\n])+\/[a-z]*)/;
73703
+ NEGATED_TEXT = /\.not\s*\.\s*(?:toHaveText|toContainText)\s*\(\s*(?:['"`]([^'"`]*)['"`]|\/((?:\\.|[^/\\\n])+)\/)?/;
73704
+ ASYNC_DESTRUCTURE_OPEN = /async\s*\(\s*\{/g;
73705
+ REQUEST_WORD = /\brequest\b/;
73540
73706
  ROLE_NAME_RE = /getByRole\s*\(\s*['"`][a-z]+['"`]\s*,\s*\{[^}]*?name\s*:\s*(?:['"`]([^'"`]+)['"`]|\/([^/]+)\/)/gi;
73541
73707
  INTERACT_VERB = /\.(click|fill|check|uncheck|setChecked|selectOption|pressSequentially)\s*\(/;
73542
73708
  ROLE_SIG_RE = /getByRole\s*\(\s*['"`]([a-z]+)['"`]\s*,\s*\{[^}]*?name\s*:\s*(?:['"`]([^'"`]+)['"`]|\/([^/]+)\/)/gi;
@@ -73557,7 +73723,20 @@ var init_assertion_strength = __esm({
73557
73723
  MATCHER_OPEN = /\s*(?:\.\s*(?:not|resolves|rejects)\s*)*\.\s*[A-Za-z_$][\w$]*\s*\(/y;
73558
73724
  ENTERED_VALUE = /\.(?:fill|pressSequentially)\s*\(\s*['"`]([^'"`]+)['"`]|keyboard\.type\s*\(\s*['"`]([^'"`]+)['"`]|\.selectOption\s*\(\s*(?:\[\s*)?(?:\{\s*(?:label|value)\s*:\s*)?['"`]([^'"`]+)['"`]/g;
73559
73725
  PAGE_NAV = /\.(?:goto|reload)\s*\(/;
73726
+ ENV_READ = String.raw`process\.env(?:(?:\?\.|\.)([A-Za-z_]\w*)|(?:\?\.)?\[\s*['"]([A-Za-z_]\w*)['"]\s*\])`;
73727
+ ENTERED_ENV = new RegExp(String.raw`\.(?:fill|pressSequentially)\s*\(\s*${ENV_READ}|keyboard\.type\s*\(\s*${ENV_READ}`, "g");
73728
+ HAVE_VALUE_ENV = new RegExp(String.raw`\.toHaveValue\s*\(\s*${ENV_READ}`);
73560
73729
  IN_FLIGHT_TEXT = /^(?:(?:sending|saving|loading|searching|checking|processing|submitting|preparing|updating|please wait|working|one moment)\b[^.]{0,40}\.{2,3}|\.{3}|…)$/i;
73730
+ LOCATOR_VALUE_READ = /\.(?:count|textContent|innerText|innerHTML|inputValue|getAttribute|isVisible|isHidden|isChecked|isEnabled|isDisabled|isEditable|allTextContents|allInnerTexts|evaluate|evaluateAll|boundingBox|all)\s*\(/;
73731
+ LOCATOR_EXPR = /^(?:this\.)?page\s*\.\s*(?:getBy\w+|locator)\s*\(/;
73732
+ ALWAYS_TRUE_ON_OBJECT = /^\)\s*\.\s*(?:toBeTruthy|toBeDefined|not\s*\.\s*(?:toBeNull|toBeUndefined|toBeFalsy))\s*\(/;
73733
+ COUNT_AT_LEAST_ZERO = /\.(?:count\s*\(\s*\)|length)[\s)]{0,10}\.(?:toBeGreaterThanOrEqual\s*\(\s*0\s*\)|toBeGreaterThan\s*\(\s*-\s*1\s*\))/;
73734
+ DEFINED_VALUE_READ = /\.\s*(?:count|textContent|innerText|innerHTML|inputValue|getAttribute|title|url|isVisible|isHidden|isChecked|isEnabled|isDisabled|isEditable|allTextContents|allInnerTexts)\s*\([^()]*\)$/;
73735
+ ALWAYS_DEFINED = /^\)\s*\.\s*(?:toBeDefined|not\s*\.\s*toBeUndefined)\s*\(/;
73736
+ SELF_COMPARE_MATCHER = /^\)\s*\.\s*(toBe|toEqual|toStrictEqual|toHaveCount)\s*\(/;
73737
+ IS_VISIBLE_TRUE = /^\)*\s*\.\s*(?:toBe\s*\(\s*true\s*\)|toBeTruthy\s*\(\s*\))/;
73738
+ PAGE_VALUE_MATCHER = /^\)\s*\.\s*(?:toBe|toEqual|toStrictEqual|toMatch|toContain)\s*\(/;
73739
+ COUNT_ONE = /\.\s*toHaveCount\s*\(\s*1\s*\)/;
73561
73740
  FORM_CONTROL_LOCATOR = /getByRole\s*\(\s*['"`](?:combobox|switch|checkbox|radio|textbox|searchbox|spinbutton|slider)['"`]|getByLabel\s*\(|getByPlaceholder\s*\(/;
73562
73741
  CONTROL_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(|\.toHaveAttribute\s*\(\s*['"`]aria-checked['"`]/;
73563
73742
  COPY_CONTROL = /\bcopy\b/i;
@@ -73766,7 +73945,7 @@ function reportedBugWhere() {
73766
73945
  function bugReviewStatus(status) {
73767
73946
  return status === "QUARANTINED" ? "confirmed" : "needs-review";
73768
73947
  }
73769
- var USER_CANCELLED_RUN_ERROR, HEAL_PATCH_HELD_RUN_ERROR_PREFIX, RUNNER_INTERRUPT_ERROR_PREFIX, SERVER_INTERRUPT_ERROR_PREFIX, RUN_LOST_ERROR_PREFIX, RUN_INTERRUPTED_ERROR_PREFIXES, RUN_INTERRUPTION_RETRIED_MARKER, RUN_INTERRUPTION_NOT_RETRIED_MARKERS, BUG_ASSERTION_TAG, UNEXPECTED_PASS_ERROR_PREFIX, BUG_TEST_BROKEN_ERROR_PREFIX, BUG_TEST_BROKEN_REASON, EMAIL_NOT_RECEIVED_PREFIXES, ENVIRONMENTAL_ERROR_PREFIXES, ENVIRONMENTAL_ERROR_STORED_PREFIXES, BUG_SURFACE_SUPPRESSING_TAGS, QUARANTINE_CLOSE_TAGS, BUG_CANDIDATE_TAG, BUG_TEST_BROKEN_TAG;
73948
+ var USER_CANCELLED_RUN_ERROR, HEAL_PATCH_HELD_RUN_ERROR_PREFIX, RUNNER_INTERRUPT_ERROR_PREFIX, SERVER_INTERRUPT_ERROR_PREFIX, RUN_LOST_ERROR_PREFIX, RUN_INTERRUPTED_ERROR_PREFIXES, RUN_INTERRUPTION_RETRIED_MARKER, RUN_INTERRUPTION_NOT_RETRIED_MARKERS, BUG_ASSERTION_TAG, UNEXPECTED_PASS_ERROR_PREFIX, BUG_TEST_BROKEN_ERROR_PREFIX, BUG_TEST_BROKEN_REASON, TEST_DID_NOT_RUN_ERROR, EMAIL_NOT_RECEIVED_PREFIXES, ENVIRONMENTAL_ERROR_PREFIXES, ENVIRONMENTAL_ERROR_STORED_PREFIXES, BUG_SURFACE_SUPPRESSING_TAGS, QUARANTINE_CLOSE_TAGS, BUG_CANDIDATE_TAG, BUG_TEST_BROKEN_TAG;
73770
73949
  var init_run_classification = __esm({
73771
73950
  "../shared/dist/run-classification.js"() {
73772
73951
  "use strict";
@@ -73786,6 +73965,7 @@ var init_run_classification = __esm({
73786
73965
  UNEXPECTED_PASS_ERROR_PREFIX = "UNEXPECTED_PASS:";
73787
73966
  BUG_TEST_BROKEN_ERROR_PREFIX = "BUG_TEST_BROKEN:";
73788
73967
  BUG_TEST_BROKEN_REASON = "bug test broken (not a bug verdict)";
73968
+ TEST_DID_NOT_RUN_ERROR = "Test did not run (a dependency failed or the run was interrupted)";
73789
73969
  EMAIL_NOT_RECEIVED_PREFIXES = [
73790
73970
  "VERIFICATION_EMAIL_NOT_RECEIVED:",
73791
73971
  "VERIFICATION_EMAIL_HAS_NO_CODE:",
@@ -76527,6 +76707,23 @@ var init_auth_block_detector = __esm({
76527
76707
  }
76528
76708
  });
76529
76709
 
76710
+ // ../shared/dist/auth-session-stamp.js
76711
+ function parseAuthSessionStamp(value) {
76712
+ if (!value || typeof value !== "object" || Array.isArray(value))
76713
+ return null;
76714
+ const { shared, role, generation } = value;
76715
+ if (shared !== true || role !== "producer" && role !== "follower")
76716
+ return null;
76717
+ return typeof generation === "string" && AUTH_SESSION_GENERATION_RE.test(generation) ? { shared: true, role, generation } : { shared: true, role };
76718
+ }
76719
+ var AUTH_SESSION_GENERATION_RE;
76720
+ var init_auth_session_stamp = __esm({
76721
+ "../shared/dist/auth-session-stamp.js"() {
76722
+ "use strict";
76723
+ AUTH_SESSION_GENERATION_RE = /^[0-9a-z]{1,16}$/;
76724
+ }
76725
+ });
76726
+
76530
76727
  // ../shared/dist/auth-state-freshness.js
76531
76728
  function isCsrfTokenName(name) {
76532
76729
  return /csrf|xsrf|forgery|authenticity|requestverification/.test(name.toLowerCase());
@@ -77755,7 +77952,7 @@ var init_agentic_cli_runtime = __esm({
77755
77952
  GROK_CLI_DEFAULT_MODEL = "grok-4.7";
77756
77953
  GROK_CLI_DEFAULT_REASONING_EFFORT = "high";
77757
77954
  CLAUDE_CLI_DEFAULT_MODEL = "claude-sonnet-5-5";
77758
- CLAUDE_CLI_DEFAULT_EFFORT = "max";
77955
+ CLAUDE_CLI_DEFAULT_EFFORT = "high";
77759
77956
  MUSE_CLI_DEFAULT_MODEL = "muse-spark-1.3-contributor";
77760
77957
  MUSE_CLI_DEFAULT_EFFORT = "high";
77761
77958
  CODEX_CLI_DEFAULT_MODEL = "gpt-6.1-sol";
@@ -77806,9 +78003,25 @@ function isOpenCodeGoModelId(id) {
77806
78003
  function hasOpenCodeGoPrefix(id) {
77807
78004
  return (id?.trim() ?? "").startsWith(OPENCODE_GO_PREFIX);
77808
78005
  }
78006
+ function hasOpenCodeGo2Prefix(id) {
78007
+ return (id?.trim() ?? "").startsWith(OPENCODE_GO_2_PREFIX);
78008
+ }
77809
78009
  function openCodeGoWireModel(id) {
77810
78010
  const trimmed = id?.trim() ?? "";
77811
- return isOpenCodeGoModelId(trimmed) ? trimmed.slice(OPENCODE_GO_PREFIX.length) : null;
78011
+ if (!isOpenCodeGoModelId(trimmed))
78012
+ return null;
78013
+ return trimmed.slice((hasOpenCodeGo2Prefix(trimmed) ? OPENCODE_GO_2_PREFIX : OPENCODE_GO_PREFIX).length);
78014
+ }
78015
+ function isZaiModelId(id) {
78016
+ const trimmed = id?.trim() ?? "";
78017
+ return ZAI_MODEL_PATTERN.test(trimmed) && !trimmed.includes("..");
78018
+ }
78019
+ function hasZaiPrefix(id) {
78020
+ return (id?.trim() ?? "").startsWith(ZAI_PREFIX);
78021
+ }
78022
+ function zaiWireModel(id) {
78023
+ const trimmed = id?.trim() ?? "";
78024
+ return isZaiModelId(trimmed) ? trimmed.slice(ZAI_PREFIX.length) : null;
77812
78025
  }
77813
78026
  function isEngineId(value) {
77814
78027
  return CLI_ENGINE_MODEL_IDS.includes(value);
@@ -77906,7 +78119,7 @@ function museCliContributorMode(env = process.env) {
77906
78119
  const raw = (env.MUSE_CLI_CONTRIBUTOR_MODE ?? "").trim().toLowerCase();
77907
78120
  return raw === "off" || raw === "false" || raw === "0" || raw === "no" ? "off" : "on";
77908
78121
  }
77909
- var CLI_ENGINE_MODEL_IDS, BROWSER_CLI_ENGINE_IDS, PIPELINE_STEPS, CLI_ENGINE_RULES, ENGINE_NAMES, OPENROUTER_PREFIX, OPENROUTER_MODEL_PATTERN, OPENCODE_GO_PREFIX, OPENCODE_GO_MODEL_PATTERN;
78122
+ var CLI_ENGINE_MODEL_IDS, BROWSER_CLI_ENGINE_IDS, PIPELINE_STEPS, CLI_ENGINE_RULES, ENGINE_NAMES, OPENROUTER_PREFIX, OPENROUTER_MODEL_PATTERN, OPENCODE_GO_PREFIX, OPENCODE_GO_2_PREFIX, OPENCODE_GO_MODEL_PATTERN, ZAI_PREFIX, ZAI_MODEL_PATTERN;
77910
78123
  var init_engine_spec = __esm({
77911
78124
  "../shared/dist/engine-spec.js"() {
77912
78125
  "use strict";
@@ -77965,7 +78178,10 @@ var init_engine_spec = __esm({
77965
78178
  OPENROUTER_PREFIX = "openrouter:";
77966
78179
  OPENROUTER_MODEL_PATTERN = /^openrouter:[a-z0-9][a-z0-9._-]{0,40}\/[A-Za-z0-9._:-]{1,100}$/;
77967
78180
  OPENCODE_GO_PREFIX = "opencode-go:";
77968
- OPENCODE_GO_MODEL_PATTERN = /^opencode-go:[a-z0-9][a-z0-9._-]{0,100}$/;
78181
+ OPENCODE_GO_2_PREFIX = "opencode-go-2:";
78182
+ OPENCODE_GO_MODEL_PATTERN = /^opencode-go(?:-2)?:[a-z0-9][a-z0-9._-]{0,100}$/;
78183
+ ZAI_PREFIX = "zai:";
78184
+ ZAI_MODEL_PATTERN = /^zai:glm-[a-z0-9][a-z0-9._-]{0,60}$/;
77969
78185
  }
77970
78186
  });
77971
78187
 
@@ -78250,6 +78466,8 @@ var init_api_model_catalog = __esm({
78250
78466
  authCaptureModel: "Login capture",
78251
78467
  plannerModel: "Scenario Planner",
78252
78468
  plannerGateModel: "Planner Gate",
78469
+ pwAgentsHealerModel: "Test Healer (Playwright agents)",
78470
+ pwAgentsReviewModel: "Plan Review (Playwright agents)",
78253
78471
  generationModel: "Code Generation",
78254
78472
  reviewModel: "Code Review",
78255
78473
  apiTestModel: "API Test Generator",
@@ -78274,11 +78492,6 @@ var init_api_model_catalog = __esm({
78274
78492
  });
78275
78493
 
78276
78494
  // ../shared/dist/provider-chains.js
78277
- function isClaudeModel(id) {
78278
- if (/claude|anthropic/i.test(id))
78279
- return true;
78280
- return API_MODEL_CATALOG.some((m) => m.provider === "anthropic" && (m.id === id || m.apiModel === id));
78281
- }
78282
78495
  function chainKey(modelId) {
78283
78496
  const id = canonicalModelId(modelId);
78284
78497
  if (!id)
@@ -78286,34 +78499,83 @@ function chainKey(modelId) {
78286
78499
  const entry = API_MODEL_CATALOG.find((m) => m.id === id || m.apiModel === id);
78287
78500
  return entry?.id ?? id;
78288
78501
  }
78502
+ function has(map2, key) {
78503
+ return Object.prototype.hasOwnProperty.call(map2, key);
78504
+ }
78289
78505
  function providerChainFor(modelId) {
78290
78506
  const key = chainKey(modelId);
78291
- if (!key || isClaudeModel(key))
78292
- return [];
78293
- return Object.prototype.hasOwnProperty.call(PROVIDER_CHAINS, key) ? PROVIDER_CHAINS[key] : [];
78507
+ return key && has(PROVIDER_CHAINS, key) ? PROVIDER_CHAINS[key] : [];
78508
+ }
78509
+ function providerChainLeadsFor(modelId) {
78510
+ const key = chainKey(modelId);
78511
+ return key && has(PROVIDER_CHAIN_LEADS, key) ? PROVIDER_CHAIN_LEADS[key] : [];
78512
+ }
78513
+ function allChains() {
78514
+ return [...Object.entries(PROVIDER_CHAINS), ...Object.entries(PROVIDER_CHAIN_LEADS)];
78294
78515
  }
78295
78516
  function isProviderChainHopId(modelId) {
78296
78517
  const id = modelId ?? "";
78297
- return id !== "" && Object.values(PROVIDER_CHAINS).some((hops) => hops.includes(id));
78518
+ return id !== "" && allChains().some(([, hops]) => hops.includes(id));
78298
78519
  }
78299
78520
  function providerChainPrimariesForHop(hopId) {
78300
78521
  const id = hopId ?? "";
78301
78522
  if (!id)
78302
78523
  return [];
78303
- return Object.entries(PROVIDER_CHAINS).filter(([, hops]) => hops.includes(id)).map(([primary]) => primary);
78524
+ return allChains().filter(([, hops]) => hops.includes(id)).map(([primary]) => primary);
78525
+ }
78526
+ function providerChainHostOf(value, modelValue) {
78527
+ if (value === modelValue)
78528
+ return "own";
78529
+ if (hasZaiPrefix(value))
78530
+ return "zai";
78531
+ if (hasOpenCodeGo2Prefix(value))
78532
+ return "opencode-go-2";
78533
+ if (hasOpenCodeGoPrefix(value))
78534
+ return "opencode-go";
78535
+ if (hasOpenRouterPrefix(value))
78536
+ return "openrouter";
78537
+ return "own";
78538
+ }
78539
+ function providerHostPlan(modelId) {
78540
+ const key = chainKey(modelId);
78541
+ if (!key)
78542
+ return [];
78543
+ const own = { host: hasOpenRouterPrefix(key) ? "openrouter" : "own", value: key };
78544
+ const steps = [
78545
+ ...providerChainLeadsFor(key).map((value) => ({ host: providerChainHostOf(value, key), value })),
78546
+ own,
78547
+ ...providerChainFor(key).map((value) => ({ host: providerChainHostOf(value, key), value }))
78548
+ ];
78549
+ const notOffered = Object.prototype.hasOwnProperty.call(PROVIDER_HOST_NOT_OFFERED, key) ? PROVIDER_HOST_NOT_OFFERED[key] : {};
78550
+ for (const [host, reason] of Object.entries(notOffered)) {
78551
+ const at = steps.findIndex((step) => step === own) + 1;
78552
+ steps.splice(at, 0, { host, value: null, notOffered: reason });
78553
+ }
78554
+ return steps;
78304
78555
  }
78305
- var PROVIDER_CHAINS;
78556
+ var PROVIDER_CHAINS, PROVIDER_CHAIN_LEADS, PROVIDER_HOST_NOT_OFFERED;
78306
78557
  var init_provider_chains = __esm({
78307
78558
  "../shared/dist/provider-chains.js"() {
78308
78559
  "use strict";
78309
78560
  init_api_model_catalog();
78561
+ init_engine_spec();
78310
78562
  PROVIDER_CHAINS = {
78311
- "minimax-m3": ["openrouter:minimax/minimax-m3", "opencode-go:minimax-m3"],
78312
- "minimax-m3.1-flash": ["openrouter:minimax/minimax-m3.1-flash", "opencode-go:minimax-m3.1-flash"],
78563
+ "minimax-m3": ["opencode-go:minimax-m3", "openrouter:minimax/minimax-m3"],
78564
+ "minimax-m3.1-flash": ["opencode-go:minimax-m3.1-flash", "openrouter:minimax/minimax-m3.1-flash"],
78313
78565
  "muse-spark-1.3-contributor": ["openrouter:meta/muse-spark-1.3-contributor"],
78314
- "openrouter:z-ai/glm-5.3-flash": ["opencode-go:glm-5.3-flash"],
78315
- "openrouter:z-ai/glm-5.3": ["opencode-go:glm-5.3"],
78316
- "openrouter:z-ai/glm-5.2": ["opencode-go:glm-5.2"]
78566
+ "claude-haiku-5-5": ["opencode-go:claude-haiku-5-5", "openrouter:anthropic/claude-haiku-5.5"],
78567
+ "gemini-3.1-pro-preview": ["openrouter:google/gemini-3.1-pro-preview"],
78568
+ "deepseek-flash": ["opencode-go-2:deepseek-v4.1-flash", "opencode-go:deepseek-v4.1-flash", "openrouter:deepseek/deepseek-v4.1-flash"],
78569
+ "deepseek-v4-pro": ["opencode-go-2:deepseek-v4-pro", "opencode-go:deepseek-v4-pro", "openrouter:deepseek/deepseek-v4-pro"]
78570
+ };
78571
+ PROVIDER_CHAIN_LEADS = {
78572
+ "openrouter:z-ai/glm-5.3-flash": ["zai:glm-5.3-flash", "opencode-go-2:glm-5.3-flash", "opencode-go:glm-5.3-flash"],
78573
+ "openrouter:z-ai/glm-5.3": ["zai:glm-5.3", "opencode-go-2:glm-5.3", "opencode-go:glm-5.3"],
78574
+ "openrouter:z-ai/glm-5.2": ["zai:glm-5.2", "opencode-go-2:glm-5.2", "opencode-go:glm-5.2"]
78575
+ };
78576
+ PROVIDER_HOST_NOT_OFFERED = {
78577
+ "muse-spark-1.3-contributor": { "opencode-go": "OpenCode Go serves Muse only on its Responses API" },
78578
+ "gemini-3.1-pro-preview": { "opencode-go": "OpenCode Go does not serve Gemini" }
78317
78579
  };
78318
78580
  }
78319
78581
  });
@@ -80272,7 +80534,7 @@ function stateLiteralsOf(line) {
80272
80534
  const out = [];
80273
80535
  for (const m of line.matchAll(STRING_LITERAL_RE)) {
80274
80536
  const text = m[1] ?? m[2] ?? m[3] ?? "";
80275
- if (text.includes("placeholder="))
80537
+ if (PLACEHOLDER_ATTR_RE.test(text))
80276
80538
  continue;
80277
80539
  if (PLACEHOLDER_CALL_TAIL_RE.test(line.slice(Math.max(0, m.index - 40), m.index)))
80278
80540
  continue;
@@ -80368,7 +80630,7 @@ function formatReadinessPollAdvisory(findings) {
80368
80630
  const where = findings.length === 1 ? "One place" : `${findings.length} places`;
80369
80631
  return `${where} re-check a background state once and assert the finished state at once (${short(first.line, 90)} then ${short(first.assertion, 90)}). ${first.reason}`;
80370
80632
  }
80371
- var READINESS_POLL_MAX_CODE_CHARS, MAX_LINE_CHARS, MAX_FINDINGS, ASSERTION_WINDOW_LINES, MAX_BLOCK_CHARS, MAX_HEAD_CHARS, STRING_LITERAL_RE, RECHECK_NAME_RE, RETRY_NAME_RE, PENDING_STATE_RE, LOCATOR_LINE_RE, CLICK_RE, RELOAD_RE, GOTO_RE, ACTION_RE, EXPECT_RE, NEGATED_RE, PENDING_ENDED_RE, POSITIVE_MATCHER_RE, ZERO_COUNT_RE, TEST_END_RE, TEST_START_RE, POLL_OPEN_RE, PLACEHOLDER_CALL_TAIL_RE, POLL_SHAPE;
80633
+ var READINESS_POLL_MAX_CODE_CHARS, MAX_LINE_CHARS, MAX_FINDINGS, ASSERTION_WINDOW_LINES, MAX_BLOCK_CHARS, MAX_HEAD_CHARS, STRING_LITERAL_RE, RECHECK_NAME_RE, RETRY_NAME_RE, PENDING_STATE_RE, LOCATOR_LINE_RE, CLICK_RE, RELOAD_RE, GOTO_RE, ACTION_RE, EXPECT_RE, NEGATED_RE, PENDING_ENDED_RE, POSITIVE_MATCHER_RE, ZERO_COUNT_RE, TEST_END_RE, TEST_START_RE, POLL_OPEN_RE, PLACEHOLDER_ATTR_RE, PLACEHOLDER_CALL_TAIL_RE, POLL_SHAPE;
80372
80634
  var init_readiness_poll = __esm({
80373
80635
  "../shared/dist/readiness-poll.js"() {
80374
80636
  "use strict";
@@ -80381,7 +80643,7 @@ var init_readiness_poll = __esm({
80381
80643
  STRING_LITERAL_RE = /'((?:\\.|[^'\\\n]){0,300})'|"((?:\\.|[^"\\\n]){0,300})"|`((?:\\.|[^`\\\n]){0,300})`/g;
80382
80644
  RECHECK_NAME_RE = /^\s{0,10}(?:check again|check (?:status|availability|now|for updates|progress)|re-?check(?: status)?|update status|see (?:latest|updates))\s{0,10}(?:\.\.\.|…)?\s{0,10}$/i;
80383
80645
  RETRY_NAME_RE = /^\s{0,10}(?:refresh(?: (?:status|list|page|results|now))?|reload(?: (?:page|results|list))?|try again|retry|load (?:again|latest))\s{0,10}(?:\.\.\.|…)?\s{0,10}$/i;
80384
- PENDING_STATE_RE = /\b(?:searching|checking|sending|pending|processing|queued|in progress|loading|generating|calculating|preparing|verifying|syncing|refreshing|not ready|please wait|waiting)\b|\b[a-z]{3,40}(?<!th)ing(?:\s{1,3}[a-z]{1,20}){0,2}\s{0,3}(?:\.\.\.|…)\s{0,10}$/i;
80646
+ PENDING_STATE_RE = /\b(?:searching|checking|sending|pending|processing|queued|in progress|loading|generating|calculating|preparing|verifying|syncing|refreshing|not ready|please wait|waiting)\b|\b(?:saving|uploading|downloading|signing|logging|submitting|creating|updating|deleting|importing|exporting|publishing|connecting|redirecting|authenticating|installing|retrieving|fetching|analy[sz]ing|running|rendering|restarting|building|compiling|booting|provisioning|deploying|indexing|migrating|launching|initiali[sz]ing|optimi[sz]ing|converting|processing)(?:\s{1,3}[a-z]{1,20}){0,2}\s{0,3}(?:\.\.\.|…)\s{0,10}$|^\s{0,10}(?:starting|scanning|working|applying|finishing)(?:\s{1,3}[a-z]{1,20}){0,2}\s{0,3}(?:\.\.\.|…)\s{0,10}$|^\s{0,10}[a-z]{3,40}(?<!th)ing\s{0,3}(?:\.\.\.|…)\s{0,10}$/i;
80385
80647
  LOCATOR_LINE_RE = /\.(?:getBy[A-Z]\w{0,30}|locator|toHaveText|toContainText)\s{0,20}\(/;
80386
80648
  CLICK_RE = /\.(?:click|dblclick|tap)\s{0,20}\(/;
80387
80649
  RELOAD_RE = /\bpage\.reload\s{0,20}\(/;
@@ -80395,6 +80657,7 @@ var init_readiness_poll = __esm({
80395
80657
  TEST_END_RE = /^\s{0,20}\}\s{0,20}\)\s{0,20};?\s{0,20}$/;
80396
80658
  TEST_START_RE = /\btest(?:\.\w{1,20})?\s{0,20}\(/;
80397
80659
  POLL_OPEN_RE = /\bexpect(?:\.soft)?\s{0,20}\(\s{0,20}async\b|\bexpect\.poll\s{0,20}\(|\bfor\s{0,20}\(|\bwhile\s{0,20}\(|\bdo\s{0,20}\{/g;
80660
+ PLACEHOLDER_ATTR_RE = /placeholder\s{0,4}[*^$~|]?=/;
80398
80661
  PLACEHOLDER_CALL_TAIL_RE = /getByPlaceholder\s{0,20}\(\s{0,20}$/;
80399
80662
  POLL_SHAPE = "await expect(async () => { await page.reload(); await expect(<the finished state>).toBeVisible({ timeout: 1500 }); }).toPass({ timeout: 20000 });";
80400
80663
  }
@@ -80796,6 +81059,15 @@ function computes(line) {
80796
81059
  const code = line.replace(STRING_RE, '""').replace(REGEX_LITERAL_RE, "$1RX").replace(LITERAL_ARITH_RE, "N");
80797
81060
  return COMPUTE_RE.test(code) || RELATIONAL_RE.test(line);
80798
81061
  }
81062
+ function identifiersIn(line) {
81063
+ const code = line.replace(STRING_RE, '""').replace(REGEX_LITERAL_RE, "$1RX");
81064
+ return [code, ...[...line.matchAll(TEMPLATE_EXPR_RE)].map((m) => m[1])].flatMap((part) => part.match(IDENTIFIER_RE) ?? []);
81065
+ }
81066
+ function addTyped(typed, value) {
81067
+ const d = digitsOf(value);
81068
+ if (/\d/.test(d))
81069
+ typed.add(d);
81070
+ }
80799
81071
  function reasonFor4(kind, label, value) {
80800
81072
  const what = kind === "derived-value-shape-only" ? `The ${label} is checked only for its shape, so any amount passes, including a wrongly computed one.` : `The ${label} is checked against a number written into the test (${value}). That number was read off the page, so when the page computes it wrong the check still passes.`;
80801
81073
  return `${what} Instead, ${COMPUTE_SHAPE} If the number is not computed from other values (a list price, an id, a fixed fee), leave it as it is. Keep the existing checks.`;
@@ -80807,25 +81079,32 @@ function analyzeDerivedValues(rawCode) {
80807
81079
  for (const body of testBodies(rawCode)) {
80808
81080
  if (findings.length >= MAX_FINDINGS4)
80809
81081
  break;
80810
- if (body.some(computes))
80811
- continue;
80812
81082
  const typed = /* @__PURE__ */ new Set();
80813
81083
  const definitions = /* @__PURE__ */ new Map();
81084
+ const computed = /* @__PURE__ */ new Set();
81085
+ const usesComputed = (text) => identifiersIn(text).some((id) => computed.has(id));
80814
81086
  for (const line of body) {
80815
81087
  if (FILL_RE2.test(line) && !EXPECT_RE3.test(line)) {
80816
- for (const m of line.matchAll(/['"`]([^'"`\n]{0,40})['"`]/g)) {
80817
- const d = digitsOf(m[1]);
80818
- if (/\d/.test(d))
80819
- typed.add(d);
80820
- }
81088
+ for (const m of line.matchAll(QUOTED_RE))
81089
+ addTyped(typed, m[1]);
81090
+ const arg = FILL_ARG_RE.exec(line)?.[1];
81091
+ const literal = arg === void 0 ? null : LITERAL_VALUE_RE.exec(definitions.get(arg) ?? "");
81092
+ const value = literal?.slice(1).find((v) => v !== void 0);
81093
+ if (value !== void 0)
81094
+ addTyped(typed, value);
80821
81095
  }
80822
81096
  const def = DEFINITION_RE.exec(line);
80823
- if (def)
81097
+ if (def) {
80824
81098
  definitions.set(def[1], def[2]);
81099
+ if (computes(def[2]) || usesComputed(def[2]))
81100
+ computed.add(def[1]);
81101
+ }
80825
81102
  }
80826
81103
  for (const line of body) {
80827
81104
  if (!EXPECT_RE3.test(line) || !VALUE_MATCHER_RE2.test(line) || /\.not\s{0,20}\./.test(line))
80828
81105
  continue;
81106
+ if (computes(line) || usesComputed(line))
81107
+ continue;
80829
81108
  const subject = EXPECT_SUBJECT_RE.exec(line)?.[1];
80830
81109
  const label = DERIVED_WORD_RE.exec(`${line} ${(subject && definitions.get(subject)) ?? ""}`)?.[0];
80831
81110
  if (!label)
@@ -80855,7 +81134,7 @@ function formatDerivedValueAdvisory(findings) {
80855
81134
  const where = findings.length === 1 ? "One computed value is" : `${findings.length} computed values are`;
80856
81135
  return `${where} checked against a copied number or only its shape (${short4(first.line, 90)}). ${first.reason}`;
80857
81136
  }
80858
- var MAX_FINDINGS4, EXPECT_RE3, DERIVED_WORD_RE, VALUE_MATCHER_RE2, MONEY_TOKEN_RE, SHAPE_ARG_RE, FILL_RE2, EXPECT_MESSAGE_RE, STRING_RE, REGEX_LITERAL_RE, COMPUTE_RE, RELATIONAL_RE, DEFINITION_RE, EXPECT_SUBJECT_RE, LITERAL_ARITH_RE, COMPUTE_SHAPE;
81137
+ var MAX_FINDINGS4, EXPECT_RE3, DERIVED_WORD_RE, VALUE_MATCHER_RE2, MONEY_TOKEN_RE, SHAPE_ARG_RE, FILL_RE2, EXPECT_MESSAGE_RE, STRING_RE, REGEX_LITERAL_RE, COMPUTE_RE, RELATIONAL_RE, DEFINITION_RE, EXPECT_SUBJECT_RE, LITERAL_ARITH_RE, TEMPLATE_EXPR_RE, IDENTIFIER_RE, QUOTED_RE, FILL_ARG_RE, LITERAL_VALUE_RE, COMPUTE_SHAPE;
80859
81138
  var init_derived_value_check = __esm({
80860
81139
  "../shared/dist/derived-value-check.js"() {
80861
81140
  "use strict";
@@ -80875,6 +81154,11 @@ var init_derived_value_check = __esm({
80875
81154
  DEFINITION_RE = /\b(?:const|let)\s{1,10}([\w$]{1,60})\s{0,10}=\s{0,10}([^\n]{0,300})/;
80876
81155
  EXPECT_SUBJECT_RE = /\bexpect(?:\.soft)?\s{0,20}\(\s{0,20}([\w$]{1,60})/;
80877
81156
  LITERAL_ARITH_RE = /\b\d[\d_.]{0,15}(?:\s{0,5}[*/+-]\s{0,5}\d[\d_.]{0,15}){1,8}\b/g;
81157
+ TEMPLATE_EXPR_RE = /\$\{([^{}\n]{0,200})\}/g;
81158
+ IDENTIFIER_RE = /[A-Za-z_$][\w$]{0,60}/g;
81159
+ QUOTED_RE = /['"`]([^'"`\n]{0,40})['"`]/g;
81160
+ FILL_ARG_RE = /\.(?:fill|type|pressSequentially|selectOption)\s{0,20}\(\s{0,20}([A-Za-z_$][\w$]{0,60})\s{0,20}[,)]/;
81161
+ LITERAL_VALUE_RE = /^\s{0,10}(?:'([^'\n]{0,40})'|"([^"\n]{0,40})"|`([^`$\n]{0,40})`|(\d[\d_,]{0,15}(?:\.\d{1,4})?))\s{0,10};?\s{0,10}$/;
80878
81162
  COMPUTE_SHAPE = "compute the expected value in the test from its inputs (the values the test typed, or each input read from the page) and compare: const toNumber = (s) => Number(s.replace(/[^\\d.-]/g, '')); const unit = toNumber(await <unit price locator>.innerText()); then expect(toNumber(await <shown value locator>.innerText())).toBeCloseTo(unit * quantity, 2); for several lines, read them all and sum them with reduce. For a comma-decimal price like \u20AC1.234,56, drop the dots and turn the comma into a point before Number, since the replace above would read it as 1.23456.";
80879
81163
  }
80880
81164
  });
@@ -82909,6 +83193,99 @@ function formatStaleAfterSubmitAdvisory(rawCode) {
82909
83193
  const more = described.length > 3 ? ` (+${described.length - 3} more)` : "";
82910
83194
  return `stale-after-submit: ${described.slice(0, 3).join("; ")}${more}; these pass before the request lands and still pass if the server rejects or ignores the save. Wait for the result instead: page.waitForResponse around the click, or assert something the submit creates (the new row, the confirmation message, a path with an end anchor such as /\\/orders\\/\\d+$/)`;
82911
83195
  }
83196
+ function regexLiteralEnd4(text, at) {
83197
+ let inClass = false;
83198
+ for (let i = at + 1; i < text.length; i++) {
83199
+ const ch = text[i];
83200
+ if (ch === "\n")
83201
+ return -1;
83202
+ if (ch === "\\") {
83203
+ i++;
83204
+ continue;
83205
+ }
83206
+ if (inClass) {
83207
+ if (ch === "]")
83208
+ inClass = false;
83209
+ continue;
83210
+ }
83211
+ if (ch === "[") {
83212
+ inClass = true;
83213
+ continue;
83214
+ }
83215
+ if (ch === "/")
83216
+ return i + 1;
83217
+ }
83218
+ return -1;
83219
+ }
83220
+ function startsWithRegexLiteral(text) {
83221
+ const t = text.trimStart();
83222
+ return t[0] === "/" && t[1] !== "/" && t[1] !== "*" && regexLiteralEnd4(t, 0) !== -1;
83223
+ }
83224
+ function afterFirstArg(args) {
83225
+ let depth = 0;
83226
+ let quote = null;
83227
+ for (let i = 0; i < args.length; i++) {
83228
+ const ch = args[i];
83229
+ if (quote) {
83230
+ if (ch === "\\") {
83231
+ i++;
83232
+ continue;
83233
+ }
83234
+ if (ch === quote)
83235
+ quote = null;
83236
+ continue;
83237
+ }
83238
+ if (ch === '"' || ch === "'" || ch === "`") {
83239
+ quote = ch;
83240
+ continue;
83241
+ }
83242
+ if (ch === "(" || ch === "[" || ch === "{")
83243
+ depth++;
83244
+ else if (ch === ")" || ch === "]" || ch === "}")
83245
+ depth--;
83246
+ else if (ch === "," && depth === 0)
83247
+ return args.slice(i + 1);
83248
+ }
83249
+ return "";
83250
+ }
83251
+ function analyzeRegexMatchers(rawCode) {
83252
+ if (!rawCode || typeof rawCode !== "string")
83253
+ return [];
83254
+ const code = stripComments2(rawCode.slice(0, MAX_LINT_INPUT));
83255
+ const out = [];
83256
+ const re = /\bexpect(?:\.soft)?\s{0,20}\(/g;
83257
+ let m;
83258
+ let examined = 0;
83259
+ let line = 1;
83260
+ let lineAt2 = 0;
83261
+ while ((m = re.exec(code)) !== null && examined++ < MAX_CALLS && out.length < MAX_REGEX_MATCHER_FINDINGS) {
83262
+ const subj = readBalanced(code, m.index + m[0].length);
83263
+ if (!subj)
83264
+ continue;
83265
+ const mm = /^\s{0,20}(\.\s{0,20}not)?\s{0,20}\.\s{0,20}(\w{1,40})\s{0,20}\(/.exec(code.slice(subj.end + 1, subj.end + 1 + 80));
83266
+ if (!mm || !REGEX_EQUALITY_MATCHERS.has(mm[2]))
83267
+ continue;
83268
+ const args = readBalanced(code, subj.end + 1 + mm[0].length);
83269
+ if (!args)
83270
+ continue;
83271
+ const expected = mm[2] === "toHaveJSProperty" ? afterFirstArg(args.text) : args.text;
83272
+ if (!startsWithRegexLiteral(expected))
83273
+ continue;
83274
+ if (mm[2] !== "toHaveJSProperty" && mm[2] !== "toContain" && (startsWithRegexLiteral(subj.text) || /^new\s+RegExp\b/.test(subj.text.trim())))
83275
+ continue;
83276
+ for (let i = code.indexOf("\n", lineAt2); i !== -1 && i < m.index; i = code.indexOf("\n", i + 1)) {
83277
+ line++;
83278
+ lineAt2 = i + 1;
83279
+ }
83280
+ out.push({ line, matcher: mm[2], negated: mm[1] !== void 0 });
83281
+ }
83282
+ return out;
83283
+ }
83284
+ function formatRegexMatcherNote(findings) {
83285
+ const lines = findings.map((f) => `Line ${f.line}: .${f.negated ? "not." : ""}${f.matcher}(\u2026 /regex/ \u2026) ${f.negated ? "always passes (a regex never equals the value), so it checks nothing" : "can never pass: this matcher compares by equality and a regex never equals a value"}.`);
83286
+ return `${lines.join("\n")}
83287
+ A regex only works in toMatch, toHaveText, toContainText, toHaveValue and similar text matchers. For a DOM property read it first: expect(await loc.evaluate((n) => n.<prop>)).toMatch(/re/). Or give toHaveJSProperty the exact string (or boolean) the page shows. Keep every other line as-is.`;
83288
+ }
82912
83289
  function lintTestQuality(rawCode, opts = {}) {
82913
83290
  if (!rawCode || typeof rawCode !== "string")
82914
83291
  return [];
@@ -82916,6 +83293,10 @@ function lintTestQuality(rawCode, opts = {}) {
82916
83293
  return lintTestData(rawCode, { pageContacts: opts.pageContacts });
82917
83294
  if (opts.only === "test-data-blocking")
82918
83295
  return analyzeTestData(rawCode, { pageContacts: opts.pageContacts }).blocking;
83296
+ if (opts.only === "regex-matcher") {
83297
+ const found = analyzeRegexMatchers(rawCode);
83298
+ return found.length > 0 ? [formatRegexMatcherNote(found)] : [];
83299
+ }
82919
83300
  const warnings = [];
82920
83301
  if (rawCode.length > MAX_LINT_INPUT) {
82921
83302
  warnings.push(`The code is ${Math.round(rawCode.length / 1024)} KB; the quality lint checked only the first ${MAX_LINT_INPUT / 1e3} KB. Split it into smaller tests (one behaviour per test).`);
@@ -83190,7 +83571,7 @@ function specItemsFromTestPlans(testPlans) {
83190
83571
  }
83191
83572
  return [...new Set(out)].slice(0, 200);
83192
83573
  }
83193
- var READ_ONLY_TAGS, PRODUCTION_READ_ONLY_GUARD_TEMPLATE, HOST_AGNOSTIC_URL_TEMPLATE, TEST_QUALITY_CONVENTIONS, NON_PROD_HOST_LABEL, NON_PROD_HOST_TOKEN, TRANSIENT_TEXT, STRING_LITERAL, FIRST_LITERAL, GET_BY_TEXT_LITERAL2, ROLE_NAME_LITERAL2, MAX_LINT_INPUT, MAX_BALANCED_SCAN, MAX_CALLS, MAX_SEEN_SCAN, ACTION_CALL, BY_NAME_LOCATOR, ACTION_AFTER, MAX_CONTACTS, MAX_SNAPSHOT_SCAN, PHONE_IN_TEXT, EMAIL_IN_TEXT, TEL_HREF, MAILTO_HREF, FIELD_LINE, INBOX_EMAIL_READ, MAIL_READ_CALL, RESERVED_EMAIL_TLD, PHONE_LABEL, NON_PHONE_NUMBER_LABEL, IDENTITY_LABEL, LOOKUP_LABEL, NON_NAME_SUFFIX_LABEL, DATE_LIKE, SIGNUP_ACTION_NAME, SIGNUP_SUBMIT_NAME, LOGIN_ACTION_NAME, SIGNUP_GOTO, LOGIN_GOTO, MINTED_INBOX_ALIAS, STAMP_EVAL, RECORDING_VALUE_PLACEHOLDERS, NEGATIVE_TEST_TITLE, NEGATIVE_SIGNUP_ASSERT, STORED_LOGIN_RE, CONFIRM_CLICK_RE, SAVE_UPDATE_RE, NOT_A_CONFIRM_RE, ENTITY_WORDS, CREATE_ENTITY_CLICK_RE, RESTORE_CLICK_RE, MAX_ACCOUNT_ACTIONS, MAX_TRY_BLOCKS, MAX_STATEMENT_LOOKBACK, MAX_FINDINGS5, MAX_TRY_BODY, AUTH_REGION_START, AUTH_REGION_END, INBOX_REGION_START, INBOX_REGION_END, ACCOUNT_ROUTE_RE, ENTITY_WORD_RES, PERSIST_CALL_RE, FILL_IDENT_ARG_RE, PERSIST_ARGS_RE, HOST_IN_URL_ARG, URL_WAIT_TOKEN, GLOB_ESCAPED, URL_WAIT_MAX_PATH, URL_WAIT_MAX_GLOB_STARS, UNREACHED_MAX_PATHS, UNREACHED_MATCH_BUDGET, STALE_TOKEN, RESULT_WAIT, WRITE_CALL_PRESENT, SUBMIT_CALL_PRESENT, TEST_CALL, VALUE_WRITE_CALLS, SUBMIT_CALLS, DISTINCT_PAGE_CALLS, OWN_CONTROL_MATCHERS, OUTCOME_CONTENT_MATCHERS, OUTCOME_STATE_MATCHERS, ANY_CONTENT_ARG, ROOT_SUBJECT, LITERAL_SUBJECT, MATCHER_AFTER_EXPECT, STALE_MAX_EVENTS, CHECKED, UNCHECKED, squash, NOT_JUDGED, STALE_REASON_TEXT, LIVE_WRITE_NAME, BUNDLED_CHECKS_BEFORE_WRITE, STOP, SYNONYMS, AREA_TOKENS;
83574
+ var READ_ONLY_TAGS, PRODUCTION_READ_ONLY_GUARD_TEMPLATE, HOST_AGNOSTIC_URL_TEMPLATE, TEST_QUALITY_CONVENTIONS, NON_PROD_HOST_LABEL, NON_PROD_HOST_TOKEN, TRANSIENT_TEXT, STRING_LITERAL, FIRST_LITERAL, GET_BY_TEXT_LITERAL2, ROLE_NAME_LITERAL2, MAX_LINT_INPUT, MAX_BALANCED_SCAN, MAX_CALLS, MAX_SEEN_SCAN, ACTION_CALL, BY_NAME_LOCATOR, ACTION_AFTER, MAX_CONTACTS, MAX_SNAPSHOT_SCAN, PHONE_IN_TEXT, EMAIL_IN_TEXT, TEL_HREF, MAILTO_HREF, FIELD_LINE, INBOX_EMAIL_READ, MAIL_READ_CALL, RESERVED_EMAIL_TLD, PHONE_LABEL, NON_PHONE_NUMBER_LABEL, IDENTITY_LABEL, LOOKUP_LABEL, NON_NAME_SUFFIX_LABEL, DATE_LIKE, SIGNUP_ACTION_NAME, SIGNUP_SUBMIT_NAME, LOGIN_ACTION_NAME, SIGNUP_GOTO, LOGIN_GOTO, MINTED_INBOX_ALIAS, STAMP_EVAL, RECORDING_VALUE_PLACEHOLDERS, NEGATIVE_TEST_TITLE, NEGATIVE_SIGNUP_ASSERT, STORED_LOGIN_RE, CONFIRM_CLICK_RE, SAVE_UPDATE_RE, NOT_A_CONFIRM_RE, ENTITY_WORDS, CREATE_ENTITY_CLICK_RE, RESTORE_CLICK_RE, MAX_ACCOUNT_ACTIONS, MAX_TRY_BLOCKS, MAX_STATEMENT_LOOKBACK, MAX_FINDINGS5, MAX_TRY_BODY, AUTH_REGION_START, AUTH_REGION_END, INBOX_REGION_START, INBOX_REGION_END, ACCOUNT_ROUTE_RE, ENTITY_WORD_RES, PERSIST_CALL_RE, FILL_IDENT_ARG_RE, PERSIST_ARGS_RE, HOST_IN_URL_ARG, URL_WAIT_TOKEN, GLOB_ESCAPED, URL_WAIT_MAX_PATH, URL_WAIT_MAX_GLOB_STARS, UNREACHED_MAX_PATHS, UNREACHED_MATCH_BUDGET, STALE_TOKEN, RESULT_WAIT, WRITE_CALL_PRESENT, SUBMIT_CALL_PRESENT, TEST_CALL, VALUE_WRITE_CALLS, SUBMIT_CALLS, DISTINCT_PAGE_CALLS, OWN_CONTROL_MATCHERS, OUTCOME_CONTENT_MATCHERS, OUTCOME_STATE_MATCHERS, ANY_CONTENT_ARG, ROOT_SUBJECT, LITERAL_SUBJECT, MATCHER_AFTER_EXPECT, STALE_MAX_EVENTS, CHECKED, UNCHECKED, squash, NOT_JUDGED, STALE_REASON_TEXT, LIVE_WRITE_NAME, BUNDLED_CHECKS_BEFORE_WRITE, MAX_REGEX_MATCHER_FINDINGS, REGEX_EQUALITY_MATCHERS, STOP, SYNONYMS, AREA_TOKENS;
83194
83575
  var init_test_authoring_quality = __esm({
83195
83576
  "../shared/dist/test-authoring-quality.js"() {
83196
83577
  "use strict";
@@ -83422,6 +83803,8 @@ var init_test_authoring_quality = __esm({
83422
83803
  };
83423
83804
  LIVE_WRITE_NAME = /\b(?:submit|place|book|reserve|confirm|pay|send|checkout|order|register|sign\s?up|create account)\b/i;
83424
83805
  BUNDLED_CHECKS_BEFORE_WRITE = 5;
83806
+ MAX_REGEX_MATCHER_FINDINGS = 10;
83807
+ REGEX_EQUALITY_MATCHERS = /* @__PURE__ */ new Set(["toBe", "toEqual", "toStrictEqual", "toContain", "toHaveJSProperty"]);
83425
83808
  STOP = /* @__PURE__ */ new Set([
83426
83809
  "a",
83427
83810
  "an",
@@ -83650,6 +84033,19 @@ var init_fence_runs = __esm({
83650
84033
  }
83651
84034
  });
83652
84035
 
84036
+ // ../shared/dist/trailing-slashes.js
84037
+ function stripTrailingSlashes(value) {
84038
+ let end = value.length;
84039
+ while (end > 0 && value.charCodeAt(end - 1) === 47)
84040
+ end--;
84041
+ return end === value.length ? value : value.slice(0, end);
84042
+ }
84043
+ var init_trailing_slashes = __esm({
84044
+ "../shared/dist/trailing-slashes.js"() {
84045
+ "use strict";
84046
+ }
84047
+ });
84048
+
83653
84049
  // ../shared/dist/survey-bug-signature.js
83654
84050
  function normalizeWords(text) {
83655
84051
  return text.toLowerCase().replace(UUID, " id ").replace(PREFIXED_ID, " id ").replace(HEX_RUN, (run) => /\d/.test(run) ? " id " : run).replace(NUMBER_RUN, " # ").replace(/[^\p{L}\p{N}#]+/gu, " ").replace(/\s+/g, " ").trim();
@@ -83660,7 +84056,7 @@ function normalizeBugPath(route) {
83660
84056
  if (hash >= 0 && path[hash + 1] !== "/")
83661
84057
  path = path.slice(0, hash);
83662
84058
  const segments = path.toLowerCase().split("/").map((segment) => /\d/.test(segment) ? ":id" : segment);
83663
- const joined = segments.join("/").replace(/\/+$/, "");
84059
+ const joined = stripTrailingSlashes(segments.join("/"));
83664
84060
  return joined || (path.startsWith("/") ? "/" : "");
83665
84061
  }
83666
84062
  function isGenericConsoleMessage(message) {
@@ -83794,6 +84190,7 @@ var SIGNATURE_SOURCE_MAX_CHARS, UUID, PREFIXED_ID, HEX_RUN, NUMBER_RUN, GENERIC_
83794
84190
  var init_survey_bug_signature = __esm({
83795
84191
  "../shared/dist/survey-bug-signature.js"() {
83796
84192
  "use strict";
84193
+ init_trailing_slashes();
83797
84194
  SIGNATURE_SOURCE_MAX_CHARS = 800;
83798
84195
  UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/g;
83799
84196
  PREFIXED_ID = /\b[a-z]{1,8}[-_]\d+\b/g;
@@ -85074,9 +85471,9 @@ function lastLocatorLabels(chain) {
85074
85471
  if (t)
85075
85472
  labels.push(t[1]);
85076
85473
  }
85077
- const has = optionText(last.args, HAS_TEXT_OPTION_RE);
85078
- if (has !== null)
85079
- labels.push(has);
85474
+ const has2 = optionText(last.args, HAS_TEXT_OPTION_RE);
85475
+ if (has2 !== null)
85476
+ labels.push(has2);
85080
85477
  }
85081
85478
  return labels.map((l) => l.replace(/^[\s^(?:]+/, "").trim());
85082
85479
  }
@@ -85833,14 +86230,17 @@ var init_promotion_quality_gate = __esm({
85833
86230
  SOURCE_RANK = { generator: 0, classifier: 0, healer: 1, human: 2 };
85834
86231
  strengthCheck = {
85835
86232
  id: "assertion-strength",
85836
- run({ code, strengthGate, flagContradictedAdditions }) {
86233
+ run({ code, tags, strengthGate, flagContradictedAdditions }) {
85837
86234
  const verdict = validateAssertionStrength(code, { flagContradictedAdditions: flagContradictedAdditions === true });
85838
86235
  if (verdict.severity === "route-bug")
85839
86236
  return [{ check: "route-bug" }];
85840
- if (verdict.severity !== "block")
86237
+ const authDowngrade = verdict.severity === "downgrade" && tags.some((t) => t.toLowerCase() === "@auth");
86238
+ if (verdict.severity !== "block" && !authDowngrade)
85841
86239
  return [];
85842
86240
  const revealed = strengthGate?.severity === "none" && strengthGate.revealEvidence === "revealed" && strengthGate.source !== "heal";
85843
- return revealed ? [] : [{ check: "strength-block" }];
86241
+ if (revealed)
86242
+ return [];
86243
+ return [{ check: authDowngrade ? "strength-downgrade-auth" : "strength-block" }];
85844
86244
  }
85845
86245
  };
85846
86246
  STRING_CONST = /\b(?:const|let|var)\s{1,20}([A-Za-z_$][\w$]{0,60})\s{0,20}=\s{0,20}(?:'([^'\\\n]{0,300})'|"([^"\\\n]{0,300})"|`([^`\\$\n]{0,300})`)\s{0,20}[;\n]/g;
@@ -86247,6 +86647,7 @@ __export(dist_exports, {
86247
86647
  AUDIO_CHUNK_DURATION_MS: () => AUDIO_CHUNK_DURATION_MS,
86248
86648
  AUTH_PATH_SIGNATURE: () => AUTH_PATH_SIGNATURE,
86249
86649
  AUTH_PROVIDER_HOST_SIGNATURES: () => AUTH_PROVIDER_HOST_SIGNATURES,
86650
+ AUTH_SESSION_GENERATION_RE: () => AUTH_SESSION_GENERATION_RE,
86250
86651
  AUTH_STATE_EXPIRY_SKEW_MS: () => AUTH_STATE_EXPIRY_SKEW_MS,
86251
86652
  AUTH_TAG_COOKIE_STATE: () => AUTH_TAG_COOKIE_STATE,
86252
86653
  AUTH_TAG_LOGIN_BEARER: () => AUTH_TAG_LOGIN_BEARER,
@@ -86379,6 +86780,8 @@ __export(dist_exports, {
86379
86780
  LIVE_FRAME_STALE_MS: () => LIVE_FRAME_STALE_MS,
86380
86781
  LIVE_FRAME_UNFOCUSED_INTERVAL_MS: () => LIVE_FRAME_UNFOCUSED_INTERVAL_MS,
86381
86782
  LIVE_THUMBNAIL_MAX_BASE64_BYTES: () => LIVE_THUMBNAIL_MAX_BASE64_BYTES,
86783
+ MAX_BALANCED_SCAN: () => MAX_BALANCED_SCAN,
86784
+ MAX_CALLS: () => MAX_CALLS,
86382
86785
  MAX_CREDIT_TOPUP_CENTS: () => MAX_CREDIT_TOPUP_CENTS,
86383
86786
  MAX_DEEPLINK_LENGTH: () => MAX_DEEPLINK_LENGTH,
86384
86787
  MAX_EMAIL_ADDRESS_LENGTH: () => MAX_EMAIL_ADDRESS_LENGTH,
@@ -86423,6 +86826,7 @@ __export(dist_exports, {
86423
86826
  MUSE_ENGINE_DEFAULT_MODEL: () => MUSE_ENGINE_DEFAULT_MODEL,
86424
86827
  MUSE_ENGINE_MODELS: () => MUSE_ENGINE_MODELS,
86425
86828
  NOREPLY_EMAIL: () => NOREPLY_EMAIL,
86829
+ OPENCODE_GO_2_PREFIX: () => OPENCODE_GO_2_PREFIX,
86426
86830
  OPENCODE_GO_MODEL_PATTERN: () => OPENCODE_GO_MODEL_PATTERN,
86427
86831
  OPENCODE_GO_PREFIX: () => OPENCODE_GO_PREFIX,
86428
86832
  OPENROUTER_MAX_CALL_COST_USD: () => OPENROUTER_MAX_CALL_COST_USD,
@@ -86458,6 +86862,8 @@ __export(dist_exports, {
86458
86862
  PROMOTION_GATE_MAX_CODE_CHARS: () => PROMOTION_GATE_MAX_CODE_CHARS,
86459
86863
  PROMOTION_QUALITY_CHECKS: () => PROMOTION_QUALITY_CHECKS,
86460
86864
  PROVIDER_CHAINS: () => PROVIDER_CHAINS,
86865
+ PROVIDER_CHAIN_LEADS: () => PROVIDER_CHAIN_LEADS,
86866
+ PROVIDER_HOST_NOT_OFFERED: () => PROVIDER_HOST_NOT_OFFERED,
86461
86867
  PUBLIC_PLANS: () => PUBLIC_PLANS,
86462
86868
  QUARANTINE_CLOSE_TAGS: () => QUARANTINE_CLOSE_TAGS,
86463
86869
  READINESS_POLL_MAX_CODE_CHARS: () => READINESS_POLL_MAX_CODE_CHARS,
@@ -86496,6 +86902,7 @@ __export(dist_exports, {
86496
86902
  SURVEY_NOTES_RENDER_MAX_CHARS: () => SURVEY_NOTES_RENDER_MAX_CHARS,
86497
86903
  SURVEY_NOTE_KEYS: () => SURVEY_NOTE_KEYS,
86498
86904
  SUSPICIOUS_PASS_TAG: () => SUSPICIOUS_PASS_TAG,
86905
+ TEST_DID_NOT_RUN_ERROR: () => TEST_DID_NOT_RUN_ERROR,
86499
86906
  TEST_QUALITY_CONVENTIONS: () => TEST_QUALITY_CONVENTIONS,
86500
86907
  TEST_USER_ENV_KEYS: () => TEST_USER_ENV_KEYS,
86501
86908
  TEST_VARIABLE_SECRET_KEY_PATTERN: () => TEST_VARIABLE_SECRET_KEY_PATTERN,
@@ -86511,6 +86918,8 @@ __export(dist_exports, {
86511
86918
  VOICE_PREVIEW_SAMPLE: () => VOICE_PREVIEW_SAMPLE,
86512
86919
  WEB_PROXY_CHAIN_HEADER: () => WEB_PROXY_CHAIN_HEADER,
86513
86920
  WITHHELD_CREDENTIAL_TEXT: () => WITHHELD_CREDENTIAL_TEXT,
86921
+ ZAI_MODEL_PATTERN: () => ZAI_MODEL_PATTERN,
86922
+ ZAI_PREFIX: () => ZAI_PREFIX,
86514
86923
  accumulateStatements: () => accumulateStatements,
86515
86924
  adoptBrokerFailover: () => adoptBrokerFailover,
86516
86925
  aiCostToCreditCents: () => aiCostToCreditCents,
@@ -86519,6 +86928,7 @@ __export(dist_exports, {
86519
86928
  analyzeMobileSelectorQuality: () => analyzeMobileSelectorQuality,
86520
86929
  analyzePersistenceReread: () => analyzePersistenceReread,
86521
86930
  analyzeReadinessPolling: () => analyzeReadinessPolling,
86931
+ analyzeRegexMatchers: () => analyzeRegexMatchers,
86522
86932
  analyzeSharedAccountUse: () => analyzeSharedAccountUse,
86523
86933
  analyzeStaleAfterSubmit: () => analyzeStaleAfterSubmit,
86524
86934
  analyzeTestData: () => analyzeTestData,
@@ -86682,6 +87092,7 @@ __export(dist_exports, {
86682
87092
  formatPersistenceRereadAdvisory: () => formatPersistenceRereadAdvisory,
86683
87093
  formatPoolBudgetLine: () => formatPoolBudgetLine,
86684
87094
  formatReadinessPollAdvisory: () => formatReadinessPollAdvisory,
87095
+ formatRegexMatcherNote: () => formatRegexMatcherNote,
86685
87096
  formatStaleAfterSubmitAdvisory: () => formatStaleAfterSubmitAdvisory,
86686
87097
  formatSuspiciousExpectation: () => formatSuspiciousExpectation,
86687
87098
  formatUrlWaitAdvisory: () => formatUrlWaitAdvisory,
@@ -86720,12 +87131,14 @@ __export(dist_exports, {
86720
87131
  hasEncodedRequestBody: () => hasEncodedRequestBody,
86721
87132
  hasEngineSpecParts: () => hasEngineSpecParts,
86722
87133
  hasOnlyConstantAssertions: () => hasOnlyConstantAssertions,
87134
+ hasOpenCodeGo2Prefix: () => hasOpenCodeGo2Prefix,
86723
87135
  hasOpenCodeGoPrefix: () => hasOpenCodeGoPrefix,
86724
87136
  hasOpenRouterPrefix: () => hasOpenRouterPrefix,
86725
87137
  hasPlatformLocator: () => hasPlatformLocator,
86726
87138
  hasReadOnlyMarker: () => hasReadOnlyMarker,
86727
87139
  hasSurveyNotes: () => hasSurveyNotes,
86728
87140
  hasTestFailContract: () => hasTestFailContract,
87141
+ hasZaiPrefix: () => hasZaiPrefix,
86729
87142
  healMobileTestSteps: () => healMobileTestSteps,
86730
87143
  healthRunWhere: () => healthRunWhere,
86731
87144
  heldCodeRecord: () => heldCodeRecord,
@@ -86829,6 +87242,7 @@ __export(dist_exports, {
86829
87242
  isValidSttProvider: () => isValidSttProvider,
86830
87243
  isValidTtsModel: () => isValidTtsModel,
86831
87244
  isValidTtsVoiceId: () => isValidTtsVoiceId,
87245
+ isZaiModelId: () => isZaiModelId,
86832
87246
  jsEscapedForms: () => jsEscapedForms,
86833
87247
  jsonStructureRefusalOf: () => jsonStructureRefusalOf,
86834
87248
  jsonStructureVerify: () => jsonStructureVerify,
@@ -86877,6 +87291,7 @@ __export(dist_exports, {
86877
87291
  parseApiCardModelUpdate: () => parseApiCardModelUpdate,
86878
87292
  parseAppTimezone: () => parseAppTimezone,
86879
87293
  parseAuditGroupScopeId: () => parseAuditGroupScopeId,
87294
+ parseAuthSessionStamp: () => parseAuthSessionStamp,
86880
87295
  parseBoolFlag: () => parseBoolFlag,
86881
87296
  parseDbPoolSize: () => parseDbPoolSize,
86882
87297
  parseDeepgramListenResponse: () => parseDeepgramListenResponse,
@@ -86920,7 +87335,11 @@ __export(dist_exports, {
86920
87335
  profileKeyRoute: () => profileKeyRoute,
86921
87336
  projectAppHosts: () => projectAppHosts,
86922
87337
  providerChainFor: () => providerChainFor,
87338
+ providerChainHostOf: () => providerChainHostOf,
87339
+ providerChainLeadsFor: () => providerChainLeadsFor,
86923
87340
  providerChainPrimariesForHop: () => providerChainPrimariesForHop,
87341
+ providerHostPlan: () => providerHostPlan,
87342
+ readBalanced: () => readBalanced,
86924
87343
  readChatFailover: () => readChatFailover,
86925
87344
  readChatReasoningTokens: () => readChatReasoningTokens,
86926
87345
  readChatUsage: () => readChatUsage,
@@ -87003,6 +87422,7 @@ __export(dist_exports, {
87003
87422
  stripCoverageComments: () => stripCoverageComments,
87004
87423
  stripEnvironmentalPrefix: () => stripEnvironmentalPrefix,
87005
87424
  stripLoginScaffolding: () => stripLoginScaffolding,
87425
+ stripTrailingSlashes: () => stripTrailingSlashes,
87006
87426
  strongerNeedsReviewSource: () => strongerNeedsReviewSource,
87007
87427
  sttModelsForProvider: () => sttModelsForProvider,
87008
87428
  summarizeHealth: () => summarizeHealth,
@@ -87030,7 +87450,8 @@ __export(dist_exports, {
87030
87450
  withReviewSource: () => withReviewSource,
87031
87451
  withoutNotChargedClaim: () => withoutNotChargedClaim,
87032
87452
  withoutServerOnlySpendFields: () => withoutServerOnlySpendFields,
87033
- withoutSurveyNotes: () => withoutSurveyNotes
87453
+ withoutSurveyNotes: () => withoutSurveyNotes,
87454
+ zaiWireModel: () => zaiWireModel
87034
87455
  });
87035
87456
  var init_dist = __esm({
87036
87457
  "../shared/dist/index.js"() {
@@ -87072,6 +87493,7 @@ var init_dist = __esm({
87072
87493
  init_admin_view_return_to();
87073
87494
  init_auth_plan();
87074
87495
  init_auth_block_detector();
87496
+ init_auth_session_stamp();
87075
87497
  init_auth_state_freshness();
87076
87498
  init_skip_coverage_detector();
87077
87499
  init_feature_coverage();
@@ -87128,6 +87550,7 @@ var init_dist = __esm({
87128
87550
  init_promotion_quality_gate();
87129
87551
  init_regex_alternation();
87130
87552
  init_page_evidence();
87553
+ init_trailing_slashes();
87131
87554
  }
87132
87555
  });
87133
87556