@validate.qa/runner 1.0.92 → 1.0.93

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.
Files changed (3) hide show
  1. package/dist/cli.js +250 -33
  2. package/dist/cli.mjs +250 -33
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -8555,6 +8555,127 @@ var require_scrub_credentials = __commonJS({
8555
8555
  }
8556
8556
  });
8557
8557
 
8558
+ // ../runner-core/dist/services/google-signin.js
8559
+ var require_google_signin = __commonJS({
8560
+ "../runner-core/dist/services/google-signin.js"(exports2) {
8561
+ "use strict";
8562
+ Object.defineProperty(exports2, "__esModule", { value: true });
8563
+ exports2.GOOGLE_SIGNIN_ENV_KEYS = exports2.GOOGLE_SIGNIN_PASSWORD_KEY = void 0;
8564
+ exports2.loadGoogleSignInConfig = loadGoogleSignInConfig;
8565
+ exports2.mergeGoogleSignInSecrets = mergeGoogleSignInSecrets;
8566
+ exports2.googleSignInGuidanceOpts = googleSignInGuidanceOpts;
8567
+ exports2.googleSignInAllowedEmails = googleSignInAllowedEmails;
8568
+ exports2.collectGoogleSignInEnv = collectGoogleSignInEnv;
8569
+ exports2.generateTotp = generateTotp;
8570
+ exports2.buildGoogleSignInPromptSection = buildGoogleSignInPromptSection;
8571
+ var node_crypto_1 = require("crypto");
8572
+ exports2.GOOGLE_SIGNIN_PASSWORD_KEY = "GOOGLE_SIGNIN_PASSWORD";
8573
+ exports2.GOOGLE_SIGNIN_ENV_KEYS = [
8574
+ "GOOGLE_SIGNIN_PASSWORD",
8575
+ "GOOGLE_SIGNIN_EMAIL",
8576
+ "GOOGLE_SIGNIN_TOTP_SECRET"
8577
+ ];
8578
+ function trimEnv(env, name) {
8579
+ const value = env[name]?.trim();
8580
+ return value ? value : void 0;
8581
+ }
8582
+ function loadGoogleSignInConfig(env = process.env) {
8583
+ const password = trimEnv(env, "GOOGLE_SIGNIN_PASSWORD");
8584
+ if (!password)
8585
+ return null;
8586
+ const email = (trimEnv(env, "GOOGLE_SIGNIN_EMAIL") ?? trimEnv(env, "VERIFICATION_INBOX_ADDRESS"))?.toLowerCase();
8587
+ if (!email || !email.includes("@"))
8588
+ return null;
8589
+ const totpSecret = trimEnv(env, "GOOGLE_SIGNIN_TOTP_SECRET");
8590
+ return {
8591
+ email,
8592
+ password,
8593
+ passwordKey: exports2.GOOGLE_SIGNIN_PASSWORD_KEY,
8594
+ totpSecret,
8595
+ totpAvailable: !!totpSecret
8596
+ };
8597
+ }
8598
+ function mergeGoogleSignInSecrets(credentials, env = process.env) {
8599
+ const cfg = loadGoogleSignInConfig(env);
8600
+ if (!cfg)
8601
+ return credentials;
8602
+ if (credentials[exports2.GOOGLE_SIGNIN_PASSWORD_KEY])
8603
+ return credentials;
8604
+ return { ...credentials, [exports2.GOOGLE_SIGNIN_PASSWORD_KEY]: cfg.password };
8605
+ }
8606
+ function googleSignInGuidanceOpts(env = process.env) {
8607
+ const cfg = loadGoogleSignInConfig(env);
8608
+ if (!cfg)
8609
+ return void 0;
8610
+ return {
8611
+ googleEmail: cfg.email,
8612
+ googlePasswordKey: cfg.passwordKey,
8613
+ googleTotpAvailable: cfg.totpAvailable
8614
+ };
8615
+ }
8616
+ function googleSignInAllowedEmails(env = process.env) {
8617
+ const cfg = loadGoogleSignInConfig(env);
8618
+ return cfg ? [cfg.email] : [];
8619
+ }
8620
+ function collectGoogleSignInEnv(env = process.env) {
8621
+ const out = {};
8622
+ for (const key of exports2.GOOGLE_SIGNIN_ENV_KEYS) {
8623
+ const value = env[key]?.trim();
8624
+ if (value)
8625
+ out[key] = value;
8626
+ }
8627
+ return out;
8628
+ }
8629
+ function generateTotp(secret, atMs = Date.now(), stepSeconds = 30, digits = 6) {
8630
+ const key = decodeBase32(secret);
8631
+ const counter = Math.floor(atMs / 1e3 / stepSeconds);
8632
+ const buf = Buffer.alloc(8);
8633
+ buf.writeUInt32BE(Math.floor(counter / 4294967296), 0);
8634
+ buf.writeUInt32BE(counter >>> 0, 4);
8635
+ const hmac = (0, node_crypto_1.createHmac)("sha1", key).update(buf).digest();
8636
+ const offset = hmac[hmac.length - 1] & 15;
8637
+ const bin = (hmac[offset] & 127) << 24 | hmac[offset + 1] << 16 | hmac[offset + 2] << 8 | hmac[offset + 3];
8638
+ const otp = bin % 10 ** digits;
8639
+ return String(otp).padStart(digits, "0");
8640
+ }
8641
+ function decodeBase32(input) {
8642
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
8643
+ const cleaned = input.toUpperCase().replace(/[\s=-]+/g, "");
8644
+ let bits = 0;
8645
+ let value = 0;
8646
+ const out = [];
8647
+ for (const ch of cleaned) {
8648
+ const idx = alphabet.indexOf(ch);
8649
+ if (idx < 0)
8650
+ continue;
8651
+ value = value << 5 | idx;
8652
+ bits += 5;
8653
+ if (bits >= 8) {
8654
+ bits -= 8;
8655
+ out.push(value >>> bits & 255);
8656
+ }
8657
+ }
8658
+ return Buffer.from(out);
8659
+ }
8660
+ function buildGoogleSignInPromptSection(opts, variant) {
8661
+ const totpNative = opts.googleTotpAvailable ? " If Google asks for a 2-step / Authenticator code, call `provision_google_totp` and type the 6-digit `code` it returns (do not invent a code)." : " If Google asks for 2-step verification and you have no authenticator code tool, STOP and report Google SSO as BLOCKED (2FA not configured on this runner).";
8662
+ const totpCli = opts.googleTotpAvailable ? " If Google asks for a 2-step / Authenticator code, call `inbox_google_totp` and type the 6-digit `code` it returns." : " If Google asks for 2-step verification, STOP and report Google SSO as BLOCKED (2FA not configured on this runner).";
8663
+ const totp = variant === "cli" ? totpCli : totpNative;
8664
+ const fill = variant === "cli" ? `fill_credential with credentialKey \`${opts.googlePasswordKey}\`` : `\`fill_credential\` (credentialKey \`${opts.googlePasswordKey}\`)`;
8665
+ const plainProvision = variant === "cli" ? "`inbox_provision_identity` with `plain: true`" : "`provision_identity` with `plain: true`";
8666
+ return `
8667
+ Google / Gmail SSO fallback (SECOND choice \u2014 email+password signup is FIRST):
8668
+ - FIRST follow the email-field playbook above whenever a signup form has an email / username / password field (including after clicking "Sign up with email"). Do NOT click Google if that form exists.
8669
+ - ONLY if there is no email+password signup field and the only path is "Continue with Google" / "Sign up with Gmail" / "Sign in with Google": click that button. If a Google popup opens, switch to it (browser tabs).
8670
+ - On accounts.google.com, type the BARE Google account email \`${opts.googleEmail}\` (no plus-tag \u2014 Google account login rejects plus-addresses) with browser_type, click Next, then fill the Google password with ${fill}. NEVER type the Google password as text and NEVER use the IMAP app password here.
8671
+ - Click Next.${totp}
8672
+ - Click Continue / Allow on any consent screen, then return to the app tab.
8673
+ - If the app then emails a verification code/link, first call ${plainProvision} (Google SSO uses the bare inbox address, not the +tag), then complete it with the inbox tools as usual.
8674
+ - Register / Google-sign-in ONCE per run. If Google says the account is already used on this app, that is success \u2014 continue as the logged-in user.`;
8675
+ }
8676
+ }
8677
+ });
8678
+
8558
8679
  // ../runner-core/dist/services/credential-tools.js
8559
8680
  var require_credential_tools = __commonJS({
8560
8681
  "../runner-core/dist/services/credential-tools.js"(exports2) {
@@ -8573,6 +8694,7 @@ var require_credential_tools = __commonJS({
8573
8694
  exports2.mcpResultIsError = mcpResultIsError;
8574
8695
  exports2.aggressiveScrubCredentials = aggressiveScrubCredentials;
8575
8696
  var scrub_credentials_js_1 = require_scrub_credentials();
8697
+ var google_signin_js_1 = require_google_signin();
8576
8698
  exports2.FILL_CREDENTIAL_TOOL = {
8577
8699
  type: "function",
8578
8700
  function: {
@@ -8583,7 +8705,7 @@ var require_credential_tools = __commonJS({
8583
8705
  properties: {
8584
8706
  credentialKey: {
8585
8707
  type: "string",
8586
- description: 'The credential variable name (e.g. "TEST_USER_EMAIL", "TEST_USER_PASSWORD", "TEST_ADMIN_EMAIL"). Must be one of the keys listed in the Test Credentials section of the prompt.'
8708
+ description: 'The credential variable name (e.g. "TEST_USER_EMAIL", "TEST_USER_PASSWORD", "GOOGLE_SIGNIN_PASSWORD"). Must be one of the keys listed in the Test Credentials section of the prompt.'
8587
8709
  },
8588
8710
  element: {
8589
8711
  type: "string",
@@ -8849,6 +8971,14 @@ CREDENTIAL ROTATION (required when the STORED user's secret changes \u2014 read
8849
8971
  didMutate: false
8850
8972
  };
8851
8973
  }
8974
+ if (key === google_signin_js_1.GOOGLE_SIGNIN_PASSWORD_KEY) {
8975
+ return {
8976
+ content: JSON.stringify({
8977
+ error: "set_credential: GOOGLE_SIGNIN_PASSWORD is a runner-operator secret and cannot be persisted to project Test Data"
8978
+ }),
8979
+ didMutate: false
8980
+ };
8981
+ }
8852
8982
  if (!(key in ctx.credentials)) {
8853
8983
  const available = Object.keys(ctx.credentials).filter((k) => ctx.credentials[k]).join(", ") || "(none configured)";
8854
8984
  return {
@@ -74110,7 +74240,7 @@ var require_inbox_tools = __commonJS({
74110
74240
  "../runner-core/dist/services/inbox-tools.js"(exports2) {
74111
74241
  "use strict";
74112
74242
  Object.defineProperty(exports2, "__esModule", { value: true });
74113
- exports2.EMAIL_VERIFICATION_UNAVAILABLE_OVERRIDE_BLOCK = exports2.INBOX_TOOL_NAMES = exports2.INBOX_TOOLS = exports2.OPEN_VERIFICATION_LINK_TOOL = exports2.GET_VERIFICATION_LINK_TOOL = exports2.EXTRACT_VERIFICATION_CODE_TOOL = exports2.READ_VERIFICATION_EMAIL_TOOL = exports2.WAIT_FOR_VERIFICATION_TOOL = exports2.CHECK_INBOX_TOOL = exports2.PROVISION_IDENTITY_TOOL = void 0;
74243
+ exports2.EMAIL_VERIFICATION_UNAVAILABLE_OVERRIDE_BLOCK = exports2.INBOX_TOOL_NAMES = exports2.INBOX_TOOLS = exports2.PROVISION_GOOGLE_TOTP_TOOL = exports2.OPEN_VERIFICATION_LINK_TOOL = exports2.GET_VERIFICATION_LINK_TOOL = exports2.EXTRACT_VERIFICATION_CODE_TOOL = exports2.READ_VERIFICATION_EMAIL_TOOL = exports2.WAIT_FOR_VERIFICATION_TOOL = exports2.CHECK_INBOX_TOOL = exports2.PROVISION_IDENTITY_TOOL = void 0;
74114
74244
  exports2.createInboxRunState = createInboxRunState;
74115
74245
  exports2.dispatchInboxTool = dispatchInboxTool;
74116
74246
  exports2.isPublicHttpUrl = isPublicHttpUrl;
@@ -74125,6 +74255,7 @@ var require_inbox_tools = __commonJS({
74125
74255
  exports2.clearThrowawayRegisterSeed = clearThrowawayRegisterSeed;
74126
74256
  exports2.buildInboxAgentsGuidance = buildInboxAgentsGuidance;
74127
74257
  var verification_inbox_js_1 = require_verification_inbox();
74258
+ var google_signin_js_1 = require_google_signin();
74128
74259
  function createInboxRunState(config, opts = {}) {
74129
74260
  const baseEmail = config.address;
74130
74261
  const tag = opts.tag !== void 0 ? opts.tag : opts.tagSeed ? (0, verification_inbox_js_1.deriveProjectInboxTag)(opts.tagSeed, opts.projectScope) : null;
@@ -74246,6 +74377,14 @@ var require_inbox_tools = __commonJS({
74246
74377
  }
74247
74378
  }
74248
74379
  };
74380
+ exports2.PROVISION_GOOGLE_TOTP_TOOL = {
74381
+ type: "function",
74382
+ function: {
74383
+ name: "provision_google_totp",
74384
+ description: "Return a one-time 6-digit Authenticator code for the operator Google account. Call this ONLY when Google Sign-In shows a 2-step / Authenticator challenge after you submitted the Google password. Type the returned code into the Google prompt. Do not invent a code.",
74385
+ parameters: { type: "object", properties: {} }
74386
+ }
74387
+ };
74249
74388
  exports2.INBOX_TOOLS = [
74250
74389
  exports2.PROVISION_IDENTITY_TOOL,
74251
74390
  exports2.CHECK_INBOX_TOOL,
@@ -74253,7 +74392,8 @@ var require_inbox_tools = __commonJS({
74253
74392
  exports2.READ_VERIFICATION_EMAIL_TOOL,
74254
74393
  exports2.EXTRACT_VERIFICATION_CODE_TOOL,
74255
74394
  exports2.GET_VERIFICATION_LINK_TOOL,
74256
- exports2.OPEN_VERIFICATION_LINK_TOOL
74395
+ exports2.OPEN_VERIFICATION_LINK_TOOL,
74396
+ exports2.PROVISION_GOOGLE_TOTP_TOOL
74257
74397
  ];
74258
74398
  exports2.INBOX_TOOL_NAMES = new Set(exports2.INBOX_TOOLS.map((t) => t.function.name));
74259
74399
  var DEFAULT_MAX_RESULT_CHARS = 8e3;
@@ -74265,7 +74405,7 @@ var require_inbox_tools = __commonJS({
74265
74405
  }
74266
74406
  var INBOX_AUTH_DEAD_GUIDANCE = "the inbox authentication is PERMANENTLY rejected (revoked/wrong app password) \u2014 STOP calling inbox tools; none of them can succeed this run. Treat email verification as UNAVAILABLE: hard-stop at any emailed code/link wall, NEVER type a guessed code, and report verification-gated flows as BLOCKED (blockedReason: inbox authentication failed). Continue with publicly reachable coverage.";
74267
74407
  async function dispatchInboxTool(toolName, toolArgs, ctx) {
74268
- if (ctx.state.authDead) {
74408
+ if (ctx.state.authDead && toolName !== "provision_google_totp") {
74269
74409
  return err(`${toolName} skipped: ${INBOX_AUTH_DEAD_GUIDANCE}`);
74270
74410
  }
74271
74411
  try {
@@ -74284,6 +74424,8 @@ var require_inbox_tools = __commonJS({
74284
74424
  return await handleGetLink(toolArgs, ctx);
74285
74425
  case "open_verification_link":
74286
74426
  return await handleOpenLink(toolArgs, ctx);
74427
+ case "provision_google_totp":
74428
+ return handleProvisionGoogleTotp();
74287
74429
  default:
74288
74430
  return err(`inbox dispatch: unknown tool "${toolName}"`);
74289
74431
  }
@@ -74459,6 +74601,20 @@ var require_inbox_tools = __commonJS({
74459
74601
  didMutate: !failed
74460
74602
  };
74461
74603
  }
74604
+ function handleProvisionGoogleTotp(env = process.env) {
74605
+ const cfg = (0, google_signin_js_1.loadGoogleSignInConfig)(env);
74606
+ if (!cfg) {
74607
+ return err("Google SSO is not configured on this runner (GOOGLE_SIGNIN_PASSWORD unset). Prefer email-field signup, or report Google SSO as BLOCKED.");
74608
+ }
74609
+ if (!cfg.totpSecret) {
74610
+ return err("Google Authenticator 2FA is not configured on this runner (GOOGLE_SIGNIN_TOTP_SECRET unset). STOP and report Google SSO as BLOCKED (2FA not configured).");
74611
+ }
74612
+ return ok({
74613
+ code: (0, google_signin_js_1.generateTotp)(cfg.totpSecret),
74614
+ digits: 6,
74615
+ instructions: "Type this 6-digit code into the Google 2-step / Authenticator prompt. Do not reuse it later \u2014 call this tool again if Google asks for another code."
74616
+ });
74617
+ }
74462
74618
  function requireProvisioned(ctx) {
74463
74619
  if (ctx.state.provisioned)
74464
74620
  return null;
@@ -74593,7 +74749,7 @@ var require_inbox_tools = __commonJS({
74593
74749
  ${where} You register using ONE real, monitored email (\`${opts.email}\`) and can complete email-verification (OTP code or confirmation link) end-to-end. This OVERRIDES the general "do not submit forms" rule for the signup/registration form ONLY.
74594
74750
 
74595
74751
  Steps:
74596
- 1. Navigate to the Sign Up / Register page (click the link in the UI).
74752
+ 1. Navigate to the Sign Up / Register page (click the link in the UI). FIRST look for an email+password signup form (including after "Sign up with email"). Use Google / Gmail SSO ONLY if that form does not exist.
74597
74753
  2. Call \`provision_identity\` \u2192 it returns the email to register with (\`${opts.email}\`). The \`+\` part is a normal sub-address that still lands in our inbox.
74598
74754
  3. Fill the signup form: type that email into the email field with \`browser_type\` (this generated inbox email is intentionally visible and is allowed for registration); fill the password field with single-field \`fill_credential\` (credentialKey \`${opts.passwordKey}\`); fill any name/other required fields with simple test values. Do NOT use \`fill_credential_form\` for registration.
74599
74755
  - If the form REJECTS the email (says "invalid email" / will not accept the "+"), call \`provision_identity\` again with \`plain: true\` and use the bare address it returns instead.
@@ -74611,6 +74767,11 @@ Rules:
74611
74767
  - The provisioned email is reused for this project; if signup says it is ALREADY registered, the account already exists \u2014 log in with that email + the \`${opts.passwordKey}\` password instead of registering again.
74612
74768
  - You register ONCE per run. After you submit the signup form in step 4, NEVER submit it again and NEVER create a second account \u2014 even if verification is slow, even if a later login attempt fails. Recover by re-polling \`wait_for_verification\` (and at most one "Resend"), not by re-registering.
74613
74769
  - Only call the verification tools AFTER submitting the signup form, and pass the site as \`senderMatch\` so you read YOUR verification email (the inbox is shared).
74770
+ ${opts.googleEmail && opts.googlePasswordKey ? (0, google_signin_js_1.buildGoogleSignInPromptSection)({
74771
+ googleEmail: opts.googleEmail,
74772
+ googlePasswordKey: opts.googlePasswordKey,
74773
+ googleTotpAvailable: opts.googleTotpAvailable
74774
+ }, "native") : ""}
74614
74775
  `;
74615
74776
  }
74616
74777
  exports2.EMAIL_VERIFICATION_UNAVAILABLE_OVERRIDE_BLOCK = `## EMAIL VERIFICATION UNAVAILABLE \u2014 FINAL OVERRIDE (supersedes any instruction above)
@@ -74765,11 +74926,12 @@ This project asked to REGISTER a new account, but this runner CANNOT receive ema
74765
74926
  }
74766
74927
  return false;
74767
74928
  }
74768
- function buildInboxAgentsGuidance(email, passwordKey) {
74929
+ function buildInboxAgentsGuidance(email, passwordKey, google) {
74930
+ const googleBlock = google ? (0, google_signin_js_1.buildGoogleSignInPromptSection)(google, "cli") : "";
74769
74931
  return `## Account registration & email verification (ENABLED)
74770
74932
  This run registers a new account using our ONE real, monitored inbox (the address \`${email}\` \u2014 the "+" part is a normal sub-address that still lands in our inbox) and can complete email verification end-to-end. This overrides any "do not submit forms" guidance for the signup form only.
74771
74933
 
74772
- 1. Go to the Sign Up / Register page.
74934
+ 1. Go to the Sign Up / Register page. FIRST look for an email+password signup form (including after "Sign up with email"). Use Google / Gmail SSO ONLY if that form does not exist.
74773
74935
  2. Call \`inbox_provision_identity\` \u2192 it returns the email to register with (\`${email}\`). Type that email into the email field.
74774
74936
  - If the form REJECTS the email (says "invalid email" / will not accept the "+"), call \`inbox_provision_identity\` with \`plain: true\` and use the bare address it returns instead.
74775
74937
  3. Fill the password with the \`${passwordKey}\` credential (use fill_credential). Submit the signup form.
@@ -74780,6 +74942,7 @@ This run registers a new account using our ONE real, monitored inbox (the addres
74780
74942
  - If it returns BOTH, try the code first; if the app insists on the link, open it, then enter the code if the page it lands on asks for one.
74781
74943
  - Otherwise call \`inbox_read_email\` to read the body.
74782
74944
  5. NEVER invent an email address \u2014 always use exactly what \`inbox_provision_identity\` returns. The address is reused for this project; if signup says it is already registered, log in with it + \`${passwordKey}\` instead. Register ONCE per run \u2014 never submit signup twice or make a second account; if verification is slow, re-poll \`inbox_wait_for_verification\` (at most one Resend) instead of re-registering.
74945
+ ${googleBlock}
74783
74946
  `;
74784
74947
  }
74785
74948
  }
@@ -88614,6 +88777,7 @@ var require_browser_config = __commonJS({
88614
88777
  var path_1 = require("path");
88615
88778
  var os_1 = require("os");
88616
88779
  var shared_1 = (init_dist(), __toCommonJS(dist_exports));
88780
+ var google_signin_js_1 = require_google_signin();
88617
88781
  exports2.IS_CLOUD = (0, shared_1.parseBoolFlag)(process.env.RUNNER_CLOUD);
88618
88782
  exports2.CLOUD_ARGS = [
88619
88783
  "--no-sandbox",
@@ -88719,6 +88883,10 @@ var require_browser_config = __commonJS({
88719
88883
  (document.head || document.documentElement).appendChild(style);
88720
88884
 
88721
88885
  // Layer 2: Web Animations API - make instant (preserves completion callbacks)
88886
+ try {
88887
+ Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
88888
+ } catch {}
88889
+
88722
88890
  const origAnimate = Element.prototype.animate;
88723
88891
  Element.prototype.animate = function(keyframes, options) {
88724
88892
  if (typeof options === 'object' && options !== null) {
@@ -88825,6 +88993,20 @@ var require_browser_config = __commonJS({
88825
88993
  return null;
88826
88994
  }
88827
88995
  }
88996
+ function googleSsoCloudLaunch(env = process.env) {
88997
+ if (!(0, shared_1.parseBoolFlag)(env.RUNNER_CLOUD))
88998
+ return null;
88999
+ if (!(0, google_signin_js_1.loadGoogleSignInConfig)(env))
89000
+ return null;
89001
+ const executablePath = getFullChromiumPath();
89002
+ if (!executablePath)
89003
+ return null;
89004
+ return {
89005
+ executablePath,
89006
+ extraArgs: ["--headless=new"],
89007
+ ignoreDefaultArgs: ["--enable-automation"]
89008
+ };
89009
+ }
88828
89010
  function getMCPBrowserConfig2(opts) {
88829
89011
  const userDataDir = opts?.forceIsolated ? null : getTestUserDataDir2();
88830
89012
  const headless = isHeadless2();
@@ -88848,15 +89030,21 @@ var require_browser_config = __commonJS({
88848
89030
  };
88849
89031
  }
88850
89032
  const headlessShellPath = getHeadlessShellPath();
88851
- const useHeadlessShell = headless && headlessShellPath && !opts?.harPath;
89033
+ const googleLaunch = googleSsoCloudLaunch();
89034
+ const useHeadlessShell = headless && headlessShellPath && !opts?.harPath && !googleLaunch;
89035
+ const cloud = (0, shared_1.parseBoolFlag)(process.env.RUNNER_CLOUD);
89036
+ const args = [
89037
+ ...cloud ? exports2.CLOUD_ARGS : ["--disable-blink-features=AutomationControlled"],
89038
+ ...googleLaunch?.extraArgs ?? []
89039
+ ];
88852
89040
  return {
88853
89041
  browserName: "chromium",
88854
89042
  isolated: true,
88855
89043
  launchOptions: {
88856
- headless,
88857
- ...useHeadlessShell ? { executablePath: headlessShellPath } : {},
89044
+ headless: googleLaunch ? false : headless,
89045
+ ...googleLaunch ? { executablePath: googleLaunch.executablePath, ignoreDefaultArgs: googleLaunch.ignoreDefaultArgs } : useHeadlessShell ? { executablePath: headlessShellPath } : {},
88858
89046
  channel: "",
88859
- args: exports2.IS_CLOUD ? exports2.CLOUD_ARGS : ["--disable-blink-features=AutomationControlled"],
89047
+ args,
88860
89048
  ...slowMo > 0 ? { slowMo } : {}
88861
89049
  },
88862
89050
  contextOptions: {
@@ -88869,15 +89057,21 @@ var require_browser_config = __commonJS({
88869
89057
  function getPlaywrightLaunchOptions2(withProfile = false, extraArgs) {
88870
89058
  const headless = isHeadless2();
88871
89059
  const slowMo = getSlowMoMs();
89060
+ const googleLaunch = googleSsoCloudLaunch();
88872
89061
  const baseArgs = exports2.IS_CLOUD ? exports2.CLOUD_ARGS : [
88873
89062
  "--disable-blink-features=AutomationControlled"
88874
89063
  ];
88875
- const mergedArgs = extraArgs && extraArgs.length > 0 ? [...baseArgs, ...extraArgs] : [...baseArgs];
89064
+ const mergedArgs = [
89065
+ ...baseArgs,
89066
+ ...googleLaunch?.extraArgs ?? [],
89067
+ ...extraArgs && extraArgs.length > 0 ? extraArgs : []
89068
+ ];
88876
89069
  return {
88877
- headless,
89070
+ headless: googleLaunch ? false : headless,
88878
89071
  // Use Chrome channel only when a real Chrome user profile is being loaded.
88879
89072
  // In isolated mode, bundled Chromium avoids hard dependency on Chrome installation.
88880
89073
  ...exports2.IS_CLOUD || !withProfile ? {} : { channel: "chrome" },
89074
+ ...googleLaunch ? { executablePath: googleLaunch.executablePath, ignoreDefaultArgs: googleLaunch.ignoreDefaultArgs } : {},
88881
89075
  args: mergedArgs,
88882
89076
  ...slowMo > 0 ? { slowMo } : {}
88883
89077
  };
@@ -320219,6 +320413,7 @@ var require_playwright_mcp_config = __commonJS({
320219
320413
  var promises_1 = require("fs/promises");
320220
320414
  var node_path_1 = require("path");
320221
320415
  var browser_config_js_1 = require_browser_config();
320416
+ var google_signin_js_1 = require_google_signin();
320222
320417
  var PLAYWRIGHT_MCP_VERSION = "0.0.68";
320223
320418
  var INBOX_SECRET_ENV_KEYS = [
320224
320419
  "VERIFICATION_INBOX_HOST",
@@ -320228,7 +320423,10 @@ var require_playwright_mcp_config = __commonJS({
320228
320423
  "VERIFICATION_INBOX_PASSWORD",
320229
320424
  "VERIFICATION_INBOX_ADDRESS",
320230
320425
  "VERIFICATION_INBOX_MAILBOX",
320231
- "VERIFICATION_INBOX_EXTRA_MAILBOXES"
320426
+ "VERIFICATION_INBOX_EXTRA_MAILBOXES",
320427
+ "GOOGLE_SIGNIN_PASSWORD",
320428
+ "GOOGLE_SIGNIN_EMAIL",
320429
+ "GOOGLE_SIGNIN_TOTP_SECRET"
320232
320430
  ];
320233
320431
  function collectInboxSecretEnv() {
320234
320432
  const out = {};
@@ -320269,12 +320467,13 @@ var require_playwright_mcp_config = __commonJS({
320269
320467
  const body = cfg.format === "json" ? buildJsonConfig(cfg) : buildTomlConfig(cfg);
320270
320468
  await (0, promises_1.writeFile)(cfg.configPath, body, { encoding: "utf8", mode: 384 });
320271
320469
  if (!cfg.cdpEndpoint && browser_config_js_1.IS_CLOUD) {
320470
+ const launchOptions = (0, browser_config_js_1.getMCPBrowserConfig)({ forceIsolated: true }).launchOptions ?? {
320471
+ headless: true,
320472
+ args: [...browser_config_js_1.CLOUD_ARGS]
320473
+ };
320272
320474
  const browserConfig = {
320273
320475
  browser: {
320274
- launchOptions: {
320275
- headless: true,
320276
- args: [...browser_config_js_1.CLOUD_ARGS]
320277
- }
320476
+ launchOptions
320278
320477
  }
320279
320478
  };
320280
320479
  await (0, promises_1.writeFile)(mcpBrowserConfigPath(cfg.configPath), JSON.stringify(browserConfig, null, 2) + "\n", { encoding: "utf8", mode: 384 });
@@ -320298,7 +320497,11 @@ var require_playwright_mcp_config = __commonJS({
320298
320497
  ];
320299
320498
  if (cfg.includeCredentialServer && cfg.cdpEndpoint) {
320300
320499
  const serverJs = (0, node_path_1.join)(__dirname, "credential-mcp-server.js");
320301
- blocks.push("[mcp_servers.validateqa_credentials]", 'command = "node"', `args = ["${tomlEscape(serverJs)}"]`, "enabled = true", "startup_timeout_sec = 30", "tool_timeout_sec = 60", "", "[mcp_servers.validateqa_credentials.env]", `CDP_ENDPOINT = "${tomlEscape(cfg.cdpEndpoint)}"`, "");
320500
+ blocks.push("[mcp_servers.validateqa_credentials]", 'command = "node"', `args = ["${tomlEscape(serverJs)}"]`, "enabled = true", "startup_timeout_sec = 30", "tool_timeout_sec = 60", "", "[mcp_servers.validateqa_credentials.env]", `CDP_ENDPOINT = "${tomlEscape(cfg.cdpEndpoint)}"`);
320501
+ for (const [k, v] of Object.entries((0, google_signin_js_1.collectGoogleSignInEnv)())) {
320502
+ blocks.push(`${k} = "${tomlEscape(v)}"`);
320503
+ }
320504
+ blocks.push("");
320302
320505
  }
320303
320506
  if (cfg.includeDiscoveryServer) {
320304
320507
  if (!cfg.runDir) {
@@ -320346,7 +320549,7 @@ var require_playwright_mcp_config = __commonJS({
320346
320549
  type: "stdio",
320347
320550
  command: "node",
320348
320551
  args: [serverJs],
320349
- env: { CDP_ENDPOINT: cfg.cdpEndpoint }
320552
+ env: { CDP_ENDPOINT: cfg.cdpEndpoint, ...(0, google_signin_js_1.collectGoogleSignInEnv)() }
320350
320553
  };
320351
320554
  }
320352
320555
  if (cfg.includeDiscoveryServer) {
@@ -328553,6 +328756,7 @@ var require_discover_explorer = __commonJS({
328553
328756
  var credential_tools_js_1 = require_credential_tools();
328554
328757
  var inbox_tools_js_1 = require_inbox_tools();
328555
328758
  var verification_inbox_js_1 = require_verification_inbox();
328759
+ var google_signin_js_1 = require_google_signin();
328556
328760
  var discover_planner_js_1 = require_discover_planner();
328557
328761
  var exploration_prompt_builder_js_1 = require_exploration_prompt_builder();
328558
328762
  var ai_queue_js_1 = require_ai_queue();
@@ -328957,7 +329161,8 @@ NEVER assert: user-specific text (names, emails), counts/numbers, timestamps, ma
328957
329161
  };
328958
329162
  function buildSystemPrompt(baseUrl, variableContext, existingSiteMap, existingTestNames, options) {
328959
329163
  const browserCredentials = variableContext.allTestVariables ?? variableContext.publicTestVariables;
328960
- const { secrets: explorerSecretVars, publics: explorerPublicVarsRaw } = (0, credential_tools_js_1.partitionTestVariables)(browserCredentials);
329164
+ const { secrets: explorerSecretVarsRaw, publics: explorerPublicVarsRaw } = (0, credential_tools_js_1.partitionTestVariables)(browserCredentials);
329165
+ const explorerSecretVars = options?.inboxPrompt ? (0, google_signin_js_1.mergeGoogleSignInSecrets)(explorerSecretVarsRaw) : explorerSecretVarsRaw;
328961
329166
  const hasCredentials = Object.keys(explorerSecretVars).length > 0;
328962
329167
  const { DISCOVERY_SHOULD_REGISTER: _omitRegisterFlag, ...explorerPublicVars } = explorerPublicVarsRaw;
328963
329168
  const explorerPublicLines = (0, credential_tools_js_1.renderPublicVariablesBlock)(explorerPublicVars);
@@ -329574,10 +329779,12 @@ ${inbox_tools_js_1.EMAIL_VERIFICATION_UNAVAILABLE_OVERRIDE_BLOCK}` : ""}`;
329574
329779
  if (emailVerificationUnavailable) {
329575
329780
  logs2.push("Email verification unavailable \u2014 the agent will ATTEMPT registration once; any flow requiring an emailed code/link will be reported BLOCKED.");
329576
329781
  }
329782
+ const googleGuidance = (0, google_signin_js_1.googleSignInGuidanceOpts)();
329577
329783
  const inboxPromptBlock = inboxState ? (0, inbox_tools_js_1.buildInboxPromptBlock)({
329578
329784
  email: inboxState.email,
329579
329785
  passwordKey: inboxState.passwordKey ?? "TEST_USER_PASSWORD",
329580
- context: options?.mode
329786
+ context: options?.mode,
329787
+ ...googleGuidance
329581
329788
  }) : "";
329582
329789
  try {
329583
329790
  const { tools: mcpTools } = await mcpClient.listTools();
@@ -329598,7 +329805,8 @@ ${inbox_tools_js_1.EMAIL_VERIFICATION_UNAVAILABLE_OVERRIDE_BLOCK}` : ""}`;
329598
329805
  }
329599
329806
  const browserCredsForTools = variableContext.allTestVariables ?? variableContext.publicTestVariables;
329600
329807
  const { secrets: explorerToolSecrets } = (0, credential_tools_js_1.partitionTestVariables)(browserCredsForTools);
329601
- if (Object.keys(explorerToolSecrets).length > 0) {
329808
+ const explorerToolSecretsWithGoogle = inboxState ? (0, google_signin_js_1.mergeGoogleSignInSecrets)(explorerToolSecrets) : explorerToolSecrets;
329809
+ if (Object.keys(explorerToolSecretsWithGoogle).length > 0) {
329602
329810
  openaiTools.push(credential_tools_js_1.FILL_CREDENTIAL_TOOL, credential_tools_js_1.FILL_CREDENTIAL_FORM_TOOL);
329603
329811
  if (options?.onCredentialUpdate) {
329604
329812
  openaiTools.push(credential_tools_js_1.SET_CREDENTIAL_TOOL);
@@ -330238,8 +330446,12 @@ ${currentSummary}`;
330238
330446
  let finishBouncedThisBatch = false;
330239
330447
  let finishStreakCountedThisBatch = false;
330240
330448
  const fullVarMapForGuard = variableContext.allTestVariables ?? variableContext.publicTestVariables;
330241
- const { secrets: secretsOnlyForGuard } = (0, credential_tools_js_1.partitionTestVariables)(fullVarMapForGuard);
330242
- const allowedCredentialValues = inboxState ? [inboxState.email] : [];
330449
+ const { secrets: partitionedSecretsForGuard } = (0, credential_tools_js_1.partitionTestVariables)(fullVarMapForGuard);
330450
+ const secretsOnlyForGuard = inboxState ? (0, google_signin_js_1.mergeGoogleSignInSecrets)(partitionedSecretsForGuard) : partitionedSecretsForGuard;
330451
+ const allowedCredentialValues = [...new Set([
330452
+ ...inboxState ? [inboxState.email, inboxState.baseEmail] : [],
330453
+ ...inboxState ? (0, google_signin_js_1.googleSignInAllowedEmails)() : []
330454
+ ].filter((value) => !!value))];
330243
330455
  const secretsForLogging = Object.fromEntries(Object.entries(secretsOnlyForGuard).filter(([, value]) => !allowedCredentialValues.includes(value)));
330244
330456
  for (const toolCall of assistantMessage.tool_calls) {
330245
330457
  const toolName = toolCall.function.name;
@@ -331090,8 +331302,9 @@ Exploration complete: ${summary}`);
331090
331302
  }
331091
331303
  const fullVarMap = variableContext.allTestVariables ?? variableContext.publicTestVariables;
331092
331304
  const { secrets: dispatchSecrets } = (0, credential_tools_js_1.partitionTestVariables)(fullVarMap);
331305
+ const fillSecrets = inboxState ? (0, google_signin_js_1.mergeGoogleSignInSecrets)(dispatchSecrets) : dispatchSecrets;
331093
331306
  try {
331094
- const result = toolName === "fill_credential" ? await (0, credential_tools_js_1.handleFillCredential)(toolArgs, { mcpClient, credentials: dispatchSecrets, maxResultChars: MAX_TOOL_RESULT_CHARS }) : await (0, credential_tools_js_1.handleFillCredentialForm)(toolArgs, { mcpClient, credentials: dispatchSecrets, maxResultChars: MAX_TOOL_RESULT_CHARS });
331307
+ const result = toolName === "fill_credential" ? await (0, credential_tools_js_1.handleFillCredential)(toolArgs, { mcpClient, credentials: fillSecrets, maxResultChars: MAX_TOOL_RESULT_CHARS }) : await (0, credential_tools_js_1.handleFillCredentialForm)(toolArgs, { mcpClient, credentials: fillSecrets, maxResultChars: MAX_TOOL_RESULT_CHARS });
331095
331308
  if (result.didMutate) {
331096
331309
  lastSnapshotText = null;
331097
331310
  const codeLines = (0, exploration_parser_js_1.extractCodeLines)(result.content);
@@ -333131,7 +333344,7 @@ ${keyLines || "- (none provided)"}
333131
333344
  ## EXACTLY what to do
333132
333345
  1. Navigate to ${baseUrl} and take a \`browser_snapshot\`.
333133
333346
  2. Find the Sign Up / Register / Create account affordance (match by PURPOSE, in the app's own language) and open the signup form. If a reveal button hides the fields ("Sign up with Email"), click it first.
333134
- 3. Follow the "Account Registration (verification inbox is ENABLED)" steps below EXACTLY: call \`provision_identity\` for the email, type that email, fill the password with \`fill_credential\`, fill any other required fields with simple test values, and submit.
333347
+ 3. Follow the "Account Registration (verification inbox is ENABLED)" steps below EXACTLY: call \`provision_identity\` for the email, type that email, fill the password with \`fill_credential\`, fill any other required fields with simple test values, and submit. If there is NO email+password signup field and only "Continue with Google" / "Sign up with Gmail", follow the Google / Gmail SSO fallback in that section (bare Google account email, \`fill_credential\` with \`GOOGLE_SIGNIN_PASSWORD\`, never the IMAP app password).
333135
333348
  4. Complete email verification using the inbox tools (\`wait_for_verification\` \u2192 enter the code or \`open_verification_link\`). Re-poll if the email is slow; resend AT MOST once; NEVER register a second account.
333136
333349
  5. Confirm you are signed in \u2014 a redirect to an authenticated route, or an in-place change to authenticated content. Take a \`browser_snapshot\`.
333137
333350
  6. \`capture_page\` the authenticated landing page in its DEFAULT state, then call \`finish_exploration\`. Do this the MOMENT the account is verified and you are signed in.
@@ -333685,6 +333898,7 @@ var require_grok_survey_runner = __commonJS({
333685
333898
  var grok_cli_js_1 = require_grok_cli();
333686
333899
  var playwright_mcp_config_js_1 = require_playwright_mcp_config();
333687
333900
  var inbox_tools_js_1 = require_inbox_tools();
333901
+ var google_signin_js_1 = require_google_signin();
333688
333902
  var exploration_parser_js_1 = require_exploration_parser();
333689
333903
  var scrub_credentials_js_1 = require_scrub_credentials();
333690
333904
  var agentic_survey_prompts_js_1 = require_agentic_survey_prompts();
@@ -334209,7 +334423,7 @@ var require_grok_survey_runner = __commonJS({
334209
334423
  };
334210
334424
  const surveyAgentsMd = inboxReg ? `${(0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)()}
334211
334425
 
334212
- ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey)}` : (0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)();
334426
+ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey, (0, google_signin_js_1.googleSignInGuidanceOpts)())}` : (0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)();
334213
334427
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "AGENTS.md"), surveyAgentsMd, "utf8");
334214
334428
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "BRIEF.md"), (0, agentic_survey_prompts_js_1.buildSurveyBriefMd)(briefInput), "utf8");
334215
334429
  log2("Wrote AGENTS.md + BRIEF.md");
@@ -335616,6 +335830,7 @@ var require_grok_discovery_runner = __commonJS({
335616
335830
  var playwright_native_js_1 = require_playwright_native();
335617
335831
  var playwright_mcp_config_js_1 = require_playwright_mcp_config();
335618
335832
  var inbox_tools_js_1 = require_inbox_tools();
335833
+ var google_signin_js_1 = require_google_signin();
335619
335834
  var scrub_credentials_js_1 = require_scrub_credentials();
335620
335835
  var grok_survey_runner_js_1 = require_grok_survey_runner();
335621
335836
  var agentic_discovery_prompts_js_1 = require_agentic_discovery_prompts();
@@ -335909,7 +336124,7 @@ var require_grok_discovery_runner = __commonJS({
335909
336124
  };
335910
336125
  const discoveryAgentsMd = inboxReg ? `${(0, agentic_discovery_prompts_js_1.buildDiscoveryAgentsMd)()}
335911
336126
 
335912
- ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey)}` : (0, agentic_discovery_prompts_js_1.buildDiscoveryAgentsMd)();
336127
+ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey, (0, google_signin_js_1.googleSignInGuidanceOpts)())}` : (0, agentic_discovery_prompts_js_1.buildDiscoveryAgentsMd)();
335913
336128
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "AGENTS.md"), discoveryAgentsMd, "utf8");
335914
336129
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "BRIEF.md"), (0, agentic_discovery_prompts_js_1.buildDiscoveryBriefMd)(briefInput), "utf8");
335915
336130
  await (0, promises_1.mkdir)(testsDirPath, { recursive: true });
@@ -336862,7 +337077,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
336862
337077
 
336863
337078
  ---
336864
337079
 
336865
- ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxRegV2.email, inboxRegV2.passwordKey)}` : "");
337080
+ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxRegV2.email, inboxRegV2.passwordKey, (0, google_signin_js_1.googleSignInGuidanceOpts)())}` : "");
336866
337081
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "AGENTS.md"), agentsMd, "utf8");
336867
337082
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "BRIEF.md"), (0, agentic_discovery_prompts_js_1.buildDiscoveryBriefMd)(briefInput), "utf8");
336868
337083
  await (0, promises_1.mkdir)(testsDirPath, { recursive: true });
@@ -337834,6 +338049,7 @@ var require_claude_survey_runner = __commonJS({
337834
338049
  var claude_stream_parser_js_1 = require_claude_stream_parser();
337835
338050
  var playwright_mcp_config_js_1 = require_playwright_mcp_config();
337836
338051
  var inbox_tools_js_1 = require_inbox_tools();
338052
+ var google_signin_js_1 = require_google_signin();
337837
338053
  var scrub_credentials_js_1 = require_scrub_credentials();
337838
338054
  var agentic_cli_constants_js_1 = require_agentic_cli_constants();
337839
338055
  var grok_survey_runner_js_1 = require_grok_survey_runner();
@@ -337934,7 +338150,7 @@ ${preview}`);
337934
338150
  };
337935
338151
  const surveyAgentsMd = inboxReg ? `${(0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)({ canvasMode })}
337936
338152
 
337937
- ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey)}` : (0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)({ canvasMode });
338153
+ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey, (0, google_signin_js_1.googleSignInGuidanceOpts)())}` : (0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)({ canvasMode });
337938
338154
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "AGENTS.md"), surveyAgentsMd, "utf8");
337939
338155
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "BRIEF.md"), (0, agentic_survey_prompts_js_1.buildSurveyBriefMd)(briefInput), "utf8");
337940
338156
  log2("Wrote AGENTS.md + BRIEF.md");
@@ -338644,6 +338860,7 @@ var require_claude_discovery_runner = __commonJS({
338644
338860
  var claude_cli_js_1 = require_claude_cli();
338645
338861
  var playwright_mcp_config_js_1 = require_playwright_mcp_config();
338646
338862
  var inbox_tools_js_1 = require_inbox_tools();
338863
+ var google_signin_js_1 = require_google_signin();
338647
338864
  var coverage_examples_content_js_1 = require_coverage_examples_content();
338648
338865
  var scrub_credentials_js_1 = require_scrub_credentials();
338649
338866
  var agentic_cli_constants_js_1 = require_agentic_cli_constants();
@@ -338812,7 +339029,7 @@ var require_claude_discovery_runner = __commonJS({
338812
339029
  };
338813
339030
  const explorerContractMd = inboxReg ? `${(0, agentic_discovery_prompts_js_1.buildExplorerContractMd)(contractInput)}
338814
339031
 
338815
- ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey)}` : (0, agentic_discovery_prompts_js_1.buildExplorerContractMd)(contractInput);
339032
+ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey, (0, google_signin_js_1.googleSignInGuidanceOpts)())}` : (0, agentic_discovery_prompts_js_1.buildExplorerContractMd)(contractInput);
338816
339033
  await (0, promises_1.writeFile)(claudeMdPath, explorerContractMd, "utf8");
338817
339034
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "BRIEF.md"), (0, agentic_discovery_prompts_js_1.buildDiscoveryBriefMd)(briefInput), "utf8");
338818
339035
  await (0, promises_1.mkdir)(testsDirPath, { recursive: true });
@@ -356069,7 +356286,7 @@ var require_package4 = __commonJS({
356069
356286
  "package.json"(exports2, module2) {
356070
356287
  module2.exports = {
356071
356288
  name: "@validate.qa/runner",
356072
- version: "1.0.92",
356289
+ version: "1.0.93",
356073
356290
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
356074
356291
  bin: {
356075
356292
  "validate-runner": "dist/cli.js"
package/dist/cli.mjs CHANGED
@@ -8560,6 +8560,127 @@ var require_scrub_credentials = __commonJS({
8560
8560
  }
8561
8561
  });
8562
8562
 
8563
+ // ../runner-core/dist/services/google-signin.js
8564
+ var require_google_signin = __commonJS({
8565
+ "../runner-core/dist/services/google-signin.js"(exports) {
8566
+ "use strict";
8567
+ Object.defineProperty(exports, "__esModule", { value: true });
8568
+ exports.GOOGLE_SIGNIN_ENV_KEYS = exports.GOOGLE_SIGNIN_PASSWORD_KEY = void 0;
8569
+ exports.loadGoogleSignInConfig = loadGoogleSignInConfig;
8570
+ exports.mergeGoogleSignInSecrets = mergeGoogleSignInSecrets;
8571
+ exports.googleSignInGuidanceOpts = googleSignInGuidanceOpts;
8572
+ exports.googleSignInAllowedEmails = googleSignInAllowedEmails;
8573
+ exports.collectGoogleSignInEnv = collectGoogleSignInEnv;
8574
+ exports.generateTotp = generateTotp;
8575
+ exports.buildGoogleSignInPromptSection = buildGoogleSignInPromptSection;
8576
+ var node_crypto_1 = __require("crypto");
8577
+ exports.GOOGLE_SIGNIN_PASSWORD_KEY = "GOOGLE_SIGNIN_PASSWORD";
8578
+ exports.GOOGLE_SIGNIN_ENV_KEYS = [
8579
+ "GOOGLE_SIGNIN_PASSWORD",
8580
+ "GOOGLE_SIGNIN_EMAIL",
8581
+ "GOOGLE_SIGNIN_TOTP_SECRET"
8582
+ ];
8583
+ function trimEnv(env, name) {
8584
+ const value = env[name]?.trim();
8585
+ return value ? value : void 0;
8586
+ }
8587
+ function loadGoogleSignInConfig(env = process.env) {
8588
+ const password = trimEnv(env, "GOOGLE_SIGNIN_PASSWORD");
8589
+ if (!password)
8590
+ return null;
8591
+ const email = (trimEnv(env, "GOOGLE_SIGNIN_EMAIL") ?? trimEnv(env, "VERIFICATION_INBOX_ADDRESS"))?.toLowerCase();
8592
+ if (!email || !email.includes("@"))
8593
+ return null;
8594
+ const totpSecret = trimEnv(env, "GOOGLE_SIGNIN_TOTP_SECRET");
8595
+ return {
8596
+ email,
8597
+ password,
8598
+ passwordKey: exports.GOOGLE_SIGNIN_PASSWORD_KEY,
8599
+ totpSecret,
8600
+ totpAvailable: !!totpSecret
8601
+ };
8602
+ }
8603
+ function mergeGoogleSignInSecrets(credentials, env = process.env) {
8604
+ const cfg = loadGoogleSignInConfig(env);
8605
+ if (!cfg)
8606
+ return credentials;
8607
+ if (credentials[exports.GOOGLE_SIGNIN_PASSWORD_KEY])
8608
+ return credentials;
8609
+ return { ...credentials, [exports.GOOGLE_SIGNIN_PASSWORD_KEY]: cfg.password };
8610
+ }
8611
+ function googleSignInGuidanceOpts(env = process.env) {
8612
+ const cfg = loadGoogleSignInConfig(env);
8613
+ if (!cfg)
8614
+ return void 0;
8615
+ return {
8616
+ googleEmail: cfg.email,
8617
+ googlePasswordKey: cfg.passwordKey,
8618
+ googleTotpAvailable: cfg.totpAvailable
8619
+ };
8620
+ }
8621
+ function googleSignInAllowedEmails(env = process.env) {
8622
+ const cfg = loadGoogleSignInConfig(env);
8623
+ return cfg ? [cfg.email] : [];
8624
+ }
8625
+ function collectGoogleSignInEnv(env = process.env) {
8626
+ const out = {};
8627
+ for (const key of exports.GOOGLE_SIGNIN_ENV_KEYS) {
8628
+ const value = env[key]?.trim();
8629
+ if (value)
8630
+ out[key] = value;
8631
+ }
8632
+ return out;
8633
+ }
8634
+ function generateTotp(secret, atMs = Date.now(), stepSeconds = 30, digits = 6) {
8635
+ const key = decodeBase32(secret);
8636
+ const counter = Math.floor(atMs / 1e3 / stepSeconds);
8637
+ const buf = Buffer.alloc(8);
8638
+ buf.writeUInt32BE(Math.floor(counter / 4294967296), 0);
8639
+ buf.writeUInt32BE(counter >>> 0, 4);
8640
+ const hmac = (0, node_crypto_1.createHmac)("sha1", key).update(buf).digest();
8641
+ const offset = hmac[hmac.length - 1] & 15;
8642
+ const bin = (hmac[offset] & 127) << 24 | hmac[offset + 1] << 16 | hmac[offset + 2] << 8 | hmac[offset + 3];
8643
+ const otp = bin % 10 ** digits;
8644
+ return String(otp).padStart(digits, "0");
8645
+ }
8646
+ function decodeBase32(input) {
8647
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
8648
+ const cleaned = input.toUpperCase().replace(/[\s=-]+/g, "");
8649
+ let bits = 0;
8650
+ let value = 0;
8651
+ const out = [];
8652
+ for (const ch of cleaned) {
8653
+ const idx = alphabet.indexOf(ch);
8654
+ if (idx < 0)
8655
+ continue;
8656
+ value = value << 5 | idx;
8657
+ bits += 5;
8658
+ if (bits >= 8) {
8659
+ bits -= 8;
8660
+ out.push(value >>> bits & 255);
8661
+ }
8662
+ }
8663
+ return Buffer.from(out);
8664
+ }
8665
+ function buildGoogleSignInPromptSection(opts, variant) {
8666
+ const totpNative = opts.googleTotpAvailable ? " If Google asks for a 2-step / Authenticator code, call `provision_google_totp` and type the 6-digit `code` it returns (do not invent a code)." : " If Google asks for 2-step verification and you have no authenticator code tool, STOP and report Google SSO as BLOCKED (2FA not configured on this runner).";
8667
+ const totpCli = opts.googleTotpAvailable ? " If Google asks for a 2-step / Authenticator code, call `inbox_google_totp` and type the 6-digit `code` it returns." : " If Google asks for 2-step verification, STOP and report Google SSO as BLOCKED (2FA not configured on this runner).";
8668
+ const totp = variant === "cli" ? totpCli : totpNative;
8669
+ const fill = variant === "cli" ? `fill_credential with credentialKey \`${opts.googlePasswordKey}\`` : `\`fill_credential\` (credentialKey \`${opts.googlePasswordKey}\`)`;
8670
+ const plainProvision = variant === "cli" ? "`inbox_provision_identity` with `plain: true`" : "`provision_identity` with `plain: true`";
8671
+ return `
8672
+ Google / Gmail SSO fallback (SECOND choice \u2014 email+password signup is FIRST):
8673
+ - FIRST follow the email-field playbook above whenever a signup form has an email / username / password field (including after clicking "Sign up with email"). Do NOT click Google if that form exists.
8674
+ - ONLY if there is no email+password signup field and the only path is "Continue with Google" / "Sign up with Gmail" / "Sign in with Google": click that button. If a Google popup opens, switch to it (browser tabs).
8675
+ - On accounts.google.com, type the BARE Google account email \`${opts.googleEmail}\` (no plus-tag \u2014 Google account login rejects plus-addresses) with browser_type, click Next, then fill the Google password with ${fill}. NEVER type the Google password as text and NEVER use the IMAP app password here.
8676
+ - Click Next.${totp}
8677
+ - Click Continue / Allow on any consent screen, then return to the app tab.
8678
+ - If the app then emails a verification code/link, first call ${plainProvision} (Google SSO uses the bare inbox address, not the +tag), then complete it with the inbox tools as usual.
8679
+ - Register / Google-sign-in ONCE per run. If Google says the account is already used on this app, that is success \u2014 continue as the logged-in user.`;
8680
+ }
8681
+ }
8682
+ });
8683
+
8563
8684
  // ../runner-core/dist/services/credential-tools.js
8564
8685
  var require_credential_tools = __commonJS({
8565
8686
  "../runner-core/dist/services/credential-tools.js"(exports) {
@@ -8578,6 +8699,7 @@ var require_credential_tools = __commonJS({
8578
8699
  exports.mcpResultIsError = mcpResultIsError;
8579
8700
  exports.aggressiveScrubCredentials = aggressiveScrubCredentials;
8580
8701
  var scrub_credentials_js_1 = require_scrub_credentials();
8702
+ var google_signin_js_1 = require_google_signin();
8581
8703
  exports.FILL_CREDENTIAL_TOOL = {
8582
8704
  type: "function",
8583
8705
  function: {
@@ -8588,7 +8710,7 @@ var require_credential_tools = __commonJS({
8588
8710
  properties: {
8589
8711
  credentialKey: {
8590
8712
  type: "string",
8591
- description: 'The credential variable name (e.g. "TEST_USER_EMAIL", "TEST_USER_PASSWORD", "TEST_ADMIN_EMAIL"). Must be one of the keys listed in the Test Credentials section of the prompt.'
8713
+ description: 'The credential variable name (e.g. "TEST_USER_EMAIL", "TEST_USER_PASSWORD", "GOOGLE_SIGNIN_PASSWORD"). Must be one of the keys listed in the Test Credentials section of the prompt.'
8592
8714
  },
8593
8715
  element: {
8594
8716
  type: "string",
@@ -8854,6 +8976,14 @@ CREDENTIAL ROTATION (required when the STORED user's secret changes \u2014 read
8854
8976
  didMutate: false
8855
8977
  };
8856
8978
  }
8979
+ if (key === google_signin_js_1.GOOGLE_SIGNIN_PASSWORD_KEY) {
8980
+ return {
8981
+ content: JSON.stringify({
8982
+ error: "set_credential: GOOGLE_SIGNIN_PASSWORD is a runner-operator secret and cannot be persisted to project Test Data"
8983
+ }),
8984
+ didMutate: false
8985
+ };
8986
+ }
8857
8987
  if (!(key in ctx.credentials)) {
8858
8988
  const available = Object.keys(ctx.credentials).filter((k) => ctx.credentials[k]).join(", ") || "(none configured)";
8859
8989
  return {
@@ -74115,7 +74245,7 @@ var require_inbox_tools = __commonJS({
74115
74245
  "../runner-core/dist/services/inbox-tools.js"(exports) {
74116
74246
  "use strict";
74117
74247
  Object.defineProperty(exports, "__esModule", { value: true });
74118
- exports.EMAIL_VERIFICATION_UNAVAILABLE_OVERRIDE_BLOCK = exports.INBOX_TOOL_NAMES = exports.INBOX_TOOLS = exports.OPEN_VERIFICATION_LINK_TOOL = exports.GET_VERIFICATION_LINK_TOOL = exports.EXTRACT_VERIFICATION_CODE_TOOL = exports.READ_VERIFICATION_EMAIL_TOOL = exports.WAIT_FOR_VERIFICATION_TOOL = exports.CHECK_INBOX_TOOL = exports.PROVISION_IDENTITY_TOOL = void 0;
74248
+ exports.EMAIL_VERIFICATION_UNAVAILABLE_OVERRIDE_BLOCK = exports.INBOX_TOOL_NAMES = exports.INBOX_TOOLS = exports.PROVISION_GOOGLE_TOTP_TOOL = exports.OPEN_VERIFICATION_LINK_TOOL = exports.GET_VERIFICATION_LINK_TOOL = exports.EXTRACT_VERIFICATION_CODE_TOOL = exports.READ_VERIFICATION_EMAIL_TOOL = exports.WAIT_FOR_VERIFICATION_TOOL = exports.CHECK_INBOX_TOOL = exports.PROVISION_IDENTITY_TOOL = void 0;
74119
74249
  exports.createInboxRunState = createInboxRunState;
74120
74250
  exports.dispatchInboxTool = dispatchInboxTool;
74121
74251
  exports.isPublicHttpUrl = isPublicHttpUrl;
@@ -74130,6 +74260,7 @@ var require_inbox_tools = __commonJS({
74130
74260
  exports.clearThrowawayRegisterSeed = clearThrowawayRegisterSeed;
74131
74261
  exports.buildInboxAgentsGuidance = buildInboxAgentsGuidance;
74132
74262
  var verification_inbox_js_1 = require_verification_inbox();
74263
+ var google_signin_js_1 = require_google_signin();
74133
74264
  function createInboxRunState(config, opts = {}) {
74134
74265
  const baseEmail = config.address;
74135
74266
  const tag = opts.tag !== void 0 ? opts.tag : opts.tagSeed ? (0, verification_inbox_js_1.deriveProjectInboxTag)(opts.tagSeed, opts.projectScope) : null;
@@ -74251,6 +74382,14 @@ var require_inbox_tools = __commonJS({
74251
74382
  }
74252
74383
  }
74253
74384
  };
74385
+ exports.PROVISION_GOOGLE_TOTP_TOOL = {
74386
+ type: "function",
74387
+ function: {
74388
+ name: "provision_google_totp",
74389
+ description: "Return a one-time 6-digit Authenticator code for the operator Google account. Call this ONLY when Google Sign-In shows a 2-step / Authenticator challenge after you submitted the Google password. Type the returned code into the Google prompt. Do not invent a code.",
74390
+ parameters: { type: "object", properties: {} }
74391
+ }
74392
+ };
74254
74393
  exports.INBOX_TOOLS = [
74255
74394
  exports.PROVISION_IDENTITY_TOOL,
74256
74395
  exports.CHECK_INBOX_TOOL,
@@ -74258,7 +74397,8 @@ var require_inbox_tools = __commonJS({
74258
74397
  exports.READ_VERIFICATION_EMAIL_TOOL,
74259
74398
  exports.EXTRACT_VERIFICATION_CODE_TOOL,
74260
74399
  exports.GET_VERIFICATION_LINK_TOOL,
74261
- exports.OPEN_VERIFICATION_LINK_TOOL
74400
+ exports.OPEN_VERIFICATION_LINK_TOOL,
74401
+ exports.PROVISION_GOOGLE_TOTP_TOOL
74262
74402
  ];
74263
74403
  exports.INBOX_TOOL_NAMES = new Set(exports.INBOX_TOOLS.map((t) => t.function.name));
74264
74404
  var DEFAULT_MAX_RESULT_CHARS = 8e3;
@@ -74270,7 +74410,7 @@ var require_inbox_tools = __commonJS({
74270
74410
  }
74271
74411
  var INBOX_AUTH_DEAD_GUIDANCE = "the inbox authentication is PERMANENTLY rejected (revoked/wrong app password) \u2014 STOP calling inbox tools; none of them can succeed this run. Treat email verification as UNAVAILABLE: hard-stop at any emailed code/link wall, NEVER type a guessed code, and report verification-gated flows as BLOCKED (blockedReason: inbox authentication failed). Continue with publicly reachable coverage.";
74272
74412
  async function dispatchInboxTool(toolName, toolArgs, ctx) {
74273
- if (ctx.state.authDead) {
74413
+ if (ctx.state.authDead && toolName !== "provision_google_totp") {
74274
74414
  return err(`${toolName} skipped: ${INBOX_AUTH_DEAD_GUIDANCE}`);
74275
74415
  }
74276
74416
  try {
@@ -74289,6 +74429,8 @@ var require_inbox_tools = __commonJS({
74289
74429
  return await handleGetLink(toolArgs, ctx);
74290
74430
  case "open_verification_link":
74291
74431
  return await handleOpenLink(toolArgs, ctx);
74432
+ case "provision_google_totp":
74433
+ return handleProvisionGoogleTotp();
74292
74434
  default:
74293
74435
  return err(`inbox dispatch: unknown tool "${toolName}"`);
74294
74436
  }
@@ -74464,6 +74606,20 @@ var require_inbox_tools = __commonJS({
74464
74606
  didMutate: !failed
74465
74607
  };
74466
74608
  }
74609
+ function handleProvisionGoogleTotp(env = process.env) {
74610
+ const cfg = (0, google_signin_js_1.loadGoogleSignInConfig)(env);
74611
+ if (!cfg) {
74612
+ return err("Google SSO is not configured on this runner (GOOGLE_SIGNIN_PASSWORD unset). Prefer email-field signup, or report Google SSO as BLOCKED.");
74613
+ }
74614
+ if (!cfg.totpSecret) {
74615
+ return err("Google Authenticator 2FA is not configured on this runner (GOOGLE_SIGNIN_TOTP_SECRET unset). STOP and report Google SSO as BLOCKED (2FA not configured).");
74616
+ }
74617
+ return ok({
74618
+ code: (0, google_signin_js_1.generateTotp)(cfg.totpSecret),
74619
+ digits: 6,
74620
+ instructions: "Type this 6-digit code into the Google 2-step / Authenticator prompt. Do not reuse it later \u2014 call this tool again if Google asks for another code."
74621
+ });
74622
+ }
74467
74623
  function requireProvisioned(ctx) {
74468
74624
  if (ctx.state.provisioned)
74469
74625
  return null;
@@ -74598,7 +74754,7 @@ var require_inbox_tools = __commonJS({
74598
74754
  ${where} You register using ONE real, monitored email (\`${opts.email}\`) and can complete email-verification (OTP code or confirmation link) end-to-end. This OVERRIDES the general "do not submit forms" rule for the signup/registration form ONLY.
74599
74755
 
74600
74756
  Steps:
74601
- 1. Navigate to the Sign Up / Register page (click the link in the UI).
74757
+ 1. Navigate to the Sign Up / Register page (click the link in the UI). FIRST look for an email+password signup form (including after "Sign up with email"). Use Google / Gmail SSO ONLY if that form does not exist.
74602
74758
  2. Call \`provision_identity\` \u2192 it returns the email to register with (\`${opts.email}\`). The \`+\` part is a normal sub-address that still lands in our inbox.
74603
74759
  3. Fill the signup form: type that email into the email field with \`browser_type\` (this generated inbox email is intentionally visible and is allowed for registration); fill the password field with single-field \`fill_credential\` (credentialKey \`${opts.passwordKey}\`); fill any name/other required fields with simple test values. Do NOT use \`fill_credential_form\` for registration.
74604
74760
  - If the form REJECTS the email (says "invalid email" / will not accept the "+"), call \`provision_identity\` again with \`plain: true\` and use the bare address it returns instead.
@@ -74616,6 +74772,11 @@ Rules:
74616
74772
  - The provisioned email is reused for this project; if signup says it is ALREADY registered, the account already exists \u2014 log in with that email + the \`${opts.passwordKey}\` password instead of registering again.
74617
74773
  - You register ONCE per run. After you submit the signup form in step 4, NEVER submit it again and NEVER create a second account \u2014 even if verification is slow, even if a later login attempt fails. Recover by re-polling \`wait_for_verification\` (and at most one "Resend"), not by re-registering.
74618
74774
  - Only call the verification tools AFTER submitting the signup form, and pass the site as \`senderMatch\` so you read YOUR verification email (the inbox is shared).
74775
+ ${opts.googleEmail && opts.googlePasswordKey ? (0, google_signin_js_1.buildGoogleSignInPromptSection)({
74776
+ googleEmail: opts.googleEmail,
74777
+ googlePasswordKey: opts.googlePasswordKey,
74778
+ googleTotpAvailable: opts.googleTotpAvailable
74779
+ }, "native") : ""}
74619
74780
  `;
74620
74781
  }
74621
74782
  exports.EMAIL_VERIFICATION_UNAVAILABLE_OVERRIDE_BLOCK = `## EMAIL VERIFICATION UNAVAILABLE \u2014 FINAL OVERRIDE (supersedes any instruction above)
@@ -74770,11 +74931,12 @@ This project asked to REGISTER a new account, but this runner CANNOT receive ema
74770
74931
  }
74771
74932
  return false;
74772
74933
  }
74773
- function buildInboxAgentsGuidance(email, passwordKey) {
74934
+ function buildInboxAgentsGuidance(email, passwordKey, google) {
74935
+ const googleBlock = google ? (0, google_signin_js_1.buildGoogleSignInPromptSection)(google, "cli") : "";
74774
74936
  return `## Account registration & email verification (ENABLED)
74775
74937
  This run registers a new account using our ONE real, monitored inbox (the address \`${email}\` \u2014 the "+" part is a normal sub-address that still lands in our inbox) and can complete email verification end-to-end. This overrides any "do not submit forms" guidance for the signup form only.
74776
74938
 
74777
- 1. Go to the Sign Up / Register page.
74939
+ 1. Go to the Sign Up / Register page. FIRST look for an email+password signup form (including after "Sign up with email"). Use Google / Gmail SSO ONLY if that form does not exist.
74778
74940
  2. Call \`inbox_provision_identity\` \u2192 it returns the email to register with (\`${email}\`). Type that email into the email field.
74779
74941
  - If the form REJECTS the email (says "invalid email" / will not accept the "+"), call \`inbox_provision_identity\` with \`plain: true\` and use the bare address it returns instead.
74780
74942
  3. Fill the password with the \`${passwordKey}\` credential (use fill_credential). Submit the signup form.
@@ -74785,6 +74947,7 @@ This run registers a new account using our ONE real, monitored inbox (the addres
74785
74947
  - If it returns BOTH, try the code first; if the app insists on the link, open it, then enter the code if the page it lands on asks for one.
74786
74948
  - Otherwise call \`inbox_read_email\` to read the body.
74787
74949
  5. NEVER invent an email address \u2014 always use exactly what \`inbox_provision_identity\` returns. The address is reused for this project; if signup says it is already registered, log in with it + \`${passwordKey}\` instead. Register ONCE per run \u2014 never submit signup twice or make a second account; if verification is slow, re-poll \`inbox_wait_for_verification\` (at most one Resend) instead of re-registering.
74950
+ ${googleBlock}
74788
74951
  `;
74789
74952
  }
74790
74953
  }
@@ -88619,6 +88782,7 @@ var require_browser_config = __commonJS({
88619
88782
  var path_1 = __require("path");
88620
88783
  var os_1 = __require("os");
88621
88784
  var shared_1 = (init_dist(), __toCommonJS(dist_exports));
88785
+ var google_signin_js_1 = require_google_signin();
88622
88786
  exports.IS_CLOUD = (0, shared_1.parseBoolFlag)(process.env.RUNNER_CLOUD);
88623
88787
  exports.CLOUD_ARGS = [
88624
88788
  "--no-sandbox",
@@ -88724,6 +88888,10 @@ var require_browser_config = __commonJS({
88724
88888
  (document.head || document.documentElement).appendChild(style);
88725
88889
 
88726
88890
  // Layer 2: Web Animations API - make instant (preserves completion callbacks)
88891
+ try {
88892
+ Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
88893
+ } catch {}
88894
+
88727
88895
  const origAnimate = Element.prototype.animate;
88728
88896
  Element.prototype.animate = function(keyframes, options) {
88729
88897
  if (typeof options === 'object' && options !== null) {
@@ -88830,6 +88998,20 @@ var require_browser_config = __commonJS({
88830
88998
  return null;
88831
88999
  }
88832
89000
  }
89001
+ function googleSsoCloudLaunch(env = process.env) {
89002
+ if (!(0, shared_1.parseBoolFlag)(env.RUNNER_CLOUD))
89003
+ return null;
89004
+ if (!(0, google_signin_js_1.loadGoogleSignInConfig)(env))
89005
+ return null;
89006
+ const executablePath = getFullChromiumPath();
89007
+ if (!executablePath)
89008
+ return null;
89009
+ return {
89010
+ executablePath,
89011
+ extraArgs: ["--headless=new"],
89012
+ ignoreDefaultArgs: ["--enable-automation"]
89013
+ };
89014
+ }
88833
89015
  function getMCPBrowserConfig2(opts) {
88834
89016
  const userDataDir = opts?.forceIsolated ? null : getTestUserDataDir2();
88835
89017
  const headless = isHeadless2();
@@ -88853,15 +89035,21 @@ var require_browser_config = __commonJS({
88853
89035
  };
88854
89036
  }
88855
89037
  const headlessShellPath = getHeadlessShellPath();
88856
- const useHeadlessShell = headless && headlessShellPath && !opts?.harPath;
89038
+ const googleLaunch = googleSsoCloudLaunch();
89039
+ const useHeadlessShell = headless && headlessShellPath && !opts?.harPath && !googleLaunch;
89040
+ const cloud = (0, shared_1.parseBoolFlag)(process.env.RUNNER_CLOUD);
89041
+ const args = [
89042
+ ...cloud ? exports.CLOUD_ARGS : ["--disable-blink-features=AutomationControlled"],
89043
+ ...googleLaunch?.extraArgs ?? []
89044
+ ];
88857
89045
  return {
88858
89046
  browserName: "chromium",
88859
89047
  isolated: true,
88860
89048
  launchOptions: {
88861
- headless,
88862
- ...useHeadlessShell ? { executablePath: headlessShellPath } : {},
89049
+ headless: googleLaunch ? false : headless,
89050
+ ...googleLaunch ? { executablePath: googleLaunch.executablePath, ignoreDefaultArgs: googleLaunch.ignoreDefaultArgs } : useHeadlessShell ? { executablePath: headlessShellPath } : {},
88863
89051
  channel: "",
88864
- args: exports.IS_CLOUD ? exports.CLOUD_ARGS : ["--disable-blink-features=AutomationControlled"],
89052
+ args,
88865
89053
  ...slowMo > 0 ? { slowMo } : {}
88866
89054
  },
88867
89055
  contextOptions: {
@@ -88874,15 +89062,21 @@ var require_browser_config = __commonJS({
88874
89062
  function getPlaywrightLaunchOptions2(withProfile = false, extraArgs) {
88875
89063
  const headless = isHeadless2();
88876
89064
  const slowMo = getSlowMoMs();
89065
+ const googleLaunch = googleSsoCloudLaunch();
88877
89066
  const baseArgs = exports.IS_CLOUD ? exports.CLOUD_ARGS : [
88878
89067
  "--disable-blink-features=AutomationControlled"
88879
89068
  ];
88880
- const mergedArgs = extraArgs && extraArgs.length > 0 ? [...baseArgs, ...extraArgs] : [...baseArgs];
89069
+ const mergedArgs = [
89070
+ ...baseArgs,
89071
+ ...googleLaunch?.extraArgs ?? [],
89072
+ ...extraArgs && extraArgs.length > 0 ? extraArgs : []
89073
+ ];
88881
89074
  return {
88882
- headless,
89075
+ headless: googleLaunch ? false : headless,
88883
89076
  // Use Chrome channel only when a real Chrome user profile is being loaded.
88884
89077
  // In isolated mode, bundled Chromium avoids hard dependency on Chrome installation.
88885
89078
  ...exports.IS_CLOUD || !withProfile ? {} : { channel: "chrome" },
89079
+ ...googleLaunch ? { executablePath: googleLaunch.executablePath, ignoreDefaultArgs: googleLaunch.ignoreDefaultArgs } : {},
88886
89080
  args: mergedArgs,
88887
89081
  ...slowMo > 0 ? { slowMo } : {}
88888
89082
  };
@@ -320224,6 +320418,7 @@ var require_playwright_mcp_config = __commonJS({
320224
320418
  var promises_1 = __require("fs/promises");
320225
320419
  var node_path_1 = __require("path");
320226
320420
  var browser_config_js_1 = require_browser_config();
320421
+ var google_signin_js_1 = require_google_signin();
320227
320422
  var PLAYWRIGHT_MCP_VERSION = "0.0.68";
320228
320423
  var INBOX_SECRET_ENV_KEYS = [
320229
320424
  "VERIFICATION_INBOX_HOST",
@@ -320233,7 +320428,10 @@ var require_playwright_mcp_config = __commonJS({
320233
320428
  "VERIFICATION_INBOX_PASSWORD",
320234
320429
  "VERIFICATION_INBOX_ADDRESS",
320235
320430
  "VERIFICATION_INBOX_MAILBOX",
320236
- "VERIFICATION_INBOX_EXTRA_MAILBOXES"
320431
+ "VERIFICATION_INBOX_EXTRA_MAILBOXES",
320432
+ "GOOGLE_SIGNIN_PASSWORD",
320433
+ "GOOGLE_SIGNIN_EMAIL",
320434
+ "GOOGLE_SIGNIN_TOTP_SECRET"
320237
320435
  ];
320238
320436
  function collectInboxSecretEnv() {
320239
320437
  const out = {};
@@ -320274,12 +320472,13 @@ var require_playwright_mcp_config = __commonJS({
320274
320472
  const body = cfg.format === "json" ? buildJsonConfig(cfg) : buildTomlConfig(cfg);
320275
320473
  await (0, promises_1.writeFile)(cfg.configPath, body, { encoding: "utf8", mode: 384 });
320276
320474
  if (!cfg.cdpEndpoint && browser_config_js_1.IS_CLOUD) {
320475
+ const launchOptions = (0, browser_config_js_1.getMCPBrowserConfig)({ forceIsolated: true }).launchOptions ?? {
320476
+ headless: true,
320477
+ args: [...browser_config_js_1.CLOUD_ARGS]
320478
+ };
320277
320479
  const browserConfig = {
320278
320480
  browser: {
320279
- launchOptions: {
320280
- headless: true,
320281
- args: [...browser_config_js_1.CLOUD_ARGS]
320282
- }
320481
+ launchOptions
320283
320482
  }
320284
320483
  };
320285
320484
  await (0, promises_1.writeFile)(mcpBrowserConfigPath(cfg.configPath), JSON.stringify(browserConfig, null, 2) + "\n", { encoding: "utf8", mode: 384 });
@@ -320303,7 +320502,11 @@ var require_playwright_mcp_config = __commonJS({
320303
320502
  ];
320304
320503
  if (cfg.includeCredentialServer && cfg.cdpEndpoint) {
320305
320504
  const serverJs = (0, node_path_1.join)(__dirname, "credential-mcp-server.js");
320306
- blocks.push("[mcp_servers.validateqa_credentials]", 'command = "node"', `args = ["${tomlEscape(serverJs)}"]`, "enabled = true", "startup_timeout_sec = 30", "tool_timeout_sec = 60", "", "[mcp_servers.validateqa_credentials.env]", `CDP_ENDPOINT = "${tomlEscape(cfg.cdpEndpoint)}"`, "");
320505
+ blocks.push("[mcp_servers.validateqa_credentials]", 'command = "node"', `args = ["${tomlEscape(serverJs)}"]`, "enabled = true", "startup_timeout_sec = 30", "tool_timeout_sec = 60", "", "[mcp_servers.validateqa_credentials.env]", `CDP_ENDPOINT = "${tomlEscape(cfg.cdpEndpoint)}"`);
320506
+ for (const [k, v] of Object.entries((0, google_signin_js_1.collectGoogleSignInEnv)())) {
320507
+ blocks.push(`${k} = "${tomlEscape(v)}"`);
320508
+ }
320509
+ blocks.push("");
320307
320510
  }
320308
320511
  if (cfg.includeDiscoveryServer) {
320309
320512
  if (!cfg.runDir) {
@@ -320351,7 +320554,7 @@ var require_playwright_mcp_config = __commonJS({
320351
320554
  type: "stdio",
320352
320555
  command: "node",
320353
320556
  args: [serverJs],
320354
- env: { CDP_ENDPOINT: cfg.cdpEndpoint }
320557
+ env: { CDP_ENDPOINT: cfg.cdpEndpoint, ...(0, google_signin_js_1.collectGoogleSignInEnv)() }
320355
320558
  };
320356
320559
  }
320357
320560
  if (cfg.includeDiscoveryServer) {
@@ -328558,6 +328761,7 @@ var require_discover_explorer = __commonJS({
328558
328761
  var credential_tools_js_1 = require_credential_tools();
328559
328762
  var inbox_tools_js_1 = require_inbox_tools();
328560
328763
  var verification_inbox_js_1 = require_verification_inbox();
328764
+ var google_signin_js_1 = require_google_signin();
328561
328765
  var discover_planner_js_1 = require_discover_planner();
328562
328766
  var exploration_prompt_builder_js_1 = require_exploration_prompt_builder();
328563
328767
  var ai_queue_js_1 = require_ai_queue();
@@ -328962,7 +329166,8 @@ NEVER assert: user-specific text (names, emails), counts/numbers, timestamps, ma
328962
329166
  };
328963
329167
  function buildSystemPrompt(baseUrl, variableContext, existingSiteMap, existingTestNames, options) {
328964
329168
  const browserCredentials = variableContext.allTestVariables ?? variableContext.publicTestVariables;
328965
- const { secrets: explorerSecretVars, publics: explorerPublicVarsRaw } = (0, credential_tools_js_1.partitionTestVariables)(browserCredentials);
329169
+ const { secrets: explorerSecretVarsRaw, publics: explorerPublicVarsRaw } = (0, credential_tools_js_1.partitionTestVariables)(browserCredentials);
329170
+ const explorerSecretVars = options?.inboxPrompt ? (0, google_signin_js_1.mergeGoogleSignInSecrets)(explorerSecretVarsRaw) : explorerSecretVarsRaw;
328966
329171
  const hasCredentials = Object.keys(explorerSecretVars).length > 0;
328967
329172
  const { DISCOVERY_SHOULD_REGISTER: _omitRegisterFlag, ...explorerPublicVars } = explorerPublicVarsRaw;
328968
329173
  const explorerPublicLines = (0, credential_tools_js_1.renderPublicVariablesBlock)(explorerPublicVars);
@@ -329579,10 +329784,12 @@ ${inbox_tools_js_1.EMAIL_VERIFICATION_UNAVAILABLE_OVERRIDE_BLOCK}` : ""}`;
329579
329784
  if (emailVerificationUnavailable) {
329580
329785
  logs2.push("Email verification unavailable \u2014 the agent will ATTEMPT registration once; any flow requiring an emailed code/link will be reported BLOCKED.");
329581
329786
  }
329787
+ const googleGuidance = (0, google_signin_js_1.googleSignInGuidanceOpts)();
329582
329788
  const inboxPromptBlock = inboxState ? (0, inbox_tools_js_1.buildInboxPromptBlock)({
329583
329789
  email: inboxState.email,
329584
329790
  passwordKey: inboxState.passwordKey ?? "TEST_USER_PASSWORD",
329585
- context: options?.mode
329791
+ context: options?.mode,
329792
+ ...googleGuidance
329586
329793
  }) : "";
329587
329794
  try {
329588
329795
  const { tools: mcpTools } = await mcpClient.listTools();
@@ -329603,7 +329810,8 @@ ${inbox_tools_js_1.EMAIL_VERIFICATION_UNAVAILABLE_OVERRIDE_BLOCK}` : ""}`;
329603
329810
  }
329604
329811
  const browserCredsForTools = variableContext.allTestVariables ?? variableContext.publicTestVariables;
329605
329812
  const { secrets: explorerToolSecrets } = (0, credential_tools_js_1.partitionTestVariables)(browserCredsForTools);
329606
- if (Object.keys(explorerToolSecrets).length > 0) {
329813
+ const explorerToolSecretsWithGoogle = inboxState ? (0, google_signin_js_1.mergeGoogleSignInSecrets)(explorerToolSecrets) : explorerToolSecrets;
329814
+ if (Object.keys(explorerToolSecretsWithGoogle).length > 0) {
329607
329815
  openaiTools.push(credential_tools_js_1.FILL_CREDENTIAL_TOOL, credential_tools_js_1.FILL_CREDENTIAL_FORM_TOOL);
329608
329816
  if (options?.onCredentialUpdate) {
329609
329817
  openaiTools.push(credential_tools_js_1.SET_CREDENTIAL_TOOL);
@@ -330243,8 +330451,12 @@ ${currentSummary}`;
330243
330451
  let finishBouncedThisBatch = false;
330244
330452
  let finishStreakCountedThisBatch = false;
330245
330453
  const fullVarMapForGuard = variableContext.allTestVariables ?? variableContext.publicTestVariables;
330246
- const { secrets: secretsOnlyForGuard } = (0, credential_tools_js_1.partitionTestVariables)(fullVarMapForGuard);
330247
- const allowedCredentialValues = inboxState ? [inboxState.email] : [];
330454
+ const { secrets: partitionedSecretsForGuard } = (0, credential_tools_js_1.partitionTestVariables)(fullVarMapForGuard);
330455
+ const secretsOnlyForGuard = inboxState ? (0, google_signin_js_1.mergeGoogleSignInSecrets)(partitionedSecretsForGuard) : partitionedSecretsForGuard;
330456
+ const allowedCredentialValues = [...new Set([
330457
+ ...inboxState ? [inboxState.email, inboxState.baseEmail] : [],
330458
+ ...inboxState ? (0, google_signin_js_1.googleSignInAllowedEmails)() : []
330459
+ ].filter((value) => !!value))];
330248
330460
  const secretsForLogging = Object.fromEntries(Object.entries(secretsOnlyForGuard).filter(([, value]) => !allowedCredentialValues.includes(value)));
330249
330461
  for (const toolCall of assistantMessage.tool_calls) {
330250
330462
  const toolName = toolCall.function.name;
@@ -331095,8 +331307,9 @@ Exploration complete: ${summary}`);
331095
331307
  }
331096
331308
  const fullVarMap = variableContext.allTestVariables ?? variableContext.publicTestVariables;
331097
331309
  const { secrets: dispatchSecrets } = (0, credential_tools_js_1.partitionTestVariables)(fullVarMap);
331310
+ const fillSecrets = inboxState ? (0, google_signin_js_1.mergeGoogleSignInSecrets)(dispatchSecrets) : dispatchSecrets;
331098
331311
  try {
331099
- const result = toolName === "fill_credential" ? await (0, credential_tools_js_1.handleFillCredential)(toolArgs, { mcpClient, credentials: dispatchSecrets, maxResultChars: MAX_TOOL_RESULT_CHARS }) : await (0, credential_tools_js_1.handleFillCredentialForm)(toolArgs, { mcpClient, credentials: dispatchSecrets, maxResultChars: MAX_TOOL_RESULT_CHARS });
331312
+ const result = toolName === "fill_credential" ? await (0, credential_tools_js_1.handleFillCredential)(toolArgs, { mcpClient, credentials: fillSecrets, maxResultChars: MAX_TOOL_RESULT_CHARS }) : await (0, credential_tools_js_1.handleFillCredentialForm)(toolArgs, { mcpClient, credentials: fillSecrets, maxResultChars: MAX_TOOL_RESULT_CHARS });
331100
331313
  if (result.didMutate) {
331101
331314
  lastSnapshotText = null;
331102
331315
  const codeLines = (0, exploration_parser_js_1.extractCodeLines)(result.content);
@@ -333136,7 +333349,7 @@ ${keyLines || "- (none provided)"}
333136
333349
  ## EXACTLY what to do
333137
333350
  1. Navigate to ${baseUrl} and take a \`browser_snapshot\`.
333138
333351
  2. Find the Sign Up / Register / Create account affordance (match by PURPOSE, in the app's own language) and open the signup form. If a reveal button hides the fields ("Sign up with Email"), click it first.
333139
- 3. Follow the "Account Registration (verification inbox is ENABLED)" steps below EXACTLY: call \`provision_identity\` for the email, type that email, fill the password with \`fill_credential\`, fill any other required fields with simple test values, and submit.
333352
+ 3. Follow the "Account Registration (verification inbox is ENABLED)" steps below EXACTLY: call \`provision_identity\` for the email, type that email, fill the password with \`fill_credential\`, fill any other required fields with simple test values, and submit. If there is NO email+password signup field and only "Continue with Google" / "Sign up with Gmail", follow the Google / Gmail SSO fallback in that section (bare Google account email, \`fill_credential\` with \`GOOGLE_SIGNIN_PASSWORD\`, never the IMAP app password).
333140
333353
  4. Complete email verification using the inbox tools (\`wait_for_verification\` \u2192 enter the code or \`open_verification_link\`). Re-poll if the email is slow; resend AT MOST once; NEVER register a second account.
333141
333354
  5. Confirm you are signed in \u2014 a redirect to an authenticated route, or an in-place change to authenticated content. Take a \`browser_snapshot\`.
333142
333355
  6. \`capture_page\` the authenticated landing page in its DEFAULT state, then call \`finish_exploration\`. Do this the MOMENT the account is verified and you are signed in.
@@ -333690,6 +333903,7 @@ var require_grok_survey_runner = __commonJS({
333690
333903
  var grok_cli_js_1 = require_grok_cli();
333691
333904
  var playwright_mcp_config_js_1 = require_playwright_mcp_config();
333692
333905
  var inbox_tools_js_1 = require_inbox_tools();
333906
+ var google_signin_js_1 = require_google_signin();
333693
333907
  var exploration_parser_js_1 = require_exploration_parser();
333694
333908
  var scrub_credentials_js_1 = require_scrub_credentials();
333695
333909
  var agentic_survey_prompts_js_1 = require_agentic_survey_prompts();
@@ -334214,7 +334428,7 @@ var require_grok_survey_runner = __commonJS({
334214
334428
  };
334215
334429
  const surveyAgentsMd = inboxReg ? `${(0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)()}
334216
334430
 
334217
- ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey)}` : (0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)();
334431
+ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey, (0, google_signin_js_1.googleSignInGuidanceOpts)())}` : (0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)();
334218
334432
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "AGENTS.md"), surveyAgentsMd, "utf8");
334219
334433
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "BRIEF.md"), (0, agentic_survey_prompts_js_1.buildSurveyBriefMd)(briefInput), "utf8");
334220
334434
  log2("Wrote AGENTS.md + BRIEF.md");
@@ -335621,6 +335835,7 @@ var require_grok_discovery_runner = __commonJS({
335621
335835
  var playwright_native_js_1 = require_playwright_native();
335622
335836
  var playwright_mcp_config_js_1 = require_playwright_mcp_config();
335623
335837
  var inbox_tools_js_1 = require_inbox_tools();
335838
+ var google_signin_js_1 = require_google_signin();
335624
335839
  var scrub_credentials_js_1 = require_scrub_credentials();
335625
335840
  var grok_survey_runner_js_1 = require_grok_survey_runner();
335626
335841
  var agentic_discovery_prompts_js_1 = require_agentic_discovery_prompts();
@@ -335914,7 +336129,7 @@ var require_grok_discovery_runner = __commonJS({
335914
336129
  };
335915
336130
  const discoveryAgentsMd = inboxReg ? `${(0, agentic_discovery_prompts_js_1.buildDiscoveryAgentsMd)()}
335916
336131
 
335917
- ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey)}` : (0, agentic_discovery_prompts_js_1.buildDiscoveryAgentsMd)();
336132
+ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey, (0, google_signin_js_1.googleSignInGuidanceOpts)())}` : (0, agentic_discovery_prompts_js_1.buildDiscoveryAgentsMd)();
335918
336133
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "AGENTS.md"), discoveryAgentsMd, "utf8");
335919
336134
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "BRIEF.md"), (0, agentic_discovery_prompts_js_1.buildDiscoveryBriefMd)(briefInput), "utf8");
335920
336135
  await (0, promises_1.mkdir)(testsDirPath, { recursive: true });
@@ -336867,7 +337082,7 @@ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwo
336867
337082
 
336868
337083
  ---
336869
337084
 
336870
- ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxRegV2.email, inboxRegV2.passwordKey)}` : "");
337085
+ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxRegV2.email, inboxRegV2.passwordKey, (0, google_signin_js_1.googleSignInGuidanceOpts)())}` : "");
336871
337086
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "AGENTS.md"), agentsMd, "utf8");
336872
337087
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "BRIEF.md"), (0, agentic_discovery_prompts_js_1.buildDiscoveryBriefMd)(briefInput), "utf8");
336873
337088
  await (0, promises_1.mkdir)(testsDirPath, { recursive: true });
@@ -337839,6 +338054,7 @@ var require_claude_survey_runner = __commonJS({
337839
338054
  var claude_stream_parser_js_1 = require_claude_stream_parser();
337840
338055
  var playwright_mcp_config_js_1 = require_playwright_mcp_config();
337841
338056
  var inbox_tools_js_1 = require_inbox_tools();
338057
+ var google_signin_js_1 = require_google_signin();
337842
338058
  var scrub_credentials_js_1 = require_scrub_credentials();
337843
338059
  var agentic_cli_constants_js_1 = require_agentic_cli_constants();
337844
338060
  var grok_survey_runner_js_1 = require_grok_survey_runner();
@@ -337939,7 +338155,7 @@ ${preview}`);
337939
338155
  };
337940
338156
  const surveyAgentsMd = inboxReg ? `${(0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)({ canvasMode })}
337941
338157
 
337942
- ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey)}` : (0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)({ canvasMode });
338158
+ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey, (0, google_signin_js_1.googleSignInGuidanceOpts)())}` : (0, agentic_survey_prompts_js_1.buildSurveyAgentsMd)({ canvasMode });
337943
338159
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "AGENTS.md"), surveyAgentsMd, "utf8");
337944
338160
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "BRIEF.md"), (0, agentic_survey_prompts_js_1.buildSurveyBriefMd)(briefInput), "utf8");
337945
338161
  log2("Wrote AGENTS.md + BRIEF.md");
@@ -338649,6 +338865,7 @@ var require_claude_discovery_runner = __commonJS({
338649
338865
  var claude_cli_js_1 = require_claude_cli();
338650
338866
  var playwright_mcp_config_js_1 = require_playwright_mcp_config();
338651
338867
  var inbox_tools_js_1 = require_inbox_tools();
338868
+ var google_signin_js_1 = require_google_signin();
338652
338869
  var coverage_examples_content_js_1 = require_coverage_examples_content();
338653
338870
  var scrub_credentials_js_1 = require_scrub_credentials();
338654
338871
  var agentic_cli_constants_js_1 = require_agentic_cli_constants();
@@ -338817,7 +339034,7 @@ var require_claude_discovery_runner = __commonJS({
338817
339034
  };
338818
339035
  const explorerContractMd = inboxReg ? `${(0, agentic_discovery_prompts_js_1.buildExplorerContractMd)(contractInput)}
338819
339036
 
338820
- ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey)}` : (0, agentic_discovery_prompts_js_1.buildExplorerContractMd)(contractInput);
339037
+ ${(0, inbox_tools_js_1.buildInboxAgentsGuidance)(inboxReg.email, inboxReg.passwordKey, (0, google_signin_js_1.googleSignInGuidanceOpts)())}` : (0, agentic_discovery_prompts_js_1.buildExplorerContractMd)(contractInput);
338821
339038
  await (0, promises_1.writeFile)(claudeMdPath, explorerContractMd, "utf8");
338822
339039
  await (0, promises_1.writeFile)((0, node_path_1.join)(runDir, "BRIEF.md"), (0, agentic_discovery_prompts_js_1.buildDiscoveryBriefMd)(briefInput), "utf8");
338823
339040
  await (0, promises_1.mkdir)(testsDirPath, { recursive: true });
@@ -356074,7 +356291,7 @@ var require_package4 = __commonJS({
356074
356291
  "package.json"(exports, module) {
356075
356292
  module.exports = {
356076
356293
  name: "@validate.qa/runner",
356077
- version: "1.0.92",
356294
+ version: "1.0.93",
356078
356295
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
356079
356296
  bin: {
356080
356297
  "validate-runner": "dist/cli.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@validate.qa/runner",
3
- "version": "1.0.92",
3
+ "version": "1.0.93",
4
4
  "description": "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
5
5
  "bin": {
6
6
  "validate-runner": "dist/cli.js"