prowl-tools 0.1.7 → 0.1.9

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>;
@@ -597,15 +605,38 @@ type ResolveHelperOptions = {
597
605
  declare function resolveHelperBinary(env?: NodeJS.ProcessEnv, options?: ResolveHelperOptions): string;
598
606
  /** Default per-request deadline for the helper transport. */
599
607
  declare const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
608
+ /**
609
+ * A server-initiated event line from the helper (ARCH-008): a JSON object with
610
+ * an `event` discriminant and **no** `id`, so it is unambiguously distinct from
611
+ * an id-matched command response. Emitted, for example, when an AXObserver
612
+ * notification fires during a `waitFor`/`openMenu` wait.
613
+ */
614
+ type MacHelperEvent = Record<string, unknown> & {
615
+ event: string;
616
+ };
600
617
  type SpawnMacHelperOptions = {
601
618
  /** Per-request deadline; a request that gets no response by then rejects. */
602
619
  requestTimeoutMs?: number;
620
+ /**
621
+ * Optional sink for server-initiated event lines. Events are informational —
622
+ * waits are resolved helper-side by the id-matched response — so they are
623
+ * forwarded here (if provided) and otherwise dropped, never touching the
624
+ * pending-request map.
625
+ */
626
+ onEvent?: (event: MacHelperEvent) => void;
627
+ /**
628
+ * Optional diagnostic sink for event handler failures. Defaults to stderr so a
629
+ * bad sink is visible without allowing it to break helper transport.
630
+ */
631
+ onEventError?: (message: string) => void;
603
632
  };
604
633
  /** A {@link MacHelperClient} backed by a spawned `prowl-macdriver serve` process. */
605
634
  declare class SpawnMacHelperClient implements MacHelperClient {
606
635
  private readonly child;
607
636
  private readonly pending;
608
637
  private readonly requestTimeoutMs;
638
+ private readonly onEvent?;
639
+ private readonly onEventError;
609
640
  private stdoutBuffer;
610
641
  private stderrBuffer;
611
642
  private nextId;
@@ -614,6 +645,7 @@ declare class SpawnMacHelperClient implements MacHelperClient {
614
645
  constructor(binaryPath: string, options?: SpawnMacHelperOptions);
615
646
  private onStdout;
616
647
  private dispatch;
648
+ private handleEvent;
617
649
  private failAll;
618
650
  private recordTerminalFailure;
619
651
  /** Number of in-flight requests awaiting a response (for teardown/tests). */
@@ -751,6 +783,38 @@ declare function collectMacdriverStatus(options?: StatusOptions): Promise<Macdri
751
783
  /** Static TCC-permission guidance printed after install / in status. */
752
784
  declare function tccGuidance(): string;
753
785
 
786
+ /** Screen dimensions in device points, as reported by the agent. */
787
+ interface ScreenSize {
788
+ width: number;
789
+ height: number;
790
+ }
791
+ /** One item in a W3C `pointer` action sequence. */
792
+ type PointerActionItem = {
793
+ type: "pointerMove";
794
+ duration: number;
795
+ x: number;
796
+ y: number;
797
+ origin?: "viewport";
798
+ } | {
799
+ type: "pointerDown";
800
+ button: number;
801
+ } | {
802
+ type: "pointerUp";
803
+ button: number;
804
+ } | {
805
+ type: "pause";
806
+ duration: number;
807
+ };
808
+ /** A single `touch` pointer input source and its ordered actions. */
809
+ interface PointerActionSequence {
810
+ type: "pointer";
811
+ id: string;
812
+ parameters: {
813
+ pointerType: "touch";
814
+ };
815
+ actions: PointerActionItem[];
816
+ }
817
+
754
818
  /** The selector kinds the native dialect understands. */
755
819
  type NativeSelectorKind = "id" | "label" | "text" | "role" | "focused";
756
820
  /**
@@ -968,6 +1032,10 @@ interface AndroidAgentClient {
968
1032
  getText(elementId: string): Promise<string | null>;
969
1033
  /** Dispatch a global key event by Android key code (goes to the focused view). */
970
1034
  pressKeyCode(keyCode: number): Promise<void>;
1035
+ /** Current screen size in pixels (uiautomator2 `/window/current/size`), for gestures. */
1036
+ windowSize(): Promise<ScreenSize>;
1037
+ /** Perform a W3C pointer action sequence (`POST /session/:id/actions`). */
1038
+ performActions(actions: PointerActionSequence): Promise<void>;
971
1039
  /** Capture the current screen as PNG bytes. */
972
1040
  screenshotPng(): Promise<Buffer>;
973
1041
  /**
@@ -1211,10 +1279,16 @@ interface IosAgentClient {
1211
1279
  /** Replace an element's text (W3C `element/value`). */
1212
1280
  setValue(elementId: string, text: string): Promise<void>;
1213
1281
  getText(elementId: string): Promise<string | null>;
1282
+ /** True only when WDA reports the element is displayed in the current viewport. */
1283
+ isDisplayed(elementId: string): Promise<boolean>;
1214
1284
  /** Send raw key sequences to the focused element (WDA `/wda/keys`). */
1215
1285
  sendKeys(keys: string[]): Promise<void>;
1216
1286
  /** Return to the springboard home screen (WDA `/wda/homescreen`). */
1217
1287
  homescreen(): Promise<void>;
1288
+ /** Current screen size in points (WDA `/window/size`), for gesture geometry. */
1289
+ windowSize(): Promise<ScreenSize>;
1290
+ /** Perform a W3C pointer action sequence (WDA `POST /session/:id/actions`). */
1291
+ performActions(actions: PointerActionSequence): Promise<void>;
1218
1292
  /**
1219
1293
  * Return the current UI hierarchy as WebDriverAgent `/source` XML. Present on
1220
1294
  * live clients and consumed by the analyzer (PROWL-061); optional so lighter
@@ -1516,7 +1590,9 @@ declare function createWdaAgentClient(transport: WdaTransport, sessionId: string
1516
1590
  * Step types that only make sense on the web target. Everything else
1517
1591
  * (`click`, `fill`, `type`, `press`, `wait`, `assert visible/notVisible`,
1518
1592
  * `screenshot`, `assertScreenshot`, `repeat`, `runHunt`, `if`, `copyText`,
1519
- * `hover`, `scrollTo`, `waitForSelector`) is portable across targets.
1593
+ * `hover`, `scrollTo`, `waitForSelector`) is portable across targets. The
1594
+ * directional `scroll` step is the one per-target exception — see
1595
+ * {@link MACOS_UNSUPPORTED_STEP_TYPES}.
1520
1596
  */
1521
1597
  declare const WEB_ONLY_STEP_TYPES: ReadonlySet<string>;
1522
1598
  /** The web-only reason a step is unsupported on a non-web target, or null if portable. */
@@ -1524,8 +1600,10 @@ declare function webOnlyReason(step: Step): string | null;
1524
1600
  /**
1525
1601
  * Throw if any step in `steps` (recursing into `if`/`repeat` bodies) is not
1526
1602
  * 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.
1603
+ * hunt itself runs. No-op for the web target; every native target rejects the
1604
+ * same web-only step vocabulary, and macOS additionally rejects the directional
1605
+ * `scroll` swipe (no AX equivalent) — but NOT `scrollTo`, which macOS maps to
1606
+ * AXScrollToVisible just as iOS/Android map it to a swipe loop.
1529
1607
  */
1530
1608
  declare function assertStepsSupportedByTarget(steps: Step[], target: Target["type"]): void;
1531
1609
  /** Read the bundle id from an iOS `.app` (root `Info.plist`), or null. */
@@ -1862,24 +1940,24 @@ declare const configSchema: z.ZodObject<{
1862
1940
  }>]>>;
1863
1941
  }, "strip", z.ZodTypeAny, {
1864
1942
  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
1943
  viewport?: "mobile" | "tablet" | "desktop" | {
1870
1944
  width: number;
1871
1945
  height: number;
1872
1946
  } | undefined;
1873
- }, {
1874
- timeout?: number | undefined;
1875
1947
  headless?: boolean | undefined;
1876
1948
  slowMo?: number | undefined;
1877
1949
  engine?: "chromium" | "firefox" | "webkit" | undefined;
1878
1950
  channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
1951
+ }, {
1952
+ timeout?: number | undefined;
1879
1953
  viewport?: "mobile" | "tablet" | "desktop" | {
1880
1954
  width: number;
1881
1955
  height: number;
1882
1956
  } | undefined;
1957
+ headless?: boolean | undefined;
1958
+ slowMo?: number | undefined;
1959
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
1960
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
1883
1961
  }>>;
1884
1962
  artifacts: z.ZodOptional<z.ZodObject<{
1885
1963
  screenshots: z.ZodOptional<z.ZodEnum<["on-failure", "all"]>>;
@@ -1993,14 +2071,14 @@ declare const configSchema: z.ZodObject<{
1993
2071
  };
1994
2072
  browser?: {
1995
2073
  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
2074
  viewport?: "mobile" | "tablet" | "desktop" | {
2001
2075
  width: number;
2002
2076
  height: number;
2003
2077
  } | undefined;
2078
+ headless?: boolean | undefined;
2079
+ slowMo?: number | undefined;
2080
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
2081
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2004
2082
  } | undefined;
2005
2083
  artifacts?: {
2006
2084
  screenshots?: "on-failure" | "all" | undefined;
@@ -2058,14 +2136,14 @@ declare const configSchema: z.ZodObject<{
2058
2136
  };
2059
2137
  browser?: {
2060
2138
  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
2139
  viewport?: "mobile" | "tablet" | "desktop" | {
2066
2140
  width: number;
2067
2141
  height: number;
2068
2142
  } | undefined;
2143
+ headless?: boolean | undefined;
2144
+ slowMo?: number | undefined;
2145
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
2146
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2069
2147
  } | undefined;
2070
2148
  artifacts?: {
2071
2149
  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>;
@@ -597,15 +605,38 @@ type ResolveHelperOptions = {
597
605
  declare function resolveHelperBinary(env?: NodeJS.ProcessEnv, options?: ResolveHelperOptions): string;
598
606
  /** Default per-request deadline for the helper transport. */
599
607
  declare const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
608
+ /**
609
+ * A server-initiated event line from the helper (ARCH-008): a JSON object with
610
+ * an `event` discriminant and **no** `id`, so it is unambiguously distinct from
611
+ * an id-matched command response. Emitted, for example, when an AXObserver
612
+ * notification fires during a `waitFor`/`openMenu` wait.
613
+ */
614
+ type MacHelperEvent = Record<string, unknown> & {
615
+ event: string;
616
+ };
600
617
  type SpawnMacHelperOptions = {
601
618
  /** Per-request deadline; a request that gets no response by then rejects. */
602
619
  requestTimeoutMs?: number;
620
+ /**
621
+ * Optional sink for server-initiated event lines. Events are informational —
622
+ * waits are resolved helper-side by the id-matched response — so they are
623
+ * forwarded here (if provided) and otherwise dropped, never touching the
624
+ * pending-request map.
625
+ */
626
+ onEvent?: (event: MacHelperEvent) => void;
627
+ /**
628
+ * Optional diagnostic sink for event handler failures. Defaults to stderr so a
629
+ * bad sink is visible without allowing it to break helper transport.
630
+ */
631
+ onEventError?: (message: string) => void;
603
632
  };
604
633
  /** A {@link MacHelperClient} backed by a spawned `prowl-macdriver serve` process. */
605
634
  declare class SpawnMacHelperClient implements MacHelperClient {
606
635
  private readonly child;
607
636
  private readonly pending;
608
637
  private readonly requestTimeoutMs;
638
+ private readonly onEvent?;
639
+ private readonly onEventError;
609
640
  private stdoutBuffer;
610
641
  private stderrBuffer;
611
642
  private nextId;
@@ -614,6 +645,7 @@ declare class SpawnMacHelperClient implements MacHelperClient {
614
645
  constructor(binaryPath: string, options?: SpawnMacHelperOptions);
615
646
  private onStdout;
616
647
  private dispatch;
648
+ private handleEvent;
617
649
  private failAll;
618
650
  private recordTerminalFailure;
619
651
  /** Number of in-flight requests awaiting a response (for teardown/tests). */
@@ -751,6 +783,38 @@ declare function collectMacdriverStatus(options?: StatusOptions): Promise<Macdri
751
783
  /** Static TCC-permission guidance printed after install / in status. */
752
784
  declare function tccGuidance(): string;
753
785
 
786
+ /** Screen dimensions in device points, as reported by the agent. */
787
+ interface ScreenSize {
788
+ width: number;
789
+ height: number;
790
+ }
791
+ /** One item in a W3C `pointer` action sequence. */
792
+ type PointerActionItem = {
793
+ type: "pointerMove";
794
+ duration: number;
795
+ x: number;
796
+ y: number;
797
+ origin?: "viewport";
798
+ } | {
799
+ type: "pointerDown";
800
+ button: number;
801
+ } | {
802
+ type: "pointerUp";
803
+ button: number;
804
+ } | {
805
+ type: "pause";
806
+ duration: number;
807
+ };
808
+ /** A single `touch` pointer input source and its ordered actions. */
809
+ interface PointerActionSequence {
810
+ type: "pointer";
811
+ id: string;
812
+ parameters: {
813
+ pointerType: "touch";
814
+ };
815
+ actions: PointerActionItem[];
816
+ }
817
+
754
818
  /** The selector kinds the native dialect understands. */
755
819
  type NativeSelectorKind = "id" | "label" | "text" | "role" | "focused";
756
820
  /**
@@ -968,6 +1032,10 @@ interface AndroidAgentClient {
968
1032
  getText(elementId: string): Promise<string | null>;
969
1033
  /** Dispatch a global key event by Android key code (goes to the focused view). */
970
1034
  pressKeyCode(keyCode: number): Promise<void>;
1035
+ /** Current screen size in pixels (uiautomator2 `/window/current/size`), for gestures. */
1036
+ windowSize(): Promise<ScreenSize>;
1037
+ /** Perform a W3C pointer action sequence (`POST /session/:id/actions`). */
1038
+ performActions(actions: PointerActionSequence): Promise<void>;
971
1039
  /** Capture the current screen as PNG bytes. */
972
1040
  screenshotPng(): Promise<Buffer>;
973
1041
  /**
@@ -1211,10 +1279,16 @@ interface IosAgentClient {
1211
1279
  /** Replace an element's text (W3C `element/value`). */
1212
1280
  setValue(elementId: string, text: string): Promise<void>;
1213
1281
  getText(elementId: string): Promise<string | null>;
1282
+ /** True only when WDA reports the element is displayed in the current viewport. */
1283
+ isDisplayed(elementId: string): Promise<boolean>;
1214
1284
  /** Send raw key sequences to the focused element (WDA `/wda/keys`). */
1215
1285
  sendKeys(keys: string[]): Promise<void>;
1216
1286
  /** Return to the springboard home screen (WDA `/wda/homescreen`). */
1217
1287
  homescreen(): Promise<void>;
1288
+ /** Current screen size in points (WDA `/window/size`), for gesture geometry. */
1289
+ windowSize(): Promise<ScreenSize>;
1290
+ /** Perform a W3C pointer action sequence (WDA `POST /session/:id/actions`). */
1291
+ performActions(actions: PointerActionSequence): Promise<void>;
1218
1292
  /**
1219
1293
  * Return the current UI hierarchy as WebDriverAgent `/source` XML. Present on
1220
1294
  * live clients and consumed by the analyzer (PROWL-061); optional so lighter
@@ -1516,7 +1590,9 @@ declare function createWdaAgentClient(transport: WdaTransport, sessionId: string
1516
1590
  * Step types that only make sense on the web target. Everything else
1517
1591
  * (`click`, `fill`, `type`, `press`, `wait`, `assert visible/notVisible`,
1518
1592
  * `screenshot`, `assertScreenshot`, `repeat`, `runHunt`, `if`, `copyText`,
1519
- * `hover`, `scrollTo`, `waitForSelector`) is portable across targets.
1593
+ * `hover`, `scrollTo`, `waitForSelector`) is portable across targets. The
1594
+ * directional `scroll` step is the one per-target exception — see
1595
+ * {@link MACOS_UNSUPPORTED_STEP_TYPES}.
1520
1596
  */
1521
1597
  declare const WEB_ONLY_STEP_TYPES: ReadonlySet<string>;
1522
1598
  /** The web-only reason a step is unsupported on a non-web target, or null if portable. */
@@ -1524,8 +1600,10 @@ declare function webOnlyReason(step: Step): string | null;
1524
1600
  /**
1525
1601
  * Throw if any step in `steps` (recursing into `if`/`repeat` bodies) is not
1526
1602
  * 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.
1603
+ * hunt itself runs. No-op for the web target; every native target rejects the
1604
+ * same web-only step vocabulary, and macOS additionally rejects the directional
1605
+ * `scroll` swipe (no AX equivalent) — but NOT `scrollTo`, which macOS maps to
1606
+ * AXScrollToVisible just as iOS/Android map it to a swipe loop.
1529
1607
  */
1530
1608
  declare function assertStepsSupportedByTarget(steps: Step[], target: Target["type"]): void;
1531
1609
  /** Read the bundle id from an iOS `.app` (root `Info.plist`), or null. */
@@ -1862,24 +1940,24 @@ declare const configSchema: z.ZodObject<{
1862
1940
  }>]>>;
1863
1941
  }, "strip", z.ZodTypeAny, {
1864
1942
  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
1943
  viewport?: "mobile" | "tablet" | "desktop" | {
1870
1944
  width: number;
1871
1945
  height: number;
1872
1946
  } | undefined;
1873
- }, {
1874
- timeout?: number | undefined;
1875
1947
  headless?: boolean | undefined;
1876
1948
  slowMo?: number | undefined;
1877
1949
  engine?: "chromium" | "firefox" | "webkit" | undefined;
1878
1950
  channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
1951
+ }, {
1952
+ timeout?: number | undefined;
1879
1953
  viewport?: "mobile" | "tablet" | "desktop" | {
1880
1954
  width: number;
1881
1955
  height: number;
1882
1956
  } | undefined;
1957
+ headless?: boolean | undefined;
1958
+ slowMo?: number | undefined;
1959
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
1960
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
1883
1961
  }>>;
1884
1962
  artifacts: z.ZodOptional<z.ZodObject<{
1885
1963
  screenshots: z.ZodOptional<z.ZodEnum<["on-failure", "all"]>>;
@@ -1993,14 +2071,14 @@ declare const configSchema: z.ZodObject<{
1993
2071
  };
1994
2072
  browser?: {
1995
2073
  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
2074
  viewport?: "mobile" | "tablet" | "desktop" | {
2001
2075
  width: number;
2002
2076
  height: number;
2003
2077
  } | undefined;
2078
+ headless?: boolean | undefined;
2079
+ slowMo?: number | undefined;
2080
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
2081
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2004
2082
  } | undefined;
2005
2083
  artifacts?: {
2006
2084
  screenshots?: "on-failure" | "all" | undefined;
@@ -2058,14 +2136,14 @@ declare const configSchema: z.ZodObject<{
2058
2136
  };
2059
2137
  browser?: {
2060
2138
  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
2139
  viewport?: "mobile" | "tablet" | "desktop" | {
2066
2140
  width: number;
2067
2141
  height: number;
2068
2142
  } | undefined;
2143
+ headless?: boolean | undefined;
2144
+ slowMo?: number | undefined;
2145
+ engine?: "chromium" | "firefox" | "webkit" | undefined;
2146
+ channel?: "chromium" | "chrome" | "chrome-beta" | "chrome-canary" | "chrome-dev" | "msedge" | "msedge-beta" | "msedge-canary" | "msedge-dev" | undefined;
2069
2147
  } | undefined;
2070
2148
  artifacts?: {
2071
2149
  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-2RNOK64Y.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
@@ -0,0 +1,53 @@
1
+ # Form Submission
2
+ # ---
3
+ # Pattern: Forms — fill text fields, pick a dropdown option, submit, verify result.
4
+ # What it tests: Complete a form and confirm the success state renders.
5
+ # Customize:
6
+ # - Point `navigate` at your form's path
7
+ # - Update the field labels, the dropdown label/option, and the button text
8
+ # to match your form
9
+ #
10
+ # Tip: Prefer stable selectors — an accessible label or a data-testid — over
11
+ # brittle CSS. Run `prowl analyze` to dump ranked selector candidates for a page.
12
+
13
+ name: form
14
+ description: Fill and submit a form, verify the success message
15
+
16
+ tags:
17
+ - forms
18
+ - input
19
+
20
+ steps:
21
+ - navigate: "/signup"
22
+
23
+ # Shorthand fill — Prowl finds the input by its label or placeholder text.
24
+ # Equivalent explicit form:
25
+ # fill:
26
+ # selector: "input[name='name']"
27
+ # value: "Ada Lovelace"
28
+ - fill:
29
+ "Full name": "Ada Lovelace"
30
+
31
+ - fill:
32
+ "Email": "ada@example.com"
33
+
34
+ # Shorthand select — finds the <select> by its label and picks the option by
35
+ # its visible text. Equivalent explicit form:
36
+ # selectOption:
37
+ # selector: "select[name='plan']"
38
+ # value: "Pro"
39
+ - select:
40
+ "Plan": "Pro"
41
+
42
+ # Shorthand click — Prowl finds a checkbox or button by its text content.
43
+ - click: "I agree to the terms"
44
+
45
+ - click: "Create account"
46
+
47
+ # Mid-flow assertion — verify the success state rendered.
48
+ - assert:
49
+ visible: "Welcome, Ada"
50
+
51
+ assertions:
52
+ - urlIncludes: "/welcome"
53
+ - noConsoleErrors: true
@@ -0,0 +1,49 @@
1
+ # macOS Hello — Your First Desktop Hunt (Experimental)
2
+ # ---
3
+ # Prowl drives native macOS apps through Apple's Accessibility API, from the same
4
+ # YAML as web hunts. This starter targets TextEdit — present on every Mac — so you
5
+ # can try the desktop target without wiring up your own app first.
6
+ #
7
+ # ── Before this hunt will run ───────────────────────────────────────────────
8
+ # 1. Install the helper: prowl macdriver install
9
+ # Until the first signed release ships, `install` returns a 404 — build from
10
+ # source instead (needs the Swift toolchain / Xcode CLT):
11
+ # cd macdriver && swift build -c release
12
+ # 2. Grant Accessibility permission to the app hosting your terminal (Terminal,
13
+ # iTerm, VS Code, …): System Settings → Privacy & Security → Accessibility.
14
+ # `prowl macdriver status` prints the resolved binary and this guidance.
15
+ # 3. Point .prowl/config.yml at a macOS target — init's default config targets
16
+ # the web. Replace its `target:` block, and scope the app under guardrails:
17
+ #
18
+ # target:
19
+ # type: macos
20
+ # app: "com.apple.TextEdit" # bundle id, or an absolute /path/to/App.app
21
+ # guardrails:
22
+ # allowedApps:
23
+ # - "com.apple.TextEdit"
24
+ #
25
+ # The macOS target is EXPERIMENTAL — the selector dialect and step coverage may
26
+ # still change. `navigate`, `waitForUrl`, and other web-only steps are rejected
27
+ # on it; the portable steps below (`type`, `assert: visible`) run on both targets.
28
+ #
29
+ # ── Finding selectors ───────────────────────────────────────────────────────
30
+ # Don't guess selectors — dump them: prowl analyze --app com.apple.TextEdit
31
+ # It walks the Accessibility tree and prints every element with ranked selector
32
+ # candidates (prefer `id=` — the native analog of data-testid). TextEdit's
33
+ # controls aren't ours, so treat the steps below as a starting point and adjust
34
+ # to what `analyze` reports on your macOS version.
35
+
36
+ name: macos-hello
37
+ description: Type into TextEdit and verify the text appears (experimental macOS target)
38
+
39
+ tags:
40
+ - macos
41
+ - smoke
42
+
43
+ steps:
44
+ # `type` sends keystrokes to the focused element — a fresh TextEdit document.
45
+ - type: "Hello from Prowl!"
46
+
47
+ # Portable assertion — the document's text should now contain what we typed.
48
+ - assert:
49
+ visible: "Hello from Prowl!"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prowl-tools",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
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",