prowl-tools 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.d.cts CHANGED
@@ -444,6 +444,8 @@ interface SessionDriver {
444
444
  goto(url: string, options?: NavigateOptions): Promise<void>;
445
445
  currentUrl(): string;
446
446
  count(selector: string): Promise<number>;
447
+ /** Count only elements the driver considers visibly present, when it can distinguish visibility from existence. */
448
+ visibleCount?(selector: string): Promise<number>;
447
449
  textContent(selector: string): Promise<string | null>;
448
450
  click(selector: string): Promise<void>;
449
451
  clickFirst(selector: string): Promise<void>;
@@ -453,6 +455,12 @@ interface SessionDriver {
453
455
  selectOption(selector: string, value: string): Promise<void>;
454
456
  selectOptionFirst(selector: string, value: string): Promise<void>;
455
457
  hover(selector: string): Promise<void>;
458
+ /**
459
+ * Scroll the viewport in `direction` by `amount` (engine-defined units: CSS
460
+ * pixels on web, a synthesized swipe distance on mobile). Native targets that
461
+ * have no scroll gesture (macOS) reject this.
462
+ */
463
+ scroll(direction: "up" | "down" | "left" | "right", amount?: number): Promise<void>;
456
464
  scrollIntoView(selector: string): Promise<void>;
457
465
  setInputFiles(selector: string, files: string | string[]): Promise<void>;
458
466
  countByRole(role: string, name: string): Promise<number>;
@@ -751,6 +759,38 @@ declare function collectMacdriverStatus(options?: StatusOptions): Promise<Macdri
751
759
  /** Static TCC-permission guidance printed after install / in status. */
752
760
  declare function tccGuidance(): string;
753
761
 
762
+ /** Screen dimensions in device points, as reported by the agent. */
763
+ interface ScreenSize {
764
+ width: number;
765
+ height: number;
766
+ }
767
+ /** One item in a W3C `pointer` action sequence. */
768
+ type PointerActionItem = {
769
+ type: "pointerMove";
770
+ duration: number;
771
+ x: number;
772
+ y: number;
773
+ origin?: "viewport";
774
+ } | {
775
+ type: "pointerDown";
776
+ button: number;
777
+ } | {
778
+ type: "pointerUp";
779
+ button: number;
780
+ } | {
781
+ type: "pause";
782
+ duration: number;
783
+ };
784
+ /** A single `touch` pointer input source and its ordered actions. */
785
+ interface PointerActionSequence {
786
+ type: "pointer";
787
+ id: string;
788
+ parameters: {
789
+ pointerType: "touch";
790
+ };
791
+ actions: PointerActionItem[];
792
+ }
793
+
754
794
  /** The selector kinds the native dialect understands. */
755
795
  type NativeSelectorKind = "id" | "label" | "text" | "role" | "focused";
756
796
  /**
@@ -968,6 +1008,10 @@ interface AndroidAgentClient {
968
1008
  getText(elementId: string): Promise<string | null>;
969
1009
  /** Dispatch a global key event by Android key code (goes to the focused view). */
970
1010
  pressKeyCode(keyCode: number): Promise<void>;
1011
+ /** Current screen size in pixels (uiautomator2 `/window/current/size`), for gestures. */
1012
+ windowSize(): Promise<ScreenSize>;
1013
+ /** Perform a W3C pointer action sequence (`POST /session/:id/actions`). */
1014
+ performActions(actions: PointerActionSequence): Promise<void>;
971
1015
  /** Capture the current screen as PNG bytes. */
972
1016
  screenshotPng(): Promise<Buffer>;
973
1017
  /**
@@ -1211,10 +1255,16 @@ interface IosAgentClient {
1211
1255
  /** Replace an element's text (W3C `element/value`). */
1212
1256
  setValue(elementId: string, text: string): Promise<void>;
1213
1257
  getText(elementId: string): Promise<string | null>;
1258
+ /** True only when WDA reports the element is displayed in the current viewport. */
1259
+ isDisplayed(elementId: string): Promise<boolean>;
1214
1260
  /** Send raw key sequences to the focused element (WDA `/wda/keys`). */
1215
1261
  sendKeys(keys: string[]): Promise<void>;
1216
1262
  /** Return to the springboard home screen (WDA `/wda/homescreen`). */
1217
1263
  homescreen(): Promise<void>;
1264
+ /** Current screen size in points (WDA `/window/size`), for gesture geometry. */
1265
+ windowSize(): Promise<ScreenSize>;
1266
+ /** Perform a W3C pointer action sequence (WDA `POST /session/:id/actions`). */
1267
+ performActions(actions: PointerActionSequence): Promise<void>;
1218
1268
  /**
1219
1269
  * Return the current UI hierarchy as WebDriverAgent `/source` XML. Present on
1220
1270
  * live clients and consumed by the analyzer (PROWL-061); optional so lighter
@@ -1516,7 +1566,9 @@ declare function createWdaAgentClient(transport: WdaTransport, sessionId: string
1516
1566
  * Step types that only make sense on the web target. Everything else
1517
1567
  * (`click`, `fill`, `type`, `press`, `wait`, `assert visible/notVisible`,
1518
1568
  * `screenshot`, `assertScreenshot`, `repeat`, `runHunt`, `if`, `copyText`,
1519
- * `hover`, `scrollTo`, `waitForSelector`) is portable across targets.
1569
+ * `hover`, `scrollTo`, `waitForSelector`) is portable across targets. The
1570
+ * directional `scroll` step is the one per-target exception — see
1571
+ * {@link MACOS_UNSUPPORTED_STEP_TYPES}.
1520
1572
  */
1521
1573
  declare const WEB_ONLY_STEP_TYPES: ReadonlySet<string>;
1522
1574
  /** The web-only reason a step is unsupported on a non-web target, or null if portable. */
@@ -1524,8 +1576,10 @@ declare function webOnlyReason(step: Step): string | null;
1524
1576
  /**
1525
1577
  * Throw if any step in `steps` (recursing into `if`/`repeat` bodies) is not
1526
1578
  * supported by `target`. `runHunt` references are validated when the referenced
1527
- * hunt itself runs. No-op for the web target; every native target (macOS,
1528
- * Android, iOS) rejects the same web-only step vocabulary.
1579
+ * hunt itself runs. No-op for the web target; every native target rejects the
1580
+ * same web-only step vocabulary, and macOS additionally rejects the directional
1581
+ * `scroll` swipe (no AX equivalent) — but NOT `scrollTo`, which macOS maps to
1582
+ * AXScrollToVisible just as iOS/Android map it to a swipe loop.
1529
1583
  */
1530
1584
  declare function assertStepsSupportedByTarget(steps: Step[], target: Target["type"]): void;
1531
1585
  /** Read the bundle id from an iOS `.app` (root `Info.plist`), or null. */
@@ -1862,24 +1916,24 @@ declare const configSchema: z.ZodObject<{
1862
1916
  }>]>>;
1863
1917
  }, "strip", z.ZodTypeAny, {
1864
1918
  timeout?: number | undefined;
1865
- headless?: boolean | undefined;
1866
- slowMo?: number | undefined;
1867
- engine?: "chromium" | "firefox" | "webkit" | undefined;
1868
- channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
1869
1919
  viewport?: "mobile" | "tablet" | "desktop" | {
1870
1920
  width: number;
1871
1921
  height: number;
1872
1922
  } | undefined;
1873
- }, {
1874
- timeout?: number | undefined;
1875
1923
  headless?: boolean | undefined;
1876
1924
  slowMo?: number | undefined;
1877
1925
  engine?: "chromium" | "firefox" | "webkit" | undefined;
1878
1926
  channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
1927
+ }, {
1928
+ timeout?: number | undefined;
1879
1929
  viewport?: "mobile" | "tablet" | "desktop" | {
1880
1930
  width: number;
1881
1931
  height: number;
1882
1932
  } | undefined;
1933
+ headless?: boolean | undefined;
1934
+ slowMo?: number | undefined;
1935
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
1936
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
1883
1937
  }>>;
1884
1938
  artifacts: z.ZodOptional<z.ZodObject<{
1885
1939
  screenshots: z.ZodOptional<z.ZodEnum<["on-failure", "all"]>>;
@@ -1993,14 +2047,14 @@ declare const configSchema: z.ZodObject<{
1993
2047
  };
1994
2048
  browser?: {
1995
2049
  timeout?: number | undefined;
1996
- headless?: boolean | undefined;
1997
- slowMo?: number | undefined;
1998
- engine?: "chromium" | "firefox" | "webkit" | undefined;
1999
- channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2000
2050
  viewport?: "mobile" | "tablet" | "desktop" | {
2001
2051
  width: number;
2002
2052
  height: number;
2003
2053
  } | undefined;
2054
+ headless?: boolean | undefined;
2055
+ slowMo?: number | undefined;
2056
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
2057
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2004
2058
  } | undefined;
2005
2059
  artifacts?: {
2006
2060
  screenshots?: "on-failure" | "all" | undefined;
@@ -2058,14 +2112,14 @@ declare const configSchema: z.ZodObject<{
2058
2112
  };
2059
2113
  browser?: {
2060
2114
  timeout?: number | undefined;
2061
- headless?: boolean | undefined;
2062
- slowMo?: number | undefined;
2063
- engine?: "chromium" | "firefox" | "webkit" | undefined;
2064
- channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2065
2115
  viewport?: "mobile" | "tablet" | "desktop" | {
2066
2116
  width: number;
2067
2117
  height: number;
2068
2118
  } | undefined;
2119
+ headless?: boolean | undefined;
2120
+ slowMo?: number | undefined;
2121
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
2122
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2069
2123
  } | undefined;
2070
2124
  artifacts?: {
2071
2125
  screenshots?: "on-failure" | "all" | undefined;
package/dist/lib.d.ts CHANGED
@@ -444,6 +444,8 @@ interface SessionDriver {
444
444
  goto(url: string, options?: NavigateOptions): Promise<void>;
445
445
  currentUrl(): string;
446
446
  count(selector: string): Promise<number>;
447
+ /** Count only elements the driver considers visibly present, when it can distinguish visibility from existence. */
448
+ visibleCount?(selector: string): Promise<number>;
447
449
  textContent(selector: string): Promise<string | null>;
448
450
  click(selector: string): Promise<void>;
449
451
  clickFirst(selector: string): Promise<void>;
@@ -453,6 +455,12 @@ interface SessionDriver {
453
455
  selectOption(selector: string, value: string): Promise<void>;
454
456
  selectOptionFirst(selector: string, value: string): Promise<void>;
455
457
  hover(selector: string): Promise<void>;
458
+ /**
459
+ * Scroll the viewport in `direction` by `amount` (engine-defined units: CSS
460
+ * pixels on web, a synthesized swipe distance on mobile). Native targets that
461
+ * have no scroll gesture (macOS) reject this.
462
+ */
463
+ scroll(direction: "up" | "down" | "left" | "right", amount?: number): Promise<void>;
456
464
  scrollIntoView(selector: string): Promise<void>;
457
465
  setInputFiles(selector: string, files: string | string[]): Promise<void>;
458
466
  countByRole(role: string, name: string): Promise<number>;
@@ -751,6 +759,38 @@ declare function collectMacdriverStatus(options?: StatusOptions): Promise<Macdri
751
759
  /** Static TCC-permission guidance printed after install / in status. */
752
760
  declare function tccGuidance(): string;
753
761
 
762
+ /** Screen dimensions in device points, as reported by the agent. */
763
+ interface ScreenSize {
764
+ width: number;
765
+ height: number;
766
+ }
767
+ /** One item in a W3C `pointer` action sequence. */
768
+ type PointerActionItem = {
769
+ type: "pointerMove";
770
+ duration: number;
771
+ x: number;
772
+ y: number;
773
+ origin?: "viewport";
774
+ } | {
775
+ type: "pointerDown";
776
+ button: number;
777
+ } | {
778
+ type: "pointerUp";
779
+ button: number;
780
+ } | {
781
+ type: "pause";
782
+ duration: number;
783
+ };
784
+ /** A single `touch` pointer input source and its ordered actions. */
785
+ interface PointerActionSequence {
786
+ type: "pointer";
787
+ id: string;
788
+ parameters: {
789
+ pointerType: "touch";
790
+ };
791
+ actions: PointerActionItem[];
792
+ }
793
+
754
794
  /** The selector kinds the native dialect understands. */
755
795
  type NativeSelectorKind = "id" | "label" | "text" | "role" | "focused";
756
796
  /**
@@ -968,6 +1008,10 @@ interface AndroidAgentClient {
968
1008
  getText(elementId: string): Promise<string | null>;
969
1009
  /** Dispatch a global key event by Android key code (goes to the focused view). */
970
1010
  pressKeyCode(keyCode: number): Promise<void>;
1011
+ /** Current screen size in pixels (uiautomator2 `/window/current/size`), for gestures. */
1012
+ windowSize(): Promise<ScreenSize>;
1013
+ /** Perform a W3C pointer action sequence (`POST /session/:id/actions`). */
1014
+ performActions(actions: PointerActionSequence): Promise<void>;
971
1015
  /** Capture the current screen as PNG bytes. */
972
1016
  screenshotPng(): Promise<Buffer>;
973
1017
  /**
@@ -1211,10 +1255,16 @@ interface IosAgentClient {
1211
1255
  /** Replace an element's text (W3C `element/value`). */
1212
1256
  setValue(elementId: string, text: string): Promise<void>;
1213
1257
  getText(elementId: string): Promise<string | null>;
1258
+ /** True only when WDA reports the element is displayed in the current viewport. */
1259
+ isDisplayed(elementId: string): Promise<boolean>;
1214
1260
  /** Send raw key sequences to the focused element (WDA `/wda/keys`). */
1215
1261
  sendKeys(keys: string[]): Promise<void>;
1216
1262
  /** Return to the springboard home screen (WDA `/wda/homescreen`). */
1217
1263
  homescreen(): Promise<void>;
1264
+ /** Current screen size in points (WDA `/window/size`), for gesture geometry. */
1265
+ windowSize(): Promise<ScreenSize>;
1266
+ /** Perform a W3C pointer action sequence (WDA `POST /session/:id/actions`). */
1267
+ performActions(actions: PointerActionSequence): Promise<void>;
1218
1268
  /**
1219
1269
  * Return the current UI hierarchy as WebDriverAgent `/source` XML. Present on
1220
1270
  * live clients and consumed by the analyzer (PROWL-061); optional so lighter
@@ -1516,7 +1566,9 @@ declare function createWdaAgentClient(transport: WdaTransport, sessionId: string
1516
1566
  * Step types that only make sense on the web target. Everything else
1517
1567
  * (`click`, `fill`, `type`, `press`, `wait`, `assert visible/notVisible`,
1518
1568
  * `screenshot`, `assertScreenshot`, `repeat`, `runHunt`, `if`, `copyText`,
1519
- * `hover`, `scrollTo`, `waitForSelector`) is portable across targets.
1569
+ * `hover`, `scrollTo`, `waitForSelector`) is portable across targets. The
1570
+ * directional `scroll` step is the one per-target exception — see
1571
+ * {@link MACOS_UNSUPPORTED_STEP_TYPES}.
1520
1572
  */
1521
1573
  declare const WEB_ONLY_STEP_TYPES: ReadonlySet<string>;
1522
1574
  /** The web-only reason a step is unsupported on a non-web target, or null if portable. */
@@ -1524,8 +1576,10 @@ declare function webOnlyReason(step: Step): string | null;
1524
1576
  /**
1525
1577
  * Throw if any step in `steps` (recursing into `if`/`repeat` bodies) is not
1526
1578
  * supported by `target`. `runHunt` references are validated when the referenced
1527
- * hunt itself runs. No-op for the web target; every native target (macOS,
1528
- * Android, iOS) rejects the same web-only step vocabulary.
1579
+ * hunt itself runs. No-op for the web target; every native target rejects the
1580
+ * same web-only step vocabulary, and macOS additionally rejects the directional
1581
+ * `scroll` swipe (no AX equivalent) — but NOT `scrollTo`, which macOS maps to
1582
+ * AXScrollToVisible just as iOS/Android map it to a swipe loop.
1529
1583
  */
1530
1584
  declare function assertStepsSupportedByTarget(steps: Step[], target: Target["type"]): void;
1531
1585
  /** Read the bundle id from an iOS `.app` (root `Info.plist`), or null. */
@@ -1862,24 +1916,24 @@ declare const configSchema: z.ZodObject<{
1862
1916
  }>]>>;
1863
1917
  }, "strip", z.ZodTypeAny, {
1864
1918
  timeout?: number | undefined;
1865
- headless?: boolean | undefined;
1866
- slowMo?: number | undefined;
1867
- engine?: "chromium" | "firefox" | "webkit" | undefined;
1868
- channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
1869
1919
  viewport?: "mobile" | "tablet" | "desktop" | {
1870
1920
  width: number;
1871
1921
  height: number;
1872
1922
  } | undefined;
1873
- }, {
1874
- timeout?: number | undefined;
1875
1923
  headless?: boolean | undefined;
1876
1924
  slowMo?: number | undefined;
1877
1925
  engine?: "chromium" | "firefox" | "webkit" | undefined;
1878
1926
  channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
1927
+ }, {
1928
+ timeout?: number | undefined;
1879
1929
  viewport?: "mobile" | "tablet" | "desktop" | {
1880
1930
  width: number;
1881
1931
  height: number;
1882
1932
  } | undefined;
1933
+ headless?: boolean | undefined;
1934
+ slowMo?: number | undefined;
1935
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
1936
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
1883
1937
  }>>;
1884
1938
  artifacts: z.ZodOptional<z.ZodObject<{
1885
1939
  screenshots: z.ZodOptional<z.ZodEnum<["on-failure", "all"]>>;
@@ -1993,14 +2047,14 @@ declare const configSchema: z.ZodObject<{
1993
2047
  };
1994
2048
  browser?: {
1995
2049
  timeout?: number | undefined;
1996
- headless?: boolean | undefined;
1997
- slowMo?: number | undefined;
1998
- engine?: "chromium" | "firefox" | "webkit" | undefined;
1999
- channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2000
2050
  viewport?: "mobile" | "tablet" | "desktop" | {
2001
2051
  width: number;
2002
2052
  height: number;
2003
2053
  } | undefined;
2054
+ headless?: boolean | undefined;
2055
+ slowMo?: number | undefined;
2056
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
2057
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2004
2058
  } | undefined;
2005
2059
  artifacts?: {
2006
2060
  screenshots?: "on-failure" | "all" | undefined;
@@ -2058,14 +2112,14 @@ declare const configSchema: z.ZodObject<{
2058
2112
  };
2059
2113
  browser?: {
2060
2114
  timeout?: number | undefined;
2061
- headless?: boolean | undefined;
2062
- slowMo?: number | undefined;
2063
- engine?: "chromium" | "firefox" | "webkit" | undefined;
2064
- channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2065
2115
  viewport?: "mobile" | "tablet" | "desktop" | {
2066
2116
  width: number;
2067
2117
  height: number;
2068
2118
  } | undefined;
2119
+ headless?: boolean | undefined;
2120
+ slowMo?: number | undefined;
2121
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
2122
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2069
2123
  } | undefined;
2070
2124
  artifacts?: {
2071
2125
  screenshots?: "on-failure" | "all" | undefined;
package/dist/lib.js CHANGED
@@ -74,7 +74,6 @@ import {
74
74
  healSelector,
75
75
  injectUsePortIntoXctestrun,
76
76
  installMacdriver,
77
- interpolateHunt,
78
77
  iosAppAllowedIdentities,
79
78
  iosNodeToNative,
80
79
  iosQueryToLocator,
@@ -150,17 +149,18 @@ import {
150
149
  wdaTestRunArgs,
151
150
  webOnlyReason,
152
151
  zipinfoArchiveLister
153
- } from "./chunk-R7NUH44M.js";
152
+ } from "./chunk-CWLRDV5P.js";
154
153
  import {
155
154
  configSchema,
156
155
  huntSchema,
156
+ interpolateHunt,
157
157
  listHunts,
158
158
  loadConfig,
159
159
  loadHunt,
160
160
  loadHuntMeta,
161
161
  loadHuntTags,
162
162
  stepSchema
163
- } from "./chunk-O3OUTZ2P.js";
163
+ } from "./chunk-JFJQNJSJ.js";
164
164
  export {
165
165
  ANDROID_INTERACTIVE_CLASSES,
166
166
  ANDROID_KEYCODES,
@@ -10,7 +10,7 @@ import {
10
10
  loadHuntTags,
11
11
  resolveViewport,
12
12
  warnLegacyConfigDir
13
- } from "./chunk-O3OUTZ2P.js";
13
+ } from "./chunk-JFJQNJSJ.js";
14
14
  export {
15
15
  CONFIG_DIR,
16
16
  LEGACY_CONFIG_DIR,
@@ -24,4 +24,4 @@ export {
24
24
  resolveViewport,
25
25
  warnLegacyConfigDir
26
26
  };
27
- //# sourceMappingURL=loader-X37URHUV.js.map
27
+ //# sourceMappingURL=loader-JTHA4BYG.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prowl-tools",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "E2E testing for native macOS apps and web apps from declarative YAML hunts.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/loader.ts","../src/config/schema.ts","../src/types/index.ts","../src/config/hunt-name.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport yaml from \"yaml\";\nimport dotenv from \"dotenv\";\nimport type { BrowserChannel, BrowserEngine, Config, Hunt, Target, Viewport } from \"../types/index.js\";\nimport { configSchema, huntSchema } from \"./schema.js\";\nimport { assertValidHuntName } from \"./hunt-name.js\";\n\nconst DEFAULT_WEB_URL = \"http://localhost:3000\";\n\nconst DEFAULT_CONFIG: Config = {\n target: {\n type: \"web\",\n url: DEFAULT_WEB_URL\n },\n browser: {\n headless: true,\n slowMo: 0,\n timeout: 30000,\n engine: \"chromium\",\n viewport: { width: 1280, height: 720 }\n },\n artifacts: {\n screenshots: \"on-failure\",\n networkHar: false,\n console: true,\n junit: false\n },\n assertions: {\n noConsoleErrors: true,\n noNetworkErrors: true,\n maxTotalTimeMs: 30000,\n networkIgnorePatterns: []\n },\n guardrails: {\n maxSteps: 50,\n allowedDomains: [\"localhost\", \"127.0.0.1\", \"0.0.0.0\"],\n allowedApps: [],\n forbiddenSelectors: [\"[data-danger]\", \".delete-btn\"],\n selfHealing: false\n },\n auth: {\n storageStatePath: \".prowl/auth-state.json\"\n },\n history: {\n maxRuns: 100\n }\n};\n\nexport const CONFIG_DIR = \".prowl\";\nexport const LEGACY_CONFIG_DIR = \".prowlqa\";\n\nlet legacyDirWarned = false;\n\n/** Warn (once per process) when a project still uses the legacy .prowlqa/ directory. */\nexport function warnLegacyConfigDir(): void {\n if (legacyDirWarned) {\n return;\n }\n legacyDirWarned = true;\n console.warn(\n 'Warning: the \".prowlqa/\" config directory is deprecated; rename it to \".prowl/\". ' +\n 'Support for \".prowlqa/\" will be removed in a future release.'\n );\n}\n\nexport function findConfigPath(startDir: string): string | null {\n let current = startDir;\n while (current) {\n // Prefer the new .prowl/ directory; fall back to the legacy .prowlqa/ at the same level.\n for (const dir of [CONFIG_DIR, LEGACY_CONFIG_DIR]) {\n const candidate = path.join(current, dir, \"config.yml\");\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n }\n const parent = path.dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n return null;\n}\n\nconst VIEWPORT_PRESETS: Record<string, Viewport> = {\n mobile: { width: 375, height: 812 },\n tablet: { width: 768, height: 1024 },\n desktop: { width: 1280, height: 720 }\n};\n\nexport function resolveViewport(\n value: string | Viewport | undefined\n): Viewport {\n if (value === undefined) {\n return DEFAULT_CONFIG.browser.viewport;\n }\n if (typeof value === \"string\") {\n const preset = VIEWPORT_PRESETS[value];\n if (!preset) {\n throw new Error(`Unknown viewport preset: \"${value}\". Use mobile, tablet, or desktop.`);\n }\n return preset;\n }\n return value;\n}\n\n/**\n * Normalize the validated target into a canonical discriminated shape. A target\n * with `type: \"macos\"` becomes a macOS target; anything else (including the\n * legacy `{ url }` with no `type`) resolves to the web target, so pre-existing\n * configs are untouched.\n */\nfunction resolveTarget(target: Config[\"target\"] | undefined): Target {\n const type = (target as { type?: string } | undefined)?.type;\n if (type === \"macos\") {\n return { type: \"macos\", app: (target as { app: string }).app };\n }\n if (type === \"android\") {\n const androidTarget = target as {\n app: string;\n deviceSerial?: string;\n coldStart?: boolean;\n };\n return {\n type: \"android\",\n app: androidTarget.app,\n ...(androidTarget.deviceSerial !== undefined ? { deviceSerial: androidTarget.deviceSerial } : {}),\n ...(androidTarget.coldStart !== undefined ? { coldStart: androidTarget.coldStart } : {})\n };\n }\n if (type === \"ios\") {\n const iosTarget = target as {\n app: string;\n udid?: string;\n coldStart?: boolean;\n };\n return {\n type: \"ios\",\n app: iosTarget.app,\n ...(iosTarget.udid !== undefined ? { udid: iosTarget.udid } : {}),\n ...(iosTarget.coldStart !== undefined ? { coldStart: iosTarget.coldStart } : {})\n };\n }\n return {\n type: \"web\",\n url: (target as { url?: string } | undefined)?.url ?? DEFAULT_WEB_URL\n };\n}\n\nfunction mergeConfig(partial: Partial<Config>): Config {\n return {\n target: resolveTarget(partial.target),\n browser: {\n headless: partial.browser?.headless ?? DEFAULT_CONFIG.browser.headless,\n slowMo: partial.browser?.slowMo ?? DEFAULT_CONFIG.browser.slowMo,\n timeout: partial.browser?.timeout ?? DEFAULT_CONFIG.browser.timeout,\n engine: (partial.browser as { engine?: BrowserEngine } | undefined)?.engine ?? DEFAULT_CONFIG.browser.engine,\n channel: (partial.browser as { channel?: BrowserChannel } | undefined)?.channel,\n viewport: resolveViewport((partial.browser as { viewport?: string | Viewport } | undefined)?.viewport)\n },\n artifacts: {\n screenshots: partial.artifacts?.screenshots ?? DEFAULT_CONFIG.artifacts.screenshots,\n networkHar: partial.artifacts?.networkHar ?? DEFAULT_CONFIG.artifacts.networkHar,\n console: partial.artifacts?.console ?? DEFAULT_CONFIG.artifacts.console,\n junit: partial.artifacts?.junit ?? DEFAULT_CONFIG.artifacts.junit\n },\n assertions: {\n noConsoleErrors:\n partial.assertions?.noConsoleErrors ?? DEFAULT_CONFIG.assertions.noConsoleErrors,\n noNetworkErrors:\n partial.assertions?.noNetworkErrors ?? DEFAULT_CONFIG.assertions.noNetworkErrors,\n maxTotalTimeMs:\n partial.assertions?.maxTotalTimeMs ?? DEFAULT_CONFIG.assertions.maxTotalTimeMs,\n networkIgnorePatterns:\n partial.assertions?.networkIgnorePatterns ??\n DEFAULT_CONFIG.assertions.networkIgnorePatterns\n },\n guardrails: {\n maxSteps: partial.guardrails?.maxSteps ?? DEFAULT_CONFIG.guardrails.maxSteps,\n allowedDomains: partial.guardrails?.allowedDomains ?? DEFAULT_CONFIG.guardrails.allowedDomains,\n allowedApps: partial.guardrails?.allowedApps ?? DEFAULT_CONFIG.guardrails.allowedApps,\n forbiddenSelectors:\n partial.guardrails?.forbiddenSelectors ?? DEFAULT_CONFIG.guardrails.forbiddenSelectors,\n selfHealing: partial.guardrails?.selfHealing ?? DEFAULT_CONFIG.guardrails.selfHealing\n },\n auth: {\n storageStatePath: partial.auth?.storageStatePath ?? (partial.auth !== undefined ? DEFAULT_CONFIG.auth.storageStatePath : undefined)\n },\n history: {\n maxRuns: partial.history?.maxRuns ?? DEFAULT_CONFIG.history.maxRuns\n },\n bugLog: partial.bugLog,\n tracing: partial.tracing,\n reliability: partial.reliability\n };\n}\n\nexport function ensureAllowedDomain(allowed: string[], urlValue: string): string[] {\n try {\n const host = new URL(urlValue).hostname;\n if (!allowed.includes(host)) {\n return [...allowed, host];\n }\n } catch {\n return allowed;\n }\n return allowed;\n}\n\nexport function loadConfig(configPath?: string): {\n config: Config;\n configPath: string;\n configDir: string;\n} {\n const resolvedPath = configPath\n ? path.resolve(configPath)\n : findConfigPath(process.cwd());\n\n if (!resolvedPath) {\n throw new Error(\"Could not find .prowl/config.yml. Run `prowl init` first.\");\n }\n\n if (!fs.existsSync(resolvedPath)) {\n throw new Error(`Config file not found at ${resolvedPath}`);\n }\n\n const configDir = path.dirname(resolvedPath);\n if (path.basename(configDir) === LEGACY_CONFIG_DIR) {\n warnLegacyConfigDir();\n }\n dotenv.config({ path: path.join(configDir, \".env\"), override: false });\n\n const raw = fs.readFileSync(resolvedPath, \"utf-8\");\n const parsed = yaml.parse(raw) ?? {};\n const validated = configSchema.parse(parsed);\n const config = mergeConfig(validated as Partial<Config>);\n\n // allowedDomains only applies to the web target; the macOS target scopes on\n // bundle IDs / process names via guardrails.allowedApps instead.\n if (config.target.type === \"web\") {\n config.guardrails.allowedDomains = ensureAllowedDomain(\n config.guardrails.allowedDomains,\n config.target.url\n );\n }\n\n return { config, configPath: resolvedPath, configDir };\n}\n\nexport function loadHunt(huntName: string, configDir: string): Hunt {\n assertValidHuntName(huntName);\n const huntPath = path.join(configDir, \"hunts\", `${huntName}.yml`);\n if (!fs.existsSync(huntPath)) {\n throw new Error(`Hunt file not found: ${huntPath}`);\n }\n const raw = fs.readFileSync(huntPath, \"utf-8\");\n const parsed = yaml.parse(raw) ?? {};\n const validated = huntSchema.parse(parsed);\n return validated as Hunt;\n}\n\nexport function loadHuntTags(huntName: string, configDir: string): string[] {\n assertValidHuntName(huntName);\n const huntPath = path.join(configDir, \"hunts\", `${huntName}.yml`);\n if (!fs.existsSync(huntPath)) {\n return [];\n }\n const raw = fs.readFileSync(huntPath, \"utf-8\");\n const parsed = yaml.parse(raw) ?? {};\n return Array.isArray(parsed.tags) ? parsed.tags : [];\n}\n\nexport function loadHuntMeta(huntName: string, configDir: string): { description?: string; tags: string[] } {\n assertValidHuntName(huntName);\n const huntPath = path.join(configDir, \"hunts\", `${huntName}.yml`);\n if (!fs.existsSync(huntPath)) {\n return { tags: [] };\n }\n const raw = fs.readFileSync(huntPath, \"utf-8\");\n const parsed = yaml.parse(raw) ?? {};\n return {\n description: typeof parsed.description === \"string\" ? parsed.description : undefined,\n tags: Array.isArray(parsed.tags) ? parsed.tags : []\n };\n}\n\nexport function listHunts(configDir: string): string[] {\n const huntsDir = path.join(configDir, \"hunts\");\n if (!fs.existsSync(huntsDir)) {\n return [];\n }\n const stats = fs.statSync(huntsDir);\n if (!stats.isDirectory()) {\n throw new Error(`Hunts path is not a directory: ${huntsDir}`);\n }\n\n const results: string[] = [];\n\n function scanDir(dir: string) {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isFile() && entry.name.endsWith(\".yml\")) {\n const fullPath = path.join(dir, entry.name);\n const relative = path.relative(huntsDir, fullPath);\n results.push(relative.replace(/\\.yml$/, \"\"));\n } else if (entry.isDirectory()) {\n scanDir(path.join(dir, entry.name));\n }\n }\n }\n\n scanDir(huntsDir);\n return results.sort((a, b) => a.localeCompare(b));\n}\n","import { z } from \"zod\";\nimport { SUPPORTED_BROWSER_ENGINES, type Step } from \"../types/index.js\";\nimport { isValidHuntName } from \"./hunt-name.js\";\n\n// Web target keeps `type` optional so pre-existing configs (`target: { url }`)\n// parse unchanged and default to the web target.\nconst webTargetSchema = z\n .object({\n type: z.literal(\"web\").optional(),\n url: z.string().min(1)\n })\n .strict();\n\n// macOS native target (experimental, PROWL-048): requires `type: \"macos\"` and an\n// app (bundle id or .app path); `url` is not accepted.\nconst macosTargetSchema = z\n .object({\n type: z.literal(\"macos\"),\n app: z.string().min(1)\n })\n .strict();\n\n// Android native target (experimental, PROWL-058): requires `type: \"android\"` and\n// an app (package name or .apk path). `deviceSerial` picks one of several attached\n// devices; `coldStart` opts into a `pm clear` before launch.\nconst androidTargetSchema = z\n .object({\n type: z.literal(\"android\"),\n app: z.string().min(1),\n deviceSerial: z.string().min(1).optional(),\n coldStart: z.boolean().optional()\n })\n .strict();\n\n// iOS simulator target (experimental, PROWL-059): requires `type: \"ios\"` and an\n// app (bundle id or .app path). `udid` picks a specific booted simulator;\n// `coldStart` opts into an uninstall+reinstall before launch (requires a .app path).\nconst iosTargetSchema = z\n .object({\n type: z.literal(\"ios\"),\n app: z.string().min(1),\n udid: z.string().min(1).optional(),\n coldStart: z.boolean().optional()\n })\n .strict();\n\n// The typed branches are tried first because each is the only one with its own\n// `type` literal; a bare `{ url }` (no type) falls through to web. An object that\n// matches none of the branches is rejected with a union error.\nexport const targetSchema = z.union([\n macosTargetSchema,\n androidTargetSchema,\n iosTargetSchema,\n webTargetSchema\n]);\n\nexport const configSchema = z\n .object({\n target: targetSchema,\n browser: z\n .object({\n headless: z.boolean().optional(),\n slowMo: z.number().optional(),\n timeout: z.number().optional(),\n engine: z.enum(SUPPORTED_BROWSER_ENGINES).optional(),\n channel: z.enum([\n \"chromium\",\n \"chrome\", \"chrome-beta\", \"chrome-canary\", \"chrome-dev\",\n \"msedge\", \"msedge-beta\", \"msedge-canary\", \"msedge-dev\"\n ]).optional(),\n viewport: z\n .union([\n z.enum([\"mobile\", \"tablet\", \"desktop\"]),\n z.object({ width: z.number().int().positive(), height: z.number().int().positive() }).strict()\n ])\n .optional()\n })\n .optional(),\n artifacts: z\n .object({\n screenshots: z.enum([\"on-failure\", \"all\"]).optional(),\n networkHar: z.boolean().optional(),\n console: z.boolean().optional(),\n junit: z.boolean().optional()\n })\n .optional(),\n assertions: z\n .object({\n noConsoleErrors: z.boolean().optional(),\n noNetworkErrors: z.boolean().optional(),\n maxTotalTimeMs: z.number().optional(),\n networkIgnorePatterns: z.array(z.string()).optional()\n })\n .optional(),\n guardrails: z\n .object({\n maxSteps: z.number().optional(),\n allowedDomains: z.array(z.string()).optional(),\n allowedApps: z.array(z.string()).optional(),\n forbiddenSelectors: z.array(z.string()).optional(),\n selfHealing: z.boolean().optional()\n })\n .optional(),\n auth: z\n .object({\n storageStatePath: z.string().optional()\n })\n .optional(),\n history: z\n .object({\n maxRuns: z.number().int().positive().optional()\n })\n .optional(),\n bugLog: z\n .object({\n enabled: z.boolean().optional(),\n backlogPath: z.string().min(1).optional(),\n resolvedPath: z.string().min(1).optional()\n })\n .strict()\n .optional(),\n tracing: z\n .object({\n header: z.string().min(1).optional()\n })\n .strict()\n .optional(),\n reliability: z\n .object({\n flakyThreshold: z.number().min(0).max(1).optional()\n })\n .strict()\n .optional()\n })\n .strict();\n\nexport const navigateStepSchema = z.object({ navigate: z.string().min(1) }).strict();\nexport const clickStepSchema = z\n .object({\n click: z.union([z.object({ selector: z.string().min(1) }).strict(), z.string().min(1)])\n })\n .strict();\n\nconst singleKeyValueSchema = z\n .record(z.string().min(1), z.string())\n .refine((record) => Object.keys(record).length === 1, {\n message: \"Expected exactly one key-value pair\"\n });\n\nexport const fillStepSchema = z\n .object({\n fill: z.union([\n z.object({ selector: z.string().min(1), value: z.string() }).strict(),\n singleKeyValueSchema\n ])\n })\n .strict();\nexport const typeStepSchema = z.object({ type: z.string() }).strict();\nexport const pressStepSchema = z\n .object({\n press: z.object({ selector: z.string().min(1), key: z.string().min(1) }).strict()\n })\n .strict();\nexport const waitForSelectorStepSchema = z\n .object({\n waitForSelector: z\n .object({ selector: z.string().min(1), timeout: z.number().optional() })\n .strict()\n })\n .strict();\nexport const waitStepSchema = z\n .object({\n wait: z.union([\n z.string().min(1),\n z.object({ for: z.string().min(1), timeout: z.number().optional() }).strict()\n ])\n })\n .strict();\nexport const waitForUrlStepSchema = z\n .object({\n waitForUrl: z.object({ value: z.string().min(1), timeout: z.number().optional() }).strict()\n })\n .strict();\nexport const waitForNetworkIdleStepSchema = z\n .object({\n waitForNetworkIdle: z.object({ timeout: z.number().optional() }).strict()\n })\n .strict();\nexport const selectOptionStepSchema = z\n .object({\n selectOption: z.object({ selector: z.string().min(1), value: z.string() }).strict()\n })\n .strict();\nexport const selectStepSchema = z\n .object({\n select: singleKeyValueSchema\n })\n .strict();\nexport const onDialogStepSchema = z\n .object({\n onDialog: z.object({ action: z.enum([\"accept\", \"dismiss\"]) }).strict()\n })\n .strict();\nexport const setInputFilesStepSchema = z\n .object({\n setInputFiles: z\n .object({\n selector: z.string().min(1),\n files: z.union([z.string().min(1), z.array(z.string().min(1)).min(1)])\n })\n .strict()\n })\n .strict();\nexport const inlineAssertStepSchema = z\n .object({\n assert: z\n .object({\n visible: z.string().min(1).optional(),\n notVisible: z.string().min(1).optional(),\n urlIncludes: z.string().min(1).optional(),\n urlEquals: z.string().min(1).optional()\n })\n .strict()\n .refine(\n (value) =>\n [value.visible, value.notVisible, value.urlIncludes, value.urlEquals].filter(\n (entry) => entry !== undefined\n ).length === 1,\n {\n message: \"assert requires exactly one of visible, notVisible, urlIncludes, urlEquals\"\n }\n )\n })\n .strict();\nexport const runHuntStepSchema = z\n .object({\n runHunt: z.union([\n z\n .string()\n .min(1)\n .refine(isValidHuntName, {\n message:\n \"Invalid hunt name. Use only letters, numbers, hyphens, underscores, and forward slashes.\"\n }),\n z\n .object({\n name: z\n .string()\n .min(1)\n .refine(isValidHuntName, {\n message:\n \"Invalid hunt name. Use only letters, numbers, hyphens, underscores, and forward slashes.\"\n }),\n vars: z.record(z.string(), z.string()).optional()\n })\n .strict()\n ])\n })\n .strict();\nexport const hoverStepSchema = z\n .object({\n hover: z.object({ selector: z.string().min(1) }).strict()\n })\n .strict();\nexport const scrollStepSchema = z\n .object({\n scroll: z\n .object({\n direction: z.enum([\"up\", \"down\", \"left\", \"right\"]),\n amount: z.number().optional()\n })\n .strict()\n })\n .strict();\nexport const scrollToStepSchema = z\n .object({\n scrollTo: z.object({ selector: z.string().min(1) }).strict()\n })\n .strict();\nexport const screenshotStepSchema = z\n .object({\n screenshot: z.object({ name: z.string().optional() }).strict()\n })\n .strict();\n\n// Recursive step schemas use z.lazy() to reference stepSchema before it's defined\nexport const ifStepSchema = z\n .object({\n if: z\n .object({\n visible: z.string().min(1).optional(),\n notVisible: z.string().min(1).optional(),\n then: z.lazy(() => z.array(stepSchema).min(1)),\n else: z.lazy(() => z.array(stepSchema).min(1)).optional()\n })\n .strict()\n .refine(\n (value) =>\n [value.visible, value.notVisible].filter((v) => v !== undefined).length === 1,\n { message: \"if requires exactly one of visible or notVisible\" }\n )\n })\n .strict();\n\nexport const repeatStepSchema = z\n .object({\n repeat: z\n .object({\n times: z.number().int().positive().optional(),\n while: z\n .object({\n visible: z.string().min(1).optional(),\n notVisible: z.string().min(1).optional()\n })\n .strict()\n .refine(\n (value) =>\n [value.visible, value.notVisible].filter((v) => v !== undefined).length === 1,\n { message: \"while requires exactly one of visible or notVisible\" }\n )\n .optional(),\n maxIterations: z.number().int().positive().optional(),\n steps: z.lazy(() => z.array(stepSchema).min(1))\n })\n .strict()\n .refine((value) => !(value.times !== undefined && value.while !== undefined), {\n message: \"repeat requires either times or while, not both\"\n })\n .refine((value) => value.times !== undefined || value.while !== undefined, {\n message: \"repeat requires either times or while\"\n })\n .refine((value) => !(value.while !== undefined && value.maxIterations === undefined), {\n message: \"while requires maxIterations\"\n })\n })\n .strict();\n\nexport const mockRouteStepSchema = z\n .object({\n mockRoute: z\n .object({\n url: z.string().min(1),\n response: z\n .object({\n status: z.number().int(),\n contentType: z.string().min(1).optional(),\n body: z.string().min(1).optional(),\n file: z.string().min(1).optional()\n })\n .strict()\n .refine(\n (value) =>\n [value.body, value.file].filter((v) => v !== undefined).length === 1,\n { message: \"response requires exactly one of body or file\" }\n )\n })\n .strict()\n })\n .strict();\n\nexport const unmockRouteStepSchema = z\n .object({\n unmockRoute: z.union([\n z.string().min(1),\n z.object({ url: z.string().min(1) }).strict()\n ])\n })\n .strict();\n\nexport const evalScriptStepSchema = z\n .object({\n evalScript: z.union([\n z.string().min(1),\n z\n .object({\n expression: z.string().min(1),\n as: z.string().min(1).optional()\n })\n .strict()\n ])\n })\n .strict();\n\nexport const runScriptStepSchema = z\n .object({\n runScript: z.object({ file: z.string().min(1) }).strict()\n })\n .strict();\n\nexport const assertScreenshotStepSchema = z\n .object({\n assertScreenshot: z\n .object({\n name: z.string().min(1),\n threshold: z.number().min(0).max(1).optional()\n })\n .strict()\n })\n .strict();\n\nexport const assertWithAiStepSchema = z\n .object({\n assertWithAI: z.string().min(1)\n })\n .strict();\n\nexport const copyTextStepSchema = z\n .object({\n copyText: z\n .object({\n selector: z.string().min(1),\n as: z.string().min(1)\n })\n .strict()\n })\n .strict();\n\nexport const waitForDownloadStepSchema = z\n .object({\n waitForDownload: z.union([\n z\n .object({\n filename: z.string().min(1).optional(),\n timeout: z.number().int().positive().optional()\n })\n .strict(),\n z.null()\n ])\n })\n .strict();\n\nexport const stepSchema: z.ZodType<Step> = z.union([\n navigateStepSchema,\n clickStepSchema,\n fillStepSchema,\n typeStepSchema,\n pressStepSchema,\n waitStepSchema,\n selectOptionStepSchema,\n selectStepSchema,\n onDialogStepSchema,\n setInputFilesStepSchema,\n inlineAssertStepSchema,\n runHuntStepSchema,\n waitForSelectorStepSchema,\n waitForUrlStepSchema,\n waitForNetworkIdleStepSchema,\n hoverStepSchema,\n scrollStepSchema,\n scrollToStepSchema,\n screenshotStepSchema,\n ifStepSchema,\n repeatStepSchema,\n mockRouteStepSchema,\n unmockRouteStepSchema,\n evalScriptStepSchema,\n runScriptStepSchema,\n assertScreenshotStepSchema,\n assertWithAiStepSchema,\n copyTextStepSchema,\n waitForDownloadStepSchema\n]);\n\nexport const assertionSchema = z.union([\n z.object({ selectorExists: z.string().min(1) }).strict(),\n z.object({ selectorNotExists: z.string().min(1) }).strict(),\n z.object({ urlIncludes: z.string().min(1) }).strict(),\n z.object({ urlEquals: z.string().min(1) }).strict(),\n z.object({ noConsoleErrors: z.boolean() }).strict(),\n z.object({ noNetworkErrors: z.boolean() }).strict()\n]);\n\nexport const huntSchema = z\n .object({\n name: z.string().optional(),\n description: z.string().optional(),\n tags: z.array(z.string().min(1)).optional(),\n vars: z.record(z.string(), z.string()).optional(),\n steps: z.array(stepSchema),\n assertions: z.array(assertionSchema).optional(),\n retry: z\n .object({\n maxRetries: z.number().int().min(0),\n delay: z.number().int().min(0).optional()\n })\n .strict()\n .optional()\n })\n .strict();\n","export const SUPPORTED_BROWSER_ENGINES = [\"chromium\", \"firefox\", \"webkit\"] as const;\n\nexport type BrowserEngine = (typeof SUPPORTED_BROWSER_ENGINES)[number];\n\nexport type BrowserChannel =\n | \"chromium\"\n | \"chrome\" | \"chrome-beta\" | \"chrome-canary\" | \"chrome-dev\"\n | \"msedge\" | \"msedge-beta\" | \"msedge-canary\" | \"msedge-dev\";\n\nexport type Viewport = {\n width: number;\n height: number;\n};\n\n/** Web execution target (default): drives a browser at `url`. */\nexport type WebTarget = {\n type: \"web\";\n url: string;\n};\n\n/**\n * macOS native execution target (experimental, PROWL-048). `app` is a bundle\n * identifier (e.g. `com.example.App`) or an absolute path to a `.app` bundle.\n * App-path guardrails are matched against the path, bundle name, and\n * `CFBundleIdentifier` from `Contents/Info.plist` when it is readable.\n */\nexport type MacosTarget = {\n type: \"macos\";\n app: string;\n};\n\n/**\n * Android native execution target (experimental, PROWL-058). `app` is an Android\n * package name (e.g. `com.example.app`) or an absolute/relative path to an `.apk`\n * file, which Prowl installs before launch. Optional `deviceSerial` selects one of\n * several attached devices/emulators; `coldStart` opts into a deterministic\n * `pm clear` before launch (default off). Android guardrails match package IDs\n * or canonical full APK paths; APK package IDs are resolved before install.\n */\nexport type AndroidTarget = {\n type: \"android\";\n app: string;\n /** adb device serial to target when more than one device is attached. */\n deviceSerial?: string;\n /** Run `pm clear <package>` before launch for a deterministic cold start (default off). */\n coldStart?: boolean;\n};\n\n/**\n * iOS simulator native execution target (experimental, PROWL-059). `app` is an\n * iOS bundle identifier (e.g. `com.example.App`) or an absolute/relative path to\n * a built `.app` bundle, which Prowl installs onto the simulator before launch.\n * Optional `udid` selects a specific booted simulator; `coldStart` opts into an\n * uninstall+reinstall before launch (default off, and only possible with a `.app`\n * path). Real devices are out of scope (PROWL-062) — simulators only. iOS\n * guardrails match bundle ids, the bundle name, or the canonical `.app` path.\n */\nexport type IosTarget = {\n type: \"ios\";\n app: string;\n /** UDID of the booted simulator to target when more than one is booted. */\n udid?: string;\n /** Uninstall+reinstall the app before launch for a deterministic cold start (default off). */\n coldStart?: boolean;\n};\n\nexport type Target = WebTarget | MacosTarget | AndroidTarget | IosTarget;\n\nexport type Config = {\n target: Target;\n browser: {\n headless: boolean;\n slowMo: number;\n timeout: number;\n engine: BrowserEngine;\n channel?: BrowserChannel;\n viewport: Viewport;\n };\n artifacts: {\n screenshots: \"on-failure\" | \"all\";\n networkHar: boolean;\n console: boolean;\n junit: boolean;\n };\n assertions: {\n noConsoleErrors: boolean;\n noNetworkErrors: boolean;\n maxTotalTimeMs: number;\n networkIgnorePatterns: string[];\n };\n guardrails: {\n maxSteps: number;\n allowedDomains: string[];\n /** Native scope analog of `allowedDomains`: allowed bundle/package IDs or canonical app artifact paths. */\n allowedApps: string[];\n forbiddenSelectors: string[];\n selfHealing: boolean;\n };\n auth: {\n storageStatePath?: string;\n };\n history: {\n maxRuns: number;\n };\n bugLog?: BugLogConfig;\n tracing?: TracingConfig;\n reliability?: ReliabilityConfig;\n};\n\nexport type ReliabilityConfig = {\n /** Flake score (0-1) at or above which a hunt is flagged flaky (default 0.3). */\n flakyThreshold?: number;\n};\n\nexport type TracingConfig = {\n /** Response header carrying the distributed-trace id (default \"traceparent\"). */\n header?: string;\n};\n\nexport type BugLogConfig = {\n enabled?: boolean;\n backlogPath?: string;\n resolvedPath?: string;\n};\n\nexport type HistoryEntry = {\n hunt: string;\n status: \"pass\" | \"fail\";\n durationMs: number;\n startedAt: string;\n runDir?: string;\n};\n\nexport type HistoryFile = {\n entries: HistoryEntry[];\n};\n\nexport type Hunt = {\n name?: string;\n description?: string;\n tags?: string[];\n vars?: Record<string, string>;\n steps: Step[];\n assertions?: Assertion[];\n retry?: {\n maxRetries: number;\n delay?: number;\n };\n};\n\nexport type NavigateStep = { navigate: string };\nexport type ClickStep = { click: { selector: string } | string };\nexport type FillStep = { fill: { selector: string; value: string } | Record<string, string> };\nexport type TypeStep = { type: string };\nexport type PressStep = { press: { selector: string; key: string } };\nexport type WaitForSelectorStep = { waitForSelector: { selector: string; timeout?: number } };\nexport type WaitStep = { wait: string | { for: string; timeout?: number } };\nexport type WaitForUrlStep = { waitForUrl: { value: string; timeout?: number } };\nexport type WaitForNetworkIdleStep = { waitForNetworkIdle: { timeout?: number } };\nexport type SelectOptionStep = { selectOption: { selector: string; value: string } };\nexport type SelectStep = { select: Record<string, string> };\nexport type OnDialogStep = { onDialog: { action: \"accept\" | \"dismiss\" } };\nexport type SetInputFilesStep = { setInputFiles: { selector: string; files: string | string[] } };\nexport type InlineAssertStep = {\n assert: {\n visible?: string;\n notVisible?: string;\n urlIncludes?: string;\n urlEquals?: string;\n };\n};\nexport type RunHuntStep = { runHunt: string | { name: string; vars?: Record<string, string> } };\nexport type HoverStep = { hover: { selector: string } };\nexport type ScrollStep = { scroll: { direction: \"up\" | \"down\" | \"left\" | \"right\"; amount?: number } };\nexport type ScrollToStep = { scrollTo: { selector: string } };\nexport type ScreenshotStep = { screenshot: { name?: string } };\nexport type IfStep = {\n if: {\n visible?: string;\n notVisible?: string;\n then: Step[];\n else?: Step[];\n };\n};\nexport type RepeatStep = {\n repeat: {\n times?: number;\n while?: { visible?: string; notVisible?: string };\n maxIterations?: number;\n steps: Step[];\n };\n};\nexport type MockRouteStep = {\n mockRoute: {\n url: string;\n response: {\n status: number;\n contentType?: string;\n body?: string;\n file?: string;\n };\n };\n};\nexport type UnmockRouteStep = { unmockRoute: string | { url: string } };\nexport type EvalScriptStep = {\n evalScript: string | { expression: string; as?: string };\n};\nexport type RunScriptStep = {\n runScript: { file: string };\n};\nexport type CopyTextStep = { copyText: { selector: string; as: string } };\nexport type WaitForDownloadStep = {\n waitForDownload: { filename?: string; timeout?: number } | null;\n};\nexport type AssertScreenshotStep = {\n assertScreenshot: {\n name: string;\n threshold?: number;\n };\n};\n\nexport type AssertWithAiStep = {\n assertWithAI: string;\n};\n\nexport type Step =\n | NavigateStep\n | ClickStep\n | FillStep\n | TypeStep\n | PressStep\n | WaitStep\n | SelectOptionStep\n | SelectStep\n | OnDialogStep\n | SetInputFilesStep\n | InlineAssertStep\n | RunHuntStep\n | WaitForSelectorStep\n | WaitForUrlStep\n | WaitForNetworkIdleStep\n | HoverStep\n | ScrollStep\n | ScrollToStep\n | ScreenshotStep\n | IfStep\n | RepeatStep\n | MockRouteStep\n | UnmockRouteStep\n | EvalScriptStep\n | RunScriptStep\n | AssertScreenshotStep\n | AssertWithAiStep\n | CopyTextStep\n | WaitForDownloadStep;\n\nexport type Assertion =\n | { selectorExists: string }\n | { selectorNotExists: string }\n | { urlIncludes: string }\n | { urlEquals: string }\n | { noConsoleErrors: boolean }\n | { noNetworkErrors: boolean };\n\nexport type StepResult = {\n type: string;\n // \"warn\" is a non-fatal outcome: the step neither passed nor failed the run\n // (e.g. `assertWithAI` skipped because no AI provider is configured).\n status: \"pass\" | \"fail\" | \"warn\";\n durationMs: number;\n selector?: string;\n value?: string;\n error?: string;\n screenshot?: string;\n /** Original selector when the step was completed via a self-healed selector. */\n healedFrom?: string;\n};\n\nexport type AssertionResult = {\n type: string;\n value?: string | boolean;\n // \"skipped\" marks an assertion that did not run on this target (e.g. a web-only\n // assertion type on a native target); it neither passes nor fails the run.\n status: \"pass\" | \"fail\" | \"skipped\";\n error?: string;\n};\n\nexport type RunArtifacts = {\n summary?: string;\n screenshots?: string[];\n console?: string;\n trace?: string;\n networkHar?: string;\n junit?: string;\n};\n\nexport type TraceCorrelation = {\n url: string;\n status: number;\n traceId: string;\n header: string;\n};\n\nexport type RunResult = {\n status: \"pass\" | \"fail\";\n exitCode: 0 | 1;\n startedAt: string;\n durationMs: number;\n hunt: string;\n targetUrl: string;\n steps: StepResult[];\n assertions: AssertionResult[];\n artifacts: RunArtifacts;\n traceCorrelations?: TraceCorrelation[];\n};\n\nexport type CiHuntResult = {\n hunt: string;\n status: \"pass\" | \"fail\" | \"skipped\";\n durationMs: number;\n runDir?: string;\n error?: string;\n};\n\nexport type CiStatus = \"pass\" | \"fail\" | \"no-hunts\" | \"all-skipped\";\n\nexport type CiFlakyHunt = {\n hunt: string;\n score: number;\n};\n\nexport type CiFailureCluster = {\n cause: string;\n stepType?: string;\n selector?: string;\n error: string;\n count: number;\n hunts: string[];\n};\n\nexport type CiResult = {\n status: CiStatus;\n startedAt: string;\n durationMs: number;\n totalHunts: number;\n passed: number;\n failed: number;\n skipped: number;\n hunts: CiHuntResult[];\n /** Hunts whose flake score is at/above the configured threshold (omitted when none). */\n flaky?: CiFlakyHunt[];\n /** Groups of failed hunts sharing a common cause (omitted when none). */\n clusters?: CiFailureCluster[];\n};\n","const HUNT_NAME_PATTERN = /^[A-Za-z0-9_-]+(?:\\/[A-Za-z0-9_-]+)*$/;\nconst HUNT_FILE_EXTENSION_PATTERN = /\\.yml$/i;\n\n/** Return whether a string is already a valid bare hunt identity. */\nexport function isValidHuntName(name: string): boolean {\n return HUNT_NAME_PATTERN.test(name);\n}\n\n/**\n * Normalize a hunt argument supplied on the command line to its bare hunt\n * identity. A hunt's identity is its file name under `.prowl/hunts/`, so this\n * accepts the literal path forms an agent (or a shell tab-completion) is likely\n * to produce and reduces them to the name the loader resolves:\n *\n * .prowl/hunts/homepage.yml -> homepage\n * hunts/homepage.yml -> homepage\n * .prowl/hunts/admin/users.yml -> admin/users\n * hunts/admin/users -> hunts/admin/users (already bare; unchanged)\n * homepage -> homepage (already bare; unchanged)\n *\n * Only supported hunt file paths have their hunts-directory prefix stripped.\n * A trailing `.yml` extension is also stripped; anything else is left untouched\n * so that genuinely invalid input still fails validation with a clear message.\n */\nexport function normalizeHuntName(input: string): string {\n let name = input.trim();\n\n if (name.startsWith(\"./\")) {\n name = name.slice(2);\n }\n\n const isSupportedHuntPath = HUNT_FILE_EXTENSION_PATTERN.test(name);\n if (isSupportedHuntPath && name.startsWith(\".prowl/hunts/\")) {\n name = name.slice(\".prowl/hunts/\".length);\n } else if (isSupportedHuntPath && name.startsWith(\"hunts/\")) {\n name = name.slice(\"hunts/\".length);\n }\n\n name = name.replace(HUNT_FILE_EXTENSION_PATTERN, \"\");\n\n return name;\n}\n\n/** Throw a user-facing error when a normalized hunt identity is invalid. */\nexport function assertValidHuntName(name: string): void {\n if (!isValidHuntName(name)) {\n throw new Error(\n `Invalid hunt name: \"${name}\". A hunt name is its file name under ` +\n `.prowl/hunts/ (letters, numbers, hyphens, underscores, and forward ` +\n `slashes for nested hunts). Accepted forms: a bare name (homepage), a ` +\n `nested name (admin/users), or a path (.prowl/hunts/homepage.yml or ` +\n `hunts/homepage.yml).`\n );\n }\n}\n"],"mappings":";AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,UAAU;AACjB,OAAO,YAAY;;;ACHnB,SAAS,SAAS;;;ACAX,IAAM,4BAA4B,CAAC,YAAY,WAAW,QAAQ;;;ACAzE,IAAM,oBAAoB;AAC1B,IAAM,8BAA8B;AAG7B,SAAS,gBAAgB,MAAuB;AACrD,SAAO,kBAAkB,KAAK,IAAI;AACpC;AAkBO,SAAS,kBAAkB,OAAuB;AACvD,MAAI,OAAO,MAAM,KAAK;AAEtB,MAAI,KAAK,WAAW,IAAI,GAAG;AACzB,WAAO,KAAK,MAAM,CAAC;AAAA,EACrB;AAEA,QAAM,sBAAsB,4BAA4B,KAAK,IAAI;AACjE,MAAI,uBAAuB,KAAK,WAAW,eAAe,GAAG;AAC3D,WAAO,KAAK,MAAM,gBAAgB,MAAM;AAAA,EAC1C,WAAW,uBAAuB,KAAK,WAAW,QAAQ,GAAG;AAC3D,WAAO,KAAK,MAAM,SAAS,MAAM;AAAA,EACnC;AAEA,SAAO,KAAK,QAAQ,6BAA6B,EAAE;AAEnD,SAAO;AACT;AAGO,SAAS,oBAAoB,MAAoB;AACtD,MAAI,CAAC,gBAAgB,IAAI,GAAG;AAC1B,UAAM,IAAI;AAAA,MACR,uBAAuB,IAAI;AAAA,IAK7B;AAAA,EACF;AACF;;;AFhDA,IAAM,kBAAkB,EACrB,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,KAAK,EAAE,SAAS;AAAA,EAChC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;AACvB,CAAC,EACA,OAAO;AAIV,IAAM,oBAAoB,EACvB,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,OAAO;AAAA,EACvB,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;AACvB,CAAC,EACA,OAAO;AAKV,IAAM,sBAAsB,EACzB,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,SAAS;AAAA,EACzB,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACrB,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACzC,WAAW,EAAE,QAAQ,EAAE,SAAS;AAClC,CAAC,EACA,OAAO;AAKV,IAAM,kBAAkB,EACrB,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,KAAK;AAAA,EACrB,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACrB,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACjC,WAAW,EAAE,QAAQ,EAAE,SAAS;AAClC,CAAC,EACA,OAAO;AAKH,IAAM,eAAe,EAAE,MAAM;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,eAAe,EACzB,OAAO;AAAA,EACN,QAAQ;AAAA,EACR,SAAS,EACN,OAAO;AAAA,IACN,UAAU,EAAE,QAAQ,EAAE,SAAS;AAAA,IAC/B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,IAC5B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,QAAQ,EAAE,KAAK,yBAAyB,EAAE,SAAS;AAAA,IACnD,SAAS,EAAE,KAAK;AAAA,MACd;AAAA,MACA;AAAA,MAAU;AAAA,MAAe;AAAA,MAAiB;AAAA,MAC1C;AAAA,MAAU;AAAA,MAAe;AAAA,MAAiB;AAAA,IAC5C,CAAC,EAAE,SAAS;AAAA,IACZ,UAAU,EACP,MAAM;AAAA,MACL,EAAE,KAAK,CAAC,UAAU,UAAU,SAAS,CAAC;AAAA,MACtC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO;AAAA,IAC/F,CAAC,EACA,SAAS;AAAA,EACd,CAAC,EACA,SAAS;AAAA,EACZ,WAAW,EACR,OAAO;AAAA,IACN,aAAa,EAAE,KAAK,CAAC,cAAc,KAAK,CAAC,EAAE,SAAS;AAAA,IACpD,YAAY,EAAE,QAAQ,EAAE,SAAS;AAAA,IACjC,SAAS,EAAE,QAAQ,EAAE,SAAS;AAAA,IAC9B,OAAO,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC9B,CAAC,EACA,SAAS;AAAA,EACZ,YAAY,EACT,OAAO;AAAA,IACN,iBAAiB,EAAE,QAAQ,EAAE,SAAS;AAAA,IACtC,iBAAiB,EAAE,QAAQ,EAAE,SAAS;AAAA,IACtC,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,IACpC,uBAAuB,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACtD,CAAC,EACA,SAAS;AAAA,EACZ,YAAY,EACT,OAAO;AAAA,IACN,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,gBAAgB,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,IAC7C,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,IAC1C,oBAAoB,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,IACjD,aAAa,EAAE,QAAQ,EAAE,SAAS;AAAA,EACpC,CAAC,EACA,SAAS;AAAA,EACZ,MAAM,EACH,OAAO;AAAA,IACN,kBAAkB,EAAE,OAAO,EAAE,SAAS;AAAA,EACxC,CAAC,EACA,SAAS;AAAA,EACZ,SAAS,EACN,OAAO;AAAA,IACN,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAChD,CAAC,EACA,SAAS;AAAA,EACZ,QAAQ,EACL,OAAO;AAAA,IACN,SAAS,EAAE,QAAQ,EAAE,SAAS;AAAA,IAC9B,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACxC,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC3C,CAAC,EACA,OAAO,EACP,SAAS;AAAA,EACZ,SAAS,EACN,OAAO;AAAA,IACN,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACrC,CAAC,EACA,OAAO,EACP,SAAS;AAAA,EACZ,aAAa,EACV,OAAO;AAAA,IACN,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACpD,CAAC,EACA,OAAO,EACP,SAAS;AACd,CAAC,EACA,OAAO;AAEH,IAAM,qBAAqB,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAC5E,IAAM,kBAAkB,EAC5B,OAAO;AAAA,EACN,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;AACxF,CAAC,EACA,OAAO;AAEV,IAAM,uBAAuB,EAC1B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EACpC,OAAO,CAAC,WAAW,OAAO,KAAK,MAAM,EAAE,WAAW,GAAG;AAAA,EACpD,SAAS;AACX,CAAC;AAEI,IAAM,iBAAiB,EAC3B,OAAO;AAAA,EACN,MAAM,EAAE,MAAM;AAAA,IACZ,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO;AAAA,IACpE;AAAA,EACF,CAAC;AACH,CAAC,EACA,OAAO;AACH,IAAM,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO;AAC7D,IAAM,kBAAkB,EAC5B,OAAO;AAAA,EACN,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAClF,CAAC,EACA,OAAO;AACH,IAAM,4BAA4B,EACtC,OAAO;AAAA,EACN,iBAAiB,EACd,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EACtE,OAAO;AACZ,CAAC,EACA,OAAO;AACH,IAAM,iBAAiB,EAC3B,OAAO;AAAA,EACN,MAAM,EAAE,MAAM;AAAA,IACZ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAChB,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO;AAAA,EAC9E,CAAC;AACH,CAAC,EACA,OAAO;AACH,IAAM,uBAAuB,EACjC,OAAO;AAAA,EACN,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO;AAC5F,CAAC,EACA,OAAO;AACH,IAAM,+BAA+B,EACzC,OAAO;AAAA,EACN,oBAAoB,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO;AAC1E,CAAC,EACA,OAAO;AACH,IAAM,yBAAyB,EACnC,OAAO;AAAA,EACN,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO;AACpF,CAAC,EACA,OAAO;AACH,IAAM,mBAAmB,EAC7B,OAAO;AAAA,EACN,QAAQ;AACV,CAAC,EACA,OAAO;AACH,IAAM,qBAAqB,EAC/B,OAAO;AAAA,EACN,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,SAAS,CAAC,EAAE,CAAC,EAAE,OAAO;AACvE,CAAC,EACA,OAAO;AACH,IAAM,0BAA0B,EACpC,OAAO;AAAA,EACN,eAAe,EACZ,OAAO;AAAA,IACN,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC1B,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAAA,EACvE,CAAC,EACA,OAAO;AACZ,CAAC,EACA,OAAO;AACH,IAAM,yBAAyB,EACnC,OAAO;AAAA,EACN,QAAQ,EACL,OAAO;AAAA,IACN,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACpC,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACvC,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACxC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACxC,CAAC,EACA,OAAO,EACP;AAAA,IACC,CAAC,UACC,CAAC,MAAM,SAAS,MAAM,YAAY,MAAM,aAAa,MAAM,SAAS,EAAE;AAAA,MACpE,CAAC,UAAU,UAAU;AAAA,IACvB,EAAE,WAAW;AAAA,IACf;AAAA,MACE,SAAS;AAAA,IACX;AAAA,EACF;AACJ,CAAC,EACA,OAAO;AACH,IAAM,oBAAoB,EAC9B,OAAO;AAAA,EACN,SAAS,EAAE,MAAM;AAAA,IACf,EACG,OAAO,EACP,IAAI,CAAC,EACL,OAAO,iBAAiB;AAAA,MACvB,SACE;AAAA,IACJ,CAAC;AAAA,IACH,EACG,OAAO;AAAA,MACN,MAAM,EACH,OAAO,EACP,IAAI,CAAC,EACL,OAAO,iBAAiB;AAAA,QACvB,SACE;AAAA,MACJ,CAAC;AAAA,MACH,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,IAClD,CAAC,EACA,OAAO;AAAA,EACZ,CAAC;AACH,CAAC,EACA,OAAO;AACH,IAAM,kBAAkB,EAC5B,OAAO;AAAA,EACN,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAC1D,CAAC,EACA,OAAO;AACH,IAAM,mBAAmB,EAC7B,OAAO;AAAA,EACN,QAAQ,EACL,OAAO;AAAA,IACN,WAAW,EAAE,KAAK,CAAC,MAAM,QAAQ,QAAQ,OAAO,CAAC;AAAA,IACjD,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,CAAC,EACA,OAAO;AACZ,CAAC,EACA,OAAO;AACH,IAAM,qBAAqB,EAC/B,OAAO;AAAA,EACN,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAC7D,CAAC,EACA,OAAO;AACH,IAAM,uBAAuB,EACjC,OAAO;AAAA,EACN,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO;AAC/D,CAAC,EACA,OAAO;AAGH,IAAM,eAAe,EACzB,OAAO;AAAA,EACN,IAAI,EACD,OAAO;AAAA,IACN,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACpC,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACvC,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,UAAU,EAAE,IAAI,CAAC,CAAC;AAAA,IAC7C,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,UAAU,EAAE,IAAI,CAAC,CAAC,EAAE,SAAS;AAAA,EAC1D,CAAC,EACA,OAAO,EACP;AAAA,IACC,CAAC,UACC,CAAC,MAAM,SAAS,MAAM,UAAU,EAAE,OAAO,CAAC,MAAM,MAAM,MAAS,EAAE,WAAW;AAAA,IAC9E,EAAE,SAAS,mDAAmD;AAAA,EAChE;AACJ,CAAC,EACA,OAAO;AAEH,IAAM,mBAAmB,EAC7B,OAAO;AAAA,EACN,QAAQ,EACL,OAAO;AAAA,IACN,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,IAC5C,OAAO,EACJ,OAAO;AAAA,MACN,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,MACpC,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACzC,CAAC,EACA,OAAO,EACP;AAAA,MACC,CAAC,UACC,CAAC,MAAM,SAAS,MAAM,UAAU,EAAE,OAAO,CAAC,MAAM,MAAM,MAAS,EAAE,WAAW;AAAA,MAC9E,EAAE,SAAS,sDAAsD;AAAA,IACnE,EACC,SAAS;AAAA,IACZ,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,IACpD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,UAAU,EAAE,IAAI,CAAC,CAAC;AAAA,EAChD,CAAC,EACA,OAAO,EACP,OAAO,CAAC,UAAU,EAAE,MAAM,UAAU,UAAa,MAAM,UAAU,SAAY;AAAA,IAC5E,SAAS;AAAA,EACX,CAAC,EACA,OAAO,CAAC,UAAU,MAAM,UAAU,UAAa,MAAM,UAAU,QAAW;AAAA,IACzE,SAAS;AAAA,EACX,CAAC,EACA,OAAO,CAAC,UAAU,EAAE,MAAM,UAAU,UAAa,MAAM,kBAAkB,SAAY;AAAA,IACpF,SAAS;AAAA,EACX,CAAC;AACL,CAAC,EACA,OAAO;AAEH,IAAM,sBAAsB,EAChC,OAAO;AAAA,EACN,WAAW,EACR,OAAO;AAAA,IACN,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACrB,UAAU,EACP,OAAO;AAAA,MACN,QAAQ,EAAE,OAAO,EAAE,IAAI;AAAA,MACvB,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,MACxC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,MACjC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACnC,CAAC,EACA,OAAO,EACP;AAAA,MACC,CAAC,UACC,CAAC,MAAM,MAAM,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,MAAM,MAAS,EAAE,WAAW;AAAA,MACrE,EAAE,SAAS,gDAAgD;AAAA,IAC7D;AAAA,EACJ,CAAC,EACA,OAAO;AACZ,CAAC,EACA,OAAO;AAEH,IAAM,wBAAwB,EAClC,OAAO;AAAA,EACN,aAAa,EAAE,MAAM;AAAA,IACnB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAChB,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAAA,EAC9C,CAAC;AACH,CAAC,EACA,OAAO;AAEH,IAAM,uBAAuB,EACjC,OAAO;AAAA,EACN,YAAY,EAAE,MAAM;AAAA,IAClB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAChB,EACG,OAAO;AAAA,MACN,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,MAC5B,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACjC,CAAC,EACA,OAAO;AAAA,EACZ,CAAC;AACH,CAAC,EACA,OAAO;AAEH,IAAM,sBAAsB,EAChC,OAAO;AAAA,EACN,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAC1D,CAAC,EACA,OAAO;AAEH,IAAM,6BAA6B,EACvC,OAAO;AAAA,EACN,kBAAkB,EACf,OAAO;AAAA,IACN,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACtB,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC/C,CAAC,EACA,OAAO;AACZ,CAAC,EACA,OAAO;AAEH,IAAM,yBAAyB,EACnC,OAAO;AAAA,EACN,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;AAChC,CAAC,EACA,OAAO;AAEH,IAAM,qBAAqB,EAC/B,OAAO;AAAA,EACN,UAAU,EACP,OAAO;AAAA,IACN,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC1B,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,CAAC,EACA,OAAO;AACZ,CAAC,EACA,OAAO;AAEH,IAAM,4BAA4B,EACtC,OAAO;AAAA,EACN,iBAAiB,EAAE,MAAM;AAAA,IACvB,EACG,OAAO;AAAA,MACN,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,MACrC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,IAChD,CAAC,EACA,OAAO;AAAA,IACV,EAAE,KAAK;AAAA,EACT,CAAC;AACH,CAAC,EACA,OAAO;AAEH,IAAM,aAA8B,EAAE,MAAM;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,kBAAkB,EAAE,MAAM;AAAA,EACrC,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAAA,EACvD,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAAA,EAC1D,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAAA,EACpD,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO;AAAA,EAClD,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO;AAAA,EAClD,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO;AACpD,CAAC;AAEM,IAAM,aAAa,EACvB,OAAO;AAAA,EACN,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,SAAS;AAAA,EAC1C,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAChD,OAAO,EAAE,MAAM,UAAU;AAAA,EACzB,YAAY,EAAE,MAAM,eAAe,EAAE,SAAS;AAAA,EAC9C,OAAO,EACJ,OAAO;AAAA,IACN,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAAA,IAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC1C,CAAC,EACA,OAAO,EACP,SAAS;AACd,CAAC,EACA,OAAO;;;ADheV,IAAM,kBAAkB;AAExB,IAAM,iBAAyB;AAAA,EAC7B,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,KAAK;AAAA,EACP;AAAA,EACA,SAAS;AAAA,IACP,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,UAAU,EAAE,OAAO,MAAM,QAAQ,IAAI;AAAA,EACvC;AAAA,EACA,WAAW;AAAA,IACT,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,YAAY;AAAA,IACV,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,uBAAuB,CAAC;AAAA,EAC1B;AAAA,EACA,YAAY;AAAA,IACV,UAAU;AAAA,IACV,gBAAgB,CAAC,aAAa,aAAa,SAAS;AAAA,IACpD,aAAa,CAAC;AAAA,IACd,oBAAoB,CAAC,iBAAiB,aAAa;AAAA,IACnD,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,kBAAkB;AAAA,EACpB;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,EACX;AACF;AAEO,IAAM,aAAa;AACnB,IAAM,oBAAoB;AAEjC,IAAI,kBAAkB;AAGf,SAAS,sBAA4B;AAC1C,MAAI,iBAAiB;AACnB;AAAA,EACF;AACA,oBAAkB;AAClB,UAAQ;AAAA,IACN;AAAA,EAEF;AACF;AAEO,SAAS,eAAe,UAAiC;AAC9D,MAAI,UAAU;AACd,SAAO,SAAS;AAEd,eAAW,OAAO,CAAC,YAAY,iBAAiB,GAAG;AACjD,YAAM,YAAY,KAAK,KAAK,SAAS,KAAK,YAAY;AACtD,UAAI,GAAG,WAAW,SAAS,GAAG;AAC5B,eAAO;AAAA,MACT;AAAA,IACF;AACA,UAAM,SAAS,KAAK,QAAQ,OAAO;AACnC,QAAI,WAAW,SAAS;AACtB;AAAA,IACF;AACA,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAEA,IAAM,mBAA6C;AAAA,EACjD,QAAQ,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,EAClC,QAAQ,EAAE,OAAO,KAAK,QAAQ,KAAK;AAAA,EACnC,SAAS,EAAE,OAAO,MAAM,QAAQ,IAAI;AACtC;AAEO,SAAS,gBACd,OACU;AACV,MAAI,UAAU,QAAW;AACvB,WAAO,eAAe,QAAQ;AAAA,EAChC;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,SAAS,iBAAiB,KAAK;AACrC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,6BAA6B,KAAK,oCAAoC;AAAA,IACxF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAQA,SAAS,cAAc,QAA8C;AACnE,QAAM,OAAQ,QAA0C;AACxD,MAAI,SAAS,SAAS;AACpB,WAAO,EAAE,MAAM,SAAS,KAAM,OAA2B,IAAI;AAAA,EAC/D;AACA,MAAI,SAAS,WAAW;AACtB,UAAM,gBAAgB;AAKtB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,KAAK,cAAc;AAAA,MACnB,GAAI,cAAc,iBAAiB,SAAY,EAAE,cAAc,cAAc,aAAa,IAAI,CAAC;AAAA,MAC/F,GAAI,cAAc,cAAc,SAAY,EAAE,WAAW,cAAc,UAAU,IAAI,CAAC;AAAA,IACxF;AAAA,EACF;AACA,MAAI,SAAS,OAAO;AAClB,UAAM,YAAY;AAKlB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,KAAK,UAAU;AAAA,MACf,GAAI,UAAU,SAAS,SAAY,EAAE,MAAM,UAAU,KAAK,IAAI,CAAC;AAAA,MAC/D,GAAI,UAAU,cAAc,SAAY,EAAE,WAAW,UAAU,UAAU,IAAI,CAAC;AAAA,IAChF;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAM,QAAyC,OAAO;AAAA,EACxD;AACF;AAEA,SAAS,YAAY,SAAkC;AACrD,SAAO;AAAA,IACL,QAAQ,cAAc,QAAQ,MAAM;AAAA,IACpC,SAAS;AAAA,MACP,UAAU,QAAQ,SAAS,YAAY,eAAe,QAAQ;AAAA,MAC9D,QAAQ,QAAQ,SAAS,UAAU,eAAe,QAAQ;AAAA,MAC1D,SAAS,QAAQ,SAAS,WAAW,eAAe,QAAQ;AAAA,MAC5D,QAAS,QAAQ,SAAoD,UAAU,eAAe,QAAQ;AAAA,MACtG,SAAU,QAAQ,SAAsD;AAAA,MACxE,UAAU,gBAAiB,QAAQ,SAA0D,QAAQ;AAAA,IACvG;AAAA,IACA,WAAW;AAAA,MACT,aAAa,QAAQ,WAAW,eAAe,eAAe,UAAU;AAAA,MACxE,YAAY,QAAQ,WAAW,cAAc,eAAe,UAAU;AAAA,MACtE,SAAS,QAAQ,WAAW,WAAW,eAAe,UAAU;AAAA,MAChE,OAAO,QAAQ,WAAW,SAAS,eAAe,UAAU;AAAA,IAC9D;AAAA,IACA,YAAY;AAAA,MACV,iBACE,QAAQ,YAAY,mBAAmB,eAAe,WAAW;AAAA,MACnE,iBACE,QAAQ,YAAY,mBAAmB,eAAe,WAAW;AAAA,MACnE,gBACE,QAAQ,YAAY,kBAAkB,eAAe,WAAW;AAAA,MAClE,uBACE,QAAQ,YAAY,yBACpB,eAAe,WAAW;AAAA,IAC9B;AAAA,IACA,YAAY;AAAA,MACV,UAAU,QAAQ,YAAY,YAAY,eAAe,WAAW;AAAA,MACpE,gBAAgB,QAAQ,YAAY,kBAAkB,eAAe,WAAW;AAAA,MAChF,aAAa,QAAQ,YAAY,eAAe,eAAe,WAAW;AAAA,MAC1E,oBACE,QAAQ,YAAY,sBAAsB,eAAe,WAAW;AAAA,MACtE,aAAa,QAAQ,YAAY,eAAe,eAAe,WAAW;AAAA,IAC5E;AAAA,IACA,MAAM;AAAA,MACJ,kBAAkB,QAAQ,MAAM,qBAAqB,QAAQ,SAAS,SAAY,eAAe,KAAK,mBAAmB;AAAA,IAC3H;AAAA,IACA,SAAS;AAAA,MACP,SAAS,QAAQ,SAAS,WAAW,eAAe,QAAQ;AAAA,IAC9D;AAAA,IACA,QAAQ,QAAQ;AAAA,IAChB,SAAS,QAAQ;AAAA,IACjB,aAAa,QAAQ;AAAA,EACvB;AACF;AAEO,SAAS,oBAAoB,SAAmB,UAA4B;AACjF,MAAI;AACF,UAAM,OAAO,IAAI,IAAI,QAAQ,EAAE;AAC/B,QAAI,CAAC,QAAQ,SAAS,IAAI,GAAG;AAC3B,aAAO,CAAC,GAAG,SAAS,IAAI;AAAA,IAC1B;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,WAAW,YAIzB;AACA,QAAM,eAAe,aACjB,KAAK,QAAQ,UAAU,IACvB,eAAe,QAAQ,IAAI,CAAC;AAEhC,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC7E;AAEA,MAAI,CAAC,GAAG,WAAW,YAAY,GAAG;AAChC,UAAM,IAAI,MAAM,4BAA4B,YAAY,EAAE;AAAA,EAC5D;AAEA,QAAM,YAAY,KAAK,QAAQ,YAAY;AAC3C,MAAI,KAAK,SAAS,SAAS,MAAM,mBAAmB;AAClD,wBAAoB;AAAA,EACtB;AACA,SAAO,OAAO,EAAE,MAAM,KAAK,KAAK,WAAW,MAAM,GAAG,UAAU,MAAM,CAAC;AAErE,QAAM,MAAM,GAAG,aAAa,cAAc,OAAO;AACjD,QAAM,SAAS,KAAK,MAAM,GAAG,KAAK,CAAC;AACnC,QAAM,YAAY,aAAa,MAAM,MAAM;AAC3C,QAAM,SAAS,YAAY,SAA4B;AAIvD,MAAI,OAAO,OAAO,SAAS,OAAO;AAChC,WAAO,WAAW,iBAAiB;AAAA,MACjC,OAAO,WAAW;AAAA,MAClB,OAAO,OAAO;AAAA,IAChB;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,YAAY,cAAc,UAAU;AACvD;AAEO,SAAS,SAAS,UAAkB,WAAyB;AAClE,sBAAoB,QAAQ;AAC5B,QAAM,WAAW,KAAK,KAAK,WAAW,SAAS,GAAG,QAAQ,MAAM;AAChE,MAAI,CAAC,GAAG,WAAW,QAAQ,GAAG;AAC5B,UAAM,IAAI,MAAM,wBAAwB,QAAQ,EAAE;AAAA,EACpD;AACA,QAAM,MAAM,GAAG,aAAa,UAAU,OAAO;AAC7C,QAAM,SAAS,KAAK,MAAM,GAAG,KAAK,CAAC;AACnC,QAAM,YAAY,WAAW,MAAM,MAAM;AACzC,SAAO;AACT;AAEO,SAAS,aAAa,UAAkB,WAA6B;AAC1E,sBAAoB,QAAQ;AAC5B,QAAM,WAAW,KAAK,KAAK,WAAW,SAAS,GAAG,QAAQ,MAAM;AAChE,MAAI,CAAC,GAAG,WAAW,QAAQ,GAAG;AAC5B,WAAO,CAAC;AAAA,EACV;AACA,QAAM,MAAM,GAAG,aAAa,UAAU,OAAO;AAC7C,QAAM,SAAS,KAAK,MAAM,GAAG,KAAK,CAAC;AACnC,SAAO,MAAM,QAAQ,OAAO,IAAI,IAAI,OAAO,OAAO,CAAC;AACrD;AAEO,SAAS,aAAa,UAAkB,WAA6D;AAC1G,sBAAoB,QAAQ;AAC5B,QAAM,WAAW,KAAK,KAAK,WAAW,SAAS,GAAG,QAAQ,MAAM;AAChE,MAAI,CAAC,GAAG,WAAW,QAAQ,GAAG;AAC5B,WAAO,EAAE,MAAM,CAAC,EAAE;AAAA,EACpB;AACA,QAAM,MAAM,GAAG,aAAa,UAAU,OAAO;AAC7C,QAAM,SAAS,KAAK,MAAM,GAAG,KAAK,CAAC;AACnC,SAAO;AAAA,IACL,aAAa,OAAO,OAAO,gBAAgB,WAAW,OAAO,cAAc;AAAA,IAC3E,MAAM,MAAM,QAAQ,OAAO,IAAI,IAAI,OAAO,OAAO,CAAC;AAAA,EACpD;AACF;AAEO,SAAS,UAAU,WAA6B;AACrD,QAAM,WAAW,KAAK,KAAK,WAAW,OAAO;AAC7C,MAAI,CAAC,GAAG,WAAW,QAAQ,GAAG;AAC5B,WAAO,CAAC;AAAA,EACV;AACA,QAAM,QAAQ,GAAG,SAAS,QAAQ;AAClC,MAAI,CAAC,MAAM,YAAY,GAAG;AACxB,UAAM,IAAI,MAAM,kCAAkC,QAAQ,EAAE;AAAA,EAC9D;AAEA,QAAM,UAAoB,CAAC;AAE3B,WAAS,QAAQ,KAAa;AAC5B,UAAM,UAAU,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAC3D,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,MAAM,GAAG;AACjD,cAAM,WAAW,KAAK,KAAK,KAAK,MAAM,IAAI;AAC1C,cAAM,WAAW,KAAK,SAAS,UAAU,QAAQ;AACjD,gBAAQ,KAAK,SAAS,QAAQ,UAAU,EAAE,CAAC;AAAA,MAC7C,WAAW,MAAM,YAAY,GAAG;AAC9B,gBAAQ,KAAK,KAAK,KAAK,MAAM,IAAI,CAAC;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAEA,UAAQ,QAAQ;AAChB,SAAO,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AAClD;","names":[]}