@validate.qa/runner 1.0.45 → 1.0.46

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 +78 -41
  2. package/dist/cli.mjs +78 -41
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -5243,6 +5243,28 @@ var init_feature_flags = __esm({
5243
5243
  }
5244
5244
  });
5245
5245
 
5246
+ // ../shared/dist/env-flags.js
5247
+ function parseBoolFlag(value, defaultValue = false) {
5248
+ if (value == null)
5249
+ return defaultValue;
5250
+ const v = value.trim().toLowerCase();
5251
+ if (v === "")
5252
+ return defaultValue;
5253
+ if (TRUTHY.has(v))
5254
+ return true;
5255
+ if (FALSY.has(v))
5256
+ return false;
5257
+ return defaultValue;
5258
+ }
5259
+ var TRUTHY, FALSY;
5260
+ var init_env_flags = __esm({
5261
+ "../shared/dist/env-flags.js"() {
5262
+ "use strict";
5263
+ TRUTHY = /* @__PURE__ */ new Set(["true", "1", "yes", "on"]);
5264
+ FALSY = /* @__PURE__ */ new Set(["false", "0", "no", "off"]);
5265
+ }
5266
+ });
5267
+
5246
5268
  // ../shared/dist/index.js
5247
5269
  var dist_exports = {};
5248
5270
  __export(dist_exports, {
@@ -5395,6 +5417,7 @@ __export(dist_exports, {
5395
5417
  normalizeTtsVoiceId: () => normalizeTtsVoiceId,
5396
5418
  otherMobilePlatform: () => otherMobilePlatform,
5397
5419
  parenDepthDelta: () => parenDepthDelta,
5420
+ parseBoolFlag: () => parseBoolFlag,
5398
5421
  pickDisplayRun: () => pickDisplayRun,
5399
5422
  pickLatestHealthRun: () => pickLatestHealthRun,
5400
5423
  placeholderizeRecordedMobileAction: () => placeholderizeRecordedMobileAction,
@@ -5450,6 +5473,7 @@ var init_dist = __esm({
5450
5473
  init_redact_needles();
5451
5474
  init_voice_config();
5452
5475
  init_feature_flags();
5476
+ init_env_flags();
5453
5477
  }
5454
5478
  });
5455
5479
 
@@ -6093,12 +6117,13 @@ var require_global_ai_slot_client = __commonJS({
6093
6117
  exports2.acquireGlobalAiSlot = acquireGlobalAiSlot;
6094
6118
  exports2.releaseGlobalAiSlot = releaseGlobalAiSlot;
6095
6119
  var crypto_1 = require("crypto");
6120
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
6096
6121
  var SERVER_URL = (process.env.SERVER_URL ?? "").replace(/\/$/, "");
6097
6122
  var AUTH_TOKEN = process.env.AUTH_TOKEN || process.env.RUNNER_TOKEN || "";
6098
6123
  var HOLDER = process.env.RUN_ID || `task-${(0, crypto_1.randomUUID)().slice(0, 8)}`;
6099
6124
  var ACQUIRE_HTTP_TIMEOUT_MS = 8e3;
6100
6125
  function isEnabled() {
6101
- return (process.env.GLOBAL_AI_LIMITER_ENABLED ?? "").trim().toLowerCase() === "true" && SERVER_URL.length > 0 && AUTH_TOKEN.length > 0;
6126
+ return (0, shared_1.parseBoolFlag)(process.env.GLOBAL_AI_LIMITER_ENABLED) && SERVER_URL.length > 0 && AUTH_TOKEN.length > 0;
6102
6127
  }
6103
6128
  function maxWaitMs() {
6104
6129
  const raw = process.env.GLOBAL_AI_ACQUIRE_MAX_WAIT_MS;
@@ -67508,6 +67533,7 @@ var require_snapshot_parser = __commonJS({
67508
67533
  exports2.detectSessionState = detectSessionState;
67509
67534
  exports2.detectReadinessSignals = detectReadinessSignals;
67510
67535
  exports2.detectViewportHints = detectViewportHints;
67536
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
67511
67537
  var INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
67512
67538
  "textbox",
67513
67539
  "searchbox",
@@ -67688,7 +67714,7 @@ var require_snapshot_parser = __commonJS({
67688
67714
  return e.name;
67689
67715
  }
67690
67716
  function parseSnapshot(snapshotText, options = {}) {
67691
- const richParse = options.richParse ?? process.env.DISCOVERY_SNAPSHOT_RICH_PARSE === "true";
67717
+ const richParse = options.richParse ?? (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_SNAPSHOT_RICH_PARSE);
67692
67718
  const lines = snapshotText.split("\n");
67693
67719
  const elements = [];
67694
67720
  const liveMessages = [];
@@ -68600,6 +68626,7 @@ var require_discover_ai_planner = __commonJS({
68600
68626
  exports2.validateAIPlannerOutput = validateAIPlannerOutput;
68601
68627
  exports2.buildFallbackPlan = buildFallbackPlan;
68602
68628
  exports2.runAIPlanner = runAIPlanner;
68629
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
68603
68630
  var ai_provider_js_1 = require_ai_provider();
68604
68631
  var ai_queue_js_1 = require_ai_queue();
68605
68632
  var ai_retry_js_1 = require_ai_retry();
@@ -69878,7 +69905,7 @@ Keep the exact JSON schema { "featureGroups":[...], "scenarios":[...], "reasonin
69878
69905
  async function runAIPlanner(siteMap, evidence, context, options) {
69879
69906
  const logs2 = [];
69880
69907
  const failurePlan = (kind, reason, legacyFallback2) => {
69881
- const noFallback = context.mode === "survey" && process.env.DISCOVERY_PLANNER_NO_FALLBACK === "true";
69908
+ const noFallback = context.mode === "survey" && (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_PLANNER_NO_FALLBACK);
69882
69909
  if (noFallback) {
69883
69910
  logs2.push(`Planner ${kind} \u2014 NO-FALLBACK: failing survey cleanly instead of fabricating slug features (${reason})`);
69884
69911
  return {
@@ -70265,7 +70292,7 @@ ${JSON.stringify(gatePlan)}`;
70265
70292
  }
70266
70293
  if (context.mode === "survey" && featureGroups.length === 0 && siteMap.pages.length > 0) {
70267
70294
  const hasGroupWorthyEvidence = siteMap.pages.some((p) => (p.forms?.length ?? 0) > 0 || (p.elements?.length ?? 0) > 0);
70268
- const noFallback = process.env.DISCOVERY_PLANNER_NO_FALLBACK === "true";
70295
+ const noFallback = (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_PLANNER_NO_FALLBACK);
70269
70296
  if (noFallback && !hasGroupWorthyEvidence) {
70270
70297
  return {
70271
70298
  scenarios,
@@ -75514,7 +75541,8 @@ var require_browser_config = __commonJS({
75514
75541
  var promises_1 = require("fs/promises");
75515
75542
  var path_1 = require("path");
75516
75543
  var os_1 = require("os");
75517
- exports2.IS_CLOUD = process.env.RUNNER_CLOUD === "true";
75544
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
75545
+ exports2.IS_CLOUD = (0, shared_1.parseBoolFlag)(process.env.RUNNER_CLOUD);
75518
75546
  exports2.CLOUD_ARGS = [
75519
75547
  "--no-sandbox",
75520
75548
  "--disable-setuid-sandbox",
@@ -75656,7 +75684,7 @@ var require_browser_config = __commonJS({
75656
75684
  }
75657
75685
  }
75658
75686
  function isHeadless2() {
75659
- return exports2.IS_CLOUD || process.env.PLAYWRIGHT_HEADLESS === "true" || process.env.NODE_ENV === "production";
75687
+ return exports2.IS_CLOUD || (0, shared_1.parseBoolFlag)(process.env.PLAYWRIGHT_HEADLESS) || process.env.NODE_ENV === "production";
75660
75688
  }
75661
75689
  function getSlowMoMs() {
75662
75690
  const raw = process.env.PLAYWRIGHT_SLOWMO;
@@ -76728,7 +76756,7 @@ var require_playwright_native = __commonJS({
76728
76756
  Object.defineProperty(exports2, "scrubHarRequestBody", { enumerable: true, get: function() {
76729
76757
  return api_call_redaction_js_2.scrubHarRequestBody;
76730
76758
  } });
76731
- var IS_CLOUD2 = process.env.RUNNER_CLOUD === "true";
76759
+ var IS_CLOUD2 = (0, shared_1.parseBoolFlag)(process.env.RUNNER_CLOUD);
76732
76760
  var PACKAGE_DIR = (0, path_1.resolve)(__dirname, "..", "..");
76733
76761
  var RUNS_DIR = process.env.RUNS_DIR || (0, path_1.join)(PACKAGE_DIR, ".qa-runs");
76734
76762
  var PW_CLI = require.resolve("@playwright/test/cli");
@@ -76972,7 +77000,7 @@ test.afterEach(async ({ page }, testInfo) => {
76972
77000
  if (useScopedApiHeaders && resolvedExtraHeaders) {
76973
77001
  await (0, promises_1.writeFile)((0, path_1.join)(runDir, "qa-api-fixtures.ts"), (0, api_auth_headers_js_1.buildOriginScopedApiFixtures)(resolvedExtraHeaders, baseUrl));
76974
77002
  }
76975
- const headless = process.env.PLAYWRIGHT_HEADLESS === "true" || process.env.NODE_ENV === "production" || IS_CLOUD2;
77003
+ const headless = (0, shared_1.parseBoolFlag)(process.env.PLAYWRIGHT_HEADLESS) || process.env.NODE_ENV === "production" || IS_CLOUD2;
76976
77004
  logs2.push(`\u2699\uFE0F Config: baseURL=${JSON.stringify(baseUrl)}, headless=${headless}${isApiTest2 ? ", API mode (no screenshot/video)" : ""}`);
76977
77005
  const absTestDir = runDir.replace(/\\/g, "/");
76978
77006
  const absResultsFile = (0, path_1.join)(runDir, "results.json").replace(/\\/g, "/");
@@ -78678,6 +78706,7 @@ var require_instrumented_context = __commonJS({
78678
78706
  var mcp_1 = require("@playwright/mcp");
78679
78707
  var index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
78680
78708
  var inMemory_js_1 = require("@modelcontextprotocol/sdk/inMemory.js");
78709
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
78681
78710
  var browser_config_js_1 = require_browser_config();
78682
78711
  var health_observer_js_1 = require_health_observer();
78683
78712
  var live_network_collector_js_1 = require_live_network_collector();
@@ -78695,7 +78724,7 @@ var require_instrumented_context = __commonJS({
78695
78724
  var OWNED_BROWSER_CLOSE_TIMEOUT_MS = intEnv("INSTRUMENTED_OWNED_BROWSER_CLOSE_TIMEOUT_MS", 1e4);
78696
78725
  var CLEANUP_TIMEOUT_MS = intEnv("INSTRUMENTED_CLEANUP_TIMEOUT_MS", 1e4);
78697
78726
  function liveCaptureAllowed(mode) {
78698
- if ((process.env.LIVE_NETWORK_COLLECTOR_ENABLED ?? "").toLowerCase() !== "true")
78727
+ if (!(0, shared_1.parseBoolFlag)(process.env.LIVE_NETWORK_COLLECTOR_ENABLED))
78699
78728
  return false;
78700
78729
  if (!mode)
78701
78730
  return false;
@@ -79158,6 +79187,7 @@ var require_snapshot_observation = __commonJS({
79158
79187
  exports2.qualifyElementLabel = qualifyElementLabel;
79159
79188
  exports2.isConsentOverlayElement = isConsentOverlayElement;
79160
79189
  var snapshot_parser_js_1 = require_snapshot_parser();
79190
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
79161
79191
  var GENERIC_LABEL_RE = /^(input field|textbox|button|link|item|field|value|tab)$/i;
79162
79192
  var NOISE_LABEL_RE = /^(skip\s+to|skip\s+nav|back\s+to\s+top|cookie|accept\s+(all\s+)?cookies)$/i;
79163
79193
  var CONSENT_OVERLAY_LABEL_RE = /\bcookies?\b|\bgdpr\b|\bconsent\b|privacy (?:policy|preferences|settings)/i;
@@ -79490,8 +79520,8 @@ var require_snapshot_observation = __commonJS({
79490
79520
  const metrics = page.snapshotMetrics ?? page.snapshotArtifact?.metrics;
79491
79521
  const sourceKind = page.snapshotMeta?.sourceKind ?? page.snapshotArtifact?.sourceKind ?? "missing";
79492
79522
  const artifact = page.snapshotArtifact;
79493
- const richRender = options.richRender ?? process.env.DISCOVERY_SNAPSHOT_RICH_RENDER === "true";
79494
- const rowActionCensus = richRender && options.mode !== "survey" && (options.rowActionCensus ?? process.env.DISCOVERY_SNAPSHOT_ROW_CENSUS === "true");
79523
+ const richRender = options.richRender ?? (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_SNAPSHOT_RICH_RENDER);
79524
+ const rowActionCensus = richRender && options.mode !== "survey" && (options.rowActionCensus ?? (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_SNAPSHOT_ROW_CENSUS));
79495
79525
  const activeScope = inferActiveSnapshotScope(page);
79496
79526
  const ranked = rankSnapshotElements(getScopedSnapshotElements(page, activeScope), withScopeContext({ ...context, richRank: richRender }, activeScope));
79497
79527
  const allInteractive = ranked.filter(({ element }) => isInteractiveCandidate(element)).filter(({ element }) => {
@@ -80373,6 +80403,7 @@ var require_snapshot_context_compactor = __commonJS({
80373
80403
  exports2.compactSnapshotMessages = compactSnapshotMessages;
80374
80404
  exports2.formatSnapshotCompactionLog = formatSnapshotCompactionLog;
80375
80405
  var crypto_1 = require("crypto");
80406
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
80376
80407
  var DEFAULT_MAX_TOOL_RESULT_CHARS = 15e3;
80377
80408
  var DEFAULT_MAX_DUPLICATE_SNAPSHOT_CHARS = 1400;
80378
80409
  var DEFAULT_MAX_TOTAL_SNAPSHOT_CHARS = 45e3;
@@ -80382,7 +80413,7 @@ var require_snapshot_context_compactor = __commonJS({
80382
80413
  maxSnapshotChars: options.maxSnapshotChars ?? DEFAULT_MAX_TOOL_RESULT_CHARS,
80383
80414
  maxDuplicateSnapshotChars: options.maxDuplicateSnapshotChars ?? DEFAULT_MAX_DUPLICATE_SNAPSHOT_CHARS,
80384
80415
  maxTotalSnapshotChars: options.maxTotalSnapshotChars ?? DEFAULT_MAX_TOTAL_SNAPSHOT_CHARS,
80385
- compactStructuredJson: options.compactStructuredJson ?? process.env.DISCOVERY_SNAPSHOT_STRUCTURED_COMPACT !== "false"
80416
+ compactStructuredJson: options.compactStructuredJson ?? (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_SNAPSHOT_STRUCTURED_COMPACT, true)
80386
80417
  };
80387
80418
  }
80388
80419
  function extractSnapshotBlock(content) {
@@ -88423,14 +88454,14 @@ Do NOT add steps you did not execute. Do NOT skip steps from the recording.${led
88423
88454
  revealedControls,
88424
88455
  // Opt-in additive-contradiction gate (see assertion-strength.ts). On Fargate this
88425
88456
  // env must be dispatcher-forwarded to take effect here; off → byte-identical.
88426
- flagContradictedAdditions: process.env.STRENGTH_ADDITIVE_CONTRADICTION_GATE === "true"
88457
+ flagContradictedAdditions: (0, shared_1.parseBoolFlag)(process.env.STRENGTH_ADDITIVE_CONTRADICTION_GATE)
88427
88458
  });
88428
88459
  } catch (err) {
88429
88460
  logs2.push(` Strength gate errored \u2014 skipping (fail-open): ${String(err)}`);
88430
88461
  }
88431
88462
  const verifyCallsSinceLastFinish = verifyCallCount - verifyCallsAtLastFinishGenerate;
88432
88463
  verifyCallsAtLastFinishGenerate = verifyCallCount;
88433
- const bugWitnessEnabled = process.env.DISCOVERY_BUG_WITNESS_ENABLED === "true";
88464
+ const bugWitnessEnabled = (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_BUG_WITNESS_ENABLED);
88434
88465
  const bugWitnessVerdict = bugWitnessEnabled ? resolveSuspectedBugVerdict(suspectedBugDeclared, bugDescription, verifyCallsSinceLastFinish, strengthVerdict?.signals) : null;
88435
88466
  if (bugWitnessVerdict) {
88436
88467
  strengthVerdict = bugWitnessVerdict;
@@ -305687,11 +305718,12 @@ var require_bootstrap_grok_auth = __commonJS({
305687
305718
  exports2.seedGrokMcpConfigIfNeeded = seedGrokMcpConfigIfNeeded;
305688
305719
  var node_fs_1 = __importDefault(require("fs"));
305689
305720
  var node_path_1 = __importDefault(require("path"));
305721
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
305690
305722
  function seedGrokAuthIfNeeded() {
305691
305723
  const home = process.env.HOME ?? "/home/appuser";
305692
305724
  const authPath = node_path_1.default.join(home, ".grok", "auth.json");
305693
305725
  const b64 = process.env.GROK_AUTH_JSON_B64;
305694
- const force = process.env.GROK_AUTH_FORCE_RESEED === "true" || process.env.GROK_AUTH_FORCE_RESEED === "1";
305726
+ const force = (0, shared_1.parseBoolFlag)(process.env.GROK_AUTH_FORCE_RESEED) || process.env.GROK_AUTH_FORCE_RESEED === "1";
305695
305727
  if (!force && node_fs_1.default.existsSync(authPath)) {
305696
305728
  return;
305697
305729
  }
@@ -307081,7 +307113,7 @@ Output the JSON envelope exactly ONCE as your final message, then exit.`;
307081
307113
  return (0, shared_1.buildSanitizedAgentEnv)({ extra });
307082
307114
  }
307083
307115
  async function runGrokHealSession(opts) {
307084
- const subagentsEnabled = (process.env.GROK_HEAL_SUBAGENTS ?? "").toLowerCase() === "true";
307116
+ const subagentsEnabled = (0, shared_1.parseBoolFlag)(process.env.GROK_HEAL_SUBAGENTS);
307085
307117
  const args = [
307086
307118
  "-p",
307087
307119
  'Read BRIEF.md in this directory. Heal TEST_UNDER_HEAL.spec.ts as instructed. Your FINAL assistant message MUST be ONLY a JSON object \u2014 no prose around it \u2014 with this shape: {"verdict":"fix|app_bug|config_issue|prereq_unmet|state_stale|test_invalid","playwrightCode":"<full file if verdict=fix>","changeDescription":"<one sentence>","reason":"<terse, when not fix>","confidence":"high|medium|low"}',
@@ -312860,6 +312892,7 @@ var require_discover_explorer = __commonJS({
312860
312892
  var ai_provider_js_1 = require_ai_provider();
312861
312893
  var snapshot_parser_js_1 = require_snapshot_parser();
312862
312894
  var scrub_credentials_js_1 = require_scrub_credentials();
312895
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
312863
312896
  var credential_tools_js_1 = require_credential_tools();
312864
312897
  var inbox_tools_js_1 = require_inbox_tools();
312865
312898
  var verification_inbox_js_1 = require_verification_inbox();
@@ -313635,7 +313668,7 @@ ${credentialBlock}${redactedBlock}${inboxBlock}`;
313635
313668
  const collectedPages = [];
313636
313669
  const collectedTransitions = [];
313637
313670
  const observedOriginCounts = /* @__PURE__ */ new Map();
313638
- const captureOriginSignals = (process.env.APP_ORIGIN_RESOLUTION ?? "").toLowerCase() === "true";
313671
+ const captureOriginSignals = (0, shared_1.parseBoolFlag)(process.env.APP_ORIGIN_RESOLUTION);
313639
313672
  const buildObservedOrigins = () => [...observedOriginCounts.entries()].sort((a, b) => b[1] - a[1]).map(([o]) => o);
313640
313673
  logs2.push(`Explorer starting - provider: ${provider}, model: ${agentModel}`);
313641
313674
  logs2.push(`Base URL: ${baseUrl}`);
@@ -313657,7 +313690,7 @@ ${credentialBlock}${redactedBlock}${inboxBlock}`;
313657
313690
  const v3Env = process.env.DISCOVERY_PROMPT_V3;
313658
313691
  const useV3 = v3Env !== "false";
313659
313692
  const useV2 = true;
313660
- const perceptionEnricherEnabled = (process.env.DISCOVERY_PERCEPTION_ENRICHER === "true" || process.env.DISCOVERY_PERCEPTION_ENRICHER === "1") && typeof options?.getPerceptionPage === "function";
313693
+ const perceptionEnricherEnabled = ((0, shared_1.parseBoolFlag)(process.env.DISCOVERY_PERCEPTION_ENRICHER) || process.env.DISCOVERY_PERCEPTION_ENRICHER === "1") && typeof options?.getPerceptionPage === "function";
313661
313694
  const linkFrontierEnabled = (0, survey_link_frontier_js_1.isSurveyLinkFrontierEnabled)() && options?.mode === "survey";
313662
313695
  const linkScope = (0, survey_link_frontier_js_1.deriveLinkScope)(baseUrl);
313663
313696
  let finishRedirects = 0;
@@ -313812,7 +313845,7 @@ ${inboxPromptBlock}`;
313812
313845
  let lastBriefRoute = "";
313813
313846
  let lastBriefIteration = 0;
313814
313847
  const BRIEF_INTERVAL = 5;
313815
- const stuckDetectorEnabled = process.env.DISCOVERY_STUCK_DETECTOR === "1" || process.env.DISCOVERY_STUCK_DETECTOR === "true";
313848
+ const stuckDetectorEnabled = process.env.DISCOVERY_STUCK_DETECTOR === "1" || (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_STUCK_DETECTOR);
313816
313849
  const stuckDetector = stuckDetectorEnabled ? new stuck_detector_js_1.StuckDetector({ repetitionReachesRecovery: !isDeepMode }) : null;
313817
313850
  while (iteration < maxIterations && !explorationComplete) {
313818
313851
  iteration++;
@@ -318022,6 +318055,7 @@ var require_discovery_verify_pool = __commonJS({
318022
318055
  var node_path_1 = require("path");
318023
318056
  var playwright_native_js_1 = require_playwright_native();
318024
318057
  var scrub_credentials_js_1 = require_scrub_credentials();
318058
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
318025
318059
  var discover_generator_js_1 = require_discover_generator();
318026
318060
  var canvas_detector_js_1 = require_canvas_detector();
318027
318061
  var agentic_discovery_prompts_js_1 = require_agentic_discovery_prompts();
@@ -318681,7 +318715,7 @@ var require_discovery_verify_pool = __commonJS({
318681
318715
  log2(`ledger: persisted ${scenarioLedgers.size} ledger file(s) to ${ledgerDir}`);
318682
318716
  }
318683
318717
  function startAuthoredWatcher(args) {
318684
- if (process.env.DISCOVERY_AUTHORED_STREAMING !== "true") {
318718
+ if (!(0, shared_1.parseBoolFlag)(process.env.DISCOVERY_AUTHORED_STREAMING)) {
318685
318719
  return { stop: () => {
318686
318720
  }, count: () => 0 };
318687
318721
  }
@@ -319085,6 +319119,7 @@ var require_grok_discovery_runner = __commonJS({
319085
319119
  var node_fs_1 = require("fs");
319086
319120
  var node_os_1 = require("os");
319087
319121
  var node_path_1 = require("path");
319122
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
319088
319123
  var instrumented_context_js_1 = require_instrumented_context();
319089
319124
  var exploration_parser_js_1 = require_exploration_parser();
319090
319125
  var bootstrap_grok_auth_js_1 = require_bootstrap_grok_auth();
@@ -319115,7 +319150,7 @@ var require_grok_discovery_runner = __commonJS({
319115
319150
  var DEFAULT_TARGET = { min: 6, max: 15 };
319116
319151
  var WATCHER_DEBOUNCE_MS = 500;
319117
319152
  var MAX_PLAN_REVISIONS = 3;
319118
- var LEGACY_PLAN_MODE = process.env.USE_LEGACY_GROK_DISCOVERY === "true";
319153
+ var LEGACY_PLAN_MODE = (0, shared_1.parseBoolFlag)(process.env.USE_LEGACY_GROK_DISCOVERY);
319119
319154
  var SNAPSHOT_EXCERPT_CHARS = 150;
319120
319155
  function isObject(v) {
319121
319156
  return typeof v === "object" && v !== null && !Array.isArray(v);
@@ -319266,7 +319301,7 @@ var require_grok_discovery_runner = __commonJS({
319266
319301
  return out;
319267
319302
  }
319268
319303
  async function runGrokDiscoveryOnRunner(ctx, callbackOptions, options = {}) {
319269
- if (process.env.USE_GROK_DISCOVERY_V2 === "true") {
319304
+ if ((0, shared_1.parseBoolFlag)(process.env.USE_GROK_DISCOVERY_V2)) {
319270
319305
  return runGrokDiscoveryV2OnRunner(ctx, callbackOptions, options);
319271
319306
  }
319272
319307
  const featureName = ctx.featureName ?? "Untitled Feature";
@@ -321738,6 +321773,7 @@ var require_tool_ledger = __commonJS({
321738
321773
  var promises_1 = require("fs/promises");
321739
321774
  var node_crypto_1 = require("crypto");
321740
321775
  var node_path_1 = require("path");
321776
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
321741
321777
  var OTHER_OUTPUT_PREVIEW_CAP = 1024;
321742
321778
  var DEFAULT_SNAPSHOT_BYTES_CAP = 16 * 1024;
321743
321779
  var KNOWN_CREDENTIAL_BEARING_TOOLS = /* @__PURE__ */ new Set([
@@ -321819,7 +321855,7 @@ var require_tool_ledger = __commonJS({
321819
321855
  let seq = 0;
321820
321856
  let turn = 0;
321821
321857
  let lastNavigateUrl = null;
321822
- const redact = opts.redact ?? process.env.DISCOVERY_LEDGER_REDACT === "true";
321858
+ const redact = opts.redact ?? (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_LEDGER_REDACT);
321823
321859
  const credentialEnvMap = opts.credentialEnvMap ?? /* @__PURE__ */ new Map();
321824
321860
  const maxSnapshotBytes = opts.maxSnapshotBytes ?? DEFAULT_SNAPSHOT_BYTES_CAP;
321825
321861
  const sessionId = (0, node_crypto_1.randomUUID)();
@@ -323440,6 +323476,7 @@ var require_discover_agent = __commonJS({
323440
323476
  var ai_queue_js_1 = require_ai_queue();
323441
323477
  var ai_retry_js_1 = require_ai_retry();
323442
323478
  var strip_json_fences_js_1 = require_strip_json_fences();
323479
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
323443
323480
  var discover_explorer_js_1 = require_discover_explorer();
323444
323481
  var discover_feature_explorer_js_1 = require_discover_feature_explorer();
323445
323482
  var discover_planner_js_1 = require_discover_planner();
@@ -323533,7 +323570,7 @@ var require_discover_agent = __commonJS({
323533
323570
  }
323534
323571
  function describeRunnerRuntime(launchOpts) {
323535
323572
  const browserMode = launchOpts?.headless === true ? "headless" : launchOpts?.headless === false ? "headed" : "default";
323536
- const runtime = process.env.RUNNER_CLOUD === "true" ? "cloud runner" : "local runner";
323573
+ const runtime = (0, shared_1.parseBoolFlag)(process.env.RUNNER_CLOUD) ? "cloud runner" : "local runner";
323537
323574
  return `Runtime: ${runtime}, browser mode: ${browserMode}`;
323538
323575
  }
323539
323576
  function formatElapsed(ms) {
@@ -323680,7 +323717,7 @@ Respond with ONLY valid JSON:
323680
323717
  }
323681
323718
  var AUTH_CAPTURE_TIMEOUT_MS = 4 * 60 * 1e3;
323682
323719
  function maybeStartLoginCaptureRun(ctx, callbackOptions, onAICall, pushLog, onObservedOrigins) {
323683
- if (process.env.AUTH_RECIPE_STAMP !== "true")
323720
+ if (!(0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP))
323684
323721
  return null;
323685
323722
  if (ctx.authRecipe) {
323686
323723
  pushLog(`auth-prologue: reusing persisted login recipe ${ctx.authRecipe.recipeHash} \u2014 skipping capture`);
@@ -323766,7 +323803,7 @@ Respond with ONLY valid JSON:
323766
323803
  if (canvasPreflight.probeRan) {
323767
323804
  ctx.appRenderType = canvasPreflight.renderType;
323768
323805
  }
323769
- const useNativeOverride = process.env.USE_NATIVE_SURVEY === "true";
323806
+ const useNativeOverride = (0, shared_1.parseBoolFlag)(process.env.USE_NATIVE_SURVEY);
323770
323807
  const surveyEngine = (0, agentic_cli_constants_js_1.getAgenticEngine)(ctx.exploreModel);
323771
323808
  if (isSurvey && surveyEngine !== "native" && !useNativeOverride) {
323772
323809
  logs2.push(`exploreModel=${ctx.exploreModel} \u2192 routing to ${surveyEngine} survey runner`);
@@ -323983,8 +324020,8 @@ Explore complete: ${exploreResult.pagesDiscovered} pages, ${exploreResult.elemen
323983
324020
  // Recipe-aware planning: when a verified login recipe is on file, the planner
323984
324021
  // plans @needs-auth (non-auth-flow) scenarios from the authenticated state
323985
324022
  // instead of authoring landing→login steps (which generate would override).
323986
- authRecipeAvailable: process.env.AUTH_RECIPE_STAMP === "true" && !!ctx.authRecipe,
323987
- authRedirectRoute: process.env.AUTH_RECIPE_STAMP === "true" ? ctx.authRecipe?.redirectRoute ?? void 0 : void 0,
324023
+ authRecipeAvailable: (0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP) && !!ctx.authRecipe,
324024
+ authRedirectRoute: (0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP) ? ctx.authRecipe?.redirectRoute ?? void 0 : void 0,
323988
324025
  testBudget
323989
324026
  }, {
323990
324027
  modelOverride: ctx.planModel ?? ctx.generateModel,
@@ -324291,7 +324328,7 @@ Fatal error: ${msg}`);
324291
324328
  if (canvasPreflight.probeRan) {
324292
324329
  ctx.appRenderType = canvasPreflight.renderType;
324293
324330
  }
324294
- const useNativeDeepOverride = process.env.USE_NATIVE_DEEP === "true";
324331
+ const useNativeDeepOverride = (0, shared_1.parseBoolFlag)(process.env.USE_NATIVE_DEEP);
324295
324332
  const deepEngine = (0, agentic_cli_constants_js_1.getAgenticEngine)(ctx.exploreModel);
324296
324333
  if (deepEngine !== "native" && !useNativeDeepOverride) {
324297
324334
  logs2.push(`exploreModel=${ctx.exploreModel} \u2192 routing to ${deepEngine} deep discovery runner`);
@@ -324562,8 +324599,8 @@ Plan (reused): ${resumeSavedScenarios.length} scenarios from the paused run.`);
324562
324599
  },
324563
324600
  // Recipe-aware planning (feature/deep): plan @needs-auth scenarios from the
324564
324601
  // authenticated state when a verified login recipe is on file for this project.
324565
- authRecipeAvailable: process.env.AUTH_RECIPE_STAMP === "true" && !!ctx.authRecipe,
324566
- authRedirectRoute: process.env.AUTH_RECIPE_STAMP === "true" ? ctx.authRecipe?.redirectRoute ?? void 0 : void 0,
324602
+ authRecipeAvailable: (0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP) && !!ctx.authRecipe,
324603
+ authRedirectRoute: (0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP) ? ctx.authRecipe?.redirectRoute ?? void 0 : void 0,
324567
324604
  testBudget: featureTestBudget
324568
324605
  }, {
324569
324606
  modelOverride: ctx.planModel ?? ctx.generateModel,
@@ -325079,6 +325116,7 @@ var require_resource_governor = __commonJS({
325079
325116
  exports2.getResourceGovernorStatus = getResourceGovernorStatus2;
325080
325117
  var fs_1 = require("fs");
325081
325118
  var os_1 = __importDefault(require("os"));
325119
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
325082
325120
  var DEFAULT_WEIGHTS = {
325083
325121
  run: 1,
325084
325122
  heal: 2.5,
@@ -325225,9 +325263,7 @@ var require_resource_governor = __commonJS({
325225
325263
  }
325226
325264
  function envBool(name, fallback) {
325227
325265
  const raw = process.env[name];
325228
- if (raw == null || raw === "")
325229
- return fallback;
325230
- return raw === "true" || raw === "1" || raw.toLowerCase() === "yes";
325266
+ return (0, shared_1.parseBoolFlag)(raw, fallback);
325231
325267
  }
325232
325268
  function envFloat(name, fallback) {
325233
325269
  const raw = process.env[name];
@@ -338385,7 +338421,7 @@ var require_package4 = __commonJS({
338385
338421
  "package.json"(exports2, module2) {
338386
338422
  module2.exports = {
338387
338423
  name: "@validate.qa/runner",
338388
- version: "1.0.45",
338424
+ version: "1.0.46",
338389
338425
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
338390
338426
  bin: {
338391
338427
  "validate-runner": "dist/cli.js"
@@ -338524,6 +338560,7 @@ function authPlanFor(tags, playwrightCode) {
338524
338560
  }
338525
338561
 
338526
338562
  // src/version-check.ts
338563
+ init_dist();
338527
338564
  var RUNNER_NPM_PACKAGE = "@validate.qa/runner";
338528
338565
  var NPM_LATEST_URL = `https://registry.npmjs.org/${encodeURIComponent(RUNNER_NPM_PACKAGE)}/latest`;
338529
338566
  var DEFAULT_TIMEOUT_MS = 8e3;
@@ -338555,10 +338592,10 @@ function isVersionOutdated(current, latest) {
338555
338592
  return cmp === -1;
338556
338593
  }
338557
338594
  function shouldSkipVersionCheck() {
338558
- if (process.env.RUNNER_CLOUD === "true") {
338595
+ if (parseBoolFlag(process.env.RUNNER_CLOUD)) {
338559
338596
  return "cloud runner (RUNNER_CLOUD=true)";
338560
338597
  }
338561
- if (process.env.VALIDATE_RUNNER_ALLOW_OUTDATED === "1" || process.env.VALIDATE_RUNNER_ALLOW_OUTDATED === "true") {
338598
+ if (parseBoolFlag(process.env.VALIDATE_RUNNER_ALLOW_OUTDATED)) {
338562
338599
  return "VALIDATE_RUNNER_ALLOW_OUTDATED is set";
338563
338600
  }
338564
338601
  return null;
@@ -345247,7 +345284,7 @@ function attachMobileDiscoveryNetworkContext(calls, result, appId) {
345247
345284
  }
345248
345285
  var runnerPackage = require_package4();
345249
345286
  var SECRET_VAR_PATTERN = /password|secret|token|api[_]?key|pass\b|credential|bearer|pat\b/i;
345250
- var IS_CLOUD = process.env.RUNNER_CLOUD === "true";
345287
+ var IS_CLOUD = parseBoolFlag(process.env.RUNNER_CLOUD);
345251
345288
  var RUNNER_NAME = runnerPackage.name ?? "@validate.qa/runner";
345252
345289
  var RUNNER_VERSION = runnerPackage.version ?? "0.0.0";
345253
345290
  var RUNNER_BUILD_ID = process.env.VALIDATE_RUNNER_BUILD_ID ?? process.env.RAILWAY_GIT_COMMIT_SHA ?? process.env.GIT_COMMIT_SHA ?? process.env.SOURCE_VERSION;
@@ -348136,9 +348173,9 @@ async function startRunner(opts) {
348136
348173
  log.info(`Project: ${projectId}`);
348137
348174
  log.info(`Mode: \u{1F3AD} Playwright Native${enableMobile ? " + \u{1F4F1} Mobile" : ""}${enableMobile && enableMobileTunnel ? " \u{1F310} Tunnel" : ""}`);
348138
348175
  log.info(`Interval: ${pollIntervalMs}ms`);
348139
- if (process.env.DISCOVERY_PROMPT_V3 === "true") {
348176
+ if (parseBoolFlag(process.env.DISCOVERY_PROMPT_V3)) {
348140
348177
  log.ok("Discovery prompt: V3 (per-turn rebuild) \u2014 DISCOVERY_PROMPT_V3=true");
348141
- } else if (process.env.DISCOVERY_PROMPT_V3 === "false") {
348178
+ } else if (!parseBoolFlag(process.env.DISCOVERY_PROMPT_V3, true)) {
348142
348179
  log.ok("Discovery prompt: V2.5 (full transcript + control brief) \u2014 DISCOVERY_PROMPT_V3=false");
348143
348180
  } else {
348144
348181
  log.ok("Discovery prompt: V3 (per-turn rebuild, default) \u2014 set DISCOVERY_PROMPT_V3=false for V2.5");
@@ -348164,7 +348201,7 @@ async function startRunner(opts) {
348164
348201
  // WebView. Enable at mobile-runner startup even when the emulator is
348165
348202
  // booted later; the feature is driver-scoped and remains dormant on
348166
348203
  // iOS. Operators may explicitly opt out.
348167
- enableChromedriverAutodownload: process.env.VALIDATEQA_CHROMEDRIVER_AUTODOWNLOAD !== "false"
348204
+ enableChromedriverAutodownload: parseBoolFlag(process.env.VALIDATEQA_CHROMEDRIVER_AUTODOWNLOAD, true)
348168
348205
  });
348169
348206
  log.ok("\u{1F4F1} Appium server started");
348170
348207
  } catch (err) {
package/dist/cli.mjs CHANGED
@@ -5248,6 +5248,28 @@ var init_feature_flags = __esm({
5248
5248
  }
5249
5249
  });
5250
5250
 
5251
+ // ../shared/dist/env-flags.js
5252
+ function parseBoolFlag(value, defaultValue = false) {
5253
+ if (value == null)
5254
+ return defaultValue;
5255
+ const v = value.trim().toLowerCase();
5256
+ if (v === "")
5257
+ return defaultValue;
5258
+ if (TRUTHY.has(v))
5259
+ return true;
5260
+ if (FALSY.has(v))
5261
+ return false;
5262
+ return defaultValue;
5263
+ }
5264
+ var TRUTHY, FALSY;
5265
+ var init_env_flags = __esm({
5266
+ "../shared/dist/env-flags.js"() {
5267
+ "use strict";
5268
+ TRUTHY = /* @__PURE__ */ new Set(["true", "1", "yes", "on"]);
5269
+ FALSY = /* @__PURE__ */ new Set(["false", "0", "no", "off"]);
5270
+ }
5271
+ });
5272
+
5251
5273
  // ../shared/dist/index.js
5252
5274
  var dist_exports = {};
5253
5275
  __export(dist_exports, {
@@ -5400,6 +5422,7 @@ __export(dist_exports, {
5400
5422
  normalizeTtsVoiceId: () => normalizeTtsVoiceId,
5401
5423
  otherMobilePlatform: () => otherMobilePlatform,
5402
5424
  parenDepthDelta: () => parenDepthDelta,
5425
+ parseBoolFlag: () => parseBoolFlag,
5403
5426
  pickDisplayRun: () => pickDisplayRun,
5404
5427
  pickLatestHealthRun: () => pickLatestHealthRun,
5405
5428
  placeholderizeRecordedMobileAction: () => placeholderizeRecordedMobileAction,
@@ -5455,6 +5478,7 @@ var init_dist = __esm({
5455
5478
  init_redact_needles();
5456
5479
  init_voice_config();
5457
5480
  init_feature_flags();
5481
+ init_env_flags();
5458
5482
  }
5459
5483
  });
5460
5484
 
@@ -6098,12 +6122,13 @@ var require_global_ai_slot_client = __commonJS({
6098
6122
  exports.acquireGlobalAiSlot = acquireGlobalAiSlot;
6099
6123
  exports.releaseGlobalAiSlot = releaseGlobalAiSlot;
6100
6124
  var crypto_1 = __require("crypto");
6125
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
6101
6126
  var SERVER_URL = (process.env.SERVER_URL ?? "").replace(/\/$/, "");
6102
6127
  var AUTH_TOKEN = process.env.AUTH_TOKEN || process.env.RUNNER_TOKEN || "";
6103
6128
  var HOLDER = process.env.RUN_ID || `task-${(0, crypto_1.randomUUID)().slice(0, 8)}`;
6104
6129
  var ACQUIRE_HTTP_TIMEOUT_MS = 8e3;
6105
6130
  function isEnabled() {
6106
- return (process.env.GLOBAL_AI_LIMITER_ENABLED ?? "").trim().toLowerCase() === "true" && SERVER_URL.length > 0 && AUTH_TOKEN.length > 0;
6131
+ return (0, shared_1.parseBoolFlag)(process.env.GLOBAL_AI_LIMITER_ENABLED) && SERVER_URL.length > 0 && AUTH_TOKEN.length > 0;
6107
6132
  }
6108
6133
  function maxWaitMs() {
6109
6134
  const raw = process.env.GLOBAL_AI_ACQUIRE_MAX_WAIT_MS;
@@ -67513,6 +67538,7 @@ var require_snapshot_parser = __commonJS({
67513
67538
  exports.detectSessionState = detectSessionState;
67514
67539
  exports.detectReadinessSignals = detectReadinessSignals;
67515
67540
  exports.detectViewportHints = detectViewportHints;
67541
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
67516
67542
  var INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
67517
67543
  "textbox",
67518
67544
  "searchbox",
@@ -67693,7 +67719,7 @@ var require_snapshot_parser = __commonJS({
67693
67719
  return e.name;
67694
67720
  }
67695
67721
  function parseSnapshot(snapshotText, options = {}) {
67696
- const richParse = options.richParse ?? process.env.DISCOVERY_SNAPSHOT_RICH_PARSE === "true";
67722
+ const richParse = options.richParse ?? (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_SNAPSHOT_RICH_PARSE);
67697
67723
  const lines = snapshotText.split("\n");
67698
67724
  const elements = [];
67699
67725
  const liveMessages = [];
@@ -68605,6 +68631,7 @@ var require_discover_ai_planner = __commonJS({
68605
68631
  exports.validateAIPlannerOutput = validateAIPlannerOutput;
68606
68632
  exports.buildFallbackPlan = buildFallbackPlan;
68607
68633
  exports.runAIPlanner = runAIPlanner;
68634
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
68608
68635
  var ai_provider_js_1 = require_ai_provider();
68609
68636
  var ai_queue_js_1 = require_ai_queue();
68610
68637
  var ai_retry_js_1 = require_ai_retry();
@@ -69883,7 +69910,7 @@ Keep the exact JSON schema { "featureGroups":[...], "scenarios":[...], "reasonin
69883
69910
  async function runAIPlanner(siteMap, evidence, context, options) {
69884
69911
  const logs2 = [];
69885
69912
  const failurePlan = (kind, reason, legacyFallback2) => {
69886
- const noFallback = context.mode === "survey" && process.env.DISCOVERY_PLANNER_NO_FALLBACK === "true";
69913
+ const noFallback = context.mode === "survey" && (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_PLANNER_NO_FALLBACK);
69887
69914
  if (noFallback) {
69888
69915
  logs2.push(`Planner ${kind} \u2014 NO-FALLBACK: failing survey cleanly instead of fabricating slug features (${reason})`);
69889
69916
  return {
@@ -70270,7 +70297,7 @@ ${JSON.stringify(gatePlan)}`;
70270
70297
  }
70271
70298
  if (context.mode === "survey" && featureGroups.length === 0 && siteMap.pages.length > 0) {
70272
70299
  const hasGroupWorthyEvidence = siteMap.pages.some((p) => (p.forms?.length ?? 0) > 0 || (p.elements?.length ?? 0) > 0);
70273
- const noFallback = process.env.DISCOVERY_PLANNER_NO_FALLBACK === "true";
70300
+ const noFallback = (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_PLANNER_NO_FALLBACK);
70274
70301
  if (noFallback && !hasGroupWorthyEvidence) {
70275
70302
  return {
70276
70303
  scenarios,
@@ -75519,7 +75546,8 @@ var require_browser_config = __commonJS({
75519
75546
  var promises_1 = __require("fs/promises");
75520
75547
  var path_1 = __require("path");
75521
75548
  var os_1 = __require("os");
75522
- exports.IS_CLOUD = process.env.RUNNER_CLOUD === "true";
75549
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
75550
+ exports.IS_CLOUD = (0, shared_1.parseBoolFlag)(process.env.RUNNER_CLOUD);
75523
75551
  exports.CLOUD_ARGS = [
75524
75552
  "--no-sandbox",
75525
75553
  "--disable-setuid-sandbox",
@@ -75661,7 +75689,7 @@ var require_browser_config = __commonJS({
75661
75689
  }
75662
75690
  }
75663
75691
  function isHeadless2() {
75664
- return exports.IS_CLOUD || process.env.PLAYWRIGHT_HEADLESS === "true" || process.env.NODE_ENV === "production";
75692
+ return exports.IS_CLOUD || (0, shared_1.parseBoolFlag)(process.env.PLAYWRIGHT_HEADLESS) || process.env.NODE_ENV === "production";
75665
75693
  }
75666
75694
  function getSlowMoMs() {
75667
75695
  const raw = process.env.PLAYWRIGHT_SLOWMO;
@@ -76733,7 +76761,7 @@ var require_playwright_native = __commonJS({
76733
76761
  Object.defineProperty(exports, "scrubHarRequestBody", { enumerable: true, get: function() {
76734
76762
  return api_call_redaction_js_2.scrubHarRequestBody;
76735
76763
  } });
76736
- var IS_CLOUD2 = process.env.RUNNER_CLOUD === "true";
76764
+ var IS_CLOUD2 = (0, shared_1.parseBoolFlag)(process.env.RUNNER_CLOUD);
76737
76765
  var PACKAGE_DIR = (0, path_1.resolve)(__dirname, "..", "..");
76738
76766
  var RUNS_DIR = process.env.RUNS_DIR || (0, path_1.join)(PACKAGE_DIR, ".qa-runs");
76739
76767
  var PW_CLI = __require.resolve("@playwright/test/cli");
@@ -76977,7 +77005,7 @@ test.afterEach(async ({ page }, testInfo) => {
76977
77005
  if (useScopedApiHeaders && resolvedExtraHeaders) {
76978
77006
  await (0, promises_1.writeFile)((0, path_1.join)(runDir, "qa-api-fixtures.ts"), (0, api_auth_headers_js_1.buildOriginScopedApiFixtures)(resolvedExtraHeaders, baseUrl));
76979
77007
  }
76980
- const headless = process.env.PLAYWRIGHT_HEADLESS === "true" || process.env.NODE_ENV === "production" || IS_CLOUD2;
77008
+ const headless = (0, shared_1.parseBoolFlag)(process.env.PLAYWRIGHT_HEADLESS) || process.env.NODE_ENV === "production" || IS_CLOUD2;
76981
77009
  logs2.push(`\u2699\uFE0F Config: baseURL=${JSON.stringify(baseUrl)}, headless=${headless}${isApiTest2 ? ", API mode (no screenshot/video)" : ""}`);
76982
77010
  const absTestDir = runDir.replace(/\\/g, "/");
76983
77011
  const absResultsFile = (0, path_1.join)(runDir, "results.json").replace(/\\/g, "/");
@@ -78683,6 +78711,7 @@ var require_instrumented_context = __commonJS({
78683
78711
  var mcp_1 = __require("@playwright/mcp");
78684
78712
  var index_js_1 = __require("@modelcontextprotocol/sdk/client/index.js");
78685
78713
  var inMemory_js_1 = __require("@modelcontextprotocol/sdk/inMemory.js");
78714
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
78686
78715
  var browser_config_js_1 = require_browser_config();
78687
78716
  var health_observer_js_1 = require_health_observer();
78688
78717
  var live_network_collector_js_1 = require_live_network_collector();
@@ -78700,7 +78729,7 @@ var require_instrumented_context = __commonJS({
78700
78729
  var OWNED_BROWSER_CLOSE_TIMEOUT_MS = intEnv("INSTRUMENTED_OWNED_BROWSER_CLOSE_TIMEOUT_MS", 1e4);
78701
78730
  var CLEANUP_TIMEOUT_MS = intEnv("INSTRUMENTED_CLEANUP_TIMEOUT_MS", 1e4);
78702
78731
  function liveCaptureAllowed(mode) {
78703
- if ((process.env.LIVE_NETWORK_COLLECTOR_ENABLED ?? "").toLowerCase() !== "true")
78732
+ if (!(0, shared_1.parseBoolFlag)(process.env.LIVE_NETWORK_COLLECTOR_ENABLED))
78704
78733
  return false;
78705
78734
  if (!mode)
78706
78735
  return false;
@@ -79163,6 +79192,7 @@ var require_snapshot_observation = __commonJS({
79163
79192
  exports.qualifyElementLabel = qualifyElementLabel;
79164
79193
  exports.isConsentOverlayElement = isConsentOverlayElement;
79165
79194
  var snapshot_parser_js_1 = require_snapshot_parser();
79195
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
79166
79196
  var GENERIC_LABEL_RE = /^(input field|textbox|button|link|item|field|value|tab)$/i;
79167
79197
  var NOISE_LABEL_RE = /^(skip\s+to|skip\s+nav|back\s+to\s+top|cookie|accept\s+(all\s+)?cookies)$/i;
79168
79198
  var CONSENT_OVERLAY_LABEL_RE = /\bcookies?\b|\bgdpr\b|\bconsent\b|privacy (?:policy|preferences|settings)/i;
@@ -79495,8 +79525,8 @@ var require_snapshot_observation = __commonJS({
79495
79525
  const metrics = page.snapshotMetrics ?? page.snapshotArtifact?.metrics;
79496
79526
  const sourceKind = page.snapshotMeta?.sourceKind ?? page.snapshotArtifact?.sourceKind ?? "missing";
79497
79527
  const artifact = page.snapshotArtifact;
79498
- const richRender = options.richRender ?? process.env.DISCOVERY_SNAPSHOT_RICH_RENDER === "true";
79499
- const rowActionCensus = richRender && options.mode !== "survey" && (options.rowActionCensus ?? process.env.DISCOVERY_SNAPSHOT_ROW_CENSUS === "true");
79528
+ const richRender = options.richRender ?? (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_SNAPSHOT_RICH_RENDER);
79529
+ const rowActionCensus = richRender && options.mode !== "survey" && (options.rowActionCensus ?? (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_SNAPSHOT_ROW_CENSUS));
79500
79530
  const activeScope = inferActiveSnapshotScope(page);
79501
79531
  const ranked = rankSnapshotElements(getScopedSnapshotElements(page, activeScope), withScopeContext({ ...context, richRank: richRender }, activeScope));
79502
79532
  const allInteractive = ranked.filter(({ element }) => isInteractiveCandidate(element)).filter(({ element }) => {
@@ -80378,6 +80408,7 @@ var require_snapshot_context_compactor = __commonJS({
80378
80408
  exports.compactSnapshotMessages = compactSnapshotMessages;
80379
80409
  exports.formatSnapshotCompactionLog = formatSnapshotCompactionLog;
80380
80410
  var crypto_1 = __require("crypto");
80411
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
80381
80412
  var DEFAULT_MAX_TOOL_RESULT_CHARS = 15e3;
80382
80413
  var DEFAULT_MAX_DUPLICATE_SNAPSHOT_CHARS = 1400;
80383
80414
  var DEFAULT_MAX_TOTAL_SNAPSHOT_CHARS = 45e3;
@@ -80387,7 +80418,7 @@ var require_snapshot_context_compactor = __commonJS({
80387
80418
  maxSnapshotChars: options.maxSnapshotChars ?? DEFAULT_MAX_TOOL_RESULT_CHARS,
80388
80419
  maxDuplicateSnapshotChars: options.maxDuplicateSnapshotChars ?? DEFAULT_MAX_DUPLICATE_SNAPSHOT_CHARS,
80389
80420
  maxTotalSnapshotChars: options.maxTotalSnapshotChars ?? DEFAULT_MAX_TOTAL_SNAPSHOT_CHARS,
80390
- compactStructuredJson: options.compactStructuredJson ?? process.env.DISCOVERY_SNAPSHOT_STRUCTURED_COMPACT !== "false"
80421
+ compactStructuredJson: options.compactStructuredJson ?? (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_SNAPSHOT_STRUCTURED_COMPACT, true)
80391
80422
  };
80392
80423
  }
80393
80424
  function extractSnapshotBlock(content) {
@@ -88428,14 +88459,14 @@ Do NOT add steps you did not execute. Do NOT skip steps from the recording.${led
88428
88459
  revealedControls,
88429
88460
  // Opt-in additive-contradiction gate (see assertion-strength.ts). On Fargate this
88430
88461
  // env must be dispatcher-forwarded to take effect here; off → byte-identical.
88431
- flagContradictedAdditions: process.env.STRENGTH_ADDITIVE_CONTRADICTION_GATE === "true"
88462
+ flagContradictedAdditions: (0, shared_1.parseBoolFlag)(process.env.STRENGTH_ADDITIVE_CONTRADICTION_GATE)
88432
88463
  });
88433
88464
  } catch (err) {
88434
88465
  logs2.push(` Strength gate errored \u2014 skipping (fail-open): ${String(err)}`);
88435
88466
  }
88436
88467
  const verifyCallsSinceLastFinish = verifyCallCount - verifyCallsAtLastFinishGenerate;
88437
88468
  verifyCallsAtLastFinishGenerate = verifyCallCount;
88438
- const bugWitnessEnabled = process.env.DISCOVERY_BUG_WITNESS_ENABLED === "true";
88469
+ const bugWitnessEnabled = (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_BUG_WITNESS_ENABLED);
88439
88470
  const bugWitnessVerdict = bugWitnessEnabled ? resolveSuspectedBugVerdict(suspectedBugDeclared, bugDescription, verifyCallsSinceLastFinish, strengthVerdict?.signals) : null;
88440
88471
  if (bugWitnessVerdict) {
88441
88472
  strengthVerdict = bugWitnessVerdict;
@@ -305692,11 +305723,12 @@ var require_bootstrap_grok_auth = __commonJS({
305692
305723
  exports.seedGrokMcpConfigIfNeeded = seedGrokMcpConfigIfNeeded;
305693
305724
  var node_fs_1 = __importDefault(__require("fs"));
305694
305725
  var node_path_1 = __importDefault(__require("path"));
305726
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
305695
305727
  function seedGrokAuthIfNeeded() {
305696
305728
  const home = process.env.HOME ?? "/home/appuser";
305697
305729
  const authPath = node_path_1.default.join(home, ".grok", "auth.json");
305698
305730
  const b64 = process.env.GROK_AUTH_JSON_B64;
305699
- const force = process.env.GROK_AUTH_FORCE_RESEED === "true" || process.env.GROK_AUTH_FORCE_RESEED === "1";
305731
+ const force = (0, shared_1.parseBoolFlag)(process.env.GROK_AUTH_FORCE_RESEED) || process.env.GROK_AUTH_FORCE_RESEED === "1";
305700
305732
  if (!force && node_fs_1.default.existsSync(authPath)) {
305701
305733
  return;
305702
305734
  }
@@ -307086,7 +307118,7 @@ Output the JSON envelope exactly ONCE as your final message, then exit.`;
307086
307118
  return (0, shared_1.buildSanitizedAgentEnv)({ extra });
307087
307119
  }
307088
307120
  async function runGrokHealSession(opts) {
307089
- const subagentsEnabled = (process.env.GROK_HEAL_SUBAGENTS ?? "").toLowerCase() === "true";
307121
+ const subagentsEnabled = (0, shared_1.parseBoolFlag)(process.env.GROK_HEAL_SUBAGENTS);
307090
307122
  const args = [
307091
307123
  "-p",
307092
307124
  'Read BRIEF.md in this directory. Heal TEST_UNDER_HEAL.spec.ts as instructed. Your FINAL assistant message MUST be ONLY a JSON object \u2014 no prose around it \u2014 with this shape: {"verdict":"fix|app_bug|config_issue|prereq_unmet|state_stale|test_invalid","playwrightCode":"<full file if verdict=fix>","changeDescription":"<one sentence>","reason":"<terse, when not fix>","confidence":"high|medium|low"}',
@@ -312865,6 +312897,7 @@ var require_discover_explorer = __commonJS({
312865
312897
  var ai_provider_js_1 = require_ai_provider();
312866
312898
  var snapshot_parser_js_1 = require_snapshot_parser();
312867
312899
  var scrub_credentials_js_1 = require_scrub_credentials();
312900
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
312868
312901
  var credential_tools_js_1 = require_credential_tools();
312869
312902
  var inbox_tools_js_1 = require_inbox_tools();
312870
312903
  var verification_inbox_js_1 = require_verification_inbox();
@@ -313640,7 +313673,7 @@ ${credentialBlock}${redactedBlock}${inboxBlock}`;
313640
313673
  const collectedPages = [];
313641
313674
  const collectedTransitions = [];
313642
313675
  const observedOriginCounts = /* @__PURE__ */ new Map();
313643
- const captureOriginSignals = (process.env.APP_ORIGIN_RESOLUTION ?? "").toLowerCase() === "true";
313676
+ const captureOriginSignals = (0, shared_1.parseBoolFlag)(process.env.APP_ORIGIN_RESOLUTION);
313644
313677
  const buildObservedOrigins = () => [...observedOriginCounts.entries()].sort((a, b) => b[1] - a[1]).map(([o]) => o);
313645
313678
  logs2.push(`Explorer starting - provider: ${provider}, model: ${agentModel}`);
313646
313679
  logs2.push(`Base URL: ${baseUrl}`);
@@ -313662,7 +313695,7 @@ ${credentialBlock}${redactedBlock}${inboxBlock}`;
313662
313695
  const v3Env = process.env.DISCOVERY_PROMPT_V3;
313663
313696
  const useV3 = v3Env !== "false";
313664
313697
  const useV2 = true;
313665
- const perceptionEnricherEnabled = (process.env.DISCOVERY_PERCEPTION_ENRICHER === "true" || process.env.DISCOVERY_PERCEPTION_ENRICHER === "1") && typeof options?.getPerceptionPage === "function";
313698
+ const perceptionEnricherEnabled = ((0, shared_1.parseBoolFlag)(process.env.DISCOVERY_PERCEPTION_ENRICHER) || process.env.DISCOVERY_PERCEPTION_ENRICHER === "1") && typeof options?.getPerceptionPage === "function";
313666
313699
  const linkFrontierEnabled = (0, survey_link_frontier_js_1.isSurveyLinkFrontierEnabled)() && options?.mode === "survey";
313667
313700
  const linkScope = (0, survey_link_frontier_js_1.deriveLinkScope)(baseUrl);
313668
313701
  let finishRedirects = 0;
@@ -313817,7 +313850,7 @@ ${inboxPromptBlock}`;
313817
313850
  let lastBriefRoute = "";
313818
313851
  let lastBriefIteration = 0;
313819
313852
  const BRIEF_INTERVAL = 5;
313820
- const stuckDetectorEnabled = process.env.DISCOVERY_STUCK_DETECTOR === "1" || process.env.DISCOVERY_STUCK_DETECTOR === "true";
313853
+ const stuckDetectorEnabled = process.env.DISCOVERY_STUCK_DETECTOR === "1" || (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_STUCK_DETECTOR);
313821
313854
  const stuckDetector = stuckDetectorEnabled ? new stuck_detector_js_1.StuckDetector({ repetitionReachesRecovery: !isDeepMode }) : null;
313822
313855
  while (iteration < maxIterations && !explorationComplete) {
313823
313856
  iteration++;
@@ -318027,6 +318060,7 @@ var require_discovery_verify_pool = __commonJS({
318027
318060
  var node_path_1 = __require("path");
318028
318061
  var playwright_native_js_1 = require_playwright_native();
318029
318062
  var scrub_credentials_js_1 = require_scrub_credentials();
318063
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
318030
318064
  var discover_generator_js_1 = require_discover_generator();
318031
318065
  var canvas_detector_js_1 = require_canvas_detector();
318032
318066
  var agentic_discovery_prompts_js_1 = require_agentic_discovery_prompts();
@@ -318686,7 +318720,7 @@ var require_discovery_verify_pool = __commonJS({
318686
318720
  log2(`ledger: persisted ${scenarioLedgers.size} ledger file(s) to ${ledgerDir}`);
318687
318721
  }
318688
318722
  function startAuthoredWatcher(args) {
318689
- if (process.env.DISCOVERY_AUTHORED_STREAMING !== "true") {
318723
+ if (!(0, shared_1.parseBoolFlag)(process.env.DISCOVERY_AUTHORED_STREAMING)) {
318690
318724
  return { stop: () => {
318691
318725
  }, count: () => 0 };
318692
318726
  }
@@ -319090,6 +319124,7 @@ var require_grok_discovery_runner = __commonJS({
319090
319124
  var node_fs_1 = __require("fs");
319091
319125
  var node_os_1 = __require("os");
319092
319126
  var node_path_1 = __require("path");
319127
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
319093
319128
  var instrumented_context_js_1 = require_instrumented_context();
319094
319129
  var exploration_parser_js_1 = require_exploration_parser();
319095
319130
  var bootstrap_grok_auth_js_1 = require_bootstrap_grok_auth();
@@ -319120,7 +319155,7 @@ var require_grok_discovery_runner = __commonJS({
319120
319155
  var DEFAULT_TARGET = { min: 6, max: 15 };
319121
319156
  var WATCHER_DEBOUNCE_MS = 500;
319122
319157
  var MAX_PLAN_REVISIONS = 3;
319123
- var LEGACY_PLAN_MODE = process.env.USE_LEGACY_GROK_DISCOVERY === "true";
319158
+ var LEGACY_PLAN_MODE = (0, shared_1.parseBoolFlag)(process.env.USE_LEGACY_GROK_DISCOVERY);
319124
319159
  var SNAPSHOT_EXCERPT_CHARS = 150;
319125
319160
  function isObject(v) {
319126
319161
  return typeof v === "object" && v !== null && !Array.isArray(v);
@@ -319271,7 +319306,7 @@ var require_grok_discovery_runner = __commonJS({
319271
319306
  return out;
319272
319307
  }
319273
319308
  async function runGrokDiscoveryOnRunner(ctx, callbackOptions, options = {}) {
319274
- if (process.env.USE_GROK_DISCOVERY_V2 === "true") {
319309
+ if ((0, shared_1.parseBoolFlag)(process.env.USE_GROK_DISCOVERY_V2)) {
319275
319310
  return runGrokDiscoveryV2OnRunner(ctx, callbackOptions, options);
319276
319311
  }
319277
319312
  const featureName = ctx.featureName ?? "Untitled Feature";
@@ -321743,6 +321778,7 @@ var require_tool_ledger = __commonJS({
321743
321778
  var promises_1 = __require("fs/promises");
321744
321779
  var node_crypto_1 = __require("crypto");
321745
321780
  var node_path_1 = __require("path");
321781
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
321746
321782
  var OTHER_OUTPUT_PREVIEW_CAP = 1024;
321747
321783
  var DEFAULT_SNAPSHOT_BYTES_CAP = 16 * 1024;
321748
321784
  var KNOWN_CREDENTIAL_BEARING_TOOLS = /* @__PURE__ */ new Set([
@@ -321824,7 +321860,7 @@ var require_tool_ledger = __commonJS({
321824
321860
  let seq = 0;
321825
321861
  let turn = 0;
321826
321862
  let lastNavigateUrl = null;
321827
- const redact = opts.redact ?? process.env.DISCOVERY_LEDGER_REDACT === "true";
321863
+ const redact = opts.redact ?? (0, shared_1.parseBoolFlag)(process.env.DISCOVERY_LEDGER_REDACT);
321828
321864
  const credentialEnvMap = opts.credentialEnvMap ?? /* @__PURE__ */ new Map();
321829
321865
  const maxSnapshotBytes = opts.maxSnapshotBytes ?? DEFAULT_SNAPSHOT_BYTES_CAP;
321830
321866
  const sessionId = (0, node_crypto_1.randomUUID)();
@@ -323445,6 +323481,7 @@ var require_discover_agent = __commonJS({
323445
323481
  var ai_queue_js_1 = require_ai_queue();
323446
323482
  var ai_retry_js_1 = require_ai_retry();
323447
323483
  var strip_json_fences_js_1 = require_strip_json_fences();
323484
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
323448
323485
  var discover_explorer_js_1 = require_discover_explorer();
323449
323486
  var discover_feature_explorer_js_1 = require_discover_feature_explorer();
323450
323487
  var discover_planner_js_1 = require_discover_planner();
@@ -323538,7 +323575,7 @@ var require_discover_agent = __commonJS({
323538
323575
  }
323539
323576
  function describeRunnerRuntime(launchOpts) {
323540
323577
  const browserMode = launchOpts?.headless === true ? "headless" : launchOpts?.headless === false ? "headed" : "default";
323541
- const runtime = process.env.RUNNER_CLOUD === "true" ? "cloud runner" : "local runner";
323578
+ const runtime = (0, shared_1.parseBoolFlag)(process.env.RUNNER_CLOUD) ? "cloud runner" : "local runner";
323542
323579
  return `Runtime: ${runtime}, browser mode: ${browserMode}`;
323543
323580
  }
323544
323581
  function formatElapsed(ms) {
@@ -323685,7 +323722,7 @@ Respond with ONLY valid JSON:
323685
323722
  }
323686
323723
  var AUTH_CAPTURE_TIMEOUT_MS = 4 * 60 * 1e3;
323687
323724
  function maybeStartLoginCaptureRun(ctx, callbackOptions, onAICall, pushLog, onObservedOrigins) {
323688
- if (process.env.AUTH_RECIPE_STAMP !== "true")
323725
+ if (!(0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP))
323689
323726
  return null;
323690
323727
  if (ctx.authRecipe) {
323691
323728
  pushLog(`auth-prologue: reusing persisted login recipe ${ctx.authRecipe.recipeHash} \u2014 skipping capture`);
@@ -323771,7 +323808,7 @@ Respond with ONLY valid JSON:
323771
323808
  if (canvasPreflight.probeRan) {
323772
323809
  ctx.appRenderType = canvasPreflight.renderType;
323773
323810
  }
323774
- const useNativeOverride = process.env.USE_NATIVE_SURVEY === "true";
323811
+ const useNativeOverride = (0, shared_1.parseBoolFlag)(process.env.USE_NATIVE_SURVEY);
323775
323812
  const surveyEngine = (0, agentic_cli_constants_js_1.getAgenticEngine)(ctx.exploreModel);
323776
323813
  if (isSurvey && surveyEngine !== "native" && !useNativeOverride) {
323777
323814
  logs2.push(`exploreModel=${ctx.exploreModel} \u2192 routing to ${surveyEngine} survey runner`);
@@ -323988,8 +324025,8 @@ Explore complete: ${exploreResult.pagesDiscovered} pages, ${exploreResult.elemen
323988
324025
  // Recipe-aware planning: when a verified login recipe is on file, the planner
323989
324026
  // plans @needs-auth (non-auth-flow) scenarios from the authenticated state
323990
324027
  // instead of authoring landing→login steps (which generate would override).
323991
- authRecipeAvailable: process.env.AUTH_RECIPE_STAMP === "true" && !!ctx.authRecipe,
323992
- authRedirectRoute: process.env.AUTH_RECIPE_STAMP === "true" ? ctx.authRecipe?.redirectRoute ?? void 0 : void 0,
324028
+ authRecipeAvailable: (0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP) && !!ctx.authRecipe,
324029
+ authRedirectRoute: (0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP) ? ctx.authRecipe?.redirectRoute ?? void 0 : void 0,
323993
324030
  testBudget
323994
324031
  }, {
323995
324032
  modelOverride: ctx.planModel ?? ctx.generateModel,
@@ -324296,7 +324333,7 @@ Fatal error: ${msg}`);
324296
324333
  if (canvasPreflight.probeRan) {
324297
324334
  ctx.appRenderType = canvasPreflight.renderType;
324298
324335
  }
324299
- const useNativeDeepOverride = process.env.USE_NATIVE_DEEP === "true";
324336
+ const useNativeDeepOverride = (0, shared_1.parseBoolFlag)(process.env.USE_NATIVE_DEEP);
324300
324337
  const deepEngine = (0, agentic_cli_constants_js_1.getAgenticEngine)(ctx.exploreModel);
324301
324338
  if (deepEngine !== "native" && !useNativeDeepOverride) {
324302
324339
  logs2.push(`exploreModel=${ctx.exploreModel} \u2192 routing to ${deepEngine} deep discovery runner`);
@@ -324567,8 +324604,8 @@ Plan (reused): ${resumeSavedScenarios.length} scenarios from the paused run.`);
324567
324604
  },
324568
324605
  // Recipe-aware planning (feature/deep): plan @needs-auth scenarios from the
324569
324606
  // authenticated state when a verified login recipe is on file for this project.
324570
- authRecipeAvailable: process.env.AUTH_RECIPE_STAMP === "true" && !!ctx.authRecipe,
324571
- authRedirectRoute: process.env.AUTH_RECIPE_STAMP === "true" ? ctx.authRecipe?.redirectRoute ?? void 0 : void 0,
324607
+ authRecipeAvailable: (0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP) && !!ctx.authRecipe,
324608
+ authRedirectRoute: (0, shared_1.parseBoolFlag)(process.env.AUTH_RECIPE_STAMP) ? ctx.authRecipe?.redirectRoute ?? void 0 : void 0,
324572
324609
  testBudget: featureTestBudget
324573
324610
  }, {
324574
324611
  modelOverride: ctx.planModel ?? ctx.generateModel,
@@ -325084,6 +325121,7 @@ var require_resource_governor = __commonJS({
325084
325121
  exports.getResourceGovernorStatus = getResourceGovernorStatus2;
325085
325122
  var fs_1 = __require("fs");
325086
325123
  var os_1 = __importDefault(__require("os"));
325124
+ var shared_1 = (init_dist(), __toCommonJS(dist_exports));
325087
325125
  var DEFAULT_WEIGHTS = {
325088
325126
  run: 1,
325089
325127
  heal: 2.5,
@@ -325230,9 +325268,7 @@ var require_resource_governor = __commonJS({
325230
325268
  }
325231
325269
  function envBool(name, fallback) {
325232
325270
  const raw = process.env[name];
325233
- if (raw == null || raw === "")
325234
- return fallback;
325235
- return raw === "true" || raw === "1" || raw.toLowerCase() === "yes";
325271
+ return (0, shared_1.parseBoolFlag)(raw, fallback);
325236
325272
  }
325237
325273
  function envFloat(name, fallback) {
325238
325274
  const raw = process.env[name];
@@ -338390,7 +338426,7 @@ var require_package4 = __commonJS({
338390
338426
  "package.json"(exports, module) {
338391
338427
  module.exports = {
338392
338428
  name: "@validate.qa/runner",
338393
- version: "1.0.45",
338429
+ version: "1.0.46",
338394
338430
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
338395
338431
  bin: {
338396
338432
  "validate-runner": "dist/cli.js"
@@ -338529,6 +338565,7 @@ function authPlanFor(tags, playwrightCode) {
338529
338565
  }
338530
338566
 
338531
338567
  // src/version-check.ts
338568
+ init_dist();
338532
338569
  var RUNNER_NPM_PACKAGE = "@validate.qa/runner";
338533
338570
  var NPM_LATEST_URL = `https://registry.npmjs.org/${encodeURIComponent(RUNNER_NPM_PACKAGE)}/latest`;
338534
338571
  var DEFAULT_TIMEOUT_MS = 8e3;
@@ -338560,10 +338597,10 @@ function isVersionOutdated(current, latest) {
338560
338597
  return cmp === -1;
338561
338598
  }
338562
338599
  function shouldSkipVersionCheck() {
338563
- if (process.env.RUNNER_CLOUD === "true") {
338600
+ if (parseBoolFlag(process.env.RUNNER_CLOUD)) {
338564
338601
  return "cloud runner (RUNNER_CLOUD=true)";
338565
338602
  }
338566
- if (process.env.VALIDATE_RUNNER_ALLOW_OUTDATED === "1" || process.env.VALIDATE_RUNNER_ALLOW_OUTDATED === "true") {
338603
+ if (parseBoolFlag(process.env.VALIDATE_RUNNER_ALLOW_OUTDATED)) {
338567
338604
  return "VALIDATE_RUNNER_ALLOW_OUTDATED is set";
338568
338605
  }
338569
338606
  return null;
@@ -345255,7 +345292,7 @@ function attachMobileDiscoveryNetworkContext(calls, result, appId) {
345255
345292
  }
345256
345293
  var runnerPackage = require_package4();
345257
345294
  var SECRET_VAR_PATTERN = /password|secret|token|api[_]?key|pass\b|credential|bearer|pat\b/i;
345258
- var IS_CLOUD = process.env.RUNNER_CLOUD === "true";
345295
+ var IS_CLOUD = parseBoolFlag(process.env.RUNNER_CLOUD);
345259
345296
  var RUNNER_NAME = runnerPackage.name ?? "@validate.qa/runner";
345260
345297
  var RUNNER_VERSION = runnerPackage.version ?? "0.0.0";
345261
345298
  var RUNNER_BUILD_ID = process.env.VALIDATE_RUNNER_BUILD_ID ?? process.env.RAILWAY_GIT_COMMIT_SHA ?? process.env.GIT_COMMIT_SHA ?? process.env.SOURCE_VERSION;
@@ -348144,9 +348181,9 @@ async function startRunner(opts) {
348144
348181
  log.info(`Project: ${projectId}`);
348145
348182
  log.info(`Mode: \u{1F3AD} Playwright Native${enableMobile ? " + \u{1F4F1} Mobile" : ""}${enableMobile && enableMobileTunnel ? " \u{1F310} Tunnel" : ""}`);
348146
348183
  log.info(`Interval: ${pollIntervalMs}ms`);
348147
- if (process.env.DISCOVERY_PROMPT_V3 === "true") {
348184
+ if (parseBoolFlag(process.env.DISCOVERY_PROMPT_V3)) {
348148
348185
  log.ok("Discovery prompt: V3 (per-turn rebuild) \u2014 DISCOVERY_PROMPT_V3=true");
348149
- } else if (process.env.DISCOVERY_PROMPT_V3 === "false") {
348186
+ } else if (!parseBoolFlag(process.env.DISCOVERY_PROMPT_V3, true)) {
348150
348187
  log.ok("Discovery prompt: V2.5 (full transcript + control brief) \u2014 DISCOVERY_PROMPT_V3=false");
348151
348188
  } else {
348152
348189
  log.ok("Discovery prompt: V3 (per-turn rebuild, default) \u2014 set DISCOVERY_PROMPT_V3=false for V2.5");
@@ -348172,7 +348209,7 @@ async function startRunner(opts) {
348172
348209
  // WebView. Enable at mobile-runner startup even when the emulator is
348173
348210
  // booted later; the feature is driver-scoped and remains dormant on
348174
348211
  // iOS. Operators may explicitly opt out.
348175
- enableChromedriverAutodownload: process.env.VALIDATEQA_CHROMEDRIVER_AUTODOWNLOAD !== "false"
348212
+ enableChromedriverAutodownload: parseBoolFlag(process.env.VALIDATEQA_CHROMEDRIVER_AUTODOWNLOAD, true)
348176
348213
  });
348177
348214
  log.ok("\u{1F4F1} Appium server started");
348178
348215
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@validate.qa/runner",
3
- "version": "1.0.45",
3
+ "version": "1.0.46",
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"