@validate.qa/runner 1.0.87 → 1.0.89

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 +3754 -45
  2. package/dist/cli.mjs +3754 -45
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1793,7 +1793,11 @@ var init_constants = __esm({
1793
1793
  "home",
1794
1794
  "waitForElement",
1795
1795
  "assertVisible",
1796
- "assertText"
1796
+ "assertText",
1797
+ /** Capture list labels / badge counts into run-local state bag (Phase 1 oracles). */
1798
+ "captureState",
1799
+ /** Assert a prior captureState delta (removed id, count change, etc.). */
1800
+ "assertStateDelta"
1797
1801
  ];
1798
1802
  BLOCKED_ENV_VARS = /* @__PURE__ */ new Set([
1799
1803
  // Execution / code-injection vectors
@@ -2228,7 +2232,10 @@ function readMobileMetadata(value) {
2228
2232
  webCss: typeof value.webCss === "string" && value.webCss.trim() ? value.webCss.trim() : void 0,
2229
2233
  webviewContext: typeof value.webviewContext === "string" && /^WEBVIEW/i.test(value.webviewContext.trim()) ? value.webviewContext.trim() : void 0,
2230
2234
  matchIndex: hasValidMatchPair ? rawMatchIndex : void 0,
2231
- expectedMatchCount: hasValidMatchPair ? rawExpectedMatchCount : void 0
2235
+ expectedMatchCount: hasValidMatchPair ? rawExpectedMatchCount : void 0,
2236
+ stateKey: typeof value.stateKey === "string" && value.stateKey.trim() ? value.stateKey.trim() : void 0,
2237
+ stateKind: typeof value.stateKind === "string" && value.stateKind.trim() ? value.stateKind.trim() : void 0,
2238
+ expect: typeof value.expect === "string" && value.expect.trim() ? value.expect.trim() : void 0
2232
2239
  };
2233
2240
  }
2234
2241
  function nonEmpty(value) {
@@ -2311,6 +2318,10 @@ function descriptionForStep(action, stepAction, metadata) {
2311
2318
  return `Assert ${label} is visible`;
2312
2319
  case "assertText":
2313
2320
  return `Assert ${label} shows "${action.value ?? action.innerText ?? ""}"`;
2321
+ case "captureState":
2322
+ return `Capture UI state "${metadata.stateKey ?? label}" (${metadata.stateKind ?? "list_ids"})`;
2323
+ case "assertStateDelta":
2324
+ return `Assert state delta "${metadata.stateKey ?? label}" expect=${metadata.expect ?? action.value ?? "changed"}`;
2314
2325
  default:
2315
2326
  return `Execute ${stepAction}`;
2316
2327
  }
@@ -2356,6 +2367,8 @@ function buildMobileStep(action, order) {
2356
2367
  step.assertion = `${labelForAction(action, metadata)} should be visible`;
2357
2368
  } else if (stepAction === "assertText") {
2358
2369
  step.assertion = action.value ?? action.innerText ?? void 0;
2370
+ } else if (stepAction === "assertStateDelta") {
2371
+ step.assertion = metadata.expect ?? action.value ?? "changed";
2359
2372
  }
2360
2373
  if ((stepAction === "swipe" || stepAction === "scroll") && (metadata.direction || metadata.distance)) {
2361
2374
  const stepMetadata = ensureMetadata(step);
@@ -2364,6 +2377,24 @@ function buildMobileStep(action, order) {
2364
2377
  if (metadata.distance)
2365
2378
  stepMetadata.distance = metadata.distance;
2366
2379
  }
2380
+ if (stepAction === "captureState" || stepAction === "assertStateDelta") {
2381
+ const stepMetadata = ensureMetadata(step);
2382
+ const stateKey = nonEmpty(metadata.stateKey) ?? nonEmpty(action.selector) ?? nonEmpty(metadata.targetLabel) ?? `state-${order}`;
2383
+ stepMetadata.stateKey = stateKey;
2384
+ if (stepAction === "captureState") {
2385
+ stepMetadata.stateKind = nonEmpty(metadata.stateKind) ?? "list_ids";
2386
+ }
2387
+ if (stepAction === "assertStateDelta") {
2388
+ stepMetadata.expect = nonEmpty(metadata.expect) ?? nonEmpty(action.value) ?? "changed";
2389
+ }
2390
+ if (!step.target) {
2391
+ step.target = {
2392
+ primary: stateKey,
2393
+ fallbacks: [],
2394
+ screenName: metadata.screenName || "UnknownScreen"
2395
+ };
2396
+ }
2397
+ }
2367
2398
  return step;
2368
2399
  }
2369
2400
  function buildLaunchStep(target, medium, appResetOnLaunch = false) {
@@ -2575,6 +2606,9 @@ function buildAppiumCode(testName, target, steps) {
2575
2606
  used.find = true;
2576
2607
  }
2577
2608
  break;
2609
+ case "captureState":
2610
+ case "assertStateDelta":
2611
+ break;
2578
2612
  default:
2579
2613
  break;
2580
2614
  }
@@ -2693,6 +2727,8 @@ function buildAppiumCode(testName, target, steps) {
2693
2727
  const expectedLiteral = toJsStringLiteral(step.assertion ?? "");
2694
2728
  const replayExpected = step.assertion?.includes("{{") ? `resolveValue(${expectedLiteral})` : expectedLiteral;
2695
2729
  pushAction(`await expectText(driver, ${sel}, ${replayExpected});`);
2730
+ } else if (step.action === "captureState" || step.action === "assertStateDelta") {
2731
+ lines.push(` // ${step.action}: ${step.description.replace(/\n/g, " ").slice(0, 120)}`);
2696
2732
  } else if (step.action === "back") {
2697
2733
  lines.push(` await driver.back();`);
2698
2734
  } else if (step.action === "home") {
@@ -3035,7 +3071,9 @@ var init_mobile_test_generation = __esm({
3035
3071
  HOME: "home",
3036
3072
  WAIT_FOR_ELEMENT: "waitForElement",
3037
3073
  ASSERT_VISIBLE: "assertVisible",
3038
- ASSERT_TEXT: "assertText"
3074
+ ASSERT_TEXT: "assertText",
3075
+ CAPTURE_STATE: "captureState",
3076
+ ASSERT_STATE_DELTA: "assertStateDelta"
3039
3077
  };
3040
3078
  MOBILE_VALUE_PLACEHOLDER_RE = /\{\{([A-Za-z0-9_]+)\}\}/g;
3041
3079
  }
@@ -3266,7 +3304,9 @@ var init_mobile_step_healer = __esm({
3266
3304
  "home",
3267
3305
  "waitForElement",
3268
3306
  "assertVisible",
3269
- "assertText"
3307
+ "assertText",
3308
+ "captureState",
3309
+ "assertStateDelta"
3270
3310
  ]);
3271
3311
  FOREIGN_PACKAGE_RE = /\b[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*){2,}\b/gi;
3272
3312
  ANDROID_RESOURCE_OWNER_RE = /([a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+):id\//gi;
@@ -80305,6 +80345,306 @@ ${JSON.stringify(gatePlan)}`;
80305
80345
  }
80306
80346
  });
80307
80347
 
80348
+ // ../runner-core/dist/services/mobile/scenario-taxonomy.js
80349
+ var require_scenario_taxonomy = __commonJS({
80350
+ "../runner-core/dist/services/mobile/scenario-taxonomy.js"(exports2) {
80351
+ "use strict";
80352
+ Object.defineProperty(exports2, "__esModule", { value: true });
80353
+ exports2.ALL_SCENARIO_KINDS = void 0;
80354
+ exports2.extractUiSignals = extractUiSignals;
80355
+ exports2.requiredScenarioKinds = requiredScenarioKinds;
80356
+ exports2.coverageGaps = coverageGaps;
80357
+ exports2.inferScenarioKind = inferScenarioKind;
80358
+ exports2.inferScenarioKinds = inferScenarioKinds;
80359
+ exports2.isStrongOracleKind = isStrongOracleKind;
80360
+ exports2.formatRequiredScenarioKindsPrompt = formatRequiredScenarioKindsPrompt;
80361
+ exports2.formatCoverageGapLog = formatCoverageGapLog;
80362
+ exports2.ALL_SCENARIO_KINDS = [
80363
+ "smoke_nav",
80364
+ "happy_submit",
80365
+ "negative_validation",
80366
+ "crud_identity",
80367
+ "count_delta",
80368
+ "persistence_roundtrip",
80369
+ "auth_session",
80370
+ "navigation_integrity",
80371
+ "permission_system",
80372
+ "double_submit"
80373
+ ];
80374
+ var DELETE_RE = /\b(delete|remove|archive|trash)\b/i;
80375
+ var EMAIL_RE = /\b(e-?mail|email address)\b/i;
80376
+ var PASSWORD_RE = /\b(password|passcode|pin)\b/i;
80377
+ var SIGN_OUT_RE = /\b(sign\s*out|log\s*out|logout)\b/i;
80378
+ var TOGGLE_RE = /\b(toggle|switch|enable|disable|on\/off)\b/i;
80379
+ var SUBMIT_RE = /\b(submit|save|send|create|confirm|apply|done|update|post)\b/i;
80380
+ var BADGE_OR_COUNT_RE = /\b(\d+)\s*(item|items|open|unread|invoice|message|result|pending|new)\b/i;
80381
+ var BADGE_LABEL_RE = /\b(badge|count|open invoices|unread|notifications?)\b/i;
80382
+ var PERMISSION_RE = /\b(camera|microphone|location|photos?|permission|allow access|not now)\b/i;
80383
+ var SETTINGS_RE = /\b(settings|preferences|profile|account)\b/i;
80384
+ var TAB_RE = /\b(tab|home|catalog|forms|edges|inbox|feed|dashboard)\b/i;
80385
+ function elementText(el) {
80386
+ return [
80387
+ el.label ?? "",
80388
+ el.text ?? "",
80389
+ el.accessibilityId ?? "",
80390
+ el.resourceId ?? "",
80391
+ el.role ?? ""
80392
+ ].join(" ");
80393
+ }
80394
+ function isEditable(el) {
80395
+ const role = el.role ?? "";
80396
+ return /EditText|TextField|SecureTextField|SearchField|AutoComplete|textbox|searchbox/i.test(role) || el.role === "textbox" || el.role === "searchbox";
80397
+ }
80398
+ function isToggle(el) {
80399
+ const role = el.role ?? "";
80400
+ return /Switch|CheckBox|Toggle|RadioButton/i.test(role) || TOGGLE_RE.test(elementText(el));
80401
+ }
80402
+ function isRowAction(el) {
80403
+ const t = elementText(el);
80404
+ return DELETE_RE.test(t) && el.actionable !== false;
80405
+ }
80406
+ function extractUiSignals(graph, appId) {
80407
+ const screens = [...graph.screens.values()].filter((s) => {
80408
+ if (!appId)
80409
+ return true;
80410
+ return s.screenId === appId || s.screenId.startsWith(`${appId}#`) || s.screenId.startsWith(`${appId}.`);
80411
+ });
80412
+ let hasListWithRowActions = false;
80413
+ let hasFormFields = false;
80414
+ let hasEmailField = false;
80415
+ let hasNumericBadge = false;
80416
+ let hasSettingsToggles = false;
80417
+ let hasSignOut = false;
80418
+ let hasDestructiveConfirm = false;
80419
+ let hasPrimarySubmit = false;
80420
+ let hasTabOrDrawerNav = false;
80421
+ let hasPermissionCopy = false;
80422
+ for (const state2 of screens) {
80423
+ const labels = state2.elements.map(elementText);
80424
+ const blob = [state2.screenName ?? "", state2.screenType ?? "", ...state2.observations ?? [], ...labels].join(" ");
80425
+ if (PASSWORD_RE.test(blob) || state2.elements.some(isEditable))
80426
+ hasFormFields = true;
80427
+ if (labels.some((t) => EMAIL_RE.test(t)) || state2.elements.some((el) => isEditable(el) && EMAIL_RE.test(elementText(el)))) {
80428
+ hasEmailField = true;
80429
+ hasFormFields = true;
80430
+ }
80431
+ if (state2.elements.some(isRowAction))
80432
+ hasListWithRowActions = true;
80433
+ if (!hasListWithRowActions && state2.elements.filter((el) => el.actionable).length >= 6 && DELETE_RE.test(blob)) {
80434
+ hasListWithRowActions = true;
80435
+ }
80436
+ if (BADGE_OR_COUNT_RE.test(blob) || BADGE_LABEL_RE.test(blob))
80437
+ hasNumericBadge = true;
80438
+ if (state2.elements.some(isToggle) || SETTINGS_RE.test(blob) && TOGGLE_RE.test(blob)) {
80439
+ hasSettingsToggles = true;
80440
+ }
80441
+ if (SIGN_OUT_RE.test(blob))
80442
+ hasSignOut = true;
80443
+ if (DELETE_RE.test(blob) && /\b(confirm|are you sure|permanently)\b/i.test(blob)) {
80444
+ hasDestructiveConfirm = true;
80445
+ }
80446
+ if (labels.some((t) => SUBMIT_RE.test(t)))
80447
+ hasPrimarySubmit = true;
80448
+ if (TAB_RE.test(blob) || state2.screenType === "TAB" || /\btab\b/i.test(state2.screenName ?? "")) {
80449
+ hasTabOrDrawerNav = true;
80450
+ }
80451
+ if (PERMISSION_RE.test(blob) || state2.screenType === "PERMISSION")
80452
+ hasPermissionCopy = true;
80453
+ }
80454
+ return {
80455
+ hasListWithRowActions,
80456
+ hasFormFields,
80457
+ hasEmailField,
80458
+ hasNumericBadge,
80459
+ hasSettingsToggles,
80460
+ hasSignOut,
80461
+ hasDestructiveConfirm,
80462
+ hasPrimarySubmit,
80463
+ hasTabOrDrawerNav,
80464
+ hasPermissionCopy
80465
+ };
80466
+ }
80467
+ function requiredScenarioKinds(signals) {
80468
+ const kinds = /* @__PURE__ */ new Set(["smoke_nav"]);
80469
+ if (signals.hasFormFields || signals.hasPrimarySubmit) {
80470
+ kinds.add("happy_submit");
80471
+ }
80472
+ if (signals.hasFormFields || signals.hasEmailField) {
80473
+ kinds.add("negative_validation");
80474
+ }
80475
+ if (signals.hasListWithRowActions) {
80476
+ kinds.add("crud_identity");
80477
+ }
80478
+ if (signals.hasNumericBadge) {
80479
+ kinds.add("count_delta");
80480
+ }
80481
+ if (signals.hasSettingsToggles) {
80482
+ kinds.add("persistence_roundtrip");
80483
+ }
80484
+ if (signals.hasSignOut) {
80485
+ kinds.add("auth_session");
80486
+ }
80487
+ if (signals.hasTabOrDrawerNav) {
80488
+ kinds.add("navigation_integrity");
80489
+ }
80490
+ if (signals.hasPermissionCopy) {
80491
+ kinds.add("permission_system");
80492
+ }
80493
+ if (signals.hasPrimarySubmit && signals.hasFormFields) {
80494
+ kinds.add("double_submit");
80495
+ }
80496
+ return exports2.ALL_SCENARIO_KINDS.filter((k) => kinds.has(k));
80497
+ }
80498
+ function coverageGaps(signals, plannedKinds) {
80499
+ const planned = new Set(plannedKinds);
80500
+ return requiredScenarioKinds(signals).filter((k) => !planned.has(k));
80501
+ }
80502
+ function inferScenarioKind(scenario) {
80503
+ const text = `${scenario.name} ${scenario.goal} ${scenario.variant ?? ""} ${scenario.type}`.toLowerCase();
80504
+ if (/\b(invalid|empty|required|validation|too short|malformed|reject|error message)\b/.test(text) || scenario.variant === "validation" || scenario.type === "EDGE_CASE" && /\b(empty|invalid|required)\b/.test(text)) {
80505
+ return "negative_validation";
80506
+ }
80507
+ if (/\b(delete|remove|wrong row|entity|archive)\b/.test(text) && /\b(list|row|item|record)\b/.test(text)) {
80508
+ return "crud_identity";
80509
+ }
80510
+ if (/\b(badge|count|unread|open invoices|\+\d|increment|decrement)\b/.test(text)) {
80511
+ return "count_delta";
80512
+ }
80513
+ if (/\b(persist|revisit|return|leave|settings|toggle|favorite|remember)\b/.test(text)) {
80514
+ return "persistence_roundtrip";
80515
+ }
80516
+ if (/\b(sign\s*out|log\s*out|session|sign\s*in|remember me|auth)\b/.test(text) || scenario.type === "HAPPY_PATH" && /\b(login|sign in)\b/.test(text)) {
80517
+ return "auth_session";
80518
+ }
80519
+ if (/\b(tab|navigate|navigation|back|deep link|empty.?state)\b/.test(text)) {
80520
+ return "navigation_integrity";
80521
+ }
80522
+ if (/\b(permission|camera|microphone|location|allow)\b/.test(text)) {
80523
+ return "permission_system";
80524
+ }
80525
+ if (/\b(double|twice|duplicate submit|double.?tap)\b/.test(text)) {
80526
+ return "double_submit";
80527
+ }
80528
+ if (scenario.type === "HAPPY_PATH" || scenario.variant === "happy") {
80529
+ return "happy_submit";
80530
+ }
80531
+ if (scenario.type === "USER_JOURNEY" || scenario.type === "REGRESSION") {
80532
+ return "navigation_integrity";
80533
+ }
80534
+ return "smoke_nav";
80535
+ }
80536
+ function inferScenarioKinds(scenarios) {
80537
+ return [...new Set(scenarios.map(inferScenarioKind))];
80538
+ }
80539
+ function isStrongOracleKind(kind) {
80540
+ return kind !== "smoke_nav" && kind !== "navigation_integrity";
80541
+ }
80542
+ function formatRequiredScenarioKindsPrompt(signals) {
80543
+ const required = requiredScenarioKinds(signals);
80544
+ if (required.length === 0)
80545
+ return "";
80546
+ const lines = required.map((kind) => {
80547
+ switch (kind) {
80548
+ case "smoke_nav":
80549
+ return '- smoke_nav: reach a primary destination and prove it with a durable product signal (not only "tab visible")';
80550
+ case "happy_submit":
80551
+ return "- happy_submit: complete a form/primary action and assert the durable result (new row, saved state, success that outlives a toast)";
80552
+ case "negative_validation":
80553
+ return "- negative_validation: submit empty/invalid input (e.g. empty required, malformed email-like field) and assert error OR blocked submit \u2014 never invent success copy";
80554
+ case "crud_identity":
80555
+ return '- crud_identity: create or note an entity id/label, perform delete/edit on THAT entity, assert identity set changed correctly (not "list still visible")';
80556
+ case "count_delta":
80557
+ return "- count_delta: capture a numeric badge/count, perform an action, assert the number changed as expected";
80558
+ case "persistence_roundtrip":
80559
+ return "- persistence_roundtrip: change a setting/toggle, leave the screen (or relaunch if policy allows), return, assert value persisted";
80560
+ case "auth_session":
80561
+ return "- auth_session: prove sign-in session (profile/sign-out) and/or sign-out leaves only logged-out chrome";
80562
+ case "navigation_integrity":
80563
+ return "- navigation_integrity: tab/drawer/back reaches the intended screen family";
80564
+ case "permission_system":
80565
+ return "- permission_system: permission prompt or settings path behaves honestly (allow/deny/settings)";
80566
+ case "double_submit":
80567
+ return "- double_submit: single user intent must not double-create (assert count +1 not +2, or single confirmation)";
80568
+ default:
80569
+ return `- ${kind}`;
80570
+ }
80571
+ });
80572
+ return "## Required scenario kinds (from observed UI \u2014 fill each or explain impossibility in reasoning)\nThese kinds are derived ONLY from controls/screens the explorer saw. Plan at least one scenario per kind when evidence supports it.\n" + lines.join("\n");
80573
+ }
80574
+ function formatCoverageGapLog(gaps) {
80575
+ if (gaps.length === 0)
80576
+ return "Scenario taxonomy: all required kinds covered by plan";
80577
+ return `Scenario taxonomy coverage gaps (required but not planned): ${gaps.join(", ")}`;
80578
+ }
80579
+ }
80580
+ });
80581
+
80582
+ // ../runner-core/dist/services/mobile/coverage-map.js
80583
+ var require_coverage_map = __commonJS({
80584
+ "../runner-core/dist/services/mobile/coverage-map.js"(exports2) {
80585
+ "use strict";
80586
+ Object.defineProperty(exports2, "__esModule", { value: true });
80587
+ exports2.buildMobileCoverageMap = buildMobileCoverageMap;
80588
+ var scenario_taxonomy_js_1 = require_scenario_taxonomy();
80589
+ function strongLookup(name, map2) {
80590
+ if (!map2)
80591
+ return false;
80592
+ if (map2 instanceof Map)
80593
+ return map2.get(name) === true;
80594
+ return Object.prototype.hasOwnProperty.call(map2, name) && map2[name] === true;
80595
+ }
80596
+ function buildMobileCoverageMap(input) {
80597
+ const signals = (0, scenario_taxonomy_js_1.extractUiSignals)(input.graph, input.appId);
80598
+ const required = (0, scenario_taxonomy_js_1.requiredScenarioKinds)(signals);
80599
+ const planned = input.plannedScenarios ?? [];
80600
+ const plannedKinds = planned.map(scenario_taxonomy_js_1.inferScenarioKind);
80601
+ const plannedSet = new Set(plannedKinds);
80602
+ const gaps = (0, scenario_taxonomy_js_1.coverageGaps)(signals, plannedKinds);
80603
+ const kindsWithStrong = /* @__PURE__ */ new Set();
80604
+ for (const s of planned) {
80605
+ const kind = (0, scenario_taxonomy_js_1.inferScenarioKind)(s);
80606
+ const isStrong = (0, scenario_taxonomy_js_1.isStrongOracleKind)(kind) || strongLookup(s.name, input.strongByScenarioName);
80607
+ if (isStrong)
80608
+ kindsWithStrong.add(kind);
80609
+ }
80610
+ const warnings = [];
80611
+ const entries = required.map((kind) => {
80612
+ const isPlanned = plannedSet.has(kind);
80613
+ const strongPlanned = kindsWithStrong.has(kind);
80614
+ let warning;
80615
+ if (!isPlanned) {
80616
+ warning = `Required kind "${kind}" has no planned scenario`;
80617
+ warnings.push(warning);
80618
+ } else if (!strongPlanned && (0, scenario_taxonomy_js_1.isStrongOracleKind)(kind)) {
80619
+ warning = `Kind "${kind}" is planned but has no strong-oracle scenario (smoke-only coverage)`;
80620
+ warnings.push(warning);
80621
+ }
80622
+ return {
80623
+ kind,
80624
+ required: true,
80625
+ planned: isPlanned,
80626
+ strongPlanned,
80627
+ warning
80628
+ };
80629
+ });
80630
+ if (planned.length > 0 && plannedKinds.every((k) => k === "smoke_nav" || k === "navigation_integrity")) {
80631
+ const w = "All planned scenarios are smoke/nav \u2014 no strong product oracles";
80632
+ if (!warnings.includes(w))
80633
+ warnings.push(w);
80634
+ }
80635
+ const summary = warnings.length === 0 ? `Coverage map: ${required.length} required kinds, all covered with strong scenarios where needed` : `Coverage map: ${warnings.length} warning(s); ${(0, scenario_taxonomy_js_1.formatCoverageGapLog)(gaps)}`;
80636
+ return {
80637
+ signals,
80638
+ requiredKinds: required,
80639
+ gaps,
80640
+ entries,
80641
+ warnings,
80642
+ summary
80643
+ };
80644
+ }
80645
+ }
80646
+ });
80647
+
80308
80648
  // ../runner-core/dist/services/mobile/mobile-discovery-prompts.js
80309
80649
  var require_mobile_discovery_prompts = __commonJS({
80310
80650
  "../runner-core/dist/services/mobile/mobile-discovery-prompts.js"(exports2) {
@@ -80322,6 +80662,8 @@ var require_mobile_discovery_prompts = __commonJS({
80322
80662
  var ai_provider_js_1 = require_ai_provider();
80323
80663
  var discover_ai_planner_js_1 = require_discover_ai_planner();
80324
80664
  var mobile_observation_js_1 = require_mobile_observation();
80665
+ var scenario_taxonomy_js_1 = require_scenario_taxonomy();
80666
+ var coverage_map_js_1 = require_coverage_map();
80325
80667
  function isTargetAppScreenId(screenId, appId) {
80326
80668
  if (!appId)
80327
80669
  return true;
@@ -80403,7 +80745,7 @@ Return ONLY one valid JSON object matching the schema below. Do NOT include <thi
80403
80745
  9. **No duplicates** - check existing test names before adding
80404
80746
  10. **All tests start from the app launch entry** - every generated test starts by launching the target app. The runner clears app data when the device/reset policy safely supports it; otherwise it performs a terminate + activate relaunch, which can preserve app session data. Therefore scenarios MUST navigate through the app's own UI from whatever launch state is valid, and MUST NOT rely on mutable data from a prior scenario disappearing. Steps must reflect this: say "Launch the app and tap Sign In" not "deep-link to the login screen". Do NOT navigate by deep-link; the app's launch + tab/drawer navigation is the only entry path. \`targetPages\` lists the screen-ids involved in the flow.
80405
80747
  11. **targetPages must be copied CHARACTER-FOR-CHARACTER from the screen-ids in the evidence** (they look like \`com.example.app.MainActivity#ab12cd34\`). NEVER invent, prettify, or abbreviate them \u2014 no "Landing", "AUTH", "Home Screen", or any name that is not literally in the provided screens. A scenario whose targetPages contains even ONE id not present in the evidence is REJECTED WHOLESALE by the validator, so a single made-up route silently destroys the entire scenario. If you are unsure which screen-id a step touches, use the screen-id of the screen where the flow STARTS.
80406
- 12. **Happy paths must verify the DURABLE OUTCOME, not just the trigger.** A HAPPY_PATH is NOT complete until it verifies the feature's real output. "Button tapped" / "Sheet opened" / "Spinner appeared" / "Settings screen opened" is NOT a happy path - that is a UI interaction test. Form-mutation happy paths (change password, create/edit/save a record, send a message, checkout, etc.) MUST include typing into the relevant fields AND committing the form (submit/save/send or keyboard Enter/Done) \u2014 navigating to the form screen alone is insufficient. Apply this to any feature where an action produces a result the user then sees or uses: CRUD creates, photo/file uploads, searches that return results, imports, exports, payments, messages sent, AI/ML outputs, generated documents, sync runs, analysis runs, conversion, data processing. The scenario MUST include:
80748
+ 12. **Happy paths must verify the DURABLE OUTCOME, not just the trigger.** A HAPPY_PATH is NOT complete until it verifies the feature's real output. "Button tapped" / "Sheet opened" / "Spinner appeared" / "Settings screen opened" is NOT a happy path - that is a UI interaction test. When the explorer observed list rows with delete/remove, plan at least one scenario that captures entity identity before the action and asserts that identity is gone or changed afterward (not merely that the list screen is still visible). When numeric badges/counts were observed, plan a before/after count check. Form-mutation happy paths (change password, create/edit/save a record, send a message, checkout, etc.) MUST include typing into the relevant fields AND committing the form (submit/save/send or keyboard Enter/Done) \u2014 navigating to the form screen alone is insufficient. Apply this to any feature where an action produces a result the user then sees or uses: CRUD creates, photo/file uploads, searches that return results, imports, exports, payments, messages sent, AI/ML outputs, generated documents, sync runs, analysis runs, conversion, data processing. The scenario MUST include:
80407
80749
  - The trigger step (Tap Submit / Generate / Send / Upload / Run / Analyze / Save / Pay / etc.)
80408
80750
  - A wait step for the operation to complete. Phrase it by SIGNAL, not wall-clock ("Wait for the result to appear - up to 60 seconds"). Prefer signals the app actually uses: spinner disappears, status badge flips to a success state, a new row appears, an item count increments, a success toast/snackbar shows, the screen transitions to a result screen.
80409
80751
  - A verification step on the DURABLE RESULT - the thing that outlives the transient UI: a new list row, a persisted record, a received message, a committed state change, visible output text. Do NOT assert on the spinner disappearing alone; assert on what replaced it.
@@ -80803,6 +81145,14 @@ SCOPE: this is a feature-focused deep run. Plan scenarios ONLY for the "${contex
80803
81145
  sections.push(`## Operator notes
80804
81146
  ${context.userNotes.trim()}`);
80805
81147
  }
81148
+ if (context.mode === "deep" || context.mode === "full") {
81149
+ const signals = (0, scenario_taxonomy_js_1.extractUiSignals)(graph, context.appId);
81150
+ const requiredBlock = (0, scenario_taxonomy_js_1.formatRequiredScenarioKindsPrompt)(signals);
81151
+ if (requiredBlock) {
81152
+ sections.push(requiredBlock);
81153
+ sections.push('## Scenario kind coverage rules\n1. Prefer scenarios whose expectedOutcomes prove durable product results (state deltas, validation errors, persistence), not only "control X is visible".\n2. For negative_validation: empty required field and/or malformed email-like input when an email field was observed.\n3. For crud_identity: assert the specific entity identity is gone/changed \u2014 never only that the list screen is still visible.\n4. For count_delta: mention the before/after numeric expectation in expectedOutcomes.\n5. If a required kind is impossible given evidence, say so in "reasoning" \u2014 do not invent unobserved screens.');
81154
+ }
81155
+ }
80806
81156
  const orderedScreens = plannableTargetAppScreens(graph, context.appId).sort((a, b) => a.firstSeenIteration - b.firstSeenIteration || a.screenId.localeCompare(b.screenId));
80807
81157
  const includedScreenIds = new Set(orderedScreens.map((state2) => state2.screenId));
80808
81158
  const maxElementsPerScreen = context.mode === "survey" ? SURVEY_MAX_ELEMENTS_PER_SCREEN : MAX_ELEMENTS_PER_SCREEN;
@@ -81526,6 +81876,43 @@ ${constraints.join("\n")}`);
81526
81876
  mobileAdaptationLogs.push(`Dropped ${guestWallFilter.dropped} guest-wall scenario(s) \u2014 explore session was authenticated; re-exec would not see sign-in gates`);
81527
81877
  }
81528
81878
  const plannedScenarios = guestWallFilter.scenarios;
81879
+ let taxonomyGapLogs = [];
81880
+ let taxonomyCoverageGaps = result.coverageGaps ?? [];
81881
+ if (input.mode !== "survey" && plannedScenarios.length > 0) {
81882
+ const signals = (0, scenario_taxonomy_js_1.extractUiSignals)(input.graph, input.appId);
81883
+ const plannedKinds = (0, scenario_taxonomy_js_1.inferScenarioKinds)(plannedScenarios);
81884
+ const gaps = (0, scenario_taxonomy_js_1.coverageGaps)(signals, plannedKinds);
81885
+ const coverageMap = (0, coverage_map_js_1.buildMobileCoverageMap)({
81886
+ graph: input.graph,
81887
+ appId: input.appId,
81888
+ plannedScenarios
81889
+ });
81890
+ taxonomyGapLogs = [(0, scenario_taxonomy_js_1.formatCoverageGapLog)(gaps), coverageMap.summary];
81891
+ if (coverageMap.warnings.length > 0) {
81892
+ taxonomyGapLogs.push(...coverageMap.warnings.slice(0, 12));
81893
+ }
81894
+ if (gaps.length > 0) {
81895
+ taxonomyGapLogs.push(`UI signals: listRowActions=${signals.hasListWithRowActions} forms=${signals.hasFormFields} email=${signals.hasEmailField} badge=${signals.hasNumericBadge} toggles=${signals.hasSettingsToggles} signOut=${signals.hasSignOut} tabs=${signals.hasTabOrDrawerNav}`);
81896
+ const detectedAt = (/* @__PURE__ */ new Date()).toISOString();
81897
+ taxonomyCoverageGaps = [
81898
+ ...taxonomyCoverageGaps,
81899
+ ...gaps.map((kind) => ({
81900
+ scenarioName: `[taxonomy] ${kind}`,
81901
+ reason: `Required scenario kind "${kind}" not represented in the planned set`,
81902
+ suggestion: `Add a ${kind} scenario backed by observed controls, or document impossibility`,
81903
+ unmetPrerequisites: [],
81904
+ detectedAt
81905
+ })),
81906
+ ...coverageMap.warnings.filter((w) => /smoke-only|no strong-oracle/i.test(w)).map((w) => ({
81907
+ scenarioName: "[coverage-map] strong-oracle gap",
81908
+ reason: w,
81909
+ suggestion: "Author durable assertStateDelta/assertText outcomes for this kind",
81910
+ unmetPrerequisites: [],
81911
+ detectedAt
81912
+ }))
81913
+ ];
81914
+ }
81915
+ }
81529
81916
  if (input.mode !== "survey" && plannedScenarios.length === 0 && input.graph.screens.size > 0) {
81530
81917
  const fallbackScenarios = buildMobileFallbackScenarios(input);
81531
81918
  if (fallbackScenarios.length > 0) {
@@ -81584,7 +81971,8 @@ ${constraints.join("\n")}`);
81584
81971
  ...result,
81585
81972
  scenarios: plannedScenarios,
81586
81973
  featureGroups: mobileFeatureGroups,
81587
- logs: [...result.logs, ...mobileAdaptationLogs]
81974
+ coverageGaps: taxonomyCoverageGaps.length > 0 ? taxonomyCoverageGaps : result.coverageGaps,
81975
+ logs: [...result.logs, ...mobileAdaptationLogs, ...taxonomyGapLogs]
81588
81976
  };
81589
81977
  }
81590
81978
  }
@@ -81663,6 +82051,7 @@ var require_mobile_generator = __commonJS({
81663
82051
  var ai_retry_js_1 = require_ai_retry();
81664
82052
  var mobile_session_keepalive_js_1 = require_mobile_session_keepalive();
81665
82053
  var discovery_lint_flags_js_1 = require_discovery_lint_flags();
82054
+ var scenario_taxonomy_js_1 = require_scenario_taxonomy();
81666
82055
  var mobile_source_parser_js_1 = require_mobile_source_parser();
81667
82056
  var mobile_source_parser_js_2 = require_mobile_source_parser();
81668
82057
  var mobile_observation_js_1 = require_mobile_observation();
@@ -81804,6 +82193,50 @@ var require_mobile_generator = __commonJS({
81804
82193
  }
81805
82194
  }
81806
82195
  };
82196
+ var MOBILE_CAPTURE_STATE_TOOL = {
82197
+ type: "function",
82198
+ function: {
82199
+ name: "mobile_capture_state",
82200
+ description: 'Capture list labels or numeric badge counts into a named state key BEFORE a mutating action (delete/create/toggle). Pair with mobile_assert_state_delta afterward to prove durable identity/count outcomes \u2014 stronger than "list still visible".',
82201
+ parameters: {
82202
+ type: "object",
82203
+ properties: {
82204
+ stateKey: {
82205
+ type: "string",
82206
+ description: 'Short key for this bag entry (e.g. "invoice_list", "open_count"). Reuse the same key in mobile_assert_state_delta.'
82207
+ },
82208
+ kind: {
82209
+ type: "string",
82210
+ enum: ["list_ids", "badge_count"],
82211
+ description: "list_ids = unique visible labels; badge_count = numeric count tokens. Default list_ids."
82212
+ }
82213
+ },
82214
+ required: ["stateKey"]
82215
+ }
82216
+ }
82217
+ };
82218
+ var MOBILE_ASSERT_STATE_DELTA_TOOL = {
82219
+ type: "function",
82220
+ function: {
82221
+ name: "mobile_assert_state_delta",
82222
+ description: "Compare the current screen to a prior mobile_capture_state. Verifies LIVE then records assertStateDelta. Use after delete/create/count-changing actions. expect: changed | entity_removed | count_decreased | count_increased | unchanged | persisted.",
82223
+ parameters: {
82224
+ type: "object",
82225
+ properties: {
82226
+ stateKey: {
82227
+ type: "string",
82228
+ description: "Must match a prior mobile_capture_state stateKey in this scenario."
82229
+ },
82230
+ expect: {
82231
+ type: "string",
82232
+ enum: ["changed", "entity_removed", "count_decreased", "count_increased", "unchanged", "persisted"],
82233
+ description: "What must differ (or persist) vs the prior capture. Default: changed."
82234
+ }
82235
+ },
82236
+ required: ["stateKey"]
82237
+ }
82238
+ }
82239
+ };
81807
82240
  var MOBILE_FILL_CREDENTIAL_TOOL = {
81808
82241
  type: "function",
81809
82242
  function: {
@@ -81826,7 +82259,7 @@ var require_mobile_generator = __commonJS({
81826
82259
  type: "function",
81827
82260
  function: {
81828
82261
  name: "finish_generate",
81829
- description: "Call when the scenario is fully exercised and its outcome is asserted. verified:true requires you to have called at least one assert tool (mobile_assert_visible / mobile_assert_text) \u2014 claiming verified without any assert is auto-downgraded.",
82262
+ description: "Call when the scenario is fully exercised and its outcome is asserted. verified:true requires you to have called at least one assert tool (mobile_assert_visible / mobile_assert_text / mobile_assert_state_delta) \u2014 claiming verified without any assert is auto-downgraded.",
81830
82263
  parameters: {
81831
82264
  type: "object",
81832
82265
  properties: {
@@ -81858,6 +82291,8 @@ var require_mobile_generator = __commonJS({
81858
82291
  MOBILE_RELAUNCH_TOOL,
81859
82292
  MOBILE_ASSERT_VISIBLE_TOOL,
81860
82293
  MOBILE_ASSERT_TEXT_TOOL,
82294
+ MOBILE_CAPTURE_STATE_TOOL,
82295
+ MOBILE_ASSERT_STATE_DELTA_TOOL,
81861
82296
  FINISH_GENERATE_TOOL
81862
82297
  ];
81863
82298
  var STRUCTURAL_KEY_MAX_ELEMENTS = 16;
@@ -82124,6 +82559,7 @@ The scenario name + goal + steps describe ONE product behavior from survey/disco
82124
82559
  - Navigation scenarios: you MUST land on the destination and assert something unique to it.
82125
82560
  4. PROVE the outcome with an assert tool that matches the scenario \u2014 not ambient chrome:
82126
82561
  - mobile_assert_visible({ref}) / mobile_assert_text({ref, expected})
82562
+ - For list delete/create or count changes: mobile_capture_state({stateKey, kind}) BEFORE the mutation, then mobile_assert_state_delta({stateKey, expect}) AFTER \u2014 proves identity/count change, not only "list screen still visible".
82127
82563
  - After sign-in \u2192 signed-in product signal; after like \u2192 liked/unlike control or durable like state; after open Settings \u2192 a settings-specific control.
82128
82564
  - Do NOT assert bottom-nav tab labels alone, notification badge counts ("N unread"), or one-time empty-state CTAs as the scenario outcome.
82129
82565
  5. Call finish_generate with verified:true ONLY if you completed the goal AND asserted a matching durable outcome. If the app cannot complete the goal, finish with verified:false and explain \u2014 never invent a green path from unrelated screens.
@@ -82237,6 +82673,7 @@ Start by calling mobile_snapshot, then execute ONLY the steps needed for this go
82237
82673
  const { scenario, driver, platform: platform3, maxIterations, agentModel, provider, aiClient, auditGroupId, onAICall, onScreenshot, targetAppId, credentials, redactionCredentials, log: emitLog, allowRelaunch } = args;
82238
82674
  const log2 = (line) => emitLog(redactCredentialValues(line, redactionCredentials));
82239
82675
  const actions = [];
82676
+ const stateBag = /* @__PURE__ */ new Map();
82240
82677
  let assertCount = 0;
82241
82678
  let finish = null;
82242
82679
  let finishIntentRejections = 0;
@@ -82706,7 +83143,9 @@ ${statePacket}`, redactionCredentials) },
82706
83143
  const screenDependentTools = /* @__PURE__ */ new Set([
82707
83144
  ...screenMutatingTools,
82708
83145
  "mobile_assert_visible",
82709
- "mobile_assert_text"
83146
+ "mobile_assert_text",
83147
+ "mobile_capture_state",
83148
+ "mobile_assert_state_delta"
82710
83149
  ]);
82711
83150
  for (const toolCall of assistantMessage.tool_calls) {
82712
83151
  const toolName = toolCall.function.name;
@@ -82750,7 +83189,7 @@ ${statePacket}`, redactionCredentials) },
82750
83189
  if (intentReason)
82751
83190
  reasons.push(intentReason);
82752
83191
  if (verifiedWithoutAssert) {
82753
- reasons.push("claimed verified:true but never called mobile_assert_visible / mobile_assert_text");
83192
+ reasons.push("claimed verified:true but never called mobile_assert_visible / mobile_assert_text / mobile_assert_state_delta");
82754
83193
  }
82755
83194
  if (strengthRejectReason !== null) {
82756
83195
  reasons.push(`assertion strength: ${strengthRejectReason} \u2014 your only live proof re-checks a control you already used. Assert the scenario OUTCOME instead: an element on the resulting screen, the created/updated row, or the success/error message.`);
@@ -82821,10 +83260,12 @@ ${statePacket}`, redactionCredentials) },
82821
83260
  }
82822
83261
  } : action;
82823
83262
  actions.push((0, shared_1.placeholderizeRecordedMobileAction)(finalizeAction(stamped), credentials));
82824
- if (action.type === "ASSERT_VISIBLE" || action.type === "ASSERT_TEXT")
83263
+ if (action.type === "ASSERT_VISIBLE" || action.type === "ASSERT_TEXT" || action.type === "ASSERT_STATE_DELTA") {
82825
83264
  assertCount++;
83265
+ }
82826
83266
  },
82827
83267
  recordedActions: actions,
83268
+ stateBag,
82828
83269
  log: log2
82829
83270
  });
82830
83271
  if (screenMutatingTools.has(toolName))
@@ -82843,7 +83284,7 @@ ${statePacket}`, redactionCredentials) },
82843
83284
  return { actions, assertCount, finish, lastSnapshot: lastTargetSnapshot, lastScreenName: lastTargetScreenName };
82844
83285
  }
82845
83286
  async function dispatchGenerateTool(args) {
82846
- const { toolName, toolArgs, driver, platform: platform3, targetAppId, latest, absorbObservation, resolveRef, resolveHybridRef, maybeEnrichHybridWeb, setLatest, credentials, screenName, allowRelaunch, recordAction, recordedActions, log: log2 } = args;
83287
+ const { toolName, toolArgs, driver, platform: platform3, targetAppId, latest, absorbObservation, resolveRef, resolveHybridRef, maybeEnrichHybridWeb, setLatest, credentials, screenName, allowRelaunch, recordAction, recordedActions, stateBag, log: log2 } = args;
82847
83288
  const unknownRef = (ref) => ({
82848
83289
  ok: false,
82849
83290
  error: `Unknown element ref "${String(ref)}". Call mobile_snapshot first; refs are only valid for the latest snapshot.`
@@ -83388,10 +83829,170 @@ ${statePacket}`, redactionCredentials) },
83388
83829
  target: metadata.targetLabel
83389
83830
  };
83390
83831
  }
83832
+ case "mobile_capture_state": {
83833
+ const stateKey = nonEmpty3(typeof toolArgs.stateKey === "string" ? toolArgs.stateKey : "");
83834
+ if (!stateKey) {
83835
+ return { ok: false, error: "mobile_capture_state requires a non-empty stateKey." };
83836
+ }
83837
+ const kindRaw = typeof toolArgs.kind === "string" ? toolArgs.kind.trim() : "list_ids";
83838
+ const kind = kindRaw === "badge_count" ? "badge_count" : "list_ids";
83839
+ const snap = latest();
83840
+ if (!snap) {
83841
+ return { ok: false, error: "No snapshot yet \u2014 call mobile_snapshot before mobile_capture_state." };
83842
+ }
83843
+ const values = captureValuesFromElements(snap.screen.elements, kind);
83844
+ stateBag.set(stateKey, { kind, values });
83845
+ recordAction({
83846
+ type: "CAPTURE_STATE",
83847
+ selector: stateKey,
83848
+ metadata: {
83849
+ screenName: screenName(),
83850
+ targetLabel: stateKey,
83851
+ stateKey,
83852
+ stateKind: kind
83853
+ }
83854
+ });
83855
+ log2(` capture_state: key=${stateKey} kind=${kind} n=${values.length}`);
83856
+ return {
83857
+ ok: true,
83858
+ captured: true,
83859
+ stateKey,
83860
+ kind,
83861
+ sample: values.slice(0, 8),
83862
+ count: values.length
83863
+ };
83864
+ }
83865
+ case "mobile_assert_state_delta": {
83866
+ const stateKey = nonEmpty3(typeof toolArgs.stateKey === "string" ? toolArgs.stateKey : "");
83867
+ if (!stateKey) {
83868
+ return { ok: false, error: "mobile_assert_state_delta requires a non-empty stateKey." };
83869
+ }
83870
+ const prior = stateBag.get(stateKey);
83871
+ if (!prior) {
83872
+ return {
83873
+ ok: false,
83874
+ error: `No prior mobile_capture_state for key "${stateKey}". Capture before the mutating action, then assert.`
83875
+ };
83876
+ }
83877
+ const expectRaw = typeof toolArgs.expect === "string" ? toolArgs.expect.trim() : "changed";
83878
+ const expect = expectRaw || "changed";
83879
+ const snap = latest();
83880
+ if (!snap) {
83881
+ return { ok: false, error: "No snapshot yet \u2014 call mobile_snapshot after the action, then assert_state_delta." };
83882
+ }
83883
+ const current = captureValuesFromElements(snap.screen.elements, prior.kind);
83884
+ const liveError = liveAssertStateDelta(prior.values, current, expect, stateKey);
83885
+ if (liveError) {
83886
+ return {
83887
+ ok: false,
83888
+ error: liveError,
83889
+ beforeSample: prior.values.slice(0, 8),
83890
+ afterSample: current.slice(0, 8)
83891
+ };
83892
+ }
83893
+ recordAction({
83894
+ type: "ASSERT_STATE_DELTA",
83895
+ value: expect,
83896
+ selector: stateKey,
83897
+ metadata: {
83898
+ screenName: screenName(),
83899
+ targetLabel: stateKey,
83900
+ stateKey,
83901
+ stateKind: prior.kind,
83902
+ expect
83903
+ }
83904
+ });
83905
+ log2(` assert_state_delta: key=${stateKey} expect=${expect}`);
83906
+ return {
83907
+ ok: true,
83908
+ asserted: "state_delta",
83909
+ stateKey,
83910
+ expect,
83911
+ beforeCount: prior.values.length,
83912
+ afterCount: current.length
83913
+ };
83914
+ }
83391
83915
  default:
83392
83916
  return { ok: false, error: `Unknown tool: ${toolName}` };
83393
83917
  }
83394
83918
  }
83919
+ function captureValuesFromElements(elements, kind) {
83920
+ if (kind === "badge_count") {
83921
+ const nums = /* @__PURE__ */ new Set();
83922
+ const preferred = /* @__PURE__ */ new Set();
83923
+ for (const el of elements) {
83924
+ const t = [el.label, el.text, el.accessibilityId].filter(Boolean).join(" ");
83925
+ for (const m of t.matchAll(/\b(\d{1,6})\b/g))
83926
+ nums.add(m[1]);
83927
+ if (/(?:count|badge|open|unread|item|invoice|result|pending)/i.test(t)) {
83928
+ for (const m of t.matchAll(/\b(\d{1,6})\b/g))
83929
+ preferred.add(m[1]);
83930
+ }
83931
+ }
83932
+ return preferred.size > 0 ? [...preferred] : [...nums].slice(0, 20);
83933
+ }
83934
+ const labels = /* @__PURE__ */ new Set();
83935
+ for (const el of elements) {
83936
+ for (const raw of [el.label, el.text, el.accessibilityId]) {
83937
+ const t = raw?.trim() ?? "";
83938
+ if (t.length < 2 || t.length > 80)
83939
+ continue;
83940
+ if (/^(true|false|null|OK|Cancel)$/i.test(t))
83941
+ continue;
83942
+ labels.add(t);
83943
+ }
83944
+ }
83945
+ return [...labels].slice(0, 80);
83946
+ }
83947
+ function liveAssertStateDelta(before, after, expect, key) {
83948
+ const beforeSet = new Set(before);
83949
+ const afterSet = new Set(after);
83950
+ const removed = before.filter((v) => !afterSet.has(v));
83951
+ const added = after.filter((v) => !beforeSet.has(v));
83952
+ const exp = expect.toLowerCase().trim();
83953
+ if (exp === "changed" || exp === "any_change") {
83954
+ if (removed.length === 0 && added.length === 0) {
83955
+ return `assertStateDelta(${key}): expected change, captures identical (${before.length} values)`;
83956
+ }
83957
+ return null;
83958
+ }
83959
+ if (exp === "removed" || exp === "entity_removed" || exp.startsWith("removed:")) {
83960
+ if (removed.length === 0) {
83961
+ return `assertStateDelta(${key}): expected at least one entity removed`;
83962
+ }
83963
+ return null;
83964
+ }
83965
+ if (exp === "count_decreased" || exp === "count-1") {
83966
+ const b = before.map(Number).filter((n) => Number.isFinite(n));
83967
+ const a = after.map(Number).filter((n) => Number.isFinite(n));
83968
+ const bMax = b.length ? Math.max(...b) : NaN;
83969
+ const aMax = a.length ? Math.max(...a) : NaN;
83970
+ if (!Number.isFinite(bMax) || !Number.isFinite(aMax) || aMax >= bMax) {
83971
+ return `assertStateDelta(${key}): expected count decrease (before max=${bMax}, after max=${aMax})`;
83972
+ }
83973
+ return null;
83974
+ }
83975
+ if (exp === "count_increased" || exp === "count+1") {
83976
+ const b = before.map(Number).filter((n) => Number.isFinite(n));
83977
+ const a = after.map(Number).filter((n) => Number.isFinite(n));
83978
+ const bMax = b.length ? Math.max(...b) : NaN;
83979
+ const aMax = a.length ? Math.max(...a) : NaN;
83980
+ if (!Number.isFinite(bMax) || !Number.isFinite(aMax) || aMax <= bMax) {
83981
+ return `assertStateDelta(${key}): expected count increase (before max=${bMax}, after max=${aMax})`;
83982
+ }
83983
+ return null;
83984
+ }
83985
+ if (exp === "unchanged" || exp === "persisted") {
83986
+ if (removed.length > 0 || added.length > 0) {
83987
+ return `assertStateDelta(${key}): expected persistence/unchanged but set changed`;
83988
+ }
83989
+ return null;
83990
+ }
83991
+ if (removed.length === 0 && added.length === 0) {
83992
+ return `assertStateDelta(${key}): expected change (expect=${expect}), state identical`;
83993
+ }
83994
+ return null;
83995
+ }
83395
83996
  function recordAssertVisible(toolArgs, ctx) {
83396
83997
  const { resolveRef, latest, screenName, platform: platform3, recordAction } = ctx;
83397
83998
  const element = resolveRef(toolArgs.ref);
@@ -84371,6 +84972,14 @@ ${statePacket}`, redactionCredentials) },
84371
84972
  lines.push(` await expect(page.getByText('${expected}')).toBeVisible();`);
84372
84973
  break;
84373
84974
  }
84975
+ case "CAPTURE_STATE":
84976
+ lines.push(` // captureState ${escape((action.metadata.stateKey ?? label).slice(0, 40))}`);
84977
+ break;
84978
+ case "ASSERT_STATE_DELTA": {
84979
+ const expect = escape((action.metadata.expect ?? action.value ?? "changed").slice(0, 40));
84980
+ lines.push(` await expect(page.getByText('state:${expect}')).toBeVisible();`);
84981
+ break;
84982
+ }
84374
84983
  case "CLEAR":
84375
84984
  lines.push(` await page.getByLabel('${label}').fill('');`);
84376
84985
  break;
@@ -84414,6 +85023,22 @@ ${statePacket}`, redactionCredentials) },
84414
85023
  return [action.selector, action.value, action.innerText, action.metadata?.targetLabel].filter((v) => typeof v === "string" && v.trim().length > 0).join(" ");
84415
85024
  }
84416
85025
  function evaluateMobileAssertionStrength(actions) {
85026
+ if (actions.some((a) => a.type === "ASSERT_STATE_DELTA")) {
85027
+ return {
85028
+ ok: true,
85029
+ severity: "none",
85030
+ reason: "state-delta oracle proves a durable product change (identity/count/persistence)",
85031
+ signals: {
85032
+ apiTest: false,
85033
+ interacted: actions.some((a) => a.type === "TAP" || a.type === "TYPE" || a.type === "CLEAR"),
85034
+ mutated: actions.some((a) => a.type === "TYPE" || a.type === "CLEAR" || a.type === "TAP"),
85035
+ navOnly: false,
85036
+ hasOutcomeProof: true,
85037
+ errorBanner: false,
85038
+ terminal: null
85039
+ }
85040
+ };
85041
+ }
84417
85042
  const modelAsserts = actions.filter((a) => a.type === "ASSERT_VISIBLE" || a.type === "ASSERT_TEXT");
84418
85043
  if (modelAsserts.length === 0) {
84419
85044
  return {
@@ -84583,6 +85208,16 @@ ${statePacket}`, redactionCredentials) },
84583
85208
  if (coldResetUnavailable)
84584
85209
  tags.push("@warm-state");
84585
85210
  const strengthBlocked = !strengthVerdict.ok || strengthVerdict.severity === "block" || strengthVerdict.severity === "route-bug" || !verified || coldResetUnavailable;
85211
+ {
85212
+ const kind = (0, scenario_taxonomy_js_1.inferScenarioKind)(scenario);
85213
+ const hasStateOracle = compiled.steps.some((s) => s.action === "assertStateDelta" || s.action === "assertText" || s.action === "captureState");
85214
+ const strong = verified && !strengthBlocked && strengthVerdict.severity === "none" && ((0, scenario_taxonomy_js_1.isStrongOracleKind)(kind) || hasStateOracle);
85215
+ if (strong)
85216
+ tags.push("@strong-oracle");
85217
+ else if (!tags.includes("@smoke") && (kind === "smoke_nav" || kind === "navigation_integrity")) {
85218
+ tags.push("@smoke");
85219
+ }
85220
+ }
84586
85221
  const strengthReason = coldResetUnavailable ? `Cold app-data reset unavailable${coldResetReason ? ` (${coldResetReason})` : ""} \u2014 generation may not match cold-boot replay. ${strengthVerdict.reason}` : !verified && recording.assertCount === 0 ? "Mobile scenario finished unverified \u2014 the agent never proved the scenario outcome live, so the recording may not demonstrate the goal (e.g. a happy path that never completed). Review before promotion." : strengthVerdict.reason;
84587
85222
  const test = {
84588
85223
  name: compiled.name,
@@ -84830,6 +85465,344 @@ Mobile generate phase complete: ${tests.length}/${scenarios.length} test(s) gene
84830
85465
  }
84831
85466
  });
84832
85467
 
85468
+ // ../runner-core/dist/services/mobile/failure-triage.js
85469
+ var require_failure_triage = __commonJS({
85470
+ "../runner-core/dist/services/mobile/failure-triage.js"(exports2) {
85471
+ "use strict";
85472
+ Object.defineProperty(exports2, "__esModule", { value: true });
85473
+ exports2.hasStrongMobileOracle = hasStrongMobileOracle;
85474
+ exports2.isStrongOracleStep = isStrongOracleStep;
85475
+ exports2.listStrongOracleKinds = listStrongOracleKinds;
85476
+ exports2.triageMobileFailure = triageMobileFailure;
85477
+ exports2.triageToHealTerminal = triageToHealTerminal;
85478
+ var STRONG_ACTIONS = /* @__PURE__ */ new Set(["assertStateDelta", "assertText", "captureState"]);
85479
+ var CHROME_VISIBLE_RE = /\b(tab|home|settings|back|menu|navigation|nav bar|bottom nav|status bar)\b/i;
85480
+ function hasStrongMobileOracle(steps) {
85481
+ return steps.some(isStrongOracleStep);
85482
+ }
85483
+ function isStrongOracleStep(step) {
85484
+ if (STRONG_ACTIONS.has(step.action))
85485
+ return true;
85486
+ if (step.action !== "assertVisible")
85487
+ return false;
85488
+ const blob = [
85489
+ step.assertion ?? "",
85490
+ step.description ?? "",
85491
+ step.target?.primary ?? "",
85492
+ ...step.target?.fallbacks ?? []
85493
+ ].join(" ");
85494
+ if (/\b(error|invalid|required|must|cannot|failed|denied|blocked|empty|missing|deleted|removed|saved|success|created|updated)\b/i.test(blob)) {
85495
+ return true;
85496
+ }
85497
+ if (CHROME_VISIBLE_RE.test(blob) && blob.length < 80)
85498
+ return false;
85499
+ return false;
85500
+ }
85501
+ function listStrongOracleKinds(steps) {
85502
+ const kinds = /* @__PURE__ */ new Set();
85503
+ for (const step of steps) {
85504
+ if (step.action === "assertStateDelta")
85505
+ kinds.add("assertStateDelta");
85506
+ else if (step.action === "assertText")
85507
+ kinds.add("assertText");
85508
+ else if (step.action === "captureState")
85509
+ kinds.add("captureState");
85510
+ else if (isStrongOracleStep(step))
85511
+ kinds.add(step.action);
85512
+ }
85513
+ return [...kinds];
85514
+ }
85515
+ function errorText(error2, logs2) {
85516
+ return `${error2 ?? ""}
85517
+ ${logs2 ?? ""}`.trim();
85518
+ }
85519
+ function leadingPrefix(error2) {
85520
+ if (!error2)
85521
+ return null;
85522
+ const m = error2.match(/^(CONFIG_ISSUE|APP_BUG|RATE_LIMIT_BLOCKED|PREREQ_UNMET|HEAL_SECRET_LEAK)\s*:/i);
85523
+ return m ? m[1].toUpperCase() : null;
85524
+ }
85525
+ function looksLikeConfig(text) {
85526
+ if (/CONFIG_ISSUE\s*:/i.test(text))
85527
+ return true;
85528
+ if (/RATE_LIMIT_BLOCKED\s*:/i.test(text))
85529
+ return true;
85530
+ if (/Missing mobile test variable/i.test(text))
85531
+ return true;
85532
+ if (/\b(quota|rate.?limit|429|lockout)\b/i.test(text))
85533
+ return true;
85534
+ if (/\b(device (?:offline|disconnected|not found)|session (?:not started|terminated|deleted))\b/i.test(text)) {
85535
+ return true;
85536
+ }
85537
+ if (/\b(Appium|adbExec|UiAutomator2|XCUITest)\b/i.test(text) && /\b(ECONNREFUSED|timeout|not available|could not start|driver)\b/i.test(text)) {
85538
+ return true;
85539
+ }
85540
+ return false;
85541
+ }
85542
+ function looksLikePrereq(text) {
85543
+ return /PREREQ_UNMET\s*:/i.test(text) || /\b(prerequisite|fixture missing|no test data|account (?:missing|not provisioned)|required entity)\b/i.test(text);
85544
+ }
85545
+ function looksLikeFlake(text) {
85546
+ return /\b(stale element|animation|transition|intermittent|flaky|race condition)\b/i.test(text) || /\b(element (?:is )?not interactable|obscured|covered by)\b/i.test(text);
85547
+ }
85548
+ function looksLikeLocatorMiss(text) {
85549
+ return /not found|no such element|No identity locator|unable to locate/i.test(text);
85550
+ }
85551
+ function looksLikeOracleFailure(text) {
85552
+ return /assertStateDelta/i.test(text) || /expected state/i.test(text) || /expected (?:["'].+["'] )?(?:to be |text|visible|removed|count)/i.test(text) || /assertion failed|Assert .+ (?:visible|shows|contains)/i.test(text);
85553
+ }
85554
+ function triageMobileFailure(input) {
85555
+ const failureCount = Math.max(1, input.failureCount ?? 1);
85556
+ const tags = input.tags ?? [];
85557
+ const text = errorText(input.error, input.logs);
85558
+ const prefix = leadingPrefix(input.error);
85559
+ const strongKinds = listStrongOracleKinds(input.steps);
85560
+ const hasStrong = strongKinds.length > 0 || tags.some((t) => t === "@strong-oracle" || t === "strong-oracle");
85561
+ const evidence = {
85562
+ hasStrongOracle: hasStrong,
85563
+ strongOracleKinds: strongKinds,
85564
+ failureCount,
85565
+ errorPrefix: prefix
85566
+ };
85567
+ if (prefix === "CONFIG_ISSUE" || prefix === "RATE_LIMIT_BLOCKED") {
85568
+ return {
85569
+ verdict: "config_issue",
85570
+ reason: `Environment/config prefix on error (${prefix})`,
85571
+ shouldHeal: false,
85572
+ healVerdict: "config_issue",
85573
+ evidence
85574
+ };
85575
+ }
85576
+ if (prefix === "APP_BUG") {
85577
+ return {
85578
+ verdict: "app_bug_candidate",
85579
+ reason: "Error already classified APP_BUG",
85580
+ shouldHeal: false,
85581
+ healVerdict: "app_bug",
85582
+ evidence
85583
+ };
85584
+ }
85585
+ if (prefix === "PREREQ_UNMET") {
85586
+ return {
85587
+ verdict: "prereq_unmet",
85588
+ reason: "Error already classified PREREQ_UNMET",
85589
+ shouldHeal: false,
85590
+ healVerdict: "prereq_unmet",
85591
+ evidence
85592
+ };
85593
+ }
85594
+ if (looksLikeConfig(text)) {
85595
+ return {
85596
+ verdict: "config_issue",
85597
+ reason: "Failure matches environment/config/device patterns",
85598
+ shouldHeal: false,
85599
+ healVerdict: "config_issue",
85600
+ evidence
85601
+ };
85602
+ }
85603
+ if (looksLikePrereq(text)) {
85604
+ return {
85605
+ verdict: "prereq_unmet",
85606
+ reason: "Failure matches missing prerequisite / fixture patterns",
85607
+ shouldHeal: false,
85608
+ healVerdict: "prereq_unmet",
85609
+ evidence
85610
+ };
85611
+ }
85612
+ if (input.uiSuccessWithFailedWriteApi && hasStrong) {
85613
+ return {
85614
+ verdict: "app_bug_candidate",
85615
+ reason: "UI path completed but a write API failed (network secondary oracle)",
85616
+ shouldHeal: false,
85617
+ healVerdict: "app_bug",
85618
+ evidence
85619
+ };
85620
+ }
85621
+ if (hasStrong && failureCount >= 2 && (looksLikeOracleFailure(text) || !looksLikeLocatorMiss(text))) {
85622
+ if (looksLikeLocatorMiss(text) && failureCount < 3) {
85623
+ return {
85624
+ verdict: "needs_heal",
85625
+ reason: "Strong oracle present but error looks like a locator miss \u2014 attempt heal",
85626
+ shouldHeal: true,
85627
+ evidence
85628
+ };
85629
+ }
85630
+ return {
85631
+ verdict: "app_bug_candidate",
85632
+ reason: `Strong oracle (${strongKinds.join(", ") || "tagged"}) failed ${failureCount}\xD7 with product-shaped error`,
85633
+ shouldHeal: false,
85634
+ healVerdict: "app_bug",
85635
+ evidence
85636
+ };
85637
+ }
85638
+ if (looksLikeFlake(text) && failureCount === 1 && !hasStrong) {
85639
+ return {
85640
+ verdict: "flake_candidate",
85641
+ reason: "Transient interactability / race signals on a weak-oracle test",
85642
+ shouldHeal: true,
85643
+ // still allow heal, but tag flaky path
85644
+ extraTags: ["@flaky"],
85645
+ evidence
85646
+ };
85647
+ }
85648
+ if (tags.includes("@smoke") && !hasStrong && looksLikeLocatorMiss(text)) {
85649
+ return {
85650
+ verdict: "needs_heal",
85651
+ reason: "Smoke/nav locator failure \u2014 heal allowed",
85652
+ shouldHeal: true,
85653
+ evidence
85654
+ };
85655
+ }
85656
+ return {
85657
+ verdict: "needs_heal",
85658
+ reason: hasStrong ? "Strong oracle first failure \u2014 allow heal once before APP_BUG escalation" : "Default: attempt script/live heal",
85659
+ shouldHeal: true,
85660
+ evidence
85661
+ };
85662
+ }
85663
+ function triageToHealTerminal(triage) {
85664
+ if (triage.shouldHeal || !triage.healVerdict)
85665
+ return null;
85666
+ return {
85667
+ verdict: triage.healVerdict,
85668
+ healReason: triage.reason,
85669
+ extraTags: triage.extraTags
85670
+ };
85671
+ }
85672
+ }
85673
+ });
85674
+
85675
+ // ../runner-core/dist/services/mobile/oracle-protection.js
85676
+ var require_oracle_protection = __commonJS({
85677
+ "../runner-core/dist/services/mobile/oracle-protection.js"(exports2) {
85678
+ "use strict";
85679
+ Object.defineProperty(exports2, "__esModule", { value: true });
85680
+ exports2.fingerprintOracles = fingerprintOracles;
85681
+ exports2.rejectOracleWeakeningPatch = rejectOracleWeakeningPatch;
85682
+ exports2.oraclesPreserved = oraclesPreserved;
85683
+ var failure_triage_js_1 = require_failure_triage();
85684
+ var EXPECT_STRENGTH = {
85685
+ entity_removed: 5,
85686
+ removed: 5,
85687
+ count_decreased: 4,
85688
+ "count-1": 4,
85689
+ count_increased: 4,
85690
+ "count+1": 4,
85691
+ persisted: 3,
85692
+ unchanged: 3,
85693
+ changed: 2,
85694
+ any_change: 2
85695
+ };
85696
+ function normalizeText(value) {
85697
+ return (value ?? "").trim().toLowerCase().replace(/\s+/g, " ");
85698
+ }
85699
+ function stateKeyOf(step) {
85700
+ const meta = step.metadata;
85701
+ const key = typeof meta?.stateKey === "string" ? meta.stateKey.trim() : "";
85702
+ return key || normalizeText(step.target?.primary) || normalizeText(step.description) || `order-${step.order}`;
85703
+ }
85704
+ function expectOf(step) {
85705
+ const meta = step.metadata;
85706
+ const fromMeta = typeof meta?.expect === "string" ? meta.expect : "";
85707
+ return normalizeText(fromMeta || step.assertion || step.value || "changed");
85708
+ }
85709
+ function fingerprintOracles(steps) {
85710
+ const assertTexts = [];
85711
+ const stateExpects = {};
85712
+ let stateDeltas = 0;
85713
+ let captures = 0;
85714
+ let strongVisible = 0;
85715
+ for (const step of steps) {
85716
+ if (step.action === "assertStateDelta") {
85717
+ stateDeltas += 1;
85718
+ stateExpects[stateKeyOf(step)] = expectOf(step);
85719
+ } else if (step.action === "captureState")
85720
+ captures += 1;
85721
+ else if (step.action === "assertText") {
85722
+ const t = normalizeText(step.assertion ?? step.value ?? step.description);
85723
+ if (t)
85724
+ assertTexts.push(t);
85725
+ } else if (step.action === "assertVisible" && (0, failure_triage_js_1.isStrongOracleStep)(step)) {
85726
+ strongVisible += 1;
85727
+ }
85728
+ }
85729
+ return {
85730
+ stateDeltas,
85731
+ captures,
85732
+ assertTexts,
85733
+ stateExpects,
85734
+ strongVisible,
85735
+ strongTotal: stateDeltas + captures + assertTexts.length + strongVisible
85736
+ };
85737
+ }
85738
+ function expectStrength(expect) {
85739
+ const e = expect.toLowerCase().trim();
85740
+ if (e.startsWith("removed:"))
85741
+ return 5;
85742
+ return EXPECT_STRENGTH[e] ?? 1;
85743
+ }
85744
+ function rejectOracleWeakeningPatch(original, patched) {
85745
+ if (!Array.isArray(patched) || patched.length === 0) {
85746
+ return "healed steps missing \u2014 refusing empty patch that would drop oracles";
85747
+ }
85748
+ const before = fingerprintOracles(original);
85749
+ const after = fingerprintOracles(patched);
85750
+ if (before.stateDeltas > 0 && after.stateDeltas < before.stateDeltas) {
85751
+ return `heal patch removed assertStateDelta oracle(s) (${before.stateDeltas} \u2192 ${after.stateDeltas}) \u2014 refusing to go green by dropping state proof`;
85752
+ }
85753
+ for (const [key, beforeExpect] of Object.entries(before.stateExpects)) {
85754
+ const afterExpect = after.stateExpects[key];
85755
+ if (!afterExpect) {
85756
+ return `heal patch removed assertStateDelta for key "${key}" (expect was ${beforeExpect})`;
85757
+ }
85758
+ if (expectStrength(afterExpect) < expectStrength(beforeExpect)) {
85759
+ return `heal patch softened assertStateDelta expect for "${key}" (${beforeExpect} \u2192 ${afterExpect})`;
85760
+ }
85761
+ }
85762
+ if (before.captures > 0 && after.captures < before.captures && after.stateDeltas === 0) {
85763
+ return `heal patch removed captureState without keeping assertStateDelta (${before.captures} \u2192 ${after.captures})`;
85764
+ }
85765
+ if (before.assertTexts.length > 0) {
85766
+ const afterSet = new Set(after.assertTexts);
85767
+ const lost = before.assertTexts.filter((t) => !afterSet.has(t));
85768
+ if (after.assertTexts.length < before.assertTexts.length) {
85769
+ return `heal patch dropped assertText outcome proof (${before.assertTexts.length} \u2192 ${after.assertTexts.length})`;
85770
+ }
85771
+ if (lost.length > 0) {
85772
+ const softKept = lost.every((t) => after.assertTexts.some((a) => a.includes(t) || t.includes(a)));
85773
+ if (!softKept) {
85774
+ return `heal patch replaced assertText expectations (${lost.slice(0, 2).join("; ")}) \u2014 outcome must stay`;
85775
+ }
85776
+ }
85777
+ }
85778
+ if (before.strongVisible > 0 && after.strongVisible + after.assertTexts.length + after.stateDeltas < before.strongVisible) {
85779
+ return `heal patch weakened strong assertVisible validation oracles (${before.strongVisible} \u2192 ${after.strongVisible})`;
85780
+ }
85781
+ if (before.strongTotal > 0 && after.strongTotal === 0) {
85782
+ return "heal patch removed all strong oracles \u2014 refusing visibility-only green path";
85783
+ }
85784
+ for (const orig of original) {
85785
+ if (orig.action !== "assertStateDelta" && orig.action !== "assertText")
85786
+ continue;
85787
+ const key = normalizeText(orig.description ?? orig.assertion ?? "");
85788
+ if (!key)
85789
+ continue;
85790
+ const stillStrong = patched.some((p) => (p.action === "assertStateDelta" || p.action === "assertText") && normalizeText(p.description ?? p.assertion ?? "") === key);
85791
+ if (stillStrong)
85792
+ continue;
85793
+ const onlyVisible = patched.some((p) => p.action === "assertVisible" && normalizeText(p.description ?? p.assertion ?? "") === key);
85794
+ if (onlyVisible) {
85795
+ return `heal patch downgraded strong oracle "${key.slice(0, 60)}" to assertVisible`;
85796
+ }
85797
+ }
85798
+ return null;
85799
+ }
85800
+ function oraclesPreserved(original, patched) {
85801
+ return rejectOracleWeakeningPatch(original, patched) === null;
85802
+ }
85803
+ }
85804
+ });
85805
+
84833
85806
  // ../runner-core/dist/services/mobile/mobile-heal-postprocess.js
84834
85807
  var require_mobile_heal_postprocess = __commonJS({
84835
85808
  "../runner-core/dist/services/mobile/mobile-heal-postprocess.js"(exports2) {
@@ -84838,6 +85811,7 @@ var require_mobile_heal_postprocess = __commonJS({
84838
85811
  exports2.redactMobileSecretsFromText = redactMobileSecretsFromText;
84839
85812
  exports2.detectMobileStepSecretLeak = detectMobileStepSecretLeak;
84840
85813
  exports2.computeMobileHealOutcome = computeMobileHealOutcome2;
85814
+ var oracle_protection_js_1 = require_oracle_protection();
84841
85815
  var REDACT_KEY_RE = /email|username|user|phone|password|secret|token|api[_-]?key|access[_-]?key|\bpass\b|credential|bearer|\bpat\b|session|cookie|jwt|otp|pin/i;
84842
85816
  var DETECT_KEY_RE = /password|secret|token|api[_]?key|\bpass\b|credential|bearer|\bpat\b/i;
84843
85817
  var MIN_REDACT_LEN = 4;
@@ -84903,18 +85877,27 @@ var require_mobile_heal_postprocess = __commonJS({
84903
85877
  function computeMobileHealOutcome2(args) {
84904
85878
  const { heal } = args;
84905
85879
  const hasFix = Array.isArray(heal.healedSteps) && heal.healedSteps.length > 0;
84906
- const isVerifiedFix = heal.passed === true && heal.verdict === "fix" && hasFix;
85880
+ let isVerifiedFix = heal.passed === true && heal.verdict === "fix" && hasFix;
84907
85881
  const secretLeak = isVerifiedFix ? detectMobileStepSecretLeak(heal.healedSteps, args.testVariables) : null;
85882
+ const oracleWeakening = isVerifiedFix && args.originalSteps ? (0, oracle_protection_js_1.rejectOracleWeakeningPatch)(args.originalSteps, heal.healedSteps ?? []) : null;
85883
+ if (oracleWeakening)
85884
+ isVerifiedFix = false;
84908
85885
  const isConfigIssue = heal.verdict === "config_issue";
84909
- const isAppBug = heal.verdict === "app_bug";
85886
+ const isAppBug = heal.verdict === "app_bug" || Boolean(oracleWeakening && heal.passed);
84910
85887
  const extraTags = new Set((heal.extraTags ?? []).filter((t) => typeof t === "string" && t.length > 0));
84911
85888
  if (secretLeak)
84912
85889
  extraTags.add("@needs-review");
85890
+ if (oracleWeakening) {
85891
+ extraTags.add("@needs-review");
85892
+ extraTags.add("@bug-found");
85893
+ }
84913
85894
  if (!heal.passed && NEEDS_REVIEW_VERDICTS.has(heal.verdict))
84914
85895
  extraTags.add("@needs-review");
84915
85896
  let status;
84916
85897
  if (secretLeak)
84917
85898
  status = "FAILED";
85899
+ else if (oracleWeakening)
85900
+ status = "FAILED";
84918
85901
  else if (isVerifiedFix)
84919
85902
  status = "PASSED";
84920
85903
  else if (isConfigIssue)
@@ -84926,6 +85909,8 @@ var require_mobile_heal_postprocess = __commonJS({
84926
85909
  error2 = void 0;
84927
85910
  } else if (secretLeak) {
84928
85911
  error2 = `HEAL_SECRET_LEAK: healed steps contained a literal secret (${secretLeak}); patch dropped, tagged @needs-review`;
85912
+ } else if (oracleWeakening) {
85913
+ error2 = `APP_BUG: heal attempted to drop strong oracle (${oracleWeakening}); patch refused`;
84929
85914
  } else if (isConfigIssue) {
84930
85915
  error2 = `CONFIG_ISSUE: ${heal.healReason ?? args.finalError ?? args.reproduceError ?? "environment/rate-limit blocker"}`;
84931
85916
  } else if (isAppBug) {
@@ -84942,13 +85927,64 @@ var require_mobile_heal_postprocess = __commonJS({
84942
85927
  error: error2,
84943
85928
  extraTags: extraTags.size > 0 ? [...extraTags] : void 0,
84944
85929
  removeTags: heal.removeTags,
84945
- shouldPatch: isVerifiedFix && !secretLeak,
85930
+ shouldPatch: isVerifiedFix && !secretLeak && !oracleWeakening,
84946
85931
  secretLeak
84947
85932
  };
84948
85933
  }
84949
85934
  }
84950
85935
  });
84951
85936
 
85937
+ // ../runner-core/dist/services/mobile/network-oracle.js
85938
+ var require_network_oracle = __commonJS({
85939
+ "../runner-core/dist/services/mobile/network-oracle.js"(exports2) {
85940
+ "use strict";
85941
+ Object.defineProperty(exports2, "__esModule", { value: true });
85942
+ exports2.evaluateNetworkSecondaryOracle = evaluateNetworkSecondaryOracle;
85943
+ exports2.uiSuccessWithFailedWriteApi = uiSuccessWithFailedWriteApi;
85944
+ var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
85945
+ function isWrite(method) {
85946
+ return WRITE_METHODS.has(method.toUpperCase());
85947
+ }
85948
+ function isServerOrClientError(status) {
85949
+ return status >= 400 && status < 600;
85950
+ }
85951
+ function isNoiseUrl(url) {
85952
+ return /\b(analytics|telemetry|sentry|bugsnag|crashlytics|facebook\.com\/tr|google-analytics|doubleclick|hotjar|segment\.io|amplitude|mixpanel)\b/i.test(url);
85953
+ }
85954
+ function evaluateNetworkSecondaryOracle(input) {
85955
+ const calls = input.apiCalls;
85956
+ if (!calls || calls.length === 0)
85957
+ return null;
85958
+ if (input.uiPathSucceeded === false)
85959
+ return null;
85960
+ for (const call of calls) {
85961
+ const method = String(call.method ?? "GET");
85962
+ const url = String(call.url ?? "");
85963
+ const status = typeof call.status === "number" ? call.status : 0;
85964
+ if (!isWrite(method))
85965
+ continue;
85966
+ if (!isServerOrClientError(status))
85967
+ continue;
85968
+ if (!url || isNoiseUrl(url))
85969
+ continue;
85970
+ if (status === 401 || status === 403)
85971
+ continue;
85972
+ return {
85973
+ kind: "write_api_failed",
85974
+ method: method.toUpperCase(),
85975
+ url: url.slice(0, 200),
85976
+ status,
85977
+ reason: `Write API ${method.toUpperCase()} ${url.slice(0, 120)} returned ${status} while UI path appeared successful`
85978
+ };
85979
+ }
85980
+ return null;
85981
+ }
85982
+ function uiSuccessWithFailedWriteApi(input) {
85983
+ return evaluateNetworkSecondaryOracle(input) !== null;
85984
+ }
85985
+ }
85986
+ });
85987
+
84952
85988
  // ../runner-core/dist/services/selector-registry-context.js
84953
85989
  var require_selector_registry_context = __commonJS({
84954
85990
  "../runner-core/dist/services/selector-registry-context.js"(exports2) {
@@ -85316,6 +86352,9 @@ var require_mobile_heal_loop = __commonJS({
85316
86352
  var ai_retry_js_1 = require_ai_retry();
85317
86353
  var mobile_source_parser_js_1 = require_mobile_source_parser();
85318
86354
  var mobile_heal_postprocess_js_1 = require_mobile_heal_postprocess();
86355
+ var failure_triage_js_1 = require_failure_triage();
86356
+ var oracle_protection_js_1 = require_oracle_protection();
86357
+ var network_oracle_js_1 = require_network_oracle();
85319
86358
  var mobile_observation_js_1 = require_mobile_observation();
85320
86359
  var selector_registry_context_js_1 = require_selector_registry_context();
85321
86360
  var mobile_session_keepalive_js_1 = require_mobile_session_keepalive();
@@ -85338,7 +86377,12 @@ Reason over steps + error + tree + registry and return working healed steps. Do
85338
86377
  {"verdict":"state_stale","reason":"leftover data blocks a baseline assertion"}
85339
86378
  {"verdict":"test_invalid","reason":"scenario cannot be made to pass"}
85340
86379
  {"verdict":"unhealable_dynamic","reason":"asserted value is inherently volatile (timestamps, counters, feeds) \u2014 no durable locator can exist; needs human review"}
85341
- For a fix, return the COMPLETE steps array (not a diff).`;
86380
+ For a fix, return the COMPLETE steps array (not a diff).
86381
+ ## Strong oracle protection (non-negotiable)
86382
+ - NEVER remove or downgrade assertStateDelta, captureState, or assertText outcome proof to go green.
86383
+ - NEVER replace a durable outcome assert with mere assertVisible of a tab/header.
86384
+ - You MAY fix locators, waits, and navigation around those oracles.
86385
+ - If the app truly violates the oracle, return verdict "app_bug" instead of stripping the assert.`;
85342
86386
  var DEFAULT_SCRIPT_MAX_ATTEMPTS = 6;
85343
86387
  var RECOVERABLE_MAX = 3;
85344
86388
  var MAX_CONSECUTIVE_INVALID_VERDICTS = 3;
@@ -85368,7 +86412,9 @@ For a fix, return the COMPLETE steps array (not a diff).`;
85368
86412
  "home",
85369
86413
  "waitForElement",
85370
86414
  "assertVisible",
85371
- "assertText"
86415
+ "assertText",
86416
+ "captureState",
86417
+ "assertStateDelta"
85372
86418
  ]);
85373
86419
  var MAX_HEALED_STEPS = 300;
85374
86420
  var TERMINAL_VERDICTS = /* @__PURE__ */ new Set([
@@ -85395,6 +86441,28 @@ For a fix, return the COMPLETE steps array (not a diff).`;
85395
86441
  function isMobileHealVerdict(value) {
85396
86442
  return MOBILE_HEAL_VERDICTS.includes(value);
85397
86443
  }
86444
+ function normalizeMobileHealVerdict(raw) {
86445
+ const v = raw.trim().toLowerCase().replace(/[\s-]+/g, "_");
86446
+ if (isMobileHealVerdict(v))
86447
+ return v;
86448
+ if (v === "appbug" || v === "application_bug" || v === "bug_found")
86449
+ return "app_bug";
86450
+ if (v === "config" || v === "configuration_issue" || v === "env" || v === "environment")
86451
+ return "config_issue";
86452
+ if (v === "prereq" || v === "prerequisite" || v === "prereq_missing")
86453
+ return "prereq_unmet";
86454
+ if (v === "stale" || v === "stale_state")
86455
+ return "state_stale";
86456
+ if (v === "invalid_test" || v === "bad_test")
86457
+ return "test_invalid";
86458
+ if (v === "unhealable" || v === "dynamic")
86459
+ return "unhealable_dynamic";
86460
+ if (v === "need_device" || v === "needs_appium" || v === "needs_live")
86461
+ return "needs_device";
86462
+ if (v === "healed" || v === "ok" || v === "pass" || v === "passed")
86463
+ return "fix";
86464
+ return null;
86465
+ }
85398
86466
  function isLocatorNotFound(error2) {
85399
86467
  return /not found|no such element/i.test(error2 ?? "");
85400
86468
  }
@@ -85676,15 +86744,43 @@ For a fix, return the COMPLETE steps array (not a diff).`;
85676
86744
  const sub = extractBracesSubstring(cleaned);
85677
86745
  obj = sub ? safeJsonParse(sub) : void 0;
85678
86746
  }
85679
- if (!isRecord(obj))
86747
+ if (!isRecord(obj)) {
86748
+ const line = cleaned.match(/\bverdict\s*[:=]\s*["']?([a-zA-Z_ -]+)["']?/i);
86749
+ if (line) {
86750
+ const verdict2 = normalizeMobileHealVerdict(line[1]);
86751
+ if (verdict2) {
86752
+ return {
86753
+ verdict: verdict2,
86754
+ reason: cleaned.slice(0, 2e3)
86755
+ };
86756
+ }
86757
+ }
86758
+ const prefix = cleaned.match(/^\s*(APP_BUG|CONFIG_ISSUE|PREREQ_UNMET|TEST_INVALID|STATE_STALE)\s*:\s*(.*)$/im);
86759
+ if (prefix) {
86760
+ const map2 = {
86761
+ APP_BUG: "app_bug",
86762
+ CONFIG_ISSUE: "config_issue",
86763
+ PREREQ_UNMET: "prereq_unmet",
86764
+ TEST_INVALID: "test_invalid",
86765
+ STATE_STALE: "state_stale"
86766
+ };
86767
+ const verdict2 = map2[prefix[1].toUpperCase()];
86768
+ if (verdict2) {
86769
+ return { verdict: verdict2, reason: (prefix[2] || cleaned).slice(0, 2e3) };
86770
+ }
86771
+ }
86772
+ return null;
86773
+ }
86774
+ const rawVerdict = obj.verdict ?? obj.Verdict ?? obj.status;
86775
+ if (typeof rawVerdict !== "string")
85680
86776
  return null;
85681
- const rawVerdict = obj.verdict;
85682
- if (typeof rawVerdict !== "string" || !isMobileHealVerdict(rawVerdict))
86777
+ const verdict = normalizeMobileHealVerdict(rawVerdict);
86778
+ if (!verdict)
85683
86779
  return null;
85684
86780
  return {
85685
- verdict: rawVerdict,
86781
+ verdict,
85686
86782
  steps: coerceSteps(obj.steps),
85687
- reason: typeof obj.reason === "string" ? obj.reason : void 0,
86783
+ reason: typeof obj.reason === "string" ? obj.reason : typeof obj.rationale === "string" ? obj.rationale : typeof obj.message === "string" ? obj.message : void 0,
85688
86784
  confidence: typeof obj.confidence === "number" ? obj.confidence : void 0
85689
86785
  };
85690
86786
  }
@@ -86033,7 +87129,7 @@ ${args.directive}`);
86033
87129
  };
86034
87130
  }
86035
87131
  markRecoverableTurn();
86036
- pendingDirective = "Your last response was not valid JSON matching the verdict schema. Return exactly one JSON verdict object \u2014 no prose, no markdown fences.";
87132
+ pendingDirective = 'SCHEMA REPAIR: Your last response was not a valid heal verdict. Reply with ONLY one JSON object (no markdown fences, no prose) of the form:\n{"verdict":"<one of: fix|app_bug|config_issue|needs_device|prereq_unmet|state_stale|test_invalid|unhealable_dynamic>","reason":"<short string>","steps":[/* optional MobileTestStep[] when verdict is fix */],"confidence":0.0}\nUse lowercase snake_case for verdict. Do not invent other verdict values.';
86037
87133
  continue;
86038
87134
  }
86039
87135
  consecutiveInvalidVerdicts = 0;
@@ -86062,6 +87158,13 @@ ${args.directive}`);
86062
87158
  pendingDirective = 'You returned verdict "fix" but no usable steps array. Return the COMPLETE healed MobileTestStep array.';
86063
87159
  continue;
86064
87160
  }
87161
+ const oracleRejection = (0, oracle_protection_js_1.rejectOracleWeakeningPatch)(steps, healedSteps);
87162
+ if (oracleRejection) {
87163
+ markRecoverableTurn();
87164
+ lastVerdict = "fix";
87165
+ pendingDirective = `ORACLE PROTECTION: ${oracleRejection}. Keep all assertStateDelta/assertText/captureState outcome proof; fix locators/navigation only. If the app violates the oracle, return verdict "app_bug".`;
87166
+ continue;
87167
+ }
86065
87168
  if (activeFailingSource && isLocatorNotFound(activeError) && !isDrift(activeError)) {
86066
87169
  const failingSourceSnapshot = activeFailingSource;
86067
87170
  const missing = timedSync("device-op", `phase1-attempt-${attempt}-static-verify`, options.onProgress, () => {
@@ -86205,6 +87308,28 @@ ${args.directive}`);
86205
87308
  if (invalidAuthSetup) {
86206
87309
  return { passed: false, verdict: "test_invalid", healReason: invalidAuthSetup };
86207
87310
  }
87311
+ const networkBug = (0, network_oracle_js_1.uiSuccessWithFailedWriteApi)({
87312
+ apiCalls: ctx.apiCalls,
87313
+ uiPathSucceeded: ctx.uiPathSucceeded
87314
+ });
87315
+ const triage = (0, failure_triage_js_1.triageMobileFailure)({
87316
+ steps,
87317
+ error: ctx.error,
87318
+ logs: ctx.logs,
87319
+ tags: ctx.tags,
87320
+ failureCount: ctx.failureCount,
87321
+ uiSuccessWithFailedWriteApi: networkBug
87322
+ });
87323
+ options.onProgress?.(`Pre-heal triage: ${triage.verdict} \u2014 ${triage.reason}`);
87324
+ const terminal = (0, failure_triage_js_1.triageToHealTerminal)(triage);
87325
+ if (terminal) {
87326
+ return {
87327
+ passed: false,
87328
+ verdict: terminal.verdict,
87329
+ healReason: terminal.healReason,
87330
+ extraTags: terminal.extraTags
87331
+ };
87332
+ }
86208
87333
  const preflight = await tryRegistryPreflight(steps, target, ctx, options);
86209
87334
  if (preflight)
86210
87335
  return preflight;
@@ -86454,6 +87579,11 @@ For a fix, return the COMPLETE steps array (not a diff). Use "observe" only to r
86454
87579
  if (parsed.verdict !== "fix" || !parsed.steps)
86455
87580
  continue;
86456
87581
  const healedSteps = parsed.steps;
87582
+ const liveOracleRejection = (0, oracle_protection_js_1.rejectOracleWeakeningPatch)(args.steps, healedSteps);
87583
+ if (liveOracleRejection) {
87584
+ options.onProgress?.(`ORACLE PROTECTION (live): ${liveOracleRejection}`);
87585
+ continue;
87586
+ }
86457
87587
  let verify;
86458
87588
  try {
86459
87589
  verify = await timed("reexec", `phase2-pass-${pass}-verify`, options.onProgress, () => runNativeTest({ steps: healedSteps, target, testVariables }));
@@ -87744,6 +88874,7 @@ var require_auth_recipe = __commonJS({
87744
88874
  var START_MARKER = `// >>> VALIDATE_QA_AUTH ${exports2.AUTH_MARKER_VERSION} \u2014 generated, do not edit >>>`;
87745
88875
  var END_MARKER = `// <<< VALIDATE_QA_AUTH ${exports2.AUTH_MARKER_VERSION} <<<`;
87746
88876
  var SHARED_AUTH_RUNTIME_ENABLED = `!/^false$/i.test((process.env.SHARED_AUTH_INJECT ?? '').trim())`;
88877
+ var WARM_PROOF_SETTLE_MS = 8e3;
87747
88878
  var AUTH_REGION_RE = /\/\/ >>> VALIDATE_QA_AUTH[^\n]*\r?\n[\s\S]*?\/\/ <<< VALIDATE_QA_AUTH[^\n]*\r?\n?/g;
87748
88879
  function computeRecipeHash(input) {
87749
88880
  const canonical = JSON.stringify({
@@ -87879,12 +89010,20 @@ ${tabs}`);
87879
89010
  const pred = urlProofPredicateExpr(recipe.authProof.route, recipe.authProof.exact);
87880
89011
  lines.push(` await page.waitForURL((u) => !(${pred})(u), { timeout: 2000 }).catch(() => {});`);
87881
89012
  lines.push(` if ((${pred})(new URL(page.url())) && !(await page.locator('input[type="password"]').first().isVisible().catch(() => false))) return;`);
87882
- } else if (loginRoute) {
87883
- lines.push(` if (await ${authProofLocator(recipe.authProof)}.isVisible().catch(() => false) && new URL(page.url()).pathname !== new URL(${JSON.stringify(loginRoute)}, page.url()).pathname) return;`);
87884
89013
  } else {
87885
- lines.push(` if (await ${authProofLocator(recipe.authProof)}.isVisible().catch(() => false)) return;`);
89014
+ const proofSettle = `await ${authProofLocator(recipe.authProof)}.waitFor({ state: 'visible', timeout: ${WARM_PROOF_SETTLE_MS} }).then(() => true).catch(() => false)`;
89015
+ if (loginRoute) {
89016
+ lines.push(` if (new URL(page.url()).pathname !== new URL(${JSON.stringify(loginRoute)}, page.url()).pathname && ${proofSettle}) return;`);
89017
+ } else {
89018
+ lines.push(` if (${proofSettle}) return;`);
89019
+ }
87886
89020
  }
87887
89021
  lines.push(` }`);
89022
+ lines.push(` if (${SHARED_AUTH_RUNTIME_ENABLED}) {`);
89023
+ lines.push(` await page.context().clearCookies().catch(() => {});`);
89024
+ lines.push(` await page.goto(${JSON.stringify(recipe.preNavRoute)}, { waitUntil: 'domcontentloaded' }).catch(() => {});`);
89025
+ lines.push(` await page.evaluate(() => { try { localStorage.clear(); sessionStorage.clear(); } catch {} }).catch(() => {});`);
89026
+ lines.push(` }`);
87888
89027
  }
87889
89028
  lines.push(` await page.goto(${JSON.stringify(recipe.preNavRoute)}, { waitUntil: 'domcontentloaded' });`);
87890
89029
  for (const cmd of recipe.preNavCmds)
@@ -95837,6 +96976,32 @@ var require_agentic_discovery_prompts = __commonJS({
95837
96976
  lines.push("For a pure navigation or page-load scenario (no in-page mutation), URL + one");
95838
96977
  lines.push("structural heading is sufficient.");
95839
96978
  lines.push("");
96979
+ lines.push("**Stop at the gate for expensive or irreversible actions.** Some controls");
96980
+ lines.push("start work that costs the account real money (an AI generation, a paid");
96981
+ lines.push("third-party call, a checkout), takes minutes to finish, or cannot be undone");
96982
+ lines.push("(delete, publish, cancel a subscription). Do NOT press them. The regression");
96983
+ lines.push("risk lives in the wiring, and the wiring is fully provable for free:");
96984
+ lines.push("- Assert the control is present and correctly ENABLED/DISABLED by its inputs.");
96985
+ lines.push("- If it opens a dialog, assert the dialog, its fields and its confirm button,");
96986
+ lines.push(" then press Cancel and assert nothing changed.");
96987
+ lines.push("- Assert the auth / quota wall fires for a caller who should be refused.");
96988
+ lines.push("A test that waits minutes for generated output cannot finish inside the run");
96989
+ lines.push("budget, bills the account on every run, and leaves permanent rows behind. If");
96990
+ lines.push("the ONLY way to prove a scenario is to trigger such an action, drop it as a");
96991
+ lines.push("gap rather than emitting a test that does.");
96992
+ lines.push("");
96993
+ lines.push("**Never sign up a new account.** Use the injected credentials. Registering a");
96994
+ lines.push("`testuser-<timestamp>` account to get past a login wall leaves a permanent,");
96995
+ lines.push("unowned user in the target database on every single run. Registration is in");
96996
+ lines.push("scope ONLY when the scenario under test IS registration, in which case use");
96997
+ lines.push("the provided inbox helper so the account is tracked and reaped.");
96998
+ lines.push("");
96999
+ lines.push("**Write the assertion so the BUG fails it.** When a scenario documents broken");
97000
+ lines.push("behaviour, still assert the CORRECT outcome. A test that passes because the");
97001
+ lines.push("error message / console error / not-found page is present inverts the suite:");
97002
+ lines.push("fixing the bug turns the test red and the fix is reported as a regression.");
97003
+ lines.push("State the intended behaviour, let it fail, and flag it as a bug.");
97004
+ lines.push("");
95840
97005
  lines.push("## Tools");
95841
97006
  lines.push("");
95842
97007
  lines.push("Browser MCP: `browser_navigate`, `browser_snapshot`, `browser_click`,");
@@ -96646,7 +97811,7 @@ var require_discover_generator = __commonJS({
96646
97811
  "../runner-core/dist/services/discover-generator.js"(exports2) {
96647
97812
  "use strict";
96648
97813
  Object.defineProperty(exports2, "__esModule", { value: true });
96649
- exports2.MIN_BUG_DESCRIPTION_LENGTH = exports2.VALID_PLAYWRIGHT_GETBY_METHODS = exports2.BLOCKED_MCP_TOOLS_SCENARIO_GEN = void 0;
97814
+ exports2.MIN_BUG_DESCRIPTION_LENGTH = exports2.NAME_PROHIBITED_ROLES = exports2.VALID_PLAYWRIGHT_GETBY_METHODS = exports2.BLOCKED_MCP_TOOLS_SCENARIO_GEN = void 0;
96650
97815
  exports2.scenarioLooksLikeRegistration = scenarioLooksLikeRegistration;
96651
97816
  exports2.signupFeatureTestingAllowed = signupFeatureTestingAllowed;
96652
97817
  exports2.scenarioTouchesSignupAuthSurface = scenarioTouchesSignupAuthSurface;
@@ -96676,6 +97841,7 @@ var require_discover_generator = __commonJS({
96676
97841
  exports2.scanFragileStructuralLocators = scanFragileStructuralLocators;
96677
97842
  exports2.bannedRoleTokensInSelector = bannedRoleTokensInSelector;
96678
97843
  exports2.scanInvalidRoleTagLocators = scanInvalidRoleTagLocators;
97844
+ exports2.scanNameProhibitedRoleLocators = scanNameProhibitedRoleLocators;
96679
97845
  exports2.scanHealedRoleTagLocators = scanHealedRoleTagLocators;
96680
97846
  exports2.validateFinalActionFidelity = validateFinalActionFidelity;
96681
97847
  exports2.resolveSuspectedBugVerdict = resolveSuspectedBugVerdict;
@@ -99743,10 +100909,55 @@ ${testOpen}`;
99743
100909
  }
99744
100910
  return findings;
99745
100911
  }
100912
+ exports2.NAME_PROHIBITED_ROLES = /* @__PURE__ */ new Set([
100913
+ "caption",
100914
+ "code",
100915
+ "deletion",
100916
+ "emphasis",
100917
+ "generic",
100918
+ "insertion",
100919
+ "mark",
100920
+ "none",
100921
+ "paragraph",
100922
+ "presentation",
100923
+ "strong",
100924
+ "subscript",
100925
+ "superscript",
100926
+ "term",
100927
+ "time"
100928
+ ]);
100929
+ function scanNameProhibitedRoleLocators(code) {
100930
+ const findings = [];
100931
+ const seen = /* @__PURE__ */ new Set();
100932
+ const scanCode = code.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "));
100933
+ const RE = /getByRole\(\s*(['"`])([a-zA-Z]+)\1\s*,\s*\{[^}]*\bname\s*:/g;
100934
+ for (const rawLine of scanCode.split("\n")) {
100935
+ const line = rawLine.replace(/\/\/.*$/, "");
100936
+ if (line.indexOf("getByRole(") === -1)
100937
+ continue;
100938
+ RE.lastIndex = 0;
100939
+ let m;
100940
+ while ((m = RE.exec(line)) !== null) {
100941
+ const role = m[2].toLowerCase();
100942
+ if (!exports2.NAME_PROHIBITED_ROLES.has(role))
100943
+ continue;
100944
+ const key = `${rawLine.trim()} ${role}`;
100945
+ if (seen.has(key))
100946
+ continue;
100947
+ seen.add(key);
100948
+ findings.push({
100949
+ line: rawLine.trim().slice(0, 200),
100950
+ role,
100951
+ reason: `ARIA prohibits an accessible name on role "${role}", so no element ever exposes one \u2014 getByRole('${role}', { name: \u2026 }) matches ZERO nodes and the assertion hangs to its timeout. Match the text instead: page.getByText('\u2026', { exact: true }), optionally scoped (e.g. page.getByRole('main').getByText('\u2026')). If you need the element itself, select a nameable ancestor (region/listitem/link/button) and assert its text.`
100952
+ });
100953
+ }
100954
+ }
100955
+ return findings;
100956
+ }
99746
100957
  function scanHealedRoleTagLocators(code, opts) {
99747
100958
  const inboxStripped = (0, inbox_stamp_js_1.stripInboxRegions)(code);
99748
100959
  const scanned = opts?.stripAuth === false ? inboxStripped : (0, auth_recipe_js_1.stripAuthRegions)(inboxStripped);
99749
- return scanInvalidRoleTagLocators(scanned);
100960
+ return [...scanInvalidRoleTagLocators(scanned), ...scanNameProhibitedRoleLocators(scanned)];
99750
100961
  }
99751
100962
  function validateFinalActionFidelity(playwrightCode, actionLedger, credentials, opts) {
99752
100963
  const ledgerSigs = [];
@@ -100467,7 +101678,7 @@ Do NOT add steps you did not execute. Do NOT skip steps from the recording.${led
100467
101678
  continue;
100468
101679
  }
100469
101680
  const roleTagMode = (0, discovery_lint_flags_js_1.roleTagLocatorLintMode)();
100470
- const roleTagFindings = roleTagMode !== "off" ? scanInvalidRoleTagLocators((0, auth_recipe_js_1.stripAuthRegions)((0, inbox_stamp_js_1.stripInboxRegions)(validated[0].playwrightCode))) : [];
101681
+ const roleTagFindings = roleTagMode !== "off" ? scanHealedRoleTagLocators(validated[0].playwrightCode) : [];
100471
101682
  if (roleTagMode === "warn" && roleTagFindings.length > 0) {
100472
101683
  logs2.push(` Role-tag locator gate [warn]: ${roleTagFindings.length} role-as-CSS-tag locator(s) \u2014 ${roleTagFindings.map((f) => sanitizeLedgerText(f.line)).join(" | ").slice(0, 300)}`);
100473
101684
  }
@@ -100480,12 +101691,10 @@ Do NOT add steps you did not execute. Do NOT skip steps from the recording.${led
100480
101691
  valid: false,
100481
101692
  revisionRequired: true,
100482
101693
  reason: "invalid_role_tag_locator",
100483
- instruction: targeted ? `One or more locators below use an ARIA ROLE as a CSS tag selector, e.g. page.locator('textbox[name^="code"]'). There is no <textbox>/<checkbox>/<heading> HTML element, so page.locator() matches ZERO nodes and the action hangs until the test times out.
100484
- For EACH flagged locator, rewrite it as a real Playwright locator:
100485
- 1. Prefer page.getByRole('<role>', { name: '<accessible name>' }) \u2014 the role is the token you wrongly put in the CSS.
100486
- 2. Or page.getByLabel('<label>'), or a type-scoped CSS like page.locator('input[type="text"]') / input[type="email"].
100487
- 3. For a verification-code field, prefer the injected helper: await __vqaEnterVerificationCode(page, code).
100488
- Keep every other line exactly as-is. Submit the COMPLETE corrected test and call finish_generate again.` : `Your resubmission STILL contains a locator that uses an ARIA role as a CSS tag selector (page.locator('<role>[\u2026]')). This can only ever match nothing. Replace EVERY such locator with page.getByRole('<role>', { name: '\u2026' }) / getByLabel / input[type="\u2026"], or use await __vqaEnterVerificationCode(page, code) for the code field, and resubmit the COMPLETE test.`,
101694
+ instruction: targeted ? `Every locator listed below matches ZERO nodes, so the step hangs until the test times out. Read the \`reason\` on each one \u2014 there are two distinct mistakes:
101695
+ (a) An ARIA ROLE used as a CSS tag selector, e.g. page.locator('textbox[name^="code"]'). There is no <textbox>/<checkbox>/<heading> element. Rewrite as page.getByRole('<role>', { name: '<accessible name>' }), or page.getByLabel('<label>'), or a type-scoped CSS like page.locator('input[type="email"]'). For a verification-code field prefer the injected helper: await __vqaEnterVerificationCode(page, code).
101696
+ (b) A { name: \u2026 } filter on a role whose accessible name ARIA PROHIBITS (paragraph, generic, code, emphasis, strong, term, time, mark, caption, presentation/none, insertion, deletion, sub/superscript). No element with those roles ever exposes a name. Match the text instead: page.getByText('\u2026', { exact: true }), scoped if needed (page.getByRole('main').getByText('\u2026')), or target a nameable ancestor such as region/listitem/link/button.
101697
+ Fix EVERY flagged locator, keep every other line exactly as-is, then submit the COMPLETE corrected test and call finish_generate again.` : `Your resubmission STILL contains a locator that can only ever match nothing \u2014 either an ARIA role used as a CSS tag selector (page.locator('<role>[\u2026]')) or a { name: \u2026 } filter on a name-prohibited role (paragraph/generic/code/emphasis/strong/term/time/\u2026). Replace EVERY one: use getByRole('<role>', { name: '\u2026' }) / getByLabel / input[type="\u2026"] for the first, and getByText('\u2026', { exact: true }) for the second. Resubmit the COMPLETE test.`,
100489
101698
  offendingLocators: roleTagFindings.map((f) => ({
100490
101699
  line: sanitizeLedgerText(f.line),
100491
101700
  reason: f.reason
@@ -101531,6 +102740,2285 @@ var require_rate_limit_detector = __commonJS({
101531
102740
  }
101532
102741
  });
101533
102742
 
102743
+ // ../../node_modules/source-map-support/node_modules/source-map/lib/base64.js
102744
+ var require_base64 = __commonJS({
102745
+ "../../node_modules/source-map-support/node_modules/source-map/lib/base64.js"(exports2) {
102746
+ "use strict";
102747
+ var intToCharMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
102748
+ exports2.encode = function(number) {
102749
+ if (0 <= number && number < intToCharMap.length) {
102750
+ return intToCharMap[number];
102751
+ }
102752
+ throw new TypeError("Must be between 0 and 63: " + number);
102753
+ };
102754
+ exports2.decode = function(charCode) {
102755
+ var bigA = 65;
102756
+ var bigZ = 90;
102757
+ var littleA = 97;
102758
+ var littleZ = 122;
102759
+ var zero = 48;
102760
+ var nine = 57;
102761
+ var plus = 43;
102762
+ var slash = 47;
102763
+ var littleOffset = 26;
102764
+ var numberOffset = 52;
102765
+ if (bigA <= charCode && charCode <= bigZ) {
102766
+ return charCode - bigA;
102767
+ }
102768
+ if (littleA <= charCode && charCode <= littleZ) {
102769
+ return charCode - littleA + littleOffset;
102770
+ }
102771
+ if (zero <= charCode && charCode <= nine) {
102772
+ return charCode - zero + numberOffset;
102773
+ }
102774
+ if (charCode == plus) {
102775
+ return 62;
102776
+ }
102777
+ if (charCode == slash) {
102778
+ return 63;
102779
+ }
102780
+ return -1;
102781
+ };
102782
+ }
102783
+ });
102784
+
102785
+ // ../../node_modules/source-map-support/node_modules/source-map/lib/base64-vlq.js
102786
+ var require_base64_vlq = __commonJS({
102787
+ "../../node_modules/source-map-support/node_modules/source-map/lib/base64-vlq.js"(exports2) {
102788
+ "use strict";
102789
+ var base64 = require_base64();
102790
+ var VLQ_BASE_SHIFT = 5;
102791
+ var VLQ_BASE = 1 << VLQ_BASE_SHIFT;
102792
+ var VLQ_BASE_MASK = VLQ_BASE - 1;
102793
+ var VLQ_CONTINUATION_BIT = VLQ_BASE;
102794
+ function toVLQSigned(aValue) {
102795
+ return aValue < 0 ? (-aValue << 1) + 1 : (aValue << 1) + 0;
102796
+ }
102797
+ function fromVLQSigned(aValue) {
102798
+ var isNegative = (aValue & 1) === 1;
102799
+ var shifted = aValue >> 1;
102800
+ return isNegative ? -shifted : shifted;
102801
+ }
102802
+ exports2.encode = function base64VLQ_encode(aValue) {
102803
+ var encoded = "";
102804
+ var digit;
102805
+ var vlq = toVLQSigned(aValue);
102806
+ do {
102807
+ digit = vlq & VLQ_BASE_MASK;
102808
+ vlq >>>= VLQ_BASE_SHIFT;
102809
+ if (vlq > 0) {
102810
+ digit |= VLQ_CONTINUATION_BIT;
102811
+ }
102812
+ encoded += base64.encode(digit);
102813
+ } while (vlq > 0);
102814
+ return encoded;
102815
+ };
102816
+ exports2.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) {
102817
+ var strLen = aStr.length;
102818
+ var result = 0;
102819
+ var shift = 0;
102820
+ var continuation, digit;
102821
+ do {
102822
+ if (aIndex >= strLen) {
102823
+ throw new Error("Expected more digits in base 64 VLQ value.");
102824
+ }
102825
+ digit = base64.decode(aStr.charCodeAt(aIndex++));
102826
+ if (digit === -1) {
102827
+ throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1));
102828
+ }
102829
+ continuation = !!(digit & VLQ_CONTINUATION_BIT);
102830
+ digit &= VLQ_BASE_MASK;
102831
+ result = result + (digit << shift);
102832
+ shift += VLQ_BASE_SHIFT;
102833
+ } while (continuation);
102834
+ aOutParam.value = fromVLQSigned(result);
102835
+ aOutParam.rest = aIndex;
102836
+ };
102837
+ }
102838
+ });
102839
+
102840
+ // ../../node_modules/source-map-support/node_modules/source-map/lib/util.js
102841
+ var require_util4 = __commonJS({
102842
+ "../../node_modules/source-map-support/node_modules/source-map/lib/util.js"(exports2) {
102843
+ "use strict";
102844
+ function getArg(aArgs, aName, aDefaultValue) {
102845
+ if (aName in aArgs) {
102846
+ return aArgs[aName];
102847
+ } else if (arguments.length === 3) {
102848
+ return aDefaultValue;
102849
+ } else {
102850
+ throw new Error('"' + aName + '" is a required argument.');
102851
+ }
102852
+ }
102853
+ exports2.getArg = getArg;
102854
+ var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;
102855
+ var dataUrlRegexp = /^data:.+\,.+$/;
102856
+ function urlParse(aUrl) {
102857
+ var match = aUrl.match(urlRegexp);
102858
+ if (!match) {
102859
+ return null;
102860
+ }
102861
+ return {
102862
+ scheme: match[1],
102863
+ auth: match[2],
102864
+ host: match[3],
102865
+ port: match[4],
102866
+ path: match[5]
102867
+ };
102868
+ }
102869
+ exports2.urlParse = urlParse;
102870
+ function urlGenerate(aParsedUrl) {
102871
+ var url = "";
102872
+ if (aParsedUrl.scheme) {
102873
+ url += aParsedUrl.scheme + ":";
102874
+ }
102875
+ url += "//";
102876
+ if (aParsedUrl.auth) {
102877
+ url += aParsedUrl.auth + "@";
102878
+ }
102879
+ if (aParsedUrl.host) {
102880
+ url += aParsedUrl.host;
102881
+ }
102882
+ if (aParsedUrl.port) {
102883
+ url += ":" + aParsedUrl.port;
102884
+ }
102885
+ if (aParsedUrl.path) {
102886
+ url += aParsedUrl.path;
102887
+ }
102888
+ return url;
102889
+ }
102890
+ exports2.urlGenerate = urlGenerate;
102891
+ function normalize(aPath) {
102892
+ var path = aPath;
102893
+ var url = urlParse(aPath);
102894
+ if (url) {
102895
+ if (!url.path) {
102896
+ return aPath;
102897
+ }
102898
+ path = url.path;
102899
+ }
102900
+ var isAbsolute2 = exports2.isAbsolute(path);
102901
+ var parts = path.split(/\/+/);
102902
+ for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
102903
+ part = parts[i];
102904
+ if (part === ".") {
102905
+ parts.splice(i, 1);
102906
+ } else if (part === "..") {
102907
+ up++;
102908
+ } else if (up > 0) {
102909
+ if (part === "") {
102910
+ parts.splice(i + 1, up);
102911
+ up = 0;
102912
+ } else {
102913
+ parts.splice(i, 2);
102914
+ up--;
102915
+ }
102916
+ }
102917
+ }
102918
+ path = parts.join("/");
102919
+ if (path === "") {
102920
+ path = isAbsolute2 ? "/" : ".";
102921
+ }
102922
+ if (url) {
102923
+ url.path = path;
102924
+ return urlGenerate(url);
102925
+ }
102926
+ return path;
102927
+ }
102928
+ exports2.normalize = normalize;
102929
+ function join8(aRoot, aPath) {
102930
+ if (aRoot === "") {
102931
+ aRoot = ".";
102932
+ }
102933
+ if (aPath === "") {
102934
+ aPath = ".";
102935
+ }
102936
+ var aPathUrl = urlParse(aPath);
102937
+ var aRootUrl = urlParse(aRoot);
102938
+ if (aRootUrl) {
102939
+ aRoot = aRootUrl.path || "/";
102940
+ }
102941
+ if (aPathUrl && !aPathUrl.scheme) {
102942
+ if (aRootUrl) {
102943
+ aPathUrl.scheme = aRootUrl.scheme;
102944
+ }
102945
+ return urlGenerate(aPathUrl);
102946
+ }
102947
+ if (aPathUrl || aPath.match(dataUrlRegexp)) {
102948
+ return aPath;
102949
+ }
102950
+ if (aRootUrl && !aRootUrl.host && !aRootUrl.path) {
102951
+ aRootUrl.host = aPath;
102952
+ return urlGenerate(aRootUrl);
102953
+ }
102954
+ var joined = aPath.charAt(0) === "/" ? aPath : normalize(aRoot.replace(/\/+$/, "") + "/" + aPath);
102955
+ if (aRootUrl) {
102956
+ aRootUrl.path = joined;
102957
+ return urlGenerate(aRootUrl);
102958
+ }
102959
+ return joined;
102960
+ }
102961
+ exports2.join = join8;
102962
+ exports2.isAbsolute = function(aPath) {
102963
+ return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
102964
+ };
102965
+ function relative(aRoot, aPath) {
102966
+ if (aRoot === "") {
102967
+ aRoot = ".";
102968
+ }
102969
+ aRoot = aRoot.replace(/\/$/, "");
102970
+ var level = 0;
102971
+ while (aPath.indexOf(aRoot + "/") !== 0) {
102972
+ var index = aRoot.lastIndexOf("/");
102973
+ if (index < 0) {
102974
+ return aPath;
102975
+ }
102976
+ aRoot = aRoot.slice(0, index);
102977
+ if (aRoot.match(/^([^\/]+:\/)?\/*$/)) {
102978
+ return aPath;
102979
+ }
102980
+ ++level;
102981
+ }
102982
+ return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
102983
+ }
102984
+ exports2.relative = relative;
102985
+ var supportsNullProto = (function() {
102986
+ var obj = /* @__PURE__ */ Object.create(null);
102987
+ return !("__proto__" in obj);
102988
+ })();
102989
+ function identity(s) {
102990
+ return s;
102991
+ }
102992
+ function toSetString(aStr) {
102993
+ if (isProtoString(aStr)) {
102994
+ return "$" + aStr;
102995
+ }
102996
+ return aStr;
102997
+ }
102998
+ exports2.toSetString = supportsNullProto ? identity : toSetString;
102999
+ function fromSetString(aStr) {
103000
+ if (isProtoString(aStr)) {
103001
+ return aStr.slice(1);
103002
+ }
103003
+ return aStr;
103004
+ }
103005
+ exports2.fromSetString = supportsNullProto ? identity : fromSetString;
103006
+ function isProtoString(s) {
103007
+ if (!s) {
103008
+ return false;
103009
+ }
103010
+ var length = s.length;
103011
+ if (length < 9) {
103012
+ return false;
103013
+ }
103014
+ if (s.charCodeAt(length - 1) !== 95 || s.charCodeAt(length - 2) !== 95 || s.charCodeAt(length - 3) !== 111 || s.charCodeAt(length - 4) !== 116 || s.charCodeAt(length - 5) !== 111 || s.charCodeAt(length - 6) !== 114 || s.charCodeAt(length - 7) !== 112 || s.charCodeAt(length - 8) !== 95 || s.charCodeAt(length - 9) !== 95) {
103015
+ return false;
103016
+ }
103017
+ for (var i = length - 10; i >= 0; i--) {
103018
+ if (s.charCodeAt(i) !== 36) {
103019
+ return false;
103020
+ }
103021
+ }
103022
+ return true;
103023
+ }
103024
+ function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
103025
+ var cmp = strcmp(mappingA.source, mappingB.source);
103026
+ if (cmp !== 0) {
103027
+ return cmp;
103028
+ }
103029
+ cmp = mappingA.originalLine - mappingB.originalLine;
103030
+ if (cmp !== 0) {
103031
+ return cmp;
103032
+ }
103033
+ cmp = mappingA.originalColumn - mappingB.originalColumn;
103034
+ if (cmp !== 0 || onlyCompareOriginal) {
103035
+ return cmp;
103036
+ }
103037
+ cmp = mappingA.generatedColumn - mappingB.generatedColumn;
103038
+ if (cmp !== 0) {
103039
+ return cmp;
103040
+ }
103041
+ cmp = mappingA.generatedLine - mappingB.generatedLine;
103042
+ if (cmp !== 0) {
103043
+ return cmp;
103044
+ }
103045
+ return strcmp(mappingA.name, mappingB.name);
103046
+ }
103047
+ exports2.compareByOriginalPositions = compareByOriginalPositions;
103048
+ function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) {
103049
+ var cmp = mappingA.generatedLine - mappingB.generatedLine;
103050
+ if (cmp !== 0) {
103051
+ return cmp;
103052
+ }
103053
+ cmp = mappingA.generatedColumn - mappingB.generatedColumn;
103054
+ if (cmp !== 0 || onlyCompareGenerated) {
103055
+ return cmp;
103056
+ }
103057
+ cmp = strcmp(mappingA.source, mappingB.source);
103058
+ if (cmp !== 0) {
103059
+ return cmp;
103060
+ }
103061
+ cmp = mappingA.originalLine - mappingB.originalLine;
103062
+ if (cmp !== 0) {
103063
+ return cmp;
103064
+ }
103065
+ cmp = mappingA.originalColumn - mappingB.originalColumn;
103066
+ if (cmp !== 0) {
103067
+ return cmp;
103068
+ }
103069
+ return strcmp(mappingA.name, mappingB.name);
103070
+ }
103071
+ exports2.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated;
103072
+ function strcmp(aStr1, aStr2) {
103073
+ if (aStr1 === aStr2) {
103074
+ return 0;
103075
+ }
103076
+ if (aStr1 === null) {
103077
+ return 1;
103078
+ }
103079
+ if (aStr2 === null) {
103080
+ return -1;
103081
+ }
103082
+ if (aStr1 > aStr2) {
103083
+ return 1;
103084
+ }
103085
+ return -1;
103086
+ }
103087
+ function compareByGeneratedPositionsInflated(mappingA, mappingB) {
103088
+ var cmp = mappingA.generatedLine - mappingB.generatedLine;
103089
+ if (cmp !== 0) {
103090
+ return cmp;
103091
+ }
103092
+ cmp = mappingA.generatedColumn - mappingB.generatedColumn;
103093
+ if (cmp !== 0) {
103094
+ return cmp;
103095
+ }
103096
+ cmp = strcmp(mappingA.source, mappingB.source);
103097
+ if (cmp !== 0) {
103098
+ return cmp;
103099
+ }
103100
+ cmp = mappingA.originalLine - mappingB.originalLine;
103101
+ if (cmp !== 0) {
103102
+ return cmp;
103103
+ }
103104
+ cmp = mappingA.originalColumn - mappingB.originalColumn;
103105
+ if (cmp !== 0) {
103106
+ return cmp;
103107
+ }
103108
+ return strcmp(mappingA.name, mappingB.name);
103109
+ }
103110
+ exports2.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated;
103111
+ function parseSourceMapInput(str) {
103112
+ return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, ""));
103113
+ }
103114
+ exports2.parseSourceMapInput = parseSourceMapInput;
103115
+ function computeSourceURL(sourceRoot, sourceURL, sourceMapURL) {
103116
+ sourceURL = sourceURL || "";
103117
+ if (sourceRoot) {
103118
+ if (sourceRoot[sourceRoot.length - 1] !== "/" && sourceURL[0] !== "/") {
103119
+ sourceRoot += "/";
103120
+ }
103121
+ sourceURL = sourceRoot + sourceURL;
103122
+ }
103123
+ if (sourceMapURL) {
103124
+ var parsed = urlParse(sourceMapURL);
103125
+ if (!parsed) {
103126
+ throw new Error("sourceMapURL could not be parsed");
103127
+ }
103128
+ if (parsed.path) {
103129
+ var index = parsed.path.lastIndexOf("/");
103130
+ if (index >= 0) {
103131
+ parsed.path = parsed.path.substring(0, index + 1);
103132
+ }
103133
+ }
103134
+ sourceURL = join8(urlGenerate(parsed), sourceURL);
103135
+ }
103136
+ return normalize(sourceURL);
103137
+ }
103138
+ exports2.computeSourceURL = computeSourceURL;
103139
+ }
103140
+ });
103141
+
103142
+ // ../../node_modules/source-map-support/node_modules/source-map/lib/array-set.js
103143
+ var require_array_set = __commonJS({
103144
+ "../../node_modules/source-map-support/node_modules/source-map/lib/array-set.js"(exports2) {
103145
+ "use strict";
103146
+ var util = require_util4();
103147
+ var has = Object.prototype.hasOwnProperty;
103148
+ var hasNativeMap = typeof Map !== "undefined";
103149
+ function ArraySet() {
103150
+ this._array = [];
103151
+ this._set = hasNativeMap ? /* @__PURE__ */ new Map() : /* @__PURE__ */ Object.create(null);
103152
+ }
103153
+ ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) {
103154
+ var set = new ArraySet();
103155
+ for (var i = 0, len = aArray.length; i < len; i++) {
103156
+ set.add(aArray[i], aAllowDuplicates);
103157
+ }
103158
+ return set;
103159
+ };
103160
+ ArraySet.prototype.size = function ArraySet_size() {
103161
+ return hasNativeMap ? this._set.size : Object.getOwnPropertyNames(this._set).length;
103162
+ };
103163
+ ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) {
103164
+ var sStr = hasNativeMap ? aStr : util.toSetString(aStr);
103165
+ var isDuplicate = hasNativeMap ? this.has(aStr) : has.call(this._set, sStr);
103166
+ var idx = this._array.length;
103167
+ if (!isDuplicate || aAllowDuplicates) {
103168
+ this._array.push(aStr);
103169
+ }
103170
+ if (!isDuplicate) {
103171
+ if (hasNativeMap) {
103172
+ this._set.set(aStr, idx);
103173
+ } else {
103174
+ this._set[sStr] = idx;
103175
+ }
103176
+ }
103177
+ };
103178
+ ArraySet.prototype.has = function ArraySet_has(aStr) {
103179
+ if (hasNativeMap) {
103180
+ return this._set.has(aStr);
103181
+ } else {
103182
+ var sStr = util.toSetString(aStr);
103183
+ return has.call(this._set, sStr);
103184
+ }
103185
+ };
103186
+ ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) {
103187
+ if (hasNativeMap) {
103188
+ var idx = this._set.get(aStr);
103189
+ if (idx >= 0) {
103190
+ return idx;
103191
+ }
103192
+ } else {
103193
+ var sStr = util.toSetString(aStr);
103194
+ if (has.call(this._set, sStr)) {
103195
+ return this._set[sStr];
103196
+ }
103197
+ }
103198
+ throw new Error('"' + aStr + '" is not in the set.');
103199
+ };
103200
+ ArraySet.prototype.at = function ArraySet_at(aIdx) {
103201
+ if (aIdx >= 0 && aIdx < this._array.length) {
103202
+ return this._array[aIdx];
103203
+ }
103204
+ throw new Error("No element indexed by " + aIdx);
103205
+ };
103206
+ ArraySet.prototype.toArray = function ArraySet_toArray() {
103207
+ return this._array.slice();
103208
+ };
103209
+ exports2.ArraySet = ArraySet;
103210
+ }
103211
+ });
103212
+
103213
+ // ../../node_modules/source-map-support/node_modules/source-map/lib/mapping-list.js
103214
+ var require_mapping_list = __commonJS({
103215
+ "../../node_modules/source-map-support/node_modules/source-map/lib/mapping-list.js"(exports2) {
103216
+ "use strict";
103217
+ var util = require_util4();
103218
+ function generatedPositionAfter(mappingA, mappingB) {
103219
+ var lineA = mappingA.generatedLine;
103220
+ var lineB = mappingB.generatedLine;
103221
+ var columnA = mappingA.generatedColumn;
103222
+ var columnB = mappingB.generatedColumn;
103223
+ return lineB > lineA || lineB == lineA && columnB >= columnA || util.compareByGeneratedPositionsInflated(mappingA, mappingB) <= 0;
103224
+ }
103225
+ function MappingList() {
103226
+ this._array = [];
103227
+ this._sorted = true;
103228
+ this._last = { generatedLine: -1, generatedColumn: 0 };
103229
+ }
103230
+ MappingList.prototype.unsortedForEach = function MappingList_forEach(aCallback, aThisArg) {
103231
+ this._array.forEach(aCallback, aThisArg);
103232
+ };
103233
+ MappingList.prototype.add = function MappingList_add(aMapping) {
103234
+ if (generatedPositionAfter(this._last, aMapping)) {
103235
+ this._last = aMapping;
103236
+ this._array.push(aMapping);
103237
+ } else {
103238
+ this._sorted = false;
103239
+ this._array.push(aMapping);
103240
+ }
103241
+ };
103242
+ MappingList.prototype.toArray = function MappingList_toArray() {
103243
+ if (!this._sorted) {
103244
+ this._array.sort(util.compareByGeneratedPositionsInflated);
103245
+ this._sorted = true;
103246
+ }
103247
+ return this._array;
103248
+ };
103249
+ exports2.MappingList = MappingList;
103250
+ }
103251
+ });
103252
+
103253
+ // ../../node_modules/source-map-support/node_modules/source-map/lib/source-map-generator.js
103254
+ var require_source_map_generator = __commonJS({
103255
+ "../../node_modules/source-map-support/node_modules/source-map/lib/source-map-generator.js"(exports2) {
103256
+ "use strict";
103257
+ var base64VLQ = require_base64_vlq();
103258
+ var util = require_util4();
103259
+ var ArraySet = require_array_set().ArraySet;
103260
+ var MappingList = require_mapping_list().MappingList;
103261
+ function SourceMapGenerator(aArgs) {
103262
+ if (!aArgs) {
103263
+ aArgs = {};
103264
+ }
103265
+ this._file = util.getArg(aArgs, "file", null);
103266
+ this._sourceRoot = util.getArg(aArgs, "sourceRoot", null);
103267
+ this._skipValidation = util.getArg(aArgs, "skipValidation", false);
103268
+ this._sources = new ArraySet();
103269
+ this._names = new ArraySet();
103270
+ this._mappings = new MappingList();
103271
+ this._sourcesContents = null;
103272
+ }
103273
+ SourceMapGenerator.prototype._version = 3;
103274
+ SourceMapGenerator.fromSourceMap = function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) {
103275
+ var sourceRoot = aSourceMapConsumer.sourceRoot;
103276
+ var generator = new SourceMapGenerator({
103277
+ file: aSourceMapConsumer.file,
103278
+ sourceRoot
103279
+ });
103280
+ aSourceMapConsumer.eachMapping(function(mapping) {
103281
+ var newMapping = {
103282
+ generated: {
103283
+ line: mapping.generatedLine,
103284
+ column: mapping.generatedColumn
103285
+ }
103286
+ };
103287
+ if (mapping.source != null) {
103288
+ newMapping.source = mapping.source;
103289
+ if (sourceRoot != null) {
103290
+ newMapping.source = util.relative(sourceRoot, newMapping.source);
103291
+ }
103292
+ newMapping.original = {
103293
+ line: mapping.originalLine,
103294
+ column: mapping.originalColumn
103295
+ };
103296
+ if (mapping.name != null) {
103297
+ newMapping.name = mapping.name;
103298
+ }
103299
+ }
103300
+ generator.addMapping(newMapping);
103301
+ });
103302
+ aSourceMapConsumer.sources.forEach(function(sourceFile) {
103303
+ var sourceRelative = sourceFile;
103304
+ if (sourceRoot !== null) {
103305
+ sourceRelative = util.relative(sourceRoot, sourceFile);
103306
+ }
103307
+ if (!generator._sources.has(sourceRelative)) {
103308
+ generator._sources.add(sourceRelative);
103309
+ }
103310
+ var content = aSourceMapConsumer.sourceContentFor(sourceFile);
103311
+ if (content != null) {
103312
+ generator.setSourceContent(sourceFile, content);
103313
+ }
103314
+ });
103315
+ return generator;
103316
+ };
103317
+ SourceMapGenerator.prototype.addMapping = function SourceMapGenerator_addMapping(aArgs) {
103318
+ var generated = util.getArg(aArgs, "generated");
103319
+ var original = util.getArg(aArgs, "original", null);
103320
+ var source = util.getArg(aArgs, "source", null);
103321
+ var name = util.getArg(aArgs, "name", null);
103322
+ if (!this._skipValidation) {
103323
+ this._validateMapping(generated, original, source, name);
103324
+ }
103325
+ if (source != null) {
103326
+ source = String(source);
103327
+ if (!this._sources.has(source)) {
103328
+ this._sources.add(source);
103329
+ }
103330
+ }
103331
+ if (name != null) {
103332
+ name = String(name);
103333
+ if (!this._names.has(name)) {
103334
+ this._names.add(name);
103335
+ }
103336
+ }
103337
+ this._mappings.add({
103338
+ generatedLine: generated.line,
103339
+ generatedColumn: generated.column,
103340
+ originalLine: original != null && original.line,
103341
+ originalColumn: original != null && original.column,
103342
+ source,
103343
+ name
103344
+ });
103345
+ };
103346
+ SourceMapGenerator.prototype.setSourceContent = function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
103347
+ var source = aSourceFile;
103348
+ if (this._sourceRoot != null) {
103349
+ source = util.relative(this._sourceRoot, source);
103350
+ }
103351
+ if (aSourceContent != null) {
103352
+ if (!this._sourcesContents) {
103353
+ this._sourcesContents = /* @__PURE__ */ Object.create(null);
103354
+ }
103355
+ this._sourcesContents[util.toSetString(source)] = aSourceContent;
103356
+ } else if (this._sourcesContents) {
103357
+ delete this._sourcesContents[util.toSetString(source)];
103358
+ if (Object.keys(this._sourcesContents).length === 0) {
103359
+ this._sourcesContents = null;
103360
+ }
103361
+ }
103362
+ };
103363
+ SourceMapGenerator.prototype.applySourceMap = function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) {
103364
+ var sourceFile = aSourceFile;
103365
+ if (aSourceFile == null) {
103366
+ if (aSourceMapConsumer.file == null) {
103367
+ throw new Error(
103368
+ `SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, or the source map's "file" property. Both were omitted.`
103369
+ );
103370
+ }
103371
+ sourceFile = aSourceMapConsumer.file;
103372
+ }
103373
+ var sourceRoot = this._sourceRoot;
103374
+ if (sourceRoot != null) {
103375
+ sourceFile = util.relative(sourceRoot, sourceFile);
103376
+ }
103377
+ var newSources = new ArraySet();
103378
+ var newNames = new ArraySet();
103379
+ this._mappings.unsortedForEach(function(mapping) {
103380
+ if (mapping.source === sourceFile && mapping.originalLine != null) {
103381
+ var original = aSourceMapConsumer.originalPositionFor({
103382
+ line: mapping.originalLine,
103383
+ column: mapping.originalColumn
103384
+ });
103385
+ if (original.source != null) {
103386
+ mapping.source = original.source;
103387
+ if (aSourceMapPath != null) {
103388
+ mapping.source = util.join(aSourceMapPath, mapping.source);
103389
+ }
103390
+ if (sourceRoot != null) {
103391
+ mapping.source = util.relative(sourceRoot, mapping.source);
103392
+ }
103393
+ mapping.originalLine = original.line;
103394
+ mapping.originalColumn = original.column;
103395
+ if (original.name != null) {
103396
+ mapping.name = original.name;
103397
+ }
103398
+ }
103399
+ }
103400
+ var source = mapping.source;
103401
+ if (source != null && !newSources.has(source)) {
103402
+ newSources.add(source);
103403
+ }
103404
+ var name = mapping.name;
103405
+ if (name != null && !newNames.has(name)) {
103406
+ newNames.add(name);
103407
+ }
103408
+ }, this);
103409
+ this._sources = newSources;
103410
+ this._names = newNames;
103411
+ aSourceMapConsumer.sources.forEach(function(sourceFile2) {
103412
+ var content = aSourceMapConsumer.sourceContentFor(sourceFile2);
103413
+ if (content != null) {
103414
+ if (aSourceMapPath != null) {
103415
+ sourceFile2 = util.join(aSourceMapPath, sourceFile2);
103416
+ }
103417
+ if (sourceRoot != null) {
103418
+ sourceFile2 = util.relative(sourceRoot, sourceFile2);
103419
+ }
103420
+ this.setSourceContent(sourceFile2, content);
103421
+ }
103422
+ }, this);
103423
+ };
103424
+ SourceMapGenerator.prototype._validateMapping = function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, aName) {
103425
+ if (aOriginal && typeof aOriginal.line !== "number" && typeof aOriginal.column !== "number") {
103426
+ throw new Error(
103427
+ "original.line and original.column are not numbers -- you probably meant to omit the original mapping entirely and only map the generated position. If so, pass null for the original mapping instead of an object with empty or null values."
103428
+ );
103429
+ }
103430
+ if (aGenerated && "line" in aGenerated && "column" in aGenerated && aGenerated.line > 0 && aGenerated.column >= 0 && !aOriginal && !aSource && !aName) {
103431
+ return;
103432
+ } else if (aGenerated && "line" in aGenerated && "column" in aGenerated && aOriginal && "line" in aOriginal && "column" in aOriginal && aGenerated.line > 0 && aGenerated.column >= 0 && aOriginal.line > 0 && aOriginal.column >= 0 && aSource) {
103433
+ return;
103434
+ } else {
103435
+ throw new Error("Invalid mapping: " + JSON.stringify({
103436
+ generated: aGenerated,
103437
+ source: aSource,
103438
+ original: aOriginal,
103439
+ name: aName
103440
+ }));
103441
+ }
103442
+ };
103443
+ SourceMapGenerator.prototype._serializeMappings = function SourceMapGenerator_serializeMappings() {
103444
+ var previousGeneratedColumn = 0;
103445
+ var previousGeneratedLine = 1;
103446
+ var previousOriginalColumn = 0;
103447
+ var previousOriginalLine = 0;
103448
+ var previousName = 0;
103449
+ var previousSource = 0;
103450
+ var result = "";
103451
+ var next;
103452
+ var mapping;
103453
+ var nameIdx;
103454
+ var sourceIdx;
103455
+ var mappings = this._mappings.toArray();
103456
+ for (var i = 0, len = mappings.length; i < len; i++) {
103457
+ mapping = mappings[i];
103458
+ next = "";
103459
+ if (mapping.generatedLine !== previousGeneratedLine) {
103460
+ previousGeneratedColumn = 0;
103461
+ while (mapping.generatedLine !== previousGeneratedLine) {
103462
+ next += ";";
103463
+ previousGeneratedLine++;
103464
+ }
103465
+ } else {
103466
+ if (i > 0) {
103467
+ if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) {
103468
+ continue;
103469
+ }
103470
+ next += ",";
103471
+ }
103472
+ }
103473
+ next += base64VLQ.encode(mapping.generatedColumn - previousGeneratedColumn);
103474
+ previousGeneratedColumn = mapping.generatedColumn;
103475
+ if (mapping.source != null) {
103476
+ sourceIdx = this._sources.indexOf(mapping.source);
103477
+ next += base64VLQ.encode(sourceIdx - previousSource);
103478
+ previousSource = sourceIdx;
103479
+ next += base64VLQ.encode(mapping.originalLine - 1 - previousOriginalLine);
103480
+ previousOriginalLine = mapping.originalLine - 1;
103481
+ next += base64VLQ.encode(mapping.originalColumn - previousOriginalColumn);
103482
+ previousOriginalColumn = mapping.originalColumn;
103483
+ if (mapping.name != null) {
103484
+ nameIdx = this._names.indexOf(mapping.name);
103485
+ next += base64VLQ.encode(nameIdx - previousName);
103486
+ previousName = nameIdx;
103487
+ }
103488
+ }
103489
+ result += next;
103490
+ }
103491
+ return result;
103492
+ };
103493
+ SourceMapGenerator.prototype._generateSourcesContent = function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) {
103494
+ return aSources.map(function(source) {
103495
+ if (!this._sourcesContents) {
103496
+ return null;
103497
+ }
103498
+ if (aSourceRoot != null) {
103499
+ source = util.relative(aSourceRoot, source);
103500
+ }
103501
+ var key = util.toSetString(source);
103502
+ return Object.prototype.hasOwnProperty.call(this._sourcesContents, key) ? this._sourcesContents[key] : null;
103503
+ }, this);
103504
+ };
103505
+ SourceMapGenerator.prototype.toJSON = function SourceMapGenerator_toJSON() {
103506
+ var map2 = {
103507
+ version: this._version,
103508
+ sources: this._sources.toArray(),
103509
+ names: this._names.toArray(),
103510
+ mappings: this._serializeMappings()
103511
+ };
103512
+ if (this._file != null) {
103513
+ map2.file = this._file;
103514
+ }
103515
+ if (this._sourceRoot != null) {
103516
+ map2.sourceRoot = this._sourceRoot;
103517
+ }
103518
+ if (this._sourcesContents) {
103519
+ map2.sourcesContent = this._generateSourcesContent(map2.sources, map2.sourceRoot);
103520
+ }
103521
+ return map2;
103522
+ };
103523
+ SourceMapGenerator.prototype.toString = function SourceMapGenerator_toString() {
103524
+ return JSON.stringify(this.toJSON());
103525
+ };
103526
+ exports2.SourceMapGenerator = SourceMapGenerator;
103527
+ }
103528
+ });
103529
+
103530
+ // ../../node_modules/source-map-support/node_modules/source-map/lib/binary-search.js
103531
+ var require_binary_search = __commonJS({
103532
+ "../../node_modules/source-map-support/node_modules/source-map/lib/binary-search.js"(exports2) {
103533
+ "use strict";
103534
+ exports2.GREATEST_LOWER_BOUND = 1;
103535
+ exports2.LEAST_UPPER_BOUND = 2;
103536
+ function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare, aBias) {
103537
+ var mid = Math.floor((aHigh - aLow) / 2) + aLow;
103538
+ var cmp = aCompare(aNeedle, aHaystack[mid], true);
103539
+ if (cmp === 0) {
103540
+ return mid;
103541
+ } else if (cmp > 0) {
103542
+ if (aHigh - mid > 1) {
103543
+ return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare, aBias);
103544
+ }
103545
+ if (aBias == exports2.LEAST_UPPER_BOUND) {
103546
+ return aHigh < aHaystack.length ? aHigh : -1;
103547
+ } else {
103548
+ return mid;
103549
+ }
103550
+ } else {
103551
+ if (mid - aLow > 1) {
103552
+ return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare, aBias);
103553
+ }
103554
+ if (aBias == exports2.LEAST_UPPER_BOUND) {
103555
+ return mid;
103556
+ } else {
103557
+ return aLow < 0 ? -1 : aLow;
103558
+ }
103559
+ }
103560
+ }
103561
+ exports2.search = function search(aNeedle, aHaystack, aCompare, aBias) {
103562
+ if (aHaystack.length === 0) {
103563
+ return -1;
103564
+ }
103565
+ var index = recursiveSearch(
103566
+ -1,
103567
+ aHaystack.length,
103568
+ aNeedle,
103569
+ aHaystack,
103570
+ aCompare,
103571
+ aBias || exports2.GREATEST_LOWER_BOUND
103572
+ );
103573
+ if (index < 0) {
103574
+ return -1;
103575
+ }
103576
+ while (index - 1 >= 0) {
103577
+ if (aCompare(aHaystack[index], aHaystack[index - 1], true) !== 0) {
103578
+ break;
103579
+ }
103580
+ --index;
103581
+ }
103582
+ return index;
103583
+ };
103584
+ }
103585
+ });
103586
+
103587
+ // ../../node_modules/source-map-support/node_modules/source-map/lib/quick-sort.js
103588
+ var require_quick_sort = __commonJS({
103589
+ "../../node_modules/source-map-support/node_modules/source-map/lib/quick-sort.js"(exports2) {
103590
+ "use strict";
103591
+ function swap(ary, x, y) {
103592
+ var temp = ary[x];
103593
+ ary[x] = ary[y];
103594
+ ary[y] = temp;
103595
+ }
103596
+ function randomIntInRange(low, high) {
103597
+ return Math.round(low + Math.random() * (high - low));
103598
+ }
103599
+ function doQuickSort(ary, comparator, p, r) {
103600
+ if (p < r) {
103601
+ var pivotIndex = randomIntInRange(p, r);
103602
+ var i = p - 1;
103603
+ swap(ary, pivotIndex, r);
103604
+ var pivot = ary[r];
103605
+ for (var j = p; j < r; j++) {
103606
+ if (comparator(ary[j], pivot) <= 0) {
103607
+ i += 1;
103608
+ swap(ary, i, j);
103609
+ }
103610
+ }
103611
+ swap(ary, i + 1, j);
103612
+ var q = i + 1;
103613
+ doQuickSort(ary, comparator, p, q - 1);
103614
+ doQuickSort(ary, comparator, q + 1, r);
103615
+ }
103616
+ }
103617
+ exports2.quickSort = function(ary, comparator) {
103618
+ doQuickSort(ary, comparator, 0, ary.length - 1);
103619
+ };
103620
+ }
103621
+ });
103622
+
103623
+ // ../../node_modules/source-map-support/node_modules/source-map/lib/source-map-consumer.js
103624
+ var require_source_map_consumer = __commonJS({
103625
+ "../../node_modules/source-map-support/node_modules/source-map/lib/source-map-consumer.js"(exports2) {
103626
+ "use strict";
103627
+ var util = require_util4();
103628
+ var binarySearch = require_binary_search();
103629
+ var ArraySet = require_array_set().ArraySet;
103630
+ var base64VLQ = require_base64_vlq();
103631
+ var quickSort = require_quick_sort().quickSort;
103632
+ function SourceMapConsumer(aSourceMap, aSourceMapURL) {
103633
+ var sourceMap = aSourceMap;
103634
+ if (typeof aSourceMap === "string") {
103635
+ sourceMap = util.parseSourceMapInput(aSourceMap);
103636
+ }
103637
+ return sourceMap.sections != null ? new IndexedSourceMapConsumer(sourceMap, aSourceMapURL) : new BasicSourceMapConsumer(sourceMap, aSourceMapURL);
103638
+ }
103639
+ SourceMapConsumer.fromSourceMap = function(aSourceMap, aSourceMapURL) {
103640
+ return BasicSourceMapConsumer.fromSourceMap(aSourceMap, aSourceMapURL);
103641
+ };
103642
+ SourceMapConsumer.prototype._version = 3;
103643
+ SourceMapConsumer.prototype.__generatedMappings = null;
103644
+ Object.defineProperty(SourceMapConsumer.prototype, "_generatedMappings", {
103645
+ configurable: true,
103646
+ enumerable: true,
103647
+ get: function() {
103648
+ if (!this.__generatedMappings) {
103649
+ this._parseMappings(this._mappings, this.sourceRoot);
103650
+ }
103651
+ return this.__generatedMappings;
103652
+ }
103653
+ });
103654
+ SourceMapConsumer.prototype.__originalMappings = null;
103655
+ Object.defineProperty(SourceMapConsumer.prototype, "_originalMappings", {
103656
+ configurable: true,
103657
+ enumerable: true,
103658
+ get: function() {
103659
+ if (!this.__originalMappings) {
103660
+ this._parseMappings(this._mappings, this.sourceRoot);
103661
+ }
103662
+ return this.__originalMappings;
103663
+ }
103664
+ });
103665
+ SourceMapConsumer.prototype._charIsMappingSeparator = function SourceMapConsumer_charIsMappingSeparator(aStr, index) {
103666
+ var c = aStr.charAt(index);
103667
+ return c === ";" || c === ",";
103668
+ };
103669
+ SourceMapConsumer.prototype._parseMappings = function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
103670
+ throw new Error("Subclasses must implement _parseMappings");
103671
+ };
103672
+ SourceMapConsumer.GENERATED_ORDER = 1;
103673
+ SourceMapConsumer.ORIGINAL_ORDER = 2;
103674
+ SourceMapConsumer.GREATEST_LOWER_BOUND = 1;
103675
+ SourceMapConsumer.LEAST_UPPER_BOUND = 2;
103676
+ SourceMapConsumer.prototype.eachMapping = function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) {
103677
+ var context = aContext || null;
103678
+ var order = aOrder || SourceMapConsumer.GENERATED_ORDER;
103679
+ var mappings;
103680
+ switch (order) {
103681
+ case SourceMapConsumer.GENERATED_ORDER:
103682
+ mappings = this._generatedMappings;
103683
+ break;
103684
+ case SourceMapConsumer.ORIGINAL_ORDER:
103685
+ mappings = this._originalMappings;
103686
+ break;
103687
+ default:
103688
+ throw new Error("Unknown order of iteration.");
103689
+ }
103690
+ var sourceRoot = this.sourceRoot;
103691
+ mappings.map(function(mapping) {
103692
+ var source = mapping.source === null ? null : this._sources.at(mapping.source);
103693
+ source = util.computeSourceURL(sourceRoot, source, this._sourceMapURL);
103694
+ return {
103695
+ source,
103696
+ generatedLine: mapping.generatedLine,
103697
+ generatedColumn: mapping.generatedColumn,
103698
+ originalLine: mapping.originalLine,
103699
+ originalColumn: mapping.originalColumn,
103700
+ name: mapping.name === null ? null : this._names.at(mapping.name)
103701
+ };
103702
+ }, this).forEach(aCallback, context);
103703
+ };
103704
+ SourceMapConsumer.prototype.allGeneratedPositionsFor = function SourceMapConsumer_allGeneratedPositionsFor(aArgs) {
103705
+ var line = util.getArg(aArgs, "line");
103706
+ var needle = {
103707
+ source: util.getArg(aArgs, "source"),
103708
+ originalLine: line,
103709
+ originalColumn: util.getArg(aArgs, "column", 0)
103710
+ };
103711
+ needle.source = this._findSourceIndex(needle.source);
103712
+ if (needle.source < 0) {
103713
+ return [];
103714
+ }
103715
+ var mappings = [];
103716
+ var index = this._findMapping(
103717
+ needle,
103718
+ this._originalMappings,
103719
+ "originalLine",
103720
+ "originalColumn",
103721
+ util.compareByOriginalPositions,
103722
+ binarySearch.LEAST_UPPER_BOUND
103723
+ );
103724
+ if (index >= 0) {
103725
+ var mapping = this._originalMappings[index];
103726
+ if (aArgs.column === void 0) {
103727
+ var originalLine = mapping.originalLine;
103728
+ while (mapping && mapping.originalLine === originalLine) {
103729
+ mappings.push({
103730
+ line: util.getArg(mapping, "generatedLine", null),
103731
+ column: util.getArg(mapping, "generatedColumn", null),
103732
+ lastColumn: util.getArg(mapping, "lastGeneratedColumn", null)
103733
+ });
103734
+ mapping = this._originalMappings[++index];
103735
+ }
103736
+ } else {
103737
+ var originalColumn = mapping.originalColumn;
103738
+ while (mapping && mapping.originalLine === line && mapping.originalColumn == originalColumn) {
103739
+ mappings.push({
103740
+ line: util.getArg(mapping, "generatedLine", null),
103741
+ column: util.getArg(mapping, "generatedColumn", null),
103742
+ lastColumn: util.getArg(mapping, "lastGeneratedColumn", null)
103743
+ });
103744
+ mapping = this._originalMappings[++index];
103745
+ }
103746
+ }
103747
+ }
103748
+ return mappings;
103749
+ };
103750
+ exports2.SourceMapConsumer = SourceMapConsumer;
103751
+ function BasicSourceMapConsumer(aSourceMap, aSourceMapURL) {
103752
+ var sourceMap = aSourceMap;
103753
+ if (typeof aSourceMap === "string") {
103754
+ sourceMap = util.parseSourceMapInput(aSourceMap);
103755
+ }
103756
+ var version = util.getArg(sourceMap, "version");
103757
+ var sources = util.getArg(sourceMap, "sources");
103758
+ var names = util.getArg(sourceMap, "names", []);
103759
+ var sourceRoot = util.getArg(sourceMap, "sourceRoot", null);
103760
+ var sourcesContent = util.getArg(sourceMap, "sourcesContent", null);
103761
+ var mappings = util.getArg(sourceMap, "mappings");
103762
+ var file = util.getArg(sourceMap, "file", null);
103763
+ if (version != this._version) {
103764
+ throw new Error("Unsupported version: " + version);
103765
+ }
103766
+ if (sourceRoot) {
103767
+ sourceRoot = util.normalize(sourceRoot);
103768
+ }
103769
+ sources = sources.map(String).map(util.normalize).map(function(source) {
103770
+ return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source) ? util.relative(sourceRoot, source) : source;
103771
+ });
103772
+ this._names = ArraySet.fromArray(names.map(String), true);
103773
+ this._sources = ArraySet.fromArray(sources, true);
103774
+ this._absoluteSources = this._sources.toArray().map(function(s) {
103775
+ return util.computeSourceURL(sourceRoot, s, aSourceMapURL);
103776
+ });
103777
+ this.sourceRoot = sourceRoot;
103778
+ this.sourcesContent = sourcesContent;
103779
+ this._mappings = mappings;
103780
+ this._sourceMapURL = aSourceMapURL;
103781
+ this.file = file;
103782
+ }
103783
+ BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype);
103784
+ BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer;
103785
+ BasicSourceMapConsumer.prototype._findSourceIndex = function(aSource) {
103786
+ var relativeSource = aSource;
103787
+ if (this.sourceRoot != null) {
103788
+ relativeSource = util.relative(this.sourceRoot, relativeSource);
103789
+ }
103790
+ if (this._sources.has(relativeSource)) {
103791
+ return this._sources.indexOf(relativeSource);
103792
+ }
103793
+ var i;
103794
+ for (i = 0; i < this._absoluteSources.length; ++i) {
103795
+ if (this._absoluteSources[i] == aSource) {
103796
+ return i;
103797
+ }
103798
+ }
103799
+ return -1;
103800
+ };
103801
+ BasicSourceMapConsumer.fromSourceMap = function SourceMapConsumer_fromSourceMap(aSourceMap, aSourceMapURL) {
103802
+ var smc = Object.create(BasicSourceMapConsumer.prototype);
103803
+ var names = smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true);
103804
+ var sources = smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true);
103805
+ smc.sourceRoot = aSourceMap._sourceRoot;
103806
+ smc.sourcesContent = aSourceMap._generateSourcesContent(
103807
+ smc._sources.toArray(),
103808
+ smc.sourceRoot
103809
+ );
103810
+ smc.file = aSourceMap._file;
103811
+ smc._sourceMapURL = aSourceMapURL;
103812
+ smc._absoluteSources = smc._sources.toArray().map(function(s) {
103813
+ return util.computeSourceURL(smc.sourceRoot, s, aSourceMapURL);
103814
+ });
103815
+ var generatedMappings = aSourceMap._mappings.toArray().slice();
103816
+ var destGeneratedMappings = smc.__generatedMappings = [];
103817
+ var destOriginalMappings = smc.__originalMappings = [];
103818
+ for (var i = 0, length = generatedMappings.length; i < length; i++) {
103819
+ var srcMapping = generatedMappings[i];
103820
+ var destMapping = new Mapping();
103821
+ destMapping.generatedLine = srcMapping.generatedLine;
103822
+ destMapping.generatedColumn = srcMapping.generatedColumn;
103823
+ if (srcMapping.source) {
103824
+ destMapping.source = sources.indexOf(srcMapping.source);
103825
+ destMapping.originalLine = srcMapping.originalLine;
103826
+ destMapping.originalColumn = srcMapping.originalColumn;
103827
+ if (srcMapping.name) {
103828
+ destMapping.name = names.indexOf(srcMapping.name);
103829
+ }
103830
+ destOriginalMappings.push(destMapping);
103831
+ }
103832
+ destGeneratedMappings.push(destMapping);
103833
+ }
103834
+ quickSort(smc.__originalMappings, util.compareByOriginalPositions);
103835
+ return smc;
103836
+ };
103837
+ BasicSourceMapConsumer.prototype._version = 3;
103838
+ Object.defineProperty(BasicSourceMapConsumer.prototype, "sources", {
103839
+ get: function() {
103840
+ return this._absoluteSources.slice();
103841
+ }
103842
+ });
103843
+ function Mapping() {
103844
+ this.generatedLine = 0;
103845
+ this.generatedColumn = 0;
103846
+ this.source = null;
103847
+ this.originalLine = null;
103848
+ this.originalColumn = null;
103849
+ this.name = null;
103850
+ }
103851
+ BasicSourceMapConsumer.prototype._parseMappings = function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
103852
+ var generatedLine = 1;
103853
+ var previousGeneratedColumn = 0;
103854
+ var previousOriginalLine = 0;
103855
+ var previousOriginalColumn = 0;
103856
+ var previousSource = 0;
103857
+ var previousName = 0;
103858
+ var length = aStr.length;
103859
+ var index = 0;
103860
+ var cachedSegments = {};
103861
+ var temp = {};
103862
+ var originalMappings = [];
103863
+ var generatedMappings = [];
103864
+ var mapping, str, segment, end, value;
103865
+ while (index < length) {
103866
+ if (aStr.charAt(index) === ";") {
103867
+ generatedLine++;
103868
+ index++;
103869
+ previousGeneratedColumn = 0;
103870
+ } else if (aStr.charAt(index) === ",") {
103871
+ index++;
103872
+ } else {
103873
+ mapping = new Mapping();
103874
+ mapping.generatedLine = generatedLine;
103875
+ for (end = index; end < length; end++) {
103876
+ if (this._charIsMappingSeparator(aStr, end)) {
103877
+ break;
103878
+ }
103879
+ }
103880
+ str = aStr.slice(index, end);
103881
+ segment = cachedSegments[str];
103882
+ if (segment) {
103883
+ index += str.length;
103884
+ } else {
103885
+ segment = [];
103886
+ while (index < end) {
103887
+ base64VLQ.decode(aStr, index, temp);
103888
+ value = temp.value;
103889
+ index = temp.rest;
103890
+ segment.push(value);
103891
+ }
103892
+ if (segment.length === 2) {
103893
+ throw new Error("Found a source, but no line and column");
103894
+ }
103895
+ if (segment.length === 3) {
103896
+ throw new Error("Found a source and line, but no column");
103897
+ }
103898
+ cachedSegments[str] = segment;
103899
+ }
103900
+ mapping.generatedColumn = previousGeneratedColumn + segment[0];
103901
+ previousGeneratedColumn = mapping.generatedColumn;
103902
+ if (segment.length > 1) {
103903
+ mapping.source = previousSource + segment[1];
103904
+ previousSource += segment[1];
103905
+ mapping.originalLine = previousOriginalLine + segment[2];
103906
+ previousOriginalLine = mapping.originalLine;
103907
+ mapping.originalLine += 1;
103908
+ mapping.originalColumn = previousOriginalColumn + segment[3];
103909
+ previousOriginalColumn = mapping.originalColumn;
103910
+ if (segment.length > 4) {
103911
+ mapping.name = previousName + segment[4];
103912
+ previousName += segment[4];
103913
+ }
103914
+ }
103915
+ generatedMappings.push(mapping);
103916
+ if (typeof mapping.originalLine === "number") {
103917
+ originalMappings.push(mapping);
103918
+ }
103919
+ }
103920
+ }
103921
+ quickSort(generatedMappings, util.compareByGeneratedPositionsDeflated);
103922
+ this.__generatedMappings = generatedMappings;
103923
+ quickSort(originalMappings, util.compareByOriginalPositions);
103924
+ this.__originalMappings = originalMappings;
103925
+ };
103926
+ BasicSourceMapConsumer.prototype._findMapping = function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, aColumnName, aComparator, aBias) {
103927
+ if (aNeedle[aLineName] <= 0) {
103928
+ throw new TypeError("Line must be greater than or equal to 1, got " + aNeedle[aLineName]);
103929
+ }
103930
+ if (aNeedle[aColumnName] < 0) {
103931
+ throw new TypeError("Column must be greater than or equal to 0, got " + aNeedle[aColumnName]);
103932
+ }
103933
+ return binarySearch.search(aNeedle, aMappings, aComparator, aBias);
103934
+ };
103935
+ BasicSourceMapConsumer.prototype.computeColumnSpans = function SourceMapConsumer_computeColumnSpans() {
103936
+ for (var index = 0; index < this._generatedMappings.length; ++index) {
103937
+ var mapping = this._generatedMappings[index];
103938
+ if (index + 1 < this._generatedMappings.length) {
103939
+ var nextMapping = this._generatedMappings[index + 1];
103940
+ if (mapping.generatedLine === nextMapping.generatedLine) {
103941
+ mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1;
103942
+ continue;
103943
+ }
103944
+ }
103945
+ mapping.lastGeneratedColumn = Infinity;
103946
+ }
103947
+ };
103948
+ BasicSourceMapConsumer.prototype.originalPositionFor = function SourceMapConsumer_originalPositionFor(aArgs) {
103949
+ var needle = {
103950
+ generatedLine: util.getArg(aArgs, "line"),
103951
+ generatedColumn: util.getArg(aArgs, "column")
103952
+ };
103953
+ var index = this._findMapping(
103954
+ needle,
103955
+ this._generatedMappings,
103956
+ "generatedLine",
103957
+ "generatedColumn",
103958
+ util.compareByGeneratedPositionsDeflated,
103959
+ util.getArg(aArgs, "bias", SourceMapConsumer.GREATEST_LOWER_BOUND)
103960
+ );
103961
+ if (index >= 0) {
103962
+ var mapping = this._generatedMappings[index];
103963
+ if (mapping.generatedLine === needle.generatedLine) {
103964
+ var source = util.getArg(mapping, "source", null);
103965
+ if (source !== null) {
103966
+ source = this._sources.at(source);
103967
+ source = util.computeSourceURL(this.sourceRoot, source, this._sourceMapURL);
103968
+ }
103969
+ var name = util.getArg(mapping, "name", null);
103970
+ if (name !== null) {
103971
+ name = this._names.at(name);
103972
+ }
103973
+ return {
103974
+ source,
103975
+ line: util.getArg(mapping, "originalLine", null),
103976
+ column: util.getArg(mapping, "originalColumn", null),
103977
+ name
103978
+ };
103979
+ }
103980
+ }
103981
+ return {
103982
+ source: null,
103983
+ line: null,
103984
+ column: null,
103985
+ name: null
103986
+ };
103987
+ };
103988
+ BasicSourceMapConsumer.prototype.hasContentsOfAllSources = function BasicSourceMapConsumer_hasContentsOfAllSources() {
103989
+ if (!this.sourcesContent) {
103990
+ return false;
103991
+ }
103992
+ return this.sourcesContent.length >= this._sources.size() && !this.sourcesContent.some(function(sc) {
103993
+ return sc == null;
103994
+ });
103995
+ };
103996
+ BasicSourceMapConsumer.prototype.sourceContentFor = function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) {
103997
+ if (!this.sourcesContent) {
103998
+ return null;
103999
+ }
104000
+ var index = this._findSourceIndex(aSource);
104001
+ if (index >= 0) {
104002
+ return this.sourcesContent[index];
104003
+ }
104004
+ var relativeSource = aSource;
104005
+ if (this.sourceRoot != null) {
104006
+ relativeSource = util.relative(this.sourceRoot, relativeSource);
104007
+ }
104008
+ var url;
104009
+ if (this.sourceRoot != null && (url = util.urlParse(this.sourceRoot))) {
104010
+ var fileUriAbsPath = relativeSource.replace(/^file:\/\//, "");
104011
+ if (url.scheme == "file" && this._sources.has(fileUriAbsPath)) {
104012
+ return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)];
104013
+ }
104014
+ if ((!url.path || url.path == "/") && this._sources.has("/" + relativeSource)) {
104015
+ return this.sourcesContent[this._sources.indexOf("/" + relativeSource)];
104016
+ }
104017
+ }
104018
+ if (nullOnMissing) {
104019
+ return null;
104020
+ } else {
104021
+ throw new Error('"' + relativeSource + '" is not in the SourceMap.');
104022
+ }
104023
+ };
104024
+ BasicSourceMapConsumer.prototype.generatedPositionFor = function SourceMapConsumer_generatedPositionFor(aArgs) {
104025
+ var source = util.getArg(aArgs, "source");
104026
+ source = this._findSourceIndex(source);
104027
+ if (source < 0) {
104028
+ return {
104029
+ line: null,
104030
+ column: null,
104031
+ lastColumn: null
104032
+ };
104033
+ }
104034
+ var needle = {
104035
+ source,
104036
+ originalLine: util.getArg(aArgs, "line"),
104037
+ originalColumn: util.getArg(aArgs, "column")
104038
+ };
104039
+ var index = this._findMapping(
104040
+ needle,
104041
+ this._originalMappings,
104042
+ "originalLine",
104043
+ "originalColumn",
104044
+ util.compareByOriginalPositions,
104045
+ util.getArg(aArgs, "bias", SourceMapConsumer.GREATEST_LOWER_BOUND)
104046
+ );
104047
+ if (index >= 0) {
104048
+ var mapping = this._originalMappings[index];
104049
+ if (mapping.source === needle.source) {
104050
+ return {
104051
+ line: util.getArg(mapping, "generatedLine", null),
104052
+ column: util.getArg(mapping, "generatedColumn", null),
104053
+ lastColumn: util.getArg(mapping, "lastGeneratedColumn", null)
104054
+ };
104055
+ }
104056
+ }
104057
+ return {
104058
+ line: null,
104059
+ column: null,
104060
+ lastColumn: null
104061
+ };
104062
+ };
104063
+ exports2.BasicSourceMapConsumer = BasicSourceMapConsumer;
104064
+ function IndexedSourceMapConsumer(aSourceMap, aSourceMapURL) {
104065
+ var sourceMap = aSourceMap;
104066
+ if (typeof aSourceMap === "string") {
104067
+ sourceMap = util.parseSourceMapInput(aSourceMap);
104068
+ }
104069
+ var version = util.getArg(sourceMap, "version");
104070
+ var sections = util.getArg(sourceMap, "sections");
104071
+ if (version != this._version) {
104072
+ throw new Error("Unsupported version: " + version);
104073
+ }
104074
+ this._sources = new ArraySet();
104075
+ this._names = new ArraySet();
104076
+ var lastOffset = {
104077
+ line: -1,
104078
+ column: 0
104079
+ };
104080
+ this._sections = sections.map(function(s) {
104081
+ if (s.url) {
104082
+ throw new Error("Support for url field in sections not implemented.");
104083
+ }
104084
+ var offset = util.getArg(s, "offset");
104085
+ var offsetLine = util.getArg(offset, "line");
104086
+ var offsetColumn = util.getArg(offset, "column");
104087
+ if (offsetLine < lastOffset.line || offsetLine === lastOffset.line && offsetColumn < lastOffset.column) {
104088
+ throw new Error("Section offsets must be ordered and non-overlapping.");
104089
+ }
104090
+ lastOffset = offset;
104091
+ return {
104092
+ generatedOffset: {
104093
+ // The offset fields are 0-based, but we use 1-based indices when
104094
+ // encoding/decoding from VLQ.
104095
+ generatedLine: offsetLine + 1,
104096
+ generatedColumn: offsetColumn + 1
104097
+ },
104098
+ consumer: new SourceMapConsumer(util.getArg(s, "map"), aSourceMapURL)
104099
+ };
104100
+ });
104101
+ }
104102
+ IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype);
104103
+ IndexedSourceMapConsumer.prototype.constructor = SourceMapConsumer;
104104
+ IndexedSourceMapConsumer.prototype._version = 3;
104105
+ Object.defineProperty(IndexedSourceMapConsumer.prototype, "sources", {
104106
+ get: function() {
104107
+ var sources = [];
104108
+ for (var i = 0; i < this._sections.length; i++) {
104109
+ for (var j = 0; j < this._sections[i].consumer.sources.length; j++) {
104110
+ sources.push(this._sections[i].consumer.sources[j]);
104111
+ }
104112
+ }
104113
+ return sources;
104114
+ }
104115
+ });
104116
+ IndexedSourceMapConsumer.prototype.originalPositionFor = function IndexedSourceMapConsumer_originalPositionFor(aArgs) {
104117
+ var needle = {
104118
+ generatedLine: util.getArg(aArgs, "line"),
104119
+ generatedColumn: util.getArg(aArgs, "column")
104120
+ };
104121
+ var sectionIndex = binarySearch.search(
104122
+ needle,
104123
+ this._sections,
104124
+ function(needle2, section2) {
104125
+ var cmp = needle2.generatedLine - section2.generatedOffset.generatedLine;
104126
+ if (cmp) {
104127
+ return cmp;
104128
+ }
104129
+ return needle2.generatedColumn - section2.generatedOffset.generatedColumn;
104130
+ }
104131
+ );
104132
+ var section = this._sections[sectionIndex];
104133
+ if (!section) {
104134
+ return {
104135
+ source: null,
104136
+ line: null,
104137
+ column: null,
104138
+ name: null
104139
+ };
104140
+ }
104141
+ return section.consumer.originalPositionFor({
104142
+ line: needle.generatedLine - (section.generatedOffset.generatedLine - 1),
104143
+ column: needle.generatedColumn - (section.generatedOffset.generatedLine === needle.generatedLine ? section.generatedOffset.generatedColumn - 1 : 0),
104144
+ bias: aArgs.bias
104145
+ });
104146
+ };
104147
+ IndexedSourceMapConsumer.prototype.hasContentsOfAllSources = function IndexedSourceMapConsumer_hasContentsOfAllSources() {
104148
+ return this._sections.every(function(s) {
104149
+ return s.consumer.hasContentsOfAllSources();
104150
+ });
104151
+ };
104152
+ IndexedSourceMapConsumer.prototype.sourceContentFor = function IndexedSourceMapConsumer_sourceContentFor(aSource, nullOnMissing) {
104153
+ for (var i = 0; i < this._sections.length; i++) {
104154
+ var section = this._sections[i];
104155
+ var content = section.consumer.sourceContentFor(aSource, true);
104156
+ if (content) {
104157
+ return content;
104158
+ }
104159
+ }
104160
+ if (nullOnMissing) {
104161
+ return null;
104162
+ } else {
104163
+ throw new Error('"' + aSource + '" is not in the SourceMap.');
104164
+ }
104165
+ };
104166
+ IndexedSourceMapConsumer.prototype.generatedPositionFor = function IndexedSourceMapConsumer_generatedPositionFor(aArgs) {
104167
+ for (var i = 0; i < this._sections.length; i++) {
104168
+ var section = this._sections[i];
104169
+ if (section.consumer._findSourceIndex(util.getArg(aArgs, "source")) === -1) {
104170
+ continue;
104171
+ }
104172
+ var generatedPosition = section.consumer.generatedPositionFor(aArgs);
104173
+ if (generatedPosition) {
104174
+ var ret = {
104175
+ line: generatedPosition.line + (section.generatedOffset.generatedLine - 1),
104176
+ column: generatedPosition.column + (section.generatedOffset.generatedLine === generatedPosition.line ? section.generatedOffset.generatedColumn - 1 : 0)
104177
+ };
104178
+ return ret;
104179
+ }
104180
+ }
104181
+ return {
104182
+ line: null,
104183
+ column: null
104184
+ };
104185
+ };
104186
+ IndexedSourceMapConsumer.prototype._parseMappings = function IndexedSourceMapConsumer_parseMappings(aStr, aSourceRoot) {
104187
+ this.__generatedMappings = [];
104188
+ this.__originalMappings = [];
104189
+ for (var i = 0; i < this._sections.length; i++) {
104190
+ var section = this._sections[i];
104191
+ var sectionMappings = section.consumer._generatedMappings;
104192
+ for (var j = 0; j < sectionMappings.length; j++) {
104193
+ var mapping = sectionMappings[j];
104194
+ var source = section.consumer._sources.at(mapping.source);
104195
+ source = util.computeSourceURL(section.consumer.sourceRoot, source, this._sourceMapURL);
104196
+ this._sources.add(source);
104197
+ source = this._sources.indexOf(source);
104198
+ var name = null;
104199
+ if (mapping.name) {
104200
+ name = section.consumer._names.at(mapping.name);
104201
+ this._names.add(name);
104202
+ name = this._names.indexOf(name);
104203
+ }
104204
+ var adjustedMapping = {
104205
+ source,
104206
+ generatedLine: mapping.generatedLine + (section.generatedOffset.generatedLine - 1),
104207
+ generatedColumn: mapping.generatedColumn + (section.generatedOffset.generatedLine === mapping.generatedLine ? section.generatedOffset.generatedColumn - 1 : 0),
104208
+ originalLine: mapping.originalLine,
104209
+ originalColumn: mapping.originalColumn,
104210
+ name
104211
+ };
104212
+ this.__generatedMappings.push(adjustedMapping);
104213
+ if (typeof adjustedMapping.originalLine === "number") {
104214
+ this.__originalMappings.push(adjustedMapping);
104215
+ }
104216
+ }
104217
+ }
104218
+ quickSort(this.__generatedMappings, util.compareByGeneratedPositionsDeflated);
104219
+ quickSort(this.__originalMappings, util.compareByOriginalPositions);
104220
+ };
104221
+ exports2.IndexedSourceMapConsumer = IndexedSourceMapConsumer;
104222
+ }
104223
+ });
104224
+
104225
+ // ../../node_modules/source-map-support/node_modules/source-map/lib/source-node.js
104226
+ var require_source_node = __commonJS({
104227
+ "../../node_modules/source-map-support/node_modules/source-map/lib/source-node.js"(exports2) {
104228
+ "use strict";
104229
+ var SourceMapGenerator = require_source_map_generator().SourceMapGenerator;
104230
+ var util = require_util4();
104231
+ var REGEX_NEWLINE = /(\r?\n)/;
104232
+ var NEWLINE_CODE = 10;
104233
+ var isSourceNode = "$$$isSourceNode$$$";
104234
+ function SourceNode(aLine, aColumn, aSource, aChunks, aName) {
104235
+ this.children = [];
104236
+ this.sourceContents = {};
104237
+ this.line = aLine == null ? null : aLine;
104238
+ this.column = aColumn == null ? null : aColumn;
104239
+ this.source = aSource == null ? null : aSource;
104240
+ this.name = aName == null ? null : aName;
104241
+ this[isSourceNode] = true;
104242
+ if (aChunks != null) this.add(aChunks);
104243
+ }
104244
+ SourceNode.fromStringWithSourceMap = function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) {
104245
+ var node = new SourceNode();
104246
+ var remainingLines = aGeneratedCode.split(REGEX_NEWLINE);
104247
+ var remainingLinesIndex = 0;
104248
+ var shiftNextLine = function() {
104249
+ var lineContents = getNextLine();
104250
+ var newLine = getNextLine() || "";
104251
+ return lineContents + newLine;
104252
+ function getNextLine() {
104253
+ return remainingLinesIndex < remainingLines.length ? remainingLines[remainingLinesIndex++] : void 0;
104254
+ }
104255
+ };
104256
+ var lastGeneratedLine = 1, lastGeneratedColumn = 0;
104257
+ var lastMapping = null;
104258
+ aSourceMapConsumer.eachMapping(function(mapping) {
104259
+ if (lastMapping !== null) {
104260
+ if (lastGeneratedLine < mapping.generatedLine) {
104261
+ addMappingWithCode(lastMapping, shiftNextLine());
104262
+ lastGeneratedLine++;
104263
+ lastGeneratedColumn = 0;
104264
+ } else {
104265
+ var nextLine = remainingLines[remainingLinesIndex] || "";
104266
+ var code = nextLine.substr(0, mapping.generatedColumn - lastGeneratedColumn);
104267
+ remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn - lastGeneratedColumn);
104268
+ lastGeneratedColumn = mapping.generatedColumn;
104269
+ addMappingWithCode(lastMapping, code);
104270
+ lastMapping = mapping;
104271
+ return;
104272
+ }
104273
+ }
104274
+ while (lastGeneratedLine < mapping.generatedLine) {
104275
+ node.add(shiftNextLine());
104276
+ lastGeneratedLine++;
104277
+ }
104278
+ if (lastGeneratedColumn < mapping.generatedColumn) {
104279
+ var nextLine = remainingLines[remainingLinesIndex] || "";
104280
+ node.add(nextLine.substr(0, mapping.generatedColumn));
104281
+ remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn);
104282
+ lastGeneratedColumn = mapping.generatedColumn;
104283
+ }
104284
+ lastMapping = mapping;
104285
+ }, this);
104286
+ if (remainingLinesIndex < remainingLines.length) {
104287
+ if (lastMapping) {
104288
+ addMappingWithCode(lastMapping, shiftNextLine());
104289
+ }
104290
+ node.add(remainingLines.splice(remainingLinesIndex).join(""));
104291
+ }
104292
+ aSourceMapConsumer.sources.forEach(function(sourceFile) {
104293
+ var content = aSourceMapConsumer.sourceContentFor(sourceFile);
104294
+ if (content != null) {
104295
+ if (aRelativePath != null) {
104296
+ sourceFile = util.join(aRelativePath, sourceFile);
104297
+ }
104298
+ node.setSourceContent(sourceFile, content);
104299
+ }
104300
+ });
104301
+ return node;
104302
+ function addMappingWithCode(mapping, code) {
104303
+ if (mapping === null || mapping.source === void 0) {
104304
+ node.add(code);
104305
+ } else {
104306
+ var source = aRelativePath ? util.join(aRelativePath, mapping.source) : mapping.source;
104307
+ node.add(new SourceNode(
104308
+ mapping.originalLine,
104309
+ mapping.originalColumn,
104310
+ source,
104311
+ code,
104312
+ mapping.name
104313
+ ));
104314
+ }
104315
+ }
104316
+ };
104317
+ SourceNode.prototype.add = function SourceNode_add(aChunk) {
104318
+ if (Array.isArray(aChunk)) {
104319
+ aChunk.forEach(function(chunk) {
104320
+ this.add(chunk);
104321
+ }, this);
104322
+ } else if (aChunk[isSourceNode] || typeof aChunk === "string") {
104323
+ if (aChunk) {
104324
+ this.children.push(aChunk);
104325
+ }
104326
+ } else {
104327
+ throw new TypeError(
104328
+ "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
104329
+ );
104330
+ }
104331
+ return this;
104332
+ };
104333
+ SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) {
104334
+ if (Array.isArray(aChunk)) {
104335
+ for (var i = aChunk.length - 1; i >= 0; i--) {
104336
+ this.prepend(aChunk[i]);
104337
+ }
104338
+ } else if (aChunk[isSourceNode] || typeof aChunk === "string") {
104339
+ this.children.unshift(aChunk);
104340
+ } else {
104341
+ throw new TypeError(
104342
+ "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
104343
+ );
104344
+ }
104345
+ return this;
104346
+ };
104347
+ SourceNode.prototype.walk = function SourceNode_walk(aFn) {
104348
+ var chunk;
104349
+ for (var i = 0, len = this.children.length; i < len; i++) {
104350
+ chunk = this.children[i];
104351
+ if (chunk[isSourceNode]) {
104352
+ chunk.walk(aFn);
104353
+ } else {
104354
+ if (chunk !== "") {
104355
+ aFn(chunk, {
104356
+ source: this.source,
104357
+ line: this.line,
104358
+ column: this.column,
104359
+ name: this.name
104360
+ });
104361
+ }
104362
+ }
104363
+ }
104364
+ };
104365
+ SourceNode.prototype.join = function SourceNode_join(aSep) {
104366
+ var newChildren;
104367
+ var i;
104368
+ var len = this.children.length;
104369
+ if (len > 0) {
104370
+ newChildren = [];
104371
+ for (i = 0; i < len - 1; i++) {
104372
+ newChildren.push(this.children[i]);
104373
+ newChildren.push(aSep);
104374
+ }
104375
+ newChildren.push(this.children[i]);
104376
+ this.children = newChildren;
104377
+ }
104378
+ return this;
104379
+ };
104380
+ SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) {
104381
+ var lastChild = this.children[this.children.length - 1];
104382
+ if (lastChild[isSourceNode]) {
104383
+ lastChild.replaceRight(aPattern, aReplacement);
104384
+ } else if (typeof lastChild === "string") {
104385
+ this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement);
104386
+ } else {
104387
+ this.children.push("".replace(aPattern, aReplacement));
104388
+ }
104389
+ return this;
104390
+ };
104391
+ SourceNode.prototype.setSourceContent = function SourceNode_setSourceContent(aSourceFile, aSourceContent) {
104392
+ this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent;
104393
+ };
104394
+ SourceNode.prototype.walkSourceContents = function SourceNode_walkSourceContents(aFn) {
104395
+ for (var i = 0, len = this.children.length; i < len; i++) {
104396
+ if (this.children[i][isSourceNode]) {
104397
+ this.children[i].walkSourceContents(aFn);
104398
+ }
104399
+ }
104400
+ var sources = Object.keys(this.sourceContents);
104401
+ for (var i = 0, len = sources.length; i < len; i++) {
104402
+ aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]);
104403
+ }
104404
+ };
104405
+ SourceNode.prototype.toString = function SourceNode_toString() {
104406
+ var str = "";
104407
+ this.walk(function(chunk) {
104408
+ str += chunk;
104409
+ });
104410
+ return str;
104411
+ };
104412
+ SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) {
104413
+ var generated = {
104414
+ code: "",
104415
+ line: 1,
104416
+ column: 0
104417
+ };
104418
+ var map2 = new SourceMapGenerator(aArgs);
104419
+ var sourceMappingActive = false;
104420
+ var lastOriginalSource = null;
104421
+ var lastOriginalLine = null;
104422
+ var lastOriginalColumn = null;
104423
+ var lastOriginalName = null;
104424
+ this.walk(function(chunk, original) {
104425
+ generated.code += chunk;
104426
+ if (original.source !== null && original.line !== null && original.column !== null) {
104427
+ if (lastOriginalSource !== original.source || lastOriginalLine !== original.line || lastOriginalColumn !== original.column || lastOriginalName !== original.name) {
104428
+ map2.addMapping({
104429
+ source: original.source,
104430
+ original: {
104431
+ line: original.line,
104432
+ column: original.column
104433
+ },
104434
+ generated: {
104435
+ line: generated.line,
104436
+ column: generated.column
104437
+ },
104438
+ name: original.name
104439
+ });
104440
+ }
104441
+ lastOriginalSource = original.source;
104442
+ lastOriginalLine = original.line;
104443
+ lastOriginalColumn = original.column;
104444
+ lastOriginalName = original.name;
104445
+ sourceMappingActive = true;
104446
+ } else if (sourceMappingActive) {
104447
+ map2.addMapping({
104448
+ generated: {
104449
+ line: generated.line,
104450
+ column: generated.column
104451
+ }
104452
+ });
104453
+ lastOriginalSource = null;
104454
+ sourceMappingActive = false;
104455
+ }
104456
+ for (var idx = 0, length = chunk.length; idx < length; idx++) {
104457
+ if (chunk.charCodeAt(idx) === NEWLINE_CODE) {
104458
+ generated.line++;
104459
+ generated.column = 0;
104460
+ if (idx + 1 === length) {
104461
+ lastOriginalSource = null;
104462
+ sourceMappingActive = false;
104463
+ } else if (sourceMappingActive) {
104464
+ map2.addMapping({
104465
+ source: original.source,
104466
+ original: {
104467
+ line: original.line,
104468
+ column: original.column
104469
+ },
104470
+ generated: {
104471
+ line: generated.line,
104472
+ column: generated.column
104473
+ },
104474
+ name: original.name
104475
+ });
104476
+ }
104477
+ } else {
104478
+ generated.column++;
104479
+ }
104480
+ }
104481
+ });
104482
+ this.walkSourceContents(function(sourceFile, sourceContent) {
104483
+ map2.setSourceContent(sourceFile, sourceContent);
104484
+ });
104485
+ return { code: generated.code, map: map2 };
104486
+ };
104487
+ exports2.SourceNode = SourceNode;
104488
+ }
104489
+ });
104490
+
104491
+ // ../../node_modules/source-map-support/node_modules/source-map/source-map.js
104492
+ var require_source_map = __commonJS({
104493
+ "../../node_modules/source-map-support/node_modules/source-map/source-map.js"(exports2) {
104494
+ "use strict";
104495
+ exports2.SourceMapGenerator = require_source_map_generator().SourceMapGenerator;
104496
+ exports2.SourceMapConsumer = require_source_map_consumer().SourceMapConsumer;
104497
+ exports2.SourceNode = require_source_node().SourceNode;
104498
+ }
104499
+ });
104500
+
104501
+ // ../../node_modules/buffer-from/index.js
104502
+ var require_buffer_from = __commonJS({
104503
+ "../../node_modules/buffer-from/index.js"(exports2, module2) {
104504
+ "use strict";
104505
+ var toString = Object.prototype.toString;
104506
+ var isModern = typeof Buffer !== "undefined" && typeof Buffer.alloc === "function" && typeof Buffer.allocUnsafe === "function" && typeof Buffer.from === "function";
104507
+ function isArrayBuffer(input) {
104508
+ return toString.call(input).slice(8, -1) === "ArrayBuffer";
104509
+ }
104510
+ function fromArrayBuffer(obj, byteOffset, length) {
104511
+ byteOffset >>>= 0;
104512
+ var maxLength = obj.byteLength - byteOffset;
104513
+ if (maxLength < 0) {
104514
+ throw new RangeError("'offset' is out of bounds");
104515
+ }
104516
+ if (length === void 0) {
104517
+ length = maxLength;
104518
+ } else {
104519
+ length >>>= 0;
104520
+ if (length > maxLength) {
104521
+ throw new RangeError("'length' is out of bounds");
104522
+ }
104523
+ }
104524
+ return isModern ? Buffer.from(obj.slice(byteOffset, byteOffset + length)) : new Buffer(new Uint8Array(obj.slice(byteOffset, byteOffset + length)));
104525
+ }
104526
+ function fromString(string, encoding) {
104527
+ if (typeof encoding !== "string" || encoding === "") {
104528
+ encoding = "utf8";
104529
+ }
104530
+ if (!Buffer.isEncoding(encoding)) {
104531
+ throw new TypeError('"encoding" must be a valid string encoding');
104532
+ }
104533
+ return isModern ? Buffer.from(string, encoding) : new Buffer(string, encoding);
104534
+ }
104535
+ function bufferFrom(value, encodingOrOffset, length) {
104536
+ if (typeof value === "number") {
104537
+ throw new TypeError('"value" argument must not be a number');
104538
+ }
104539
+ if (isArrayBuffer(value)) {
104540
+ return fromArrayBuffer(value, encodingOrOffset, length);
104541
+ }
104542
+ if (typeof value === "string") {
104543
+ return fromString(value, encodingOrOffset);
104544
+ }
104545
+ return isModern ? Buffer.from(value) : new Buffer(value);
104546
+ }
104547
+ module2.exports = bufferFrom;
104548
+ }
104549
+ });
104550
+
104551
+ // ../../node_modules/source-map-support/source-map-support.js
104552
+ var require_source_map_support = __commonJS({
104553
+ "../../node_modules/source-map-support/source-map-support.js"(exports2, module2) {
104554
+ "use strict";
104555
+ var SourceMapConsumer = require_source_map().SourceMapConsumer;
104556
+ var path = require("path");
104557
+ var fs;
104558
+ try {
104559
+ fs = require("fs");
104560
+ if (!fs.existsSync || !fs.readFileSync) {
104561
+ fs = null;
104562
+ }
104563
+ } catch (err) {
104564
+ }
104565
+ var bufferFrom = require_buffer_from();
104566
+ function dynamicRequire(mod, request) {
104567
+ return mod.require(request);
104568
+ }
104569
+ var errorFormatterInstalled = false;
104570
+ var uncaughtShimInstalled = false;
104571
+ var emptyCacheBetweenOperations = false;
104572
+ var environment = "auto";
104573
+ var fileContentsCache = {};
104574
+ var sourceMapCache = {};
104575
+ var reSourceMap = /^data:application\/json[^,]+base64,/;
104576
+ var retrieveFileHandlers = [];
104577
+ var retrieveMapHandlers = [];
104578
+ function isInBrowser() {
104579
+ if (environment === "browser")
104580
+ return true;
104581
+ if (environment === "node")
104582
+ return false;
104583
+ return typeof window !== "undefined" && typeof XMLHttpRequest === "function" && !(window.require && window.module && window.process && window.process.type === "renderer");
104584
+ }
104585
+ function hasGlobalProcessEventEmitter() {
104586
+ return typeof process === "object" && process !== null && typeof process.on === "function";
104587
+ }
104588
+ function globalProcessVersion() {
104589
+ if (typeof process === "object" && process !== null) {
104590
+ return process.version;
104591
+ } else {
104592
+ return "";
104593
+ }
104594
+ }
104595
+ function globalProcessStderr() {
104596
+ if (typeof process === "object" && process !== null) {
104597
+ return process.stderr;
104598
+ }
104599
+ }
104600
+ function globalProcessExit(code) {
104601
+ if (typeof process === "object" && process !== null && typeof process.exit === "function") {
104602
+ return process.exit(code);
104603
+ }
104604
+ }
104605
+ function handlerExec(list) {
104606
+ return function(arg) {
104607
+ for (var i = 0; i < list.length; i++) {
104608
+ var ret = list[i](arg);
104609
+ if (ret) {
104610
+ return ret;
104611
+ }
104612
+ }
104613
+ return null;
104614
+ };
104615
+ }
104616
+ var retrieveFile = handlerExec(retrieveFileHandlers);
104617
+ retrieveFileHandlers.push(function(path2) {
104618
+ path2 = path2.trim();
104619
+ if (/^file:/.test(path2)) {
104620
+ path2 = path2.replace(/file:\/\/\/(\w:)?/, function(protocol, drive) {
104621
+ return drive ? "" : (
104622
+ // file:///C:/dir/file -> C:/dir/file
104623
+ "/"
104624
+ );
104625
+ });
104626
+ }
104627
+ if (path2 in fileContentsCache) {
104628
+ return fileContentsCache[path2];
104629
+ }
104630
+ var contents = "";
104631
+ try {
104632
+ if (!fs) {
104633
+ var xhr = new XMLHttpRequest();
104634
+ xhr.open(
104635
+ "GET",
104636
+ path2,
104637
+ /** async */
104638
+ false
104639
+ );
104640
+ xhr.send(null);
104641
+ if (xhr.readyState === 4 && xhr.status === 200) {
104642
+ contents = xhr.responseText;
104643
+ }
104644
+ } else if (fs.existsSync(path2)) {
104645
+ contents = fs.readFileSync(path2, "utf8");
104646
+ }
104647
+ } catch (er) {
104648
+ }
104649
+ return fileContentsCache[path2] = contents;
104650
+ });
104651
+ function supportRelativeURL(file, url) {
104652
+ if (!file) return url;
104653
+ var dir = path.dirname(file);
104654
+ var match = /^\w+:\/\/[^\/]*/.exec(dir);
104655
+ var protocol = match ? match[0] : "";
104656
+ var startPath = dir.slice(protocol.length);
104657
+ if (protocol && /^\/\w\:/.test(startPath)) {
104658
+ protocol += "/";
104659
+ return protocol + path.resolve(dir.slice(protocol.length), url).replace(/\\/g, "/");
104660
+ }
104661
+ return protocol + path.resolve(dir.slice(protocol.length), url);
104662
+ }
104663
+ function retrieveSourceMapURL(source) {
104664
+ var fileData;
104665
+ if (isInBrowser()) {
104666
+ try {
104667
+ var xhr = new XMLHttpRequest();
104668
+ xhr.open("GET", source, false);
104669
+ xhr.send(null);
104670
+ fileData = xhr.readyState === 4 ? xhr.responseText : null;
104671
+ var sourceMapHeader = xhr.getResponseHeader("SourceMap") || xhr.getResponseHeader("X-SourceMap");
104672
+ if (sourceMapHeader) {
104673
+ return sourceMapHeader;
104674
+ }
104675
+ } catch (e) {
104676
+ }
104677
+ }
104678
+ fileData = retrieveFile(source);
104679
+ var re = /(?:\/\/[@#][\s]*sourceMappingURL=([^\s'"]+)[\s]*$)|(?:\/\*[@#][\s]*sourceMappingURL=([^\s*'"]+)[\s]*(?:\*\/)[\s]*$)/mg;
104680
+ var lastMatch, match;
104681
+ while (match = re.exec(fileData)) lastMatch = match;
104682
+ if (!lastMatch) return null;
104683
+ return lastMatch[1];
104684
+ }
104685
+ var retrieveSourceMap = handlerExec(retrieveMapHandlers);
104686
+ retrieveMapHandlers.push(function(source) {
104687
+ var sourceMappingURL = retrieveSourceMapURL(source);
104688
+ if (!sourceMappingURL) return null;
104689
+ var sourceMapData;
104690
+ if (reSourceMap.test(sourceMappingURL)) {
104691
+ var rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(",") + 1);
104692
+ sourceMapData = bufferFrom(rawData, "base64").toString();
104693
+ sourceMappingURL = source;
104694
+ } else {
104695
+ sourceMappingURL = supportRelativeURL(source, sourceMappingURL);
104696
+ sourceMapData = retrieveFile(sourceMappingURL);
104697
+ }
104698
+ if (!sourceMapData) {
104699
+ return null;
104700
+ }
104701
+ return {
104702
+ url: sourceMappingURL,
104703
+ map: sourceMapData
104704
+ };
104705
+ });
104706
+ function mapSourcePosition(position) {
104707
+ var sourceMap = sourceMapCache[position.source];
104708
+ if (!sourceMap) {
104709
+ var urlAndMap = retrieveSourceMap(position.source);
104710
+ if (urlAndMap) {
104711
+ sourceMap = sourceMapCache[position.source] = {
104712
+ url: urlAndMap.url,
104713
+ map: new SourceMapConsumer(urlAndMap.map)
104714
+ };
104715
+ if (sourceMap.map.sourcesContent) {
104716
+ sourceMap.map.sources.forEach(function(source, i) {
104717
+ var contents = sourceMap.map.sourcesContent[i];
104718
+ if (contents) {
104719
+ var url = supportRelativeURL(sourceMap.url, source);
104720
+ fileContentsCache[url] = contents;
104721
+ }
104722
+ });
104723
+ }
104724
+ } else {
104725
+ sourceMap = sourceMapCache[position.source] = {
104726
+ url: null,
104727
+ map: null
104728
+ };
104729
+ }
104730
+ }
104731
+ if (sourceMap && sourceMap.map && typeof sourceMap.map.originalPositionFor === "function") {
104732
+ var originalPosition = sourceMap.map.originalPositionFor(position);
104733
+ if (originalPosition.source !== null) {
104734
+ originalPosition.source = supportRelativeURL(
104735
+ sourceMap.url,
104736
+ originalPosition.source
104737
+ );
104738
+ return originalPosition;
104739
+ }
104740
+ }
104741
+ return position;
104742
+ }
104743
+ function mapEvalOrigin(origin) {
104744
+ var match = /^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(origin);
104745
+ if (match) {
104746
+ var position = mapSourcePosition({
104747
+ source: match[2],
104748
+ line: +match[3],
104749
+ column: match[4] - 1
104750
+ });
104751
+ return "eval at " + match[1] + " (" + position.source + ":" + position.line + ":" + (position.column + 1) + ")";
104752
+ }
104753
+ match = /^eval at ([^(]+) \((.+)\)$/.exec(origin);
104754
+ if (match) {
104755
+ return "eval at " + match[1] + " (" + mapEvalOrigin(match[2]) + ")";
104756
+ }
104757
+ return origin;
104758
+ }
104759
+ function CallSiteToString() {
104760
+ var fileName;
104761
+ var fileLocation = "";
104762
+ if (this.isNative()) {
104763
+ fileLocation = "native";
104764
+ } else {
104765
+ fileName = this.getScriptNameOrSourceURL();
104766
+ if (!fileName && this.isEval()) {
104767
+ fileLocation = this.getEvalOrigin();
104768
+ fileLocation += ", ";
104769
+ }
104770
+ if (fileName) {
104771
+ fileLocation += fileName;
104772
+ } else {
104773
+ fileLocation += "<anonymous>";
104774
+ }
104775
+ var lineNumber = this.getLineNumber();
104776
+ if (lineNumber != null) {
104777
+ fileLocation += ":" + lineNumber;
104778
+ var columnNumber = this.getColumnNumber();
104779
+ if (columnNumber) {
104780
+ fileLocation += ":" + columnNumber;
104781
+ }
104782
+ }
104783
+ }
104784
+ var line = "";
104785
+ var functionName = this.getFunctionName();
104786
+ var addSuffix = true;
104787
+ var isConstructor = this.isConstructor();
104788
+ var isMethodCall = !(this.isToplevel() || isConstructor);
104789
+ if (isMethodCall) {
104790
+ var typeName = this.getTypeName();
104791
+ if (typeName === "[object Object]") {
104792
+ typeName = "null";
104793
+ }
104794
+ var methodName = this.getMethodName();
104795
+ if (functionName) {
104796
+ if (typeName && functionName.indexOf(typeName) != 0) {
104797
+ line += typeName + ".";
104798
+ }
104799
+ line += functionName;
104800
+ if (methodName && functionName.indexOf("." + methodName) != functionName.length - methodName.length - 1) {
104801
+ line += " [as " + methodName + "]";
104802
+ }
104803
+ } else {
104804
+ line += typeName + "." + (methodName || "<anonymous>");
104805
+ }
104806
+ } else if (isConstructor) {
104807
+ line += "new " + (functionName || "<anonymous>");
104808
+ } else if (functionName) {
104809
+ line += functionName;
104810
+ } else {
104811
+ line += fileLocation;
104812
+ addSuffix = false;
104813
+ }
104814
+ if (addSuffix) {
104815
+ line += " (" + fileLocation + ")";
104816
+ }
104817
+ return line;
104818
+ }
104819
+ function cloneCallSite(frame) {
104820
+ var object = {};
104821
+ Object.getOwnPropertyNames(Object.getPrototypeOf(frame)).forEach(function(name) {
104822
+ object[name] = /^(?:is|get)/.test(name) ? function() {
104823
+ return frame[name].call(frame);
104824
+ } : frame[name];
104825
+ });
104826
+ object.toString = CallSiteToString;
104827
+ return object;
104828
+ }
104829
+ function wrapCallSite(frame, state2) {
104830
+ if (state2 === void 0) {
104831
+ state2 = { nextPosition: null, curPosition: null };
104832
+ }
104833
+ if (frame.isNative()) {
104834
+ state2.curPosition = null;
104835
+ return frame;
104836
+ }
104837
+ var source = frame.getFileName() || frame.getScriptNameOrSourceURL();
104838
+ if (source) {
104839
+ var line = frame.getLineNumber();
104840
+ var column = frame.getColumnNumber() - 1;
104841
+ var noHeader = /^v(10\.1[6-9]|10\.[2-9][0-9]|10\.[0-9]{3,}|1[2-9]\d*|[2-9]\d|\d{3,}|11\.11)/;
104842
+ var headerLength = noHeader.test(globalProcessVersion()) ? 0 : 62;
104843
+ if (line === 1 && column > headerLength && !isInBrowser() && !frame.isEval()) {
104844
+ column -= headerLength;
104845
+ }
104846
+ var position = mapSourcePosition({
104847
+ source,
104848
+ line,
104849
+ column
104850
+ });
104851
+ state2.curPosition = position;
104852
+ frame = cloneCallSite(frame);
104853
+ var originalFunctionName = frame.getFunctionName;
104854
+ frame.getFunctionName = function() {
104855
+ if (state2.nextPosition == null) {
104856
+ return originalFunctionName();
104857
+ }
104858
+ return state2.nextPosition.name || originalFunctionName();
104859
+ };
104860
+ frame.getFileName = function() {
104861
+ return position.source;
104862
+ };
104863
+ frame.getLineNumber = function() {
104864
+ return position.line;
104865
+ };
104866
+ frame.getColumnNumber = function() {
104867
+ return position.column + 1;
104868
+ };
104869
+ frame.getScriptNameOrSourceURL = function() {
104870
+ return position.source;
104871
+ };
104872
+ return frame;
104873
+ }
104874
+ var origin = frame.isEval() && frame.getEvalOrigin();
104875
+ if (origin) {
104876
+ origin = mapEvalOrigin(origin);
104877
+ frame = cloneCallSite(frame);
104878
+ frame.getEvalOrigin = function() {
104879
+ return origin;
104880
+ };
104881
+ return frame;
104882
+ }
104883
+ return frame;
104884
+ }
104885
+ function prepareStackTrace(error2, stack) {
104886
+ if (emptyCacheBetweenOperations) {
104887
+ fileContentsCache = {};
104888
+ sourceMapCache = {};
104889
+ }
104890
+ var name = error2.name || "Error";
104891
+ var message = error2.message || "";
104892
+ var errorString = name + ": " + message;
104893
+ var state2 = { nextPosition: null, curPosition: null };
104894
+ var processedStack = [];
104895
+ for (var i = stack.length - 1; i >= 0; i--) {
104896
+ processedStack.push("\n at " + wrapCallSite(stack[i], state2));
104897
+ state2.nextPosition = state2.curPosition;
104898
+ }
104899
+ state2.curPosition = state2.nextPosition = null;
104900
+ return errorString + processedStack.reverse().join("");
104901
+ }
104902
+ function getErrorSource(error2) {
104903
+ var match = /\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(error2.stack);
104904
+ if (match) {
104905
+ var source = match[1];
104906
+ var line = +match[2];
104907
+ var column = +match[3];
104908
+ var contents = fileContentsCache[source];
104909
+ if (!contents && fs && fs.existsSync(source)) {
104910
+ try {
104911
+ contents = fs.readFileSync(source, "utf8");
104912
+ } catch (er) {
104913
+ contents = "";
104914
+ }
104915
+ }
104916
+ if (contents) {
104917
+ var code = contents.split(/(?:\r\n|\r|\n)/)[line - 1];
104918
+ if (code) {
104919
+ return source + ":" + line + "\n" + code + "\n" + new Array(column).join(" ") + "^";
104920
+ }
104921
+ }
104922
+ }
104923
+ return null;
104924
+ }
104925
+ function printErrorAndExit(error2) {
104926
+ var source = getErrorSource(error2);
104927
+ var stderr = globalProcessStderr();
104928
+ if (stderr && stderr._handle && stderr._handle.setBlocking) {
104929
+ stderr._handle.setBlocking(true);
104930
+ }
104931
+ if (source) {
104932
+ console.error();
104933
+ console.error(source);
104934
+ }
104935
+ console.error(error2.stack);
104936
+ globalProcessExit(1);
104937
+ }
104938
+ function shimEmitUncaughtException() {
104939
+ var origEmit = process.emit;
104940
+ process.emit = function(type) {
104941
+ if (type === "uncaughtException") {
104942
+ var hasStack = arguments[1] && arguments[1].stack;
104943
+ var hasListeners = this.listeners(type).length > 0;
104944
+ if (hasStack && !hasListeners) {
104945
+ return printErrorAndExit(arguments[1]);
104946
+ }
104947
+ }
104948
+ return origEmit.apply(this, arguments);
104949
+ };
104950
+ }
104951
+ var originalRetrieveFileHandlers = retrieveFileHandlers.slice(0);
104952
+ var originalRetrieveMapHandlers = retrieveMapHandlers.slice(0);
104953
+ exports2.wrapCallSite = wrapCallSite;
104954
+ exports2.getErrorSource = getErrorSource;
104955
+ exports2.mapSourcePosition = mapSourcePosition;
104956
+ exports2.retrieveSourceMap = retrieveSourceMap;
104957
+ exports2.install = function(options) {
104958
+ options = options || {};
104959
+ if (options.environment) {
104960
+ environment = options.environment;
104961
+ if (["node", "browser", "auto"].indexOf(environment) === -1) {
104962
+ throw new Error("environment " + environment + " was unknown. Available options are {auto, browser, node}");
104963
+ }
104964
+ }
104965
+ if (options.retrieveFile) {
104966
+ if (options.overrideRetrieveFile) {
104967
+ retrieveFileHandlers.length = 0;
104968
+ }
104969
+ retrieveFileHandlers.unshift(options.retrieveFile);
104970
+ }
104971
+ if (options.retrieveSourceMap) {
104972
+ if (options.overrideRetrieveSourceMap) {
104973
+ retrieveMapHandlers.length = 0;
104974
+ }
104975
+ retrieveMapHandlers.unshift(options.retrieveSourceMap);
104976
+ }
104977
+ if (options.hookRequire && !isInBrowser()) {
104978
+ var Module = dynamicRequire(module2, "module");
104979
+ var $compile = Module.prototype._compile;
104980
+ if (!$compile.__sourceMapSupport) {
104981
+ Module.prototype._compile = function(content, filename) {
104982
+ fileContentsCache[filename] = content;
104983
+ sourceMapCache[filename] = void 0;
104984
+ return $compile.call(this, content, filename);
104985
+ };
104986
+ Module.prototype._compile.__sourceMapSupport = true;
104987
+ }
104988
+ }
104989
+ if (!emptyCacheBetweenOperations) {
104990
+ emptyCacheBetweenOperations = "emptyCacheBetweenOperations" in options ? options.emptyCacheBetweenOperations : false;
104991
+ }
104992
+ if (!errorFormatterInstalled) {
104993
+ errorFormatterInstalled = true;
104994
+ Error.prepareStackTrace = prepareStackTrace;
104995
+ }
104996
+ if (!uncaughtShimInstalled) {
104997
+ var installHandler = "handleUncaughtExceptions" in options ? options.handleUncaughtExceptions : true;
104998
+ try {
104999
+ var worker_threads = dynamicRequire(module2, "worker_threads");
105000
+ if (worker_threads.isMainThread === false) {
105001
+ installHandler = false;
105002
+ }
105003
+ } catch (e) {
105004
+ }
105005
+ if (installHandler && hasGlobalProcessEventEmitter()) {
105006
+ uncaughtShimInstalled = true;
105007
+ shimEmitUncaughtException();
105008
+ }
105009
+ }
105010
+ };
105011
+ exports2.resetRetrieveHandlers = function() {
105012
+ retrieveFileHandlers.length = 0;
105013
+ retrieveMapHandlers.length = 0;
105014
+ retrieveFileHandlers = originalRetrieveFileHandlers.slice(0);
105015
+ retrieveMapHandlers = originalRetrieveMapHandlers.slice(0);
105016
+ retrieveSourceMap = handlerExec(retrieveMapHandlers);
105017
+ retrieveFile = handlerExec(retrieveFileHandlers);
105018
+ };
105019
+ }
105020
+ });
105021
+
101534
105022
  // ../../node_modules/typescript/lib/typescript.js
101535
105023
  var require_typescript = __commonJS({
101536
105024
  "../../node_modules/typescript/lib/typescript.js"(exports2, module2) {
@@ -110187,7 +113675,7 @@ ${lanes.join("\n")}
110187
113675
  debugMode: !!process.env.NODE_INSPECTOR_IPC || !!process.env.VSCODE_INSPECTOR_OPTIONS || some(process.execArgv, (arg) => /^--(?:inspect|debug)(?:-brk)?(?:=\d+)?$/i.test(arg)) || !!process.recordreplay,
110188
113676
  tryEnableSourceMapsForHost() {
110189
113677
  try {
110190
- require("source-map-support").install();
113678
+ require_source_map_support().install();
110191
113679
  } catch {
110192
113680
  }
110193
113681
  },
@@ -338722,7 +342210,7 @@ var require_decoder = __commonJS({
338722
342210
  });
338723
342211
 
338724
342212
  // ../../node_modules/adm-zip/util/index.js
338725
- var require_util4 = __commonJS({
342213
+ var require_util5 = __commonJS({
338726
342214
  "../../node_modules/adm-zip/util/index.js"(exports2, module2) {
338727
342215
  "use strict";
338728
342216
  module2.exports = require_utils2();
@@ -338737,7 +342225,7 @@ var require_util4 = __commonJS({
338737
342225
  var require_entryHeader = __commonJS({
338738
342226
  "../../node_modules/adm-zip/headers/entryHeader.js"(exports2, module2) {
338739
342227
  "use strict";
338740
- var Utils = require_util4();
342228
+ var Utils = require_util5();
338741
342229
  var Constants = Utils.Constants;
338742
342230
  module2.exports = function() {
338743
342231
  var _verMade = 20, _version = 10, _flags = 0, _method = 0, _time = 0, _crc = 0, _compressedSize = 0, _size = 0, _fnameLen = 0, _extraLen = 0, _comLen = 0, _diskStart = 0, _inattr = 0, _attr = 0, _offset = 0;
@@ -339008,7 +342496,7 @@ var require_entryHeader = __commonJS({
339008
342496
  var require_mainHeader = __commonJS({
339009
342497
  "../../node_modules/adm-zip/headers/mainHeader.js"(exports2, module2) {
339010
342498
  "use strict";
339011
- var Utils = require_util4();
342499
+ var Utils = require_util5();
339012
342500
  var Constants = Utils.Constants;
339013
342501
  module2.exports = function() {
339014
342502
  var _volumeEntries = 0, _totalEntries = 0, _size = 0, _offset = 0, _commentLength = 0;
@@ -339306,7 +342794,7 @@ var require_methods = __commonJS({
339306
342794
  var require_zipEntry = __commonJS({
339307
342795
  "../../node_modules/adm-zip/zipEntry.js"(exports2, module2) {
339308
342796
  "use strict";
339309
- var Utils = require_util4();
342797
+ var Utils = require_util5();
339310
342798
  var Headers = require_headers3();
339311
342799
  var Constants = Utils.Constants;
339312
342800
  var Methods = require_methods();
@@ -339640,7 +343128,7 @@ var require_zipFile = __commonJS({
339640
343128
  "use strict";
339641
343129
  var ZipEntry = require_zipEntry();
339642
343130
  var Headers = require_headers3();
339643
- var Utils = require_util4();
343131
+ var Utils = require_util5();
339644
343132
  module2.exports = function(inBuffer, options) {
339645
343133
  var entryList = [], entryTable = {}, _comment = Buffer.alloc(0), mainHeader = new Headers.MainHeader(), loadedEntries = false;
339646
343134
  var password = null;
@@ -339985,7 +343473,7 @@ var require_zipFile = __commonJS({
339985
343473
  var require_adm_zip = __commonJS({
339986
343474
  "../../node_modules/adm-zip/adm-zip.js"(exports2, module2) {
339987
343475
  "use strict";
339988
- var Utils = require_util4();
343476
+ var Utils = require_util5();
339989
343477
  var pth = require("path");
339990
343478
  var ZipEntry = require_zipEntry();
339991
343479
  var ZipFile = require_zipFile();
@@ -351618,7 +355106,7 @@ var require_package4 = __commonJS({
351618
355106
  "package.json"(exports2, module2) {
351619
355107
  module2.exports = {
351620
355108
  name: "@validate.qa/runner",
351621
- version: "1.0.87",
355109
+ version: "1.0.89",
351622
355110
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
351623
355111
  bin: {
351624
355112
  "validate-runner": "dist/cli.js"
@@ -352479,6 +355967,68 @@ async function waitForUiSettle(sessionPath, opts = {}) {
352479
355967
  }
352480
355968
  return { settled: false, lastFingerprint, frames };
352481
355969
  }
355970
+ var SYSTEM_UI_DISMISS_LABELS = [
355971
+ "OK",
355972
+ "Got it",
355973
+ "GOT IT",
355974
+ "Continue",
355975
+ "Close",
355976
+ "Dismiss",
355977
+ "I understand",
355978
+ "Accept",
355979
+ // Android 15+ / 16 KB page-size compatibility dialog primary action.
355980
+ "OK, got it"
355981
+ ];
355982
+ function extractElementId(value) {
355983
+ if (!value || typeof value !== "object") return null;
355984
+ const v = value;
355985
+ const elementId = v.ELEMENT ?? v["element-6066-11e4-a52e-4f735466cecf"] ?? null;
355986
+ if (typeof elementId !== "string" || !ELEMENT_ID_PATTERN.test(elementId)) return null;
355987
+ return elementId;
355988
+ }
355989
+ async function dismissBlockingSystemUi(sessionPath, platform3, opts = {}) {
355990
+ const maxDismisses = Math.max(1, Math.min(5, opts.maxDismisses ?? 3));
355991
+ const dismissed = [];
355992
+ for (let i = 0; i < maxDismisses; i++) {
355993
+ let tapped = false;
355994
+ for (const label of SYSTEM_UI_DISMISS_LABELS) {
355995
+ try {
355996
+ const strategies = platform3 === "ANDROID" ? [
355997
+ { using: "-android uiautomator", value: `new UiSelector().text("${label.replace(/"/g, '\\"')}")` },
355998
+ { using: "accessibility id", value: label }
355999
+ ] : [
356000
+ { using: "accessibility id", value: label },
356001
+ { using: "-ios predicate string", value: `label == "${label.replace(/"/g, '\\"')}" OR name == "${label.replace(/"/g, '\\"')}"` }
356002
+ ];
356003
+ for (const strategy of strategies) {
356004
+ try {
356005
+ const elResult = await appiumRequest(`${sessionPath}/element`, {
356006
+ method: "POST",
356007
+ body: JSON.stringify(strategy)
356008
+ });
356009
+ const elementId = extractElementId(readValue(elResult));
356010
+ if (!elementId) continue;
356011
+ await appiumRequest(`${sessionPath}/element/${elementId}/click`, {
356012
+ method: "POST",
356013
+ body: "{}"
356014
+ });
356015
+ dismissed.push(label);
356016
+ tapped = true;
356017
+ await waitForUiSettle(sessionPath, { timeoutMs: 1200, pollMs: 200, minStableFrames: 1 });
356018
+ break;
356019
+ } catch (err) {
356020
+ if (isAppiumDriverDeadError(err)) throw err;
356021
+ }
356022
+ }
356023
+ if (tapped) break;
356024
+ } catch (err) {
356025
+ if (isAppiumDriverDeadError(err)) throw err;
356026
+ }
356027
+ }
356028
+ if (!tapped) break;
356029
+ }
356030
+ return { dismissed, ok: dismissed.length > 0 };
356031
+ }
352482
356032
  async function waitForColdBootSettle(sessionPath) {
352483
356033
  await waitForUiSettle(sessionPath, {
352484
356034
  timeoutMs: MOBILE_COLD_BOOT_SETTLE_MS,
@@ -355216,6 +358766,107 @@ async function waitForColdBootContent(sessionId, log2, timeoutMs = 2e4) {
355216
358766
  }
355217
358767
  log2(` Cold-boot wait timed out after ${timeoutMs}ms (last tree had ${lastCount} node(s)) \u2014 proceeding anyway.`);
355218
358768
  }
358769
+ async function dismissSystemUiAfterColdBoot(sessionId, platform3, log2) {
358770
+ try {
358771
+ const result = await dismissBlockingSystemUi(`/session/${sessionId}`, platform3);
358772
+ if (result.dismissed.length > 0) {
358773
+ log2(` Dismissed system UI: ${result.dismissed.join(" \u2192 ")}`);
358774
+ }
358775
+ } catch (err) {
358776
+ log2(` System UI dismiss skipped (${err instanceof Error ? err.message : String(err)})`);
358777
+ }
358778
+ }
358779
+ async function captureMobileStateValues(sessionId, kind) {
358780
+ const res = await wdRequest(`/session/${sessionId}/source`);
358781
+ const xml = typeof res?.value === "string" ? res.value : "";
358782
+ if (kind === "badge_count") {
358783
+ const nums = /* @__PURE__ */ new Set();
358784
+ for (const m of xml.matchAll(/\b(\d{1,6})\b/g)) {
358785
+ nums.add(m[1]);
358786
+ }
358787
+ const preferred = /* @__PURE__ */ new Set();
358788
+ for (const m of xml.matchAll(/(?:count|badge|open|unread|item|invoice|result|pending)[^>]{0,80}?\b(\d{1,6})\b/gi)) {
358789
+ preferred.add(m[1]);
358790
+ }
358791
+ for (const m of xml.matchAll(/\b(\d{1,6})\b[^>]{0,80}?(?:count|badge|open|unread|items?)/gi)) {
358792
+ preferred.add(m[1]);
358793
+ }
358794
+ return preferred.size > 0 ? [...preferred] : [...nums].slice(0, 20);
358795
+ }
358796
+ const labels = /* @__PURE__ */ new Set();
358797
+ const attrRe = /(?:text|content-desc|name|label)="([^"]{2,80})"/gi;
358798
+ for (const m of xml.matchAll(attrRe)) {
358799
+ const t = m[1].trim();
358800
+ if (t.length < 2 || t.length > 80) continue;
358801
+ if (/^(true|false|null|OK|Cancel)$/i.test(t)) continue;
358802
+ labels.add(t);
358803
+ }
358804
+ return [...labels].slice(0, 80);
358805
+ }
358806
+ function assertMobileStateDelta(before, after, expect, key, log2) {
358807
+ const beforeSet = new Set(before);
358808
+ const afterSet = new Set(after);
358809
+ const removed = before.filter((v) => !afterSet.has(v));
358810
+ const added = after.filter((v) => !beforeSet.has(v));
358811
+ log2(` assertStateDelta key=${key} expect=${expect} removed=${removed.length} added=${added.length}`);
358812
+ const exp = expect.toLowerCase().trim();
358813
+ if (exp === "changed" || exp === "any_change") {
358814
+ if (removed.length === 0 && added.length === 0) {
358815
+ throw new Error(`assertStateDelta(${key}): expected state to change, but capture is identical (${before.length} values)`);
358816
+ }
358817
+ return;
358818
+ }
358819
+ if (exp === "removed" || exp === "entity_removed" || exp.startsWith("removed:")) {
358820
+ const target = exp.startsWith("removed:") ? expect.slice("removed:".length).trim() : "";
358821
+ if (target) {
358822
+ if (!removed.includes(target) && afterSet.has(target)) {
358823
+ throw new Error(`assertStateDelta(${key}): expected "${target}" removed, but it is still present`);
358824
+ }
358825
+ if (!beforeSet.has(target)) {
358826
+ throw new Error(`assertStateDelta(${key}): expected "${target}" to have been in the prior capture`);
358827
+ }
358828
+ if (afterSet.has(target)) {
358829
+ throw new Error(`assertStateDelta(${key}): "${target}" was not removed`);
358830
+ }
358831
+ return;
358832
+ }
358833
+ if (removed.length === 0) {
358834
+ throw new Error(`assertStateDelta(${key}): expected at least one entity removed`);
358835
+ }
358836
+ return;
358837
+ }
358838
+ if (exp === "count_decreased" || exp === "count-1") {
358839
+ const b = before.map(Number).filter((n) => Number.isFinite(n));
358840
+ const a = after.map(Number).filter((n) => Number.isFinite(n));
358841
+ const bMax = b.length ? Math.max(...b) : NaN;
358842
+ const aMax = a.length ? Math.max(...a) : NaN;
358843
+ if (!Number.isFinite(bMax) || !Number.isFinite(aMax) || aMax >= bMax) {
358844
+ throw new Error(`assertStateDelta(${key}): expected count decrease (before max=${bMax}, after max=${aMax})`);
358845
+ }
358846
+ return;
358847
+ }
358848
+ if (exp === "count_increased" || exp === "count+1") {
358849
+ const b = before.map(Number).filter((n) => Number.isFinite(n));
358850
+ const a = after.map(Number).filter((n) => Number.isFinite(n));
358851
+ const bMax = b.length ? Math.max(...b) : NaN;
358852
+ const aMax = a.length ? Math.max(...a) : NaN;
358853
+ if (!Number.isFinite(bMax) || !Number.isFinite(aMax) || aMax <= bMax) {
358854
+ throw new Error(`assertStateDelta(${key}): expected count increase (before max=${bMax}, after max=${aMax})`);
358855
+ }
358856
+ return;
358857
+ }
358858
+ if (exp === "unchanged" || exp === "persisted") {
358859
+ if (removed.length > 0 || added.length > 0) {
358860
+ throw new Error(
358861
+ `assertStateDelta(${key}): expected persistence/unchanged, but removed=[${removed.slice(0, 5).join(", ")}] added=[${added.slice(0, 5).join(", ")}]`
358862
+ );
358863
+ }
358864
+ return;
358865
+ }
358866
+ if (removed.length === 0 && added.length === 0) {
358867
+ throw new Error(`assertStateDelta(${key}): expected change (expect=${expect}), state identical`);
358868
+ }
358869
+ }
355219
358870
  async function restoreTargetAppIfExternal(sessionId, target, log2, source, failOnExternal) {
355220
358871
  let boundary = null;
355221
358872
  try {
@@ -356361,6 +360012,7 @@ async function executeMobileTest(options) {
356361
360012
  }
356362
360013
  const stepResults = [];
356363
360014
  const screenshots = [];
360015
+ const stateBag = /* @__PURE__ */ new Map();
356364
360016
  let apiCalls = [];
356365
360017
  let sessionId = null;
356366
360018
  let selectedDevice;
@@ -356571,6 +360223,9 @@ async function executeMobileTest(options) {
356571
360223
  if (clearedAppDataBeforeLaunch) {
356572
360224
  await waitForColdBootContent(sessionId, log2);
356573
360225
  }
360226
+ if (options.target.launchMode !== "RESUME") {
360227
+ await dismissSystemUiAfterColdBoot(sessionId, options.target.platform, log2);
360228
+ }
356574
360229
  if (options.target.launchMode === "DEEP_LINK" && options.target.deeplink) {
356575
360230
  try {
356576
360231
  log2(`Opening deep link: ${options.target.deeplink}`);
@@ -356665,6 +360320,25 @@ async function executeMobileTest(options) {
356665
360320
  case "assertText":
356666
360321
  await executeAssertText(sessionId, step, runPlatform, isCrossPlatform);
356667
360322
  break;
360323
+ case "captureState": {
360324
+ const key = String(step.metadata?.stateKey ?? step.target?.primary ?? `state-${step.order}`);
360325
+ const kind = String(step.metadata?.stateKind ?? "list_ids");
360326
+ const values = await captureMobileStateValues(sessionId, kind);
360327
+ stateBag.set(key, { kind, values, capturedAt: Date.now() });
360328
+ log2(` captureState key=${key} kind=${kind} n=${values.length}`);
360329
+ break;
360330
+ }
360331
+ case "assertStateDelta": {
360332
+ const key = String(step.metadata?.stateKey ?? step.target?.primary ?? "");
360333
+ const expect = String(step.metadata?.expect ?? step.assertion ?? "changed");
360334
+ const prior = stateBag.get(key);
360335
+ if (!prior) {
360336
+ throw new Error(`assertStateDelta: no prior captureState for key "${key}"`);
360337
+ }
360338
+ const current = await captureMobileStateValues(sessionId, prior.kind);
360339
+ assertMobileStateDelta(prior.values, current, expect, key, log2);
360340
+ break;
360341
+ }
356668
360342
  default: {
356669
360343
  const _exhaustive = step.action;
356670
360344
  status = "failed";
@@ -356843,6 +360517,10 @@ async function createMobileDiscoverySession(target, options) {
356843
360517
  );
356844
360518
  }
356845
360519
  }
360520
+ try {
360521
+ await dismissBlockingSystemUi(`/session/${sessionId}`, target.platform);
360522
+ } catch {
360523
+ }
356846
360524
  let stopped = false;
356847
360525
  return {
356848
360526
  sessionId,
@@ -356980,6 +360658,8 @@ async function driveHarvestStep(sessionId, step, elementId, platform3) {
356980
360658
  case "waitForElement":
356981
360659
  case "assertVisible":
356982
360660
  case "assertText":
360661
+ case "captureState":
360662
+ case "assertStateDelta":
356983
360663
  return true;
356984
360664
  }
356985
360665
  }
@@ -357013,6 +360693,7 @@ async function harvestPlatformLocators(options) {
357013
360693
  try {
357014
360694
  options.onSessionReady?.(session.sessionId, session.deviceId, platform3);
357015
360695
  await freshLaunchTargetApp(session.sessionId, platform3, options.target.appId, log2);
360696
+ await dismissSystemUiAfterColdBoot(session.sessionId, platform3, log2);
357016
360697
  if (options.target.launchMode === "DEEP_LINK" && options.target.deeplink) {
357017
360698
  await openDeepLink(session.sessionId, platform3, options.target.deeplink, options.target.appId);
357018
360699
  }
@@ -357288,7 +360969,9 @@ function decideMobileDeviceGate(input) {
357288
360969
  }
357289
360970
  }
357290
360971
  const isHealForHeldTest = runMode === "heal" && !!testCaseId && healHoldTestCaseIds.has(testCaseId);
357291
- const reservedForHeals = isHealForHeldTest ? Math.max(0, healHoldTestCaseIds.size - 1) : healHoldTestCaseIds.size;
360972
+ const rawReservedForHeals = isHealForHeldTest ? Math.max(0, healHoldTestCaseIds.size - 1) : healHoldTestCaseIds.size;
360973
+ const maxHealReserve = capacity <= 1 ? capacity : Math.max(1, capacity - 1);
360974
+ const reservedForHeals = Math.min(rawReservedForHeals, maxHealReserve);
357292
360975
  if (activeMobileOps + reservedForHeals >= capacity) {
357293
360976
  const reason = reservedForHeals > 0 ? `capacity reserved for pending auto-heal: ${activeMobileOps}+${reservedForHeals}/${capacity}` : `mobile capacity reached: ${activeMobileOps}/${capacity} in use`;
357294
360977
  return { claim: false, disposition: "defer", reason };
@@ -359124,6 +362807,11 @@ var MobileBridgeDriver = class {
359124
362807
  } catch (err) {
359125
362808
  if (isRecoverableAppiumSessionFailure(err)) throw err;
359126
362809
  }
362810
+ try {
362811
+ await dismissBlockingSystemUi(this.sessionPath, this.platform);
362812
+ } catch (err) {
362813
+ if (isRecoverableAppiumSessionFailure(err) || isAppiumDriverDeadError(err)) throw err;
362814
+ }
359127
362815
  });
359128
362816
  }
359129
362817
  /**
@@ -359161,6 +362849,11 @@ var MobileBridgeDriver = class {
359161
362849
  } catch (err) {
359162
362850
  if (isRecoverableAppiumSessionFailure(err)) throw err;
359163
362851
  }
362852
+ try {
362853
+ await dismissBlockingSystemUi(this.sessionPath, this.platform);
362854
+ } catch (err) {
362855
+ if (isRecoverableAppiumSessionFailure(err) || isAppiumDriverDeadError(err)) throw err;
362856
+ }
359164
362857
  return true;
359165
362858
  } catch (err) {
359166
362859
  if (isRecoverableAppiumSessionFailure(err)) throw err;
@@ -362520,6 +366213,17 @@ ${finalVerifyResult.logs ?? ""}`;
362520
366213
  }
362521
366214
  };
362522
366215
  log.info("\u{1FA7A} Mobile AI heal \u2014 Phase 1 (script) \u2192 Phase 2 (live device, lazy)...");
366216
+ const tagList = Array.isArray(run2.tags) ? run2.tags : [];
366217
+ const failureCount = Math.max(
366218
+ 1,
366219
+ typeof run2.consecutiveFails === "number" && run2.consecutiveFails > 0 ? run2.consecutiveFails : tagList.includes("@bug-found") ? 2 : 1
366220
+ );
366221
+ const reproduceApiCalls = Array.isArray(nativeVerify.last?.apiCalls) ? nativeVerify.last.apiCalls.map((c) => ({
366222
+ method: typeof c.method === "string" ? c.method : void 0,
366223
+ url: typeof c.url === "string" ? c.url : void 0,
366224
+ status: typeof c.status === "number" ? c.status : void 0
366225
+ })) : void 0;
366226
+ const uiPathSucceeded = Array.isArray(reproduce.stepResults) && reproduce.stepResults.filter((s) => s.status === "passed").length >= Math.max(1, reproduce.stepResults.length - 1);
362523
366227
  const heal = await (0, import_runner_core14.executeMobileTestWithHealing)(
362524
366228
  mobileSteps,
362525
366229
  healTarget,
@@ -362528,7 +366232,11 @@ ${finalVerifyResult.logs ?? ""}`;
362528
366232
  logs: reproduce.logs,
362529
366233
  failingSource: reproduce.failingSource,
362530
366234
  testVariables: run2.testVariables,
362531
- testName: run2.testName
366235
+ testName: run2.testName,
366236
+ tags: tagList,
366237
+ failureCount,
366238
+ apiCalls: reproduceApiCalls,
366239
+ uiPathSucceeded
362532
366240
  },
362533
366241
  healerOptions
362534
366242
  );
@@ -362537,7 +366245,8 @@ ${finalVerifyResult.logs ?? ""}`;
362537
366245
  heal,
362538
366246
  finalError: finalRes?.error ?? null,
362539
366247
  reproduceError,
362540
- testVariables: run2.testVariables
366248
+ testVariables: run2.testVariables,
366249
+ originalSteps: mobileSteps
362541
366250
  });
362542
366251
  await postResult(opts.serverUrl, headers, run2.runId, {
362543
366252
  status: outcome.status,