@oniroproject/core 0.7.0 → 0.9.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.cjs CHANGED
@@ -37,22 +37,29 @@ __export(index_exports, {
37
37
  ChecksumMismatchError: () => ChecksumMismatchError,
38
38
  CmdToolsNotInstalledError: () => CmdToolsNotInstalledError,
39
39
  CommandFailedError: () => CommandFailedError,
40
+ INSTALL_TMP_DIRNAME: () => INSTALL_TMP_DIRNAME,
41
+ InsufficientSpaceError: () => InsufficientSpaceError,
40
42
  OHOS_URL_BASE: () => OHOS_URL_BASE,
41
43
  OniroError: () => OniroError,
42
44
  SdkNotInstalledError: () => SdkNotInstalledError,
45
+ TMP_DIR_HINT: () => TMP_DIR_HINT,
43
46
  UnsupportedPlatformError: () => UnsupportedPlatformError,
44
47
  VERSION: () => VERSION,
45
48
  applyChanges: () => applyChanges,
46
49
  attemptHdcConnection: () => attemptHdcConnection,
50
+ buildCmdWrapper: () => buildCmdWrapper,
47
51
  buildGestureCommands: () => buildGestureCommands,
52
+ buildGestureUitestCommand: () => buildGestureUitestCommand,
48
53
  buildHap: () => buildHap,
49
54
  buildHvigorwArgs: () => buildHvigorwArgs,
50
55
  buildInputCommand: () => buildInputCommand,
51
56
  buildRawTouchCommand: () => buildRawTouchCommand,
52
57
  captureBurst: () => captureBurst,
53
58
  consoleLogger: () => consoleLogger,
59
+ createInstallTempDir: () => createInstallTempDir,
54
60
  createMaterial: () => createMaterial,
55
61
  createScaffold: () => createScaffold,
62
+ createTempWorkDir: () => createTempWorkDir,
56
63
  decideInstallMethod: () => decideInstallMethod,
57
64
  decideReboot: () => decideReboot,
58
65
  decryptPwd: () => decryptPwd,
@@ -73,14 +80,19 @@ __export(index_exports, {
73
80
  dumpScreen: () => dumpScreen,
74
81
  dumpWindow: () => dumpWindow,
75
82
  encryptPwd: () => encryptPwd,
83
+ ensureFreeSpace: () => ensureFreeSpace,
76
84
  ensureOhModules: () => ensureOhModules,
77
85
  ensureOk: () => ensureOk,
86
+ ensureRemoteOk: () => ensureRemoteOk,
87
+ escapeCmdArgument: () => escapeCmdArgument,
88
+ escapeCmdCommand: () => escapeCmdCommand,
78
89
  extractTarball: () => extractTarball,
79
90
  extractZipWithProgress: () => extractZipWithProgress,
80
91
  findAppProcessId: () => findAppProcessId,
81
92
  findCmdToolsSourceDir: () => findCmdToolsSourceDir,
82
93
  findRunningProcess: () => findRunningProcess,
83
94
  forceStop: () => forceStop,
95
+ formatBytes: () => formatBytes,
84
96
  generateSigningConfigs: () => generateSigningConfigs,
85
97
  getBundleName: () => getBundleName,
86
98
  getCmdToolsBin: () => getCmdToolsBin,
@@ -90,6 +102,7 @@ __export(index_exports, {
90
102
  getDeviceInfo: () => getDeviceInfo,
91
103
  getDisplaySize: () => getDisplaySize,
92
104
  getEmulatorDir: () => getEmulatorDir,
105
+ getFreeSpaceBytes: () => getFreeSpaceBytes,
93
106
  getHdcPath: () => getHdcPath,
94
107
  getHvigorwPath: () => getHvigorwPath,
95
108
  getInstalledSdks: () => getInstalledSdks,
@@ -107,14 +120,18 @@ __export(index_exports, {
107
120
  installEmulator: () => installEmulator,
108
121
  isCmdToolsInstalled: () => isCmdToolsInstalled,
109
122
  isEmulatorInstalled: () => isEmulatorInstalled,
123
+ isOutOfSpaceError: () => isOutOfSpaceError,
124
+ isRamBackedPath: () => isRamBackedPath,
110
125
  isValidBundleName: () => isValidBundleName,
111
126
  isValidProjectName: () => isValidProjectName,
127
+ killProcessTree: () => killProcessTree,
112
128
  launchApp: () => launchApp,
113
129
  listAbilities: () => listAbilities,
114
130
  listDevices: () => listDevices,
115
131
  listModules: () => listModules,
116
132
  listRunningProcesses: () => listRunningProcesses,
117
133
  listTemplates: () => listTemplates,
134
+ needsCmdWrapper: () => needsCmdWrapper,
118
135
  nonInteractivePrompter: () => nonInteractivePrompter,
119
136
  noopLogger: () => noopLogger,
120
137
  noopProgress: () => noopProgress,
@@ -124,6 +141,8 @@ __export(index_exports, {
124
141
  parseCodelinterFindings: () => parseCodelinterFindings,
125
142
  parseDeviceList: () => parseDeviceList,
126
143
  parseHilogLine: () => parseHilogLine,
144
+ parseMainAbilityFromBmDump: () => parseMainAbilityFromBmDump,
145
+ parseRemoteExit: () => parseRemoteExit,
127
146
  pickSigningKind: () => pickSigningKind,
128
147
  prepareSigning: () => prepareSigning,
129
148
  pruneLayout: () => pruneLayout,
@@ -134,6 +153,8 @@ __export(index_exports, {
134
153
  removeCmdTools: () => removeCmdTools,
135
154
  removeEmulator: () => removeEmulator,
136
155
  removeSdk: () => removeSdk,
156
+ removeTempWorkDir: () => removeTempWorkDir,
157
+ resolveTmpRoot: () => resolveTmpRoot,
137
158
  runCodelinter: () => runCodelinter,
138
159
  runHvigorw: () => runHvigorw,
139
160
  runOhpm: () => runOhpm,
@@ -146,11 +167,15 @@ __export(index_exports, {
146
167
  sendRawTouch: () => sendRawTouch,
147
168
  setHilogLevel: () => setHilogLevel,
148
169
  shell: () => shell,
170
+ shellChecked: () => shellChecked,
171
+ spawnCompat: () => spawnCompat,
149
172
  startEmulator: () => startEmulator,
150
173
  staticConfig: () => staticConfig,
151
174
  stopEmulator: () => stopEmulator,
152
175
  streamHilog: () => streamHilog,
153
176
  takeScreenshot: () => takeScreenshot,
177
+ toLongPath: () => toLongPath,
178
+ toSpaceError: () => toSpaceError,
154
179
  uninstallApp: () => uninstallApp,
155
180
  validateTemplateLayout: () => validateTemplateLayout,
156
181
  verifySha256: () => verifySha256,
@@ -159,6 +184,7 @@ __export(index_exports, {
159
184
  waitForCondition: () => waitForCondition,
160
185
  waitForLog: () => waitForLog,
161
186
  watchLog: () => watchLog,
187
+ waypointsToRawEvents: () => waypointsToRawEvents,
162
188
  writeJson5File: () => writeJson5File,
163
189
  writeJsonFile: () => writeJsonFile
164
190
  });
@@ -271,9 +297,9 @@ var CmdToolsNotInstalledError = class extends OniroError {
271
297
  expectedPath;
272
298
  };
273
299
  var UnsupportedPlatformError = class extends OniroError {
274
- constructor(platform6) {
275
- super(`Unsupported platform: ${platform6}.`);
276
- this.platform = platform6;
300
+ constructor(platform7) {
301
+ super(`Unsupported platform: ${platform7}.`);
302
+ this.platform = platform7;
277
303
  this.name = "UnsupportedPlatformError";
278
304
  }
279
305
  platform;
@@ -288,6 +314,14 @@ var ChecksumMismatchError = class extends OniroError {
288
314
  expected;
289
315
  actual;
290
316
  };
317
+ var InsufficientSpaceError = class extends OniroError {
318
+ constructor(message, dir, cause) {
319
+ super(message, cause);
320
+ this.dir = dir;
321
+ this.name = "InsufficientSpaceError";
322
+ }
323
+ dir;
324
+ };
291
325
  var CancelledError = class extends OniroError {
292
326
  constructor(message = "Operation cancelled.") {
293
327
  super(message);
@@ -334,29 +368,29 @@ var OHOS_URL_BASE = "https://repo.huaweicloud.com/openharmony/os";
334
368
  // src/sdk/platform.ts
335
369
  var os2 = __toESM(require("os"), 1);
336
370
  function getOsFolder() {
337
- const platform6 = os2.platform();
338
- if (platform6 === "linux") return "linux";
339
- if (platform6 === "darwin") return "darwin";
340
- if (platform6 === "win32") return "windows";
341
- throw new UnsupportedPlatformError(platform6);
371
+ const platform7 = os2.platform();
372
+ if (platform7 === "linux") return "linux";
373
+ if (platform7 === "darwin") return "darwin";
374
+ if (platform7 === "win32") return "windows";
375
+ throw new UnsupportedPlatformError(platform7);
342
376
  }
343
377
  function getSdkFilename(version) {
344
- const platform6 = os2.platform();
378
+ const platform7 = os2.platform();
345
379
  const v = version ?? ALL_SDKS[ALL_SDKS.length - 1].version;
346
380
  const strips = ALL_SDKS.find((r) => r.version === v)?.tarballStrip ?? { linuxWindows: 1, darwin: 3 };
347
- if (platform6 === "linux") {
381
+ if (platform7 === "linux") {
348
382
  return { filename: "ohos-sdk-windows_linux-public.tar.gz", osFolder: "linux", strip: strips.linuxWindows };
349
383
  }
350
- if (platform6 === "darwin") {
384
+ if (platform7 === "darwin") {
351
385
  if (os2.arch() === "arm64") {
352
386
  return { filename: "L2-SDK-MAC-M1-PUBLIC.tar.gz", osFolder: "darwin", strip: strips.darwin };
353
387
  }
354
388
  return { filename: "ohos-sdk-mac-public.tar.gz", osFolder: "darwin", strip: strips.darwin };
355
389
  }
356
- if (platform6 === "win32") {
390
+ if (platform7 === "win32") {
357
391
  return { filename: "ohos-sdk-windows_linux-public.tar.gz", osFolder: "windows", strip: strips.linuxWindows };
358
392
  }
359
- throw new UnsupportedPlatformError(platform6);
393
+ throw new UnsupportedPlatformError(platform7);
360
394
  }
361
395
 
362
396
  // src/sdk/paths.ts
@@ -375,6 +409,14 @@ function getCmdToolsPath(config) {
375
409
  function getEmulatorDir(config) {
376
410
  return config.get("emulatorDir", defaultPaths.emulatorDir());
377
411
  }
412
+ function toLongPath(p, platform7 = os3.platform()) {
413
+ if (platform7 !== "win32") return p;
414
+ try {
415
+ return fs.realpathSync.native(p);
416
+ } catch {
417
+ return p;
418
+ }
419
+ }
378
420
  function pickExisting(candidates) {
379
421
  for (const c of candidates) {
380
422
  if (fs.existsSync(c)) return c;
@@ -397,6 +439,8 @@ function getOhpmPath(config) {
397
439
  return getCmdToolsBin(config, "ohpm");
398
440
  }
399
441
  function getHdcPath(config) {
442
+ const override = config.get("hdcPath", "");
443
+ if (override) return override;
400
444
  const base = path2.join(getCmdToolsPath(config), "sdk", "default", "openharmony", "toolchains");
401
445
  if (os3.platform() === "win32") {
402
446
  return pickExisting([
@@ -408,12 +452,11 @@ function getHdcPath(config) {
408
452
  }
409
453
  return path2.join(base, "hdc");
410
454
  }
411
- function getHvigorwPath(config, projectDir) {
412
- const local = pickExisting([
413
- path2.join(projectDir, "hvigorw"),
414
- path2.join(projectDir, "hvigorw.bat"),
415
- path2.join(projectDir, "hvigorw.cmd")
416
- ]);
455
+ function getHvigorwPath(config, projectDir, platform7 = os3.platform()) {
456
+ const posixFirst = ["hvigorw", "hvigorw.bat", "hvigorw.cmd"];
457
+ const windowsFirst = ["hvigorw.bat", "hvigorw.cmd", "hvigorw"];
458
+ const names = platform7 === "win32" ? windowsFirst : posixFirst;
459
+ const local = pickExisting(names.map((n) => path2.join(projectDir, n)));
417
460
  if (fs.existsSync(local) && isProjectLocalHvigorwWorking(projectDir)) {
418
461
  return local;
419
462
  }
@@ -447,8 +490,164 @@ function detectProjectSdkVersion(projectRoot, logger = noopLogger) {
447
490
  }
448
491
  }
449
492
 
450
- // src/sdk/download.ts
493
+ // src/sdk/tmp.ts
451
494
  var fs3 = __toESM(require("fs"), 1);
495
+ var os4 = __toESM(require("os"), 1);
496
+ var path4 = __toESM(require("path"), 1);
497
+ var INSTALL_TMP_DIRNAME = ".oniro-tmp";
498
+ var TMPFS_MAGIC = 16914836;
499
+ var RAMFS_MAGIC = 2240043254;
500
+ var HINT_EXAMPLE = os4.platform() === "win32" ? "D:\\oniro-tmp" : "~/.cache/oniro-tmp";
501
+ var TMP_DIR_HINT = `Point the scratch directory at a filesystem with more room using --tmp-dir <path> (or the ONIRO_TMP_DIR environment variable), e.g. --tmp-dir ${HINT_EXAMPLE}.`;
502
+ function resolveTmpRoot(config, override, installRoot) {
503
+ const explicit = (override ?? "").trim();
504
+ if (explicit) return path4.resolve(explicit);
505
+ const configured = config.get("tmpDir", "").trim();
506
+ if (configured) return path4.resolve(configured);
507
+ if (installRoot) return path4.join(path4.resolve(installRoot), INSTALL_TMP_DIRNAME);
508
+ return os4.tmpdir();
509
+ }
510
+ function createTempWorkDir(root, prefix) {
511
+ try {
512
+ fs3.mkdirSync(root, { recursive: true });
513
+ return fs3.mkdtempSync(path4.join(root, prefix));
514
+ } catch (err) {
515
+ if (isOutOfSpaceError(err)) throw toSpaceError(err, root, "a temporary directory");
516
+ throw new OniroError(
517
+ `Cannot create a temporary directory in '${root}': ${err instanceof Error ? err.message : String(err)}
518
+ ${TMP_DIR_HINT}`,
519
+ err
520
+ );
521
+ }
522
+ }
523
+ function removeTempWorkDir(dir, root) {
524
+ fs3.rmSync(dir, { recursive: true, force: true });
525
+ if (!root || path4.basename(root) !== INSTALL_TMP_DIRNAME) return;
526
+ try {
527
+ fs3.rmdirSync(root);
528
+ } catch {
529
+ }
530
+ }
531
+ function createInstallTempDir(opts) {
532
+ const requested = (opts.override ?? "").trim() || opts.config.get("tmpDir", "").trim();
533
+ const root = resolveTmpRoot(opts.config, opts.override, opts.installRoot);
534
+ try {
535
+ return { dir: createTempWorkDir(root, opts.prefix), root };
536
+ } catch (err) {
537
+ const fallback = os4.tmpdir();
538
+ if (requested || isOutOfSpaceError(err) || path4.resolve(fallback) === path4.resolve(root)) throw err;
539
+ const reason = err instanceof Error ? err.message.split("\n")[0] : String(err);
540
+ (opts.logger ?? noopLogger).warn(`${reason} Falling back to '${fallback}'.`);
541
+ return { dir: createTempWorkDir(fallback, opts.prefix), root: fallback };
542
+ }
543
+ }
544
+ function nearestExisting(dir) {
545
+ let current = path4.resolve(dir);
546
+ for (; ; ) {
547
+ if (fs3.existsSync(current)) return current;
548
+ const parent = path4.dirname(current);
549
+ if (parent === current) return null;
550
+ current = parent;
551
+ }
552
+ }
553
+ function getFreeSpaceBytes(dir) {
554
+ const target = nearestExisting(dir);
555
+ if (!target) return null;
556
+ try {
557
+ const stats = fs3.statfsSync(target);
558
+ return Number(stats.bsize) * Number(stats.bavail);
559
+ } catch {
560
+ return null;
561
+ }
562
+ }
563
+ function isRamBackedPath(dir) {
564
+ const target = nearestExisting(dir);
565
+ if (!target) return false;
566
+ try {
567
+ const type = Number(fs3.statfsSync(target).type);
568
+ return type === TMPFS_MAGIC || type === RAMFS_MAGIC;
569
+ } catch {
570
+ return false;
571
+ }
572
+ }
573
+ function formatBytes(bytes) {
574
+ const units = ["B", "KiB", "MiB", "GiB", "TiB"];
575
+ let value = Math.max(0, bytes);
576
+ let unit = 0;
577
+ while (value >= 1024 && unit < units.length - 1) {
578
+ value /= 1024;
579
+ unit++;
580
+ }
581
+ return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;
582
+ }
583
+ function isOutOfSpaceError(err) {
584
+ if (err instanceof InsufficientSpaceError) return true;
585
+ const seen = /* @__PURE__ */ new Set();
586
+ let current = err;
587
+ while (current && typeof current === "object" && !seen.has(current)) {
588
+ seen.add(current);
589
+ const e = current;
590
+ if (e.code === "ENOSPC" || e.code === "EDQUOT") return true;
591
+ if (typeof e.message === "string" && /ENOSPC|EDQUOT|no space left on device/i.test(e.message)) return true;
592
+ current = e.cause;
593
+ }
594
+ return false;
595
+ }
596
+ function spaceMessage(dir, what, opts) {
597
+ const need = typeof opts.requiredBytes === "number" ? `needs about ${formatBytes(opts.requiredBytes)}` : null;
598
+ const free = typeof opts.freeBytes === "number" ? `${formatBytes(opts.freeBytes)} available` : null;
599
+ const amounts = [need, free].filter(Boolean).join(", ");
600
+ const lines = [`Not enough free space in '${dir}' for ${what}${amounts ? ` (${amounts})` : ""}.`];
601
+ if (isRamBackedPath(dir)) {
602
+ lines.push(
603
+ `'${dir}' is on a RAM-backed filesystem (tmpfs), so its capacity is limited by free memory, not by free disk.`
604
+ );
605
+ }
606
+ if (opts.tmpDirHint) lines.push(TMP_DIR_HINT);
607
+ return lines.join("\n");
608
+ }
609
+ function ensureFreeSpace(dir, requiredBytes, what) {
610
+ if (!Number.isFinite(requiredBytes) || requiredBytes <= 0) return;
611
+ const freeBytes = getFreeSpaceBytes(dir);
612
+ if (freeBytes === null || freeBytes >= requiredBytes) return;
613
+ throw new InsufficientSpaceError(
614
+ spaceMessage(dir, what, { requiredBytes, freeBytes, tmpDirHint: true }),
615
+ dir
616
+ );
617
+ }
618
+ function errorPath(err) {
619
+ const seen = /* @__PURE__ */ new Set();
620
+ let current = err;
621
+ while (current && typeof current === "object" && !seen.has(current)) {
622
+ seen.add(current);
623
+ const e = current;
624
+ if (typeof e.path === "string" && e.path) return e.path;
625
+ if (typeof e.dest === "string" && e.dest) return e.dest;
626
+ current = e.cause;
627
+ }
628
+ return null;
629
+ }
630
+ function isInside(child, parent) {
631
+ const rel = path4.relative(path4.resolve(parent), path4.resolve(child));
632
+ return rel === "" || !rel.startsWith("..") && !path4.isAbsolute(rel);
633
+ }
634
+ function toSpaceError(err, tmpRoot, what) {
635
+ if (err instanceof InsufficientSpaceError) return err;
636
+ if (!isOutOfSpaceError(err)) return err;
637
+ const failed = errorPath(err);
638
+ const failedDir = failed ? path4.dirname(path4.resolve(failed)) : path4.resolve(tmpRoot);
639
+ const inTmp = isInside(failedDir, tmpRoot);
640
+ const dir = inTmp ? path4.resolve(tmpRoot) : failedDir;
641
+ return new InsufficientSpaceError(
642
+ spaceMessage(dir, what, { freeBytes: getFreeSpaceBytes(dir), tmpDirHint: inTmp }),
643
+ dir,
644
+ err
645
+ );
646
+ }
647
+
648
+ // src/sdk/download.ts
649
+ var fs4 = __toESM(require("fs"), 1);
650
+ var path5 = __toESM(require("path"), 1);
452
651
  var crypto = __toESM(require("crypto"), 1);
453
652
  var import_node_stream = require("stream");
454
653
  var import_node_util = require("util");
@@ -458,36 +657,57 @@ var pipelineAsync = (0, import_node_util.promisify)(import_node_stream.pipeline)
458
657
  async function downloadFile(opts) {
459
658
  const { url, dest, progress, abortSignal } = opts;
460
659
  const proto = url.startsWith("https") ? https : http;
461
- return new Promise((resolve2, reject) => {
660
+ return new Promise((resolve4, reject) => {
462
661
  const s = Math.max(0, Math.min(100, opts.start ?? 0));
463
662
  const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));
464
663
  let settled = false;
465
664
  const done = (err) => {
466
665
  if (settled) return;
467
666
  settled = true;
468
- err ? reject(err) : resolve2();
667
+ err ? reject(err) : resolve4();
469
668
  };
470
669
  if (abortSignal?.aborted) {
471
670
  done(new CancelledError("Download cancelled before start."));
472
671
  return;
473
672
  }
474
- const file = fs3.createWriteStream(dest);
673
+ const destDir = path5.dirname(path5.resolve(dest));
674
+ const what = opts.what ?? `the download of '${url}'`;
675
+ const writeFailed = (err) => isOutOfSpaceError(err) ? toSpaceError(err, opts.tmpRoot ?? destDir, what) : new OniroError(`Error writing '${dest}': ${err instanceof Error ? err.message : String(err)}`, err);
676
+ const file = fs4.createWriteStream(dest);
677
+ let activeResponse;
678
+ const failWith = (err) => {
679
+ file.close(() => fs4.rm(dest, { force: true }, () => done(err)));
680
+ };
681
+ file.on("error", (err) => {
682
+ try {
683
+ activeResponse?.destroy?.();
684
+ } catch {
685
+ }
686
+ failWith(writeFailed(err));
687
+ });
475
688
  const req = proto.get(url, (response) => {
689
+ activeResponse = response;
476
690
  if (response.statusCode !== 200) {
477
691
  try {
478
692
  response.destroy();
479
693
  } catch {
480
694
  }
481
- try {
482
- file.close();
483
- } catch {
484
- }
485
- fs3.unlink(dest, () => {
486
- });
487
- done(new OniroError(`Failed to download '${url}' (HTTP ${response.statusCode})`));
695
+ failWith(new OniroError(`Failed to download '${url}' (HTTP ${response.statusCode})`));
488
696
  return;
489
697
  }
490
698
  const total = parseInt(response.headers["content-length"] || "0", 10);
699
+ if (total > 0) {
700
+ try {
701
+ ensureFreeSpace(opts.tmpRoot ?? destDir, total, what);
702
+ } catch (err) {
703
+ try {
704
+ response.destroy();
705
+ } catch {
706
+ }
707
+ failWith(err);
708
+ return;
709
+ }
710
+ }
491
711
  let downloaded = 0;
492
712
  let lastOverall = Math.round(s);
493
713
  response.on("data", (chunk) => {
@@ -511,38 +731,26 @@ async function downloadFile(opts) {
511
731
  const inc = endOverall - lastOverall;
512
732
  if (inc > 0) progress.report({ message: "Downloading: 100%", increment: inc });
513
733
  }
514
- file.close((err) => err ? done(err) : done());
734
+ file.close((err) => err ? done(writeFailed(err)) : done());
515
735
  });
516
736
  abortSignal?.addEventListener("abort", () => {
517
737
  response.destroy();
518
- file.close();
519
- fs3.unlink(dest, () => {
520
- });
521
- done(new CancelledError("Download cancelled."));
738
+ failWith(new CancelledError("Download cancelled."));
522
739
  });
523
740
  });
524
741
  req.on("error", (err) => {
525
- try {
526
- file.close();
527
- } catch {
528
- }
529
- fs3.unlink(dest, () => {
530
- });
531
- done(new OniroError(`Error downloading '${url}': ${err.message}`, err));
742
+ failWith(new OniroError(`Error downloading '${url}': ${err.message}`, err));
532
743
  });
533
744
  abortSignal?.addEventListener("abort", () => {
534
745
  req.destroy();
535
- file.close();
536
- fs3.unlink(dest, () => {
537
- });
538
- done(new CancelledError("Download cancelled."));
746
+ failWith(new CancelledError("Download cancelled."));
539
747
  });
540
748
  });
541
749
  }
542
750
  async function verifySha256(filePath, sha256Path) {
543
- const expected = fs3.readFileSync(sha256Path, "utf8").split(/\s+/)[0];
751
+ const expected = fs4.readFileSync(sha256Path, "utf8").split(/\s+/)[0];
544
752
  const hash = crypto.createHash("sha256");
545
- await pipelineAsync(fs3.createReadStream(filePath), hash);
753
+ await pipelineAsync(fs4.createReadStream(filePath), hash);
546
754
  const actual = hash.digest("hex");
547
755
  if (actual !== expected) {
548
756
  throw new ChecksumMismatchError(expected, actual);
@@ -550,9 +758,9 @@ async function verifySha256(filePath, sha256Path) {
550
758
  }
551
759
 
552
760
  // src/sdk/extract.ts
553
- var fs4 = __toESM(require("fs"), 1);
554
- var os4 = __toESM(require("os"), 1);
555
- var path4 = __toESM(require("path"), 1);
761
+ var fs5 = __toESM(require("fs"), 1);
762
+ var os5 = __toESM(require("os"), 1);
763
+ var path6 = __toESM(require("path"), 1);
556
764
  var import_node_stream2 = require("stream");
557
765
  var import_node_util2 = require("util");
558
766
  var tar = __toESM(require("tar"), 1);
@@ -569,12 +777,12 @@ async function extractZipWithProgress(opts) {
569
777
  const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));
570
778
  let processed = 0;
571
779
  let lastOverall = Math.round(s);
572
- await fs4.promises.mkdir(dest, { recursive: true });
573
- const destRoot = path4.resolve(dest);
780
+ await fs5.promises.mkdir(dest, { recursive: true });
781
+ const destRoot = path6.resolve(dest);
574
782
  const safeResolveTarget = (entryName) => {
575
- const resolved = path4.resolve(destRoot, entryName);
576
- const rel = path4.relative(destRoot, resolved);
577
- if (rel.startsWith("..") || path4.isAbsolute(rel)) {
783
+ const resolved = path6.resolve(destRoot, entryName);
784
+ const rel = path6.relative(destRoot, resolved);
785
+ if (rel.startsWith("..") || path6.isAbsolute(rel)) {
578
786
  throw new OniroError(`Blocked ZIP entry with illegal path: ${entryName}`);
579
787
  }
580
788
  return resolved;
@@ -586,25 +794,25 @@ async function extractZipWithProgress(opts) {
586
794
  const attr = file.attr ? file.attr >>> 16 : 0;
587
795
  const isSymlink = "isSymbolicLink" in file ? Boolean(file.isSymbolicLink) : (attr & 61440) === 40960;
588
796
  if (file.isDirectory) {
589
- await fs4.promises.mkdir(targetPath, { recursive: true });
797
+ await fs5.promises.mkdir(targetPath, { recursive: true });
590
798
  } else if (isSymlink) {
591
- await fs4.promises.mkdir(path4.dirname(targetPath), { recursive: true });
799
+ await fs5.promises.mkdir(path6.dirname(targetPath), { recursive: true });
592
800
  const linkTargetBuffer = await zip.entryData(file);
593
801
  const linkTarget = linkTargetBuffer.toString("utf8");
594
802
  try {
595
- const isWin = os4.platform() === "win32";
596
- await fs4.promises.symlink(linkTarget, targetPath, isWin ? "file" : void 0);
803
+ const isWin = os5.platform() === "win32";
804
+ await fs5.promises.symlink(linkTarget, targetPath, isWin ? "file" : void 0);
597
805
  } catch (e) {
598
806
  logger.warn(`Failed to create symlink at ${targetPath}: ${String(e)}`);
599
807
  }
600
808
  } else {
601
- await fs4.promises.mkdir(path4.dirname(targetPath), { recursive: true });
809
+ await fs5.promises.mkdir(path6.dirname(targetPath), { recursive: true });
602
810
  const readStream = await zip.stream(file);
603
- const writeStream = fs4.createWriteStream(targetPath);
811
+ const writeStream = fs5.createWriteStream(targetPath);
604
812
  await pipelineAsync2(readStream, writeStream);
605
813
  if (attr > 0) {
606
814
  try {
607
- await fs4.promises.chmod(targetPath, attr & 511);
815
+ await fs5.promises.chmod(targetPath, attr & 511);
608
816
  } catch {
609
817
  }
610
818
  }
@@ -636,41 +844,41 @@ async function extractTarball(tarPath, dest, strip = 0) {
636
844
  }
637
845
 
638
846
  // src/sdk/list.ts
639
- var fs5 = __toESM(require("fs"), 1);
640
- var path5 = __toESM(require("path"), 1);
847
+ var fs6 = __toESM(require("fs"), 1);
848
+ var path7 = __toESM(require("path"), 1);
641
849
  function getSupportedSdksForUi(config) {
642
- const base = path5.join(getSdkRootDir(config), getOsFolder());
850
+ const base = path7.join(getSdkRootDir(config), getOsFolder());
643
851
  return ALL_SDKS.map((sdk) => ({
644
852
  version: sdk.version,
645
853
  api: sdk.api,
646
- installed: fs5.existsSync(path5.join(base, sdk.api))
854
+ installed: fs6.existsSync(path7.join(base, sdk.api))
647
855
  })).sort((a, b) => Number(b.api) - Number(a.api));
648
856
  }
649
857
  function getInstalledSdks(config) {
650
858
  const sdkRoot = getSdkRootDir(config);
651
859
  const versions = /* @__PURE__ */ new Set();
652
- if (!fs5.existsSync(sdkRoot)) return [];
860
+ if (!fs6.existsSync(sdkRoot)) return [];
653
861
  for (const osFolder of ["linux", "darwin", "windows"]) {
654
- const osPath = path5.join(sdkRoot, osFolder);
655
- if (!fs5.existsSync(osPath) || !fs5.statSync(osPath).isDirectory()) continue;
656
- for (const api of fs5.readdirSync(osPath)) {
657
- const apiPath = path5.join(osPath, api);
658
- if (fs5.statSync(apiPath).isDirectory()) versions.add(api);
862
+ const osPath = path7.join(sdkRoot, osFolder);
863
+ if (!fs6.existsSync(osPath) || !fs6.statSync(osPath).isDirectory()) continue;
864
+ for (const api of fs6.readdirSync(osPath)) {
865
+ const apiPath = path7.join(osPath, api);
866
+ if (fs6.statSync(apiPath).isDirectory()) versions.add(api);
659
867
  }
660
868
  }
661
869
  return ALL_SDKS.filter((sdk) => versions.has(sdk.api)).map((sdk) => sdk.version);
662
870
  }
663
871
 
664
872
  // src/sdk/remove.ts
665
- var fs6 = __toESM(require("fs"), 1);
666
- var path6 = __toESM(require("path"), 1);
873
+ var fs7 = __toESM(require("fs"), 1);
874
+ var path8 = __toESM(require("path"), 1);
667
875
  function removeSdk(config, api) {
668
876
  const sdkRoot = getSdkRootDir(config);
669
877
  let removed = false;
670
878
  for (const osFolder of ["linux", "darwin", "windows"]) {
671
- const sdkPath = path6.join(sdkRoot, osFolder, api);
672
- if (fs6.existsSync(sdkPath)) {
673
- fs6.rmSync(sdkPath, { recursive: true, force: true });
879
+ const sdkPath = path8.join(sdkRoot, osFolder, api);
880
+ if (fs7.existsSync(sdkPath)) {
881
+ fs7.rmSync(sdkPath, { recursive: true, force: true });
674
882
  removed = true;
675
883
  }
676
884
  }
@@ -678,19 +886,18 @@ function removeSdk(config, api) {
678
886
  }
679
887
 
680
888
  // src/sdk/install.ts
681
- var fs8 = __toESM(require("fs"), 1);
682
- var os5 = __toESM(require("os"), 1);
683
- var path7 = __toESM(require("path"), 1);
889
+ var fs9 = __toESM(require("fs"), 1);
890
+ var path9 = __toESM(require("path"), 1);
684
891
 
685
892
  // src/sdk/move.ts
686
- var fs7 = __toESM(require("fs"), 1);
893
+ var fs8 = __toESM(require("fs"), 1);
687
894
  function movePath(src, dest) {
688
895
  try {
689
- fs7.renameSync(src, dest);
896
+ fs8.renameSync(src, dest);
690
897
  } catch (err) {
691
898
  if (err.code !== "EXDEV") throw err;
692
- fs7.cpSync(src, dest, { recursive: true });
693
- fs7.rmSync(src, { recursive: true, force: true });
899
+ fs8.cpSync(src, dest, { recursive: true });
900
+ fs8.rmSync(src, { recursive: true, force: true });
694
901
  }
695
902
  }
696
903
 
@@ -702,21 +909,29 @@ async function downloadAndInstallSdk(opts) {
702
909
  const urlBase = config.get("sdkUrlBase", OHOS_URL_BASE);
703
910
  const downloadUrl = `${urlBase}/${version}-Release/${filename}`;
704
911
  const sha256Url = `${downloadUrl}.sha256`;
705
- const tmpDir = fs8.mkdtempSync(path7.join(os5.tmpdir(), "oniro-sdk-"));
706
- const tarPath = path7.join(tmpDir, filename);
707
- const sha256Path = path7.join(tmpDir, `${filename}.sha256`);
708
- const extractDir = path7.join(tmpDir, "extract");
709
- fs8.mkdirSync(extractDir);
710
- const sdkInstallDir = path7.join(getSdkRootDir(config), osFolder, api);
711
- fs8.mkdirSync(path7.dirname(sdkInstallDir), { recursive: true });
912
+ const what = `the SDK ${version} install`;
913
+ const sdkRoot = getSdkRootDir(config);
914
+ const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
915
+ config,
916
+ override: opts.tmpDir,
917
+ installRoot: sdkRoot,
918
+ prefix: "oniro-sdk-",
919
+ logger
920
+ });
921
+ const tarPath = path9.join(tmpDir, filename);
922
+ const sha256Path = path9.join(tmpDir, `${filename}.sha256`);
923
+ const extractDir = path9.join(tmpDir, "extract");
924
+ fs9.mkdirSync(extractDir);
925
+ const sdkInstallDir = path9.join(sdkRoot, osFolder, api);
926
+ fs9.mkdirSync(path9.dirname(sdkInstallDir), { recursive: true });
712
927
  const checkCancelled = () => {
713
928
  if (abortSignal?.aborted) throw new CancelledError();
714
929
  };
715
930
  try {
716
931
  progress?.report({ message: "Downloading SDK archive...", increment: 0 });
717
- await downloadFile({ url: downloadUrl, dest: tarPath, progress, abortSignal, start: 0, range: 35 });
932
+ await downloadFile({ url: downloadUrl, dest: tarPath, progress, abortSignal, start: 0, range: 35, what, tmpRoot });
718
933
  progress?.report({ message: "Downloading checksum...", increment: 0 });
719
- await downloadFile({ url: sha256Url, dest: sha256Path, progress, abortSignal, start: 35, range: 10 });
934
+ await downloadFile({ url: sha256Url, dest: sha256Path, progress, abortSignal, start: 35, range: 10, what, tmpRoot });
720
935
  progress?.report({ message: "Verifying checksum...", increment: 0 });
721
936
  await verifySha256(tarPath, sha256Path);
722
937
  progress?.report({ message: "Verifying checksum...", increment: 5 });
@@ -725,13 +940,13 @@ async function downloadAndInstallSdk(opts) {
725
940
  await extractTarball(tarPath, extractDir, strip);
726
941
  progress?.report({ message: "Extracting SDK (this may take a while)...", increment: 10 });
727
942
  checkCancelled();
728
- const osContentPath = path7.join(extractDir, osFolder);
729
- if (!fs8.existsSync(osContentPath)) {
943
+ const osContentPath = path9.join(extractDir, osFolder);
944
+ if (!fs9.existsSync(osContentPath)) {
730
945
  throw new OniroError(
731
946
  `Expected folder '${osFolder}' not found in extracted SDK. Tarball layout may have changed.`
732
947
  );
733
948
  }
734
- const zipFiles = fs8.readdirSync(osContentPath).filter((n2) => n2.endsWith(".zip"));
949
+ const zipFiles = fs9.readdirSync(osContentPath).filter((n2) => n2.endsWith(".zip"));
735
950
  const componentsStart = 60;
736
951
  const componentsBudget = 35;
737
952
  const n = zipFiles.length;
@@ -746,39 +961,114 @@ async function downloadAndInstallSdk(opts) {
746
961
  for (const zipFile of zipFiles) {
747
962
  checkCancelled();
748
963
  logger.info(`Extracting component ${zipFile}`);
749
- const zipPath = path7.join(osContentPath, zipFile);
964
+ const zipPath = path9.join(osContentPath, zipFile);
750
965
  const thisBudget = base + (rem > 0 ? 1 : 0);
751
966
  if (rem > 0) rem--;
752
967
  await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });
753
968
  cursor += thisBudget;
754
- fs8.unlinkSync(zipPath);
969
+ fs9.unlinkSync(zipPath);
755
970
  }
756
971
  progress?.report({ message: "Finalizing installation...", increment: 0 });
757
- if (fs8.existsSync(sdkInstallDir)) {
758
- fs8.rmSync(sdkInstallDir, { recursive: true, force: true });
972
+ if (fs9.existsSync(sdkInstallDir)) {
973
+ fs9.rmSync(sdkInstallDir, { recursive: true, force: true });
759
974
  }
760
975
  movePath(osContentPath, sdkInstallDir);
761
976
  progress?.report({ message: "Finalizing installation...", increment: 3 });
762
977
  progress?.report({ message: "Cleaning up...", increment: 0 });
763
- fs8.rmSync(tmpDir, { recursive: true, force: true });
978
+ removeTempWorkDir(tmpDir, tmpRoot);
764
979
  progress?.report({ message: "Cleaning up...", increment: 2 });
765
980
  } catch (err) {
766
- logger.error(`SDK install failed: ${err instanceof Error ? err.message : String(err)}`);
767
- fs8.rmSync(tmpDir, { recursive: true, force: true });
768
- throw err;
981
+ const wrapped = toSpaceError(err, tmpRoot, what);
982
+ logger.error(`SDK install failed: ${wrapped instanceof Error ? wrapped.message : String(wrapped)}`);
983
+ removeTempWorkDir(tmpDir, tmpRoot);
984
+ throw wrapped;
769
985
  }
770
986
  }
771
987
 
772
988
  // src/cmdTools/install.ts
773
- var fs9 = __toESM(require("fs"), 1);
989
+ var fs10 = __toESM(require("fs"), 1);
774
990
  var os6 = __toESM(require("os"), 1);
775
- var path8 = __toESM(require("path"), 1);
991
+ var path11 = __toESM(require("path"), 1);
992
+ var import_node_child_process2 = require("child_process");
993
+
994
+ // src/hdc/spawnCompat.ts
995
+ var path10 = __toESM(require("path"), 1);
776
996
  var import_node_child_process = require("child_process");
777
- function getCmdToolsDownloadUrl(config, platform6 = os6.platform()) {
778
- if (platform6 === "linux") {
997
+ var WINDOWS_BATCH_RE = /\.(bat|cmd)$/i;
998
+ var CMD_META_RE = /([()[\]%!^"`<>&|;, *?])/g;
999
+ var CMD_SHIM_RE = /node_modules[\\/]\.bin[\\/][^\\/]+\.cmd$/i;
1000
+ var UNSAFE_CMD_CHARS_RE = /["\r\n\0]/;
1001
+ function needsCmdWrapper(command, platform7 = process.platform) {
1002
+ return platform7 === "win32" && WINDOWS_BATCH_RE.test(command);
1003
+ }
1004
+ function escapeCmdArgument(arg, doubleEscapeMetaChars = false) {
1005
+ let out = String(arg);
1006
+ out = out.replace(/(\\*)"/g, '$1$1\\"');
1007
+ out = out.replace(/(\\*)$/, "$1$1");
1008
+ out = `"${out}"`;
1009
+ out = out.replace(CMD_META_RE, "^$1");
1010
+ if (doubleEscapeMetaChars) out = out.replace(CMD_META_RE, "^$1");
1011
+ return out;
1012
+ }
1013
+ function escapeCmdCommand(command) {
1014
+ return command.replace(CMD_META_RE, "^$1");
1015
+ }
1016
+ function buildCmdWrapper(command, args) {
1017
+ assertCmdSafe(command, `command ${command}`);
1018
+ args.forEach((a, i) => assertCmdSafe(a, `argument ${i} (${a})`));
1019
+ const normalized = path10.normalize(command);
1020
+ const double = CMD_SHIM_RE.test(normalized);
1021
+ const line = [escapeCmdCommand(normalized), ...args.map((a) => escapeCmdArgument(a, double))].join(" ");
1022
+ return {
1023
+ command: process.env.ComSpec ?? process.env.COMSPEC ?? "cmd.exe",
1024
+ args: ["/d", "/s", "/c", `"${line}"`]
1025
+ };
1026
+ }
1027
+ function assertCmdSafe(value, label) {
1028
+ if (UNSAFE_CMD_CHARS_RE.test(value)) {
1029
+ throw new OniroError(
1030
+ `Cannot run a Windows batch wrapper with a quote, newline or NUL in the ${label}: cmd.exe cannot pass it through unambiguously.`
1031
+ );
1032
+ }
1033
+ }
1034
+ function spawnCompat(command, args, options = {}) {
1035
+ if (!needsCmdWrapper(command)) {
1036
+ return (0, import_node_child_process.spawn)(command, [...args], { ...options, shell: false });
1037
+ }
1038
+ const wrapped = buildCmdWrapper(command, args);
1039
+ return (0, import_node_child_process.spawn)(wrapped.command, wrapped.args, {
1040
+ ...options,
1041
+ shell: false,
1042
+ // The line is already escaped; stop Node from re-quoting it.
1043
+ windowsVerbatimArguments: true
1044
+ });
1045
+ }
1046
+ function killProcessTree(child) {
1047
+ if (process.platform === "win32" && typeof child.pid === "number") {
1048
+ try {
1049
+ const killer = (0, import_node_child_process.spawn)("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore" });
1050
+ killer.on("error", () => {
1051
+ try {
1052
+ child.kill("SIGKILL");
1053
+ } catch {
1054
+ }
1055
+ });
1056
+ return;
1057
+ } catch {
1058
+ }
1059
+ }
1060
+ try {
1061
+ child.kill("SIGKILL");
1062
+ } catch {
1063
+ }
1064
+ }
1065
+
1066
+ // src/cmdTools/install.ts
1067
+ function getCmdToolsDownloadUrl(config, platform7 = os6.platform()) {
1068
+ if (platform7 === "linux") {
779
1069
  return config.get("cmdToolsUrlLinux", defaultPaths.cmdToolsUrlLinux);
780
1070
  }
781
- if (platform6 === "win32") {
1071
+ if (platform7 === "win32") {
782
1072
  const url = config.get("cmdToolsUrlWindows", "");
783
1073
  if (!url) {
784
1074
  throw new OniroError(
@@ -787,7 +1077,7 @@ function getCmdToolsDownloadUrl(config, platform6 = os6.platform()) {
787
1077
  }
788
1078
  return url;
789
1079
  }
790
- if (platform6 === "darwin") {
1080
+ if (platform7 === "darwin") {
791
1081
  const url = config.get("cmdToolsUrlMac", "");
792
1082
  if (!url) {
793
1083
  throw new OniroError(
@@ -796,20 +1086,20 @@ function getCmdToolsDownloadUrl(config, platform6 = os6.platform()) {
796
1086
  }
797
1087
  return url;
798
1088
  }
799
- throw new UnsupportedPlatformError(platform6);
1089
+ throw new UnsupportedPlatformError(platform7);
800
1090
  }
801
1091
  function findCmdToolsSourceDir(extractPath) {
802
1092
  const known = [
803
- path8.join(extractPath, "command-line-tools"),
804
- path8.join(extractPath, "oh-command-line-tools"),
805
- path8.join(extractPath, "commandline-tools")
1093
+ path11.join(extractPath, "command-line-tools"),
1094
+ path11.join(extractPath, "oh-command-line-tools"),
1095
+ path11.join(extractPath, "commandline-tools")
806
1096
  ];
807
1097
  for (const c of known) {
808
- if (fs9.existsSync(c)) return c;
1098
+ if (fs10.existsSync(c)) return c;
809
1099
  }
810
- const entries = fs9.readdirSync(extractPath, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path8.join(extractPath, e.name));
1100
+ const entries = fs10.readdirSync(extractPath, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path11.join(extractPath, e.name));
811
1101
  for (const dir of entries) {
812
- if (fs9.existsSync(path8.join(dir, "bin"))) return dir;
1102
+ if (fs10.existsSync(path11.join(dir, "bin"))) return dir;
813
1103
  }
814
1104
  throw new OniroError("Could not locate command line tools folder in the extracted archive.");
815
1105
  }
@@ -817,53 +1107,62 @@ async function installCmdTools(opts) {
817
1107
  const { config, progress, abortSignal } = opts;
818
1108
  const logger = opts.logger ?? noopLogger;
819
1109
  const CMD_PATH = getCmdToolsPath(config);
820
- const tmpDir = fs9.mkdtempSync(path8.join(os6.tmpdir(), "oniro-cmdtools-"));
821
- const zipPath = opts.localZipPath ?? path8.join(tmpDir, "oh-command-line-tools.zip");
822
- const extractPath = path8.join(tmpDir, "oh-command-line-tools");
1110
+ const what = "the command-line tools install";
1111
+ const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
1112
+ config,
1113
+ override: opts.tmpDir,
1114
+ installRoot: path11.dirname(CMD_PATH),
1115
+ prefix: "oniro-cmdtools-",
1116
+ logger
1117
+ });
1118
+ const zipPath = opts.localZipPath ?? path11.join(tmpDir, "oh-command-line-tools.zip");
1119
+ const extractPath = path11.join(tmpDir, "oh-command-line-tools");
823
1120
  try {
824
1121
  if (!opts.localZipPath) {
825
1122
  const url = getCmdToolsDownloadUrl(config);
826
1123
  progress?.report({ message: "Downloading command line tools...", increment: 0 });
827
- await downloadFile({ url, dest: zipPath, progress, abortSignal, start: 0, range: 50 });
1124
+ await downloadFile({ url, dest: zipPath, progress, abortSignal, start: 0, range: 50, what, tmpRoot });
828
1125
  }
829
1126
  progress?.report({ message: "Extracting tools...", increment: 0 });
830
1127
  await extractZipWithProgress({ zipPath, dest: extractPath, progress, start: 50, range: 45, logger });
831
- fs9.mkdirSync(CMD_PATH, { recursive: true });
1128
+ fs10.mkdirSync(CMD_PATH, { recursive: true });
832
1129
  const srcDir = findCmdToolsSourceDir(extractPath);
833
- for (const entry of fs9.readdirSync(srcDir)) {
834
- const src = path8.join(srcDir, entry);
835
- const dest = path8.join(CMD_PATH, entry);
836
- if (fs9.statSync(src).isDirectory()) {
837
- if (fs9.existsSync(dest)) fs9.rmSync(dest, { recursive: true, force: true });
1130
+ for (const entry of fs10.readdirSync(srcDir)) {
1131
+ const src = path11.join(srcDir, entry);
1132
+ const dest = path11.join(CMD_PATH, entry);
1133
+ if (fs10.statSync(src).isDirectory()) {
1134
+ if (fs10.existsSync(dest)) fs10.rmSync(dest, { recursive: true, force: true });
838
1135
  movePath(src, dest);
839
1136
  } else {
840
- fs9.copyFileSync(src, dest);
1137
+ fs10.copyFileSync(src, dest);
841
1138
  }
842
1139
  }
843
- const binDir = path8.join(CMD_PATH, "bin");
844
- if (fs9.existsSync(binDir) && os6.platform() !== "win32") {
845
- for (const file of fs9.readdirSync(binDir)) {
846
- fs9.chmodSync(path8.join(binDir, file), 493);
1140
+ const binDir = path11.join(CMD_PATH, "bin");
1141
+ if (fs10.existsSync(binDir) && os6.platform() !== "win32") {
1142
+ for (const file of fs10.readdirSync(binDir)) {
1143
+ fs10.chmodSync(path11.join(binDir, file), 493);
847
1144
  }
848
1145
  }
849
1146
  progress?.report({ message: "Finalizing installation...", increment: 5 });
850
1147
  progress?.report({ message: "Cleaning up...", increment: 0 });
1148
+ } catch (err) {
1149
+ throw toSpaceError(err, tmpRoot, what);
851
1150
  } finally {
852
- fs9.rmSync(tmpDir, { recursive: true, force: true });
1151
+ removeTempWorkDir(tmpDir, tmpRoot);
853
1152
  }
854
1153
  }
855
1154
  function getCmdToolsStatus(config) {
856
1155
  const cmdPath = getCmdToolsPath(config);
857
- const binDir = path8.join(cmdPath, "bin");
1156
+ const binDir = path11.join(cmdPath, "bin");
858
1157
  const candidates = os6.platform() === "win32" ? ["ohpm.exe", "ohpm.cmd", "ohpm.bat", "ohpm"] : ["ohpm"];
859
- const bin = candidates.map((c) => path8.join(binDir, c)).find((p) => fs9.existsSync(p));
1158
+ const bin = candidates.map((c) => path11.join(binDir, c)).find((p) => fs10.existsSync(p));
860
1159
  if (!bin) {
861
1160
  return { installed: false, status: "Not installed" };
862
1161
  }
863
1162
  try {
864
- const versionFile = path8.join(cmdPath, "version.txt");
865
- if (fs9.existsSync(versionFile)) {
866
- const content = fs9.readFileSync(versionFile, "utf8");
1163
+ const versionFile = path11.join(cmdPath, "version.txt");
1164
+ if (fs10.existsSync(versionFile)) {
1165
+ const content = fs10.readFileSync(versionFile, "utf8");
867
1166
  for (const line of content.split(/\r?\n/)) {
868
1167
  const m = line.match(/^\s*#\s*Version:\s*(.+)$/);
869
1168
  if (m?.[1]) return { installed: true, status: `Installed (${m[1].trim()})` };
@@ -872,7 +1171,14 @@ function getCmdToolsStatus(config) {
872
1171
  } catch {
873
1172
  }
874
1173
  try {
875
- const version = (0, import_node_child_process.execFileSync)(bin, ["-v"], { encoding: "utf8" }).trim();
1174
+ const wrapped = needsCmdWrapper(bin);
1175
+ const probe = wrapped ? buildCmdWrapper(bin, ["-v"]) : { command: bin, args: ["-v"] };
1176
+ const res = (0, import_node_child_process2.spawnSync)(probe.command, probe.args, {
1177
+ encoding: "utf8",
1178
+ windowsVerbatimArguments: wrapped
1179
+ });
1180
+ if (res.error || res.status !== 0) throw res.error ?? new Error(`exit ${String(res.status)}`);
1181
+ const version = res.stdout.trim();
876
1182
  return { installed: true, status: `Installed (${version})` };
877
1183
  } catch {
878
1184
  return { installed: true, status: "Installed (version unknown)" };
@@ -883,14 +1189,14 @@ function isCmdToolsInstalled(config) {
883
1189
  }
884
1190
  function removeCmdTools(config) {
885
1191
  const cmdPath = getCmdToolsPath(config);
886
- if (fs9.existsSync(cmdPath)) {
887
- fs9.rmSync(cmdPath, { recursive: true, force: true });
1192
+ if (fs10.existsSync(cmdPath)) {
1193
+ fs10.rmSync(cmdPath, { recursive: true, force: true });
888
1194
  }
889
1195
  }
890
1196
 
891
1197
  // src/sign/encryptKey.ts
892
- var fs10 = __toESM(require("fs"), 1);
893
- var path9 = __toESM(require("path"), 1);
1198
+ var fs11 = __toESM(require("fs"), 1);
1199
+ var path12 = __toESM(require("path"), 1);
894
1200
  var crypto2 = __toESM(require("crypto"), 1);
895
1201
  var DAEMON_ROOT_KEY_COMPONENT_LENGTH = 16;
896
1202
  var DAEMON_SALT_KEY_LENGTH = 16;
@@ -962,33 +1268,33 @@ function getRootKey(fdComponents, salt) {
962
1268
  function createAndStoreKey(dir, keyLength) {
963
1269
  const key = crypto2.randomBytes(keyLength);
964
1270
  const hash = crypto2.createHash("sha256").update(key).digest("hex");
965
- const filePath = path9.join(dir, hash);
966
- fs10.writeFileSync(filePath, key);
967
- fs10.chmodSync(filePath, KEY_FILE_PERMISSIONS);
1271
+ const filePath = path12.join(dir, hash);
1272
+ fs11.writeFileSync(filePath, key);
1273
+ fs11.chmodSync(filePath, KEY_FILE_PERMISSIONS);
968
1274
  return key;
969
1275
  }
970
1276
  function createAndStoreEnKey(rootKey, ceDir) {
971
1277
  const workKey = crypto2.randomBytes(DAEMON_WORK_KEY_LENGTH);
972
1278
  const encrypted = encrypt(rootKey, workKey);
973
1279
  const hash = crypto2.createHash("sha256").update(encrypted).digest("hex");
974
- const filePath = path9.join(ceDir, hash);
975
- fs10.writeFileSync(filePath, encrypted);
976
- fs10.chmodSync(filePath, KEY_FILE_PERMISSIONS);
1280
+ const filePath = path12.join(ceDir, hash);
1281
+ fs11.writeFileSync(filePath, encrypted);
1282
+ fs11.chmodSync(filePath, KEY_FILE_PERMISSIONS);
977
1283
  }
978
1284
  function createMaterial(materialPath) {
979
- fs10.mkdirSync(materialPath, { recursive: true });
980
- fs10.chmodSync(materialPath, KEY_FILE_DIRECTORY_PERMISSIONS);
981
- const fdDir = path9.join(materialPath, "fd");
982
- const acDir = path9.join(materialPath, "ac");
983
- const ceDir = path9.join(materialPath, "ce");
984
- fs10.mkdirSync(fdDir, { recursive: true });
985
- fs10.mkdirSync(acDir, { recursive: true });
986
- fs10.mkdirSync(ceDir, { recursive: true });
1285
+ fs11.mkdirSync(materialPath, { recursive: true });
1286
+ fs11.chmodSync(materialPath, KEY_FILE_DIRECTORY_PERMISSIONS);
1287
+ const fdDir = path12.join(materialPath, "fd");
1288
+ const acDir = path12.join(materialPath, "ac");
1289
+ const ceDir = path12.join(materialPath, "ce");
1290
+ fs11.mkdirSync(fdDir, { recursive: true });
1291
+ fs11.mkdirSync(acDir, { recursive: true });
1292
+ fs11.mkdirSync(ceDir, { recursive: true });
987
1293
  const fdSubDirs = ["0", "1", "2"];
988
1294
  const fdComponents = [];
989
1295
  for (const sub of fdSubDirs) {
990
- const subDir = path9.join(fdDir, sub);
991
- fs10.mkdirSync(subDir, { recursive: true });
1296
+ const subDir = path12.join(fdDir, sub);
1297
+ fs11.mkdirSync(subDir, { recursive: true });
992
1298
  const comp = createAndStoreKey(subDir, DAEMON_ROOT_KEY_COMPONENT_LENGTH);
993
1299
  fdComponents.push(comp);
994
1300
  }
@@ -997,24 +1303,24 @@ function createMaterial(materialPath) {
997
1303
  createAndStoreEnKey(rootKey, ceDir);
998
1304
  }
999
1305
  function readSingleFile(dir) {
1000
- if (!fs10.existsSync(dir) || !fs10.statSync(dir).isDirectory()) {
1306
+ if (!fs11.existsSync(dir) || !fs11.statSync(dir).isDirectory()) {
1001
1307
  throw new Error(`Missing signing material directory: ${dir}`);
1002
1308
  }
1003
- const files = fs10.readdirSync(dir).filter((f) => f !== ".DS_Store");
1309
+ const files = fs11.readdirSync(dir).filter((f) => f !== ".DS_Store");
1004
1310
  if (files.length !== 1) {
1005
1311
  throw new Error(`Signing material in ${dir} is illegal (expected exactly one file).`);
1006
1312
  }
1007
- return fs10.readFileSync(path9.join(dir, files[0]));
1313
+ return fs11.readFileSync(path12.join(dir, files[0]));
1008
1314
  }
1009
1315
  function getKey(materialPath) {
1010
- if (!fs10.existsSync(materialPath) || !fs10.statSync(materialPath).isDirectory()) {
1316
+ if (!fs11.existsSync(materialPath) || !fs11.statSync(materialPath).isDirectory()) {
1011
1317
  throw new Error("Material directory does not exist.");
1012
1318
  }
1013
- const fdDir = path9.join(materialPath, "fd");
1014
- const fdComponents = ["0", "1", "2"].map((sub) => readSingleFile(path9.join(fdDir, sub)));
1015
- const salt = readSingleFile(path9.join(materialPath, "ac"));
1319
+ const fdDir = path12.join(materialPath, "fd");
1320
+ const fdComponents = ["0", "1", "2"].map((sub) => readSingleFile(path12.join(fdDir, sub)));
1321
+ const salt = readSingleFile(path12.join(materialPath, "ac"));
1016
1322
  const rootKey = getRootKey(fdComponents, salt);
1017
- const workMaterial = readSingleFile(path9.join(materialPath, "ce"));
1323
+ const workMaterial = readSingleFile(path12.join(materialPath, "ce"));
1018
1324
  return decrypt(rootKey, workMaterial);
1019
1325
  }
1020
1326
  function encryptPwd(password, materialPath) {
@@ -1029,9 +1335,9 @@ function decryptPwd(encryptedHex, materialPath) {
1029
1335
  }
1030
1336
 
1031
1337
  // src/sign/generateSigningConfigs.ts
1032
- var fs11 = __toESM(require("fs"), 1);
1033
- var path10 = __toESM(require("path"), 1);
1034
- var import_node_child_process2 = require("child_process");
1338
+ var fs12 = __toESM(require("fs"), 1);
1339
+ var path13 = __toESM(require("path"), 1);
1340
+ var import_node_child_process3 = require("child_process");
1035
1341
  var import_json52 = __toESM(require("json5"), 1);
1036
1342
 
1037
1343
  // src/sign/applicationCert.ts
@@ -1100,17 +1406,17 @@ var SIGNING_KIND_CONFIG = {
1100
1406
  };
1101
1407
  function copyFilesToProject(projectDir, paths, kind, logger, applicationCertPath) {
1102
1408
  logger.info("[sign] Copying signing material into project...");
1103
- const signaturesDir = path10.join(projectDir, "signatures");
1104
- fs11.mkdirSync(signaturesDir, { recursive: true });
1105
- fs11.copyFileSync(paths.keystore, path10.join(signaturesDir, "OpenHarmony.p12"));
1106
- fs11.copyFileSync(paths.profileCert, path10.join(signaturesDir, "OpenHarmonyProfileRelease.pem"));
1107
- fs11.copyFileSync(paths.unsignedProfileTemplate, path10.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json"));
1409
+ const signaturesDir = path13.join(projectDir, "signatures");
1410
+ fs12.mkdirSync(signaturesDir, { recursive: true });
1411
+ fs12.copyFileSync(paths.keystore, path13.join(signaturesDir, "OpenHarmony.p12"));
1412
+ fs12.copyFileSync(paths.profileCert, path13.join(signaturesDir, "OpenHarmonyProfileRelease.pem"));
1413
+ fs12.copyFileSync(paths.unsignedProfileTemplate, path13.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json"));
1108
1414
  if (kind === "application-release") {
1109
- const dest = path10.join(signaturesDir, "OpenHarmonyApplication.cer");
1415
+ const dest = path13.join(signaturesDir, "OpenHarmonyApplication.cer");
1110
1416
  if (applicationCertPath) {
1111
- fs11.copyFileSync(applicationCertPath, dest);
1417
+ fs12.copyFileSync(applicationCertPath, dest);
1112
1418
  } else {
1113
- fs11.writeFileSync(dest, OPEN_HARMONY_APPLICATION_CERT);
1419
+ fs12.writeFileSync(dest, OPEN_HARMONY_APPLICATION_CERT);
1114
1420
  }
1115
1421
  }
1116
1422
  }
@@ -1119,7 +1425,7 @@ function resolveAppFeature(apl, override) {
1119
1425
  return apl === "normal" ? "hos_normal_app" : "hos_system_app";
1120
1426
  }
1121
1427
  function extractLeafCertificate(chainPath) {
1122
- const certContent = fs11.readFileSync(chainPath, "utf-8");
1428
+ const certContent = fs12.readFileSync(chainPath, "utf-8");
1123
1429
  const parts = certContent.split("-----END CERTIFICATE-----");
1124
1430
  if (parts.length < 3) {
1125
1431
  throw new OniroError(`${chainPath} does not contain enough certificates.`);
@@ -1129,20 +1435,20 @@ function extractLeafCertificate(chainPath) {
1129
1435
  function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}) {
1130
1436
  const kind = options.kind ?? pickSigningKind(apl);
1131
1437
  logger.info(`[sign] Modifying profile template (apl=${apl}, app-feature=${appFeature}, kind=${kind})...`);
1132
- const appJsonPath = path10.join(projectDir, "AppScope/app.json5");
1133
- const profileTemplatePath = path10.join(projectDir, "signatures/UnsgnedReleasedProfileTemplate.json");
1134
- if (!fs11.existsSync(appJsonPath)) {
1438
+ const appJsonPath = path13.join(projectDir, "AppScope/app.json5");
1439
+ const profileTemplatePath = path13.join(projectDir, "signatures/UnsgnedReleasedProfileTemplate.json");
1440
+ if (!fs12.existsSync(appJsonPath)) {
1135
1441
  throw new OniroError(`${appJsonPath} does not exist.`);
1136
1442
  }
1137
1443
  let appJson;
1138
1444
  try {
1139
- appJson = import_json52.default.parse(fs11.readFileSync(appJsonPath, "utf-8"));
1445
+ appJson = import_json52.default.parse(fs12.readFileSync(appJsonPath, "utf-8"));
1140
1446
  } catch (e) {
1141
1447
  throw new OniroError(`Error parsing ${appJsonPath}: ${e.message}`, e);
1142
1448
  }
1143
1449
  let profileTemplate;
1144
1450
  try {
1145
- profileTemplate = JSON.parse(fs11.readFileSync(profileTemplatePath, "utf-8"));
1451
+ profileTemplate = JSON.parse(fs12.readFileSync(profileTemplatePath, "utf-8"));
1146
1452
  } catch (e) {
1147
1453
  throw new OniroError(`Error parsing ${profileTemplatePath}: ${e.message}`, e);
1148
1454
  }
@@ -1155,7 +1461,7 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
1155
1461
  profileTemplate["bundle-info"]["bundle-name"] = appJson.app.bundleName;
1156
1462
  profileTemplate["bundle-info"]["apl"] = apl;
1157
1463
  profileTemplate["bundle-info"]["app-feature"] = appFeature;
1158
- const distCertChainPath = path10.join(
1464
+ const distCertChainPath = path13.join(
1159
1465
  projectDir,
1160
1466
  "signatures",
1161
1467
  SIGNING_KIND_CONFIG[kind].certBasename
@@ -1165,13 +1471,13 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
1165
1471
  profileTemplate.acls = profileTemplate.acls ?? {};
1166
1472
  profileTemplate.acls["allowed-acls"] = options.acls;
1167
1473
  }
1168
- fs11.writeFileSync(profileTemplatePath, JSON.stringify(profileTemplate, null, 2));
1474
+ fs12.writeFileSync(profileTemplatePath, JSON.stringify(profileTemplate, null, 2));
1169
1475
  }
1170
1476
  function generateP7bFile(projectDir, paths, logger, passwords) {
1171
1477
  logger.info("[sign] Generating P7b profile via hap-sign-tool...");
1172
- const signaturesDir = path10.join(projectDir, "signatures");
1173
- const profileTemplatePath = path10.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json");
1174
- const outputProfilePath = path10.join(signaturesDir, "app1-profile.p7b");
1478
+ const signaturesDir = path13.join(projectDir, "signatures");
1479
+ const profileTemplatePath = path13.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json");
1480
+ const outputProfilePath = path13.join(signaturesDir, "app1-profile.p7b");
1175
1481
  const args = [
1176
1482
  "-jar",
1177
1483
  paths.signTool,
@@ -1196,7 +1502,7 @@ function generateP7bFile(projectDir, paths, logger, passwords) {
1196
1502
  passwords.store
1197
1503
  ];
1198
1504
  try {
1199
- (0, import_node_child_process2.execFileSync)("java", args, { stdio: "inherit" });
1505
+ (0, import_node_child_process3.execFileSync)("java", args, { stdio: "inherit" });
1200
1506
  } catch (e) {
1201
1507
  throw new OniroError(
1202
1508
  `hap-sign-tool failed. Ensure a JDK (with keytool/java) is on PATH. Underlying error: ${e.message}`,
@@ -1205,11 +1511,11 @@ function generateP7bFile(projectDir, paths, logger, passwords) {
1205
1511
  }
1206
1512
  }
1207
1513
  function detectSigningConfigNames(projectDir) {
1208
- const buildProfilePath = path10.join(projectDir, "build-profile.json5");
1209
- if (!fs11.existsSync(buildProfilePath)) return ["default"];
1514
+ const buildProfilePath = path13.join(projectDir, "build-profile.json5");
1515
+ if (!fs12.existsSync(buildProfilePath)) return ["default"];
1210
1516
  let parsed;
1211
1517
  try {
1212
- parsed = import_json52.default.parse(fs11.readFileSync(buildProfilePath, "utf-8"));
1518
+ parsed = import_json52.default.parse(fs12.readFileSync(buildProfilePath, "utf-8"));
1213
1519
  } catch {
1214
1520
  return ["default"];
1215
1521
  }
@@ -1226,14 +1532,14 @@ function detectSigningConfigNames(projectDir) {
1226
1532
  }
1227
1533
  function updateBuildProfile(projectDir, kind, logger, passwords) {
1228
1534
  logger.info("[sign] Writing signing configs into build-profile.json5...");
1229
- const materialDir = path10.join(projectDir, "signatures", "material");
1230
- const buildProfilePath = path10.join(projectDir, "build-profile.json5");
1535
+ const materialDir = path13.join(projectDir, "signatures", "material");
1536
+ const buildProfilePath = path13.join(projectDir, "build-profile.json5");
1231
1537
  const encryptedStorePassword = encryptPwd(passwords.store, materialDir);
1232
1538
  const encryptedKeyPassword = encryptPwd(passwords.key, materialDir);
1233
1539
  let buildProfile = { app: {} };
1234
- if (fs11.existsSync(buildProfilePath)) {
1540
+ if (fs12.existsSync(buildProfilePath)) {
1235
1541
  try {
1236
- buildProfile = import_json52.default.parse(fs11.readFileSync(buildProfilePath, "utf-8"));
1542
+ buildProfile = import_json52.default.parse(fs12.readFileSync(buildProfilePath, "utf-8"));
1237
1543
  } catch (e) {
1238
1544
  throw new OniroError(`Error parsing ${buildProfilePath}: ${e.message}`, e);
1239
1545
  }
@@ -1254,13 +1560,13 @@ function updateBuildProfile(projectDir, kind, logger, passwords) {
1254
1560
  storeFile: "./signatures/OpenHarmony.p12"
1255
1561
  }
1256
1562
  }));
1257
- fs11.writeFileSync(buildProfilePath, JSON.stringify(buildProfile, null, 2));
1563
+ fs12.writeFileSync(buildProfilePath, JSON.stringify(buildProfile, null, 2));
1258
1564
  }
1259
1565
  function prepareMaterialDirectory(projectDir, logger) {
1260
1566
  logger.info("[sign] Generating fresh signing material...");
1261
- const materialDir = path10.join(projectDir, "signatures", "material");
1262
- if (fs11.existsSync(materialDir)) {
1263
- fs11.rmSync(materialDir, { recursive: true, force: true });
1567
+ const materialDir = path13.join(projectDir, "signatures", "material");
1568
+ if (fs12.existsSync(materialDir)) {
1569
+ fs12.rmSync(materialDir, { recursive: true, force: true });
1264
1570
  }
1265
1571
  createMaterial(materialDir);
1266
1572
  }
@@ -1283,15 +1589,15 @@ function generateSigningConfigs(options) {
1283
1589
  "Could not detect project SDK version (compileSdkVersion missing in build-profile.json5)."
1284
1590
  );
1285
1591
  }
1286
- const sdkPath = path10.join(sdkHome, String(sdkVersion));
1287
- if (!fs11.existsSync(sdkPath)) {
1592
+ const sdkPath = path13.join(sdkHome, String(sdkVersion));
1593
+ if (!fs12.existsSync(sdkPath)) {
1288
1594
  throw new OniroError(`SDK path does not exist: ${sdkPath}`);
1289
1595
  }
1290
1596
  const paths = {
1291
- signTool: path10.join(sdkPath, "toolchains/lib/hap-sign-tool.jar"),
1292
- keystore: path10.join(sdkPath, "toolchains/lib/OpenHarmony.p12"),
1293
- profileCert: path10.join(sdkPath, "toolchains/lib/OpenHarmonyProfileRelease.pem"),
1294
- unsignedProfileTemplate: path10.join(sdkPath, "toolchains/lib/UnsgnedReleasedProfileTemplate.json")
1597
+ signTool: path13.join(sdkPath, "toolchains/lib/hap-sign-tool.jar"),
1598
+ keystore: path13.join(sdkPath, "toolchains/lib/OpenHarmony.p12"),
1599
+ profileCert: path13.join(sdkPath, "toolchains/lib/OpenHarmonyProfileRelease.pem"),
1600
+ unsignedProfileTemplate: path13.join(sdkPath, "toolchains/lib/UnsgnedReleasedProfileTemplate.json")
1295
1601
  };
1296
1602
  const kind = pickSigningKind(apl);
1297
1603
  const passwords = options.passwords ?? DEFAULT_PASSWORDS;
@@ -1305,60 +1611,81 @@ function generateSigningConfigs(options) {
1305
1611
  }
1306
1612
 
1307
1613
  // src/emulator/install.ts
1308
- var fs12 = __toESM(require("fs"), 1);
1309
- var os7 = __toESM(require("os"), 1);
1310
- var path11 = __toESM(require("path"), 1);
1614
+ var fs13 = __toESM(require("fs"), 1);
1615
+ var path14 = __toESM(require("path"), 1);
1311
1616
  async function installEmulator(opts) {
1312
1617
  const { config, progress, abortSignal } = opts;
1313
1618
  const logger = opts.logger ?? noopLogger;
1314
1619
  const url = config.get("emulatorUrl", defaultPaths.emulatorUrl);
1315
1620
  const emulatorDir = getEmulatorDir(config);
1316
- const tmpDir = fs12.mkdtempSync(path11.join(os7.tmpdir(), "oniro-emulator-"));
1317
- const tmpZip = path11.join(tmpDir, "oniro_emulator.zip");
1621
+ const what = "the emulator install";
1622
+ const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
1623
+ config,
1624
+ override: opts.tmpDir,
1625
+ installRoot: path14.dirname(emulatorDir),
1626
+ prefix: "oniro-emulator-",
1627
+ logger
1628
+ });
1629
+ const tmpZip = path14.join(tmpDir, "oniro_emulator.zip");
1318
1630
  try {
1319
- fs12.mkdirSync(emulatorDir, { recursive: true });
1631
+ fs13.mkdirSync(emulatorDir, { recursive: true });
1320
1632
  progress?.report({ message: "Downloading emulator...", increment: 0 });
1321
- await downloadFile({ url, dest: tmpZip, progress, abortSignal, start: 0, range: 50 });
1633
+ await downloadFile({ url, dest: tmpZip, progress, abortSignal, start: 0, range: 50, what, tmpRoot });
1322
1634
  progress?.report({ message: "Extracting emulator...", increment: 0 });
1323
1635
  await extractZipWithProgress({ zipPath: tmpZip, dest: emulatorDir, progress, start: 50, range: 45, logger });
1324
- const runSh = path11.join(emulatorDir, "images", "run.sh");
1325
- if (fs12.existsSync(runSh)) {
1326
- fs12.chmodSync(runSh, 493);
1636
+ const runSh = path14.join(emulatorDir, "images", "run.sh");
1637
+ if (fs13.existsSync(runSh)) {
1638
+ fs13.chmodSync(runSh, 493);
1327
1639
  }
1328
1640
  progress?.report({ message: "Finalizing installation...", increment: 5 });
1641
+ } catch (err) {
1642
+ throw toSpaceError(err, tmpRoot, what);
1329
1643
  } finally {
1330
- fs12.rmSync(tmpDir, { recursive: true, force: true });
1644
+ removeTempWorkDir(tmpDir, tmpRoot);
1331
1645
  }
1332
1646
  }
1333
1647
  function isEmulatorInstalled(config) {
1334
- const imagesDir = path11.join(getEmulatorDir(config), "images");
1335
- return fs12.existsSync(path11.join(imagesDir, "run.sh")) || fs12.existsSync(path11.join(imagesDir, "run.bat"));
1648
+ const imagesDir = path14.join(getEmulatorDir(config), "images");
1649
+ return fs13.existsSync(path14.join(imagesDir, "run.sh")) || fs13.existsSync(path14.join(imagesDir, "run.bat"));
1336
1650
  }
1337
1651
  function removeEmulator(config) {
1338
1652
  const emulatorDir = getEmulatorDir(config);
1339
- if (fs12.existsSync(emulatorDir)) {
1340
- fs12.rmSync(emulatorDir, { recursive: true, force: true });
1653
+ if (fs13.existsSync(emulatorDir)) {
1654
+ fs13.rmSync(emulatorDir, { recursive: true, force: true });
1341
1655
  }
1342
1656
  }
1343
1657
 
1344
1658
  // src/emulator/lifecycle.ts
1345
- var fs13 = __toESM(require("fs"), 1);
1346
- var os8 = __toESM(require("os"), 1);
1347
- var path12 = __toESM(require("path"), 1);
1659
+ var fs15 = __toESM(require("fs"), 1);
1660
+ var os7 = __toESM(require("os"), 1);
1661
+ var path15 = __toESM(require("path"), 1);
1348
1662
  var import_node_child_process4 = require("child_process");
1349
1663
 
1350
1664
  // src/hdc/exec.ts
1351
- var import_node_child_process3 = require("child_process");
1665
+ var fs14 = __toESM(require("fs"), 1);
1666
+ function errorMessage(err) {
1667
+ return err instanceof Error ? err.message : String(err);
1668
+ }
1352
1669
  function runProcess(opts) {
1353
1670
  const { command, args, cwd, env, onOutput } = opts;
1354
1671
  const timeoutMs = opts.timeoutMs ?? 6e4;
1355
1672
  const { abortSignal } = opts;
1356
- return new Promise((resolve2, reject) => {
1673
+ return new Promise((resolve4, reject) => {
1357
1674
  if (abortSignal?.aborted) {
1358
1675
  reject(new CancelledError(`Command aborted before start: ${command}`));
1359
1676
  return;
1360
1677
  }
1361
- const child = (0, import_node_child_process3.spawn)(command, [...args], { cwd, env, shell: false });
1678
+ if (needsCmdWrapper(command) && !fs14.existsSync(command)) {
1679
+ reject(new OniroError(`Failed to spawn ${command}: ENOENT (no such file)`));
1680
+ return;
1681
+ }
1682
+ let child;
1683
+ try {
1684
+ child = spawnCompat(command, args, { cwd, env });
1685
+ } catch (err) {
1686
+ reject(new OniroError(`Failed to spawn ${command}: ${errorMessage(err)}`, err));
1687
+ return;
1688
+ }
1362
1689
  let stdout = "";
1363
1690
  let stderr = "";
1364
1691
  let settled = false;
@@ -1371,26 +1698,20 @@ function runProcess(opts) {
1371
1698
  if (settled) return;
1372
1699
  settled = true;
1373
1700
  cleanup();
1374
- try {
1375
- child.kill("SIGKILL");
1376
- } catch {
1377
- }
1701
+ killProcessTree(child);
1378
1702
  reject(new CancelledError(`Command aborted: ${command} ${args.join(" ")}`));
1379
1703
  };
1380
1704
  const timer = setTimeout(() => {
1381
1705
  timedOut = true;
1382
- try {
1383
- child.kill("SIGKILL");
1384
- } catch {
1385
- }
1706
+ killProcessTree(child);
1386
1707
  }, timeoutMs);
1387
1708
  abortSignal?.addEventListener("abort", onAbort, { once: true });
1388
- child.stdout.on("data", (d) => {
1709
+ child.stdout?.on("data", (d) => {
1389
1710
  const s = d.toString();
1390
1711
  stdout += s;
1391
1712
  onOutput?.(s, "stdout");
1392
1713
  });
1393
- child.stderr.on("data", (d) => {
1714
+ child.stderr?.on("data", (d) => {
1394
1715
  const s = d.toString();
1395
1716
  stderr += s;
1396
1717
  onOutput?.(s, "stderr");
@@ -1414,7 +1735,7 @@ ${stderr.trim()}` : "")
1414
1735
  );
1415
1736
  return;
1416
1737
  }
1417
- resolve2({ code: code ?? -1, stdout, stderr });
1738
+ resolve4({ code: code ?? -1, stdout, stderr });
1418
1739
  });
1419
1740
  });
1420
1741
  }
@@ -1440,9 +1761,29 @@ function ensureOk(result, command) {
1440
1761
  }
1441
1762
  return result;
1442
1763
  }
1764
+ var REMOTE_RC_RE = /__ONIRO_RC=(-?\d+)__/g;
1765
+ function parseRemoteExit(stdout) {
1766
+ let code = null;
1767
+ for (const m of stdout.matchAll(REMOTE_RC_RE)) code = Number(m[1]);
1768
+ if (code === null) return null;
1769
+ return { code, stdout: stdout.replace(REMOTE_RC_RE, "").replace(/[ \t\r\n]+$/, "") };
1770
+ }
1771
+ async function shellChecked(opts) {
1772
+ const { command, ...rest } = opts;
1773
+ const res = await hdcExec({ ...rest, args: ["shell", `${command}; echo "__ONIRO_RC=$?__"`] });
1774
+ const parsed = parseRemoteExit(res.stdout);
1775
+ if (!parsed) return res;
1776
+ return { code: parsed.code, stdout: parsed.stdout, stderr: res.stderr };
1777
+ }
1778
+ function ensureRemoteOk(result, command) {
1779
+ if (result.code !== 0) {
1780
+ throw new CommandFailedError(command, result.code, result.stderr.trim() || result.stdout.trim());
1781
+ }
1782
+ return result;
1783
+ }
1443
1784
 
1444
1785
  // src/emulator/lifecycle.ts
1445
- var PID_FILE = path12.join(os8.tmpdir(), "oniro_emulator.pid");
1786
+ var PID_FILE = path15.join(os7.tmpdir(), "oniro_emulator.pid");
1446
1787
  async function attemptHdcConnection(config, address = "127.0.0.1:55555", logger = noopLogger) {
1447
1788
  try {
1448
1789
  await hdcExec({ config, args: ["start", "-r"], logger });
@@ -1455,24 +1796,24 @@ async function attemptHdcConnection(config, address = "127.0.0.1:55555", logger
1455
1796
  }
1456
1797
  }
1457
1798
  function resolveLauncher(imagesPath, headless, connect) {
1458
- const runSh = path12.join(imagesPath, "run.sh");
1459
- const runBat = path12.join(imagesPath, "run.bat");
1799
+ const runSh = path15.join(imagesPath, "run.sh");
1800
+ const runBat = path15.join(imagesPath, "run.bat");
1460
1801
  const extra = [];
1461
1802
  if (headless) extra.push("--headless");
1462
1803
  if (connect) extra.push("--connect", connect);
1463
- if (os8.platform() === "win32") {
1464
- if (fs13.existsSync(runBat)) {
1804
+ if (os7.platform() === "win32") {
1805
+ if (fs15.existsSync(runBat)) {
1465
1806
  return { command: "cmd.exe", args: ["/c", runBat, ...extra], cwd: imagesPath };
1466
1807
  }
1467
- if (fs13.existsSync(runSh)) {
1808
+ if (fs15.existsSync(runSh)) {
1468
1809
  return { command: "bash", args: [runSh, ...extra], cwd: imagesPath };
1469
1810
  }
1470
1811
  throw new OniroError(`No emulator launcher (run.bat or run.sh) found in ${imagesPath}.`);
1471
1812
  }
1472
- if (fs13.existsSync(runSh)) {
1813
+ if (fs15.existsSync(runSh)) {
1473
1814
  return { command: "bash", args: [runSh, ...extra], cwd: imagesPath };
1474
1815
  }
1475
- if (fs13.existsSync(runBat)) {
1816
+ if (fs15.existsSync(runBat)) {
1476
1817
  return { command: "bash", args: [runBat, ...extra], cwd: imagesPath };
1477
1818
  }
1478
1819
  throw new OniroError(`No emulator launcher (run.sh or run.bat) found in ${imagesPath}.`);
@@ -1480,9 +1821,9 @@ function resolveLauncher(imagesPath, headless, connect) {
1480
1821
  async function startEmulator(opts) {
1481
1822
  const { config } = opts;
1482
1823
  const logger = opts.logger ?? noopLogger;
1483
- if (os8.platform() !== "win32" && fs13.existsSync(PID_FILE)) {
1824
+ if (os7.platform() !== "win32" && fs15.existsSync(PID_FILE)) {
1484
1825
  try {
1485
- const pid = Number(fs13.readFileSync(PID_FILE, "utf8").trim());
1826
+ const pid = Number(fs15.readFileSync(PID_FILE, "utf8").trim());
1486
1827
  if (Number.isFinite(pid) && pid > 0) {
1487
1828
  try {
1488
1829
  process.kill(pid, 0);
@@ -1498,13 +1839,13 @@ async function startEmulator(opts) {
1498
1839
  logger.warn(`Could not read PID file: ${err.message}`);
1499
1840
  }
1500
1841
  }
1501
- const imagesPath = path12.join(getEmulatorDir(config), "images");
1502
- if (!fs13.existsSync(imagesPath)) {
1842
+ const imagesPath = path15.join(getEmulatorDir(config), "images");
1843
+ if (!fs15.existsSync(imagesPath)) {
1503
1844
  throw new OniroError(`Emulator images directory not found at ${imagesPath}. Run \`oniro-app emulator install\` first.`);
1504
1845
  }
1505
1846
  const launcher = resolveLauncher(imagesPath, opts.headless === true, opts.connect);
1506
- const logPath = opts.logFile ?? (os8.platform() === "win32" ? "NUL" : "/dev/null");
1507
- const logFd = fs13.openSync(logPath, "a");
1847
+ const logPath = opts.logFile ?? (os7.platform() === "win32" ? "NUL" : "/dev/null");
1848
+ const logFd = fs15.openSync(logPath, "a");
1508
1849
  let child;
1509
1850
  try {
1510
1851
  child = (0, import_node_child_process4.spawn)(launcher.command, [...launcher.args], {
@@ -1514,19 +1855,19 @@ async function startEmulator(opts) {
1514
1855
  windowsHide: true
1515
1856
  });
1516
1857
  } finally {
1517
- fs13.closeSync(logFd);
1858
+ fs15.closeSync(logFd);
1518
1859
  }
1519
1860
  if (!child.pid) {
1520
1861
  throw new OniroError(`Failed to spawn launcher (${launcher.command} ${launcher.args.join(" ")}).`);
1521
1862
  }
1522
- fs13.writeFileSync(PID_FILE, String(child.pid));
1863
+ fs15.writeFileSync(PID_FILE, String(child.pid));
1523
1864
  child.unref();
1524
1865
  logger.info(`Emulator launched (PID ${child.pid}). Logs: ${logPath}`);
1525
- const earlyExit = new Promise((resolve2) => {
1526
- child.once("exit", (code) => resolve2(code));
1527
- child.once("error", () => resolve2(-1));
1866
+ const earlyExit = new Promise((resolve4) => {
1867
+ child.once("exit", (code) => resolve4(code));
1868
+ child.once("error", () => resolve4(-1));
1528
1869
  });
1529
- const liveness = new Promise((resolve2) => setTimeout(() => resolve2("alive"), 2e3));
1870
+ const liveness = new Promise((resolve4) => setTimeout(() => resolve4("alive"), 2e3));
1530
1871
  const outcome = await Promise.race([earlyExit, liveness]);
1531
1872
  if (outcome !== "alive") {
1532
1873
  const tail = readTail(logPath, 4e3);
@@ -1566,24 +1907,24 @@ ${tail}` : ""}`);
1566
1907
  }
1567
1908
  function readTail(filePath, bytes) {
1568
1909
  try {
1569
- const stat = fs13.statSync(filePath);
1910
+ const stat = fs15.statSync(filePath);
1570
1911
  const start = Math.max(0, stat.size - bytes);
1571
- const fd = fs13.openSync(filePath, "r");
1912
+ const fd = fs15.openSync(filePath, "r");
1572
1913
  try {
1573
1914
  const buf = Buffer.alloc(stat.size - start);
1574
- fs13.readSync(fd, buf, 0, buf.length, start);
1915
+ fs15.readSync(fd, buf, 0, buf.length, start);
1575
1916
  return buf.toString("utf8");
1576
1917
  } finally {
1577
- fs13.closeSync(fd);
1918
+ fs15.closeSync(fd);
1578
1919
  }
1579
1920
  } catch {
1580
1921
  return "";
1581
1922
  }
1582
1923
  }
1583
1924
  async function stopEmulator(logger = noopLogger) {
1584
- if (fs13.existsSync(PID_FILE)) {
1925
+ if (fs15.existsSync(PID_FILE)) {
1585
1926
  try {
1586
- const pid = Number(fs13.readFileSync(PID_FILE, "utf8").trim());
1927
+ const pid = Number(fs15.readFileSync(PID_FILE, "utf8").trim());
1587
1928
  if (Number.isFinite(pid) && pid > 0) {
1588
1929
  try {
1589
1930
  process.kill(pid, "SIGTERM");
@@ -1596,13 +1937,13 @@ async function stopEmulator(logger = noopLogger) {
1596
1937
  logger.warn(`Could not read PID file: ${err.message}`);
1597
1938
  }
1598
1939
  }
1599
- const [killCmd, ...killArgs] = os8.platform() === "win32" ? ["taskkill", "/IM", "qemu-system-x86_64.exe", "/F"] : ["pkill", "-f", "qemu-system-x86_64"];
1940
+ const [killCmd, ...killArgs] = os7.platform() === "win32" ? ["taskkill", "/IM", "qemu-system-x86_64.exe", "/F"] : ["pkill", "-f", "qemu-system-x86_64"];
1600
1941
  try {
1601
1942
  await runProcess({ command: killCmd, args: killArgs, logger });
1602
1943
  } catch (err) {
1603
1944
  logger.warn(`[emulator] could not run ${killCmd}: ${err.message}`);
1604
1945
  }
1605
- fs13.rm(PID_FILE, { force: true }, (err) => {
1946
+ fs15.rm(PID_FILE, { force: true }, (err) => {
1606
1947
  if (err) logger.warn(`Could not remove PID file: ${err.message}`);
1607
1948
  });
1608
1949
  }
@@ -1725,7 +2066,7 @@ async function getDisplaySize(config, opts = {}) {
1725
2066
 
1726
2067
  // src/hdc/wait.ts
1727
2068
  function delay(ms, signal) {
1728
- return new Promise((resolve2, reject) => {
2069
+ return new Promise((resolve4, reject) => {
1729
2070
  if (signal?.aborted) {
1730
2071
  reject(new CancelledError("Wait cancelled."));
1731
2072
  return;
@@ -1740,7 +2081,7 @@ function delay(ms, signal) {
1740
2081
  };
1741
2082
  const timer = setTimeout(() => {
1742
2083
  cleanup();
1743
- resolve2();
2084
+ resolve4();
1744
2085
  }, ms);
1745
2086
  signal?.addEventListener("abort", onAbort, { once: true });
1746
2087
  });
@@ -1769,21 +2110,20 @@ async function waitForCondition(opts) {
1769
2110
  }
1770
2111
 
1771
2112
  // src/hdc/app.ts
1772
- var fs15 = __toESM(require("fs"), 1);
1773
- var path14 = __toESM(require("path"), 1);
1774
- var import_node_child_process5 = require("child_process");
2113
+ var fs17 = __toESM(require("fs"), 1);
2114
+ var path17 = __toESM(require("path"), 1);
1775
2115
 
1776
2116
  // src/hdc/project.ts
1777
- var fs14 = __toESM(require("fs"), 1);
1778
- var path13 = __toESM(require("path"), 1);
2117
+ var fs16 = __toESM(require("fs"), 1);
2118
+ var path16 = __toESM(require("path"), 1);
1779
2119
  var import_json53 = __toESM(require("json5"), 1);
1780
2120
  function readJson5(filePath) {
1781
- const content = fs14.readFileSync(filePath, "utf-8");
2121
+ const content = fs16.readFileSync(filePath, "utf-8");
1782
2122
  return import_json53.default.parse(content);
1783
2123
  }
1784
2124
  function getBundleName(projectDir) {
1785
- const appJsonPath = path13.join(projectDir, "AppScope", "app.json5");
1786
- if (!fs14.existsSync(appJsonPath)) {
2125
+ const appJsonPath = path16.join(projectDir, "AppScope", "app.json5");
2126
+ if (!fs16.existsSync(appJsonPath)) {
1787
2127
  throw new OniroError(`Could not find app.json5 at ${appJsonPath}`);
1788
2128
  }
1789
2129
  const appJson = readJson5(appJsonPath);
@@ -1793,8 +2133,8 @@ function getBundleName(projectDir) {
1793
2133
  return appJson.app.bundleName;
1794
2134
  }
1795
2135
  function getMainAbility(projectDir, moduleName = "entry", abilityName) {
1796
- const moduleJsonPath = path13.join(projectDir, moduleName, "src", "main", "module.json5");
1797
- if (!fs14.existsSync(moduleJsonPath)) {
2136
+ const moduleJsonPath = path16.join(projectDir, moduleName, "src", "main", "module.json5");
2137
+ if (!fs16.existsSync(moduleJsonPath)) {
1798
2138
  throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
1799
2139
  }
1800
2140
  const moduleJson = readJson5(moduleJsonPath);
@@ -1817,8 +2157,8 @@ function getMainAbility(projectDir, moduleName = "entry", abilityName) {
1817
2157
  async function installApp(opts) {
1818
2158
  const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
1819
2159
  const relativeHapPath = opts.hapPath ?? opts.config.get("hapPath", defaultPaths.hapPath);
1820
- const hapPath = path14.isAbsolute(relativeHapPath) ? relativeHapPath : path14.join(opts.projectDir, relativeHapPath);
1821
- if (!fs15.existsSync(hapPath)) {
2160
+ const hapPath = path17.isAbsolute(relativeHapPath) ? relativeHapPath : path17.join(opts.projectDir, relativeHapPath);
2161
+ if (!fs17.existsSync(hapPath)) {
1822
2162
  throw new OniroError(`HAP file not found at: ${hapPath}. Build and sign the app first.`);
1823
2163
  }
1824
2164
  const result = await hdcExec({ config: opts.config, args: ["install", hapPath], timeoutMs: 3e5 });
@@ -1835,13 +2175,59 @@ async function installApp(opts) {
1835
2175
  function detectAaStartFailure(output) {
1836
2176
  return /failed to start ability|Error Code:\s*\d|Error Message:/i.test(output) ? output.trim() : null;
1837
2177
  }
2178
+ function parseMainAbilityFromBmDump(stdout) {
2179
+ const start = stdout.indexOf("{");
2180
+ if (start < 0) return null;
2181
+ let info;
2182
+ try {
2183
+ info = JSON.parse(stdout.slice(start));
2184
+ } catch {
2185
+ return null;
2186
+ }
2187
+ const mods = Array.isArray(info?.hapModuleInfos) ? info.hapModuleInfos : [];
2188
+ const abilityOf = (m) => m?.mainElementName || m?.mainAbility || void 0;
2189
+ const isEntry = (m) => m?.moduleType === 1 || m?.moduleType === "1" || m?.moduleType === "entry";
2190
+ const entry = mods.find((m) => isEntry(m) && abilityOf(m));
2191
+ const any = mods.find((m) => abilityOf(m));
2192
+ return entry && abilityOf(entry) || any && abilityOf(any) || null;
2193
+ }
2194
+ async function resolveInstalledMainAbility(opts) {
2195
+ const res = await shell({
2196
+ config: opts.config,
2197
+ command: `bm dump -n ${opts.bundle}`,
2198
+ deviceSerial: opts.deviceSerial,
2199
+ timeoutMs: 15e3,
2200
+ logger: opts.logger
2201
+ });
2202
+ const ability = parseMainAbilityFromBmDump(res.stdout);
2203
+ if (!ability) {
2204
+ throw new OniroError(
2205
+ `Could not determine the main ability for installed bundle ${opts.bundle} (is it installed?). Pass an explicit ability instead.`
2206
+ );
2207
+ }
2208
+ return ability;
2209
+ }
1838
2210
  async function launchApp(opts) {
1839
2211
  const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
1840
- const bundleName = getBundleName(opts.projectDir);
1841
- const mainAbility = getMainAbility(opts.projectDir, opts.moduleName, opts.abilityName);
2212
+ let bundleName;
2213
+ let mainAbility;
2214
+ if (opts.bundleName) {
2215
+ bundleName = opts.bundleName;
2216
+ mainAbility = opts.abilityName ?? await resolveInstalledMainAbility({
2217
+ config: opts.config,
2218
+ bundle: bundleName,
2219
+ deviceSerial: opts.deviceSerial,
2220
+ logger: opts.logger
2221
+ });
2222
+ } else {
2223
+ if (!opts.projectDir) throw new OniroError("launchApp requires either bundleName or projectDir.");
2224
+ bundleName = getBundleName(opts.projectDir);
2225
+ mainAbility = getMainAbility(opts.projectDir, opts.moduleName, opts.abilityName);
2226
+ }
1842
2227
  const result = await hdcExec({
1843
2228
  config: opts.config,
1844
- args: ["shell", "aa", "start", "-a", mainAbility, "-b", bundleName]
2229
+ args: ["shell", "aa", "start", "-a", mainAbility, "-b", bundleName],
2230
+ deviceSerial: opts.deviceSerial
1845
2231
  });
1846
2232
  if (result.stdout.trim()) logger.info(result.stdout.trim());
1847
2233
  if (result.stderr.trim()) logger.warn(result.stderr.trim());
@@ -1856,11 +2242,17 @@ function listRunningProcesses(config, options = {}) {
1856
2242
  const logger = options.logger ?? noopLogger;
1857
2243
  const timeoutMs = options.timeoutMs ?? 1e3;
1858
2244
  const hdc = getHdcPath(config);
1859
- return new Promise((resolve2, reject) => {
1860
- const proc = (0, import_node_child_process5.spawn)(hdc, ["track-jpid"]);
2245
+ return new Promise((resolve4, reject) => {
2246
+ let proc;
2247
+ try {
2248
+ proc = spawnCompat(hdc, ["track-jpid"]);
2249
+ } catch (err) {
2250
+ reject(new OniroError(`Failed to spawn ${hdc}: ${err instanceof Error ? err.message : String(err)}`, err));
2251
+ return;
2252
+ }
1861
2253
  const processes = [];
1862
2254
  let resolved = false;
1863
- proc.stdout.on("data", (data) => {
2255
+ proc.stdout?.on("data", (data) => {
1864
2256
  for (const line of data.toString().split("\n").filter(Boolean)) {
1865
2257
  const match = line.match(/^(\d+)\s+(.+)$/);
1866
2258
  if (!match) continue;
@@ -1869,13 +2261,13 @@ function listRunningProcesses(config, options = {}) {
1869
2261
  processes.push({ pid, name });
1870
2262
  if (options.targetProcessName && name === options.targetProcessName && !resolved) {
1871
2263
  resolved = true;
1872
- proc.kill();
1873
- resolve2(pid);
2264
+ killProcessTree(proc);
2265
+ resolve4(pid);
1874
2266
  return;
1875
2267
  }
1876
2268
  }
1877
2269
  });
1878
- proc.stderr.on("data", (data) => {
2270
+ proc.stderr?.on("data", (data) => {
1879
2271
  logger.warn(`[hdc track-jpid] ${data.toString()}`);
1880
2272
  });
1881
2273
  proc.on("error", (err) => {
@@ -1887,11 +2279,11 @@ function listRunningProcesses(config, options = {}) {
1887
2279
  const timeout = setTimeout(() => {
1888
2280
  if (resolved) return;
1889
2281
  resolved = true;
1890
- proc.kill();
2282
+ killProcessTree(proc);
1891
2283
  if (options.targetProcessName) {
1892
2284
  reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
1893
2285
  } else {
1894
- resolve2(processes);
2286
+ resolve4(processes);
1895
2287
  }
1896
2288
  }, timeoutMs);
1897
2289
  proc.on("close", () => {
@@ -1901,7 +2293,7 @@ function listRunningProcesses(config, options = {}) {
1901
2293
  if (options.targetProcessName) {
1902
2294
  reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
1903
2295
  } else {
1904
- resolve2(processes);
2296
+ resolve4(processes);
1905
2297
  }
1906
2298
  });
1907
2299
  });
@@ -1921,8 +2313,17 @@ async function findRunningProcess(opts) {
1921
2313
  logger: opts.logger
1922
2314
  });
1923
2315
  const pid = res.stdout.trim().split(/\s+/).filter(Boolean)[0];
1924
- if (res.code !== 0 || !pid || !/^\d+$/.test(pid)) return null;
1925
- return { pid, name: opts.bundle };
2316
+ if (res.code === 0 && pid && /^\d+$/.test(pid)) return { pid, name: opts.bundle };
2317
+ try {
2318
+ const list = await listRunningProcesses(opts.config, { timeoutMs: 1200, logger: opts.logger });
2319
+ if (Array.isArray(list)) {
2320
+ const mine = (name) => name === opts.bundle || name.startsWith(`${opts.bundle}/`) || name.startsWith(`${opts.bundle}:`);
2321
+ const match = list.find((p) => p.name === opts.bundle) ?? list.find((p) => mine(p.name));
2322
+ if (match) return match;
2323
+ }
2324
+ } catch {
2325
+ }
2326
+ return null;
1926
2327
  }
1927
2328
  async function uninstallApp(opts) {
1928
2329
  const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
@@ -2036,12 +2437,12 @@ async function reboot(opts) {
2036
2437
  }
2037
2438
 
2038
2439
  // src/hdc/screen.ts
2039
- var fs16 = __toESM(require("fs"), 1);
2040
- var os9 = __toESM(require("os"), 1);
2041
- var path15 = __toESM(require("path"), 1);
2440
+ var fs18 = __toESM(require("fs"), 1);
2441
+ var os8 = __toESM(require("os"), 1);
2442
+ var path18 = __toESM(require("path"), 1);
2042
2443
  var import_node_crypto = require("crypto");
2043
2444
  function tmpName(ext) {
2044
- return path15.join(os9.tmpdir(), `oniro_screen_${(0, import_node_crypto.randomBytes)(6).toString("hex")}.${ext}`);
2445
+ return path18.join(os8.tmpdir(), `oniro_screen_${(0, import_node_crypto.randomBytes)(6).toString("hex")}.${ext}`);
2045
2446
  }
2046
2447
  async function takeScreenshot(opts) {
2047
2448
  const remote = "/data/local/tmp/oniro_screenshot.jpeg";
@@ -2051,11 +2452,11 @@ async function takeScreenshot(opts) {
2051
2452
  const local = tmpName("jpeg");
2052
2453
  try {
2053
2454
  await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
2054
- const pixels = await fs16.promises.readFile(local);
2455
+ const pixels = await fs18.promises.readFile(local);
2055
2456
  const size = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial }) ?? { width: 0, height: 0 };
2056
2457
  return { pixels, width: size.width, height: size.height };
2057
2458
  } finally {
2058
- fs16.promises.unlink(local).catch(() => {
2459
+ fs18.promises.unlink(local).catch(() => {
2059
2460
  });
2060
2461
  void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
2061
2462
  });
@@ -2074,9 +2475,9 @@ async function captureBurst(opts) {
2074
2475
  const local = tmpName(`burst_${i}.jpeg`);
2075
2476
  try {
2076
2477
  await recvFile({ config: opts.config, remote: `${remoteDir}/f${i}.jpeg`, local, deviceSerial: opts.deviceSerial });
2077
- frames.push(await fs16.promises.readFile(local));
2478
+ frames.push(await fs18.promises.readFile(local));
2078
2479
  } finally {
2079
- fs16.promises.unlink(local).catch(() => {
2480
+ fs18.promises.unlink(local).catch(() => {
2080
2481
  });
2081
2482
  }
2082
2483
  }
@@ -2120,8 +2521,8 @@ function buildInputCommand(opts) {
2120
2521
  }
2121
2522
  async function sendInput(opts) {
2122
2523
  const cmd = buildInputCommand(opts);
2123
- const res = await shell({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
2124
- ensureOk(res, `hdc shell ${cmd}`);
2524
+ const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
2525
+ ensureRemoteOk(res, `hdc shell ${cmd}`);
2125
2526
  }
2126
2527
  function buildGestureCommands(waypoints) {
2127
2528
  if (waypoints.length < 2) {
@@ -2164,32 +2565,47 @@ function waypointsToRawEvents(waypoints, holdStartMs = 0, holdEndMs = 0) {
2164
2565
  events.push({ type: "up", x: last.x, y: last.y, t: last.t + holdStartMs + holdEndMs });
2165
2566
  return events;
2166
2567
  }
2568
+ var UITEST_VELOCITY_MIN = 200;
2569
+ var UITEST_VELOCITY_MAX = 4e4;
2570
+ function buildGestureUitestCommand(waypoints, opts = {}) {
2571
+ if (waypoints.length < 2) throw new OniroError("sendGesture requires at least two waypoints.");
2572
+ const a = waypoints[0];
2573
+ const b = waypoints[waypoints.length - 1];
2574
+ const dist = Math.hypot(b.x - a.x, b.y - a.y);
2575
+ const dtMs = b.t - a.t;
2576
+ const op = (opts.holdStartMs ?? 0) > 0 ? "drag" : "swipe";
2577
+ let cmd = `uitest uiInput ${op} ${a.x} ${a.y} ${b.x} ${b.y}`;
2578
+ if (dtMs > 0 && dist > 0) {
2579
+ const v = Math.round(dist / (dtMs / 1e3));
2580
+ cmd += ` ${Math.max(UITEST_VELOCITY_MIN, Math.min(UITEST_VELOCITY_MAX, v))}`;
2581
+ }
2582
+ return cmd;
2583
+ }
2167
2584
  async function sendGesture(opts) {
2168
- const wantsHold = (opts.holdStartMs ?? 0) > 0 || (opts.holdEndMs ?? 0) > 0;
2169
- if (wantsHold) {
2170
- await sendRawTouch({
2171
- config: opts.config,
2172
- events: waypointsToRawEvents(opts.waypoints, opts.holdStartMs, opts.holdEndMs),
2173
- deviceSerial: opts.deviceSerial,
2174
- logger: opts.logger
2175
- });
2176
- return;
2585
+ if ((opts.holdEndMs ?? 0) > 0) {
2586
+ opts.logger?.warn(
2587
+ "sendGesture: hold-end has no uitest equivalent and is ignored; use sendRawTouch for a trailing hold."
2588
+ );
2177
2589
  }
2178
- for (const cmd of buildGestureCommands(opts.waypoints)) {
2179
- const res = await shell({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
2180
- ensureOk(res, `hdc shell ${cmd}`);
2590
+ if (opts.waypoints.length > 2) {
2591
+ opts.logger?.debug(
2592
+ `sendGesture: ${opts.waypoints.length} waypoints collapsed to first\u2192last (uitest has no polyline path).`
2593
+ );
2181
2594
  }
2595
+ const cmd = buildGestureUitestCommand(opts.waypoints, { holdStartMs: opts.holdStartMs });
2596
+ const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
2597
+ ensureRemoteOk(res, `hdc shell ${cmd}`);
2182
2598
  }
2183
2599
  async function sendRawTouch(opts) {
2184
2600
  const cmd = buildRawTouchCommand(opts.events);
2185
- const res = await shell({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
2186
- ensureOk(res, `hdc shell ${cmd}`);
2601
+ const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
2602
+ ensureRemoteOk(res, `hdc shell ${cmd}`);
2187
2603
  }
2188
2604
 
2189
2605
  // src/hdc/dump.ts
2190
- var fs17 = __toESM(require("fs"), 1);
2191
- var os10 = __toESM(require("os"), 1);
2192
- var path16 = __toESM(require("path"), 1);
2606
+ var fs19 = __toESM(require("fs"), 1);
2607
+ var os9 = __toESM(require("os"), 1);
2608
+ var path19 = __toESM(require("path"), 1);
2193
2609
  var import_node_crypto2 = require("crypto");
2194
2610
  function parseBounds(s) {
2195
2611
  const m = /^\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]$/.exec(s ?? "");
@@ -2274,10 +2690,10 @@ async function dumpLayout(opts) {
2274
2690
  if (!m) throw new OniroError(`Could not parse dumpLayout output:
2275
2691
  ${dump.stdout}`);
2276
2692
  const remote = m[1];
2277
- const local = path16.join(os10.tmpdir(), `oniro_layout_${(0, import_node_crypto2.randomBytes)(6).toString("hex")}.json`);
2693
+ const local = path19.join(os9.tmpdir(), `oniro_layout_${(0, import_node_crypto2.randomBytes)(6).toString("hex")}.json`);
2278
2694
  try {
2279
2695
  await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
2280
- const parsed = JSON.parse(await fs17.promises.readFile(local, "utf8"));
2696
+ const parsed = JSON.parse(await fs19.promises.readFile(local, "utf8"));
2281
2697
  const display = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial });
2282
2698
  if (opts.prune === false) {
2283
2699
  return { display, tree: parsed };
@@ -2286,7 +2702,7 @@ ${dump.stdout}`);
2286
2702
  const tree = Array.isArray(prunedRaw) ? { children: prunedRaw } : prunedRaw ?? { children: [] };
2287
2703
  return { display, tree };
2288
2704
  } finally {
2289
- fs17.promises.unlink(local).catch(() => {
2705
+ fs19.promises.unlink(local).catch(() => {
2290
2706
  });
2291
2707
  void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
2292
2708
  });
@@ -2294,14 +2710,21 @@ ${dump.stdout}`);
2294
2710
  }
2295
2711
 
2296
2712
  // src/hdc/hilog.ts
2297
- var import_node_child_process6 = require("child_process");
2298
2713
  function setHilogLevel(opts) {
2299
2714
  const logger = opts.logger ?? noopLogger;
2300
2715
  const hdc = getHdcPath(opts.config);
2301
- return new Promise((resolve2, reject) => {
2302
- const child = (0, import_node_child_process6.spawn)(hdc, ["shell", "hilog", "-b", opts.level]);
2716
+ return new Promise((resolve4, reject) => {
2717
+ let child;
2718
+ try {
2719
+ child = spawnCompat(hdc, ["shell", "hilog", "-b", opts.level]);
2720
+ } catch (err) {
2721
+ const msg = err instanceof Error ? err.message : String(err);
2722
+ logger.error(`[hilog] failed to spawn hdc: ${msg}`);
2723
+ reject(err instanceof Error ? err : new Error(msg));
2724
+ return;
2725
+ }
2303
2726
  let stderr = "";
2304
- child.stderr.on("data", (chunk) => {
2727
+ child.stderr?.on("data", (chunk) => {
2305
2728
  stderr += chunk.toString();
2306
2729
  });
2307
2730
  child.once("error", (err) => {
@@ -2310,7 +2733,7 @@ function setHilogLevel(opts) {
2310
2733
  });
2311
2734
  child.once("close", (code) => {
2312
2735
  if (code === 0) {
2313
- resolve2();
2736
+ resolve4();
2314
2737
  } else {
2315
2738
  const msg = stderr.trim() || `hdc shell hilog -b ${opts.level} exited with code ${code}`;
2316
2739
  logger.error(`[hilog] ${msg}`);
@@ -2330,7 +2753,7 @@ function streamHilog(opts) {
2330
2753
  if (opts.domain !== void 0 && `${opts.domain}` !== "") {
2331
2754
  args.push("-D", `${opts.domain}`);
2332
2755
  }
2333
- return (0, import_node_child_process6.spawn)(hdc, args);
2756
+ return spawnCompat(hdc, args);
2334
2757
  }
2335
2758
  var HILOG_LINE_RE = /^(\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\s+(\d+)\s+(\d+)\s+([DIWEF])\s+(\S+):\s+(.*)$/;
2336
2759
  function parseHilogLine(line) {
@@ -2365,7 +2788,7 @@ async function resolveProcessId(config, bundle, deviceSerial) {
2365
2788
  return proc?.pid;
2366
2789
  }
2367
2790
  function waitForLog(opts) {
2368
- return new Promise((resolve2, reject) => {
2791
+ return new Promise((resolve4, reject) => {
2369
2792
  const deadline = Date.now() + opts.timeoutMs;
2370
2793
  let settled = false;
2371
2794
  let child = null;
@@ -2376,10 +2799,7 @@ function waitForLog(opts) {
2376
2799
  if (reconnectTimer) clearTimeout(reconnectTimer);
2377
2800
  opts.abortSignal?.removeEventListener("abort", onAbort);
2378
2801
  if (child) {
2379
- try {
2380
- child.kill("SIGKILL");
2381
- } catch {
2382
- }
2802
+ killProcessTree(child);
2383
2803
  child = null;
2384
2804
  }
2385
2805
  };
@@ -2387,7 +2807,7 @@ function waitForLog(opts) {
2387
2807
  if (settled) return;
2388
2808
  settled = true;
2389
2809
  cleanup();
2390
- resolve2(entry);
2810
+ resolve4(entry);
2391
2811
  };
2392
2812
  const fail = (err) => {
2393
2813
  if (settled) return;
@@ -2395,6 +2815,7 @@ function waitForLog(opts) {
2395
2815
  cleanup();
2396
2816
  reject(err);
2397
2817
  };
2818
+ const failWith = (err) => fail(err instanceof Error ? err : new Error(String(err)));
2398
2819
  const onAbort = () => fail(new CancelledError("waitForLog cancelled."));
2399
2820
  const timer = setTimeout(
2400
2821
  () => fail(new OniroError(`No log line matched ${String(opts.pattern)} within ${opts.timeoutMs}ms.`)),
@@ -2424,17 +2845,17 @@ function waitForLog(opts) {
2424
2845
  if (settled || child !== stream) return;
2425
2846
  child = null;
2426
2847
  if (Date.now() < deadline) {
2427
- reconnectTimer = setTimeout(() => void spawnStream(), 1e3);
2848
+ reconnectTimer = setTimeout(() => void spawnStream().catch(failWith), 1e3);
2428
2849
  }
2429
2850
  };
2430
2851
  stream.once("close", onEnd);
2431
2852
  stream.once("error", onEnd);
2432
2853
  };
2433
- void spawnStream();
2854
+ void spawnStream().catch(failWith);
2434
2855
  });
2435
2856
  }
2436
2857
  function watchLog(opts) {
2437
- return new Promise((resolve2, reject) => {
2858
+ return new Promise((resolve4, reject) => {
2438
2859
  const matches = [];
2439
2860
  let settled = false;
2440
2861
  let child = null;
@@ -2443,10 +2864,7 @@ function watchLog(opts) {
2443
2864
  clearTimeout(timer);
2444
2865
  opts.abortSignal?.removeEventListener("abort", onAbort);
2445
2866
  if (child) {
2446
- try {
2447
- child.kill("SIGKILL");
2448
- } catch {
2449
- }
2867
+ killProcessTree(child);
2450
2868
  child = null;
2451
2869
  }
2452
2870
  };
@@ -2454,7 +2872,7 @@ function watchLog(opts) {
2454
2872
  if (settled) return;
2455
2873
  settled = true;
2456
2874
  cleanup();
2457
- resolve2(opts.dedup === false ? matches : dedupEntries(matches));
2875
+ resolve4(opts.dedup === false ? matches : dedupEntries(matches));
2458
2876
  };
2459
2877
  const onAbort = () => {
2460
2878
  if (settled) return;
@@ -2479,7 +2897,12 @@ function watchLog(opts) {
2479
2897
  if (entry && opts.pattern.test(entryText(entry))) matches.push(entry);
2480
2898
  }
2481
2899
  });
2482
- })();
2900
+ })().catch((err) => {
2901
+ if (settled) return;
2902
+ settled = true;
2903
+ cleanup();
2904
+ reject(err instanceof Error ? err : new Error(String(err)));
2905
+ });
2483
2906
  });
2484
2907
  }
2485
2908
  async function dumpLog(opts) {
@@ -2506,9 +2929,8 @@ async function dumpLog(opts) {
2506
2929
  }
2507
2930
 
2508
2931
  // src/build/runHvigorw.ts
2509
- var fs18 = __toESM(require("fs"), 1);
2510
- var path17 = __toESM(require("path"), 1);
2511
- var import_node_child_process7 = require("child_process");
2932
+ var fs20 = __toESM(require("fs"), 1);
2933
+ var path20 = __toESM(require("path"), 1);
2512
2934
  function buildHvigorwArgs(opts) {
2513
2935
  const args = [opts.task ?? "assembleHap", "--mode", "module"];
2514
2936
  args.push("-p", `product=${opts.product ?? "default"}`);
@@ -2520,19 +2942,23 @@ function buildHvigorwArgs(opts) {
2520
2942
  return args;
2521
2943
  }
2522
2944
  function runHvigorw(opts) {
2523
- const { config, projectDir } = opts;
2945
+ const { config } = opts;
2946
+ const projectDir = toLongPath(opts.projectDir);
2524
2947
  const logger = opts.logger ?? noopLogger;
2525
- if (!fs18.existsSync(path17.join(projectDir, "build-profile.json5"))) {
2948
+ if (!fs20.existsSync(path20.join(projectDir, "build-profile.json5"))) {
2526
2949
  throw new OniroError(`Not an OpenHarmony project: ${projectDir} (build-profile.json5 not found).`);
2527
2950
  }
2528
- if (!fs18.existsSync(getCmdToolsPath(config))) {
2951
+ if (!fs20.existsSync(getCmdToolsPath(config))) {
2529
2952
  throw new CmdToolsNotInstalledError(getCmdToolsPath(config));
2530
2953
  }
2531
2954
  const hvigorw = getHvigorwPath(config, projectDir);
2955
+ if (!fs20.existsSync(hvigorw)) {
2956
+ throw new OniroError(`hvigorw wrapper not found at ${hvigorw}.`);
2957
+ }
2532
2958
  const args = buildHvigorwArgs(opts);
2533
2959
  if (process.platform !== "win32") {
2534
2960
  try {
2535
- fs18.chmodSync(hvigorw, 493);
2961
+ fs20.chmodSync(hvigorw, 493);
2536
2962
  } catch {
2537
2963
  }
2538
2964
  }
@@ -2540,32 +2966,35 @@ function runHvigorw(opts) {
2540
2966
  ...process.env,
2541
2967
  OHOS_BASE_SDK_HOME: getOhosBaseSdkHome(config)
2542
2968
  };
2543
- return new Promise((resolve2, reject) => {
2969
+ return new Promise((resolve4, reject) => {
2544
2970
  if (opts.abortSignal?.aborted) {
2545
2971
  reject(new CancelledError("hvigorw build cancelled."));
2546
2972
  return;
2547
2973
  }
2548
2974
  logger.info(`[build] ${hvigorw} ${args.join(" ")}`);
2549
- const child = (0, import_node_child_process7.spawn)(hvigorw, args, { cwd: projectDir, env, shell: false });
2975
+ let child;
2976
+ try {
2977
+ child = spawnCompat(hvigorw, args, { cwd: projectDir, env });
2978
+ } catch (err) {
2979
+ reject(new OniroError(`Failed to start hvigorw: ${err instanceof Error ? err.message : String(err)}`, err));
2980
+ return;
2981
+ }
2550
2982
  let settled = false;
2551
2983
  const cleanup = () => opts.abortSignal?.removeEventListener("abort", onAbort);
2552
2984
  const onAbort = () => {
2553
2985
  if (settled) return;
2554
2986
  settled = true;
2555
2987
  cleanup();
2556
- try {
2557
- child.kill("SIGKILL");
2558
- } catch {
2559
- }
2988
+ killProcessTree(child);
2560
2989
  reject(new CancelledError("hvigorw build cancelled."));
2561
2990
  };
2562
2991
  opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
2563
- child.stdout.on("data", (chunk) => {
2992
+ child.stdout?.on("data", (chunk) => {
2564
2993
  const text = chunk.toString();
2565
2994
  opts.onOutput?.(text, "stdout");
2566
2995
  logger.info(text.trimEnd());
2567
2996
  });
2568
- child.stderr.on("data", (chunk) => {
2997
+ child.stderr?.on("data", (chunk) => {
2569
2998
  const text = chunk.toString();
2570
2999
  opts.onOutput?.(text, "stderr");
2571
3000
  logger.warn(text.trimEnd());
@@ -2581,19 +3010,18 @@ function runHvigorw(opts) {
2581
3010
  settled = true;
2582
3011
  cleanup();
2583
3012
  const exitCode = code ?? 1;
2584
- if (exitCode === 0) resolve2({ exitCode });
3013
+ if (exitCode === 0) resolve4({ exitCode });
2585
3014
  else reject(new OniroError(`hvigorw exited with code ${exitCode}`));
2586
3015
  });
2587
3016
  });
2588
3017
  }
2589
3018
 
2590
3019
  // src/build/discoverHaps.ts
2591
- var fs19 = __toESM(require("fs"), 1);
2592
- var path18 = __toESM(require("path"), 1);
2593
- function moduleOf(projectDir, hapPath) {
2594
- const rel = path18.relative(projectDir, hapPath);
2595
- const first = rel.split(path18.sep)[0];
2596
- return first && first !== ".." ? first : "(root)";
3020
+ var fs21 = __toESM(require("fs"), 1);
3021
+ var path21 = __toESM(require("path"), 1);
3022
+ function moduleOfHap(hapFileName) {
3023
+ const dash = hapFileName.indexOf("-");
3024
+ return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
2597
3025
  }
2598
3026
  async function discoverHaps(opts) {
2599
3027
  const { projectDir } = opts;
@@ -2601,14 +3029,14 @@ async function discoverHaps(opts) {
2601
3029
  const result = {};
2602
3030
  const walk = async (dir, depth) => {
2603
3031
  if (depth > maxDepth) return;
2604
- const entries = await fs19.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
3032
+ const entries = await fs21.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
2605
3033
  for (const e of entries) {
2606
- const full = path18.join(dir, e.name);
3034
+ const full = path21.join(dir, e.name);
2607
3035
  if (e.isDirectory()) {
2608
3036
  if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
2609
3037
  await walk(full, depth + 1);
2610
3038
  } else if (e.isFile() && e.name.endsWith(".hap")) {
2611
- const moduleName = moduleOf(projectDir, full);
3039
+ const moduleName = moduleOfHap(e.name);
2612
3040
  const bucket = result[moduleName] ??= { signed: [], unsigned: [] };
2613
3041
  if (e.name.includes("unsigned")) bucket.unsigned.push(full);
2614
3042
  else if (e.name.includes("signed")) bucket.signed.push(full);
@@ -2620,8 +3048,8 @@ async function discoverHaps(opts) {
2620
3048
  }
2621
3049
 
2622
3050
  // src/build/ohpm.ts
2623
- var fs20 = __toESM(require("fs"), 1);
2624
- var path19 = __toESM(require("path"), 1);
3051
+ var fs22 = __toESM(require("fs"), 1);
3052
+ var path22 = __toESM(require("path"), 1);
2625
3053
  function runOhpm(opts) {
2626
3054
  return runProcess({
2627
3055
  command: getOhpmPath(opts.config),
@@ -2634,7 +3062,7 @@ function runOhpm(opts) {
2634
3062
  });
2635
3063
  }
2636
3064
  async function ensureOhModules(opts) {
2637
- if (fs20.existsSync(path19.join(opts.projectDir, "oh_modules"))) {
3065
+ if (fs22.existsSync(path22.join(opts.projectDir, "oh_modules"))) {
2638
3066
  return { installed: false };
2639
3067
  }
2640
3068
  const res = await runOhpm({
@@ -2686,10 +3114,11 @@ async function buildHap(opts) {
2686
3114
  const logger = scopedLogger(opts.logger ?? noopLogger, "build");
2687
3115
  const warnings = [];
2688
3116
  const start = Date.now();
3117
+ const projectDir = toLongPath(opts.projectDir);
2689
3118
  if (opts.autoInstallDeps !== false) {
2690
3119
  const r = await ensureOhModules({
2691
3120
  config: opts.config,
2692
- projectDir: opts.projectDir,
3121
+ projectDir,
2693
3122
  abortSignal: opts.abortSignal,
2694
3123
  onOutput: opts.onOutput,
2695
3124
  logger: opts.logger
@@ -2698,7 +3127,7 @@ async function buildHap(opts) {
2698
3127
  }
2699
3128
  const { exitCode } = await runHvigorw({
2700
3129
  config: opts.config,
2701
- projectDir: opts.projectDir,
3130
+ projectDir,
2702
3131
  product: opts.product,
2703
3132
  module: opts.module,
2704
3133
  buildMode: opts.mode,
@@ -2708,7 +3137,7 @@ async function buildHap(opts) {
2708
3137
  onOutput: opts.onOutput,
2709
3138
  logger: opts.logger
2710
3139
  });
2711
- const discoveredHaps = await discoverHaps({ projectDir: opts.projectDir });
3140
+ const discoveredHaps = await discoverHaps({ projectDir });
2712
3141
  const anySigned = Object.values(discoveredHaps).some((m) => m.signed.length > 0);
2713
3142
  if (!anySigned) {
2714
3143
  warnings.push(
@@ -2729,21 +3158,21 @@ function isValidBundleName(bundleName) {
2729
3158
  }
2730
3159
 
2731
3160
  // src/project/templates.ts
2732
- var fs21 = __toESM(require("fs"), 1);
2733
- var path20 = __toESM(require("path"), 1);
3161
+ var fs23 = __toESM(require("fs"), 1);
3162
+ var path23 = __toESM(require("path"), 1);
2734
3163
  function toHumanTemplateName(folderName) {
2735
3164
  return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
2736
3165
  }
2737
3166
  function listTemplates(templateRoot) {
2738
- if (!fs21.existsSync(templateRoot)) return [];
2739
- const entries = fs21.readdirSync(templateRoot, { withFileTypes: true });
3167
+ if (!fs23.existsSync(templateRoot)) return [];
3168
+ const entries = fs23.readdirSync(templateRoot, { withFileTypes: true });
2740
3169
  return entries.filter((e) => e.isDirectory()).map((e) => {
2741
- const dir = path20.join(templateRoot, e.name);
2742
- const metaPath = path20.join(dir, "template.json");
3170
+ const dir = path23.join(templateRoot, e.name);
3171
+ const metaPath = path23.join(dir, "template.json");
2743
3172
  let meta = {};
2744
- if (fs21.existsSync(metaPath)) {
3173
+ if (fs23.existsSync(metaPath)) {
2745
3174
  try {
2746
- meta = JSON.parse(fs21.readFileSync(metaPath, "utf8"));
3175
+ meta = JSON.parse(fs23.readFileSync(metaPath, "utf8"));
2747
3176
  } catch {
2748
3177
  }
2749
3178
  }
@@ -2758,57 +3187,57 @@ function listTemplates(templateRoot) {
2758
3187
  function validateTemplateLayout(templateDir, defaultModuleName) {
2759
3188
  const required = [
2760
3189
  "build-profile.json5",
2761
- path20.join("AppScope", "app.json5"),
2762
- path20.join(defaultModuleName, "src", "main", "module.json5"),
2763
- path20.join(defaultModuleName, "oh-package.json5"),
3190
+ path23.join("AppScope", "app.json5"),
3191
+ path23.join(defaultModuleName, "src", "main", "module.json5"),
3192
+ path23.join(defaultModuleName, "oh-package.json5"),
2764
3193
  "hvigorfile.ts"
2765
3194
  ];
2766
- return required.filter((rel) => !fs21.existsSync(path20.join(templateDir, rel)));
3195
+ return required.filter((rel) => !fs23.existsSync(path23.join(templateDir, rel)));
2767
3196
  }
2768
3197
 
2769
3198
  // src/project/createScaffold.ts
2770
- var fs23 = __toESM(require("fs"), 1);
2771
- var path21 = __toESM(require("path"), 1);
3199
+ var fs25 = __toESM(require("fs"), 1);
3200
+ var path24 = __toESM(require("path"), 1);
2772
3201
 
2773
3202
  // src/project/jsonHelpers.ts
2774
- var fs22 = __toESM(require("fs"), 1);
3203
+ var fs24 = __toESM(require("fs"), 1);
2775
3204
  var import_json54 = __toESM(require("json5"), 1);
2776
3205
  function readJson5File(filePath) {
2777
- return import_json54.default.parse(fs22.readFileSync(filePath, "utf8"));
3206
+ return import_json54.default.parse(fs24.readFileSync(filePath, "utf8"));
2778
3207
  }
2779
3208
  function writeJson5File(filePath, value) {
2780
- fs22.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
3209
+ fs24.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
2781
3210
  }
2782
3211
  function readJsonFile(filePath) {
2783
- return JSON.parse(fs22.readFileSync(filePath, "utf8"));
3212
+ return JSON.parse(fs24.readFileSync(filePath, "utf8"));
2784
3213
  }
2785
3214
  function writeJsonFile(filePath, value) {
2786
- fs22.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
3215
+ fs24.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
2787
3216
  }
2788
3217
 
2789
3218
  // src/project/createScaffold.ts
2790
3219
  var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
2791
3220
  async function pathExists(p) {
2792
3221
  try {
2793
- await fs23.promises.access(p);
3222
+ await fs25.promises.access(p);
2794
3223
  return true;
2795
3224
  } catch {
2796
3225
  return false;
2797
3226
  }
2798
3227
  }
2799
3228
  async function copyDirRecursive(srcDir, destDir) {
2800
- await fs23.promises.mkdir(destDir, { recursive: true });
2801
- const entries = await fs23.promises.readdir(srcDir, { withFileTypes: true });
3229
+ await fs25.promises.mkdir(destDir, { recursive: true });
3230
+ const entries = await fs25.promises.readdir(srcDir, { withFileTypes: true });
2802
3231
  for (const entry of entries) {
2803
- const src = path21.join(srcDir, entry.name);
2804
- const dest = path21.join(destDir, entry.name);
3232
+ const src = path24.join(srcDir, entry.name);
3233
+ const dest = path24.join(destDir, entry.name);
2805
3234
  if (entry.isDirectory()) {
2806
3235
  await copyDirRecursive(src, dest);
2807
3236
  } else if (entry.isSymbolicLink()) {
2808
3237
  continue;
2809
3238
  } else if (entry.isFile()) {
2810
3239
  if (entry.name === "template.json") continue;
2811
- await fs23.promises.copyFile(src, dest);
3240
+ await fs25.promises.copyFile(src, dest);
2812
3241
  }
2813
3242
  }
2814
3243
  }
@@ -2816,9 +3245,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
2816
3245
  const stack = [projectDir];
2817
3246
  while (stack.length > 0) {
2818
3247
  const currentDir = stack.pop();
2819
- const entries = await fs23.promises.readdir(currentDir, { withFileTypes: true });
3248
+ const entries = await fs25.promises.readdir(currentDir, { withFileTypes: true });
2820
3249
  for (const entry of entries) {
2821
- const fullPath = path21.join(currentDir, entry.name);
3250
+ const fullPath = path24.join(currentDir, entry.name);
2822
3251
  if (entry.isDirectory()) {
2823
3252
  if (IGNORED_DIRS.has(entry.name)) continue;
2824
3253
  stack.push(fullPath);
@@ -2840,23 +3269,23 @@ function toJavaPropertiesPath(p) {
2840
3269
  function createOrUpdateLocalProperties(projectDir, sdkDir) {
2841
3270
  const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
2842
3271
  `;
2843
- fs23.writeFileSync(path21.join(projectDir, "local.properties"), content, "utf8");
3272
+ fs25.writeFileSync(path24.join(projectDir, "local.properties"), content, "utf8");
2844
3273
  }
2845
3274
  function renameIfExists(fromPath, toPath) {
2846
- if (fs23.existsSync(fromPath) && fromPath !== toPath) {
2847
- fs23.renameSync(fromPath, toPath);
3275
+ if (fs25.existsSync(fromPath) && fromPath !== toPath) {
3276
+ fs25.renameSync(fromPath, toPath);
2848
3277
  }
2849
3278
  }
2850
3279
  function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
2851
- const appJsonPath = path21.join(projectDir, "AppScope", "app.json5");
2852
- if (fs23.existsSync(appJsonPath)) {
3280
+ const appJsonPath = path24.join(projectDir, "AppScope", "app.json5");
3281
+ if (fs25.existsSync(appJsonPath)) {
2853
3282
  const appJson = readJson5File(appJsonPath);
2854
3283
  appJson.app = appJson.app ?? {};
2855
3284
  appJson.app.bundleName = args.bundleName;
2856
3285
  writeJson5File(appJsonPath, appJson);
2857
3286
  }
2858
- const stringsPath = path21.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
2859
- if (fs23.existsSync(stringsPath)) {
3287
+ const stringsPath = path24.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
3288
+ if (fs25.existsSync(stringsPath)) {
2860
3289
  const strings = readJsonFile(stringsPath);
2861
3290
  if (Array.isArray(strings.string)) {
2862
3291
  const appName = strings.string.find((s) => s.name === "app_name");
@@ -2864,8 +3293,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
2864
3293
  }
2865
3294
  writeJsonFile(stringsPath, strings);
2866
3295
  }
2867
- const buildProfilePath = path21.join(projectDir, "build-profile.json5");
2868
- if (fs23.existsSync(buildProfilePath)) {
3296
+ const buildProfilePath = path24.join(projectDir, "build-profile.json5");
3297
+ if (fs25.existsSync(buildProfilePath)) {
2869
3298
  const buildProfile = readJson5File(buildProfilePath);
2870
3299
  buildProfile.app = buildProfile.app ?? {};
2871
3300
  if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
@@ -2878,23 +3307,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
2878
3307
  }
2879
3308
  writeJson5File(buildProfilePath, buildProfile);
2880
3309
  }
2881
- const moduleJsonPath = path21.join(projectDir, args.moduleName, "src", "main", "module.json5");
2882
- if (fs23.existsSync(moduleJsonPath)) {
3310
+ const moduleJsonPath = path24.join(projectDir, args.moduleName, "src", "main", "module.json5");
3311
+ if (fs25.existsSync(moduleJsonPath)) {
2883
3312
  const moduleJson = readJson5File(moduleJsonPath);
2884
3313
  moduleJson.module = moduleJson.module ?? {};
2885
3314
  moduleJson.module.name = args.moduleName;
2886
3315
  writeJson5File(moduleJsonPath, moduleJson);
2887
3316
  }
2888
- const moduleOhPackagePath = path21.join(projectDir, args.moduleName, "oh-package.json5");
2889
- if (fs23.existsSync(moduleOhPackagePath)) {
3317
+ const moduleOhPackagePath = path24.join(projectDir, args.moduleName, "oh-package.json5");
3318
+ if (fs25.existsSync(moduleOhPackagePath)) {
2890
3319
  const pkg = readJson5File(moduleOhPackagePath);
2891
3320
  pkg.name = args.moduleName;
2892
3321
  writeJson5File(moduleOhPackagePath, pkg);
2893
3322
  }
2894
- const vscodeDir = path21.join(projectDir, ".vscode");
2895
- fs23.mkdirSync(vscodeDir, { recursive: true });
3323
+ const vscodeDir = path24.join(projectDir, ".vscode");
3324
+ fs25.mkdirSync(vscodeDir, { recursive: true });
2896
3325
  const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
2897
- writeJsonFile(path21.join(vscodeDir, "settings.json"), {
3326
+ writeJsonFile(path24.join(vscodeDir, "settings.json"), {
2898
3327
  "oniro.hapPath": hapPath,
2899
3328
  "files.associations": { "*.json5": "jsonc" }
2900
3329
  });
@@ -2911,7 +3340,7 @@ async function createScaffold(opts) {
2911
3340
  if (!opts.location || !await pathExists(opts.location)) {
2912
3341
  throw new OniroError(`Location does not exist: ${opts.location}`);
2913
3342
  }
2914
- const templateDir = path21.join(opts.templateRoot, opts.templateId);
3343
+ const templateDir = path24.join(opts.templateRoot, opts.templateId);
2915
3344
  if (!await pathExists(templateDir)) {
2916
3345
  throw new OniroError(`Template not found: ${templateDir}`);
2917
3346
  }
@@ -2924,17 +3353,17 @@ async function createScaffold(opts) {
2924
3353
  throw new OniroError(`Template '${opts.templateId}' is missing required files:
2925
3354
  - ${missing.join("\n- ")}`);
2926
3355
  }
2927
- const projectDir = path21.join(opts.location, opts.projectName);
3356
+ const projectDir = path24.join(opts.location, opts.projectName);
2928
3357
  if (await pathExists(projectDir)) {
2929
3358
  if (!opts.overwrite) {
2930
3359
  throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
2931
3360
  }
2932
- await fs23.promises.rm(projectDir, { recursive: true, force: true });
3361
+ await fs25.promises.rm(projectDir, { recursive: true, force: true });
2933
3362
  }
2934
3363
  logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
2935
3364
  await copyDirRecursive(templateDir, projectDir);
2936
3365
  if (moduleName !== defaultModuleName) {
2937
- renameIfExists(path21.join(projectDir, defaultModuleName), path21.join(projectDir, moduleName));
3366
+ renameIfExists(path24.join(projectDir, defaultModuleName), path24.join(projectDir, moduleName));
2938
3367
  }
2939
3368
  updateTemplateConfigs(
2940
3369
  projectDir,
@@ -2951,11 +3380,11 @@ async function createScaffold(opts) {
2951
3380
  }
2952
3381
 
2953
3382
  // src/project/listModules.ts
2954
- var fs24 = __toESM(require("fs"), 1);
2955
- var path22 = __toESM(require("path"), 1);
3383
+ var fs26 = __toESM(require("fs"), 1);
3384
+ var path25 = __toESM(require("path"), 1);
2956
3385
  function listModules(opts) {
2957
- const buildProfile = path22.join(opts.projectDir, "build-profile.json5");
2958
- if (!fs24.existsSync(buildProfile)) {
3386
+ const buildProfile = path25.join(opts.projectDir, "build-profile.json5");
3387
+ if (!fs26.existsSync(buildProfile)) {
2959
3388
  throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
2960
3389
  }
2961
3390
  const parsed = readJson5File(buildProfile);
@@ -2967,12 +3396,12 @@ function listModules(opts) {
2967
3396
  }
2968
3397
 
2969
3398
  // src/project/abilities.ts
2970
- var fs25 = __toESM(require("fs"), 1);
2971
- var path23 = __toESM(require("path"), 1);
3399
+ var fs27 = __toESM(require("fs"), 1);
3400
+ var path26 = __toESM(require("path"), 1);
2972
3401
  function listAbilities(opts) {
2973
3402
  const moduleName = opts.moduleName ?? "entry";
2974
- const moduleJsonPath = path23.join(opts.projectDir, moduleName, "src", "main", "module.json5");
2975
- if (!fs25.existsSync(moduleJsonPath)) {
3403
+ const moduleJsonPath = path26.join(opts.projectDir, moduleName, "src", "main", "module.json5");
3404
+ if (!fs27.existsSync(moduleJsonPath)) {
2976
3405
  throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
2977
3406
  }
2978
3407
  const parsed = readJson5File(moduleJsonPath);
@@ -2980,12 +3409,12 @@ function listAbilities(opts) {
2980
3409
  }
2981
3410
 
2982
3411
  // src/project/prepareSigning.ts
2983
- var fs26 = __toESM(require("fs"), 1);
2984
- var path24 = __toESM(require("path"), 1);
3412
+ var fs28 = __toESM(require("fs"), 1);
3413
+ var path27 = __toESM(require("path"), 1);
2985
3414
  function hasSigningArtifacts(dir) {
2986
- if (!fs26.existsSync(path24.join(dir, "signatures"))) return false;
2987
- const buildProfile = path24.join(dir, "build-profile.json5");
2988
- if (!fs26.existsSync(buildProfile)) return false;
3415
+ if (!fs28.existsSync(path27.join(dir, "signatures"))) return false;
3416
+ const buildProfile = path27.join(dir, "build-profile.json5");
3417
+ if (!fs28.existsSync(buildProfile)) return false;
2989
3418
  try {
2990
3419
  const parsed = readJson5File(buildProfile);
2991
3420
  return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
@@ -3075,8 +3504,8 @@ async function diffHapAssets(opts) {
3075
3504
  }
3076
3505
 
3077
3506
  // src/install/apply.ts
3078
- var fs27 = __toESM(require("fs"), 1);
3079
- var path25 = __toESM(require("path"), 1);
3507
+ var fs29 = __toESM(require("fs"), 1);
3508
+ var path28 = __toESM(require("path"), 1);
3080
3509
  function decideInstallMethod(s) {
3081
3510
  if (!s.signInfoInconsistent) return "replace";
3082
3511
  if (s.isSystemBundle && !s.allowUninstall) return "refuse";
@@ -3097,7 +3526,7 @@ async function pidOf(config, bundle, deviceSerial) {
3097
3526
  async function resolveHapPath(opts) {
3098
3527
  let hapPath = opts.hapPath;
3099
3528
  if (hapPath) {
3100
- if (!path25.isAbsolute(hapPath) && opts.projectDir) hapPath = path25.join(opts.projectDir, hapPath);
3529
+ if (!path28.isAbsolute(hapPath) && opts.projectDir) hapPath = path28.join(opts.projectDir, hapPath);
3101
3530
  } else {
3102
3531
  if (!opts.projectDir) throw new OniroError("applyChanges requires hapPath or projectDir.");
3103
3532
  const haps = await discoverHaps({ projectDir: opts.projectDir });
@@ -3116,7 +3545,7 @@ async function resolveHapPath(opts) {
3116
3545
  hapPath = withSigned[0][1].signed[0];
3117
3546
  }
3118
3547
  }
3119
- if (!fs27.existsSync(hapPath)) throw new OniroError(`HAP not found at ${hapPath}.`);
3548
+ if (!fs29.existsSync(hapPath)) throw new OniroError(`HAP not found at ${hapPath}.`);
3120
3549
  return hapPath;
3121
3550
  }
3122
3551
  async function applyChanges(opts) {
@@ -3126,7 +3555,7 @@ async function applyChanges(opts) {
3126
3555
  const allowUninstall = opts.allowUninstall ?? false;
3127
3556
  const hapPath = await resolveHapPath(opts);
3128
3557
  let assetsChanged = false;
3129
- if (opts.installedHapPath && fs27.existsSync(opts.installedHapPath)) {
3558
+ if (opts.installedHapPath && fs29.existsSync(opts.installedHapPath)) {
3130
3559
  try {
3131
3560
  const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
3132
3561
  assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
@@ -3168,7 +3597,7 @@ async function applyChanges(opts) {
3168
3597
  }
3169
3598
 
3170
3599
  // src/index.ts
3171
- var VERSION = "0.7.0";
3600
+ var VERSION = "0.9.0";
3172
3601
  // Annotate the CommonJS export names for ESM import in node:
3173
3602
  0 && (module.exports = {
3174
3603
  ALL_SDKS,
@@ -3178,22 +3607,29 @@ var VERSION = "0.7.0";
3178
3607
  ChecksumMismatchError,
3179
3608
  CmdToolsNotInstalledError,
3180
3609
  CommandFailedError,
3610
+ INSTALL_TMP_DIRNAME,
3611
+ InsufficientSpaceError,
3181
3612
  OHOS_URL_BASE,
3182
3613
  OniroError,
3183
3614
  SdkNotInstalledError,
3615
+ TMP_DIR_HINT,
3184
3616
  UnsupportedPlatformError,
3185
3617
  VERSION,
3186
3618
  applyChanges,
3187
3619
  attemptHdcConnection,
3620
+ buildCmdWrapper,
3188
3621
  buildGestureCommands,
3622
+ buildGestureUitestCommand,
3189
3623
  buildHap,
3190
3624
  buildHvigorwArgs,
3191
3625
  buildInputCommand,
3192
3626
  buildRawTouchCommand,
3193
3627
  captureBurst,
3194
3628
  consoleLogger,
3629
+ createInstallTempDir,
3195
3630
  createMaterial,
3196
3631
  createScaffold,
3632
+ createTempWorkDir,
3197
3633
  decideInstallMethod,
3198
3634
  decideReboot,
3199
3635
  decryptPwd,
@@ -3214,14 +3650,19 @@ var VERSION = "0.7.0";
3214
3650
  dumpScreen,
3215
3651
  dumpWindow,
3216
3652
  encryptPwd,
3653
+ ensureFreeSpace,
3217
3654
  ensureOhModules,
3218
3655
  ensureOk,
3656
+ ensureRemoteOk,
3657
+ escapeCmdArgument,
3658
+ escapeCmdCommand,
3219
3659
  extractTarball,
3220
3660
  extractZipWithProgress,
3221
3661
  findAppProcessId,
3222
3662
  findCmdToolsSourceDir,
3223
3663
  findRunningProcess,
3224
3664
  forceStop,
3665
+ formatBytes,
3225
3666
  generateSigningConfigs,
3226
3667
  getBundleName,
3227
3668
  getCmdToolsBin,
@@ -3231,6 +3672,7 @@ var VERSION = "0.7.0";
3231
3672
  getDeviceInfo,
3232
3673
  getDisplaySize,
3233
3674
  getEmulatorDir,
3675
+ getFreeSpaceBytes,
3234
3676
  getHdcPath,
3235
3677
  getHvigorwPath,
3236
3678
  getInstalledSdks,
@@ -3248,14 +3690,18 @@ var VERSION = "0.7.0";
3248
3690
  installEmulator,
3249
3691
  isCmdToolsInstalled,
3250
3692
  isEmulatorInstalled,
3693
+ isOutOfSpaceError,
3694
+ isRamBackedPath,
3251
3695
  isValidBundleName,
3252
3696
  isValidProjectName,
3697
+ killProcessTree,
3253
3698
  launchApp,
3254
3699
  listAbilities,
3255
3700
  listDevices,
3256
3701
  listModules,
3257
3702
  listRunningProcesses,
3258
3703
  listTemplates,
3704
+ needsCmdWrapper,
3259
3705
  nonInteractivePrompter,
3260
3706
  noopLogger,
3261
3707
  noopProgress,
@@ -3265,6 +3711,8 @@ var VERSION = "0.7.0";
3265
3711
  parseCodelinterFindings,
3266
3712
  parseDeviceList,
3267
3713
  parseHilogLine,
3714
+ parseMainAbilityFromBmDump,
3715
+ parseRemoteExit,
3268
3716
  pickSigningKind,
3269
3717
  prepareSigning,
3270
3718
  pruneLayout,
@@ -3275,6 +3723,8 @@ var VERSION = "0.7.0";
3275
3723
  removeCmdTools,
3276
3724
  removeEmulator,
3277
3725
  removeSdk,
3726
+ removeTempWorkDir,
3727
+ resolveTmpRoot,
3278
3728
  runCodelinter,
3279
3729
  runHvigorw,
3280
3730
  runOhpm,
@@ -3287,11 +3737,15 @@ var VERSION = "0.7.0";
3287
3737
  sendRawTouch,
3288
3738
  setHilogLevel,
3289
3739
  shell,
3740
+ shellChecked,
3741
+ spawnCompat,
3290
3742
  startEmulator,
3291
3743
  staticConfig,
3292
3744
  stopEmulator,
3293
3745
  streamHilog,
3294
3746
  takeScreenshot,
3747
+ toLongPath,
3748
+ toSpaceError,
3295
3749
  uninstallApp,
3296
3750
  validateTemplateLayout,
3297
3751
  verifySha256,
@@ -3300,6 +3754,7 @@ var VERSION = "0.7.0";
3300
3754
  waitForCondition,
3301
3755
  waitForLog,
3302
3756
  watchLog,
3757
+ waypointsToRawEvents,
3303
3758
  writeJson5File,
3304
3759
  writeJsonFile
3305
3760
  });