@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.
- package/dist/chunk-2OKZY3WN.mjs +291 -0
- package/dist/{chunk-5P4ANVDY.mjs → chunk-4SZC5ZX3.mjs} +5092 -760
- package/dist/{chunk-2XD63NU5.mjs → chunk-BBTK6OX6.mjs} +567 -84
- package/dist/{chunk-WDXLAZ2J.mjs → chunk-CO5KHIVX.mjs} +3 -2
- package/dist/{chunk-HMUC3DKS.mjs → chunk-CYWHPXNZ.mjs} +2281 -2
- package/dist/{chunk-MAO6ADAO.mjs → chunk-FQUH2PU2.mjs} +1 -1
- package/dist/{chunk-MBKGTELT.mjs → chunk-IGXGSDE3.mjs} +701 -283
- package/dist/{chunk-II7QW7MZ.mjs → chunk-M3VZGHZQ.mjs} +14 -11
- package/dist/{chunk-GIIIVO2W.mjs → chunk-SN3PN4G4.mjs} +151 -11
- package/dist/{chunk-6NIT2CCH.mjs → chunk-TPU42VH2.mjs} +10 -9
- package/dist/{chunk-MHFP3QXU.mjs → chunk-XZUUBMP3.mjs} +1 -1
- package/dist/cli.js +8994 -1015
- package/dist/cli.mjs +211 -170
- package/dist/credential-mcp-server.js +503 -79
- package/dist/credential-mcp-server.mjs +3 -3
- package/dist/discovery-mcp-server.js +654 -87
- package/dist/discovery-mcp-server.mjs +4 -4
- package/dist/dist-VTPBY2C4.mjs +17 -0
- package/dist/inbox-mcp-server.js +496 -73
- package/dist/inbox-mcp-server.mjs +3 -3
- package/dist/route-seed-worker.js +2780 -74
- package/dist/route-seed-worker.mjs +14 -7
- package/dist/run-write-guard-preload.js +1206 -160
- package/dist/run-write-guard-preload.mjs +5 -285
- package/dist/run-write-guard.js +1206 -160
- package/dist/run-write-guard.mjs +3 -3
- package/package.json +3 -3
- package/dist/dist-DFNLMH6L.mjs +0 -16
|
@@ -1815,7 +1815,7 @@ function reportedBugWhere() {
|
|
|
1815
1815
|
function bugReviewStatus(status) {
|
|
1816
1816
|
return status === "QUARANTINED" ? "confirmed" : "needs-review";
|
|
1817
1817
|
}
|
|
1818
|
-
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;
|
|
1818
|
+
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;
|
|
1819
1819
|
var init_run_classification = __esm({
|
|
1820
1820
|
"../shared/dist/run-classification.js"() {
|
|
1821
1821
|
"use strict";
|
|
@@ -1835,6 +1835,7 @@ var init_run_classification = __esm({
|
|
|
1835
1835
|
UNEXPECTED_PASS_ERROR_PREFIX = "UNEXPECTED_PASS:";
|
|
1836
1836
|
BUG_TEST_BROKEN_ERROR_PREFIX = "BUG_TEST_BROKEN:";
|
|
1837
1837
|
BUG_TEST_BROKEN_REASON = "bug test broken (not a bug verdict)";
|
|
1838
|
+
TEST_DID_NOT_RUN_ERROR = "Test did not run (a dependency failed or the run was interrupted)";
|
|
1838
1839
|
EMAIL_NOT_RECEIVED_PREFIXES = [
|
|
1839
1840
|
"VERIFICATION_EMAIL_NOT_RECEIVED:",
|
|
1840
1841
|
"VERIFICATION_EMAIL_HAS_NO_CODE:",
|
|
@@ -2938,176 +2939,6 @@ var init_origin_domain = __esm({
|
|
|
2938
2939
|
}
|
|
2939
2940
|
});
|
|
2940
2941
|
|
|
2941
|
-
// ../shared/dist/auth-block-detector.js
|
|
2942
|
-
function stripEchoLines(text) {
|
|
2943
|
-
return text.split("\n").filter((line) => !ECHO_LINE_RE.test(line)).join("\n");
|
|
2944
|
-
}
|
|
2945
|
-
function matchesAny(text, patterns) {
|
|
2946
|
-
return patterns.some((p) => p.test(text));
|
|
2947
|
-
}
|
|
2948
|
-
function detectAuthBlock(input) {
|
|
2949
|
-
const tags = input.tags ?? [];
|
|
2950
|
-
const isAuthed = tags.some((t) => AUTHED_TAGS.includes(t));
|
|
2951
|
-
if (!isAuthed)
|
|
2952
|
-
return NO_DETECTION;
|
|
2953
|
-
const meta = [input.testName, input.description].filter(Boolean).join(" ");
|
|
2954
|
-
if (matchesAny(meta, INTENTIONAL_NEGATIVE_AUTH))
|
|
2955
|
-
return NO_DETECTION;
|
|
2956
|
-
const sources = [];
|
|
2957
|
-
if (input.error)
|
|
2958
|
-
sources.push(stripEchoLines(input.error));
|
|
2959
|
-
if (input.logs)
|
|
2960
|
-
sources.push(stripEchoLines(input.logs));
|
|
2961
|
-
for (const sr of input.stepResults ?? []) {
|
|
2962
|
-
if (sr.error)
|
|
2963
|
-
sources.push(stripEchoLines(sr.error));
|
|
2964
|
-
}
|
|
2965
|
-
for (const text of sources) {
|
|
2966
|
-
if (!text)
|
|
2967
|
-
continue;
|
|
2968
|
-
for (const sig of AUTH_BLOCK_SIGNATURES) {
|
|
2969
|
-
if (sig.re.test(text)) {
|
|
2970
|
-
return {
|
|
2971
|
-
detected: true,
|
|
2972
|
-
reason: sig.reason,
|
|
2973
|
-
evidence: [`login-block signature "${sig.reason}" in: "${text.slice(0, 140).replace(/\s+/g, " ").trim()}"`]
|
|
2974
|
-
};
|
|
2975
|
-
}
|
|
2976
|
-
}
|
|
2977
|
-
}
|
|
2978
|
-
return NO_DETECTION;
|
|
2979
|
-
}
|
|
2980
|
-
function detectApiColdSessionBlock(input) {
|
|
2981
|
-
const tags = input.tags ?? [];
|
|
2982
|
-
if (!tags.includes("@api"))
|
|
2983
|
-
return NO_DETECTION;
|
|
2984
|
-
const cookieMissing = input.authStateExpected && !input.authStateInjected;
|
|
2985
|
-
const standingMissing = !!input.needsStandingHeaders && !input.standingHeadersInjected;
|
|
2986
|
-
if (!cookieMissing && !standingMissing)
|
|
2987
|
-
return NO_DETECTION;
|
|
2988
|
-
const has401Status = (input.apiCalls ?? []).some((c) => c && (c.status === 401 || c.status === 403));
|
|
2989
|
-
const texts = [];
|
|
2990
|
-
if (input.error)
|
|
2991
|
-
texts.push(input.error);
|
|
2992
|
-
if (input.logs)
|
|
2993
|
-
texts.push(input.logs);
|
|
2994
|
-
for (const sr of input.stepResults ?? [])
|
|
2995
|
-
if (sr.error)
|
|
2996
|
-
texts.push(sr.error);
|
|
2997
|
-
const has401Text = texts.some((t) => UNAUTHORIZED_TEXT_RE.test(t));
|
|
2998
|
-
if (!has401Status && !has401Text)
|
|
2999
|
-
return NO_DETECTION;
|
|
3000
|
-
const missingAuth = cookieMissing ? "cold injected auth session (401/403 with no storageState)" : "missing standing auth header (401/403 with no API_AUTH_HEADERS installed)";
|
|
3001
|
-
const injectedNoun = cookieMissing ? "injected session was absent/expired" : "standing auth header was not installed";
|
|
3002
|
-
return {
|
|
3003
|
-
detected: true,
|
|
3004
|
-
reason: missingAuth,
|
|
3005
|
-
evidence: [
|
|
3006
|
-
has401Status ? `a captured @api call returned 401/403 while the ${injectedNoun}` : `a 401/403 signal in the run error/logs while the ${injectedNoun}`
|
|
3007
|
-
]
|
|
3008
|
-
};
|
|
3009
|
-
}
|
|
3010
|
-
function coldSessionConfigMessage(context, reason, evidence) {
|
|
3011
|
-
return `CONFIG_ISSUE: ${context} without valid injected auth (${reason}) \u2014 no session cookie was injected this run. Ensure the project login (auth-setup recipe / prewarm) is configured so the shared session jar warms (a project with no login: set TEST_USER_EMAIL and TEST_USER_PASSWORD in Test Data \u2192 Test Variables so a session can be captured); for endpoints that authenticate with a standing API key or bearer header instead, set them in the project's API_AUTH_HEADERS variable (injected as request headers). Evidence: ${evidence.join("; ")}`;
|
|
3012
|
-
}
|
|
3013
|
-
var NO_DETECTION, AUTHED_TAGS, LOGIN_CTX, AUTH_BLOCK_SIGNATURES, INTENTIONAL_NEGATIVE_AUTH, ECHO_LINE_RE, UNAUTHORIZED_TEXT_RE;
|
|
3014
|
-
var init_auth_block_detector = __esm({
|
|
3015
|
-
"../shared/dist/auth-block-detector.js"() {
|
|
3016
|
-
"use strict";
|
|
3017
|
-
NO_DETECTION = { detected: false, reason: "", evidence: [] };
|
|
3018
|
-
AUTHED_TAGS = ["@needs-auth", "@inline-login"];
|
|
3019
|
-
LOGIN_CTX = "\\b(?:log\\s*in|login|logging\\s+in|sign[\\s-]?in|signing\\s+in|continue)\\b";
|
|
3020
|
-
AUTH_BLOCK_SIGNATURES = [
|
|
3021
|
-
{ reason: "incorrect password", re: /\b(incorrect|invalid|wrong|bad)\s+password\b/i },
|
|
3022
|
-
{ reason: "password is incorrect", re: /\bpassword\s+(is\s+)?(incorrect|invalid|wrong)\b/i },
|
|
3023
|
-
{ reason: "invalid credentials", re: /\b(invalid|incorrect|wrong|bad)\s+(login\s+)?credentials\b/i },
|
|
3024
|
-
{ reason: "credentials do not match", re: /\bcredentials\b[^\n]{0,40}\b(do(?:es)?\s*n['’]?t|do\s+not)\s+match\b/i },
|
|
3025
|
-
{ reason: "incorrect email or password", re: /\b(incorrect|invalid|wrong)\s+(email|username)\s+or\s+password\b/i },
|
|
3026
|
-
// Require an EXPLICIT negative (codex #21): the old `(not\s+)?(confirmed|verified)` made the negation
|
|
3027
|
-
// optional, so a benign "Email verified" success message / feature assertion matched and hid a real
|
|
3028
|
-
// feature failure as a CONFIG_ISSUE. Only "email not (yet) confirmed/verified" or "unconfirmed/unverified".
|
|
3029
|
-
{ reason: "email not confirmed", re: /\b(e-?mail)\b[^\n]{0,30}\b(not\s+(?:yet\s+)?(?:confirmed|verified)|unconfirmed|unverified)\b/i },
|
|
3030
|
-
{ reason: "please confirm your email", re: /\bplease\s+(confirm|verify)\s+your\s+(e-?mail)\b/i },
|
|
3031
|
-
// The bare "confirm/verify your email" and "account not found" phrases are ALSO ordinary feature copy
|
|
3032
|
-
// ("Verify your email banner", a 404-style "Account not found" page), so they only count with a
|
|
3033
|
-
// login/sign-in context on the SAME line (either side). "Please confirm/verify your email" above
|
|
3034
|
-
// is already an explicit prompt and stays unconditional.
|
|
3035
|
-
{ reason: "confirm your email to continue", re: new RegExp(`${LOGIN_CTX}[^\\n]{0,80}\\bconfirm\\s+your\\s+e-?mail\\b|\\bconfirm\\s+your\\s+e-?mail\\b[^\\n]{0,80}${LOGIN_CTX}`, "i") },
|
|
3036
|
-
{ reason: "verify your email to continue", re: new RegExp(`${LOGIN_CTX}[^\\n]{0,80}\\bverify\\s+your\\s+e-?mail\\b|\\bverify\\s+your\\s+e-?mail\\b[^\\n]{0,80}${LOGIN_CTX}`, "i") },
|
|
3037
|
-
{
|
|
3038
|
-
reason: "account not found",
|
|
3039
|
-
re: new RegExp(`${LOGIN_CTX}[^\\n]{0,80}\\baccount\\b[^\\n]{0,20}\\b(?:not\\s+found|does(?:n['\u2019]t| not)\\s+exist)\\b|\\baccount\\b[^\\n]{0,20}\\b(?:not\\s+found|does(?:n['\u2019]t| not)\\s+exist)\\b[^\\n]{0,80}${LOGIN_CTX}`, "i")
|
|
3040
|
-
},
|
|
3041
|
-
{ reason: "authentication failed", re: /\bauthentication\s+failed\b/i },
|
|
3042
|
-
{ reason: "login failed", re: /\b(login|log\s*in|sign[\s-]?in)\s+failed\b/i }
|
|
3043
|
-
];
|
|
3044
|
-
INTENTIONAL_NEGATIVE_AUTH = [
|
|
3045
|
-
/\b(invalid|incorrect|wrong|bad)\s+(password|credentials|email|login)\b/i,
|
|
3046
|
-
/\b(negative|unhappy)\s+(login|auth|sign[\s-]?in|path|case|flow|test)\b/i,
|
|
3047
|
-
// "should fail" et al must be TIED to an auth noun (codex #21): a bare `should\s+(fail|reject|deny)`
|
|
3048
|
-
// exempted benign names like "Export should fail gracefully", silently disabling the anti-lockout
|
|
3049
|
-
// protection for them. Require a login/auth noun on either side of the "should fail / fail to log in".
|
|
3050
|
-
/\b(login|log\s*in|sign[\s-]?in|auth\w*|credential|password)\b[^\n]{0,40}\bshould\s+(fail|reject|deny)\b/i,
|
|
3051
|
-
/\bshould\s+(fail|reject|deny|not\s+log(?:\s*in)?)\b[^\n]{0,40}\b(login|log\s*in|sign[\s-]?in|auth\w*|credential|password|unauthenticated)\b/i,
|
|
3052
|
-
/\bfailed?\s+login\b/i,
|
|
3053
|
-
/\blogin\s+(error|failure|rejected?)\b/i,
|
|
3054
|
-
/\b(reject|deny|denied|block(ed)?)\b[^\n]{0,20}\b(login|sign[\s-]?in|auth|credential|password)\b/i
|
|
3055
|
-
];
|
|
3056
|
-
ECHO_LINE_RE = /^\s*(?:(?:📋|🎭|🌐|⚙️?)|(?:stderr:\s*|stdout:\s*)?Locator:)/u;
|
|
3057
|
-
UNAUTHORIZED_TEXT_RE = /(?:return(?:s|ed|ing)?|respond(?:s|ed|ing)?|got|receiv(?:e|ed|ing)|gives?|sends?|yield(?:s|ed|ing)?|results?\s+in)\s+(?:a\s+|an\s+|the\s+)?(?:401|403)\b|\bstatus(?:\s+code)?\s*:?\s*(?:401|403)\b|\bHTTP\/[\d.]+\s+(?:401|403)\b|(?:401|403)['’]d\b|(?:[→⇒]|->)\s*(?:401|403)\b|(?:return(?:s|ed|ing)?|respond(?:s|ed|ing)?|got|receiv(?:e|ed|ing)|threw|throws?)\s+(?:a\s+|an\s+)?(?:unauthorized|forbidden)\b|\bnot\s+authenticated\b/i;
|
|
3058
|
-
}
|
|
3059
|
-
});
|
|
3060
|
-
|
|
3061
|
-
// ../shared/dist/skip-coverage-detector.js
|
|
3062
|
-
function detectSkippedApiCoverage(steps) {
|
|
3063
|
-
const allSkipped = steps.length > 0 && steps.every((s) => s.status === "skipped");
|
|
3064
|
-
if (allSkipped) {
|
|
3065
|
-
if (steps.every((s) => s.skipKind === "fixme")) {
|
|
3066
|
-
return {
|
|
3067
|
-
detected: false,
|
|
3068
|
-
logLine: "All @api tests skipped, but EVERY skip is a deliberate fixme (intentional N/A \u2014 e.g. a UI-only redirect login) \u2014 NOT relabelling CONFIG_ISSUE"
|
|
3069
|
-
};
|
|
3070
|
-
}
|
|
3071
|
-
return {
|
|
3072
|
-
detected: true,
|
|
3073
|
-
error: (
|
|
3074
|
-
// Name BOTH auth mechanisms (item 5d): the all-skipped copy used to say only "refresh the auth
|
|
3075
|
-
// state", which misdirects a @auth-standing operator (whose real gap is a missing API_AUTH_HEADERS
|
|
3076
|
-
// key, not a cold cookie session) to warm a login that was never the problem.
|
|
3077
|
-
"CONFIG_ISSUE: Authenticated @api coverage was NOT exercised \u2014 every test skipped (cold injected session, a missing standing auth header, or an unresolved fixme). Provide the auth the endpoints need \u2014 warm the project login/session cookie (auth-setup recipe / prewarm), or set a standing API key/bearer in the project's API_AUTH_HEADERS variable \u2014 so the assertions actually run."
|
|
3078
|
-
),
|
|
3079
|
-
logLine: "All @api tests skipped \u2014 posting ERROR/CONFIG_ISSUE (not PASSED) so zero authenticated coverage is visible, not silent green"
|
|
3080
|
-
};
|
|
3081
|
-
}
|
|
3082
|
-
const runtimeSkipped = steps.filter((s) => s.status === "skipped" && s.skipKind === "skip");
|
|
3083
|
-
if (runtimeSkipped.length === 0)
|
|
3084
|
-
return { detected: false };
|
|
3085
|
-
const reasons = [...new Set(runtimeSkipped.map((s) => `"${s.title ?? "test"}"${s.skipReason ? ` (${s.skipReason})` : ""}`))].join("; ");
|
|
3086
|
-
return {
|
|
3087
|
-
detected: true,
|
|
3088
|
-
error: `CONFIG_ISSUE: ${runtimeSkipped.length} of ${steps.length} @api tests skipped at runtime \u2014 that coverage was NOT exercised. Skipped: ${reasons}`,
|
|
3089
|
-
logLine: `${runtimeSkipped.length}/${steps.length} @api tests skipped at runtime \u2014 posting ERROR/CONFIG_ISSUE (not PASSED) so the coverage hole is visible, not silent green`
|
|
3090
|
-
};
|
|
3091
|
-
}
|
|
3092
|
-
var init_skip_coverage_detector = __esm({
|
|
3093
|
-
"../shared/dist/skip-coverage-detector.js"() {
|
|
3094
|
-
"use strict";
|
|
3095
|
-
}
|
|
3096
|
-
});
|
|
3097
|
-
|
|
3098
|
-
// ../shared/dist/feature-flags.js
|
|
3099
|
-
function isSharedAuthInjectEnabled(value = process.env.SHARED_AUTH_INJECT) {
|
|
3100
|
-
return value?.trim().toLowerCase() !== "false";
|
|
3101
|
-
}
|
|
3102
|
-
function isAuthReadinessGuardEnabled(value = process.env.AUTH_READINESS_GUARD) {
|
|
3103
|
-
return value?.trim().toLowerCase() !== "false";
|
|
3104
|
-
}
|
|
3105
|
-
var init_feature_flags = __esm({
|
|
3106
|
-
"../shared/dist/feature-flags.js"() {
|
|
3107
|
-
"use strict";
|
|
3108
|
-
}
|
|
3109
|
-
});
|
|
3110
|
-
|
|
3111
2942
|
// ../shared/dist/repository-cli.js
|
|
3112
2943
|
function isRepositoryCli(value) {
|
|
3113
2944
|
return typeof value === "string" && REPOSITORY_CLIS.includes(value);
|
|
@@ -4499,7 +4330,7 @@ function unescapeQuotedBody(raw) {
|
|
|
4499
4330
|
return raw.replace(/\\(['"`\\])/g, "$1");
|
|
4500
4331
|
}
|
|
4501
4332
|
function extractRoleNameValue(line) {
|
|
4502
|
-
const m = line.match(new RegExp(`getByRole\\s*\\([^,]
|
|
4333
|
+
const m = line.match(new RegExp(`getByRole\\s*\\([^,]{1,200},\\s*\\{[^}]{0,200}?name\\s*:\\s*(?:${QUOTED_BODY}|\\/([^/]*?)\\/)`, "i"));
|
|
4503
4334
|
if (!m)
|
|
4504
4335
|
return null;
|
|
4505
4336
|
const raw = m[1] ?? m[2] ?? m[3];
|
|
@@ -5207,6 +5038,8 @@ function stripCoverageComments(code) {
|
|
|
5207
5038
|
let copyFrom = 0;
|
|
5208
5039
|
let i = 0;
|
|
5209
5040
|
let quote = null;
|
|
5041
|
+
let prev = "";
|
|
5042
|
+
let noRegexBefore = 0;
|
|
5210
5043
|
while (i < code.length) {
|
|
5211
5044
|
const ch = code[i];
|
|
5212
5045
|
if (quote) {
|
|
@@ -5214,12 +5047,24 @@ function stripCoverageComments(code) {
|
|
|
5214
5047
|
i += 2;
|
|
5215
5048
|
continue;
|
|
5216
5049
|
}
|
|
5217
|
-
if (ch === quote || ch === "\n" && quote !== "`")
|
|
5050
|
+
if (ch === quote || ch === "\n" && quote !== "`") {
|
|
5218
5051
|
quote = null;
|
|
5052
|
+
prev = ch === "\n" ? prev : ch;
|
|
5053
|
+
}
|
|
5219
5054
|
i++;
|
|
5220
5055
|
continue;
|
|
5221
5056
|
}
|
|
5222
5057
|
const next = code[i + 1];
|
|
5058
|
+
if (ch === "/" && next !== "*" && next !== "/" && i >= noRegexBefore && (prev === "" || REGEX_PRECEDER2.includes(prev))) {
|
|
5059
|
+
const end = regexLiteralEnd3(code, i);
|
|
5060
|
+
if (end > 0) {
|
|
5061
|
+
i = end;
|
|
5062
|
+
prev = "a";
|
|
5063
|
+
continue;
|
|
5064
|
+
}
|
|
5065
|
+
const eol = code.indexOf("\n", i);
|
|
5066
|
+
noRegexBefore = eol === -1 ? code.length : eol;
|
|
5067
|
+
}
|
|
5223
5068
|
if (ch === "/" && next === "*") {
|
|
5224
5069
|
const end = code.indexOf("*/", i + 2);
|
|
5225
5070
|
const stop = end === -1 ? code.length : end + 2;
|
|
@@ -5238,11 +5083,39 @@ function stripCoverageComments(code) {
|
|
|
5238
5083
|
}
|
|
5239
5084
|
if (ch === '"' || ch === "'" || ch === "`")
|
|
5240
5085
|
quote = ch;
|
|
5086
|
+
if (ch !== " " && ch !== " " && ch !== "\n" && ch !== "\r")
|
|
5087
|
+
prev = ch;
|
|
5241
5088
|
i++;
|
|
5242
5089
|
}
|
|
5243
5090
|
out.push(code.slice(copyFrom));
|
|
5244
5091
|
return out.join("");
|
|
5245
5092
|
}
|
|
5093
|
+
function regexLiteralEnd3(code, start) {
|
|
5094
|
+
let inClass = false;
|
|
5095
|
+
for (let j = start + 1; j < code.length; j++) {
|
|
5096
|
+
const c = code[j];
|
|
5097
|
+
if (c === "\n")
|
|
5098
|
+
return -1;
|
|
5099
|
+
if (c === "\\") {
|
|
5100
|
+
j++;
|
|
5101
|
+
continue;
|
|
5102
|
+
}
|
|
5103
|
+
if (inClass) {
|
|
5104
|
+
if (c === "]")
|
|
5105
|
+
inClass = false;
|
|
5106
|
+
continue;
|
|
5107
|
+
}
|
|
5108
|
+
if (c === "[")
|
|
5109
|
+
inClass = true;
|
|
5110
|
+
else if (c === "/") {
|
|
5111
|
+
let k = j + 1;
|
|
5112
|
+
while (k < code.length && isIdentChar(code[k]))
|
|
5113
|
+
k++;
|
|
5114
|
+
return k;
|
|
5115
|
+
}
|
|
5116
|
+
}
|
|
5117
|
+
return -1;
|
|
5118
|
+
}
|
|
5246
5119
|
function isIdentChar(ch) {
|
|
5247
5120
|
if (!ch)
|
|
5248
5121
|
return false;
|
|
@@ -5900,7 +5773,7 @@ function assessTitleCoverage(title, code) {
|
|
|
5900
5773
|
const repeatedHit = [...repeated].some((term) => hay.includes(term));
|
|
5901
5774
|
return { covered: hit >= needed || repeatedHit, missingTerms };
|
|
5902
5775
|
}
|
|
5903
|
-
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;
|
|
5776
|
+
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;
|
|
5904
5777
|
var init_expected_outcome_coverage = __esm({
|
|
5905
5778
|
"../shared/dist/expected-outcome-coverage.js"() {
|
|
5906
5779
|
"use strict";
|
|
@@ -5937,6 +5810,7 @@ var init_expected_outcome_coverage = __esm({
|
|
|
5937
5810
|
]);
|
|
5938
5811
|
MAX_ASSERTION_JOIN_CHARS = 8e3;
|
|
5939
5812
|
MAX_COVERAGE_LINE_CHARS = 2e3;
|
|
5813
|
+
REGEX_PRECEDER2 = "(,=:[!&|?{};+-*%<>~^";
|
|
5940
5814
|
BLOCK_SCAFFOLD = /=>|\b(?:test|describe|it|beforeEach|afterEach|beforeAll|afterAll|function)\b/;
|
|
5941
5815
|
cachedAssertionInput = null;
|
|
5942
5816
|
cachedAssertionSource = { raw: "", normalized: "", bindings: /* @__PURE__ */ new Map(), bindingRefs: /* @__PURE__ */ new Map() };
|
|
@@ -6387,7 +6261,7 @@ function detectsErrorBannerAssertion(code) {
|
|
|
6387
6261
|
const cleaned = stripCommentsAndLogs(stripLoginScaffolding(code));
|
|
6388
6262
|
const lines = cleaned.split("\n");
|
|
6389
6263
|
const candidates = [];
|
|
6390
|
-
const positive = (stmt) => !
|
|
6264
|
+
const positive = (stmt) => !claimsAbsence(stmt);
|
|
6391
6265
|
const statements = liveExpectStatements(cleaned).map((s) => s.stmt);
|
|
6392
6266
|
for (const stmt of statements) {
|
|
6393
6267
|
if (positive(stmt))
|
|
@@ -6516,6 +6390,12 @@ function detectsObservedFailureAsExpected(code) {
|
|
|
6516
6390
|
return FAILURE_STATUS_ASSERT.some((re) => re.test(stmt)) || hasFailedListener && FAILED_LIST_ASSERT.test(stmt);
|
|
6517
6391
|
});
|
|
6518
6392
|
}
|
|
6393
|
+
function claimsAbsence(stmt) {
|
|
6394
|
+
const negated = NEGATED_ASSERT_NOT.test(stmt);
|
|
6395
|
+
const bare = negated ? stmt.replace(NOT_BEFORE_MATCHER, ".") : stmt;
|
|
6396
|
+
const absenceMatcher = /\.toBeHidden\s*\(|\.toHaveCount\s*\(\s*0\s*\)/.test(bare) || VALUE_ABSENCE.test(bare) || OPTION_ABSENCE.test(bare);
|
|
6397
|
+
return negated !== absenceMatcher;
|
|
6398
|
+
}
|
|
6519
6399
|
function isVacuousErrorAbsence(stmt, presence) {
|
|
6520
6400
|
if (!ABSENCE_MATCHER.test(stmt))
|
|
6521
6401
|
return false;
|
|
@@ -6531,19 +6411,53 @@ function isChromeTarget(stmt) {
|
|
|
6531
6411
|
return CHROME_LOCATOR.test(stmt) && !CONTENT_ROLE.test(stmt) && !/getByText\s*\(/.test(stmt);
|
|
6532
6412
|
}
|
|
6533
6413
|
function countsAsContentText(stmt) {
|
|
6534
|
-
if (!TEXT_CONTENT_MATCHER.test(stmt))
|
|
6414
|
+
if (!TEXT_CONTENT_MATCHER.test(stmt) || NEGATED_ASSERT.test(stmt))
|
|
6535
6415
|
return false;
|
|
6536
6416
|
if (isSymbolOnlyArgument(stmt, TEXT_CONTENT_MATCHER))
|
|
6537
6417
|
return false;
|
|
6538
|
-
|
|
6418
|
+
return onContentTarget(stmt);
|
|
6419
|
+
}
|
|
6420
|
+
function onContentTarget(stmt) {
|
|
6421
|
+
return !isChromeTarget(stmt) || /getByRole\s*\(\s*['"`]main['"`]/i.test(stmt);
|
|
6422
|
+
}
|
|
6423
|
+
function provesTextRemoved(stmt, presence) {
|
|
6424
|
+
const m = stmt.match(NEGATED_TEXT);
|
|
6425
|
+
if (!m || !onContentTarget(stmt))
|
|
6426
|
+
return false;
|
|
6427
|
+
const text = m[1] ?? m[2];
|
|
6428
|
+
if (text === void 0)
|
|
6539
6429
|
return true;
|
|
6540
|
-
|
|
6430
|
+
if (!/[\p{L}\p{N}]/u.test(text))
|
|
6431
|
+
return false;
|
|
6432
|
+
return !ERROR_TEXT_WORDS.test(text) || presence().includes(text);
|
|
6541
6433
|
}
|
|
6542
6434
|
function isDataContentRole(stmt) {
|
|
6543
6435
|
return CONTENT_ROLE.test(stmt) && !ANNOUNCE_ROLE.test(stmt);
|
|
6544
6436
|
}
|
|
6437
|
+
function destructuresRequest(code) {
|
|
6438
|
+
let readTo = -1;
|
|
6439
|
+
for (const m of code.matchAll(ASYNC_DESTRUCTURE_OPEN)) {
|
|
6440
|
+
const start = m.index + m[0].length;
|
|
6441
|
+
if (start <= readTo)
|
|
6442
|
+
continue;
|
|
6443
|
+
let end = start;
|
|
6444
|
+
while (end < code.length && code[end] !== "}" && code[end] !== ")")
|
|
6445
|
+
end++;
|
|
6446
|
+
readTo = end;
|
|
6447
|
+
if (end === code.length)
|
|
6448
|
+
return false;
|
|
6449
|
+
if (code[end] !== "}" || !REQUEST_WORD.test(code.slice(start, end)))
|
|
6450
|
+
continue;
|
|
6451
|
+
let close = end + 1;
|
|
6452
|
+
while (close < code.length && /\s/.test(code[close]))
|
|
6453
|
+
close++;
|
|
6454
|
+
if (code[close] === ")")
|
|
6455
|
+
return true;
|
|
6456
|
+
}
|
|
6457
|
+
return false;
|
|
6458
|
+
}
|
|
6545
6459
|
function isApiTest(code) {
|
|
6546
|
-
const usesRequestFixture =
|
|
6460
|
+
const usesRequestFixture = destructuresRequest(code) || /\brequest\.(get|post|put|patch|delete|head|fetch)\s*\(/.test(code);
|
|
6547
6461
|
if (!usesRequestFixture)
|
|
6548
6462
|
return false;
|
|
6549
6463
|
const drivesUi = /\bpage\.(getBy\w+|locator|click|fill|goto|waitForURL|reload)\s*\(/.test(code) || /\.(click|fill|check|uncheck|selectOption|pressSequentially)\s*\(/.test(code);
|
|
@@ -6802,6 +6716,9 @@ function hasOnlyConstantAssertions(code) {
|
|
|
6802
6716
|
const { constant, real } = constantAssertions(code);
|
|
6803
6717
|
return constant.length > 0 && real === 0;
|
|
6804
6718
|
}
|
|
6719
|
+
function envValueKey(name) {
|
|
6720
|
+
return `\0env:${name}`;
|
|
6721
|
+
}
|
|
6805
6722
|
function enteredValues(stmts) {
|
|
6806
6723
|
const values = /* @__PURE__ */ new Map();
|
|
6807
6724
|
const navLines = [];
|
|
@@ -6810,24 +6727,55 @@ function enteredValues(stmts) {
|
|
|
6810
6727
|
navLines.push(startLine);
|
|
6811
6728
|
let m;
|
|
6812
6729
|
ENTERED_VALUE.lastIndex = 0;
|
|
6813
|
-
|
|
6814
|
-
const
|
|
6815
|
-
if (!
|
|
6816
|
-
values.set(value, startLine);
|
|
6817
|
-
|
|
6730
|
+
const add = (value) => {
|
|
6731
|
+
const lines = values.get(value);
|
|
6732
|
+
if (!lines)
|
|
6733
|
+
values.set(value, [startLine]);
|
|
6734
|
+
else if (lines[lines.length - 1] !== startLine)
|
|
6735
|
+
lines.push(startLine);
|
|
6736
|
+
};
|
|
6737
|
+
while (m = ENTERED_VALUE.exec(stmt))
|
|
6738
|
+
add((m[1] ?? m[2] ?? m[3]).toLowerCase());
|
|
6739
|
+
ENTERED_ENV.lastIndex = 0;
|
|
6740
|
+
while (m = ENTERED_ENV.exec(stmt))
|
|
6741
|
+
add(envValueKey(m[1] ?? m[2] ?? m[3] ?? m[4]));
|
|
6818
6742
|
}
|
|
6819
6743
|
return { values, navLines };
|
|
6820
6744
|
}
|
|
6821
|
-
function
|
|
6745
|
+
function countBelow(lines, line) {
|
|
6746
|
+
let lo = 0;
|
|
6747
|
+
let hi = lines.length;
|
|
6748
|
+
while (lo < hi) {
|
|
6749
|
+
const mid = lo + hi >> 1;
|
|
6750
|
+
if (lines[mid] < line)
|
|
6751
|
+
lo = mid + 1;
|
|
6752
|
+
else
|
|
6753
|
+
hi = mid;
|
|
6754
|
+
}
|
|
6755
|
+
return lo;
|
|
6756
|
+
}
|
|
6757
|
+
function enteredLinesOf(stmt, entered) {
|
|
6822
6758
|
const m = stmt.match(/\.toHaveValue\s*\(\s*(['"`])((?:(?!\1).)+)\1/);
|
|
6823
|
-
if (
|
|
6759
|
+
if (m)
|
|
6760
|
+
return entered.values.get(m[2].toLowerCase());
|
|
6761
|
+
const env = stmt.match(HAVE_VALUE_ENV);
|
|
6762
|
+
return env ? entered.values.get(envValueKey(env[1] ?? env[2])) : void 0;
|
|
6763
|
+
}
|
|
6764
|
+
function typedSinceLastNav(stmt, entered, startLine, lines = enteredLinesOf(stmt, entered)) {
|
|
6765
|
+
if (!lines || startLine === void 0)
|
|
6766
|
+
return false;
|
|
6767
|
+
const before = countBelow(lines, startLine);
|
|
6768
|
+
if (before === 0)
|
|
6824
6769
|
return false;
|
|
6825
|
-
|
|
6826
|
-
|
|
6770
|
+
return countBelow(entered.navLines, startLine) === countBelow(entered.navLines, lines[before - 1] + 1);
|
|
6771
|
+
}
|
|
6772
|
+
function isEnteredValueEcho(stmt, entered, startLine) {
|
|
6773
|
+
const lines = enteredLinesOf(stmt, entered);
|
|
6774
|
+
if (!lines)
|
|
6827
6775
|
return false;
|
|
6828
|
-
if (startLine === void 0)
|
|
6776
|
+
if (startLine === void 0 || lines[0] >= startLine)
|
|
6829
6777
|
return true;
|
|
6830
|
-
return
|
|
6778
|
+
return typedSinceLastNav(stmt, entered, startLine, lines);
|
|
6831
6779
|
}
|
|
6832
6780
|
function isAnyValueMatcher(stmt) {
|
|
6833
6781
|
if (/\.not\.toHaveValue\s*\(\s*(?:['"`]{2}|\/\^?\$?\/)/.test(stmt))
|
|
@@ -6917,6 +6865,43 @@ function hasAttributeTransition(stmts) {
|
|
|
6917
6865
|
return true;
|
|
6918
6866
|
return false;
|
|
6919
6867
|
}
|
|
6868
|
+
function comparesWithItself(subject, tail) {
|
|
6869
|
+
const m = SELF_COMPARE_MATCHER.exec(tail);
|
|
6870
|
+
if (!m)
|
|
6871
|
+
return false;
|
|
6872
|
+
const args = balancedArguments(tail, m[0].length, MATCHER_ARGS_MAX);
|
|
6873
|
+
if (args === null)
|
|
6874
|
+
return false;
|
|
6875
|
+
const squash2 = (x) => x.replace(/^\s*await\s+/, "").replace(/\s+/g, "");
|
|
6876
|
+
const expected = squash2(args);
|
|
6877
|
+
return expected === squash2(m[1] === "toHaveCount" ? `${subject}.count()` : subject);
|
|
6878
|
+
}
|
|
6879
|
+
function asPlainAssertion(s) {
|
|
6880
|
+
const { stmt } = s;
|
|
6881
|
+
if (COUNT_AT_LEAST_ZERO.test(stmt))
|
|
6882
|
+
return [];
|
|
6883
|
+
const subject = extractExpectSubject(stmt);
|
|
6884
|
+
if (subject === null)
|
|
6885
|
+
return [s];
|
|
6886
|
+
const plain = subject.replace(/^await\s+/, "").trim();
|
|
6887
|
+
const subjectAt = stmt.indexOf(subject, stmt.search(EXPECT_CALL_RE));
|
|
6888
|
+
const tail = stmt.slice(subjectAt + subject.length).trimStart();
|
|
6889
|
+
const as = (rewritten) => [{ ...s, stmt: rewritten }];
|
|
6890
|
+
if (LOCATOR_EXPR.test(plain) && !LOCATOR_VALUE_READ.test(plain) && ALWAYS_TRUE_ON_OBJECT.test(tail))
|
|
6891
|
+
return [];
|
|
6892
|
+
if (DEFINED_VALUE_READ.test(plain) && ALWAYS_DEFINED.test(tail))
|
|
6893
|
+
return [];
|
|
6894
|
+
if (comparesWithItself(plain, tail))
|
|
6895
|
+
return [];
|
|
6896
|
+
const visible = /^(.+)\.\s*isVisible\s*\(\s*\)$/s.exec(plain);
|
|
6897
|
+
if (visible && IS_VISIBLE_TRUE.test(tail))
|
|
6898
|
+
return as(`await expect(${visible[1]}).toBeVisible();`);
|
|
6899
|
+
if (/^page\s*\.\s*(?:url|title)\s*\(\s*\)$/.test(plain) && PAGE_VALUE_MATCHER.test(tail)) {
|
|
6900
|
+
const matcher = plain.includes("url") ? "toHaveURL" : "toHaveTitle";
|
|
6901
|
+
return as(`await expect(page)${tail.replace(/^\)\s*\.\s*\w+\s*\(/, `.${matcher}(`)}`);
|
|
6902
|
+
}
|
|
6903
|
+
return [s];
|
|
6904
|
+
}
|
|
6920
6905
|
function creditsOutcomeAlways(stmt, entered, startLine) {
|
|
6921
6906
|
if (!OUTCOME_ALWAYS.some((re) => re.test(stmt)))
|
|
6922
6907
|
return false;
|
|
@@ -6990,6 +6975,8 @@ function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstM
|
|
|
6990
6975
|
continue;
|
|
6991
6976
|
if (isVacuousErrorAbsence(stmt, presence))
|
|
6992
6977
|
continue;
|
|
6978
|
+
if (COUNT_ONE.test(stmt) && quotedAssertedStrings(stmt).some((t) => clicked.has(t.toLowerCase())))
|
|
6979
|
+
continue;
|
|
6993
6980
|
if (creditsOutcomeAlways(stmt, entered, startLine))
|
|
6994
6981
|
return { kind: "durable" };
|
|
6995
6982
|
if (mutated && !NEGATED_ASSERT.test(stmt) && MESSAGE_SURFACE.test(stmt) && OUTCOME_TEXT.test(assertedText(stmt))) {
|
|
@@ -6999,12 +6986,15 @@ function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstM
|
|
|
6999
6986
|
else
|
|
7000
6987
|
return { kind: "durable" };
|
|
7001
6988
|
}
|
|
7002
|
-
|
|
6989
|
+
const retyped = typedSinceLastNav(stmt, entered, startLine);
|
|
6990
|
+
if (!retyped && STATE_MATCHER.test(stmt) && (persistence && startLine !== void 0 ? reopenedAfterSave(startLine, persistence, persistence.reloadCalls) : reloaded))
|
|
7003
6991
|
return { kind: "durable" };
|
|
7004
|
-
if (provesStoredControlValue(stmt, startLine, persistence))
|
|
6992
|
+
if (!retyped && provesStoredControlValue(stmt, startLine, persistence))
|
|
7005
6993
|
return { kind: "durable" };
|
|
7006
6994
|
if (countsAsContentText(stmt))
|
|
7007
6995
|
return { kind: "durable" };
|
|
6996
|
+
if (provesTextRemoved(stmt, presence))
|
|
6997
|
+
return { kind: "durable" };
|
|
7008
6998
|
if (mutated && VISIBILITY_MATCHER.test(stmt)) {
|
|
7009
6999
|
const revealsText = GET_BY_TEXT.test(stmt) || HAS_TEXT_FILTER.test(stmt) || CONTENT_ROLE.test(stmt);
|
|
7010
7000
|
if (revealsText && !isChromeTarget(stmt)) {
|
|
@@ -7071,7 +7061,7 @@ function detectOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMut
|
|
|
7071
7061
|
function validateAssertionStrength(code, opts = {}) {
|
|
7072
7062
|
const body = stripLoginScaffolding(code);
|
|
7073
7063
|
const lines = body.split("\n");
|
|
7074
|
-
const stmts = liveExpectStatements(stripCoverageComments(body));
|
|
7064
|
+
const stmts = liveExpectStatements(stripCoverageComments(body)).flatMap(asPlainAssertion);
|
|
7075
7065
|
const base = (extra) => ({
|
|
7076
7066
|
apiTest: false,
|
|
7077
7067
|
interacted: false,
|
|
@@ -7277,7 +7267,7 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
7277
7267
|
signals
|
|
7278
7268
|
};
|
|
7279
7269
|
}
|
|
7280
|
-
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;
|
|
7270
|
+
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;
|
|
7281
7271
|
var init_assertion_strength = __esm({
|
|
7282
7272
|
"../shared/dist/assertion-strength.js"() {
|
|
7283
7273
|
"use strict";
|
|
@@ -7302,8 +7292,8 @@ var init_assertion_strength = __esm({
|
|
|
7302
7292
|
// form field value
|
|
7303
7293
|
/\.toMatch\s*\(/,
|
|
7304
7294
|
// string/regex content match (e.g. textContent() vs /[2-9] selected/)
|
|
7305
|
-
|
|
7306
|
-
// a control became DISABLED — a gating/validation outcome
|
|
7295
|
+
/(?<!\.not\s*)\.\s*toBeDisabled\s*\(/,
|
|
7296
|
+
// a control became DISABLED — a gating/validation outcome (not.toBeDisabled is the toBeEnabled twin)
|
|
7307
7297
|
/\.not\.toBeVisible\s*\(/,
|
|
7308
7298
|
/\.toBeHidden\s*\(/
|
|
7309
7299
|
// something the action removed/closed (disappearance proof)
|
|
@@ -7311,7 +7301,7 @@ var init_assertion_strength = __esm({
|
|
|
7311
7301
|
FORM_INPUT = /\.(fill|selectOption|setInputFiles|check|uncheck|setChecked|pressSequentially)\s*\(|keyboard\.type\s*\(/;
|
|
7312
7302
|
ANY_CLICK = /\.click\s*\(/;
|
|
7313
7303
|
NAV_LOCATOR = /getByRole\s*\(\s*['"`](?:link|menuitem)['"`]/i;
|
|
7314
|
-
URL_PROOF = /\.toHaveURL\s*\(|\.waitForURL\s*\(/;
|
|
7304
|
+
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*\)/;
|
|
7315
7305
|
RELOAD = /\.reload\s*\(/;
|
|
7316
7306
|
EXPECT_STMT = /\bexpect\s*[.(]/;
|
|
7317
7307
|
BLOCK_SCAFFOLD2 = /=>|\b(?:test|describe|it|beforeEach|afterEach|beforeAll|afterAll|function)\b/;
|
|
@@ -7340,6 +7330,7 @@ var init_assertion_strength = __esm({
|
|
|
7340
7330
|
INBOX_START = /^\s*\/\/\s*>>>\s*VALIDATE_QA_INBOX/;
|
|
7341
7331
|
INBOX_END = /^\s*\/\/\s*<<<\s*VALIDATE_QA_INBOX/;
|
|
7342
7332
|
NEGATED_ASSERT = /\.not\s*\.\s*to[A-Z]\w*|\.toBeHidden\s*\(/;
|
|
7333
|
+
NEGATED_ASSERT_NOT = /\.not\s*\.\s*to[A-Z]/;
|
|
7343
7334
|
CONST_CHAIN_MAX_DEPTH = 5;
|
|
7344
7335
|
TYPED_INPUT = /\.(fill|type|pressSequentially|setInputFiles)\s*\(/;
|
|
7345
7336
|
TITLE_LINE = /^\s*(?:test|describe)(?:\.\w+)?\s*\(/;
|
|
@@ -7355,8 +7346,14 @@ var init_assertion_strength = __esm({
|
|
|
7355
7346
|
CATCH_ALL_PATTERN = /^(['"`])\*\*(?:\/\*)?\1$|^\/\.\*\/[a-z]*$/;
|
|
7356
7347
|
GUARD_HANDLER = /\bMUTATING\.has\s*\(|blockedbyclient|Read-only guard/;
|
|
7357
7348
|
ABSENCE_MATCHER = /\.not\.toBeVisible\s*\(|\.toBeHidden\s*\(|\.toHaveCount\s*\(\s*0\s*\)/;
|
|
7349
|
+
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*\())/;
|
|
7350
|
+
OPTION_ABSENCE = /\.(?:toBeVisible\s*\(\s*\{[^{}()]{0,200}\bvisible|toBeAttached\s*\(\s*\{[^{}()]{0,200}\battached)\s*:\s*false\b/;
|
|
7351
|
+
NOT_BEFORE_MATCHER = /\.not\s*\.\s*(?=to[A-Z])/g;
|
|
7358
7352
|
ERROR_TEXT_WORDS = /error|fail|wrong|try again|unable|could ?n.?t|can.?t|problem|invalid|unavailable/i;
|
|
7359
7353
|
TEXT_REGEX_ARG = /(?:getByText|hasText|getByRole\([^)]{0,200}name)\s*[:(]\s*(\/(?:\\.|[^/\\\n])+\/[a-z]*)/;
|
|
7354
|
+
NEGATED_TEXT = /\.not\s*\.\s*(?:toHaveText|toContainText)\s*\(\s*(?:['"`]([^'"`]*)['"`]|\/((?:\\.|[^/\\\n])+)\/)?/;
|
|
7355
|
+
ASYNC_DESTRUCTURE_OPEN = /async\s*\(\s*\{/g;
|
|
7356
|
+
REQUEST_WORD = /\brequest\b/;
|
|
7360
7357
|
ROLE_NAME_RE = /getByRole\s*\(\s*['"`][a-z]+['"`]\s*,\s*\{[^}]*?name\s*:\s*(?:['"`]([^'"`]+)['"`]|\/([^/]+)\/)/gi;
|
|
7361
7358
|
INTERACT_VERB = /\.(click|fill|check|uncheck|setChecked|selectOption|pressSequentially)\s*\(/;
|
|
7362
7359
|
ROLE_SIG_RE = /getByRole\s*\(\s*['"`]([a-z]+)['"`]\s*,\s*\{[^}]*?name\s*:\s*(?:['"`]([^'"`]+)['"`]|\/([^/]+)\/)/gi;
|
|
@@ -7377,7 +7374,20 @@ var init_assertion_strength = __esm({
|
|
|
7377
7374
|
MATCHER_OPEN = /\s*(?:\.\s*(?:not|resolves|rejects)\s*)*\.\s*[A-Za-z_$][\w$]*\s*\(/y;
|
|
7378
7375
|
ENTERED_VALUE = /\.(?:fill|pressSequentially)\s*\(\s*['"`]([^'"`]+)['"`]|keyboard\.type\s*\(\s*['"`]([^'"`]+)['"`]|\.selectOption\s*\(\s*(?:\[\s*)?(?:\{\s*(?:label|value)\s*:\s*)?['"`]([^'"`]+)['"`]/g;
|
|
7379
7376
|
PAGE_NAV = /\.(?:goto|reload)\s*\(/;
|
|
7377
|
+
ENV_READ = String.raw`process\.env(?:(?:\?\.|\.)([A-Za-z_]\w*)|(?:\?\.)?\[\s*['"]([A-Za-z_]\w*)['"]\s*\])`;
|
|
7378
|
+
ENTERED_ENV = new RegExp(String.raw`\.(?:fill|pressSequentially)\s*\(\s*${ENV_READ}|keyboard\.type\s*\(\s*${ENV_READ}`, "g");
|
|
7379
|
+
HAVE_VALUE_ENV = new RegExp(String.raw`\.toHaveValue\s*\(\s*${ENV_READ}`);
|
|
7380
7380
|
IN_FLIGHT_TEXT = /^(?:(?:sending|saving|loading|searching|checking|processing|submitting|preparing|updating|please wait|working|one moment)\b[^.]{0,40}\.{2,3}|\.{3}|…)$/i;
|
|
7381
|
+
LOCATOR_VALUE_READ = /\.(?:count|textContent|innerText|innerHTML|inputValue|getAttribute|isVisible|isHidden|isChecked|isEnabled|isDisabled|isEditable|allTextContents|allInnerTexts|evaluate|evaluateAll|boundingBox|all)\s*\(/;
|
|
7382
|
+
LOCATOR_EXPR = /^(?:this\.)?page\s*\.\s*(?:getBy\w+|locator)\s*\(/;
|
|
7383
|
+
ALWAYS_TRUE_ON_OBJECT = /^\)\s*\.\s*(?:toBeTruthy|toBeDefined|not\s*\.\s*(?:toBeNull|toBeUndefined|toBeFalsy))\s*\(/;
|
|
7384
|
+
COUNT_AT_LEAST_ZERO = /\.(?:count\s*\(\s*\)|length)[\s)]{0,10}\.(?:toBeGreaterThanOrEqual\s*\(\s*0\s*\)|toBeGreaterThan\s*\(\s*-\s*1\s*\))/;
|
|
7385
|
+
DEFINED_VALUE_READ = /\.\s*(?:count|textContent|innerText|innerHTML|inputValue|getAttribute|title|url|isVisible|isHidden|isChecked|isEnabled|isDisabled|isEditable|allTextContents|allInnerTexts)\s*\([^()]*\)$/;
|
|
7386
|
+
ALWAYS_DEFINED = /^\)\s*\.\s*(?:toBeDefined|not\s*\.\s*toBeUndefined)\s*\(/;
|
|
7387
|
+
SELF_COMPARE_MATCHER = /^\)\s*\.\s*(toBe|toEqual|toStrictEqual|toHaveCount)\s*\(/;
|
|
7388
|
+
IS_VISIBLE_TRUE = /^\)*\s*\.\s*(?:toBe\s*\(\s*true\s*\)|toBeTruthy\s*\(\s*\))/;
|
|
7389
|
+
PAGE_VALUE_MATCHER = /^\)\s*\.\s*(?:toBe|toEqual|toStrictEqual|toMatch|toContain)\s*\(/;
|
|
7390
|
+
COUNT_ONE = /\.\s*toHaveCount\s*\(\s*1\s*\)/;
|
|
7381
7391
|
FORM_CONTROL_LOCATOR = /getByRole\s*\(\s*['"`](?:combobox|switch|checkbox|radio|textbox|searchbox|spinbutton|slider)['"`]|getByLabel\s*\(|getByPlaceholder\s*\(/;
|
|
7382
7392
|
CONTROL_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(|\.toHaveAttribute\s*\(\s*['"`]aria-checked['"`]/;
|
|
7383
7393
|
COPY_CONTROL = /\bcopy\b/i;
|
|
@@ -8859,51 +8869,188 @@ function deriveAuthPlan(tags, code, opts) {
|
|
|
8859
8869
|
const apiWithoutStoredCreds = isApi && !t.includes("@auth") && !t.includes("@needs-auth") && !!code?.trim() && !codeReadsStoredCredentials(code);
|
|
8860
8870
|
const needsLoginCreds = authedLegacy && !selfLoginWithoutStoredCreds && !apiWithoutStoredCreds;
|
|
8861
8871
|
return {
|
|
8862
|
-
version: 1,
|
|
8863
|
-
source: "legacy",
|
|
8864
|
-
acquisition: cookie ? "browser-bootstrap" : authedLegacy ? "request-login" : "none",
|
|
8865
|
-
presentation: authedLegacy ? "cookie" : "none",
|
|
8866
|
-
needsCookieState: cookie,
|
|
8867
|
-
needsStandingHeaders: false,
|
|
8868
|
-
// A legacy bare-@api test keeps injecting standing headers IF the project configured them
|
|
8869
|
-
// (preserving today's behavior) — but does not require them. Non-@api legacy tests never inject.
|
|
8870
|
-
standingHeadersMode: isApi ? "legacy-if-configured" : "none",
|
|
8871
|
-
needsLoginCreds,
|
|
8872
|
-
requiredEnvKeys: needsLoginCreds ? [...TEST_USER_ENV_KEYS] : []
|
|
8872
|
+
version: 1,
|
|
8873
|
+
source: "legacy",
|
|
8874
|
+
acquisition: cookie ? "browser-bootstrap" : authedLegacy ? "request-login" : "none",
|
|
8875
|
+
presentation: authedLegacy ? "cookie" : "none",
|
|
8876
|
+
needsCookieState: cookie,
|
|
8877
|
+
needsStandingHeaders: false,
|
|
8878
|
+
// A legacy bare-@api test keeps injecting standing headers IF the project configured them
|
|
8879
|
+
// (preserving today's behavior) — but does not require them. Non-@api legacy tests never inject.
|
|
8880
|
+
standingHeadersMode: isApi ? "legacy-if-configured" : "none",
|
|
8881
|
+
needsLoginCreds,
|
|
8882
|
+
requiredEnvKeys: needsLoginCreds ? [...TEST_USER_ENV_KEYS] : []
|
|
8883
|
+
};
|
|
8884
|
+
}
|
|
8885
|
+
function authTypeTag(tags) {
|
|
8886
|
+
const t = Array.isArray(tags) ? tags : [];
|
|
8887
|
+
const explicit = explicitAuthTypeTags(t);
|
|
8888
|
+
return explicit.length === 1 ? explicit[0] : void 0;
|
|
8889
|
+
}
|
|
8890
|
+
var AUTH_TAG_COOKIE_STATE, AUTH_TAG_LOGIN_COOKIE, AUTH_TAG_LOGIN_BEARER, AUTH_TAG_STANDING, AUTH_TAG_NONE, AUTH_TAG_UNSUPPORTED, AUTH_TYPE_TAGS, AUTH_TAG_ALIASES, TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY;
|
|
8891
|
+
var init_auth_plan = __esm({
|
|
8892
|
+
"../shared/dist/auth-plan.js"() {
|
|
8893
|
+
"use strict";
|
|
8894
|
+
AUTH_TAG_COOKIE_STATE = "@auth-cookie-state";
|
|
8895
|
+
AUTH_TAG_LOGIN_COOKIE = "@auth-login-cookie";
|
|
8896
|
+
AUTH_TAG_LOGIN_BEARER = "@auth-login-bearer";
|
|
8897
|
+
AUTH_TAG_STANDING = "@auth-standing";
|
|
8898
|
+
AUTH_TAG_NONE = "@auth-none";
|
|
8899
|
+
AUTH_TAG_UNSUPPORTED = "@auth-unsupported";
|
|
8900
|
+
AUTH_TYPE_TAGS = [
|
|
8901
|
+
AUTH_TAG_COOKIE_STATE,
|
|
8902
|
+
AUTH_TAG_LOGIN_COOKIE,
|
|
8903
|
+
AUTH_TAG_LOGIN_BEARER,
|
|
8904
|
+
AUTH_TAG_STANDING,
|
|
8905
|
+
AUTH_TAG_NONE,
|
|
8906
|
+
AUTH_TAG_UNSUPPORTED
|
|
8907
|
+
];
|
|
8908
|
+
AUTH_TAG_ALIASES = {
|
|
8909
|
+
"@auth-cookie": AUTH_TAG_COOKIE_STATE,
|
|
8910
|
+
"@auth-bearer": AUTH_TAG_LOGIN_BEARER,
|
|
8911
|
+
"@auth-token": AUTH_TAG_LOGIN_BEARER,
|
|
8912
|
+
"@auth-api-key": AUTH_TAG_STANDING,
|
|
8913
|
+
"@auth-standing-header": AUTH_TAG_STANDING
|
|
8914
|
+
};
|
|
8915
|
+
TEST_USER_ENV_KEYS = ["TEST_USER_EMAIL", "TEST_USER_PASSWORD"];
|
|
8916
|
+
API_AUTH_HEADERS_ENV_KEY = "API_AUTH_HEADERS";
|
|
8917
|
+
}
|
|
8918
|
+
});
|
|
8919
|
+
|
|
8920
|
+
// ../shared/dist/auth-block-detector.js
|
|
8921
|
+
function stripEchoLines(text) {
|
|
8922
|
+
return text.split("\n").filter((line) => !ECHO_LINE_RE.test(line)).join("\n");
|
|
8923
|
+
}
|
|
8924
|
+
function matchesAny(text, patterns) {
|
|
8925
|
+
return patterns.some((p) => p.test(text));
|
|
8926
|
+
}
|
|
8927
|
+
function detectAuthBlock(input) {
|
|
8928
|
+
const tags = input.tags ?? [];
|
|
8929
|
+
const isAuthed = tags.some((t) => AUTHED_TAGS.includes(t));
|
|
8930
|
+
if (!isAuthed)
|
|
8931
|
+
return NO_DETECTION;
|
|
8932
|
+
const meta = [input.testName, input.description].filter(Boolean).join(" ");
|
|
8933
|
+
if (matchesAny(meta, INTENTIONAL_NEGATIVE_AUTH))
|
|
8934
|
+
return NO_DETECTION;
|
|
8935
|
+
const sources = [];
|
|
8936
|
+
if (input.error)
|
|
8937
|
+
sources.push(stripEchoLines(input.error));
|
|
8938
|
+
if (input.logs)
|
|
8939
|
+
sources.push(stripEchoLines(input.logs));
|
|
8940
|
+
for (const sr of input.stepResults ?? []) {
|
|
8941
|
+
if (sr.error)
|
|
8942
|
+
sources.push(stripEchoLines(sr.error));
|
|
8943
|
+
}
|
|
8944
|
+
for (const text of sources) {
|
|
8945
|
+
if (!text)
|
|
8946
|
+
continue;
|
|
8947
|
+
for (const sig of AUTH_BLOCK_SIGNATURES) {
|
|
8948
|
+
if (sig.re.test(text)) {
|
|
8949
|
+
return {
|
|
8950
|
+
detected: true,
|
|
8951
|
+
reason: sig.reason,
|
|
8952
|
+
evidence: [`login-block signature "${sig.reason}" in: "${text.slice(0, 140).replace(/\s+/g, " ").trim()}"`]
|
|
8953
|
+
};
|
|
8954
|
+
}
|
|
8955
|
+
}
|
|
8956
|
+
}
|
|
8957
|
+
return NO_DETECTION;
|
|
8958
|
+
}
|
|
8959
|
+
function detectApiColdSessionBlock(input) {
|
|
8960
|
+
const tags = input.tags ?? [];
|
|
8961
|
+
if (!tags.includes("@api"))
|
|
8962
|
+
return NO_DETECTION;
|
|
8963
|
+
const cookieMissing = input.authStateExpected && !input.authStateInjected;
|
|
8964
|
+
const standingMissing = !!input.needsStandingHeaders && !input.standingHeadersInjected;
|
|
8965
|
+
if (!cookieMissing && !standingMissing)
|
|
8966
|
+
return NO_DETECTION;
|
|
8967
|
+
const has401Status = (input.apiCalls ?? []).some((c) => c && (c.status === 401 || c.status === 403));
|
|
8968
|
+
const texts = [];
|
|
8969
|
+
if (input.error)
|
|
8970
|
+
texts.push(input.error);
|
|
8971
|
+
if (input.logs)
|
|
8972
|
+
texts.push(input.logs);
|
|
8973
|
+
for (const sr of input.stepResults ?? [])
|
|
8974
|
+
if (sr.error)
|
|
8975
|
+
texts.push(sr.error);
|
|
8976
|
+
const has401Text = texts.some((t) => UNAUTHORIZED_TEXT_RE.test(t));
|
|
8977
|
+
if (!has401Status && !has401Text)
|
|
8978
|
+
return NO_DETECTION;
|
|
8979
|
+
const missingAuth = cookieMissing ? "cold injected auth session (401/403 with no storageState)" : "missing standing auth header (401/403 with no API_AUTH_HEADERS installed)";
|
|
8980
|
+
const injectedNoun = cookieMissing ? "injected session was absent/expired" : "standing auth header was not installed";
|
|
8981
|
+
return {
|
|
8982
|
+
detected: true,
|
|
8983
|
+
reason: missingAuth,
|
|
8984
|
+
evidence: [
|
|
8985
|
+
has401Status ? `a captured @api call returned 401/403 while the ${injectedNoun}` : `a 401/403 signal in the run error/logs while the ${injectedNoun}`
|
|
8986
|
+
]
|
|
8873
8987
|
};
|
|
8874
8988
|
}
|
|
8875
|
-
function
|
|
8876
|
-
|
|
8877
|
-
const explicit = explicitAuthTypeTags(t);
|
|
8878
|
-
return explicit.length === 1 ? explicit[0] : void 0;
|
|
8989
|
+
function coldSessionConfigMessage(context, reason, evidence) {
|
|
8990
|
+
return `CONFIG_ISSUE: ${context} without valid injected auth (${reason}) \u2014 no session cookie was injected this run. Ensure the project login (auth-setup recipe / prewarm) is configured so the shared session jar warms (a project with no login: set TEST_USER_EMAIL and TEST_USER_PASSWORD in Test Data \u2192 Test Variables so a session can be captured); for endpoints that authenticate with a standing API key or bearer header instead, set them in the project's API_AUTH_HEADERS variable (injected as request headers). Evidence: ${evidence.join("; ")}`;
|
|
8879
8991
|
}
|
|
8880
|
-
var
|
|
8881
|
-
var
|
|
8882
|
-
"../shared/dist/auth-
|
|
8992
|
+
var NO_DETECTION, AUTHED_TAGS, LOGIN_CTX, AUTH_BLOCK_SIGNATURES, INTENTIONAL_NEGATIVE_AUTH, ECHO_LINE_RE, UNAUTHORIZED_TEXT_RE;
|
|
8993
|
+
var init_auth_block_detector = __esm({
|
|
8994
|
+
"../shared/dist/auth-block-detector.js"() {
|
|
8883
8995
|
"use strict";
|
|
8884
|
-
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
8996
|
+
NO_DETECTION = { detected: false, reason: "", evidence: [] };
|
|
8997
|
+
AUTHED_TAGS = ["@needs-auth", "@inline-login"];
|
|
8998
|
+
LOGIN_CTX = "\\b(?:log\\s*in|login|logging\\s+in|sign[\\s-]?in|signing\\s+in|continue)\\b";
|
|
8999
|
+
AUTH_BLOCK_SIGNATURES = [
|
|
9000
|
+
{ reason: "incorrect password", re: /\b(incorrect|invalid|wrong|bad)\s+password\b/i },
|
|
9001
|
+
{ reason: "password is incorrect", re: /\bpassword\s+(is\s+)?(incorrect|invalid|wrong)\b/i },
|
|
9002
|
+
{ reason: "invalid credentials", re: /\b(invalid|incorrect|wrong|bad)\s+(login\s+)?credentials\b/i },
|
|
9003
|
+
{ reason: "credentials do not match", re: /\bcredentials\b[^\n]{0,40}\b(do(?:es)?\s*n['’]?t|do\s+not)\s+match\b/i },
|
|
9004
|
+
{ reason: "incorrect email or password", re: /\b(incorrect|invalid|wrong)\s+(email|username)\s+or\s+password\b/i },
|
|
9005
|
+
// Require an EXPLICIT negative (codex #21): the old `(not\s+)?(confirmed|verified)` made the negation
|
|
9006
|
+
// optional, so a benign "Email verified" success message / feature assertion matched and hid a real
|
|
9007
|
+
// feature failure as a CONFIG_ISSUE. Only "email not (yet) confirmed/verified" or "unconfirmed/unverified".
|
|
9008
|
+
{ reason: "email not confirmed", re: /\b(e-?mail)\b[^\n]{0,30}\b(not\s+(?:yet\s+)?(?:confirmed|verified)|unconfirmed|unverified)\b/i },
|
|
9009
|
+
{ reason: "please confirm your email", re: /\bplease\s+(confirm|verify)\s+your\s+(e-?mail)\b/i },
|
|
9010
|
+
// The bare "confirm/verify your email" and "account not found" phrases are ALSO ordinary feature copy
|
|
9011
|
+
// ("Verify your email banner", a 404-style "Account not found" page), so they only count with a
|
|
9012
|
+
// login/sign-in context on the SAME line (either side). "Please confirm/verify your email" above
|
|
9013
|
+
// is already an explicit prompt and stays unconditional.
|
|
9014
|
+
{ reason: "confirm your email to continue", re: new RegExp(`${LOGIN_CTX}[^\\n]{0,80}\\bconfirm\\s+your\\s+e-?mail\\b|\\bconfirm\\s+your\\s+e-?mail\\b[^\\n]{0,80}${LOGIN_CTX}`, "i") },
|
|
9015
|
+
{ reason: "verify your email to continue", re: new RegExp(`${LOGIN_CTX}[^\\n]{0,80}\\bverify\\s+your\\s+e-?mail\\b|\\bverify\\s+your\\s+e-?mail\\b[^\\n]{0,80}${LOGIN_CTX}`, "i") },
|
|
9016
|
+
{
|
|
9017
|
+
reason: "account not found",
|
|
9018
|
+
re: new RegExp(`${LOGIN_CTX}[^\\n]{0,80}\\baccount\\b[^\\n]{0,20}\\b(?:not\\s+found|does(?:n['\u2019]t| not)\\s+exist)\\b|\\baccount\\b[^\\n]{0,20}\\b(?:not\\s+found|does(?:n['\u2019]t| not)\\s+exist)\\b[^\\n]{0,80}${LOGIN_CTX}`, "i")
|
|
9019
|
+
},
|
|
9020
|
+
{ reason: "authentication failed", re: /\bauthentication\s+failed\b/i },
|
|
9021
|
+
{ reason: "login failed", re: /\b(login|log\s*in|sign[\s-]?in)\s+failed\b/i }
|
|
8897
9022
|
];
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
"
|
|
8902
|
-
"
|
|
8903
|
-
|
|
8904
|
-
|
|
8905
|
-
|
|
8906
|
-
|
|
9023
|
+
INTENTIONAL_NEGATIVE_AUTH = [
|
|
9024
|
+
/\b(invalid|incorrect|wrong|bad)\s+(password|credentials|email|login)\b/i,
|
|
9025
|
+
/\b(negative|unhappy)\s+(login|auth|sign[\s-]?in|path|case|flow|test)\b/i,
|
|
9026
|
+
// "should fail" et al must be TIED to an auth noun (codex #21): a bare `should\s+(fail|reject|deny)`
|
|
9027
|
+
// exempted benign names like "Export should fail gracefully", silently disabling the anti-lockout
|
|
9028
|
+
// protection for them. Require a login/auth noun on either side of the "should fail / fail to log in".
|
|
9029
|
+
/\b(login|log\s*in|sign[\s-]?in|auth\w*|credential|password)\b[^\n]{0,40}\bshould\s+(fail|reject|deny)\b/i,
|
|
9030
|
+
/\bshould\s+(fail|reject|deny|not\s+log(?:\s*in)?)\b[^\n]{0,40}\b(login|log\s*in|sign[\s-]?in|auth\w*|credential|password|unauthenticated)\b/i,
|
|
9031
|
+
/\bfailed?\s+login\b/i,
|
|
9032
|
+
/\blogin\s+(error|failure|rejected?)\b/i,
|
|
9033
|
+
/\b(reject|deny|denied|block(ed)?)\b[^\n]{0,20}\b(login|sign[\s-]?in|auth|credential|password)\b/i
|
|
9034
|
+
];
|
|
9035
|
+
ECHO_LINE_RE = /^\s*(?:(?:📋|🎭|🌐|⚙️?)|(?:stderr:\s*|stdout:\s*)?Locator:)/u;
|
|
9036
|
+
UNAUTHORIZED_TEXT_RE = /(?:return(?:s|ed|ing)?|respond(?:s|ed|ing)?|got|receiv(?:e|ed|ing)|gives?|sends?|yield(?:s|ed|ing)?|results?\s+in)\s+(?:a\s+|an\s+|the\s+)?(?:401|403)\b|\bstatus(?:\s+code)?\s*:?\s*(?:401|403)\b|\bHTTP\/[\d.]+\s+(?:401|403)\b|(?:401|403)['’]d\b|(?:[→⇒]|->)\s*(?:401|403)\b|(?:return(?:s|ed|ing)?|respond(?:s|ed|ing)?|got|receiv(?:e|ed|ing)|threw|throws?)\s+(?:a\s+|an\s+)?(?:unauthorized|forbidden)\b|\bnot\s+authenticated\b/i;
|
|
9037
|
+
}
|
|
9038
|
+
});
|
|
9039
|
+
|
|
9040
|
+
// ../shared/dist/auth-session-stamp.js
|
|
9041
|
+
function parseAuthSessionStamp(value) {
|
|
9042
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
9043
|
+
return null;
|
|
9044
|
+
const { shared, role, generation } = value;
|
|
9045
|
+
if (shared !== true || role !== "producer" && role !== "follower")
|
|
9046
|
+
return null;
|
|
9047
|
+
return typeof generation === "string" && AUTH_SESSION_GENERATION_RE.test(generation) ? { shared: true, role, generation } : { shared: true, role };
|
|
9048
|
+
}
|
|
9049
|
+
var AUTH_SESSION_GENERATION_RE;
|
|
9050
|
+
var init_auth_session_stamp = __esm({
|
|
9051
|
+
"../shared/dist/auth-session-stamp.js"() {
|
|
9052
|
+
"use strict";
|
|
9053
|
+
AUTH_SESSION_GENERATION_RE = /^[0-9a-z]{1,16}$/;
|
|
8907
9054
|
}
|
|
8908
9055
|
});
|
|
8909
9056
|
|
|
@@ -9092,6 +9239,43 @@ var init_auth_state_freshness = __esm({
|
|
|
9092
9239
|
}
|
|
9093
9240
|
});
|
|
9094
9241
|
|
|
9242
|
+
// ../shared/dist/skip-coverage-detector.js
|
|
9243
|
+
function detectSkippedApiCoverage(steps) {
|
|
9244
|
+
const allSkipped = steps.length > 0 && steps.every((s) => s.status === "skipped");
|
|
9245
|
+
if (allSkipped) {
|
|
9246
|
+
if (steps.every((s) => s.skipKind === "fixme")) {
|
|
9247
|
+
return {
|
|
9248
|
+
detected: false,
|
|
9249
|
+
logLine: "All @api tests skipped, but EVERY skip is a deliberate fixme (intentional N/A \u2014 e.g. a UI-only redirect login) \u2014 NOT relabelling CONFIG_ISSUE"
|
|
9250
|
+
};
|
|
9251
|
+
}
|
|
9252
|
+
return {
|
|
9253
|
+
detected: true,
|
|
9254
|
+
error: (
|
|
9255
|
+
// Name BOTH auth mechanisms (item 5d): the all-skipped copy used to say only "refresh the auth
|
|
9256
|
+
// state", which misdirects a @auth-standing operator (whose real gap is a missing API_AUTH_HEADERS
|
|
9257
|
+
// key, not a cold cookie session) to warm a login that was never the problem.
|
|
9258
|
+
"CONFIG_ISSUE: Authenticated @api coverage was NOT exercised \u2014 every test skipped (cold injected session, a missing standing auth header, or an unresolved fixme). Provide the auth the endpoints need \u2014 warm the project login/session cookie (auth-setup recipe / prewarm), or set a standing API key/bearer in the project's API_AUTH_HEADERS variable \u2014 so the assertions actually run."
|
|
9259
|
+
),
|
|
9260
|
+
logLine: "All @api tests skipped \u2014 posting ERROR/CONFIG_ISSUE (not PASSED) so zero authenticated coverage is visible, not silent green"
|
|
9261
|
+
};
|
|
9262
|
+
}
|
|
9263
|
+
const runtimeSkipped = steps.filter((s) => s.status === "skipped" && s.skipKind === "skip");
|
|
9264
|
+
if (runtimeSkipped.length === 0)
|
|
9265
|
+
return { detected: false };
|
|
9266
|
+
const reasons = [...new Set(runtimeSkipped.map((s) => `"${s.title ?? "test"}"${s.skipReason ? ` (${s.skipReason})` : ""}`))].join("; ");
|
|
9267
|
+
return {
|
|
9268
|
+
detected: true,
|
|
9269
|
+
error: `CONFIG_ISSUE: ${runtimeSkipped.length} of ${steps.length} @api tests skipped at runtime \u2014 that coverage was NOT exercised. Skipped: ${reasons}`,
|
|
9270
|
+
logLine: `${runtimeSkipped.length}/${steps.length} @api tests skipped at runtime \u2014 posting ERROR/CONFIG_ISSUE (not PASSED) so the coverage hole is visible, not silent green`
|
|
9271
|
+
};
|
|
9272
|
+
}
|
|
9273
|
+
var init_skip_coverage_detector = __esm({
|
|
9274
|
+
"../shared/dist/skip-coverage-detector.js"() {
|
|
9275
|
+
"use strict";
|
|
9276
|
+
}
|
|
9277
|
+
});
|
|
9278
|
+
|
|
9095
9279
|
// ../shared/dist/feature-coverage.js
|
|
9096
9280
|
function computeFeatureCoverage(input) {
|
|
9097
9281
|
const { tests } = input;
|
|
@@ -9783,6 +9967,19 @@ var init_deepgram_speech = __esm({
|
|
|
9783
9967
|
}
|
|
9784
9968
|
});
|
|
9785
9969
|
|
|
9970
|
+
// ../shared/dist/feature-flags.js
|
|
9971
|
+
function isSharedAuthInjectEnabled(value = process.env.SHARED_AUTH_INJECT) {
|
|
9972
|
+
return value?.trim().toLowerCase() !== "false";
|
|
9973
|
+
}
|
|
9974
|
+
function isAuthReadinessGuardEnabled(value = process.env.AUTH_READINESS_GUARD) {
|
|
9975
|
+
return value?.trim().toLowerCase() !== "false";
|
|
9976
|
+
}
|
|
9977
|
+
var init_feature_flags = __esm({
|
|
9978
|
+
"../shared/dist/feature-flags.js"() {
|
|
9979
|
+
"use strict";
|
|
9980
|
+
}
|
|
9981
|
+
});
|
|
9982
|
+
|
|
9786
9983
|
// ../shared/dist/analytics-url.js
|
|
9787
9984
|
function isSensitiveQueryKey(key) {
|
|
9788
9985
|
return SENSITIVE_QUERY_KEY_RE.test(key);
|
|
@@ -10085,7 +10282,7 @@ var init_agentic_cli_runtime = __esm({
|
|
|
10085
10282
|
GROK_CLI_DEFAULT_MODEL = "grok-4.7";
|
|
10086
10283
|
GROK_CLI_DEFAULT_REASONING_EFFORT = "high";
|
|
10087
10284
|
CLAUDE_CLI_DEFAULT_MODEL = "claude-sonnet-5-5";
|
|
10088
|
-
CLAUDE_CLI_DEFAULT_EFFORT = "
|
|
10285
|
+
CLAUDE_CLI_DEFAULT_EFFORT = "high";
|
|
10089
10286
|
MUSE_CLI_DEFAULT_MODEL = "muse-spark-1.3-contributor";
|
|
10090
10287
|
MUSE_CLI_DEFAULT_EFFORT = "high";
|
|
10091
10288
|
CODEX_CLI_DEFAULT_MODEL = "gpt-6.1-sol";
|
|
@@ -10136,9 +10333,25 @@ function isOpenCodeGoModelId(id) {
|
|
|
10136
10333
|
function hasOpenCodeGoPrefix(id) {
|
|
10137
10334
|
return (id?.trim() ?? "").startsWith(OPENCODE_GO_PREFIX);
|
|
10138
10335
|
}
|
|
10336
|
+
function hasOpenCodeGo2Prefix(id) {
|
|
10337
|
+
return (id?.trim() ?? "").startsWith(OPENCODE_GO_2_PREFIX);
|
|
10338
|
+
}
|
|
10139
10339
|
function openCodeGoWireModel(id) {
|
|
10140
10340
|
const trimmed = id?.trim() ?? "";
|
|
10141
|
-
|
|
10341
|
+
if (!isOpenCodeGoModelId(trimmed))
|
|
10342
|
+
return null;
|
|
10343
|
+
return trimmed.slice((hasOpenCodeGo2Prefix(trimmed) ? OPENCODE_GO_2_PREFIX : OPENCODE_GO_PREFIX).length);
|
|
10344
|
+
}
|
|
10345
|
+
function isZaiModelId(id) {
|
|
10346
|
+
const trimmed = id?.trim() ?? "";
|
|
10347
|
+
return ZAI_MODEL_PATTERN.test(trimmed) && !trimmed.includes("..");
|
|
10348
|
+
}
|
|
10349
|
+
function hasZaiPrefix(id) {
|
|
10350
|
+
return (id?.trim() ?? "").startsWith(ZAI_PREFIX);
|
|
10351
|
+
}
|
|
10352
|
+
function zaiWireModel(id) {
|
|
10353
|
+
const trimmed = id?.trim() ?? "";
|
|
10354
|
+
return isZaiModelId(trimmed) ? trimmed.slice(ZAI_PREFIX.length) : null;
|
|
10142
10355
|
}
|
|
10143
10356
|
function isEngineId(value) {
|
|
10144
10357
|
return CLI_ENGINE_MODEL_IDS.includes(value);
|
|
@@ -10236,7 +10449,7 @@ function museCliContributorMode(env = process.env) {
|
|
|
10236
10449
|
const raw = (env.MUSE_CLI_CONTRIBUTOR_MODE ?? "").trim().toLowerCase();
|
|
10237
10450
|
return raw === "off" || raw === "false" || raw === "0" || raw === "no" ? "off" : "on";
|
|
10238
10451
|
}
|
|
10239
|
-
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;
|
|
10452
|
+
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;
|
|
10240
10453
|
var init_engine_spec = __esm({
|
|
10241
10454
|
"../shared/dist/engine-spec.js"() {
|
|
10242
10455
|
"use strict";
|
|
@@ -10295,7 +10508,10 @@ var init_engine_spec = __esm({
|
|
|
10295
10508
|
OPENROUTER_PREFIX = "openrouter:";
|
|
10296
10509
|
OPENROUTER_MODEL_PATTERN = /^openrouter:[a-z0-9][a-z0-9._-]{0,40}\/[A-Za-z0-9._:-]{1,100}$/;
|
|
10297
10510
|
OPENCODE_GO_PREFIX = "opencode-go:";
|
|
10298
|
-
|
|
10511
|
+
OPENCODE_GO_2_PREFIX = "opencode-go-2:";
|
|
10512
|
+
OPENCODE_GO_MODEL_PATTERN = /^opencode-go(?:-2)?:[a-z0-9][a-z0-9._-]{0,100}$/;
|
|
10513
|
+
ZAI_PREFIX = "zai:";
|
|
10514
|
+
ZAI_MODEL_PATTERN = /^zai:glm-[a-z0-9][a-z0-9._-]{0,60}$/;
|
|
10299
10515
|
}
|
|
10300
10516
|
});
|
|
10301
10517
|
|
|
@@ -10580,6 +10796,8 @@ var init_api_model_catalog = __esm({
|
|
|
10580
10796
|
authCaptureModel: "Login capture",
|
|
10581
10797
|
plannerModel: "Scenario Planner",
|
|
10582
10798
|
plannerGateModel: "Planner Gate",
|
|
10799
|
+
pwAgentsHealerModel: "Test Healer (Playwright agents)",
|
|
10800
|
+
pwAgentsReviewModel: "Plan Review (Playwright agents)",
|
|
10583
10801
|
generationModel: "Code Generation",
|
|
10584
10802
|
reviewModel: "Code Review",
|
|
10585
10803
|
apiTestModel: "API Test Generator",
|
|
@@ -10604,11 +10822,6 @@ var init_api_model_catalog = __esm({
|
|
|
10604
10822
|
});
|
|
10605
10823
|
|
|
10606
10824
|
// ../shared/dist/provider-chains.js
|
|
10607
|
-
function isClaudeModel(id) {
|
|
10608
|
-
if (/claude|anthropic/i.test(id))
|
|
10609
|
-
return true;
|
|
10610
|
-
return API_MODEL_CATALOG.some((m) => m.provider === "anthropic" && (m.id === id || m.apiModel === id));
|
|
10611
|
-
}
|
|
10612
10825
|
function chainKey(modelId) {
|
|
10613
10826
|
const id = canonicalModelId(modelId);
|
|
10614
10827
|
if (!id)
|
|
@@ -10616,34 +10829,83 @@ function chainKey(modelId) {
|
|
|
10616
10829
|
const entry = API_MODEL_CATALOG.find((m) => m.id === id || m.apiModel === id);
|
|
10617
10830
|
return entry?.id ?? id;
|
|
10618
10831
|
}
|
|
10832
|
+
function has(map, key) {
|
|
10833
|
+
return Object.prototype.hasOwnProperty.call(map, key);
|
|
10834
|
+
}
|
|
10619
10835
|
function providerChainFor(modelId) {
|
|
10620
10836
|
const key = chainKey(modelId);
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10837
|
+
return key && has(PROVIDER_CHAINS, key) ? PROVIDER_CHAINS[key] : [];
|
|
10838
|
+
}
|
|
10839
|
+
function providerChainLeadsFor(modelId) {
|
|
10840
|
+
const key = chainKey(modelId);
|
|
10841
|
+
return key && has(PROVIDER_CHAIN_LEADS, key) ? PROVIDER_CHAIN_LEADS[key] : [];
|
|
10842
|
+
}
|
|
10843
|
+
function allChains() {
|
|
10844
|
+
return [...Object.entries(PROVIDER_CHAINS), ...Object.entries(PROVIDER_CHAIN_LEADS)];
|
|
10624
10845
|
}
|
|
10625
10846
|
function isProviderChainHopId(modelId) {
|
|
10626
10847
|
const id = modelId ?? "";
|
|
10627
|
-
return id !== "" &&
|
|
10848
|
+
return id !== "" && allChains().some(([, hops]) => hops.includes(id));
|
|
10628
10849
|
}
|
|
10629
10850
|
function providerChainPrimariesForHop(hopId) {
|
|
10630
10851
|
const id = hopId ?? "";
|
|
10631
10852
|
if (!id)
|
|
10632
10853
|
return [];
|
|
10633
|
-
return
|
|
10854
|
+
return allChains().filter(([, hops]) => hops.includes(id)).map(([primary]) => primary);
|
|
10855
|
+
}
|
|
10856
|
+
function providerChainHostOf(value, modelValue) {
|
|
10857
|
+
if (value === modelValue)
|
|
10858
|
+
return "own";
|
|
10859
|
+
if (hasZaiPrefix(value))
|
|
10860
|
+
return "zai";
|
|
10861
|
+
if (hasOpenCodeGo2Prefix(value))
|
|
10862
|
+
return "opencode-go-2";
|
|
10863
|
+
if (hasOpenCodeGoPrefix(value))
|
|
10864
|
+
return "opencode-go";
|
|
10865
|
+
if (hasOpenRouterPrefix(value))
|
|
10866
|
+
return "openrouter";
|
|
10867
|
+
return "own";
|
|
10868
|
+
}
|
|
10869
|
+
function providerHostPlan(modelId) {
|
|
10870
|
+
const key = chainKey(modelId);
|
|
10871
|
+
if (!key)
|
|
10872
|
+
return [];
|
|
10873
|
+
const own = { host: hasOpenRouterPrefix(key) ? "openrouter" : "own", value: key };
|
|
10874
|
+
const steps = [
|
|
10875
|
+
...providerChainLeadsFor(key).map((value) => ({ host: providerChainHostOf(value, key), value })),
|
|
10876
|
+
own,
|
|
10877
|
+
...providerChainFor(key).map((value) => ({ host: providerChainHostOf(value, key), value }))
|
|
10878
|
+
];
|
|
10879
|
+
const notOffered = Object.prototype.hasOwnProperty.call(PROVIDER_HOST_NOT_OFFERED, key) ? PROVIDER_HOST_NOT_OFFERED[key] : {};
|
|
10880
|
+
for (const [host, reason] of Object.entries(notOffered)) {
|
|
10881
|
+
const at = steps.findIndex((step) => step === own) + 1;
|
|
10882
|
+
steps.splice(at, 0, { host, value: null, notOffered: reason });
|
|
10883
|
+
}
|
|
10884
|
+
return steps;
|
|
10634
10885
|
}
|
|
10635
|
-
var PROVIDER_CHAINS;
|
|
10886
|
+
var PROVIDER_CHAINS, PROVIDER_CHAIN_LEADS, PROVIDER_HOST_NOT_OFFERED;
|
|
10636
10887
|
var init_provider_chains = __esm({
|
|
10637
10888
|
"../shared/dist/provider-chains.js"() {
|
|
10638
10889
|
"use strict";
|
|
10639
10890
|
init_api_model_catalog();
|
|
10891
|
+
init_engine_spec();
|
|
10640
10892
|
PROVIDER_CHAINS = {
|
|
10641
|
-
"minimax-m3": ["
|
|
10642
|
-
"minimax-m3.1-flash": ["
|
|
10893
|
+
"minimax-m3": ["opencode-go:minimax-m3", "openrouter:minimax/minimax-m3"],
|
|
10894
|
+
"minimax-m3.1-flash": ["opencode-go:minimax-m3.1-flash", "openrouter:minimax/minimax-m3.1-flash"],
|
|
10643
10895
|
"muse-spark-1.3-contributor": ["openrouter:meta/muse-spark-1.3-contributor"],
|
|
10644
|
-
"
|
|
10645
|
-
"
|
|
10646
|
-
"
|
|
10896
|
+
"claude-haiku-5-5": ["opencode-go:claude-haiku-5-5", "openrouter:anthropic/claude-haiku-5.5"],
|
|
10897
|
+
"gemini-3.1-pro-preview": ["openrouter:google/gemini-3.1-pro-preview"],
|
|
10898
|
+
"deepseek-flash": ["opencode-go-2:deepseek-v4.1-flash", "opencode-go:deepseek-v4.1-flash", "openrouter:deepseek/deepseek-v4.1-flash"],
|
|
10899
|
+
"deepseek-v4-pro": ["opencode-go-2:deepseek-v4-pro", "opencode-go:deepseek-v4-pro", "openrouter:deepseek/deepseek-v4-pro"]
|
|
10900
|
+
};
|
|
10901
|
+
PROVIDER_CHAIN_LEADS = {
|
|
10902
|
+
"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"],
|
|
10903
|
+
"openrouter:z-ai/glm-5.3": ["zai:glm-5.3", "opencode-go-2:glm-5.3", "opencode-go:glm-5.3"],
|
|
10904
|
+
"openrouter:z-ai/glm-5.2": ["zai:glm-5.2", "opencode-go-2:glm-5.2", "opencode-go:glm-5.2"]
|
|
10905
|
+
};
|
|
10906
|
+
PROVIDER_HOST_NOT_OFFERED = {
|
|
10907
|
+
"muse-spark-1.3-contributor": { "opencode-go": "OpenCode Go serves Muse only on its Responses API" },
|
|
10908
|
+
"gemini-3.1-pro-preview": { "opencode-go": "OpenCode Go does not serve Gemini" }
|
|
10647
10909
|
};
|
|
10648
10910
|
}
|
|
10649
10911
|
});
|
|
@@ -12581,7 +12843,7 @@ function stateLiteralsOf(line) {
|
|
|
12581
12843
|
const out = [];
|
|
12582
12844
|
for (const m of line.matchAll(STRING_LITERAL_RE)) {
|
|
12583
12845
|
const text = m[1] ?? m[2] ?? m[3] ?? "";
|
|
12584
|
-
if (
|
|
12846
|
+
if (PLACEHOLDER_ATTR_RE.test(text))
|
|
12585
12847
|
continue;
|
|
12586
12848
|
if (PLACEHOLDER_CALL_TAIL_RE.test(line.slice(Math.max(0, m.index - 40), m.index)))
|
|
12587
12849
|
continue;
|
|
@@ -12677,7 +12939,7 @@ function formatReadinessPollAdvisory(findings) {
|
|
|
12677
12939
|
const where = findings.length === 1 ? "One place" : `${findings.length} places`;
|
|
12678
12940
|
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}`;
|
|
12679
12941
|
}
|
|
12680
|
-
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;
|
|
12942
|
+
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;
|
|
12681
12943
|
var init_readiness_poll = __esm({
|
|
12682
12944
|
"../shared/dist/readiness-poll.js"() {
|
|
12683
12945
|
"use strict";
|
|
@@ -12690,7 +12952,7 @@ var init_readiness_poll = __esm({
|
|
|
12690
12952
|
STRING_LITERAL_RE = /'((?:\\.|[^'\\\n]){0,300})'|"((?:\\.|[^"\\\n]){0,300})"|`((?:\\.|[^`\\\n]){0,300})`/g;
|
|
12691
12953
|
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;
|
|
12692
12954
|
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;
|
|
12693
|
-
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,
|
|
12955
|
+
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;
|
|
12694
12956
|
LOCATOR_LINE_RE = /\.(?:getBy[A-Z]\w{0,30}|locator|toHaveText|toContainText)\s{0,20}\(/;
|
|
12695
12957
|
CLICK_RE = /\.(?:click|dblclick|tap)\s{0,20}\(/;
|
|
12696
12958
|
RELOAD_RE = /\bpage\.reload\s{0,20}\(/;
|
|
@@ -12704,6 +12966,7 @@ var init_readiness_poll = __esm({
|
|
|
12704
12966
|
TEST_END_RE = /^\s{0,20}\}\s{0,20}\)\s{0,20};?\s{0,20}$/;
|
|
12705
12967
|
TEST_START_RE = /\btest(?:\.\w{1,20})?\s{0,20}\(/;
|
|
12706
12968
|
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;
|
|
12969
|
+
PLACEHOLDER_ATTR_RE = /placeholder\s{0,4}[*^$~|]?=/;
|
|
12707
12970
|
PLACEHOLDER_CALL_TAIL_RE = /getByPlaceholder\s{0,20}\(\s{0,20}$/;
|
|
12708
12971
|
POLL_SHAPE = "await expect(async () => { await page.reload(); await expect(<the finished state>).toBeVisible({ timeout: 1500 }); }).toPass({ timeout: 20000 });";
|
|
12709
12972
|
}
|
|
@@ -13105,6 +13368,15 @@ function computes(line) {
|
|
|
13105
13368
|
const code = line.replace(STRING_RE, '""').replace(REGEX_LITERAL_RE, "$1RX").replace(LITERAL_ARITH_RE, "N");
|
|
13106
13369
|
return COMPUTE_RE.test(code) || RELATIONAL_RE.test(line);
|
|
13107
13370
|
}
|
|
13371
|
+
function identifiersIn(line) {
|
|
13372
|
+
const code = line.replace(STRING_RE, '""').replace(REGEX_LITERAL_RE, "$1RX");
|
|
13373
|
+
return [code, ...[...line.matchAll(TEMPLATE_EXPR_RE)].map((m) => m[1])].flatMap((part) => part.match(IDENTIFIER_RE) ?? []);
|
|
13374
|
+
}
|
|
13375
|
+
function addTyped(typed, value) {
|
|
13376
|
+
const d = digitsOf(value);
|
|
13377
|
+
if (/\d/.test(d))
|
|
13378
|
+
typed.add(d);
|
|
13379
|
+
}
|
|
13108
13380
|
function reasonFor4(kind, label, value) {
|
|
13109
13381
|
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.`;
|
|
13110
13382
|
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.`;
|
|
@@ -13116,25 +13388,32 @@ function analyzeDerivedValues(rawCode) {
|
|
|
13116
13388
|
for (const body of testBodies(rawCode)) {
|
|
13117
13389
|
if (findings.length >= MAX_FINDINGS4)
|
|
13118
13390
|
break;
|
|
13119
|
-
if (body.some(computes))
|
|
13120
|
-
continue;
|
|
13121
13391
|
const typed = /* @__PURE__ */ new Set();
|
|
13122
13392
|
const definitions = /* @__PURE__ */ new Map();
|
|
13393
|
+
const computed = /* @__PURE__ */ new Set();
|
|
13394
|
+
const usesComputed = (text) => identifiersIn(text).some((id) => computed.has(id));
|
|
13123
13395
|
for (const line of body) {
|
|
13124
13396
|
if (FILL_RE2.test(line) && !EXPECT_RE3.test(line)) {
|
|
13125
|
-
for (const m of line.matchAll(
|
|
13126
|
-
|
|
13127
|
-
|
|
13128
|
-
|
|
13129
|
-
|
|
13397
|
+
for (const m of line.matchAll(QUOTED_RE))
|
|
13398
|
+
addTyped(typed, m[1]);
|
|
13399
|
+
const arg = FILL_ARG_RE.exec(line)?.[1];
|
|
13400
|
+
const literal = arg === void 0 ? null : LITERAL_VALUE_RE.exec(definitions.get(arg) ?? "");
|
|
13401
|
+
const value = literal?.slice(1).find((v) => v !== void 0);
|
|
13402
|
+
if (value !== void 0)
|
|
13403
|
+
addTyped(typed, value);
|
|
13130
13404
|
}
|
|
13131
13405
|
const def = DEFINITION_RE.exec(line);
|
|
13132
|
-
if (def)
|
|
13406
|
+
if (def) {
|
|
13133
13407
|
definitions.set(def[1], def[2]);
|
|
13408
|
+
if (computes(def[2]) || usesComputed(def[2]))
|
|
13409
|
+
computed.add(def[1]);
|
|
13410
|
+
}
|
|
13134
13411
|
}
|
|
13135
13412
|
for (const line of body) {
|
|
13136
13413
|
if (!EXPECT_RE3.test(line) || !VALUE_MATCHER_RE2.test(line) || /\.not\s{0,20}\./.test(line))
|
|
13137
13414
|
continue;
|
|
13415
|
+
if (computes(line) || usesComputed(line))
|
|
13416
|
+
continue;
|
|
13138
13417
|
const subject = EXPECT_SUBJECT_RE.exec(line)?.[1];
|
|
13139
13418
|
const label = DERIVED_WORD_RE.exec(`${line} ${(subject && definitions.get(subject)) ?? ""}`)?.[0];
|
|
13140
13419
|
if (!label)
|
|
@@ -13164,7 +13443,7 @@ function formatDerivedValueAdvisory(findings) {
|
|
|
13164
13443
|
const where = findings.length === 1 ? "One computed value is" : `${findings.length} computed values are`;
|
|
13165
13444
|
return `${where} checked against a copied number or only its shape (${short4(first.line, 90)}). ${first.reason}`;
|
|
13166
13445
|
}
|
|
13167
|
-
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;
|
|
13446
|
+
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;
|
|
13168
13447
|
var init_derived_value_check = __esm({
|
|
13169
13448
|
"../shared/dist/derived-value-check.js"() {
|
|
13170
13449
|
"use strict";
|
|
@@ -13184,6 +13463,11 @@ var init_derived_value_check = __esm({
|
|
|
13184
13463
|
DEFINITION_RE = /\b(?:const|let)\s{1,10}([\w$]{1,60})\s{0,10}=\s{0,10}([^\n]{0,300})/;
|
|
13185
13464
|
EXPECT_SUBJECT_RE = /\bexpect(?:\.soft)?\s{0,20}\(\s{0,20}([\w$]{1,60})/;
|
|
13186
13465
|
LITERAL_ARITH_RE = /\b\d[\d_.]{0,15}(?:\s{0,5}[*/+-]\s{0,5}\d[\d_.]{0,15}){1,8}\b/g;
|
|
13466
|
+
TEMPLATE_EXPR_RE = /\$\{([^{}\n]{0,200})\}/g;
|
|
13467
|
+
IDENTIFIER_RE = /[A-Za-z_$][\w$]{0,60}/g;
|
|
13468
|
+
QUOTED_RE = /['"`]([^'"`\n]{0,40})['"`]/g;
|
|
13469
|
+
FILL_ARG_RE = /\.(?:fill|type|pressSequentially|selectOption)\s{0,20}\(\s{0,20}([A-Za-z_$][\w$]{0,60})\s{0,20}[,)]/;
|
|
13470
|
+
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}$/;
|
|
13187
13471
|
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.";
|
|
13188
13472
|
}
|
|
13189
13473
|
});
|
|
@@ -15218,6 +15502,99 @@ function formatStaleAfterSubmitAdvisory(rawCode) {
|
|
|
15218
15502
|
const more = described.length > 3 ? ` (+${described.length - 3} more)` : "";
|
|
15219
15503
|
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+$/)`;
|
|
15220
15504
|
}
|
|
15505
|
+
function regexLiteralEnd4(text, at) {
|
|
15506
|
+
let inClass = false;
|
|
15507
|
+
for (let i = at + 1; i < text.length; i++) {
|
|
15508
|
+
const ch = text[i];
|
|
15509
|
+
if (ch === "\n")
|
|
15510
|
+
return -1;
|
|
15511
|
+
if (ch === "\\") {
|
|
15512
|
+
i++;
|
|
15513
|
+
continue;
|
|
15514
|
+
}
|
|
15515
|
+
if (inClass) {
|
|
15516
|
+
if (ch === "]")
|
|
15517
|
+
inClass = false;
|
|
15518
|
+
continue;
|
|
15519
|
+
}
|
|
15520
|
+
if (ch === "[") {
|
|
15521
|
+
inClass = true;
|
|
15522
|
+
continue;
|
|
15523
|
+
}
|
|
15524
|
+
if (ch === "/")
|
|
15525
|
+
return i + 1;
|
|
15526
|
+
}
|
|
15527
|
+
return -1;
|
|
15528
|
+
}
|
|
15529
|
+
function startsWithRegexLiteral(text) {
|
|
15530
|
+
const t = text.trimStart();
|
|
15531
|
+
return t[0] === "/" && t[1] !== "/" && t[1] !== "*" && regexLiteralEnd4(t, 0) !== -1;
|
|
15532
|
+
}
|
|
15533
|
+
function afterFirstArg(args) {
|
|
15534
|
+
let depth = 0;
|
|
15535
|
+
let quote = null;
|
|
15536
|
+
for (let i = 0; i < args.length; i++) {
|
|
15537
|
+
const ch = args[i];
|
|
15538
|
+
if (quote) {
|
|
15539
|
+
if (ch === "\\") {
|
|
15540
|
+
i++;
|
|
15541
|
+
continue;
|
|
15542
|
+
}
|
|
15543
|
+
if (ch === quote)
|
|
15544
|
+
quote = null;
|
|
15545
|
+
continue;
|
|
15546
|
+
}
|
|
15547
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
15548
|
+
quote = ch;
|
|
15549
|
+
continue;
|
|
15550
|
+
}
|
|
15551
|
+
if (ch === "(" || ch === "[" || ch === "{")
|
|
15552
|
+
depth++;
|
|
15553
|
+
else if (ch === ")" || ch === "]" || ch === "}")
|
|
15554
|
+
depth--;
|
|
15555
|
+
else if (ch === "," && depth === 0)
|
|
15556
|
+
return args.slice(i + 1);
|
|
15557
|
+
}
|
|
15558
|
+
return "";
|
|
15559
|
+
}
|
|
15560
|
+
function analyzeRegexMatchers(rawCode) {
|
|
15561
|
+
if (!rawCode || typeof rawCode !== "string")
|
|
15562
|
+
return [];
|
|
15563
|
+
const code = stripComments2(rawCode.slice(0, MAX_LINT_INPUT));
|
|
15564
|
+
const out = [];
|
|
15565
|
+
const re = /\bexpect(?:\.soft)?\s{0,20}\(/g;
|
|
15566
|
+
let m;
|
|
15567
|
+
let examined = 0;
|
|
15568
|
+
let line = 1;
|
|
15569
|
+
let lineAt2 = 0;
|
|
15570
|
+
while ((m = re.exec(code)) !== null && examined++ < MAX_CALLS && out.length < MAX_REGEX_MATCHER_FINDINGS) {
|
|
15571
|
+
const subj = readBalanced(code, m.index + m[0].length);
|
|
15572
|
+
if (!subj)
|
|
15573
|
+
continue;
|
|
15574
|
+
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));
|
|
15575
|
+
if (!mm || !REGEX_EQUALITY_MATCHERS.has(mm[2]))
|
|
15576
|
+
continue;
|
|
15577
|
+
const args = readBalanced(code, subj.end + 1 + mm[0].length);
|
|
15578
|
+
if (!args)
|
|
15579
|
+
continue;
|
|
15580
|
+
const expected = mm[2] === "toHaveJSProperty" ? afterFirstArg(args.text) : args.text;
|
|
15581
|
+
if (!startsWithRegexLiteral(expected))
|
|
15582
|
+
continue;
|
|
15583
|
+
if (mm[2] !== "toHaveJSProperty" && mm[2] !== "toContain" && (startsWithRegexLiteral(subj.text) || /^new\s+RegExp\b/.test(subj.text.trim())))
|
|
15584
|
+
continue;
|
|
15585
|
+
for (let i = code.indexOf("\n", lineAt2); i !== -1 && i < m.index; i = code.indexOf("\n", i + 1)) {
|
|
15586
|
+
line++;
|
|
15587
|
+
lineAt2 = i + 1;
|
|
15588
|
+
}
|
|
15589
|
+
out.push({ line, matcher: mm[2], negated: mm[1] !== void 0 });
|
|
15590
|
+
}
|
|
15591
|
+
return out;
|
|
15592
|
+
}
|
|
15593
|
+
function formatRegexMatcherNote(findings) {
|
|
15594
|
+
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"}.`);
|
|
15595
|
+
return `${lines.join("\n")}
|
|
15596
|
+
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.`;
|
|
15597
|
+
}
|
|
15221
15598
|
function lintTestQuality(rawCode, opts = {}) {
|
|
15222
15599
|
if (!rawCode || typeof rawCode !== "string")
|
|
15223
15600
|
return [];
|
|
@@ -15225,6 +15602,10 @@ function lintTestQuality(rawCode, opts = {}) {
|
|
|
15225
15602
|
return lintTestData(rawCode, { pageContacts: opts.pageContacts });
|
|
15226
15603
|
if (opts.only === "test-data-blocking")
|
|
15227
15604
|
return analyzeTestData(rawCode, { pageContacts: opts.pageContacts }).blocking;
|
|
15605
|
+
if (opts.only === "regex-matcher") {
|
|
15606
|
+
const found = analyzeRegexMatchers(rawCode);
|
|
15607
|
+
return found.length > 0 ? [formatRegexMatcherNote(found)] : [];
|
|
15608
|
+
}
|
|
15228
15609
|
const warnings = [];
|
|
15229
15610
|
if (rawCode.length > MAX_LINT_INPUT) {
|
|
15230
15611
|
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).`);
|
|
@@ -15499,7 +15880,7 @@ function specItemsFromTestPlans(testPlans) {
|
|
|
15499
15880
|
}
|
|
15500
15881
|
return [...new Set(out)].slice(0, 200);
|
|
15501
15882
|
}
|
|
15502
|
-
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;
|
|
15883
|
+
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;
|
|
15503
15884
|
var init_test_authoring_quality = __esm({
|
|
15504
15885
|
"../shared/dist/test-authoring-quality.js"() {
|
|
15505
15886
|
"use strict";
|
|
@@ -15731,6 +16112,8 @@ var init_test_authoring_quality = __esm({
|
|
|
15731
16112
|
};
|
|
15732
16113
|
LIVE_WRITE_NAME = /\b(?:submit|place|book|reserve|confirm|pay|send|checkout|order|register|sign\s?up|create account)\b/i;
|
|
15733
16114
|
BUNDLED_CHECKS_BEFORE_WRITE = 5;
|
|
16115
|
+
MAX_REGEX_MATCHER_FINDINGS = 10;
|
|
16116
|
+
REGEX_EQUALITY_MATCHERS = /* @__PURE__ */ new Set(["toBe", "toEqual", "toStrictEqual", "toContain", "toHaveJSProperty"]);
|
|
15734
16117
|
STOP = /* @__PURE__ */ new Set([
|
|
15735
16118
|
"a",
|
|
15736
16119
|
"an",
|
|
@@ -15959,6 +16342,19 @@ var init_fence_runs = __esm({
|
|
|
15959
16342
|
}
|
|
15960
16343
|
});
|
|
15961
16344
|
|
|
16345
|
+
// ../shared/dist/trailing-slashes.js
|
|
16346
|
+
function stripTrailingSlashes(value) {
|
|
16347
|
+
let end = value.length;
|
|
16348
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47)
|
|
16349
|
+
end--;
|
|
16350
|
+
return end === value.length ? value : value.slice(0, end);
|
|
16351
|
+
}
|
|
16352
|
+
var init_trailing_slashes = __esm({
|
|
16353
|
+
"../shared/dist/trailing-slashes.js"() {
|
|
16354
|
+
"use strict";
|
|
16355
|
+
}
|
|
16356
|
+
});
|
|
16357
|
+
|
|
15962
16358
|
// ../shared/dist/survey-bug-signature.js
|
|
15963
16359
|
function normalizeWords(text) {
|
|
15964
16360
|
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();
|
|
@@ -15969,7 +16365,7 @@ function normalizeBugPath(route) {
|
|
|
15969
16365
|
if (hash >= 0 && path[hash + 1] !== "/")
|
|
15970
16366
|
path = path.slice(0, hash);
|
|
15971
16367
|
const segments = path.toLowerCase().split("/").map((segment) => /\d/.test(segment) ? ":id" : segment);
|
|
15972
|
-
const joined = segments.join("/")
|
|
16368
|
+
const joined = stripTrailingSlashes(segments.join("/"));
|
|
15973
16369
|
return joined || (path.startsWith("/") ? "/" : "");
|
|
15974
16370
|
}
|
|
15975
16371
|
function isGenericConsoleMessage(message) {
|
|
@@ -16103,6 +16499,7 @@ var SIGNATURE_SOURCE_MAX_CHARS, UUID, PREFIXED_ID, HEX_RUN, NUMBER_RUN, GENERIC_
|
|
|
16103
16499
|
var init_survey_bug_signature = __esm({
|
|
16104
16500
|
"../shared/dist/survey-bug-signature.js"() {
|
|
16105
16501
|
"use strict";
|
|
16502
|
+
init_trailing_slashes();
|
|
16106
16503
|
SIGNATURE_SOURCE_MAX_CHARS = 800;
|
|
16107
16504
|
UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/g;
|
|
16108
16505
|
PREFIXED_ID = /\b[a-z]{1,8}[-_]\d+\b/g;
|
|
@@ -17383,9 +17780,9 @@ function lastLocatorLabels(chain) {
|
|
|
17383
17780
|
if (t)
|
|
17384
17781
|
labels.push(t[1]);
|
|
17385
17782
|
}
|
|
17386
|
-
const
|
|
17387
|
-
if (
|
|
17388
|
-
labels.push(
|
|
17783
|
+
const has2 = optionText(last.args, HAS_TEXT_OPTION_RE);
|
|
17784
|
+
if (has2 !== null)
|
|
17785
|
+
labels.push(has2);
|
|
17389
17786
|
}
|
|
17390
17787
|
return labels.map((l) => l.replace(/^[\s^(?:]+/, "").trim());
|
|
17391
17788
|
}
|
|
@@ -18142,14 +18539,17 @@ var init_promotion_quality_gate = __esm({
|
|
|
18142
18539
|
SOURCE_RANK = { generator: 0, classifier: 0, healer: 1, human: 2 };
|
|
18143
18540
|
strengthCheck = {
|
|
18144
18541
|
id: "assertion-strength",
|
|
18145
|
-
run({ code, strengthGate, flagContradictedAdditions }) {
|
|
18542
|
+
run({ code, tags, strengthGate, flagContradictedAdditions }) {
|
|
18146
18543
|
const verdict = validateAssertionStrength(code, { flagContradictedAdditions: flagContradictedAdditions === true });
|
|
18147
18544
|
if (verdict.severity === "route-bug")
|
|
18148
18545
|
return [{ check: "route-bug" }];
|
|
18149
|
-
|
|
18546
|
+
const authDowngrade = verdict.severity === "downgrade" && tags.some((t) => t.toLowerCase() === "@auth");
|
|
18547
|
+
if (verdict.severity !== "block" && !authDowngrade)
|
|
18150
18548
|
return [];
|
|
18151
18549
|
const revealed = strengthGate?.severity === "none" && strengthGate.revealEvidence === "revealed" && strengthGate.source !== "heal";
|
|
18152
|
-
|
|
18550
|
+
if (revealed)
|
|
18551
|
+
return [];
|
|
18552
|
+
return [{ check: authDowngrade ? "strength-downgrade-auth" : "strength-block" }];
|
|
18153
18553
|
}
|
|
18154
18554
|
};
|
|
18155
18555
|
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;
|
|
@@ -18556,6 +18956,7 @@ __export(dist_exports, {
|
|
|
18556
18956
|
AUDIO_CHUNK_DURATION_MS: () => AUDIO_CHUNK_DURATION_MS,
|
|
18557
18957
|
AUTH_PATH_SIGNATURE: () => AUTH_PATH_SIGNATURE,
|
|
18558
18958
|
AUTH_PROVIDER_HOST_SIGNATURES: () => AUTH_PROVIDER_HOST_SIGNATURES,
|
|
18959
|
+
AUTH_SESSION_GENERATION_RE: () => AUTH_SESSION_GENERATION_RE,
|
|
18559
18960
|
AUTH_STATE_EXPIRY_SKEW_MS: () => AUTH_STATE_EXPIRY_SKEW_MS,
|
|
18560
18961
|
AUTH_TAG_COOKIE_STATE: () => AUTH_TAG_COOKIE_STATE,
|
|
18561
18962
|
AUTH_TAG_LOGIN_BEARER: () => AUTH_TAG_LOGIN_BEARER,
|
|
@@ -18688,6 +19089,8 @@ __export(dist_exports, {
|
|
|
18688
19089
|
LIVE_FRAME_STALE_MS: () => LIVE_FRAME_STALE_MS,
|
|
18689
19090
|
LIVE_FRAME_UNFOCUSED_INTERVAL_MS: () => LIVE_FRAME_UNFOCUSED_INTERVAL_MS,
|
|
18690
19091
|
LIVE_THUMBNAIL_MAX_BASE64_BYTES: () => LIVE_THUMBNAIL_MAX_BASE64_BYTES,
|
|
19092
|
+
MAX_BALANCED_SCAN: () => MAX_BALANCED_SCAN,
|
|
19093
|
+
MAX_CALLS: () => MAX_CALLS,
|
|
18691
19094
|
MAX_CREDIT_TOPUP_CENTS: () => MAX_CREDIT_TOPUP_CENTS,
|
|
18692
19095
|
MAX_DEEPLINK_LENGTH: () => MAX_DEEPLINK_LENGTH,
|
|
18693
19096
|
MAX_EMAIL_ADDRESS_LENGTH: () => MAX_EMAIL_ADDRESS_LENGTH,
|
|
@@ -18732,6 +19135,7 @@ __export(dist_exports, {
|
|
|
18732
19135
|
MUSE_ENGINE_DEFAULT_MODEL: () => MUSE_ENGINE_DEFAULT_MODEL,
|
|
18733
19136
|
MUSE_ENGINE_MODELS: () => MUSE_ENGINE_MODELS,
|
|
18734
19137
|
NOREPLY_EMAIL: () => NOREPLY_EMAIL,
|
|
19138
|
+
OPENCODE_GO_2_PREFIX: () => OPENCODE_GO_2_PREFIX,
|
|
18735
19139
|
OPENCODE_GO_MODEL_PATTERN: () => OPENCODE_GO_MODEL_PATTERN,
|
|
18736
19140
|
OPENCODE_GO_PREFIX: () => OPENCODE_GO_PREFIX,
|
|
18737
19141
|
OPENROUTER_MAX_CALL_COST_USD: () => OPENROUTER_MAX_CALL_COST_USD,
|
|
@@ -18767,6 +19171,8 @@ __export(dist_exports, {
|
|
|
18767
19171
|
PROMOTION_GATE_MAX_CODE_CHARS: () => PROMOTION_GATE_MAX_CODE_CHARS,
|
|
18768
19172
|
PROMOTION_QUALITY_CHECKS: () => PROMOTION_QUALITY_CHECKS,
|
|
18769
19173
|
PROVIDER_CHAINS: () => PROVIDER_CHAINS,
|
|
19174
|
+
PROVIDER_CHAIN_LEADS: () => PROVIDER_CHAIN_LEADS,
|
|
19175
|
+
PROVIDER_HOST_NOT_OFFERED: () => PROVIDER_HOST_NOT_OFFERED,
|
|
18770
19176
|
PUBLIC_PLANS: () => PUBLIC_PLANS,
|
|
18771
19177
|
QUARANTINE_CLOSE_TAGS: () => QUARANTINE_CLOSE_TAGS,
|
|
18772
19178
|
READINESS_POLL_MAX_CODE_CHARS: () => READINESS_POLL_MAX_CODE_CHARS,
|
|
@@ -18805,6 +19211,7 @@ __export(dist_exports, {
|
|
|
18805
19211
|
SURVEY_NOTES_RENDER_MAX_CHARS: () => SURVEY_NOTES_RENDER_MAX_CHARS,
|
|
18806
19212
|
SURVEY_NOTE_KEYS: () => SURVEY_NOTE_KEYS,
|
|
18807
19213
|
SUSPICIOUS_PASS_TAG: () => SUSPICIOUS_PASS_TAG,
|
|
19214
|
+
TEST_DID_NOT_RUN_ERROR: () => TEST_DID_NOT_RUN_ERROR,
|
|
18808
19215
|
TEST_QUALITY_CONVENTIONS: () => TEST_QUALITY_CONVENTIONS,
|
|
18809
19216
|
TEST_USER_ENV_KEYS: () => TEST_USER_ENV_KEYS,
|
|
18810
19217
|
TEST_VARIABLE_SECRET_KEY_PATTERN: () => TEST_VARIABLE_SECRET_KEY_PATTERN,
|
|
@@ -18820,6 +19227,8 @@ __export(dist_exports, {
|
|
|
18820
19227
|
VOICE_PREVIEW_SAMPLE: () => VOICE_PREVIEW_SAMPLE,
|
|
18821
19228
|
WEB_PROXY_CHAIN_HEADER: () => WEB_PROXY_CHAIN_HEADER,
|
|
18822
19229
|
WITHHELD_CREDENTIAL_TEXT: () => WITHHELD_CREDENTIAL_TEXT,
|
|
19230
|
+
ZAI_MODEL_PATTERN: () => ZAI_MODEL_PATTERN,
|
|
19231
|
+
ZAI_PREFIX: () => ZAI_PREFIX,
|
|
18823
19232
|
accumulateStatements: () => accumulateStatements,
|
|
18824
19233
|
adoptBrokerFailover: () => adoptBrokerFailover,
|
|
18825
19234
|
aiCostToCreditCents: () => aiCostToCreditCents,
|
|
@@ -18828,6 +19237,7 @@ __export(dist_exports, {
|
|
|
18828
19237
|
analyzeMobileSelectorQuality: () => analyzeMobileSelectorQuality,
|
|
18829
19238
|
analyzePersistenceReread: () => analyzePersistenceReread,
|
|
18830
19239
|
analyzeReadinessPolling: () => analyzeReadinessPolling,
|
|
19240
|
+
analyzeRegexMatchers: () => analyzeRegexMatchers,
|
|
18831
19241
|
analyzeSharedAccountUse: () => analyzeSharedAccountUse,
|
|
18832
19242
|
analyzeStaleAfterSubmit: () => analyzeStaleAfterSubmit,
|
|
18833
19243
|
analyzeTestData: () => analyzeTestData,
|
|
@@ -18991,6 +19401,7 @@ __export(dist_exports, {
|
|
|
18991
19401
|
formatPersistenceRereadAdvisory: () => formatPersistenceRereadAdvisory,
|
|
18992
19402
|
formatPoolBudgetLine: () => formatPoolBudgetLine,
|
|
18993
19403
|
formatReadinessPollAdvisory: () => formatReadinessPollAdvisory,
|
|
19404
|
+
formatRegexMatcherNote: () => formatRegexMatcherNote,
|
|
18994
19405
|
formatStaleAfterSubmitAdvisory: () => formatStaleAfterSubmitAdvisory,
|
|
18995
19406
|
formatSuspiciousExpectation: () => formatSuspiciousExpectation,
|
|
18996
19407
|
formatUrlWaitAdvisory: () => formatUrlWaitAdvisory,
|
|
@@ -19029,12 +19440,14 @@ __export(dist_exports, {
|
|
|
19029
19440
|
hasEncodedRequestBody: () => hasEncodedRequestBody,
|
|
19030
19441
|
hasEngineSpecParts: () => hasEngineSpecParts,
|
|
19031
19442
|
hasOnlyConstantAssertions: () => hasOnlyConstantAssertions,
|
|
19443
|
+
hasOpenCodeGo2Prefix: () => hasOpenCodeGo2Prefix,
|
|
19032
19444
|
hasOpenCodeGoPrefix: () => hasOpenCodeGoPrefix,
|
|
19033
19445
|
hasOpenRouterPrefix: () => hasOpenRouterPrefix,
|
|
19034
19446
|
hasPlatformLocator: () => hasPlatformLocator,
|
|
19035
19447
|
hasReadOnlyMarker: () => hasReadOnlyMarker,
|
|
19036
19448
|
hasSurveyNotes: () => hasSurveyNotes,
|
|
19037
19449
|
hasTestFailContract: () => hasTestFailContract,
|
|
19450
|
+
hasZaiPrefix: () => hasZaiPrefix,
|
|
19038
19451
|
healMobileTestSteps: () => healMobileTestSteps,
|
|
19039
19452
|
healthRunWhere: () => healthRunWhere,
|
|
19040
19453
|
heldCodeRecord: () => heldCodeRecord,
|
|
@@ -19138,6 +19551,7 @@ __export(dist_exports, {
|
|
|
19138
19551
|
isValidSttProvider: () => isValidSttProvider,
|
|
19139
19552
|
isValidTtsModel: () => isValidTtsModel,
|
|
19140
19553
|
isValidTtsVoiceId: () => isValidTtsVoiceId,
|
|
19554
|
+
isZaiModelId: () => isZaiModelId,
|
|
19141
19555
|
jsEscapedForms: () => jsEscapedForms,
|
|
19142
19556
|
jsonStructureRefusalOf: () => jsonStructureRefusalOf,
|
|
19143
19557
|
jsonStructureVerify: () => jsonStructureVerify,
|
|
@@ -19186,6 +19600,7 @@ __export(dist_exports, {
|
|
|
19186
19600
|
parseApiCardModelUpdate: () => parseApiCardModelUpdate,
|
|
19187
19601
|
parseAppTimezone: () => parseAppTimezone,
|
|
19188
19602
|
parseAuditGroupScopeId: () => parseAuditGroupScopeId,
|
|
19603
|
+
parseAuthSessionStamp: () => parseAuthSessionStamp,
|
|
19189
19604
|
parseBoolFlag: () => parseBoolFlag,
|
|
19190
19605
|
parseDbPoolSize: () => parseDbPoolSize,
|
|
19191
19606
|
parseDeepgramListenResponse: () => parseDeepgramListenResponse,
|
|
@@ -19229,7 +19644,11 @@ __export(dist_exports, {
|
|
|
19229
19644
|
profileKeyRoute: () => profileKeyRoute,
|
|
19230
19645
|
projectAppHosts: () => projectAppHosts,
|
|
19231
19646
|
providerChainFor: () => providerChainFor,
|
|
19647
|
+
providerChainHostOf: () => providerChainHostOf,
|
|
19648
|
+
providerChainLeadsFor: () => providerChainLeadsFor,
|
|
19232
19649
|
providerChainPrimariesForHop: () => providerChainPrimariesForHop,
|
|
19650
|
+
providerHostPlan: () => providerHostPlan,
|
|
19651
|
+
readBalanced: () => readBalanced,
|
|
19233
19652
|
readChatFailover: () => readChatFailover,
|
|
19234
19653
|
readChatReasoningTokens: () => readChatReasoningTokens,
|
|
19235
19654
|
readChatUsage: () => readChatUsage,
|
|
@@ -19312,6 +19731,7 @@ __export(dist_exports, {
|
|
|
19312
19731
|
stripCoverageComments: () => stripCoverageComments,
|
|
19313
19732
|
stripEnvironmentalPrefix: () => stripEnvironmentalPrefix,
|
|
19314
19733
|
stripLoginScaffolding: () => stripLoginScaffolding,
|
|
19734
|
+
stripTrailingSlashes: () => stripTrailingSlashes,
|
|
19315
19735
|
strongerNeedsReviewSource: () => strongerNeedsReviewSource,
|
|
19316
19736
|
sttModelsForProvider: () => sttModelsForProvider,
|
|
19317
19737
|
summarizeHealth: () => summarizeHealth,
|
|
@@ -19339,7 +19759,8 @@ __export(dist_exports, {
|
|
|
19339
19759
|
withReviewSource: () => withReviewSource,
|
|
19340
19760
|
withoutNotChargedClaim: () => withoutNotChargedClaim,
|
|
19341
19761
|
withoutServerOnlySpendFields: () => withoutServerOnlySpendFields,
|
|
19342
|
-
withoutSurveyNotes: () => withoutSurveyNotes
|
|
19762
|
+
withoutSurveyNotes: () => withoutSurveyNotes,
|
|
19763
|
+
zaiWireModel: () => zaiWireModel
|
|
19343
19764
|
});
|
|
19344
19765
|
var init_dist = __esm({
|
|
19345
19766
|
"../shared/dist/index.js"() {
|
|
@@ -19381,6 +19802,7 @@ var init_dist = __esm({
|
|
|
19381
19802
|
init_admin_view_return_to();
|
|
19382
19803
|
init_auth_plan();
|
|
19383
19804
|
init_auth_block_detector();
|
|
19805
|
+
init_auth_session_stamp();
|
|
19384
19806
|
init_auth_state_freshness();
|
|
19385
19807
|
init_skip_coverage_detector();
|
|
19386
19808
|
init_feature_coverage();
|
|
@@ -19437,6 +19859,7 @@ var init_dist = __esm({
|
|
|
19437
19859
|
init_promotion_quality_gate();
|
|
19438
19860
|
init_regex_alternation();
|
|
19439
19861
|
init_page_evidence();
|
|
19862
|
+
init_trailing_slashes();
|
|
19440
19863
|
}
|
|
19441
19864
|
});
|
|
19442
19865
|
|
|
@@ -19470,12 +19893,7 @@ export {
|
|
|
19470
19893
|
isAppOriginResolutionEnabled,
|
|
19471
19894
|
resolveCrossOriginConfigOverride,
|
|
19472
19895
|
deriveAuthPlan,
|
|
19473
|
-
detectAuthBlock,
|
|
19474
|
-
detectApiColdSessionBlock,
|
|
19475
|
-
coldSessionConfigMessage,
|
|
19476
|
-
detectSkippedApiCoverage,
|
|
19477
19896
|
isSharedAuthInjectEnabled,
|
|
19478
|
-
isAuthReadinessGuardEnabled,
|
|
19479
19897
|
isRepositoryCli,
|
|
19480
19898
|
repositoryCliLabel,
|
|
19481
19899
|
dist_exports,
|