@phone-use/sdk 0.4.0 → 0.5.0

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/index.d.mts CHANGED
@@ -477,10 +477,335 @@ declare function executeAction(core: DeviceCore, action: Action, opts?: ActOptio
477
477
  */
478
478
  declare function createAgentDeviceBackend(config?: DeviceConfig): DeviceBackend;
479
479
  //#endregion
480
+ //#region src/lifecycle.d.ts
481
+ /** The platform a {@link Device} runs on. */
482
+ type DevicePlatform = 'ios' | 'android';
483
+ /** Lifecycle state of a {@link Device} handle. */
484
+ type DeviceStatus = 'running' | 'closed';
485
+ /**
486
+ * The Device lifecycle handle: id, pinned backend, close/dispose, idle lease +
487
+ * reaper — plus the action verb surface layered onto the same type.
488
+ * `ios.launch()`/`ios.connect()` and `android.launch()`/`android.connect()`
489
+ * all return it, built over `createDeviceHandle`.
490
+ */
491
+ interface Device {
492
+ /** udid (iOS) / serial (Android). */
493
+ readonly id: string;
494
+ /** Which platform this device runs. */
495
+ readonly platform: DevicePlatform;
496
+ /** Simulator/device name when known. */
497
+ readonly name?: string | undefined;
498
+ /** Name of the backend driving this device. */
499
+ readonly backendName: string;
500
+ /** The backend's declared capability set. */
501
+ readonly capabilities: ReadonlySet<Capability>;
502
+ /**
503
+ * The pinned backend — `new DeviceContext(device.backend)` works today.
504
+ * Backend calls through this handle count as activity for the idle lease.
505
+ */
506
+ readonly backend: DeviceBackend;
507
+ /** true when launch() created the device — close() then also deletes it. */
508
+ readonly createdByUs: boolean;
509
+ /** Current lifecycle state. */
510
+ readonly status: DeviceStatus;
511
+ /** Sugar for `status === 'closed'`. */
512
+ readonly isClosed: boolean;
513
+ /** Re-arm the idle lease (ms overrides the configured window for this arm only). */
514
+ extendLease(ms?: number): void;
515
+ /** Canonical, idempotent shutdown. `await using` is sugar over this. */
516
+ close(): Promise<void>;
517
+ /** `await using` support — delegates to {@link Device.close}. */
518
+ [Symbol.asyncDispose](): Promise<void>;
519
+ /** Look at the screen: elements + rendered text + portable Action[]. */
520
+ observe(opts?: {
521
+ signal?: AbortSignal | undefined;
522
+ }): Promise<ObserveResult>;
523
+ /** Tap by label/id query. Auto-waits; never throws for normal outcomes. */
524
+ tap(target: string | ElementQuery, opts?: ActOptions): Promise<ActionResult>;
525
+ /** Type text (optionally into a field resolved by query); %name% secrets substituted. */
526
+ type(text: string, opts?: ActOptions & {
527
+ field?: string | ElementQuery | undefined;
528
+ submit?: boolean | undefined;
529
+ }): Promise<ActionResult>;
530
+ /** Execute a portable Action deterministically — no re-inference. */
531
+ act(action: Action, opts?: ActOptions): Promise<ActionResult>;
532
+ /** App management: open by name/deep link, list installed, current app. */
533
+ readonly apps: {
534
+ /** Open an app by name/bundle id, or a deep link when `url` is set. */
535
+ open(app: string, opts?: {
536
+ relaunch?: boolean | undefined;
537
+ url?: string | undefined;
538
+ signal?: AbortSignal | undefined;
539
+ }): Promise<ActionResult>;
540
+ /** List installed app bundle ids. */
541
+ list(opts?: {
542
+ signal?: AbortSignal | undefined;
543
+ }): Promise<string[]>;
544
+ /** The frontmost app name from the last observation (no new snapshot). */
545
+ current(): string | undefined;
546
+ };
547
+ /** Screen-level verbs: scroll, screenshot, waitForText, alert, back, home. */
548
+ readonly screen: {
549
+ /** Scroll the active scroll view one step. */
550
+ scroll(direction: ScrollDirection, opts?: {
551
+ signal?: AbortSignal | undefined;
552
+ }): Promise<ActionResult>;
553
+ /** Save a screenshot to `path`. */
554
+ screenshot(opts: {
555
+ path: string;
556
+ signal?: AbortSignal | undefined;
557
+ }): Promise<{
558
+ success: boolean;
559
+ message: string;
560
+ path?: string | undefined;
561
+ }>;
562
+ /** Block until `text` appears on screen or the timeout elapses. */
563
+ waitForText(text: string, opts?: {
564
+ timeoutMs?: number | undefined;
565
+ signal?: AbortSignal | undefined;
566
+ }): Promise<ActionResult>;
567
+ /** Read ('get'), accept, or dismiss a blocking system alert. */
568
+ alert(action: 'get' | 'accept' | 'dismiss', opts?: {
569
+ signal?: AbortSignal | undefined;
570
+ }): Promise<ActionResult>;
571
+ /** Navigate back. */
572
+ back(opts?: {
573
+ signal?: AbortSignal | undefined;
574
+ }): Promise<ActionResult>;
575
+ /** Go to the home screen. */
576
+ home(opts?: {
577
+ signal?: AbortSignal | undefined;
578
+ }): Promise<ActionResult>;
579
+ };
580
+ /** %name% secret store — values substituted at execution, redacted everywhere else. */
581
+ readonly secrets: SecretStore;
582
+ }
583
+ /** Inputs to {@link createDeviceHandle} — what an engine supplies per device. */
584
+ type CreateDeviceHandleOptions = {
585
+ /** udid (iOS) / serial (Android). */
586
+ id: string;
587
+ /** Which platform the device runs. */
588
+ platform: DevicePlatform;
589
+ /** Simulator/device name when known. */
590
+ name?: string | undefined;
591
+ /** The backend pinned to this device. */
592
+ backend: DeviceBackend;
593
+ /** true when the engine created the device (close() then also deletes it). */
594
+ createdByUs: boolean;
595
+ /** Idle window in ms; false disables the lease. Default 180_000 (3m). */
596
+ idleTimeoutMs?: number | false | undefined;
597
+ /** Observer for reaper-initiated closes (the SDK never logs). */
598
+ onIdleClose?: ((device: Device) => void) | undefined;
599
+ /** Initial %name% secret values. */
600
+ secrets?: Record<string, string> | undefined;
601
+ /** Platform teardown: shutdown (+ delete when createdByUs). */
602
+ doClose: () => Promise<void>;
603
+ };
604
+ /**
605
+ * Assemble a Device handle over a backend: lease/reaper, verb surface,
606
+ * close/dispose semantics. Engine authors (ios and android here,
607
+ * phone-backend-* third parties) build on this; tests fabricate devices with
608
+ * it over a FakeBackend.
609
+ */
610
+ declare function createDeviceHandle(opts: CreateDeviceHandleOptions): Device;
611
+ //#endregion
612
+ //#region src/backends/android.d.ts
613
+ /** Binary-stdout runner for `adb exec-out` (screencap). Resolves with the raw bytes. */
614
+ type BinaryExecRunner = (file: string, args: string[], opts?: {
615
+ timeoutMs?: number | undefined;
616
+ }) => Promise<Uint8Array>;
617
+ /** Options for {@link AndroidBackend} / {@link createAndroidBackend}. */
618
+ type AndroidBackendOptions = {
619
+ /** adb serial to target (`adb -s`); omit when exactly one device is attached. */
620
+ serial?: string | undefined;
621
+ /** Path to the adb binary (default: `adb` on PATH). */
622
+ adbBin?: string | undefined;
623
+ /** Per-command ceiling in ms before a hung adb call rejects with TimeoutError (default 30_000). */
624
+ commandTimeoutMs?: number | undefined;
625
+ };
626
+ /**
627
+ * Drive an Android device or emulator over adb. Implements the
628
+ * {@link DeviceBackend} contract with uiautomator for the tree, screencap for
629
+ * pixels, and `input` for gestures. Stateless across calls except the ref → rect
630
+ * map from the last snapshot (what makes press-by-ref work).
631
+ */
632
+ declare class AndroidBackend extends BaseDeviceBackend {
633
+ private readonly serial;
634
+ private readonly adbBin;
635
+ private readonly timeoutMs;
636
+ private readonly exec;
637
+ private readonly execBinary;
638
+ private readonly sleep;
639
+ private rects;
640
+ private sizeCache;
641
+ private launchablesCache;
642
+ constructor(opts?: AndroidBackendOptions);
643
+ private withSerial;
644
+ /** Normalize an exec failure into the PhoneUseError the contract promises. */
645
+ private fail;
646
+ /** Run an adb command, returning stdout text. */
647
+ private adb;
648
+ /** `adb shell <argv>` — each argument quoted for the device shell. */
649
+ private shell;
650
+ /** `adb shell <literal>` for the few CONSTANT commands that need a pipe. Never pass input. */
651
+ private shellRaw;
652
+ private center;
653
+ /** The screen size input coordinates map to (an `Override size` wins over `Physical size`). */
654
+ private screenSize;
655
+ snapshot(opts?: {
656
+ interactiveOnly?: boolean | undefined;
657
+ }): Promise<Snapshot>;
658
+ /** The package of the resumed (frontmost) activity, for the snapshot header. */
659
+ private foregroundPackage;
660
+ screenshot(opts: {
661
+ path: string;
662
+ }): Promise<{
663
+ path: string;
664
+ }>;
665
+ press(target: PressTarget): Promise<void>;
666
+ longPress(ref: string, durationMs?: number): Promise<void>;
667
+ fill(ref: string, text: string): Promise<void>;
668
+ /**
669
+ * Empty the currently-focused text field. Ctrl+A then DEL (`input
670
+ * keycombination`, Android 12+); a short MOVE_END + backspace sweep stays as
671
+ * the fallback for the rare field that ignores the select combo. Replaces a
672
+ * 60-backspace sweep that left residue on long fields and made repeated
673
+ * `type`s ACCUMULATE, sending the agent into retry loops.
674
+ */
675
+ private clearFocusedField;
676
+ typeText(text: string): Promise<void>;
677
+ /** The IME id of senzhk/ADBKeyBoard, the de-facto Unicode input path for adb. */
678
+ private static readonly ADB_IME;
679
+ /**
680
+ * Type non-ASCII via the ADB Keyboard broadcast. The IME must be the ACTIVE
681
+ * keyboard; some OEM builds deny the shell WRITE_SECURE_SETTINGS so `ime set`
682
+ * cannot switch it. We try (works on stock builds) and restore the previous
683
+ * keyboard afterwards when we did the switching. Never a silent drop.
684
+ */
685
+ private typeUnicode;
686
+ pressKey(_key: 'return'): Promise<void>;
687
+ scroll(direction: ScrollDirection): Promise<void>;
688
+ pan(x: number, y: number, dx: number, dy: number, durationMs?: number): Promise<void>;
689
+ waitForText(text: string, timeoutMs?: number): Promise<void>;
690
+ home(): Promise<void>;
691
+ back(): Promise<void>;
692
+ /** Packages that expose a launcher icon — the set `open <name>` can resolve to. */
693
+ private launchables;
694
+ /**
695
+ * Resolve a human app name to an installed package: agents say "Markor" or
696
+ * "Simple Calendar", `am` needs `net.gsantner.markor`. Score each launchable
697
+ * package by how many of the query's words appear in its id; best (shortest
698
+ * on a tie) wins. An exact package id passes straight through. Returns
699
+ * undefined when nothing matches and the query is not a package id at all.
700
+ */
701
+ private resolvePackage;
702
+ openApp(opts: {
703
+ app?: string | undefined;
704
+ url?: string | undefined;
705
+ relaunch?: boolean | undefined;
706
+ }): Promise<OpenAppResult>;
707
+ listApps(): Promise<string[]>;
708
+ closeSession(): Promise<void>;
709
+ }
710
+ /**
711
+ * Backend factory for the `android-adb` registry entry: an
712
+ * {@link AndroidDeviceConfig} pins the serial; anything else targets the single
713
+ * attached device.
714
+ */
715
+ declare function createAndroidBackend(config?: DeviceConfig | AndroidBackendOptions): AndroidBackend;
716
+ /** One row of `adb devices -l`. */
717
+ type AndroidDeviceInfo = {
718
+ /** adb serial, e.g. `emulator-5554` or `R58M12ABCDE`. */
719
+ serial: string;
720
+ /** adb state: `device` (ready), `unauthorized`, `offline`, … */
721
+ state: string;
722
+ /** Model name when adb reports one. */
723
+ model?: string | undefined;
724
+ };
725
+ type CommonAndroidOptions = {
726
+ /** Path to the adb binary (default: `adb` on PATH). */
727
+ adbBin?: string | undefined;
728
+ /** Idle lease window in ms (false disables). Default 180_000 (3 min). */
729
+ idleTimeoutMs?: number | false | undefined;
730
+ /** Observer for reaper-initiated closes. */
731
+ onIdleClose?: ((device: Device) => void) | undefined;
732
+ /** Initial %name% secret values (see Device.secrets). */
733
+ secrets?: Record<string, string> | undefined;
734
+ };
735
+ /** Options for `android.connect()`. */
736
+ type AndroidConnectOptions = CommonAndroidOptions;
737
+ /** Options for `android.list()`. */
738
+ type AndroidListOptions = {
739
+ /** Path to the adb binary (default: `adb` on PATH). */
740
+ adbBin?: string | undefined;
741
+ };
742
+ /** The child-process handle the emulator spawner returns (what `android.launch()` kills on close). */
743
+ type EmulatorProcess = {
744
+ /** Send a signal to the emulator process. */
745
+ kill(signal?: NodeJS.Signals): void;
746
+ /** Subscribe once to process exit. */
747
+ once(event: 'exit', listener: () => void): unknown;
748
+ /** True once the process has exited. */
749
+ readonly exited: boolean;
750
+ };
751
+ /** Options for `android.launch()` — which AVD, which port, headless or not. */
752
+ type AndroidLaunchOptions = CommonAndroidOptions & {
753
+ /** The AVD name (`emulator -list-avds`). Required. */
754
+ avd: string;
755
+ /** Console port; the serial becomes `emulator-<port>`. Default 5554. Must be even. */
756
+ port?: number | undefined;
757
+ /** Path to the `emulator` binary (default: `$ANDROID_HOME/emulator/emulator`, else `emulator` on PATH). */
758
+ emulatorBin?: string | undefined;
759
+ /** Run without a window (default true — cloud hosts have no display). */
760
+ headless?: boolean | undefined;
761
+ /** `-read-only`: lets several instances of ONE AVD run at once (what a cloud worker wants). */
762
+ readOnly?: boolean | undefined;
763
+ /** Extra emulator arguments appended verbatim (e.g. `-gpu swiftshader_indirect`). */
764
+ extraArgs?: string[] | undefined;
765
+ /** Boot ceiling in ms for `sys.boot_completed` (default 180_000). */
766
+ bootTimeoutMs?: number | undefined;
767
+ };
768
+ /** Devices adb currently sees, with their state. */
769
+ declare function list(options?: AndroidListOptions): Promise<AndroidDeviceInfo[]>;
770
+ /**
771
+ * Attach to a device adb already sees. With a serial, that device; without,
772
+ * the single ready device (several attached → an error naming them, so verbs
773
+ * never land on the wrong phone). `close()` releases the handle and never
774
+ * shuts the device down — it was yours before we connected.
775
+ */
776
+ declare function connect$1(serial?: string, options?: AndroidConnectOptions): Promise<Device>;
777
+ /**
778
+ * Boot a DEDICATED emulator instance from an AVD and return a {@link Device}
779
+ * pinned to its serial (`emulator-<port>`). `close()` kills the instance.
780
+ * `readOnly: true` lets several instances of one AVD run side by side, which
781
+ * is how a cloud worker turns one golden image into N phones.
782
+ */
783
+ declare function launch$1(options: AndroidLaunchOptions): Promise<Device>;
784
+ /**
785
+ * The Android engine object (the `ios` twin): `android.connect()` for a device
786
+ * adb already sees, `android.launch()` for a dedicated emulator instance,
787
+ * `android.list()` to see what is attached. All return/describe the same
788
+ * Device type the iOS engine does.
789
+ */
790
+ declare const android: {
791
+ /** Attach to an attached device or running emulator by serial (no-arg: the single ready device). */
792
+ readonly connect: typeof connect$1;
793
+ /** Boot a dedicated emulator instance from an AVD and return a Device pinned to it. */
794
+ readonly launch: typeof launch$1;
795
+ /** Devices adb currently sees, with their state. */
796
+ readonly list: typeof list;
797
+ };
798
+ //#endregion
480
799
  //#region src/backends/cloud-sandbox.d.ts
481
800
  /** Every device verb a cloud sandbox accepts over the RPC wire. The worker's
482
801
  * runtime set is contract-tested against this union. */
483
- type SandboxRpcMethod = 'snapshot' | 'screenshot' | 'press' | 'longPress' | 'fill' | 'typeText' | 'pressKey' | 'scroll' | 'pan' | 'installApp' | 'waitForText' | 'systemAlert' | 'home' | 'back' | 'openApp' | 'listApps' | 'closeSession';
802
+ type SandboxRpcMethod = 'snapshot' | 'screenshot' | 'press' | 'longPress' | 'fill' | 'typeText' | 'pressKey' | 'scroll' | 'pan' | 'installApp' | 'waitForText' | 'systemAlert' | 'home' | 'back' | 'openApp' | 'listApps' | 'closeSession' | 'checkpoint' | 'restoreCheckpoint' | 'listCheckpoints' | 'deleteCheckpoint';
803
+ /** One saved device state, as reported by the worker. */
804
+ type SandboxCheckpointInfo = {
805
+ id: string;
806
+ label?: string | undefined;
807
+ createdAt: string;
808
+ };
484
809
  /** Body of `POST <endpoint>/rpc`: one verb and its positional arguments. */
485
810
  type SandboxRpcRequest = {
486
811
  method: SandboxRpcMethod;
@@ -546,7 +871,33 @@ declare class CloudSandboxBackend extends BaseDeviceBackend {
546
871
  }): Promise<OpenAppResult>;
547
872
  listApps(): Promise<string[]>;
548
873
  closeSession(): Promise<void>;
874
+ /** Save the device's current state. Returns the checkpoint's id. */
875
+ checkpoint(opts?: {
876
+ label?: string;
877
+ }): Promise<SandboxCheckpointInfo>;
878
+ /** Restore a checkpoint by id or label. The checkpoint survives — restore as
879
+ * often as needed. Device identity may change server-side; the sandbox
880
+ * endpoint/token stay valid. */
881
+ restoreCheckpoint(ref: string): Promise<{
882
+ checkpointId: string;
883
+ }>;
884
+ /** List this sandbox's checkpoints. */
885
+ listCheckpoints(): Promise<SandboxCheckpointInfo[]>;
886
+ /** Delete a checkpoint by id or label. */
887
+ deleteCheckpoint(ref: string): Promise<{
888
+ deleted: boolean;
889
+ }>;
549
890
  /** Upload a zipped .app bundle (base64) and install it on the sandbox device. */
891
+ /**
892
+ * Upload a zipped .app as a raw stream. Prefer this over {@link installApp}:
893
+ * base64 inside a JSON body inflates the payload by a third, which caps real
894
+ * apps near 144MB. Pass a `Bun.file(...)` (or any Blob) and the bytes go to the
895
+ * wire without being buffered in memory.
896
+ */
897
+ installAppStream(zip: Blob): Promise<{
898
+ installed?: string;
899
+ }>;
900
+ /** @deprecated Base64-in-JSON; use {@link installAppStream}. */
550
901
  installApp(base64Zip: string): Promise<{
551
902
  installed?: string;
552
903
  }>;
@@ -620,138 +971,6 @@ declare class DeviceRunnerBackend extends BaseDeviceBackend {
620
971
  * `PHONE_USE_RUNNER_URL` / `PHONE_USE_RUNNER_TOKEN` when `config` is omitted). */
621
972
  declare const createDeviceRunnerBackend: (config?: DeviceRunnerConfig) => DeviceRunnerBackend;
622
973
  //#endregion
623
- //#region src/lifecycle.d.ts
624
- /** The platform a {@link Device} runs on. */
625
- type DevicePlatform = 'ios' | 'android';
626
- /** Lifecycle state of a {@link Device} handle. */
627
- type DeviceStatus = 'running' | 'closed';
628
- /**
629
- * The Device lifecycle handle: id, pinned backend, close/dispose, idle lease +
630
- * reaper — plus the action verb surface layered onto the same type.
631
- * `ios.launch()` and `ios.connect()` return it; the future android engine will
632
- * share `createDeviceHandle`.
633
- */
634
- interface Device {
635
- /** udid (iOS) / serial (Android). */
636
- readonly id: string;
637
- /** Which platform this device runs. */
638
- readonly platform: DevicePlatform;
639
- /** Simulator/device name when known. */
640
- readonly name?: string | undefined;
641
- /** Name of the backend driving this device. */
642
- readonly backendName: string;
643
- /** The backend's declared capability set. */
644
- readonly capabilities: ReadonlySet<Capability>;
645
- /**
646
- * The pinned backend — `new DeviceContext(device.backend)` works today.
647
- * Backend calls through this handle count as activity for the idle lease.
648
- */
649
- readonly backend: DeviceBackend;
650
- /** true when launch() created the device — close() then also deletes it. */
651
- readonly createdByUs: boolean;
652
- /** Current lifecycle state. */
653
- readonly status: DeviceStatus;
654
- /** Sugar for `status === 'closed'`. */
655
- readonly isClosed: boolean;
656
- /** Re-arm the idle lease (ms overrides the configured window for this arm only). */
657
- extendLease(ms?: number): void;
658
- /** Canonical, idempotent shutdown. `await using` is sugar over this. */
659
- close(): Promise<void>;
660
- /** `await using` support — delegates to {@link Device.close}. */
661
- [Symbol.asyncDispose](): Promise<void>;
662
- /** Look at the screen: elements + rendered text + portable Action[]. */
663
- observe(opts?: {
664
- signal?: AbortSignal | undefined;
665
- }): Promise<ObserveResult>;
666
- /** Tap by label/id query. Auto-waits; never throws for normal outcomes. */
667
- tap(target: string | ElementQuery, opts?: ActOptions): Promise<ActionResult>;
668
- /** Type text (optionally into a field resolved by query); %name% secrets substituted. */
669
- type(text: string, opts?: ActOptions & {
670
- field?: string | ElementQuery | undefined;
671
- submit?: boolean | undefined;
672
- }): Promise<ActionResult>;
673
- /** Execute a portable Action deterministically — no re-inference. */
674
- act(action: Action, opts?: ActOptions): Promise<ActionResult>;
675
- /** App management: open by name/deep link, list installed, current app. */
676
- readonly apps: {
677
- /** Open an app by name/bundle id, or a deep link when `url` is set. */
678
- open(app: string, opts?: {
679
- relaunch?: boolean | undefined;
680
- url?: string | undefined;
681
- signal?: AbortSignal | undefined;
682
- }): Promise<ActionResult>;
683
- /** List installed app bundle ids. */
684
- list(opts?: {
685
- signal?: AbortSignal | undefined;
686
- }): Promise<string[]>;
687
- /** The frontmost app name from the last observation (no new snapshot). */
688
- current(): string | undefined;
689
- };
690
- /** Screen-level verbs: scroll, screenshot, waitForText, alert, back, home. */
691
- readonly screen: {
692
- /** Scroll the active scroll view one step. */
693
- scroll(direction: ScrollDirection, opts?: {
694
- signal?: AbortSignal | undefined;
695
- }): Promise<ActionResult>;
696
- /** Save a screenshot to `path`. */
697
- screenshot(opts: {
698
- path: string;
699
- signal?: AbortSignal | undefined;
700
- }): Promise<{
701
- success: boolean;
702
- message: string;
703
- path?: string | undefined;
704
- }>;
705
- /** Block until `text` appears on screen or the timeout elapses. */
706
- waitForText(text: string, opts?: {
707
- timeoutMs?: number | undefined;
708
- signal?: AbortSignal | undefined;
709
- }): Promise<ActionResult>;
710
- /** Read ('get'), accept, or dismiss a blocking system alert. */
711
- alert(action: 'get' | 'accept' | 'dismiss', opts?: {
712
- signal?: AbortSignal | undefined;
713
- }): Promise<ActionResult>;
714
- /** Navigate back. */
715
- back(opts?: {
716
- signal?: AbortSignal | undefined;
717
- }): Promise<ActionResult>;
718
- /** Go to the home screen. */
719
- home(opts?: {
720
- signal?: AbortSignal | undefined;
721
- }): Promise<ActionResult>;
722
- };
723
- /** %name% secret store — values substituted at execution, redacted everywhere else. */
724
- readonly secrets: SecretStore;
725
- }
726
- /** Inputs to {@link createDeviceHandle} — what an engine supplies per device. */
727
- type CreateDeviceHandleOptions = {
728
- /** udid (iOS) / serial (Android). */
729
- id: string;
730
- /** Which platform the device runs. */
731
- platform: DevicePlatform;
732
- /** Simulator/device name when known. */
733
- name?: string | undefined;
734
- /** The backend pinned to this device. */
735
- backend: DeviceBackend;
736
- /** true when the engine created the device (close() then also deletes it). */
737
- createdByUs: boolean;
738
- /** Idle window in ms; false disables the lease. Default 180_000 (3m). */
739
- idleTimeoutMs?: number | false | undefined;
740
- /** Observer for reaper-initiated closes (the SDK never logs). */
741
- onIdleClose?: ((device: Device) => void) | undefined;
742
- /** Initial %name% secret values. */
743
- secrets?: Record<string, string> | undefined;
744
- /** Platform teardown: shutdown (+ delete when createdByUs). */
745
- doClose: () => Promise<void>;
746
- };
747
- /**
748
- * Assemble a Device handle over a backend: lease/reaper, verb surface,
749
- * close/dispose semantics. Engine authors (ios here, android in item 7b,
750
- * phone-backend-* third parties) build on this; tests fabricate devices with
751
- * it over a FakeBackend.
752
- */
753
- declare function createDeviceHandle(opts: CreateDeviceHandleOptions): Device;
754
- //#endregion
755
974
  //#region src/backends/ios.d.ts
756
975
  type CommonIosOptions = {
757
976
  /** Custom simulator device set directory (maps to `simctl --set`). */
@@ -819,14 +1038,14 @@ declare const ios: {
819
1038
  //#region src/index.d.ts
820
1039
  /**
821
1040
  * @phone-use/sdk — the device runtime SDK: engine-as-object lifecycle
822
- * (ios.launch/connect → Device), Device backends, config, errors, capabilities,
1041
+ * (ios.launch/connect and android.launch/connect → Device), Device backends, config, errors, capabilities,
823
1042
  * and the action verb surface.
824
1043
  *
825
1044
  * The test double (FakeBackend) lives on the "@phone-use/sdk/testing" subpath,
826
1045
  * deliberately not re-exported here.
827
1046
  */
828
1047
  /** The published package version (kept in sync with package.json by the release flow). */
829
- declare const VERSION = "0.3.1";
1048
+ declare const VERSION = "0.5.0";
830
1049
  //#endregion
831
- export { ALL_CAPABILITIES, AbortedError, type ActOptions, type Action, type ActionEvidence, ActionFailedError, type ActionResult, type ActionVerb, type AlertAction, type AlertOutcome, type AndroidDeviceConfig, type BackendAlertResult, type BackendFactory, BaseDeviceBackend, type Capability, CloudSandboxBackend, type CloudSandboxBackendOptions, type CommonDeviceConfig, type CompiledSkill, type CreateDeviceHandleOptions, type Device, type DeviceBackend, type DeviceConfig, DeviceCore, DeviceInUseError, DeviceNotFoundError, type DevicePlatform, DeviceRunnerBackend, type DeviceRunnerConfig, type DeviceStatus, type ElementQuery, type IosConnectOptions, type IosDeviceConfig, type IosLaunchOptions, type Observation, type ObserveResult, type ObservedElement, type OpenAppResult, PhoneUseError, type PhoneUseErrorCode, type PhoneUseErrorDetails, type PressTarget, type Rect, type RenderState, type Resolution, type ResolveOpts, type SandboxRpcFailure, type SandboxRpcMethod, type SandboxRpcRequest, type SandboxRpcResponse, type SandboxRpcSuccess, type ScrollDirection, SecretStore, SessionNotFoundError, type Snapshot, type SnapshotNode, TimeoutError, type UiElement, UnsupportedCapabilityError, VERSION, buildObserveResult, createAgentDeviceBackend, createCloudSandboxBackend, createDeviceHandle, createDeviceRunnerBackend, describeError, executeAction, getBackendFactory, ios, labelMatches, listBackends, matchInElements, registerBackend, toActions, toPhoneUseError };
1050
+ export { ALL_CAPABILITIES, AbortedError, type ActOptions, type Action, type ActionEvidence, ActionFailedError, type ActionResult, type ActionVerb, type AlertAction, type AlertOutcome, AndroidBackend, type AndroidBackendOptions, type AndroidConnectOptions, type AndroidDeviceConfig, type AndroidDeviceInfo, type AndroidLaunchOptions, type AndroidListOptions, type BackendAlertResult, type BackendFactory, BaseDeviceBackend, type BinaryExecRunner, type Capability, CloudSandboxBackend, type CloudSandboxBackendOptions, type CommonDeviceConfig, type CompiledSkill, type CreateDeviceHandleOptions, type Device, type DeviceBackend, type DeviceConfig, DeviceCore, DeviceInUseError, DeviceNotFoundError, type DevicePlatform, DeviceRunnerBackend, type DeviceRunnerConfig, type DeviceStatus, type ElementQuery, type EmulatorProcess, type IosConnectOptions, type IosDeviceConfig, type IosLaunchOptions, type Observation, type ObserveResult, type ObservedElement, type OpenAppResult, PhoneUseError, type PhoneUseErrorCode, type PhoneUseErrorDetails, type PressTarget, type Rect, type RenderState, type Resolution, type ResolveOpts, type SandboxCheckpointInfo, type SandboxRpcFailure, type SandboxRpcMethod, type SandboxRpcRequest, type SandboxRpcResponse, type SandboxRpcSuccess, type ScrollDirection, SecretStore, SessionNotFoundError, type Snapshot, type SnapshotNode, TimeoutError, type UiElement, UnsupportedCapabilityError, VERSION, android, buildObserveResult, createAgentDeviceBackend, createAndroidBackend, createCloudSandboxBackend, createDeviceHandle, createDeviceRunnerBackend, describeError, executeAction, getBackendFactory, ios, labelMatches, listBackends, matchInElements, registerBackend, toActions, toPhoneUseError };
832
1051
  //# sourceMappingURL=index.d.mts.map