@oniroproject/core 0.6.2 → 0.8.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
@@ -8,6 +8,12 @@ interface Logger {
8
8
  }
9
9
  declare const noopLogger: Logger;
10
10
  declare const consoleLogger: Logger;
11
+ /**
12
+ * Wrap a Logger so every message is prefixed with `[<scope>] `. Standardizes the
13
+ * ad-hoc `[hdc]` / `[build]` / `[sign]` / `[hilog]` / `[emulator]` prefixes that
14
+ * were previously hand-written at each call site.
15
+ */
16
+ declare function scopedLogger(logger: Logger, scope: string): Logger;
11
17
 
12
18
  interface ProgressUpdate {
13
19
  message?: string;
@@ -22,7 +28,7 @@ declare const noopProgress: ProgressReporter;
22
28
  * Keys read from the ConfigProvider by core. Frontends (CLI, VS Code extension)
23
29
  * implement the provider however they like (env vars, settings.json, etc.).
24
30
  */
25
- type ConfigKey = 'sdkRootDir' | 'cmdToolsPath' | 'emulatorDir' | 'hapPath' | 'cmdToolsUrlLinux' | 'cmdToolsUrlWindows' | 'cmdToolsUrlMac' | 'emulatorUrl';
31
+ type ConfigKey = 'sdkRootDir' | 'cmdToolsPath' | 'hdcPath' | 'emulatorDir' | 'hapPath' | 'cmdToolsUrlLinux' | 'cmdToolsUrlWindows' | 'cmdToolsUrlMac' | 'emulatorUrl' | 'tmpDir' | 'sdkUrlBase' | 'applicationCertPath';
26
32
  interface ConfigProvider {
27
33
  /**
28
34
  * Get the configured value for `key`, or `fallback` if unset/empty.
@@ -90,9 +96,29 @@ declare class ChecksumMismatchError extends OniroError {
90
96
  readonly actual: string;
91
97
  constructor(expected: string, actual: string);
92
98
  }
99
+ /**
100
+ * A download/extract ran out of room on the filesystem holding its scratch
101
+ * directory. The message is built by the caller (see `sdk/tmp.ts`) so it can name
102
+ * the directory, whether it is RAM-backed, and how to point elsewhere.
103
+ */
104
+ declare class InsufficientSpaceError extends OniroError {
105
+ readonly dir: string;
106
+ constructor(message: string, dir: string, cause?: unknown);
107
+ }
93
108
  declare class CancelledError extends OniroError {
94
109
  constructor(message?: string);
95
110
  }
111
+ /**
112
+ * A spawned command ran to completion but exited non-zero. Lets callers
113
+ * distinguish "the tool ran and failed" from "the tool could not be spawned"
114
+ * (a missing binary surfaces as an OniroError / CmdToolsNotInstalledError).
115
+ */
116
+ declare class CommandFailedError extends OniroError {
117
+ readonly command: string;
118
+ readonly exitCode: number;
119
+ readonly stderr: string;
120
+ constructor(command: string, exitCode: number, stderr: string);
121
+ }
96
122
 
97
123
  /**
98
124
  * Carries the cross-cutting dependencies most core functions need: a Logger and a ConfigProvider.
@@ -107,6 +133,17 @@ declare function defaultContext(overrides?: Partial<OniroContext>): OniroContext
107
133
  interface SdkRelease {
108
134
  version: string;
109
135
  api: string;
136
+ /**
137
+ * Number of leading path components to strip when extracting the release
138
+ * tarball, per OS family. The Huawei mirror packs linux+windows in one
139
+ * tarball (no top-level wrapper for some releases → 0, else 1); macOS
140
+ * tarballs have a deeper layout (3). This table is the single source of
141
+ * truth read by `getSdkFilename()`.
142
+ */
143
+ tarballStrip: {
144
+ linuxWindows: number;
145
+ darwin: number;
146
+ };
110
147
  }
111
148
  /**
112
149
  * Known OpenHarmony SDK releases. Kept in sync with the bash CLI / extension.
@@ -131,9 +168,9 @@ interface SdkArchiveInfo {
131
168
  * Resolve the SDK archive filename, OS folder, and tar strip count for the current platform.
132
169
  *
133
170
  * The Huawei mirror packages Linux and Windows together in one tarball with `linux/` and
134
- * `windows/` subfolders. For 5.0.0/5.0.1/6.0 the tarball has no extra top-level wrapper
135
- * (strip=0); newer/older releases wrap the OS folders in a single top-level directory (strip=1).
136
- * macOS tarballs have a deeper layout (strip=3).
171
+ * `windows/` subfolders; macOS tarballs have a deeper layout. The per-release strip counts
172
+ * live in {@link ALL_SDKS} (`tarballStrip`). An unrecognized version falls back to the
173
+ * historical default (linux/windows=1, darwin=3).
137
174
  */
138
175
  declare function getSdkFilename(version?: string): SdkArchiveInfo;
139
176
 
@@ -146,18 +183,27 @@ declare function getOhosBaseSdkHome(config: ConfigProvider): string;
146
183
  declare function getCmdToolsPath(config: ConfigProvider): string;
147
184
  declare function getEmulatorDir(config: ConfigProvider): string;
148
185
  /**
149
- * Resolve the OHPM binary path inside the command-line tools install.
150
- * On Windows tries common executable suffixes (.exe, .cmd, .bat) before the POSIX name.
186
+ * Resolve a binary inside the command-line tools `bin/` directory by name
187
+ * (e.g. `'ohpm'`, `'hvigorw'`, `'codelinter'`). On Windows tries common
188
+ * executable suffixes (.exe, .cmd, .bat) before the POSIX name.
151
189
  */
152
- declare function getCmdToolsBin(config: ConfigProvider): string;
190
+ declare function getCmdToolsBin(config: ConfigProvider, name?: string): string;
191
+ /** Resolve the OHPM binary path inside the command-line tools install. */
192
+ declare function getOhpmPath(config: ConfigProvider): string;
153
193
  /**
154
- * Resolve the hdc binary path inside the SDK toolchains tree.
194
+ * Resolve the hdc binary. An explicit `hdcPath` override (config key / `ONIRO_HDC`
195
+ * env var) wins — point it at a wrapper/proxy hdc when the device is not directly
196
+ * attached here (e.g. a remote device behind an SSH-tunnel `hdc` wrapper). When
197
+ * unset, fall back to the hdc bundled in the SDK toolchains tree.
155
198
  */
156
199
  declare function getHdcPath(config: ConfigProvider): string;
157
200
  /**
158
- * Resolve the hvigorw wrapper for a project, preferring the project-local copy
159
- * (which carries the project's pinned hvigor version) and falling back to the
160
- * one shipped with the command-line tools.
201
+ * Resolve the hvigorw wrapper for a project. Prefers the project-local copy
202
+ * (which carries the project's pinned hvigor version) — but ONLY when that
203
+ * wrapper is structurally complete. HMOS-vendored projects (systemui, launcher)
204
+ * ship a project-local `hvigorw` whose `hvigor/` install is absent, so the
205
+ * wrapper crashes on startup; in that case we fall back to the hvigorw bundled
206
+ * with the command-line tools, which is always installed.
161
207
  */
162
208
  declare function getHvigorwPath(config: ConfigProvider, projectDir: string): string;
163
209
 
@@ -168,6 +214,82 @@ declare function getHvigorwPath(config: ConfigProvider, projectDir: string): str
168
214
  */
169
215
  declare function detectProjectSdkVersion(projectRoot: string, logger?: Logger): number | undefined;
170
216
 
217
+ /** Name of the scratch folder created next to an install target. */
218
+ declare const INSTALL_TMP_DIRNAME = ".oniro-tmp";
219
+ /** Advice appended to out-of-space failures in the scratch directory. */
220
+ declare const TMP_DIR_HINT: string;
221
+ /**
222
+ * Resolve the directory that download/extract scratch space is created in.
223
+ *
224
+ * Precedence: explicit override (CLI `--tmp-dir`) → `tmpDir` config key
225
+ * (`ONIRO_TMP_DIR`) → `<installRoot>/.oniro-tmp` → the system temp dir.
226
+ *
227
+ * The default sits next to the install target so that the unpacked tree is renamed
228
+ * into place rather than copied across a device boundary, and so the system temp dir
229
+ * — a RAM-backed `tmpfs` on most Linux systems, and far smaller than a multi-GB
230
+ * archive — is never in the picture.
231
+ */
232
+ declare function resolveTmpRoot(config: ConfigProvider, override?: string, installRoot?: string): string;
233
+ /** Create a private scratch directory under `root`, creating `root` if needed. */
234
+ declare function createTempWorkDir(root: string, prefix: string): string;
235
+ /**
236
+ * Remove a scratch directory once an install is done, taking the `.oniro-tmp` root
237
+ * with it when that leaves it empty. A root the caller named explicitly is left alone,
238
+ * as are roots another install is still using (the rmdir simply fails).
239
+ */
240
+ declare function removeTempWorkDir(dir: string, root?: string): void;
241
+ interface InstallTempDirOptions {
242
+ config: ConfigProvider;
243
+ /** Explicit scratch directory (CLI `--tmp-dir`). */
244
+ override?: string;
245
+ /** Directory the install lands in; the default scratch root is created inside it. */
246
+ installRoot: string;
247
+ prefix: string;
248
+ logger?: Logger;
249
+ }
250
+ interface InstallTempDir {
251
+ /** The private per-run scratch directory. Remove it when the install finishes. */
252
+ dir: string;
253
+ /** The configurable root it was created under, for out-of-space messages. */
254
+ root: string;
255
+ }
256
+ /**
257
+ * Create the scratch directory for an install, defaulting to `<installRoot>/.oniro-tmp`.
258
+ *
259
+ * When that default is unusable — a read-only or root-owned install parent, say — the
260
+ * system temp dir is used instead. A directory the caller asked for explicitly is never
261
+ * swapped out silently, and a full filesystem is reported rather than papered over.
262
+ */
263
+ declare function createInstallTempDir(opts: InstallTempDirOptions): InstallTempDir;
264
+ /**
265
+ * Bytes available to an unprivileged user on the filesystem holding `dir`.
266
+ * Returns null when the platform cannot report it.
267
+ */
268
+ declare function getFreeSpaceBytes(dir: string): number | null;
269
+ /**
270
+ * Whether `dir` lives on a RAM-backed filesystem (`tmpfs`/`ramfs`), i.e. one whose
271
+ * capacity comes out of memory rather than disk.
272
+ */
273
+ declare function isRamBackedPath(dir: string): boolean;
274
+ declare function formatBytes(bytes: number): string;
275
+ /** Recognise an out-of-disk-space failure from fs/stream errors and their wrappers. */
276
+ declare function isOutOfSpaceError(err: unknown): boolean;
277
+ /**
278
+ * Fail before writing a byte when the filesystem holding `dir` cannot take
279
+ * `requiredBytes`. A no-op when free space cannot be determined.
280
+ */
281
+ declare function ensureFreeSpace(dir: string, requiredBytes: number, what: string): void;
282
+ /**
283
+ * Convert an out-of-space failure into an {@link InsufficientSpaceError}; any other
284
+ * error is returned unchanged, so callers can `throw toSpaceError(err, ...)`.
285
+ *
286
+ * `tmpRoot` is the scratch directory the operation was using. Failures under it are
287
+ * reported against it (not the per-run subdirectory the user cannot configure) and get
288
+ * the `--tmp-dir` remedy; failures elsewhere — an install target that is full — name
289
+ * their own directory and skip the remedy, which would not help.
290
+ */
291
+ declare function toSpaceError(err: unknown, tmpRoot: string, what: string): unknown;
292
+
171
293
  interface DownloadOptions {
172
294
  url: string;
173
295
  dest: string;
@@ -177,10 +299,21 @@ interface DownloadOptions {
177
299
  start?: number;
178
300
  /** Overall progress range to consume (0..100). Default 100. */
179
301
  range?: number;
302
+ /** What the download is for, used in out-of-space messages. */
303
+ what?: string;
304
+ /**
305
+ * Configurable scratch root that `dest` lives under, if any. Out-of-space messages
306
+ * name it instead of the per-run subdirectory, since that is what the user can change.
307
+ */
308
+ tmpRoot?: string;
180
309
  }
181
310
  /**
182
311
  * Stream a remote file to disk with optional progress reporting and cancellation.
183
312
  * Follows redirects via the `follow-redirects` library.
313
+ *
314
+ * Fails fast with an `InsufficientSpaceError` when the destination filesystem cannot
315
+ * hold the advertised `content-length` — the common case being a system temp dir on a
316
+ * RAM-backed tmpfs that is far smaller than the SDK/tools archives.
184
317
  */
185
318
  declare function downloadFile(opts: DownloadOptions): Promise<void>;
186
319
  /**
@@ -239,6 +372,11 @@ interface InstallSdkOptions {
239
372
  progress?: ProgressReporter;
240
373
  abortSignal?: AbortSignal;
241
374
  logger?: Logger;
375
+ /**
376
+ * Scratch directory for the download/extract temporaries. Overrides the `tmpDir`
377
+ * config key and the default location next to the install target.
378
+ */
379
+ tmpDir?: string;
242
380
  }
243
381
  /**
244
382
  * Download and install an OpenHarmony SDK release into `<sdkRootDir>/<osFolder>/<api>`.
@@ -276,6 +414,11 @@ interface InstallCmdToolsOptions {
276
414
  logger?: Logger;
277
415
  /** Skip download and install from a local zip the caller already has. */
278
416
  localZipPath?: string;
417
+ /**
418
+ * Scratch directory for the download/extract temporaries. Overrides the `tmpDir`
419
+ * config key and the default location next to the install target.
420
+ */
421
+ tmpDir?: string;
279
422
  }
280
423
  /**
281
424
  * Install the OpenHarmony command-line tools into `<cmdToolsPath>`.
@@ -321,6 +464,11 @@ type Apl = 'normal' | 'system_basic' | 'system_core';
321
464
  type AppFeature = 'hos_normal_app' | 'hos_system_app';
322
465
  declare const APL_VALUES: readonly Apl[];
323
466
  declare const APP_FEATURE_VALUES: readonly AppFeature[];
467
+ /** Keystore passwords. These must match the keystore in use. */
468
+ interface SigningPasswords {
469
+ store: string;
470
+ key: string;
471
+ }
324
472
  /**
325
473
  * Which signing key pairs with the chosen `apl`.
326
474
  *
@@ -362,6 +510,18 @@ interface GenerateSigningConfigsOptions {
362
510
  * existing `allowed-acls` is left alone.
363
511
  */
364
512
  acls?: string[];
513
+ /**
514
+ * Keystore passwords written into the profile sign step and the build-profile
515
+ * signingConfigs. Defaults to `'123456'` (the SDK's bundled OpenHarmony.p12
516
+ * password). Only override when supplying a matching custom keystore.
517
+ */
518
+ passwords?: SigningPasswords;
519
+ /**
520
+ * Override the bundled application cert chain (application-release kind only).
521
+ * When set, this file is copied to `signatures/OpenHarmonyApplication.cer`
522
+ * instead of the inlined cert. May also be sourced from `config.applicationCertPath`.
523
+ */
524
+ applicationCertPath?: string;
365
525
  /** Optional logger; defaults to no-op. */
366
526
  logger?: Logger;
367
527
  }
@@ -386,14 +546,20 @@ interface InstallEmulatorOptions {
386
546
  progress?: ProgressReporter;
387
547
  abortSignal?: AbortSignal;
388
548
  logger?: Logger;
549
+ /**
550
+ * Scratch directory for the downloaded ZIP. Overrides the `tmpDir` config key and
551
+ * the default location next to the install target.
552
+ */
553
+ tmpDir?: string;
389
554
  }
390
555
  /**
391
556
  * Download and extract the Oniro emulator into the configured `emulatorDir`.
392
557
  */
393
558
  declare function installEmulator(opts: InstallEmulatorOptions): Promise<void>;
394
559
  /**
395
- * Heuristic: emulator is considered installed if `images/run.sh` is present.
396
- * On Windows-only emulator builds (when they exist) this may not apply.
560
+ * Heuristic: the emulator is considered installed if either bundled launcher
561
+ * (`images/run.sh` or `images/run.bat`) is present, so a Windows-only build is
562
+ * detected too.
397
563
  */
398
564
  declare function isEmulatorInstalled(config: ConfigProvider): boolean;
399
565
  declare function removeEmulator(config: ConfigProvider): void;
@@ -439,16 +605,485 @@ interface StartEmulatorOptions {
439
605
  declare function startEmulator(opts: StartEmulatorOptions): Promise<void>;
440
606
  declare function stopEmulator(logger?: Logger): Promise<void>;
441
607
 
608
+ /** Result of a spawned command. `code` is the process exit code (-1 if it was killed). */
609
+ interface HdcExecResult {
610
+ code: number;
611
+ stdout: string;
612
+ stderr: string;
613
+ }
614
+ /** Streamed output callback, invoked per stdout/stderr chunk as it arrives. */
615
+ type OutputSink = (chunk: string, stream: 'stdout' | 'stderr') => void;
616
+ interface RunProcessOptions {
617
+ /** Executable to spawn. */
618
+ command: string;
619
+ /** Args passed verbatim (spawn runs with `shell: false`, so no shell parsing). */
620
+ args: readonly string[];
621
+ cwd?: string;
622
+ env?: NodeJS.ProcessEnv;
623
+ /** Kill the process after this many ms and reject. Default 60_000. */
624
+ timeoutMs?: number;
625
+ /** Abort the process; rejects with CancelledError. */
626
+ abortSignal?: AbortSignal;
627
+ /** Receive stdout/stderr chunks as they arrive (in addition to the buffered result). */
628
+ onOutput?: OutputSink;
629
+ /** Reserved for future scoped diagnostics; the buffered result is returned regardless. */
630
+ logger?: Logger;
631
+ }
632
+ /**
633
+ * Spawn an arbitrary process with `shell: false` and collect its output. The
634
+ * single low-level primitive every other command in the package builds on —
635
+ * because args are passed as an array and never interpolated into a shell
636
+ * string, command construction is injection-safe by construction.
637
+ *
638
+ * Resolves with `{ code, stdout, stderr }` for ANY exit code (callers opt into
639
+ * throw-on-non-zero via {@link ensureOk}). Rejects only on spawn failure
640
+ * (e.g. missing binary), timeout, or abort.
641
+ */
642
+ declare function runProcess(opts: RunProcessOptions): Promise<HdcExecResult>;
643
+ interface HdcExecOptions {
644
+ config: ConfigProvider;
645
+ /** Args passed to hdc verbatim, e.g. `['shell','aa','start','-a',ability,'-b',bundle]`. */
646
+ args: readonly string[];
647
+ /** Device serial; when set, prepends `['-t', serial]`. */
648
+ deviceSerial?: string;
649
+ /** Default 60_000. */
650
+ timeoutMs?: number;
651
+ abortSignal?: AbortSignal;
652
+ onOutput?: OutputSink;
653
+ logger?: Logger;
654
+ }
655
+ /**
656
+ * Run `hdc [-t <serial>] <args...>`. Resolves with `{ code, stdout, stderr }`
657
+ * for any exit code; use {@link ensureOk} to throw on non-zero.
658
+ */
659
+ declare function hdcExec(opts: HdcExecOptions): Promise<HdcExecResult>;
660
+ interface HdcShellOptions extends Omit<HdcExecOptions, 'args'> {
661
+ /** A single shell command, run as `hdc shell <command>` (one argv element — not host word-split). */
662
+ command: string;
663
+ }
664
+ /** Convenience wrapper for `hdc shell <command>`. */
665
+ declare function shell(opts: HdcShellOptions): Promise<HdcExecResult>;
666
+ /**
667
+ * Throw a typed {@link CommandFailedError} when `result.code !== 0`, otherwise
668
+ * return the result unchanged. Lets callers opt into throw-semantics.
669
+ */
670
+ declare function ensureOk(result: HdcExecResult, command: string): HdcExecResult;
671
+ /**
672
+ * Parse the exit-code marker appended by {@link shellChecked}. Pure/testable.
673
+ * Returns the remote exit code plus stdout with every marker occurrence
674
+ * stripped, or `null` when no marker is present (the command was killed/timed
675
+ * out, or the device shell never reached the trailing `echo`).
676
+ */
677
+ declare function parseRemoteExit(stdout: string): {
678
+ code: number;
679
+ stdout: string;
680
+ } | null;
681
+ /**
682
+ * Like {@link shell}, but recovers the REMOTE command's exit status.
683
+ *
684
+ * `hdc shell "<cmd>"` reports hdc's OWN exit code (≈ always 0) regardless of
685
+ * whether `<cmd>` succeeded on the device — so on-device failures (`uinput`
686
+ * rejecting its args, a `bm install` error, a missing binary) otherwise look
687
+ * like success. We append an exit-code marker, parse it back out, and report
688
+ * it as `code`, with the marker stripped from stdout. Pair with
689
+ * {@link ensureRemoteOk} to throw on a non-zero remote exit.
690
+ */
691
+ declare function shellChecked(opts: HdcShellOptions): Promise<HdcExecResult>;
692
+ /**
693
+ * Throw a typed {@link CommandFailedError} on a non-zero result, preferring
694
+ * stderr but falling back to stdout for the detail — device tools like
695
+ * `uinput`/`uitest` print their errors to stdout, not stderr.
696
+ */
697
+ declare function ensureRemoteOk(result: HdcExecResult, command: string): HdcExecResult;
698
+
699
+ interface DeviceInfo {
700
+ /** Connect key — a USB serial or a `host:port` for a TCP target. */
701
+ serial: string;
702
+ /** 'Connected' | 'Offline' | 'Unauthorized' | … | 'Unknown' when not reported. */
703
+ status: string;
704
+ /** 'USB' | 'TCP' | … when reported by `-v`. */
705
+ connection?: string;
706
+ /** Device model, populated by getDeviceInfo (not by the bare target list). */
707
+ model?: string;
708
+ }
709
+ /**
710
+ * Parse the output of `hdc list targets -v` into structured rows. The first token
711
+ * of each non-empty row is the connect key (serial); connection/status are matched
712
+ * by keyword among the remaining tokens. `[Empty]` (no devices) yields `[]`.
713
+ */
714
+ declare function parseDeviceList(stdout: string): DeviceInfo[];
715
+ /** List connected hdc targets via `hdc list targets -v`. Empty list when none. */
716
+ declare function listDevices(config: ConfigProvider, opts?: {
717
+ timeoutMs?: number;
718
+ logger?: Logger;
719
+ }): Promise<DeviceInfo[]>;
720
+ /**
721
+ * Resolve which device serial to address: an explicit `serial` wins, then the
722
+ * `ONIRO_DEVICE_SERIAL` / `DEVICE_SERIAL` env vars, then the single connected
723
+ * device. Throws when none or more than one is connected and nothing was specified.
724
+ */
725
+ declare function selectDevice(config: ConfigProvider, serial?: string, opts?: {
726
+ timeoutMs?: number;
727
+ logger?: Logger;
728
+ }): Promise<string>;
729
+
730
+ interface ParamOptions {
731
+ deviceSerial?: string;
732
+ timeoutMs?: number;
733
+ logger?: Logger;
734
+ }
735
+ /** Read a system property via `hdc shell param get <key>`. Returns the trimmed value. */
736
+ declare function paramGet(config: ConfigProvider, key: string, opts?: ParamOptions): Promise<string>;
737
+ /**
738
+ * Set a system property via `hdc shell param set <key> <value>`. The canonical
739
+ * reboot path is `paramSet(config, 'ohos.startup.powerctrl', 'reboot')`.
740
+ */
741
+ declare function paramSet(config: ConfigProvider, key: string, value: string, opts?: ParamOptions): Promise<void>;
742
+
743
+ interface SendFileOptions {
744
+ config: ConfigProvider;
745
+ /** Local source path. */
746
+ local: string;
747
+ /** Remote destination path on the device. */
748
+ remote: string;
749
+ deviceSerial?: string;
750
+ timeoutMs?: number;
751
+ abortSignal?: AbortSignal;
752
+ onOutput?: OutputSink;
753
+ logger?: Logger;
754
+ }
755
+ /** Push a local file to the device via `hdc file send <local> <remote>`. */
756
+ declare function sendFile(opts: SendFileOptions): Promise<void>;
757
+ interface RecvFileOptions {
758
+ config: ConfigProvider;
759
+ /** Remote source path on the device. */
760
+ remote: string;
761
+ /** Local destination path. */
762
+ local: string;
763
+ deviceSerial?: string;
764
+ timeoutMs?: number;
765
+ abortSignal?: AbortSignal;
766
+ onOutput?: OutputSink;
767
+ logger?: Logger;
768
+ }
769
+ /** Pull a file from the device via `hdc file recv <remote> <local>`. */
770
+ declare function recvFile(opts: RecvFileOptions): Promise<void>;
771
+
772
+ interface DisplaySize {
773
+ width: number;
774
+ height: number;
775
+ }
776
+ interface DisplaySizeOptions {
777
+ deviceSerial?: string;
778
+ timeoutMs?: number;
779
+ logger?: Logger;
780
+ }
781
+ /**
782
+ * Resolve the device's render resolution from `hidumper -s 10 -a screen`
783
+ * (`render resolution=WxH`). Returns null when unavailable. This is the W/H
784
+ * source for screenshots and the 0–1 normalization of layout bounds — no image
785
+ * decoding is involved.
786
+ */
787
+ declare function getDisplaySize(config: ConfigProvider, opts?: DisplaySizeOptions): Promise<DisplaySize | null>;
788
+
789
+ interface WaitForConditionOptions {
790
+ /** Resolves true when the condition is satisfied. Called once per poll. */
791
+ probe: () => Promise<boolean>;
792
+ /** Overall deadline. */
793
+ timeoutMs: number;
794
+ /** Poll interval. Default 2000. */
795
+ pollMs?: number;
796
+ /** Abort the wait; rejects with CancelledError. */
797
+ abortSignal?: AbortSignal;
798
+ /** Called every `heartbeatEvery` attempts (default 6) with progress info. */
799
+ onHeartbeat?: (attempt: number, remainingMs: number) => void;
800
+ heartbeatEvery?: number;
801
+ logger?: Logger;
802
+ /** Message for the timeout error. */
803
+ timeoutMessage?: string;
804
+ }
805
+ /**
806
+ * Generic deadline + poll + heartbeat loop. Calls `probe()` every `pollMs` until
807
+ * it resolves true (→ resolve) or the deadline passes (→ throw OniroError).
808
+ * A probe that throws is treated as "not yet" (the loop keeps polling) — this is
809
+ * what lets device waits tolerate transient hdc disconnects mid-reboot. Aborting
810
+ * the signal rejects with CancelledError.
811
+ *
812
+ * Extracted from the emulator hdc-wait loop so device lifecycle helpers share it.
813
+ */
814
+ declare function waitForCondition(opts: WaitForConditionOptions): Promise<void>;
815
+
816
+ interface WaitForBundleOptions {
817
+ config: ConfigProvider;
818
+ bundle: string;
819
+ deviceSerial?: string;
820
+ timeoutMs?: number;
821
+ abortSignal?: AbortSignal;
822
+ logger?: Logger;
823
+ }
824
+ /**
825
+ * Poll `pidof <bundle>` until the bundle has a clean numeric pid. Empty/failed
826
+ * pidof responses (including while the device is unreachable) do NOT count.
827
+ */
828
+ declare function waitForBundle(opts: WaitForBundleOptions): Promise<void>;
829
+ interface WaitForBootOptions {
830
+ config: ConfigProvider;
831
+ /** Require a clean numeric pid for this process/bundle name before returning. */
832
+ untilPidOf?: string;
833
+ deviceSerial?: string;
834
+ timeoutMs?: number;
835
+ abortSignal?: AbortSignal;
836
+ logger?: Logger;
837
+ }
838
+ /**
839
+ * Poll until the device responds AND (when `untilPidOf` is set) that process has
840
+ * a clean numeric pid. Tolerates the transient hdc disconnect during a reboot.
841
+ */
842
+ declare function waitForBoot(opts: WaitForBootOptions): Promise<void>;
843
+ interface RebootOptions {
844
+ config: ConfigProvider;
845
+ /** 'system' (default) reboots via param set; bootloader/recovery via `reboot <mode>`. */
846
+ mode?: 'system' | 'bootloader' | 'recovery';
847
+ /** When set (system mode), block until this bundle has a clean numeric pid after the reboot. */
848
+ waitForBundle?: string;
849
+ deviceSerial?: string;
850
+ timeoutMs?: number;
851
+ abortSignal?: AbortSignal;
852
+ logger?: Logger;
853
+ }
854
+ /**
855
+ * Reboot the device. System reboots use `param set ohos.startup.powerctrl reboot`
856
+ * (the path that works when force-stopping systemui is blocked); bootloader/
857
+ * recovery use `hdc shell reboot <mode>`. A reboot frequently tears down the hdc
858
+ * connection before the command returns, so command failure here is tolerated.
859
+ *
860
+ * When `waitForBundle` is set (system mode), waits for the device to drop and
861
+ * come back with the bundle running — so it doesn't return on the pre-reboot pid.
862
+ * A TCP target (e.g. an emulator at `127.0.0.1:55555`) is reconnected via
863
+ * `hdc tconn` during that wait, since hdc does not auto-reconnect TCP sessions
864
+ * across a reboot the way it does USB devices — pass the address as `deviceSerial`.
865
+ */
866
+ declare function reboot(opts: RebootOptions): Promise<void>;
867
+
868
+ interface Screenshot {
869
+ /** Raw JPEG bytes, exactly as `snapshot_display` wrote them (no decode/resize). */
870
+ pixels: Buffer;
871
+ /** Device render width/height from hidumper; 0 when it couldn't be resolved. */
872
+ width: number;
873
+ height: number;
874
+ }
875
+ interface ScreenshotOptions {
876
+ config: ConfigProvider;
877
+ deviceSerial?: string;
878
+ timeoutMs?: number;
879
+ logger?: Logger;
880
+ }
881
+ /**
882
+ * Capture the screen via on-device `snapshot_display`, pull the JPEG bytes back,
883
+ * and return them raw alongside the device resolution. The agent-facing grid
884
+ * overlay / downscale / base64 encoding stays in the MCP — core does no image
885
+ * decoding and adds no image dependency.
886
+ */
887
+ declare function takeScreenshot(opts: ScreenshotOptions): Promise<Screenshot>;
888
+ interface CaptureBurstOptions {
889
+ config: ConfigProvider;
890
+ count: number;
891
+ /** Delay between device-side captures, ms. */
892
+ intervalMs: number;
893
+ deviceSerial?: string;
894
+ timeoutMs?: number;
895
+ logger?: Logger;
896
+ }
897
+ /**
898
+ * Capture `count` frames `intervalMs` apart in a single device-side loop, then
899
+ * pull each frame back. Returns the raw JPEG buffers in order. The MCP composites
900
+ * these into a contact sheet + per-frame diff; core just returns the frames.
901
+ */
902
+ declare function captureBurst(opts: CaptureBurstOptions): Promise<Buffer[]>;
903
+
904
+ type InputType = 'click' | 'doubleClick' | 'longClick' | 'swipe' | 'drag' | 'fling' | 'keyEvent' | 'inputText';
905
+ interface SendInputOptions {
906
+ config: ConfigProvider;
907
+ type: InputType;
908
+ /** Pixel coordinates. The %→px conversion lives in the MCP, not core. */
909
+ pxX?: number;
910
+ pxY?: number;
911
+ pxX2?: number;
912
+ pxY2?: number;
913
+ /** Velocity for swipe/drag/fling. */
914
+ speed?: number;
915
+ /** Key id or symbolic name (Back/Home/Power) for keyEvent. */
916
+ key?: string | number;
917
+ /** Text for inputText. */
918
+ text?: string;
919
+ deviceSerial?: string;
920
+ logger?: Logger;
921
+ }
922
+ /**
923
+ * Build the `uitest uiInput …` command for an input action, in pixel space.
924
+ * Pure (no I/O) so it is unit-testable. Mirrors the proven MCP construction
925
+ * minus the percentage→pixel step.
926
+ */
927
+ declare function buildInputCommand(opts: SendInputOptions): string;
928
+ /** Inject a UI input action via `uitest uiInput` (pixel coordinates). */
929
+ declare function sendInput(opts: SendInputOptions): Promise<void>;
930
+ interface Waypoint {
931
+ /** Pixel x. */
932
+ x: number;
933
+ /** Pixel y. */
934
+ y: number;
935
+ /** Time in ms relative to the gesture start. */
936
+ t: number;
937
+ }
938
+ interface SendGestureOptions {
939
+ config: ConfigProvider;
940
+ waypoints: Waypoint[];
941
+ /** Hold at the first point before moving (ms). Honored via the raw-touch path. */
942
+ holdStartMs?: number;
943
+ /** Hold at the last point before lifting (ms). Honored via the raw-touch path. */
944
+ holdEndMs?: number;
945
+ deviceSerial?: string;
946
+ logger?: Logger;
947
+ }
948
+ /**
949
+ * Build the chained `uitest uiInput drag` commands for a multi-segment path.
950
+ * Per segment, speed is derived from the waypoint time deltas (px/s). Pure.
951
+ */
952
+ declare function buildGestureCommands(waypoints: Waypoint[]): string[];
953
+ interface RawTouchEvent {
954
+ type: 'down' | 'move' | 'up';
955
+ x: number;
956
+ y: number;
957
+ /** Time in ms relative to the gesture start. */
958
+ t: number;
959
+ }
960
+ interface SendRawTouchOptions {
961
+ config: ConfigProvider;
962
+ events: RawTouchEvent[];
963
+ deviceSerial?: string;
964
+ logger?: Logger;
965
+ }
966
+ /**
967
+ * Build a single `uinput -T` touch operation sequence from down/move/up events,
968
+ * interleaving `-i <ms>` intervals from the event time deltas. Pure.
969
+ */
970
+ declare function buildRawTouchCommand(events: RawTouchEvent[]): string;
971
+ /** Expand a waypoint path (+ optional holds) into raw down/move/up events for
972
+ * the `uinput` escape hatch ({@link sendRawTouch} / {@link buildRawTouchCommand}). */
973
+ declare function waypointsToRawEvents(waypoints: Waypoint[], holdStartMs?: number, holdEndMs?: number): RawTouchEvent[];
974
+ interface GestureUitestOptions {
975
+ /** A leading press-hold; when > 0 the stroke uses `drag` (press-and-hold,
976
+ * then move) instead of `swipe`. uitest has no arbitrary hold duration. */
977
+ holdStartMs?: number;
978
+ }
979
+ /**
980
+ * Build a single continuous `uitest uiInput` stroke for a waypoint path. Pure.
981
+ *
982
+ * uitest has no polyline or stationary-hold primitive, so the path is collapsed
983
+ * to first→last (gesture-nav strokes are straight lines) with the velocity
984
+ * derived from the total elapsed time and clamped to uitest's range. A
985
+ * requested `holdStartMs` maps to `drag` (which presses-and-holds before
986
+ * moving — uitest's nearest equivalent to a leading hold); otherwise `swipe`.
987
+ */
988
+ declare function buildGestureUitestCommand(waypoints: Waypoint[], opts?: GestureUitestOptions): string;
989
+ /**
990
+ * Drive a swipe-style gesture via a single continuous `uitest uiInput` stroke —
991
+ * the MMI-injection path that `inputMonitor`-based services (gesture-nav,
992
+ * systemui overlays) actually observe. Preferred over raw `uinput`, whose
993
+ * kernel virtual-device events do not reach `inputMonitor` on some native-boot
994
+ * devices (and whose multi-op form some on-device `uinput` builds reject).
995
+ *
996
+ * uitest has no polyline or stationary-hold primitive: a multi-waypoint path is
997
+ * collapsed to first→last, `holdStartMs` maps to `drag` (press-hold-then-move),
998
+ * and `holdEndMs` has no equivalent (ignored). For true press-time control use
999
+ * {@link sendRawTouch} (raw `uinput`) — accepting the device caveats above.
1000
+ */
1001
+ declare function sendGesture(opts: SendGestureOptions): Promise<void>;
1002
+ /**
1003
+ * Low-level touch injection via `uinput -T`. The escape hatch when press timing
1004
+ * matters (e.g. Quickstep motion-pause), which `uitest uiInput` can't express.
1005
+ *
1006
+ * WARNING: uinput's gesture form `uinput -T -g x1 y1 x2 y2 [press] [total]`
1007
+ * silently no-ops if `press < 500ms` or `total - press < 500ms` ("press time is
1008
+ * out of range" — it runs nothing). Keep press and post-press windows ≥ 500ms.
1009
+ *
1010
+ * DEVICE CAVEAT: on some native-boot devices these kernel-`uinput` events never
1011
+ * reach MMI `inputMonitor` services (gesture-nav, systemui), and some on-device
1012
+ * `uinput` builds reject the multi-op `-d/-m/-u` form with "wrong number of
1013
+ * parameters". Prefer {@link sendGesture} (uitest) for those; this path now
1014
+ * surfaces such failures instead of silently succeeding.
1015
+ */
1016
+ declare function sendRawTouch(opts: SendRawTouchOptions): Promise<void>;
1017
+
1018
+ /** A raw `uitest dumpLayout` node (attributes are strings). */
1019
+ interface RawLayoutNode {
1020
+ attributes?: Record<string, string>;
1021
+ children?: RawLayoutNode[];
1022
+ }
1023
+ /** A pruned, 0–1-normalized layout node. */
1024
+ interface LayoutNode {
1025
+ /** bounds [x1,y1,x2,y2] normalized to 0–1 of the display. */
1026
+ b?: [number, number, number, number];
1027
+ /** center [x,y] normalized to 0–1. */
1028
+ c?: [number, number];
1029
+ type?: string;
1030
+ text?: string;
1031
+ desc?: string;
1032
+ id?: string;
1033
+ key?: string;
1034
+ bundle?: string;
1035
+ click?: boolean;
1036
+ check?: boolean;
1037
+ checked?: boolean;
1038
+ sel?: boolean;
1039
+ focus?: boolean;
1040
+ scroll?: boolean;
1041
+ longClick?: boolean;
1042
+ children?: LayoutNode[];
1043
+ }
1044
+ interface DumpLayoutResult {
1045
+ display: DisplaySize | null;
1046
+ tree: LayoutNode;
1047
+ }
1048
+ /** Parse a uitest bounds string `"[x1,y1][x2,y2]"` into a tuple, or null. */
1049
+ declare function parseBounds(s: string | undefined): [number, number, number, number] | null;
1050
+ /**
1051
+ * Prune a raw `uitest dumpLayout` tree into a compact, signal-bearing tree with
1052
+ * bounds/center normalized to 0–1 of the display. Structural wrapper nodes with
1053
+ * no signal collapse into their children. Returns a node, a flat list of nodes
1054
+ * (collapsed wrapper with multiple children), or null (nothing useful). Ported
1055
+ * verbatim from the proven MCP `pruneNode`.
1056
+ */
1057
+ declare function pruneLayout(node: RawLayoutNode, display: DisplaySize | null): LayoutNode | LayoutNode[] | null;
1058
+ interface DumpLayoutOptions {
1059
+ config: ConfigProvider;
1060
+ /** Filter to a single window/bundle (`uitest dumpLayout -b '<bundle>'`). */
1061
+ bundleName?: string;
1062
+ /** When false, return the parsed-but-unpruned tree. Default true. */
1063
+ prune?: boolean;
1064
+ deviceSerial?: string;
1065
+ timeoutMs?: number;
1066
+ logger?: Logger;
1067
+ }
1068
+ /**
1069
+ * Dump the current on-screen layout via `uitest dumpLayout`, pull the JSON, and
1070
+ * return a pruned, 0–1-normalized tree (or the raw parsed tree when `prune:false`).
1071
+ */
1072
+ declare function dumpLayout(opts: DumpLayoutOptions): Promise<DumpLayoutResult>;
1073
+
442
1074
  /**
443
1075
  * Read the project's bundle name from `AppScope/app.json5`.
444
1076
  */
445
1077
  declare function getBundleName(projectDir: string): string;
446
1078
  /**
447
- * Read the main ability from `<module>/src/main/module.json5`. Defaults to `entry`
448
- * for the module folder name if not provided — projects with custom module names
449
- * should pass it explicitly.
1079
+ * Read the ability to launch from `<module>/src/main/module.json5`. Defaults to
1080
+ * `entry` for the module folder name. Resolution order:
1081
+ * 1. `abilityName`, if given and present in `module.abilities[]`.
1082
+ * 2. `module.mainElement`.
1083
+ * 3. The first `visible` ability, then the first ability, from `module.abilities[]`.
1084
+ * Modules with multiple abilities can be targeted explicitly via `abilityName`.
450
1085
  */
451
- declare function getMainAbility(projectDir: string, moduleName?: string): string;
1086
+ declare function getMainAbility(projectDir: string, moduleName?: string, abilityName?: string): string;
452
1087
 
453
1088
  interface InstallAppOptions {
454
1089
  config: ConfigProvider;
@@ -460,14 +1095,48 @@ interface InstallAppOptions {
460
1095
  hapPath?: string;
461
1096
  logger?: Logger;
462
1097
  }
463
- declare function installApp(opts: InstallAppOptions): Promise<void>;
1098
+ interface InstallAppResult {
1099
+ installed: boolean;
1100
+ /** Bundle name read from the project's AppScope/app.json5, or '' if unavailable. */
1101
+ bundleName: string;
1102
+ /** The resolved absolute HAP path that was installed. */
1103
+ hapPath: string;
1104
+ /** Combined stdout+stderr from the install, trimmed. */
1105
+ output: string;
1106
+ }
1107
+ declare function installApp(opts: InstallAppOptions): Promise<InstallAppResult>;
464
1108
  interface LaunchAppOptions {
465
1109
  config: ConfigProvider;
466
- projectDir: string;
467
- /** Override the module name if it isn't the default `entry`. */
1110
+ /** Project mode: resolve bundle + main ability from the project. Required unless `bundleName` is given. */
1111
+ projectDir?: string;
1112
+ /**
1113
+ * Bundle mode: launch an already-installed app directly by bundle name (no
1114
+ * project needed). When set, `projectDir` is ignored. If `abilityName` is
1115
+ * omitted, the main ability is resolved from the device via `bm dump -n`.
1116
+ */
1117
+ bundleName?: string;
1118
+ /** Override the module name if it isn't the default `entry` (project mode). */
468
1119
  moduleName?: string;
1120
+ /** Explicit ability to launch; defaults to the module's mainElement / first visible ability (project mode) or the installed bundle's main ability (bundle mode). */
1121
+ abilityName?: string;
1122
+ deviceSerial?: string;
469
1123
  logger?: Logger;
470
1124
  }
1125
+ /**
1126
+ * `aa start` exits 0 even when the launch is refused — a locked screen
1127
+ * (`Error Code:10106102`), a missing ability, a permission denial, etc. The failure
1128
+ * only shows up in its output. Returns the offending text when the output indicates a
1129
+ * failed launch, or null when it looks like a success.
1130
+ */
1131
+ declare function detectAaStartFailure(output: string): string | null;
1132
+ /**
1133
+ * Parse the main ability of an installed bundle from `bm dump -n <bundle>`
1134
+ * output. Pure/testable. The output is a bundle-name prefix line followed by a
1135
+ * JSON blob; we take the entry module's `mainElementName` (fallback
1136
+ * `mainAbility`), or the first module that declares one. Returns null when the
1137
+ * bundle isn't installed or the output is unparseable.
1138
+ */
1139
+ declare function parseMainAbilityFromBmDump(stdout: string): string | null;
471
1140
  declare function launchApp(opts: LaunchAppOptions): Promise<void>;
472
1141
  interface RunningProcess {
473
1142
  pid: string;
@@ -484,6 +1153,30 @@ declare function listRunningProcesses(config: ConfigProvider, options?: {
484
1153
  logger?: Logger;
485
1154
  }): Promise<RunningProcess[] | string>;
486
1155
  declare function findAppProcessId(config: ConfigProvider, projectDir: string, logger?: Logger): Promise<string>;
1156
+ interface BundleOptions {
1157
+ config: ConfigProvider;
1158
+ bundle: string;
1159
+ deviceSerial?: string;
1160
+ timeoutMs?: number;
1161
+ logger?: Logger;
1162
+ }
1163
+ /**
1164
+ * Non-throwing companion to {@link listRunningProcesses}: resolve a running
1165
+ * process for a bundle, or `null` when it isn't running. Suitable for "is X
1166
+ * running?" checks (e.g. the pre/post-install pid comparison in applyChanges).
1167
+ *
1168
+ * `pidof` matches the bundle's main (UIAbility) process. When that isn't found,
1169
+ * we fall back to `track-jpid` to also catch **extension-ability** processes,
1170
+ * which run under a separate process name `"<bundle>:<ext>"` (e.g. a
1171
+ * ServiceExtension, FormExtension, UIExtension or input method). Without this,
1172
+ * "verify the running process took the change" silently reported nothing for an
1173
+ * app whose only live process is an extension.
1174
+ */
1175
+ declare function findRunningProcess(opts: BundleOptions): Promise<RunningProcess | null>;
1176
+ /** Uninstall an app by bundle name (`hdc uninstall <bundle>`). */
1177
+ declare function uninstallApp(opts: BundleOptions): Promise<void>;
1178
+ /** Force-stop an app (`hdc shell aa force-stop <bundle>`). */
1179
+ declare function forceStop(opts: BundleOptions): Promise<void>;
487
1180
 
488
1181
  type HilogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'FATAL';
489
1182
  /** A parsed line of `hdc shell hilog` output. */
@@ -512,11 +1205,16 @@ interface StreamHilogOptions {
512
1205
  config: ConfigProvider;
513
1206
  /** Restrict the stream to a single process id (passed as `-P <pid>`). */
514
1207
  processId?: string;
1208
+ /** Filter by hilog domain, e.g. '0xD003900' (passed as `-D <domain>`). */
1209
+ domain?: string | number;
1210
+ /** Address a specific device (`-t <serial>`). */
1211
+ deviceSerial?: string;
515
1212
  }
516
1213
  /**
517
- * Spawn `hdc shell hilog [-P <pid>]` and return the child process. The caller
518
- * owns the stdout/stderr streams (typically wired through `parseHilogLine`) and
519
- * is responsible for killing the process when streaming should stop.
1214
+ * Spawn `hdc [-t serial] shell hilog [-P <pid>] [-D <domain>]` and return the
1215
+ * child process. The caller owns the stdout/stderr streams (typically wired
1216
+ * through `parseHilogLine`) and is responsible for killing the process when
1217
+ * streaming should stop.
520
1218
  */
521
1219
  declare function streamHilog(opts: StreamHilogOptions): ChildProcessWithoutNullStreams;
522
1220
  /**
@@ -525,6 +1223,61 @@ declare function streamHilog(opts: StreamHilogOptions): ChildProcessWithoutNullS
525
1223
  * banners, blank lines, or partial chunks).
526
1224
  */
527
1225
  declare function parseHilogLine(line: string): HilogEntry | null;
1226
+ /** Collapse consecutive duplicate entries (same level/tag/message), ignoring time/pid. */
1227
+ declare function dedupEntries(entries: HilogEntry[]): HilogEntry[];
1228
+ interface WaitForLogOptions {
1229
+ config: ConfigProvider;
1230
+ /** Tested against `"<tag>: <message>"` of each parsed line. */
1231
+ pattern: RegExp;
1232
+ timeoutMs: number;
1233
+ /** Restrict to a bundle's pid (resolved via pidof; re-resolved on each reconnect). */
1234
+ bundle?: string;
1235
+ domain?: string | number;
1236
+ deviceSerial?: string;
1237
+ abortSignal?: AbortSignal;
1238
+ logger?: Logger;
1239
+ }
1240
+ /**
1241
+ * Resolve with the first hilog entry whose `"<tag>: <message>"` matches `pattern`.
1242
+ * The underlying stream is auto-respawned if it dies before the deadline, so the
1243
+ * wait survives a reboot mid-observation. Rejects on timeout (OniroError) or
1244
+ * abort (CancelledError).
1245
+ */
1246
+ declare function waitForLog(opts: WaitForLogOptions): Promise<HilogEntry>;
1247
+ interface WatchLogOptions {
1248
+ config: ConfigProvider;
1249
+ pattern: RegExp;
1250
+ /** How long to collect matching entries. */
1251
+ durationMs: number;
1252
+ bundle?: string;
1253
+ domain?: string | number;
1254
+ deviceSerial?: string;
1255
+ /** Collapse consecutive duplicate lines. Default true. */
1256
+ dedup?: boolean;
1257
+ abortSignal?: AbortSignal;
1258
+ logger?: Logger;
1259
+ }
1260
+ /** Collect all hilog entries matching `pattern` for `durationMs`. Deduped by default. */
1261
+ declare function watchLog(opts: WatchLogOptions): Promise<HilogEntry[]>;
1262
+ interface DumpLogOptions {
1263
+ config: ConfigProvider;
1264
+ /** Cap the result to the last N lines (device-side `tail -n`). */
1265
+ lines?: number;
1266
+ /** Restrict to a bundle's running pid (no output if it isn't running). */
1267
+ bundle?: string;
1268
+ /** Extended-regex string applied device-side via `grep -E`. */
1269
+ grep?: string;
1270
+ domain?: string | number;
1271
+ deviceSerial?: string;
1272
+ timeoutMs?: number;
1273
+ logger?: Logger;
1274
+ }
1275
+ /**
1276
+ * One-shot `hilog -x` dump, optionally filtered by domain, bundle pid, and a
1277
+ * grep regex, capped to the last `lines`. Mirrors the proven MCP get_logs
1278
+ * pipeline. Returns parsed entries.
1279
+ */
1280
+ declare function dumpLog(opts: DumpLogOptions): Promise<HilogEntry[]>;
528
1281
 
529
1282
  interface RunHvigorwOptions {
530
1283
  config: ConfigProvider;
@@ -539,6 +1292,13 @@ interface RunHvigorwOptions {
539
1292
  task?: string;
540
1293
  /** Extra raw args appended after the standard ones. */
541
1294
  extraArgs?: readonly string[];
1295
+ /**
1296
+ * Build modules in parallel. Default `true`. Pass `false` to add `--no-parallel`
1297
+ * for projects that require serial builds.
1298
+ */
1299
+ parallel?: boolean;
1300
+ /** Abort the build; rejects with CancelledError and kills the hvigorw process. */
1301
+ abortSignal?: AbortSignal;
542
1302
  logger?: Logger;
543
1303
  /**
544
1304
  * Optional callback for each stdout/stderr chunk, lets callers stream output
@@ -549,12 +1309,132 @@ interface RunHvigorwOptions {
549
1309
  interface RunHvigorwResult {
550
1310
  exitCode: number;
551
1311
  }
1312
+ /**
1313
+ * Build the hvigorw argv. Pure (no I/O) so it is unit-testable. `--no-parallel`
1314
+ * is added ONLY when `parallel === false` — builds are parallel by default.
1315
+ */
1316
+ declare function buildHvigorwArgs(opts: {
1317
+ task?: string;
1318
+ product?: string;
1319
+ module?: string;
1320
+ buildMode?: string;
1321
+ parallel?: boolean;
1322
+ extraArgs?: readonly string[];
1323
+ }): string[];
552
1324
  /**
553
1325
  * Run the project's `hvigorw` wrapper. Replaces the extension's vscode-tasks indirection
554
1326
  * and the bash CLI's chained `clean` + `assembleHap` calls with a single direct spawn.
555
1327
  */
556
1328
  declare function runHvigorw(opts: RunHvigorwOptions): Promise<RunHvigorwResult>;
557
1329
 
1330
+ interface ModuleHaps {
1331
+ signed: string[];
1332
+ unsigned: string[];
1333
+ }
1334
+ interface DiscoverHapsOptions {
1335
+ projectDir: string;
1336
+ /** Max directory recursion depth. Default 8. */
1337
+ maxDepth?: number;
1338
+ }
1339
+ /**
1340
+ * Walk a project's build outputs and group `*-signed.hap` / `*-unsigned.hap`
1341
+ * by build module name (parsed from the HAP filename). Skips `node_modules` /
1342
+ * `oh_modules` / `.git`. Ported from the proven MCP `findHaps`, extended with
1343
+ * per-module grouping so multi-module projects can install the right HAP.
1344
+ * Empty object when nothing is built.
1345
+ */
1346
+ declare function discoverHaps(opts: DiscoverHapsOptions): Promise<Record<string, ModuleHaps>>;
1347
+
1348
+ interface RunOhpmOptions {
1349
+ config: ConfigProvider;
1350
+ projectDir: string;
1351
+ args: readonly string[];
1352
+ timeoutMs?: number;
1353
+ abortSignal?: AbortSignal;
1354
+ onOutput?: OutputSink;
1355
+ logger?: Logger;
1356
+ }
1357
+ /** Run `ohpm <args>` in the project directory. Resolves with the raw result (any exit code). */
1358
+ declare function runOhpm(opts: RunOhpmOptions): Promise<HdcExecResult>;
1359
+ /**
1360
+ * Install dependencies (`ohpm install --all`) only when `oh_modules/` is missing.
1361
+ * Returns `{ installed: true }` when it ran. Throws CommandFailedError if the
1362
+ * install ran and failed.
1363
+ */
1364
+ declare function ensureOhModules(opts: {
1365
+ config: ConfigProvider;
1366
+ projectDir: string;
1367
+ abortSignal?: AbortSignal;
1368
+ onOutput?: OutputSink;
1369
+ logger?: Logger;
1370
+ }): Promise<{
1371
+ installed: boolean;
1372
+ }>;
1373
+
1374
+ interface CodelinterFinding {
1375
+ file: string;
1376
+ line: number;
1377
+ severity: string;
1378
+ /** Rule code/id when present in the output, else ''. */
1379
+ code: string;
1380
+ message: string;
1381
+ }
1382
+ interface CodelinterResult {
1383
+ /** codelinter process exit code. */
1384
+ code: number;
1385
+ findings: CodelinterFinding[];
1386
+ /** Combined stdout+stderr, for callers that want the raw report. */
1387
+ raw: string;
1388
+ }
1389
+ /**
1390
+ * Best-effort parser for codelinter output lines of the shape
1391
+ * `<file>:<line>[:<col>]: <severity>: <message> [<rule-code>]`. Lines that don't
1392
+ * match are ignored. Exported as a pure function so it is unit-testable.
1393
+ */
1394
+ declare function parseCodelinterFindings(output: string): CodelinterFinding[];
1395
+ interface RunCodelinterOptions {
1396
+ config: ConfigProvider;
1397
+ projectDir: string;
1398
+ /** Files/globs to lint; when omitted, codelinter is run with no file args. */
1399
+ files?: readonly string[];
1400
+ timeoutMs?: number;
1401
+ abortSignal?: AbortSignal;
1402
+ logger?: Logger;
1403
+ }
1404
+ /** Run the OpenHarmony codelinter and return parsed findings + the raw report. */
1405
+ declare function runCodelinter(opts: RunCodelinterOptions): Promise<CodelinterResult>;
1406
+
1407
+ interface BuildHapOptions {
1408
+ config: ConfigProvider;
1409
+ projectDir: string;
1410
+ product?: string;
1411
+ module?: string;
1412
+ /** Forwarded as hvigor `buildMode` (e.g. release, debug). */
1413
+ mode?: string;
1414
+ /** hvigor task. Default `assembleHap`. */
1415
+ task?: string;
1416
+ /** Run `ohpm install --all` first when `oh_modules/` is missing. Default true. */
1417
+ autoInstallDeps?: boolean;
1418
+ /** Build modules in parallel. Default true (see runHvigorw). */
1419
+ parallel?: boolean;
1420
+ abortSignal?: AbortSignal;
1421
+ onOutput?: (chunk: string, stream: 'stdout' | 'stderr') => void;
1422
+ logger?: Logger;
1423
+ }
1424
+ interface BuildHapResult {
1425
+ exitCode: number;
1426
+ durationMs: number;
1427
+ /** Built HAPs grouped by module folder. */
1428
+ discoveredHaps: Record<string, ModuleHaps>;
1429
+ warnings: string[];
1430
+ }
1431
+ /**
1432
+ * High-level build orchestration: ensure deps → run hvigorw → discover the
1433
+ * produced HAPs. The single call the CLI and MCP want; `runHvigorw` stays a raw
1434
+ * single-spawn primitive.
1435
+ */
1436
+ declare function buildHap(opts: BuildHapOptions): Promise<BuildHapResult>;
1437
+
558
1438
  /**
559
1439
  * Conservative project-folder-name validator (no path separators, conservative charset).
560
1440
  */
@@ -610,6 +1490,55 @@ interface CreateScaffoldResult {
610
1490
  */
611
1491
  declare function createScaffold(opts: CreateScaffoldOptions): Promise<CreateScaffoldResult>;
612
1492
 
1493
+ interface ProjectModule {
1494
+ name: string;
1495
+ /** Source path relative to the project root (e.g. `./entry`). */
1496
+ srcPath: string;
1497
+ /** Target names declared under the module (often empty). */
1498
+ targets: string[];
1499
+ }
1500
+ /**
1501
+ * Read the `modules[]` declared in `build-profile.json5` so callers can target a
1502
+ * specific module in a multi-module project.
1503
+ */
1504
+ declare function listModules(opts: {
1505
+ projectDir: string;
1506
+ }): ProjectModule[];
1507
+
1508
+ interface AbilityInfo {
1509
+ name: string;
1510
+ type?: string;
1511
+ visible?: boolean;
1512
+ srcEntry?: string;
1513
+ }
1514
+ /**
1515
+ * Read all abilities declared in a module's `module.json5` `abilities[]`.
1516
+ * Defaults to the `entry` module folder.
1517
+ */
1518
+ declare function listAbilities(opts: {
1519
+ projectDir: string;
1520
+ moduleName?: string;
1521
+ }): AbilityInfo[];
1522
+
1523
+ interface PrepareSigningOptions {
1524
+ config: ConfigProvider;
1525
+ projectDir: string;
1526
+ apl?: Apl;
1527
+ appFeature?: AppFeature;
1528
+ acls?: string[];
1529
+ passwords?: SigningPasswords;
1530
+ logger?: Logger;
1531
+ }
1532
+ interface PrepareSigningResult {
1533
+ source: 'present' | 'fresh';
1534
+ }
1535
+ /**
1536
+ * Ensure a project has signing material: a no-op when `signatures/` +
1537
+ * signingConfigs already exist ('present'), otherwise generate them via
1538
+ * {@link generateSigningConfigs} ('fresh', which needs java + the SDK).
1539
+ */
1540
+ declare function prepareSigning(opts: PrepareSigningOptions): PrepareSigningResult;
1541
+
613
1542
  declare function readJson5File<T>(filePath: string): T;
614
1543
  /**
615
1544
  * Write strict JSON content (quoted keys) to a `.json5` file. Keeps the file
@@ -619,6 +1548,127 @@ declare function writeJson5File(filePath: string, value: unknown): void;
619
1548
  declare function readJsonFile<T>(filePath: string): T;
620
1549
  declare function writeJsonFile(filePath: string, value: unknown): void;
621
1550
 
1551
+ interface HidumperOptions {
1552
+ config: ConfigProvider;
1553
+ deviceSerial?: string;
1554
+ timeoutMs?: number;
1555
+ logger?: Logger;
1556
+ }
1557
+ interface ScreenDump {
1558
+ width: number;
1559
+ height: number;
1560
+ /** Raw hidumper screen output. */
1561
+ raw: string;
1562
+ }
1563
+ /** `hidumper -s 10 -a screen` → parsed render resolution + raw text, or null. */
1564
+ declare function dumpScreen(opts: HidumperOptions): Promise<ScreenDump | null>;
1565
+ /** `hidumper -s WindowManagerService -a -a` — windows in z-order with surface presence. */
1566
+ declare function dumpWindow(opts: HidumperOptions): Promise<string>;
1567
+ /** `hidumper -s RenderService -a allInfo` — composition state / refresh rate. */
1568
+ declare function dumpRenderService(opts: HidumperOptions): Promise<string>;
1569
+
1570
+ interface DeviceFullInfo {
1571
+ serial: string;
1572
+ model?: string;
1573
+ manufacturer?: string;
1574
+ brand?: string;
1575
+ osFullName?: string;
1576
+ osReleaseType?: string;
1577
+ sdkApiVersion?: string;
1578
+ buildVersion?: string;
1579
+ display: {
1580
+ width: number;
1581
+ height: number;
1582
+ } | null;
1583
+ }
1584
+ interface GetDeviceInfoOptions {
1585
+ config: ConfigProvider;
1586
+ deviceSerial?: string;
1587
+ timeoutMs?: number;
1588
+ logger?: Logger;
1589
+ }
1590
+ /** Collate device properties (`param get` × N) and the display resolution. */
1591
+ declare function getDeviceInfo(opts: GetDeviceInfoOptions): Promise<DeviceFullInfo>;
1592
+
1593
+ interface HapAssetDiff {
1594
+ /** File paths present in the new HAP but not the installed one. */
1595
+ addedAssetPaths: string[];
1596
+ /** File paths present in the installed HAP but not the new one. */
1597
+ removedAssetPaths: string[];
1598
+ }
1599
+ /** Pure set-diff of two file-name listings, sorted. */
1600
+ declare function diffEntryNames(installed: Iterable<string>, next: Iterable<string>): HapAssetDiff;
1601
+ /**
1602
+ * Diff the file manifests of two HAP (zip) archives. Drives the ACE-extractor
1603
+ * cache-invalidation reboot decision in `applyChanges`: when the new HAP adds or
1604
+ * renames file paths vs the installed one, the path-keyed asset cache can serve
1605
+ * stale "GetAsset failed" errors until a reboot.
1606
+ */
1607
+ declare function diffHapAssets(opts: {
1608
+ installedHap: string;
1609
+ newHap: string;
1610
+ }): Promise<HapAssetDiff>;
1611
+
1612
+ type InstallMethod = 'replace' | 'uninstall-install' | 'refuse';
1613
+ /**
1614
+ * P0-5a decision: how to install given whether `hdc install -r` reported a
1615
+ * sign-info-inconsistent error (9568332). System bundles are NOT silently
1616
+ * uninstalled (that can brick the device) unless explicitly allowed.
1617
+ */
1618
+ declare function decideInstallMethod(s: {
1619
+ signInfoInconsistent: boolean;
1620
+ isSystemBundle: boolean;
1621
+ allowUninstall: boolean;
1622
+ }): InstallMethod;
1623
+ interface RebootDecision {
1624
+ reboot: boolean;
1625
+ reason: 'asset-cache' | 'pid-unchanged' | 'none';
1626
+ }
1627
+ /**
1628
+ * P0-5b/c decision: whether to reboot after installing. Reboot when the HAP's
1629
+ * asset paths changed (ACE extractor cache is path-keyed and survives a process
1630
+ * kill), or when a persistent/system bundle's process didn't restart.
1631
+ */
1632
+ declare function decideReboot(s: {
1633
+ assetsChanged: boolean;
1634
+ isSystemBundle: boolean;
1635
+ preInstallPid: number | null;
1636
+ postInstallPid: number | null;
1637
+ }): RebootDecision;
1638
+ interface ApplyChangesOptions {
1639
+ config: ConfigProvider;
1640
+ bundle: string;
1641
+ /** Explicit HAP path. If omitted, resolved from projectDir (+ module) via discoverHaps. */
1642
+ hapPath?: string;
1643
+ projectDir?: string;
1644
+ module?: string;
1645
+ /** Local path to the currently-installed HAP; enables the asset-cache diff/reboot. */
1646
+ installedHapPath?: string;
1647
+ /** Persistent/system bundle (e.g. systemui). Default false. */
1648
+ isSystemBundle?: boolean;
1649
+ /** Permit uninstalling a system bundle on sign-info mismatch (dangerous). Default false. */
1650
+ allowUninstall?: boolean;
1651
+ deviceSerial?: string;
1652
+ abortSignal?: AbortSignal;
1653
+ logger?: Logger;
1654
+ }
1655
+ interface ApplyChangesResult {
1656
+ method: 'replace' | 'uninstall-install' | 'reboot';
1657
+ preInstallPid: number | null;
1658
+ postInstallPid: number | null;
1659
+ replaced: boolean;
1660
+ /** True when an asset-path change forced the reboot. */
1661
+ cacheCleared: boolean;
1662
+ }
1663
+ /**
1664
+ * Install a HAP and verify the running process took the change. Handles the
1665
+ * three failure modes the naive "install the most recent signed HAP" deploy
1666
+ * ignores: sign-info-inconsistent on `-r`, asset-cache invalidation, and a
1667
+ * persistent bundle that didn't restart. See {@link decideInstallMethod} /
1668
+ * {@link decideReboot} for the (pure, tested) branch logic.
1669
+ */
1670
+ declare function applyChanges(opts: ApplyChangesOptions): Promise<ApplyChangesResult>;
1671
+
622
1672
  declare const VERSION: string;
623
1673
 
624
- export { ALL_SDKS, APL_VALUES, APP_FEATURE_VALUES, type Apl, type AppFeature, CancelledError, ChecksumMismatchError, CmdToolsNotInstalledError, type CmdToolsStatus, type ConfigKey, type ConfigProvider, type CreateScaffoldOptions, type CreateScaffoldResult, type DownloadOptions, type ExtractZipOptions, type GenerateSigningConfigsOptions, type HilogEntry, type HilogLevel, type InstallAppOptions, type InstallCmdToolsOptions, type InstallEmulatorOptions, type InstallSdkOptions, type LaunchAppOptions, type Logger, OHOS_URL_BASE, type OniroContext, OniroError, type OsFolder, type ProgressReporter, type ProgressUpdate, type Prompter, type RunHvigorwOptions, type RunHvigorwResult, type RunningProcess, type SdkArchiveInfo, type SdkInfo, SdkNotInstalledError, type SdkRelease, type SetHilogLevelOptions, type SigningKind, type StartEmulatorOptions, type StreamHilogOptions, type TemplateOption, UnsupportedPlatformError, VERSION, attemptHdcConnection, consoleLogger, createMaterial, createScaffold, decryptPwd, defaultContext, defaultPaths, detectProjectSdkVersion, detectSigningConfigNames, downloadAndInstallSdk, downloadFile, encryptPwd, extractTarball, extractZipWithProgress, findAppProcessId, findCmdToolsSourceDir, generateSigningConfigs, getBundleName, getCmdToolsBin, getCmdToolsDownloadUrl, getCmdToolsPath, getCmdToolsStatus, getEmulatorDir, getHdcPath, getHvigorwPath, getInstalledSdks, getKey, getMainAbility, getOhosBaseSdkHome, getOsFolder, getSdkFilename, getSdkRootDir, getSupportedSdksForUi, installApp, installCmdTools, installEmulator, isCmdToolsInstalled, isEmulatorInstalled, isValidBundleName, isValidProjectName, launchApp, listRunningProcesses, listTemplates, nonInteractivePrompter, noopLogger, noopProgress, parseHilogLine, pickSigningKind, readJson5File, readJsonFile, removeCmdTools, removeEmulator, removeSdk, runHvigorw, setHilogLevel, startEmulator, staticConfig, stopEmulator, streamHilog, validateTemplateLayout, verifySha256, writeJson5File, writeJsonFile };
1674
+ export { ALL_SDKS, APL_VALUES, APP_FEATURE_VALUES, type AbilityInfo, type Apl, type AppFeature, type ApplyChangesOptions, type ApplyChangesResult, type BuildHapOptions, type BuildHapResult, type BundleOptions, CancelledError, type CaptureBurstOptions, ChecksumMismatchError, CmdToolsNotInstalledError, type CmdToolsStatus, type CodelinterFinding, type CodelinterResult, CommandFailedError, type ConfigKey, type ConfigProvider, type CreateScaffoldOptions, type CreateScaffoldResult, type DeviceFullInfo, type DeviceInfo, type DiscoverHapsOptions, type DisplaySize, type DisplaySizeOptions, type DownloadOptions, type DumpLayoutOptions, type DumpLayoutResult, type DumpLogOptions, type ExtractZipOptions, type GenerateSigningConfigsOptions, type GestureUitestOptions, type GetDeviceInfoOptions, type HapAssetDiff, type HdcExecOptions, type HdcExecResult, type HdcShellOptions, type HidumperOptions, type HilogEntry, type HilogLevel, INSTALL_TMP_DIRNAME, type InputType, type InstallAppOptions, type InstallAppResult, type InstallCmdToolsOptions, type InstallEmulatorOptions, type InstallMethod, type InstallSdkOptions, type InstallTempDir, type InstallTempDirOptions, InsufficientSpaceError, type LaunchAppOptions, type LayoutNode, type Logger, type ModuleHaps, OHOS_URL_BASE, type OniroContext, OniroError, type OsFolder, type OutputSink, type ParamOptions, type PrepareSigningOptions, type PrepareSigningResult, type ProgressReporter, type ProgressUpdate, type ProjectModule, type Prompter, type RawLayoutNode, type RawTouchEvent, type RebootDecision, type RebootOptions, type RecvFileOptions, type RunCodelinterOptions, type RunHvigorwOptions, type RunHvigorwResult, type RunOhpmOptions, type RunProcessOptions, type RunningProcess, type ScreenDump, type Screenshot, type ScreenshotOptions, type SdkArchiveInfo, type SdkInfo, SdkNotInstalledError, type SdkRelease, type SendFileOptions, type SendGestureOptions, type SendInputOptions, type SendRawTouchOptions, type SetHilogLevelOptions, type SigningKind, type SigningPasswords, type StartEmulatorOptions, type StreamHilogOptions, TMP_DIR_HINT, type TemplateOption, UnsupportedPlatformError, VERSION, type WaitForBootOptions, type WaitForBundleOptions, type WaitForConditionOptions, type WaitForLogOptions, type WatchLogOptions, type Waypoint, applyChanges, attemptHdcConnection, buildGestureCommands, buildGestureUitestCommand, buildHap, buildHvigorwArgs, buildInputCommand, buildRawTouchCommand, captureBurst, consoleLogger, createInstallTempDir, createMaterial, createScaffold, createTempWorkDir, decideInstallMethod, decideReboot, decryptPwd, dedupEntries, defaultContext, defaultPaths, detectAaStartFailure, detectProjectSdkVersion, detectSigningConfigNames, diffEntryNames, diffHapAssets, discoverHaps, downloadAndInstallSdk, downloadFile, dumpLayout, dumpLog, dumpRenderService, dumpScreen, dumpWindow, encryptPwd, ensureFreeSpace, ensureOhModules, ensureOk, ensureRemoteOk, extractTarball, extractZipWithProgress, findAppProcessId, findCmdToolsSourceDir, findRunningProcess, forceStop, formatBytes, generateSigningConfigs, getBundleName, getCmdToolsBin, getCmdToolsDownloadUrl, getCmdToolsPath, getCmdToolsStatus, getDeviceInfo, getDisplaySize, getEmulatorDir, getFreeSpaceBytes, getHdcPath, getHvigorwPath, getInstalledSdks, getKey, getMainAbility, getOhosBaseSdkHome, getOhpmPath, getOsFolder, getSdkFilename, getSdkRootDir, getSupportedSdksForUi, hdcExec, installApp, installCmdTools, installEmulator, isCmdToolsInstalled, isEmulatorInstalled, isOutOfSpaceError, isRamBackedPath, isValidBundleName, isValidProjectName, launchApp, listAbilities, listDevices, listModules, listRunningProcesses, listTemplates, nonInteractivePrompter, noopLogger, noopProgress, paramGet, paramSet, parseBounds, parseCodelinterFindings, parseDeviceList, parseHilogLine, parseMainAbilityFromBmDump, parseRemoteExit, pickSigningKind, prepareSigning, pruneLayout, readJson5File, readJsonFile, reboot, recvFile, removeCmdTools, removeEmulator, removeSdk, removeTempWorkDir, resolveTmpRoot, runCodelinter, runHvigorw, runOhpm, runProcess, scopedLogger, selectDevice, sendFile, sendGesture, sendInput, sendRawTouch, setHilogLevel, shell, shellChecked, startEmulator, staticConfig, stopEmulator, streamHilog, takeScreenshot, toSpaceError, uninstallApp, validateTemplateLayout, verifySha256, waitForBoot, waitForBundle, waitForCondition, waitForLog, watchLog, waypointsToRawEvents, writeJson5File, writeJsonFile };