@oniroproject/core 0.16.0 → 0.18.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.cts CHANGED
@@ -28,7 +28,7 @@ declare const noopProgress: ProgressReporter;
28
28
  * Keys read from the ConfigProvider by core. Frontends (CLI, VS Code extension)
29
29
  * implement the provider however they like (env vars, settings.json, etc.).
30
30
  */
31
- type ConfigKey = 'sdkRootDir' | 'cmdToolsPath' | 'hdcPath' | 'emulatorDir' | 'hapPath' | 'cmdToolsUrlLinux' | 'cmdToolsUrlWindows' | 'cmdToolsUrlMac' | 'emulatorUrl' | 'tmpDir' | 'sdkUrlBase' | 'applicationCertPath' | 'harmonyosSdkPath' | 'harmonyosAuthDir' | 'harmonyosSigningDir';
31
+ type ConfigKey = 'sdkRootDir' | 'cmdToolsPath' | 'hdcPath' | 'emulatorDir' | 'hapPath' | 'cmdToolsUrlLinux' | 'cmdToolsUrlWindows' | 'cmdToolsUrlMac' | 'emulatorUrl' | 'tmpDir' | 'sdkUrlBase' | 'applicationCertPath' | 'harmonyosSdkPath' | 'harmonyosAuthDir' | 'harmonyosSigningDir' | 'cacheDir' | 'docsDir';
32
32
  interface ConfigProvider {
33
33
  /**
34
34
  * Get the configured value for `key`, or `fallback` if unset/empty.
@@ -46,6 +46,7 @@ declare const defaultPaths: {
46
46
  readonly emulatorDir: () => string;
47
47
  readonly harmonyosAuthDir: () => string;
48
48
  readonly harmonyosSigningDir: () => string;
49
+ readonly cacheDir: () => string;
49
50
  readonly hapPath: "entry/build/default/outputs/default/entry-default-signed.hap";
50
51
  readonly emulatorUrl: "https://github.com/eclipse-oniro4openharmony/device_board_oniro/releases/latest/download/oniro_emulator.zip";
51
52
  readonly cmdToolsUrlLinux: "https://repo.huaweicloud.com/harmonyos/ohpm/5.1.0/commandline-tools-linux-x64-5.1.0.840.zip";
@@ -257,6 +258,12 @@ declare function getHvigorwPath(config: ConfigProvider, projectDir: string, plat
257
258
  * `00308018 SDK path does not exist` / "SDK license agreement is not accepted".
258
259
  */
259
260
  declare function findMissingProjectSdk(config: ConfigProvider, projectRoot: string): SdkNotInstalledError | null;
261
+ /**
262
+ * The SDK API directory an OpenHarmony project builds against, as hvigor finds it:
263
+ * `<sdk home>/<compileSdkVersion>`, else under the project's `local.properties`
264
+ * `sdk.dir`. Undefined when neither holds it or the project names no numeric API.
265
+ */
266
+ declare function resolveProjectSdkDir(config: ConfigProvider, projectRoot: string): string | undefined;
260
267
  /**
261
268
  * Detect the SDK API a project targets by reading `build-profile.json5`.
262
269
  * Returns the `compileSdkVersion` of the first declared product, or undefined
@@ -426,6 +433,64 @@ interface ZipEntry {
426
433
  attr?: number;
427
434
  }
428
435
 
436
+ /**
437
+ * A HarmonyOS SDK install. Unlike the OpenHarmony SDK, which `oniro-app sdk install`
438
+ * downloads, the HarmonyOS SDK only ships inside DevEco Studio or the login-gated
439
+ * HarmonyOS command-line tools, so oniro-app locates an existing install.
440
+ */
441
+ interface HarmonyOsSdk {
442
+ /** The directory containing `default/`; hvigor receives it as `DEVECO_SDK_HOME`. */
443
+ sdkPath: string;
444
+ /** The DevEco Studio or command-line-tools install holding the SDK, its tools and JBR. */
445
+ installRoot: string;
446
+ /** From `default/sdk-pkg.json`, e.g. `HarmonyOS 6.1.1`. */
447
+ displayName?: string;
448
+ /**
449
+ * The release as `compileSdkVersion` names it, e.g. `6.1.1(24)`, from
450
+ * `default/sdk-pkg.json`. hvigor builds only projects that name this release.
451
+ */
452
+ version?: string;
453
+ /** The API level, e.g. `24`, from `default/sdk-pkg.json`. */
454
+ apiVersion?: string;
455
+ /**
456
+ * Where it was found: `configured` (ONIRO_HARMONYOS_SDK_PATH), `deveco-studio`,
457
+ * or `cmdtools` (the HarmonyOS edition of the command-line tools at `cmdToolsPath`).
458
+ */
459
+ source?: HarmonyOsSdkSource;
460
+ }
461
+ type HarmonyOsSdkSource = 'configured' | 'deveco-studio' | 'cmdtools';
462
+ /** What `default/sdk-pkg.json` says about an SDK. */
463
+ interface SdkPkgInfo {
464
+ /** e.g. `HarmonyOS 6.1.1`. */
465
+ displayName?: string;
466
+ /** `<platformVersion>(<apiVersion>)`, e.g. `6.1.1(24)`. */
467
+ version?: string;
468
+ /** e.g. `6.1.1`. */
469
+ platformVersion?: string;
470
+ /** e.g. `24`. */
471
+ apiVersion?: string;
472
+ /** The SDK build, e.g. `6.1.1.125`. */
473
+ build?: string;
474
+ }
475
+ /** {@link SdkPkgInfo} from `<sdkPath>/default/sdk-pkg.json`; empty when it is missing or unreadable. */
476
+ declare function readSdkPkg(sdkPath: string): SdkPkgInfo;
477
+ /**
478
+ * Locate a HarmonyOS SDK, or return null when none is installed.
479
+ *
480
+ * Order: `harmonyosSdkPath` (`ONIRO_HARMONYOS_SDK_PATH`, an install root or its
481
+ * `sdk` directory), then DevEco Studio in its default location, then the
482
+ * command-line tools at `cmdToolsPath` when they are the HarmonyOS edition.
483
+ */
484
+ declare function findHarmonyOsSdk(opts: {
485
+ config: ConfigProvider;
486
+ logger?: Logger;
487
+ }): HarmonyOsSdk | null;
488
+ /** Like `findHarmonyOsSdk`, but throws an actionable error when none is installed. */
489
+ declare function requireHarmonyOsSdk(opts: {
490
+ config: ConfigProvider;
491
+ logger?: Logger;
492
+ }): HarmonyOsSdk;
493
+
429
494
  interface SdkInfo {
430
495
  version: string;
431
496
  api: string;
@@ -436,6 +501,27 @@ interface SdkInfo {
436
501
  * Sorted by API descending (newest first).
437
502
  */
438
503
  declare function getSupportedSdksForUi(config: ConfigProvider): SdkInfo[];
504
+ /** The HarmonyOS SDK on this machine, in the shape `sdk list` prints. */
505
+ interface HarmonyOsSdkListing {
506
+ flavour: 'HarmonyOS';
507
+ /** e.g. `HarmonyOS 6.1.1`. */
508
+ displayName?: string;
509
+ /** The release, e.g. `6.1.1`. */
510
+ version?: string;
511
+ /** e.g. `24`. */
512
+ api?: string;
513
+ installed: true;
514
+ /** The SDK directory hvigor receives as `DEVECO_SDK_HOME`. */
515
+ path: string;
516
+ /** Where it was found; `cmdtools` for the command-line tools at `cmdToolsPath`. */
517
+ source?: HarmonyOsSdkSource;
518
+ }
519
+ /**
520
+ * The HarmonyOS SDK a HarmonyOS build would use, or null. `sdk install` does not
521
+ * manage it: it ships with the HarmonyOS command-line tools (`cmdtools`) or
522
+ * DevEco Studio (#21).
523
+ */
524
+ declare function getHarmonyOsSdkListing(config: ConfigProvider): HarmonyOsSdkListing | null;
439
525
  /**
440
526
  * Return the SDK versions that have at least one OS-folder install in `sdkRootDir`.
441
527
  * Scans `linux`, `darwin`, `windows` so the list is consistent across machines that
@@ -546,12 +632,49 @@ interface InstallCmdToolsOptions {
546
632
  * config key and the default location next to the install target.
547
633
  */
548
634
  tmpDir?: string;
635
+ /**
636
+ * Filesystem seams for tests: `move` stages each extracted entry inside the
637
+ * install directory (default {@link movePath}), `rename` swaps entries in and
638
+ * out of it (default `fs.renameSync`).
639
+ * @internal
640
+ */
641
+ fsOps?: Partial<CmdToolsFsOps>;
642
+ }
643
+ interface InstallCmdToolsResult {
644
+ /** The install directory. */
645
+ path: string;
646
+ /** What is installed now. */
647
+ installed: CmdToolsInfo;
648
+ /** What the install replaced; absent when the directory was missing or empty. */
649
+ previous?: CmdToolsInfo;
650
+ }
651
+ /**
652
+ * What `installCmdTools` says when it replaces an install: which release replaces
653
+ * which, and when hvigor changes major version or the new release is older, that
654
+ * too. Pure.
655
+ */
656
+ declare function describeReplacement(previous: CmdToolsInfo, next: CmdToolsInfo): string[];
657
+ /** @internal */
658
+ interface CmdToolsFsOps {
659
+ move: (src: string, dest: string) => void;
660
+ rename: (src: string, dest: string) => void;
549
661
  }
550
662
  /**
551
663
  * Install the OpenHarmony command-line tools into `<cmdToolsPath>`.
552
664
  * Either downloads from the platform-specific URL or installs from a caller-supplied ZIP.
665
+ *
666
+ * The archive is extracted to scratch space and staged inside the install
667
+ * directory; only once the whole tree is staged are its entries swapped in for the
668
+ * old ones. A failure before that (a full disk mid-copy, say) leaves the install
669
+ * directory as it was, and one during the swap rolls it back (#16). A successful
670
+ * install replaces the directory's contents outright, so it holds exactly what a
671
+ * clean extraction of the archive holds, whatever an earlier failed attempt or an
672
+ * older version left there. Entries that are not the tools' (see `TOOL_ENTRIES`) stay.
673
+ *
674
+ * When it replaces an install, it logs which release replaces which before the
675
+ * old one is deleted, and returns both (#25).
553
676
  */
554
- declare function installCmdTools(opts: InstallCmdToolsOptions): Promise<void>;
677
+ declare function installCmdTools(opts: InstallCmdToolsOptions): Promise<InstallCmdToolsResult>;
555
678
  interface CmdToolsStatus {
556
679
  installed: boolean;
557
680
  status: string;
@@ -564,8 +687,50 @@ interface CmdToolsStatus {
564
687
  path: string;
565
688
  exists: boolean;
566
689
  };
690
+ /** The bundle release, e.g. `6.1.1.280`, as in `status`. Set when known. */
691
+ version?: string;
692
+ /** The SDK the tools bundle (the HarmonyOS SDK, in the HarmonyOS edition). Set when installed and present. */
693
+ sdk?: CmdToolsSdk;
694
+ /** Versions of the tools inside, from `version.txt`, e.g. `{ hvigor: '6.24.2', ohpm: '6.1.2.268' }`. */
695
+ tools?: Record<string, string>;
567
696
  }
568
697
  type CmdToolsFlavour = 'HarmonyOS' | 'OpenHarmony';
698
+ /** The SDK a command-line tools install ships under `sdk/`. */
699
+ interface CmdToolsSdk {
700
+ /** The `sdk` directory, which HarmonyOS builds receive as `DEVECO_SDK_HOME`. */
701
+ path: string;
702
+ /** e.g. `HarmonyOS 6.1.1`. */
703
+ displayName?: string;
704
+ /** e.g. `6.1.1`. */
705
+ platformVersion?: string;
706
+ /** e.g. `24`. */
707
+ apiVersion?: string;
708
+ /** The SDK build, e.g. `6.1.1.125`. */
709
+ build?: string;
710
+ }
711
+ /** What a command-line tools install holds: its release, flavour, SDK and tool versions. */
712
+ interface CmdToolsInfo {
713
+ /** From `version.txt` (`# Version: 6.1.1.280`). */
714
+ version?: string;
715
+ flavour: CmdToolsFlavour;
716
+ sdk?: CmdToolsSdk;
717
+ /** Tool versions `version.txt` lists (`hvigor : 6.24.2`). */
718
+ tools: Record<string, string>;
719
+ }
720
+ /**
721
+ * Read what the command-line tools at `cmdToolsPath` are, from `version.txt` and
722
+ * `sdk/default/sdk-pkg.json`. Fields it cannot find are left out. Pure file reads.
723
+ */
724
+ declare function readCmdToolsInfo(cmdToolsPath: string): CmdToolsInfo;
725
+ /**
726
+ * One line naming a tools install: `6.1.1.280 (HarmonyOS 6.1.1, API 24, hvigor 6.24.2)`,
727
+ * leaving out what is unknown.
728
+ */
729
+ declare function describeCmdTools(info: {
730
+ version?: string;
731
+ sdk?: CmdToolsSdk;
732
+ tools?: Record<string, string>;
733
+ }): string;
569
734
  /**
570
735
  * The flavour of a command-line tools install: `HarmonyOS` when it bundles the
571
736
  * HarmonyOS SDK (`sdk/default/hms`, as the Huawei developer-portal download
@@ -575,8 +740,9 @@ type CmdToolsFlavour = 'HarmonyOS' | 'OpenHarmony';
575
740
  declare function detectCmdToolsFlavour(cmdToolsPath: string): CmdToolsFlavour;
576
741
  /**
577
742
  * Reports whether ohpm is present at the configured path, and if so its version,
578
- * flavour, and the hdc binary in use. Prefers reading `version.txt`
579
- * (`# Version: x.y.z`) before falling back to executing the binary with `-v`.
743
+ * flavour, the SDK it bundles, its tools' versions (see {@link readCmdToolsInfo})
744
+ * and the hdc binary in use. The version comes from `version.txt`
745
+ * (`# Version: x.y.z`), else from running ohpm with `-v`.
580
746
  */
581
747
  declare function getCmdToolsStatus(config: ConfigProvider): CmdToolsStatus;
582
748
  declare function isCmdToolsInstalled(config: ConfigProvider): boolean;
@@ -684,6 +850,25 @@ interface GenerateSigningConfigsOptions {
684
850
  * @internal exposed for tests.
685
851
  */
686
852
  declare function detectSigningConfigNames(projectDir: string): string[];
853
+ /** What the signing material in a `signatures` directory amounts to, for a one-line summary. */
854
+ interface SigningMaterialSummary {
855
+ /** The profile's type: `release` for the SDK's template. */
856
+ profileType?: string;
857
+ apl?: string;
858
+ /**
859
+ * The end of the profile's validity window. The SDK's template carries a fixed
860
+ * one that ended in 2023, which OpenHarmony devices do not enforce.
861
+ */
862
+ profileNotAfter?: Date;
863
+ /** When the certificate that signs HAPs expires. */
864
+ certificateNotAfter?: Date;
865
+ }
866
+ /** `release profile, apl normal; certificate valid until 2049-12-31 12:21 UTC`. Empty when nothing is known. */
867
+ declare function describeSigningMaterial(summary: SigningMaterialSummary): string;
868
+ interface GenerateSigningConfigsResult extends SigningMaterialSummary {
869
+ signaturesDir: string;
870
+ kind: SigningKind;
871
+ }
687
872
  /**
688
873
  * Generate signing configs for an OpenHarmony project: copies certs, signs the profile,
689
874
  * generates the signing material, and writes the resulting `signingConfigs` entry into
@@ -691,7 +876,7 @@ declare function detectSigningConfigNames(projectDir: string): string[];
691
876
  *
692
877
  * Requires `java` on PATH (the OpenHarmony hap-sign-tool ships as a .jar).
693
878
  */
694
- declare function generateSigningConfigs(options: GenerateSigningConfigsOptions): void;
879
+ declare function generateSigningConfigs(options: GenerateSigningConfigsOptions): GenerateSigningConfigsResult;
695
880
 
696
881
  /** What signing needs to know about a built HAP. */
697
882
  interface HapSigningInfo {
@@ -736,6 +921,8 @@ interface SignOpenHarmonyHapResult {
736
921
  /** API level of the SDK whose signing material was used. */
737
922
  sdkApi: string;
738
923
  kind: SigningKind;
924
+ /** The profile and certificate the HAP was signed with. */
925
+ material: SigningMaterialSummary;
739
926
  }
740
927
  /**
741
928
  * Sign a prebuilt HAP, with no project, for OpenHarmony devices: the SDK's
@@ -746,6 +933,109 @@ interface SignOpenHarmonyHapResult {
746
933
  */
747
934
  declare function signOpenHarmonyHap(opts: SignOpenHarmonyHapOptions): Promise<SignOpenHarmonyHapResult>;
748
935
 
936
+ /** One certificate of a signing chain, in a form fit for printing and JSON. */
937
+ interface CertificateInfo {
938
+ /** `CN=…, OU=…, O=…, C=…`, most specific first, as Java and openssl print it. */
939
+ subject: string;
940
+ issuer: string;
941
+ /** The subject's common name, unescaped. */
942
+ commonName?: string;
943
+ notBefore: Date;
944
+ notAfter: Date;
945
+ /** SHA-256 fingerprint, colon-separated hex. */
946
+ fingerprint256: string;
947
+ selfSigned: boolean;
948
+ }
949
+
950
+ /**
951
+ * Who issued the signing material: the OpenHarmony SDK's development certificate
952
+ * and `pki_internal` profile, which OpenHarmony devices accept and HarmonyOS
953
+ * devices do not; AppGallery Connect, whose chain ends at `Huawei CBG Root CA G2`;
954
+ * or neither.
955
+ */
956
+ type HapSigner = 'openharmony-dev' | 'harmonyos-agc' | 'other';
957
+ /** `valid`: exit 0. `invalid` (unsigned, bad signature, expired, mismatched): 1. `unverified` (no java or hap-sign-tool): 2. */
958
+ type HapVerifyStatus = 'valid' | 'invalid' | 'unverified';
959
+ interface HapProfileReport {
960
+ /** `debug` or `release`. */
961
+ type?: string;
962
+ /** `app_gallery` (AGC) or `pki_internal` (the OpenHarmony SDK's). */
963
+ issuer?: string;
964
+ bundleName?: string;
965
+ developerId?: string;
966
+ apl?: string;
967
+ appFeature?: string;
968
+ /** UDIDs a debug profile is limited to; a release profile names none. */
969
+ deviceCount: number;
970
+ notBefore?: Date;
971
+ notAfter?: Date;
972
+ expired: boolean;
973
+ /** Whole days until `notAfter`; negative once past it. */
974
+ daysLeft?: number;
975
+ /**
976
+ * Whether a device refuses the HAP once the profile is out of date. Not for the
977
+ * OpenHarmony SDK's development profile, whose fixed 2020-2023 window
978
+ * OpenHarmony devices ignore.
979
+ */
980
+ expiryEnforced: boolean;
981
+ /** Whether the profile names the certificate that signed the HAP; undefined when it names none. */
982
+ issuedForSigningCertificate?: boolean;
983
+ }
984
+ interface VerifyHapResult {
985
+ hapPath: string;
986
+ status: HapVerifyStatus;
987
+ /** Whether the HAP has a signing block at all. */
988
+ signed: boolean;
989
+ /** hap-sign-tool `verify-app` accepted the signature. */
990
+ signatureValid: boolean;
991
+ signer?: HapSigner;
992
+ /** The signing chain, leaf first. */
993
+ chain: CertificateInfo[];
994
+ /** Common name (else subject) of the chain's root. */
995
+ root?: string;
996
+ profile?: HapProfileReport;
997
+ /** The bundle name in the HAP's own module.json. */
998
+ hapBundleName?: string;
999
+ /** `app.compileSdkType` in the HAP's module.json: `OpenHarmony` or `HarmonyOS`, when the toolchain wrote it. */
1000
+ hapCompileSdkType?: string;
1001
+ /** What makes it `invalid` or `unverified`. Empty when `valid`. */
1002
+ problems: string[];
1003
+ /** Worth knowing; no effect on `status`. */
1004
+ notes: string[];
1005
+ /** hap-sign-tool's own error lines, when it refused the HAP. */
1006
+ toolErrors: string[];
1007
+ signTool?: string;
1008
+ java?: string;
1009
+ }
1010
+ interface VerifyHapOptions {
1011
+ hapPath: string;
1012
+ config: ConfigProvider;
1013
+ logger?: Logger;
1014
+ /** The time profile and certificate validity is judged at. Default now. */
1015
+ now?: Date;
1016
+ /** Use this `hap-sign-tool.jar` instead of looking for one. */
1017
+ signTool?: string;
1018
+ /** Use this java instead of looking for one. */
1019
+ java?: string;
1020
+ }
1021
+ /**
1022
+ * A `hap-sign-tool.jar` to verify with: an installed OpenHarmony SDK's, else the
1023
+ * HarmonyOS SDK's, else the command-line tools'. Any of them verifies any HAP.
1024
+ */
1025
+ declare function findHapSignTool(config: ConfigProvider, logger?: Logger): string | null;
1026
+ /**
1027
+ * Verify a HAP's signature with the SDK's `hap-sign-tool.jar verify-app`, then
1028
+ * read what signed it: the certificate chain, whether it is OpenHarmony
1029
+ * development material or AppGallery Connect's, and the provisioning profile's
1030
+ * type, bundle, APL, devices and validity. Never throws for a HAP that is
1031
+ * unsigned, mis-signed or expired; that is the `status` and `problems`.
1032
+ */
1033
+ declare function verifyHap(opts: VerifyHapOptions): Promise<VerifyHapResult>;
1034
+ /** 0 valid, 1 invalid (unsigned, bad signature, expired, mismatched), 2 could not verify. */
1035
+ declare function verifyHapExitCode(result: Pick<VerifyHapResult, 'status'>): number;
1036
+ /** {@link verifyHap}'s result as the lines `oniro-app app verify` prints. */
1037
+ declare function formatHapVerification(result: VerifyHapResult): string;
1038
+
749
1039
  interface InstallEmulatorOptions {
750
1040
  config: ConfigProvider;
751
1041
  progress?: ProgressReporter;
@@ -769,6 +1059,223 @@ declare function installEmulator(opts: InstallEmulatorOptions): Promise<void>;
769
1059
  declare function isEmulatorInstalled(config: ConfigProvider): boolean;
770
1060
  declare function removeEmulator(config: ConfigProvider): void;
771
1061
 
1062
+ /**
1063
+ * Health of one emulator instance:
1064
+ * - `stopped`: no QEMU process.
1065
+ * - `booting`: QEMU is alive; hdc cannot reach the guest yet, or `bootevent.boot.completed` is not `true`.
1066
+ * - `ready`: `hdc shell param get bootevent.boot.completed` answers `true`.
1067
+ * - `hdc-lost`: the instance was ready during this boot and hdc can no longer reach it.
1068
+ * - `stuck`: QEMU is alive but the boot has not completed within the instance's boot timeout.
1069
+ */
1070
+ type EmulatorHealth = 'stopped' | 'booting' | 'ready' | 'hdc-lost' | 'stuck';
1071
+ /** Ports of pool instance `n`: hdc 55555+n, VNC display n (5900+n), telnet serial 4444+n. */
1072
+ interface PoolInstancePorts {
1073
+ hdc: number;
1074
+ vncDisplay: number;
1075
+ vnc: number;
1076
+ serial: number;
1077
+ }
1078
+ declare function poolInstancePorts(n: number): PoolInstancePorts;
1079
+ /** The writable disks run.sh attaches, in its order (the guest sees them as vda..vdd). */
1080
+ declare const POOL_DISKS: readonly ["updater", "system", "vendor", "userdata"];
1081
+ /** Every file a pool instance needs in `<emulatorDir>/images`. */
1082
+ declare const POOL_REQUIRED_IMAGES: readonly ["bzImage", "ramdisk.img", ...string[]];
1083
+ /** run.sh's kernel command line, verbatim. */
1084
+ declare const EMULATOR_KERNEL_APPEND: string;
1085
+ /** Pool defaults: smaller than run.sh's 6 CPUs / 4 GB so several instances fit on one host. */
1086
+ declare const POOL_DEFAULT_SMP = 2;
1087
+ declare const POOL_DEFAULT_MEMORY = "2048M";
1088
+ declare const POOL_DEFAULT_RESOLUTION = "360x720";
1089
+ /** Seconds after launch past which a boot that has not completed counts as `stuck`. */
1090
+ declare const DEFAULT_BOOT_TIMEOUT_SECONDS = 300;
1091
+ type EmulatorAccel = 'auto' | 'kvm' | 'hvf' | 'whpx' | 'tcg';
1092
+ /**
1093
+ * QEMU accelerator and CPU arguments, chosen as run.sh chooses them: KVM on Linux,
1094
+ * HVF on an x86_64 Mac, TCG on Apple Silicon, WHPX on Windows. Pure/testable.
1095
+ */
1096
+ declare function emulatorAccelArgs(accel?: EmulatorAccel, platform?: NodeJS.Platform, arch?: string): string[];
1097
+ interface PoolQemuSpec {
1098
+ instance: number;
1099
+ /** The instance's state directory, holding `<disk>.qcow2`. */
1100
+ dir: string;
1101
+ /** `<emulatorDir>/images`, holding bzImage and ramdisk.img. */
1102
+ imagesDir: string;
1103
+ smp: number;
1104
+ memory: string;
1105
+ resolution: string;
1106
+ headless: boolean;
1107
+ /** `es1370` or `ES1370`, whichever this QEMU names it. */
1108
+ audioDevice: string;
1109
+ accelArgs: readonly string[];
1110
+ ports: PoolInstancePorts;
1111
+ }
1112
+ /**
1113
+ * The QEMU command line of a pool instance: run.sh's (q35, kernel/initrd/append,
1114
+ * four virtio-blk disks in the same order, virtio-gpu, user networking forwarding
1115
+ * the guest's hdcd port 55555) with the disks replaced by the instance's qcow2
1116
+ * overlays and every host port bound to 127.0.0.1 at the instance's own number.
1117
+ * Audio goes to a `none` backend so instances do not compete for the host's sound
1118
+ * server. Pure/testable.
1119
+ */
1120
+ declare function buildPoolQemuArgs(spec: PoolQemuSpec): string[];
1121
+ /** Inputs to {@link classifyEmulatorHealth}. */
1122
+ interface HealthInputs {
1123
+ /** QEMU is alive. */
1124
+ alive: boolean;
1125
+ /** hdc ran a shell command on the guest. */
1126
+ hdcReachable: boolean;
1127
+ /** `bootevent.boot.completed` is `true`. */
1128
+ bootCompleted: boolean;
1129
+ /** This boot has been seen ready before. */
1130
+ wasReady: boolean;
1131
+ /** Milliseconds since QEMU was launched, when known. */
1132
+ elapsedMs?: number;
1133
+ bootTimeoutMs: number;
1134
+ }
1135
+ /** The health code for one probe. Pure/testable. */
1136
+ declare function classifyEmulatorHealth(i: HealthInputs): EmulatorHealth;
1137
+ interface HdcBootProbe {
1138
+ hdcReachable: boolean;
1139
+ bootCompleted: boolean;
1140
+ }
1141
+ /**
1142
+ * Ask the guest at `address` whether it has booted: `hdc tconn <address>` (which
1143
+ * adds the target to the running hdc server, never restarting it), then
1144
+ * `hdc -t <address> shell param get bootevent.boot.completed`.
1145
+ */
1146
+ declare function probeEmulatorBoot(config: ConfigProvider, address: string, opts?: {
1147
+ logger?: Logger;
1148
+ timeoutMs?: number;
1149
+ }): Promise<HdcBootProbe>;
1150
+ /** One instance as `emulator status` reports it. */
1151
+ interface EmulatorInstanceStatus {
1152
+ /** 0 is the default emulator (run.sh); 1.. are pool instances. */
1153
+ instance: number;
1154
+ state: EmulatorHealth;
1155
+ /** hdc serial: `127.0.0.1:<hdcPort>`. */
1156
+ address: string;
1157
+ hdcPort: number;
1158
+ /** VNC TCP port (headless pool instances). */
1159
+ vncPort?: number;
1160
+ /** Telnet serial console port (pool instances). */
1161
+ serialPort?: number;
1162
+ pid?: number;
1163
+ hdcReachable: boolean;
1164
+ bootCompleted: boolean;
1165
+ /** Pool instance state directory (overlays, instance.json, qemu.log). */
1166
+ dir?: string;
1167
+ logFile?: string;
1168
+ memory?: string;
1169
+ smp?: number;
1170
+ headless?: boolean;
1171
+ startedAt?: string;
1172
+ readyAt?: string;
1173
+ /** Seconds from launch to the first `ready` of this boot. */
1174
+ bootSeconds?: number;
1175
+ }
1176
+ /**
1177
+ * Status of pool instance `n`, probing hdc when QEMU is alive. Records the first
1178
+ * `ready` (and a later loss of hdc) in the instance's `instance.json`, which is what
1179
+ * tells `hdc-lost` apart from `booting`.
1180
+ */
1181
+ declare function getPoolInstanceStatus(config: ConfigProvider, n: number, opts?: {
1182
+ logger?: Logger;
1183
+ probeTimeoutMs?: number;
1184
+ }): Promise<EmulatorInstanceStatus>;
1185
+ /** Status of every pool instance that has a state directory, probed in parallel. */
1186
+ declare function listPoolInstanceStatuses(config: ConfigProvider, opts?: {
1187
+ logger?: Logger;
1188
+ probeTimeoutMs?: number;
1189
+ }): Promise<EmulatorInstanceStatus[]>;
1190
+ /**
1191
+ * Status of the default emulator (instance 0, launched by run.sh). Without a record
1192
+ * of an earlier `ready`, it is never `hdc-lost`; `stuck` counts from the PID file's
1193
+ * mtime, i.e. the launch.
1194
+ */
1195
+ declare function getDefaultInstanceStatus(config: ConfigProvider, opts: {
1196
+ running: boolean;
1197
+ address?: string;
1198
+ logger?: Logger;
1199
+ probeTimeoutMs?: number;
1200
+ bootTimeoutSeconds?: number;
1201
+ }): Promise<EmulatorInstanceStatus>;
1202
+ /** Whether `port` can be bound on `host` right now. */
1203
+ declare function isTcpPortFree(port: number, host?: string): Promise<boolean>;
1204
+ declare function readLogTail(filePath: string, bytes: number): string;
1205
+ interface StartPoolInstanceOptions {
1206
+ config: ConfigProvider;
1207
+ /** Pool instance number, 1..99. */
1208
+ instance: number;
1209
+ logger?: Logger;
1210
+ /** Virtual CPUs. Default {@link POOL_DEFAULT_SMP}. */
1211
+ smp?: number;
1212
+ /** RAM in QEMU's `-m` syntax. Default {@link POOL_DEFAULT_MEMORY}. */
1213
+ memory?: string;
1214
+ /** Display resolution, WxH. Default {@link POOL_DEFAULT_RESOLUTION}. */
1215
+ resolution?: string;
1216
+ /** VNC on 127.0.0.1:590n instead of a local SDL window. Default true. */
1217
+ headless?: boolean;
1218
+ /** Discard the instance's overlays first: a factory reset. */
1219
+ fresh?: boolean;
1220
+ /** Seconds after launch past which a boot that has not completed is `stuck`. Default 300. */
1221
+ bootTimeoutSeconds?: number;
1222
+ /** If > 0, wait up to this many seconds for `ready`. */
1223
+ waitReadySeconds?: number;
1224
+ /** Poll interval of that wait, ms. Default 5000. */
1225
+ pollIntervalMs?: number;
1226
+ /** QEMU binary. Default `QEMU_BIN`, else `qemu-system-x86_64` from PATH. */
1227
+ qemuBin?: string;
1228
+ /** qemu-img binary. Default: next to `qemuBin`, else from PATH. */
1229
+ qemuImg?: string;
1230
+ /** Accelerator. Default `auto` (KVM on Linux, as run.sh). */
1231
+ accel?: EmulatorAccel;
1232
+ /** QEMU's stdout/stderr. Default `<instance dir>/qemu.log`. */
1233
+ logFile?: string;
1234
+ /** How long QEMU must stay up after launch before it counts as started, ms. Default 2000. */
1235
+ earlyExitWindowMs?: number;
1236
+ abortSignal?: AbortSignal;
1237
+ }
1238
+ /**
1239
+ * Launch pool instance `n` (n >= 1): its own QEMU, detached, on copy-on-write
1240
+ * overlays of the bundled images, with hdc forwarded from 127.0.0.1:55555+n, VNC
1241
+ * on display n and the serial console on telnet 4444+n. The default emulator
1242
+ * (run.sh, instance 0) opens the same images read-write, so the two cannot run at
1243
+ * once; that is checked up front. If the instance is already running, nothing is
1244
+ * launched. Connects hdc with `hdc tconn` only; the hdc server is never restarted.
1245
+ */
1246
+ declare function startPoolInstance(opts: StartPoolInstanceOptions): Promise<EmulatorInstanceStatus>;
1247
+ interface WaitPoolInstanceReadyOptions {
1248
+ config: ConfigProvider;
1249
+ instance: number;
1250
+ timeoutSeconds: number;
1251
+ /** Default 5000. */
1252
+ pollIntervalMs?: number;
1253
+ logger?: Logger;
1254
+ abortSignal?: AbortSignal;
1255
+ }
1256
+ /**
1257
+ * Poll pool instance `n` until it is `ready`. Throws when QEMU exits (with the log
1258
+ * tail) or the timeout passes.
1259
+ */
1260
+ declare function waitPoolInstanceReady(opts: WaitPoolInstanceReadyOptions): Promise<EmulatorInstanceStatus>;
1261
+ interface StopPoolInstanceOptions {
1262
+ config: ConfigProvider;
1263
+ instance: number;
1264
+ /** Also delete the instance's directory: overlays, log and state. */
1265
+ discard?: boolean;
1266
+ logger?: Logger;
1267
+ /** How long to wait for QEMU to exit after SIGTERM before SIGKILL, ms. Default 15000. */
1268
+ killTimeoutMs?: number;
1269
+ }
1270
+ /**
1271
+ * Stop pool instance `n`: signal only its own QEMU (by the PID it recorded, checked
1272
+ * against the instance directory on Linux), drop its target from the hdc server with
1273
+ * `hdc tconn <address> -remove`, and with `discard` delete its overlays. Other
1274
+ * instances, the default emulator and every other QEMU are left alone. Resolves to
1275
+ * whether a running QEMU was stopped.
1276
+ */
1277
+ declare function stopPoolInstance(opts: StopPoolInstanceOptions): Promise<boolean>;
1278
+
772
1279
  /**
773
1280
  * Try to connect hdc to the emulator. Resolves true on success, false otherwise.
774
1281
  */
@@ -798,6 +1305,12 @@ interface StartEmulatorOptions {
798
1305
  waitForHdcSeconds?: number;
799
1306
  /** Poll interval for the hdc wait, ms. Default 5000. */
800
1307
  hdcPollIntervalMs?: number;
1308
+ /**
1309
+ * If > 0, block until the guest reports `bootevent.boot.completed=true` over hdc, up
1310
+ * to this many seconds. Connects with `hdc tconn` only: unlike `waitForHdcSeconds`,
1311
+ * it never restarts the hdc server, so other connected devices are not disturbed.
1312
+ */
1313
+ waitReadySeconds?: number;
801
1314
  abortSignal?: AbortSignal;
802
1315
  }
803
1316
  /**
@@ -813,12 +1326,17 @@ interface EmulatorStatus {
813
1326
  installed: boolean;
814
1327
  /** The configured emulator directory. */
815
1328
  dir: string;
816
- /** Whether an emulator QEMU process is alive. */
1329
+ /** Whether the default emulator's QEMU is alive (pool instances do not count). */
817
1330
  running: boolean;
818
1331
  /** The hdc address checked for `connected`. */
819
1332
  address: string;
820
1333
  /** hdc lists `address` as a Connected target. */
821
1334
  connected: boolean;
1335
+ /**
1336
+ * Every instance: the default emulator (instance 0, `address`) first, then each pool
1337
+ * instance that has a state directory, with its health code.
1338
+ */
1339
+ instances: EmulatorInstanceStatus[];
822
1340
  }
823
1341
  /**
824
1342
  * Report on the Oniro emulator without starting it: installed, running, and whether
@@ -830,6 +1348,66 @@ declare function getEmulatorStatus(config: ConfigProvider, opts?: {
830
1348
  logger?: Logger;
831
1349
  }): Promise<EmulatorStatus>;
832
1350
 
1351
+ /**
1352
+ * PID file of the default emulator (instance 0), the one `startEmulator` launches
1353
+ * through the bundled run.sh/run.bat.
1354
+ */
1355
+ declare const DEFAULT_EMULATOR_PID_FILE: string;
1356
+ /** Highest pool instance number `--instance` accepts. */
1357
+ declare const MAX_POOL_INSTANCE = 99;
1358
+ /** Whether a process with this PID exists (signal 0 probes without signalling). */
1359
+ declare function isPidAlive(pid: number | undefined): boolean;
1360
+ /** The PID of the default emulator (instance 0) when its PID file names a live process. */
1361
+ declare function readDefaultEmulatorPid(pidFile?: string): number | undefined;
1362
+ /** Throw unless `n` is a pool instance number (1..{@link MAX_POOL_INSTANCE}). */
1363
+ declare function assertPoolInstance(n: number): void;
1364
+ /** Where pool instances keep their state: `<emulatorDir>/instances`. */
1365
+ declare function poolRootDir(config: ConfigProvider): string;
1366
+ /** State directory of pool instance `n`: overlays, `instance.json`, `qemu.log`. */
1367
+ declare function poolInstanceDir(config: ConfigProvider, n: number): string;
1368
+ /** Size and mtime of a base image when its overlay was created; a change means the overlay is stale. */
1369
+ interface BaseImageFingerprint {
1370
+ size: number;
1371
+ mtimeMs: number;
1372
+ }
1373
+ /** What `instance.json` records about a pool instance. */
1374
+ interface PoolInstanceState {
1375
+ instance: number;
1376
+ /** QEMU's PID while it runs. */
1377
+ pid?: number;
1378
+ hdcPort: number;
1379
+ vncDisplay: number;
1380
+ serialPort: number;
1381
+ memory: string;
1382
+ smp: number;
1383
+ resolution: string;
1384
+ headless: boolean;
1385
+ /** Seconds after `startedAt` past which a boot that never reached `ready` is `stuck`. */
1386
+ bootTimeoutSeconds: number;
1387
+ /** ISO time QEMU was launched. */
1388
+ startedAt?: string;
1389
+ /** ISO time this boot was first seen ready (`bootevent.boot.completed=true`). */
1390
+ readyAt?: string;
1391
+ /** ISO time hdc was first seen unable to reach the instance after it had been ready. */
1392
+ lostAt?: string;
1393
+ logFile: string;
1394
+ /** Base image name (e.g. `userdata.img`) → fingerprint at overlay creation. */
1395
+ bases?: Record<string, BaseImageFingerprint>;
1396
+ }
1397
+ declare function stateFile(dir: string): string;
1398
+ declare function readPoolState(dir: string): PoolInstanceState | undefined;
1399
+ declare function writePoolState(dir: string, state: PoolInstanceState): void;
1400
+ /**
1401
+ * Whether `pid` is the QEMU of the instance in `dir`. On Linux the command line must
1402
+ * name the directory, so a PID the OS recycled for another process is not mistaken
1403
+ * for the instance (and never signalled); elsewhere only liveness is checked.
1404
+ */
1405
+ declare function isInstanceProcess(pid: number | undefined, dir: string): boolean;
1406
+ /** Instance numbers that have a state directory, ascending. */
1407
+ declare function listPoolInstanceNumbers(config: ConfigProvider): number[];
1408
+ /** PIDs of pool instances whose QEMU is alive. */
1409
+ declare function livePoolPids(config: ConfigProvider): Map<number, number>;
1410
+
833
1411
  /**
834
1412
  * True when `command` must be routed through `cmd.exe` to run at all —
835
1413
  * i.e. we are on Windows and the target is a batch wrapper.
@@ -1369,6 +1947,156 @@ declare function sendGesture(opts: SendGestureOptions): Promise<void>;
1369
1947
  */
1370
1948
  declare function sendRawTouch(opts: SendRawTouchOptions): Promise<void>;
1371
1949
 
1950
+ /** A `--selector` expression (attribute DSL or XPath) that does not parse. */
1951
+ declare class SelectorParseError extends OniroError {
1952
+ /** Offset into `input` where parsing stopped. */
1953
+ readonly position: number;
1954
+ readonly input: string;
1955
+ constructor(detail: string,
1956
+ /** Offset into `input` where parsing stopped. */
1957
+ position: number, input: string);
1958
+ }
1959
+ /**
1960
+ * The element attributes a `--selector` expression (DSL key or XPath `@name`)
1961
+ * can test, read off the pruned tree `dump layout` prints. Strings compare as
1962
+ * they appear there; the boolean ones are always present as "true" or "false".
1963
+ */
1964
+ declare const SELECTOR_KEYS: readonly ["text", "desc", "hint", "id", "key", "type", "enabled", "focused", "checked", "selected", "visible", "clickable", "longClickable", "checkable", "scrollable"];
1965
+ type SelectorKey = (typeof SELECTOR_KEYS)[number];
1966
+ /** The canonical key for `name` (`description` is `desc`), or undefined when it is not one. */
1967
+ declare function resolveSelectorKey(name: string): SelectorKey | undefined;
1968
+ /**
1969
+ * The value of a selector attribute on a node. `key` falls back to `id` (the
1970
+ * pruned tree drops a key equal to the id); `enabled` is the inverse of
1971
+ * `disabled`; `visible` means drawn and not covered by an overlay.
1972
+ */
1973
+ declare function selectorAttribute(n: FlatLayoutNode, key: SelectorKey): string | undefined;
1974
+ /** A layout node's own fields, tagged with its enclosing window's bundle and id. */
1975
+ declare function flatLayoutNode(n: LayoutNode, window: string | undefined, windowId: number | undefined): FlatLayoutNode;
1976
+ /** The node carries fields of its own, not just children. */
1977
+ declare function hasOwnFields(n: LayoutNode): boolean;
1978
+ /** A pruned layout node with links to its parent and children, for selector and XPath evaluation. */
1979
+ interface IndexedLayoutNode {
1980
+ flat: FlatLayoutNode;
1981
+ parent: IndexedLayoutNode | null;
1982
+ children: IndexedLayoutNode[];
1983
+ /** Position in depth-first (paint) order. */
1984
+ order: number;
1985
+ /** A bare container: no fields of its own (it never matches a selector). */
1986
+ empty: boolean;
1987
+ }
1988
+ /** Link up a pruned tree; returns its root. Depth-first order matches {@link flattenLayout}. */
1989
+ declare function indexLayout(tree: LayoutNode): IndexedLayoutNode;
1990
+ /** Every node of an indexed tree, depth-first. */
1991
+ declare function allIndexed(root: IndexedLayoutNode): IndexedLayoutNode[];
1992
+
1993
+ type Expr = {
1994
+ k: 'or' | 'and';
1995
+ a: Expr;
1996
+ b: Expr;
1997
+ } | {
1998
+ k: 'cmp';
1999
+ op: CmpOp;
2000
+ a: Expr;
2001
+ b: Expr;
2002
+ } | {
2003
+ k: 'attr';
2004
+ key: SelectorKey;
2005
+ } | {
2006
+ k: 'str';
2007
+ v: string;
2008
+ } | {
2009
+ k: 'num';
2010
+ v: number;
2011
+ } | {
2012
+ k: 'fn';
2013
+ name: FnName;
2014
+ args: Expr[];
2015
+ };
2016
+ type CmpOp = '=' | '!=' | '<' | '<=' | '>' | '>=';
2017
+ type FnName = 'contains' | 'starts-with' | 'ends-with' | 'not' | 'position' | 'last';
2018
+ type Step = {
2019
+ axis: 'child' | 'descendant';
2020
+ name: string;
2021
+ predicates: Expr[];
2022
+ } | {
2023
+ axis: 'self' | 'descendant-or-self' | 'parent';
2024
+ };
2025
+ /** A parsed XPath expression (see {@link parseXPath}). */
2026
+ interface XPathExpression {
2027
+ /** The source text. */
2028
+ readonly source: string;
2029
+ /** Where evaluation starts: the document, or a parenthesised path filtered by predicates. */
2030
+ readonly start: {
2031
+ group: XPathExpression;
2032
+ predicates: Expr[];
2033
+ } | 'root';
2034
+ readonly steps: readonly Step[];
2035
+ }
2036
+ /** Parse an XPath expression in the supported subset; throws {@link SelectorParseError}. */
2037
+ declare function parseXPath(source: string): XPathExpression;
2038
+ /**
2039
+ * Evaluate an XPath expression (source text or {@link parseXPath} result) over
2040
+ * a pruned layout tree. Returns the matching nodes in paint order, tagged with
2041
+ * their window; bare containers are never returned.
2042
+ */
2043
+ declare function evaluateXPath(tree: LayoutNode, expr: XPathExpression | string): FlatLayoutNode[];
2044
+
2045
+ /** `=` equals, `*=` contains, `^=` starts with, `$=` ends with, `/=` matches a regular expression. */
2046
+ type SelectorOperator = '=' | '*=' | '^=' | '$=' | '/=';
2047
+ interface SelectorClause {
2048
+ key: SelectorKey;
2049
+ op: SelectorOperator;
2050
+ value: string;
2051
+ /** Regular-expression flags, for `/=` (`text/=^sign/i`). */
2052
+ flags?: string;
2053
+ }
2054
+ /** `type=Button,text*=Sign[1]`: every clause must hold; `index` picks one match. */
2055
+ interface DslSelector {
2056
+ kind: 'dsl';
2057
+ clauses: SelectorClause[];
2058
+ /** 0-based index into the matches in paint order; negative counts from the end (`[last]` is -1). */
2059
+ index?: number;
2060
+ raw: string;
2061
+ }
2062
+ /** `xpath=//Button[@text="OK"]`. */
2063
+ interface XPathSelector {
2064
+ kind: 'xpath';
2065
+ xpath: XPathExpression;
2066
+ raw: string;
2067
+ }
2068
+ /** A parsed `--selector` expression. */
2069
+ type ElementSelector = DslSelector | XPathSelector;
2070
+ /**
2071
+ * Parse a `--selector` expression: `xpath=<expr>` (see ./xpath.ts for the
2072
+ * subset), or the attribute DSL `key<op>value[,key<op>value…][n]` with keys
2073
+ * from {@link SELECTOR_KEYS}. Throws {@link SelectorParseError}.
2074
+ */
2075
+ declare function parseSelector(input: string): ElementSelector;
2076
+ /** Whether one clause holds on a node. String comparisons are case-sensitive. */
2077
+ declare function clauseMatches(n: FlatLayoutNode, clause: SelectorClause): boolean;
2078
+ /**
2079
+ * Every node of a pruned layout tree matching `selector`, in paint order,
2080
+ * tagged with its window. The DSL index suffix is not applied here (callers
2081
+ * pick with it); bare containers never match.
2082
+ */
2083
+ declare function matchSelector(tree: LayoutNode, selector: ElementSelector): FlatLayoutNode[];
2084
+ /** Render DSL clauses (and an index) back into `--selector` text that {@link parseSelector} reads back. */
2085
+ declare function formatSelector(clauses: readonly SelectorClause[], index?: number): string;
2086
+ /** The recorded attributes of an element, as `dump layout` / `wait --json` print them. */
2087
+ type RecordedElement = Partial<FlatLayoutNode>;
2088
+ /**
2089
+ * The most specific stable `--selector` for a recorded element: the first of
2090
+ * `type` plus one of id, key, text, desc or hint (in that order of
2091
+ * stability), then type plus every stable attribute it has, that matches
2092
+ * exactly this element in `tree`; failing that, the full clause set with the
2093
+ * element's `[n]` index among its matches. Exact (`=`) clauses only, so the
2094
+ * selector does not drift onto similar elements. The element is found in
2095
+ * `tree` by its type, id, key and labels (nearest `c` breaks a tie); throws
2096
+ * when it is not there. Pure — the replay side of `record` (O-9) builds on it.
2097
+ */
2098
+ declare function selectorFor(tree: LayoutNode, element: RecordedElement): string;
2099
+
1372
2100
  /** A raw `uitest dumpLayout` node (attributes are strings). */
1373
2101
  interface RawLayoutNode {
1374
2102
  attributes?: Record<string, string>;
@@ -1397,6 +2125,13 @@ interface LayoutNode {
1397
2125
  longClick?: boolean;
1398
2126
  /** The component is disabled (`enabled: false`). */
1399
2127
  disabled?: boolean;
2128
+ /** The component is not drawn (`visible: false`). */
2129
+ hidden?: boolean;
2130
+ /**
2131
+ * Set on the node where a window starts: its window id (uitest's
2132
+ * `hostWindowId`, the `WinId` column of `hidumper -s WindowManagerService -a -a`).
2133
+ */
2134
+ windowId?: number;
1400
2135
  /** The node's center is painted over by a later filled node (an overlay, a
1401
2136
  * dialog scrim, the soft keyboard), so a tap there would land on that instead. */
1402
2137
  covered?: boolean;
@@ -1436,14 +2171,36 @@ declare function findCoveredNodes(root: RawLayoutNode): Set<RawLayoutNode>;
1436
2171
  * from the proven MCP `pruneNode`; `covered` (from {@link findCoveredNodes})
1437
2172
  * marks nodes hidden under an overlay.
1438
2173
  */
1439
- declare function pruneLayout(node: RawLayoutNode, display: DisplaySize | null, covered?: ReadonlySet<RawLayoutNode>): LayoutNode | LayoutNode[] | null;
2174
+ declare function pruneLayout(node: RawLayoutNode, display: DisplaySize | null, covered?: ReadonlySet<RawLayoutNode>, parentWindow?: string): LayoutNode | LayoutNode[] | null;
1440
2175
  /** A pruned layout node without children, tagged with the window it belongs to. */
1441
2176
  interface FlatLayoutNode extends Omit<LayoutNode, 'children'> {
1442
2177
  /** Bundle of the enclosing window (the nearest node carrying `bundle`). */
1443
2178
  window?: string;
2179
+ /** Id of the enclosing window (the nearest node carrying `windowId`). */
2180
+ windowId?: number;
1444
2181
  }
1445
2182
  /** Flatten a pruned layout tree into a depth-first (paint-order) list. */
1446
2183
  declare function flattenLayout(tree: LayoutNode): FlatLayoutNode[];
2184
+ /** A window found in a pruned layout tree. */
2185
+ interface LayoutWindow {
2186
+ windowId: number;
2187
+ /** Bundle owning the window, when uitest reports one. */
2188
+ bundle?: string;
2189
+ /** Bounds [x1,y1,x2,y2] normalized to 0–1 of the display. */
2190
+ b?: [number, number, number, number];
2191
+ }
2192
+ /** The windows in a pruned layout tree, in paint order. Pure. */
2193
+ declare function listLayoutWindows(tree: LayoutNode): LayoutWindow[];
2194
+ /**
2195
+ * The part of a pruned tree that belongs to window `windowId`, under an empty
2196
+ * root like a full dump's, or null when the window is not in the tree. Windows
2197
+ * nested inside it are left out. Pure.
2198
+ */
2199
+ declare function windowSubtree(tree: LayoutNode, windowId: number): LayoutNode | null;
2200
+ /** The same as {@link windowSubtree}, on a raw (unpruned) `uitest dumpLayout` tree. */
2201
+ declare function rawWindowSubtree(tree: RawLayoutNode, windowId: number): RawLayoutNode | null;
2202
+ /** The error for a `--window` that is not in the layout, listing the windows that are. */
2203
+ declare function windowNotFoundError(windows: readonly LayoutWindow[], windowId: number): OniroError;
1447
2204
  /** Selects layout nodes by what an agent can read off the screen. */
1448
2205
  interface LayoutSelector {
1449
2206
  /** Matches `text`, `desc`, or `hint`: case-insensitive exact matches win; otherwise substring matches. */
@@ -1453,8 +2210,18 @@ interface LayoutSelector {
1453
2210
  /** Restricts to a component type (e.g. `Button`, `TextInput`); case-insensitive. */
1454
2211
  type?: string;
1455
2212
  }
1456
- /** Throw unless `selector` constrains something: a non-blank text, an id, or a type. */
1457
- declare function assertLayoutSelector(selector: LayoutSelector): void;
2213
+ /**
2214
+ * What to look for: the plain `--target` fields ({@link LayoutSelector}) or a
2215
+ * parsed `--selector` expression ({@link ElementSelector}: the attribute DSL or XPath).
2216
+ */
2217
+ type ElementQuery = LayoutSelector | ElementSelector;
2218
+ /** The query is a parsed `--selector` expression rather than plain `--target` fields. */
2219
+ declare function isElementSelector(q: ElementQuery): q is ElementSelector;
2220
+ /**
2221
+ * Throw unless `selector` constrains something: a non-blank text, an id, or a
2222
+ * type. A parsed {@link ElementSelector} always does.
2223
+ */
2224
+ declare function assertLayoutSelector(selector: ElementQuery): void;
1458
2225
  /**
1459
2226
  * The tree without the windows owned by `bundle` — e.g. the soft keyboard, whose
1460
2227
  * keys ("Done", "9") would otherwise match element selectors. Pure.
@@ -1464,9 +2231,11 @@ declare function withoutWindow(tree: LayoutNode, bundle: string): LayoutNode;
1464
2231
  * Find the nodes matching `selector` in a pruned layout tree, in paint order.
1465
2232
  * For `text`, exact (case-insensitive, trimmed) matches are returned when any
1466
2233
  * exist; otherwise substring matches. Covered nodes are included — callers
1467
- * decide what to do with them (see {@link pickTarget}).
2234
+ * decide what to do with them (see {@link pickTarget}). A parsed
2235
+ * {@link ElementSelector} returns every match ({@link matchSelector}); its
2236
+ * index suffix is applied by {@link pickTarget} and {@link findVisibleMatch}.
1468
2237
  */
1469
- declare function findLayoutNodes(tree: LayoutNode, selector: LayoutSelector): FlatLayoutNode[];
2238
+ declare function findLayoutNodes(tree: LayoutNode, selector: ElementQuery): FlatLayoutNode[];
1470
2239
  /** One-line summary of a node, used in errors and logs. */
1471
2240
  declare function describeLayoutNode(n: FlatLayoutNode): string;
1472
2241
  /** Why {@link pickTarget} could not choose a node. */
@@ -1475,18 +2244,34 @@ declare class TargetNotFoundError extends OniroError {
1475
2244
  readonly reason: PickTargetFailure;
1476
2245
  constructor(message: string, reason: PickTargetFailure);
1477
2246
  }
2247
+ /**
2248
+ * The first uncovered node matching `selector`, or null. When a DSL selector
2249
+ * carries an index (`[n]`), only that match counts, and only while uncovered.
2250
+ */
2251
+ declare function findVisibleMatch(tree: LayoutNode, selector: ElementQuery): FlatLayoutNode | null;
1478
2252
  /**
1479
2253
  * Choose the single node to act on for `selector`. Covered nodes are skipped;
1480
2254
  * clickable matches are preferred over plain ones (a "Sign in" Button over the
1481
2255
  * "Sign in" title); a match nested inside another clickable match collapses
1482
2256
  * into it. `index` picks among what remains, in paint order. Throws
1483
2257
  * {@link TargetNotFoundError} when nothing (or more than one node) qualifies.
2258
+ *
2259
+ * For a parsed selector with an index (the DSL's `[n]` suffix, or `index`),
2260
+ * the index picks from every match in paint order, the list
2261
+ * `dump layout --selector` prints, and that element must be on screen and
2262
+ * uncovered; the preferences above do not apply.
1484
2263
  */
1485
- declare function pickTarget(tree: LayoutNode, selector: LayoutSelector, index?: number): FlatLayoutNode;
2264
+ declare function pickTarget(tree: LayoutNode, selector: ElementQuery, index?: number): FlatLayoutNode;
1486
2265
  interface DumpLayoutOptions {
1487
2266
  config: ConfigProvider;
1488
2267
  /** Filter to a single window/bundle (`uitest dumpLayout -b '<bundle>'`). */
1489
2268
  bundleName?: string;
2269
+ /**
2270
+ * Keep only this window (an id from `dump windows`, or a `windowId` in the
2271
+ * layout). The whole screen is still dumped, so overlays from other windows
2272
+ * still mark nodes covered and the soft keyboard is still detected.
2273
+ */
2274
+ windowId?: number;
1490
2275
  /** When false, return the parsed-but-unpruned tree. Default true. */
1491
2276
  prune?: boolean;
1492
2277
  /**
@@ -1504,6 +2289,33 @@ interface DumpLayoutOptions {
1504
2289
  */
1505
2290
  declare function dumpLayout(opts: DumpLayoutOptions): Promise<DumpLayoutResult>;
1506
2291
 
2292
+ /** A row of the `hidumper -s WindowManagerService -a -a` window table. */
2293
+ interface WindowInfo {
2294
+ /** `WinId`: what `--window` takes, and the `windowId` in `dump layout`. */
2295
+ id: number;
2296
+ /** `WindowName`, which hidumper cuts to 20 characters. */
2297
+ name: string;
2298
+ displayId: number;
2299
+ pid: number;
2300
+ /** Window type: 1 is an app's main window; 2000 and up are system windows. */
2301
+ type: number;
2302
+ /** Stacking order; -1 for a window that is not shown. */
2303
+ zOrder: number;
2304
+ /** [x, y, width, height] in device pixels. */
2305
+ rect?: [number, number, number, number];
2306
+ /** It is the `Focus window`. */
2307
+ focused: boolean;
2308
+ }
2309
+ /** Parse the window table of `hidumper -s WindowManagerService -a -a`. Pure. */
2310
+ declare function parseWindowList(raw: string): WindowInfo[];
2311
+ interface ListWindowsOptions {
2312
+ config: ConfigProvider;
2313
+ deviceSerial?: string;
2314
+ logger?: Logger;
2315
+ }
2316
+ /** List the device's windows (shown ones first, in the order hidumper prints them). */
2317
+ declare function listWindows(opts: ListWindowsOptions): Promise<WindowInfo[]>;
2318
+
1507
2319
  /**
1508
2320
  * Extract input-method bundle names from `hidumper -s 3703 -a -a` output, whose
1509
2321
  * `imeList` entries look like `"ime": "com.example.kikakeyboard/ServiceExtAbility"`.
@@ -1527,6 +2339,12 @@ declare function findKeyboardWindow(tree: LayoutNode, imeBundles: readonly strin
1527
2339
 
1528
2340
  /** `uitest uiInput` actions plus the composite ones built on top of them. */
1529
2341
  type UiInputType = InputType | 'clearText' | 'hideKeyboard';
2342
+ /**
2343
+ * What selectors search (input, wait, screenshot and `dump layout --selector`):
2344
+ * the tree minus the soft-keyboard window, whose keys are not targets, unless
2345
+ * the caller restricted the dump to one window, which is then the one asked for.
2346
+ */
2347
+ declare function selectableTree(layout: DumpLayoutResult, windowId?: number): DumpLayoutResult['tree'];
1530
2348
  interface DeviceOptions {
1531
2349
  config: ConfigProvider;
1532
2350
  deviceSerial?: string;
@@ -1538,9 +2356,12 @@ interface DeviceOptions {
1538
2356
  */
1539
2357
  declare function hideKeyboard(opts: DeviceOptions): Promise<boolean>;
1540
2358
  interface LocateTargetOptions extends DeviceOptions {
1541
- selector: LayoutSelector;
2359
+ /** `--target` fields, or a parsed `--selector` expression (see {@link parseSelector}). */
2360
+ selector: ElementQuery;
1542
2361
  /** Picks among several matching elements (see {@link pickTarget}). */
1543
2362
  index?: number;
2363
+ /** Only look in this window (see {@link DumpLayoutOptions.windowId}). */
2364
+ windowId?: number;
1544
2365
  /**
1545
2366
  * When the soft keyboard is up and the target is missing, covered, or matches
1546
2367
  * only a non-clickable label (the button may be hidden below the keyboard),
@@ -1576,10 +2397,12 @@ interface PerformInputOptions extends DeviceOptions {
1576
2397
  /** End point as 0–1 fractions of the display. */
1577
2398
  fx2?: number;
1578
2399
  fy2?: number;
1579
- /** Start point: the center of the element matching this selector. */
1580
- target?: LayoutSelector;
2400
+ /** Start point: the center of the element matching this selector (`--target` fields or a parsed `--selector`). */
2401
+ target?: ElementQuery;
1581
2402
  /** Picks among several elements matching `target`. */
1582
2403
  targetIndex?: number;
2404
+ /** Look for `target` only in this window. */
2405
+ windowId?: number;
1583
2406
  /** Velocity for swipe/drag/fling. */
1584
2407
  speed?: number;
1585
2408
  /** Key for keyEvent (see `resolveKeyEvent`). */
@@ -1608,7 +2431,10 @@ interface PerformInputResult {
1608
2431
  */
1609
2432
  declare function performInput(opts: PerformInputOptions): Promise<PerformInputResult>;
1610
2433
  interface WaitForTargetOptions extends DeviceOptions {
1611
- selector: LayoutSelector;
2434
+ /** `--target` fields, or a parsed `--selector` expression. */
2435
+ selector: ElementQuery;
2436
+ /** Only look in this window; while it is not on screen nothing matches. */
2437
+ windowId?: number;
1612
2438
  /** Wait until no uncovered element matches, instead of until one does. */
1613
2439
  gone?: boolean;
1614
2440
  timeoutMs: number;
@@ -1619,7 +2445,8 @@ interface WaitForTargetOptions extends DeviceOptions {
1619
2445
  /**
1620
2446
  * Poll the layout until an uncovered element matches `selector` (resolving with
1621
2447
  * it), or with `gone`, until none does (resolving null). Keys on the soft
1622
- * keyboard are ignored. Throws on timeout.
2448
+ * keyboard are ignored. A DSL selector's `[n]` waits for that match. Throws on
2449
+ * timeout.
1623
2450
  */
1624
2451
  declare function waitForTarget(opts: WaitForTargetOptions): Promise<FlatLayoutNode | null>;
1625
2452
 
@@ -1928,6 +2755,300 @@ interface DumpLogOptions {
1928
2755
  */
1929
2756
  declare function dumpLog(opts: DumpLogOptions): Promise<HilogEntry[]>;
1930
2757
 
2758
+ /** The power manager's state, as `hidumper -s 3301` prints it: AWAKE, DIM, INACTIVE, SLEEP, … */
2759
+ declare function parsePowerState(hidumperOutput: string): string | null;
2760
+ /** The SceneBoard lock screen is on top: its root component is in the layout. */
2761
+ declare function isLockScreenShown(tree: LayoutNode): boolean;
2762
+ interface WakeScreenOptions {
2763
+ config: ConfigProvider;
2764
+ deviceSerial?: string;
2765
+ logger?: Logger;
2766
+ }
2767
+ interface WakeScreenResult {
2768
+ /** The device was not AWAKE and `power-shell wakeup` was sent. */
2769
+ woke: boolean;
2770
+ /** The lock screen was swiped away. */
2771
+ unlocked: boolean;
2772
+ /** The lock screen is still shown after the swipe: it needs a PIN, password or pattern. */
2773
+ locked: boolean;
2774
+ }
2775
+ /**
2776
+ * Turn the screen on and swipe away a lock screen that has no credential, so UI
2777
+ * tests and input reach the app. A lock screen that asks for a credential stays
2778
+ * (`locked: true`). Best effort: a check that fails is treated as "nothing to do".
2779
+ */
2780
+ declare function wakeAndUnlock(opts: WakeScreenOptions): Promise<WakeScreenResult>;
2781
+ /**
2782
+ * Keep the screen on for `ms` (`power-shell timeout -o`), so a long run does not
2783
+ * let it turn off; returns a function that restores the configured timeout.
2784
+ */
2785
+ declare function holdScreenOn(opts: WakeScreenOptions & {
2786
+ ms: number;
2787
+ }): Promise<() => Promise<void>>;
2788
+
2789
+ type Box = [number, number, number, number];
2790
+ /** Window name used for nodes outside any bundle window. */
2791
+ declare const NO_WINDOW = "(none)";
2792
+ /** Counts for one window of a layout. */
2793
+ interface LayoutWindowSummary {
2794
+ /** Bundle owning the window, or `(none)` for nodes outside any bundle window. */
2795
+ window: string;
2796
+ /** Pruned elements in the window. */
2797
+ elements: number;
2798
+ /** Elements that carry something to read: text, description, placeholder, or an image. */
2799
+ content: number;
2800
+ /** Clickable elements. */
2801
+ clickable: number;
2802
+ /** Elements with non-empty text. */
2803
+ text: number;
2804
+ }
2805
+ interface LayoutSummary {
2806
+ display: DumpLayoutResult['display'];
2807
+ windows: LayoutWindowSummary[];
2808
+ /** The same counts over the whole layout. */
2809
+ total: Omit<LayoutWindowSummary, 'window'>;
2810
+ /** Present when the dump detected the soft keyboard. */
2811
+ keyboard?: DumpLayoutResult['keyboard'];
2812
+ }
2813
+ /** Per-window element, content, clickable and text counts of a pruned layout. Pure. */
2814
+ declare function summarizeLayout(layout: DumpLayoutResult): LayoutSummary;
2815
+ /** How a baseline element was paired with a current one. */
2816
+ type LayoutMatchKind = 'id' | 'key' | 'text' | 'type';
2817
+ /** The identifying fields of an element, as reported in a diff. */
2818
+ interface LayoutDiffNode {
2819
+ window?: string;
2820
+ type?: string;
2821
+ id?: string;
2822
+ key?: string;
2823
+ text?: string;
2824
+ desc?: string;
2825
+ hint?: string;
2826
+ /** Bounds as 0-1 fractions of the display. */
2827
+ b?: Box;
2828
+ }
2829
+ interface LayoutMatch {
2830
+ by: LayoutMatchKind;
2831
+ baseline: LayoutDiffNode;
2832
+ current: LayoutDiffNode;
2833
+ /** Intersection over union of the two boxes (1 = same place and size). */
2834
+ iou: number;
2835
+ /** Fields whose value differs (`text`, `type`, `click`, `disabled`, `checked`, …). */
2836
+ changed: string[];
2837
+ }
2838
+ interface LayoutDiff {
2839
+ /**
2840
+ * 0-1: the sum, over matched pairs, of their IoU (halved when a field
2841
+ * changed), divided by matched + missing + extra. 1 = the same layout.
2842
+ */
2843
+ similarity: number;
2844
+ matched: LayoutMatch[];
2845
+ /** Baseline elements with no counterpart now. */
2846
+ missing: LayoutDiffNode[];
2847
+ /** Current elements with no counterpart in the baseline. */
2848
+ extra: LayoutDiffNode[];
2849
+ /** Matched pairs that moved (IoU under 0.9) or changed a field. */
2850
+ moved: number;
2851
+ changed: number;
2852
+ counts: {
2853
+ baseline: number;
2854
+ current: number;
2855
+ };
2856
+ }
2857
+ /** Matched pairs with an IoU under this are reported as moved. */
2858
+ declare const LAYOUT_MOVED_IOU = 0.9;
2859
+ /** Intersection over union of two 0-1 boxes; 1 when neither has a box, 0 when only one has. */
2860
+ declare function boxIoU(a: Box | undefined, b: Box | undefined): number;
2861
+ /** Accept a `dump layout` result, or a bare pruned tree. Throws on a `--raw` dump. */
2862
+ declare function parseLayoutBaseline(json: unknown): DumpLayoutResult;
2863
+ /**
2864
+ * Compare two pruned layouts. Elements are paired within the same window by
2865
+ * id, then key, then label (text, description or placeholder) and type, then
2866
+ * type with overlapping boxes; each rule pairs greedily by highest IoU. Boxes
2867
+ * are the dump's 0-1 fractions of the display, so layouts from screens of
2868
+ * different resolution compare. Pure.
2869
+ */
2870
+ declare function diffLayouts(baseline: DumpLayoutResult, current: DumpLayoutResult): LayoutDiff;
2871
+
2872
+ /** A decoded 8-bit greyscale image, row-major, one byte per pixel. */
2873
+ interface GreyImage {
2874
+ width: number;
2875
+ height: number;
2876
+ data: Uint8Array;
2877
+ }
2878
+ /** Bits in a {@link pHash} / {@link dHash}. */
2879
+ declare const HASH_BITS = 64;
2880
+ /** A frame whose pHash is this close to a flat frame's is blank (deveco-cli's threshold)… */
2881
+ declare const BLANK_PHASH_DISTANCE = 10;
2882
+ /**
2883
+ * …provided its grey levels barely vary. A pattern that varies in one
2884
+ * direction only (full-width bands) also has a sparse DCT and hashes close to
2885
+ * flat, so the hash alone is not enough.
2886
+ */
2887
+ declare const BLANK_MAX_STDDEV = 10;
2888
+ /**
2889
+ * A frame where at least this share of the app area is the background colour
2890
+ * is blank, whatever its hash says. A "Hello World" page leaves about 1 % of
2891
+ * the area as ink, so the bar sits well above it.
2892
+ */
2893
+ declare const BLANK_BACKGROUND_SHARE = 0.998;
2894
+ /**
2895
+ * Resample to `width`x`height` by area averaging (each output pixel is the
2896
+ * mean of the source pixels it covers), which keeps thin features such as text
2897
+ * as a faint mark instead of dropping them.
2898
+ */
2899
+ declare function resizeGrey(img: GreyImage, width: number, height: number): GreyImage;
2900
+ /** The rows from `top` to `bottom` (fractions 0-1 of the height). */
2901
+ declare function cropRows(img: GreyImage, top: number, bottom: number): GreyImage;
2902
+ /** Hamming distance between two equal-length hex hashes (0 = identical, 64 = every bit differs). */
2903
+ declare function hammingDistance(a: string, b: string): number;
2904
+ /**
2905
+ * 64-bit DCT perceptual hash as 16 hex digits: the image reduced to 32x32, its
2906
+ * orthonormal DCT, the 8x8 lowest frequencies compared with their median (the
2907
+ * DC term left out of the median). Coefficients under one grey level count as
2908
+ * zero, so a flat frame with compression noise still hashes as flat.
2909
+ */
2910
+ declare function pHash(img: GreyImage): string;
2911
+ /**
2912
+ * 64-bit difference hash as 16 hex digits: the image reduced to 9x8, one bit
2913
+ * per horizontally adjacent pair (left brighter than right). Cheaper than the
2914
+ * pHash and more sensitive to small shifts.
2915
+ */
2916
+ declare function dHash(img: GreyImage): string;
2917
+ /** pHash of a flat (single-colour) frame; every flat frame hashes the same. */
2918
+ declare function flatFrameHash(): string;
2919
+ /**
2920
+ * Share (0-1) of pixels whose grey level moved by more than `threshold`
2921
+ * (default 24 of 255), with both images reduced to a common thumbnail.
2922
+ */
2923
+ declare function pixelChangeRatio(a: GreyImage, b: GreyImage, threshold?: number): number;
2924
+ interface ImageComparison {
2925
+ /** pHash Hamming distance, 0-64 (0 = perceptually identical). */
2926
+ phashDistance: number;
2927
+ /** dHash Hamming distance, 0-64. */
2928
+ dhashDistance: number;
2929
+ /** Share (0-1) of pixels that changed by more than 24 grey levels. */
2930
+ pixelChangeRatio: number;
2931
+ /** The two images have different dimensions (compared after scaling to a common size). */
2932
+ sizeMismatch: boolean;
2933
+ /** Both hashes within 4 bits and under 1 % of pixels changed. */
2934
+ same: boolean;
2935
+ }
2936
+ /** Thresholds behind {@link ImageComparison.same}. */
2937
+ declare const SAME_MAX_HASH_DISTANCE = 4;
2938
+ declare const SAME_MAX_CHANGE_RATIO = 0.01;
2939
+ /** Compare two screenshots: perceptual-hash distances plus the share of pixels that changed. */
2940
+ declare function compareImages(baseline: GreyImage, current: GreyImage): ImageComparison;
2941
+ interface BlankAnalysis {
2942
+ /** The app area shows nothing: flat by pHash with little variance, or almost all one colour. */
2943
+ blank: boolean;
2944
+ /** Share (0-1) of the app area within 24 grey levels of its dominant colour; 1 = a flat frame. */
2945
+ blankScore: number;
2946
+ /** pHash Hamming distance from a flat frame (0-64); at most 10 is blank. */
2947
+ phashDistance: number;
2948
+ /** Standard deviation of the app area's grey levels (0 = flat). */
2949
+ stdDev: number;
2950
+ /** The dominant grey level (0-255) of the app area. */
2951
+ background: number;
2952
+ }
2953
+ /**
2954
+ * Whether a screenshot shows a blank app: the status and navigation bars are
2955
+ * cropped off (top 6 %, bottom 4 %), then the frame is blank when its pHash is
2956
+ * within {@link BLANK_PHASH_DISTANCE} bits of a flat frame's and its standard
2957
+ * deviation is at most {@link BLANK_MAX_STDDEV}, or when at least
2958
+ * {@link BLANK_BACKGROUND_SHARE} of it is the dominant colour.
2959
+ */
2960
+ declare function analyzeBlank(img: GreyImage): BlankAnalysis;
2961
+
2962
+ /** Default wait between the process appearing and the screenshot. */
2963
+ declare const DEFAULT_SMOKE_DELAY_MS = 2000;
2964
+ /** Default deadline for the process to appear after launch. */
2965
+ declare const DEFAULT_SMOKE_PID_TIMEOUT_MS = 10000;
2966
+ /** Decodes a JPEG screenshot to greyscale. Core decodes no images; the CLI passes a sharp-based one. */
2967
+ type GreyscaleDecoder = (jpeg: Buffer) => Promise<GreyImage>;
2968
+ /** What a {@link SmokeCrashProbe} is asked: was there a crash of `bundle` since `since`? */
2969
+ interface SmokeCrashProbeArgs {
2970
+ config: ConfigProvider;
2971
+ bundle: string;
2972
+ /** When the launch started; only crashes at or after it count. */
2973
+ since: Date;
2974
+ /**
2975
+ * Whether the launched process is still the one that started. A probe can
2976
+ * wait for a faultlog when it is not (hiview writes it seconds after the
2977
+ * death) and look only once when it is.
2978
+ */
2979
+ alive: boolean;
2980
+ deviceSerial?: string;
2981
+ logger?: Logger;
2982
+ }
2983
+ /**
2984
+ * Crash-detection hook. Resolve a description of the newest crash (cpp_crash,
2985
+ * js_crash, app_freeze, …) of the bundle since the launch, or null when there
2986
+ * was none. The CLI passes the faultlog reader (`latestCrash`). A probe that
2987
+ * throws is logged and counts as no crash.
2988
+ */
2989
+ type SmokeCrashProbe<C = unknown> = (args: SmokeCrashProbeArgs) => Promise<C | null>;
2990
+ interface SmokeCheckOptions<C = unknown> {
2991
+ config: ConfigProvider;
2992
+ bundle: string;
2993
+ /** When the launch was issued (crash window start). Default: when the check starts. */
2994
+ since?: Date;
2995
+ /** Wait between the process appearing and the screenshot. Default {@link DEFAULT_SMOKE_DELAY_MS}. */
2996
+ delayMs?: number;
2997
+ /** Deadline for the process to appear. Default {@link DEFAULT_SMOKE_PID_TIMEOUT_MS}. */
2998
+ pidTimeoutMs?: number;
2999
+ /** Where to write the screenshot JPEG. When omitted it is analysed but not kept. */
3000
+ screenshotPath?: string;
3001
+ /** Turns the JPEG into greyscale for the blank check; without it `blankScreen` is null. */
3002
+ decodeGreyscale?: GreyscaleDecoder;
3003
+ /** Crash-detection hook; see {@link SmokeCrashProbe}. Without it `crash` is null. */
3004
+ crashProbe?: SmokeCrashProbe<C>;
3005
+ deviceSerial?: string;
3006
+ logger?: Logger;
3007
+ }
3008
+ interface SmokeResult<C = unknown> {
3009
+ /** All checks passed: the process came up and stayed up, the screen is not blank, no crash. */
3010
+ passed: boolean;
3011
+ /** Why it failed, one line per failed check; empty when it passed. */
3012
+ failures: string[];
3013
+ /** Pid seen after launch, or null when the process never appeared. */
3014
+ pid: number | null;
3015
+ /** The process seen after launch was still running (same pid) after the delay. */
3016
+ alive: boolean;
3017
+ /** Pid after the delay when it differs from `pid` (the app died and was restarted), else absent. */
3018
+ pidAfter?: number | null;
3019
+ /** The app area is a flat frame; null when no decoder was given or the screenshot failed. */
3020
+ blankScreen: boolean | null;
3021
+ /** Share (0-1) of the app area in its dominant colour; 1 = flat. Null with `blankScreen`. */
3022
+ blankScore: number | null;
3023
+ /** The blank-check measurements (pHash distance from a flat frame, standard deviation, background). */
3024
+ blank?: BlankAnalysis;
3025
+ /** Path of the saved screenshot, or null when none was kept. */
3026
+ screenshot: string | null;
3027
+ /** The crash probe's finding, or null (no crash, or no probe). */
3028
+ crash: C | null;
3029
+ /** Whether a crash probe ran; `crash: null` without one means "not checked". */
3030
+ crashChecked: boolean;
3031
+ delayMs: number;
3032
+ }
3033
+ /** Combine the observations into a verdict. Pure. */
3034
+ declare function smokeVerdict(o: {
3035
+ pid: number | null;
3036
+ alive: boolean;
3037
+ blankScreen: boolean | null;
3038
+ crash: unknown;
3039
+ }): {
3040
+ passed: boolean;
3041
+ failures: string[];
3042
+ };
3043
+ /**
3044
+ * Smoke-check a just-launched app: wait for its process, let it settle for
3045
+ * `delayMs`, capture a screenshot and judge it against a flat frame, check the
3046
+ * process is still the same one, and ask the crash probe (when given) for a
3047
+ * crash since launch. Never throws for a failed check — the verdict is in the
3048
+ * result; it throws only when the device cannot be reached.
3049
+ */
3050
+ declare function smokeCheck<C = unknown>(opts: SmokeCheckOptions<C>): Promise<SmokeResult<C>>;
3051
+
1931
3052
  interface RunHvigorwOptions {
1932
3053
  config: ConfigProvider;
1933
3054
  projectDir: string;
@@ -1985,9 +3106,17 @@ interface DiscoverHapsOptions {
1985
3106
  /** Max directory recursion depth. Default 8. */
1986
3107
  maxDepth?: number;
1987
3108
  }
3109
+ /**
3110
+ * A module's test HAP (`<module>-ohosTest-{signed,unsigned}.hap`, built from
3111
+ * `src/ohosTest`). Its filename starts with the module name, so without this it
3112
+ * would be grouped with the module's own HAPs, and, being built last by
3113
+ * `oniro-app test`, picked over them for install.
3114
+ */
3115
+ declare function isTestHap(hapFileName: string): boolean;
1988
3116
  /**
1989
3117
  * Walk a project's build outputs and group `*-signed.hap` / `*-unsigned.hap`
1990
- * by build module name (parsed from the HAP filename). Skips `node_modules` /
3118
+ * by build module name (parsed from the HAP filename). Test HAPs
3119
+ * (`*-ohosTest-*.hap`, see {@link isTestHap}) are left out. Skips `node_modules` /
1991
3120
  * `oh_modules` / `.git`, and, when `projectDir` is an app project root, any
1992
3121
  * other app project nested inside it, whose HAPs belong to another app.
1993
3122
  * Ported from the proven MCP `findHaps`, extended with per-module grouping so
@@ -2112,55 +3241,266 @@ interface RunCodelinterOptions {
2112
3241
  declare function runCodelinter(opts: RunCodelinterOptions): Promise<CodelinterResult>;
2113
3242
 
2114
3243
  /**
2115
- * A hint for build output whose cause the compiler errors do not name, or
2116
- * undefined. Pure/testable.
2117
- */
2118
- declare function diagnoseBuildFailure(output: string): string | undefined;
2119
- interface BuildHapOptions {
2120
- config: ConfigProvider;
2121
- projectDir: string;
2122
- product?: string;
2123
- module?: string;
2124
- /** Forwarded as hvigor `buildMode` (e.g. release, debug). */
2125
- mode?: string;
2126
- /** hvigor task. Default `assembleHap`. */
3244
+ * Where a diagnostic comes from: the ArkTS compiler, hvigor itself (configuration
3245
+ * and task errors), the native toolchain (clang, lld), ohpm, the SDK the project
3246
+ * compiles against, the signing material (a signingConfig for the other runtime),
3247
+ * or `check arkts`.
3248
+ */
3249
+ type DiagnosticSource = 'arkts' | 'hvigor' | 'native' | 'ohpm' | 'sdk' | 'signing' | 'arkts-check';
3250
+ /** One error or warning, in a shape shared by `build --json` and `check arkts --json`. */
3251
+ interface BuildDiagnostic {
3252
+ severity: 'error' | 'warning';
3253
+ source: DiagnosticSource;
3254
+ /** The tool's code: eight digits for hvigor, ArkTS and ohpm (e.g. `10605008`). */
3255
+ code?: string;
3256
+ /** The ArkTS linter rule, e.g. `arkts-no-any-unknown`. */
3257
+ rule?: string;
3258
+ message: string;
3259
+ /** Relative to the project root when the file lies inside it, else absolute. */
3260
+ file?: string;
3261
+ line?: number;
3262
+ column?: number;
3263
+ /** The hvigor task that reported it, e.g. `:entry:default@CompileArkTS`. */
2127
3264
  task?: string;
2128
- /** Run `ohpm install --all` first when `oh_modules/` is missing. Default true. */
2129
- autoInstallDeps?: boolean;
2130
- /** Build modules in parallel. Default true (see runHvigorw). */
2131
- parallel?: boolean;
2132
- abortSignal?: AbortSignal;
2133
- onOutput?: (chunk: string, stream: 'stdout' | 'stderr') => void;
2134
- logger?: Logger;
2135
- }
2136
- interface BuildHapResult {
2137
- exitCode: number;
2138
- durationMs: number;
2139
- /** Built HAPs grouped by module folder. */
2140
- discoveredHaps: Record<string, ModuleHaps>;
2141
- warnings: string[];
3265
+ /** For `sdk` diagnostics: the API level the build needs. */
3266
+ api?: string;
3267
+ }
3268
+ interface ParsedBuildOutput {
3269
+ /** The first hvigor task reported as failed. */
3270
+ failedTask?: string;
3271
+ diagnostics: BuildDiagnostic[];
3272
+ /** hvigor's own `COMPILE RESULT` counts. They can exceed the distinct diagnostics, so are a cross-check only. */
3273
+ reportedErrors?: number;
3274
+ reportedWarnings?: number;
3275
+ }
3276
+ /** Build output as plain lines: colour codes stripped and, of a line redrawn with `\r`, its last state. */
3277
+ declare function cleanBuildOutput(output: string): string[];
3278
+ /** The last `n` lines of build output, cleaned. */
3279
+ declare function buildOutputTail(output: string, n?: number): string;
3280
+ /**
3281
+ * Parse hvigor build output (stdout and stderr together, ANSI codes and all) into
3282
+ * diagnostics. Pure/testable. Understands the ArkTS compiler's coded and located
3283
+ * blocks, hvigor's coded configuration and task errors, clang and lld output from
3284
+ * a native build, and ohpm's coded errors. hvigor prints the ArkTS block twice, so
3285
+ * diagnostics are de-duplicated; `projectDir` makes paths inside it relative.
3286
+ */
3287
+ declare function parseBuildOutput(output: string, opts?: {
3288
+ projectDir?: string;
3289
+ }): ParsedBuildOutput;
3290
+ /** A symbol the compiler says a kit or `@ohos.*` module does not export. */
3291
+ interface MissingSdkSymbol {
3292
+ symbol: string;
3293
+ module: string;
2142
3294
  }
3295
+ /** The kit/`@ohos` symbols that diagnostics report missing, de-duplicated. Pure. */
3296
+ declare function missingSdkSymbols(diagnostics: readonly BuildDiagnostic[]): MissingSdkSymbol[];
2143
3297
  /**
2144
- * High-level build orchestration: ensure deps → run hvigorw → discover the
2145
- * produced HAPs. The single call the CLI and MCP want; `runHvigorw` stays a raw
2146
- * single-spawn primitive.
3298
+ * When the build failed on kit or `@ohos` symbols that a newer installed SDK
3299
+ * declares, one `sdk` diagnostic naming the API level that has them all (#22);
3300
+ * otherwise null. `sdkHome` holds one folder per API level; `projectApi` is the
3301
+ * project's compileSdkVersion. Best effort: it reads declaration files and does
3302
+ * not know about SDKs that are not installed.
2147
3303
  */
2148
- declare function buildHap(opts: BuildHapOptions): Promise<BuildHapResult>;
2149
-
3304
+ declare function sdkTooOldDiagnostic(diagnostics: readonly BuildDiagnostic[], sdkHome: string, projectApi: number | undefined): BuildDiagnostic | null;
2150
3305
  /**
2151
- * Conservative project-folder-name validator (no path separators, conservative charset).
3306
+ * The package an `oh_modules/` path belongs to, e.g. `@ohos/flutter_ohos` for
3307
+ * `oh_modules/.ohpm/@ohos+flutter_ohos@1.0.0/oh_modules/@ohos/flutter_ohos/src/…`.
2152
3308
  */
2153
- declare function isValidProjectName(name: string): boolean;
3309
+ declare function ohModulesPackage(file: string): string | undefined;
2154
3310
  /**
2155
- * Bundle-name validator. Allows reverse-DNS style identifiers like `com.example.myapp`.
3311
+ * A hint when the ArkTS errors are missing properties or names inside
3312
+ * `oh_modules/`: a dependency calling an API newer than the SDK the build used
3313
+ * (#22). Message-level only; it does not read the dependencies. `sdkLabel` names
3314
+ * that SDK (`HarmonyOS 5.1.0 (API 18) at …`) and `remedy` how to get a newer one.
3315
+ * Null when no such error is there.
2156
3316
  */
2157
- declare function isValidBundleName(bundleName: string): boolean;
3317
+ declare function dependencyApiDiagnostic(diagnostics: readonly BuildDiagnostic[], sdkLabel: string | undefined, remedy: string): BuildDiagnostic | null;
2158
3318
 
2159
- interface TemplateOption {
2160
- id: string;
2161
- label: string;
2162
- description: string;
2163
- defaultModuleName: string;
3319
+ /**
3320
+ * Which runtime a project targets. OpenHarmony projects build against the public
3321
+ * OpenHarmony SDK; HarmonyOS projects build against Huawei's HarmonyOS SDK and
3322
+ * need an AGC-issued certificate to sign (see `harmonyos/signing`).
3323
+ */
3324
+ type RuntimeOs = 'OpenHarmony' | 'HarmonyOS';
3325
+ /**
3326
+ * Detect the runtime a project targets from `build-profile.json5`.
3327
+ *
3328
+ * HarmonyOS only when the product declares `runtimeOS: "HarmonyOS"`, which DevEco
3329
+ * Studio writes for every HarmonyOS project. Anything else — no such field, or a
3330
+ * missing or unreadable profile — is OpenHarmony, so existing projects behave
3331
+ * exactly as they did before HarmonyOS support. Reads the named product, else the
3332
+ * first one.
3333
+ */
3334
+ declare function detectRuntimeOs(projectDir: string, productName?: string): RuntimeOs;
3335
+ /**
3336
+ * HarmonyOS SDK releases, mapping API level to the release version DevEco writes
3337
+ * into `compileSdkVersion`, for when the installed SDK does not name the requested
3338
+ * level itself. Only releases read from a real `sdk/default/sdk-pkg.json` are listed.
3339
+ */
3340
+ declare const HARMONYOS_SDK_VERSIONS: ReadonlyMap<number, string>;
3341
+ /**
3342
+ * The `"<version>(<api>)"` label a HarmonyOS product declares for an API level, or
3343
+ * undefined when no HarmonyOS release is known for it.
3344
+ */
3345
+ declare function harmonyOsSdkLabelForApi(api: number): string | undefined;
3346
+
3347
+ /** The SDK a build compiles against, as `build --json` reports it (#22). */
3348
+ interface BuildSdk {
3349
+ runtimeOS: RuntimeOs;
3350
+ /** e.g. `HarmonyOS 6.1.1`, `OpenHarmony 5.1.0`. */
3351
+ displayName?: string;
3352
+ /** The release as the SDK names it: `6.1.1(24)` for HarmonyOS, the build (`5.1.0.107`) for OpenHarmony. */
3353
+ version?: string;
3354
+ /** e.g. `24`. */
3355
+ api?: string;
3356
+ /** The SDK directory: `DEVECO_SDK_HOME` for HarmonyOS, `<sdk home>/<api>` for OpenHarmony. */
3357
+ path: string;
3358
+ }
3359
+ /**
3360
+ * The SDK a build of `projectDir` uses, found the way the build finds it: the
3361
+ * HarmonyOS SDK for a HarmonyOS product, else the OpenHarmony API folder for the
3362
+ * project's compileSdkVersion. Undefined when it cannot be told.
3363
+ */
3364
+ declare function resolveBuildSdk(opts: {
3365
+ config: ConfigProvider;
3366
+ projectDir: string;
3367
+ runtimeOS: RuntimeOs;
3368
+ logger?: Logger;
3369
+ }): BuildSdk | undefined;
3370
+ /** `HarmonyOS 5.1.0 (API 18) at <path>`. */
3371
+ declare function describeBuildSdk(sdk: BuildSdk): string;
3372
+
3373
+ /**
3374
+ * A hint for build output whose cause the compiler errors do not name, or
3375
+ * undefined. Pure/testable. A symbol missing from a kit reads as a system API
3376
+ * unless `newerSdkHasIt`, when a newer installed SDK declares it (see
3377
+ * {@link sdkTooOldDiagnostic}).
3378
+ */
3379
+ declare function diagnoseBuildFailure(output: string, newerSdkHasIt?: boolean): string | undefined;
3380
+ interface BuildHapOptions {
3381
+ config: ConfigProvider;
3382
+ projectDir: string;
3383
+ product?: string;
3384
+ module?: string;
3385
+ /** Forwarded as hvigor `buildMode` (e.g. release, debug). */
3386
+ mode?: string;
3387
+ /** hvigor task. Default `assembleHap`. */
3388
+ task?: string;
3389
+ /** Run `ohpm install --all` first when `oh_modules/` is missing. Default true. */
3390
+ autoInstallDeps?: boolean;
3391
+ /** Build modules in parallel. Default true (see runHvigorw). */
3392
+ parallel?: boolean;
3393
+ abortSignal?: AbortSignal;
3394
+ onOutput?: (chunk: string, stream: 'stdout' | 'stderr') => void;
3395
+ logger?: Logger;
3396
+ }
3397
+ interface BuildSummary {
3398
+ /** Distinct error diagnostics. */
3399
+ errors: number;
3400
+ /** Distinct warning diagnostics. */
3401
+ warnings: number;
3402
+ /** hvigor's `COMPILE RESULT` error count, which can exceed `errors`. */
3403
+ reportedErrors?: number;
3404
+ reportedWarnings?: number;
3405
+ }
3406
+ interface BuildHapResult {
3407
+ exitCode: number;
3408
+ durationMs: number;
3409
+ /** Built HAPs grouped by module folder. */
3410
+ discoveredHaps: Record<string, ModuleHaps>;
3411
+ warnings: string[];
3412
+ /** Compiler warnings (and errors, for a failed build) parsed from the output. */
3413
+ diagnostics: BuildDiagnostic[];
3414
+ summary: BuildSummary;
3415
+ /** The SDK the build compiled against, when it could be told. */
3416
+ sdk?: BuildSdk;
3417
+ }
3418
+ /**
3419
+ * The build ran and failed: hvigor (or the `ohpm install` before it) exited
3420
+ * non-zero. Carries what {@link parseBuildOutput} found, so callers need not
3421
+ * scrape the output.
3422
+ */
3423
+ declare class BuildFailedError extends OniroError {
3424
+ readonly exitCode: number;
3425
+ readonly diagnostics: BuildDiagnostic[];
3426
+ readonly summary: BuildSummary;
3427
+ readonly rawTail: string;
3428
+ readonly failedTask?: string | undefined;
3429
+ readonly hint?: string | undefined;
3430
+ /** The SDK hvigor compiled against, when it could be told (not for an ohpm failure). */
3431
+ sdk?: BuildSdk;
3432
+ constructor(message: string, exitCode: number, diagnostics: BuildDiagnostic[], summary: BuildSummary, rawTail: string, failedTask?: string | undefined, hint?: string | undefined, cause?: unknown);
3433
+ }
3434
+ /**
3435
+ * High-level build orchestration: ensure deps → run hvigorw → discover the
3436
+ * produced HAPs. The single call the CLI and MCP want; `runHvigorw` stays a raw
3437
+ * single-spawn primitive.
3438
+ */
3439
+ declare function buildHap(opts: BuildHapOptions): Promise<BuildHapResult>;
3440
+ /** What {@link buildWithDiagnostics} returns: one shape for a build that passed and one that failed. */
3441
+ interface BuildReport {
3442
+ ok: boolean;
3443
+ exitCode: number;
3444
+ durationMs: number;
3445
+ /** The first task hvigor reported failed, or `ohpm install --all`. */
3446
+ failedTask?: string;
3447
+ diagnostics: BuildDiagnostic[];
3448
+ summary: BuildSummary;
3449
+ /** Built HAPs grouped by module folder; empty when the build failed. */
3450
+ discoveredHaps: Record<string, ModuleHaps>;
3451
+ warnings: string[];
3452
+ /** The error message the build failed with (what `oniro-app build` prints). */
3453
+ error?: string;
3454
+ /** The SDK the project compiles against is not installed: install it and build again. */
3455
+ missingSdk?: {
3456
+ api: string;
3457
+ version?: string;
3458
+ expectedPath: string;
3459
+ };
3460
+ /**
3461
+ * The SDK hvigor compiled against (`runtimeOS`, `displayName`, `version`, `api`,
3462
+ * `path`), when it could be told. Absent for an ohpm failure or a missing SDK.
3463
+ */
3464
+ sdk?: BuildSdk;
3465
+ /** The last 200 lines of build output, colour codes removed. Empty for a successful build. */
3466
+ rawTail: string;
3467
+ }
3468
+ /**
3469
+ * {@link buildHap}, but a build that fails returns `ok: false` with the parsed
3470
+ * diagnostics instead of throwing, as does a project whose SDK is not installed
3471
+ * (one `sdk` diagnostic, plus `missingSdk`). Errors that mean the build could not
3472
+ * run at all (no command-line tools, not a project, cancelled) still throw.
3473
+ */
3474
+ declare function buildWithDiagnostics(opts: BuildHapOptions): Promise<BuildReport>;
3475
+
3476
+ /**
3477
+ * Why the signingConfig a product names cannot sign for the runtime it targets,
3478
+ * or undefined when it can (or names none, or the profile cannot be read).
3479
+ *
3480
+ * A HarmonyOS device accepts only AppGallery Connect material, which
3481
+ * `sign --harmonyos` writes with `type: "HarmonyOS"`, the field hvigor keys on.
3482
+ * Material without it is the OpenHarmony development certificate a plain `sign`
3483
+ * writes, and hvigor's SignHap still signs with it, producing a
3484
+ * `-signed.hap` that only fails at install time (#19). The mirror case, HarmonyOS
3485
+ * material on an OpenHarmony product, is reported too. Reads the named product,
3486
+ * else the first one, like {@link detectRuntimeOs}.
3487
+ */
3488
+ declare function signingMismatch(projectDir: string, runtimeOS: RuntimeOs, productName?: string): string | undefined;
3489
+
3490
+ /**
3491
+ * Conservative project-folder-name validator (no path separators, conservative charset).
3492
+ */
3493
+ declare function isValidProjectName(name: string): boolean;
3494
+ /**
3495
+ * Bundle-name validator. Allows reverse-DNS style identifiers like `com.example.myapp`.
3496
+ */
3497
+ declare function isValidBundleName(bundleName: string): boolean;
3498
+
3499
+ interface TemplateOption {
3500
+ id: string;
3501
+ label: string;
3502
+ description: string;
3503
+ defaultModuleName: string;
2164
3504
  }
2165
3505
  /**
2166
3506
  * Enumerate templates inside `templateRoot`. Each direct subfolder is a template;
@@ -2397,69 +3737,6 @@ declare function bundleNameFromHapConfig(text: string): string | null;
2397
3737
  /** The bundle a HAP installs as, read from its `module.json` or `config.json`; null when neither names one. */
2398
3738
  declare function readHapBundleName(hapPath: string): Promise<string | null>;
2399
3739
 
2400
- /**
2401
- * Which runtime a project targets. OpenHarmony projects build against the public
2402
- * OpenHarmony SDK; HarmonyOS projects build against Huawei's HarmonyOS SDK and
2403
- * need an AGC-issued certificate to sign (see `harmonyos/signing`).
2404
- */
2405
- type RuntimeOs = 'OpenHarmony' | 'HarmonyOS';
2406
- /**
2407
- * Detect the runtime a project targets from `build-profile.json5`.
2408
- *
2409
- * HarmonyOS only when the product declares `runtimeOS: "HarmonyOS"`, which DevEco
2410
- * Studio writes for every HarmonyOS project. Anything else — no such field, or a
2411
- * missing or unreadable profile — is OpenHarmony, so existing projects behave
2412
- * exactly as they did before HarmonyOS support. Reads the named product, else the
2413
- * first one.
2414
- */
2415
- declare function detectRuntimeOs(projectDir: string, productName?: string): RuntimeOs;
2416
- /**
2417
- * HarmonyOS SDK releases, mapping API level to the release version DevEco writes
2418
- * into `compileSdkVersion`, for when the installed SDK does not name the requested
2419
- * level itself. Only releases read from a real `sdk/default/sdk-pkg.json` are listed.
2420
- */
2421
- declare const HARMONYOS_SDK_VERSIONS: ReadonlyMap<number, string>;
2422
- /**
2423
- * The `"<version>(<api>)"` label a HarmonyOS product declares for an API level, or
2424
- * undefined when no HarmonyOS release is known for it.
2425
- */
2426
- declare function harmonyOsSdkLabelForApi(api: number): string | undefined;
2427
-
2428
- /**
2429
- * A HarmonyOS SDK install. Unlike the OpenHarmony SDK, which `oniro-app sdk install`
2430
- * downloads, the HarmonyOS SDK only ships inside DevEco Studio or the login-gated
2431
- * HarmonyOS command-line tools, so oniro-app locates an existing install.
2432
- */
2433
- interface HarmonyOsSdk {
2434
- /** The directory containing `default/`; hvigor receives it as `DEVECO_SDK_HOME`. */
2435
- sdkPath: string;
2436
- /** The DevEco Studio or command-line-tools install holding the SDK, its tools and JBR. */
2437
- installRoot: string;
2438
- /** From `default/sdk-pkg.json`, e.g. `HarmonyOS 6.1.1`. */
2439
- displayName?: string;
2440
- /**
2441
- * The release as `compileSdkVersion` names it, e.g. `6.1.1(24)`, from
2442
- * `default/sdk-pkg.json`. hvigor builds only projects that name this release.
2443
- */
2444
- version?: string;
2445
- }
2446
- /**
2447
- * Locate a HarmonyOS SDK, or return null when none is installed.
2448
- *
2449
- * Order: `harmonyosSdkPath` (`ONIRO_HARMONYOS_SDK_PATH`, an install root or its
2450
- * `sdk` directory), then DevEco Studio in its default location, then the
2451
- * command-line tools at `cmdToolsPath` when they are the HarmonyOS edition.
2452
- */
2453
- declare function findHarmonyOsSdk(opts: {
2454
- config: ConfigProvider;
2455
- logger?: Logger;
2456
- }): HarmonyOsSdk | null;
2457
- /** Like `findHarmonyOsSdk`, but throws an actionable error when none is installed. */
2458
- declare function requireHarmonyOsSdk(opts: {
2459
- config: ConfigProvider;
2460
- logger?: Logger;
2461
- }): HarmonyOsSdk;
2462
-
2463
3740
  type HuaweiSiteCode = 'CN' | 'EU' | 'SG' | 'RU';
2464
3741
  interface HuaweiSite {
2465
3742
  code: HuaweiSiteCode;
@@ -2586,13 +3863,37 @@ interface HarmonyOsSessionOptions {
2586
3863
  logger?: Logger;
2587
3864
  http?: HarmonyOsHttpClient;
2588
3865
  tokenStore?: TokenStore;
2589
- /** Called with the sign-in URL before the browser opens, so a CLI can print it. */
2590
- onLoginUrl?: (url: string) => void;
3866
+ /**
3867
+ * Called with the sign-in URL before the browser opens, so a CLI can print it,
3868
+ * and the loopback port the sign-in page will redirect to.
3869
+ */
3870
+ onLoginUrl?: (url: string, info: {
3871
+ port: number;
3872
+ }) => void;
3873
+ }
3874
+ interface HarmonyOsLoginOptions {
3875
+ /** How long to wait for the sign-in. Default {@link LOGIN_TIMEOUT_MS}. */
3876
+ timeoutMs?: number;
3877
+ /**
3878
+ * Loopback port the sign-in page redirects to. Default: one the OS assigns. Fix
3879
+ * it to forward the port from the machine with the browser beforehand, with
3880
+ * `ssh -L <port>:127.0.0.1:<port>`.
3881
+ */
3882
+ port?: number;
3883
+ /** Default true. False leaves opening the URL (from `onLoginUrl`) to the user. */
3884
+ openBrowser?: boolean;
3885
+ /**
3886
+ * Callback addresses the user pastes, one per item — say, a `readline`
3887
+ * interface over stdin. For a browser on another machine, whose redirect to
3888
+ * this machine's loopback port cannot load: the address it was sent to,
3889
+ * copied from its address bar, completes the sign-in instead. The loopback
3890
+ * listener keeps running alongside, and whichever arrives first wins; a pasted
3891
+ * line that is not this sign-in's callback is reported and the next one read.
3892
+ */
3893
+ pastedCallbacks?: AsyncIterable<string>;
2591
3894
  }
2592
3895
  interface HarmonyOsSession {
2593
- login(opts?: {
2594
- timeoutMs?: number;
2595
- }): Promise<HuaweiUserInfo>;
3896
+ login(opts?: HarmonyOsLoginOptions): Promise<HuaweiUserInfo>;
2596
3897
  /** Resolves false when there was no session to end. */
2597
3898
  logout(): Promise<boolean>;
2598
3899
  /** The signed-in account, or null. `refresh` mints a fresh AGC access token. */
@@ -2646,20 +3947,39 @@ interface SigningMaterialPaths {
2646
3947
  profilePath: string;
2647
3948
  }
2648
3949
 
2649
- /** The fields of a provisioning profile that decide whether it can be reused. */
3950
+ /** The fields of a provisioning profile that decide whether it can be reused, and what it allows. */
2650
3951
  interface ProvisionProfileInfo {
3952
+ /** `debug` or `release`. */
3953
+ type?: string;
3954
+ /** Who signed the profile: `app_gallery` for AGC, `pki_internal` for the OpenHarmony SDK's. */
3955
+ issuer?: string;
2651
3956
  bundleName?: string;
2652
- /** The AGC team the profile was issued to. */
3957
+ /** The AGC team the profile was issued to; `OpenHarmony` for the SDK's. */
2653
3958
  developerId?: string;
3959
+ apl?: string;
3960
+ appFeature?: string;
3961
+ notBefore?: Date;
2654
3962
  notAfter?: Date;
2655
3963
  /** Uppercased UDIDs the debug profile is valid for. */
2656
3964
  deviceIds: string[];
2657
3965
  aclPermissions: string[];
2658
- /** PEM of the certificate the profile was issued for. */
3966
+ /** PEM of the certificate a debug profile was issued for. */
2659
3967
  developmentCertificate?: string;
3968
+ /** PEM of the certificate a release profile was issued for. */
3969
+ distributionCertificate?: string;
2660
3970
  }
2661
3971
  /** Read a `.p7b` profile; null when it is missing or unreadable, which means "regenerate". */
2662
3972
  declare function readProvisionProfile(profilePath: string): ProvisionProfileInfo | null;
3973
+ /** {@link readProvisionProfile} on the bytes of a `.p7b`; null when they hold no profile. */
3974
+ declare function parseProvisionProfile(buffer: Buffer): ProvisionProfileInfo | null;
3975
+ /** `2026-10-01 11:50 UTC`. */
3976
+ declare function formatUtc(date: Date): string;
3977
+ /**
3978
+ * The profile's type and expiry, for a one-line summary: `debug, valid until
3979
+ * 2026-10-01 11:50 UTC`, or `debug, expired 2026-10-01 11:50 UTC`. Omits what
3980
+ * the profile does not say.
3981
+ */
3982
+ declare function describeProfileValidity(profile: Pick<ProvisionProfileInfo, 'type' | 'notAfter'>, now?: Date): string;
2663
3983
 
2664
3984
  interface HarmonyOsAutoSignOptions {
2665
3985
  config: ConfigProvider;
@@ -2682,6 +4002,10 @@ interface HarmonyOsSigningResult {
2682
4002
  regenerated: boolean;
2683
4003
  /** UDIDs the profile is valid for. */
2684
4004
  deviceIds: string[];
4005
+ /** The profile's type: `debug` for the material AGC issues here. */
4006
+ profileType?: string;
4007
+ /** When the profile expires. AGC debug profiles last 14 days. */
4008
+ notAfter?: Date;
2685
4009
  }
2686
4010
  /**
2687
4011
  * Sign a HarmonyOS project with the signed-in Huawei developer account, the way
@@ -2716,6 +4040,2123 @@ interface HarmonyOsSignHapResult extends HarmonyOsSigningResult {
2716
4040
  */
2717
4041
  declare function harmonyOsSignHap(opts: HarmonyOsSignHapOptions): Promise<HarmonyOsSignHapResult>;
2718
4042
 
4043
+ /**
4044
+ * Parser for the output of `aa test … -s unittest OpenHarmonyTestRunner` (the
4045
+ * Hypium runner). Each case prints a block when it starts (`STATUS_CODE: 1`) and
4046
+ * one when it ends, carrying `class=`, `test=`, `stream=` (the failure message),
4047
+ * `stack=` (several lines) and `consuming=` (ms). The run ends with
4048
+ * `OHOS_REPORT_RESULT: stream=Tests run: N, Failure: F, Error: E, Pass: P, Ignore: I`,
4049
+ * `OHOS_REPORT_CODE` and `TestFinished-ResultCode` / `-ResultMsg`.
4050
+ */
4051
+ type TestStatus = 'pass' | 'fail' | 'error' | 'ignore' | 'unknown';
4052
+ interface TestCaseResult {
4053
+ /** The `describe` name. */
4054
+ suite: string;
4055
+ /** The `it` name. */
4056
+ name: string;
4057
+ status: TestStatus;
4058
+ /** The runner's raw `OHOS_REPORT_STATUS_CODE` for the finished case. */
4059
+ statusCode: number;
4060
+ durationMs?: number;
4061
+ /** The assertion or error message (`stream=`), e.g. `expect 0 equals 3`. */
4062
+ message?: string;
4063
+ /** The JS stack the runner printed, project frames and Hypium frames alike. */
4064
+ stack?: string;
4065
+ }
4066
+ interface TestSummary {
4067
+ run: number;
4068
+ pass: number;
4069
+ fail: number;
4070
+ error: number;
4071
+ ignore: number;
4072
+ }
4073
+ interface ParsedTestOutput {
4074
+ tests: TestCaseResult[];
4075
+ /** From `OHOS_REPORT_RESULT`, or counted from `tests` when the runner never printed it. */
4076
+ summary: TestSummary;
4077
+ /** True when `OHOS_REPORT_RESULT` was printed. */
4078
+ summaryReported: boolean;
4079
+ /** `OHOS_REPORT_CODE`: 0 when every case passed, -1 otherwise. */
4080
+ reportCode?: number;
4081
+ /** `TestFinished-ResultCode`: 0 when the run itself completed, whatever the cases did. */
4082
+ resultCode?: number;
4083
+ /** `TestFinished-ResultMsg`, e.g. `The specified module name is not found.` */
4084
+ resultMessage?: string;
4085
+ /** `taskconsuming=`: the whole run, in ms. */
4086
+ durationMs?: number;
4087
+ /** For a dry run (`-s dryRun true`): the suites and their cases, without running them. */
4088
+ dryRun?: Array<{
4089
+ suite: string;
4090
+ name: string;
4091
+ }>;
4092
+ }
4093
+ /**
4094
+ * The runner's status codes, as observed with Hypium 1.0.24 on OpenHarmony 7.0:
4095
+ * 1 starts a case, 0 passed, -2 an assertion failed, -1 the case threw. -3 is
4096
+ * assumed to mean ignored (the code was not observed); anything else is
4097
+ * reported as `unknown`, with the raw code kept.
4098
+ */
4099
+ declare function statusFromCode(code: number): TestStatus;
4100
+ /** Parse `aa test` output. Pure. Lines that are not runner markers are ignored. */
4101
+ declare function parseTestOutput(output: string): ParsedTestOutput;
4102
+
4103
+ interface RunTestsOptions {
4104
+ config: ConfigProvider;
4105
+ projectDir: string;
4106
+ /** The module whose `src/ohosTest` suite runs. Default `entry`. */
4107
+ module?: string;
4108
+ /** hvigor product. Default `default`. */
4109
+ product?: string;
4110
+ /** Run only these: `Suite`, `Suite#case`, or several joined by commas (the runner's `-s class`). */
4111
+ testClass?: string;
4112
+ /** Per-case timeout passed to the runner (`-s timeout`), ms. Default 15000. */
4113
+ caseTimeoutMs?: number;
4114
+ /** Wall-clock limit for the whole `aa test` run, ms; `aa test` can hang when the runner dies. Default 600000. */
4115
+ runTimeoutMs?: number;
4116
+ /** Build the main and test HAPs first. Default true. */
4117
+ build?: boolean;
4118
+ /**
4119
+ * Turn the screen on, swipe away a lock screen without a credential, and keep
4120
+ * the screen on during the run, so UI tests reach the app. Default true.
4121
+ */
4122
+ wakeScreen?: boolean;
4123
+ /** hvigor build mode (e.g. debug). */
4124
+ mode?: string;
4125
+ /** Run `ohpm install --all` first when `oh_modules/` is missing. Default true. */
4126
+ autoInstallDeps?: boolean;
4127
+ deviceSerial?: string;
4128
+ abortSignal?: AbortSignal;
4129
+ /** Build and runner output as it arrives. */
4130
+ onOutput?: OutputSink;
4131
+ logger?: Logger;
4132
+ }
4133
+ /** How the run ended: every case passed, some case failed or threw, or the run itself did not complete. */
4134
+ type TestOutcome = 'passed' | 'failed' | 'runner-error';
4135
+ interface TestRunReport {
4136
+ ok: boolean;
4137
+ outcome: TestOutcome;
4138
+ module: string;
4139
+ bundle?: string;
4140
+ /** The test module's name, from `src/ohosTest/module.json5` (`entry_test` in the templates). Left installed. */
4141
+ testModule?: string;
4142
+ tests: TestCaseResult[];
4143
+ summary: TestSummary;
4144
+ /** `TestFinished-ResultCode`: 0 when the run completed, whatever the cases did. */
4145
+ resultCode?: number;
4146
+ resultMessage?: string;
4147
+ /** `OHOS_REPORT_CODE`: 0 when every case passed. */
4148
+ reportCode?: number;
4149
+ haps: {
4150
+ main?: string;
4151
+ test?: string;
4152
+ };
4153
+ /** Why the run did not complete (outcome `runner-error`). */
4154
+ error?: string;
4155
+ /** For a build that failed: its diagnostics and task (see `build --json`). */
4156
+ failedTask?: string;
4157
+ diagnostics?: BuildDiagnostic[];
4158
+ /** hilog lines of the app's processes during the run (last 300): assertion logs, JS crash stacks. */
4159
+ log: string[];
4160
+ /** Things that may explain a failure without being one, e.g. a lock screen that needs a credential. */
4161
+ warnings: string[];
4162
+ durationMs: number;
4163
+ /** The last 200 lines of `aa test` output (or of the build output, when the build failed). */
4164
+ rawTail: string;
4165
+ }
4166
+ /** Where hvigor writes a module's test HAP for a product. */
4167
+ declare function testHapPath(moduleDir: string, module: string, product?: string, signed?: boolean): string;
4168
+ /**
4169
+ * The `aa test` command line. Pure. `testClass` is a `Suite`, `Suite#case`, or
4170
+ * a comma-separated list of them; it is quoted for the device shell.
4171
+ */
4172
+ declare function aaTestCommand(opts: {
4173
+ bundle: string;
4174
+ testModule: string;
4175
+ caseTimeoutMs?: number;
4176
+ testClass?: string;
4177
+ }): string;
4178
+ /** The test module name declared in `<moduleDir>/src/ohosTest/module.json5`. */
4179
+ declare function readTestModuleName(moduleDir: string): string;
4180
+ /** The outcome of a parsed run. Pure. */
4181
+ declare function decideOutcome(run: {
4182
+ resultCode?: number;
4183
+ summary: TestSummary;
4184
+ completed: boolean;
4185
+ }): {
4186
+ outcome: TestOutcome;
4187
+ error?: string;
4188
+ };
4189
+ /**
4190
+ * Build a module's main and `ohosTest` HAPs, install both, run the suite with
4191
+ * `aa test` (Hypium's OpenHarmonyTestRunner) and parse the result. Never throws
4192
+ * for a failed test, a failed build or a run that did not complete: those come
4193
+ * back as `outcome` `failed` or `runner-error`. Throws only when it cannot start
4194
+ * (no such module, cancelled).
4195
+ */
4196
+ declare function runTests(opts: RunTestsOptions): Promise<TestRunReport>;
4197
+
4198
+ /**
4199
+ * `check arkts`: the SDK's own ArkTS checker (ets-loader's `etsStandaloneChecker`,
4200
+ * the type and linter pass `CompileArkTS` runs) plus the ArkUI component-model and
4201
+ * project-config rules hvigor enforces later in a build, without a build. It runs
4202
+ * deveco-cli's `arkts-check.cjs` (MIT, vendored under `vendor/deveco-cli/`, adapted
4203
+ * to take the SDK directory) in a child node process, against the SDK the project
4204
+ * compiles with.
4205
+ */
4206
+ /** Where the SDK the checker loads came from. */
4207
+ interface ArktsCheckSdk {
4208
+ /** The directory holding `ets/`, `previewer/` and `toolchains/`. */
4209
+ dir: string;
4210
+ runtimeOS: RuntimeOs;
4211
+ /** The project's `compileSdkVersion` API level, for an OpenHarmony project. */
4212
+ api?: number;
4213
+ /** HarmonyOS's `hms/ets`, added to the checker's API paths. */
4214
+ hmsEtsDir?: string;
4215
+ }
4216
+ interface ArktsCheckSummary {
4217
+ errors: number;
4218
+ warnings: number;
4219
+ fixed: number;
4220
+ /** Source files the checker was given. */
4221
+ files: number;
4222
+ /**
4223
+ * Diagnostics that came from the SDK's ArkTS checker rather than the project rules.
4224
+ * Zero alongside project-rule findings can mean the checker produced nothing, so it
4225
+ * is reported rather than inferred.
4226
+ */
4227
+ checkerDiagnostics: number;
4228
+ }
4229
+ interface ArktsCheckReport {
4230
+ /** True when the check ran and found no error. */
4231
+ ok: boolean;
4232
+ /** False when the checker could not run or crashed: then nothing is known about the code. */
4233
+ completed: boolean;
4234
+ diagnostics: BuildDiagnostic[];
4235
+ /** Diagnostics `--fix` rewrote away, verified by a re-check. */
4236
+ fixed: BuildDiagnostic[];
4237
+ /** Files `--fix` edited that were not in `files` (an `export` added in the declaring module). */
4238
+ alsoModified: string[];
4239
+ summary: ArktsCheckSummary;
4240
+ sdk?: ArktsCheckSdk;
4241
+ durationMs: number;
4242
+ /** Why the check did not complete. */
4243
+ error?: string;
4244
+ }
4245
+ interface ArktsCheckOptions {
4246
+ config: ConfigProvider;
4247
+ projectDir: string;
4248
+ /** Check only these `.ets` files (relative to the project or absolute); project-wide rules are skipped. */
4249
+ files?: string[];
4250
+ /** Apply the checker's verified fixes (compiler suggestions, import paths, missing `export`, ...). */
4251
+ fix?: boolean;
4252
+ /** Override the SDK directory (holding `ets/`); by default the one the project compiles with. */
4253
+ sdkDir?: string;
4254
+ /** With `sdkDir`: HarmonyOS's `hms/ets` API directory to add. */
4255
+ hmsEtsDir?: string;
4256
+ /** Kill the checker after this long. Default 300 000 ms. */
4257
+ timeoutMs?: number;
4258
+ abortSignal?: AbortSignal;
4259
+ logger?: Logger;
4260
+ /** The checker script; tests substitute a stand-in. */
4261
+ scriptPath?: string;
4262
+ /** The node binary that runs it. Default: the one running this process. */
4263
+ nodePath?: string;
4264
+ }
4265
+ /**
4266
+ * The vendored `arkts-check.cjs`: beside `dist/` once published, two levels up
4267
+ * from `src/check/` in the repo.
4268
+ */
4269
+ declare function arktsCheckerScript(): string;
4270
+ /**
4271
+ * The SDK `check arkts` loads for a project: for HarmonyOS, the located HarmonyOS
4272
+ * SDK's `default/openharmony` plus `default/hms/ets`; for OpenHarmony, the API
4273
+ * directory named by `compileSdkVersion` under the SDK home (or the project's
4274
+ * `local.properties` `sdk.dir`). Throws `SdkNotInstalledError` when that API is not
4275
+ * installed, so a caller can offer to install it.
4276
+ */
4277
+ declare function resolveArktsCheckSdk(config: ConfigProvider, projectDir: string, logger?: Logger): ArktsCheckSdk;
4278
+ /**
4279
+ * Turn the checker's stdout into a report. A run that printed no JSON (the checker
4280
+ * threw, which it does on purpose rather than report a crash as a clean result) or
4281
+ * printed `error` is `completed: false`.
4282
+ */
4283
+ declare function parseArktsCheckOutput(stdout: string, stderr: string, exitCode: number): Omit<ArktsCheckReport, 'sdk' | 'durationMs'>;
4284
+ /**
4285
+ * Run `check arkts` on a project. Resolves with `completed: false` and `error` when
4286
+ * the checker could not run or crashed; throws only when the SDK cannot be resolved
4287
+ * (`SdkNotInstalledError` when the project's API is not installed).
4288
+ */
4289
+ declare function checkArkts(opts: ArktsCheckOptions): Promise<ArktsCheckReport>;
4290
+
4291
+ /**
4292
+ * `oniro-app doctor`: one verdict on whether this machine can build, check, sign,
4293
+ * install and test a project, with the tool versions in use so drift between two
4294
+ * runs is visible. Each check is `ok`, `warn`, `fail` or `skip`, with a one-line fix.
4295
+ */
4296
+ type DoctorStatus = 'ok' | 'warn' | 'fail' | 'skip';
4297
+ interface DoctorCheck {
4298
+ /** Stable key: `node`, `java`, `sdk`, `cmdtools`, `cmdtools-flavour`, `arkts-check`, `hdc`, `device`, `signing`, `disk`. */
4299
+ id: string;
4300
+ status: DoctorStatus;
4301
+ /** What was found, one line. */
4302
+ detail: string;
4303
+ /** What to run or change, when the status is not ok. */
4304
+ fix?: string;
4305
+ /** True when `fix` was applied by `doctor --fix` (the status is then the re-checked one). */
4306
+ fixed?: boolean;
4307
+ }
4308
+ interface DoctorProject {
4309
+ dir: string;
4310
+ runtimeOS: RuntimeOs;
4311
+ /** As written in build-profile.json5: an API level, or `6.0.0(20)` for HarmonyOS. */
4312
+ compileSdkVersion?: string | number;
4313
+ compatibleSdkVersion?: string | number;
4314
+ /** The API level a device must run at least: compatibleSdkVersion, else compileSdkVersion. */
4315
+ minApi?: number;
4316
+ }
4317
+ /** Versions in use, recorded so a change between two runs shows (#25). */
4318
+ interface DoctorVersions {
4319
+ node: string;
4320
+ java?: string;
4321
+ cmdTools?: string;
4322
+ cmdToolsFlavour?: string;
4323
+ /** The SDK directory a build or `check arkts` of the project uses. */
4324
+ sdk?: string;
4325
+ hdc?: string;
4326
+ deviceApi?: string;
4327
+ }
4328
+ interface DoctorReport {
4329
+ /** True when no check failed. */
4330
+ ok: boolean;
4331
+ checks: DoctorCheck[];
4332
+ project?: DoctorProject;
4333
+ versions: DoctorVersions;
4334
+ }
4335
+ interface DoctorOptions {
4336
+ config: ConfigProvider;
4337
+ /** A project to check the SDK, flavour, device API and signing for. */
4338
+ projectDir?: string;
4339
+ /** Install the project's missing OpenHarmony SDK. */
4340
+ fix?: boolean;
4341
+ /** Check a device is reachable (default true). False skips `device`. */
4342
+ device?: boolean;
4343
+ deviceSerial?: string;
4344
+ /** Run `check arkts` on a generated one-file project (default true). */
4345
+ arktsSelfTest?: boolean;
4346
+ logger?: Logger;
4347
+ progress?: ProgressReporter;
4348
+ env?: NodeJS.ProcessEnv;
4349
+ /** Seams for tests. */
4350
+ installSdk?: (opts: InstallSdkOptions) => Promise<void>;
4351
+ arktsCheckerScript?: string;
4352
+ }
4353
+ /**
4354
+ * What a complete command-line tools install holds. `cmdtools install` extracting
4355
+ * only part of the archive leaves `bin/ohpm` in place, so "installed" alone does
4356
+ * not catch it (#16).
4357
+ */
4358
+ declare const CMD_TOOLS_REQUIRED: readonly ["bin/ohpm", "bin/hvigorw", "bin/codelinter", "hvigor", "ohpm", "codelinter", "tool/node", "sdk/default/openharmony/toolchains", "version.txt"];
4359
+ /** Parse `20` or `"6.0.0(20)"` to its API level. */
4360
+ declare function apiLevelOf(value: unknown): number | undefined;
4361
+ declare function describeProject(projectDir: string): DoctorProject;
4362
+ declare function checkNode(version?: string): DoctorCheck;
4363
+ /** The command-line tools are installed, complete, and of a recorded version. */
4364
+ declare function checkCmdTools(config: ConfigProvider, versions: DoctorVersions): DoctorCheck;
4365
+ /** codelinter only fully checks projects of its own flavour (#21). */
4366
+ declare function checkCmdToolsFlavour(versions: DoctorVersions, project: DoctorProject | undefined, toolsOk?: boolean): DoctorCheck;
4367
+ /** The signing material the project's signingConfigs name exists. */
4368
+ declare function checkSigning(project: DoctorProject): DoctorCheck;
4369
+ /** Free space where SDKs install and where the project builds. */
4370
+ declare function checkDisk(dirs: string[], statfs?: (dir: string) => {
4371
+ bavail: number;
4372
+ bsize: number;
4373
+ }): DoctorCheck;
4374
+ /** Run every check. Never throws for a failed check; `ok` is false when any check failed. */
4375
+ declare function runDoctor(opts: DoctorOptions): Promise<DoctorReport>;
4376
+
4377
+ interface ScreenPage {
4378
+ /**
4379
+ * The name a route uses to reach the page: the `main_pages.json` entry (`pages/Index`) for an `@Entry` page
4380
+ * (its `routeName` for a named route), the route name for a `NavDestination` (`Detail`), the struct name for a
4381
+ * `NavDestination` struct no route registers.
4382
+ */
4383
+ name: string;
4384
+ module: string;
4385
+ /** Project-relative path of the file declaring the page's component (or route-map builder). */
4386
+ file: string;
4387
+ line: number;
4388
+ /** The struct rendered as the page, when there is one. */
4389
+ component: string | null;
4390
+ /** The component is decorated `@Entry`. */
4391
+ entry: boolean;
4392
+ kind: 'entry' | 'navDestination';
4393
+ /** Listed in `main_pages.json`, a route map, a `.navDestination()` builder, or an `@Entry({ routeName })`. */
4394
+ registered: boolean;
4395
+ /**
4396
+ * Component calls the page renders, through its custom components and `@Builder`s, excluding layout
4397
+ * containers (`Column`, `Row`, `Stack`, `List`, `Navigation`, `NavDestination`, ...) and `Blank`/`Divider`.
4398
+ * Each `ForEach`/`LazyForEach`/`Repeat` item template and each `if` branch counts once.
4399
+ */
4400
+ contentNodes: number;
4401
+ /** Distinct literal route targets pushed from the page's component or the custom components it renders. */
4402
+ routesOut: string[];
4403
+ }
4404
+ interface ScreenRoute {
4405
+ /** The page whose component holds the call site, else the enclosing struct, class or function. */
4406
+ from: string;
4407
+ /** The target: a `pages/...` url, a NavDestination route name, or the source of a non-literal argument. */
4408
+ to: string;
4409
+ file: string;
4410
+ line: number;
4411
+ /** The call: `pushUrl`, `replaceUrl`, `pushNamedRoute`, `replaceNamedRoute`, `pushPath`, `pushPathByName`, `replacePath`, `replacePathByName`, `pushDestination`, `pushDestinationByName` or `loadContent`. */
4412
+ via: string;
4413
+ /** The target is not a string literal or a constant resolvable in the project (`to` is then its source text). */
4414
+ dynamic?: true;
4415
+ }
4416
+ interface ScreenPlaceholder {
4417
+ file: string;
4418
+ line: number;
4419
+ text: string;
4420
+ /** `comment` (TODO/FIXME), `text` (a placeholder-like string literal), `resource` (such a string in string.json), `empty-build`, `no-content` (a page that renders only containers). */
4421
+ kind: 'comment' | 'text' | 'resource' | 'empty-build' | 'no-content';
4422
+ }
4423
+ interface ScreensInventory {
4424
+ projectDir: string;
4425
+ modules: string[];
4426
+ pages: ScreenPage[];
4427
+ routes: ScreenRoute[];
4428
+ placeholders: ScreenPlaceholder[];
4429
+ /** Things the inventory could not resolve: a listed page whose file is missing, a route-map builder not found, ... */
4430
+ warnings: string[];
4431
+ }
4432
+ interface ScreensOptions {
4433
+ projectDir: string;
4434
+ }
4435
+ /** Layout-only components: they arrange content but are not content. */
4436
+ declare const LAYOUT_COMPONENTS: ReadonlySet<string>;
4437
+ /**
4438
+ * Build the static screen inventory of an OpenHarmony/HarmonyOS project: its pages (`@Entry` pages from
4439
+ * `main_pages.json`, `NavDestination`s from route maps and `.navDestination()` builders), the route call sites
4440
+ * between them, and placeholder markers. Reads every module in `build-profile.json5`; needs no SDK and no build.
4441
+ * Throws `OniroError` when the project cannot be read.
4442
+ */
4443
+ declare function inventoryScreens(opts: ScreensOptions): ScreensInventory;
4444
+
4445
+ interface ScreensSpec {
4446
+ /** Screens the spec asks for: a name, or a name with its own minimum. */
4447
+ screens?: Array<string | {
4448
+ name: string;
4449
+ minContentNodes?: number;
4450
+ }>;
4451
+ /** Routes the spec asks for. Without `from`, a push call site anywhere in the app satisfies it. */
4452
+ routes?: Array<{
4453
+ from?: string;
4454
+ to: string;
4455
+ }>;
4456
+ /** Content nodes every screen needs (default 1). */
4457
+ minContentNodes?: number;
4458
+ }
4459
+ interface ScreenSpecResult {
4460
+ name: string;
4461
+ ok: boolean;
4462
+ required: number;
4463
+ /** The best matching page (the one with the most content nodes). */
4464
+ page?: string;
4465
+ file?: string;
4466
+ contentNodes?: number;
4467
+ reason?: string;
4468
+ }
4469
+ interface RouteSpecResult {
4470
+ from?: string;
4471
+ to: string;
4472
+ ok: boolean;
4473
+ /** The first call site that satisfies the route. */
4474
+ site?: Pick<ScreenRoute, 'from' | 'to' | 'file' | 'line' | 'via'>;
4475
+ reason?: string;
4476
+ }
4477
+ interface ScreensSpecReport {
4478
+ ok: boolean;
4479
+ screens: ScreenSpecResult[];
4480
+ routes: RouteSpecResult[];
4481
+ /** One line per failed screen or route. */
4482
+ failures: string[];
4483
+ }
4484
+ /** Pages a spec name refers to, by route name, last path segment (`pages/Detail` -> `Detail`) or component, ignoring case. */
4485
+ declare function pagesMatching(inventory: Pick<ScreensInventory, 'pages'>, name: string): ScreenPage[];
4486
+ /**
4487
+ * The G2 gate as a pure function of a `screens` inventory: every spec screen has a page with at least
4488
+ * `minContentNodes` content nodes, and every spec route has a push or replace call site (`router.pushUrl`,
4489
+ * `NavPathStack.pushPathByName`, ...; `loadContent` and non-literal targets do not count). A route's `from`
4490
+ * matches the page holding the call site, or a page whose `routesOut` (which includes the custom components it
4491
+ * renders) has the target. Names match a page's route name, its last path segment or its component, ignoring case.
4492
+ */
4493
+ declare function checkScreensAgainstSpec(inventory: Pick<ScreensInventory, 'pages' | 'routes'>, spec: ScreensSpec): ScreensSpecReport;
4494
+
4495
+ /**
4496
+ * A small token scanner and declaration finder for ArkTS (`.ets`) sources.
4497
+ *
4498
+ * Plain TypeScript cannot parse ArkTS: `struct`, the UI trailing-closure syntax
4499
+ * (`Column() { Text('a') }`) and `$r`/`$$` are not TypeScript. The screen
4500
+ * inventory only needs tokens with line numbers, matched brackets, and the
4501
+ * struct, class, function and method declarations with their decorators, so a
4502
+ * scanner that gets comments, strings, template literals and regex literals
4503
+ * right is enough, needs no dependency, and does not depend on an SDK being
4504
+ * installed.
4505
+ */
4506
+ type TokenKind = 'ident' | 'string' | 'template' | 'number' | 'punct' | 'regex' | 'eof';
4507
+ interface Token {
4508
+ kind: TokenKind;
4509
+ /** Source text of the token (for strings and templates, including the quotes). */
4510
+ value: string;
4511
+ /** For `string` and `template` tokens: the unquoted text (a template's static parts only). */
4512
+ text: string;
4513
+ /** 1-based line of the token's first character. */
4514
+ line: number;
4515
+ start: number;
4516
+ end: number;
4517
+ }
4518
+ interface SourceComment {
4519
+ text: string;
4520
+ line: number;
4521
+ }
4522
+ interface Decorator {
4523
+ name: string;
4524
+ /** Index of the `(` of the decorator's arguments, when it has any. */
4525
+ argsOpen?: number;
4526
+ }
4527
+ interface Declaration {
4528
+ kind: 'struct' | 'class' | 'function' | 'enum' | 'namespace' | 'object';
4529
+ name: string;
4530
+ decorators: Decorator[];
4531
+ /** Index of the name token. */
4532
+ nameIndex: number;
4533
+ line: number;
4534
+ /** Indices of the body's `{` and `}`. */
4535
+ bodyOpen: number;
4536
+ bodyClose: number;
4537
+ }
4538
+ interface ScannedSource {
4539
+ src: string;
4540
+ tokens: Token[];
4541
+ comments: SourceComment[];
4542
+ /** For each bracket token, the index of its partner; -1 for other tokens or an unbalanced bracket. */
4543
+ match: Int32Array;
4544
+ declarations: Declaration[];
4545
+ }
4546
+ /** Tokenize an ArkTS/TypeScript source, keeping comments aside. */
4547
+ declare function scanEts(src: string): ScannedSource;
4548
+
4549
+ /**
4550
+ * Types of the SDK declaration index behind `oniro-app api search` and `api show`:
4551
+ * every class, interface, function, member, enum, ArkUI component and decorator the
4552
+ * ArkTS declaration files of one SDK API level declare, and the Node-API C functions,
4553
+ * types and macros its native sysroot headers declare.
4554
+ */
4555
+ type ApiSymbolKind = 'namespace' | 'class' | 'interface' | 'enum' | 'enumMember' | 'type' | 'function' | 'method' | 'constructor' | 'property' | 'variable'
4556
+ /** An ArkUI built-in component (`declare const Column: ColumnInterface`) or a declared `struct`. */
4557
+ | 'component'
4558
+ /** An ArkUI decorator (`declare const Local: PropertyDecorator`). */
4559
+ | 'decorator'
4560
+ /** C: a `#define`. */
4561
+ | 'macro'
4562
+ /** C: a `typedef`. */
4563
+ | 'typedef'
4564
+ /** C: a `typedef struct { ... }`. */
4565
+ | 'struct';
4566
+ type ApiLanguage = 'arkts' | 'c';
4567
+ interface ApiEntry {
4568
+ /** The declared name: `pushPathByName`. */
4569
+ name: string;
4570
+ /** The name with its enclosing namespaces, classes and interfaces: `NavPathStack.pushPathByName`. */
4571
+ qualifiedName: string;
4572
+ kind: ApiSymbolKind;
4573
+ language: ApiLanguage;
4574
+ /**
4575
+ * The module that declares it: `@ohos.router`, `@arkts.collections`, a path under
4576
+ * `ets/api` for files that are not modules (`application/UIAbilityContext`), `component/navigation`
4577
+ * for the global ArkUI declarations, or the header (`napi/native_api.h`).
4578
+ */
4579
+ module: string;
4580
+ /** The kit that exports it (`@kit.ArkUI`): from the `ets/kits` re-exports, else the file's `@kit` tag. */
4581
+ kit?: string;
4582
+ /** How an app imports it, when a kit or module exports it: `import { router } from '@kit.ArkUI'`. */
4583
+ import?: string;
4584
+ /** Declared globally (the ArkUI component files): usable without an import. */
4585
+ global?: boolean;
4586
+ /** The API level that introduced it: the lowest `@since` of its doc comments (or its parent's). */
4587
+ since?: number;
4588
+ /** The `@since` values as written, when one carries more than a number (`12 dynamic`, `23 static`). */
4589
+ sinceText?: string;
4590
+ /** `@deprecated` as written (`since 9`); an empty string when the tag has no text. */
4591
+ deprecated?: string;
4592
+ /** The API level of `@deprecated since N`. */
4593
+ deprecatedSince?: number;
4594
+ /** `@useinstead`: what to use instead. */
4595
+ useInstead?: string;
4596
+ /** `@syscap`. */
4597
+ syscap?: string;
4598
+ /** `@systemapi`: only system apps may call it. */
4599
+ systemApi?: boolean;
4600
+ /** The file that declares it, relative to the SDK directory (`ets/component/navigation.d.ts`). */
4601
+ file: string;
4602
+ /** 1-based line of the declaration (not of its doc comment). */
4603
+ line: number;
4604
+ /** The declaration text, whitespace collapsed (the header only for classes, interfaces, namespaces and enums). */
4605
+ signature: string;
4606
+ /** The first line of its doc comment. */
4607
+ doc?: string;
4608
+ }
4609
+ /** The index of one SDK directory. */
4610
+ interface ApiIndex {
4611
+ /** Bumped whenever the shape or the extraction changes, so old caches are rebuilt. */
4612
+ format: number;
4613
+ /** The SDK API directory indexed (holding `ets/` and `native/`). */
4614
+ sdkDir: string;
4615
+ /** The API level from `ets/oh-uni-package.json`. */
4616
+ api?: number;
4617
+ /** The SDK version from `ets/oh-uni-package.json` (`6.0.0.47`). */
4618
+ sdkVersion?: string;
4619
+ /** What the cache is keyed by: the SDK directory and the mtimes of its `oh-uni-package.json` files. */
4620
+ key: string;
4621
+ builtAt: string;
4622
+ /** Declaration files read. */
4623
+ files: number;
4624
+ buildMs: number;
4625
+ entries: ApiEntry[];
4626
+ }
4627
+
4628
+ /**
4629
+ * Build, cache and load the declaration index of one SDK API directory.
4630
+ *
4631
+ * Sources, relative to the SDK directory:
4632
+ * - `ets/api/**` and `ets/arkts/**` (`.d.ts`, `.d.ets`): the `@ohos.*` and `@arkts.*` modules;
4633
+ * - `ets/component/**`: the global ArkUI component and decorator declarations;
4634
+ * - `ets/kits/@kit.*.d.ts`: which kit re-exports each module symbol (no entries of their own);
4635
+ * - `native/sysroot/usr/include/{napi/*.h,node_api*.h,js_native_api*.h}`: Node-API.
4636
+ *
4637
+ * The index is JSON, cached per SDK directory and rebuilt when the mtime of its
4638
+ * `oh-uni-package.json` files (rewritten by an SDK install) or the index format changes.
4639
+ */
4640
+ declare const API_INDEX_FORMAT = 1;
4641
+ interface BuildApiIndexOptions {
4642
+ /**
4643
+ * The TypeScript module to parse with. By default the SDK's bundled one
4644
+ * (`ets/build-tools/ets-loader/node_modules/typescript`), else one resolvable from here.
4645
+ */
4646
+ typescript?: unknown;
4647
+ logger?: Logger;
4648
+ }
4649
+ /** What a cached index of `sdkDir` must match to be reused. */
4650
+ declare function apiIndexKey(sdkDir: string): string;
4651
+ /** Build the index of one SDK API directory (holding `ets/`, and `native/` for Node-API). */
4652
+ declare function buildApiIndex(sdkDir: string, opts?: BuildApiIndexOptions): ApiIndex;
4653
+ /** The cache file of `sdkDir`'s index under `cacheDir`. */
4654
+ declare function apiIndexCachePath(cacheDir: string, sdkDir: string): string;
4655
+ declare function serializeApiIndex(index: ApiIndex): string;
4656
+ declare function deserializeApiIndex(json: string): ApiIndex;
4657
+ interface LoadApiIndexOptions extends BuildApiIndexOptions {
4658
+ /** Where indexes are cached (an `api-index/` folder is created in it). Omit to not cache. */
4659
+ cacheDir?: string;
4660
+ /** Rebuild even when the cache is current. */
4661
+ rebuild?: boolean;
4662
+ }
4663
+ interface LoadedApiIndex {
4664
+ index: ApiIndex;
4665
+ /** True when it came from the cache. */
4666
+ cached: boolean;
4667
+ cachePath?: string;
4668
+ /** Wall time to load or build it. */
4669
+ loadMs: number;
4670
+ }
4671
+ /** The index of `sdkDir`: the cached one when it is current, else a new build (then cached). */
4672
+ declare function loadApiIndex(sdkDir: string, opts?: LoadApiIndexOptions): LoadedApiIndex;
4673
+
4674
+ /**
4675
+ * Ranked token search and exact lookup over an `ApiIndex`, in process.
4676
+ *
4677
+ * Each whitespace-separated query token must match an entry, in its name or
4678
+ * qualified name, or in its doc line; the scores add up. Per token, best first:
4679
+ * the exact name, the exact qualified name or a dotted suffix of it
4680
+ * (`router.pushUrl`), a name prefix, a camelCase or snake_case part of the name
4681
+ * (`Path` in `pushPathByName`), a substring of the name, then a word in the doc
4682
+ * line. Ties go to types over members, then current over deprecated, public over
4683
+ * system APIs, and shorter names.
4684
+ */
4685
+ interface ApiSearchOptions {
4686
+ /** Only entries a kit exports: `ArkUI`, `@kit.ArkUI` (case-insensitive). */
4687
+ kit?: string;
4688
+ /** Only these kinds. */
4689
+ kinds?: readonly ApiSymbolKind[];
4690
+ /** Only `arkts` (ArkTS declarations) or `c` (Node-API headers). */
4691
+ language?: 'arkts' | 'c';
4692
+ /** Leave out `@deprecated` entries. */
4693
+ noDeprecated?: boolean;
4694
+ /** Leave out `@systemapi` entries. */
4695
+ noSystemApi?: boolean;
4696
+ /** At most this many hits. Default 20. */
4697
+ limit?: number;
4698
+ }
4699
+ interface ApiSearchHit extends ApiEntry {
4700
+ score: number;
4701
+ /** Other declarations of the same symbol in the same file (overloads), not listed separately. */
4702
+ overloads?: number;
4703
+ }
4704
+ interface ApiSearchResult {
4705
+ query: string;
4706
+ /** Distinct symbols that matched, before the limit. */
4707
+ total: number;
4708
+ hits: ApiSearchHit[];
4709
+ }
4710
+ /** `ArkUI`, `arkui`, `@kit.ArkUI` -> `@kit.arkui`. */
4711
+ declare function normalizeKit(kit: string): string;
4712
+ /** `pushPathByName` -> push, path, by, name; `napi_create_object` -> napi, create, object. */
4713
+ declare function nameParts(name: string): string[];
4714
+ /** Ranked search of `index` for `query`. */
4715
+ declare function searchApi(index: ApiIndex, query: string, opts?: ApiSearchOptions): ApiSearchResult;
4716
+ interface ApiShowResult {
4717
+ symbol: string;
4718
+ found: boolean;
4719
+ /** Every declaration of it (overloads included), exact qualified-name matches first. */
4720
+ entries: ApiEntry[];
4721
+ }
4722
+ /**
4723
+ * Exact lookup: the declarations whose qualified name is `symbol` (`NavPathStack.pushPathByName`,
4724
+ * `router.pushUrl`, `Column`, `@Local`), or, when none is, whose qualified name ends with
4725
+ * `.symbol` (`Preferences.get` finds `preferences.Preferences.get`). Case-sensitive.
4726
+ */
4727
+ declare function showApi(index: ApiIndex, symbol: string, opts?: Pick<ApiSearchOptions, 'kit' | 'kinds' | 'language'>): ApiShowResult;
4728
+
4729
+ /** Which SDK API directory `api search` and `api show` read, and why. */
4730
+ interface ApiSdkSelection {
4731
+ sdkDir: string;
4732
+ api?: number;
4733
+ source: 'sdk-option' | 'api-option' | 'project' | 'newest-installed';
4734
+ /** Why the SDK is not the one the project asks for, when it is not. */
4735
+ note?: string;
4736
+ }
4737
+ interface ResolveApiSdkOptions {
4738
+ /** An SDK API directory (holding `ets/`), used as is. */
4739
+ sdkDir?: string;
4740
+ /** An API level: `<sdk home>/<api>`. */
4741
+ api?: number;
4742
+ /** A project directory; its `compileSdkVersion` picks the SDK. Searched upwards for `build-profile.json5`. */
4743
+ projectDir?: string;
4744
+ }
4745
+ /** The installed OpenHarmony SDK API levels under the SDK home, newest first. */
4746
+ declare function installedApiLevels(config: ConfigProvider): number[];
4747
+ /**
4748
+ * Pick the SDK: `sdkDir`, else `<sdk home>/<api>`, else the one the enclosing
4749
+ * project's `compileSdkVersion` names (as hvigor finds it), else the newest installed.
4750
+ */
4751
+ declare function resolveApiSdk(config: ConfigProvider, opts?: ResolveApiSdkOptions): ApiSdkSelection;
4752
+ /** Where API indexes are cached: `<cacheDir>/api-index/` (`cacheDir` defaults to `~/.oniro/cache`). */
4753
+ declare function getApiIndexCacheDir(config: ConfigProvider): string;
4754
+
4755
+ /**
4756
+ * The doc-comment tags the index records, read from the `/** ... *\/` blocks before a
4757
+ * declaration. OpenHarmony stacks one block per API level that changed a symbol's
4758
+ * documentation (the `@since 10` block, then the `@since 11` block that adds
4759
+ * `@atomicservice`, ...), so a symbol's facts come from all of its blocks.
4760
+ */
4761
+ interface DocTags {
4762
+ /** The lowest numeric `@since`. */
4763
+ since?: number;
4764
+ /** The `@since` values with a qualifier (`12 dynamic`), joined with `, `. */
4765
+ sinceText?: string;
4766
+ deprecated?: string;
4767
+ deprecatedSince?: number;
4768
+ useInstead?: string;
4769
+ syscap?: string;
4770
+ systemApi?: boolean;
4771
+ /** `@kit` (on a file's `@file` block): `ArkUI`. */
4772
+ kit?: string;
4773
+ /** The block is a file header (`@file`, `@addtogroup`), not a declaration's doc. */
4774
+ fileHeader?: boolean;
4775
+ doc?: string;
4776
+ }
4777
+ /** The tags of one block. */
4778
+ declare function parseDocBlock(block: string): DocTags;
4779
+ /**
4780
+ * The tags of a declaration from all its doc blocks, oldest first: the lowest
4781
+ * `@since` (of the public blocks, when the newest block is public), a deprecation
4782
+ * from any block, and the syscap, system-API flag and doc line of the newest block.
4783
+ * File-header blocks are skipped.
4784
+ */
4785
+ declare function mergeDocBlocks(blocks: readonly string[]): DocTags;
4786
+
4787
+ /**
4788
+ * `api show` beyond the exact lookup: on a miss, which other installed SDKs declare
4789
+ * the symbol, and the close names this SDK does declare. This is the answer to "does
4790
+ * this member exist at this API level": a hallucinated member gets the real ones.
4791
+ */
4792
+ interface ApiElsewhere {
4793
+ api: number;
4794
+ /** The lowest `@since` of its declarations there. */
4795
+ since?: number;
4796
+ }
4797
+ /**
4798
+ * Close names for a symbol `index` does not declare: for `Parent.member`, the
4799
+ * members of `Parent` sharing a camelCase part with `member` (most shared first), then
4800
+ * the search hits for `member` itself, else the first functions and methods of `Parent`.
4801
+ */
4802
+ declare function suggestApiSymbols(index: ApiIndex, symbol: string, limit?: number): string[];
4803
+ interface FindInOtherSdksOptions {
4804
+ cacheDir?: string;
4805
+ kit?: string;
4806
+ logger?: Logger;
4807
+ }
4808
+ /** The installed SDKs other than `exceptSdkDir` that declare `symbol`, newest first. Builds their indexes if needed. */
4809
+ declare function findApiInOtherSdks(config: ConfigProvider, symbol: string, exceptSdkDir: string, opts?: FindInOtherSdksOptions): ApiElsewhere[];
4810
+
4811
+ /**
4812
+ * What a faultlog is. `sample_stack` is the periodic stack sampling hiview adds
4813
+ * to a freeze (`freeze-cpuinfo-ext-*`), not a fault of its own.
4814
+ */
4815
+ type FaultLogKind = 'cpp_crash' | 'js_crash' | 'app_freeze' | 'sample_stack' | 'unknown';
4816
+ /** The three kinds that are a fault of the process. */
4817
+ type FaultLogFamily = 'cpp_crash' | 'js_crash' | 'app_freeze';
4818
+ declare const FAULT_LOG_FAMILIES: readonly FaultLogFamily[];
4819
+ type FaultConfidence = 'high' | 'medium' | 'low';
4820
+ /** `full`: the faultlog's header region is present; `fragment`: a pasted excerpt. */
4821
+ type FaultCompleteness = 'full' | 'fragment';
4822
+ interface FaultLogClassification {
4823
+ kind: FaultLogKind;
4824
+ /** For `app_freeze`, the event (`THREAD_BLOCK_6S`, `APP_INPUT_BLOCK`, `LIFECYCLE_TIMEOUT`). */
4825
+ subtype?: string;
4826
+ confidence: FaultConfidence;
4827
+ completeness: FaultCompleteness;
4828
+ /** Why the kind was chosen. */
4829
+ evidence: string[];
4830
+ /** Why each other kind was ruled out. */
4831
+ excluded: Array<{
4832
+ kind: FaultLogFamily;
4833
+ reason: string;
4834
+ }>;
4835
+ /** Set when several kinds matched and no rule picks one (`kind: 'unknown'`), or the runner-up of a mixed fragment. */
4836
+ candidates: Array<{
4837
+ kind: FaultLogFamily;
4838
+ confidence: FaultConfidence;
4839
+ evidence: string[];
4840
+ arbitrable: boolean;
4841
+ }>;
4842
+ /** Set when the input is not a faultlog at all. */
4843
+ outOfScope?: {
4844
+ reason: 'empty' | 'hilog_stream' | 'other_platform';
4845
+ detail: string;
4846
+ };
4847
+ }
4848
+ /** A faultlog above this is refused rather than silently truncated. */
4849
+ declare const MAX_FAULTLOG_BYTES: number;
4850
+ /**
4851
+ * Classify faultlog text by its structure alone (never by file name), so the
4852
+ * same input always gets the same answer. Order: a whole faultlog's header,
4853
+ * then sample-stack markers, then the patterns of an excerpt.
4854
+ */
4855
+ declare function classifyFaultLog(input: string): FaultLogClassification;
4856
+
4857
+ /** `Tid:20020, Name:com.example.app` (leading space tolerated, as in cppcrash). */
4858
+ declare const THREAD_HEADER_RE: RegExp;
4859
+ /** Where a frame's code lives: the OS, the app, or something else (an anonymous mapping). */
4860
+ type FrameArea = 'system' | 'app' | 'other';
4861
+ interface NativeFrame {
4862
+ index: number;
4863
+ pc: string;
4864
+ /** Library or executable path, e.g. `/system/lib64/libace_compatible.z.so` or `[shmm]`. */
4865
+ library: string;
4866
+ /** `do_dlsym+492`, when the log has one. */
4867
+ symbol: string | null;
4868
+ buildId: string | null;
4869
+ area: FrameArea;
4870
+ /** The line as printed, trimmed. */
4871
+ raw: string;
4872
+ }
4873
+ interface JsFrame {
4874
+ /** Function name (`anonymous` for lambdas), when the line has one. */
4875
+ function: string | null;
4876
+ /** Module after the function name (`entry`), when the line has one. */
4877
+ module: string | null;
4878
+ file: string;
4879
+ line: number;
4880
+ column: number;
4881
+ /** In the project's own sources (`<module>/src/main/…`), not the SDK or a dependency. */
4882
+ project: boolean;
4883
+ raw: string;
4884
+ }
4885
+ type StackFrame = ({
4886
+ kind: 'native';
4887
+ } & NativeFrame) | ({
4888
+ kind: 'js';
4889
+ } & JsFrame);
4890
+ interface ThreadStack {
4891
+ tid: string;
4892
+ name: string;
4893
+ frames: StackFrame[];
4894
+ }
4895
+ /** Parse one native frame line, or `null` if it is not one. */
4896
+ declare function parseNativeFrame(line: string): NativeFrame | null;
4897
+ /** Parse one ArkTS/JS frame line, or `null` if it is not one. */
4898
+ declare function parseJsFrame(line: string): JsFrame | null;
4899
+ /** Parse a native or JS frame line. */
4900
+ declare function parseFrame(line: string): StackFrame | null;
4901
+ /** Split stack text at `Tid:…, Name:…` headers. A repeated tid replaces the earlier one. */
4902
+ declare function parseThreadStacks(lines: readonly string[]): Map<string, ThreadStack>;
4903
+ /** The stack-capture error lines in a section, each with what it means (deduplicated). */
4904
+ declare function extractStackErrors(lines: readonly string[]): string[];
4905
+
4906
+ interface BinderNode {
4907
+ pid: string;
4908
+ tid: string;
4909
+ }
4910
+ /** One binder transaction from the freeze log's BinderCatcher section. */
4911
+ interface BinderTransaction {
4912
+ srcPid: string;
4913
+ srcTid: string;
4914
+ dstPid: string;
4915
+ dstTid: string;
4916
+ code: string;
4917
+ waitSeconds: number;
4918
+ frzState: string;
4919
+ async: boolean;
4920
+ raw: string;
4921
+ }
4922
+ interface BinderInfo {
4923
+ transactions: BinderTransaction[];
4924
+ /** pid → process name, from the peers' stacks. */
4925
+ peers: Map<string, string>;
4926
+ }
4927
+ /** One synchronous wait in the chain the faulting thread belongs to. */
4928
+ interface BinderEdge {
4929
+ /** `pid:tid(process/thread)`; a tid of 0 means every binder thread of the process is busy (IPC full). */
4930
+ from: string;
4931
+ to: string;
4932
+ waitSeconds: number;
4933
+ code: string;
4934
+ frzState?: string;
4935
+ }
4936
+ interface BinderPropagation {
4937
+ /** Longest wait first. */
4938
+ edges: BinderTransaction[];
4939
+ /** Deadlock cycles, one representative per strongly connected group. */
4940
+ cycles: BinderNode[][];
4941
+ notes: string[];
4942
+ }
4943
+ /** `pid:tid(process/thread)`; the main thread's name usually equals the process name, so it is shown once. */
4944
+ declare function nodeLabel(node: BinderNode, processNames: Map<string, string>, threadNames?: Map<string, string>): string;
4945
+ /** Parse the BinderCatcher section: transactions, then the peers' stacks. */
4946
+ declare function parseBinder(lines: readonly string[]): BinderInfo;
4947
+ /**
4948
+ * The synchronous binder chain the faulting thread is part of: what it waits on
4949
+ * (downstream) and who waits on it (upstream), anchored on every thread of the
4950
+ * faulting process that appears in a transaction, plus any deadlock cycles.
4951
+ */
4952
+ declare function buildPropagation(binder: BinderInfo, faultPid: string, faultTid: string): BinderPropagation;
4953
+
4954
+ declare const CPP_HEADER: {
4955
+ readonly module: RegExp;
4956
+ readonly version: RegExp;
4957
+ readonly pid: RegExp;
4958
+ readonly uid: RegExp;
4959
+ readonly process: RegExp;
4960
+ readonly lifetime: RegExp;
4961
+ readonly timestamp: RegExp;
4962
+ readonly reason: RegExp;
4963
+ readonly lastFatalMessage: RegExp;
4964
+ };
4965
+ interface CppCrashLog {
4966
+ header: Partial<Record<keyof typeof CPP_HEADER, string>>;
4967
+ /** The first thread of `Fault thread info:`. */
4968
+ faultThread: ThreadStack | null;
4969
+ /** The GWP-ASan report, from its banner to its end marker. */
4970
+ gwpAsan: string;
4971
+ }
4972
+ declare function parseCppCrash(lines: readonly string[]): CppCrashLog;
4973
+ declare const JS_HEADER: {
4974
+ readonly module: RegExp;
4975
+ readonly process: RegExp;
4976
+ readonly package: RegExp;
4977
+ readonly version: RegExp;
4978
+ readonly pid: RegExp;
4979
+ readonly uid: RegExp;
4980
+ readonly faultTime: RegExp;
4981
+ readonly timestamp: RegExp;
4982
+ readonly reason: RegExp;
4983
+ readonly errorName: RegExp;
4984
+ readonly errorMessage: RegExp;
4985
+ readonly errorCode: RegExp;
4986
+ };
4987
+ interface JsCrashLog {
4988
+ header: Partial<Record<keyof typeof JS_HEADER, string>>;
4989
+ faultTid: string;
4990
+ faultThreadName: string;
4991
+ /** The `Stacktrace:` section, one frame per line as printed. */
4992
+ stack: string[];
4993
+ /** The same frames, parsed. */
4994
+ frames: StackFrame[];
4995
+ /** The `HybridStack:` section (native and JS frames interleaved), when present. */
4996
+ hybrid: StackFrame[];
4997
+ }
4998
+ declare function parseJsCrash(lines: readonly string[]): JsCrashLog;
4999
+ declare const FREEZE_HEADER: {
5000
+ readonly module: RegExp;
5001
+ readonly reason: RegExp;
5002
+ readonly process: RegExp;
5003
+ readonly pid: RegExp;
5004
+ };
5005
+ declare const FREEZE_MSG: {
5006
+ readonly eventName: RegExp;
5007
+ readonly timestamp: RegExp;
5008
+ readonly pid: RegExp;
5009
+ readonly tid: RegExp;
5010
+ readonly process: RegExp;
5011
+ readonly msg: RegExp;
5012
+ readonly faultTime: RegExp;
5013
+ };
5014
+ interface FreezeReport {
5015
+ msg: Partial<Record<keyof typeof FREEZE_MSG, string>>;
5016
+ stacks: Map<string, ThreadStack>;
5017
+ stackErrors: string[];
5018
+ }
5019
+ interface FreezeLog {
5020
+ header: Partial<Record<keyof typeof FREEZE_HEADER, string>>;
5021
+ /** The header's Reason, else the event name. */
5022
+ reason: string;
5023
+ /** The first report (warning). */
5024
+ warning: FreezeReport;
5025
+ /** The second report (block), taken a few seconds later, when present. */
5026
+ block: FreezeReport | null;
5027
+ binder: BinderInfo;
5028
+ /** tid of the FFRT worker running the blocked queue task, when there is one. */
5029
+ ffrtTid: string;
5030
+ /** pid → process name, for labelling binder nodes. */
5031
+ processNames: Map<string, string>;
5032
+ pid: string;
5033
+ process: string;
5034
+ /** The blocked thread: the FFRT worker when the queue is blocked, else the reported TID, else the main thread. */
5035
+ faultTid: string;
5036
+ }
5037
+ declare function parseFreeze(lines: readonly string[]): FreezeLog;
5038
+
5039
+ /**
5040
+ * The native crash record faultloggerd writes to `/data/log/faultlog/temp/`
5041
+ * (`cppcrash-<pid>-<epoch ms>.json`) before hiview turns it into a cppcrash
5042
+ * faultlog. When hiview refuses the record (on some builds it does not
5043
+ * recognise processdump at `/root/system/bin/processdump` and logs
5044
+ * `Fail to add fault log … is not processdump`), this file is the only record
5045
+ * of an app's native crash. Written for this package; not part of the deveco-cli port.
5046
+ */
5047
+ interface JsonFrame {
5048
+ pc?: string;
5049
+ symbol?: string;
5050
+ offset?: number;
5051
+ file?: string;
5052
+ buildId?: string;
5053
+ /** JS frames carry these instead of `pc`. */
5054
+ packageName?: string;
5055
+ line?: number;
5056
+ column?: number;
5057
+ }
5058
+ interface JsonThread {
5059
+ thread_name?: string;
5060
+ tid?: number;
5061
+ frames?: JsonFrame[];
5062
+ }
5063
+ interface CrashJson {
5064
+ JSON_VERSION?: string;
5065
+ BUILD_INFO?: string;
5066
+ TIMESTAMP?: string;
5067
+ PID?: number;
5068
+ UID?: number;
5069
+ PNAME?: string;
5070
+ PROCESS_LIFETIME?: string;
5071
+ LOG_SOURCE?: string;
5072
+ REASON?: string;
5073
+ LAST_FATAL_MESSAGE?: string;
5074
+ KEY_THREAD_INFO?: JsonThread;
5075
+ OTHER_THREAD_INFO?: JsonThread[];
5076
+ KEY_THREAD_REGISTERS?: string;
5077
+ }
5078
+ /** Whether text is a faultloggerd crash record rather than a faultlog. */
5079
+ declare function isCrashJson(text: string): boolean;
5080
+ /**
5081
+ * Render a crash record as the cppcrash faultlog hiview would have written, so
5082
+ * one parser reads both. Throws on invalid JSON.
5083
+ */
5084
+ declare function renderCrashJson(text: string): string;
5085
+
5086
+ /** The trailing `HiLog:` section of a faultlog (from that line on), or `''`. */
5087
+ declare function hilogSection(lines: readonly string[]): string;
5088
+
5089
+ /** One fault, read from a faultlog: what kind, where it happened, and why. */
5090
+ interface CrashVerdict {
5091
+ /** A process fault (`cpp_crash`, `js_crash` or `app_freeze`); false for a sample stack or an unrecognised log. */
5092
+ crashed: boolean;
5093
+ kind: FaultLogKind;
5094
+ /** For `app_freeze`, the event (`THREAD_BLOCK_6S`, `APP_INPUT_BLOCK`, `LIFECYCLE_TIMEOUT`). */
5095
+ subtype: string | null;
5096
+ confidence: FaultConfidence;
5097
+ completeness: FaultCompleteness;
5098
+ /** The app's bundle name (`Module name:` of an app's faultlog; for a native service, its module). */
5099
+ bundle: string | null;
5100
+ process: string | null;
5101
+ pid: number | null;
5102
+ uid: number | null;
5103
+ /** The faulting (or blocked) thread. */
5104
+ tid: number | null;
5105
+ threadName: string | null;
5106
+ /** When the fault happened, as the log prints it (device local time, `YYYY-MM-DD HH:MM:SS.mmm`). */
5107
+ time: string | null;
5108
+ /** `Reason:` — the signal (`Signal:SIGSEGV(SEGV_MAPERR)@0x0 …`), the JS error class, or the freeze event. */
5109
+ reason: string | null;
5110
+ /** The top frame of the faulting thread, as printed. */
5111
+ topFrame: string | null;
5112
+ /** The first frame in the app's own code: an ArkTS frame under `<module>/src/main/`, else a native frame in the app's libraries. */
5113
+ projectFrame: string | null;
5114
+ /** Source position of the first project ArkTS frame, as the log prints it (`entry/src/main/ets/pages/Index.ets`). */
5115
+ file: string | null;
5116
+ line: number | null;
5117
+ column: number | null;
5118
+ /** For a JS crash: the error and its stack. */
5119
+ jsError: {
5120
+ name: string;
5121
+ message: string;
5122
+ stack: string[];
5123
+ } | null;
5124
+ /** Every frame of the faulting thread as printed, native and ArkTS interleaved, top first (for a freeze, from the first report). */
5125
+ stack: string[];
5126
+ /** Native frames of the faulting thread (for a freeze, from the first report). */
5127
+ nativeFrames: NativeFrame[];
5128
+ /** ArkTS frames of the faulting thread. */
5129
+ jsFrames: JsFrame[];
5130
+ /** For a freeze: the synchronous binder calls the blocked thread is part of, longest wait first. */
5131
+ binderChain: BinderEdge[];
5132
+ /** For a freeze: binder deadlock cycles, `a -> b -> a`. */
5133
+ deadlocks: string[];
5134
+ /** Notes on the binder chain, the stack capture, or the classification. */
5135
+ notes: string[];
5136
+ /** cppcrash `LastFatalMessage:` (an abort message), when present. */
5137
+ lastFatalMessage: string | null;
5138
+ /** cppcrash GWP-ASan report, when present. */
5139
+ gwpAsan: string | null;
5140
+ /** Why the kind was chosen. */
5141
+ evidence: string[];
5142
+ /** The faultlog's file name, e.g. `jscrash-com.example.app-20010043-20261105123257298.log`. */
5143
+ name: string | null;
5144
+ /** Where the faultlog is: its path on the device, or the local file it was read from. */
5145
+ path: string | null;
5146
+ /** A local copy of the whole faultlog, when one was saved. */
5147
+ rawPath: string | null;
5148
+ }
5149
+ interface AnalyzeFaultLogOptions {
5150
+ name?: string;
5151
+ path?: string;
5152
+ rawPath?: string;
5153
+ }
5154
+ /** Freeze logs print `2026/11/05-12:42:29[:053]`; give every kind `2026-11-05 12:42:29[.053]`. */
5155
+ declare function normalizeFaultTime(value: string | undefined): string | null;
5156
+ /**
5157
+ * Classify a faultlog and read its fault: kind and confidence, the process, the
5158
+ * reason, the top and first project frames (with `file:line:column` for ArkTS),
5159
+ * the JS error, the native frames and, for a freeze, the binder chain.
5160
+ */
5161
+ declare function analyzeFaultLog(input: string, opts?: AnalyzeFaultLogOptions): CrashVerdict;
5162
+
5163
+ /** Where hiview keeps faultlogs. */
5164
+ declare const FAULTLOG_DIR = "/data/log/faultlog/faultlogger";
5165
+ /** Where faultloggerd leaves native crash records (`cppcrash-<pid>-<epoch ms>.json`). */
5166
+ declare const FAULTLOG_TEMP_DIR = "/data/log/faultlog/temp";
5167
+ /** `hidumper -s 1201` is hiview; `-p Faultlogger` its faultlog plugin. */
5168
+ declare const faultloggerCommand: (args: string) => string;
5169
+ interface FaultLogEntry {
5170
+ /** File name, e.g. `jscrash-com.example.app-20010043-20261105123257298.log`. */
5171
+ name: string;
5172
+ /** Path on the device. */
5173
+ path: string;
5174
+ /** `faultlogger`: a hiview faultlog; `temp`: a faultloggerd crash record hiview has not (or will not) turn into one. */
5175
+ source: 'faultlogger' | 'temp';
5176
+ /** The file-name prefix: `cppcrash`, `jscrash`, `appfreeze`, `sysfreeze`, `syswarning`, … */
5177
+ type: string;
5178
+ /** Bundle or process name. */
5179
+ module: string | null;
5180
+ pid: number | null;
5181
+ uid: number | null;
5182
+ /** Device-local time of the fault, `YYYY-MM-DD HH:MM:SS.mmm`. */
5183
+ time: string | null;
5184
+ /** The fault's instant, when known: always for a crash record, for a faultlog when the device's UTC offset was read. */
5185
+ epochMs: number | null;
5186
+ }
5187
+ interface FaultLogDeviceOptions {
5188
+ config: ConfigProvider;
5189
+ deviceSerial?: string;
5190
+ timeoutMs?: number;
5191
+ logger?: Logger;
5192
+ }
5193
+ interface ListFaultLogsOptions extends FaultLogDeviceOptions {
5194
+ /** Only entries of this bundle (exact module/process name). */
5195
+ bundle?: string;
5196
+ /** Only entries since this instant, or since this many seconds before the device's clock now. */
5197
+ since?: Date | number;
5198
+ /** Also list faultloggerd's native crash records that have no faultlog. Default true. */
5199
+ includeCrashRecords?: boolean;
5200
+ }
5201
+ /** The file names between the `******` lines of `hidumper … -p Faultlogger -l`, or null if the output is not a list. */
5202
+ declare function parseFaultLogList(stdout: string): string[] | null;
5203
+ /**
5204
+ * Read `<type>-<module>-<uid>-<yyyyMMddHHmmss[SSS]>.log`. `utcOffsetMinutes`
5205
+ * (the device's) turns the local time into `epochMs`.
5206
+ */
5207
+ declare function parseFaultLogName(name: string, utcOffsetMinutes?: number): FaultLogEntry | null;
5208
+ /** `+0100` → 60. */
5209
+ declare function parseUtcOffset(value: string): number | null;
5210
+ /** Parse the `== <path>` / head-of-file blocks the crash-record listing prints. */
5211
+ declare function parseCrashRecordHeads(stdout: string): FaultLogEntry[];
5212
+ /**
5213
+ * List faultlogs on the device, newest first: hiview's (`hidumper -s 1201 -a
5214
+ * '-p Faultlogger -LogSuffixWithMs'`, else `ls` of {@link FAULTLOG_DIR}) and,
5215
+ * unless turned off, faultloggerd's native crash records that hiview never
5216
+ * turned into a faultlog.
5217
+ */
5218
+ declare function listFaultLogs(opts: ListFaultLogsOptions): Promise<FaultLogEntry[]>;
5219
+ /** Drop the `[ability]` / `HiviewService` banner hidumper prints before the file. */
5220
+ declare function stripHidumperBanner(stdout: string): string;
5221
+ interface ReadFaultLogOptions extends FaultLogDeviceOptions {
5222
+ entry: FaultLogEntry;
5223
+ }
5224
+ /** The whole faultlog (or crash record) as text: `hidumper … -f <name>`, else `cat`. */
5225
+ declare function readFaultLog(opts: ReadFaultLogOptions): Promise<string>;
5226
+ interface LatestCrashOptions extends FaultLogDeviceOptions {
5227
+ /** Bundle to look for; any process when unset. */
5228
+ bundle?: string;
5229
+ /** Only faults since this instant, or since this many seconds before the device's clock now. */
5230
+ since?: Date | number;
5231
+ /**
5232
+ * Keep looking this long (ms) when nothing is found yet: hiview writes a
5233
+ * faultlog a moment after the process dies. Default 0 (look once).
5234
+ */
5235
+ waitMs?: number;
5236
+ /** Poll interval while waiting. Default 1000. */
5237
+ pollMs?: number;
5238
+ /** Save the whole faultlog in this directory and report it as `rawPath`. */
5239
+ saveDir?: string;
5240
+ }
5241
+ /**
5242
+ * The newest fault of `bundle` (since `since`) on the device, classified and
5243
+ * parsed, or null when there is none. Considers faultlogs of every kind and
5244
+ * native crash records hiview did not turn into one.
5245
+ */
5246
+ declare function latestCrash(opts: LatestCrashOptions): Promise<CrashVerdict | null>;
5247
+
5248
+ /** The flow file format version this code reads and writes. */
5249
+ declare const FLOW_VERSION = 1;
5250
+ /** What a step does. `wait` only waits for its selector (or, with `gone`, for it to disappear). */
5251
+ declare const FLOW_ACTIONS: readonly ["click", "longClick", "doubleClick", "swipe", "inputText", "keyEvent", "wait"];
5252
+ type FlowAction = (typeof FLOW_ACTIONS)[number];
5253
+ /** A point as 0–1 fractions of the display, as `dump layout` prints centers. */
5254
+ interface FlowPoint {
5255
+ fx: number;
5256
+ fy: number;
5257
+ }
5258
+ /** One step of a flow. See packages/cli/README.md (`replay`) for the format. */
5259
+ interface FlowStep {
5260
+ action: FlowAction;
5261
+ /**
5262
+ * The element to wait for and act on, as `--selector` text (`type=Button,id=continueBtn`,
5263
+ * `xpath=//Button[@text="OK"]`). Optional for keyEvent (waited for, not tapped) and
5264
+ * inputText (types into the focused field); click-like actions and swipe need it or `fallback`.
5265
+ */
5266
+ selector?: string;
5267
+ /** Where to act when there is no selector (or, with `replay --fallback`, when it is not found). */
5268
+ fallback?: FlowPoint;
5269
+ /** inputText: the text to type. */
5270
+ text?: string;
5271
+ /** inputText: clear the field first. */
5272
+ clear?: boolean;
5273
+ /** keyEvent: a key name (Back, Home, Enter, Delete, …), a KeyCode id, or a combo like `Ctrl+A`. */
5274
+ key?: string | number;
5275
+ /** swipe: where the finger ends. */
5276
+ to?: FlowPoint;
5277
+ /** swipe: velocity, px/s (uitest default 600). */
5278
+ speed?: number;
5279
+ /** wait: wait until no element matches the selector, instead of until one does. */
5280
+ gone?: boolean;
5281
+ /** A selector for an element that must be on screen after the step. */
5282
+ expect?: string;
5283
+ /** Pause after the action, before `expect` and the next step, ms. */
5284
+ waitMs?: number;
5285
+ /** This step's timeout for its selector and `expect`, ms (default: `replay --step-timeout`). */
5286
+ timeoutMs?: number;
5287
+ /** Free text for people reading the flow; ignored. */
5288
+ note?: string;
5289
+ }
5290
+ /** The device a flow was recorded or written for (informational). */
5291
+ interface FlowDevice {
5292
+ api?: number;
5293
+ display?: {
5294
+ width: number;
5295
+ height: number;
5296
+ };
5297
+ }
5298
+ /** A flow file: versioned JSON, written by `record` or by hand, run by `replay`. */
5299
+ interface Flow {
5300
+ version: typeof FLOW_VERSION;
5301
+ /** The app the flow drives; replay reports a divergence as `wrong-screen` when it is not on screen. */
5302
+ bundle?: string;
5303
+ /** The ability `replay --launch` starts (default: the bundle's main ability). */
5304
+ ability?: string;
5305
+ device?: FlowDevice;
5306
+ steps: FlowStep[];
5307
+ }
5308
+ /** A flow file that is not valid JSON or does not follow the format; lists every problem. */
5309
+ declare class FlowFormatError extends OniroError {
5310
+ readonly problems: string[];
5311
+ readonly file?: string | undefined;
5312
+ constructor(problems: string[], file?: string | undefined);
5313
+ }
5314
+ /**
5315
+ * Validate a parsed flow document, reporting every problem at once (field paths
5316
+ * such as `steps[2].selector`), and return it typed. Selectors are parsed, so a
5317
+ * flow that loads replays without a selector syntax error. Pure.
5318
+ */
5319
+ declare function parseFlow(doc: unknown, file?: string): Flow;
5320
+ /** Read and validate a flow file. Throws {@link FlowFormatError}. */
5321
+ declare function readFlowFile(file: string): Flow;
5322
+ /** A flow as the JSON text `record` writes (two-space indent, trailing newline). */
5323
+ declare function formatFlow(flow: Flow): string;
5324
+
5325
+ /**
5326
+ * One finger of a pointer event, as `uitest uiRecord record` writes it: `W1_*`
5327
+ * and `W2_*` are widgets hit-tested at the down and up points, `X_POSI`, `Y_POSI`
5328
+ * and `X2_POSI`, `Y2_POSI` the down and up points in pixels. The points are
5329
+ * exact; the widgets are not reliable (see {@link flowFromRecording}).
5330
+ */
5331
+ interface UiRecordFinger {
5332
+ W1_BOUNDS?: string;
5333
+ W1_HIER?: string;
5334
+ W1_ID?: string;
5335
+ W1_Text?: string;
5336
+ W1_Type?: string;
5337
+ X_POSI?: string;
5338
+ Y_POSI?: string;
5339
+ X2_POSI?: string;
5340
+ Y2_POSI?: string;
5341
+ [field: string]: unknown;
5342
+ }
5343
+ /**
5344
+ * One line of uitest's `record.csv`, which is JSON Lines despite its name. Pointer
5345
+ * events carry `OP_TYPE` click, longClick, doubleClick, swipe, fling, drag, back,
5346
+ * home or recent, the foreground `BUNDLE` and `ABILITY`, and `fingerList`; key
5347
+ * events carry `OP_TYPE` key and `KeyCode1`..`KeyCode3` (each keystroke is two
5348
+ * lines, the second carrying the layout path). With `-l`, `FILEPAHT` (sic) is the
5349
+ * layout uitest dumped when it wrote the event.
5350
+ */
5351
+ interface UiRecordEvent {
5352
+ OP_TYPE: string;
5353
+ EVENT_TYPE?: string;
5354
+ BUNDLE?: string;
5355
+ ABILITY?: string;
5356
+ FILEPAHT?: string;
5357
+ fingerNumber?: string;
5358
+ fingerList?: UiRecordFinger[];
5359
+ KeyCode1?: string;
5360
+ KeyCode2?: string;
5361
+ KeyCode3?: string;
5362
+ [field: string]: unknown;
5363
+ }
5364
+ /** Parse the lines of uitest's `record.csv` (JSON Lines); other lines are skipped. Pure. */
5365
+ declare function parseUiRecordLines(text: string): UiRecordEvent[];
5366
+ /** The character a keystroke types (KeyCode ids, modifiers included), or undefined for other keys. Pure. */
5367
+ declare function keystrokeChar(codes: readonly number[]): string | undefined;
5368
+ /** A keystroke as a `keyEvent` key: a name `input --key` knows, a KeyCode id, or a `+` combo. Pure. */
5369
+ declare function keystrokeName(codes: readonly number[]): string;
5370
+ /**
5371
+ * The element a touch at `p` lands on in a pruned layout: the last element in
5372
+ * paint order whose bounds contain the point and that is not covered, skipping
5373
+ * window roots and bare containers. Pure.
5374
+ */
5375
+ declare function elementAt(tree: LayoutNode, p: FlowPoint): FlatLayoutNode | undefined;
5376
+ /**
5377
+ * A selector for a text field that does not depend on its content (which typing
5378
+ * changes): its type with its id, key or placeholder, else every one of them
5379
+ * plus the field's `[n]` index. Pure.
5380
+ */
5381
+ declare function fieldSelector(tree: LayoutNode, field: FlatLayoutNode): string | undefined;
5382
+ /**
5383
+ * A selector for an element that appeared with the step: unique and uncovered in
5384
+ * `after`, absent from `before`, inside the app's window. Ids and keys are tried
5385
+ * before texts. Undefined when nothing new is identifiable (the step did not
5386
+ * visibly change the app). Pure.
5387
+ */
5388
+ declare function expectFor(before: LayoutNode, after: LayoutNode, opts?: {
5389
+ bundle?: string;
5390
+ keyboardIds?: ReadonlySet<number>;
5391
+ }): string | undefined;
5392
+ /** When things happened during the recording, read off the device (epoch ms). */
5393
+ interface RecordingTimes {
5394
+ /** When the `initial` layout was dumped. */
5395
+ initial: number;
5396
+ /** Every touch-down during the recording, in order (hilog `ServerMsgHandler: [P:D:…]`). */
5397
+ touchDowns: readonly number[];
5398
+ /** When uitest wrote each layout file (its mtime), by device path. */
5399
+ layouts: ReadonlyMap<string, number>;
5400
+ }
5401
+ /**
5402
+ * The touch-down time of each pointer event, by event index, when the events
5403
+ * account for exactly the touch-downs seen: one per finger (two for a
5404
+ * doubleClick), and none or one for back/home/recent (which uitest also reports
5405
+ * for keys). Undefined when neither count matches. Pure.
5406
+ */
5407
+ declare function alignTouches(events: readonly UiRecordEvent[], touchDowns: readonly number[]): Map<number, number> | undefined;
5408
+ interface FlowFromRecordingInput {
5409
+ events: readonly UiRecordEvent[];
5410
+ /** The pruned layouts the recorder saved, by the device path in each event's `FILEPAHT`. */
5411
+ layouts: ReadonlyMap<string, LayoutNode>;
5412
+ /** A pruned layout dumped just before recording started. */
5413
+ initial: LayoutNode;
5414
+ /** A pruned layout dumped just after recording stopped (the state after the last event). */
5415
+ final?: LayoutNode;
5416
+ /** When the touches and the layouts happened; without it the layouts are taken in event order. */
5417
+ times?: RecordingTimes;
5418
+ display: DisplaySize;
5419
+ /** Input-method bundles (see `getImeBundles`), to tell taps on the soft keyboard apart. */
5420
+ imeBundles?: readonly string[];
5421
+ /** The app being recorded; default: the first bundle the pointer events name. */
5422
+ bundle?: string;
5423
+ ability?: string;
5424
+ api?: number;
5425
+ }
5426
+ interface FlowFromRecordingResult {
5427
+ flow: Flow;
5428
+ /** Events that could not be turned into steps, steps left without a selector, timing problems. */
5429
+ warnings: string[];
5430
+ }
5431
+ /**
5432
+ * Turn the events of a `uitest uiRecord record -l` session into a flow. Each
5433
+ * pointer event becomes a step on the element under its touch point in the
5434
+ * layout on screen at that moment (uitest's own widget when that layout has it
5435
+ * there, since uitest hit-tests late), with {@link selectorFor}'s selector, the
5436
+ * touch point as `fallback`, and as `expect` an element that appeared after it
5437
+ * ({@link expectFor}). Taps on the soft keyboard and typed keystrokes collapse
5438
+ * into one inputText step on the focused field ({@link fieldSelector}), with the
5439
+ * text read off that field afterwards; other keys, and back and home, become
5440
+ * keyEvent steps. A tap on a field next to the inputText step for that field is
5441
+ * dropped (inputText taps it). Pure.
5442
+ */
5443
+ declare function flowFromRecording(input: FlowFromRecordingInput): FlowFromRecordingResult;
5444
+
5445
+ /** Where `uitest uiRecord record` writes its events on the device (fixed by uitest). */
5446
+ declare const UI_RECORD_CSV = "/data/local/tmp/record.csv";
5447
+ interface RecordFlowOptions {
5448
+ config: ConfigProvider;
5449
+ deviceSerial?: string;
5450
+ logger?: Logger;
5451
+ /** Stop after this long, ms. */
5452
+ durationMs?: number;
5453
+ /** Stop when this aborts (Ctrl+C). Recording runs until one of the two. */
5454
+ abortSignal?: AbortSignal;
5455
+ /** The app being recorded; default: the foreground app when recording starts. */
5456
+ bundle?: string;
5457
+ /**
5458
+ * Turn the screen on, swipe away a lock screen without a credential, and keep
5459
+ * the screen on while recording (restored afterwards). Default true.
5460
+ */
5461
+ wake?: boolean;
5462
+ /** Called when the recorder has written more events (raw lines, two per keystroke). */
5463
+ onEvents?: (count: number) => void;
5464
+ /** How often to poll the recorder, ms. Default 1000. */
5465
+ pollMs?: number;
5466
+ /**
5467
+ * Keep uitest's raw recording here: `record.csv`, the layout files, the
5468
+ * recorder's console, and `recording.json` (display, IME bundles, touch and
5469
+ * layout times, the layouts dumped before and after). For bug reports.
5470
+ */
5471
+ rawDir?: string;
5472
+ }
5473
+ interface RecordFlowResult extends FlowFromRecordingResult {
5474
+ /** The raw event lines uitest wrote. */
5475
+ events: number;
5476
+ }
5477
+ /**
5478
+ * A device timestamp as `date '+%Y-%m-%d %H:%M:%S.%N %z'` and `stat -c %y` print it
5479
+ * (`2026-11-05 14:37:23.885001099 +0100`), in epoch ms; undefined when it does not parse. Pure.
5480
+ */
5481
+ declare function parseDeviceTime(text: string): number | undefined;
5482
+ /**
5483
+ * The touch-down times in `hilog -x` output: the multimodal input service logs
5484
+ * `ServerMsgHandler: [P:D:<id>|…]` for each finger going down. hilog prints local
5485
+ * time without a year or zone, so `reference` (a {@link parseDeviceTime} string
5486
+ * from the device) supplies them. Only touches at or after `since` (epoch ms) count. Pure.
5487
+ */
5488
+ declare function parseTouchDowns(hilog: string, reference: string, since?: number): number[];
5489
+ /** `Current ForAbility :com.example.app, EntryAbility` from the recorder's console. Pure. */
5490
+ declare function parseRecorderForeground(consoleText: string): {
5491
+ bundle: string;
5492
+ ability: string;
5493
+ } | undefined;
5494
+ /**
5495
+ * Record a flow with uitest's own recorder: run `uitest uiRecord record -l` in
5496
+ * the background on the device (it logs every touch and key, with the widget
5497
+ * under the finger, and dumps the layout for each), stop it with SIGINT after
5498
+ * `durationMs` or when `abortSignal` aborts, then pull its event file and
5499
+ * layouts and turn them into a flow ({@link flowFromRecording}). uitest writes
5500
+ * an event only once the next touch has started, so the multimodal input
5501
+ * service's hilog domain is followed meanwhile for the touch-down times, and the
5502
+ * layouts' modification times place them on the same clock. A layout dumped
5503
+ * just before starting and one just after stopping bracket the session. Events
5504
+ * made by `input` (uitest uiInput) are recorded too. While the recorder runs,
5505
+ * `uitest dumpLayout` blocks for everyone using the device.
5506
+ */
5507
+ declare function recordFlow(opts: RecordFlowOptions): Promise<RecordFlowResult>;
5508
+
5509
+ /** Why a replay stopped at a step. */
5510
+ type DivergenceReason =
5511
+ /** The step's element did not appear within the timeout. */
5512
+ 'not-found'
5513
+ /** The step ran, but its `expect` element did not appear. */
5514
+ | 'expect-not-found'
5515
+ /** The flow's app is not on screen (it crashed, another app or the lock screen is in front). */
5516
+ | 'wrong-screen'
5517
+ /** Several elements match the step's selector (append `[n]` or make it more specific). */
5518
+ | 'ambiguous'
5519
+ /** The element is there but covered by an overlay. */
5520
+ | 'covered'
5521
+ /** The input could not be sent. */
5522
+ | 'action-failed';
5523
+ interface ReplayStepResult {
5524
+ index: number;
5525
+ action: FlowStep['action'];
5526
+ selector?: string;
5527
+ ok: boolean;
5528
+ durationMs: number;
5529
+ /** The element the step acted on. */
5530
+ target?: string;
5531
+ /** The step acted on its fallback point (no selector, or `fallback: true` and the selector was not found). */
5532
+ usedFallback?: boolean;
5533
+ /** This step's screenshot (`screenshotsDir`). */
5534
+ screenshot?: string;
5535
+ }
5536
+ /** What was on screen when the flow diverged. */
5537
+ interface DivergenceLayout {
5538
+ /** Windows on screen, in paint order. */
5539
+ windows: Array<{
5540
+ windowId: number;
5541
+ bundle?: string;
5542
+ }>;
5543
+ /** The flow's app has a window on screen. */
5544
+ appOnScreen?: boolean;
5545
+ lockScreen: boolean;
5546
+ keyboard: boolean;
5547
+ /** The app's elements (or, when it is not on screen, every element), one line each, capped. */
5548
+ elements: string[];
5549
+ /** How many elements there were before the cap. */
5550
+ elementCount: number;
5551
+ }
5552
+ /** An element that matches all but one clause of the step's selector. */
5553
+ interface NearMatch {
5554
+ element: string;
5555
+ /** The clause it fails, e.g. `text=Continue`. */
5556
+ differs: string;
5557
+ }
5558
+ interface ReplayReport {
5559
+ ok: boolean;
5560
+ /** passed: every step ran; diverged: a step failed (exit 1); error: the replay could not run (exit 2). */
5561
+ outcome: 'passed' | 'diverged' | 'error';
5562
+ bundle?: string;
5563
+ /** Steps run (first index, last index), 0-based and inclusive. */
5564
+ range: [number, number];
5565
+ steps: ReplayStepResult[];
5566
+ failedStep?: number;
5567
+ reason?: DivergenceReason;
5568
+ message?: string;
5569
+ /** The selector that was not satisfied (the step's, or its expect). */
5570
+ selector?: string;
5571
+ /** Screenshot taken when the flow diverged. */
5572
+ screenshot?: string;
5573
+ layout?: DivergenceLayout;
5574
+ nearMatches?: NearMatch[];
5575
+ /** Why the replay could not run (outcome error). */
5576
+ error?: string;
5577
+ warnings: string[];
5578
+ }
5579
+ interface ReplayFlowOptions {
5580
+ config: ConfigProvider;
5581
+ flow: Flow;
5582
+ deviceSerial?: string;
5583
+ logger?: Logger;
5584
+ /** First step to run, 0-based. Default 0. */
5585
+ from?: number;
5586
+ /** Last step to run, 0-based and inclusive. Default: the last step. */
5587
+ to?: number;
5588
+ /** How long to wait for a step's selector and its expect, ms. Default 10000. A step's `timeoutMs` overrides it. */
5589
+ stepTimeoutMs?: number;
5590
+ /** Poll interval of those waits, ms. Default 500. */
5591
+ pollMs?: number;
5592
+ /** Save a screenshot after every step here (`step-<i>.jpeg`); the divergence screenshot goes here too. */
5593
+ screenshotsDir?: string;
5594
+ /** Act on a step's fallback point when its selector is not found, instead of diverging. */
5595
+ fallback?: boolean;
5596
+ /** Force-stop and start the flow's app before the first step. */
5597
+ launch?: boolean;
5598
+ /** Turn the screen on, swipe away a lock screen without a credential, keep it on during the run. Default true. */
5599
+ wake?: boolean;
5600
+ /** Take a screenshot when the flow diverges. Default true. */
5601
+ divergenceScreenshot?: boolean;
5602
+ onStep?: (result: ReplayStepResult) => void;
5603
+ abortSignal?: AbortSignal;
5604
+ }
5605
+ /** Elements matching every clause of a DSL selector but one, for the divergence report. Pure. */
5606
+ declare function nearMatches(tree: DumpLayoutResult['tree'], selector: ElementSelector, limit?: number): NearMatch[];
5607
+ /** What is on screen, focused on the flow's app. Pure. */
5608
+ declare function summarizeDivergenceLayout(layout: DumpLayoutResult, bundle?: string): DivergenceLayout;
5609
+ /**
5610
+ * Replay a flow on the device through the same path as `input --selector` and
5611
+ * `wait --selector`: for each step, wait for its selector, act on the element
5612
+ * (or on its fallback point), pause `waitMs`, then wait for its `expect`. Stops
5613
+ * at the first step that fails and reports why (see {@link DivergenceReason}),
5614
+ * with a screenshot, a summary of what was on screen, and the elements that
5615
+ * nearly match the selector. Never throws for a divergence or a missing device:
5616
+ * the report's outcome says which.
5617
+ */
5618
+ declare function replayFlow(opts: ReplayFlowOptions): Promise<ReplayReport>;
5619
+
5620
+ /**
5621
+ * Parsing of `hitrace` text output: ftrace text whose user-space markers are
5622
+ * `tracing_mark_write` events.
5623
+ *
5624
+ * What an OpenHarmony API 26 device writes (seen on a real capture):
5625
+ *
5626
+ * ```
5627
+ * ample.perfprobe-17599 ( 17599) [005] ..... 149437.321439: tracing_mark_write: B|17599|H:ReceiveVsync name:WM_17599 ... vsyncId:16026, fd:26|M0538
5628
+ * ample.perfprobe-17599 ( 17599) [005] ..... 149437.337990: tracing_mark_write: E|17599|M0538
5629
+ * OS_IPC_13_4366-4366 ( 2693) [006] ..... 149433.777705: tracing_mark_write: B|2693|H:[a92ab18be48d19e,27224d3,0]#virtual int ...StartAbility(...)|I31
5630
+ * RSUniRenderThre-3012 ( 2695) [004] ..... 149433.818003: tracing_mark_write: C|2695|H:JANK_FRAME_1-5F|1|M0538
5631
+ * ```
5632
+ *
5633
+ * - `B|<tgid>|H:<name>|<level><tag>` opens a slice on the writing thread,
5634
+ * `E|<tgid>|<level><tag>` closes the innermost one. The trailing level and tag
5635
+ * (`I39`, `M0538`) are new in recent releases; older ones end at the name.
5636
+ * - `S|<tgid>|H:<name>|<cookie>|…` / `F|…` start and finish an async slice,
5637
+ * `C|<tgid>|H:<name>|<value>|…` sets a counter.
5638
+ * - Names carry an `H:` prefix and, when a HiTraceChain is active, a
5639
+ * `[chainId,spanId,parentSpanId]#` prefix; both are stripped.
5640
+ * - The task column is the thread's comm (15 characters at most: an app's
5641
+ * main thread shows the END of its bundle name, `ample.perfprobe`) and its
5642
+ * tid; the parenthesised column is the tgid (`-------` for idle). Traces
5643
+ * recorded without the tgid column parse too (the B/E payload has the tgid).
5644
+ *
5645
+ * `sched_switch` lines are used, when the `sched` category was on, for the CPU
5646
+ * time of main threads (tid == tgid).
5647
+ */
5648
+ /** A closed (or, at the end of the trace, still open) synchronous slice. */
5649
+ interface TraceSlice {
5650
+ tid: number;
5651
+ /** Process (tgid) from the marker. */
5652
+ pid: number;
5653
+ /** Name without the `H:` and HiTraceChain prefixes. */
5654
+ name: string;
5655
+ /** Start, ms on the trace clock (boot time by default). */
5656
+ ts: number;
5657
+ /** Duration, ms; undefined when the slice was still open at the end of the trace. */
5658
+ dur?: number;
5659
+ /** Nesting depth on its thread, 0 for outermost. */
5660
+ depth: number;
5661
+ }
5662
+ /** An async slice (`S`/`F` pair). */
5663
+ interface TraceAsyncSlice {
5664
+ pid: number;
5665
+ name: string;
5666
+ cookie: string;
5667
+ ts: number;
5668
+ dur?: number;
5669
+ }
5670
+ interface TraceCounterSample {
5671
+ pid: number;
5672
+ name: string;
5673
+ ts: number;
5674
+ value: number;
5675
+ }
5676
+ interface TraceModel {
5677
+ slices: TraceSlice[];
5678
+ asyncSlices: TraceAsyncSlice[];
5679
+ counters: TraceCounterSample[];
5680
+ /** tid → its comm (the last one seen), and tid → tgid. */
5681
+ threads: Map<number, {
5682
+ comm: string;
5683
+ pid: number;
5684
+ }>;
5685
+ /** First and last event timestamps, ms. */
5686
+ startMs: number;
5687
+ endMs: number;
5688
+ /** Lines that looked like trace events. */
5689
+ eventCount: number;
5690
+ /** `tracing_mark_write` events. */
5691
+ markerCount: number;
5692
+ /** `sched_switch` events seen (0: the sched category was off). */
5693
+ schedSwitchCount: number;
5694
+ /**
5695
+ * CPU time per thread id, ms, from sched_switch (empty without sched data). A
5696
+ * process's main thread has tid == pid, so its entry is `get(pid)`; this needs no
5697
+ * tgid column.
5698
+ */
5699
+ mainThreadCpuMs: Map<number, number>;
5700
+ /**
5701
+ * RenderService surface name → the pid that owns it, from
5702
+ * `RSUniRender::QuickPrepare:[<surface>] nodeId[…] pid[<pid>]` (graphic category).
5703
+ * An app's main window surface is named after the last part of its bundle
5704
+ * name and an index (`perfprobe0`), which identifies the app's process when
5705
+ * its thread names did not make it into the trace (`<...>`).
5706
+ */
5707
+ surfacePids: Map<string, number>;
5708
+ /** From the `entries-in-buffer/entries-written: a/b` header, when present. */
5709
+ entriesInBuffer?: number;
5710
+ entriesWritten?: number;
5711
+ }
5712
+ interface ParseTraceOptions {
5713
+ /** Keep only the slices this returns true for (called when a slice closes, and for open ones at the end). Default: all. */
5714
+ keepSlice?: (slice: TraceSlice, threadComm: string | undefined) => boolean;
5715
+ }
5716
+ /** `H:[chain]#name` → `name`. Pure. */
5717
+ declare function cleanMarkerName(raw: string): string;
5718
+ /** Incremental parser; feed lines, then `finish()`. */
5719
+ declare class TraceParser {
5720
+ private readonly opts;
5721
+ private readonly model;
5722
+ private readonly stacks;
5723
+ private readonly openAsync;
5724
+ private readonly switchedIn;
5725
+ private headerDone;
5726
+ constructor(opts?: ParseTraceOptions);
5727
+ line(raw: string): void;
5728
+ private bound;
5729
+ private schedSwitch;
5730
+ private marker;
5731
+ private close;
5732
+ finish(): TraceModel;
5733
+ }
5734
+ /** Parse hitrace text held in memory. Pure. */
5735
+ declare function parseTraceText(text: string, opts?: ParseTraceOptions): TraceModel;
5736
+ /** Parse a hitrace text file, streaming it line by line (traces run to hundreds of MB). */
5737
+ declare function parseTraceFile(file: string, opts?: ParseTraceOptions): Promise<TraceModel>;
5738
+
5739
+ /**
5740
+ * Turn a parsed hitrace capture into the numbers a performance gate needs:
5741
+ * the app's frames (janky ones against the display's refresh interval), its
5742
+ * cold-start time, main-thread load, and RenderService's own per-scene jank
5743
+ * reports. Pure.
5744
+ *
5745
+ * Markers this relies on, as an OpenHarmony API 26 device (ArkUI, RenderService,
5746
+ * ability runtime) emits them with the `ace graphic app ability window`
5747
+ * categories:
5748
+ *
5749
+ * - Frames: on the app's main thread (tid == pid) each UI frame is one
5750
+ * `ReceiveVsync name:WM_<pid> … now:<vsync ns> expectedEnd:<ns> vsyncId:<n>`
5751
+ * slice enclosing `OnVsyncEvent` → `UIVsyncTask` → `FlushLayoutTask` /
5752
+ * `FlushRenderTask`. ArkUI only asks for a vsync when something is dirty, so
5753
+ * an idle app writes no frames. A frame's time is from its vsync (`now:`) to
5754
+ * the end of the slice, so a frame whose callback was held up by other work on
5755
+ * the main thread counts the wait too; it is janky when that exceeds one
5756
+ * refresh interval (the UI missed the next vsync).
5757
+ * - Refresh interval: `VSyncReceiver:period:<ns>` inside those frames, else
5758
+ * `refreshPeriod is: <ns>`, else the caller's rate (hidumper), else 60 Hz.
5759
+ * - Cold start: from `AbilityManagerClient::StartAbility` on the `aa` tool's
5760
+ * thread (else `AbilityManagerService::StartAbility` in foundation) before the
5761
+ * app's process appears, to `RSJankStats::ReportEventFirstFrame app pid <pid>`
5762
+ * in render_service (the first frame composited), else to the end of the app's
5763
+ * first UI frame.
5764
+ * - Scenes: `RSJankStats::ReportEventJankFrame maxFrameTime is …`,
5765
+ * `ReportEventHitchTimeRatio hitch time ratio is … ms/s` and
5766
+ * `ReportEventResponse responseLatency is …ms` name a scene (APP_LIST_FLING,
5767
+ * ABILITY_OR_PAGE_SWITCH, …) and the bundle.
5768
+ */
5769
+ interface PerfFrameStats {
5770
+ /** UI frames the app's main thread produced. */
5771
+ total: number;
5772
+ /** Frames that took longer than one refresh interval (vsync to done). */
5773
+ janky: number;
5774
+ /** janky / total (0 without frames). */
5775
+ jankRate: number;
5776
+ p50Ms: number;
5777
+ p95Ms: number;
5778
+ maxMs: number;
5779
+ /** Refresh intervals missed in all: Σ floor(frame / interval). */
5780
+ missedVsyncs: number;
5781
+ /** The longest frames, longest first: offset from the trace start and duration, ms. */
5782
+ longest: Array<{
5783
+ atMs: number;
5784
+ ms: number;
5785
+ }>;
5786
+ }
5787
+ interface PerfStartup {
5788
+ /** Launch request to the app's first frame on screen, ms. */
5789
+ coldMs: number;
5790
+ /** The app's first UI frame on its main thread (initial build, measure, layout), ms. */
5791
+ firstFrameMs: number | null;
5792
+ /** Launch request to the app's process being forked, ms. */
5793
+ processMs: number | null;
5794
+ /** Where coldMs starts and ends. */
5795
+ from: string;
5796
+ to: string;
5797
+ }
5798
+ interface PerfScene {
5799
+ /** RenderService's scene id, e.g. APP_LIST_FLING, ABILITY_OR_PAGE_SWITCH. */
5800
+ scene: string;
5801
+ page?: string;
5802
+ maxFrameMs?: number;
5803
+ maxHitchMs?: number;
5804
+ hitchMsPerS?: number;
5805
+ responseMs?: number;
5806
+ }
5807
+ interface TraceSummary {
5808
+ /** The app's process (main thread id). */
5809
+ pid: number | null;
5810
+ /** Length of the capture, ms. */
5811
+ durationMs: number;
5812
+ refreshRateHz: number;
5813
+ frames: PerfFrameStats;
5814
+ startup: PerfStartup | null;
5815
+ mainThread: {
5816
+ /** Time in top-level traced slices on the main thread, ms. */
5817
+ busyMs: number;
5818
+ /** CPU time of the main thread, ms (only with the `sched` category). */
5819
+ cpuMs: number | null;
5820
+ };
5821
+ scenes: PerfScene[];
5822
+ notes: string[];
5823
+ }
5824
+ interface SummarizeTraceOptions {
5825
+ bundle: string;
5826
+ /** The app's pid when known (e.g. `pidof` after the capture); otherwise found from the trace. */
5827
+ pid?: number;
5828
+ /** Refresh rate to use when the trace has no vsync period. */
5829
+ refreshRateHz?: number;
5830
+ /** The capture cold-launched the app: report startup, and leave its first frame out of the frame stats. */
5831
+ launched?: boolean;
5832
+ }
5833
+ /** Slices the summary needs; pass as `keepSlice` to keep memory flat on long captures. */
5834
+ declare function perfSliceFilter(slice: TraceSlice): boolean;
5835
+ /** The thread name an app's main thread gets: the bundle name, cut to its last (or first) 15 characters. */
5836
+ declare function commMatchesBundle(comm: string, bundle: string): boolean;
5837
+ /** The q-quantile (0..1) of sorted values, nearest-rank. */
5838
+ declare function quantile(sorted: number[], q: number): number;
5839
+ /** Candidate app pids: main threads named after the bundle, and pids whose markers name it (`…##<bundle>`). */
5840
+ declare function findAppPids(model: TraceModel, bundle: string): number[];
5841
+ /** Pids owning a RenderService surface named `<last part of the bundle><index>`, the app's main window. */
5842
+ declare function findAppPidsBySurface(model: TraceModel, bundle: string): number[];
5843
+ /** Summarise a capture for one bundle. Pure. */
5844
+ declare function summarizeTrace(model: TraceModel, opts: SummarizeTraceOptions): TraceSummary;
5845
+
5846
+ /** One row of `hiperf report --sort dso,func`. */
5847
+ interface HiperfFunction {
5848
+ /** Share of the samples' event count, %. */
5849
+ percent: number;
5850
+ dso: string;
5851
+ func: string;
5852
+ }
5853
+ interface HiperfReport {
5854
+ /** The sampled event, e.g. `hw-cpu-cycles`. */
5855
+ event?: string;
5856
+ samples: number;
5857
+ top: HiperfFunction[];
5858
+ }
5859
+ /**
5860
+ * Parse `hiperf report -i <data> --sort dso,func` text:
5861
+ *
5862
+ * ```
5863
+ * Event: hw-cpu-cycles (type 0 id 0)
5864
+ * Samples Count: 25
5865
+ * Event Count: 20091
5866
+ * Heating count dso func
5867
+ * 39.16% 7868 [kernel.kallsyms] _raw_spin_unlock_irqrestore
5868
+ * 32.58% 6546 /system/lib/ld-musl-aarch64.so.1 /system/lib/ld-musl-aarch64.so.1+0x13fd6c
5869
+ * ```
5870
+ *
5871
+ * Several events (several `Event:` sections) add up their samples; rows keep
5872
+ * the first section's order. Pure.
5873
+ */
5874
+ declare function parseHiperfReport(text: string, limit?: number): HiperfReport;
5875
+
5876
+ /**
5877
+ * Categories captured by default: ArkUI (frames), graphic (vsync period,
5878
+ * RenderService first-frame and jank reports), app and ability (launch),
5879
+ * window. `sched` adds the main thread's CPU time, at a large cost in buffer.
5880
+ */
5881
+ declare const DEFAULT_TRACE_CATEGORIES: readonly ["ace", "app", "graphic", "ability", "window"];
5882
+ /** hitrace buffer, KB (its own default is 18432). */
5883
+ declare const DEFAULT_TRACE_BUFFER_KB = 65536;
5884
+ /** How long a `--launch` capture keeps running after the launch, and a plain capture lasts, ms. */
5885
+ declare const DEFAULT_PERF_FOR_MS = 5000;
5886
+ /** How long a `--flow` capture keeps running after the flow, ms. */
5887
+ declare const DEFAULT_PERF_FLOW_TAIL_MS = 1000;
5888
+ interface PerfTraceOptions {
5889
+ config: ConfigProvider;
5890
+ deviceSerial?: string;
5891
+ logger?: Logger;
5892
+ /** The app to measure. Defaults to the flow's bundle. */
5893
+ bundle?: string;
5894
+ /** Ability `launch` starts (default: the bundle's main ability, or the flow's). */
5895
+ ability?: string;
5896
+ /** Force-stop and cold-launch the bundle once tracing runs; reports startup. */
5897
+ launch?: boolean;
5898
+ /** Replay this flow while tracing (after the launch, with `launch`). */
5899
+ flow?: Flow;
5900
+ /** Replay options passed through (step timeout, fallback, screenshots). */
5901
+ replay?: Pick<ReplayFlowOptions, 'stepTimeoutMs' | 'fallback' | 'screenshotsDir' | 'from' | 'to' | 'onStep'>;
5902
+ /**
5903
+ * Without a flow: how long to capture (after the launch with `launch`), ms;
5904
+ * default {@link DEFAULT_PERF_FOR_MS}. With a flow: how long to keep capturing
5905
+ * after it, default {@link DEFAULT_PERF_FLOW_TAIL_MS}.
5906
+ */
5907
+ forMs?: number;
5908
+ /** Local path for the trace (default: a new file in the system temp dir). */
5909
+ out?: string;
5910
+ /** hitrace categories (default {@link DEFAULT_TRACE_CATEGORIES}). */
5911
+ categories?: string[];
5912
+ /** hitrace buffer size, KB (default {@link DEFAULT_TRACE_BUFFER_KB}). */
5913
+ bufferKb?: number;
5914
+ /** Turn the screen on and swipe away a credential-less lock screen, and keep it on. Default true. */
5915
+ wake?: boolean;
5916
+ /** Also sample the app's process with hiperf and report its top functions. */
5917
+ hiperf?: boolean;
5918
+ abortSignal?: AbortSignal;
5919
+ }
5920
+ interface PerfTraceReport {
5921
+ /** The capture completed and was summarised. */
5922
+ ok: boolean;
5923
+ bundle: string;
5924
+ durationMs: number;
5925
+ /** The trace, pulled to the host. */
5926
+ trace: string | null;
5927
+ refreshRateHz: number | null;
5928
+ frames: PerfFrameStats | null;
5929
+ startup: PerfStartup | null;
5930
+ flow: ReplayReport | null;
5931
+ pid: number | null;
5932
+ mainThread: TraceSummary['mainThread'] | null;
5933
+ scenes: PerfScene[];
5934
+ hiperf?: (HiperfReport & {
5935
+ data: string | null;
5936
+ }) | {
5937
+ error: string;
5938
+ };
5939
+ categories: string[];
5940
+ notes: string[];
5941
+ /** Why the capture could not complete. */
5942
+ error?: string;
5943
+ }
5944
+ interface PerfThresholds {
5945
+ /** Fail when frames.jankRate is above this (0..1). */
5946
+ maxJankRate?: number;
5947
+ /** Fail when startup.coldMs is above this. */
5948
+ maxStartupMs?: number;
5949
+ }
5950
+ interface PerfGateResult {
5951
+ passed: boolean;
5952
+ failures: string[];
5953
+ }
5954
+ /** Check a report against thresholds; a metric that was not measured fails a threshold set on it. Pure. */
5955
+ declare function evaluatePerfGate(report: Pick<PerfTraceReport, 'frames' | 'startup' | 'flow'>, t: PerfThresholds): PerfGateResult;
5956
+ /** `activeMode: 1080x2400, refreshRate=59` in `hidumper -s RenderService -a screen`. Pure. */
5957
+ declare function parseActiveRefreshRate(hidumper: string): number | null;
5958
+ /**
5959
+ * Capture a hitrace trace on the device while the app cold-launches, a flow is
5960
+ * replayed, or for a fixed time; pull it and summarise it for the bundle (see
5961
+ * {@link summarizeTrace}). Never throws for a failed capture or a missing
5962
+ * device: `ok` is false and `error` says why. Tracing is always stopped.
5963
+ */
5964
+ declare function perfTrace(opts: PerfTraceOptions): Promise<PerfTraceReport>;
5965
+
5966
+ /**
5967
+ * Search over the OpenHarmony application-development documentation (`docs sync`
5968
+ * clones `en/application-dev` of gitcode.com/openharmony/docs). The SDK typings
5969
+ * behind `api search` / `api show` say whether a symbol exists and with what
5970
+ * signature; the docs say how an API is used, which business error codes a kit
5971
+ * throws and how the platform behaves. The index is deterministic, built in memory
5972
+ * in a few seconds from titles, headings and an inverted word index, and answers a
5973
+ * query in milliseconds; bodies are read on demand.
5974
+ */
5975
+ interface DocEntry {
5976
+ /** Path relative to the `en/application-dev` tree, e.g. `ui/arkts-navigation-jump.md`. */
5977
+ path: string;
5978
+ title: string;
5979
+ /** Every `##`–`####` heading with its 1-based line. */
5980
+ headings: DocHeading[];
5981
+ bytes: number;
5982
+ }
5983
+ interface DocHeading {
5984
+ line: number;
5985
+ level: number;
5986
+ text: string;
5987
+ }
5988
+ interface DocSearchHit {
5989
+ path: string;
5990
+ title: string;
5991
+ score: number;
5992
+ /** Headings that contain a query word (at most 6), to pass to `show`. */
5993
+ headings: {
5994
+ line: number;
5995
+ text: string;
5996
+ }[];
5997
+ /** First paragraph after the title, trimmed. */
5998
+ snippet: string;
5999
+ }
6000
+ interface DocSearchOptions {
6001
+ /** At most n hits (default 8, at most 30). */
6002
+ limit?: number;
6003
+ /** Only documents under this subtree, e.g. `ui`, `reference/errorcodes`. */
6004
+ section?: string;
6005
+ }
6006
+ interface DocSearchResult {
6007
+ query: string;
6008
+ /** The words the query was read as. */
6009
+ terms: string[];
6010
+ total: number;
6011
+ hits: DocSearchHit[];
6012
+ }
6013
+ interface DocShowOptions {
6014
+ /** A heading (or a distinctive part of it, case-insensitive): only that section. */
6015
+ heading?: string;
6016
+ /** Line cap (default 250, at most 1200). */
6017
+ maxLines?: number;
6018
+ }
6019
+ type DocShowResult = {
6020
+ found: true;
6021
+ path: string;
6022
+ /** The text (images and inline HTML dropped), cut at `maxLines` with a note. */
6023
+ text: string;
6024
+ truncated: boolean;
6025
+ /** The headings inside what was shown. */
6026
+ headings: {
6027
+ line: number;
6028
+ text: string;
6029
+ }[];
6030
+ /** Lines of the whole section before the cap. */
6031
+ lines: number;
6032
+ } | {
6033
+ found: false;
6034
+ path: string;
6035
+ error: string;
6036
+ /** Similar document paths, or the document's headings when the heading did not match. */
6037
+ suggestions: string[];
6038
+ };
6039
+ /** Every `.md` under `tree`, sorted, skipping figure directories. */
6040
+ declare function listMarkdown(tree: string): string[];
6041
+ /** Lower-cased words of a text: identifiers keep their dots, 2–40 chars, no long digit runs (hashes, ids). */
6042
+ declare function docTokens(text: string): string[];
6043
+ interface QueryTerm {
6044
+ term: string;
6045
+ /** 1 for a word of the query, 0.4 for a part of a camelCase or dotted identifier. */
6046
+ weight: number;
6047
+ }
6048
+ /**
6049
+ * The query's words plus the parts of camelCase and dotted identifiers
6050
+ * (`NavPathStack` → nav, path, stack), so a guide that says "path stack" still matches;
6051
+ * the parts weigh less and are not required.
6052
+ */
6053
+ declare function docQueryTerms(query: string): QueryTerm[];
6054
+ /** Whether `term` occurs in `text` as a whole word (a trailing API-level suffix such as `insert10+` still counts). */
6055
+ declare function wordIn(text: string, term: string): boolean;
6056
+ /** Title and headings of one document. */
6057
+ declare function parseDoc(rel: string, text: string): DocEntry;
6058
+ /**
6059
+ * Distinct index words of a document: its text plus the words of its path. A dotted
6060
+ * identifier also contributes its parts (`this.pathstack.pushpathbyname` → pathstack,
6061
+ * pushpathbyname) and a word with a trailing API-level suffix its stem
6062
+ * (`pushpathbyname10` → pushpathbyname), so the words a reader types are the words
6063
+ * the index holds.
6064
+ */
6065
+ declare function docWords(rel: string, text: string): Set<string>;
6066
+ declare class DocsIndex {
6067
+ readonly tree: string;
6068
+ readonly docs: readonly DocEntry[];
6069
+ /** Build time, ms. */
6070
+ readonly buildMs: number;
6071
+ /** word → ascending document ids (packed: 4 bytes per occurrence). */
6072
+ private readonly postings;
6073
+ private constructor();
6074
+ /** The index of a tree, built on the first call of a process and kept. */
6075
+ static load(tree: string): DocsIndex;
6076
+ /** An index over in-memory documents (tests). `tree` is used by `show` for reading files. */
6077
+ static fromDocs(tree: string, docs: {
6078
+ path: string;
6079
+ text: string;
6080
+ }[]): DocsIndex;
6081
+ /** Forget the cached index of a tree (after a sync). */
6082
+ static forget(tree: string): void;
6083
+ get size(): number;
6084
+ private has;
6085
+ /**
6086
+ * Documents containing every word of the query (any of them when none does), scored by
6087
+ * where the words occur: title, headings, path, body; a document whose title is exactly a
6088
+ * query word, or that contains the whole query in a title or heading, ranks higher; the
6089
+ * generated API reference ranks a little below the guides, system-API pages and tables of
6090
+ * contents below everything.
6091
+ */
6092
+ search(query: string, o?: DocSearchOptions): DocSearchResult;
6093
+ private snippet;
6094
+ /**
6095
+ * A document, or one of its sections: from the heading that matches `heading`
6096
+ * (exactly, else by substring, case-insensitive) to the next heading of the same or a
6097
+ * higher level. Image lines and inline HTML are dropped; the text is cut at `maxLines`
6098
+ * with a note of what was left out.
6099
+ */
6100
+ show(rel: string, o?: DocShowOptions): DocShowResult;
6101
+ }
6102
+
6103
+ /** The OpenHarmony documentation repository. */
6104
+ declare const DOCS_REPO = "https://gitcode.com/openharmony/docs";
6105
+ /** The part of the repository `docs search` reads; device, kernel and the Chinese tree stay out. */
6106
+ declare const DOCS_SPARSE_PATH = "en/application-dev";
6107
+ /** Sparse-checkout patterns (non-cone): the tree without its figures, which are about 90% of its bytes. */
6108
+ declare const DOCS_SPARSE_PATTERNS: readonly string[];
6109
+ /**
6110
+ * The release branch of the docs repository for an SDK: from its version
6111
+ * (`oh-uni-package.json`: `6.1.0.31` → `OpenHarmony-6.1-Release`, `5.1.0.107` →
6112
+ * `OpenHarmony-5.1.0-Release`), else from the API level (18 → 5.1.0, 20 → 6.0,
6113
+ * 23 → 6.1, 26 → 7.0), else `master`.
6114
+ */
6115
+ declare function docsRefFor(sdk: {
6116
+ api?: number;
6117
+ version?: string;
6118
+ }): string;
6119
+ /** `{ api, version }` of an SDK API directory, from `ets/oh-uni-package.json`; empty when unreadable. */
6120
+ declare function readSdkRelease(sdkDir: string): {
6121
+ api?: number;
6122
+ version?: string;
6123
+ };
6124
+ /** Where the clones live: the `docsDir` config key, default `<sdkRootDir>/docs`. */
6125
+ declare function getDocsRootDir(config: ConfigProvider): string;
6126
+ /** The clone of one release: `<docs root>/<ref>`. */
6127
+ declare function docsDirFor(config: ConfigProvider, ref: string): string;
6128
+ /** The `en/application-dev` tree of a clone, or null when the release has not been synced. */
6129
+ declare function docsTree(docsDir: string): string | null;
6130
+ interface SyncDocsOptions {
6131
+ /** The branch or tag to clone. */
6132
+ ref: string;
6133
+ /** Where to clone (normally `docsDirFor(config, ref)`). */
6134
+ dir: string;
6135
+ /** Repository URL (default {@link DOCS_REPO}). */
6136
+ repo?: string;
6137
+ logger?: Logger;
6138
+ /** Per git step; the clone of a release takes a minute or two. Default 10 minutes. */
6139
+ timeoutMs?: number;
6140
+ abortSignal?: AbortSignal;
6141
+ }
6142
+ interface SyncDocsResult {
6143
+ dir: string;
6144
+ ref: string;
6145
+ /** Markdown files under `en/application-dev`. */
6146
+ files: number;
6147
+ /** False when the clone was created, true when an existing one was brought up to date. */
6148
+ updated: boolean;
6149
+ /** The commit the tree is at. */
6150
+ commit?: string;
6151
+ }
6152
+ /**
6153
+ * Clone or update the documentation of one release: a partial (`--filter=blob:none`),
6154
+ * depth-1, sparse clone of `en/application-dev` without its figures, about 100 MB
6155
+ * instead of the 2 GB a plain clone of the tree is. A second call on an existing
6156
+ * clone fetches the branch head and resets to it. Needs `git` on the PATH.
6157
+ */
6158
+ declare function syncDocs(opts: SyncDocsOptions): Promise<SyncDocsResult>;
6159
+
2719
6160
  declare const VERSION: string;
2720
6161
 
2721
- export { ALL_SDKS, APL_VALUES, APP_FEATURE_VALUES, type AbilityInfo, type AgcAuthInfo, AgcError, type Apl, type AppFeature, type ApplyChangesOptions, type ApplyChangesResult, type BuildHapOptions, type BuildHapResult, type BundleOptions, CancelledError, type CaptureBurstOptions, type CaptureLogOptions, type CaptureLogResult, ChecksumMismatchError, type CmdToolsFlavour, CmdToolsNotInstalledError, type CmdToolsStatus, type CmdWrapper, type CodelinterFinding, type CodelinterReport, type CodelinterResult, type CodelinterSummary, CommandFailedError, type ConfigKey, type ConfigProvider, type CreateScaffoldOptions, type CreateScaffoldResult, type DeveloperAgreementStatus, type DeviceFullInfo, type DeviceInfo, type DiscoverHapsOptions, type DisplaySize, type DisplaySizeOptions, type DownloadOptions, type DumpLayoutOptions, type DumpLayoutResult, type DumpLogOptions, type EmulatorStatus, type ExtractZipOptions, type FlatLayoutNode, type GenerateSigningConfigsOptions, type GestureUitestOptions, type GetDeviceInfoOptions, HARMONYOS_SDK_VERSIONS, HUAWEI_SITES, type HapAssetDiff, type HapSigningInfo, type HapZip, type HarmonyOsAutoSignOptions, type HarmonyOsSdk, type HarmonyOsSession, type HarmonyOsSessionOptions, type HarmonyOsSignHapOptions, type HarmonyOsSignHapResult, type HarmonyOsSigningResult, type HdcExecOptions, type HdcExecResult, type HdcShellOptions, type HidumperOptions, type HilogEntry, type HilogLevel, type HuaweiSite, type HuaweiSiteCode, type HuaweiTeam, type HuaweiUserInfo, INSTALL_TMP_DIRNAME, type InputType, type InstallAppOptions, type InstallAppResult, type InstallCandidate, type InstallCmdToolsOptions, type InstallEmulatorOptions, type InstallMethod, type InstallSdkFromArchiveOptions, type InstallSdkOptions, type InstallTempDir, type InstallTempDirOptions, type InstalledSdk, InsufficientSpaceError, type KeyboardState, type LaunchAppOptions, type LayoutNode, type LayoutSelector, type LocateTargetOptions, type LocatedTarget, type Logger, type ModuleHaps, OHOS_DAILY_BUILDS_URL, OHOS_URL_BASE, type OniroContext, OniroError, type OsFolder, type OutputSink, type ParamOptions, type PerformInputOptions, type PerformInputResult, type PickTargetFailure, type PickedHap, type PrepareSigningOptions, type PrepareSigningResult, type ProgressReporter, type ProgressUpdate, type ProjectModule, type Prompter, type ProvisionProfileInfo, type RawLayoutNode, type RawTouchEvent, type RebootDecision, type RebootOptions, type RecvFileOptions, type RunCodelinterOptions, type RunHvigorwOptions, type RunHvigorwResult, type RunOhpmOptions, type RunProcessOptions, type RunningProcess, type RuntimeOs, SIGNED_HAP_CHUNK_SIZE, SIGNING_ERRORS, type ScreenDump, type Screenshot, type ScreenshotOptions, type SdkArchiveInfo, type SdkInfo, SdkNotInstalledError, type SdkRelease, type SendFileOptions, type SendGestureOptions, type SendInputOptions, type SendRawTouchOptions, type SetHilogLevelOptions, type SignOpenHarmonyHapOptions, type SignOpenHarmonyHapResult, type SigningKind, type SigningMaterialPaths, type SigningPasswords, type StartEmulatorOptions, type StoredSession, type StreamHilogOptions, TMP_DIR_HINT, TargetNotFoundError, type TemplateOption, type TokenStore, type UiInputType, UnsupportedPlatformError, VERSION, type WaitForBootOptions, type WaitForBundleOptions, type WaitForConditionOptions, type WaitForLogOptions, type WaitForTargetOptions, type WatchLogOptions, type Waypoint, appSandboxDir, applyChanges, assertDevicePath, assertLayoutSelector, attemptHdcConnection, buildCmdWrapper, buildGestureCommands, buildGestureUitestCommand, buildHap, buildHvigorwArgs, buildInputCommand, buildRawTouchCommand, bundleNameFromHapConfig, captureBurst, captureLog, cleanCodelinterOutput, consoleLogger, createHarmonyOsSession, createInstallTempDir, createMaterial, createScaffold, createTempWorkDir, createTokenStore, decideInstallMethod, decideReboot, decryptPwd, dedupEntries, defaultContext, defaultPaths, defaultSignedHapPath, describeLayoutNode, detectAaStartFailure, detectCmdToolsFlavour, detectInstallFailure, detectProjectSdkVersion, detectRuntimeOs, detectSigningConfigNames, diagnoseBuildFailure, diffEntryNames, diffHapAssets, discoverHaps, downloadAndInstallSdk, downloadFile, dumpLayout, dumpLog, dumpRenderService, dumpScreen, dumpWindow, encryptPwd, ensureFreeSpace, ensureInstallOk, ensureOhModules, ensureOk, ensureRemoteOk, escapeCmdArgument, escapeCmdCommand, existingHapOrUnsigned, extractTarball, extractZipWithProgress, findAppProcessId, findCmdToolsSourceDir, findCoveredNodes, findHarmonyOsSdk, findKeyboardWindow, findLayoutNodes, findMissingProjectSdk, findRunningProcess, findSdkOsDir, flattenLayout, forceStop, formatBytes, generateSigningConfigs, getBundleName, getCmdToolsBin, getCmdToolsDownloadUrl, getCmdToolsPath, getCmdToolsStatus, getDeviceInfo, getDisplaySize, getEmulatorDir, getEmulatorStatus, getFreeSpaceBytes, getHdcPath, getHvigorwPath, getImeBundles, getInstalledSdks, getKey, getMainAbility, getOhosBaseSdkHome, getOhpmPath, getOsFolder, getSdkFilename, getSdkRootDir, getSupportedSdksForUi, harmonyOsAutoSign, harmonyOsSdkLabelForApi, harmonyOsSignHap, hdcClientFailure, hdcExec, hdcTargetArgs, hdcTargetArgsFor, hideKeyboard, hilogTimeMs, installApp, installCmdTools, installEmulator, installFailureReason, installSdkFromArchive, isBundleInstalled, isCmdToolsInstalled, isEmulatorInstalled, isOutOfSpaceError, isRamBackedPath, isUnsignedHap, isUsableDevice, isValidBundleName, isValidProjectName, killProcessTree, launchApp, listAbilities, listDevices, listModules, listRunningProcesses, listTemplates, locateTarget, missingProjectRootFiles, needsCmdWrapper, nonInteractivePrompter, noopLogger, noopProgress, normaliseLocalPath, paramGet, paramGetMany, paramSet, parseBounds, parseCodelinterFindings, parseCodelinterReport, parseDeviceList, parseHilogLine, parseImeBundles, parseMainAbilityFromBmDump, parseParamValues, parseRemoteExit, performInput, pickHap, pickSigningKind, pickTarget, prepareSigning, pruneLayout, readHapBundleName, readHapSigningInfo, readJson5File, readJsonFile, readProvisionProfile, readZipEntry, reboot, recvFile, removeCmdTools, removeEmulator, removeSdk, removeTempWorkDir, requireHarmonyOsSdk, resolveDeviceSerial, resolveKeyEvent, resolveTmpRoot, runCodelinter, runHvigorw, runOhpm, runProcess, scopedLogger, selectDevice, sendFile, sendGesture, sendInput, sendRawTouch, setHilogLevel, shell, shellChecked, signOpenHarmonyHap, spawnCompat, startEmulator, staticConfig, stopEmulator, streamHilog, takeScreenshot, toLongPath, toSpaceError, uninstallApp, unsignedHapRejection, validateTemplateLayout, verifySha256, waitForBoot, waitForBundle, waitForCondition, waitForLog, waitForTarget, watchLog, waypointsToRawEvents, withHapZip, withoutWindow, writeJson5File, writeJsonFile };
6162
+ export { ALL_SDKS, API_INDEX_FORMAT, APL_VALUES, APP_FEATURE_VALUES, type AbilityInfo, type AgcAuthInfo, AgcError, type AnalyzeFaultLogOptions, type ApiElsewhere, type ApiEntry, type ApiIndex, type ApiLanguage, type ApiSdkSelection, type ApiSearchHit, type ApiSearchOptions, type ApiSearchResult, type ApiShowResult, type ApiSymbolKind, type Apl, type AppFeature, type ApplyChangesOptions, type ApplyChangesResult, type ArktsCheckOptions, type ArktsCheckReport, type ArktsCheckSdk, type ArktsCheckSummary, BLANK_BACKGROUND_SHARE, BLANK_MAX_STDDEV, BLANK_PHASH_DISTANCE, type BaseImageFingerprint, type BinderEdge, type BinderInfo, type BinderNode, type BinderPropagation, type BinderTransaction, type BlankAnalysis, type BuildApiIndexOptions, type BuildDiagnostic, BuildFailedError, type BuildHapOptions, type BuildHapResult, type BuildReport, type BuildSdk, type BuildSummary, type BundleOptions, CMD_TOOLS_REQUIRED, CancelledError, type CaptureBurstOptions, type CaptureLogOptions, type CaptureLogResult, type CertificateInfo, ChecksumMismatchError, type CmdToolsFlavour, type CmdToolsFsOps, type CmdToolsInfo, CmdToolsNotInstalledError, type CmdToolsSdk, type CmdToolsStatus, type CmdWrapper, type CodelinterFinding, type CodelinterReport, type CodelinterResult, type CodelinterSummary, CommandFailedError, type ConfigKey, type ConfigProvider, type CppCrashLog, type CrashJson, type CrashVerdict, type CreateScaffoldOptions, type CreateScaffoldResult, DEFAULT_BOOT_TIMEOUT_SECONDS, DEFAULT_EMULATOR_PID_FILE, DEFAULT_PERF_FLOW_TAIL_MS, DEFAULT_PERF_FOR_MS, DEFAULT_SMOKE_DELAY_MS, DEFAULT_SMOKE_PID_TIMEOUT_MS, DEFAULT_TRACE_BUFFER_KB, DEFAULT_TRACE_CATEGORIES, DOCS_REPO, DOCS_SPARSE_PATH, DOCS_SPARSE_PATTERNS, type Declaration, type Decorator, type DeveloperAgreementStatus, type DeviceFullInfo, type DeviceInfo, type DiagnosticSource, type DiscoverHapsOptions, type DisplaySize, type DisplaySizeOptions, type DivergenceLayout, type DivergenceReason, type DocEntry, type DocHeading, type DocSearchHit, type DocSearchOptions, type DocSearchResult, type DocShowOptions, type DocShowResult, type DocTags, DocsIndex, type DoctorCheck, type DoctorOptions, type DoctorProject, type DoctorReport, type DoctorStatus, type DoctorVersions, type DownloadOptions, type DslSelector, type DumpLayoutOptions, type DumpLayoutResult, type DumpLogOptions, EMULATOR_KERNEL_APPEND, type ElementQuery, type ElementSelector, type EmulatorAccel, type EmulatorHealth, type EmulatorInstanceStatus, type EmulatorStatus, type ExtractZipOptions, FAULTLOG_DIR, FAULTLOG_TEMP_DIR, FAULT_LOG_FAMILIES, FLOW_ACTIONS, FLOW_VERSION, type FaultCompleteness, type FaultConfidence, type FaultLogClassification, type FaultLogDeviceOptions, type FaultLogEntry, type FaultLogFamily, type FaultLogKind, type FindInOtherSdksOptions, type FlatLayoutNode, type Flow, type FlowAction, type FlowDevice, FlowFormatError, type FlowFromRecordingInput, type FlowFromRecordingResult, type FlowPoint, type FlowStep, type FrameArea, type FreezeLog, type FreezeReport, type GenerateSigningConfigsOptions, type GenerateSigningConfigsResult, type GestureUitestOptions, type GetDeviceInfoOptions, type GreyImage, type GreyscaleDecoder, HARMONYOS_SDK_VERSIONS, HASH_BITS, HUAWEI_SITES, type HapAssetDiff, type HapProfileReport, type HapSigner, type HapSigningInfo, type HapVerifyStatus, type HapZip, type HarmonyOsAutoSignOptions, type HarmonyOsLoginOptions, type HarmonyOsSdk, type HarmonyOsSdkListing, type HarmonyOsSdkSource, type HarmonyOsSession, type HarmonyOsSessionOptions, type HarmonyOsSignHapOptions, type HarmonyOsSignHapResult, type HarmonyOsSigningResult, type HdcBootProbe, type HdcExecOptions, type HdcExecResult, type HdcShellOptions, type HealthInputs, type HidumperOptions, type HilogEntry, type HilogLevel, type HiperfFunction, type HiperfReport, type HuaweiSite, type HuaweiSiteCode, type HuaweiTeam, type HuaweiUserInfo, INSTALL_TMP_DIRNAME, type ImageComparison, type IndexedLayoutNode, type InputType, type InstallAppOptions, type InstallAppResult, type InstallCandidate, type InstallCmdToolsOptions, type InstallCmdToolsResult, type InstallEmulatorOptions, type InstallMethod, type InstallSdkFromArchiveOptions, type InstallSdkOptions, type InstallTempDir, type InstallTempDirOptions, type InstalledSdk, InsufficientSpaceError, type JsCrashLog, type JsFrame, type KeyboardState, LAYOUT_COMPONENTS, LAYOUT_MOVED_IOU, type LatestCrashOptions, type LaunchAppOptions, type LayoutDiff, type LayoutDiffNode, type LayoutMatch, type LayoutMatchKind, type LayoutNode, type LayoutSelector, type LayoutSummary, type LayoutWindow, type LayoutWindowSummary, type ListFaultLogsOptions, type ListWindowsOptions, type LoadApiIndexOptions, type LoadedApiIndex, type LocateTargetOptions, type LocatedTarget, type Logger, MAX_FAULTLOG_BYTES, MAX_POOL_INSTANCE, type MissingSdkSymbol, type ModuleHaps, NO_WINDOW, type NativeFrame, type NearMatch, OHOS_DAILY_BUILDS_URL, OHOS_URL_BASE, type OniroContext, OniroError, type OsFolder, type OutputSink, POOL_DEFAULT_MEMORY, POOL_DEFAULT_RESOLUTION, POOL_DEFAULT_SMP, POOL_DISKS, POOL_REQUIRED_IMAGES, type ParamOptions, type ParseTraceOptions, type ParsedBuildOutput, type ParsedTestOutput, type PerfFrameStats, type PerfGateResult, type PerfScene, type PerfStartup, type PerfThresholds, type PerfTraceOptions, type PerfTraceReport, type PerformInputOptions, type PerformInputResult, type PickTargetFailure, type PickedHap, type PoolInstancePorts, type PoolInstanceState, type PoolQemuSpec, type PrepareSigningOptions, type PrepareSigningResult, type ProgressReporter, type ProgressUpdate, type ProjectModule, type Prompter, type ProvisionProfileInfo, type QueryTerm, type RawLayoutNode, type RawTouchEvent, type ReadFaultLogOptions, type RebootDecision, type RebootOptions, type RecordFlowOptions, type RecordFlowResult, type RecordedElement, type RecordingTimes, type RecvFileOptions, type ReplayFlowOptions, type ReplayReport, type ReplayStepResult, type ResolveApiSdkOptions, type RouteSpecResult, type RunCodelinterOptions, type RunHvigorwOptions, type RunHvigorwResult, type RunOhpmOptions, type RunProcessOptions, type RunTestsOptions, type RunningProcess, type RuntimeOs, SAME_MAX_CHANGE_RATIO, SAME_MAX_HASH_DISTANCE, SELECTOR_KEYS, SIGNED_HAP_CHUNK_SIZE, SIGNING_ERRORS, type ScannedSource, type ScreenDump, type ScreenPage, type ScreenPlaceholder, type ScreenRoute, type ScreenSpecResult, type ScreensInventory, type ScreensOptions, type ScreensSpec, type ScreensSpecReport, type Screenshot, type ScreenshotOptions, type SdkArchiveInfo, type SdkInfo, SdkNotInstalledError, type SdkPkgInfo, type SdkRelease, type SelectorClause, type SelectorKey, type SelectorOperator, SelectorParseError, type SendFileOptions, type SendGestureOptions, type SendInputOptions, type SendRawTouchOptions, type SetHilogLevelOptions, type SignOpenHarmonyHapOptions, type SignOpenHarmonyHapResult, type SigningKind, type SigningMaterialPaths, type SigningMaterialSummary, type SigningPasswords, type SmokeCheckOptions, type SmokeCrashProbe, type SmokeCrashProbeArgs, type SmokeResult, type SourceComment, type StackFrame, type StartEmulatorOptions, type StartPoolInstanceOptions, type StopPoolInstanceOptions, type StoredSession, type StreamHilogOptions, type SummarizeTraceOptions, type SyncDocsOptions, type SyncDocsResult, THREAD_HEADER_RE, TMP_DIR_HINT, TargetNotFoundError, type TemplateOption, type TestCaseResult, type TestOutcome, type TestRunReport, type TestStatus, type TestSummary, type ThreadStack, type Token, type TokenKind, type TokenStore, type TraceAsyncSlice, type TraceCounterSample, type TraceModel, TraceParser, type TraceSlice, type TraceSummary, UI_RECORD_CSV, type UiInputType, type UiRecordEvent, type UiRecordFinger, UnsupportedPlatformError, VERSION, type VerifyHapOptions, type VerifyHapResult, type WaitForBootOptions, type WaitForBundleOptions, type WaitForConditionOptions, type WaitForLogOptions, type WaitForTargetOptions, type WaitPoolInstanceReadyOptions, type WakeScreenOptions, type WakeScreenResult, type WatchLogOptions, type Waypoint, type WindowInfo, type XPathExpression, type XPathSelector, aaTestCommand, alignTouches, allIndexed, analyzeBlank, analyzeFaultLog, apiIndexCachePath, apiIndexKey, apiLevelOf, appSandboxDir, applyChanges, arktsCheckerScript, assertDevicePath, assertLayoutSelector, assertPoolInstance, attemptHdcConnection, boxIoU, buildApiIndex, buildCmdWrapper, buildGestureCommands, buildGestureUitestCommand, buildHap, buildHvigorwArgs, buildInputCommand, buildOutputTail, buildPoolQemuArgs, buildPropagation, buildRawTouchCommand, buildWithDiagnostics, bundleNameFromHapConfig, captureBurst, captureLog, checkArkts, checkCmdTools, checkCmdToolsFlavour, checkDisk, checkNode, checkScreensAgainstSpec, checkSigning, classifyEmulatorHealth, classifyFaultLog, clauseMatches, cleanBuildOutput, cleanCodelinterOutput, cleanMarkerName, commMatchesBundle, compareImages, consoleLogger, createHarmonyOsSession, createInstallTempDir, createMaterial, createScaffold, createTempWorkDir, createTokenStore, cropRows, dHash, decideInstallMethod, decideOutcome, decideReboot, decryptPwd, dedupEntries, defaultContext, defaultPaths, defaultSignedHapPath, dependencyApiDiagnostic, describeBuildSdk, describeCmdTools, describeLayoutNode, describeProfileValidity, describeProject, describeReplacement, describeSigningMaterial, deserializeApiIndex, detectAaStartFailure, detectCmdToolsFlavour, detectInstallFailure, detectProjectSdkVersion, detectRuntimeOs, detectSigningConfigNames, diagnoseBuildFailure, diffEntryNames, diffHapAssets, diffLayouts, discoverHaps, docQueryTerms, docTokens, docWords, docsDirFor, docsRefFor, docsTree, downloadAndInstallSdk, downloadFile, dumpLayout, dumpLog, dumpRenderService, dumpScreen, dumpWindow, elementAt, emulatorAccelArgs, encryptPwd, ensureFreeSpace, ensureInstallOk, ensureOhModules, ensureOk, ensureRemoteOk, escapeCmdArgument, escapeCmdCommand, evaluatePerfGate, evaluateXPath, existingHapOrUnsigned, expectFor, extractStackErrors, extractTarball, extractZipWithProgress, faultloggerCommand, fieldSelector, findApiInOtherSdks, findAppPids, findAppPidsBySurface, findAppProcessId, findCmdToolsSourceDir, findCoveredNodes, findHapSignTool, findHarmonyOsSdk, findKeyboardWindow, findLayoutNodes, findMissingProjectSdk, findRunningProcess, findSdkOsDir, findVisibleMatch, flatFrameHash, flatLayoutNode, flattenLayout, flowFromRecording, forceStop, formatBytes, formatFlow, formatHapVerification, formatSelector, formatUtc, generateSigningConfigs, getApiIndexCacheDir, getBundleName, getCmdToolsBin, getCmdToolsDownloadUrl, getCmdToolsPath, getCmdToolsStatus, getDefaultInstanceStatus, getDeviceInfo, getDisplaySize, getDocsRootDir, getEmulatorDir, getEmulatorStatus, getFreeSpaceBytes, getHarmonyOsSdkListing, getHdcPath, getHvigorwPath, getImeBundles, getInstalledSdks, getKey, getMainAbility, getOhosBaseSdkHome, getOhpmPath, getOsFolder, getPoolInstanceStatus, getSdkFilename, getSdkRootDir, getSupportedSdksForUi, hammingDistance, harmonyOsAutoSign, harmonyOsSdkLabelForApi, harmonyOsSignHap, hasOwnFields, hdcClientFailure, hdcExec, hdcTargetArgs, hdcTargetArgsFor, hideKeyboard, hilogSection, hilogTimeMs, holdScreenOn, indexLayout, installApp, installCmdTools, installEmulator, installFailureReason, installSdkFromArchive, installedApiLevels, inventoryScreens, isBundleInstalled, isCmdToolsInstalled, isCrashJson, isElementSelector, isEmulatorInstalled, isInstanceProcess, isLockScreenShown, isOutOfSpaceError, isPidAlive, isRamBackedPath, isTcpPortFree, isTestHap, isUnsignedHap, isUsableDevice, isValidBundleName, isValidProjectName, keystrokeChar, keystrokeName, killProcessTree, latestCrash, launchApp, listAbilities, listDevices, listFaultLogs, listLayoutWindows, listMarkdown, listModules, listPoolInstanceNumbers, listPoolInstanceStatuses, listRunningProcesses, listTemplates, listWindows, livePoolPids, loadApiIndex, locateTarget, matchSelector, mergeDocBlocks, missingProjectRootFiles, missingSdkSymbols, nameParts, nearMatches, needsCmdWrapper, nodeLabel, nonInteractivePrompter, noopLogger, noopProgress, normaliseLocalPath, normalizeFaultTime, normalizeKit, ohModulesPackage, pHash, pagesMatching, paramGet, paramGetMany, paramSet, parseActiveRefreshRate, parseArktsCheckOutput, parseBinder, parseBounds, parseBuildOutput, parseCodelinterFindings, parseCodelinterReport, parseCppCrash, parseCrashRecordHeads, parseDeviceList, parseDeviceTime, parseDoc, parseDocBlock, parseFaultLogList, parseFaultLogName, parseFlow, parseFrame, parseFreeze, parseHilogLine, parseHiperfReport, parseImeBundles, parseJsCrash, parseJsFrame, parseLayoutBaseline, parseMainAbilityFromBmDump, parseNativeFrame, parseParamValues, parsePowerState, parseProvisionProfile, parseRecorderForeground, parseRemoteExit, parseSelector, parseTestOutput, parseThreadStacks, parseTouchDowns, parseTraceFile, parseTraceText, parseUiRecordLines, parseUtcOffset, parseWindowList, parseXPath, perfSliceFilter, perfTrace, performInput, pickHap, pickSigningKind, pickTarget, pixelChangeRatio, poolInstanceDir, poolInstancePorts, poolRootDir, prepareSigning, probeEmulatorBoot, pruneLayout, quantile, rawWindowSubtree, readCmdToolsInfo, readDefaultEmulatorPid, readFaultLog, readFlowFile, readHapBundleName, readHapSigningInfo, readJson5File, readJsonFile, readLogTail, readPoolState, readProvisionProfile, readSdkPkg, readSdkRelease, readTestModuleName, readZipEntry, reboot, recordFlow, recvFile, removeCmdTools, removeEmulator, removeSdk, removeTempWorkDir, renderCrashJson, replayFlow, requireHarmonyOsSdk, resizeGrey, resolveApiSdk, resolveArktsCheckSdk, resolveBuildSdk, resolveDeviceSerial, resolveKeyEvent, resolveProjectSdkDir, resolveSelectorKey, resolveTmpRoot, runCodelinter, runDoctor, runHvigorw, runOhpm, runProcess, runTests, scanEts, scopedLogger, sdkTooOldDiagnostic, searchApi, selectDevice, selectableTree, selectorAttribute, selectorFor, sendFile, sendGesture, sendInput, sendRawTouch, serializeApiIndex, setHilogLevel, shell, shellChecked, showApi, signOpenHarmonyHap, signingMismatch, smokeCheck, smokeVerdict, spawnCompat, startEmulator, startPoolInstance, stateFile, staticConfig, statusFromCode, stopEmulator, stopPoolInstance, streamHilog, stripHidumperBanner, suggestApiSymbols, summarizeDivergenceLayout, summarizeLayout, summarizeTrace, syncDocs, takeScreenshot, testHapPath, toLongPath, toSpaceError, uninstallApp, unsignedHapRejection, validateTemplateLayout, verifyHap, verifyHapExitCode, verifySha256, waitForBoot, waitForBundle, waitForCondition, waitForLog, waitForTarget, waitPoolInstanceReady, wakeAndUnlock, watchLog, waypointsToRawEvents, windowNotFoundError, windowSubtree, withHapZip, withoutWindow, wordIn, writeJson5File, writeJsonFile, writePoolState };