@oniroproject/core 0.14.0 → 0.14.1
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 +15 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +15 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ports/logger.ts","../src/ports/progress.ts","../src/ports/config.ts","../src/ports/prompter.ts","../src/ports/errors.ts","../src/ports/context.ts","../src/sdk/constants.ts","../src/sdk/platform.ts","../src/sdk/paths.ts","../src/harmonyos/sdk.ts","../src/sdk/detectProjectSdk.ts","../src/sdk/tmp.ts","../src/sdk/download.ts","../src/sdk/extract.ts","../src/sdk/list.ts","../src/sdk/remove.ts","../src/sdk/install.ts","../src/sdk/move.ts","../src/cmdTools/install.ts","../src/hdc/spawnCompat.ts","../src/sign/encryptKey.ts","../src/sign/generateSigningConfigs.ts","../src/sign/applicationCert.ts","../src/emulator/install.ts","../src/emulator/lifecycle.ts","../src/hdc/exec.ts","../src/hdc/devices.ts","../src/hdc/param.ts","../src/hdc/files.ts","../src/hdc/display.ts","../src/hdc/wait.ts","../src/hdc/app.ts","../src/build/discoverHaps.ts","../src/hdc/project.ts","../src/hdc/lifecycle.ts","../src/hdc/screen.ts","../src/hdc/input.ts","../src/hdc/dump.ts","../src/hdc/ime.ts","../src/hdc/uiActions.ts","../src/hdc/hilog.ts","../src/build/runHvigorw.ts","../src/harmonyos/target.ts","../src/build/ohpm.ts","../src/build/codelinter.ts","../src/build/buildHap.ts","../src/project/validators.ts","../src/project/templates.ts","../src/project/createScaffold.ts","../src/project/jsonHelpers.ts","../src/project/listModules.ts","../src/project/abilities.ts","../src/project/prepareSigning.ts","../src/device/hidumper.ts","../src/device/info.ts","../src/install/diffHapAssets.ts","../src/install/apply.ts","../src/harmonyos/auth/endpoints.ts","../src/harmonyos/auth/tokenStore.ts","../src/harmonyos/auth/session.ts","../src/harmonyos/http.ts","../src/harmonyos/auth/callbackServer.ts","../src/harmonyos/auth/browser.ts","../src/harmonyos/signing/errors.ts","../src/harmonyos/signing/profile.ts","../src/harmonyos/signing/autoSign.ts","../src/harmonyos/signing/agc.ts","../src/harmonyos/signing/devices.ts","../src/harmonyos/signing/keystore.ts","../src/harmonyos/java.ts","../src/harmonyos/signing/paths.ts","../src/harmonyos/signing/project.ts","../src/harmonyos/signing/aclPermissionList.ts","../src/index.ts"],"sourcesContent":["export interface Logger {\n debug(message: string): void;\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n\nexport const noopLogger: Logger = {\n debug() {},\n info() {},\n warn() {},\n error() {},\n};\n\nexport const consoleLogger: Logger = {\n debug: (m) => console.debug(m),\n info: (m) => console.log(m),\n warn: (m) => console.warn(m),\n error: (m) => console.error(m),\n};\n\n/**\n * Wrap a Logger so every message is prefixed with `[<scope>] `. Standardizes the\n * ad-hoc `[hdc]` / `[build]` / `[sign]` / `[hilog]` / `[emulator]` prefixes that\n * were previously hand-written at each call site.\n */\nexport function scopedLogger(logger: Logger, scope: string): Logger {\n const prefix = `[${scope}] `;\n return {\n debug: (m) => logger.debug(prefix + m),\n info: (m) => logger.info(prefix + m),\n warn: (m) => logger.warn(prefix + m),\n error: (m) => logger.error(prefix + m),\n };\n}\n","export interface ProgressUpdate {\n message?: string;\n increment?: number;\n}\n\nexport interface ProgressReporter {\n report(update: ProgressUpdate): void;\n}\n\nexport const noopProgress: ProgressReporter = {\n report() {},\n};\n","import * as os from 'node:os';\nimport * as path from 'node:path';\n\n/**\n * Keys read from the ConfigProvider by core. Frontends (CLI, VS Code extension)\n * implement the provider however they like (env vars, settings.json, etc.).\n */\nexport type ConfigKey =\n | 'sdkRootDir'\n | 'cmdToolsPath'\n | 'hdcPath'\n | 'emulatorDir'\n | 'hapPath'\n | 'cmdToolsUrlLinux'\n | 'cmdToolsUrlWindows'\n | 'cmdToolsUrlMac'\n | 'emulatorUrl'\n // Scratch directory for download/extract temporaries. Defaults to the system temp\n // dir, which is often a RAM-backed tmpfs too small for multi-GB archives; point\n // this at a disk-backed directory when that bites.\n | 'tmpDir'\n // Base URL for OpenHarmony SDK release downloads. Defaults to the Huawei mirror\n // (`OHOS_URL_BASE`); override to point at a private/CI mirror.\n | 'sdkUrlBase'\n // Optional path to an external application-cert chain that overrides the bundled\n // `OpenHarmonyApplication.cer` during signing. Empty/unset → use the bundled cert.\n | 'applicationCertPath'\n // A HarmonyOS SDK: a DevEco Studio or HarmonyOS command-line-tools install, or its\n // `sdk` directory. Autodetected when unset; never downloaded.\n | 'harmonyosSdkPath'\n // Encrypted Huawei developer-account token. Default `~/.oniro/harmonyos`.\n | 'harmonyosAuthDir'\n // Generated HarmonyOS signing material (p12/csr/cer/p7b). Default `~/.ohos/config`,\n // where DevEco Studio keeps its own.\n | 'harmonyosSigningDir';\n\nexport interface ConfigProvider {\n /**\n * Get the configured value for `key`, or `fallback` if unset/empty.\n * Implementations should expand the literal `${userHome}` to the user's home dir.\n */\n get<T extends string | number | boolean>(key: ConfigKey, fallback: T): T;\n}\n\n/**\n * Default config values used when a ConfigProvider returns the fallback.\n * These match the historical paths used by the bash CLI and the extension.\n */\nexport const defaultPaths = {\n sdkRootDir: () => path.join(os.homedir(), 'setup-ohos-sdk'),\n cmdToolsPath: () => path.join(os.homedir(), 'command-line-tools'),\n emulatorDir: () => path.join(os.homedir(), 'oniro-emulator'),\n harmonyosAuthDir: () => path.join(os.homedir(), '.oniro', 'harmonyos'),\n harmonyosSigningDir: () => path.join(os.homedir(), '.ohos', 'config'),\n hapPath: 'entry/build/default/outputs/default/entry-default-signed.hap',\n emulatorUrl:\n 'https://github.com/eclipse-oniro4openharmony/device_board_oniro/releases/latest/download/oniro_emulator.zip',\n // The Huawei mirror only hosts a public Linux build of the command-line tools.\n // Windows and macOS require a manual download from the Huawei developer portal\n // (https://developer.huawei.com/...); pass the resulting ZIP to `cmdtools install --from-zip <path>`\n // or set ONIRO_CMD_TOOLS_URL_WINDOWS / ONIRO_CMD_TOOLS_URL_MAC to a self-hosted URL.\n cmdToolsUrlLinux:\n 'https://repo.huaweicloud.com/harmonyos/ohpm/5.1.0/commandline-tools-linux-x64-5.1.0.840.zip',\n} as const;\n\n/**\n * A simple in-memory ConfigProvider, useful for tests and as a base for CLI/extension impls.\n */\nexport function staticConfig(values: Partial<Record<ConfigKey, string>> = {}): ConfigProvider {\n return {\n get<T extends string | number | boolean>(key: ConfigKey, fallback: T): T {\n const v = values[key];\n if (v === undefined || v === '') {\n return fallback;\n }\n // Expand ${userHome} like the extension does.\n if (typeof v === 'string' && v.includes('${userHome}')) {\n return v.replace(/\\$\\{userHome\\}/g, os.homedir()) as unknown as T;\n }\n return v as unknown as T;\n },\n };\n}\n","/**\n * Interactive prompts. Frontends implement these — CLI uses @inquirer/prompts,\n * the extension uses `vscode.window.show*`. Core never assumes a TTY.\n */\nexport interface Prompter {\n /** Ask the user to confirm an action. */\n confirm(message: string, defaultValue?: boolean): Promise<boolean>;\n /** Ask the user for a single line of text. */\n input(message: string, defaultValue?: string): Promise<string>;\n /** Ask the user to pick a directory on disk; resolves to an absolute path or null if cancelled. */\n selectDirectory(message: string, defaultPath?: string): Promise<string | null>;\n /** Ask the user to pick a file on disk; resolves to an absolute path or null if cancelled. */\n selectFile(message: string, filters?: { extensions?: string[] }): Promise<string | null>;\n}\n\n/**\n * Throws on any prompt — used in non-interactive contexts where all answers must come from flags.\n */\nexport const nonInteractivePrompter: Prompter = {\n async confirm(message) {\n throw new Error(`Non-interactive mode: cannot confirm \"${message}\"`);\n },\n async input(message) {\n throw new Error(`Non-interactive mode: cannot ask \"${message}\"`);\n },\n async selectDirectory(message) {\n throw new Error(`Non-interactive mode: cannot prompt for directory \"${message}\"`);\n },\n async selectFile(message) {\n throw new Error(`Non-interactive mode: cannot prompt for file \"${message}\"`);\n },\n};\n","export class OniroError extends Error {\n constructor(message: string, public override readonly cause?: unknown) {\n super(message);\n this.name = 'OniroError';\n }\n}\n\nexport class SdkNotInstalledError extends OniroError {\n /** `version` is the release that ships `api` (e.g. `6.0` for API 20), when one is known. */\n constructor(\n public readonly api: string,\n public readonly expectedPath: string,\n public readonly version?: string,\n ) {\n super(\n `SDK API ${api} is not installed at ${expectedPath}.` +\n (version ? ` Install it with \\`oniro-app sdk install ${version}\\`.` : ''),\n );\n this.name = 'SdkNotInstalledError';\n }\n}\n\nexport class CmdToolsNotInstalledError extends OniroError {\n constructor(public readonly expectedPath: string) {\n super(`OpenHarmony command-line tools are not installed at ${expectedPath}.`);\n this.name = 'CmdToolsNotInstalledError';\n }\n}\n\nexport class UnsupportedPlatformError extends OniroError {\n constructor(public readonly platform: string) {\n super(`Unsupported platform: ${platform}.`);\n this.name = 'UnsupportedPlatformError';\n }\n}\n\nexport class ChecksumMismatchError extends OniroError {\n constructor(public readonly expected: string, public readonly actual: string) {\n super(`SHA256 mismatch: expected ${expected}, got ${actual}.`);\n this.name = 'ChecksumMismatchError';\n }\n}\n\n/**\n * A download/extract ran out of room on the filesystem holding its scratch\n * directory. The message is built by the caller (see `sdk/tmp.ts`) so it can name\n * the directory, whether it is RAM-backed, and how to point elsewhere.\n */\nexport class InsufficientSpaceError extends OniroError {\n constructor(message: string, public readonly dir: string, cause?: unknown) {\n super(message, cause);\n this.name = 'InsufficientSpaceError';\n }\n}\n\nexport class CancelledError extends OniroError {\n constructor(message = 'Operation cancelled.') {\n super(message);\n this.name = 'CancelledError';\n }\n}\n\n/**\n * A spawned command ran to completion but exited non-zero. Lets callers\n * distinguish \"the tool ran and failed\" from \"the tool could not be spawned\"\n * (a missing binary surfaces as an OniroError / CmdToolsNotInstalledError).\n */\nexport class CommandFailedError extends OniroError {\n constructor(\n public readonly command: string,\n public readonly exitCode: number,\n public readonly stderr: string,\n ) {\n super(`Command failed (exit ${exitCode}): ${command}${stderr ? `\\n${stderr}` : ''}`);\n this.name = 'CommandFailedError';\n }\n}\n","import { Logger, noopLogger } from './logger.js';\nimport { ConfigProvider, staticConfig } from './config.js';\n\n/**\n * Carries the cross-cutting dependencies most core functions need: a Logger and a ConfigProvider.\n * Functions that report progress or prompt the user take those as additional parameters.\n */\nexport interface OniroContext {\n logger: Logger;\n config: ConfigProvider;\n}\n\nexport function defaultContext(overrides: Partial<OniroContext> = {}): OniroContext {\n return {\n logger: overrides.logger ?? noopLogger,\n config: overrides.config ?? staticConfig(),\n };\n}\n","export interface SdkRelease {\n version: string;\n api: string;\n /**\n * Number of leading path components to strip when extracting the release\n * tarball, per OS family. The Huawei mirror packs linux+windows in one\n * tarball (no top-level wrapper for some releases → 0, else 1); macOS\n * tarballs have a deeper layout (3). This table is the single source of\n * truth read by `getSdkFilename()`.\n */\n tarballStrip: { linuxWindows: number; darwin: number };\n /**\n * Appended to the archive basename when the mirror re-published a release under a\n * dated name (e.g. 7.0 ships `ohos-sdk-windows_linux-public_20260829.tar.gz`, whose\n * components are the `-Release` build; the undated archive holds `-Beta` ones).\n */\n archiveSuffix?: string;\n}\n\n/**\n * Known OpenHarmony SDK releases. Kept in sync with the bash CLI / extension.\n * Update when a new SDK ships.\n */\nexport const ALL_SDKS: readonly SdkRelease[] = [\n { version: '4.0', api: '10', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '4.1', api: '11', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '5.0.0', api: '12', tarballStrip: { linuxWindows: 0, darwin: 3 } },\n { version: '5.0.1', api: '13', tarballStrip: { linuxWindows: 0, darwin: 3 } },\n { version: '5.0.2', api: '14', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '5.0.3', api: '15', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '5.1.0', api: '18', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '5.1.1', api: '19', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '6.0', api: '20', tarballStrip: { linuxWindows: 0, darwin: 3 } },\n { version: '6.1', api: '23', tarballStrip: { linuxWindows: 0, darwin: 3 } },\n { version: '7.0', api: '26', tarballStrip: { linuxWindows: 1, darwin: 3 }, archiveSuffix: '_20260829' },\n];\n\nexport const OHOS_URL_BASE = 'https://repo.huaweicloud.com/openharmony/os';\n","import * as os from 'node:os';\nimport { ALL_SDKS } from './constants.js';\nimport { UnsupportedPlatformError } from '../ports/errors.js';\n\nexport type OsFolder = 'linux' | 'darwin' | 'windows';\n\n/**\n * Map Node's `os.platform()` to the OS folder name used in the SDK install layout\n * and the SDK release tarballs.\n */\nexport function getOsFolder(): OsFolder {\n const platform = os.platform();\n if (platform === 'linux') return 'linux';\n if (platform === 'darwin') return 'darwin';\n if (platform === 'win32') return 'windows';\n throw new UnsupportedPlatformError(platform);\n}\n\nexport interface SdkArchiveInfo {\n filename: string;\n osFolder: OsFolder;\n /** Number of leading path components to strip when extracting the tarball. */\n strip: number;\n}\n\n/**\n * Resolve the SDK archive filename, OS folder, and tar strip count for the current platform.\n *\n * The Huawei mirror packages Linux and Windows together in one tarball with `linux/` and\n * `windows/` subfolders; macOS tarballs have a deeper layout. The per-release strip counts\n * live in {@link ALL_SDKS} (`tarballStrip`), as does any dated `archiveSuffix`. An\n * unrecognized version falls back to the historical default (linux/windows=1, darwin=3).\n */\nexport function getSdkFilename(version?: string): SdkArchiveInfo {\n const platform = os.platform();\n const v = version ?? ALL_SDKS[ALL_SDKS.length - 1]!.version;\n const release = ALL_SDKS.find((r) => r.version === v);\n const strips = release?.tarballStrip ?? { linuxWindows: 1, darwin: 3 };\n const archive = (base: string) => `${base}${release?.archiveSuffix ?? ''}.tar.gz`;\n\n if (platform === 'linux') {\n return { filename: archive('ohos-sdk-windows_linux-public'), osFolder: 'linux', strip: strips.linuxWindows };\n }\n if (platform === 'darwin') {\n if (os.arch() === 'arm64') {\n return { filename: archive('L2-SDK-MAC-M1-PUBLIC'), osFolder: 'darwin', strip: strips.darwin };\n }\n return { filename: archive('ohos-sdk-mac-public'), osFolder: 'darwin', strip: strips.darwin };\n }\n if (platform === 'win32') {\n return { filename: archive('ohos-sdk-windows_linux-public'), osFolder: 'windows', strip: strips.linuxWindows };\n }\n throw new UnsupportedPlatformError(platform);\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { ConfigProvider, defaultPaths } from '../ports/config.js';\nimport { getOsFolder } from './platform.js';\nimport { findHarmonyOsSdk } from '../harmonyos/sdk.js';\n\nexport function getSdkRootDir(config: ConfigProvider): string {\n return config.get('sdkRootDir', defaultPaths.sdkRootDir());\n}\n\n/**\n * Base SDK home for the current OS: `<sdkRootDir>/<linux|darwin|windows>`.\n * SDK API folders (e.g. `12`, `18`, `20`) live inside this directory.\n */\nexport function getOhosBaseSdkHome(config: ConfigProvider): string {\n return path.join(getSdkRootDir(config), getOsFolder());\n}\n\nexport function getCmdToolsPath(config: ConfigProvider): string {\n return config.get('cmdToolsPath', defaultPaths.cmdToolsPath());\n}\n\nexport function getEmulatorDir(config: ConfigProvider): string {\n return config.get('emulatorDir', defaultPaths.emulatorDir());\n}\n\n/**\n * Expand a Windows 8.3 short path (`C:\\Users\\FRANCE~1\\...`) to its long form.\n *\n * Short names reach us whenever a caller passes `%TEMP%` or a path built in a\n * `cmd` context, and hvigor cannot resolve a module directory underneath one:\n * it aborts with `00303149 Configuration Error / Path not found` naming a\n * `srcPath` that plainly exists. Node and the Win32 API resolve short names\n * fine, so the mismatch only surfaces once hvigor is running.\n *\n * No-op off Windows, where short names do not exist and resolving would only\n * dereference symlinks the caller chose deliberately. On Windows it does also\n * canonicalise case and follow junctions — the same path the OS resolves to\n * anyway.\n *\n * Returns `p` unchanged when it does not exist, so a caller's \"not found\"\n * error still quotes the path the user actually typed.\n *\n * `platform` is injectable so the behaviour is unit-testable off Windows.\n */\nexport function toLongPath(p: string, platform: NodeJS.Platform = os.platform()): string {\n if (platform !== 'win32') return p;\n try {\n return fs.realpathSync.native(p);\n } catch {\n return p;\n }\n}\n\nfunction pickExisting(candidates: string[]): string {\n for (const c of candidates) {\n if (fs.existsSync(c)) return c;\n }\n return candidates[0]!;\n}\n\n/**\n * Resolve a binary inside the command-line tools `bin/` directory by name\n * (e.g. `'ohpm'`, `'hvigorw'`, `'codelinter'`). On Windows tries common\n * executable suffixes (.exe, .cmd, .bat) before the POSIX name.\n */\nexport function getCmdToolsBin(config: ConfigProvider, name = 'ohpm'): string {\n const binDir = path.join(getCmdToolsPath(config), 'bin');\n if (os.platform() === 'win32') {\n return pickExisting([\n path.join(binDir, `${name}.exe`),\n path.join(binDir, `${name}.cmd`),\n path.join(binDir, `${name}.bat`),\n path.join(binDir, name),\n ]);\n }\n return path.join(binDir, name);\n}\n\n/** Resolve the OHPM binary path inside the command-line tools install. */\nexport function getOhpmPath(config: ConfigProvider): string {\n return getCmdToolsBin(config, 'ohpm');\n}\n\n/**\n * Resolve the hdc binary. An explicit `hdcPath` override (config key / `ONIRO_HDC`\n * env var) wins — point it at a wrapper/proxy hdc when the device is not directly\n * attached here (e.g. a remote device behind an SSH-tunnel `hdc` wrapper). When\n * unset, fall back to the hdc bundled in the SDK toolchains tree.\n */\nexport function getHdcPath(config: ConfigProvider): string {\n const override = config.get('hdcPath', '');\n if (override) return override;\n const hdc = hdcInSdk(path.join(getCmdToolsPath(config), 'sdk'));\n if (fs.existsSync(hdc)) return hdc;\n // A HarmonyOS-only machine has no OpenHarmony command-line tools; the HarmonyOS\n // SDK ships an hdc of its own, at the same place inside the SDK.\n const harmonySdk = findHarmonyOsSdk({ config });\n const harmonyHdc = harmonySdk ? hdcInSdk(harmonySdk.sdkPath) : undefined;\n return harmonyHdc && fs.existsSync(harmonyHdc) ? harmonyHdc : hdc;\n}\n\nfunction hdcInSdk(sdkDir: string): string {\n const base = path.join(sdkDir, 'default', 'openharmony', 'toolchains');\n if (os.platform() === 'win32') {\n return pickExisting([\n path.join(base, 'hdc.exe'),\n path.join(base, 'hdc.bat'),\n path.join(base, 'hdc.cmd'),\n path.join(base, 'hdc'),\n ]);\n }\n return path.join(base, 'hdc');\n}\n\n/**\n * Resolve the hvigorw wrapper for a project. Prefers the project-local copy\n * (which carries the project's pinned hvigor version) — but ONLY when that\n * wrapper is structurally complete. HMOS-vendored projects (systemui, launcher)\n * ship a project-local `hvigorw` whose `hvigor/` install is absent, so the\n * wrapper crashes on startup; in that case we fall back to the hvigorw bundled\n * with the command-line tools, which is always installed.\n *\n * DevEco projects ship both wrappers side by side: an extensionless POSIX shell\n * script and a `.bat` for Windows. The candidate order is therefore\n * platform-dependent — picking the shell script on Windows would hand `spawn` a\n * file the OS cannot execute.\n */\nexport function getHvigorwPath(\n config: ConfigProvider,\n projectDir: string,\n platform: NodeJS.Platform = os.platform(),\n): string {\n const posixFirst = ['hvigorw', 'hvigorw.bat', 'hvigorw.cmd'];\n const windowsFirst = ['hvigorw.bat', 'hvigorw.cmd', 'hvigorw'];\n const names = platform === 'win32' ? windowsFirst : posixFirst;\n const local = pickExisting(names.map((n) => path.join(projectDir, n)));\n if (fs.existsSync(local) && isProjectLocalHvigorwWorking(projectDir)) {\n return local;\n }\n return getCmdToolsBin(config, 'hvigorw');\n}\n\n/**\n * A project-local hvigorw wrapper only works when the project also has a\n * populated `hvigor/` install. The structural check (wrapper script + its\n * node_modules) is fast and avoids spawning `hvigorw --version` for the common,\n * working case.\n */\nfunction isProjectLocalHvigorwWorking(projectDir: string): boolean {\n const wrapper = path.join(projectDir, 'hvigor', 'hvigor-wrapper.js');\n const nodeModules = path.join(projectDir, 'hvigor', 'node_modules');\n return fs.existsSync(wrapper) && fs.existsSync(nodeModules);\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport { defaultPaths } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\n\n/**\n * A HarmonyOS SDK install. Unlike the OpenHarmony SDK, which `oniro-app sdk install`\n * downloads, the HarmonyOS SDK only ships inside DevEco Studio or the login-gated\n * HarmonyOS command-line tools, so oniro-app locates an existing install.\n */\nexport interface HarmonyOsSdk {\n /** The directory containing `default/`; hvigor receives it as `DEVECO_SDK_HOME`. */\n sdkPath: string;\n /** The DevEco Studio or command-line-tools install holding the SDK, its tools and JBR. */\n installRoot: string;\n /** From `default/sdk-pkg.json`, e.g. `HarmonyOS 6.1.1`. */\n displayName?: string;\n /**\n * The release as `compileSdkVersion` names it, e.g. `6.1.1(24)`, from\n * `default/sdk-pkg.json`. hvigor builds only projects that name this release.\n */\n version?: string;\n}\n\n/** `displayName` and `version` from `default/sdk-pkg.json`, where it has them. */\nfunction readSdkPkg(sdkPath: string): Pick<HarmonyOsSdk, 'displayName' | 'version'> {\n let data: { displayName?: unknown; platformVersion?: unknown; apiVersion?: unknown } | undefined;\n try {\n data = JSON.parse(fs.readFileSync(path.join(sdkPath, 'default', 'sdk-pkg.json'), 'utf8')).data;\n } catch {\n return {};\n }\n const text = (value: unknown) =>\n typeof value === 'string' || typeof value === 'number' ? String(value) || undefined : undefined;\n const platformVersion = text(data?.platformVersion);\n const apiVersion = text(data?.apiVersion);\n return {\n displayName: text(data?.displayName),\n version: platformVersion && apiVersion ? `${platformVersion}(${apiVersion})` : undefined,\n };\n}\n\n/**\n * Resolve an install root, or an SDK directory itself, to a HarmonyOS SDK.\n *\n * HarmonyOS and OpenHarmony SDKs share one layout, so an autodetected candidate\n * must also name itself HarmonyOS in `sdk-pkg.json` — otherwise the OpenHarmony\n * command-line tools would pass. An explicitly configured path is taken as given.\n */\nfunction resolveSdk(root: string, requireHarmonyOs: boolean): HarmonyOsSdk | null {\n const nested = path.join(root, 'sdk');\n const sdkPath = [nested, root].find((dir) => fs.existsSync(path.join(dir, 'default', 'openharmony')));\n if (!sdkPath) return null;\n\n const pkg = readSdkPkg(sdkPath);\n if (requireHarmonyOs && !pkg.displayName?.startsWith('HarmonyOS')) return null;\n return { sdkPath, installRoot: sdkPath === nested ? root : path.dirname(root), ...pkg };\n}\n\n/** Where DevEco Studio installs by default. It has no Linux release. */\nfunction studioCandidates(): string[] {\n if (process.platform === 'darwin') {\n return [\n '/Applications/DevEco-Studio.app/Contents',\n path.join(os.homedir(), 'Applications', 'DevEco-Studio.app', 'Contents'),\n ];\n }\n if (process.platform === 'win32') {\n return [path.join(process.env.ProgramFiles ?? 'C:\\\\Program Files', 'Huawei', 'DevEco Studio')];\n }\n return [];\n}\n\n/**\n * Locate a HarmonyOS SDK, or return null when none is installed.\n *\n * Order: `harmonyosSdkPath` (`ONIRO_HARMONYOS_SDK_PATH`, an install root or its\n * `sdk` directory), then DevEco Studio in its default location, then the\n * command-line tools at `cmdToolsPath` when they are the HarmonyOS edition.\n */\nexport function findHarmonyOsSdk(opts: { config: ConfigProvider; logger?: Logger }): HarmonyOsSdk | null {\n const logger = opts.logger ?? noopLogger;\n\n const configured = opts.config.get('harmonyosSdkPath', '');\n if (configured) {\n const sdk = resolveSdk(configured, false);\n if (sdk) return sdk;\n logger.warn(`ONIRO_HARMONYOS_SDK_PATH points at ${configured}, which holds no SDK; ignoring it.`);\n }\n\n const candidates = [\n ...studioCandidates(),\n opts.config.get('cmdToolsPath', defaultPaths.cmdToolsPath()),\n ];\n for (const candidate of candidates) {\n const sdk = resolveSdk(candidate, true);\n if (sdk) {\n logger.debug(`[harmonyos] Using the ${sdk.displayName} SDK at ${sdk.sdkPath}.`);\n return sdk;\n }\n }\n return null;\n}\n\n/** Like `findHarmonyOsSdk`, but throws an actionable error when none is installed. */\nexport function requireHarmonyOsSdk(opts: { config: ConfigProvider; logger?: Logger }): HarmonyOsSdk {\n const sdk = findHarmonyOsSdk(opts);\n if (sdk) return sdk;\n throw new OniroError(\n 'No HarmonyOS SDK found. It ships inside DevEco Studio or the HarmonyOS command-line tools and ' +\n 'cannot be downloaded the way the OpenHarmony SDK is. Install one, then set ONIRO_HARMONYOS_SDK_PATH ' +\n 'to the install (or its sdk directory).',\n );\n}\n\n/**\n * Locate a tool (`hvigorw`, `ohpm`) in a HarmonyOS install: the command-line tools\n * keep them in `bin`, DevEco Studio in `tools/<name>/bin`. Null when absent.\n */\nexport function findHarmonyOsTool(sdk: HarmonyOsSdk, name: string): string | null {\n const names = process.platform === 'win32' ? [`${name}.bat`, `${name}.cmd`, `${name}.exe`] : [name];\n for (const dir of [path.join(sdk.installRoot, 'bin'), path.join(sdk.installRoot, 'tools', name, 'bin')]) {\n for (const candidate of names) {\n const full = path.join(dir, candidate);\n if (fs.existsSync(full)) return full;\n }\n }\n return null;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport JSON5 from 'json5';\nimport { Logger, noopLogger } from '../ports/logger.js';\nimport type { ConfigProvider } from '../ports/config.js';\nimport { SdkNotInstalledError } from '../ports/errors.js';\nimport { ALL_SDKS } from './constants.js';\nimport { getOhosBaseSdkHome } from './paths.js';\n\n/**\n * The `sdk.dir` a project's `local.properties` names (a base SDK home holding API\n * folders, as `createScaffold` writes it), unescaped, or undefined.\n */\nfunction localPropertiesSdkDir(projectRoot: string): string | undefined {\n try {\n const content = fs.readFileSync(path.join(projectRoot, 'local.properties'), 'utf-8');\n const m = /^\\s*sdk\\.dir\\s*[=:]\\s*(.+?)\\s*$/m.exec(content);\n return m ? m[1]!.replace(/\\\\(.)/g, '$1') : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * The OpenHarmony SDK an OpenHarmony project builds against is missing, as a typed\n * error naming the release to install, or null when it is installed or the project\n * declares no numeric `compileSdkVersion`. hvigor looks for\n * `<sdk home>/<compileSdkVersion>`, the home being `OHOS_BASE_SDK_HOME` or the\n * project's `local.properties` `sdk.dir`, and otherwise fails late with\n * `00308018 SDK path does not exist` / \"SDK license agreement is not accepted\".\n */\nexport function findMissingProjectSdk(config: ConfigProvider, projectRoot: string): SdkNotInstalledError | null {\n const api = detectProjectSdkVersion(projectRoot);\n if (api === undefined) return null;\n const expected = path.join(getOhosBaseSdkHome(config), String(api));\n if (fs.existsSync(expected)) return null;\n const localSdkDir = localPropertiesSdkDir(projectRoot);\n if (localSdkDir && fs.existsSync(path.join(localSdkDir, String(api)))) return null;\n return new SdkNotInstalledError(String(api), expected, ALL_SDKS.find((s) => s.api === String(api))?.version);\n}\n\n/**\n * Detect the SDK API a project targets by reading `build-profile.json5`.\n * Returns the `compileSdkVersion` of the first declared product, or undefined\n * if the file is missing/malformed or no product declares one.\n */\nexport function detectProjectSdkVersion(projectRoot: string, logger: Logger = noopLogger): number | undefined {\n const buildProfilePath = path.join(projectRoot, 'build-profile.json5');\n if (!fs.existsSync(buildProfilePath)) {\n logger.warn(`build-profile.json5 not found at ${projectRoot}`);\n return undefined;\n }\n try {\n const content = fs.readFileSync(buildProfilePath, 'utf-8');\n const config = JSON5.parse(content) as { app?: { products?: Array<{ compileSdkVersion?: unknown }> } };\n const product = config.app?.products?.[0];\n const v = product?.compileSdkVersion;\n return typeof v === 'number' ? v : undefined;\n } catch (err) {\n logger.error(`Error reading build-profile.json5 at ${projectRoot}: ${String(err)}`);\n return undefined;\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { InsufficientSpaceError, OniroError } from '../ports/errors.js';\n\n/** Name of the scratch folder created next to an install target. */\nexport const INSTALL_TMP_DIRNAME = '.oniro-tmp';\n\n/** `statfs` type magics for the Linux filesystems whose capacity comes out of RAM. */\nconst TMPFS_MAGIC = 0x01021994;\nconst RAMFS_MAGIC = 0x858458f6;\n\nconst HINT_EXAMPLE = os.platform() === 'win32' ? 'D:\\\\oniro-tmp' : '~/.cache/oniro-tmp';\n\n/** Advice appended to out-of-space failures in the scratch directory. */\nexport const TMP_DIR_HINT =\n 'Point the scratch directory at a filesystem with more room using --tmp-dir <path> ' +\n `(or the ONIRO_TMP_DIR environment variable), e.g. --tmp-dir ${HINT_EXAMPLE}.`;\n\n/**\n * Resolve the directory that download/extract scratch space is created in.\n *\n * Precedence: explicit override (CLI `--tmp-dir`) → `tmpDir` config key\n * (`ONIRO_TMP_DIR`) → `<installRoot>/.oniro-tmp` → the system temp dir.\n *\n * The default sits next to the install target so that the unpacked tree is renamed\n * into place rather than copied across a device boundary, and so the system temp dir\n * — a RAM-backed `tmpfs` on most Linux systems, and far smaller than a multi-GB\n * archive — is never in the picture.\n */\nexport function resolveTmpRoot(config: ConfigProvider, override?: string, installRoot?: string): string {\n const explicit = (override ?? '').trim();\n if (explicit) return path.resolve(explicit);\n const configured = config.get('tmpDir', '').trim();\n if (configured) return path.resolve(configured);\n if (installRoot) return path.join(path.resolve(installRoot), INSTALL_TMP_DIRNAME);\n return os.tmpdir();\n}\n\n/** Create a private scratch directory under `root`, creating `root` if needed. */\nexport function createTempWorkDir(root: string, prefix: string): string {\n try {\n fs.mkdirSync(root, { recursive: true });\n return fs.mkdtempSync(path.join(root, prefix));\n } catch (err) {\n if (isOutOfSpaceError(err)) throw toSpaceError(err, root, 'a temporary directory');\n throw new OniroError(\n `Cannot create a temporary directory in '${root}': ${err instanceof Error ? err.message : String(err)}\\n${TMP_DIR_HINT}`,\n err,\n );\n }\n}\n\n/**\n * Remove a scratch directory once an install is done, taking the `.oniro-tmp` root\n * with it when that leaves it empty. A root the caller named explicitly is left alone,\n * as are roots another install is still using (the rmdir simply fails).\n */\nexport function removeTempWorkDir(dir: string, root?: string): void {\n fs.rmSync(dir, { recursive: true, force: true });\n if (!root || path.basename(root) !== INSTALL_TMP_DIRNAME) return;\n try {\n fs.rmdirSync(root);\n } catch {\n // Not empty (a concurrent install) or already gone — nothing to do.\n }\n}\n\nexport interface InstallTempDirOptions {\n config: ConfigProvider;\n /** Explicit scratch directory (CLI `--tmp-dir`). */\n override?: string;\n /** Directory the install lands in; the default scratch root is created inside it. */\n installRoot: string;\n prefix: string;\n logger?: Logger;\n}\n\nexport interface InstallTempDir {\n /** The private per-run scratch directory. Remove it when the install finishes. */\n dir: string;\n /** The configurable root it was created under, for out-of-space messages. */\n root: string;\n}\n\n/**\n * Create the scratch directory for an install, defaulting to `<installRoot>/.oniro-tmp`.\n *\n * When that default is unusable — a read-only or root-owned install parent, say — the\n * system temp dir is used instead. A directory the caller asked for explicitly is never\n * swapped out silently, and a full filesystem is reported rather than papered over.\n */\nexport function createInstallTempDir(opts: InstallTempDirOptions): InstallTempDir {\n const requested =\n (opts.override ?? '').trim() || opts.config.get('tmpDir', '').trim();\n const root = resolveTmpRoot(opts.config, opts.override, opts.installRoot);\n\n try {\n return { dir: createTempWorkDir(root, opts.prefix), root };\n } catch (err) {\n const fallback = os.tmpdir();\n if (requested || isOutOfSpaceError(err) || path.resolve(fallback) === path.resolve(root)) throw err;\n const reason = err instanceof Error ? err.message.split(/\\r?\\n/)[0] : String(err);\n (opts.logger ?? noopLogger).warn(`${reason} Falling back to '${fallback}'.`);\n return { dir: createTempWorkDir(fallback, opts.prefix), root: fallback };\n }\n}\n\n/** Nearest existing ancestor of `dir` (or null if even the root is unreadable). */\nfunction nearestExisting(dir: string): string | null {\n let current = path.resolve(dir);\n for (;;) {\n if (fs.existsSync(current)) return current;\n const parent = path.dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\n/**\n * Bytes available to an unprivileged user on the filesystem holding `dir`.\n * Returns null when the platform cannot report it.\n */\nexport function getFreeSpaceBytes(dir: string): number | null {\n const target = nearestExisting(dir);\n if (!target) return null;\n try {\n const stats = fs.statfsSync(target);\n return Number(stats.bsize) * Number(stats.bavail);\n } catch {\n return null;\n }\n}\n\n/**\n * Whether `dir` lives on a RAM-backed filesystem (`tmpfs`/`ramfs`), i.e. one whose\n * capacity comes out of memory rather than disk.\n */\nexport function isRamBackedPath(dir: string): boolean {\n const target = nearestExisting(dir);\n if (!target) return false;\n try {\n const type = Number(fs.statfsSync(target).type);\n return type === TMPFS_MAGIC || type === RAMFS_MAGIC;\n } catch {\n return false;\n }\n}\n\nexport function formatBytes(bytes: number): string {\n const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB'];\n let value = Math.max(0, bytes);\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit++;\n }\n return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;\n}\n\n/** Recognise an out-of-disk-space failure from fs/stream errors and their wrappers. */\nexport function isOutOfSpaceError(err: unknown): boolean {\n if (err instanceof InsufficientSpaceError) return true;\n const seen = new Set<unknown>();\n let current: unknown = err;\n while (current && typeof current === 'object' && !seen.has(current)) {\n seen.add(current);\n const e = current as { code?: unknown; message?: unknown; cause?: unknown };\n if (e.code === 'ENOSPC' || e.code === 'EDQUOT') return true;\n if (typeof e.message === 'string' && /ENOSPC|EDQUOT|no space left on device/i.test(e.message)) return true;\n current = e.cause;\n }\n return false;\n}\n\n/** The user-facing \"no room\" explanation, with a way out when the temp dir is to blame. */\nfunction spaceMessage(\n dir: string,\n what: string,\n opts: { requiredBytes?: number | null; freeBytes?: number | null; tmpDirHint: boolean },\n): string {\n const need = typeof opts.requiredBytes === 'number' ? `needs about ${formatBytes(opts.requiredBytes)}` : null;\n const free = typeof opts.freeBytes === 'number' ? `${formatBytes(opts.freeBytes)} available` : null;\n const amounts = [need, free].filter(Boolean).join(', ');\n\n const lines = [`Not enough free space in '${dir}' for ${what}${amounts ? ` (${amounts})` : ''}.`];\n if (isRamBackedPath(dir)) {\n lines.push(\n `'${dir}' is on a RAM-backed filesystem (tmpfs), so its capacity is limited by free memory, not by free disk.`,\n );\n }\n if (opts.tmpDirHint) lines.push(TMP_DIR_HINT);\n return lines.join('\\n');\n}\n\n/**\n * Fail before writing a byte when the filesystem holding `dir` cannot take\n * `requiredBytes`. A no-op when free space cannot be determined.\n */\nexport function ensureFreeSpace(dir: string, requiredBytes: number, what: string): void {\n if (!Number.isFinite(requiredBytes) || requiredBytes <= 0) return;\n const freeBytes = getFreeSpaceBytes(dir);\n if (freeBytes === null || freeBytes >= requiredBytes) return;\n throw new InsufficientSpaceError(\n spaceMessage(dir, what, { requiredBytes, freeBytes, tmpDirHint: true }),\n dir,\n );\n}\n\n/** The filesystem path an fs error refers to, from anywhere in its cause chain. */\nfunction errorPath(err: unknown): string | null {\n const seen = new Set<unknown>();\n let current: unknown = err;\n while (current && typeof current === 'object' && !seen.has(current)) {\n seen.add(current);\n const e = current as { path?: unknown; dest?: unknown; cause?: unknown };\n if (typeof e.path === 'string' && e.path) return e.path;\n if (typeof e.dest === 'string' && e.dest) return e.dest;\n current = e.cause;\n }\n return null;\n}\n\nfunction isInside(child: string, parent: string): boolean {\n const rel = path.relative(path.resolve(parent), path.resolve(child));\n return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));\n}\n\n/**\n * Convert an out-of-space failure into an {@link InsufficientSpaceError}; any other\n * error is returned unchanged, so callers can `throw toSpaceError(err, ...)`.\n *\n * `tmpRoot` is the scratch directory the operation was using. Failures under it are\n * reported against it (not the per-run subdirectory the user cannot configure) and get\n * the `--tmp-dir` remedy; failures elsewhere — an install target that is full — name\n * their own directory and skip the remedy, which would not help.\n */\nexport function toSpaceError(err: unknown, tmpRoot: string, what: string): unknown {\n if (err instanceof InsufficientSpaceError) return err;\n if (!isOutOfSpaceError(err)) return err;\n\n const failed = errorPath(err);\n const failedDir = failed ? path.dirname(path.resolve(failed)) : path.resolve(tmpRoot);\n const inTmp = isInside(failedDir, tmpRoot);\n const dir = inTmp ? path.resolve(tmpRoot) : failedDir;\n return new InsufficientSpaceError(\n spaceMessage(dir, what, { freeBytes: getFreeSpaceBytes(dir), tmpDirHint: inTmp }),\n dir,\n err,\n );\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport { pipeline } from 'node:stream';\nimport { promisify } from 'node:util';\nimport followRedirects from 'follow-redirects';\nimport type { ProgressReporter } from '../ports/progress.js';\nimport { CancelledError, ChecksumMismatchError, OniroError } from '../ports/errors.js';\nimport { ensureFreeSpace, isOutOfSpaceError, toSpaceError } from './tmp.js';\n\nconst { http, https } = followRedirects;\nconst pipelineAsync = promisify(pipeline);\n\nexport interface DownloadOptions {\n url: string;\n dest: string;\n progress?: ProgressReporter;\n abortSignal?: AbortSignal;\n /** Overall progress start offset (0..100). Default 0. */\n start?: number;\n /** Overall progress range to consume (0..100). Default 100. */\n range?: number;\n /** What the download is for, used in out-of-space messages. */\n what?: string;\n /**\n * Configurable scratch root that `dest` lives under, if any. Out-of-space messages\n * name it instead of the per-run subdirectory, since that is what the user can change.\n */\n tmpRoot?: string;\n}\n\n/**\n * Stream a remote file to disk with optional progress reporting and cancellation.\n * Follows redirects via the `follow-redirects` library.\n *\n * Fails fast with an `InsufficientSpaceError` when the destination filesystem cannot\n * hold the advertised `content-length` — the common case being a system temp dir on a\n * RAM-backed tmpfs that is far smaller than the SDK/tools archives.\n */\nexport async function downloadFile(opts: DownloadOptions): Promise<void> {\n const { url, dest, progress, abortSignal } = opts;\n const proto = url.startsWith('https') ? https : http;\n\n return new Promise((resolve, reject) => {\n const s = Math.max(0, Math.min(100, opts.start ?? 0));\n const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));\n\n let settled = false;\n const done = (err?: unknown) => {\n if (settled) return;\n settled = true;\n err ? reject(err) : resolve();\n };\n\n if (abortSignal?.aborted) {\n done(new CancelledError('Download cancelled before start.'));\n return;\n }\n\n const destDir = path.dirname(path.resolve(dest));\n const what = opts.what ?? `the download of '${url}'`;\n\n // Out of space gets the directory-aware explanation; anything else (a bad path,\n // a permission problem) still surfaces as a typed error rather than a raw fs one.\n const writeFailed = (err: unknown): unknown =>\n isOutOfSpaceError(err)\n ? toSpaceError(err, opts.tmpRoot ?? destDir, what)\n : new OniroError(`Error writing '${dest}': ${err instanceof Error ? err.message : String(err)}`, err);\n\n const file = fs.createWriteStream(dest);\n let activeResponse: NodeJS.ReadableStream | undefined;\n\n // Settle only once the partial file is gone, so a caller that retries — or a test\n // that checks — never observes the leftover. Closing before removing keeps Windows\n // happy, where an open file cannot be deleted.\n const failWith = (err: unknown) => {\n file.close(() => fs.rm(dest, { force: true }, () => done(err)));\n };\n\n // A write-stream failure (most often ENOSPC) has no other listener; without this\n // it would surface as an unhandled 'error' event and take the process down.\n file.on('error', (err) => {\n try { (activeResponse as { destroy?: () => void } | undefined)?.destroy?.(); } catch {}\n failWith(writeFailed(err));\n });\n\n const req = proto.get(url, (response) => {\n activeResponse = response;\n if (response.statusCode !== 200) {\n try { response.destroy(); } catch {}\n failWith(new OniroError(`Failed to download '${url}' (HTTP ${response.statusCode})`));\n return;\n }\n\n const total = parseInt(response.headers['content-length'] || '0', 10);\n\n // Refuse to start rather than filling the filesystem (or RAM, on tmpfs) first.\n if (total > 0) {\n try {\n ensureFreeSpace(opts.tmpRoot ?? destDir, total, what);\n } catch (err) {\n try { response.destroy(); } catch {}\n failWith(err);\n return;\n }\n }\n\n let downloaded = 0;\n let lastOverall = Math.round(s);\n\n response.on('data', (chunk: Buffer) => {\n downloaded += chunk.length;\n if (progress && total) {\n const localPercent = Math.min(100, Math.round((downloaded / total) * 100));\n const overall = Math.min(100, Math.round(s + (downloaded / total) * r));\n const inc = overall - lastOverall;\n if (inc > 0) {\n progress.report({ message: `Downloading: ${localPercent}%`, increment: inc });\n lastOverall = overall;\n } else {\n progress.report({ message: `Downloading: ${localPercent}%`, increment: 0 });\n }\n }\n });\n\n response.pipe(file);\n\n file.on('finish', () => {\n if (progress) {\n const endOverall = Math.min(100, Math.round(s + r));\n const inc = endOverall - lastOverall;\n if (inc > 0) progress.report({ message: 'Downloading: 100%', increment: inc });\n }\n file.close((err) => (err ? done(writeFailed(err)) : done()));\n });\n\n abortSignal?.addEventListener('abort', () => {\n response.destroy();\n failWith(new CancelledError('Download cancelled.'));\n });\n });\n\n req.on('error', (err) => {\n failWith(new OniroError(`Error downloading '${url}': ${err.message}`, err));\n });\n\n abortSignal?.addEventListener('abort', () => {\n req.destroy();\n failWith(new CancelledError('Download cancelled.'));\n });\n });\n}\n\n/**\n * Verify the SHA-256 checksum of a file against an on-disk .sha256 file.\n * The .sha256 file is expected to contain the hex digest as its first whitespace-delimited token.\n */\nexport async function verifySha256(filePath: string, sha256Path: string): Promise<void> {\n const expected = fs.readFileSync(sha256Path, 'utf8').split(/\\s+/)[0]!;\n const hash = crypto.createHash('sha256');\n await pipelineAsync(fs.createReadStream(filePath), hash);\n const actual = hash.digest('hex');\n if (actual !== expected) {\n throw new ChecksumMismatchError(expected, actual);\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { pipeline } from 'node:stream';\nimport { promisify } from 'node:util';\nimport * as tar from 'tar';\nimport StreamZip from 'node-stream-zip';\nimport type { ProgressReporter } from '../ports/progress.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\n\nconst pipelineAsync = promisify(pipeline);\n\nexport interface ExtractZipOptions {\n zipPath: string;\n dest: string;\n progress?: ProgressReporter;\n /** Overall progress start offset (0..100). Default 0. */\n start?: number;\n /** Overall progress range to consume (0..100). Default 100. */\n range?: number;\n logger?: Logger;\n}\n\n/**\n * Extract a ZIP to a destination directory, preserving file permissions and following\n * symlinks defensively. Protects against Zip Slip (entries whose paths escape `dest`).\n */\nexport async function extractZipWithProgress(opts: ExtractZipOptions): Promise<void> {\n const { zipPath, dest, progress } = opts;\n const logger = opts.logger ?? noopLogger;\n\n const zip = new (StreamZip as unknown as { async: new (cfg: { file: string }) => StreamZipAsync }).async({ file: zipPath });\n const entries = await zip.entries();\n const files = Object.values(entries);\n const total = files.length || 1;\n\n const s = Math.max(0, Math.min(100, opts.start ?? 0));\n const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));\n\n let processed = 0;\n let lastOverall = Math.round(s);\n\n await fs.promises.mkdir(dest, { recursive: true });\n const destRoot = path.resolve(dest);\n\n const safeResolveTarget = (entryName: string): string => {\n const resolved = path.resolve(destRoot, entryName);\n const rel = path.relative(destRoot, resolved);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new OniroError(`Blocked ZIP entry with illegal path: ${entryName}`);\n }\n return resolved;\n };\n\n try {\n for (const file of files) {\n const entryName = file.name;\n const targetPath = safeResolveTarget(entryName);\n const attr = file.attr ? (file.attr >>> 16) : 0;\n const isSymlink = 'isSymbolicLink' in file\n ? Boolean(file.isSymbolicLink)\n : (attr & 0o170000) === 0o120000;\n\n if (file.isDirectory) {\n await fs.promises.mkdir(targetPath, { recursive: true });\n } else if (isSymlink) {\n await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });\n const linkTargetBuffer = await zip.entryData(file);\n const linkTarget = linkTargetBuffer.toString('utf8');\n try {\n const isWin = os.platform() === 'win32';\n await fs.promises.symlink(linkTarget, targetPath, isWin ? 'file' : undefined);\n } catch (e) {\n logger.warn(`Failed to create symlink at ${targetPath}: ${String(e)}`);\n }\n } else {\n await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });\n const readStream = await zip.stream(file);\n const writeStream = fs.createWriteStream(targetPath);\n await pipelineAsync(readStream, writeStream);\n if (attr > 0) {\n try {\n await fs.promises.chmod(targetPath, attr & 0o777);\n } catch {\n // Best-effort: Windows or filesystems without POSIX perms — ignore.\n }\n }\n }\n\n processed++;\n if (progress) {\n const localPercent = Math.min(100, Math.round((processed / total) * 100));\n const overall = Math.min(100, Math.round(s + (processed / total) * r));\n const inc = overall - lastOverall;\n if (inc > 0) {\n progress.report({ message: `Extracting: ${localPercent}%`, increment: inc });\n lastOverall = overall;\n } else {\n progress.report({ message: `Extracting: ${localPercent}%`, increment: 0 });\n }\n }\n }\n } finally {\n await zip.close();\n }\n\n if (progress) {\n const endOverall = Math.min(100, Math.round(s + r));\n const inc = endOverall - lastOverall;\n if (inc > 0) progress.report({ message: 'Extracting: 100%', increment: inc });\n }\n}\n\n/**\n * Extract a tar/tar.gz/tar.bz2 archive. Wraps `tar.x`.\n */\nexport async function extractTarball(tarPath: string, dest: string, strip = 0): Promise<void> {\n await tar.x({ file: tarPath, cwd: dest, strip });\n}\n\n// node-stream-zip's TypeScript types aren't great; this is the minimal shape we use.\ninterface ZipEntry {\n name: string;\n isDirectory: boolean;\n isSymbolicLink?: boolean;\n attr?: number;\n}\ninterface StreamZipAsync {\n entries(): Promise<Record<string, ZipEntry>>;\n entryData(entry: ZipEntry): Promise<Buffer>;\n stream(entry: ZipEntry): Promise<NodeJS.ReadableStream>;\n close(): Promise<void>;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { ALL_SDKS } from './constants.js';\nimport { getSdkRootDir } from './paths.js';\nimport { getOsFolder } from './platform.js';\nimport type { ConfigProvider } from '../ports/config.js';\n\nexport interface SdkInfo {\n version: string;\n api: string;\n installed: boolean;\n}\n\n/**\n * List supported SDKs annotated with whether they are installed for the current OS.\n * Sorted by API descending (newest first).\n */\nexport function getSupportedSdksForUi(config: ConfigProvider): SdkInfo[] {\n const base = path.join(getSdkRootDir(config), getOsFolder());\n return ALL_SDKS.map((sdk) => ({\n version: sdk.version,\n api: sdk.api,\n installed: fs.existsSync(path.join(base, sdk.api)),\n })).sort((a, b) => Number(b.api) - Number(a.api));\n}\n\n/**\n * Return the SDK versions that have at least one OS-folder install in `sdkRootDir`.\n * Scans `linux`, `darwin`, `windows` so the list is consistent across machines that\n * share an SDK root over a network mount.\n */\nexport function getInstalledSdks(config: ConfigProvider): string[] {\n const sdkRoot = getSdkRootDir(config);\n const versions = new Set<string>();\n if (!fs.existsSync(sdkRoot)) return [];\n\n for (const osFolder of ['linux', 'darwin', 'windows'] as const) {\n const osPath = path.join(sdkRoot, osFolder);\n if (!fs.existsSync(osPath) || !fs.statSync(osPath).isDirectory()) continue;\n for (const api of fs.readdirSync(osPath)) {\n const apiPath = path.join(osPath, api);\n if (fs.statSync(apiPath).isDirectory()) versions.add(api);\n }\n }\n return ALL_SDKS.filter((sdk) => versions.has(sdk.api)).map((sdk) => sdk.version);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { getSdkRootDir } from './paths.js';\nimport type { ConfigProvider } from '../ports/config.js';\n\n/**\n * Remove an installed SDK for a given API level, across all OS folders.\n * Returns true if at least one folder was deleted.\n */\nexport function removeSdk(config: ConfigProvider, api: string): boolean {\n const sdkRoot = getSdkRootDir(config);\n let removed = false;\n for (const osFolder of ['linux', 'darwin', 'windows']) {\n const sdkPath = path.join(sdkRoot, osFolder, api);\n if (fs.existsSync(sdkPath)) {\n fs.rmSync(sdkPath, { recursive: true, force: true });\n removed = true;\n }\n }\n return removed;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { ProgressReporter } from '../ports/progress.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { CancelledError, OniroError } from '../ports/errors.js';\nimport { OHOS_URL_BASE } from './constants.js';\nimport { getSdkFilename } from './platform.js';\nimport { getSdkRootDir } from './paths.js';\nimport { downloadFile, verifySha256 } from './download.js';\nimport { extractTarball, extractZipWithProgress } from './extract.js';\nimport { movePath } from './move.js';\nimport { createInstallTempDir, removeTempWorkDir, toSpaceError } from './tmp.js';\n\nexport interface InstallSdkOptions {\n config: ConfigProvider;\n version: string;\n api: string;\n progress?: ProgressReporter;\n abortSignal?: AbortSignal;\n logger?: Logger;\n /**\n * Scratch directory for the download/extract temporaries. Overrides the `tmpDir`\n * config key and the default location next to the install target.\n */\n tmpDir?: string;\n}\n\n/**\n * Download and install an OpenHarmony SDK release into `<sdkRootDir>/<osFolder>/<api>`.\n *\n * Progress budget (overall 0..100):\n * 0..35 SDK archive download\n * 35..45 Checksum download\n * 45..50 Checksum verify\n * 50..60 Tarball extract\n * 60..95 Component ZIP extracts\n * 95..100 Finalize + cleanup\n */\nexport async function downloadAndInstallSdk(opts: InstallSdkOptions): Promise<void> {\n const { config, version, api, progress, abortSignal } = opts;\n const logger = opts.logger ?? noopLogger;\n\n const { filename, osFolder, strip } = getSdkFilename(version);\n const urlBase = config.get('sdkUrlBase', OHOS_URL_BASE);\n const downloadUrl = `${urlBase}/${version}-Release/${filename}`;\n const sha256Url = `${downloadUrl}.sha256`;\n\n const what = `the SDK ${version} install`;\n const sdkRoot = getSdkRootDir(config);\n const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({\n config,\n override: opts.tmpDir,\n installRoot: sdkRoot,\n prefix: 'oniro-sdk-',\n logger,\n });\n const tarPath = path.join(tmpDir, filename);\n const sha256Path = path.join(tmpDir, `${filename}.sha256`);\n const extractDir = path.join(tmpDir, 'extract');\n fs.mkdirSync(extractDir);\n\n const sdkInstallDir = path.join(sdkRoot, osFolder, api);\n fs.mkdirSync(path.dirname(sdkInstallDir), { recursive: true });\n\n const checkCancelled = () => {\n if (abortSignal?.aborted) throw new CancelledError();\n };\n\n try {\n progress?.report({ message: 'Downloading SDK archive...', increment: 0 });\n await downloadFile({ url: downloadUrl, dest: tarPath, progress, abortSignal, start: 0, range: 35, what, tmpRoot });\n\n progress?.report({ message: 'Downloading checksum...', increment: 0 });\n await downloadFile({ url: sha256Url, dest: sha256Path, progress, abortSignal, start: 35, range: 10, what, tmpRoot });\n\n progress?.report({ message: 'Verifying checksum...', increment: 0 });\n await verifySha256(tarPath, sha256Path);\n progress?.report({ message: 'Verifying checksum...', increment: 5 });\n\n checkCancelled();\n\n progress?.report({ message: 'Extracting SDK (this may take a while)...', increment: 0 });\n await extractTarball(tarPath, extractDir, strip);\n progress?.report({ message: 'Extracting SDK (this may take a while)...', increment: 10 });\n\n checkCancelled();\n\n const osContentPath = path.join(extractDir, osFolder);\n if (!fs.existsSync(osContentPath)) {\n throw new OniroError(\n `Expected folder '${osFolder}' not found in extracted SDK. Tarball layout may have changed.`,\n );\n }\n const zipFiles = fs.readdirSync(osContentPath).filter((n) => n.endsWith('.zip'));\n\n const componentsStart = 60;\n const componentsBudget = 35;\n const n = zipFiles.length;\n if (n === 0) {\n progress?.report({ message: 'No SDK component ZIPs found.', increment: componentsBudget });\n } else {\n progress?.report({ message: 'Extracting SDK components...', increment: 0 });\n }\n\n const base = n > 0 ? Math.floor(componentsBudget / n) : 0;\n let rem = n > 0 ? componentsBudget % n : 0;\n let cursor = componentsStart;\n\n for (const zipFile of zipFiles) {\n checkCancelled();\n logger.info(`Extracting component ${zipFile}`);\n const zipPath = path.join(osContentPath, zipFile);\n const thisBudget = base + (rem > 0 ? 1 : 0);\n if (rem > 0) rem--;\n await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });\n cursor += thisBudget;\n fs.unlinkSync(zipPath);\n }\n\n progress?.report({ message: 'Finalizing installation...', increment: 0 });\n if (fs.existsSync(sdkInstallDir)) {\n fs.rmSync(sdkInstallDir, { recursive: true, force: true });\n }\n movePath(osContentPath, sdkInstallDir);\n progress?.report({ message: 'Finalizing installation...', increment: 3 });\n\n progress?.report({ message: 'Cleaning up...', increment: 0 });\n removeTempWorkDir(tmpDir, tmpRoot);\n progress?.report({ message: 'Cleaning up...', increment: 2 });\n } catch (err) {\n const wrapped = toSpaceError(err, tmpRoot, what);\n logger.error(`SDK install failed: ${wrapped instanceof Error ? wrapped.message : String(wrapped)}`);\n removeTempWorkDir(tmpDir, tmpRoot);\n throw wrapped;\n }\n}\n","import * as fs from 'node:fs';\n\n/**\n * Move a file or directory from `src` to `dest`.\n *\n * Prefers an atomic `rename`, but transparently falls back to a recursive\n * copy-then-remove when the two paths live on different filesystems. `rename(2)`\n * fails with `EXDEV` across mount boundaries, which happens routinely during\n * install: the OS temp dir (where archives are extracted) and the install target\n * are frequently separate devices — a `tmpfs` `/tmp` with an on-disk home, a Docker\n * volume or bind mount at the install path, an overlay vs. a mounted cache, etc.\n *\n * Callers are expected to have already cleared `dest` if it must be replaced\n * (both current callers `rmSync` first). The copy preserves file modes and\n * symlinks (Node's default `cp` behavior), which the SDK/toolchains rely on.\n */\nexport function movePath(src: string, dest: string): void {\n try {\n fs.renameSync(src, dest);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'EXDEV') throw err;\n // Cross-device move: copy the tree, then drop the source.\n fs.cpSync(src, dest, { recursive: true });\n fs.rmSync(src, { recursive: true, force: true });\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport type { ConfigProvider } from '../ports/config.js';\nimport { defaultPaths } from '../ports/config.js';\nimport type { ProgressReporter } from '../ports/progress.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError, UnsupportedPlatformError } from '../ports/errors.js';\nimport { getCmdToolsPath, getHdcPath } from '../sdk/paths.js';\nimport { downloadFile } from '../sdk/download.js';\nimport { extractZipWithProgress } from '../sdk/extract.js';\nimport { movePath } from '../sdk/move.js';\nimport { buildCmdWrapper, needsCmdWrapper } from '../hdc/spawnCompat.js';\nimport { createInstallTempDir, removeTempWorkDir, toSpaceError } from '../sdk/tmp.js';\n\n/**\n * Resolve the per-platform download URL for the OpenHarmony command-line tools.\n *\n * Only Linux has a public download URL on the Huawei mirror. Windows and macOS\n * builds are gated behind the Huawei developer portal: users must download the\n * ZIP manually and pass it via `--from-zip`, or self-host the archive and point\n * `cmdToolsUrlWindows` / `cmdToolsUrlMac` at it.\n *\n * @param platform Defaults to the current host. Override for testing.\n */\nexport function getCmdToolsDownloadUrl(config: ConfigProvider, platform: NodeJS.Platform = os.platform()): string {\n if (platform === 'linux') {\n return config.get('cmdToolsUrlLinux', defaultPaths.cmdToolsUrlLinux);\n }\n if (platform === 'win32') {\n const url = config.get('cmdToolsUrlWindows', '');\n if (!url) {\n throw new OniroError(\n 'No Windows command-line tools URL configured. The Huawei mirror does not host a public Windows build; ' +\n 'download the ZIP from the Huawei developer portal and run `oniro-app cmdtools install --from-zip <path>`, ' +\n 'or set ONIRO_CMD_TOOLS_URL_WINDOWS to a self-hosted URL.',\n );\n }\n return url;\n }\n if (platform === 'darwin') {\n const url = config.get('cmdToolsUrlMac', '');\n if (!url) {\n throw new OniroError(\n 'No macOS command-line tools URL configured. The Huawei mirror does not host a public macOS build; ' +\n 'download the ZIP from the Huawei developer portal and run `oniro-app cmdtools install --from-zip <path>`, ' +\n 'or set ONIRO_CMD_TOOLS_URL_MAC to a self-hosted URL.',\n );\n }\n return url;\n }\n throw new UnsupportedPlatformError(platform);\n}\n\n/**\n * Locate the extracted command-line tools' source root within a temp extraction folder.\n * Tries known top-level names, then any subdirectory containing a `bin/` folder.\n */\nexport function findCmdToolsSourceDir(extractPath: string): string {\n const known = [\n path.join(extractPath, 'command-line-tools'),\n path.join(extractPath, 'oh-command-line-tools'),\n path.join(extractPath, 'commandline-tools'),\n ];\n for (const c of known) {\n if (fs.existsSync(c)) return c;\n }\n const entries = fs\n .readdirSync(extractPath, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => path.join(extractPath, e.name));\n for (const dir of entries) {\n if (fs.existsSync(path.join(dir, 'bin'))) return dir;\n }\n throw new OniroError('Could not locate command line tools folder in the extracted archive.');\n}\n\nexport interface InstallCmdToolsOptions {\n config: ConfigProvider;\n progress?: ProgressReporter;\n abortSignal?: AbortSignal;\n logger?: Logger;\n /** Skip download and install from a local zip the caller already has. */\n localZipPath?: string;\n /**\n * Scratch directory for the download/extract temporaries. Overrides the `tmpDir`\n * config key and the default location next to the install target.\n */\n tmpDir?: string;\n}\n\n/**\n * Install the OpenHarmony command-line tools into `<cmdToolsPath>`.\n * Either downloads from the platform-specific URL or installs from a caller-supplied ZIP.\n */\nexport async function installCmdTools(opts: InstallCmdToolsOptions): Promise<void> {\n const { config, progress, abortSignal } = opts;\n const logger = opts.logger ?? noopLogger;\n const CMD_PATH = getCmdToolsPath(config);\n const what = 'the command-line tools install';\n\n const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({\n config,\n override: opts.tmpDir,\n installRoot: path.dirname(CMD_PATH),\n prefix: 'oniro-cmdtools-',\n logger,\n });\n const zipPath = opts.localZipPath ?? path.join(tmpDir, 'oh-command-line-tools.zip');\n const extractPath = path.join(tmpDir, 'oh-command-line-tools');\n\n try {\n if (!opts.localZipPath) {\n const url = getCmdToolsDownloadUrl(config);\n progress?.report({ message: 'Downloading command line tools...', increment: 0 });\n await downloadFile({ url, dest: zipPath, progress, abortSignal, start: 0, range: 50, what, tmpRoot });\n }\n\n progress?.report({ message: 'Extracting tools...', increment: 0 });\n await extractZipWithProgress({ zipPath, dest: extractPath, progress, start: 50, range: 45, logger });\n\n fs.mkdirSync(CMD_PATH, { recursive: true });\n const srcDir = findCmdToolsSourceDir(extractPath);\n\n for (const entry of fs.readdirSync(srcDir)) {\n const src = path.join(srcDir, entry);\n const dest = path.join(CMD_PATH, entry);\n if (fs.statSync(src).isDirectory()) {\n if (fs.existsSync(dest)) fs.rmSync(dest, { recursive: true, force: true });\n movePath(src, dest);\n } else {\n fs.copyFileSync(src, dest);\n }\n }\n\n const binDir = path.join(CMD_PATH, 'bin');\n if (fs.existsSync(binDir) && os.platform() !== 'win32') {\n for (const file of fs.readdirSync(binDir)) {\n fs.chmodSync(path.join(binDir, file), 0o755);\n }\n }\n\n progress?.report({ message: 'Finalizing installation...', increment: 5 });\n progress?.report({ message: 'Cleaning up...', increment: 0 });\n } catch (err) {\n throw toSpaceError(err, tmpRoot, what);\n } finally {\n removeTempWorkDir(tmpDir, tmpRoot);\n }\n}\n\nexport interface CmdToolsStatus {\n installed: boolean;\n status: string;\n /** Install directory (the configured `cmdToolsPath`). */\n path: string;\n /** Which SDK flavour the tools ship; see {@link detectCmdToolsFlavour}. Set when installed. */\n flavour?: CmdToolsFlavour;\n /** The hdc binary commands use, and whether it exists. */\n hdc: { path: string; exists: boolean };\n}\n\nexport type CmdToolsFlavour = 'HarmonyOS' | 'OpenHarmony';\n\n/**\n * The flavour of a command-line tools install: `HarmonyOS` when it bundles the\n * HarmonyOS SDK (`sdk/default/hms`, as the Huawei developer-portal download\n * does), otherwise `OpenHarmony`. codelinter only fully checks projects of its\n * own flavour (`runtimeOS` in build-profile.json5).\n */\nexport function detectCmdToolsFlavour(cmdToolsPath: string): CmdToolsFlavour {\n return fs.existsSync(path.join(cmdToolsPath, 'sdk', 'default', 'hms')) ? 'HarmonyOS' : 'OpenHarmony';\n}\n\n/**\n * Reports whether ohpm is present at the configured path, and if so its version,\n * flavour, and the hdc binary in use. Prefers reading `version.txt`\n * (`# Version: x.y.z`) before falling back to executing the binary with `-v`.\n */\nexport function getCmdToolsStatus(config: ConfigProvider): CmdToolsStatus {\n const cmdPath = getCmdToolsPath(config);\n const hdcPath = getHdcPath(config);\n const base = { path: cmdPath, hdc: { path: hdcPath, exists: fs.existsSync(hdcPath) } };\n const binDir = path.join(cmdPath, 'bin');\n const candidates = os.platform() === 'win32'\n ? ['ohpm.exe', 'ohpm.cmd', 'ohpm.bat', 'ohpm']\n : ['ohpm'];\n const bin = candidates.map((c) => path.join(binDir, c)).find((p) => fs.existsSync(p));\n if (!bin) {\n return { installed: false, status: 'Not installed', ...base };\n }\n const installed = { installed: true, ...base, flavour: detectCmdToolsFlavour(cmdPath) };\n\n // Prefer version.txt.\n try {\n const versionFile = path.join(cmdPath, 'version.txt');\n if (fs.existsSync(versionFile)) {\n const content = fs.readFileSync(versionFile, 'utf8');\n for (const line of content.split(/\\r?\\n/)) {\n const m = line.match(/^\\s*#\\s*Version:\\s*(.+)$/);\n if (m?.[1]) return { ...installed, status: `Installed (${m[1].trim()})` };\n }\n }\n } catch {\n // Fall through to exec.\n }\n\n try {\n // `ohpm` is a .bat wrapper on Windows, which cannot be spawned directly\n // (EINVAL since Node 20.12.2) — go through cmd.exe there.\n const wrapped = needsCmdWrapper(bin);\n const probe = wrapped ? buildCmdWrapper(bin, ['-v']) : { command: bin, args: ['-v'] };\n const res = spawnSync(probe.command, probe.args, {\n encoding: 'utf8',\n windowsVerbatimArguments: wrapped,\n });\n if (res.error || res.status !== 0) throw res.error ?? new Error(`exit ${String(res.status)}`);\n const version = res.stdout.trim();\n return { ...installed, status: `Installed (${version})` };\n } catch {\n return { ...installed, status: 'Installed (version unknown)' };\n }\n}\n\nexport function isCmdToolsInstalled(config: ConfigProvider): boolean {\n return getCmdToolsStatus(config).installed;\n}\n\nexport function removeCmdTools(config: ConfigProvider): void {\n const cmdPath = getCmdToolsPath(config);\n if (fs.existsSync(cmdPath)) {\n fs.rmSync(cmdPath, { recursive: true, force: true });\n }\n}\n","import * as path from 'node:path';\nimport { spawn, type ChildProcess, type SpawnOptions } from 'node:child_process';\nimport { OniroError } from '../ports/errors.js';\n\n/**\n * Windows batch wrappers (`.bat` / `.cmd`) cannot be executed by\n * `CreateProcess` — they are scripts interpreted by `cmd.exe`. Node used to\n * paper over that by silently prepending `cmd.exe /c`, but the fix for\n * CVE-2024-27980 (Node 18.20.2 / 20.12.2 / 21.7.3 and later) removed the\n * implicit shell: `spawn('foo.cmd', args)` with `shell: false` now throws a\n * bare `Error: spawn EINVAL`.\n *\n * That matters here because the OpenHarmony command-line tools ship as batch\n * wrappers on Windows (`ohpm.bat`, `hvigorw.bat`, `codelinter.bat`), so every\n * build and lint invocation hit that throw.\n *\n * We therefore invoke `cmd.exe /d /s /c \"<command> <args...>\"` explicitly.\n * Doing it ourselves — rather than passing `shell: true` — is what preserves\n * the \"arguments are never word-split\" guarantee the rest of this package\n * relies on: `shell: true` hands `cmd.exe` the raw, unescaped join of command\n * and args, reintroducing exactly the injection surface `runProcess` exists to\n * avoid. The escaping below follows https://qntm.org/cmd (the same algorithm\n * `cross-spawn` uses).\n */\n\nconst WINDOWS_BATCH_RE = /\\.(bat|cmd)$/i;\n\n/** Characters `cmd.exe` treats specially, including whitespace. */\nconst CMD_META_RE = /([()[\\]%!^\"`<>&|;, *?])/g;\n\n/**\n * npm-style shims (`node_modules/.bin/foo.cmd`) forward their arguments with a\n * bare `%*`, so the command line is parsed a second time inside the shim and\n * metacharacters need a second layer of escaping. Ordinary wrappers must NOT\n * be double-escaped — the surplus carets would end up in the argument values.\n */\nconst CMD_SHIM_RE = /node_modules[\\\\/]\\.bin[\\\\/][^\\\\/]+\\.cmd$/i;\n\n/**\n * Characters that cannot be passed through `cmd.exe` without ambiguity.\n *\n * The OpenHarmony wrappers end in `call \"<inner>\\tool.bat\" %*`, and the inner\n * script forwards the same `%*` to node — so every argument is re-parsed by\n * `cmd.exe` twice more after we hand off the command line. Quoting is what\n * survives those hops: metacharacters inside a quoted token stay inert no\n * matter how many times the line is re-parsed.\n *\n * A double quote is the one thing that breaks that. `cmd.exe` has no `\\\"`\n * escape — it simply toggles quote state on every `\"` — so an embedded quote\n * ends the quoted region early and everything after it is re-parsed as\n * command syntax. Newlines and NULs cannot be carried at all. None of the\n * tools invoked here need any of them, so we refuse loudly rather than pass\n * something subtly different from what the caller asked for.\n *\n * Known remaining edge: the wrappers run under `setlocal enabledelayedexpansion`,\n * so a literal `!` in an argument is subject to delayed expansion. It can\n * corrupt a value but not execute anything, and no argument this package builds\n * contains one.\n */\nconst UNSAFE_CMD_CHARS_RE = /[\"\\r\\n\\0]/;\n\n/**\n * True when `command` must be routed through `cmd.exe` to run at all —\n * i.e. we are on Windows and the target is a batch wrapper.\n *\n * `platform` is injectable so the behaviour is unit-testable off Windows.\n */\nexport function needsCmdWrapper(command: string, platform: NodeJS.Platform = process.platform): boolean {\n return platform === 'win32' && WINDOWS_BATCH_RE.test(command);\n}\n\n/**\n * Escape one argument for a `cmd.exe` command line: quote it, double the\n * backslashes that would otherwise escape the closing quote, then caret-escape\n * every metacharacter.\n *\n * `doubleEscapeMetaChars` adds the second caret layer needed by `%*`-forwarding\n * shims — see {@link CMD_SHIM_RE}.\n */\nexport function escapeCmdArgument(arg: string, doubleEscapeMetaChars = false): string {\n let out = String(arg);\n // Backslashes preceding a quote are doubled, and the quote itself escaped.\n out = out.replace(/(\\\\*)\"/g, '$1$1\\\\\"');\n // Trailing backslashes are doubled so they don't escape our closing quote.\n out = out.replace(/(\\\\*)$/, '$1$1');\n out = `\"${out}\"`;\n out = out.replace(CMD_META_RE, '^$1');\n if (doubleEscapeMetaChars) out = out.replace(CMD_META_RE, '^$1');\n return out;\n}\n\n/**\n * Escape the executable path. It is caret-escaped but deliberately NOT quoted:\n * `cmd.exe /s /c \"...\"` strips the outer quotes of the whole line, and a quoted\n * first token confuses that parse. Caret-escaping the spaces is what makes\n * `C:\\Program Files\\...` work.\n */\nexport function escapeCmdCommand(command: string): string {\n return command.replace(CMD_META_RE, '^$1');\n}\n\nexport interface CmdWrapper {\n command: string;\n args: string[];\n}\n\n/**\n * Build the `cmd.exe /d /s /c \"<command> <args...>\"` invocation for a batch\n * wrapper. Pure (no I/O, no spawning) so the escaping is unit-testable on every\n * platform.\n *\n * `/d` skips AutoRun registry commands, `/s` keeps the outer quotes intact,\n * `/c` runs the command and exits.\n *\n * @throws OniroError if the command or any argument contains a character that\n * cannot survive `cmd.exe` unambiguously (see {@link UNSAFE_CMD_CHARS_RE}).\n */\nexport function buildCmdWrapper(command: string, args: readonly string[]): CmdWrapper {\n assertCmdSafe(command, `command ${command}`);\n args.forEach((a, i) => assertCmdSafe(a, `argument ${i} (${a})`));\n\n // Forward slashes in a command path make cmd.exe report \"not recognized\".\n const normalized = path.normalize(command);\n const double = CMD_SHIM_RE.test(normalized);\n const line = [escapeCmdCommand(normalized), ...args.map((a) => escapeCmdArgument(a, double))].join(' ');\n return {\n command: process.env.ComSpec ?? process.env.COMSPEC ?? 'cmd.exe',\n args: ['/d', '/s', '/c', `\"${line}\"`],\n };\n}\n\nfunction assertCmdSafe(value: string, label: string): void {\n if (UNSAFE_CMD_CHARS_RE.test(value)) {\n throw new OniroError(\n `Cannot run a Windows batch wrapper with a quote, newline or NUL in the ${label}: ` +\n 'cmd.exe cannot pass it through unambiguously.',\n );\n }\n}\n\n/**\n * `child_process.spawn`, but able to run Windows batch wrappers.\n *\n * Identical to `spawn` everywhere else — on POSIX, and on Windows for real\n * executables, the command and args are passed straight through with\n * `shell: false`.\n */\nexport function spawnCompat(\n command: string,\n args: readonly string[],\n options: SpawnOptions = {},\n): ChildProcess {\n if (!needsCmdWrapper(command)) {\n return spawn(command, [...args], { ...options, shell: false });\n }\n const wrapped = buildCmdWrapper(command, args);\n return spawn(wrapped.command, wrapped.args, {\n ...options,\n shell: false,\n // The line is already escaped; stop Node from re-quoting it.\n windowsVerbatimArguments: true,\n });\n}\n\n/**\n * Kill a child and everything it started.\n *\n * On Windows a signal only reaches the process we spawned — killing the\n * `cmd.exe` wrapper leaves the Node/hvigor process it launched running, so an\n * aborted or timed-out build would keep holding the project's output files.\n * `taskkill /T /F` tears down the whole tree instead.\n */\nexport function killProcessTree(child: ChildProcess): void {\n if (process.platform === 'win32' && typeof child.pid === 'number') {\n try {\n const killer = spawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore' });\n // taskkill missing from PATH must not raise an unhandled 'error' event.\n killer.on('error', () => {\n try {\n child.kill('SIGKILL');\n } catch {\n /* already gone */\n }\n });\n return;\n } catch {\n /* fall through to the plain kill below */\n }\n }\n try {\n child.kill('SIGKILL');\n } catch {\n /* already gone */\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\n\nconst DAEMON_ROOT_KEY_COMPONENT_LENGTH = 16;\nconst DAEMON_SALT_KEY_LENGTH = 16;\nconst DAEMON_WORK_KEY_LENGTH = 16;\nconst KEY_FILE_DIRECTORY_PERMISSIONS = 0o755;\nconst KEY_FILE_PERMISSIONS = 0o600;\n\nconst COMPONENT = Buffer.from([\n 49, 243, 9, 115, 214, 175, 91, 184, 211, 190, 177, 88, 101, 131, 192, 119,\n]);\n\n/**\n * Encrypts data using AES-128-GCM.\n * Output layout: [4-byte BE length][12-byte IV][ciphertext][16-byte auth tag].\n */\nfunction encrypt(key: Buffer, data: Buffer): Buffer {\n const iv = crypto.randomBytes(12);\n const cipher = crypto.createCipheriv('aes-128-gcm', key, iv);\n const ciphertext = Buffer.concat([cipher.update(data), cipher.final()]);\n const authTag = cipher.getAuthTag();\n const totalLength = ciphertext.length + authTag.length;\n const out = Buffer.alloc(4 + iv.length + ciphertext.length + authTag.length);\n out.writeUInt32BE(totalLength, 0);\n iv.copy(out, 4);\n ciphertext.copy(out, 16);\n authTag.copy(out, 16 + ciphertext.length);\n return out;\n}\n\nfunction decrypt(key: Buffer, data: Buffer): Buffer {\n const totalLength = data.readUInt32BE(0);\n const iv = data.subarray(4, 16);\n const ciphertextLength = totalLength - 16;\n const ciphertext = data.subarray(16, 16 + ciphertextLength);\n const authTag = data.subarray(16 + ciphertextLength);\n const decipher = crypto.createDecipheriv('aes-128-gcm', key, iv);\n decipher.setAuthTag(authTag);\n return Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n}\n\nfunction xorBuffers(buffers: Buffer[]): Buffer {\n if (buffers.length === 0) {\n throw new Error('No buffers provided for XOR.');\n }\n const result = Buffer.from(buffers[0]!);\n for (let i = 1; i < buffers.length; i++) {\n const buf = buffers[i]!;\n if (buf.length !== result.length) {\n throw new Error('Buffers have different lengths in XOR.');\n }\n for (let j = 0; j < result.length; j++) {\n result[j] = result[j]! ^ buf[j]!;\n }\n }\n return result;\n}\n\nfunction getRootKey(fdComponents: Buffer[], salt: Buffer): Buffer {\n const components = fdComponents.concat([COMPONENT]);\n const xored = xorBuffers(components);\n return crypto.pbkdf2Sync(xored.toString(), salt, 10000, 16, 'sha256');\n}\n\nfunction createAndStoreKey(dir: string, keyLength: number): Buffer {\n const key = crypto.randomBytes(keyLength);\n const hash = crypto.createHash('sha256').update(key).digest('hex');\n const filePath = path.join(dir, hash);\n fs.writeFileSync(filePath, key);\n fs.chmodSync(filePath, KEY_FILE_PERMISSIONS);\n return key;\n}\n\nfunction createAndStoreEnKey(rootKey: Buffer, ceDir: string): void {\n const workKey = crypto.randomBytes(DAEMON_WORK_KEY_LENGTH);\n const encrypted = encrypt(rootKey, workKey);\n const hash = crypto.createHash('sha256').update(encrypted).digest('hex');\n const filePath = path.join(ceDir, hash);\n fs.writeFileSync(filePath, encrypted);\n fs.chmodSync(filePath, KEY_FILE_PERMISSIONS);\n}\n\n/**\n * Generates the signing-material directory tree: fd/{0,1,2}, ac, ce.\n * Each subfolder contains a randomly-named keyfile derived as described in\n * the OpenHarmony hap-sign-tool reference implementation.\n */\nexport function createMaterial(materialPath: string): void {\n fs.mkdirSync(materialPath, { recursive: true });\n fs.chmodSync(materialPath, KEY_FILE_DIRECTORY_PERMISSIONS);\n\n const fdDir = path.join(materialPath, 'fd');\n const acDir = path.join(materialPath, 'ac');\n const ceDir = path.join(materialPath, 'ce');\n\n fs.mkdirSync(fdDir, { recursive: true });\n fs.mkdirSync(acDir, { recursive: true });\n fs.mkdirSync(ceDir, { recursive: true });\n\n const fdSubDirs = ['0', '1', '2'];\n const fdComponents: Buffer[] = [];\n for (const sub of fdSubDirs) {\n const subDir = path.join(fdDir, sub);\n fs.mkdirSync(subDir, { recursive: true });\n const comp = createAndStoreKey(subDir, DAEMON_ROOT_KEY_COMPONENT_LENGTH);\n fdComponents.push(comp);\n }\n\n const salt = createAndStoreKey(acDir, DAEMON_SALT_KEY_LENGTH);\n const rootKey = getRootKey(fdComponents, salt);\n createAndStoreEnKey(rootKey, ceDir);\n}\n\nfunction readSingleFile(dir: string): Buffer {\n if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {\n throw new Error(`Missing signing material directory: ${dir}`);\n }\n const files = fs.readdirSync(dir).filter((f) => f !== '.DS_Store');\n if (files.length !== 1) {\n throw new Error(`Signing material in ${dir} is illegal (expected exactly one file).`);\n }\n return fs.readFileSync(path.join(dir, files[0]!));\n}\n\n/**\n * Re-derives the work key from an existing material directory.\n */\nexport function getKey(materialPath: string): Buffer {\n if (!fs.existsSync(materialPath) || !fs.statSync(materialPath).isDirectory()) {\n throw new Error('Material directory does not exist.');\n }\n\n const fdDir = path.join(materialPath, 'fd');\n const fdComponents = ['0', '1', '2'].map((sub) => readSingleFile(path.join(fdDir, sub)));\n const salt = readSingleFile(path.join(materialPath, 'ac'));\n const rootKey = getRootKey(fdComponents, salt);\n const workMaterial = readSingleFile(path.join(materialPath, 'ce'));\n return decrypt(rootKey, workMaterial);\n}\n\n/**\n * Encrypts a password using the work key derived from `materialPath`.\n * Returns the encrypted blob as a hex string (the format expected in build-profile.json5).\n */\nexport function encryptPwd(password: string, materialPath: string): string {\n const key = getKey(materialPath);\n const pwdBuffer = Buffer.from(password, 'utf-8');\n return encrypt(key, pwdBuffer).toString('hex');\n}\n\n/**\n * Inverse of `encryptPwd`. Exposed for parity with the original CLI.\n */\nexport function decryptPwd(encryptedHex: string, materialPath: string): string {\n const key = getKey(materialPath);\n const encryptedBuffer = Buffer.from(encryptedHex, 'hex');\n return decrypt(key, encryptedBuffer).toString('utf-8');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { execFileSync } from 'node:child_process';\nimport JSON5 from 'json5';\nimport { encryptPwd, createMaterial } from './encryptKey.js';\nimport { OPEN_HARMONY_APPLICATION_CERT } from './applicationCert.js';\nimport { detectProjectSdkVersion } from '../sdk/detectProjectSdk.js';\nimport { ALL_SDKS } from '../sdk/constants.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError, SdkNotInstalledError } from '../ports/errors.js';\n\n/** Ability Privilege Level written into the profile's `bundle-info.apl`. */\nexport type Apl = 'normal' | 'system_basic' | 'system_core';\n\n/** App feature written into the profile's `bundle-info.app-feature`. */\nexport type AppFeature = 'hos_normal_app' | 'hos_system_app';\n\nexport const APL_VALUES: readonly Apl[] = ['normal', 'system_basic', 'system_core'];\nexport const APP_FEATURE_VALUES: readonly AppFeature[] = ['hos_normal_app', 'hos_system_app'];\n\n/** Keystore passwords. These must match the keystore in use. */\nexport interface SigningPasswords {\n store: string;\n key: string;\n}\n\nconst DEFAULT_PASSWORDS: SigningPasswords = { store: '123456', key: '123456' };\n\n/**\n * Which signing key pairs with the chosen `apl`.\n *\n * - `'profile-release'` — the **OpenHarmony Application Profile Release** key.\n * Default for apl=normal. Matches the cert chain that ships with the SDK\n * (`OpenHarmonyProfileRelease.pem`). What `hvigor` uses for ordinary apps.\n *\n * - `'application-release'` — the **OpenHarmony Application Release** key.\n * Required for apl=system_basic|system_core. BMS's parse-profile-prop check\n * rejects HAPs whose `distribution-certificate` subject is \"Application\n * Profile Release\" when the HAP requests permissions above its apl. The\n * matching cert chain (`OpenHarmonyApplication.cer`) is not shipped in the\n * SDK, so we ship it ourselves under `applicationCert.ts`.\n */\nexport type SigningKind = 'profile-release' | 'application-release';\n\n/** @internal exposed for tests. */\nexport function pickSigningKind(apl: Apl): SigningKind {\n return apl === 'normal' ? 'profile-release' : 'application-release';\n}\n\ninterface SigningKindConfig {\n /** keystore alias used by hvigor's SignHap task. */\n hapKeyAlias: string;\n /** filename of the cert chain inside `signatures/` referenced by build-profile.json5 `certpath`. */\n certBasename: string;\n}\n\nconst SIGNING_KIND_CONFIG: Record<SigningKind, SigningKindConfig> = {\n 'profile-release': {\n hapKeyAlias: 'openharmony application profile release',\n certBasename: 'OpenHarmonyProfileRelease.pem',\n },\n 'application-release': {\n hapKeyAlias: 'OpenHarmony Application Release',\n certBasename: 'OpenHarmonyApplication.cer',\n },\n};\n\nexport interface GenerateSigningConfigsOptions {\n /** Absolute path to the OpenHarmony project (the folder containing build-profile.json5). */\n projectDir: string;\n /** Absolute path to the OS-specific SDK home (the folder containing API-version subfolders). */\n sdkHome: string;\n /**\n * APL level to write into the profile's `bundle-info.apl`. Defaults to `'normal'`.\n * Apps requesting permissions above `normal` (e.g. `ohos.permission.GET_WIFI_INFO_INTERNAL`)\n * need `system_basic` or `system_core` — otherwise `bm install` fails with\n * `grant request permissions failed`.\n */\n apl?: Apl;\n /**\n * App feature to write into `bundle-info.app-feature`. Defaults to `'hos_normal_app'`\n * when `apl='normal'`, otherwise `'hos_system_app'`.\n */\n appFeature?: AppFeature;\n /**\n * Permission names to write into the profile's `acls.allowed-acls`. Required for\n * apps that request permissions above their `apl` (e.g. a system_basic app\n * requesting `ohos.permission.CAPTURE_SCREEN`). When omitted, the template's\n * existing `allowed-acls` is left alone.\n */\n acls?: string[];\n /**\n * Privileges to write into the profile's `app-privilege-capabilities`, e.g.\n * `AllowAppUsePrivilegeExtension` for an app that declares a privileged extension\n * ability (else install fails with 9568344 \"not allow use privilege extension\"),\n * `AllowAppMultiProcess` or `AllowAppDesktopIconHide`. When omitted, the\n * template's value is left alone.\n */\n appPrivilegeCapabilities?: string[];\n /**\n * Keystore passwords written into the profile sign step and the build-profile\n * signingConfigs. Defaults to `'123456'` (the SDK's bundled OpenHarmony.p12\n * password). Only override when supplying a matching custom keystore.\n */\n passwords?: SigningPasswords;\n /**\n * Override the bundled application cert chain (application-release kind only).\n * When set, this file is copied to `signatures/OpenHarmonyApplication.cer`\n * instead of the inlined cert. May also be sourced from `config.applicationCertPath`.\n */\n applicationCertPath?: string;\n /** Optional logger; defaults to no-op. */\n logger?: Logger;\n}\n\nfunction copyFilesToProject(\n projectDir: string,\n paths: { keystore: string; profileCert: string; unsignedProfileTemplate: string },\n kind: SigningKind,\n logger: Logger,\n applicationCertPath?: string,\n): void {\n logger.info('[sign] Copying signing material into project...');\n const signaturesDir = path.join(projectDir, 'signatures');\n fs.mkdirSync(signaturesDir, { recursive: true });\n\n fs.copyFileSync(paths.keystore, path.join(signaturesDir, 'OpenHarmony.p12'));\n fs.copyFileSync(paths.profileCert, path.join(signaturesDir, 'OpenHarmonyProfileRelease.pem'));\n fs.copyFileSync(paths.unsignedProfileTemplate, path.join(signaturesDir, 'UnsgnedReleasedProfileTemplate.json'));\n\n if (kind === 'application-release') {\n const dest = path.join(signaturesDir, 'OpenHarmonyApplication.cer');\n if (applicationCertPath) {\n fs.copyFileSync(applicationCertPath, dest);\n } else {\n fs.writeFileSync(dest, OPEN_HARMONY_APPLICATION_CERT);\n }\n }\n}\n\n/**\n * Pick the app-feature value: explicit override wins; otherwise `hos_normal_app` for\n * apl=normal, `hos_system_app` for system_basic/system_core.\n * @internal exposed for tests.\n */\nexport function resolveAppFeature(apl: Apl, override?: AppFeature): AppFeature {\n if (override) return override;\n return apl === 'normal' ? 'hos_normal_app' : 'hos_system_app';\n}\n\n/**\n * Read the third certificate (the leaf) from a 3-cert PEM chain. The chain is\n * stored root → intermediate → leaf, so the distribution-certificate we want\n * is the third block.\n */\nfunction extractLeafCertificate(chainPath: string): string {\n const certContent = fs.readFileSync(chainPath, 'utf-8');\n const parts = certContent.split('-----END CERTIFICATE-----');\n if (parts.length < 3) {\n throw new OniroError(`${chainPath} does not contain enough certificates.`);\n }\n return parts[2]!.trim() + '\\n-----END CERTIFICATE-----\\n';\n}\n\n/** @internal exposed for tests. */\nexport function modifyProfileTemplate(\n projectDir: string,\n apl: Apl,\n appFeature: AppFeature,\n logger: Logger,\n options: { kind?: SigningKind; acls?: string[]; appPrivilegeCapabilities?: string[] } = {},\n): void {\n const kind = options.kind ?? pickSigningKind(apl);\n logger.info(`[sign] Modifying profile template (apl=${apl}, app-feature=${appFeature}, kind=${kind})...`);\n const appJsonPath = path.join(projectDir, 'AppScope/app.json5');\n const profileTemplatePath = path.join(projectDir, 'signatures/UnsgnedReleasedProfileTemplate.json');\n\n if (!fs.existsSync(appJsonPath)) {\n throw new OniroError(`${appJsonPath} does not exist.`);\n }\n\n let appJson: { app?: { bundleName?: string } };\n try {\n appJson = JSON5.parse(fs.readFileSync(appJsonPath, 'utf-8'));\n } catch (e) {\n throw new OniroError(`Error parsing ${appJsonPath}: ${(e as Error).message}`, e);\n }\n\n let profileTemplate: {\n 'bundle-info'?: {\n 'bundle-name'?: string;\n 'distribution-certificate'?: string;\n apl?: string;\n 'app-feature'?: string;\n };\n acls?: { 'allowed-acls'?: string[] };\n 'app-privilege-capabilities'?: string[];\n };\n try {\n profileTemplate = JSON.parse(fs.readFileSync(profileTemplatePath, 'utf-8'));\n } catch (e) {\n throw new OniroError(`Error parsing ${profileTemplatePath}: ${(e as Error).message}`, e);\n }\n\n if (!appJson.app?.bundleName) {\n throw new OniroError('app.json5 does not contain app.bundleName.');\n }\n if (!profileTemplate['bundle-info']) {\n throw new OniroError('UnsgnedReleasedProfileTemplate.json is missing the bundle-info section.');\n }\n\n profileTemplate['bundle-info']['bundle-name'] = appJson.app.bundleName;\n profileTemplate['bundle-info']['apl'] = apl;\n profileTemplate['bundle-info']['app-feature'] = appFeature;\n\n const distCertChainPath = path.join(\n projectDir,\n 'signatures',\n SIGNING_KIND_CONFIG[kind].certBasename,\n );\n profileTemplate['bundle-info']['distribution-certificate'] = extractLeafCertificate(distCertChainPath);\n\n if (options.acls !== undefined) {\n profileTemplate.acls = profileTemplate.acls ?? {};\n profileTemplate.acls['allowed-acls'] = options.acls;\n }\n if (options.appPrivilegeCapabilities !== undefined) {\n profileTemplate['app-privilege-capabilities'] = options.appPrivilegeCapabilities;\n }\n\n fs.writeFileSync(profileTemplatePath, JSON.stringify(profileTemplate, null, 2));\n}\n\nfunction generateP7bFile(\n projectDir: string,\n paths: { signTool: string; profileCert: string; keystore: string },\n logger: Logger,\n passwords: SigningPasswords,\n): void {\n logger.info('[sign] Generating P7b profile via hap-sign-tool...');\n const signaturesDir = path.join(projectDir, 'signatures');\n const profileTemplatePath = path.join(signaturesDir, 'UnsgnedReleasedProfileTemplate.json');\n const outputProfilePath = path.join(signaturesDir, 'app1-profile.p7b');\n\n // The profile itself is always signed by the Profile Release key, regardless\n // of the HAP signing kind. The profile's `distribution-certificate` field\n // (set by modifyProfileTemplate) is what tells BMS which cert will sign the HAP.\n const args = [\n '-jar', paths.signTool,\n 'sign-profile',\n '-keyAlias', 'openharmony application profile release',\n '-signAlg', 'SHA256withECDSA',\n '-mode', 'localSign',\n '-profileCertFile', paths.profileCert,\n '-inFile', profileTemplatePath,\n '-keystoreFile', paths.keystore,\n '-outFile', outputProfilePath,\n '-keyPwd', passwords.key,\n '-keystorePwd', passwords.store,\n ];\n\n try {\n execFileSync('java', args, { stdio: 'inherit' });\n } catch (e) {\n throw new OniroError(\n `hap-sign-tool failed. Ensure a JDK (with keytool/java) is on PATH. Underlying error: ${(e as Error).message}`,\n e,\n );\n }\n}\n\n/**\n * Read all `products[*].signingConfig` names from the project's build-profile.json5.\n * Returns the unique names in declaration order. Falls back to `['default']` when\n * the file is missing or has no products.\n * @internal exposed for tests.\n */\nexport function detectSigningConfigNames(projectDir: string): string[] {\n const buildProfilePath = path.join(projectDir, 'build-profile.json5');\n if (!fs.existsSync(buildProfilePath)) return ['default'];\n\n let parsed: { app?: { products?: Array<{ signingConfig?: unknown }> } };\n try {\n parsed = JSON5.parse(fs.readFileSync(buildProfilePath, 'utf-8'));\n } catch {\n return ['default'];\n }\n\n const products = parsed.app?.products;\n if (!Array.isArray(products) || products.length === 0) return ['default'];\n\n const names: string[] = [];\n for (const product of products) {\n const name = product.signingConfig;\n if (typeof name === 'string' && name.length > 0 && !names.includes(name)) {\n names.push(name);\n }\n }\n return names.length > 0 ? names : ['default'];\n}\n\n/** @internal exposed for tests. Needs `signatures/material` (see {@link createMaterial}). */\nexport function updateBuildProfile(projectDir: string, kind: SigningKind, logger: Logger, passwords: SigningPasswords): void {\n logger.info('[sign] Writing signing configs into build-profile.json5...');\n const materialDir = path.join(projectDir, 'signatures', 'material');\n const buildProfilePath = path.join(projectDir, 'build-profile.json5');\n\n const encryptedStorePassword = encryptPwd(passwords.store, materialDir);\n const encryptedKeyPassword = encryptPwd(passwords.key, materialDir);\n\n let buildProfile: { app?: { signingConfigs?: unknown[]; products?: Array<{ signingConfig?: unknown }> } } = { app: {} };\n if (fs.existsSync(buildProfilePath)) {\n try {\n buildProfile = JSON5.parse(fs.readFileSync(buildProfilePath, 'utf-8'));\n } catch (e) {\n throw new OniroError(`Error parsing ${buildProfilePath}: ${(e as Error).message}`, e);\n }\n }\n\n const { hapKeyAlias, certBasename } = SIGNING_KIND_CONFIG[kind];\n const configNames = detectSigningConfigNames(projectDir);\n logger.info(`[sign] Writing signingConfigs entries: ${configNames.join(', ')}`);\n\n buildProfile.app = buildProfile.app ?? {};\n buildProfile.app.signingConfigs = configNames.map((name) => ({\n name,\n material: {\n certpath: `./signatures/${certBasename}`,\n storePassword: encryptedStorePassword,\n keyAlias: hapKeyAlias,\n keyPassword: encryptedKeyPassword,\n profile: './signatures/app1-profile.p7b',\n signAlg: 'SHA256withECDSA',\n storeFile: './signatures/OpenHarmony.p12',\n },\n }));\n // A product that names no signingConfig builds unsigned HAPs even with one defined.\n for (const product of buildProfile.app.products ?? []) {\n if (typeof product.signingConfig !== 'string' || product.signingConfig === '') {\n product.signingConfig = configNames[0];\n logger.info(`[sign] Pointing a product with no signingConfig at \"${configNames[0]}\".`);\n }\n }\n\n // Intentionally strict JSON (not JSON5) — keeps the file readable by VS Code's JSON parser.\n fs.writeFileSync(buildProfilePath, JSON.stringify(buildProfile, null, 2));\n}\n\nfunction prepareMaterialDirectory(projectDir: string, logger: Logger): void {\n logger.info('[sign] Generating fresh signing material...');\n const materialDir = path.join(projectDir, 'signatures', 'material');\n if (fs.existsSync(materialDir)) {\n fs.rmSync(materialDir, { recursive: true, force: true });\n }\n createMaterial(materialDir);\n}\n\n/**\n * Generate signing configs for an OpenHarmony project: copies certs, signs the profile,\n * generates the signing material, and writes the resulting `signingConfigs` entry into\n * `build-profile.json5`.\n *\n * Requires `java` on PATH (the OpenHarmony hap-sign-tool ships as a .jar).\n */\nexport function generateSigningConfigs(options: GenerateSigningConfigsOptions): void {\n const { projectDir, sdkHome } = options;\n const logger = options.logger ?? noopLogger;\n const apl: Apl = options.apl ?? 'normal';\n if (!APL_VALUES.includes(apl)) {\n throw new OniroError(`Invalid apl '${apl}'. Expected one of: ${APL_VALUES.join(', ')}.`);\n }\n const appFeature: AppFeature = resolveAppFeature(apl, options.appFeature);\n if (!APP_FEATURE_VALUES.includes(appFeature)) {\n throw new OniroError(\n `Invalid appFeature '${appFeature}'. Expected one of: ${APP_FEATURE_VALUES.join(', ')}.`,\n );\n }\n\n const sdkVersion = detectProjectSdkVersion(projectDir, logger);\n if (!sdkVersion) {\n throw new OniroError(\n 'Could not detect project SDK version (compileSdkVersion missing in build-profile.json5).',\n );\n }\n\n const sdkPath = path.join(sdkHome, String(sdkVersion));\n if (!fs.existsSync(sdkPath)) {\n throw new SdkNotInstalledError(String(sdkVersion), sdkPath, ALL_SDKS.find((s) => s.api === String(sdkVersion))?.version);\n }\n\n const paths = {\n signTool: path.join(sdkPath, 'toolchains/lib/hap-sign-tool.jar'),\n keystore: path.join(sdkPath, 'toolchains/lib/OpenHarmony.p12'),\n profileCert: path.join(sdkPath, 'toolchains/lib/OpenHarmonyProfileRelease.pem'),\n unsignedProfileTemplate: path.join(sdkPath, 'toolchains/lib/UnsgnedReleasedProfileTemplate.json'),\n };\n\n const kind = pickSigningKind(apl);\n const passwords = options.passwords ?? DEFAULT_PASSWORDS;\n\n logger.info('[sign] Starting signing configuration generation...');\n copyFilesToProject(projectDir, paths, kind, logger, options.applicationCertPath);\n modifyProfileTemplate(projectDir, apl, appFeature, logger, {\n kind,\n acls: options.acls,\n appPrivilegeCapabilities: options.appPrivilegeCapabilities,\n });\n generateP7bFile(projectDir, paths, logger, passwords);\n prepareMaterialDirectory(projectDir, logger);\n updateBuildProfile(projectDir, kind, logger, passwords);\n logger.info('[sign] Signing configuration generated successfully.');\n}\n","/**\n * PEM-encoded certificate chain for the OpenHarmony Application Release key.\n *\n * Root-CA → Application-CA → Application-Release leaf. This is the public\n * OpenHarmony test PKI that ships with system app source trees (e.g.\n * `applications/standard/launcher/signature/OpenHarmonyApplication.cer`). It\n * pairs with the private key stored under alias `OpenHarmony Application Release`\n * in the SDK's `OpenHarmony.p12` keystore.\n *\n * Used to sign HAPs that request privileged permissions (apl >= system_basic).\n * For apl=normal the existing `OpenHarmonyProfileRelease.pem` chain — already\n * shipped in the SDK — is used instead.\n */\nexport const OPEN_HARMONY_APPLICATION_CERT = `-----BEGIN CERTIFICATE-----\nMIICRDCCAcmgAwIBAgIED+E4izAMBggqhkjOPQQDAwUAMGgxCzAJBgNVBAYTAkNO\nMRQwEgYDVQQKEwtPcGVuSGFybW9ueTEZMBcGA1UECxMQT3Blbkhhcm1vbnkgVGVh\nbTEoMCYGA1UEAxMfT3Blbkhhcm1vbnkgQXBwbGljYXRpb24gUm9vdCBDQTAeFw0y\nMTAyMDIxMjE0MThaFw00OTEyMzExMjE0MThaMGgxCzAJBgNVBAYTAkNOMRQwEgYD\nVQQKEwtPcGVuSGFybW9ueTEZMBcGA1UECxMQT3Blbkhhcm1vbnkgVGVhbTEoMCYG\nA1UEAxMfT3Blbkhhcm1vbnkgQXBwbGljYXRpb24gUm9vdCBDQTB2MBAGByqGSM49\nAgEGBSuBBAAiA2IABE023XmRaw2DnO8NSsb+KG/uY0FtS3u5LQucdr3qWVnRW5ui\nQIL6ttNZBEeLTUeYcJZCpayg9Llf+1SmDA7dY4iP2EcRo4UN3rilovtfFfsmH4ty\n3SApHVFzWUl+NwdH8KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwHQYDVR0OBBYEFBc6EKGrGXzlAE+s0Zgnsphadw7NMAwGCCqGSM49BAMDBQAD\nZwAwZAIwd1p3JzHN93eoPped1li0j64npgqNzwy4OrkehYAqNXpcpaEcLZ7UxW8E\nI2lZJ3SbAjAkqySHb12sIwdSFKSN9KCMMEo/eUT5dUXlcKR2nZz0MJdxT5F51qcX\n1CumzkcYhgU=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICYTCCAeWgAwIBAgIEHmXAPTAMBggqhkjOPQQDAwUAMGgxCzAJBgNVBAYTAkNO\nMRQwEgYDVQQKEwtPcGVuSGFybW9ueTEZMBcGA1UECxMQT3Blbkhhcm1vbnkgVGVh\nbTEoMCYGA1UEAxMfT3Blbkhhcm1vbnkgQXBwbGljYXRpb24gUm9vdCBDQTAeFw0y\nMTAyMDIxMjE1MzJaFw00OTEyMzExMjE1MzJaMGMxCzAJBgNVBAYTAkNOMRQwEgYD\nVQQKEwtPcGVuSGFybW9ueTEZMBcGA1UECxMQT3Blbkhhcm1vbnkgVGVhbTEjMCEG\nA1UEAxMaT3Blbkhhcm1vbnkgQXBwbGljYXRpb24gQ0EwdjAQBgcqhkjOPQIBBgUr\ngQQAIgNiAAQhnu7Hna8XNa2KyqRf5+lBJScE4xqf89N0g0OuqAb2re8nGsvWkw26\nuDekfnBYicd+G3Cydqa2zFIwV7Talyg2ULW3r8KbGpyl84mJEPPRmCGJ+H9gtCsf\n+OrJ4Y76LVWjYzBhMB8GA1UdIwQYMBaAFBc6EKGrGXzlAE+s0Zgnsphadw7NMA8G\nA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTbhrciFtUL\noUu33SV7ufEFfaItRzAMBggqhkjOPQQDAwUAA2gAMGUCMG3cXjiDmXTvf7D4Omhf\nqcc2nuO+EMfWE+N9ZhBP5UhV34mAGWi3SfLU6rcV0urWEQIxAMYIb3epOnKhUrcm\nLfu1WKzFlpYQwmw73RaCHP2I3k6NcuWOYeNwWXSNZ8o0nzvaLg==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICMzCCAbegAwIBAgIEaOC/zDAMBggqhkjOPQQDAwUAMGMxCzAJBgNVBAYTAkNO\nMRQwEgYDVQQKEwtPcGVuSGFybW9ueTEZMBcGA1UECxMQT3Blbkhhcm1vbnkgVGVh\nbTEjMCEGA1UEAxMaT3Blbkhhcm1vbnkgQXBwbGljYXRpb24gQ0EwHhcNMjEwMjAy\nMTIxOTMxWhcNNDkxMjMxMTIxOTMxWjBoMQswCQYDVQQGEwJDTjEUMBIGA1UEChML\nT3Blbkhhcm1vbnkxGTAXBgNVBAsTEE9wZW5IYXJtb255IFRlYW0xKDAmBgNVBAMT\nH09wZW5IYXJtb255IEFwcGxpY2F0aW9uIFJlbGVhc2UwWTATBgcqhkjOPQIBBggq\nhkjOPQMBBwNCAATbYOCQQpW5fdkYHN45v0X3AHax12jPBdEDosFRIZ1eXmxOYzSG\nJwMfsHhUU90E8lI0TXYZnNmgM1sovubeQqATo1IwUDAfBgNVHSMEGDAWgBTbhrci\nFtULoUu33SV7ufEFfaItRzAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFPtxruhl\ncRBQsJdwcZqLu9oNUVgaMAwGCCqGSM49BAMDBQADaAAwZQIxAJta0PQ2p4DIu/ps\nLMdLCDgQ5UH1l0B4PGhBlMgdi2zf8nk9spazEQI/0XNwpft8QAIwHSuA2WelVi/o\nzAlF08DnbJrOOtOnQq5wHOPlDYB4OtUzOYJk9scotrEnJxJzGsh/\n-----END CERTIFICATE-----\n`;\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport { defaultPaths } from '../ports/config.js';\nimport type { ProgressReporter } from '../ports/progress.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { getEmulatorDir } from '../sdk/paths.js';\nimport { downloadFile } from '../sdk/download.js';\nimport { extractZipWithProgress } from '../sdk/extract.js';\nimport { createInstallTempDir, removeTempWorkDir, toSpaceError } from '../sdk/tmp.js';\n\nexport interface InstallEmulatorOptions {\n config: ConfigProvider;\n progress?: ProgressReporter;\n abortSignal?: AbortSignal;\n logger?: Logger;\n /**\n * Scratch directory for the downloaded ZIP. Overrides the `tmpDir` config key and\n * the default location next to the install target.\n */\n tmpDir?: string;\n}\n\n/**\n * Download and extract the Oniro emulator into the configured `emulatorDir`.\n */\nexport async function installEmulator(opts: InstallEmulatorOptions): Promise<void> {\n const { config, progress, abortSignal } = opts;\n const logger = opts.logger ?? noopLogger;\n\n const url = config.get('emulatorUrl', defaultPaths.emulatorUrl);\n const emulatorDir = getEmulatorDir(config);\n const what = 'the emulator install';\n const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({\n config,\n override: opts.tmpDir,\n installRoot: path.dirname(emulatorDir),\n prefix: 'oniro-emulator-',\n logger,\n });\n const tmpZip = path.join(tmpDir, 'oniro_emulator.zip');\n\n try {\n fs.mkdirSync(emulatorDir, { recursive: true });\n\n progress?.report({ message: 'Downloading emulator...', increment: 0 });\n await downloadFile({ url, dest: tmpZip, progress, abortSignal, start: 0, range: 50, what, tmpRoot });\n\n progress?.report({ message: 'Extracting emulator...', increment: 0 });\n await extractZipWithProgress({ zipPath: tmpZip, dest: emulatorDir, progress, start: 50, range: 45, logger });\n\n const runSh = path.join(emulatorDir, 'images', 'run.sh');\n if (fs.existsSync(runSh)) {\n fs.chmodSync(runSh, 0o755);\n }\n progress?.report({ message: 'Finalizing installation...', increment: 5 });\n } catch (err) {\n throw toSpaceError(err, tmpRoot, what);\n } finally {\n removeTempWorkDir(tmpDir, tmpRoot);\n }\n}\n\n/**\n * Heuristic: the emulator is considered installed if either bundled launcher\n * (`images/run.sh` or `images/run.bat`) is present, so a Windows-only build is\n * detected too.\n */\nexport function isEmulatorInstalled(config: ConfigProvider): boolean {\n const imagesDir = path.join(getEmulatorDir(config), 'images');\n return fs.existsSync(path.join(imagesDir, 'run.sh')) || fs.existsSync(path.join(imagesDir, 'run.bat'));\n}\n\nexport function removeEmulator(config: ConfigProvider): void {\n const emulatorDir = getEmulatorDir(config);\n if (fs.existsSync(emulatorDir)) {\n fs.rmSync(emulatorDir, { recursive: true, force: true });\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { CancelledError, OniroError } from '../ports/errors.js';\nimport { getEmulatorDir } from '../sdk/paths.js';\nimport { hdcExec, runProcess } from '../hdc/exec.js';\nimport { isEmulatorInstalled } from './install.js';\n\nconst PID_FILE = path.join(os.tmpdir(), 'oniro_emulator.pid');\n\n/**\n * Try to connect hdc to the emulator. Resolves true on success, false otherwise.\n */\nexport async function attemptHdcConnection(\n config: ConfigProvider,\n address = '127.0.0.1:55555',\n logger: Logger = noopLogger,\n): Promise<boolean> {\n try {\n await hdcExec({ config, args: ['start', '-r'], logger });\n await hdcExec({ config, args: ['tconn', address], logger });\n const targets = await hdcExec({ config, args: ['list', 'targets'], logger });\n return targets.stdout.includes(address);\n } catch (err) {\n logger.warn(`hdc connection attempt failed: ${(err as Error).message}`);\n return false;\n }\n}\n\ninterface LauncherSpec {\n /** Executable to spawn (e.g. `bash` on POSIX, `cmd.exe` on Windows). */\n command: string;\n /** Args, including the launcher script path. */\n args: readonly string[];\n /** Working directory (images dir). */\n cwd: string;\n}\n\n/**\n * Pick the right bundled launcher for the current OS. Prefers run.bat on Windows\n * and run.sh elsewhere; falls back to the other if only one is present.\n */\nfunction resolveLauncher(\n imagesPath: string,\n headless: boolean,\n connect: string | undefined,\n): LauncherSpec {\n const runSh = path.join(imagesPath, 'run.sh');\n const runBat = path.join(imagesPath, 'run.bat');\n const extra: string[] = [];\n if (headless) extra.push('--headless');\n if (connect) extra.push('--connect', connect);\n\n if (os.platform() === 'win32') {\n if (fs.existsSync(runBat)) {\n return { command: 'cmd.exe', args: ['/c', runBat, ...extra], cwd: imagesPath };\n }\n if (fs.existsSync(runSh)) {\n return { command: 'bash', args: [runSh, ...extra], cwd: imagesPath };\n }\n throw new OniroError(`No emulator launcher (run.bat or run.sh) found in ${imagesPath}.`);\n }\n\n if (fs.existsSync(runSh)) {\n return { command: 'bash', args: [runSh, ...extra], cwd: imagesPath };\n }\n if (fs.existsSync(runBat)) {\n return { command: 'bash', args: [runBat, ...extra], cwd: imagesPath };\n }\n throw new OniroError(`No emulator launcher (run.sh or run.bat) found in ${imagesPath}.`);\n}\n\nexport interface StartEmulatorOptions {\n config: ConfigProvider;\n logger?: Logger;\n /** Pass --headless to the bundled launcher (VNC + telnet serial, no local window). */\n headless?: boolean;\n /**\n * Override the launcher's host:port for hdc port forwarding. Defaults to the\n * launcher's own default (typically `127.0.0.1:55555`). Use `0.0.0.0:55555`\n * on hosts where QEMU refuses to bind the hostfwd to 127.0.0.1 (e.g. some\n * CI runners with restricted loopback bindings).\n */\n connect?: string;\n /**\n * Redirect launcher stdout/stderr to this file. Default: discard\n * (/dev/null on POSIX, NUL on Windows). Use a real path in CI so you can\n * surface qemu output on failure.\n */\n logFile?: string;\n /**\n * If > 0, block until hdc connects to the running emulator, up to this many\n * seconds. 0 (default) returns as soon as the launcher process is spawned.\n */\n waitForHdcSeconds?: number;\n /** Poll interval for the hdc wait, ms. Default 5000. */\n hdcPollIntervalMs?: number;\n abortSignal?: AbortSignal;\n}\n\n/**\n * Launch the Oniro emulator in the background via the bundled run.sh/run.bat.\n *\n * The launcher process is detached + unref'd so callers can exit while the\n * emulator keeps running. A PID file is written to the OS temp dir so\n * `stopEmulator` and rerun-detection logic can find the process later.\n */\nexport async function startEmulator(opts: StartEmulatorOptions): Promise<void> {\n const { config } = opts;\n const logger = opts.logger ?? noopLogger;\n\n // Detect a still-running emulator from a previous run (POSIX only — Windows\n // PID semantics with process groups make this unreliable to check by hand).\n if (os.platform() !== 'win32' && fs.existsSync(PID_FILE)) {\n try {\n const pid = Number(fs.readFileSync(PID_FILE, 'utf8').trim());\n if (Number.isFinite(pid) && pid > 0) {\n try {\n process.kill(pid, 0);\n logger.info(`Emulator already running (PID ${pid}); not starting another.`);\n if (opts.waitForHdcSeconds && opts.waitForHdcSeconds > 0) {\n await waitForHdc(config, opts.waitForHdcSeconds, opts.hdcPollIntervalMs ?? 5000, logger, opts.abortSignal);\n }\n return;\n } catch {\n // Stale PID file — fall through and launch a fresh one.\n }\n }\n } catch (err) {\n logger.warn(`Could not read PID file: ${(err as Error).message}`);\n }\n }\n\n const imagesPath = path.join(getEmulatorDir(config), 'images');\n if (!fs.existsSync(imagesPath)) {\n throw new OniroError(`Emulator images directory not found at ${imagesPath}. Run \\`oniro-app emulator install\\` first.`);\n }\n const launcher = resolveLauncher(imagesPath, opts.headless === true, opts.connect);\n\n // Open the log target. Default to OS-level null sink so the child process\n // doesn't keep the parent's stdout/stderr file descriptors alive.\n const logPath = opts.logFile ?? (os.platform() === 'win32' ? 'NUL' : '/dev/null');\n const logFd = fs.openSync(logPath, 'a');\n\n let child;\n try {\n child = spawn(launcher.command, [...launcher.args], {\n cwd: launcher.cwd,\n detached: true,\n stdio: ['ignore', logFd, logFd],\n windowsHide: true,\n });\n } finally {\n fs.closeSync(logFd);\n }\n\n // Catch synchronous spawn failures (e.g. bash not found on PATH).\n if (!child.pid) {\n throw new OniroError(`Failed to spawn launcher (${launcher.command} ${launcher.args.join(' ')}).`);\n }\n\n // Record PID + detach. The launcher script `exec`s into qemu so this PID\n // remains valid for the whole emulator lifetime.\n fs.writeFileSync(PID_FILE, String(child.pid));\n child.unref();\n logger.info(`Emulator launched (PID ${child.pid}). Logs: ${logPath}`);\n\n // Watch for an immediate failure (e.g. KVM unavailable → run.sh exits ~instantly\n // with a friendly error). We hold a reference to the exit event but won't await\n // it if the child stays alive.\n const earlyExit = new Promise<number | null>((resolve) => {\n child.once('exit', (code) => resolve(code));\n child.once('error', () => resolve(-1));\n });\n const liveness = new Promise<'alive'>((resolve) => setTimeout(() => resolve('alive'), 2000));\n const outcome = await Promise.race([earlyExit, liveness]);\n if (outcome !== 'alive') {\n const tail = readTail(logPath, 4000);\n throw new OniroError(\n `Emulator launcher exited with code ${outcome} before reaching steady state. Tail of ${logPath}:\\n${tail}`,\n );\n }\n\n if (opts.waitForHdcSeconds && opts.waitForHdcSeconds > 0) {\n await waitForHdc(config, opts.waitForHdcSeconds, opts.hdcPollIntervalMs ?? 5000, logger, opts.abortSignal, logPath);\n }\n}\n\nasync function waitForHdc(\n config: ConfigProvider,\n timeoutSeconds: number,\n pollIntervalMs: number,\n logger: Logger,\n abortSignal?: AbortSignal,\n logPathForDiagnostics?: string,\n): Promise<void> {\n const deadline = Date.now() + timeoutSeconds * 1000;\n let attempt = 0;\n while (Date.now() < deadline) {\n if (abortSignal?.aborted) throw new CancelledError('hdc wait cancelled.');\n attempt++;\n if (await attemptHdcConnection(config, undefined, noopLogger)) {\n logger.info(`hdc connected on attempt ${attempt}.`);\n return;\n }\n // Every ~6 attempts, log a heartbeat with the latest emulator log tail so\n // a hung guest is debuggable from a single command's output stream.\n if (attempt % 6 === 0) {\n logger.info(`hdc not yet ready (attempt ${attempt}, ${Math.max(0, deadline - Date.now()) / 1000 | 0}s remaining).`);\n if (logPathForDiagnostics) {\n const tail = readTail(logPathForDiagnostics, 1200);\n if (tail.trim()) logger.debug(`emulator log tail:\\n${tail}`);\n }\n }\n await new Promise((r) => setTimeout(r, pollIntervalMs));\n }\n const tail = logPathForDiagnostics ? readTail(logPathForDiagnostics, 4000) : '';\n throw new OniroError(`hdc did not connect within ${timeoutSeconds}s.${tail ? `\\nTail of emulator log:\\n${tail}` : ''}`);\n}\n\nfunction readTail(filePath: string, bytes: number): string {\n try {\n const stat = fs.statSync(filePath);\n const start = Math.max(0, stat.size - bytes);\n const fd = fs.openSync(filePath, 'r');\n try {\n const buf = Buffer.alloc(stat.size - start);\n fs.readSync(fd, buf, 0, buf.length, start);\n return buf.toString('utf8');\n } finally {\n fs.closeSync(fd);\n }\n } catch {\n return '';\n }\n}\n\nexport async function stopEmulator(logger: Logger = noopLogger): Promise<void> {\n // Prefer killing the recorded PID; fall back to a broad kill for stragglers.\n if (fs.existsSync(PID_FILE)) {\n try {\n const pid = Number(fs.readFileSync(PID_FILE, 'utf8').trim());\n if (Number.isFinite(pid) && pid > 0) {\n try {\n process.kill(pid, 'SIGTERM');\n logger.info(`Sent SIGTERM to emulator PID ${pid}.`);\n } catch (err) {\n logger.warn(`Could not signal PID ${pid}: ${(err as Error).message}`);\n }\n }\n } catch (err) {\n logger.warn(`Could not read PID file: ${(err as Error).message}`);\n }\n }\n\n // pkill / taskkill exit non-zero when nothing matched — runProcess resolves on any\n // exit code, so we simply ignore that. The try/catch only guards a missing binary.\n const [killCmd, ...killArgs] = os.platform() === 'win32'\n ? ['taskkill', '/IM', 'qemu-system-x86_64.exe', '/F']\n : ['pkill', '-f', 'qemu-system-x86_64'];\n try {\n await runProcess({ command: killCmd!, args: killArgs, logger });\n } catch (err) {\n logger.warn(`[emulator] could not run ${killCmd}: ${(err as Error).message}`);\n }\n\n fs.rm(PID_FILE, { force: true }, (err) => {\n if (err) logger.warn(`Could not remove PID file: ${err.message}`);\n });\n}\n\nexport interface EmulatorStatus {\n installed: boolean;\n /** The configured emulator directory. */\n dir: string;\n /** Whether an emulator QEMU process is alive. */\n running: boolean;\n /** The hdc address checked for `connected`. */\n address: string;\n /** hdc lists `address` as a Connected target. */\n connected: boolean;\n}\n\n/**\n * Whether a `qemu-system-x86_64` process is alive: the PID file from `startEmulator`\n * (POSIX only, as there), else a process-table scan.\n */\nasync function isQemuRunning(logger: Logger): Promise<boolean> {\n if (os.platform() !== 'win32') {\n try {\n const pid = Number(fs.readFileSync(PID_FILE, 'utf8').trim());\n if (Number.isFinite(pid) && pid > 0) {\n process.kill(pid, 0);\n return true;\n }\n } catch {\n // No PID file, or the process is gone: scan the process table.\n }\n }\n const [cmd, ...args] = os.platform() === 'win32'\n ? ['tasklist', '/FI', 'IMAGENAME eq qemu-system-x86_64.exe', '/NH']\n : ['pgrep', '-f', 'qemu-system-x86_64'];\n try {\n const res = await runProcess({ command: cmd!, args, timeoutMs: 10_000, logger });\n return os.platform() === 'win32' ? /qemu-system-x86_64/i.test(res.stdout) : res.code === 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Report on the Oniro emulator without starting it: installed, running, and whether\n * hdc sees it at `address` (default `127.0.0.1:55555`). Other emulators, such as\n * DevEco Studio's HarmonyOS emulator, are not covered: they appear in `listDevices`.\n */\nexport async function getEmulatorStatus(\n config: ConfigProvider,\n opts: { address?: string; logger?: Logger } = {},\n): Promise<EmulatorStatus> {\n const logger = opts.logger ?? noopLogger;\n const address = opts.address ?? '127.0.0.1:55555';\n const dir = getEmulatorDir(config);\n let connected = false;\n try {\n const targets = await hdcExec({ config, args: ['list', 'targets', '-v'], timeoutMs: 10_000, logger });\n connected = targets.stdout.split('\\n').some((l) => l.trim().startsWith(address) && /\\bConnected\\b/.test(l));\n } catch {\n // No hdc: not connected.\n }\n return {\n installed: isEmulatorInstalled(config),\n dir,\n running: await isQemuRunning(logger),\n address,\n connected,\n };\n}\n","import * as fs from 'node:fs';\nimport type { ChildProcess } from 'node:child_process';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { CancelledError, CommandFailedError, OniroError } from '../ports/errors.js';\nimport { getHdcPath } from '../sdk/paths.js';\nimport { killProcessTree, needsCmdWrapper, spawnCompat } from './spawnCompat.js';\n\n/** Result of a spawned command. `code` is the process exit code (-1 if it was killed). */\nexport interface HdcExecResult {\n code: number;\n stdout: string;\n stderr: string;\n}\n\n/** Streamed output callback, invoked per stdout/stderr chunk as it arrives. */\nexport type OutputSink = (chunk: string, stream: 'stdout' | 'stderr') => void;\n\n/** Message of an unknown thrown value, for uniform spawn-failure reporting. */\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nexport interface RunProcessOptions {\n /** Executable to spawn. */\n command: string;\n /** Args passed verbatim (spawn runs with `shell: false`, so no shell parsing). */\n args: readonly string[];\n cwd?: string;\n env?: NodeJS.ProcessEnv;\n /** Kill the process after this many ms and reject. Default 60_000. */\n timeoutMs?: number;\n /** Abort the process; rejects with CancelledError. */\n abortSignal?: AbortSignal;\n /** Receive stdout/stderr chunks as they arrive (in addition to the buffered result). */\n onOutput?: OutputSink;\n /** Reserved for future scoped diagnostics; the buffered result is returned regardless. */\n logger?: Logger;\n}\n\n/**\n * Spawn an arbitrary process with `shell: false` and collect its output. The\n * single low-level primitive every other command in the package builds on —\n * because args are passed as an array and never interpolated into a shell\n * string, command construction is injection-safe by construction.\n *\n * The one exception is a Windows batch wrapper (`.bat`/`.cmd`, how the\n * OpenHarmony command-line tools ship there), which the OS cannot execute\n * directly: those go through `cmd.exe` with every argument individually\n * escaped — see {@link spawnCompat}. The array-in, no-word-splitting contract\n * is preserved.\n *\n * Resolves with `{ code, stdout, stderr }` for ANY exit code (callers opt into\n * throw-on-non-zero via {@link ensureOk}). Rejects only on spawn failure\n * (e.g. missing binary), timeout, or abort.\n */\nexport function runProcess(opts: RunProcessOptions): Promise<HdcExecResult> {\n const { command, args, cwd, env, onOutput } = opts;\n const timeoutMs = opts.timeoutMs ?? 60_000;\n const { abortSignal } = opts;\n\n return new Promise<HdcExecResult>((resolve, reject) => {\n if (abortSignal?.aborted) {\n reject(new CancelledError(`Command aborted before start: ${command}`));\n return;\n }\n\n // A batch wrapper runs through cmd.exe, which cannot report ENOENT for the\n // wrapper itself — it would exit 1 with \"is not recognized as an internal\n // or external command\". Check up front so a missing tool keeps surfacing as\n // a spawn failure on Windows too.\n if (needsCmdWrapper(command) && !fs.existsSync(command)) {\n reject(new OniroError(`Failed to spawn ${command}: ENOENT (no such file)`));\n return;\n }\n\n let child: ChildProcess;\n try {\n child = spawnCompat(command, args, { cwd, env });\n } catch (err) {\n // spawn() can also fail synchronously (EINVAL, EACCES). Report it the\n // same way as the asynchronous 'error' event so callers see one message.\n reject(new OniroError(`Failed to spawn ${command}: ${errorMessage(err)}`, err));\n return;\n }\n\n let stdout = '';\n let stderr = '';\n let settled = false;\n let timedOut = false;\n\n const cleanup = (): void => {\n clearTimeout(timer);\n abortSignal?.removeEventListener('abort', onAbort);\n };\n\n const onAbort = (): void => {\n if (settled) return;\n settled = true;\n cleanup();\n killProcessTree(child);\n reject(new CancelledError(`Command aborted: ${command} ${args.join(' ')}`));\n };\n\n const timer = setTimeout(() => {\n timedOut = true;\n killProcessTree(child);\n }, timeoutMs);\n\n abortSignal?.addEventListener('abort', onAbort, { once: true });\n\n child.stdout?.on('data', (d: Buffer) => {\n const s = d.toString();\n stdout += s;\n onOutput?.(s, 'stdout');\n });\n child.stderr?.on('data', (d: Buffer) => {\n const s = d.toString();\n stderr += s;\n onOutput?.(s, 'stderr');\n });\n\n child.on('error', (err) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(new OniroError(`Failed to spawn ${command}: ${err.message}`, err));\n });\n\n child.on('close', (code) => {\n if (settled) return;\n settled = true;\n cleanup();\n if (timedOut) {\n reject(\n new OniroError(\n `Command timed out after ${timeoutMs}ms: ${command} ${args.join(' ')}` +\n (stderr.trim() ? `\\n${stderr.trim()}` : ''),\n ),\n );\n return;\n }\n resolve({ code: code ?? -1, stdout, stderr });\n });\n });\n}\n\n/**\n * The device to address: an explicit serial wins, then the `ONIRO_DEVICE_SERIAL` /\n * `DEVICE_SERIAL` env vars. `auto`, or nothing at all, leaves the choice to hdc,\n * which only works while a single target is connected.\n */\nexport function resolveDeviceSerial(explicit?: string, env: NodeJS.ProcessEnv = process.env): string | undefined {\n if (explicit && explicit !== 'auto') return explicit;\n const fromEnv = env.ONIRO_DEVICE_SERIAL || env.DEVICE_SERIAL;\n return fromEnv && fromEnv !== 'auto' ? fromEnv : undefined;\n}\n\n/** `['-t', <serial>]` for the device {@link resolveDeviceSerial} picks, or `[]` to let hdc choose. */\nexport function hdcTargetArgs(explicit?: string): string[] {\n const serial = resolveDeviceSerial(explicit);\n return serial ? ['-t', serial] : [];\n}\n\n/**\n * hdc subcommands served by the hdc server itself rather than a device. They only\n * take `-t` when the caller names a device explicitly, never from the env var.\n */\nconst HOST_COMMANDS = new Set(['list', 'tconn', 'start', 'kill', 'version', 'checkserver']);\n\n/** The `-t <serial>` prefix for `hdc <args...>`, following {@link HdcExecOptions.deviceSerial}'s rules. */\nexport function hdcTargetArgsFor(args: readonly string[], explicit?: string): string[] {\n if (HOST_COMMANDS.has(args[0] ?? '')) return explicit ? ['-t', explicit] : [];\n return hdcTargetArgs(explicit);\n}\n\n/**\n * The `[Fail]…` line hdc printed instead of running the command, or null. hdc\n * exits 0 even then: `[Fail]ExecuteCommand need connect-key?` (several targets\n * and no `-t`), `[Fail]Not match target founded` (unknown serial), a failed file\n * transfer. Only the first line of output counts, so device-side output further\n * down that happens to contain the marker is left alone. Pure/testable.\n */\nexport function hdcClientFailure(output: string): string | null {\n const first = output.split(/\\r?\\n/).find((l) => l.trim() !== '')?.trim() ?? '';\n return first.startsWith('[Fail]') ? first : null;\n}\n\nexport interface HdcExecOptions {\n config: ConfigProvider;\n /** Args passed to hdc verbatim, e.g. `['shell','aa','start','-a',ability,'-b',bundle]`. */\n args: readonly string[];\n /**\n * Device serial; prepends `['-t', serial]`. When unset, `ONIRO_DEVICE_SERIAL`\n * applies (see {@link resolveDeviceSerial}), except for hdc server commands\n * such as `list targets` and `tconn`.\n */\n deviceSerial?: string;\n /** Default 60_000. */\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n onOutput?: OutputSink;\n logger?: Logger;\n}\n\n/**\n * Run `hdc [-t <serial>] <args...>`. Resolves with `{ code, stdout, stderr }`\n * for any exit code; use {@link ensureOk} to throw on non-zero. A `[Fail]` line\n * from hdc itself is reported as exit code 1 (see {@link hdcClientFailure}).\n */\nexport async function hdcExec(opts: HdcExecOptions): Promise<HdcExecResult> {\n const hdc = getHdcPath(opts.config);\n const res = await runProcess({\n command: hdc,\n args: [...hdcTargetArgsFor(opts.args, opts.deviceSerial), ...opts.args],\n timeoutMs: opts.timeoutMs,\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n logger: opts.logger,\n });\n if (res.code === 0 && hdcClientFailure(`${res.stdout}\\n${res.stderr}`)) return { ...res, code: 1 };\n return res;\n}\n\nexport interface HdcShellOptions extends Omit<HdcExecOptions, 'args'> {\n /** A single shell command, run as `hdc shell <command>` (one argv element — not host word-split). */\n command: string;\n}\n\n/** Convenience wrapper for `hdc shell <command>`. */\nexport function shell(opts: HdcShellOptions): Promise<HdcExecResult> {\n const { command, ...rest } = opts;\n return hdcExec({ ...rest, args: ['shell', command] });\n}\n\n/**\n * Throw a typed {@link CommandFailedError} when `result.code !== 0`, otherwise\n * return the result unchanged. Lets callers opt into throw-semantics.\n */\nexport function ensureOk(result: HdcExecResult, command: string): HdcExecResult {\n if (result.code !== 0) {\n throw new CommandFailedError(command, result.code, withTargetHint(result.stderr.trim() || result.stdout.trim()));\n }\n return result;\n}\n\n/** Append how to pick a device when hdc refused to choose between several. */\nfunction withTargetHint(detail: string): string {\n if (!/need connect-key|Not match target/i.test(detail)) return detail;\n return (\n `${detail}\\nMore than one target is connected, or the serial is unknown: pass --device <serial> ` +\n 'or set ONIRO_DEVICE_SERIAL to one listed by `oniro-app devices`.'\n );\n}\n\n/** Matches the exit-code marker {@link shellChecked} appends. */\nconst REMOTE_RC_RE = /__ONIRO_RC=(-?\\d+)__/g;\n\n/**\n * Parse the exit-code marker appended by {@link shellChecked}. Pure/testable.\n * Returns the remote exit code plus stdout with every marker occurrence\n * stripped, or `null` when no marker is present (the command was killed/timed\n * out, or the device shell never reached the trailing `echo`).\n */\nexport function parseRemoteExit(stdout: string): { code: number; stdout: string } | null {\n let code: number | null = null;\n for (const m of stdout.matchAll(REMOTE_RC_RE)) code = Number(m[1]);\n if (code === null) return null;\n return { code, stdout: stdout.replace(REMOTE_RC_RE, '').replace(/[ \\t\\r\\n]+$/, '') };\n}\n\n/**\n * Like {@link shell}, but recovers the REMOTE command's exit status.\n *\n * `hdc shell \"<cmd>\"` reports hdc's OWN exit code (≈ always 0) regardless of\n * whether `<cmd>` succeeded on the device — so on-device failures (`uinput`\n * rejecting its args, a `bm install` error, a missing binary) otherwise look\n * like success. We append an exit-code marker, parse it back out, and report\n * it as `code`, with the marker stripped from stdout. Pair with\n * {@link ensureRemoteOk} to throw on a non-zero remote exit.\n */\nexport async function shellChecked(opts: HdcShellOptions): Promise<HdcExecResult> {\n const { command, ...rest } = opts;\n const res = await hdcExec({ ...rest, args: ['shell', `${command}; echo \"__ONIRO_RC=$?__\"`] });\n const parsed = parseRemoteExit(res.stdout);\n if (!parsed) return res; // marker missing — fall back to hdc's own exit code\n return { code: parsed.code, stdout: parsed.stdout, stderr: res.stderr };\n}\n\n/**\n * Throw a typed {@link CommandFailedError} on a non-zero result, preferring\n * stderr but falling back to stdout for the detail — device tools like\n * `uinput`/`uitest` print their errors to stdout, not stderr.\n */\nexport function ensureRemoteOk(result: HdcExecResult, command: string): HdcExecResult {\n if (result.code !== 0) {\n throw new CommandFailedError(command, result.code, withTargetHint(result.stderr.trim() || result.stdout.trim()));\n }\n return result;\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { hdcExec, resolveDeviceSerial } from './exec.js';\n\nexport interface DeviceInfo {\n /** Connect key — a USB serial or a `host:port` for a TCP target. */\n serial: string;\n /** 'Connected' | 'Offline' | 'Unauthorized' | … | 'Unknown' when not reported. */\n status: string;\n /** 'USB' | 'TCP' | … when reported by `-v`. */\n connection?: string;\n /** Device model, populated by getDeviceInfo (not by the bare target list). */\n model?: string;\n}\n\n// Recognised tokens in `hdc list targets -v` rows. Parsing is positional-agnostic\n// (we scan the row's tokens) so it tolerates hdc version differences in column order.\nconst STATUS_TOKENS = new Set([\n 'Connected',\n 'Offline',\n 'Unauthorized',\n 'Authorizing',\n 'Disconnected',\n 'Recovery',\n]);\nconst CONNECTION_TOKENS = new Set(['USB', 'TCP', 'UART', 'BT', 'UNKNOWN']);\n\n/**\n * Parse the output of `hdc list targets -v` into structured rows. The first token\n * of each non-empty row is the connect key (serial); connection/status are matched\n * by keyword among the remaining tokens. `[Empty]` (no devices) yields `[]`.\n */\nexport function parseDeviceList(stdout: string): DeviceInfo[] {\n const devices: DeviceInfo[] = [];\n for (const line of stdout.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('[Empty]')) continue;\n const cols = trimmed.split(/\\s+/);\n const serial = cols[0];\n if (!serial) continue;\n const rest = cols.slice(1);\n const connection = rest.find((c) => CONNECTION_TOKENS.has(c));\n const status = rest.find((c) => STATUS_TOKENS.has(c)) ?? 'Unknown';\n const info: DeviceInfo = { serial, status };\n if (connection) info.connection = connection;\n devices.push(info);\n }\n return devices;\n}\n\n/** List connected hdc targets via `hdc list targets -v`. Empty list when none. */\nexport async function listDevices(\n config: ConfigProvider,\n opts: { timeoutMs?: number; logger?: Logger } = {},\n): Promise<DeviceInfo[]> {\n const res = await hdcExec({\n config,\n args: ['list', 'targets', '-v'],\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n return parseDeviceList(res.stdout);\n}\n\n/**\n * Resolve which device serial to address: an explicit `serial` wins, then the\n * `ONIRO_DEVICE_SERIAL` / `DEVICE_SERIAL` env vars, then the single connected\n * device. Throws when none or more than one is connected and nothing was specified.\n */\nexport async function selectDevice(\n config: ConfigProvider,\n serial?: string,\n opts: { timeoutMs?: number; logger?: Logger } = {},\n): Promise<string> {\n const resolved = resolveDeviceSerial(serial);\n if (resolved) return resolved;\n\n const usable = (await listDevices(config, opts)).filter(\n (d) => d.status === 'Connected' || d.status === 'Unknown',\n );\n if (usable.length === 1) return usable[0]!.serial;\n if (usable.length === 0) {\n throw new OniroError('No connected device found. Connect a device/emulator or set ONIRO_DEVICE_SERIAL.');\n }\n throw new OniroError(\n `Multiple devices connected (${usable.map((d) => d.serial).join(', ')}). ` +\n 'Set ONIRO_DEVICE_SERIAL to choose one.',\n );\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { shell, ensureOk } from './exec.js';\n\nexport interface ParamOptions {\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * `param get` prints this instead of a value for an unset property (and still\n * exits 0), e.g. `Get parameter \"const.product.os.dist.name\" fail! errNum is:106!`\n * on OpenHarmony.\n */\nconst PARAM_MISSING_RE = /^Get parameter \".*\" fail!/;\n\n/** Read a system property via `hdc shell param get <key>`. Returns the trimmed value; throws when it is unset. */\nexport async function paramGet(config: ConfigProvider, key: string, opts: ParamOptions = {}): Promise<string> {\n const res = await shell({\n config,\n command: `param get ${key}`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n ensureOk(res, `hdc shell param get ${key}`);\n const value = res.stdout.trim();\n if (PARAM_MISSING_RE.test(value)) throw new OniroError(`System parameter ${key} is not set: ${value}`);\n return value;\n}\n\nconst PARAM_SEPARATOR = '__ONIRO_PARAM__';\n\n/**\n * Split the output of {@link paramGetMany}'s single shell call back into one value\n * per key; unset properties come back undefined. Pure/testable.\n */\nexport function parseParamValues(keys: readonly string[], stdout: string): Record<string, string | undefined> {\n const parts = stdout.split(PARAM_SEPARATOR);\n const values: Record<string, string | undefined> = {};\n keys.forEach((key, i) => {\n const value = parts[i]?.trim();\n values[key] = value && !PARAM_MISSING_RE.test(value) ? value : undefined;\n });\n return values;\n}\n\n/** Read several system properties in one `hdc shell` round trip. Unset properties come back undefined. */\nexport async function paramGetMany(\n config: ConfigProvider,\n keys: readonly string[],\n opts: ParamOptions = {},\n): Promise<Record<string, string | undefined>> {\n const res = await shell({\n config,\n command: keys.map((k) => `param get ${k}; echo ${PARAM_SEPARATOR}`).join('; '),\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n ensureOk(res, 'hdc shell param get …');\n return parseParamValues(keys, res.stdout);\n}\n\n/**\n * Set a system property via `hdc shell param set <key> <value>`. The canonical\n * reboot path is `paramSet(config, 'ohos.startup.powerctrl', 'reboot')`.\n */\nexport async function paramSet(\n config: ConfigProvider,\n key: string,\n value: string,\n opts: ParamOptions = {},\n): Promise<void> {\n const res = await shell({\n config,\n command: `param set ${key} ${value}`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n ensureOk(res, `hdc shell param set ${key} ${value}`);\n}\n","import * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { toLongPath } from '../sdk/paths.js';\nimport { hdcExec, ensureOk, ensureRemoteOk, shellChecked, type OutputSink } from './exec.js';\n\n/**\n * A host path in the form hdc understands: absolute, with native separators and,\n * on Windows, no 8.3 short names. hdc treats a forward-slash Windows path such as\n * `C:/Users/me/x.txt` as relative and joins it onto the current directory. The\n * last component may not exist yet (a `recv` destination).\n */\nexport function normaliseLocalPath(local: string): string {\n const abs = path.resolve(local);\n const long = toLongPath(abs);\n return long !== abs ? long : path.join(toLongPath(path.dirname(abs)), path.basename(abs));\n}\n\n/**\n * Reject a device path that a Windows shell already rewrote into a host path:\n * Git Bash turns `/data/local/tmp/x` into `C:/Program Files/Git/data/local/tmp/x`\n * before the CLI sees it. Device paths never start with a drive letter.\n */\nexport function assertDevicePath(remote: string): void {\n if (/^[A-Za-z]:[\\\\/]/.test(remote)) {\n throw new OniroError(\n `The device path ${remote} is a Windows path. Git Bash rewrites arguments that start with /: ` +\n 'run the command with MSYS_NO_PATHCONV=1, or from PowerShell or cmd.',\n );\n }\n}\n\n/** Where `hdc shell` sees an app's el2 sandbox; the app itself sees it as `/data/storage/el2/base`. */\nexport function appSandboxDir(bundle: string): string {\n return `/data/app/el2/100/base/${bundle}`;\n}\n\n/** Quote a string for the device's POSIX shell. */\nfunction shQuote(s: string): string {\n return `'${s.replace(/'/g, `'\\\\''`)}'`;\n}\n\nexport interface SendFileOptions {\n config: ConfigProvider;\n /** Local source path. */\n local: string;\n /**\n * Remote destination path on the device. With `bundle`, a relative path is\n * resolved inside that app's sandbox (`files/x` is the app's application-level\n * filesDir, `haps/entry/files/x` the entry module's).\n */\n remote: string;\n /**\n * Push into this app's sandbox and give the file to the app's user afterwards:\n * hdc writes files as root, which the app cannot read until they are chowned.\n */\n bundle?: string;\n deviceSerial?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n onOutput?: OutputSink;\n logger?: Logger;\n}\n\n/**\n * Push a local file to the device via `hdc file send <local> <remote>`. Returns\n * the device path the file was written to.\n */\nexport async function sendFile(opts: SendFileOptions): Promise<string> {\n assertDevicePath(opts.remote);\n const local = normaliseLocalPath(opts.local);\n const sandbox = opts.bundle ? appSandboxDir(opts.bundle) : undefined;\n const remote = sandbox && !opts.remote.startsWith('/') ? path.posix.join(sandbox, opts.remote) : opts.remote;\n if (sandbox && !remote.startsWith(`${sandbox}/`)) {\n throw new OniroError(`${remote} is outside the sandbox of ${opts.bundle} (${sandbox}).`);\n }\n const device = { config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger };\n\n if (sandbox) {\n const mkdir = `mkdir -p ${shQuote(path.posix.dirname(remote))}`;\n ensureRemoteOk(await shellChecked({ ...device, command: mkdir }), `hdc shell ${mkdir}`);\n }\n const res = await hdcExec({\n ...device,\n args: ['file', 'send', local, remote],\n timeoutMs: opts.timeoutMs ?? 600_000,\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n });\n ensureOk(res, `hdc file send ${local} ${remote}`);\n\n if (sandbox) {\n // Everything in the sandbox belongs to the app, so hand over the whole top-level\n // directory the file went into: that covers the parents mkdir created too.\n const top = path.posix.join(sandbox, path.posix.relative(sandbox, remote).split('/')[0]!);\n const chown = `chown -R \"$(stat -c %u:%g ${shQuote(sandbox)})\" ${shQuote(top)}`;\n ensureRemoteOk(await shellChecked({ ...device, command: chown }), `hdc shell ${chown}`);\n }\n return remote;\n}\n\nexport interface RecvFileOptions {\n config: ConfigProvider;\n /** Remote source path on the device. */\n remote: string;\n /** Local destination path. */\n local: string;\n deviceSerial?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n onOutput?: OutputSink;\n logger?: Logger;\n}\n\n/** Pull a file from the device via `hdc file recv <remote> <local>`. */\nexport async function recvFile(opts: RecvFileOptions): Promise<void> {\n assertDevicePath(opts.remote);\n const local = normaliseLocalPath(opts.local);\n const res = await hdcExec({\n config: opts.config,\n args: ['file', 'recv', opts.remote, local],\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 600_000,\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n logger: opts.logger,\n });\n ensureOk(res, `hdc file recv ${opts.remote} ${local}`);\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { shell } from './exec.js';\n\nexport interface DisplaySize {\n width: number;\n height: number;\n}\n\nexport interface DisplaySizeOptions {\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * Resolve the device's render resolution from `hidumper -s 10 -a screen`\n * (`render resolution=WxH`). Returns null when unavailable. This is the W/H\n * source for screenshots and the 0–1 normalization of layout bounds — no image\n * decoding is involved.\n */\nexport async function getDisplaySize(config: ConfigProvider, opts: DisplaySizeOptions = {}): Promise<DisplaySize | null> {\n const res = await shell({\n config,\n command: 'hidumper -s 10 -a screen',\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n if (res.code !== 0) return null;\n const m = res.stdout.match(/render resolution=(\\d+)x(\\d+)/);\n if (!m) return null;\n return { width: Number(m[1]), height: Number(m[2]) };\n}\n","import type { Logger } from '../ports/logger.js';\nimport { CancelledError, OniroError } from '../ports/errors.js';\n\nexport interface WaitForConditionOptions {\n /** Resolves true when the condition is satisfied. Called once per poll. */\n probe: () => Promise<boolean>;\n /** Overall deadline. */\n timeoutMs: number;\n /** Poll interval. Default 2000. */\n pollMs?: number;\n /** Abort the wait; rejects with CancelledError. */\n abortSignal?: AbortSignal;\n /** Called every `heartbeatEvery` attempts (default 6) with progress info. */\n onHeartbeat?: (attempt: number, remainingMs: number) => void;\n heartbeatEvery?: number;\n logger?: Logger;\n /** Message for the timeout error. */\n timeoutMessage?: string;\n}\n\n/** Sleep `ms`, rejecting early (CancelledError) if `signal` aborts. */\nfunction delay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(new CancelledError('Wait cancelled.'));\n return;\n }\n const onAbort = (): void => {\n cleanup();\n reject(new CancelledError('Wait cancelled.'));\n };\n const cleanup = (): void => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n };\n const timer = setTimeout(() => {\n cleanup();\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/**\n * Generic deadline + poll + heartbeat loop. Calls `probe()` every `pollMs` until\n * it resolves true (→ resolve) or the deadline passes (→ throw OniroError).\n * A probe that throws is treated as \"not yet\" (the loop keeps polling) — this is\n * what lets device waits tolerate transient hdc disconnects mid-reboot. Aborting\n * the signal rejects with CancelledError.\n *\n * Extracted from the emulator hdc-wait loop so device lifecycle helpers share it.\n */\nexport async function waitForCondition(opts: WaitForConditionOptions): Promise<void> {\n const pollMs = opts.pollMs ?? 2000;\n const heartbeatEvery = opts.heartbeatEvery ?? 6;\n const deadline = Date.now() + opts.timeoutMs;\n let attempt = 0;\n\n while (Date.now() < deadline) {\n if (opts.abortSignal?.aborted) throw new CancelledError('Wait cancelled.');\n attempt++;\n\n let ok = false;\n try {\n ok = await opts.probe();\n } catch {\n ok = false; // transient failure (e.g. hdc disconnect) — keep polling\n }\n if (ok) return;\n\n if (opts.onHeartbeat && attempt % heartbeatEvery === 0) {\n opts.onHeartbeat(attempt, Math.max(0, deadline - Date.now()));\n }\n await delay(pollMs, opts.abortSignal);\n }\n\n throw new OniroError(opts.timeoutMessage ?? `Condition not met within ${opts.timeoutMs}ms.`);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ChildProcess } from 'node:child_process';\nimport type { ConfigProvider } from '../ports/config.js';\nimport { defaultPaths } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger, scopedLogger } from '../ports/logger.js';\nimport { CommandFailedError, OniroError } from '../ports/errors.js';\nimport { getHdcPath } from '../sdk/paths.js';\nimport { discoverHaps, pickHap } from '../build/discoverHaps.js';\nimport { killProcessTree, spawnCompat } from './spawnCompat.js';\nimport { hdcExec, hdcTargetArgs, shell, ensureOk, type HdcExecResult } from './exec.js';\nimport { getBundleName, getMainAbility } from './project.js';\n\nexport interface InstallAppOptions {\n config: ConfigProvider;\n projectDir: string;\n /**\n * Explicit path (absolute, or relative to projectDir) to the `.hap`. Falls back\n * to the `hapPath` config key, then to the well-known signed entry HAP, then to\n * the HAPs the build produced (signed first, else unsigned). A `*-signed.hap`\n * that does not exist falls back to its `*-unsigned.hap` sibling.\n */\n hapPath?: string;\n deviceSerial?: string;\n logger?: Logger;\n}\n\nexport interface InstallAppResult {\n installed: boolean;\n /** Bundle name read from the project's AppScope/app.json5, or '' if unavailable. */\n bundleName: string;\n /** The resolved absolute HAP path that was installed. */\n hapPath: string;\n /** Combined stdout+stderr from the install, trimmed. */\n output: string;\n}\n\n/**\n * The bundle manager's rejection in `hdc install` output, or null when the\n * install went through. hdc exits 0 either way: success prints `msg:install\n * bundle successfully.`, a rejection `msg:error: failed to install bundle.`\n * with a `code:95xxxxx`. Pure/testable.\n */\nexport function detectInstallFailure(output: string): string | null {\n return /\\[Fail\\]|msg:\\s*error|error:\\s*failed to install|code:\\s*95\\d{5}/i.test(output) ? output.trim() : null;\n}\n\n/** The HAP an install is about to push, and how it was chosen. */\nexport interface InstallCandidate {\n path: string;\n /** True when no signed HAP was found and this unsigned one was taken instead. */\n fallback?: boolean;\n}\n\n/** Whether a HAP is an `*-unsigned.hap`, by its file name as hvigor writes it. */\nexport function isUnsignedHap(hapPath: string): boolean {\n return path.basename(hapPath).includes('unsigned');\n}\n\n/**\n * The bundle manager's reason from rejected `hdc install` output, e.g. `code\n * 9568320: no signature file`, else the output's first line. Pure/testable.\n */\nexport function installFailureReason(output: string): string {\n const code = /code:\\s*(\\d+)/i.exec(output);\n if (!code) return output.trim().split(/\\r?\\n/)[0] ?? '';\n const message = /error:\\s*([^\\r\\n]+)/i.exec(output.slice(code.index + code[0].length))?.[1]?.trim().replace(/\\.$/, '');\n return message ? `code ${code[1]}: ${message}` : `code ${code[1]}`;\n}\n\n/**\n * The message for a target that rejected an unsigned HAP: what was tried, the\n * bundle manager's reason, and, when the reason is the missing signature, how to\n * sign for the target. Pure/testable.\n */\nexport function unsignedHapRejection(output: string, hap: InstallCandidate): string {\n const name = path.basename(hap.path);\n const reason = installFailureReason(output);\n const what = hap.fallback\n ? `No signed HAP was found, so the unsigned ${name} was tried, and the target rejected it (${reason}).`\n : `The target rejected the unsigned ${name} (${reason}).`;\n if (!/9568320|signature|pkcs7/i.test(reason)) return what;\n return (\n `${what} This target installs only signed HAPs. Sign the project for it, build again, and install the signed HAP: ` +\n '`oniro-app sign` for an OpenHarmony device or the Oniro emulator, `oniro-app sign --harmonyos` for a HarmonyOS device.'\n );\n}\n\n/**\n * Throw when hdc or the bundle manager rejected an install: a typed\n * {@link CommandFailedError}, or, when the bundle manager turned down an unsigned\n * `hap`, an {@link OniroError} explaining {@link unsignedHapRejection why}.\n */\nexport function ensureInstallOk(result: HdcExecResult, command: string, hap?: InstallCandidate): HdcExecResult {\n const output = `${result.stdout}\\n${result.stderr}`;\n if (hap && isUnsignedHap(hap.path) && /code:\\s*95\\d{5}/i.test(output)) {\n throw new OniroError(unsignedHapRejection(output, hap), new CommandFailedError(command, result.code || 1, output.trim()));\n }\n ensureOk(result, command);\n const failure = detectInstallFailure(output);\n if (failure) throw new CommandFailedError(command, 1, failure);\n return result;\n}\n\n/**\n * An existing HAP at `hapPath`, or, when that is a `*-signed.hap` that does not\n * exist, its `*-unsigned.hap` sibling. Undefined when neither exists.\n */\nexport function existingHapOrUnsigned(hapPath: string): InstallCandidate | undefined {\n if (fs.existsSync(hapPath)) return { path: hapPath };\n const sibling = hapPath.replace(/-signed\\.hap$/i, '-unsigned.hap');\n return sibling !== hapPath && fs.existsSync(sibling) ? { path: sibling, fallback: true } : undefined;\n}\n\nasync function resolveInstallHap(opts: InstallAppOptions, logger: Logger): Promise<InstallCandidate> {\n const warnIfFallback = (hap: InstallCandidate): InstallCandidate => {\n if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path.basename(hap.path)}.`);\n return hap;\n };\n const configured = opts.hapPath ?? opts.config.get('hapPath', '');\n const relative = configured || defaultPaths.hapPath;\n const hapPath = path.isAbsolute(relative) ? relative : path.join(opts.projectDir, relative);\n if (configured) {\n const hap = existingHapOrUnsigned(hapPath);\n if (!hap) throw new OniroError(`HAP file not found at: ${hapPath}. Build the app first.`);\n return warnIfFallback(hap);\n }\n if (fs.existsSync(hapPath)) return { path: hapPath };\n // No explicit HAP and no signed entry HAP: take what the build produced, a\n // signed HAP first, then the entry's unsigned one, then any unsigned one.\n const haps = await discoverHaps({ projectDir: opts.projectDir });\n const anySigned = Object.values(haps).some((m) => m.signed.length > 0);\n const entryUnsigned = anySigned ? undefined : existingHapOrUnsigned(hapPath);\n if (entryUnsigned) return warnIfFallback(entryUnsigned);\n const picked = pickHap(haps);\n if (!picked) throw new OniroError(`No HAP found under ${opts.projectDir}. Build the app first (\\`oniro-app build\\`).`);\n return warnIfFallback({ path: picked.path, fallback: !picked.signed });\n}\n\nexport async function installApp(opts: InstallAppOptions): Promise<InstallAppResult> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n const hap = await resolveInstallHap(opts, logger);\n const hapPath = hap.path;\n\n const result = await hdcExec({\n config: opts.config,\n args: ['install', hapPath],\n deviceSerial: opts.deviceSerial,\n timeoutMs: 300_000,\n });\n if (result.stdout.trim()) logger.info(result.stdout.trim());\n if (result.stderr.trim()) logger.warn(result.stderr.trim());\n ensureInstallOk(result, `hdc install ${hapPath}`, hap);\n\n let bundleName = '';\n try {\n bundleName = getBundleName(opts.projectDir);\n } catch {\n // bundleName is informational; a HAP from a project without AppScope still installs.\n }\n return { installed: true, bundleName, hapPath, output: `${result.stdout}${result.stderr}`.trim() };\n}\n\n/**\n * Whether `bm dump -n <bundle>` finds the bundle on the device. A missing bundle\n * prints `error: failed to get information…`; an installed one, `<bundle>:` and\n * its JSON.\n */\nexport async function isBundleInstalled(opts: BundleOptions): Promise<boolean> {\n const safe = opts.bundle.replace(/'/g, `'\\\\''`);\n const res = await shell({\n config: opts.config,\n command: `bm dump -n '${safe}'`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 15_000,\n logger: opts.logger,\n });\n ensureOk(res, `hdc shell bm dump -n ${opts.bundle}`);\n return res.stdout.includes('{') && !/failed to get information/i.test(res.stdout);\n}\n\nexport interface LaunchAppOptions {\n config: ConfigProvider;\n /** Project mode: resolve bundle + main ability from the project. Required unless `bundleName` is given. */\n projectDir?: string;\n /**\n * Bundle mode: launch an already-installed app directly by bundle name (no\n * project needed). When set, `projectDir` is ignored. If `abilityName` is\n * omitted, the main ability is resolved from the device via `bm dump -n`.\n */\n bundleName?: string;\n /** Override the module name if it isn't the default `entry` (project mode). */\n moduleName?: string;\n /** Explicit ability to launch; defaults to the module's mainElement / first visible ability (project mode) or the installed bundle's main ability (bundle mode). */\n abilityName?: string;\n deviceSerial?: string;\n logger?: Logger;\n}\n\n/**\n * `aa start` exits 0 even when the launch is refused — a locked screen\n * (`Error Code:10106102`), a missing ability, a permission denial, etc. The failure\n * only shows up in its output. Returns the offending text when the output indicates a\n * failed launch, or null when it looks like a success.\n */\nexport function detectAaStartFailure(output: string): string | null {\n return /failed to start ability|Error Code:\\s*\\d|Error Message:/i.test(output) ? output.trim() : null;\n}\n\n/**\n * Parse the main ability of an installed bundle from `bm dump -n <bundle>`\n * output. Pure/testable. The output is a bundle-name prefix line followed by a\n * JSON blob; we take the entry module's `mainElementName` (fallback\n * `mainAbility`), or the first module that declares one. Returns null when the\n * bundle isn't installed or the output is unparseable.\n */\nexport function parseMainAbilityFromBmDump(stdout: string): string | null {\n const start = stdout.indexOf('{');\n if (start < 0) return null;\n let info: { hapModuleInfos?: Array<{ mainElementName?: string; mainAbility?: string; moduleType?: number | string }> };\n try {\n info = JSON.parse(stdout.slice(start));\n } catch {\n return null;\n }\n const mods = Array.isArray(info?.hapModuleInfos) ? info.hapModuleInfos : [];\n const abilityOf = (m: { mainElementName?: string; mainAbility?: string }): string | undefined =>\n (m?.mainElementName || m?.mainAbility) || undefined;\n const isEntry = (m: { moduleType?: number | string }): boolean =>\n m?.moduleType === 1 || m?.moduleType === '1' || m?.moduleType === 'entry';\n const entry = mods.find((m) => isEntry(m) && abilityOf(m));\n const any = mods.find((m) => abilityOf(m));\n return (entry && abilityOf(entry)) || (any && abilityOf(any)) || null;\n}\n\n/** Resolve an installed bundle's main ability off the device via `bm dump -n`. */\nasync function resolveInstalledMainAbility(opts: {\n config: ConfigProvider;\n bundle: string;\n deviceSerial?: string;\n logger?: Logger;\n}): Promise<string> {\n const res = await shell({\n config: opts.config,\n command: `bm dump -n ${opts.bundle}`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: 15_000,\n logger: opts.logger,\n });\n const ability = parseMainAbilityFromBmDump(res.stdout);\n if (!ability) {\n throw new OniroError(\n `Could not determine the main ability for installed bundle ${opts.bundle} ` +\n `(is it installed?). Pass an explicit ability instead.`,\n );\n }\n return ability;\n}\n\nexport async function launchApp(opts: LaunchAppOptions): Promise<void> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n let bundleName: string;\n let mainAbility: string;\n if (opts.bundleName) {\n // Bundle mode: launch an already-installed app directly (no project).\n bundleName = opts.bundleName;\n mainAbility =\n opts.abilityName ??\n (await resolveInstalledMainAbility({\n config: opts.config,\n bundle: bundleName,\n deviceSerial: opts.deviceSerial,\n logger: opts.logger,\n }));\n } else {\n if (!opts.projectDir) throw new OniroError('launchApp requires either bundleName or projectDir.');\n bundleName = getBundleName(opts.projectDir);\n mainAbility = getMainAbility(opts.projectDir, opts.moduleName, opts.abilityName);\n }\n // Pass ability/bundle as discrete argv elements (shell:false), never interpolated\n // into a host shell string — this is the injection fix vs the old `aa start -a ${x}`.\n const result = await hdcExec({\n config: opts.config,\n args: ['shell', 'aa', 'start', '-a', mainAbility, '-b', bundleName],\n deviceSerial: opts.deviceSerial,\n });\n if (result.stdout.trim()) logger.info(result.stdout.trim());\n if (result.stderr.trim()) logger.warn(result.stderr.trim());\n ensureOk(result, `hdc shell aa start -a ${mainAbility} -b ${bundleName}`);\n // `aa start` reports launch failures in its output, not its exit code — surface them\n // instead of silently reporting success.\n const failure = detectAaStartFailure(`${result.stdout}\\n${result.stderr}`);\n if (failure) {\n throw new OniroError(`Failed to launch ${bundleName} (${mainAbility}): ${failure}`);\n }\n}\n\nexport interface RunningProcess {\n pid: string;\n name: string;\n}\n\n/**\n * List running processes via `hdc track-jpid`. Times out after `timeoutMs`.\n * When `targetProcessName` is set, resolves to that process's PID early; otherwise\n * resolves to the full list collected within the timeout window.\n */\nexport function listRunningProcesses(\n config: ConfigProvider,\n options: { targetProcessName?: string; timeoutMs?: number; deviceSerial?: string; logger?: Logger } = {},\n): Promise<RunningProcess[] | string> {\n const logger = options.logger ?? noopLogger;\n const timeoutMs = options.timeoutMs ?? 1000;\n const hdc = getHdcPath(config);\n\n return new Promise((resolve, reject) => {\n // `hdc` may be a batch wrapper on Windows (an `hdcPath` override pointing at\n // a proxy/tunnel script), which a bare spawn cannot execute — spawnCompat\n // routes those through cmd.exe. It can also throw synchronously, so the\n // failure is funnelled into the same rejection as the 'error' event below.\n let proc: ChildProcess;\n try {\n proc = spawnCompat(hdc, [...hdcTargetArgs(options.deviceSerial), 'track-jpid']);\n } catch (err) {\n reject(new OniroError(`Failed to spawn ${hdc}: ${err instanceof Error ? err.message : String(err)}`, err));\n return;\n }\n const processes: RunningProcess[] = [];\n let resolved = false;\n\n proc.stdout?.on('data', (data: Buffer) => {\n for (const line of data.toString().split(/\\r?\\n/).filter(Boolean)) {\n const match = line.match(/^(\\d+)\\s+(.+)$/);\n if (!match) continue;\n const pid = match[1]!;\n const name = match[2]!;\n processes.push({ pid, name });\n if (options.targetProcessName && name === options.targetProcessName && !resolved) {\n resolved = true;\n killProcessTree(proc);\n resolve(pid);\n return;\n }\n }\n });\n\n proc.stderr?.on('data', (data: Buffer) => {\n logger.warn(`[hdc track-jpid] ${data.toString()}`);\n });\n\n proc.on('error', (err) => {\n if (!resolved) {\n resolved = true;\n reject(err);\n }\n });\n\n const timeout = setTimeout(() => {\n if (resolved) return;\n resolved = true;\n killProcessTree(proc);\n if (options.targetProcessName) {\n reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));\n } else {\n resolve(processes);\n }\n }, timeoutMs);\n\n proc.on('close', () => {\n clearTimeout(timeout);\n if (resolved) return;\n resolved = true;\n if (options.targetProcessName) {\n reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));\n } else {\n resolve(processes);\n }\n });\n });\n}\n\nexport async function findAppProcessId(config: ConfigProvider, projectDir: string, logger?: Logger): Promise<string> {\n const bundleName = getBundleName(projectDir);\n const result = await listRunningProcesses(config, { targetProcessName: bundleName, logger });\n return result as string;\n}\n\nexport interface BundleOptions {\n config: ConfigProvider;\n bundle: string;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * Non-throwing companion to {@link listRunningProcesses}: resolve a running\n * process for a bundle, or `null` when it isn't running. Suitable for \"is X\n * running?\" checks (e.g. the pre/post-install pid comparison in applyChanges).\n *\n * `pidof` matches the bundle's main (UIAbility) process. When that isn't found,\n * we fall back to `track-jpid` to also catch **extension-ability** processes,\n * which run under a separate process name `\"<bundle>:<ext>\"` (e.g. a\n * ServiceExtension, FormExtension, UIExtension or input method). Without this,\n * \"verify the running process took the change\" silently reported nothing for an\n * app whose only live process is an extension.\n */\nexport async function findRunningProcess(opts: BundleOptions): Promise<RunningProcess | null> {\n const safe = opts.bundle.replace(/'/g, `'\\\\''`);\n const res = await shell({\n config: opts.config,\n command: `pidof '${safe}'`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n const pid = res.stdout.trim().split(/\\s+/).filter(Boolean)[0];\n if (res.code === 0 && pid && /^\\d+$/.test(pid)) return { pid, name: opts.bundle };\n\n // Fallback: the bundle may only be alive as an extension process. track-jpid\n // names them \"<bundle>/<bundle>:<ext>\" (vs bare \"<bundle>\" for the main).\n try {\n const list = await listRunningProcesses(opts.config, {\n timeoutMs: 1200,\n deviceSerial: opts.deviceSerial,\n logger: opts.logger,\n });\n if (Array.isArray(list)) {\n const mine = (name: string): boolean =>\n name === opts.bundle || name.startsWith(`${opts.bundle}/`) || name.startsWith(`${opts.bundle}:`);\n const match = list.find((p) => p.name === opts.bundle) ?? list.find((p) => mine(p.name));\n if (match) return match;\n }\n } catch {\n // best-effort; fall through to \"not running\"\n }\n return null;\n}\n\n/** Uninstall an app by bundle name (`hdc uninstall <bundle>`). */\nexport async function uninstallApp(opts: BundleOptions): Promise<void> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n const res = await hdcExec({\n config: opts.config,\n args: ['uninstall', opts.bundle],\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 120_000,\n });\n if (res.stdout.trim()) logger.info(res.stdout.trim());\n if (res.stderr.trim()) logger.warn(res.stderr.trim());\n ensureOk(res, `hdc uninstall ${opts.bundle}`);\n}\n\n/** Force-stop an app (`hdc shell aa force-stop <bundle>`). */\nexport async function forceStop(opts: BundleOptions): Promise<void> {\n const res = await shell({\n config: opts.config,\n command: `aa force-stop ${opts.bundle}`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 30_000,\n logger: opts.logger,\n });\n ensureOk(res, `hdc shell aa force-stop ${opts.bundle}`);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { OniroError } from '../ports/errors.js';\n\nexport interface ModuleHaps {\n signed: string[];\n unsigned: string[];\n}\n\nexport interface DiscoverHapsOptions {\n projectDir: string;\n /** Max directory recursion depth. Default 8. */\n maxDepth?: number;\n}\n\n/**\n * The build module a HAP belongs to, parsed from its filename\n * (`<module>-<target>-<buildMode>-{signed,unsigned}.hap`): the segment before\n * the first dash. This is the build module NAME — what `--module` refers to and\n * what hvigor stamps into the filename — which, unlike the first path segment,\n * is robust to nested project layouts (e.g. systemui's\n * `product/phone/<folder>/build/.../phone_gestureNavigation-...-signed.hap`,\n * where the module folder is not a top-level directory under projectDir).\n */\nfunction moduleOfHap(hapFileName: string): string {\n const dash = hapFileName.indexOf('-');\n return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\\.hap$/i, '');\n}\n\n/**\n * Walk a project's build outputs and group `*-signed.hap` / `*-unsigned.hap`\n * by build module name (parsed from the HAP filename). Skips `node_modules` /\n * `oh_modules` / `.git`. Ported from the proven MCP `findHaps`, extended with\n * per-module grouping so multi-module projects can install the right HAP.\n * Each list is newest first, so a fresh build wins over HAPs committed to the\n * repository. Empty object when nothing is built.\n */\nexport async function discoverHaps(opts: DiscoverHapsOptions): Promise<Record<string, ModuleHaps>> {\n const { projectDir } = opts;\n const maxDepth = opts.maxDepth ?? 8;\n const result: Record<string, ModuleHaps> = {};\n\n const walk = async (dir: string, depth: number): Promise<void> => {\n if (depth > maxDepth) return;\n const entries = await fs.promises.readdir(dir, { withFileTypes: true }).catch(() => [] as fs.Dirent[]);\n for (const e of entries) {\n const full = path.join(dir, e.name);\n if (e.isDirectory()) {\n if (e.name === 'node_modules' || e.name === 'oh_modules' || e.name === '.git') continue;\n await walk(full, depth + 1);\n } else if (e.isFile() && e.name.endsWith('.hap')) {\n const moduleName = moduleOfHap(e.name);\n const bucket = (result[moduleName] ??= { signed: [], unsigned: [] });\n if (e.name.includes('unsigned')) bucket.unsigned.push(full);\n else if (e.name.includes('signed')) bucket.signed.push(full);\n }\n }\n };\n\n await walk(projectDir, 0);\n const mtime = (p: string): number => fs.statSync(p).mtimeMs;\n for (const bucket of Object.values(result)) {\n bucket.signed.sort((a, b) => mtime(b) - mtime(a));\n bucket.unsigned.sort((a, b) => mtime(b) - mtime(a));\n }\n return result;\n}\n\nexport interface PickedHap {\n module: string;\n path: string;\n /** False for an `*-unsigned.hap`, which targets that verify signatures reject. */\n signed: boolean;\n}\n\n/**\n * The HAP to install from {@link discoverHaps} output: a module's newest signed\n * HAP, else its newest unsigned one. Without `module`, the single module that\n * has a signed HAP, else the single one that has any HAP. Null when nothing is\n * built; throws when several modules qualify and none was named.\n */\nexport function pickHap(haps: Record<string, ModuleHaps>, module?: string): PickedHap | null {\n const pick = (name: string): PickedHap | null => {\n const signed = haps[name]?.signed[0];\n if (signed) return { module: name, path: signed, signed: true };\n const unsigned = haps[name]?.unsigned[0];\n return unsigned ? { module: name, path: unsigned, signed: false } : null;\n };\n if (module) return pick(module);\n const names = Object.keys(haps);\n const withSigned = names.filter((n) => haps[n]!.signed.length > 0);\n const candidates = withSigned.length > 0 ? withSigned : names.filter((n) => haps[n]!.unsigned.length > 0);\n if (candidates.length === 0) return null;\n if (candidates.length > 1) {\n throw new OniroError(`Multiple modules have built HAPs (${candidates.join(', ')}). Pass a module to choose.`);\n }\n return pick(candidates[0]!);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport JSON5 from 'json5';\nimport { OniroError } from '../ports/errors.js';\n\nfunction readJson5<T>(filePath: string): T {\n const content = fs.readFileSync(filePath, 'utf-8');\n return JSON5.parse(content) as T;\n}\n\n/**\n * Read the project's bundle name from `AppScope/app.json5`.\n */\nexport function getBundleName(projectDir: string): string {\n const appJsonPath = path.join(projectDir, 'AppScope', 'app.json5');\n if (!fs.existsSync(appJsonPath)) {\n throw new OniroError(`Could not find app.json5 at ${appJsonPath}`);\n }\n const appJson = readJson5<{ app?: { bundleName?: string } }>(appJsonPath);\n if (!appJson.app?.bundleName) {\n throw new OniroError('bundleName not found in app.json5');\n }\n return appJson.app.bundleName;\n}\n\n/**\n * Read the ability to launch from `<module>/src/main/module.json5`. Defaults to\n * `entry` for the module folder name. Resolution order:\n * 1. `abilityName`, if given and present in `module.abilities[]`.\n * 2. `module.mainElement`.\n * 3. The first `visible` ability, then the first ability, from `module.abilities[]`.\n * Modules with multiple abilities can be targeted explicitly via `abilityName`.\n */\nexport function getMainAbility(projectDir: string, moduleName = 'entry', abilityName?: string): string {\n const moduleJsonPath = path.join(projectDir, moduleName, 'src', 'main', 'module.json5');\n if (!fs.existsSync(moduleJsonPath)) {\n throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);\n }\n const moduleJson = readJson5<{\n module?: { mainElement?: string; abilities?: Array<{ name?: string; visible?: boolean }> };\n }>(moduleJsonPath);\n const module = moduleJson.module ?? {};\n\n if (abilityName) {\n const match = module.abilities?.find((a) => a.name === abilityName);\n if (match?.name) return match.name;\n throw new OniroError(`Ability \"${abilityName}\" not found in module.json5 at ${moduleJsonPath}`);\n }\n\n if (module.mainElement) return module.mainElement;\n\n const abilities = module.abilities ?? [];\n const visible = abilities.find((a) => a.visible && a.name);\n if (visible?.name) return visible.name;\n const first = abilities.find((a) => a.name);\n if (first?.name) return first.name;\n\n throw new OniroError('mainElement not found in module.json5');\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger, scopedLogger } from '../ports/logger.js';\nimport { hdcExec, shell } from './exec.js';\nimport { paramSet } from './param.js';\nimport { findRunningProcess } from './app.js';\nimport { waitForCondition } from './wait.js';\n\n/** Probe whether the device responds to a trivial shell command. */\nasync function isReachable(config: ConfigProvider, deviceSerial?: string): Promise<boolean> {\n try {\n const res = await shell({ config, command: 'echo oniro_ping', deviceSerial, timeoutMs: 5_000 });\n return res.code === 0 && res.stdout.includes('oniro_ping');\n } catch {\n return false;\n }\n}\n\n/**\n * A TCP/network hdc target — \"host:port\", e.g. the emulator's `127.0.0.1:55555`.\n * USB serials (e.g. `emulator-5554`) have no `:port` suffix.\n */\nconst TCP_SERIAL_RE = /^.+:\\d+$/;\n\n/**\n * Polls in a row on which `hdc tconn` says a TCP target is already connected while it\n * does not answer, before the hdc server is restarted.\n */\nconst WEDGED_POLLS_BEFORE_RESTART = 3;\n\n/**\n * Re-establish the hdc connection to a TCP target, best-effort. hdc auto-reconnects\n * a USB device when it re-enumerates, but a TCP target must be reconnected explicitly\n * with `hdc tconn` after the session drops — which is exactly what a reboot does, so\n * without this a post-reboot `waitForBundle`/`waitForBoot` polls a dead socket until it\n * times out. A no-op for USB serials or when no serial is given, so it is safe to call\n * before every poll; failure is swallowed (the device may still be down, and the probe\n * that follows reports not-ready so we simply poll again).\n *\n * After a reboot the hdc server can also wedge on the old session: it keeps the target\n * \"Connected\", answers `tconn` with \"Target is connected, repeat operation\" and fails\n * every command (\"session is dead\") until the server restarts. Seen intermittently\n * with the OpenHarmony 7.0 emulator. So the returned function counts the polls on\n * which tconn claims a connection the target does not answer, and after\n * {@link WEDGED_POLLS_BEFORE_RESTART} of them in a row restarts the server with\n * `hdc start -r`, as `attemptHdcConnection` does, and reconnects. The count lives in\n * the closure, so create one reconnector per wait.\n */\nfunction tcpReconnector(config: ConfigProvider, deviceSerial: string | undefined, logger: Logger): () => Promise<void> {\n let wedgedPolls = 0;\n return async () => {\n if (!deviceSerial || !TCP_SERIAL_RE.test(deviceSerial)) return;\n let claimsConnected = false;\n try {\n const res = await hdcExec({ config, args: ['tconn', deviceSerial], timeoutMs: 5_000, logger });\n claimsConnected = /already connected|repeat operation/i.test(`${res.stdout}\\n${res.stderr}`);\n } catch {\n /* still down — the following probe reports not-ready and we poll again */\n }\n // A healthy session also answers \"repeat operation\"; only an unreachable one counts.\n if (!claimsConnected || (await isReachable(config, deviceSerial))) {\n wedgedPolls = 0;\n return;\n }\n if (++wedgedPolls < WEDGED_POLLS_BEFORE_RESTART) return;\n wedgedPolls = 0;\n logger.warn(`hdc reports ${deviceSerial} as connected but it does not answer; restarting the hdc server.`);\n try {\n await hdcExec({ config, args: ['start', '-r'], timeoutMs: 15_000, logger });\n await hdcExec({ config, args: ['tconn', deviceSerial], timeoutMs: 5_000, logger });\n } catch {\n /* the next poll tries again */\n }\n };\n}\n\nexport interface WaitForBundleOptions {\n config: ConfigProvider;\n bundle: string;\n deviceSerial?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/**\n * Poll `pidof <bundle>` until the bundle has a clean numeric pid. Empty/failed\n * pidof responses (including while the device is unreachable) do NOT count.\n */\nexport async function waitForBundle(opts: WaitForBundleOptions): Promise<void> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n const timeoutMs = opts.timeoutMs ?? 180_000;\n const reconnectIfTcp = tcpReconnector(opts.config, opts.deviceSerial, logger);\n await waitForCondition({\n probe: async () => {\n await reconnectIfTcp();\n return (\n (await findRunningProcess({ config: opts.config, bundle: opts.bundle, deviceSerial: opts.deviceSerial, timeoutMs: 8_000 })) !== null\n );\n },\n timeoutMs,\n pollMs: 2_000,\n abortSignal: opts.abortSignal,\n onHeartbeat: (attempt, remaining) =>\n logger.info(`waiting for ${opts.bundle} (attempt ${attempt}, ${Math.floor(remaining / 1000)}s left)`),\n timeoutMessage: `Bundle ${opts.bundle} did not start within ${timeoutMs}ms.`,\n });\n}\n\nexport interface WaitForBootOptions {\n config: ConfigProvider;\n /** Require a clean numeric pid for this process/bundle name before returning. */\n untilPidOf?: string;\n deviceSerial?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/**\n * Poll until the device responds AND (when `untilPidOf` is set) that process has\n * a clean numeric pid. Tolerates the transient hdc disconnect during a reboot.\n */\nexport async function waitForBoot(opts: WaitForBootOptions): Promise<void> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n const timeoutMs = opts.timeoutMs ?? 180_000;\n const reconnectIfTcp = tcpReconnector(opts.config, opts.deviceSerial, logger);\n await waitForCondition({\n probe: async () => {\n await reconnectIfTcp();\n if (!(await isReachable(opts.config, opts.deviceSerial))) return false;\n if (!opts.untilPidOf) return true;\n return (\n (await findRunningProcess({ config: opts.config, bundle: opts.untilPidOf, deviceSerial: opts.deviceSerial, timeoutMs: 8_000 })) !== null\n );\n },\n timeoutMs,\n pollMs: 2_000,\n abortSignal: opts.abortSignal,\n onHeartbeat: (attempt, remaining) =>\n logger.info(`waiting for boot (attempt ${attempt}, ${Math.floor(remaining / 1000)}s left)`),\n timeoutMessage: `Device did not boot within ${timeoutMs}ms.`,\n });\n}\n\nexport interface RebootOptions {\n config: ConfigProvider;\n /** 'system' (default) reboots via param set; bootloader/recovery via `reboot <mode>`. */\n mode?: 'system' | 'bootloader' | 'recovery';\n /** When set (system mode), block until this bundle has a clean numeric pid after the reboot. */\n waitForBundle?: string;\n deviceSerial?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/**\n * Reboot the device. System reboots use `param set ohos.startup.powerctrl reboot`\n * (the path that works when force-stopping systemui is blocked); bootloader/\n * recovery use `hdc shell reboot <mode>`. A reboot frequently tears down the hdc\n * connection before the command returns, so command failure here is tolerated.\n *\n * When `waitForBundle` is set (system mode), waits for the device to drop and\n * come back with the bundle running — so it doesn't return on the pre-reboot pid.\n * A TCP target (e.g. an emulator at `127.0.0.1:55555`) is reconnected via\n * `hdc tconn` during that wait, since hdc does not auto-reconnect TCP sessions\n * across a reboot the way it does USB devices — pass the address as `deviceSerial`.\n */\nexport async function reboot(opts: RebootOptions): Promise<void> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n const mode = opts.mode ?? 'system';\n const timeoutMs = opts.timeoutMs ?? 180_000;\n\n logger.info(`Rebooting device (${mode})...`);\n try {\n if (mode === 'system') {\n await paramSet(opts.config, 'ohos.startup.powerctrl', 'reboot', {\n deviceSerial: opts.deviceSerial,\n timeoutMs: 15_000,\n logger: opts.logger,\n });\n } else {\n await shell({ config: opts.config, command: `reboot ${mode}`, deviceSerial: opts.deviceSerial, timeoutMs: 15_000 });\n }\n } catch (err) {\n // Expected: the reboot tore down hdc before the command returned cleanly.\n logger.debug(`reboot command did not return cleanly: ${(err as Error).message}`);\n }\n\n if (mode !== 'system' || !opts.waitForBundle) return;\n\n // Wait for the device to actually go down first (best-effort) so the subsequent\n // bundle wait can't match the pre-reboot process, then wait for it to return.\n try {\n await waitForCondition({\n probe: async () => !(await isReachable(opts.config, opts.deviceSerial)),\n timeoutMs: Math.min(timeoutMs, 30_000),\n pollMs: 1_500,\n abortSignal: opts.abortSignal,\n timeoutMessage: 'device did not become unreachable',\n });\n } catch {\n // Device may reboot too fast to observe the down state — proceed to wait for it.\n }\n\n await waitForBundle({\n config: opts.config,\n bundle: opts.waitForBundle,\n deviceSerial: opts.deviceSerial,\n timeoutMs,\n abortSignal: opts.abortSignal,\n logger: opts.logger,\n });\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { randomBytes } from 'node:crypto';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { shell, ensureOk } from './exec.js';\nimport { recvFile } from './files.js';\nimport { getDisplaySize } from './display.js';\n\nexport interface Screenshot {\n /** Raw JPEG bytes, exactly as `snapshot_display` wrote them (no decode/resize). */\n pixels: Buffer;\n /** Device render width/height from hidumper; 0 when it couldn't be resolved. */\n width: number;\n height: number;\n}\n\nexport interface ScreenshotOptions {\n config: ConfigProvider;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\nfunction tmpName(ext: string): string {\n return path.join(os.tmpdir(), `oniro_screen_${randomBytes(6).toString('hex')}.${ext}`);\n}\n\n/**\n * Capture the screen via on-device `snapshot_display`, pull the JPEG bytes back,\n * and return them raw alongside the device resolution. The agent-facing grid\n * overlay / downscale / base64 encoding stays in the MCP — core does no image\n * decoding and adds no image dependency.\n */\nexport async function takeScreenshot(opts: ScreenshotOptions): Promise<Screenshot> {\n const remote = '/data/local/tmp/oniro_screenshot.jpeg';\n const timeoutMs = opts.timeoutMs ?? 30_000;\n\n const cap = await shell({ config: opts.config, command: `snapshot_display -f ${remote}`, deviceSerial: opts.deviceSerial, timeoutMs });\n ensureOk(cap, `snapshot_display -f ${remote}`);\n\n const local = tmpName('jpeg');\n try {\n await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });\n const pixels = await fs.promises.readFile(local);\n const size = (await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial })) ?? { width: 0, height: 0 };\n return { pixels, width: size.width, height: size.height };\n } finally {\n fs.promises.unlink(local).catch(() => {});\n void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {});\n }\n}\n\nexport interface CaptureBurstOptions {\n config: ConfigProvider;\n count: number;\n /** Delay between device-side captures, ms. */\n intervalMs: number;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * Capture `count` frames `intervalMs` apart in a single device-side loop, then\n * pull each frame back. Returns the raw JPEG buffers in order. The MCP composites\n * these into a contact sheet + per-frame diff; core just returns the frames.\n */\nexport async function captureBurst(opts: CaptureBurstOptions): Promise<Buffer[]> {\n const count = Math.max(1, Math.floor(opts.count));\n const remoteDir = `/data/local/tmp/oniro_burst_${randomBytes(6).toString('hex')}`;\n const sleepSec = opts.intervalMs > 0 ? (opts.intervalMs / 1000).toFixed(3) : '0';\n // One device-side loop so the frames are device-timed, not gated on host roundtrips.\n const loop =\n `mkdir -p ${remoteDir}; i=0; while [ $i -lt ${count} ]; do ` +\n `snapshot_display -f ${remoteDir}/f$i.jpeg; ` +\n `[ ${count} -gt 1 ] && sleep ${sleepSec}; i=$((i+1)); done`;\n const cap = await shell({ config: opts.config, command: loop, deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 120_000 });\n ensureOk(cap, 'snapshot_display burst');\n\n const frames: Buffer[] = [];\n try {\n for (let i = 0; i < count; i++) {\n const local = tmpName(`burst_${i}.jpeg`);\n try {\n await recvFile({ config: opts.config, remote: `${remoteDir}/f${i}.jpeg`, local, deviceSerial: opts.deviceSerial });\n frames.push(await fs.promises.readFile(local));\n } finally {\n fs.promises.unlink(local).catch(() => {});\n }\n }\n } finally {\n void shell({ config: opts.config, command: `rm -rf ${remoteDir}`, deviceSerial: opts.deviceSerial }).catch(() => {});\n }\n return frames;\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { shellChecked, ensureRemoteOk } from './exec.js';\n\nexport type InputType =\n | 'click'\n | 'doubleClick'\n | 'longClick'\n | 'swipe'\n | 'drag'\n | 'fling'\n | 'keyEvent'\n | 'inputText';\n\nexport interface SendInputOptions {\n config: ConfigProvider;\n type: InputType;\n /** Pixel coordinates. The %→px conversion lives in the MCP, not core. */\n pxX?: number;\n pxY?: number;\n pxX2?: number;\n pxY2?: number;\n /** Velocity for swipe/drag/fling. */\n speed?: number;\n /** Key for keyEvent: a KeyCode id, a name (Back, Delete, Enter, …), or a combo like `Ctrl+A`. See {@link resolveKeyEvent}. */\n key?: string | number;\n /** Text for inputText. */\n text?: string;\n deviceSerial?: string;\n logger?: Logger;\n}\n\n// uitest accepts these key names itself.\nconst UITEST_KEY_NAMES = ['Back', 'Home', 'Power'];\n\n// OpenHarmony KeyCode ids (@ohos.multimodalInput.keyCode) for keys addressed by name.\nconst KEY_IDS: Record<string, number> = {\n back: 2,\n home: 1,\n power: 18,\n volumeup: 16,\n volumedown: 17,\n up: 2012,\n down: 2013,\n left: 2014,\n right: 2015,\n alt: 2045,\n shift: 2047,\n tab: 2049,\n space: 2050,\n enter: 2054,\n delete: 2055,\n backspace: 2055,\n pageup: 2068,\n pagedown: 2069,\n escape: 2070,\n esc: 2070,\n forwarddelete: 2071,\n ctrl: 2072,\n meta: 2076,\n movehome: 2081,\n moveend: 2082,\n};\n\nfunction keyId(name: string): number {\n const k = name.trim().toLowerCase();\n if (/^\\d+$/.test(k)) return Number(k);\n if (/^[a-z]$/.test(k)) return 2017 + (k.charCodeAt(0) - 97); // KEYCODE_A..KEYCODE_Z\n const id = KEY_IDS[k];\n if (id === undefined) {\n throw new OniroError(\n `Unknown key \"${name}\". Use a numeric KeyCode id, a letter, or one of: ` +\n `${Object.keys(KEY_IDS).join(', ')}. Combine up to three with \"+\", e.g. Ctrl+A.`,\n );\n }\n return id;\n}\n\n/**\n * Resolve a key spec to `uitest uiInput keyEvent` arguments. Accepts uitest's\n * own names (Back/Home/Power), numeric KeyCode ids, named keys (Delete, Enter,\n * Tab, Escape, MoveHome, …), single letters, and combos of up to three keys\n * joined by \"+\" (e.g. `Ctrl+A`) or given as space-separated ids. Pure.\n */\nexport function resolveKeyEvent(key: string | number): string {\n const spec = String(key).trim();\n if (spec === '') throw new OniroError('send input \"keyEvent\" requires a key.');\n const native = UITEST_KEY_NAMES.find((n) => n.toLowerCase() === spec.toLowerCase());\n if (native) return native;\n const parts = spec.includes('+') ? spec.split('+') : spec.split(/\\s+/);\n if (parts.length > 3) throw new OniroError(`uitest injects at most three keys at once; got \"${spec}\".`);\n return parts.map(keyId).join(' ');\n}\n\nfunction reqNum(value: number | undefined, name: string, type: string): number {\n if (value === undefined || Number.isNaN(value)) {\n throw new OniroError(`send input \"${type}\" requires a numeric ${name}.`);\n }\n return value;\n}\n\n/**\n * Build the `uitest uiInput …` command for an input action, in pixel space.\n * Pure (no I/O) so it is unit-testable. Mirrors the proven MCP construction\n * minus the percentage→pixel step.\n */\nexport function buildInputCommand(opts: SendInputOptions): string {\n switch (opts.type) {\n case 'click':\n case 'doubleClick':\n case 'longClick':\n return `uitest uiInput ${opts.type} ${reqNum(opts.pxX, 'pxX', opts.type)} ${reqNum(opts.pxY, 'pxY', opts.type)}`;\n case 'swipe':\n case 'drag':\n case 'fling': {\n const base =\n `uitest uiInput ${opts.type} ${reqNum(opts.pxX, 'pxX', opts.type)} ${reqNum(opts.pxY, 'pxY', opts.type)} ` +\n `${reqNum(opts.pxX2, 'pxX2', opts.type)} ${reqNum(opts.pxY2, 'pxY2', opts.type)}`;\n return opts.speed !== undefined ? `${base} ${opts.speed}` : base;\n }\n case 'keyEvent':\n if (opts.key === undefined || opts.key === '') throw new OniroError('send input \"keyEvent\" requires a key.');\n return `uitest uiInput keyEvent ${resolveKeyEvent(opts.key)}`;\n case 'inputText': {\n const t = String(opts.text ?? '').replace(/'/g, `'\\\\''`);\n if (opts.pxX !== undefined && opts.pxY !== undefined) {\n return `uitest uiInput inputText ${opts.pxX} ${opts.pxY} '${t}'`;\n }\n return `uitest uiInput text '${t}'`;\n }\n }\n}\n\n/** Inject a UI input action via `uitest uiInput` (pixel coordinates). */\nexport async function sendInput(opts: SendInputOptions): Promise<void> {\n const cmd = buildInputCommand(opts);\n const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 30_000, logger: opts.logger });\n ensureRemoteOk(res, `hdc shell ${cmd}`);\n}\n\nexport interface Waypoint {\n /** Pixel x. */\n x: number;\n /** Pixel y. */\n y: number;\n /** Time in ms relative to the gesture start. */\n t: number;\n}\n\nexport interface SendGestureOptions {\n config: ConfigProvider;\n waypoints: Waypoint[];\n /** Hold at the first point before moving (ms). Honored via the raw-touch path. */\n holdStartMs?: number;\n /** Hold at the last point before lifting (ms). Honored via the raw-touch path. */\n holdEndMs?: number;\n deviceSerial?: string;\n logger?: Logger;\n}\n\n/**\n * Build the chained `uitest uiInput drag` commands for a multi-segment path.\n * Per segment, speed is derived from the waypoint time deltas (px/s). Pure.\n */\nexport function buildGestureCommands(waypoints: Waypoint[]): string[] {\n if (waypoints.length < 2) {\n throw new OniroError('sendGesture requires at least two waypoints.');\n }\n const cmds: string[] = [];\n for (let i = 1; i < waypoints.length; i++) {\n const a = waypoints[i - 1]!;\n const b = waypoints[i]!;\n const dt = b.t - a.t;\n const dist = Math.hypot(b.x - a.x, b.y - a.y);\n let cmd = `uitest uiInput drag ${a.x} ${a.y} ${b.x} ${b.y}`;\n if (dt > 0 && dist > 0) cmd += ` ${Math.round(dist / (dt / 1000))}`;\n cmds.push(cmd);\n }\n return cmds;\n}\n\nexport interface RawTouchEvent {\n type: 'down' | 'move' | 'up';\n x: number;\n y: number;\n /** Time in ms relative to the gesture start. */\n t: number;\n}\n\nexport interface SendRawTouchOptions {\n config: ConfigProvider;\n events: RawTouchEvent[];\n deviceSerial?: string;\n logger?: Logger;\n}\n\n/**\n * Build a single `uinput -T` touch operation sequence from down/move/up events,\n * interleaving `-i <ms>` intervals from the event time deltas. Pure.\n */\nexport function buildRawTouchCommand(events: RawTouchEvent[]): string {\n if (events.length === 0) throw new OniroError('sendRawTouch requires at least one event.');\n const ops: string[] = [];\n let prev: RawTouchEvent | null = null;\n for (const ev of events) {\n if (prev && ev.t > prev.t) ops.push(`-i ${ev.t - prev.t}`);\n if (ev.type === 'down') ops.push(`-d ${ev.x} ${ev.y}`);\n else if (ev.type === 'up') ops.push(`-u ${ev.x} ${ev.y}`);\n else ops.push(`-m ${prev ? `${prev.x} ${prev.y} ` : ''}${ev.x} ${ev.y}`);\n prev = ev;\n }\n return `uinput -T ${ops.join(' ')}`;\n}\n\n/** Expand a waypoint path (+ optional holds) into raw down/move/up events for\n * the `uinput` escape hatch ({@link sendRawTouch} / {@link buildRawTouchCommand}). */\nexport function waypointsToRawEvents(waypoints: Waypoint[], holdStartMs = 0, holdEndMs = 0): RawTouchEvent[] {\n if (waypoints.length < 2) throw new OniroError('sendGesture requires at least two waypoints.');\n const first = waypoints[0]!;\n const events: RawTouchEvent[] = [{ type: 'down', x: first.x, y: first.y, t: 0 }];\n for (let i = 1; i < waypoints.length; i++) {\n const w = waypoints[i]!;\n events.push({ type: 'move', x: w.x, y: w.y, t: w.t + holdStartMs });\n }\n const last = waypoints[waypoints.length - 1]!;\n events.push({ type: 'up', x: last.x, y: last.y, t: last.t + holdStartMs + holdEndMs });\n return events;\n}\n\n// `uitest uiInput swipe/drag` accepts a velocity in [200, 40000] px/s.\nconst UITEST_VELOCITY_MIN = 200;\nconst UITEST_VELOCITY_MAX = 40000;\n\nexport interface GestureUitestOptions {\n /** A leading press-hold; when > 0 the stroke uses `drag` (press-and-hold,\n * then move) instead of `swipe`. uitest has no arbitrary hold duration. */\n holdStartMs?: number;\n}\n\n/**\n * Build a single continuous `uitest uiInput` stroke for a waypoint path. Pure.\n *\n * uitest has no polyline or stationary-hold primitive, so the path is collapsed\n * to first→last (gesture-nav strokes are straight lines) with the velocity\n * derived from the total elapsed time and clamped to uitest's range. A\n * requested `holdStartMs` maps to `drag` (which presses-and-holds before\n * moving — uitest's nearest equivalent to a leading hold); otherwise `swipe`.\n */\nexport function buildGestureUitestCommand(waypoints: Waypoint[], opts: GestureUitestOptions = {}): string {\n if (waypoints.length < 2) throw new OniroError('sendGesture requires at least two waypoints.');\n const a = waypoints[0]!;\n const b = waypoints[waypoints.length - 1]!;\n const dist = Math.hypot(b.x - a.x, b.y - a.y);\n const dtMs = b.t - a.t;\n const op = (opts.holdStartMs ?? 0) > 0 ? 'drag' : 'swipe';\n let cmd = `uitest uiInput ${op} ${a.x} ${a.y} ${b.x} ${b.y}`;\n if (dtMs > 0 && dist > 0) {\n const v = Math.round(dist / (dtMs / 1000));\n cmd += ` ${Math.max(UITEST_VELOCITY_MIN, Math.min(UITEST_VELOCITY_MAX, v))}`;\n }\n return cmd;\n}\n\n/**\n * Drive a swipe-style gesture via a single continuous `uitest uiInput` stroke —\n * the MMI-injection path that `inputMonitor`-based services (gesture-nav,\n * systemui overlays) actually observe. Preferred over raw `uinput`, whose\n * kernel virtual-device events do not reach `inputMonitor` on some native-boot\n * devices (and whose multi-op form some on-device `uinput` builds reject).\n *\n * uitest has no polyline or stationary-hold primitive: a multi-waypoint path is\n * collapsed to first→last, `holdStartMs` maps to `drag` (press-hold-then-move),\n * and `holdEndMs` has no equivalent (ignored). For true press-time control use\n * {@link sendRawTouch} (raw `uinput`) — accepting the device caveats above.\n */\nexport async function sendGesture(opts: SendGestureOptions): Promise<void> {\n if ((opts.holdEndMs ?? 0) > 0) {\n opts.logger?.warn(\n 'sendGesture: hold-end has no uitest equivalent and is ignored; use sendRawTouch for a trailing hold.',\n );\n }\n if (opts.waypoints.length > 2) {\n opts.logger?.debug(\n `sendGesture: ${opts.waypoints.length} waypoints collapsed to first→last (uitest has no polyline path).`,\n );\n }\n const cmd = buildGestureUitestCommand(opts.waypoints, { holdStartMs: opts.holdStartMs });\n const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 30_000, logger: opts.logger });\n ensureRemoteOk(res, `hdc shell ${cmd}`);\n}\n\n/**\n * Low-level touch injection via `uinput -T`. The escape hatch when press timing\n * matters (e.g. Quickstep motion-pause), which `uitest uiInput` can't express.\n *\n * WARNING: uinput's gesture form `uinput -T -g x1 y1 x2 y2 [press] [total]`\n * silently no-ops if `press < 500ms` or `total - press < 500ms` (\"press time is\n * out of range\" — it runs nothing). Keep press and post-press windows ≥ 500ms.\n *\n * DEVICE CAVEAT: on some native-boot devices these kernel-`uinput` events never\n * reach MMI `inputMonitor` services (gesture-nav, systemui), and some on-device\n * `uinput` builds reject the multi-op `-d/-m/-u` form with \"wrong number of\n * parameters\". Prefer {@link sendGesture} (uitest) for those; this path now\n * surfaces such failures instead of silently succeeding.\n */\nexport async function sendRawTouch(opts: SendRawTouchOptions): Promise<void> {\n const cmd = buildRawTouchCommand(opts.events);\n const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 30_000, logger: opts.logger });\n ensureRemoteOk(res, `hdc shell ${cmd}`);\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { randomBytes } from 'node:crypto';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { shell, ensureOk } from './exec.js';\nimport { recvFile } from './files.js';\nimport { getDisplaySize, type DisplaySize } from './display.js';\nimport { getImeBundles, findKeyboardWindow } from './ime.js';\n\n/** A raw `uitest dumpLayout` node (attributes are strings). */\nexport interface RawLayoutNode {\n attributes?: Record<string, string>;\n children?: RawLayoutNode[];\n}\n\n/** A pruned, 0–1-normalized layout node. */\nexport interface LayoutNode {\n /** bounds [x1,y1,x2,y2] normalized to 0–1 of the display. */\n b?: [number, number, number, number];\n /** center [x,y] normalized to 0–1. */\n c?: [number, number];\n type?: string;\n text?: string;\n desc?: string;\n /** Placeholder text, e.g. an empty TextInput's \"you@example.com\". */\n hint?: string;\n id?: string;\n key?: string;\n bundle?: string;\n click?: boolean;\n check?: boolean;\n checked?: boolean;\n sel?: boolean;\n focus?: boolean;\n scroll?: boolean;\n longClick?: boolean;\n /** The component is disabled (`enabled: false`). */\n disabled?: boolean;\n /** The node's center is painted over by a later filled node (an overlay, a\n * dialog scrim, the soft keyboard), so a tap there would land on that instead. */\n covered?: boolean;\n children?: LayoutNode[];\n}\n\n/** The soft keyboard, when an input-method window is on screen. */\nexport interface KeyboardState {\n shown: boolean;\n /** Bundle of the input-method window. */\n bundle?: string;\n /** Bounds [x1,y1,x2,y2] normalized to 0–1 of the display. */\n b?: [number, number, number, number];\n}\n\nexport interface DumpLayoutResult {\n display: DisplaySize | null;\n tree: LayoutNode;\n /** Present when the dump was asked to detect the soft keyboard. */\n keyboard?: KeyboardState;\n}\n\n/** Parse a uitest bounds string `\"[x1,y1][x2,y2]\"` into a tuple, or null. */\nexport function parseBounds(s: string | undefined): [number, number, number, number] | null {\n const m = /^\\[(-?\\d+),(-?\\d+)\\]\\[(-?\\d+),(-?\\d+)\\]$/.exec(s ?? '');\n if (!m) return null;\n return [Number(m[1]), Number(m[2]), Number(m[3]), Number(m[4])];\n}\n\n// Container types that almost never carry useful info on their own.\nconst STRUCTURAL_TYPES = new Set([\n 'Stack', 'Column', 'Row', 'Flex', '__Common__', 'Grid', 'GridItem',\n 'List', 'ListItem', 'Scroll', 'Swiper', 'SwiperContent', 'Navigator',\n 'Tabs', 'TabContent', 'RelativeContainer', 'WaterFlow', 'FlowItem',\n]);\n\nconst FLAG_MAP: ReadonlyArray<[string, keyof LayoutNode]> = [\n ['clickable', 'click'],\n ['checkable', 'check'],\n ['checked', 'checked'],\n ['selected', 'sel'],\n ['focused', 'focus'],\n ['scrollable', 'scroll'],\n ['longClickable', 'longClick'],\n];\n\n/** Alpha (0–255) of a uitest `#AARRGGBB` / `#RRGGBB` color; 0 when absent or malformed. */\nfunction colorAlpha(color: string | undefined): number {\n const m = /^#([0-9a-f]{2})?[0-9a-f]{6}$/i.exec(color ?? '');\n if (!m) return 0;\n return m[1] === undefined ? 255 : parseInt(m[1], 16);\n}\n\n/** Whether a node paints a visible fill over whatever was drawn before it. */\nfunction paintsFill(a: Record<string, string>): boolean {\n if (a.visible === 'false') return false;\n if (a.opacity !== undefined && a.opacity !== '' && !(Number(a.opacity) > 0)) return false;\n return colorAlpha(a.backgroundColor) > 0;\n}\n\n/**\n * Find nodes whose center is painted over by a later node with a visible\n * background fill — a full-screen overlay, a dialog scrim, a sticky bar, or the\n * soft-keyboard window. Paint order is depth-first, siblings ordered by\n * `zIndex`, windows in dump order; ancestors and descendants never cover a node.\n *\n * A heuristic: only background fills count (an Image or Text drawn on top does\n * not), which is what overlays in practice use.\n */\nexport function findCoveredNodes(root: RawLayoutNode): Set<RawLayoutNode> {\n interface Painted {\n node: RawLayoutNode;\n bounds: [number, number, number, number] | null;\n /** Index just past this node's last descendant in `order`. */\n end: number;\n }\n const order: Painted[] = [];\n const fills: number[] = [];\n const visit = (n: RawLayoutNode): void => {\n const a = n.attributes ?? {};\n const entry: Painted = { node: n, bounds: parseBounds(a.bounds), end: 0 };\n if (entry.bounds && paintsFill(a)) fills.push(order.length);\n order.push(entry);\n const kids = (n.children ?? [])\n .map((c, i) => ({ c, i, z: Number(c.attributes?.zIndex) || 0 }))\n .sort((p, q) => p.z - q.z || p.i - q.i);\n for (const k of kids) visit(k.c);\n entry.end = order.length;\n };\n visit(root);\n\n const covered = new Set<RawLayoutNode>();\n for (const p of order) {\n if (!p.bounds) continue;\n const cx = (p.bounds[0] + p.bounds[2]) / 2;\n const cy = (p.bounds[1] + p.bounds[3]) / 2;\n for (const j of fills) {\n if (j < p.end) continue;\n const q = order[j]!.bounds!;\n if (cx >= q[0] && cx < q[2] && cy >= q[1] && cy < q[3]) {\n covered.add(p.node);\n break;\n }\n }\n }\n return covered;\n}\n\n/**\n * Prune a raw `uitest dumpLayout` tree into a compact, signal-bearing tree with\n * bounds/center normalized to 0–1 of the display. Structural wrapper nodes with\n * no signal collapse into their children. Returns a node, a flat list of nodes\n * (collapsed wrapper with multiple children), or null (nothing useful). Ported\n * from the proven MCP `pruneNode`; `covered` (from {@link findCoveredNodes})\n * marks nodes hidden under an overlay.\n */\nexport function pruneLayout(\n node: RawLayoutNode,\n display: DisplaySize | null,\n covered?: ReadonlySet<RawLayoutNode>,\n): LayoutNode | LayoutNode[] | null {\n const a = node.attributes ?? {};\n const px = parseBounds(a.bounds);\n const out: LayoutNode = {};\n if (px && display) {\n const w = display.width || 1;\n const h = display.height || 1;\n out.b = [\n +(px[0] / w).toFixed(3),\n +(px[1] / h).toFixed(3),\n +(px[2] / w).toFixed(3),\n +(px[3] / h).toFixed(3),\n ];\n out.c = [+(((px[0] + px[2]) / 2) / w).toFixed(3), +(((px[1] + px[3]) / 2) / h).toFixed(3)];\n }\n if (a.type && !STRUCTURAL_TYPES.has(a.type)) out.type = a.type;\n if (a.text) out.text = a.text;\n if (a.description) out.desc = a.description;\n if (a.hint) out.hint = a.hint;\n if (a.id) out.id = a.id;\n if (a.key && a.key !== a.id) out.key = a.key;\n if (a.bundleName) out.bundle = a.bundleName;\n for (const [attr, short] of FLAG_MAP) {\n if (a[attr] === 'true') (out[short] as boolean) = true;\n }\n if (a.enabled === 'false') out.disabled = true;\n if (covered?.has(node)) out.covered = true;\n\n const children: LayoutNode[] = [];\n for (const c of node.children ?? []) {\n const pc = pruneLayout(c, display, covered);\n if (pc) {\n if (Array.isArray(pc)) children.push(...pc);\n else children.push(pc);\n }\n }\n\n const hasSignal = Boolean(\n out.text || out.desc || out.hint || out.id || out.key || out.click ||\n out.scroll || out.check || out.longClick || out.bundle ||\n (out.type && out.type !== 'root'),\n );\n\n if (!hasSignal && children.length === 0) return null;\n // Collapse structural wrappers: pass children up to the parent.\n if (!hasSignal) return children.length === 1 ? children[0]! : children;\n\n if (children.length) out.children = children;\n return out;\n}\n\n/** A pruned layout node without children, tagged with the window it belongs to. */\nexport interface FlatLayoutNode extends Omit<LayoutNode, 'children'> {\n /** Bundle of the enclosing window (the nearest node carrying `bundle`). */\n window?: string;\n}\n\n/** Flatten a pruned layout tree into a depth-first (paint-order) list. */\nexport function flattenLayout(tree: LayoutNode): FlatLayoutNode[] {\n const out: FlatLayoutNode[] = [];\n const visit = (n: LayoutNode, window: string | undefined): void => {\n const { children, ...rest } = n;\n const win = n.bundle ?? window;\n if (Object.keys(rest).length > 0) out.push({ ...rest, ...(win ? { window: win } : {}) });\n for (const c of children ?? []) visit(c, win);\n };\n visit(tree, undefined);\n return out;\n}\n\n/** Selects layout nodes by what an agent can read off the screen. */\nexport interface LayoutSelector {\n /** Matches `text`, `desc`, or `hint`: case-insensitive exact matches win; otherwise substring matches. */\n text?: string;\n /** Matches `id` or `key` exactly. */\n id?: string;\n /** Restricts to a component type (e.g. `Button`, `TextInput`); case-insensitive. */\n type?: string;\n}\n\n/** Throw unless `selector` constrains something: a non-blank text, an id, or a type. */\nexport function assertLayoutSelector(selector: LayoutSelector): void {\n if (selector.text === undefined && selector.id === undefined && selector.type === undefined) {\n throw new OniroError('A layout selector needs a text, id, or type.');\n }\n if (selector.text !== undefined && selector.text.trim() === '') {\n throw new OniroError('A layout selector text must not be blank.');\n }\n}\n\n/**\n * The tree without the windows owned by `bundle` — e.g. the soft keyboard, whose\n * keys (\"Done\", \"9\") would otherwise match element selectors. Pure.\n */\nexport function withoutWindow(tree: LayoutNode, bundle: string): LayoutNode {\n const children = (tree.children ?? []).filter((c) => c.bundle !== bundle).map((c) => withoutWindow(c, bundle));\n return tree.children ? { ...tree, children } : tree;\n}\n\n/**\n * Find the nodes matching `selector` in a pruned layout tree, in paint order.\n * For `text`, exact (case-insensitive, trimmed) matches are returned when any\n * exist; otherwise substring matches. Covered nodes are included — callers\n * decide what to do with them (see {@link pickTarget}).\n */\nexport function findLayoutNodes(tree: LayoutNode, selector: LayoutSelector): FlatLayoutNode[] {\n assertLayoutSelector(selector);\n const type = selector.type?.toLowerCase();\n const nodes = flattenLayout(tree).filter(\n (n) =>\n (type === undefined || n.type?.toLowerCase() === type) &&\n (selector.id === undefined || n.id === selector.id || n.key === selector.id),\n );\n if (selector.text === undefined) return nodes;\n\n const want = selector.text.trim().toLowerCase();\n const labels = (n: FlatLayoutNode): string[] =>\n [n.text, n.desc, n.hint].filter((s): s is string => !!s).map((s) => s.trim().toLowerCase());\n const exact = nodes.filter((n) => labels(n).some((l) => l === want));\n if (exact.length > 0) return exact;\n return nodes.filter((n) => labels(n).some((l) => l.includes(want)));\n}\n\nfunction describeSelector(s: LayoutSelector): string {\n const parts: string[] = [];\n if (s.text !== undefined) parts.push(`text \"${s.text}\"`);\n if (s.id !== undefined) parts.push(`id \"${s.id}\"`);\n if (s.type !== undefined) parts.push(`type ${s.type}`);\n return parts.join(', ');\n}\n\n/** One-line summary of a node, used in errors and logs. */\nexport function describeLayoutNode(n: FlatLayoutNode): string {\n const label = n.text ?? n.desc ?? (n.hint !== undefined ? `hint: ${n.hint}` : undefined);\n const at = n.c ? ` at ${n.c[0].toFixed(3)},${n.c[1].toFixed(3)}` : '';\n return `${n.type ?? 'node'}${label !== undefined ? ` \"${label}\"` : ''}${n.id ? ` #${n.id}` : ''}${at}`;\n}\n\nconst area = (b: [number, number, number, number] | undefined): number => (b ? (b[2] - b[0]) * (b[3] - b[1]) : 0);\n\n/** `outer` is larger than `inner` and contains its center. */\nfunction enclosesTarget(outer: FlatLayoutNode, inner: FlatLayoutNode): boolean {\n const b = outer.b;\n const c = inner.c;\n if (!b || !c) return false;\n return c[0] >= b[0] && c[0] <= b[2] && c[1] >= b[1] && c[1] <= b[3] && area(b) > area(inner.b);\n}\n\n/** Why {@link pickTarget} could not choose a node. */\nexport type PickTargetFailure = 'none' | 'covered' | 'ambiguous';\n\nexport class TargetNotFoundError extends OniroError {\n constructor(\n message: string,\n readonly reason: PickTargetFailure,\n ) {\n super(message);\n this.name = 'TargetNotFoundError';\n }\n}\n\n/**\n * Choose the single node to act on for `selector`. Covered nodes are skipped;\n * clickable matches are preferred over plain ones (a \"Sign in\" Button over the\n * \"Sign in\" title); a match nested inside another clickable match collapses\n * into it. `index` picks among what remains, in paint order. Throws\n * {@link TargetNotFoundError} when nothing (or more than one node) qualifies.\n */\nexport function pickTarget(tree: LayoutNode, selector: LayoutSelector, index?: number): FlatLayoutNode {\n const matches = findLayoutNodes(tree, selector).filter((n) => n.c !== undefined);\n const what = describeSelector(selector);\n if (matches.length === 0) {\n throw new TargetNotFoundError(`No on-screen element matches ${what}. Run \\`oniro-app dump layout --flat\\` to see what is there.`, 'none');\n }\n const visible = matches.filter((n) => !n.covered);\n if (visible.length === 0) {\n throw new TargetNotFoundError(\n `Found ${matches.length} element(s) matching ${what}, but each is covered by an overlay ` +\n `(dialog, keyboard, or another layer): ${matches.map(describeLayoutNode).join('; ')}.`,\n 'covered',\n );\n }\n const clickable = visible.filter((n) => n.click);\n const preferred = clickable.length > 0 ? clickable : visible;\n // A label nested inside a clickable match (a Button's own Text) is the same target.\n const candidates = preferred.filter((n) => !preferred.some((o) => o !== n && o.click && enclosesTarget(o, n)));\n if (index !== undefined) {\n const picked = candidates[index];\n if (!picked) {\n throw new TargetNotFoundError(`Index ${index} is out of range: ${candidates.length} element(s) match ${what}.`, 'ambiguous');\n }\n return picked;\n }\n if (candidates.length > 1) {\n throw new TargetNotFoundError(\n `${candidates.length} elements match ${what}; pass an index to choose: ` +\n candidates.map((n, i) => `[${i}] ${describeLayoutNode(n)}`).join('; '),\n 'ambiguous',\n );\n }\n return candidates[0]!;\n}\n\nexport interface DumpLayoutOptions {\n config: ConfigProvider;\n /** Filter to a single window/bundle (`uitest dumpLayout -b '<bundle>'`). */\n bundleName?: string;\n /** When false, return the parsed-but-unpruned tree. Default true. */\n prune?: boolean;\n /**\n * Also report whether the soft keyboard is on screen (one extra `hidumper` call).\n * Ignored with `bundleName`, which filters the keyboard window out of the dump.\n */\n detectKeyboard?: boolean;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * Dump the current on-screen layout via `uitest dumpLayout`, pull the JSON, and\n * return a pruned, 0–1-normalized tree (or the raw parsed tree when `prune:false`).\n */\nexport async function dumpLayout(opts: DumpLayoutOptions): Promise<DumpLayoutResult> {\n const timeoutMs = opts.timeoutMs ?? 30_000;\n const bundleArg = opts.bundleName ? ` -b '${opts.bundleName.replace(/'/g, `'\\\\''`)}'` : '';\n const dump = await shell({ config: opts.config, command: `uitest dumpLayout${bundleArg}`, deviceSerial: opts.deviceSerial, timeoutMs });\n ensureOk(dump, 'uitest dumpLayout');\n\n const m = dump.stdout.match(/saved to:\\s*(\\S+)/i);\n if (!m) throw new OniroError(`Could not parse dumpLayout output:\\n${dump.stdout}`);\n const remote = m[1]!;\n const local = path.join(os.tmpdir(), `oniro_layout_${randomBytes(6).toString('hex')}.json`);\n\n try {\n await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });\n const parsed = JSON.parse(await fs.promises.readFile(local, 'utf8')) as RawLayoutNode;\n const display = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial });\n\n if (opts.prune === false) {\n return { display, tree: parsed as unknown as LayoutNode };\n }\n const prunedRaw = pruneLayout(parsed, display, findCoveredNodes(parsed));\n const tree: LayoutNode = Array.isArray(prunedRaw) ? { children: prunedRaw } : prunedRaw ?? { children: [] };\n if (!opts.detectKeyboard || opts.bundleName) return { display, tree };\n\n const imeBundles = await getImeBundles(opts.config, { deviceSerial: opts.deviceSerial, logger: opts.logger });\n const kb = findKeyboardWindow(tree, imeBundles);\n const keyboard: KeyboardState = kb ? { shown: true, bundle: kb.bundle, ...(kb.b ? { b: kb.b } : {}) } : { shown: false };\n return { display, tree, keyboard };\n } finally {\n fs.promises.unlink(local).catch(() => {});\n void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {});\n }\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { shell } from './exec.js';\nimport type { LayoutNode } from './dump.js';\n\n/** System ability id of the input method service, for `hidumper -s`. */\nconst INPUT_METHOD_SA_ID = 3703;\n\n// Used when hidumper can't list the installed input methods.\nconst IME_BUNDLE_FALLBACK = /inputmethod|keyboard|(^|\\.)ime(\\.|$)/i;\n\n/**\n * Extract input-method bundle names from `hidumper -s 3703 -a -a` output, whose\n * `imeList` entries look like `\"ime\": \"com.example.kikakeyboard/ServiceExtAbility\"`.\n * The current IME comes first. Pure.\n */\nexport function parseImeBundles(output: string): string[] {\n const current: string[] = [];\n const others: string[] = [];\n const entry = /\\{[^{}]*\"ime\"\\s*:\\s*\"([^\"/]+)\\/[^\"]*\"[^{}]*\\}/g;\n for (const m of output.matchAll(entry)) {\n const bundle = m[1]!;\n const list = /\"isCurrentIme\"\\s*:\\s*\"true\"/.test(m[0]) ? current : others;\n if (!current.includes(bundle) && !others.includes(bundle)) list.push(bundle);\n }\n return [...current, ...others];\n}\n\n/**\n * List the installed input-method bundles (current first). Empty when hidumper\n * fails or times out, so keyboard detection never fails the caller.\n */\nexport async function getImeBundles(\n config: ConfigProvider,\n opts: { deviceSerial?: string; logger?: Logger } = {},\n): Promise<string[]> {\n try {\n const res = await shell({\n config,\n command: `hidumper -s ${INPUT_METHOD_SA_ID} -a '-a'`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: 10_000,\n logger: opts.logger,\n });\n if (res.code === 0) return parseImeBundles(res.stdout);\n } catch (err) {\n opts.logger?.debug(`could not list input methods: ${err instanceof Error ? err.message : String(err)}`);\n }\n return [];\n}\n\n/**\n * Find the input-method window in a pruned layout tree. uitest lists the soft\n * keyboard as its own window (a node carrying the IME's `bundle`) only while it\n * is shown. With no known IME bundles, falls back to a name heuristic. Pure.\n */\nexport function findKeyboardWindow(tree: LayoutNode, imeBundles: readonly string[]): LayoutNode | null {\n const isIme = (bundle: string): boolean =>\n imeBundles.length > 0 ? imeBundles.includes(bundle) : IME_BUNDLE_FALLBACK.test(bundle);\n const stack: LayoutNode[] = [tree];\n while (stack.length > 0) {\n const n = stack.shift()!;\n if (n.bundle && isIme(n.bundle)) return n;\n stack.push(...(n.children ?? []));\n }\n return null;\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport {\n assertLayoutSelector,\n dumpLayout,\n findLayoutNodes,\n pickTarget,\n withoutWindow,\n TargetNotFoundError,\n type DumpLayoutResult,\n type FlatLayoutNode,\n type LayoutSelector,\n} from './dump.js';\nimport { getDisplaySize, type DisplaySize } from './display.js';\nimport { sendInput, type InputType } from './input.js';\nimport { waitForCondition } from './wait.js';\n\n/** `uitest uiInput` actions plus the composite ones built on top of them. */\nexport type UiInputType = InputType | 'clearText' | 'hideKeyboard';\n\n// Give a just-tapped field time to take focus (and the IME to attach) before typing.\nconst FOCUS_SETTLE_MS = 400;\n// Let the layout reflow after the soft keyboard closes.\nconst KEYBOARD_SETTLE_MS = 400;\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** The app's elements: the tree minus the soft-keyboard window, whose keys are not targets. */\nfunction targetTree(layout: DumpLayoutResult): DumpLayoutResult['tree'] {\n const kb = layout.keyboard;\n return kb?.shown && kb.bundle ? withoutWindow(layout.tree, kb.bundle) : layout.tree;\n}\n\n/** A 0–1 fraction of a display dimension as a pixel inside it (1.0 maps to the last pixel). */\nfunction fractionToPixel(f: number, size: number): number {\n return Math.min(size - 1, Math.round(f * size));\n}\n\ninterface DeviceOptions {\n config: ConfigProvider;\n deviceSerial?: string;\n logger?: Logger;\n}\n\nfunction pressBack(opts: DeviceOptions): Promise<void> {\n return sendInput({ config: opts.config, type: 'keyEvent', key: 'Back', deviceSerial: opts.deviceSerial, logger: opts.logger });\n}\n\n/**\n * Dismiss the soft keyboard with Back — only when it is actually on screen, since\n * Back without a keyboard navigates away. Returns whether a keyboard was dismissed.\n */\nexport async function hideKeyboard(opts: DeviceOptions): Promise<boolean> {\n const { keyboard } = await dumpLayout({ ...opts, detectKeyboard: true });\n if (!keyboard?.shown) return false;\n await pressBack(opts);\n await sleep(KEYBOARD_SETTLE_MS);\n return true;\n}\n\nexport interface LocateTargetOptions extends DeviceOptions {\n selector: LayoutSelector;\n /** Picks among several matching elements (see {@link pickTarget}). */\n index?: number;\n /**\n * When the soft keyboard is up and the target is missing, covered, or matches\n * only a non-clickable label (the button may be hidden below the keyboard),\n * dismiss the keyboard and look again. Default true.\n */\n hideKeyboard?: boolean;\n}\n\nexport interface LocatedTarget {\n node: FlatLayoutNode;\n /** Center of the element in device pixels. */\n x: number;\n y: number;\n display: DisplaySize;\n /** The soft keyboard was dismissed to reach the element. */\n keyboardHidden: boolean;\n}\n\n/**\n * Resolve a selector against the live layout to one element and its pixel\n * center. Keys on the soft keyboard are not candidates.\n */\nexport async function locateTarget(opts: LocateTargetOptions): Promise<LocatedTarget> {\n assertLayoutSelector(opts.selector);\n const dumpOpts = { config: opts.config, detectKeyboard: true, deviceSerial: opts.deviceSerial, logger: opts.logger };\n let layout = await dumpLayout(dumpOpts);\n // Without the display size no node has a position, and every match would look missing.\n if (!layout.display) throw new OniroError('Could not read the display size to locate the element.');\n let keyboardHidden = false;\n let node: FlatLayoutNode | undefined;\n let failure: unknown;\n try {\n node = pickTarget(targetTree(layout), opts.selector, opts.index);\n } catch (err) {\n if (!(err instanceof TargetNotFoundError) || err.reason === 'ambiguous') throw err;\n failure = err;\n }\n if ((!node || !node.click) && layout.keyboard?.shown && opts.hideKeyboard !== false) {\n opts.logger?.debug('target not reachable while the keyboard is up; dismissing it and looking again');\n await pressBack(opts);\n await sleep(KEYBOARD_SETTLE_MS);\n keyboardHidden = true;\n layout = await dumpLayout(dumpOpts);\n if (!layout.display) throw new OniroError('Could not read the display size to locate the element.');\n node = pickTarget(targetTree(layout), opts.selector, opts.index);\n }\n if (!node) throw failure;\n if (!node.c) throw new OniroError('The element has no on-screen position.');\n const x = fractionToPixel(node.c[0], layout.display.width);\n const y = fractionToPixel(node.c[1], layout.display.height);\n return { node, x, y, display: layout.display, keyboardHidden };\n}\n\nexport interface PerformInputOptions extends DeviceOptions {\n type: UiInputType;\n /** Start point in device pixels. */\n pxX?: number;\n pxY?: number;\n /** End point in device pixels (swipe/drag/fling). */\n pxX2?: number;\n pxY2?: number;\n /** Start point as 0–1 fractions of the display. */\n fx?: number;\n fy?: number;\n /** End point as 0–1 fractions of the display. */\n fx2?: number;\n fy2?: number;\n /** Start point: the center of the element matching this selector. */\n target?: LayoutSelector;\n /** Picks among several elements matching `target`. */\n targetIndex?: number;\n /** Velocity for swipe/drag/fling. */\n speed?: number;\n /** Key for keyEvent (see `resolveKeyEvent`). */\n key?: string | number;\n /** Text for inputText. */\n text?: string;\n /** inputText: clear the field before typing. */\n clear?: boolean;\n /** Dismiss the soft keyboard after the action, if it is up. */\n hideKeyboard?: boolean;\n}\n\nexport interface PerformInputResult {\n /** Resolved start point in device pixels, when the action has one. */\n x?: number;\n y?: number;\n /** The element `target` resolved to. */\n target?: FlatLayoutNode;\n /** The soft keyboard was dismissed (to reach the target, or because it was asked to). */\n keyboardHidden: boolean;\n}\n\nfunction fraction(value: number | undefined, name: string): number | undefined {\n if (value === undefined) return undefined;\n if (!(value >= 0 && value <= 1)) throw new OniroError(`${name} must be a fraction between 0 and 1; got ${value}.`);\n return value;\n}\n\nfunction pair<T>(a: T | undefined, b: T | undefined, names: string): [T, T] | undefined {\n if (a === undefined && b === undefined) return undefined;\n if (a === undefined || b === undefined) throw new OniroError(`Give both ${names}.`);\n return [a, b];\n}\n\n/**\n * Perform a UI input action. Beyond the raw `uitest uiInput` primitives, this\n * resolves the start point from an element selector (`target`), 0–1 display\n * fractions, or pixels; clears text fields (Ctrl+A, Delete); and dismisses the\n * soft keyboard only when it is up.\n */\nexport async function performInput(opts: PerformInputOptions): Promise<PerformInputResult> {\n const device: DeviceOptions = { config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger };\n const startFx = pair(fraction(opts.fx, '--fx'), fraction(opts.fy, '--fy'), '--fx and --fy');\n const startPx = pair(opts.pxX, opts.pxY, '--x and --y');\n const endFx = pair(fraction(opts.fx2, '--fx2'), fraction(opts.fy2, '--fy2'), '--fx2 and --fy2');\n const endPx = pair(opts.pxX2, opts.pxY2, '--x2 and --y2');\n if ([opts.target, startFx, startPx].filter((s) => s !== undefined).length > 1) {\n throw new OniroError('Give the start point one way: a target, fractions (--fx/--fy), or pixels (--x/--y).');\n }\n if (endFx && endPx) throw new OniroError('Give the end point one way: fractions (--fx2/--fy2) or pixels (--x2/--y2).');\n\n let display: DisplaySize | null | undefined;\n const toPx = async ([fx, fy]: [number, number]): Promise<[number, number]> => {\n display ??= await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial, logger: opts.logger });\n if (!display) throw new OniroError('Could not read the display size to convert fractions to pixels.');\n return [fractionToPixel(fx, display.width), fractionToPixel(fy, display.height)];\n };\n\n const result: PerformInputResult = { keyboardHidden: false };\n let start = startPx;\n if (opts.target) {\n const located = await locateTarget({ ...device, selector: opts.target, index: opts.targetIndex });\n display = located.display;\n start = [located.x, located.y];\n result.target = located.node;\n result.keyboardHidden = located.keyboardHidden;\n } else if (startFx) {\n start = await toPx(startFx);\n }\n const end = endFx ? await toPx(endFx) : endPx;\n if (start) [result.x, result.y] = start;\n\n const tapToFocus = async (): Promise<void> => {\n if (!start) return;\n await sendInput({ ...device, type: 'click', pxX: start[0], pxY: start[1] });\n await sleep(FOCUS_SETTLE_MS);\n };\n const clearFocused = async (): Promise<void> => {\n await sendInput({ ...device, type: 'keyEvent', key: 'Ctrl+A' });\n await sendInput({ ...device, type: 'keyEvent', key: 'Delete' });\n };\n\n switch (opts.type) {\n case 'hideKeyboard':\n result.keyboardHidden = (await hideKeyboard(device)) || result.keyboardHidden;\n return result;\n case 'clearText':\n await tapToFocus();\n await clearFocused();\n break;\n case 'inputText':\n if (opts.clear) {\n await tapToFocus();\n await clearFocused();\n await sendInput({ ...device, type: 'inputText', text: opts.text });\n } else {\n await sendInput({ ...device, type: 'inputText', pxX: start?.[0], pxY: start?.[1], text: opts.text });\n }\n break;\n default:\n await sendInput({\n ...device,\n type: opts.type,\n pxX: start?.[0],\n pxY: start?.[1],\n pxX2: end?.[0],\n pxY2: end?.[1],\n speed: opts.speed,\n key: opts.key,\n text: opts.text,\n });\n }\n\n if (opts.hideKeyboard) result.keyboardHidden = (await hideKeyboard(device)) || result.keyboardHidden;\n return result;\n}\n\nexport interface WaitForTargetOptions extends DeviceOptions {\n selector: LayoutSelector;\n /** Wait until no uncovered element matches, instead of until one does. */\n gone?: boolean;\n timeoutMs: number;\n /** Poll interval. Default 500 (each poll is a full layout dump). */\n pollMs?: number;\n abortSignal?: AbortSignal;\n}\n\n/**\n * Poll the layout until an uncovered element matches `selector` (resolving with\n * it), or with `gone`, until none does (resolving null). Keys on the soft\n * keyboard are ignored. Throws on timeout.\n */\nexport async function waitForTarget(opts: WaitForTargetOptions): Promise<FlatLayoutNode | null> {\n const { selector } = opts;\n assertLayoutSelector(selector);\n let found = null as FlatLayoutNode | null;\n await waitForCondition({\n probe: async () => {\n const layout = await dumpLayout({\n config: opts.config,\n detectKeyboard: true,\n deviceSerial: opts.deviceSerial,\n logger: opts.logger,\n });\n found = findLayoutNodes(targetTree(layout), selector).find((n) => !n.covered) ?? null;\n return opts.gone ? found === null : found !== null;\n },\n timeoutMs: opts.timeoutMs,\n pollMs: opts.pollMs ?? 500,\n abortSignal: opts.abortSignal,\n logger: opts.logger,\n timeoutMessage: opts.gone\n ? `An element matching the selector was still on screen after ${opts.timeoutMs}ms.`\n : `No element matching the selector appeared within ${opts.timeoutMs}ms.`,\n });\n return opts.gone ? null : found;\n}\n","import * as fs from 'node:fs';\nimport type { ChildProcess, ChildProcessWithoutNullStreams } from 'node:child_process';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { CancelledError, OniroError } from '../ports/errors.js';\nimport { getHdcPath } from '../sdk/paths.js';\nimport { killProcessTree, spawnCompat } from './spawnCompat.js';\nimport { ensureOk, hdcTargetArgs, shell } from './exec.js';\nimport { findRunningProcess } from './app.js';\n\nexport type HilogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'FATAL';\n\n/** A parsed line of `hdc shell hilog` output. */\nexport interface HilogEntry {\n /** \"MM-DD HH:MM:SS.mmm\". The device timestamp; no year. */\n time: string;\n pid: string;\n tid: string;\n /** Short level letter as printed by hilog: D, I, W, E (F is rare). */\n level: 'D' | 'I' | 'W' | 'E' | 'F';\n tag: string;\n message: string;\n}\n\nexport interface SetHilogLevelOptions {\n config: ConfigProvider;\n level: HilogLevel;\n deviceSerial?: string;\n logger?: Logger;\n}\n\n/**\n * Set the hilog buffer level on the connected device. Resolves when the\n * underlying `hdc shell hilog -b <LEVEL>` exits successfully; rejects with\n * the stderr text if the command fails.\n */\nexport function setHilogLevel(opts: SetHilogLevelOptions): Promise<void> {\n const logger = opts.logger ?? noopLogger;\n const hdc = getHdcPath(opts.config);\n return new Promise((resolve, reject) => {\n // `hdc` may be a batch wrapper on Windows (an `hdcPath` override pointing at\n // a proxy/tunnel script), which a bare spawn cannot execute — spawnCompat\n // routes those through cmd.exe. It can also throw synchronously, so the\n // failure is funnelled into the same rejection as the 'error' event below.\n let child: ChildProcess;\n try {\n child = spawnCompat(hdc, [...hdcTargetArgs(opts.deviceSerial), 'shell', 'hilog', '-b', opts.level]);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`[hilog] failed to spawn hdc: ${msg}`);\n reject(err instanceof Error ? err : new Error(msg));\n return;\n }\n let stderr = '';\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n child.once('error', (err) => {\n logger.error(`[hilog] failed to spawn hdc: ${err.message}`);\n reject(err);\n });\n child.once('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n const msg = stderr.trim() || `hdc shell hilog -b ${opts.level} exited with code ${code}`;\n logger.error(`[hilog] ${msg}`);\n reject(new Error(msg));\n }\n });\n });\n}\n\nexport interface StreamHilogOptions {\n config: ConfigProvider;\n /** Restrict the stream to a single process id (passed as `-P <pid>`). */\n processId?: string;\n /** Filter by hilog domain, e.g. '0xD003900' (passed as `-D <domain>`). */\n domain?: string | number;\n /** Address a specific device (`-t <serial>`); defaults to `ONIRO_DEVICE_SERIAL`. */\n deviceSerial?: string;\n}\n\n/**\n * Spawn `hdc [-t serial] shell hilog [-P <pid>] [-D <domain>]` and return the\n * child process. The caller owns the stdout/stderr streams (typically wired\n * through `parseHilogLine`) and is responsible for killing the process when\n * streaming should stop.\n */\nexport function streamHilog(opts: StreamHilogOptions): ChildProcessWithoutNullStreams {\n const hdc = getHdcPath(opts.config);\n const args: string[] = [...hdcTargetArgs(opts.deviceSerial)];\n args.push('shell', 'hilog');\n if (opts.processId && opts.processId.trim() !== '') {\n args.push('-P', opts.processId.trim());\n }\n if (opts.domain !== undefined && `${opts.domain}` !== '') {\n args.push('-D', `${opts.domain}`);\n }\n // Keeps the published non-null-stdio signature rather than pushing `?.` onto\n // every consumer. Sound because no stdio option is passed: both spawnCompat\n // branches inherit spawn's default `stdio: 'pipe'`, so the streams exist.\n return spawnCompat(hdc, args) as ChildProcessWithoutNullStreams;\n}\n\n// `\\S+` is greedy on the tag so values like `C01406/OHOS::RS` aren't split at\n// the first internal colon — the regex backtracks to the last `:` followed by\n// whitespace, which is the actual tag/message separator hilog emits.\nconst HILOG_LINE_RE = /^(\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3})\\s+(\\d+)\\s+(\\d+)\\s+([DIWEF])\\s+(\\S+):\\s+(.*)$/;\n\n/**\n * Parse a single line of `hdc shell hilog` output into structured fields.\n * Returns null when the line doesn't match the expected hilog format (e.g.\n * banners, blank lines, or partial chunks).\n */\nexport function parseHilogLine(line: string): HilogEntry | null {\n const match = HILOG_LINE_RE.exec(line);\n if (!match) return null;\n return {\n time: match[1]!,\n pid: match[2]!,\n tid: match[3]!,\n level: match[4]! as HilogEntry['level'],\n tag: match[5]!.trim(),\n message: match[6]!,\n };\n}\n\n/** The searchable text a pattern is tested against: `\"<tag>: <message>\"`. */\nfunction entryText(e: HilogEntry): string {\n return `${e.tag}: ${e.message}`;\n}\n\n/** Collapse consecutive duplicate entries (same level/tag/message), ignoring time/pid. */\nexport function dedupEntries(entries: HilogEntry[]): HilogEntry[] {\n const out: HilogEntry[] = [];\n let lastKey = '';\n for (const e of entries) {\n const key = `${e.level}|${e.tag}|${e.message}`;\n if (key === lastKey) continue;\n out.push(e);\n lastKey = key;\n }\n return out;\n}\n\n/** Resolve a bundle name to its pid for `-P` filtering, or undefined if not running. */\nasync function resolveProcessId(\n config: ConfigProvider,\n bundle: string | undefined,\n deviceSerial?: string,\n): Promise<string | undefined> {\n if (!bundle) return undefined;\n const proc = await findRunningProcess({ config, bundle, deviceSerial });\n return proc?.pid;\n}\n\nexport interface WaitForLogOptions {\n config: ConfigProvider;\n /** Tested against `\"<tag>: <message>\"` of each parsed line. */\n pattern: RegExp;\n timeoutMs: number;\n /** Restrict to a bundle's pid (resolved via pidof; re-resolved on each reconnect). */\n bundle?: string;\n domain?: string | number;\n deviceSerial?: string;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/**\n * Resolve with the first hilog entry whose `\"<tag>: <message>\"` matches `pattern`.\n * The underlying stream is auto-respawned if it dies before the deadline, so the\n * wait survives a reboot mid-observation. Rejects on timeout (OniroError) or\n * abort (CancelledError).\n */\nexport function waitForLog(opts: WaitForLogOptions): Promise<HilogEntry> {\n return new Promise<HilogEntry>((resolve, reject) => {\n const deadline = Date.now() + opts.timeoutMs;\n let settled = false;\n let child: ChildProcessWithoutNullStreams | null = null;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let buf = '';\n\n const cleanup = (): void => {\n clearTimeout(timer);\n if (reconnectTimer) clearTimeout(reconnectTimer);\n opts.abortSignal?.removeEventListener('abort', onAbort);\n if (child) {\n // A batch wrapper's own death would leave the hdc process it launched\n // streaming; tear down the whole tree.\n killProcessTree(child);\n child = null;\n }\n };\n const finish = (entry: HilogEntry): void => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(entry);\n };\n const fail = (err: Error): void => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(err);\n };\n const failWith = (err: unknown): void => fail(err instanceof Error ? err : new Error(String(err)));\n const onAbort = (): void => fail(new CancelledError('waitForLog cancelled.'));\n const timer = setTimeout(\n () => fail(new OniroError(`No log line matched ${String(opts.pattern)} within ${opts.timeoutMs}ms.`)),\n opts.timeoutMs,\n );\n opts.abortSignal?.addEventListener('abort', onAbort, { once: true });\n\n const spawnStream = async (): Promise<void> => {\n if (settled) return;\n const processId = await resolveProcessId(opts.config, opts.bundle, opts.deviceSerial);\n if (settled) return;\n const stream = streamHilog({ config: opts.config, processId, domain: opts.domain, deviceSerial: opts.deviceSerial });\n child = stream;\n stream.stdout.on('data', (d: Buffer) => {\n buf += d.toString();\n const lines = buf.split(/\\r?\\n/);\n buf = lines.pop() ?? '';\n for (const line of lines) {\n const entry = parseHilogLine(line);\n if (entry && opts.pattern.test(entryText(entry))) {\n finish(entry);\n return;\n }\n }\n });\n const onEnd = (): void => {\n if (settled || child !== stream) return;\n child = null;\n if (Date.now() < deadline) {\n // Auto-reconnect (survives a reboot) until the deadline.\n reconnectTimer = setTimeout(() => void spawnStream().catch(failWith), 1_000);\n }\n };\n stream.once('close', onEnd);\n stream.once('error', onEnd);\n };\n\n // spawnStream can reject (device lookup, or a synchronous spawn failure);\n // surface it as this promise's rejection instead of an unhandled one.\n void spawnStream().catch(failWith);\n });\n}\n\nexport interface WatchLogOptions {\n config: ConfigProvider;\n pattern: RegExp;\n /** How long to collect matching entries. */\n durationMs: number;\n bundle?: string;\n domain?: string | number;\n deviceSerial?: string;\n /** Collapse consecutive duplicate lines. Default true. */\n dedup?: boolean;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/** Collect all hilog entries matching `pattern` for `durationMs`. Deduped by default. */\nexport function watchLog(opts: WatchLogOptions): Promise<HilogEntry[]> {\n return new Promise<HilogEntry[]>((resolve, reject) => {\n const matches: HilogEntry[] = [];\n let settled = false;\n let child: ChildProcessWithoutNullStreams | null = null;\n let buf = '';\n\n const cleanup = (): void => {\n clearTimeout(timer);\n opts.abortSignal?.removeEventListener('abort', onAbort);\n if (child) {\n // A batch wrapper's own death would leave the hdc process it launched\n // streaming; tear down the whole tree.\n killProcessTree(child);\n child = null;\n }\n };\n const done = (): void => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(opts.dedup === false ? matches : dedupEntries(matches));\n };\n const onAbort = (): void => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(new CancelledError('watchLog cancelled.'));\n };\n const timer = setTimeout(done, opts.durationMs);\n opts.abortSignal?.addEventListener('abort', onAbort, { once: true });\n\n void (async () => {\n const processId = await resolveProcessId(opts.config, opts.bundle, opts.deviceSerial);\n if (settled) return;\n const stream = streamHilog({ config: opts.config, processId, domain: opts.domain, deviceSerial: opts.deviceSerial });\n child = stream;\n stream.stdout.on('data', (d: Buffer) => {\n buf += d.toString();\n const lines = buf.split(/\\r?\\n/);\n buf = lines.pop() ?? '';\n for (const line of lines) {\n const entry = parseHilogLine(line);\n if (entry && opts.pattern.test(entryText(entry))) matches.push(entry);\n }\n });\n // A device lookup or synchronous spawn failure used to surface as an\n // unhandled rejection while watchLog quietly resolved empty at the deadline.\n })().catch((err: unknown) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(err instanceof Error ? err : new Error(String(err)));\n });\n });\n}\n\nexport interface CaptureLogOptions {\n config: ConfigProvider;\n /** File the hilog lines are appended to. */\n file: string;\n /** Stop after this long. Default: run until `abortSignal` fires. */\n durationMs?: number;\n /** Keep only the lines this matches. Default: every line. */\n pattern?: RegExp;\n /** Clear the device's log buffer first (`hilog -r`), so the file covers only this session. */\n clear?: boolean;\n domain?: string | number;\n deviceSerial?: string;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\nexport interface CaptureLogResult {\n file: string;\n /** Lines written to `file`. */\n lines: number;\n /** How many times the stream dropped and was respawned. */\n reconnects: number;\n}\n\n/**\n * Stream hilog into `file` until `durationMs` passes or `abortSignal` fires. The\n * device's log buffer is small (256 KB per type by default) and chatty components\n * such as ArkWeb wrap it within seconds, so a dump taken at the end of a session\n * loses its start; a capture running throughout does not. Each chunk is written\n * synchronously, so killing the process keeps what was captured. The stream is\n * respawned when it drops (a reboot, a lost connection). Resolves at the deadline\n * or on abort.\n */\nexport async function captureLog(opts: CaptureLogOptions): Promise<CaptureLogResult> {\n const logger = opts.logger ?? noopLogger;\n if (opts.clear) {\n const res = await shell({ config: opts.config, command: 'hilog -r', deviceSerial: opts.deviceSerial, timeoutMs: 10_000, logger });\n ensureOk(res, 'hdc shell hilog -r');\n }\n const fd = fs.openSync(opts.file, 'a');\n let lines = 0;\n let reconnects = 0;\n\n try {\n await new Promise<void>((resolve, reject) => {\n const deadline = opts.durationMs !== undefined ? Date.now() + opts.durationMs : Infinity;\n let settled = false;\n let child: ChildProcessWithoutNullStreams | null = null;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let buf = '';\n // Cleared once the capture ends: the killed stream can still emit a chunk,\n // which must not reach the file descriptor closed below.\n let open = true;\n\n const write = (line: string): void => {\n if (!open || (opts.pattern && !opts.pattern.test(line))) return;\n fs.writeSync(fd, `${line}\\n`);\n lines++;\n };\n const cleanup = (): void => {\n if (timer) clearTimeout(timer);\n if (reconnectTimer) clearTimeout(reconnectTimer);\n opts.abortSignal?.removeEventListener('abort', finish);\n if (buf.trim()) write(buf.trimEnd());\n buf = '';\n open = false;\n if (child) {\n child.stdout.removeAllListeners('data');\n killProcessTree(child);\n child = null;\n }\n };\n function finish(): void {\n if (settled) return;\n settled = true;\n cleanup();\n resolve();\n }\n const fail = (err: unknown): void => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(err instanceof Error ? err : new Error(String(err)));\n };\n const timer = opts.durationMs !== undefined ? setTimeout(finish, opts.durationMs) : undefined;\n if (opts.abortSignal?.aborted) {\n finish();\n return;\n }\n opts.abortSignal?.addEventListener('abort', finish, { once: true });\n\n const spawnStream = (): void => {\n if (settled) return;\n const stream = streamHilog({ config: opts.config, domain: opts.domain, deviceSerial: opts.deviceSerial });\n child = stream;\n stream.stdout.on('data', (d: Buffer) => {\n buf += d.toString();\n const parts = buf.split(/\\r?\\n/);\n buf = parts.pop() ?? '';\n for (const line of parts) write(line);\n });\n const onEnd = (): void => {\n if (settled || child !== stream) return;\n child = null;\n if (Date.now() >= deadline) return;\n reconnects++;\n logger.warn(`[hilog] stream ended; reconnecting (${reconnects}).`);\n reconnectTimer = setTimeout(() => {\n try {\n spawnStream();\n } catch (err) {\n fail(err);\n }\n }, 2_000);\n };\n stream.once('close', onEnd);\n stream.once('error', onEnd);\n };\n spawnStream();\n });\n } finally {\n fs.closeSync(fd);\n }\n return { file: opts.file, lines, reconnects };\n}\n\nexport interface DumpLogOptions {\n config: ConfigProvider;\n /** Cap the result to the last N lines (device-side `tail -n`). */\n lines?: number;\n /** Restrict to a bundle's running pid (no output if it isn't running). */\n bundle?: string;\n /** Extended-regex string applied device-side via `grep -E`. */\n grep?: string;\n domain?: string | number;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * One-shot `hilog -x` dump, optionally filtered by domain, bundle pid, and a\n * grep regex, capped to the last `lines`. Mirrors the proven MCP get_logs\n * pipeline. Returns parsed entries.\n */\nexport async function dumpLog(opts: DumpLogOptions): Promise<HilogEntry[]> {\n let pipe = 'hilog -x';\n if (opts.domain !== undefined && `${opts.domain}` !== '') pipe += ` -D ${opts.domain}`;\n if (opts.bundle) {\n const proc = await findRunningProcess({ config: opts.config, bundle: opts.bundle, deviceSerial: opts.deviceSerial });\n if (!proc) return [];\n pipe += ` | grep -E '\\\\b${proc.pid}\\\\b'`;\n }\n if (opts.grep) {\n const safeGrep = opts.grep.replace(/'/g, `'\\\\''`);\n pipe += ` | grep -E '${safeGrep}'`;\n }\n if (opts.lines && opts.lines > 0) pipe += ` | tail -n ${Math.floor(opts.lines)}`;\n\n const res = await shell({\n config: opts.config,\n command: pipe,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 30_000,\n logger: opts.logger,\n });\n return res.stdout\n .split(/\\r?\\n/)\n .map((line) => parseHilogLine(line))\n .filter((e): e is HilogEntry => e !== null);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ChildProcess } from 'node:child_process';\nimport { killProcessTree, spawnCompat } from '../hdc/spawnCompat.js';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { CancelledError, CmdToolsNotInstalledError, OniroError } from '../ports/errors.js';\nimport { getHvigorwPath, getOhosBaseSdkHome, getCmdToolsPath, toLongPath } from '../sdk/paths.js';\nimport { detectRuntimeOs } from '../harmonyos/target.js';\nimport { findHarmonyOsTool, requireHarmonyOsSdk } from '../harmonyos/sdk.js';\n\nexport interface RunHvigorwOptions {\n config: ConfigProvider;\n projectDir: string;\n /** Forwarded as `-p product=<product>`. Default `default`. */\n product?: string;\n /** Forwarded as `-p module=<module>` when set. */\n module?: string;\n /** Forwarded as `-p buildMode=<mode>` when set. */\n buildMode?: string;\n /** hvigor task to run. Default `assembleHap`. */\n task?: string;\n /** Extra raw args appended after the standard ones. */\n extraArgs?: readonly string[];\n /**\n * Build modules in parallel. Default `true`. Pass `false` to add `--no-parallel`\n * for projects that require serial builds.\n */\n parallel?: boolean;\n /** Abort the build; rejects with CancelledError and kills the hvigorw process. */\n abortSignal?: AbortSignal;\n logger?: Logger;\n /**\n * Optional callback for each stdout/stderr chunk, lets callers stream output\n * to a terminal or webview without buffering. Lines also flow through `logger`.\n */\n onOutput?: (chunk: string, stream: 'stdout' | 'stderr') => void;\n}\n\nexport interface RunHvigorwResult {\n exitCode: number;\n}\n\n/**\n * Build the hvigorw argv. Pure (no I/O) so it is unit-testable. `--no-parallel`\n * is added ONLY when `parallel === false` — builds are parallel by default.\n */\nexport function buildHvigorwArgs(opts: {\n task?: string;\n product?: string;\n module?: string;\n buildMode?: string;\n parallel?: boolean;\n extraArgs?: readonly string[];\n}): string[] {\n const args: string[] = [opts.task ?? 'assembleHap', '--mode', 'module'];\n args.push('-p', `product=${opts.product ?? 'default'}`);\n if (opts.module) args.push('-p', `module=${opts.module}`);\n if (opts.buildMode) args.push('-p', `buildMode=${opts.buildMode}`);\n args.push('--stacktrace', '--no-daemon');\n if (opts.parallel === false) args.push('--no-parallel');\n if (opts.extraArgs?.length) args.push(...opts.extraArgs);\n return args;\n}\n\n/**\n * Run the project's `hvigorw` wrapper. Replaces the extension's vscode-tasks indirection\n * and the bash CLI's chained `clean` + `assembleHap` calls with a single direct spawn.\n */\nexport function runHvigorw(opts: RunHvigorwOptions): Promise<RunHvigorwResult> {\n const { config } = opts;\n // hvigor resolves each module's `srcPath` against the project dir it is given\n // and fails on a Windows 8.3 short path, so hand it the long form.\n const projectDir = toLongPath(opts.projectDir);\n const logger = opts.logger ?? noopLogger;\n\n if (!fs.existsSync(path.join(projectDir, 'build-profile.json5'))) {\n throw new OniroError(`Not an OpenHarmony project: ${projectDir} (build-profile.json5 not found).`);\n }\n\n let hvigorw: string;\n let sdkEnv: NodeJS.ProcessEnv;\n if (detectRuntimeOs(projectDir, opts.product) === 'HarmonyOS') {\n // Nothing comes from the OpenHarmony command-line tools: the SDK is passed as\n // DEVECO_SDK_HOME, and hvigorw is the project's own or the HarmonyOS install's.\n const sdk = requireHarmonyOsSdk({ config, logger });\n sdkEnv = { DEVECO_SDK_HOME: sdk.sdkPath };\n const resolved = getHvigorwPath(config, projectDir);\n hvigorw = resolved.startsWith(projectDir) ? resolved : (findHarmonyOsTool(sdk, 'hvigorw') ?? resolved);\n logger.info(`[build] Building for HarmonyOS against the SDK at ${sdk.sdkPath}.`);\n } else {\n if (!fs.existsSync(getCmdToolsPath(config))) {\n throw new CmdToolsNotInstalledError(getCmdToolsPath(config));\n }\n sdkEnv = { OHOS_BASE_SDK_HOME: getOhosBaseSdkHome(config) };\n hvigorw = getHvigorwPath(config, projectDir);\n }\n\n if (!fs.existsSync(hvigorw)) {\n throw new OniroError(`hvigorw wrapper not found at ${hvigorw}.`);\n }\n const args = buildHvigorwArgs(opts);\n\n // Ensure hvigorw is executable on POSIX (project-local copies often aren't after a fresh clone).\n if (process.platform !== 'win32') {\n try { fs.chmodSync(hvigorw, 0o755); } catch { /* best effort */ }\n }\n\n const env: NodeJS.ProcessEnv = { ...process.env, ...sdkEnv };\n\n return new Promise((resolve, reject) => {\n if (opts.abortSignal?.aborted) {\n reject(new CancelledError('hvigorw build cancelled.'));\n return;\n }\n logger.info(`[build] ${hvigorw} ${args.join(' ')}`);\n // On Windows hvigorw is a .bat wrapper, which spawnCompat routes through\n // cmd.exe — a direct spawn there throws `EINVAL` on Node 20.12.2+.\n let child: ChildProcess;\n try {\n child = spawnCompat(hvigorw, args, { cwd: projectDir, env });\n } catch (err) {\n // spawn() can fail synchronously; report it like the 'error' event below\n // instead of letting a bare OS error escape to the CLI.\n reject(new OniroError(`Failed to start hvigorw: ${err instanceof Error ? err.message : String(err)}`, err));\n return;\n }\n let settled = false;\n const cleanup = (): void => opts.abortSignal?.removeEventListener('abort', onAbort);\n const onAbort = (): void => {\n if (settled) return;\n settled = true;\n cleanup();\n killProcessTree(child);\n reject(new CancelledError('hvigorw build cancelled.'));\n };\n opts.abortSignal?.addEventListener('abort', onAbort, { once: true });\n child.stdout?.on('data', (chunk: Buffer) => {\n const text = chunk.toString();\n opts.onOutput?.(text, 'stdout');\n logger.info(text.trimEnd());\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n const text = chunk.toString();\n opts.onOutput?.(text, 'stderr');\n logger.warn(text.trimEnd());\n });\n child.on('error', (err) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(new OniroError(`Failed to start hvigorw: ${err.message}`, err));\n });\n child.on('close', (code) => {\n if (settled) return;\n settled = true;\n cleanup();\n const exitCode = code ?? 1;\n if (exitCode === 0) resolve({ exitCode });\n else reject(new OniroError(`hvigorw exited with code ${exitCode}`));\n });\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport JSON5 from 'json5';\n\n/**\n * Which runtime a project targets. OpenHarmony projects build against the public\n * OpenHarmony SDK; HarmonyOS projects build against Huawei's HarmonyOS SDK and\n * need an AGC-issued certificate to sign (see `harmonyos/signing`).\n */\nexport type RuntimeOs = 'OpenHarmony' | 'HarmonyOS';\n\n/**\n * Detect the runtime a project targets from `build-profile.json5`.\n *\n * HarmonyOS only when the product declares `runtimeOS: \"HarmonyOS\"`, which DevEco\n * Studio writes for every HarmonyOS project. Anything else — no such field, or a\n * missing or unreadable profile — is OpenHarmony, so existing projects behave\n * exactly as they did before HarmonyOS support. Reads the named product, else the\n * first one.\n */\nexport function detectRuntimeOs(projectDir: string, productName?: string): RuntimeOs {\n let products: Array<{ name?: unknown; runtimeOS?: unknown }> = [];\n try {\n const parsed = JSON5.parse(fs.readFileSync(path.join(projectDir, 'build-profile.json5'), 'utf-8')) as {\n app?: { products?: unknown };\n };\n if (Array.isArray(parsed.app?.products)) products = parsed.app.products;\n } catch {\n return 'OpenHarmony';\n }\n const product = products.find((p) => p.name === productName) ?? products[0];\n return product?.runtimeOS === 'HarmonyOS' ? 'HarmonyOS' : 'OpenHarmony';\n}\n\n/**\n * HarmonyOS SDK releases, mapping API level to the release version DevEco writes\n * into `compileSdkVersion`, for when the installed SDK does not name the requested\n * level itself. Only releases read from a real `sdk/default/sdk-pkg.json` are listed.\n */\nexport const HARMONYOS_SDK_VERSIONS: ReadonlyMap<number, string> = new Map([\n [12, '5.0.0'],\n [13, '5.0.1'],\n [14, '5.0.2'],\n [15, '5.0.3'],\n [16, '5.0.4'],\n [17, '5.0.5'],\n [18, '5.1.0'],\n [19, '5.1.1'],\n [20, '6.0.0'],\n [21, '6.0.1'],\n [24, '6.1.1'],\n]);\n\n/**\n * The `\"<version>(<api>)\"` label a HarmonyOS product declares for an API level, or\n * undefined when no HarmonyOS release is known for it.\n */\nexport function harmonyOsSdkLabelForApi(api: number): string | undefined {\n const version = HARMONYOS_SDK_VERSIONS.get(api);\n return version ? `${version}(${api})` : undefined;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { runProcess, ensureOk, type HdcExecResult, type OutputSink } from '../hdc/exec.js';\nimport { getOhpmPath } from '../sdk/paths.js';\n\nexport interface RunOhpmOptions {\n config: ConfigProvider;\n projectDir: string;\n args: readonly string[];\n /**\n * Explicit ohpm binary. HarmonyOS projects pass the one from their own install;\n * when omitted the OpenHarmony command-line tools' ohpm is used.\n */\n ohpmPath?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n onOutput?: OutputSink;\n logger?: Logger;\n}\n\n/** Run `ohpm <args>` in the project directory. Resolves with the raw result (any exit code). */\nexport function runOhpm(opts: RunOhpmOptions): Promise<HdcExecResult> {\n return runProcess({\n command: opts.ohpmPath ?? getOhpmPath(opts.config),\n args: [...opts.args],\n cwd: opts.projectDir,\n timeoutMs: opts.timeoutMs ?? 600_000,\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n logger: opts.logger,\n });\n}\n\n/**\n * Install dependencies (`ohpm install --all`) only when `oh_modules/` is missing.\n * Returns `{ installed: true }` when it ran. Throws CommandFailedError if the\n * install ran and failed.\n */\nexport async function ensureOhModules(opts: {\n config: ConfigProvider;\n projectDir: string;\n /** See {@link RunOhpmOptions.ohpmPath}. */\n ohpmPath?: string;\n abortSignal?: AbortSignal;\n onOutput?: OutputSink;\n logger?: Logger;\n}): Promise<{ installed: boolean }> {\n if (fs.existsSync(path.join(opts.projectDir, 'oh_modules'))) {\n return { installed: false };\n }\n const res = await runOhpm({\n config: opts.config,\n projectDir: opts.projectDir,\n ohpmPath: opts.ohpmPath,\n args: ['install', '--all'],\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n logger: opts.logger,\n });\n ensureOk(res, 'ohpm install --all');\n return { installed: true };\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { runProcess } from '../hdc/exec.js';\nimport { getCmdToolsBin } from '../sdk/paths.js';\n\nexport interface CodelinterFinding {\n file: string;\n line: number;\n /** Column, when the report gives one. */\n column?: number;\n /** `error`, `warning`, `suggestion` or `info` (codelinter's `warn` reads as `warning`). */\n severity: string;\n /** Rule code/id when present in the output, else ''. */\n code: string;\n message: string;\n}\n\n/** codelinter's own totals, from its `-Defects: N; Errors: N; Warns: N; Suggestions: N;` line. */\nexport interface CodelinterSummary {\n defects: number;\n errors: number;\n warnings: number;\n suggestions: number;\n}\n\nexport interface CodelinterReport {\n findings: CodelinterFinding[];\n /** The totals codelinter printed (all zero for \"No defects found\"), or null when it printed none. */\n summary: CodelinterSummary | null;\n /**\n * codelinter's remarks about the run itself rather than the code, e.g. \"The type of\n * command line tools does not match that of the project\".\n */\n notices: string[];\n /** True when codelinter warned that the report may be incomplete. */\n incomplete: boolean;\n}\n\nexport interface CodelinterResult extends CodelinterReport {\n /** codelinter process exit code: 1 whenever it found any defect, warnings included. */\n code: number;\n /** Combined stdout+stderr, with colour codes and progress-bar redraws removed. */\n raw: string;\n}\n\n/** Legacy one-line shape: `<file>:<line>[:<col>]: <severity>: <message> [<rule>]`. */\nconst FINDING_RE = /^(.*?):(\\d+):(?:(\\d+):)?\\s*(error|warning|warn|suggestion|info)\\b[:\\s-]*(.*)$/i;\nconst TRAILING_CODE_RE = /[([]([\\w@/.\\-]+)[)\\]]\\s*$/;\n/** Table shape: a `<file>(<count>)` header, then `<line>:<col> <severity> <message> <rule>` rows. */\nconst FILE_HEADER_RE = /^(.+\\.\\w+)\\((\\d+)\\)$/;\nconst ROW_RE = /^(\\d+):(\\d+)\\s+(error|warning|warn|suggestion|info)\\s+(.*)$/i;\nconst RULE_RE = /^@?[\\w.-]+(?:\\/[\\w.-]+)+$/;\nconst SUMMARY_RE = /Defects:\\s*(\\d+);\\s*Errors:\\s*(\\d+);\\s*Warns:\\s*(\\d+);\\s*Suggestions:\\s*(\\d+)/i;\nconst NOTICE_RE = /does not match that of the project|error occurred during linting|incomplete report/i;\nconst ANSI_RE = /\\x1b\\[[0-9;]*[A-Za-z]/g;\n\n/**\n * codelinter output as plain lines: colour codes stripped, and of each line redrawn\n * with `\\r` (its progress bar) only the final state kept.\n */\nexport function cleanCodelinterOutput(output: string): string {\n return output\n .replace(ANSI_RE, '')\n .split('\\n')\n .map((line) => (line.split('\\r').filter((s) => s.trim() !== '').pop() ?? '').trimEnd())\n .join('\\n');\n}\n\nfunction normaliseSeverity(s: string): string {\n const lower = s.toLowerCase();\n return lower === 'warn' ? 'warning' : lower;\n}\n\n/**\n * Parse a codelinter report. Pure/testable. Understands the table codelinter prints\n * (a `<file>(<count>)` header followed by `<line>:<col> <severity> <message> <rule>`\n * rows, then a `-Defects: …` summary) and the one-line\n * `<file>:<line>[:<col>]: <severity>: <message> [<rule>]` shape. Other lines are ignored.\n */\nexport function parseCodelinterReport(output: string): CodelinterReport {\n const findings: CodelinterFinding[] = [];\n const notices: string[] = [];\n let summary: CodelinterSummary | null = null;\n let file = '';\n\n for (const rawLine of cleanCodelinterOutput(output).split('\\n')) {\n const line = rawLine.trim();\n if (!line) continue;\n\n const row = ROW_RE.exec(line);\n if (row) {\n // A row before any file header has nothing to attach to.\n if (!file) continue;\n const columns = row[4]!.trim().split(/\\s{2,}/);\n const last = columns[columns.length - 1]!;\n const code = columns.length > 1 && RULE_RE.test(last) ? last : '';\n const message = (code ? columns.slice(0, -1) : columns).join(' ').trim();\n findings.push({\n file,\n line: Number(row[1]),\n column: Number(row[2]),\n severity: normaliseSeverity(row[3]!),\n code,\n message,\n });\n continue;\n }\n const header = FILE_HEADER_RE.exec(line);\n if (header) {\n file = header[1]!;\n continue;\n }\n const legacy = FINDING_RE.exec(line);\n if (legacy) {\n let message = legacy[5]!.trim();\n let code = '';\n const codeMatch = TRAILING_CODE_RE.exec(message);\n if (codeMatch) {\n code = codeMatch[1]!;\n message = message.slice(0, codeMatch.index).trim();\n }\n const finding: CodelinterFinding = {\n file: legacy[1]!.trim(),\n line: Number(legacy[2]),\n severity: normaliseSeverity(legacy[4]!),\n code,\n message,\n };\n if (legacy[3]) finding.column = Number(legacy[3]);\n findings.push(finding);\n continue;\n }\n const totals = SUMMARY_RE.exec(line);\n if (totals) {\n summary = {\n defects: Number(totals[1]),\n errors: Number(totals[2]),\n warnings: Number(totals[3]),\n suggestions: Number(totals[4]),\n };\n continue;\n }\n if (/no defects found/i.test(line)) {\n summary = { defects: 0, errors: 0, warnings: 0, suggestions: 0 };\n continue;\n }\n if (NOTICE_RE.test(line)) notices.push(line);\n }\n\n return { findings, summary, notices, incomplete: notices.length > 0 };\n}\n\n/** The findings of a codelinter report; see {@link parseCodelinterReport}. */\nexport function parseCodelinterFindings(output: string): CodelinterFinding[] {\n return parseCodelinterReport(output).findings;\n}\n\nexport interface RunCodelinterOptions {\n config: ConfigProvider;\n projectDir: string;\n /** Files/globs to lint; when omitted, codelinter is run with no file args. */\n files?: readonly string[];\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/** Run the OpenHarmony codelinter and return the parsed report + the cleaned raw output. */\nexport async function runCodelinter(opts: RunCodelinterOptions): Promise<CodelinterResult> {\n const res = await runProcess({\n command: getCmdToolsBin(opts.config, 'codelinter'),\n args: opts.files?.length ? [...opts.files] : [],\n cwd: opts.projectDir,\n timeoutMs: opts.timeoutMs ?? 600_000,\n abortSignal: opts.abortSignal,\n logger: opts.logger,\n });\n const raw = `${res.stdout}${res.stderr}`;\n return { code: res.code, ...parseCodelinterReport(raw), raw: cleanCodelinterOutput(raw) };\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger, scopedLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { runHvigorw } from './runHvigorw.js';\nimport { ensureOhModules } from './ohpm.js';\nimport { discoverHaps, type ModuleHaps } from './discoverHaps.js';\nimport { toLongPath } from '../sdk/paths.js';\nimport { findMissingProjectSdk } from '../sdk/detectProjectSdk.js';\nimport { detectRuntimeOs } from '../harmonyos/target.js';\nimport { findHarmonyOsSdk, findHarmonyOsTool } from '../harmonyos/sdk.js';\n\n/** How much of the build output is kept for {@link diagnoseBuildFailure}, from the end. */\nconst DIAGNOSIS_OUTPUT_LIMIT = 2_000_000;\n\n/**\n * A hint for build output whose cause the compiler errors do not name, or\n * undefined. Pure/testable.\n */\nexport function diagnoseBuildFailure(output: string): string | undefined {\n if (/is not exported from Kit|has no exported member .*@systemapi/i.test(output)) {\n return (\n 'The project calls system APIs (`@systemapi`), which the public SDK leaves out. Build against the ' +\n 'full OpenHarmony SDK: unpack its components into <root>/<os>/<api> of a separate SDK root and set ' +\n 'ONIRO_SDK_ROOT_DIR to that root. Installing such an app also needs privileged signing ' +\n '(`oniro-app sign --apl system_core --acls … --app-privilege-capabilities …`).'\n );\n }\n if (/00308018|SDK path does not exist|SDK license agreement is not accepted/i.test(output)) {\n return 'hvigor cannot find the SDK the project compiles against: check `oniro-app sdk list` against compileSdkVersion.';\n }\n return undefined;\n}\n\nexport interface BuildHapOptions {\n config: ConfigProvider;\n projectDir: string;\n product?: string;\n module?: string;\n /** Forwarded as hvigor `buildMode` (e.g. release, debug). */\n mode?: string;\n /** hvigor task. Default `assembleHap`. */\n task?: string;\n /** Run `ohpm install --all` first when `oh_modules/` is missing. Default true. */\n autoInstallDeps?: boolean;\n /** Build modules in parallel. Default true (see runHvigorw). */\n parallel?: boolean;\n abortSignal?: AbortSignal;\n onOutput?: (chunk: string, stream: 'stdout' | 'stderr') => void;\n logger?: Logger;\n}\n\nexport interface BuildHapResult {\n exitCode: number;\n durationMs: number;\n /** Built HAPs grouped by module folder. */\n discoveredHaps: Record<string, ModuleHaps>;\n warnings: string[];\n}\n\n/**\n * High-level build orchestration: ensure deps → run hvigorw → discover the\n * produced HAPs. The single call the CLI and MCP want; `runHvigorw` stays a raw\n * single-spawn primitive.\n */\nexport async function buildHap(opts: BuildHapOptions): Promise<BuildHapResult> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'build');\n const warnings: string[] = [];\n const start = Date.now();\n // Normalise once so ohpm, hvigor and HAP discovery all agree on the project\n // dir, and the returned artifact paths come back in long form.\n const projectDir = toLongPath(opts.projectDir);\n const isHarmonyOs = detectRuntimeOs(projectDir, opts.product) === 'HarmonyOS';\n\n // Fail before ohpm and hvigor run, with the release to install, rather than on\n // hvigor's own late and vaguer error.\n const missingSdk = isHarmonyOs ? null : findMissingProjectSdk(opts.config, projectDir);\n if (missingSdk) throw missingSdk;\n\n if (opts.autoInstallDeps !== false) {\n // HarmonyOS projects install dependencies with their own install's ohpm.\n const harmonySdk = isHarmonyOs ? findHarmonyOsSdk({ config: opts.config, logger: opts.logger }) : null;\n const r = await ensureOhModules({\n config: opts.config,\n projectDir,\n ohpmPath: (harmonySdk && findHarmonyOsTool(harmonySdk, 'ohpm')) ?? undefined,\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n logger: opts.logger,\n });\n if (r.installed) logger.info('ran ohpm install --all (oh_modules was missing)');\n }\n\n let output = '';\n let exitCode: number;\n try {\n ({ exitCode } = await runHvigorw({\n config: opts.config,\n projectDir,\n product: opts.product,\n module: opts.module,\n buildMode: opts.mode,\n task: opts.task,\n parallel: opts.parallel,\n abortSignal: opts.abortSignal,\n onOutput: (chunk, stream) => {\n output = (output + chunk).slice(-DIAGNOSIS_OUTPUT_LIMIT);\n opts.onOutput?.(chunk, stream);\n },\n logger: opts.logger,\n }));\n } catch (err) {\n const hint = diagnoseBuildFailure(output);\n if (hint && err instanceof OniroError) throw new OniroError(`${err.message}\\n${hint}`, err);\n throw err;\n }\n\n const discoveredHaps = await discoverHaps({ projectDir });\n const anySigned = Object.values(discoveredHaps).some((m) => m.signed.length > 0);\n if (!anySigned) {\n warnings.push(\n isHarmonyOs\n ? 'No signed HAPs found. The HarmonyOS emulator installs the unsigned HAP as it is; for a device, ' +\n 'run `oniro-app sign --harmonyos` to have AppGallery Connect issue a certificate and profile.'\n : 'No signed HAPs found: most OpenHarmony targets reject unsigned HAPs. Run `oniro-app sign` ' +\n 'to generate local signing material, then build again.',\n );\n }\n\n return { exitCode, durationMs: Date.now() - start, discoveredHaps, warnings };\n}\n","/**\n * Conservative project-folder-name validator (no path separators, conservative charset).\n */\nexport function isValidProjectName(name: string): boolean {\n if (!name) return false;\n if (name.includes('/') || name.includes('\\\\')) return false;\n return /^[A-Za-z0-9._-]+$/.test(name);\n}\n\n/**\n * Bundle-name validator. Allows reverse-DNS style identifiers like `com.example.myapp`.\n */\nexport function isValidBundleName(bundleName: string): boolean {\n return /^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z][A-Za-z0-9_]*)+$/.test(bundleName);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nexport interface TemplateOption {\n id: string;\n label: string;\n description: string;\n defaultModuleName: string;\n}\n\ninterface TemplateMeta {\n id?: string;\n label?: string;\n description?: string;\n defaultModuleName?: string;\n}\n\nfunction toHumanTemplateName(folderName: string): string {\n return folderName.replace(/([a-z])([A-Z])/g, '$1 $2');\n}\n\n/**\n * Enumerate templates inside `templateRoot`. Each direct subfolder is a template;\n * per-template metadata (label/description/defaultModuleName) may live in a\n * `template.json` file alongside the template content.\n *\n * Callers own the template root — the CLI ships its own under\n * `<cli-package>/templates/`, the VS Code extension uses `extensionPath/template`.\n */\nexport function listTemplates(templateRoot: string): TemplateOption[] {\n if (!fs.existsSync(templateRoot)) return [];\n const entries = fs.readdirSync(templateRoot, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory())\n .map((e) => {\n const dir = path.join(templateRoot, e.name);\n const metaPath = path.join(dir, 'template.json');\n let meta: TemplateMeta = {};\n if (fs.existsSync(metaPath)) {\n try {\n meta = JSON.parse(fs.readFileSync(metaPath, 'utf8')) as TemplateMeta;\n } catch {\n // Ignore malformed template metadata.\n }\n }\n return {\n id: e.name,\n label: meta.label ?? toHumanTemplateName(e.name),\n description: meta.description ?? '',\n defaultModuleName: (meta.defaultModuleName ?? 'entry').trim() || 'entry',\n };\n })\n .sort((a, b) => a.label.localeCompare(b.label));\n}\n\n/**\n * Verify that a template directory contains the files required by the scaffold pipeline.\n * Returns the list of missing relative paths, or [] if the template is complete.\n */\nexport function validateTemplateLayout(templateDir: string, defaultModuleName: string): string[] {\n const required = [\n 'build-profile.json5',\n path.join('AppScope', 'app.json5'),\n path.join(defaultModuleName, 'src', 'main', 'module.json5'),\n path.join(defaultModuleName, 'oh-package.json5'),\n 'hvigorfile.ts',\n ];\n return required.filter((rel) => !fs.existsSync(path.join(templateDir, rel)));\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { getOhosBaseSdkHome } from '../sdk/paths.js';\nimport { HARMONYOS_SDK_VERSIONS, detectRuntimeOs, harmonyOsSdkLabelForApi } from '../harmonyos/target.js';\nimport { findHarmonyOsSdk } from '../harmonyos/sdk.js';\nimport { listTemplates, validateTemplateLayout } from './templates.js';\nimport { isValidBundleName, isValidProjectName } from './validators.js';\nimport { readJson5File, readJsonFile, writeJson5File, writeJsonFile } from './jsonHelpers.js';\n\nconst IGNORED_DIRS = new Set(['oh_modules', 'node_modules', 'build', '.hvigor']);\n\nexport interface CreateScaffoldOptions {\n config: ConfigProvider;\n templateId: string;\n projectName: string;\n bundleName: string;\n /** Parent directory that will contain the new project folder. */\n location: string;\n sdkApi: number;\n /** Module folder name. Defaults to the template's `defaultModuleName`. */\n moduleName?: string;\n /** Absolute path to the directory containing template subfolders. */\n templateRoot: string;\n /** If the destination exists, remove it before scaffolding instead of throwing. */\n overwrite?: boolean;\n logger?: Logger;\n}\n\nexport interface CreateScaffoldResult {\n projectDir: string;\n}\n\n/**\n * Async existence check.\n */\nasync function pathExists(p: string): Promise<boolean> {\n try {\n await fs.promises.access(p);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Recursively copy a template directory, skipping symlinks and template metadata.\n */\nasync function copyDirRecursive(srcDir: string, destDir: string): Promise<void> {\n await fs.promises.mkdir(destDir, { recursive: true });\n const entries = await fs.promises.readdir(srcDir, { withFileTypes: true });\n for (const entry of entries) {\n const src = path.join(srcDir, entry.name);\n const dest = path.join(destDir, entry.name);\n if (entry.isDirectory()) {\n await copyDirRecursive(src, dest);\n } else if (entry.isSymbolicLink()) {\n continue;\n } else if (entry.isFile()) {\n if (entry.name === 'template.json') continue;\n await fs.promises.copyFile(src, dest);\n }\n }\n}\n\n/**\n * Normalize every .json5 file in `projectDir` to strict JSON formatting (quoted keys).\n * Keeps JSON5 parsers happy while letting VS Code's built-in JSON parser handle them.\n */\nasync function normalizeJson5ToJson(projectDir: string, logger: Logger): Promise<void> {\n const stack: string[] = [projectDir];\n while (stack.length > 0) {\n const currentDir = stack.pop()!;\n const entries = await fs.promises.readdir(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name)) continue;\n stack.push(fullPath);\n continue;\n }\n if (!entry.isFile() || !entry.name.endsWith('.json5')) continue;\n try {\n const parsed = readJson5File<unknown>(fullPath);\n writeJson5File(fullPath, parsed);\n } catch (err) {\n logger.warn(`Failed to normalize ${fullPath}: ${String(err)}`);\n }\n }\n }\n}\n\nfunction toJavaPropertiesPath(p: string): string {\n return process.platform === 'win32' ? p.replace(/\\\\/g, '\\\\\\\\') : p;\n}\n\nfunction createOrUpdateLocalProperties(projectDir: string, sdkDir: string): void {\n const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}\\n`;\n fs.writeFileSync(path.join(projectDir, 'local.properties'), content, 'utf8');\n}\n\nfunction renameIfExists(fromPath: string, toPath: string): void {\n if (fs.existsSync(fromPath) && fromPath !== toPath) {\n fs.renameSync(fromPath, toPath);\n }\n}\n\n/**\n * Apply user-selected names/versions to template files. Mirrors the writes done by\n * the extension's `updateTemplateConfigs` so a scaffold is identical regardless of\n * which frontend produced it.\n */\nfunction updateTemplateConfigs(\n projectDir: string,\n args: {\n projectName: string;\n bundleName: string;\n /** A plain API level for OpenHarmony; `\"<version>(<api>)\"` for HarmonyOS. */\n sdkVersion: number | string;\n moduleName: string;\n },\n sdkBaseDir: string,\n): void {\n // 1) AppScope/app.json5 -> bundleName\n const appJsonPath = path.join(projectDir, 'AppScope', 'app.json5');\n if (fs.existsSync(appJsonPath)) {\n const appJson = readJson5File<{ app?: { bundleName?: string } }>(appJsonPath);\n appJson.app = appJson.app ?? {};\n appJson.app.bundleName = args.bundleName;\n writeJson5File(appJsonPath, appJson);\n }\n\n // 2) AppScope/resources/base/element/string.json -> app_name = projectName\n const stringsPath = path.join(projectDir, 'AppScope', 'resources', 'base', 'element', 'string.json');\n if (fs.existsSync(stringsPath)) {\n const strings = readJsonFile<{ string?: Array<{ name?: string; value?: string }> }>(stringsPath);\n if (Array.isArray(strings.string)) {\n const appName = strings.string.find((s) => s.name === 'app_name');\n if (appName) appName.value = args.projectName;\n }\n writeJsonFile(stringsPath, strings);\n }\n\n // 3) build-profile.json5 -> sdk + module name + srcPath\n const buildProfilePath = path.join(projectDir, 'build-profile.json5');\n if (fs.existsSync(buildProfilePath)) {\n const buildProfile = readJson5File<{\n app?: { products?: Array<{ compileSdkVersion?: number | string; compatibleSdkVersion?: number | string }> };\n modules?: Array<{ name?: string; srcPath?: string }>;\n }>(buildProfilePath);\n buildProfile.app = buildProfile.app ?? {};\n if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {\n buildProfile.app.products[0]!.compileSdkVersion = args.sdkVersion;\n buildProfile.app.products[0]!.compatibleSdkVersion = args.sdkVersion;\n }\n if (Array.isArray(buildProfile.modules) && buildProfile.modules.length > 0) {\n buildProfile.modules[0]!.name = args.moduleName;\n buildProfile.modules[0]!.srcPath = `./${args.moduleName}`;\n }\n writeJson5File(buildProfilePath, buildProfile);\n }\n\n // 4) <module>/src/main/module.json5 -> module.name\n const moduleJsonPath = path.join(projectDir, args.moduleName, 'src', 'main', 'module.json5');\n if (fs.existsSync(moduleJsonPath)) {\n const moduleJson = readJson5File<{ module?: { name?: string } }>(moduleJsonPath);\n moduleJson.module = moduleJson.module ?? {};\n moduleJson.module.name = args.moduleName;\n writeJson5File(moduleJsonPath, moduleJson);\n }\n\n // 5) <module>/oh-package.json5 -> name\n const moduleOhPackagePath = path.join(projectDir, args.moduleName, 'oh-package.json5');\n if (fs.existsSync(moduleOhPackagePath)) {\n const pkg = readJson5File<{ name?: string }>(moduleOhPackagePath);\n pkg.name = args.moduleName;\n writeJson5File(moduleOhPackagePath, pkg);\n }\n\n // 6) .vscode/settings.json — useful for users who do open the project in VS Code.\n const vscodeDir = path.join(projectDir, '.vscode');\n fs.mkdirSync(vscodeDir, { recursive: true });\n const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;\n writeJsonFile(path.join(vscodeDir, 'settings.json'), {\n 'oniro.hapPath': hapPath,\n 'files.associations': { '*.json5': 'jsonc' },\n });\n\n // 7) local.properties — sdk.dir must point at the OS base SDK home (containing API folders),\n // NOT a specific API folder, otherwise hvigor double-nests the lookup.\n createOrUpdateLocalProperties(projectDir, sdkBaseDir);\n}\n\n/**\n * Scaffold a new Oniro/OpenHarmony project from a template. Returns the absolute path\n * to the created project directory.\n */\nexport async function createScaffold(opts: CreateScaffoldOptions): Promise<CreateScaffoldResult> {\n const logger = opts.logger ?? noopLogger;\n\n if (!isValidProjectName(opts.projectName)) {\n throw new OniroError(`Invalid project name '${opts.projectName}'. Use letters/numbers/._- and no slashes.`);\n }\n if (!isValidBundleName(opts.bundleName)) {\n throw new OniroError(`Invalid bundle name '${opts.bundleName}'. Example: com.example.myapplication`);\n }\n if (!opts.location || !(await pathExists(opts.location))) {\n throw new OniroError(`Location does not exist: ${opts.location}`);\n }\n\n const templateDir = path.join(opts.templateRoot, opts.templateId);\n if (!(await pathExists(templateDir))) {\n throw new OniroError(`Template not found: ${templateDir}`);\n }\n\n const templates = listTemplates(opts.templateRoot);\n const selected = templates.find((t) => t.id === opts.templateId);\n const defaultModuleName = selected?.defaultModuleName ?? 'entry';\n const moduleName = (opts.moduleName ?? defaultModuleName).trim() || defaultModuleName;\n\n const missing = validateTemplateLayout(templateDir, defaultModuleName);\n if (missing.length > 0) {\n throw new OniroError(`Template '${opts.templateId}' is missing required files:\\n- ${missing.join('\\n- ')}`);\n }\n\n // HarmonyOS templates declare the SDK as \"<version>(<api>)\" and build against the\n // HarmonyOS SDK; OpenHarmony ones take the plain API level and the OpenHarmony SDK.\n let sdkVersion: number | string = opts.sdkApi;\n let sdkBaseDir = getOhosBaseSdkHome(opts.config);\n if (detectRuntimeOs(templateDir) === 'HarmonyOS') {\n const harmonySdk = findHarmonyOsSdk({ config: opts.config, logger });\n // The installed SDK names its own release, which covers API levels newer than the table.\n const label = harmonySdk?.version?.endsWith(`(${opts.sdkApi})`)\n ? harmonySdk.version\n : harmonyOsSdkLabelForApi(opts.sdkApi);\n if (!label) {\n throw new OniroError(\n `No HarmonyOS release is known for API ${opts.sdkApi}. Known: ${[...HARMONYOS_SDK_VERSIONS.keys()].join(', ')}` +\n (harmonySdk?.version ? `, and the installed SDK's ${harmonySdk.version}.` : '.'),\n );\n }\n sdkVersion = label;\n if (!harmonySdk) {\n logger.warn('[create] No HarmonyOS SDK found; set ONIRO_HARMONYOS_SDK_PATH before building.');\n } else {\n sdkBaseDir = harmonySdk.sdkPath;\n if (harmonySdk.version && harmonySdk.version !== label) {\n // hvigor fails with \"SDK component missing\" when compileSdkVersion names another release.\n logger.warn(\n `[create] The HarmonyOS SDK at ${harmonySdk.sdkPath} is ${harmonySdk.version}, so a project ` +\n `declaring ${label} will not build against it. Install ${label}, or create with the installed API level.`,\n );\n }\n }\n }\n\n const projectDir = path.join(opts.location, opts.projectName);\n if (await pathExists(projectDir)) {\n if (!opts.overwrite) {\n throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);\n }\n await fs.promises.rm(projectDir, { recursive: true, force: true });\n }\n\n logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);\n await copyDirRecursive(templateDir, projectDir);\n\n if (moduleName !== defaultModuleName) {\n renameIfExists(path.join(projectDir, defaultModuleName), path.join(projectDir, moduleName));\n }\n\n updateTemplateConfigs(\n projectDir,\n {\n projectName: opts.projectName,\n bundleName: opts.bundleName,\n sdkVersion,\n moduleName,\n },\n sdkBaseDir,\n );\n\n await normalizeJson5ToJson(projectDir, logger);\n\n return { projectDir };\n}\n","import * as fs from 'node:fs';\nimport JSON5 from 'json5';\n\nexport function readJson5File<T>(filePath: string): T {\n return JSON5.parse(fs.readFileSync(filePath, 'utf8')) as T;\n}\n\n/**\n * Write strict JSON content (quoted keys) to a `.json5` file. Keeps the file\n * compatible with VS Code's JSON parser while remaining valid JSON5.\n */\nexport function writeJson5File(filePath: string, value: unknown): void {\n fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\\n', 'utf8');\n}\n\nexport function readJsonFile<T>(filePath: string): T {\n return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T;\n}\n\nexport function writeJsonFile(filePath: string, value: unknown): void {\n fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\\n', 'utf8');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { OniroError } from '../ports/errors.js';\nimport { readJson5File } from './jsonHelpers.js';\n\nexport interface ProjectModule {\n name: string;\n /** Source path relative to the project root (e.g. `./entry`). */\n srcPath: string;\n /** Target names declared under the module (often empty). */\n targets: string[];\n}\n\ninterface BuildProfile {\n modules?: Array<{ name?: string; srcPath?: string; targets?: Array<{ name?: string }> }>;\n}\n\n/**\n * Read the `modules[]` declared in `build-profile.json5` so callers can target a\n * specific module in a multi-module project.\n */\nexport function listModules(opts: { projectDir: string }): ProjectModule[] {\n const buildProfile = path.join(opts.projectDir, 'build-profile.json5');\n if (!fs.existsSync(buildProfile)) {\n throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);\n }\n const parsed = readJson5File<BuildProfile>(buildProfile);\n return (parsed.modules ?? [])\n .filter((m): m is { name: string; srcPath?: string; targets?: Array<{ name?: string }> } => Boolean(m.name))\n .map((m) => ({\n name: m.name,\n srcPath: m.srcPath ?? `./${m.name}`,\n targets: (m.targets ?? []).map((t) => t.name).filter((n): n is string => Boolean(n)),\n }));\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { OniroError } from '../ports/errors.js';\nimport { readJson5File } from './jsonHelpers.js';\n\nexport interface AbilityInfo {\n name: string;\n type?: string;\n visible?: boolean;\n srcEntry?: string;\n}\n\ninterface ModuleJson {\n module?: { abilities?: Array<{ name?: string; type?: string; visible?: boolean; srcEntry?: string }> };\n}\n\n/**\n * Read all abilities declared in a module's `module.json5` `abilities[]`.\n * Defaults to the `entry` module folder.\n */\nexport function listAbilities(opts: { projectDir: string; moduleName?: string }): AbilityInfo[] {\n const moduleName = opts.moduleName ?? 'entry';\n const moduleJsonPath = path.join(opts.projectDir, moduleName, 'src', 'main', 'module.json5');\n if (!fs.existsSync(moduleJsonPath)) {\n throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);\n }\n const parsed = readJson5File<ModuleJson>(moduleJsonPath);\n return (parsed.module?.abilities ?? [])\n .filter((a): a is { name: string; type?: string; visible?: boolean; srcEntry?: string } => Boolean(a.name))\n .map((a) => ({ name: a.name, type: a.type, visible: a.visible, srcEntry: a.srcEntry }));\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { getOhosBaseSdkHome } from '../sdk/paths.js';\nimport { generateSigningConfigs, type Apl, type AppFeature, type SigningPasswords } from '../sign/generateSigningConfigs.js';\nimport { readJson5File } from './jsonHelpers.js';\n\nexport interface PrepareSigningOptions {\n config: ConfigProvider;\n projectDir: string;\n // Forwarded to the fresh-generate fallback:\n apl?: Apl;\n appFeature?: AppFeature;\n acls?: string[];\n appPrivilegeCapabilities?: string[];\n passwords?: SigningPasswords;\n logger?: Logger;\n}\n\nexport interface PrepareSigningResult {\n source: 'present' | 'fresh';\n}\n\n/** A project has usable signing material if `signatures/` exists AND build-profile declares signingConfigs. */\nfunction hasSigningArtifacts(dir: string): boolean {\n if (!fs.existsSync(path.join(dir, 'signatures'))) return false;\n const buildProfile = path.join(dir, 'build-profile.json5');\n if (!fs.existsSync(buildProfile)) return false;\n try {\n const parsed = readJson5File<{ app?: { signingConfigs?: unknown[] } }>(buildProfile);\n return Array.isArray(parsed.app?.signingConfigs) && parsed.app!.signingConfigs!.length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Ensure a project has signing material: a no-op when `signatures/` +\n * signingConfigs already exist ('present'), otherwise generate them via\n * {@link generateSigningConfigs} ('fresh', which needs java + the SDK).\n */\nexport function prepareSigning(opts: PrepareSigningOptions): PrepareSigningResult {\n if (hasSigningArtifacts(opts.projectDir)) {\n return { source: 'present' };\n }\n generateSigningConfigs({\n projectDir: opts.projectDir,\n sdkHome: getOhosBaseSdkHome(opts.config),\n apl: opts.apl,\n appFeature: opts.appFeature,\n acls: opts.acls,\n appPrivilegeCapabilities: opts.appPrivilegeCapabilities,\n passwords: opts.passwords,\n logger: opts.logger,\n });\n return { source: 'fresh' };\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { shell } from '../hdc/exec.js';\n\nexport interface HidumperOptions {\n config: ConfigProvider;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\nexport interface ScreenDump {\n width: number;\n height: number;\n /** Raw hidumper screen output. */\n raw: string;\n}\n\n/** `hidumper -s 10 -a screen` → parsed render resolution + raw text, or null. */\nexport async function dumpScreen(opts: HidumperOptions): Promise<ScreenDump | null> {\n const res = await shell({ config: opts.config, command: 'hidumper -s 10 -a screen', deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 10_000, logger: opts.logger });\n if (res.code !== 0) return null;\n const m = res.stdout.match(/render resolution=(\\d+)x(\\d+)/);\n if (!m) return null;\n return { width: Number(m[1]), height: Number(m[2]), raw: res.stdout };\n}\n\n/** `hidumper -s WindowManagerService -a -a` — windows in z-order with surface presence. */\nexport async function dumpWindow(opts: HidumperOptions): Promise<string> {\n const res = await shell({ config: opts.config, command: 'hidumper -s WindowManagerService -a -a', deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 15_000, logger: opts.logger });\n return res.stdout;\n}\n\n/** `hidumper -s RenderService -a allInfo` — composition state / refresh rate. */\nexport async function dumpRenderService(opts: HidumperOptions): Promise<string> {\n const res = await shell({ config: opts.config, command: 'hidumper -s RenderService -a allInfo', deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 15_000, logger: opts.logger });\n return res.stdout;\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { paramGetMany } from '../hdc/param.js';\nimport { dumpScreen } from './hidumper.js';\n\nexport interface DeviceFullInfo {\n serial: string;\n model?: string;\n manufacturer?: string;\n brand?: string;\n /** `HarmonyOS` when the device reports a HarmonyOS distribution, else `OpenHarmony` (Oniro included). */\n osFamily?: 'HarmonyOS' | 'OpenHarmony';\n /** Distribution name (`const.product.os.dist.name`): `HarmonyOS`; unset on OpenHarmony. */\n osDistName?: string;\n /** Distribution version (`const.product.os.dist.version`), e.g. `6.1.0` on HarmonyOS. */\n osDistVersion?: string;\n osFullName?: string;\n osReleaseType?: string;\n sdkApiVersion?: string;\n buildVersion?: string;\n /** CPU ABIs (`const.product.cpu.abilist`), e.g. `arm64-v8a` or `x86_64`: native libraries must match. */\n abi?: string;\n /** `phone`, `tablet`, `wearable`, `default`, … */\n deviceType?: string;\n display: { width: number; height: number } | null;\n}\n\ntype ParamField = Exclude<keyof DeviceFullInfo, 'serial' | 'display' | 'osFamily'>;\n\n// The MCP get_device_info property set, plus what picking a target for an app needs.\nconst PROPS: ReadonlyArray<[ParamField, string]> = [\n ['model', 'const.product.model'],\n ['manufacturer', 'const.product.manufacturer'],\n ['brand', 'const.product.brand'],\n ['osDistName', 'const.product.os.dist.name'],\n ['osDistVersion', 'const.product.os.dist.version'],\n ['osFullName', 'const.ohos.fullname'],\n ['osReleaseType', 'const.ohos.releasetype'],\n ['sdkApiVersion', 'const.ohos.apiversion'],\n ['buildVersion', 'const.product.software.version'],\n ['abi', 'const.product.cpu.abilist'],\n ['deviceType', 'const.product.devicetype'],\n];\n\nexport interface GetDeviceInfoOptions {\n config: ConfigProvider;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/** Collate device properties (one `param get` round trip) and the display resolution. */\nexport async function getDeviceInfo(opts: GetDeviceInfoOptions): Promise<DeviceFullInfo> {\n const info: DeviceFullInfo = { serial: opts.deviceSerial ?? '(default)', display: null };\n\n try {\n const values = await paramGetMany(\n opts.config,\n PROPS.map(([, prop]) => prop),\n { deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 10_000, logger: opts.logger },\n );\n for (const [field, prop] of PROPS) {\n const value = values[prop];\n if (value) info[field] = value;\n }\n } catch {\n // Missing properties are left undefined rather than failing the whole collation.\n }\n if (info.osDistName || info.osFullName) {\n info.osFamily = /harmonyos/i.test(info.osDistName ?? '') ? 'HarmonyOS' : 'OpenHarmony';\n }\n\n const screen = await dumpScreen({ config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger });\n if (screen) info.display = { width: screen.width, height: screen.height };\n return info;\n}\n","import StreamZip from 'node-stream-zip';\n\n// node-stream-zip's types are thin; this is the minimal shape we use (mirrors sdk/extract.ts).\ninterface ZipEntry {\n name: string;\n isDirectory: boolean;\n}\ninterface StreamZipAsync {\n entries(): Promise<Record<string, ZipEntry>>;\n close(): Promise<void>;\n}\n\nexport interface HapAssetDiff {\n /** File paths present in the new HAP but not the installed one. */\n addedAssetPaths: string[];\n /** File paths present in the installed HAP but not the new one. */\n removedAssetPaths: string[];\n}\n\n/** Pure set-diff of two file-name listings, sorted. */\nexport function diffEntryNames(installed: Iterable<string>, next: Iterable<string>): HapAssetDiff {\n const installedSet = new Set(installed);\n const nextSet = new Set(next);\n return {\n addedAssetPaths: [...nextSet].filter((n) => !installedSet.has(n)).sort(),\n removedAssetPaths: [...installedSet].filter((n) => !nextSet.has(n)).sort(),\n };\n}\n\nasync function listFileEntries(hapPath: string): Promise<string[]> {\n const zip = new (StreamZip as unknown as { async: new (cfg: { file: string }) => StreamZipAsync }).async({ file: hapPath });\n try {\n const entries = await zip.entries();\n return Object.values(entries)\n .filter((e) => !e.isDirectory)\n .map((e) => e.name);\n } finally {\n await zip.close();\n }\n}\n\n/**\n * Diff the file manifests of two HAP (zip) archives. Drives the ACE-extractor\n * cache-invalidation reboot decision in `applyChanges`: when the new HAP adds or\n * renames file paths vs the installed one, the path-keyed asset cache can serve\n * stale \"GetAsset failed\" errors until a reboot.\n */\nexport async function diffHapAssets(opts: { installedHap: string; newHap: string }): Promise<HapAssetDiff> {\n const [installed, next] = await Promise.all([listFileEntries(opts.installedHap), listFileEntries(opts.newHap)]);\n return diffEntryNames(installed, next);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger, scopedLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { hdcExec } from '../hdc/exec.js';\nimport {\n ensureInstallOk,\n existingHapOrUnsigned,\n findRunningProcess,\n isBundleInstalled,\n uninstallApp,\n type InstallCandidate,\n} from '../hdc/app.js';\nimport { reboot } from '../hdc/lifecycle.js';\nimport { discoverHaps, pickHap } from '../build/discoverHaps.js';\nimport { diffHapAssets } from './diffHapAssets.js';\n\nexport type InstallMethod = 'replace' | 'uninstall-install' | 'refuse';\n\n/**\n * P0-5a decision: how to install given whether `hdc install -r` reported a\n * sign-info-inconsistent error (9568332). System bundles are NOT silently\n * uninstalled (that can brick the device) unless explicitly allowed.\n */\nexport function decideInstallMethod(s: {\n signInfoInconsistent: boolean;\n isSystemBundle: boolean;\n allowUninstall: boolean;\n}): InstallMethod {\n if (!s.signInfoInconsistent) return 'replace';\n if (s.isSystemBundle && !s.allowUninstall) return 'refuse';\n return 'uninstall-install';\n}\n\nexport interface RebootDecision {\n reboot: boolean;\n reason: 'asset-cache' | 'pid-unchanged' | 'none';\n}\n\n/**\n * P0-5b/c decision: whether to reboot after installing. Reboot when the HAP's\n * asset paths changed (ACE extractor cache is path-keyed and survives a process\n * kill), or when a persistent/system bundle's process didn't restart.\n */\nexport function decideReboot(s: {\n assetsChanged: boolean;\n isSystemBundle: boolean;\n preInstallPid: number | null;\n postInstallPid: number | null;\n}): RebootDecision {\n if (s.assetsChanged) return { reboot: true, reason: 'asset-cache' };\n if (s.isSystemBundle && s.preInstallPid !== null && s.postInstallPid === s.preInstallPid) {\n return { reboot: true, reason: 'pid-unchanged' };\n }\n return { reboot: false, reason: 'none' };\n}\n\nconst SIGN_INFO_INCONSISTENT = /9568332|sign.*info.*inconsistent/i;\n\nexport interface ApplyChangesOptions {\n config: ConfigProvider;\n bundle: string;\n /** Explicit HAP path. If omitted, resolved from projectDir (+ module) via discoverHaps. */\n hapPath?: string;\n projectDir?: string;\n module?: string;\n /** Local path to the currently-installed HAP; enables the asset-cache diff/reboot. */\n installedHapPath?: string;\n /** Persistent/system bundle (e.g. systemui). Default false. */\n isSystemBundle?: boolean;\n /** Permit uninstalling a system bundle on sign-info mismatch (dangerous). Default false. */\n allowUninstall?: boolean;\n deviceSerial?: string;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\nexport interface ApplyChangesResult {\n method: 'replace' | 'uninstall-install' | 'reboot';\n preInstallPid: number | null;\n postInstallPid: number | null;\n replaced: boolean;\n /** True when an asset-path change forced the reboot. */\n cacheCleared: boolean;\n}\n\nasync function pidOf(config: ConfigProvider, bundle: string, deviceSerial?: string): Promise<number | null> {\n const proc = await findRunningProcess({ config, bundle, deviceSerial });\n return proc ? Number(proc.pid) : null;\n}\n\nasync function resolveHap(opts: ApplyChangesOptions, logger: Logger): Promise<InstallCandidate> {\n let hap: InstallCandidate | undefined;\n if (opts.hapPath) {\n const hapPath =\n !path.isAbsolute(opts.hapPath) && opts.projectDir ? path.join(opts.projectDir, opts.hapPath) : opts.hapPath;\n hap = existingHapOrUnsigned(hapPath);\n if (!hap) throw new OniroError(`HAP not found at ${hapPath}.`);\n } else {\n if (!opts.projectDir) throw new OniroError('applyChanges requires hapPath or projectDir.');\n const picked = pickHap(await discoverHaps({ projectDir: opts.projectDir }), opts.module);\n if (!picked) throw new OniroError(`No HAP found${opts.module ? ` for module ${opts.module}` : ''}. Build first.`);\n hap = { path: picked.path, fallback: !picked.signed };\n }\n if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path.basename(hap.path)}.`);\n return hap;\n}\n\n/**\n * Install a HAP and verify the running process took the change. Handles the\n * three failure modes the naive \"install the most recent signed HAP\" deploy\n * ignores: sign-info-inconsistent on `-r`, asset-cache invalidation, and a\n * persistent bundle that didn't restart. See {@link decideInstallMethod} /\n * {@link decideReboot} for the (pure, tested) branch logic.\n */\nexport async function applyChanges(opts: ApplyChangesOptions): Promise<ApplyChangesResult> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'apply');\n const { config, bundle, deviceSerial } = opts;\n const isSystemBundle = opts.isSystemBundle ?? false;\n const allowUninstall = opts.allowUninstall ?? false;\n\n const hap = await resolveHap(opts, logger);\n const hapPath = hap.path;\n logger.info(`installing ${hapPath}`);\n\n // Asset-path diff (best-effort; only when the caller supplies the installed HAP).\n let assetsChanged = false;\n if (opts.installedHapPath && fs.existsSync(opts.installedHapPath)) {\n try {\n const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });\n assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;\n } catch (err) {\n logger.debug(`asset diff skipped: ${(err as Error).message}`);\n }\n }\n\n const preInstallPid = await pidOf(config, bundle, deviceSerial);\n\n // Attempt a replace install, then decide based on the sign-info signal.\n const replaceRes = await hdcExec({ config, args: ['install', '-r', hapPath], deviceSerial, timeoutMs: 300_000 });\n const signInfoInconsistent = SIGN_INFO_INCONSISTENT.test(`${replaceRes.stdout}${replaceRes.stderr}`);\n const decision = decideInstallMethod({ signInfoInconsistent, isSystemBundle, allowUninstall });\n\n let installMethod: 'replace' | 'uninstall-install';\n if (decision === 'refuse') {\n throw new OniroError(\n `Refusing to reinstall system bundle ${bundle}: signing certs are inconsistent (9568332). ` +\n 'Align the signing certs first — uninstalling a system bundle can brick the device. ' +\n 'Pass allowUninstall to override.',\n );\n }\n if (decision === 'uninstall-install') {\n logger.warn(`sign-info inconsistent for ${bundle}; uninstalling then installing fresh.`);\n await uninstallApp({ config, bundle, deviceSerial });\n ensureInstallOk(\n await hdcExec({ config, args: ['install', hapPath], deviceSerial, timeoutMs: 300_000 }),\n `hdc install ${hapPath}`,\n hap,\n );\n installMethod = 'uninstall-install';\n } else {\n ensureInstallOk(replaceRes, `hdc install -r ${hapPath}`, hap);\n installMethod = 'replace';\n }\n\n // hdc's own exit code says nothing about the bundle manager's verdict, so\n // confirm the bundle is there before reporting success.\n if (!(await isBundleInstalled({ config, bundle, deviceSerial }))) {\n throw new OniroError(\n `hdc reported ${path.basename(hapPath)} as installed, but bm dump does not list ${bundle}. ` +\n 'Check that the HAP was built from this project (its bundleName must match).',\n );\n }\n\n let postInstallPid = await pidOf(config, bundle, deviceSerial);\n const rebootDecision = decideReboot({ assetsChanged, isSystemBundle, preInstallPid, postInstallPid });\n\n let method: ApplyChangesResult['method'] = installMethod;\n let cacheCleared = false;\n if (rebootDecision.reboot) {\n logger.info(`rebooting (${rebootDecision.reason}) to apply changes to ${bundle}.`);\n await reboot({ config, waitForBundle: bundle, deviceSerial, abortSignal: opts.abortSignal, logger: opts.logger });\n postInstallPid = await pidOf(config, bundle, deviceSerial);\n method = 'reboot';\n cacheCleared = rebootDecision.reason === 'asset-cache';\n }\n\n return { method, preInstallPid, postInstallPid, replaced: installMethod === 'replace', cacheCleared };\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/auth/auth-config.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n *\n * These are private, undocumented Huawei endpoints and can change without notice.\n */\n\n/** Client ID the DevEco CLI registers as with the Huawei login service. */\nexport const HUAWEI_APP_ID = '1009';\n\n/** Version string the temp-token exchange expects. */\nexport const HUAWEI_API_VERSION = '1.0.0';\n\n/** How long to wait for the user to finish signing in in their browser. */\nexport const LOGIN_TIMEOUT_MS = 600_000;\n\nexport type HuaweiSiteCode = 'CN' | 'EU' | 'SG' | 'RU';\n\nexport interface HuaweiSite {\n code: HuaweiSiteCode;\n /** `siteId` as reported by the login callback. */\n siteId: string;\n /** The token exchange's `site` parameter. The European site's is `DE`, not `EU`. */\n siteParam: string;\n /** Sign-in page and `authrouter` token endpoints. */\n loginUrl: string;\n /** AppGallery Connect certificate, device and profile calls. */\n agcBaseUrl: string;\n language: string;\n}\n\n/**\n * Regional endpoints.\n *\n * Upstream hardcodes the Chinese-mainland hosts and refuses any other `siteId`.\n * DevEco Studio resolves every host through Huawei's Global Routing Service (GRS),\n * service `com.huawei.devecostudio.region`, by the user's country; these are its\n * answers for keys `spaceintroduce` (sign-in, token exchange) and `agcsign`\n * (signing). If a region stops working, diff against\n *\n * POST https://grs.dbankcloud.com/grs/2.0/router?issue_country=<ISO>&app_name=devecostudio\n *\n * The `siteId` → `site` mapping is DevEco Studio's own (1 CN, 5 SG, 7 DE, 8 RU).\n */\nexport const HUAWEI_SITES: Readonly<Record<HuaweiSiteCode, HuaweiSite>> = {\n CN: {\n code: 'CN',\n siteId: '1',\n siteParam: 'CN',\n loginUrl: 'https://cn.devecostudio.huawei.com',\n agcBaseUrl: 'https://connect-api.cloud.huawei.com',\n language: 'zh_CN',\n },\n SG: {\n code: 'SG',\n siteId: '5',\n siteParam: 'SG',\n loginUrl: 'https://sg.devecostudio.huawei.com',\n agcBaseUrl: 'https://connect-api-dra.cloud.huawei.com',\n language: 'zh_CN',\n },\n EU: {\n code: 'EU',\n siteId: '7',\n siteParam: 'DE',\n loginUrl: 'https://de.devecostudio.huawei.com',\n agcBaseUrl: 'https://connect-api-dre.cloud.huawei.com',\n language: 'de_DE',\n },\n RU: {\n code: 'RU',\n siteId: '8',\n siteParam: 'RU',\n loginUrl: 'https://ru.devecostudio.huawei.com',\n agcBaseUrl: 'https://connect-api-drru.cloud.huawei.com',\n language: 'ru_RU',\n },\n};\n\n/** The team list is served from one host for every region (GRS key `agcups`). */\nexport const AGC_TEAMS_URL = 'https://connect-api.cloud.huawei.com/api/ups/user-permission-service/v1/user-team-list';\n\n/**\n * Resolve the `siteId` the login callback reports, or null for one this table does\n * not know — sending an account's token to another region's hosts gets it refused.\n */\nexport function siteForId(siteId: string): HuaweiSite | null {\n return Object.values(HUAWEI_SITES).find((s) => s.siteId === siteId) ?? null;\n}\n\n/** Paths shared by every region; only the host differs. */\nexport const AUTH_PATHS = {\n /** The browser authenticates here, then redirects to the loopback server. */\n AUTH_APPLY: 'console/DevEcoIDE/apply',\n /** Exchanges the browser's temp token for a JWT. */\n TEMP_TOKEN_CHECK: 'authrouter/auth/api/temptoken/check',\n /** Validates a JWT and, with `refresh`, mints an AGC access token. */\n JWT_TOKEN_CHECK: 'authrouter/auth/api/jwToken/check',\n LOGIN_SUCCESS: 'console/DevEcoCLI/loginSuccess',\n LOGIN_FAILED: 'console/DevEcoCLI/loginFailed',\n LOGOUT: 'authrouter/auth/api/logout',\n /**\n * Whether an account without real-name verification accepted the developer\n * agreement, which is what lets it sign. From DevEco Studio (`space.agr.url`).\n */\n UNREALNAME_AGREEMENT: 'authrouter/unrealname/agreement',\n} as const;\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/auth/utils/local-crypto.ts`, `src/auth/utils/token-storage.ts`),\n * Copyright (c) 2026 Huawei Device Co., Ltd., licensed under the MIT License.\n * See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport type { ConfigProvider } from '../../ports/config.js';\nimport { defaultPaths } from '../../ports/config.js';\nimport type { Logger } from '../../ports/logger.js';\nimport { noopLogger } from '../../ports/logger.js';\nimport { OniroError } from '../../ports/errors.js';\n\nconst ALGORITHM = 'aes-256-gcm';\nconst KEY_LENGTH = 32;\nconst IV_LENGTH = 12;\nconst TOKEN_FILE = 'token.enc';\nconst KEY_FILE = 'kek.bin';\nconst DIR_MODE = 0o700;\nconst FILE_MODE = 0o600;\n\ninterface EncryptedBlob {\n version: 1;\n algorithm: typeof ALGORITHM;\n ciphertext: string;\n iv: string;\n authTag: string;\n}\n\nfunction encrypt(key: Buffer, plaintext: Buffer): EncryptedBlob {\n const iv = crypto.randomBytes(IV_LENGTH);\n const cipher = crypto.createCipheriv(ALGORITHM, key, iv);\n const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n return {\n version: 1,\n algorithm: ALGORITHM,\n ciphertext: ciphertext.toString('base64'),\n iv: iv.toString('base64'),\n authTag: cipher.getAuthTag().toString('base64'),\n };\n}\n\nfunction decrypt(key: Buffer, blob: EncryptedBlob): Buffer {\n const decipher = crypto.createDecipheriv(ALGORITHM, key, Buffer.from(blob.iv, 'base64'));\n decipher.setAuthTag(Buffer.from(blob.authTag, 'base64'));\n return Buffer.concat([decipher.update(Buffer.from(blob.ciphertext, 'base64')), decipher.final()]);\n}\n\nfunction isEncryptedBlob(value: unknown): value is EncryptedBlob {\n if (!value || typeof value !== 'object') return false;\n const b = value as Partial<EncryptedBlob>;\n return (\n b.algorithm === ALGORITHM &&\n typeof b.ciphertext === 'string' &&\n typeof b.iv === 'string' &&\n typeof b.authTag === 'string'\n );\n}\n\nfunction permissionHint(dir: string): string {\n return process.platform === 'win32'\n ? `Permission denied writing ${dir}. Grant write permission to that directory.`\n : `Permission denied writing ${dir}. Try: chown -R \"$(whoami)\" ${dir}`;\n}\n\nfunction ensureDir(dir: string): void {\n try {\n fs.mkdirSync(dir, { recursive: true, mode: DIR_MODE });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'EACCES') {\n throw new OniroError(permissionHint(dir), err);\n }\n throw err;\n }\n}\n\n/**\n * A signed-in account: the durable credential plus its region, since every later\n * request goes to that region's hosts and only the login callback reports it.\n */\nexport interface StoredSession {\n jwtToken: string;\n /** `siteId` from the login callback. */\n siteId: string;\n}\n\nexport interface TokenStore {\n save(session: StoredSession): void;\n load(): StoredSession | null;\n clear(): void;\n /** Where the encrypted token lives — surfaced by `auth status`. */\n readonly tokenPath: string;\n}\n\nexport interface CreateTokenStoreOptions {\n config: ConfigProvider;\n logger?: Logger;\n}\n\n/**\n * Persist the Huawei account JWT under the configured auth directory\n * (`ONIRO_HARMONYOS_AUTH_DIR`, default `~/.oniro/harmonyos`).\n *\n * The token is encrypted with a random key kept in a *different* directory, so a\n * stray copy of one of them — a config-dir backup, a synced dotfile repo — does not\n * yield the token. Both live on the same disk, so this is no defence against a local\n * attacker who can read the user's whole home. Treat the token as a credential.\n */\nexport function createTokenStore(opts: CreateTokenStoreOptions): TokenStore {\n const logger = opts.logger ?? noopLogger;\n const authDir = opts.config.get('harmonyosAuthDir', defaultPaths.harmonyosAuthDir());\n const tokenPath = path.join(authDir, TOKEN_FILE);\n const keyPath = path.join(os.homedir(), '.local', 'share', 'oniro-app', 'keys', KEY_FILE);\n\n function loadOrCreateKey(): Buffer {\n if (fs.existsSync(keyPath)) {\n const existing = fs.readFileSync(keyPath);\n if (existing.length === KEY_LENGTH) return existing;\n logger.warn('[harmonyos] The token key file was malformed; regenerating (you will need to log in again).');\n }\n ensureDir(path.dirname(keyPath));\n const key = crypto.randomBytes(KEY_LENGTH);\n fs.writeFileSync(keyPath, key, { mode: FILE_MODE });\n return key;\n }\n\n return {\n tokenPath,\n\n save(session: StoredSession): void {\n if (!session.jwtToken) throw new OniroError('Refusing to store an empty token.');\n const payload = Buffer.from(JSON.stringify(session), 'utf8');\n const blob = encrypt(loadOrCreateKey(), payload);\n ensureDir(authDir);\n fs.writeFileSync(tokenPath, JSON.stringify(blob, null, 2), { mode: FILE_MODE });\n },\n\n load(): StoredSession | null {\n if (!fs.existsSync(tokenPath)) return null;\n try {\n const blob: unknown = JSON.parse(fs.readFileSync(tokenPath, 'utf8'));\n if (!isEncryptedBlob(blob)) return null;\n const { jwtToken, siteId } = JSON.parse(decrypt(loadOrCreateKey(), blob).toString('utf8')) as Partial<StoredSession>;\n return typeof jwtToken === 'string' && jwtToken && typeof siteId === 'string' ? { jwtToken, siteId } : null;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n // A permissions problem is transient and the user can fix it; anything else\n // means the stored token is unusable, so drop it rather than failing every\n // later command with the same decrypt error.\n if (code === 'EACCES' || code === 'EPERM') {\n logger.warn(`[harmonyos] Cannot read ${tokenPath}: ${permissionHint(authDir)}`);\n return null;\n }\n logger.debug(`[harmonyos] Discarding unreadable token at ${tokenPath}.`);\n try {\n fs.rmSync(tokenPath, { force: true });\n } catch {\n // Best effort.\n }\n return null;\n }\n },\n\n clear(): void {\n try {\n fs.rmSync(tokenPath, { force: true });\n } catch (err) {\n throw new OniroError(`Failed to remove ${tokenPath}.`, err);\n }\n },\n };\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/auth/login/login-service.ts`, `src/auth/utils/token-checker.ts`,\n * `src/auth/login/user-info-fetcher.ts`, `src/auth/team/team-service.ts`),\n * Copyright (c) 2026 Huawei Device Co., Ltd., licensed under the MIT License.\n * See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as crypto from 'node:crypto';\nimport type { ConfigProvider } from '../../ports/config.js';\nimport type { Logger } from '../../ports/logger.js';\nimport { noopLogger } from '../../ports/logger.js';\nimport { OniroError } from '../../ports/errors.js';\nimport { createHttpClient, describeResponse, type HarmonyOsHttpClient } from '../http.js';\nimport { createTokenStore, type TokenStore } from './tokenStore.js';\nimport {\n AGC_TEAMS_URL,\n AUTH_PATHS,\n HUAWEI_APP_ID,\n HUAWEI_API_VERSION,\n HUAWEI_SITES,\n LOGIN_TIMEOUT_MS,\n siteForId,\n type HuaweiSite,\n} from './endpoints.js';\nimport { startCallbackServer } from './callbackServer.js';\nimport { openBrowser } from './browser.js';\nimport type { AgcAuthInfo, DeveloperAgreementStatus, HuaweiTeam, HuaweiUserInfo } from './types.js';\n\nexport interface HarmonyOsSessionOptions {\n config: ConfigProvider;\n logger?: Logger;\n http?: HarmonyOsHttpClient;\n tokenStore?: TokenStore;\n /** Called with the sign-in URL before the browser opens, so a CLI can print it. */\n onLoginUrl?: (url: string) => void;\n}\n\nexport interface HarmonyOsSession {\n login(opts?: { timeoutMs?: number }): Promise<HuaweiUserInfo>;\n /** Resolves false when there was no session to end. */\n logout(): Promise<boolean>;\n /** The signed-in account, or null. `refresh` mints a fresh AGC access token. */\n getUserInfo(opts?: { refresh?: boolean }): Promise<HuaweiUserInfo | null>;\n listTeams(): Promise<HuaweiTeam[]>;\n /** Credentials for AGC calls. Throws when signed out, or when the account may not sign. */\n resolveAgcAuth(opts?: { teamId?: string }): Promise<AgcAuthInfo>;\n /** Whether the account accepted the developer agreement; null when undeterminable. */\n getDeveloperAgreement(user: HuaweiUserInfo): Promise<DeveloperAgreementStatus | null>;\n readonly tokenPath: string;\n}\n\n/** Response of `jwToken/check`. */\ninterface TokenCheckResponse {\n status?: boolean;\n userInfo?: { accessToken?: string; userId?: string; name?: string; nationalCode?: string; realName?: unknown };\n}\n\nconst NOT_SIGNED_IN = 'Not signed in. Run `oniro-app auth login` first.';\n\nexport function createHarmonyOsSession(opts: HarmonyOsSessionOptions): HarmonyOsSession {\n const logger = opts.logger ?? noopLogger;\n const http = opts.http ?? createHttpClient({ logger });\n const store = opts.tokenStore ?? createTokenStore({ config: opts.config, logger });\n\n /** Exchange the browser's short-lived temp token for the durable JWT. */\n async function exchangeTempToken(site: HuaweiSite, tempToken: string): Promise<string> {\n const response = await http.get(`${site.loginUrl}/${AUTH_PATHS.TEMP_TOKEN_CHECK}`, {\n query: {\n // The page sometimes appends extra `&`-joined parameters to the token.\n tempToken: tempToken.split('&')[0],\n site: site.siteParam,\n version: HUAWEI_API_VERSION,\n appid: HUAWEI_APP_ID,\n },\n });\n const jwtToken = response.data.trim();\n if (response.statusCode === 200 && /^[^.]+\\.[^.]+\\.[^.]+$/.test(jwtToken)) return jwtToken;\n\n // Any token the endpoint will not redeem — expired, reused, or sent to the\n // wrong region — gets the same empty 200, so there is no reason to report.\n throw new OniroError(\n `${site.loginUrl} would not exchange the login token for a session (${describeResponse(response)}). ` +\n 'Login tokens are single-use and short-lived; run `oniro-app auth login` again.',\n );\n }\n\n /** Validate the JWT with its region; null when it is no longer valid. */\n async function userFromJwt(site: HuaweiSite, jwtToken: string, refresh: boolean): Promise<HuaweiUserInfo | null> {\n const response = await http.get(`${site.loginUrl}/${AUTH_PATHS.JWT_TOKEN_CHECK}`, {\n headers: { refresh: String(refresh), jwtToken },\n });\n let info: TokenCheckResponse;\n try {\n if (response.statusCode !== 200) throw new Error();\n info = JSON.parse(response.data) as TokenCheckResponse;\n } catch {\n throw new OniroError(`Could not validate the session with ${site.loginUrl} (${describeResponse(response)}).`);\n }\n const user = info.userInfo;\n if (!info.status || !user?.accessToken) return null;\n return {\n userId: user.userId ?? '',\n userName: user.name ?? '',\n accessToken: user.accessToken,\n countryCode: user.nationalCode ?? '',\n siteCode: site.code,\n isRealName: String(user.realName) === 'true',\n };\n }\n\n async function getUserInfo(o: { refresh?: boolean } = {}): Promise<HuaweiUserInfo | null> {\n const stored = store.load();\n const site = stored && siteForId(stored.siteId);\n const user = site ? await userFromJwt(site, stored.jwtToken, o.refresh ?? false) : null;\n if (stored && !user) {\n logger.debug('[harmonyos] The stored session is no longer valid; clearing it.');\n store.clear();\n }\n return user;\n }\n\n async function requireUser(): Promise<HuaweiUserInfo> {\n const user = await getUserInfo({ refresh: true });\n if (!user) throw new OniroError(NOT_SIGNED_IN);\n return user;\n }\n\n async function getDeveloperAgreement(user: HuaweiUserInfo): Promise<DeveloperAgreementStatus | null> {\n try {\n const response = await http.get(`${HUAWEI_SITES[user.siteCode].loginUrl}/${AUTH_PATHS.UNREALNAME_AGREEMENT}`, {\n headers: { accessToken: user.accessToken },\n });\n const payload = JSON.parse(response.data) as {\n success?: unknown;\n body?: { signedFlag?: unknown; signLastestFlag?: unknown };\n };\n if (response.statusCode !== 200 || String(payload.success) !== 'true' || !payload.body) return null;\n return { signed: payload.body.signedFlag === true, latest: payload.body.signLastestFlag === true };\n } catch {\n return null;\n }\n }\n\n return {\n tokenPath: store.tokenPath,\n getUserInfo,\n getDeveloperAgreement,\n\n async login(o = {}): Promise<HuaweiUserInfo> {\n // Sign-in starts on the Chinese-mainland page, which redirects every account to\n // its own region's; the callback then reports which region that was.\n const start = HUAWEI_SITES.CN.loginUrl;\n const clientSecret = crypto.randomUUID().replace(/-/g, '');\n const server = await startCallbackServer({\n clientSecret,\n baseUrl: start,\n successPath: AUTH_PATHS.LOGIN_SUCCESS,\n failedPath: AUTH_PATHS.LOGIN_FAILED,\n });\n\n try {\n const loginUrl = `${start}/${AUTH_PATHS.AUTH_APPLY}?port=${server.port}&appid=${HUAWEI_APP_ID}&code=${clientSecret}`;\n opts.onLoginUrl?.(loginUrl);\n // Not awaited: some launchers exit only when the browser does.\n openBrowser(loginUrl).catch((err: Error) => {\n // Headless hosts have no browser; the URL was surfaced via onLoginUrl.\n logger.warn(`[harmonyos] Could not open a browser automatically: ${err.message}`);\n });\n\n const callback = await server.waitForCallback(o.timeoutMs ?? LOGIN_TIMEOUT_MS);\n const site = siteForId(callback.siteId);\n if (!site) {\n throw new OniroError(`The account belongs to a Huawei region oniro-app does not know (siteId ${callback.siteId}).`);\n }\n\n const jwtToken = await exchangeTempToken(site, callback.tempToken);\n const user = await userFromJwt(site, jwtToken, false);\n if (!user) throw new OniroError('Login did not yield a usable session. Try again.');\n store.save({ jwtToken, siteId: site.siteId });\n logger.info(`[harmonyos] Signed in as ${user.userName || user.userId} (${site.code}).`);\n return user;\n } finally {\n await server.stop();\n }\n },\n\n async logout(): Promise<boolean> {\n const stored = store.load();\n if (!stored) return false;\n const site = siteForId(stored.siteId);\n try {\n if (site) {\n await http.post(`${site.loginUrl}/${AUTH_PATHS.LOGOUT}`, {\n query: { jwtToken: stored.jwtToken },\n timeoutMs: 5_000,\n });\n }\n } catch {\n // Telling the server is best effort; clearing locally is what signs out here.\n } finally {\n store.clear();\n }\n return true;\n },\n\n async listTeams(): Promise<HuaweiTeam[]> {\n const user = await requireUser();\n const response = await http.get(AGC_TEAMS_URL, {\n headers: {\n oauth2Token: user.accessToken,\n uid: user.userId,\n source: 'cli',\n lang: HUAWEI_SITES[user.siteCode].language,\n },\n timeoutMs: 15_000,\n });\n if (response.statusCode === 401) {\n throw new OniroError('The session has expired. Run `oniro-app auth login` again.');\n }\n if (response.statusCode !== 200) {\n throw new OniroError(`Could not list AGC teams (${describeResponse(response)}).`);\n }\n return parseTeamList(response.data);\n },\n\n async resolveAgcAuth(o: { teamId?: string } = {}): Promise<AgcAuthInfo> {\n const user = await requireUser();\n // Real-name verification is not required: like DevEco Studio, an unverified\n // account — the norm outside the Chinese mainland — may sign once it has\n // accepted the developer agreement. Studio accepts it from a dialog; a CLI\n // must not accept legal terms silently, so it only checks.\n if (!user.isRealName) {\n const agreement = await getDeveloperAgreement(user);\n if (agreement && !(agreement.signed && agreement.latest)) {\n throw new OniroError(\n 'This Huawei account has not accepted the current HUAWEI Developer Basic Service Agreement, which ' +\n 'accounts without real-name verification need before AppGallery Connect issues signing material. ' +\n 'Accept it in AppGallery Connect (https://developer.huawei.com/consumer/en/service/josp/agc/index.html) ' +\n 'or by running automatic signing once in DevEco Studio, then try again.',\n );\n }\n // When the status cannot be read, AGC is the authority and refuses by itself.\n }\n return {\n uid: user.userId,\n // Personal accounts sign under their own user id; `--team-id` picks another team.\n teamId: o.teamId ?? user.userId,\n accessToken: user.accessToken,\n baseUrl: HUAWEI_SITES[user.siteCode].agcBaseUrl,\n };\n },\n };\n}\n\n/**\n * Parse the AGC team list. Failures arrive as HTTP 200 with a non-zero `ret.code`.\n *\n * @internal exposed for tests.\n */\nexport function parseTeamList(body: string): HuaweiTeam[] {\n let payload: { ret?: { code?: number; msg?: string }; teams?: unknown };\n try {\n payload = JSON.parse(body);\n } catch {\n return [];\n }\n if (payload.ret && payload.ret.code !== 0) {\n throw new OniroError(\n `AppGallery Connect refused the team list (code ${payload.ret.code}${payload.ret.msg ? `: ${payload.ret.msg}` : ''}).`,\n );\n }\n if (!Array.isArray(payload.teams)) return [];\n return payload.teams\n .map((t: { id?: unknown; name?: unknown }) => ({ id: String(t?.id ?? ''), name: String(t?.name ?? '') }))\n .filter((t) => t.id);\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/utils/http-client.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport { EnvHttpProxyAgent, fetch, type Response } from 'undici';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\n\n/**\n * Upstream's request headers, kept identical: these are private endpoints, and\n * matching the client they were built for removes one variable when they misbehave.\n */\nconst DEFAULT_HEADERS = {\n 'user-agent':\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',\n 'accept-language': 'zh-CN',\n accept: 'application/json, text/plain, */*',\n};\n\nconst DEFAULT_TIMEOUT_MS = 20_000;\n\nexport interface HttpResponse {\n /** Body as text. Several endpoints send JSON under a non-JSON content type. */\n data: string;\n statusCode: number;\n /** Reason phrase. Some AGC errors are reported only here. Empty over HTTP/2. */\n statusText: string;\n}\n\nexport interface HttpRequestOptions {\n headers?: Record<string, string>;\n query?: Record<string, unknown>;\n /** Sent as JSON. */\n body?: unknown;\n timeoutMs?: number;\n}\n\n/**\n * `get`, `post` and `delete` resolve for any HTTP status: AGC reports failures\n * through the status, the reason phrase and the body, so callers read all three.\n * `getBinary` is for downloads and rejects on a non-2xx status.\n */\nexport interface HarmonyOsHttpClient {\n get(url: string, opts?: HttpRequestOptions): Promise<HttpResponse>;\n post(url: string, opts?: HttpRequestOptions): Promise<HttpResponse>;\n delete(url: string, opts?: HttpRequestOptions): Promise<HttpResponse>;\n getBinary(url: string, opts?: HttpRequestOptions): Promise<Buffer>;\n}\n\n/** Query parameters that carry credentials for the user's Huawei account. */\nconst SENSITIVE_PARAMS = new Set(['temptoken', 'jwttoken', 'code', 'oauth2token', 'accesstoken']);\n\n/**\n * A log-safe form of a URL: credential-bearing query values become `***`.\n *\n * @internal exposed for tests.\n */\nexport function redactUrl(url: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return url;\n }\n for (const key of [...parsed.searchParams.keys()]) {\n if (SENSITIVE_PARAMS.has(key.toLowerCase())) parsed.searchParams.set(key, '***');\n }\n return parsed.toString();\n}\n\n/**\n * A short, log-safe preview of a response body. Suppressed entirely when it looks\n * like a bare JWT, so a credential cannot leak into an error message.\n *\n * @internal exposed for tests.\n */\nexport function previewBody(body: string, limit = 300): string {\n const trimmed = body.trim();\n if (!trimmed) return '(empty body)';\n if (/^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/.test(trimmed)) return '(a token-shaped value)';\n const collapsed = trimmed.replace(/\\s+/g, ' ');\n return collapsed.length > limit ? `${collapsed.slice(0, limit)}…` : collapsed;\n}\n\n/** `HTTP 500 Internal Server Error: <body preview>`, for error messages. */\nexport function describeResponse(response: HttpResponse): string {\n const status = `HTTP ${response.statusCode}${response.statusText ? ` ${response.statusText}` : ''}`;\n return `${status}: ${previewBody(response.data)}`;\n}\n\nfunction buildUrl(url: string, query?: Record<string, unknown>): string {\n if (!query) return url;\n const parsed = new URL(url);\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== null) parsed.searchParams.set(key, String(value));\n }\n return parsed.toString();\n}\n\n/** The HTTP client for the HarmonyOS auth and signing flows. */\nexport function createHttpClient(opts: { logger?: Logger } = {}): HarmonyOsHttpClient {\n const logger = opts.logger ?? noopLogger;\n // Node's own fetch ignores HTTPS_PROXY / HTTP_PROXY / NO_PROXY; this agent honours them.\n const dispatcher = new EnvHttpProxyAgent();\n\n async function send(method: string, url: string, options: HttpRequestOptions): Promise<Response> {\n const target = buildUrl(url, options.query);\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const headers: Record<string, string> = { ...DEFAULT_HEADERS, ...options.headers };\n let body: string | undefined;\n if (options.body !== undefined) {\n body = JSON.stringify(options.body);\n headers['content-type'] = 'application/json';\n }\n\n // The query string can carry credentials, so only the redacted URL is logged.\n logger.debug(`[harmonyos] ${method} ${redactUrl(target)}`);\n try {\n return await fetch(target, {\n method,\n headers,\n body,\n signal: AbortSignal.timeout(timeoutMs),\n dispatcher,\n });\n } catch (err) {\n const reason =\n err instanceof Error && err.name === 'TimeoutError'\n ? `timed out after ${timeoutMs}ms`\n : err instanceof Error\n ? err.message\n : String(err);\n throw new OniroError(\n `${method} ${redactUrl(target)} failed: ${reason}. ` +\n 'Check the network connection and any proxy configuration (HTTPS_PROXY / HTTP_PROXY).',\n err,\n );\n }\n }\n\n async function request(method: string, url: string, options: HttpRequestOptions = {}): Promise<HttpResponse> {\n const response = await send(method, url, options);\n return { data: await response.text(), statusCode: response.status, statusText: response.statusText };\n }\n\n return {\n get: (url, o) => request('GET', url, o),\n post: (url, o) => request('POST', url, o),\n delete: (url, o) => request('DELETE', url, o),\n async getBinary(url, o = {}) {\n const response = await send('GET', url, o);\n if (!response.ok) {\n throw new OniroError(`Download of ${redactUrl(response.url || url)} failed (HTTP ${response.status}).`);\n }\n return Buffer.from(await response.arrayBuffer());\n },\n };\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/auth/login/local-auth-server.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as http from 'node:http';\nimport * as crypto from 'node:crypto';\nimport type { AddressInfo } from 'node:net';\nimport { CancelledError, OniroError } from '../../ports/errors.js';\n\n/** What the login page hands back once the user has signed in. */\nexport interface LoginCallback {\n tempToken: string;\n /** The account's region; see `siteForId`. */\n siteId: string;\n}\n\nconst CALLBACK_PATH = '/callback';\nconst MAX_BODY_BYTES = 65_536;\n\nexport interface CallbackServer {\n /** Port the loopback listener bound to. Handed to the login page as `?port=`. */\n readonly port: number;\n /** Resolves with the browser's callback, including one that arrived before this was called. */\n waitForCallback(timeoutMs: number): Promise<LoginCallback>;\n stop(): Promise<void>;\n}\n\n/**\n * Constant-time compare of the `code` parameter against the secret this process\n * generated. Without it any local page could POST a token of its own choosing to\n * the loopback port while a login is in flight.\n */\nfunction codeMatches(code: string | null, secret: string): boolean {\n const a = Buffer.from(code ?? '', 'utf8');\n const b = Buffer.from(secret, 'utf8');\n return a.length === b.length && crypto.timingSafeEqual(a, b);\n}\n\nfunction isQuit(quit: string | null): boolean {\n return quit === 'true' || quit === 'access_denied' || quit === 'quit';\n}\n\nexport interface StartCallbackServerOptions {\n /** Secret echoed back by the login page; proves the callback is ours. */\n clientSecret: string;\n /** Host the browser is redirected to after the callback is handled. */\n baseUrl: string;\n successPath: string;\n failedPath: string;\n}\n\n/**\n * Start a loopback HTTP server that receives the browser's login callback.\n *\n * Bound to 127.0.0.1 on an OS-assigned port: the login page is told which port\n * to redirect to, so nothing needs to be reserved or configured.\n */\nexport async function startCallbackServer(\n opts: StartCallbackServerOptions,\n): Promise<CallbackServer> {\n // Settled by the first valid callback, whenever it arrives: the browser can come\n // back before anyone is waiting for it.\n let resolveCallback!: (value: LoginCallback) => void;\n let rejectCallback!: (reason: Error) => void;\n const callback = new Promise<LoginCallback>((resolve, reject) => {\n resolveCallback = resolve;\n rejectCallback = reject;\n });\n // A cancellation nobody waits for yet must not surface as an unhandled rejection.\n callback.catch(() => {});\n\n const server = http.createServer((req, res) => {\n // Reject requests that did not address us by our own loopback authority —\n // cheap defence against DNS-rebinding onto the callback port.\n const host = (req.headers.host ?? '').toLowerCase();\n const port = (server.address() as AddressInfo | null)?.port;\n if (host !== `127.0.0.1:${port}` && host !== `localhost:${port}`) {\n res.writeHead(400);\n res.end('Bad Host');\n return;\n }\n\n const url = new URL(req.url ?? '', `http://${host}`);\n if (url.pathname !== CALLBACK_PATH) {\n res.writeHead(404);\n res.end('Not Found');\n return;\n }\n\n const finish = (params: URLSearchParams) => {\n if (!codeMatches(params.get('code'), opts.clientSecret)) {\n res.writeHead(400);\n res.end('Bad Request');\n return;\n }\n if (isQuit(params.get('quit'))) {\n res.writeHead(302, { Location: `${opts.baseUrl}/${opts.failedPath}` });\n res.end();\n rejectCallback(new CancelledError('Login was cancelled in the browser.'));\n return;\n }\n const tempToken = params.get('tempToken');\n const siteId = params.get('siteId');\n if (!tempToken || !siteId) {\n res.writeHead(400);\n res.end('Bad Request');\n return;\n }\n res.writeHead(302, { Location: `${opts.baseUrl}/${opts.successPath}` });\n res.end();\n resolveCallback({ tempToken, siteId });\n };\n\n if (req.method === 'POST') {\n let body = '';\n let size = 0;\n req.on('data', (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_BODY_BYTES) {\n req.destroy(new Error('Request body too large'));\n return;\n }\n body += chunk.toString();\n });\n req.on('end', () => finish(body.trim() ? new URLSearchParams(body) : url.searchParams));\n } else {\n finish(url.searchParams);\n }\n });\n\n // Keep-alive would hold the process open after the single callback we care about.\n server.keepAliveTimeout = 1;\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', (err) => reject(new OniroError('Failed to start the local login callback server.', err)));\n server.listen(0, '127.0.0.1', resolve);\n });\n\n const port = (server.address() as AddressInfo).port;\n\n return {\n port,\n\n waitForCallback(timeoutMs: number): Promise<LoginCallback> {\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new OniroError(`Timed out after ${Math.round(timeoutMs / 1000)}s waiting for the browser login to complete.`)),\n timeoutMs,\n );\n });\n return Promise.race([callback, timeout]).finally(() => clearTimeout(timer));\n },\n\n stop(): Promise<void> {\n return new Promise<void>((resolve) => {\n server.closeAllConnections?.();\n // The browser may still be holding the redirect response; do not let a slow\n // client keep the CLI alive.\n const timer = setTimeout(resolve, 100);\n server.close(() => {\n clearTimeout(timer);\n resolve();\n });\n });\n },\n };\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/auth/login/browser.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport { spawn } from 'node:child_process';\nimport { OniroError } from '../../ports/errors.js';\n\nfunction isSafeUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return ['http:', 'https:'].includes(parsed.protocol) && parsed.hostname !== '' && !url.includes('\"');\n } catch {\n return false;\n }\n}\n\n/** `start` on Windows goes through cmd, where these are shell metacharacters. */\nfunction escapeForCmd(s: string): string {\n return s.replace(/[&|<>()^%!]/g, (c) => `^${c}`);\n}\n\n/**\n * Open `url` in the user's default browser. Resolves once the launcher exits\n * successfully.\n *\n * Some launchers (`xdg-open` without a desktop environment, `$BROWSER`) only exit\n * when the browser does, so callers should not wait on this before carrying on;\n * the launcher is detached so it neither keeps this process alive nor dies with it.\n * Headless environments (CI, a remote shell) have no browser to open; the caller\n * is expected to print the URL as well so the user can open it themselves.\n */\nexport function openBrowser(url: string): Promise<void> {\n if (!isSafeUrl(url)) {\n return Promise.reject(new OniroError(`Refusing to open unsafe URL: ${JSON.stringify(url)}`));\n }\n\n const [command, args] =\n process.platform === 'win32'\n ? ['cmd', ['/c', 'start', '\"\"', escapeForCmd(url)]]\n : process.platform === 'darwin'\n ? ['open', [url]]\n : ['xdg-open', [url]];\n\n const child = spawn(command as string, args as string[], {\n stdio: 'ignore',\n shell: false,\n detached: true,\n windowsHide: true,\n });\n child.unref();\n\n return new Promise<void>((resolve, reject) => {\n child.on('error', (err) => reject(new OniroError(`Failed to open a browser (${command}).`, err)));\n child.on('exit', (code) =>\n code === 0 ? resolve() : reject(new OniroError(`Browser launcher '${command}' exited with code ${code}.`)),\n );\n });\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/config/signature.ts`, `src/signature/cert-api.ts`,\n * `src/signature/device-manager.ts`, `src/signature/generate-profile.ts`),\n * Copyright (c) 2026 Huawei Device Co., Ltd., licensed under the MIT License.\n * See packages/core/src/harmonyos/NOTICE.md.\n */\nimport { OniroError } from '../../ports/errors.js';\n\n/** Raised when AppGallery Connect rejects a request, or its output does not check out. */\nexport class AgcError extends OniroError {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly retCode?: string,\n ) {\n super(message);\n this.name = 'AgcError';\n }\n}\n\n/** User-facing messages for the signing failure modes; each says what to do next. */\nexport const SIGNING_ERRORS = {\n FORBIDDEN:\n 'This account has no AppGallery Connect permission for the selected team. Ask the team administrator for access, or pass --team-id for a team you do have access to (`oniro-app auth team list`).',\n UNAUTHORIZED: 'AppGallery Connect rejected the access token. Run `oniro-app auth login` again.',\n NETWORK:\n 'Could not reach AppGallery Connect. Check the network connection and any proxy configuration (HTTPS_PROXY / HTTP_PROXY).',\n USER_NOT_HARMONY:\n 'This Huawei account is not enrolled for HarmonyOS development. Request HarmonyOS access for it in AppGallery Connect.',\n CERT_REQUEST: 'AppGallery Connect did not issue the debug certificate.',\n CERT_LIMIT:\n 'This team has reached its debug-certificate limit. Delete an unused certificate in AppGallery Connect and retry.',\n DEVICE_ADD: 'AppGallery Connect did not register the device.',\n DEVICE_LIMIT: 'This team has reached its device limit. Remove an unused device in AppGallery Connect and retry.',\n DEVICE_NAME_REPEAT: 'A device with that name is already registered. Retry.',\n DEVICE_NONE:\n 'No device is connected and none is registered to this team, but a debug profile must name at least one. Connect a device and retry.',\n PROFILE_ADD: 'AppGallery Connect did not issue the provisioning profile.',\n PROFILE_NAME_REPEAT: 'A provisioning profile with that name already exists in AppGallery Connect. Retry.',\n PROVISION_LIMIT:\n 'This team has reached its debug-profile limit. Delete unused profiles in AppGallery Connect and retry.',\n CERT_INVALID: 'AppGallery Connect returned an unreadable certificate. Retry with --force.',\n CERT_EXPIRED: 'The signing certificate is outside its validity window. Check the system clock, then retry with --force.',\n CERT_PROFILE_MISMATCH:\n 'The provisioning profile was not issued for the downloaded certificate. Retry with --force.',\n KEYSTORE_CERT_MISMATCH:\n 'The local keystore does not hold the key the downloaded certificate was issued for. Retry with --force.',\n BUNDLE_NAME_INVALID:\n 'Invalid bundle name. It must be 7–128 characters, start with a letter, and have at least three dot-separated segments (for example com.example.app).',\n} as const;\n\n/** AGC `ret.code` values that have a specific remedy. */\nconst RET_CODE_ERRORS: Readonly<Record<string, string>> = {\n '205389872': SIGNING_ERRORS.CERT_LIMIT,\n '205389904': SIGNING_ERRORS.USER_NOT_HARMONY,\n '205389859': SIGNING_ERRORS.DEVICE_LIMIT,\n '205389857': SIGNING_ERRORS.DEVICE_NAME_REPEAT,\n '205389938': SIGNING_ERRORS.PROVISION_LIMIT,\n '205389830': SIGNING_ERRORS.PROFILE_NAME_REPEAT,\n};\n\n/** Reason phrase of the 403 Huawei's proxy answers with when it blocks the caller. */\nconst PROXY_BLOCKED = 'Openproxy_Blocked_URL_list';\n\n/** The `ret` envelope around every AGC response. It is occasionally a JSON string itself. */\nexport function readRet(body: string): { code?: unknown; msg?: unknown } | null {\n try {\n let ret = (JSON.parse(body) as { ret?: unknown }).ret;\n if (typeof ret === 'string') ret = JSON.parse(ret);\n return ret && typeof ret === 'object' ? (ret as { code?: unknown; msg?: unknown }) : null;\n } catch {\n return null;\n }\n}\n\nexport type AgcOperation = 'cert' | 'device' | 'profile';\n\nconst FALLBACK: Record<AgcOperation, string> = {\n cert: SIGNING_ERRORS.CERT_REQUEST,\n device: SIGNING_ERRORS.DEVICE_ADD,\n profile: SIGNING_ERRORS.PROFILE_ADD,\n};\n\n/**\n * Map an AGC failure onto an actionable error. AGC fails through the HTTP status,\n * the reason phrase, or a non-zero `ret.code` under HTTP 200; all three are read.\n */\nexport function mapAgcError(\n operation: AgcOperation,\n statusCode: number | undefined,\n reasonPhrase: string,\n body: string,\n): AgcError {\n if (statusCode === 403) {\n return new AgcError(reasonPhrase === PROXY_BLOCKED ? SIGNING_ERRORS.NETWORK : SIGNING_ERRORS.FORBIDDEN, 403);\n }\n if (statusCode === 401) return new AgcError(SIGNING_ERRORS.UNAUTHORIZED, 401);\n\n const ret = readRet(body);\n const retCode = ret?.code === undefined ? undefined : String(ret.code);\n const msg = typeof ret?.msg === 'string' && ret.msg.trim() ? ret.msg : undefined;\n return new AgcError((retCode && RET_CODE_ERRORS[retCode]) || msg || FALLBACK[operation], statusCode, retCode);\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/signature/generate-profile.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as fs from 'node:fs';\nimport { X509Certificate } from 'node:crypto';\nimport forge from 'node-forge';\nimport { AgcError, SIGNING_ERRORS } from './errors.js';\n\n/** The fields of a provisioning profile that decide whether it can be reused. */\nexport interface ProvisionProfileInfo {\n bundleName?: string;\n /** The AGC team the profile was issued to. */\n developerId?: string;\n notAfter?: Date;\n /** Uppercased UDIDs the debug profile is valid for. */\n deviceIds: string[];\n aclPermissions: string[];\n /** PEM of the certificate the profile was issued for. */\n developmentCertificate?: string;\n}\n\n/**\n * The JSON payload of a `.p7b` profile. The file is PKCS#7 signed data carrying\n * the JSON in the clear, so it is found by scanning for the balanced object that\n * has `bundle-info` — node-forge cannot parse the EC certificates around it.\n *\n * @internal exposed for tests.\n */\nexport function extractProfileJson(buffer: Buffer): string | null {\n const text = buffer.toString('latin1');\n for (let start = text.indexOf('{'); start !== -1; start = text.indexOf('{', start + 1)) {\n let depth = 0;\n let inString = false;\n let escaped = false;\n for (let i = start; i < text.length; i++) {\n const ch = text[i]!;\n if (escaped) escaped = false;\n else if (inString) {\n if (ch === '\\\\') escaped = true;\n else if (ch === '\"') inString = false;\n } else if (ch === '\"') inString = true;\n else if (ch === '{') depth++;\n else if (ch === '}' && --depth === 0) {\n // The payload is UTF-8; re-decode so non-ASCII survives.\n const json = Buffer.from(text.slice(start, i + 1), 'latin1').toString('utf8');\n try {\n if ('bundle-info' in (JSON.parse(json) as object)) return json;\n } catch {\n // Some other brace pair in the binary framing; keep scanning.\n }\n break;\n }\n }\n }\n return null;\n}\n\n/** Read a `.p7b` profile; null when it is missing or unreadable, which means \"regenerate\". */\nexport function readProvisionProfile(profilePath: string): ProvisionProfileInfo | null {\n let raw: {\n validity?: { 'not-after'?: unknown };\n 'bundle-info'?: { 'bundle-name'?: unknown; 'developer-id'?: unknown; 'development-certificate'?: unknown };\n 'debug-info'?: { 'device-ids'?: unknown };\n acls?: { 'allowed-acls'?: unknown };\n };\n try {\n const json = extractProfileJson(fs.readFileSync(profilePath));\n if (!json) return null;\n raw = JSON.parse(json);\n } catch {\n return null;\n }\n const str = (v: unknown) => (typeof v === 'string' ? v : undefined);\n const strings = (v: unknown) => (Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : []);\n const notAfter = raw.validity?.['not-after'];\n const bundle = raw['bundle-info'] ?? {};\n return {\n bundleName: str(bundle['bundle-name']),\n developerId: str(bundle['developer-id']),\n // Epoch seconds.\n notAfter: typeof notAfter === 'number' ? new Date(notAfter * 1000) : undefined,\n deviceIds: strings(raw['debug-info']?.['device-ids']).map((d) => d.toUpperCase()),\n aclPermissions: strings(raw.acls?.['allowed-acls']),\n developmentCertificate: str(bundle['development-certificate']),\n };\n}\n\nfunction parseCertificate(pem: string): X509Certificate {\n try {\n return new X509Certificate(pem);\n } catch {\n throw new AgcError(SIGNING_ERRORS.CERT_INVALID);\n }\n}\n\n/**\n * Whether the p12 holds the key `certificate` certifies, by comparing public keys.\n *\n * node-forge reads the PKCS#12 container, which Node cannot. Not the certificate\n * inside it, though: forge parses only RSA certificates, and hap-sign-tool makes\n * ECC keys, so forge hands back the raw ASN.1 for Node's X.509 parser. Any read\n * failure, a wrong password included, is \"no\".\n *\n * @internal exposed for tests.\n */\nexport function keystoreHoldsKey(\n p12Path: string,\n keyAlias: string,\n keyPwd: string,\n certificate: X509Certificate,\n): boolean {\n try {\n const der = forge.util.createBuffer(fs.readFileSync(p12Path).toString('binary'));\n const p12 = forge.pkcs12.pkcs12FromAsn1(forge.asn1.fromDer(der), keyPwd);\n const certBag = forge.pki.oids.certBag ?? '1.2.840.113549.1.12.10.1.3';\n const wanted = certificate.publicKey.export({ type: 'spki', format: 'der' });\n return (p12.getBags({ bagType: certBag })[certBag] ?? []).some((bag) => {\n if (bag.attributes?.friendlyName?.[0]?.toLowerCase() !== keyAlias.toLowerCase()) return false;\n const asn1 = bag.cert ? forge.pki.certificateToAsn1(bag.cert) : bag.asn1;\n if (!asn1) return false;\n const bagCert = new X509Certificate(Buffer.from(forge.asn1.toDer(asn1).getBytes(), 'binary'));\n return bagCert.publicKey.export({ type: 'spki', format: 'der' }).equals(wanted);\n });\n } catch {\n return false;\n }\n}\n\n/**\n * Check that the downloaded certificate chain is in date, that the profile was\n * issued for its leaf certificate, and that the keystore holds the certified key.\n * A mismatch here would otherwise surface much later, as an install failure.\n */\nexport function verifySigningMaterial(opts: {\n profilePath: string;\n cerPath: string;\n p12Path: string;\n keyAlias: string;\n keyPwd: string;\n now?: Date;\n}): void {\n const pems = fs.readFileSync(opts.cerPath, 'utf8').match(/-----BEGIN CERTIFICATE-----[\\s\\S]*?-----END CERTIFICATE-----/g);\n const chain = (pems ?? []).map(parseCertificate);\n const leaf = chain.find((c) => !c.ca) ?? chain.at(-1);\n if (!leaf) throw new AgcError(SIGNING_ERRORS.CERT_INVALID);\n\n const now = opts.now ?? new Date();\n if (chain.some((c) => now < new Date(c.validFrom) || now > new Date(c.validTo))) {\n throw new AgcError(SIGNING_ERRORS.CERT_EXPIRED);\n }\n\n const issuedFor = readProvisionProfile(opts.profilePath)?.developmentCertificate;\n if (!issuedFor || parseCertificate(issuedFor).fingerprint256 !== leaf.fingerprint256) {\n throw new AgcError(SIGNING_ERRORS.CERT_PROFILE_MISMATCH);\n }\n if (!keystoreHoldsKey(opts.p12Path, opts.keyAlias, opts.keyPwd, leaf)) {\n throw new AgcError(SIGNING_ERRORS.KEYSTORE_CERT_MISMATCH);\n }\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/commands/signature.ts`, `src/signature/generate-certificate.ts`,\n * `src/signature/re-generate-sign.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport JSON5 from 'json5';\nimport type { ConfigProvider } from '../../ports/config.js';\nimport type { Logger } from '../../ports/logger.js';\nimport { noopLogger } from '../../ports/logger.js';\nimport { OniroError } from '../../ports/errors.js';\nimport { createMaterial, encryptPwd, getKey } from '../../sign/encryptKey.js';\nimport { getBundleName } from '../../hdc/project.js';\nimport { isValidBundleName } from '../../project/validators.js';\nimport { createHttpClient, type HarmonyOsHttpClient } from '../http.js';\nimport { requireHarmonyOsSdk } from '../sdk.js';\nimport type { HarmonyOsSession } from '../auth/session.js';\nimport { createAgcClient } from './agc.js';\nimport { collectLocalDevices, registerDevices } from './devices.js';\nimport { AgcError, SIGNING_ERRORS } from './errors.js';\nimport { KEY_ALIAS, SIGN_ALG, generateKeystoreAndCsr } from './keystore.js';\nimport { resolveSigningMaterialPaths, type SigningMaterialPaths } from './paths.js';\nimport { readProvisionProfile, verifySigningMaterial } from './profile.js';\nimport { collectAclPermissions } from './project.js';\n\ninterface BuildProfile {\n app?: {\n signingConfigs?: Array<{ name?: string; type?: string; material?: Record<string, string> }>;\n products?: Array<{ name?: string; signingConfig?: string; bundleName?: string }>;\n };\n}\n\n/**\n * Why the existing material cannot be reused, or null when it can. Reuse matters:\n * every regeneration spends a slot of the team's small certificate quota.\n *\n * @internal exposed for tests.\n */\nexport function shouldRegenerate(input: {\n paths: SigningMaterialPaths;\n buildProfile: BuildProfile;\n productName: string;\n bundleName: string;\n teamId: string;\n connectedUdids: string[];\n aclPermissions: string[];\n force?: boolean;\n now?: Date;\n}): string | null {\n if (input.force) return '--force was passed';\n const missing = Object.values(input.paths).find((file) => !fs.existsSync(file));\n if (missing) return `${missing} is missing`;\n\n // The keystore password only exists, encrypted, in the project's signingConfig; a\n // fresh checkout reusing the material from ~/.ohos/config cannot recover it.\n const config = input.buildProfile.app?.signingConfigs?.find((c) => c.name === input.productName);\n if (config?.type !== 'HarmonyOS' || config.material?.profile !== input.paths.profilePath) {\n return 'build-profile.json5 has no signingConfig for this material';\n }\n\n const profile = readProvisionProfile(input.paths.profilePath);\n if (!profile) return 'the provisioning profile could not be read';\n if (profile.bundleName !== input.bundleName) return `the profile is for bundle '${profile.bundleName}'`;\n if (profile.developerId && profile.developerId !== input.teamId) {\n return `the profile was issued to team '${profile.developerId}'`;\n }\n if (profile.notAfter && profile.notAfter <= (input.now ?? new Date())) return 'the profile has expired';\n const unnamed = input.connectedUdids.filter((udid) => !profile.deviceIds.includes(udid.toUpperCase()));\n if (unnamed.length > 0) return `${unnamed.length} connected device(s) are not named in the profile`;\n const acls = input.aclPermissions.filter((p) => !profile.aclPermissions.includes(p));\n if (acls.length > 0) return `the profile lacks ACL permission(s) ${acls.join(', ')}`;\n return null;\n}\n\n/**\n * Point `productName` at a HarmonyOS signingConfig for `paths`, replacing any config\n * of that name and leaving every other one alone. The keystore and key share one\n * password, so one ciphertext serves both.\n *\n * @internal exposed for tests.\n */\nexport function writeSigningConfig(opts: {\n buildProfilePath: string;\n buildProfile: BuildProfile;\n productName: string;\n paths: SigningMaterialPaths;\n encryptedPassword: string;\n}): void {\n const app = (opts.buildProfile.app ??= {});\n const entry = {\n name: opts.productName,\n // `type` is what makes hvigor treat this as HarmonyOS signing material.\n type: 'HarmonyOS',\n material: {\n certpath: opts.paths.cerPath,\n keyAlias: KEY_ALIAS,\n keyPassword: opts.encryptedPassword,\n profile: opts.paths.profilePath,\n signAlg: SIGN_ALG,\n storeFile: opts.paths.p12Path,\n storePassword: opts.encryptedPassword,\n },\n };\n app.signingConfigs = [...(app.signingConfigs ?? []).filter((c) => c.name !== opts.productName), entry];\n for (const product of app.products ?? []) {\n if (product.name === opts.productName) product.signingConfig = opts.productName;\n }\n // Strict JSON, like the OpenHarmony signing path: still valid JSON5.\n fs.writeFileSync(opts.buildProfilePath, JSON.stringify(opts.buildProfile, null, 2));\n}\n\nexport interface HarmonyOsAutoSignOptions {\n config: ConfigProvider;\n session: HarmonyOsSession;\n projectDir: string;\n /** Default `default`. */\n productName?: string;\n /** AGC team. Defaults to the signed-in account's own id. */\n teamId?: string;\n /** Regenerate even when the existing material is still valid. */\n force?: boolean;\n http?: HarmonyOsHttpClient;\n logger?: Logger;\n}\n\nexport interface HarmonyOsSigningResult {\n bundleName: string;\n teamId: string;\n paths: SigningMaterialPaths;\n /** False when still-valid material was reused without asking AGC for anything. */\n regenerated: boolean;\n /** UDIDs the profile is valid for. */\n deviceIds: string[];\n}\n\n/**\n * Sign a HarmonyOS project with the signed-in Huawei developer account, the way\n * DevEco Studio's automatic signing does: generate a keystore and CSR, have AGC\n * issue a debug certificate, register connected devices, issue a debug profile\n * naming the team's devices, and write the encrypted signingConfig.\n */\nexport async function harmonyOsAutoSign(opts: HarmonyOsAutoSignOptions): Promise<HarmonyOsSigningResult> {\n const logger = opts.logger ?? noopLogger;\n const productName = opts.productName ?? 'default';\n const projectDir = path.resolve(opts.projectDir);\n const buildProfilePath = path.join(projectDir, 'build-profile.json5');\n\n let buildProfile: BuildProfile;\n try {\n buildProfile = JSON5.parse(fs.readFileSync(buildProfilePath, 'utf-8')) as BuildProfile;\n } catch (err) {\n throw new OniroError(`Could not read ${buildProfilePath}: ${(err as Error).message}`, err);\n }\n const product = buildProfile.app?.products?.find((p) => p.name === productName);\n if (!product) throw new OniroError(`${buildProfilePath} declares no product named '${productName}'.`);\n // A product may override the app's bundle name. Validated before anything reaches\n // AGC, so a bad name costs no certificate.\n const bundleName = product.bundleName || getBundleName(projectDir);\n if (!isValidBundleName(bundleName) || bundleName.split('.').length < 3 || bundleName.length < 7 || bundleName.length > 128) {\n throw new AgcError(SIGNING_ERRORS.BUNDLE_NAME_INVALID);\n }\n\n const sdk = requireHarmonyOsSdk({ config: opts.config, logger });\n const auth = await opts.session.resolveAgcAuth({ teamId: opts.teamId });\n const aclPermissions = collectAclPermissions(projectDir, logger);\n const paths = resolveSigningMaterialPaths(opts.config, productName, projectDir);\n logger.info(`[harmonyos] Signing ${bundleName} (product '${productName}', team ${auth.teamId}).`);\n\n const connected = await collectLocalDevices(opts.config, logger);\n const result = (regenerated: boolean): HarmonyOsSigningResult => ({\n bundleName,\n teamId: auth.teamId,\n paths,\n regenerated,\n deviceIds: readProvisionProfile(paths.profilePath)?.deviceIds ?? [],\n });\n\n const reason = shouldRegenerate({\n paths,\n buildProfile,\n productName,\n bundleName,\n teamId: auth.teamId,\n connectedUdids: connected.map((d) => d.udid),\n aclPermissions,\n force: opts.force,\n });\n if (!reason) {\n logger.info('[harmonyos] Reusing the existing signing material, which is still valid.');\n return result(false);\n }\n logger.info(`[harmonyos] Regenerating signing material: ${reason}.`);\n\n // Before anything is deleted: a profile must name at least one device.\n const agc = createAgcClient(opts.http ?? createHttpClient({ logger }), auth);\n const deviceIds = await registerDevices(agc, connected, logger);\n for (const file of Object.values(paths)) fs.rmSync(file, { force: true });\n\n // AGC will not issue a second certificate under one name, so ours is replaced.\n // The name is oniro-app's own: upstream uses DevEco Studio's `auto_debug_`, and\n // replacing that certificate would revoke the material Studio signs with.\n const certName = `oniro_debug_${auth.teamId.replace(/[\\\\/.:]/g, '')}.cer`;\n const stale = (await agc.listCertificates()).find((c) => c.certName === certName);\n if (stale) {\n logger.info(`[harmonyos] Replacing the previous '${certName}' certificate in AppGallery Connect...`);\n await agc.deleteCertificate(stale.id);\n }\n\n const { keyPwd, csr } = await generateKeystoreAndCsr({ sdk, p12Path: paths.p12Path, csrPath: paths.csrPath, logger });\n logger.info('[harmonyos] Requesting a debug certificate from AppGallery Connect...');\n await agc.addCertificate(certName, csr);\n const cert = (await agc.listCertificates()).find((c) => c.certName === certName);\n if (!cert) throw new AgcError(SIGNING_ERRORS.CERT_REQUEST);\n await agc.download('cert', cert.certObjectId, paths.cerPath);\n\n logger.info('[harmonyos] Issuing the debug provisioning profile...');\n const profile = await agc.addDebugProfile({\n provisionName: `oniro_${crypto.randomBytes(6).toString('hex')}`,\n bundleName,\n certId: cert.id,\n deviceIds,\n aclPermissions,\n });\n try {\n await agc.download('profile', profile.provisionFileUrl, paths.profilePath);\n } finally {\n // The file is what the build needs; the AGC record would only use up the team's quota.\n await agc.deleteProfile(profile.id).catch((err: Error) => {\n logger.debug(`[harmonyos] Could not delete profile ${profile.id} from AppGallery Connect: ${err.message}`);\n });\n }\n try {\n verifySigningMaterial({ ...paths, keyAlias: KEY_ALIAS, keyPwd });\n } catch (err) {\n fs.rmSync(paths.profilePath, { force: true });\n throw err;\n }\n\n // The OpenHarmony signing path's encryption, with its material next to the keystores.\n // Shared by every project there, so existing material is kept.\n const materialDir = path.join(path.dirname(paths.p12Path), 'material');\n try {\n getKey(materialDir);\n } catch {\n createMaterial(materialDir);\n }\n writeSigningConfig({ buildProfilePath, buildProfile, productName, paths, encryptedPassword: encryptPwd(keyPwd, materialDir) });\n logger.info(`[harmonyos] Wrote signingConfigs['${productName}'] to ${buildProfilePath}.`);\n return result(true);\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/signature/cert-api.ts`, `src/signature/device-manager.ts`,\n * `src/signature/generate-profile.ts`, `src/signature/download.ts`),\n * Copyright (c) 2026 Huawei Device Co., Ltd., licensed under the MIT License.\n * See packages/core/src/harmonyos/NOTICE.md.\n *\n * These are private, undocumented AppGallery Connect endpoints.\n */\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { ChecksumMismatchError } from '../../ports/errors.js';\nimport type { AgcAuthInfo } from '../auth/types.js';\nimport type { HarmonyOsHttpClient, HttpRequestOptions } from '../http.js';\nimport { mapAgcError, readRet, type AgcOperation } from './errors.js';\n\nconst ENDPOINTS = {\n CERT_LIST: '/api/cps/harmony-cert-manage/v1/cert/list',\n CERT_ADD: '/api/cps/harmony-cert-manage/v1/cert/add',\n CERT_DELETE: '/api/cps/harmony-cert-manage/v1/cert/delete',\n /** Exchanges an object id for a short-lived signed download URL. */\n OBJECT_URL: '/api/amis/app-manage/v1/objects/url/reapply',\n DEVICE_LIST: '/api/cps/device-manage/v1/device/list',\n DEVICE_ADD: '/api/cps/device-manage/v1/device/add',\n /** Debug (\"test\") provisioning profiles — the only kind oniro-app issues. */\n PROVISION_ADD: '/api/cps/provision-manage/v1/ide/test/provision/add',\n PROVISION_DELETE: '/api/cps/provision-manage/v1/provision/delete',\n} as const;\n\n/** AGC device-type codes, by the device kind `hdc` reports. */\nconst DEVICE_TYPE_CODES: Record<string, number> = { liteWearable: 1, wearable: 2, tv: 3, phone: 4 };\n\nexport interface AgcCertificate {\n id: string;\n certName: string;\n /** Object-store handle, exchanged for a download URL. */\n certObjectId: string;\n}\n\nexport interface AgcDevice {\n id: string;\n udid: string;\n}\n\nexport type AgcClient = ReturnType<typeof createAgcClient>;\n\n/** The AppGallery Connect signing endpoints, bound to one account and team. */\nexport function createAgcClient(http: HarmonyOsHttpClient, auth: AgcAuthInfo) {\n /** Call an endpoint and return its body; any failure form becomes an AgcError. */\n async function call<T>(\n operation: AgcOperation,\n method: 'get' | 'post' | 'delete',\n endpoint: string,\n opts: Omit<HttpRequestOptions, 'headers'> = {},\n ): Promise<T> {\n const response = await http[method](`${auth.baseUrl}${endpoint}`, {\n ...opts,\n headers: { uid: auth.uid, teamId: auth.teamId, oauth2Token: auth.accessToken },\n });\n if (response.statusCode !== 200 || readRet(response.data)?.code !== 0) {\n throw mapAgcError(operation, response.statusCode, response.statusText, response.data);\n }\n return JSON.parse(response.data) as T;\n }\n\n return {\n async listCertificates(): Promise<AgcCertificate[]> {\n return (await call<{ certList?: AgcCertificate[] }>('cert', 'post', ENDPOINTS.CERT_LIST)).certList ?? [];\n },\n\n async addCertificate(certName: string, csr: string): Promise<void> {\n // certType 1 is a debug certificate.\n await call('cert', 'post', ENDPOINTS.CERT_ADD, { body: { csr, certName, certType: '1' } });\n },\n\n async deleteCertificate(certId: string): Promise<void> {\n await call('cert', 'delete', ENDPOINTS.CERT_DELETE, { body: { certIds: [certId] } });\n },\n\n /** Every device registered to the team, across pages. */\n async listDevices(): Promise<AgcDevice[]> {\n const pageSize = 100;\n const devices: AgcDevice[] = [];\n for (let start = 1; ; start++) {\n const page = await call<{ list?: AgcDevice[]; totalCount?: number }>('device', 'get', ENDPOINTS.DEVICE_LIST, {\n query: { encodeFlag: 0, start, pageSize },\n });\n devices.push(...(page.list ?? []));\n if (!page.list?.length || devices.length >= (page.totalCount ?? 0)) return devices;\n }\n },\n\n async addDevice(udid: string, deviceKind: string): Promise<void> {\n // AGC rejects duplicate device names, so the name is made unique.\n const deviceName = `oniro_app_device_${crypto.randomBytes(4).toString('hex')}`;\n await call('device', 'post', ENDPOINTS.DEVICE_ADD, {\n body: { deviceName, udid, deviceType: String(DEVICE_TYPE_CODES[deviceKind] ?? DEVICE_TYPE_CODES.phone) },\n });\n },\n\n /** Issue a debug profile; returns its id and object handle. */\n async addDebugProfile(opts: {\n provisionName: string;\n bundleName: string;\n certId: string;\n deviceIds: string[];\n aclPermissions: string[];\n }): Promise<{ id: string; provisionFileUrl: string }> {\n return call('profile', 'post', ENDPOINTS.PROVISION_ADD, {\n body: {\n provisionName: opts.provisionName,\n packageName: opts.bundleName,\n certList: [opts.certId],\n deviceList: opts.deviceIds,\n ...(opts.aclPermissions.length ? { aclPermissionList: opts.aclPermissions } : {}),\n },\n });\n },\n\n async deleteProfile(id: string): Promise<void> {\n await call('profile', 'delete', ENDPOINTS.PROVISION_DELETE, { query: { id } });\n },\n\n /**\n * Download a certificate or profile object to `dest`, checking the digest AGC\n * supplies with the URL. Nothing is written unless it matches.\n */\n async download(operation: AgcOperation, objectId: string, dest: string): Promise<void> {\n const { urlsInfo } = await call<{ urlsInfo?: Array<{ newUrl: string; sha256: string }> }>(\n operation,\n 'post',\n ENDPOINTS.OBJECT_URL,\n { body: { sourceUrls: objectId } },\n );\n const target = urlsInfo?.[0];\n if (!target) throw mapAgcError(operation, 200, '', '');\n\n const buffer = await http.getBinary(target.newUrl, { timeoutMs: 60_000 });\n const actual = crypto.createHash('sha256').update(buffer).digest('hex');\n if (target.sha256 && actual !== target.sha256.toLowerCase()) {\n throw new ChecksumMismatchError(target.sha256, actual);\n }\n fs.mkdirSync(path.dirname(dest), { recursive: true, mode: 0o700 });\n fs.writeFileSync(dest, buffer, { mode: 0o600 });\n },\n };\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/signature/device-manager.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport type { ConfigProvider } from '../../ports/config.js';\nimport type { Logger } from '../../ports/logger.js';\nimport { hdcExec } from '../../hdc/exec.js';\nimport { listDevices } from '../../hdc/devices.js';\nimport type { AgcClient } from './agc.js';\nimport { AgcError, SIGNING_ERRORS } from './errors.js';\n\n/**\n * The 64-hex UDID from `bm get -u` output, uppercased, or '' when there is none.\n * The wording around it varies by release, so any 64-hex token is accepted.\n *\n * @internal exposed for tests.\n */\nexport function parseUdid(stdout: string): string {\n return stdout.match(/\\b[A-Fa-f0-9]{64}\\b/)?.[0].toUpperCase() ?? '';\n}\n\n/**\n * The AGC device kind for a `hw_sc.build.os.deviceType` value. Anything else,\n * including an inaccessible property, is a phone.\n *\n * @internal exposed for tests.\n */\nexport function parseDeviceKind(stdout: string): string {\n return ['liteWearable', 'wearable', 'tv'].find((kind) => stdout.includes(kind)) ?? 'phone';\n}\n\nexport interface LocalDevice {\n serial: string;\n /** Uppercased. */\n udid: string;\n kind: string;\n}\n\n/** UDID and kind of every connected device; one that will not answer is skipped. */\nexport async function collectLocalDevices(config: ConfigProvider, logger: Logger): Promise<LocalDevice[]> {\n const devices: LocalDevice[] = [];\n for (const target of await listDevices(config, { logger, timeoutMs: 15_000 })) {\n if (target.status !== 'Connected') continue;\n const shell = async (...args: string[]) =>\n (await hdcExec({ config, deviceSerial: target.serial, args: ['shell', ...args], timeoutMs: 15_000, logger }))\n .stdout;\n try {\n const udid = parseUdid(await shell('bm', 'get', '-u'));\n if (!udid) {\n logger.warn(`[harmonyos] ${target.serial} did not report a UDID; skipping it.`);\n continue;\n }\n devices.push({ serial: target.serial, udid, kind: parseDeviceKind(await shell('getprop', 'hw_sc.build.os.deviceType')) });\n } catch (err) {\n logger.warn(`[harmonyos] Could not read ${target.serial}: ${(err as Error).message}`);\n }\n }\n return devices;\n}\n\n/**\n * Register the connected devices the team does not know yet, and return the ids of\n * every device registered to the team.\n *\n * The profile names every registered device, not only the connected ones, so it\n * stays valid across devices — and no device needs to be connected at all once the\n * team has some registered (from another machine, or by DevEco Studio).\n */\nexport async function registerDevices(agc: AgcClient, connected: LocalDevice[], logger: Logger): Promise<string[]> {\n let devices = await agc.listDevices();\n const registered = new Set(devices.map((d) => d.udid.toUpperCase()));\n\n const unregistered = connected.filter((d) => !registered.has(d.udid));\n for (const device of unregistered) {\n logger.info(`[harmonyos] Registering ${device.serial} with AppGallery Connect...`);\n await agc.addDevice(device.udid, device.kind);\n }\n if (unregistered.length > 0) devices = await agc.listDevices();\n\n const deviceIds = devices.map((d) => d.id);\n if (deviceIds.length === 0) throw new AgcError(SIGNING_ERRORS.DEVICE_NONE);\n if (connected.length === 0) {\n logger.warn(\n `[harmonyos] No device is connected; the profile will name the ${deviceIds.length} device(s) already registered to this team.`,\n );\n }\n return deviceIds;\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/signature/signature-tool.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Logger } from '../../ports/logger.js';\nimport { OniroError } from '../../ports/errors.js';\nimport { runProcess } from '../../hdc/exec.js';\nimport type { HarmonyOsSdk } from '../sdk.js';\nimport { findJava } from '../java.js';\n\n/** Alias of the key pair inside the generated p12. */\nexport const KEY_ALIAS = 'debugKey';\nexport const SIGN_ALG = 'SHA256withECDSA';\n\n/**\n * hap-sign-tool argv with password values masked, for logging.\n *\n * @internal exposed for tests.\n */\nexport function redactArgs(args: readonly string[]): string[] {\n return args.map((arg, i) => (args[i - 1] === '-keyPwd' || args[i - 1] === '-keystorePwd' ? '******' : arg));\n}\n\n/**\n * Generate the local p12 keystore and the CSR AGC turns into a certificate.\n * Returns the random keystore password in the clear; the caller encrypts it\n * before it reaches `build-profile.json5`, and it is never logged.\n */\nexport async function generateKeystoreAndCsr(opts: {\n sdk: HarmonyOsSdk;\n p12Path: string;\n csrPath: string;\n logger: Logger;\n}): Promise<{ keyPwd: string; csr: string }> {\n const jar = path.join(opts.sdk.sdkPath, 'default', 'openharmony', 'toolchains', 'lib', 'hap-sign-tool.jar');\n if (!fs.existsSync(jar)) {\n throw new OniroError(`hap-sign-tool.jar not found at ${jar}; the HarmonyOS SDK looks incomplete.`);\n }\n const java = findJava(opts.sdk);\n const keyPwd = crypto.randomBytes(12).toString('base64url').replaceAll(/[-_]/g, '');\n fs.mkdirSync(path.dirname(opts.p12Path), { recursive: true, mode: 0o700 });\n\n const run = async (what: string, args: string[]) => {\n const argv = ['-jar', jar, ...args, '-keyAlias', KEY_ALIAS, '-keystoreFile', opts.p12Path, '-keystorePwd', keyPwd, '-keyPwd', keyPwd];\n opts.logger.debug(`[harmonyos] ${java} ${redactArgs(argv).join(' ')}`);\n const result = await runProcess({ command: java, args: argv, timeoutMs: 120_000, logger: opts.logger });\n if (result.code !== 0) {\n const detail = (result.stderr || result.stdout || '').trim();\n throw new OniroError(`hap-sign-tool failed to ${what} (exit ${result.code}).${detail ? `\\n${detail}` : ''}`);\n }\n };\n\n opts.logger.info('[harmonyos] Generating the local keystore and certificate signing request...');\n await run('generate the key pair', ['generate-keypair', '-keyAlg', 'ECC', '-keySize', 'NIST-P-256']);\n await run('generate the CSR', ['generate-csr', '-subject', 'CN=DebugKey', '-signAlg', SIGN_ALG, '-outFile', opts.csrPath]);\n return { keyPwd, csr: fs.readFileSync(opts.csrPath, 'utf8') };\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { OniroError } from '../ports/errors.js';\nimport type { HarmonyOsSdk } from './sdk.js';\n\nconst JAVA_BIN = process.platform === 'win32' ? 'java.exe' : 'java';\n\n/**\n * Locate a Java runtime for `hap-sign-tool.jar`: `JAVA_HOME`, then the JetBrains\n * Runtime DevEco Studio bundles (so Studio users need no separate JDK), then `PATH`.\n */\nexport function findJava(sdk?: HarmonyOsSdk, env: NodeJS.ProcessEnv = process.env): string {\n const candidates = [\n env.JAVA_HOME && path.join(env.JAVA_HOME, 'bin', JAVA_BIN),\n sdk && path.join(sdk.installRoot, 'jbr', 'bin', JAVA_BIN),\n // macOS: the JBR is itself a bundle inside Studio's Contents.\n sdk && path.join(sdk.installRoot, 'jbr', 'Contents', 'Home', 'bin', JAVA_BIN),\n ...(env.PATH ?? '').split(path.delimiter).map((dir) => dir && path.join(dir, JAVA_BIN)),\n ];\n const found = candidates.find((c): c is string => !!c && fs.existsSync(c));\n if (found) return found;\n throw new OniroError(\n 'No Java runtime found. HarmonyOS signing runs the SDK\\'s hap-sign-tool.jar, which needs one: ' +\n 'install a JDK and set JAVA_HOME, or install DevEco Studio, whose bundled runtime is used automatically.',\n );\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/signature/signature-tool.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as crypto from 'node:crypto';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../../ports/config.js';\nimport { defaultPaths } from '../../ports/config.js';\n\n/** The four files of a HarmonyOS signing setup. */\nexport interface SigningMaterialPaths {\n p12Path: string;\n csrPath: string;\n cerPath: string;\n profilePath: string;\n}\n\n/** @internal exposed for tests. */\nexport function sanitizeNamePart(raw?: string): string {\n const safe = (raw?.trim() ?? '').replace(/[\\\\/:*?\"<>|=.-]+/g, '_');\n return safe.slice(0, 64) || 'default';\n}\n\n/**\n * Where the material for a (product, project) pair lives: `harmonyosSigningDir`\n * (default `~/.ohos/config`, as DevEco Studio uses), named after Studio's pattern.\n * Keyed by project *path*, so two checkouts of one app never share a keystore.\n */\nexport function resolveSigningMaterialPaths(\n config: ConfigProvider,\n productName: string | undefined,\n projectRoot: string,\n): SigningMaterialPaths {\n const hash = crypto.createHash('sha256').update(projectRoot, 'utf8').digest('base64url').replaceAll(/[-_]/g, '');\n const base = path.join(\n config.get('harmonyosSigningDir', defaultPaths.harmonyosSigningDir()),\n `${sanitizeNamePart(productName)}_${path.basename(projectRoot)}_${hash}=`,\n );\n return { p12Path: `${base}.p12`, csrPath: `${base}.csr`, cerPath: `${base}.cer`, profilePath: `${base}.p7b` };\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport JSON5 from 'json5';\nimport type { Logger } from '../../ports/logger.js';\nimport { noopLogger } from '../../ports/logger.js';\nimport { listModules } from '../../project/listModules.js';\nimport { ACL_PERMISSIONS } from './aclPermissionList.js';\n\n/** Read `requestPermissions[].name` out of one module config, if present. */\nfunction readRequestedPermissions(moduleConfigPath: string): string[] {\n if (!fs.existsSync(moduleConfigPath)) return [];\n try {\n const parsed = JSON5.parse(fs.readFileSync(moduleConfigPath, 'utf-8')) as {\n module?: { requestPermissions?: Array<{ name?: unknown }> };\n };\n return (parsed.module?.requestPermissions ?? [])\n .map((p) => p?.name)\n .filter((n): n is string => typeof n === 'string' && n.length > 0);\n } catch {\n return [];\n }\n}\n\n/**\n * Collect the ACL-gated permissions the project requests.\n *\n * These must be named in the provisioning profile or the HAP is refused at install\n * time. Both `src/main` and `src/ohosTest` are scanned, since a test module's\n * permissions are equally gated.\n */\nexport function collectAclPermissions(\n projectDir: string,\n logger: Logger = noopLogger,\n): string[] {\n const requested = new Set<string>();\n\n for (const module of listModules({ projectDir })) {\n const moduleRoot = path.resolve(projectDir, module.srcPath);\n for (const sourceSet of ['main', 'ohosTest']) {\n for (const name of readRequestedPermissions(\n path.join(moduleRoot, 'src', sourceSet, 'module.json5'),\n )) {\n requested.add(name);\n }\n }\n }\n\n const acls = [...requested].filter((p) => ACL_PERMISSIONS.has(p)).sort();\n if (acls.length > 0) {\n logger.info(`[harmonyos] Project requests ${acls.length} ACL permission(s): ${acls.join(', ')}`);\n }\n return acls;\n}\n","/*\n * The permission list below is data from openharmony-sig/deveco-cli\n * (`src/resources/aclPermission/aclPermissionsInfo.json`), Copyright (c) 2026\n * Huawei Device Co., Ltd., licensed under the MIT License.\n * See packages/core/src/harmonyos/NOTICE.md.\n */\n\n/**\n * HarmonyOS permissions that are ACL-gated: an app requesting one needs it listed\n * in its provisioning profile, or installation is refused on-device.\n */\nexport const ACL_PERMISSIONS: ReadonlySet<string> = new Set([\n 'ohos.permission.ACCESS_DDK_HID',\n 'ohos.permission.ACCESS_DDK_SCSI_PERIPHERAL',\n 'ohos.permission.ACCESS_DDK_USB',\n 'ohos.permission.ACCESS_DDK_USB_SERIAL',\n 'ohos.permission.ACCESS_DISK_PHY_INFO',\n 'ohos.permission.ACCESS_FIDO2_ONLINEAUTH',\n 'ohos.permission.ACCESS_NET_TRACE_INFO',\n 'ohos.permission.ACCESS_USER_FULL_DISK',\n 'ohos.permission.ACCESS_VIRTUAL_SCREEN',\n 'ohos.permission.CUSTOMIZE_SAVE_BUTTON',\n 'ohos.permission.CUSTOM_SCREEN_RECORDING',\n 'ohos.permission.DLP_GET_HIDE_STATUS',\n 'ohos.permission.FILE_ACCESS_PERSIST',\n 'ohos.permission.GET_ABILITY_INFO',\n 'ohos.permission.GET_ETHERNET_LOCAL_MAC',\n 'ohos.permission.GET_IP_MAC_INFO',\n 'ohos.permission.GET_WIFI_LOCAL_MAC',\n 'ohos.permission.GET_WIFI_PEERS_MAC',\n 'ohos.permission.HOOK_KEY_EVENT',\n 'ohos.permission.INPUT_MONITORING',\n 'ohos.permission.INTERCEPT_INPUT_EVENT',\n 'ohos.permission.KEEP_BACKGROUND_RUNNING_SYSTEM',\n 'ohos.permission.LINKTURBO',\n 'ohos.permission.MANAGE_APN_SETTING',\n 'ohos.permission.MANAGE_PASTEBOARD_APP_SHARE_OPTION',\n 'ohos.permission.MANAGE_SCREEN_TIME_GUARD',\n 'ohos.permission.MANAGE_UDMF_APP_SHARE_OPTION',\n 'ohos.permission.PERSISTENT_BLUETOOTH_PEERS_MAC',\n 'ohos.permission.PERSONAL_MANAGE_RESTRICTIONS',\n 'ohos.permission.PRELOAD_FILE',\n 'ohos.permission.READ_AUDIO',\n 'ohos.permission.READ_CONTACTS',\n 'ohos.permission.READ_IMAGEVIDEO',\n 'ohos.permission.READ_LOCAL_DEVICE_NAME',\n 'ohos.permission.READ_PASTEBOARD',\n 'ohos.permission.READ_WRITE_DESKTOP_DIRECTORY',\n 'ohos.permission.READ_WRITE_DOCUMENTS_DIRECTORY',\n 'ohos.permission.READ_WRITE_DOWNLOAD_DIRECTORY',\n 'ohos.permission.READ_WRITE_USB_DEV',\n 'ohos.permission.READ_WRITE_USER_FILE',\n 'ohos.permission.SET_PAC_URL',\n 'ohos.permission.SET_SYSTEMSHARE_APPLAUNCHTRUSTLIST',\n 'ohos.permission.SHORT_TERM_WRITE_IMAGEVIDEO',\n 'ohos.permission.START_PROVISIONING_MESSAGE',\n 'ohos.permission.SUBSCRIBE_NOTIFICATION',\n 'ohos.permission.SYSTEM_FLOAT_WINDOW',\n 'ohos.permission.USE_FLOAT_BALL',\n 'ohos.permission.USE_FRAUD_APP_PICKER',\n 'ohos.permission.USE_FRAUD_CALL_LOG_PICKER',\n 'ohos.permission.USE_FRAUD_MESSAGES_PICKER',\n 'ohos.permission.WEB_NATIVE_MESSAGING',\n 'ohos.permission.WRITE_AUDIO',\n 'ohos.permission.WRITE_CONTACTS',\n 'ohos.permission.WRITE_IMAGEVIDEO',\n 'ohos.permission.atomicService.MANAGE_STORAGE',\n 'ohos.permission.kernel.ALLOW_EXECUTABLE_FORT_MEMORY',\n 'ohos.permission.kernel.ALLOW_WRITABLE_CODE_MEMORY',\n 'ohos.permission.kernel.DISABLE_CODE_MEMORY_PROTECTION',\n 'ohos.permission.kernel.DISABLE_GOTPLT_RO_PROTECTION',\n]);\n\n","declare const __PKG_VERSION__: string;\nexport const VERSION = __PKG_VERSION__;\n\nexport * from './ports/index.js';\nexport * from './sdk/index.js';\nexport * from './cmdTools/index.js';\nexport * from './sign/index.js';\nexport * from './emulator/index.js';\nexport * from './hdc/index.js';\nexport * from './build/index.js';\nexport * from './project/index.js';\nexport * from './device/index.js';\nexport * from './install/index.js';\nexport * from './harmonyos/index.js';\n"],"mappings":"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","names":["platform","os","platform","fs","os","path","os","path","platform","fs","path","fs","os","path","fs","path","resolve","fs","os","path","pipeline","promisify","pipelineAsync","promisify","pipeline","fs","path","fs","path","fs","path","fs","n","fs","os","path","path","platform","platform","fs","path","crypto","fs","path","JSON5","JSON5","fs","path","fs","os","path","spawn","fs","resolve","spawn","resolve","tail","path","resolve","fs","path","fs","path","fs","path","JSON5","JSON5","relative","resolve","fs","os","path","randomBytes","randomBytes","fs","os","path","randomBytes","randomBytes","resolve","x","fs","resolve","fs","path","fs","path","JSON5","resolve","fs","path","fs","path","fs","path","fs","JSON5","fs","path","fs","path","fs","path","StreamZip","fs","path","fs","os","path","crypto","encrypt","decrypt","crypto","http","crypto","resolve","port","spawn","spawn","resolve","http","fs","x","crypto","fs","path","JSON5","crypto","fs","path","http","shell","crypto","fs","path","fs","path","crypto","path","fs","path","JSON5","JSON5","JSON5"]}
|
|
1
|
+
{"version":3,"sources":["../src/ports/logger.ts","../src/ports/progress.ts","../src/ports/config.ts","../src/ports/prompter.ts","../src/ports/errors.ts","../src/ports/context.ts","../src/sdk/constants.ts","../src/sdk/platform.ts","../src/sdk/paths.ts","../src/harmonyos/sdk.ts","../src/sdk/detectProjectSdk.ts","../src/sdk/tmp.ts","../src/sdk/download.ts","../src/sdk/extract.ts","../src/sdk/list.ts","../src/sdk/remove.ts","../src/sdk/install.ts","../src/sdk/move.ts","../src/cmdTools/install.ts","../src/hdc/spawnCompat.ts","../src/sign/encryptKey.ts","../src/sign/generateSigningConfigs.ts","../src/sign/applicationCert.ts","../src/emulator/install.ts","../src/emulator/lifecycle.ts","../src/hdc/exec.ts","../src/hdc/devices.ts","../src/hdc/param.ts","../src/hdc/files.ts","../src/hdc/display.ts","../src/hdc/wait.ts","../src/hdc/app.ts","../src/build/discoverHaps.ts","../src/hdc/project.ts","../src/hdc/lifecycle.ts","../src/hdc/screen.ts","../src/hdc/input.ts","../src/hdc/dump.ts","../src/hdc/ime.ts","../src/hdc/uiActions.ts","../src/hdc/hilog.ts","../src/build/runHvigorw.ts","../src/harmonyos/target.ts","../src/build/ohpm.ts","../src/build/codelinter.ts","../src/build/buildHap.ts","../src/project/validators.ts","../src/project/templates.ts","../src/project/createScaffold.ts","../src/project/jsonHelpers.ts","../src/project/listModules.ts","../src/project/abilities.ts","../src/project/prepareSigning.ts","../src/device/hidumper.ts","../src/device/info.ts","../src/install/diffHapAssets.ts","../src/install/apply.ts","../src/harmonyos/auth/endpoints.ts","../src/harmonyos/auth/tokenStore.ts","../src/harmonyos/auth/session.ts","../src/harmonyos/http.ts","../src/harmonyos/auth/callbackServer.ts","../src/harmonyos/auth/browser.ts","../src/harmonyos/signing/errors.ts","../src/harmonyos/signing/profile.ts","../src/harmonyos/signing/autoSign.ts","../src/harmonyos/signing/agc.ts","../src/harmonyos/signing/devices.ts","../src/harmonyos/signing/keystore.ts","../src/harmonyos/java.ts","../src/harmonyos/signing/paths.ts","../src/harmonyos/signing/project.ts","../src/harmonyos/signing/aclPermissionList.ts","../src/index.ts"],"sourcesContent":["export interface Logger {\n debug(message: string): void;\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n}\n\nexport const noopLogger: Logger = {\n debug() {},\n info() {},\n warn() {},\n error() {},\n};\n\nexport const consoleLogger: Logger = {\n debug: (m) => console.debug(m),\n info: (m) => console.log(m),\n warn: (m) => console.warn(m),\n error: (m) => console.error(m),\n};\n\n/**\n * Wrap a Logger so every message is prefixed with `[<scope>] `. Standardizes the\n * ad-hoc `[hdc]` / `[build]` / `[sign]` / `[hilog]` / `[emulator]` prefixes that\n * were previously hand-written at each call site.\n */\nexport function scopedLogger(logger: Logger, scope: string): Logger {\n const prefix = `[${scope}] `;\n return {\n debug: (m) => logger.debug(prefix + m),\n info: (m) => logger.info(prefix + m),\n warn: (m) => logger.warn(prefix + m),\n error: (m) => logger.error(prefix + m),\n };\n}\n","export interface ProgressUpdate {\n message?: string;\n increment?: number;\n}\n\nexport interface ProgressReporter {\n report(update: ProgressUpdate): void;\n}\n\nexport const noopProgress: ProgressReporter = {\n report() {},\n};\n","import * as os from 'node:os';\nimport * as path from 'node:path';\n\n/**\n * Keys read from the ConfigProvider by core. Frontends (CLI, VS Code extension)\n * implement the provider however they like (env vars, settings.json, etc.).\n */\nexport type ConfigKey =\n | 'sdkRootDir'\n | 'cmdToolsPath'\n | 'hdcPath'\n | 'emulatorDir'\n | 'hapPath'\n | 'cmdToolsUrlLinux'\n | 'cmdToolsUrlWindows'\n | 'cmdToolsUrlMac'\n | 'emulatorUrl'\n // Scratch directory for download/extract temporaries. Defaults to the system temp\n // dir, which is often a RAM-backed tmpfs too small for multi-GB archives; point\n // this at a disk-backed directory when that bites.\n | 'tmpDir'\n // Base URL for OpenHarmony SDK release downloads. Defaults to the Huawei mirror\n // (`OHOS_URL_BASE`); override to point at a private/CI mirror.\n | 'sdkUrlBase'\n // Optional path to an external application-cert chain that overrides the bundled\n // `OpenHarmonyApplication.cer` during signing. Empty/unset → use the bundled cert.\n | 'applicationCertPath'\n // A HarmonyOS SDK: a DevEco Studio or HarmonyOS command-line-tools install, or its\n // `sdk` directory. Autodetected when unset; never downloaded.\n | 'harmonyosSdkPath'\n // Encrypted Huawei developer-account token. Default `~/.oniro/harmonyos`.\n | 'harmonyosAuthDir'\n // Generated HarmonyOS signing material (p12/csr/cer/p7b). Default `~/.ohos/config`,\n // where DevEco Studio keeps its own.\n | 'harmonyosSigningDir';\n\nexport interface ConfigProvider {\n /**\n * Get the configured value for `key`, or `fallback` if unset/empty.\n * Implementations should expand the literal `${userHome}` to the user's home dir.\n */\n get<T extends string | number | boolean>(key: ConfigKey, fallback: T): T;\n}\n\n/**\n * Default config values used when a ConfigProvider returns the fallback.\n * These match the historical paths used by the bash CLI and the extension.\n */\nexport const defaultPaths = {\n sdkRootDir: () => path.join(os.homedir(), 'setup-ohos-sdk'),\n cmdToolsPath: () => path.join(os.homedir(), 'command-line-tools'),\n emulatorDir: () => path.join(os.homedir(), 'oniro-emulator'),\n harmonyosAuthDir: () => path.join(os.homedir(), '.oniro', 'harmonyos'),\n harmonyosSigningDir: () => path.join(os.homedir(), '.ohos', 'config'),\n hapPath: 'entry/build/default/outputs/default/entry-default-signed.hap',\n emulatorUrl:\n 'https://github.com/eclipse-oniro4openharmony/device_board_oniro/releases/latest/download/oniro_emulator.zip',\n // The Huawei mirror only hosts a public Linux build of the command-line tools.\n // Windows and macOS require a manual download from the Huawei developer portal\n // (https://developer.huawei.com/...); pass the resulting ZIP to `cmdtools install --from-zip <path>`\n // or set ONIRO_CMD_TOOLS_URL_WINDOWS / ONIRO_CMD_TOOLS_URL_MAC to a self-hosted URL.\n cmdToolsUrlLinux:\n 'https://repo.huaweicloud.com/harmonyos/ohpm/5.1.0/commandline-tools-linux-x64-5.1.0.840.zip',\n} as const;\n\n/**\n * A simple in-memory ConfigProvider, useful for tests and as a base for CLI/extension impls.\n */\nexport function staticConfig(values: Partial<Record<ConfigKey, string>> = {}): ConfigProvider {\n return {\n get<T extends string | number | boolean>(key: ConfigKey, fallback: T): T {\n const v = values[key];\n if (v === undefined || v === '') {\n return fallback;\n }\n // Expand ${userHome} like the extension does.\n if (typeof v === 'string' && v.includes('${userHome}')) {\n return v.replace(/\\$\\{userHome\\}/g, os.homedir()) as unknown as T;\n }\n return v as unknown as T;\n },\n };\n}\n","/**\n * Interactive prompts. Frontends implement these — CLI uses @inquirer/prompts,\n * the extension uses `vscode.window.show*`. Core never assumes a TTY.\n */\nexport interface Prompter {\n /** Ask the user to confirm an action. */\n confirm(message: string, defaultValue?: boolean): Promise<boolean>;\n /** Ask the user for a single line of text. */\n input(message: string, defaultValue?: string): Promise<string>;\n /** Ask the user to pick a directory on disk; resolves to an absolute path or null if cancelled. */\n selectDirectory(message: string, defaultPath?: string): Promise<string | null>;\n /** Ask the user to pick a file on disk; resolves to an absolute path or null if cancelled. */\n selectFile(message: string, filters?: { extensions?: string[] }): Promise<string | null>;\n}\n\n/**\n * Throws on any prompt — used in non-interactive contexts where all answers must come from flags.\n */\nexport const nonInteractivePrompter: Prompter = {\n async confirm(message) {\n throw new Error(`Non-interactive mode: cannot confirm \"${message}\"`);\n },\n async input(message) {\n throw new Error(`Non-interactive mode: cannot ask \"${message}\"`);\n },\n async selectDirectory(message) {\n throw new Error(`Non-interactive mode: cannot prompt for directory \"${message}\"`);\n },\n async selectFile(message) {\n throw new Error(`Non-interactive mode: cannot prompt for file \"${message}\"`);\n },\n};\n","export class OniroError extends Error {\n constructor(message: string, public override readonly cause?: unknown) {\n super(message);\n this.name = 'OniroError';\n }\n}\n\nexport class SdkNotInstalledError extends OniroError {\n /** `version` is the release that ships `api` (e.g. `6.0` for API 20), when one is known. */\n constructor(\n public readonly api: string,\n public readonly expectedPath: string,\n public readonly version?: string,\n ) {\n super(\n `SDK API ${api} is not installed at ${expectedPath}.` +\n (version ? ` Install it with \\`oniro-app sdk install ${version}\\`.` : ''),\n );\n this.name = 'SdkNotInstalledError';\n }\n}\n\nexport class CmdToolsNotInstalledError extends OniroError {\n constructor(public readonly expectedPath: string) {\n super(`OpenHarmony command-line tools are not installed at ${expectedPath}.`);\n this.name = 'CmdToolsNotInstalledError';\n }\n}\n\nexport class UnsupportedPlatformError extends OniroError {\n constructor(public readonly platform: string) {\n super(`Unsupported platform: ${platform}.`);\n this.name = 'UnsupportedPlatformError';\n }\n}\n\nexport class ChecksumMismatchError extends OniroError {\n constructor(public readonly expected: string, public readonly actual: string) {\n super(`SHA256 mismatch: expected ${expected}, got ${actual}.`);\n this.name = 'ChecksumMismatchError';\n }\n}\n\n/**\n * A download/extract ran out of room on the filesystem holding its scratch\n * directory. The message is built by the caller (see `sdk/tmp.ts`) so it can name\n * the directory, whether it is RAM-backed, and how to point elsewhere.\n */\nexport class InsufficientSpaceError extends OniroError {\n constructor(message: string, public readonly dir: string, cause?: unknown) {\n super(message, cause);\n this.name = 'InsufficientSpaceError';\n }\n}\n\nexport class CancelledError extends OniroError {\n constructor(message = 'Operation cancelled.') {\n super(message);\n this.name = 'CancelledError';\n }\n}\n\n/**\n * A spawned command ran to completion but exited non-zero. Lets callers\n * distinguish \"the tool ran and failed\" from \"the tool could not be spawned\"\n * (a missing binary surfaces as an OniroError / CmdToolsNotInstalledError).\n */\nexport class CommandFailedError extends OniroError {\n constructor(\n public readonly command: string,\n public readonly exitCode: number,\n public readonly stderr: string,\n ) {\n super(`Command failed (exit ${exitCode}): ${command}${stderr ? `\\n${stderr}` : ''}`);\n this.name = 'CommandFailedError';\n }\n}\n","import { Logger, noopLogger } from './logger.js';\nimport { ConfigProvider, staticConfig } from './config.js';\n\n/**\n * Carries the cross-cutting dependencies most core functions need: a Logger and a ConfigProvider.\n * Functions that report progress or prompt the user take those as additional parameters.\n */\nexport interface OniroContext {\n logger: Logger;\n config: ConfigProvider;\n}\n\nexport function defaultContext(overrides: Partial<OniroContext> = {}): OniroContext {\n return {\n logger: overrides.logger ?? noopLogger,\n config: overrides.config ?? staticConfig(),\n };\n}\n","export interface SdkRelease {\n version: string;\n api: string;\n /**\n * Number of leading path components to strip when extracting the release\n * tarball, per OS family. The Huawei mirror packs linux+windows in one\n * tarball (no top-level wrapper for some releases → 0, else 1); macOS\n * tarballs have a deeper layout (3). This table is the single source of\n * truth read by `getSdkFilename()`.\n */\n tarballStrip: { linuxWindows: number; darwin: number };\n /**\n * Appended to the archive basename when the mirror re-published a release under a\n * dated name (e.g. 7.0 ships `ohos-sdk-windows_linux-public_20260829.tar.gz`, whose\n * components are the `-Release` build; the undated archive holds `-Beta` ones).\n */\n archiveSuffix?: string;\n}\n\n/**\n * Known OpenHarmony SDK releases. Kept in sync with the bash CLI / extension.\n * Update when a new SDK ships.\n */\nexport const ALL_SDKS: readonly SdkRelease[] = [\n { version: '4.0', api: '10', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '4.1', api: '11', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '5.0.0', api: '12', tarballStrip: { linuxWindows: 0, darwin: 3 } },\n { version: '5.0.1', api: '13', tarballStrip: { linuxWindows: 0, darwin: 3 } },\n { version: '5.0.2', api: '14', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '5.0.3', api: '15', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '5.1.0', api: '18', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '5.1.1', api: '19', tarballStrip: { linuxWindows: 1, darwin: 3 } },\n { version: '6.0', api: '20', tarballStrip: { linuxWindows: 0, darwin: 3 } },\n { version: '6.1', api: '23', tarballStrip: { linuxWindows: 0, darwin: 3 } },\n { version: '7.0', api: '26', tarballStrip: { linuxWindows: 1, darwin: 3 }, archiveSuffix: '_20260829' },\n];\n\nexport const OHOS_URL_BASE = 'https://repo.huaweicloud.com/openharmony/os';\n","import * as os from 'node:os';\nimport { ALL_SDKS } from './constants.js';\nimport { UnsupportedPlatformError } from '../ports/errors.js';\n\nexport type OsFolder = 'linux' | 'darwin' | 'windows';\n\n/**\n * Map Node's `os.platform()` to the OS folder name used in the SDK install layout\n * and the SDK release tarballs.\n */\nexport function getOsFolder(): OsFolder {\n const platform = os.platform();\n if (platform === 'linux') return 'linux';\n if (platform === 'darwin') return 'darwin';\n if (platform === 'win32') return 'windows';\n throw new UnsupportedPlatformError(platform);\n}\n\nexport interface SdkArchiveInfo {\n filename: string;\n osFolder: OsFolder;\n /** Number of leading path components to strip when extracting the tarball. */\n strip: number;\n}\n\n/**\n * Resolve the SDK archive filename, OS folder, and tar strip count for the current platform.\n *\n * The Huawei mirror packages Linux and Windows together in one tarball with `linux/` and\n * `windows/` subfolders; macOS tarballs have a deeper layout. The per-release strip counts\n * live in {@link ALL_SDKS} (`tarballStrip`), as does any dated `archiveSuffix`. An\n * unrecognized version falls back to the historical default (linux/windows=1, darwin=3).\n */\nexport function getSdkFilename(version?: string): SdkArchiveInfo {\n const platform = os.platform();\n const v = version ?? ALL_SDKS[ALL_SDKS.length - 1]!.version;\n const release = ALL_SDKS.find((r) => r.version === v);\n const strips = release?.tarballStrip ?? { linuxWindows: 1, darwin: 3 };\n const archive = (base: string) => `${base}${release?.archiveSuffix ?? ''}.tar.gz`;\n\n if (platform === 'linux') {\n return { filename: archive('ohos-sdk-windows_linux-public'), osFolder: 'linux', strip: strips.linuxWindows };\n }\n if (platform === 'darwin') {\n if (os.arch() === 'arm64') {\n return { filename: archive('L2-SDK-MAC-M1-PUBLIC'), osFolder: 'darwin', strip: strips.darwin };\n }\n return { filename: archive('ohos-sdk-mac-public'), osFolder: 'darwin', strip: strips.darwin };\n }\n if (platform === 'win32') {\n return { filename: archive('ohos-sdk-windows_linux-public'), osFolder: 'windows', strip: strips.linuxWindows };\n }\n throw new UnsupportedPlatformError(platform);\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { ConfigProvider, defaultPaths } from '../ports/config.js';\nimport { getOsFolder } from './platform.js';\nimport { findHarmonyOsSdk } from '../harmonyos/sdk.js';\n\nexport function getSdkRootDir(config: ConfigProvider): string {\n return config.get('sdkRootDir', defaultPaths.sdkRootDir());\n}\n\n/**\n * Base SDK home for the current OS: `<sdkRootDir>/<linux|darwin|windows>`.\n * SDK API folders (e.g. `12`, `18`, `20`) live inside this directory.\n */\nexport function getOhosBaseSdkHome(config: ConfigProvider): string {\n return path.join(getSdkRootDir(config), getOsFolder());\n}\n\nexport function getCmdToolsPath(config: ConfigProvider): string {\n return config.get('cmdToolsPath', defaultPaths.cmdToolsPath());\n}\n\nexport function getEmulatorDir(config: ConfigProvider): string {\n return config.get('emulatorDir', defaultPaths.emulatorDir());\n}\n\n/**\n * Expand a Windows 8.3 short path (`C:\\Users\\FRANCE~1\\...`) to its long form.\n *\n * Short names reach us whenever a caller passes `%TEMP%` or a path built in a\n * `cmd` context, and hvigor cannot resolve a module directory underneath one:\n * it aborts with `00303149 Configuration Error / Path not found` naming a\n * `srcPath` that plainly exists. Node and the Win32 API resolve short names\n * fine, so the mismatch only surfaces once hvigor is running.\n *\n * No-op off Windows, where short names do not exist and resolving would only\n * dereference symlinks the caller chose deliberately. On Windows it does also\n * canonicalise case and follow junctions — the same path the OS resolves to\n * anyway.\n *\n * Returns `p` unchanged when it does not exist, so a caller's \"not found\"\n * error still quotes the path the user actually typed.\n *\n * `platform` is injectable so the behaviour is unit-testable off Windows.\n */\nexport function toLongPath(p: string, platform: NodeJS.Platform = os.platform()): string {\n if (platform !== 'win32') return p;\n try {\n return fs.realpathSync.native(p);\n } catch {\n return p;\n }\n}\n\nfunction pickExisting(candidates: string[]): string {\n for (const c of candidates) {\n if (fs.existsSync(c)) return c;\n }\n return candidates[0]!;\n}\n\n/**\n * Resolve a binary inside the command-line tools `bin/` directory by name\n * (e.g. `'ohpm'`, `'hvigorw'`, `'codelinter'`). On Windows tries common\n * executable suffixes (.exe, .cmd, .bat) before the POSIX name.\n */\nexport function getCmdToolsBin(config: ConfigProvider, name = 'ohpm'): string {\n const binDir = path.join(getCmdToolsPath(config), 'bin');\n if (os.platform() === 'win32') {\n return pickExisting([\n path.join(binDir, `${name}.exe`),\n path.join(binDir, `${name}.cmd`),\n path.join(binDir, `${name}.bat`),\n path.join(binDir, name),\n ]);\n }\n return path.join(binDir, name);\n}\n\n/** Resolve the OHPM binary path inside the command-line tools install. */\nexport function getOhpmPath(config: ConfigProvider): string {\n return getCmdToolsBin(config, 'ohpm');\n}\n\n/**\n * Resolve the hdc binary. An explicit `hdcPath` override (config key / `ONIRO_HDC`\n * env var) wins — point it at a wrapper/proxy hdc when the device is not directly\n * attached here (e.g. a remote device behind an SSH-tunnel `hdc` wrapper). When\n * unset, fall back to the hdc bundled in the SDK toolchains tree.\n */\nexport function getHdcPath(config: ConfigProvider): string {\n const override = config.get('hdcPath', '');\n if (override) return override;\n const hdc = hdcInSdk(path.join(getCmdToolsPath(config), 'sdk'));\n if (fs.existsSync(hdc)) return hdc;\n // A HarmonyOS-only machine has no OpenHarmony command-line tools; the HarmonyOS\n // SDK ships an hdc of its own, at the same place inside the SDK.\n const harmonySdk = findHarmonyOsSdk({ config });\n const harmonyHdc = harmonySdk ? hdcInSdk(harmonySdk.sdkPath) : undefined;\n return harmonyHdc && fs.existsSync(harmonyHdc) ? harmonyHdc : hdc;\n}\n\nfunction hdcInSdk(sdkDir: string): string {\n const base = path.join(sdkDir, 'default', 'openharmony', 'toolchains');\n if (os.platform() === 'win32') {\n return pickExisting([\n path.join(base, 'hdc.exe'),\n path.join(base, 'hdc.bat'),\n path.join(base, 'hdc.cmd'),\n path.join(base, 'hdc'),\n ]);\n }\n return path.join(base, 'hdc');\n}\n\n/**\n * Resolve the hvigorw wrapper for a project. Prefers the project-local copy\n * (which carries the project's pinned hvigor version) — but ONLY when that\n * wrapper is structurally complete. HMOS-vendored projects (systemui, launcher)\n * ship a project-local `hvigorw` whose `hvigor/` install is absent, so the\n * wrapper crashes on startup; in that case we fall back to the hvigorw bundled\n * with the command-line tools, which is always installed.\n *\n * DevEco projects ship both wrappers side by side: an extensionless POSIX shell\n * script and a `.bat` for Windows. The candidate order is therefore\n * platform-dependent — picking the shell script on Windows would hand `spawn` a\n * file the OS cannot execute.\n */\nexport function getHvigorwPath(\n config: ConfigProvider,\n projectDir: string,\n platform: NodeJS.Platform = os.platform(),\n): string {\n const posixFirst = ['hvigorw', 'hvigorw.bat', 'hvigorw.cmd'];\n const windowsFirst = ['hvigorw.bat', 'hvigorw.cmd', 'hvigorw'];\n const names = platform === 'win32' ? windowsFirst : posixFirst;\n const local = pickExisting(names.map((n) => path.join(projectDir, n)));\n if (fs.existsSync(local) && isProjectLocalHvigorwWorking(projectDir)) {\n return local;\n }\n return getCmdToolsBin(config, 'hvigorw');\n}\n\n/**\n * A project-local hvigorw wrapper only works when the project also has a\n * populated `hvigor/` install. The structural check (wrapper script + its\n * node_modules) is fast and avoids spawning `hvigorw --version` for the common,\n * working case.\n */\nfunction isProjectLocalHvigorwWorking(projectDir: string): boolean {\n const wrapper = path.join(projectDir, 'hvigor', 'hvigor-wrapper.js');\n const nodeModules = path.join(projectDir, 'hvigor', 'node_modules');\n return fs.existsSync(wrapper) && fs.existsSync(nodeModules);\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport { defaultPaths } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\n\n/**\n * A HarmonyOS SDK install. Unlike the OpenHarmony SDK, which `oniro-app sdk install`\n * downloads, the HarmonyOS SDK only ships inside DevEco Studio or the login-gated\n * HarmonyOS command-line tools, so oniro-app locates an existing install.\n */\nexport interface HarmonyOsSdk {\n /** The directory containing `default/`; hvigor receives it as `DEVECO_SDK_HOME`. */\n sdkPath: string;\n /** The DevEco Studio or command-line-tools install holding the SDK, its tools and JBR. */\n installRoot: string;\n /** From `default/sdk-pkg.json`, e.g. `HarmonyOS 6.1.1`. */\n displayName?: string;\n /**\n * The release as `compileSdkVersion` names it, e.g. `6.1.1(24)`, from\n * `default/sdk-pkg.json`. hvigor builds only projects that name this release.\n */\n version?: string;\n}\n\n/** `displayName` and `version` from `default/sdk-pkg.json`, where it has them. */\nfunction readSdkPkg(sdkPath: string): Pick<HarmonyOsSdk, 'displayName' | 'version'> {\n let data: { displayName?: unknown; platformVersion?: unknown; apiVersion?: unknown } | undefined;\n try {\n data = JSON.parse(fs.readFileSync(path.join(sdkPath, 'default', 'sdk-pkg.json'), 'utf8')).data;\n } catch {\n return {};\n }\n const text = (value: unknown) =>\n typeof value === 'string' || typeof value === 'number' ? String(value) || undefined : undefined;\n const platformVersion = text(data?.platformVersion);\n const apiVersion = text(data?.apiVersion);\n return {\n displayName: text(data?.displayName),\n version: platformVersion && apiVersion ? `${platformVersion}(${apiVersion})` : undefined,\n };\n}\n\n/**\n * Resolve an install root, or an SDK directory itself, to a HarmonyOS SDK.\n *\n * HarmonyOS and OpenHarmony SDKs share one layout, so an autodetected candidate\n * must also name itself HarmonyOS in `sdk-pkg.json` — otherwise the OpenHarmony\n * command-line tools would pass. An explicitly configured path is taken as given.\n */\nfunction resolveSdk(root: string, requireHarmonyOs: boolean): HarmonyOsSdk | null {\n const nested = path.join(root, 'sdk');\n const sdkPath = [nested, root].find((dir) => fs.existsSync(path.join(dir, 'default', 'openharmony')));\n if (!sdkPath) return null;\n\n const pkg = readSdkPkg(sdkPath);\n if (requireHarmonyOs && !pkg.displayName?.startsWith('HarmonyOS')) return null;\n return { sdkPath, installRoot: sdkPath === nested ? root : path.dirname(root), ...pkg };\n}\n\n/** Where DevEco Studio installs by default. It has no Linux release. */\nfunction studioCandidates(): string[] {\n if (process.platform === 'darwin') {\n return [\n '/Applications/DevEco-Studio.app/Contents',\n path.join(os.homedir(), 'Applications', 'DevEco-Studio.app', 'Contents'),\n ];\n }\n if (process.platform === 'win32') {\n return [path.join(process.env.ProgramFiles ?? 'C:\\\\Program Files', 'Huawei', 'DevEco Studio')];\n }\n return [];\n}\n\n/**\n * Locate a HarmonyOS SDK, or return null when none is installed.\n *\n * Order: `harmonyosSdkPath` (`ONIRO_HARMONYOS_SDK_PATH`, an install root or its\n * `sdk` directory), then DevEco Studio in its default location, then the\n * command-line tools at `cmdToolsPath` when they are the HarmonyOS edition.\n */\nexport function findHarmonyOsSdk(opts: { config: ConfigProvider; logger?: Logger }): HarmonyOsSdk | null {\n const logger = opts.logger ?? noopLogger;\n\n const configured = opts.config.get('harmonyosSdkPath', '');\n if (configured) {\n const sdk = resolveSdk(configured, false);\n if (sdk) return sdk;\n logger.warn(`ONIRO_HARMONYOS_SDK_PATH points at ${configured}, which holds no SDK; ignoring it.`);\n }\n\n const candidates = [\n ...studioCandidates(),\n opts.config.get('cmdToolsPath', defaultPaths.cmdToolsPath()),\n ];\n for (const candidate of candidates) {\n const sdk = resolveSdk(candidate, true);\n if (sdk) {\n logger.debug(`[harmonyos] Using the ${sdk.displayName} SDK at ${sdk.sdkPath}.`);\n return sdk;\n }\n }\n return null;\n}\n\n/** Like `findHarmonyOsSdk`, but throws an actionable error when none is installed. */\nexport function requireHarmonyOsSdk(opts: { config: ConfigProvider; logger?: Logger }): HarmonyOsSdk {\n const sdk = findHarmonyOsSdk(opts);\n if (sdk) return sdk;\n throw new OniroError(\n 'No HarmonyOS SDK found. It ships inside DevEco Studio or the HarmonyOS command-line tools and ' +\n 'cannot be downloaded the way the OpenHarmony SDK is. Install one, then set ONIRO_HARMONYOS_SDK_PATH ' +\n 'to the install (or its sdk directory).',\n );\n}\n\n/**\n * Locate a tool (`hvigorw`, `ohpm`) in a HarmonyOS install: the command-line tools\n * keep them in `bin`, DevEco Studio in `tools/<name>/bin`. Null when absent.\n */\nexport function findHarmonyOsTool(sdk: HarmonyOsSdk, name: string): string | null {\n const names = process.platform === 'win32' ? [`${name}.bat`, `${name}.cmd`, `${name}.exe`] : [name];\n for (const dir of [path.join(sdk.installRoot, 'bin'), path.join(sdk.installRoot, 'tools', name, 'bin')]) {\n for (const candidate of names) {\n const full = path.join(dir, candidate);\n if (fs.existsSync(full)) return full;\n }\n }\n return null;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport JSON5 from 'json5';\nimport { Logger, noopLogger } from '../ports/logger.js';\nimport type { ConfigProvider } from '../ports/config.js';\nimport { SdkNotInstalledError } from '../ports/errors.js';\nimport { ALL_SDKS } from './constants.js';\nimport { getOhosBaseSdkHome } from './paths.js';\n\n/**\n * The `sdk.dir` a project's `local.properties` names (a base SDK home holding API\n * folders, as `createScaffold` writes it), unescaped, or undefined.\n */\nfunction localPropertiesSdkDir(projectRoot: string): string | undefined {\n try {\n const content = fs.readFileSync(path.join(projectRoot, 'local.properties'), 'utf-8');\n const m = /^\\s*sdk\\.dir\\s*[=:]\\s*(.+?)\\s*$/m.exec(content);\n return m ? m[1]!.replace(/\\\\(.)/g, '$1') : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * The OpenHarmony SDK an OpenHarmony project builds against is missing, as a typed\n * error naming the release to install, or null when it is installed or the project\n * declares no numeric `compileSdkVersion`. hvigor looks for\n * `<sdk home>/<compileSdkVersion>`, the home being `OHOS_BASE_SDK_HOME` or the\n * project's `local.properties` `sdk.dir`, and otherwise fails late with\n * `00308018 SDK path does not exist` / \"SDK license agreement is not accepted\".\n */\nexport function findMissingProjectSdk(config: ConfigProvider, projectRoot: string): SdkNotInstalledError | null {\n const api = detectProjectSdkVersion(projectRoot);\n if (api === undefined) return null;\n const expected = path.join(getOhosBaseSdkHome(config), String(api));\n if (fs.existsSync(expected)) return null;\n const localSdkDir = localPropertiesSdkDir(projectRoot);\n if (localSdkDir && fs.existsSync(path.join(localSdkDir, String(api)))) return null;\n return new SdkNotInstalledError(String(api), expected, ALL_SDKS.find((s) => s.api === String(api))?.version);\n}\n\n/**\n * Detect the SDK API a project targets by reading `build-profile.json5`.\n * Returns the `compileSdkVersion` of the first declared product, or undefined\n * if the file is missing/malformed or no product declares one.\n */\nexport function detectProjectSdkVersion(projectRoot: string, logger: Logger = noopLogger): number | undefined {\n const buildProfilePath = path.join(projectRoot, 'build-profile.json5');\n if (!fs.existsSync(buildProfilePath)) {\n logger.warn(`build-profile.json5 not found at ${projectRoot}`);\n return undefined;\n }\n try {\n const content = fs.readFileSync(buildProfilePath, 'utf-8');\n const config = JSON5.parse(content) as { app?: { products?: Array<{ compileSdkVersion?: unknown }> } };\n const product = config.app?.products?.[0];\n const v = product?.compileSdkVersion;\n return typeof v === 'number' ? v : undefined;\n } catch (err) {\n logger.error(`Error reading build-profile.json5 at ${projectRoot}: ${String(err)}`);\n return undefined;\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { InsufficientSpaceError, OniroError } from '../ports/errors.js';\n\n/** Name of the scratch folder created next to an install target. */\nexport const INSTALL_TMP_DIRNAME = '.oniro-tmp';\n\n/** `statfs` type magics for the Linux filesystems whose capacity comes out of RAM. */\nconst TMPFS_MAGIC = 0x01021994;\nconst RAMFS_MAGIC = 0x858458f6;\n\nconst HINT_EXAMPLE = os.platform() === 'win32' ? 'D:\\\\oniro-tmp' : '~/.cache/oniro-tmp';\n\n/** Advice appended to out-of-space failures in the scratch directory. */\nexport const TMP_DIR_HINT =\n 'Point the scratch directory at a filesystem with more room using --tmp-dir <path> ' +\n `(or the ONIRO_TMP_DIR environment variable), e.g. --tmp-dir ${HINT_EXAMPLE}.`;\n\n/**\n * Resolve the directory that download/extract scratch space is created in.\n *\n * Precedence: explicit override (CLI `--tmp-dir`) → `tmpDir` config key\n * (`ONIRO_TMP_DIR`) → `<installRoot>/.oniro-tmp` → the system temp dir.\n *\n * The default sits next to the install target so that the unpacked tree is renamed\n * into place rather than copied across a device boundary, and so the system temp dir\n * — a RAM-backed `tmpfs` on most Linux systems, and far smaller than a multi-GB\n * archive — is never in the picture.\n */\nexport function resolveTmpRoot(config: ConfigProvider, override?: string, installRoot?: string): string {\n const explicit = (override ?? '').trim();\n if (explicit) return path.resolve(explicit);\n const configured = config.get('tmpDir', '').trim();\n if (configured) return path.resolve(configured);\n if (installRoot) return path.join(path.resolve(installRoot), INSTALL_TMP_DIRNAME);\n return os.tmpdir();\n}\n\n/** Create a private scratch directory under `root`, creating `root` if needed. */\nexport function createTempWorkDir(root: string, prefix: string): string {\n try {\n fs.mkdirSync(root, { recursive: true });\n return fs.mkdtempSync(path.join(root, prefix));\n } catch (err) {\n if (isOutOfSpaceError(err)) throw toSpaceError(err, root, 'a temporary directory');\n throw new OniroError(\n `Cannot create a temporary directory in '${root}': ${err instanceof Error ? err.message : String(err)}\\n${TMP_DIR_HINT}`,\n err,\n );\n }\n}\n\n/**\n * Remove a scratch directory once an install is done, taking the `.oniro-tmp` root\n * with it when that leaves it empty. A root the caller named explicitly is left alone,\n * as are roots another install is still using (the rmdir simply fails).\n */\nexport function removeTempWorkDir(dir: string, root?: string): void {\n fs.rmSync(dir, { recursive: true, force: true });\n if (!root || path.basename(root) !== INSTALL_TMP_DIRNAME) return;\n try {\n fs.rmdirSync(root);\n } catch {\n // Not empty (a concurrent install) or already gone — nothing to do.\n }\n}\n\nexport interface InstallTempDirOptions {\n config: ConfigProvider;\n /** Explicit scratch directory (CLI `--tmp-dir`). */\n override?: string;\n /** Directory the install lands in; the default scratch root is created inside it. */\n installRoot: string;\n prefix: string;\n logger?: Logger;\n}\n\nexport interface InstallTempDir {\n /** The private per-run scratch directory. Remove it when the install finishes. */\n dir: string;\n /** The configurable root it was created under, for out-of-space messages. */\n root: string;\n}\n\n/**\n * Create the scratch directory for an install, defaulting to `<installRoot>/.oniro-tmp`.\n *\n * When that default is unusable — a read-only or root-owned install parent, say — the\n * system temp dir is used instead. A directory the caller asked for explicitly is never\n * swapped out silently, and a full filesystem is reported rather than papered over.\n */\nexport function createInstallTempDir(opts: InstallTempDirOptions): InstallTempDir {\n const requested =\n (opts.override ?? '').trim() || opts.config.get('tmpDir', '').trim();\n const root = resolveTmpRoot(opts.config, opts.override, opts.installRoot);\n\n try {\n return { dir: createTempWorkDir(root, opts.prefix), root };\n } catch (err) {\n const fallback = os.tmpdir();\n if (requested || isOutOfSpaceError(err) || path.resolve(fallback) === path.resolve(root)) throw err;\n const reason = err instanceof Error ? err.message.split(/\\r?\\n/)[0] : String(err);\n (opts.logger ?? noopLogger).warn(`${reason} Falling back to '${fallback}'.`);\n return { dir: createTempWorkDir(fallback, opts.prefix), root: fallback };\n }\n}\n\n/** Nearest existing ancestor of `dir` (or null if even the root is unreadable). */\nfunction nearestExisting(dir: string): string | null {\n let current = path.resolve(dir);\n for (;;) {\n if (fs.existsSync(current)) return current;\n const parent = path.dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\n/**\n * Bytes available to an unprivileged user on the filesystem holding `dir`.\n * Returns null when the platform cannot report it.\n */\nexport function getFreeSpaceBytes(dir: string): number | null {\n const target = nearestExisting(dir);\n if (!target) return null;\n try {\n const stats = fs.statfsSync(target);\n return Number(stats.bsize) * Number(stats.bavail);\n } catch {\n return null;\n }\n}\n\n/**\n * Whether `dir` lives on a RAM-backed filesystem (`tmpfs`/`ramfs`), i.e. one whose\n * capacity comes out of memory rather than disk.\n */\nexport function isRamBackedPath(dir: string): boolean {\n const target = nearestExisting(dir);\n if (!target) return false;\n try {\n const type = Number(fs.statfsSync(target).type);\n return type === TMPFS_MAGIC || type === RAMFS_MAGIC;\n } catch {\n return false;\n }\n}\n\nexport function formatBytes(bytes: number): string {\n const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB'];\n let value = Math.max(0, bytes);\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit++;\n }\n return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;\n}\n\n/** Recognise an out-of-disk-space failure from fs/stream errors and their wrappers. */\nexport function isOutOfSpaceError(err: unknown): boolean {\n if (err instanceof InsufficientSpaceError) return true;\n const seen = new Set<unknown>();\n let current: unknown = err;\n while (current && typeof current === 'object' && !seen.has(current)) {\n seen.add(current);\n const e = current as { code?: unknown; message?: unknown; cause?: unknown };\n if (e.code === 'ENOSPC' || e.code === 'EDQUOT') return true;\n if (typeof e.message === 'string' && /ENOSPC|EDQUOT|no space left on device/i.test(e.message)) return true;\n current = e.cause;\n }\n return false;\n}\n\n/** The user-facing \"no room\" explanation, with a way out when the temp dir is to blame. */\nfunction spaceMessage(\n dir: string,\n what: string,\n opts: { requiredBytes?: number | null; freeBytes?: number | null; tmpDirHint: boolean },\n): string {\n const need = typeof opts.requiredBytes === 'number' ? `needs about ${formatBytes(opts.requiredBytes)}` : null;\n const free = typeof opts.freeBytes === 'number' ? `${formatBytes(opts.freeBytes)} available` : null;\n const amounts = [need, free].filter(Boolean).join(', ');\n\n const lines = [`Not enough free space in '${dir}' for ${what}${amounts ? ` (${amounts})` : ''}.`];\n if (isRamBackedPath(dir)) {\n lines.push(\n `'${dir}' is on a RAM-backed filesystem (tmpfs), so its capacity is limited by free memory, not by free disk.`,\n );\n }\n if (opts.tmpDirHint) lines.push(TMP_DIR_HINT);\n return lines.join('\\n');\n}\n\n/**\n * Fail before writing a byte when the filesystem holding `dir` cannot take\n * `requiredBytes`. A no-op when free space cannot be determined.\n */\nexport function ensureFreeSpace(dir: string, requiredBytes: number, what: string): void {\n if (!Number.isFinite(requiredBytes) || requiredBytes <= 0) return;\n const freeBytes = getFreeSpaceBytes(dir);\n if (freeBytes === null || freeBytes >= requiredBytes) return;\n throw new InsufficientSpaceError(\n spaceMessage(dir, what, { requiredBytes, freeBytes, tmpDirHint: true }),\n dir,\n );\n}\n\n/** The filesystem path an fs error refers to, from anywhere in its cause chain. */\nfunction errorPath(err: unknown): string | null {\n const seen = new Set<unknown>();\n let current: unknown = err;\n while (current && typeof current === 'object' && !seen.has(current)) {\n seen.add(current);\n const e = current as { path?: unknown; dest?: unknown; cause?: unknown };\n if (typeof e.path === 'string' && e.path) return e.path;\n if (typeof e.dest === 'string' && e.dest) return e.dest;\n current = e.cause;\n }\n return null;\n}\n\nfunction isInside(child: string, parent: string): boolean {\n const rel = path.relative(path.resolve(parent), path.resolve(child));\n return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));\n}\n\n/**\n * Convert an out-of-space failure into an {@link InsufficientSpaceError}; any other\n * error is returned unchanged, so callers can `throw toSpaceError(err, ...)`.\n *\n * `tmpRoot` is the scratch directory the operation was using. Failures under it are\n * reported against it (not the per-run subdirectory the user cannot configure) and get\n * the `--tmp-dir` remedy; failures elsewhere — an install target that is full — name\n * their own directory and skip the remedy, which would not help.\n */\nexport function toSpaceError(err: unknown, tmpRoot: string, what: string): unknown {\n if (err instanceof InsufficientSpaceError) return err;\n if (!isOutOfSpaceError(err)) return err;\n\n const failed = errorPath(err);\n const failedDir = failed ? path.dirname(path.resolve(failed)) : path.resolve(tmpRoot);\n const inTmp = isInside(failedDir, tmpRoot);\n const dir = inTmp ? path.resolve(tmpRoot) : failedDir;\n return new InsufficientSpaceError(\n spaceMessage(dir, what, { freeBytes: getFreeSpaceBytes(dir), tmpDirHint: inTmp }),\n dir,\n err,\n );\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport { pipeline } from 'node:stream';\nimport { promisify } from 'node:util';\nimport followRedirects from 'follow-redirects';\nimport type { ProgressReporter } from '../ports/progress.js';\nimport { CancelledError, ChecksumMismatchError, OniroError } from '../ports/errors.js';\nimport { ensureFreeSpace, isOutOfSpaceError, toSpaceError } from './tmp.js';\n\nconst { http, https } = followRedirects;\nconst pipelineAsync = promisify(pipeline);\n\nexport interface DownloadOptions {\n url: string;\n dest: string;\n progress?: ProgressReporter;\n abortSignal?: AbortSignal;\n /** Overall progress start offset (0..100). Default 0. */\n start?: number;\n /** Overall progress range to consume (0..100). Default 100. */\n range?: number;\n /** What the download is for, used in out-of-space messages. */\n what?: string;\n /**\n * Configurable scratch root that `dest` lives under, if any. Out-of-space messages\n * name it instead of the per-run subdirectory, since that is what the user can change.\n */\n tmpRoot?: string;\n}\n\n/**\n * Stream a remote file to disk with optional progress reporting and cancellation.\n * Follows redirects via the `follow-redirects` library.\n *\n * Fails fast with an `InsufficientSpaceError` when the destination filesystem cannot\n * hold the advertised `content-length` — the common case being a system temp dir on a\n * RAM-backed tmpfs that is far smaller than the SDK/tools archives.\n */\nexport async function downloadFile(opts: DownloadOptions): Promise<void> {\n const { url, dest, progress, abortSignal } = opts;\n const proto = url.startsWith('https') ? https : http;\n\n return new Promise((resolve, reject) => {\n const s = Math.max(0, Math.min(100, opts.start ?? 0));\n const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));\n\n let settled = false;\n const done = (err?: unknown) => {\n if (settled) return;\n settled = true;\n err ? reject(err) : resolve();\n };\n\n if (abortSignal?.aborted) {\n done(new CancelledError('Download cancelled before start.'));\n return;\n }\n\n const destDir = path.dirname(path.resolve(dest));\n const what = opts.what ?? `the download of '${url}'`;\n\n // Out of space gets the directory-aware explanation; anything else (a bad path,\n // a permission problem) still surfaces as a typed error rather than a raw fs one.\n const writeFailed = (err: unknown): unknown =>\n isOutOfSpaceError(err)\n ? toSpaceError(err, opts.tmpRoot ?? destDir, what)\n : new OniroError(`Error writing '${dest}': ${err instanceof Error ? err.message : String(err)}`, err);\n\n const file = fs.createWriteStream(dest);\n let activeResponse: NodeJS.ReadableStream | undefined;\n\n // Settle only once the partial file is gone, so a caller that retries — or a test\n // that checks — never observes the leftover. Closing before removing keeps Windows\n // happy, where an open file cannot be deleted.\n const failWith = (err: unknown) => {\n file.close(() => fs.rm(dest, { force: true }, () => done(err)));\n };\n\n // A write-stream failure (most often ENOSPC) has no other listener; without this\n // it would surface as an unhandled 'error' event and take the process down.\n file.on('error', (err) => {\n try { (activeResponse as { destroy?: () => void } | undefined)?.destroy?.(); } catch {}\n failWith(writeFailed(err));\n });\n\n const req = proto.get(url, (response) => {\n activeResponse = response;\n if (response.statusCode !== 200) {\n try { response.destroy(); } catch {}\n failWith(new OniroError(`Failed to download '${url}' (HTTP ${response.statusCode})`));\n return;\n }\n\n const total = parseInt(response.headers['content-length'] || '0', 10);\n\n // Refuse to start rather than filling the filesystem (or RAM, on tmpfs) first.\n if (total > 0) {\n try {\n ensureFreeSpace(opts.tmpRoot ?? destDir, total, what);\n } catch (err) {\n try { response.destroy(); } catch {}\n failWith(err);\n return;\n }\n }\n\n let downloaded = 0;\n let lastOverall = Math.round(s);\n\n response.on('data', (chunk: Buffer) => {\n downloaded += chunk.length;\n if (progress && total) {\n const localPercent = Math.min(100, Math.round((downloaded / total) * 100));\n const overall = Math.min(100, Math.round(s + (downloaded / total) * r));\n const inc = overall - lastOverall;\n if (inc > 0) {\n progress.report({ message: `Downloading: ${localPercent}%`, increment: inc });\n lastOverall = overall;\n } else {\n progress.report({ message: `Downloading: ${localPercent}%`, increment: 0 });\n }\n }\n });\n\n response.pipe(file);\n\n file.on('finish', () => {\n if (progress) {\n const endOverall = Math.min(100, Math.round(s + r));\n const inc = endOverall - lastOverall;\n if (inc > 0) progress.report({ message: 'Downloading: 100%', increment: inc });\n }\n file.close((err) => (err ? done(writeFailed(err)) : done()));\n });\n\n abortSignal?.addEventListener('abort', () => {\n response.destroy();\n failWith(new CancelledError('Download cancelled.'));\n });\n });\n\n req.on('error', (err) => {\n failWith(new OniroError(`Error downloading '${url}': ${err.message}`, err));\n });\n\n abortSignal?.addEventListener('abort', () => {\n req.destroy();\n failWith(new CancelledError('Download cancelled.'));\n });\n });\n}\n\n/**\n * Verify the SHA-256 checksum of a file against an on-disk .sha256 file.\n * The .sha256 file is expected to contain the hex digest as its first whitespace-delimited token.\n */\nexport async function verifySha256(filePath: string, sha256Path: string): Promise<void> {\n const expected = fs.readFileSync(sha256Path, 'utf8').split(/\\s+/)[0]!;\n const hash = crypto.createHash('sha256');\n await pipelineAsync(fs.createReadStream(filePath), hash);\n const actual = hash.digest('hex');\n if (actual !== expected) {\n throw new ChecksumMismatchError(expected, actual);\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { pipeline } from 'node:stream';\nimport { promisify } from 'node:util';\nimport * as tar from 'tar';\nimport StreamZip from 'node-stream-zip';\nimport type { ProgressReporter } from '../ports/progress.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\n\nconst pipelineAsync = promisify(pipeline);\n\nexport interface ExtractZipOptions {\n zipPath: string;\n dest: string;\n progress?: ProgressReporter;\n /** Overall progress start offset (0..100). Default 0. */\n start?: number;\n /** Overall progress range to consume (0..100). Default 100. */\n range?: number;\n logger?: Logger;\n}\n\n/**\n * Extract a ZIP to a destination directory, preserving file permissions and following\n * symlinks defensively. Protects against Zip Slip (entries whose paths escape `dest`).\n */\nexport async function extractZipWithProgress(opts: ExtractZipOptions): Promise<void> {\n const { zipPath, dest, progress } = opts;\n const logger = opts.logger ?? noopLogger;\n\n const zip = new (StreamZip as unknown as { async: new (cfg: { file: string }) => StreamZipAsync }).async({ file: zipPath });\n const entries = await zip.entries();\n const files = Object.values(entries);\n const total = files.length || 1;\n\n const s = Math.max(0, Math.min(100, opts.start ?? 0));\n const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));\n\n let processed = 0;\n let lastOverall = Math.round(s);\n\n await fs.promises.mkdir(dest, { recursive: true });\n const destRoot = path.resolve(dest);\n\n const safeResolveTarget = (entryName: string): string => {\n const resolved = path.resolve(destRoot, entryName);\n const rel = path.relative(destRoot, resolved);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new OniroError(`Blocked ZIP entry with illegal path: ${entryName}`);\n }\n return resolved;\n };\n\n try {\n for (const file of files) {\n const entryName = file.name;\n const targetPath = safeResolveTarget(entryName);\n const attr = file.attr ? (file.attr >>> 16) : 0;\n const isSymlink = 'isSymbolicLink' in file\n ? Boolean(file.isSymbolicLink)\n : (attr & 0o170000) === 0o120000;\n\n if (file.isDirectory) {\n await fs.promises.mkdir(targetPath, { recursive: true });\n } else if (isSymlink) {\n await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });\n const linkTargetBuffer = await zip.entryData(file);\n const linkTarget = linkTargetBuffer.toString('utf8');\n try {\n const isWin = os.platform() === 'win32';\n await fs.promises.symlink(linkTarget, targetPath, isWin ? 'file' : undefined);\n } catch (e) {\n logger.warn(`Failed to create symlink at ${targetPath}: ${String(e)}`);\n }\n } else {\n await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });\n const readStream = await zip.stream(file);\n const writeStream = fs.createWriteStream(targetPath);\n await pipelineAsync(readStream, writeStream);\n if (attr > 0) {\n try {\n await fs.promises.chmod(targetPath, attr & 0o777);\n } catch {\n // Best-effort: Windows or filesystems without POSIX perms — ignore.\n }\n }\n }\n\n processed++;\n if (progress) {\n const localPercent = Math.min(100, Math.round((processed / total) * 100));\n const overall = Math.min(100, Math.round(s + (processed / total) * r));\n const inc = overall - lastOverall;\n if (inc > 0) {\n progress.report({ message: `Extracting: ${localPercent}%`, increment: inc });\n lastOverall = overall;\n } else {\n progress.report({ message: `Extracting: ${localPercent}%`, increment: 0 });\n }\n }\n }\n } finally {\n await zip.close();\n }\n\n if (progress) {\n const endOverall = Math.min(100, Math.round(s + r));\n const inc = endOverall - lastOverall;\n if (inc > 0) progress.report({ message: 'Extracting: 100%', increment: inc });\n }\n}\n\n/**\n * Extract a tar/tar.gz/tar.bz2 archive. Wraps `tar.x`.\n */\nexport async function extractTarball(tarPath: string, dest: string, strip = 0): Promise<void> {\n await tar.x({ file: tarPath, cwd: dest, strip });\n}\n\n// node-stream-zip's TypeScript types aren't great; this is the minimal shape we use.\ninterface ZipEntry {\n name: string;\n isDirectory: boolean;\n isSymbolicLink?: boolean;\n attr?: number;\n}\ninterface StreamZipAsync {\n entries(): Promise<Record<string, ZipEntry>>;\n entryData(entry: ZipEntry): Promise<Buffer>;\n stream(entry: ZipEntry): Promise<NodeJS.ReadableStream>;\n close(): Promise<void>;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { ALL_SDKS } from './constants.js';\nimport { getSdkRootDir } from './paths.js';\nimport { getOsFolder } from './platform.js';\nimport type { ConfigProvider } from '../ports/config.js';\n\nexport interface SdkInfo {\n version: string;\n api: string;\n installed: boolean;\n}\n\n/**\n * List supported SDKs annotated with whether they are installed for the current OS.\n * Sorted by API descending (newest first).\n */\nexport function getSupportedSdksForUi(config: ConfigProvider): SdkInfo[] {\n const base = path.join(getSdkRootDir(config), getOsFolder());\n return ALL_SDKS.map((sdk) => ({\n version: sdk.version,\n api: sdk.api,\n installed: fs.existsSync(path.join(base, sdk.api)),\n })).sort((a, b) => Number(b.api) - Number(a.api));\n}\n\n/**\n * Return the SDK versions that have at least one OS-folder install in `sdkRootDir`.\n * Scans `linux`, `darwin`, `windows` so the list is consistent across machines that\n * share an SDK root over a network mount.\n */\nexport function getInstalledSdks(config: ConfigProvider): string[] {\n const sdkRoot = getSdkRootDir(config);\n const versions = new Set<string>();\n if (!fs.existsSync(sdkRoot)) return [];\n\n for (const osFolder of ['linux', 'darwin', 'windows'] as const) {\n const osPath = path.join(sdkRoot, osFolder);\n if (!fs.existsSync(osPath) || !fs.statSync(osPath).isDirectory()) continue;\n for (const api of fs.readdirSync(osPath)) {\n const apiPath = path.join(osPath, api);\n if (fs.statSync(apiPath).isDirectory()) versions.add(api);\n }\n }\n return ALL_SDKS.filter((sdk) => versions.has(sdk.api)).map((sdk) => sdk.version);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { getSdkRootDir } from './paths.js';\nimport type { ConfigProvider } from '../ports/config.js';\n\n/**\n * Remove an installed SDK for a given API level, across all OS folders.\n * Returns true if at least one folder was deleted.\n */\nexport function removeSdk(config: ConfigProvider, api: string): boolean {\n const sdkRoot = getSdkRootDir(config);\n let removed = false;\n for (const osFolder of ['linux', 'darwin', 'windows']) {\n const sdkPath = path.join(sdkRoot, osFolder, api);\n if (fs.existsSync(sdkPath)) {\n fs.rmSync(sdkPath, { recursive: true, force: true });\n removed = true;\n }\n }\n return removed;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { ProgressReporter } from '../ports/progress.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { CancelledError, OniroError } from '../ports/errors.js';\nimport { OHOS_URL_BASE } from './constants.js';\nimport { getSdkFilename } from './platform.js';\nimport { getSdkRootDir } from './paths.js';\nimport { downloadFile, verifySha256 } from './download.js';\nimport { extractTarball, extractZipWithProgress } from './extract.js';\nimport { movePath } from './move.js';\nimport { createInstallTempDir, removeTempWorkDir, toSpaceError } from './tmp.js';\n\nexport interface InstallSdkOptions {\n config: ConfigProvider;\n version: string;\n api: string;\n progress?: ProgressReporter;\n abortSignal?: AbortSignal;\n logger?: Logger;\n /**\n * Scratch directory for the download/extract temporaries. Overrides the `tmpDir`\n * config key and the default location next to the install target.\n */\n tmpDir?: string;\n}\n\n/**\n * Download and install an OpenHarmony SDK release into `<sdkRootDir>/<osFolder>/<api>`.\n *\n * Progress budget (overall 0..100):\n * 0..35 SDK archive download\n * 35..45 Checksum download\n * 45..50 Checksum verify\n * 50..60 Tarball extract\n * 60..95 Component ZIP extracts\n * 95..100 Finalize + cleanup\n */\nexport async function downloadAndInstallSdk(opts: InstallSdkOptions): Promise<void> {\n const { config, version, api, progress, abortSignal } = opts;\n const logger = opts.logger ?? noopLogger;\n\n const { filename, osFolder, strip } = getSdkFilename(version);\n const urlBase = config.get('sdkUrlBase', OHOS_URL_BASE);\n const downloadUrl = `${urlBase}/${version}-Release/${filename}`;\n const sha256Url = `${downloadUrl}.sha256`;\n\n const what = `the SDK ${version} install`;\n const sdkRoot = getSdkRootDir(config);\n const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({\n config,\n override: opts.tmpDir,\n installRoot: sdkRoot,\n prefix: 'oniro-sdk-',\n logger,\n });\n const tarPath = path.join(tmpDir, filename);\n const sha256Path = path.join(tmpDir, `${filename}.sha256`);\n const extractDir = path.join(tmpDir, 'extract');\n fs.mkdirSync(extractDir);\n\n const sdkInstallDir = path.join(sdkRoot, osFolder, api);\n fs.mkdirSync(path.dirname(sdkInstallDir), { recursive: true });\n\n const checkCancelled = () => {\n if (abortSignal?.aborted) throw new CancelledError();\n };\n\n try {\n progress?.report({ message: 'Downloading SDK archive...', increment: 0 });\n await downloadFile({ url: downloadUrl, dest: tarPath, progress, abortSignal, start: 0, range: 35, what, tmpRoot });\n\n progress?.report({ message: 'Downloading checksum...', increment: 0 });\n await downloadFile({ url: sha256Url, dest: sha256Path, progress, abortSignal, start: 35, range: 10, what, tmpRoot });\n\n progress?.report({ message: 'Verifying checksum...', increment: 0 });\n await verifySha256(tarPath, sha256Path);\n progress?.report({ message: 'Verifying checksum...', increment: 5 });\n\n checkCancelled();\n\n progress?.report({ message: 'Extracting SDK (this may take a while)...', increment: 0 });\n await extractTarball(tarPath, extractDir, strip);\n progress?.report({ message: 'Extracting SDK (this may take a while)...', increment: 10 });\n\n checkCancelled();\n\n const osContentPath = path.join(extractDir, osFolder);\n if (!fs.existsSync(osContentPath)) {\n throw new OniroError(\n `Expected folder '${osFolder}' not found in extracted SDK. Tarball layout may have changed.`,\n );\n }\n const zipFiles = fs.readdirSync(osContentPath).filter((n) => n.endsWith('.zip'));\n\n const componentsStart = 60;\n const componentsBudget = 35;\n const n = zipFiles.length;\n if (n === 0) {\n progress?.report({ message: 'No SDK component ZIPs found.', increment: componentsBudget });\n } else {\n progress?.report({ message: 'Extracting SDK components...', increment: 0 });\n }\n\n const base = n > 0 ? Math.floor(componentsBudget / n) : 0;\n let rem = n > 0 ? componentsBudget % n : 0;\n let cursor = componentsStart;\n\n for (const zipFile of zipFiles) {\n checkCancelled();\n logger.info(`Extracting component ${zipFile}`);\n const zipPath = path.join(osContentPath, zipFile);\n const thisBudget = base + (rem > 0 ? 1 : 0);\n if (rem > 0) rem--;\n await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });\n cursor += thisBudget;\n fs.unlinkSync(zipPath);\n }\n\n progress?.report({ message: 'Finalizing installation...', increment: 0 });\n if (fs.existsSync(sdkInstallDir)) {\n fs.rmSync(sdkInstallDir, { recursive: true, force: true });\n }\n movePath(osContentPath, sdkInstallDir);\n progress?.report({ message: 'Finalizing installation...', increment: 3 });\n\n progress?.report({ message: 'Cleaning up...', increment: 0 });\n removeTempWorkDir(tmpDir, tmpRoot);\n progress?.report({ message: 'Cleaning up...', increment: 2 });\n } catch (err) {\n const wrapped = toSpaceError(err, tmpRoot, what);\n logger.error(`SDK install failed: ${wrapped instanceof Error ? wrapped.message : String(wrapped)}`);\n removeTempWorkDir(tmpDir, tmpRoot);\n throw wrapped;\n }\n}\n","import * as fs from 'node:fs';\n\n/**\n * Move a file or directory from `src` to `dest`.\n *\n * Prefers an atomic `rename`, but transparently falls back to a recursive\n * copy-then-remove when the two paths live on different filesystems. `rename(2)`\n * fails with `EXDEV` across mount boundaries, which happens routinely during\n * install: the OS temp dir (where archives are extracted) and the install target\n * are frequently separate devices — a `tmpfs` `/tmp` with an on-disk home, a Docker\n * volume or bind mount at the install path, an overlay vs. a mounted cache, etc.\n *\n * Callers are expected to have already cleared `dest` if it must be replaced\n * (both current callers `rmSync` first). The copy preserves file modes and\n * symlinks (Node's default `cp` behavior), which the SDK/toolchains rely on.\n */\nexport function movePath(src: string, dest: string): void {\n try {\n fs.renameSync(src, dest);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'EXDEV') throw err;\n // Cross-device move: copy the tree, then drop the source.\n fs.cpSync(src, dest, { recursive: true });\n fs.rmSync(src, { recursive: true, force: true });\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport type { ConfigProvider } from '../ports/config.js';\nimport { defaultPaths } from '../ports/config.js';\nimport type { ProgressReporter } from '../ports/progress.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError, UnsupportedPlatformError } from '../ports/errors.js';\nimport { getCmdToolsPath, getHdcPath } from '../sdk/paths.js';\nimport { downloadFile } from '../sdk/download.js';\nimport { extractZipWithProgress } from '../sdk/extract.js';\nimport { movePath } from '../sdk/move.js';\nimport { buildCmdWrapper, needsCmdWrapper } from '../hdc/spawnCompat.js';\nimport { createInstallTempDir, removeTempWorkDir, toSpaceError } from '../sdk/tmp.js';\n\n/**\n * Resolve the per-platform download URL for the OpenHarmony command-line tools.\n *\n * Only Linux has a public download URL on the Huawei mirror. Windows and macOS\n * builds are gated behind the Huawei developer portal: users must download the\n * ZIP manually and pass it via `--from-zip`, or self-host the archive and point\n * `cmdToolsUrlWindows` / `cmdToolsUrlMac` at it.\n *\n * @param platform Defaults to the current host. Override for testing.\n */\nexport function getCmdToolsDownloadUrl(config: ConfigProvider, platform: NodeJS.Platform = os.platform()): string {\n if (platform === 'linux') {\n return config.get('cmdToolsUrlLinux', defaultPaths.cmdToolsUrlLinux);\n }\n if (platform === 'win32') {\n const url = config.get('cmdToolsUrlWindows', '');\n if (!url) {\n throw new OniroError(\n 'No Windows command-line tools URL configured. The Huawei mirror does not host a public Windows build; ' +\n 'download the ZIP from the Huawei developer portal and run `oniro-app cmdtools install --from-zip <path>`, ' +\n 'or set ONIRO_CMD_TOOLS_URL_WINDOWS to a self-hosted URL.',\n );\n }\n return url;\n }\n if (platform === 'darwin') {\n const url = config.get('cmdToolsUrlMac', '');\n if (!url) {\n throw new OniroError(\n 'No macOS command-line tools URL configured. The Huawei mirror does not host a public macOS build; ' +\n 'download the ZIP from the Huawei developer portal and run `oniro-app cmdtools install --from-zip <path>`, ' +\n 'or set ONIRO_CMD_TOOLS_URL_MAC to a self-hosted URL.',\n );\n }\n return url;\n }\n throw new UnsupportedPlatformError(platform);\n}\n\n/**\n * Locate the extracted command-line tools' source root within a temp extraction folder.\n * Tries known top-level names, then any subdirectory containing a `bin/` folder.\n */\nexport function findCmdToolsSourceDir(extractPath: string): string {\n const known = [\n path.join(extractPath, 'command-line-tools'),\n path.join(extractPath, 'oh-command-line-tools'),\n path.join(extractPath, 'commandline-tools'),\n ];\n for (const c of known) {\n if (fs.existsSync(c)) return c;\n }\n const entries = fs\n .readdirSync(extractPath, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => path.join(extractPath, e.name));\n for (const dir of entries) {\n if (fs.existsSync(path.join(dir, 'bin'))) return dir;\n }\n throw new OniroError('Could not locate command line tools folder in the extracted archive.');\n}\n\nexport interface InstallCmdToolsOptions {\n config: ConfigProvider;\n progress?: ProgressReporter;\n abortSignal?: AbortSignal;\n logger?: Logger;\n /** Skip download and install from a local zip the caller already has. */\n localZipPath?: string;\n /**\n * Scratch directory for the download/extract temporaries. Overrides the `tmpDir`\n * config key and the default location next to the install target.\n */\n tmpDir?: string;\n}\n\n/**\n * Install the OpenHarmony command-line tools into `<cmdToolsPath>`.\n * Either downloads from the platform-specific URL or installs from a caller-supplied ZIP.\n */\nexport async function installCmdTools(opts: InstallCmdToolsOptions): Promise<void> {\n const { config, progress, abortSignal } = opts;\n const logger = opts.logger ?? noopLogger;\n const CMD_PATH = getCmdToolsPath(config);\n const what = 'the command-line tools install';\n\n const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({\n config,\n override: opts.tmpDir,\n installRoot: path.dirname(CMD_PATH),\n prefix: 'oniro-cmdtools-',\n logger,\n });\n const zipPath = opts.localZipPath ?? path.join(tmpDir, 'oh-command-line-tools.zip');\n const extractPath = path.join(tmpDir, 'oh-command-line-tools');\n\n try {\n if (!opts.localZipPath) {\n const url = getCmdToolsDownloadUrl(config);\n progress?.report({ message: 'Downloading command line tools...', increment: 0 });\n await downloadFile({ url, dest: zipPath, progress, abortSignal, start: 0, range: 50, what, tmpRoot });\n }\n\n progress?.report({ message: 'Extracting tools...', increment: 0 });\n await extractZipWithProgress({ zipPath, dest: extractPath, progress, start: 50, range: 45, logger });\n\n fs.mkdirSync(CMD_PATH, { recursive: true });\n const srcDir = findCmdToolsSourceDir(extractPath);\n\n for (const entry of fs.readdirSync(srcDir)) {\n const src = path.join(srcDir, entry);\n const dest = path.join(CMD_PATH, entry);\n if (fs.statSync(src).isDirectory()) {\n if (fs.existsSync(dest)) fs.rmSync(dest, { recursive: true, force: true });\n movePath(src, dest);\n } else {\n fs.copyFileSync(src, dest);\n }\n }\n\n const binDir = path.join(CMD_PATH, 'bin');\n if (fs.existsSync(binDir) && os.platform() !== 'win32') {\n for (const file of fs.readdirSync(binDir)) {\n fs.chmodSync(path.join(binDir, file), 0o755);\n }\n }\n\n progress?.report({ message: 'Finalizing installation...', increment: 5 });\n progress?.report({ message: 'Cleaning up...', increment: 0 });\n } catch (err) {\n throw toSpaceError(err, tmpRoot, what);\n } finally {\n removeTempWorkDir(tmpDir, tmpRoot);\n }\n}\n\nexport interface CmdToolsStatus {\n installed: boolean;\n status: string;\n /** Install directory (the configured `cmdToolsPath`). */\n path: string;\n /** Which SDK flavour the tools ship; see {@link detectCmdToolsFlavour}. Set when installed. */\n flavour?: CmdToolsFlavour;\n /** The hdc binary commands use, and whether it exists. */\n hdc: { path: string; exists: boolean };\n}\n\nexport type CmdToolsFlavour = 'HarmonyOS' | 'OpenHarmony';\n\n/**\n * The flavour of a command-line tools install: `HarmonyOS` when it bundles the\n * HarmonyOS SDK (`sdk/default/hms`, as the Huawei developer-portal download\n * does), otherwise `OpenHarmony`. codelinter only fully checks projects of its\n * own flavour (`runtimeOS` in build-profile.json5).\n */\nexport function detectCmdToolsFlavour(cmdToolsPath: string): CmdToolsFlavour {\n return fs.existsSync(path.join(cmdToolsPath, 'sdk', 'default', 'hms')) ? 'HarmonyOS' : 'OpenHarmony';\n}\n\n/**\n * Reports whether ohpm is present at the configured path, and if so its version,\n * flavour, and the hdc binary in use. Prefers reading `version.txt`\n * (`# Version: x.y.z`) before falling back to executing the binary with `-v`.\n */\nexport function getCmdToolsStatus(config: ConfigProvider): CmdToolsStatus {\n const cmdPath = getCmdToolsPath(config);\n const hdcPath = getHdcPath(config);\n const base = { path: cmdPath, hdc: { path: hdcPath, exists: fs.existsSync(hdcPath) } };\n const binDir = path.join(cmdPath, 'bin');\n const candidates = os.platform() === 'win32'\n ? ['ohpm.exe', 'ohpm.cmd', 'ohpm.bat', 'ohpm']\n : ['ohpm'];\n const bin = candidates.map((c) => path.join(binDir, c)).find((p) => fs.existsSync(p));\n if (!bin) {\n return { installed: false, status: 'Not installed', ...base };\n }\n const installed = { installed: true, ...base, flavour: detectCmdToolsFlavour(cmdPath) };\n\n // Prefer version.txt.\n try {\n const versionFile = path.join(cmdPath, 'version.txt');\n if (fs.existsSync(versionFile)) {\n const content = fs.readFileSync(versionFile, 'utf8');\n for (const line of content.split(/\\r?\\n/)) {\n const m = line.match(/^\\s*#\\s*Version:\\s*(.+)$/);\n if (m?.[1]) return { ...installed, status: `Installed (${m[1].trim()})` };\n }\n }\n } catch {\n // Fall through to exec.\n }\n\n try {\n // `ohpm` is a .bat wrapper on Windows, which cannot be spawned directly\n // (EINVAL since Node 20.12.2) — go through cmd.exe there.\n const wrapped = needsCmdWrapper(bin);\n const probe = wrapped ? buildCmdWrapper(bin, ['-v']) : { command: bin, args: ['-v'] };\n const res = spawnSync(probe.command, probe.args, {\n encoding: 'utf8',\n windowsVerbatimArguments: wrapped,\n });\n if (res.error || res.status !== 0) throw res.error ?? new Error(`exit ${String(res.status)}`);\n const version = res.stdout.trim();\n return { ...installed, status: `Installed (${version})` };\n } catch {\n return { ...installed, status: 'Installed (version unknown)' };\n }\n}\n\nexport function isCmdToolsInstalled(config: ConfigProvider): boolean {\n return getCmdToolsStatus(config).installed;\n}\n\nexport function removeCmdTools(config: ConfigProvider): void {\n const cmdPath = getCmdToolsPath(config);\n if (fs.existsSync(cmdPath)) {\n fs.rmSync(cmdPath, { recursive: true, force: true });\n }\n}\n","import * as path from 'node:path';\nimport { spawn, type ChildProcess, type SpawnOptions } from 'node:child_process';\nimport { OniroError } from '../ports/errors.js';\n\n/**\n * Windows batch wrappers (`.bat` / `.cmd`) cannot be executed by\n * `CreateProcess` — they are scripts interpreted by `cmd.exe`. Node used to\n * paper over that by silently prepending `cmd.exe /c`, but the fix for\n * CVE-2024-27980 (Node 18.20.2 / 20.12.2 / 21.7.3 and later) removed the\n * implicit shell: `spawn('foo.cmd', args)` with `shell: false` now throws a\n * bare `Error: spawn EINVAL`.\n *\n * That matters here because the OpenHarmony command-line tools ship as batch\n * wrappers on Windows (`ohpm.bat`, `hvigorw.bat`, `codelinter.bat`), so every\n * build and lint invocation hit that throw.\n *\n * We therefore invoke `cmd.exe /d /s /c \"<command> <args...>\"` explicitly.\n * Doing it ourselves — rather than passing `shell: true` — is what preserves\n * the \"arguments are never word-split\" guarantee the rest of this package\n * relies on: `shell: true` hands `cmd.exe` the raw, unescaped join of command\n * and args, reintroducing exactly the injection surface `runProcess` exists to\n * avoid. The escaping below follows https://qntm.org/cmd (the same algorithm\n * `cross-spawn` uses).\n */\n\nconst WINDOWS_BATCH_RE = /\\.(bat|cmd)$/i;\n\n/** Characters `cmd.exe` treats specially, including whitespace. */\nconst CMD_META_RE = /([()[\\]%!^\"`<>&|;, *?])/g;\n\n/**\n * npm-style shims (`node_modules/.bin/foo.cmd`) forward their arguments with a\n * bare `%*`, so the command line is parsed a second time inside the shim and\n * metacharacters need a second layer of escaping. Ordinary wrappers must NOT\n * be double-escaped — the surplus carets would end up in the argument values.\n */\nconst CMD_SHIM_RE = /node_modules[\\\\/]\\.bin[\\\\/][^\\\\/]+\\.cmd$/i;\n\n/**\n * Characters that cannot be passed through `cmd.exe` without ambiguity.\n *\n * The OpenHarmony wrappers end in `call \"<inner>\\tool.bat\" %*`, and the inner\n * script forwards the same `%*` to node — so every argument is re-parsed by\n * `cmd.exe` twice more after we hand off the command line. Quoting is what\n * survives those hops: metacharacters inside a quoted token stay inert no\n * matter how many times the line is re-parsed.\n *\n * A double quote is the one thing that breaks that. `cmd.exe` has no `\\\"`\n * escape — it simply toggles quote state on every `\"` — so an embedded quote\n * ends the quoted region early and everything after it is re-parsed as\n * command syntax. Newlines and NULs cannot be carried at all. None of the\n * tools invoked here need any of them, so we refuse loudly rather than pass\n * something subtly different from what the caller asked for.\n *\n * Known remaining edge: the wrappers run under `setlocal enabledelayedexpansion`,\n * so a literal `!` in an argument is subject to delayed expansion. It can\n * corrupt a value but not execute anything, and no argument this package builds\n * contains one.\n */\nconst UNSAFE_CMD_CHARS_RE = /[\"\\r\\n\\0]/;\n\n/**\n * True when `command` must be routed through `cmd.exe` to run at all —\n * i.e. we are on Windows and the target is a batch wrapper.\n *\n * `platform` is injectable so the behaviour is unit-testable off Windows.\n */\nexport function needsCmdWrapper(command: string, platform: NodeJS.Platform = process.platform): boolean {\n return platform === 'win32' && WINDOWS_BATCH_RE.test(command);\n}\n\n/**\n * Escape one argument for a `cmd.exe` command line: quote it, double the\n * backslashes that would otherwise escape the closing quote, then caret-escape\n * every metacharacter.\n *\n * `doubleEscapeMetaChars` adds the second caret layer needed by `%*`-forwarding\n * shims — see {@link CMD_SHIM_RE}.\n */\nexport function escapeCmdArgument(arg: string, doubleEscapeMetaChars = false): string {\n let out = String(arg);\n // Backslashes preceding a quote are doubled, and the quote itself escaped.\n out = out.replace(/(\\\\*)\"/g, '$1$1\\\\\"');\n // Trailing backslashes are doubled so they don't escape our closing quote.\n out = out.replace(/(\\\\*)$/, '$1$1');\n out = `\"${out}\"`;\n out = out.replace(CMD_META_RE, '^$1');\n if (doubleEscapeMetaChars) out = out.replace(CMD_META_RE, '^$1');\n return out;\n}\n\n/**\n * Escape the executable path. It is caret-escaped but deliberately NOT quoted:\n * `cmd.exe /s /c \"...\"` strips the outer quotes of the whole line, and a quoted\n * first token confuses that parse. Caret-escaping the spaces is what makes\n * `C:\\Program Files\\...` work.\n */\nexport function escapeCmdCommand(command: string): string {\n return command.replace(CMD_META_RE, '^$1');\n}\n\nexport interface CmdWrapper {\n command: string;\n args: string[];\n}\n\n/**\n * Build the `cmd.exe /d /s /c \"<command> <args...>\"` invocation for a batch\n * wrapper. Pure (no I/O, no spawning) so the escaping is unit-testable on every\n * platform.\n *\n * `/d` skips AutoRun registry commands, `/s` keeps the outer quotes intact,\n * `/c` runs the command and exits.\n *\n * @throws OniroError if the command or any argument contains a character that\n * cannot survive `cmd.exe` unambiguously (see {@link UNSAFE_CMD_CHARS_RE}).\n */\nexport function buildCmdWrapper(command: string, args: readonly string[]): CmdWrapper {\n assertCmdSafe(command, `command ${command}`);\n args.forEach((a, i) => assertCmdSafe(a, `argument ${i} (${a})`));\n\n // Forward slashes in a command path make cmd.exe report \"not recognized\".\n const normalized = path.normalize(command);\n const double = CMD_SHIM_RE.test(normalized);\n const line = [escapeCmdCommand(normalized), ...args.map((a) => escapeCmdArgument(a, double))].join(' ');\n return {\n command: process.env.ComSpec ?? process.env.COMSPEC ?? 'cmd.exe',\n args: ['/d', '/s', '/c', `\"${line}\"`],\n };\n}\n\nfunction assertCmdSafe(value: string, label: string): void {\n if (UNSAFE_CMD_CHARS_RE.test(value)) {\n throw new OniroError(\n `Cannot run a Windows batch wrapper with a quote, newline or NUL in the ${label}: ` +\n 'cmd.exe cannot pass it through unambiguously.',\n );\n }\n}\n\n/**\n * `child_process.spawn`, but able to run Windows batch wrappers.\n *\n * Identical to `spawn` everywhere else — on POSIX, and on Windows for real\n * executables, the command and args are passed straight through with\n * `shell: false`.\n */\nexport function spawnCompat(\n command: string,\n args: readonly string[],\n options: SpawnOptions = {},\n): ChildProcess {\n if (!needsCmdWrapper(command)) {\n return spawn(command, [...args], { ...options, shell: false });\n }\n const wrapped = buildCmdWrapper(command, args);\n return spawn(wrapped.command, wrapped.args, {\n ...options,\n shell: false,\n // The line is already escaped; stop Node from re-quoting it.\n windowsVerbatimArguments: true,\n });\n}\n\n/**\n * Kill a child and everything it started.\n *\n * On Windows a signal only reaches the process we spawned — killing the\n * `cmd.exe` wrapper leaves the Node/hvigor process it launched running, so an\n * aborted or timed-out build would keep holding the project's output files.\n * `taskkill /T /F` tears down the whole tree instead.\n */\nexport function killProcessTree(child: ChildProcess): void {\n if (process.platform === 'win32' && typeof child.pid === 'number') {\n try {\n const killer = spawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore' });\n // taskkill missing from PATH must not raise an unhandled 'error' event.\n killer.on('error', () => {\n try {\n child.kill('SIGKILL');\n } catch {\n /* already gone */\n }\n });\n return;\n } catch {\n /* fall through to the plain kill below */\n }\n }\n try {\n child.kill('SIGKILL');\n } catch {\n /* already gone */\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\n\nconst DAEMON_ROOT_KEY_COMPONENT_LENGTH = 16;\nconst DAEMON_SALT_KEY_LENGTH = 16;\nconst DAEMON_WORK_KEY_LENGTH = 16;\nconst KEY_FILE_DIRECTORY_PERMISSIONS = 0o755;\nconst KEY_FILE_PERMISSIONS = 0o600;\n\nconst COMPONENT = Buffer.from([\n 49, 243, 9, 115, 214, 175, 91, 184, 211, 190, 177, 88, 101, 131, 192, 119,\n]);\n\n/**\n * Encrypts data using AES-128-GCM.\n * Output layout: [4-byte BE length][12-byte IV][ciphertext][16-byte auth tag].\n */\nfunction encrypt(key: Buffer, data: Buffer): Buffer {\n const iv = crypto.randomBytes(12);\n const cipher = crypto.createCipheriv('aes-128-gcm', key, iv);\n const ciphertext = Buffer.concat([cipher.update(data), cipher.final()]);\n const authTag = cipher.getAuthTag();\n const totalLength = ciphertext.length + authTag.length;\n const out = Buffer.alloc(4 + iv.length + ciphertext.length + authTag.length);\n out.writeUInt32BE(totalLength, 0);\n iv.copy(out, 4);\n ciphertext.copy(out, 16);\n authTag.copy(out, 16 + ciphertext.length);\n return out;\n}\n\nfunction decrypt(key: Buffer, data: Buffer): Buffer {\n const totalLength = data.readUInt32BE(0);\n const iv = data.subarray(4, 16);\n const ciphertextLength = totalLength - 16;\n const ciphertext = data.subarray(16, 16 + ciphertextLength);\n const authTag = data.subarray(16 + ciphertextLength);\n const decipher = crypto.createDecipheriv('aes-128-gcm', key, iv);\n decipher.setAuthTag(authTag);\n return Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n}\n\nfunction xorBuffers(buffers: Buffer[]): Buffer {\n if (buffers.length === 0) {\n throw new Error('No buffers provided for XOR.');\n }\n const result = Buffer.from(buffers[0]!);\n for (let i = 1; i < buffers.length; i++) {\n const buf = buffers[i]!;\n if (buf.length !== result.length) {\n throw new Error('Buffers have different lengths in XOR.');\n }\n for (let j = 0; j < result.length; j++) {\n result[j] = result[j]! ^ buf[j]!;\n }\n }\n return result;\n}\n\nfunction getRootKey(fdComponents: Buffer[], salt: Buffer): Buffer {\n const components = fdComponents.concat([COMPONENT]);\n const xored = xorBuffers(components);\n return crypto.pbkdf2Sync(xored.toString(), salt, 10000, 16, 'sha256');\n}\n\nfunction createAndStoreKey(dir: string, keyLength: number): Buffer {\n const key = crypto.randomBytes(keyLength);\n const hash = crypto.createHash('sha256').update(key).digest('hex');\n const filePath = path.join(dir, hash);\n fs.writeFileSync(filePath, key);\n fs.chmodSync(filePath, KEY_FILE_PERMISSIONS);\n return key;\n}\n\nfunction createAndStoreEnKey(rootKey: Buffer, ceDir: string): void {\n const workKey = crypto.randomBytes(DAEMON_WORK_KEY_LENGTH);\n const encrypted = encrypt(rootKey, workKey);\n const hash = crypto.createHash('sha256').update(encrypted).digest('hex');\n const filePath = path.join(ceDir, hash);\n fs.writeFileSync(filePath, encrypted);\n fs.chmodSync(filePath, KEY_FILE_PERMISSIONS);\n}\n\n/**\n * Generates the signing-material directory tree: fd/{0,1,2}, ac, ce.\n * Each subfolder contains a randomly-named keyfile derived as described in\n * the OpenHarmony hap-sign-tool reference implementation.\n */\nexport function createMaterial(materialPath: string): void {\n fs.mkdirSync(materialPath, { recursive: true });\n fs.chmodSync(materialPath, KEY_FILE_DIRECTORY_PERMISSIONS);\n\n const fdDir = path.join(materialPath, 'fd');\n const acDir = path.join(materialPath, 'ac');\n const ceDir = path.join(materialPath, 'ce');\n\n fs.mkdirSync(fdDir, { recursive: true });\n fs.mkdirSync(acDir, { recursive: true });\n fs.mkdirSync(ceDir, { recursive: true });\n\n const fdSubDirs = ['0', '1', '2'];\n const fdComponents: Buffer[] = [];\n for (const sub of fdSubDirs) {\n const subDir = path.join(fdDir, sub);\n fs.mkdirSync(subDir, { recursive: true });\n const comp = createAndStoreKey(subDir, DAEMON_ROOT_KEY_COMPONENT_LENGTH);\n fdComponents.push(comp);\n }\n\n const salt = createAndStoreKey(acDir, DAEMON_SALT_KEY_LENGTH);\n const rootKey = getRootKey(fdComponents, salt);\n createAndStoreEnKey(rootKey, ceDir);\n}\n\nfunction readSingleFile(dir: string): Buffer {\n if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {\n throw new Error(`Missing signing material directory: ${dir}`);\n }\n const files = fs.readdirSync(dir).filter((f) => f !== '.DS_Store');\n if (files.length !== 1) {\n throw new Error(`Signing material in ${dir} is illegal (expected exactly one file).`);\n }\n return fs.readFileSync(path.join(dir, files[0]!));\n}\n\n/**\n * Re-derives the work key from an existing material directory.\n */\nexport function getKey(materialPath: string): Buffer {\n if (!fs.existsSync(materialPath) || !fs.statSync(materialPath).isDirectory()) {\n throw new Error('Material directory does not exist.');\n }\n\n const fdDir = path.join(materialPath, 'fd');\n const fdComponents = ['0', '1', '2'].map((sub) => readSingleFile(path.join(fdDir, sub)));\n const salt = readSingleFile(path.join(materialPath, 'ac'));\n const rootKey = getRootKey(fdComponents, salt);\n const workMaterial = readSingleFile(path.join(materialPath, 'ce'));\n return decrypt(rootKey, workMaterial);\n}\n\n/**\n * Encrypts a password using the work key derived from `materialPath`.\n * Returns the encrypted blob as a hex string (the format expected in build-profile.json5).\n */\nexport function encryptPwd(password: string, materialPath: string): string {\n const key = getKey(materialPath);\n const pwdBuffer = Buffer.from(password, 'utf-8');\n return encrypt(key, pwdBuffer).toString('hex');\n}\n\n/**\n * Inverse of `encryptPwd`. Exposed for parity with the original CLI.\n */\nexport function decryptPwd(encryptedHex: string, materialPath: string): string {\n const key = getKey(materialPath);\n const encryptedBuffer = Buffer.from(encryptedHex, 'hex');\n return decrypt(key, encryptedBuffer).toString('utf-8');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { execFileSync } from 'node:child_process';\nimport JSON5 from 'json5';\nimport { encryptPwd, createMaterial } from './encryptKey.js';\nimport { OPEN_HARMONY_APPLICATION_CERT } from './applicationCert.js';\nimport { detectProjectSdkVersion } from '../sdk/detectProjectSdk.js';\nimport { ALL_SDKS } from '../sdk/constants.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError, SdkNotInstalledError } from '../ports/errors.js';\n\n/** Ability Privilege Level written into the profile's `bundle-info.apl`. */\nexport type Apl = 'normal' | 'system_basic' | 'system_core';\n\n/** App feature written into the profile's `bundle-info.app-feature`. */\nexport type AppFeature = 'hos_normal_app' | 'hos_system_app';\n\nexport const APL_VALUES: readonly Apl[] = ['normal', 'system_basic', 'system_core'];\nexport const APP_FEATURE_VALUES: readonly AppFeature[] = ['hos_normal_app', 'hos_system_app'];\n\n/** Keystore passwords. These must match the keystore in use. */\nexport interface SigningPasswords {\n store: string;\n key: string;\n}\n\nconst DEFAULT_PASSWORDS: SigningPasswords = { store: '123456', key: '123456' };\n\n/**\n * Which signing key pairs with the chosen `apl`.\n *\n * - `'profile-release'` — the **OpenHarmony Application Profile Release** key.\n * Default for apl=normal. Matches the cert chain that ships with the SDK\n * (`OpenHarmonyProfileRelease.pem`). What `hvigor` uses for ordinary apps.\n *\n * - `'application-release'` — the **OpenHarmony Application Release** key.\n * Required for apl=system_basic|system_core. BMS's parse-profile-prop check\n * rejects HAPs whose `distribution-certificate` subject is \"Application\n * Profile Release\" when the HAP requests permissions above its apl. The\n * matching cert chain (`OpenHarmonyApplication.cer`) is not shipped in the\n * SDK, so we ship it ourselves under `applicationCert.ts`.\n */\nexport type SigningKind = 'profile-release' | 'application-release';\n\n/** @internal exposed for tests. */\nexport function pickSigningKind(apl: Apl): SigningKind {\n return apl === 'normal' ? 'profile-release' : 'application-release';\n}\n\ninterface SigningKindConfig {\n /** keystore alias used by hvigor's SignHap task. */\n hapKeyAlias: string;\n /** filename of the cert chain inside `signatures/` referenced by build-profile.json5 `certpath`. */\n certBasename: string;\n}\n\nconst SIGNING_KIND_CONFIG: Record<SigningKind, SigningKindConfig> = {\n 'profile-release': {\n hapKeyAlias: 'openharmony application profile release',\n certBasename: 'OpenHarmonyProfileRelease.pem',\n },\n 'application-release': {\n hapKeyAlias: 'OpenHarmony Application Release',\n certBasename: 'OpenHarmonyApplication.cer',\n },\n};\n\nexport interface GenerateSigningConfigsOptions {\n /** Absolute path to the OpenHarmony project (the folder containing build-profile.json5). */\n projectDir: string;\n /** Absolute path to the OS-specific SDK home (the folder containing API-version subfolders). */\n sdkHome: string;\n /**\n * APL level to write into the profile's `bundle-info.apl`. Defaults to `'normal'`.\n * Apps requesting permissions above `normal` (e.g. `ohos.permission.GET_WIFI_INFO_INTERNAL`)\n * need `system_basic` or `system_core` — otherwise `bm install` fails with\n * `grant request permissions failed`.\n */\n apl?: Apl;\n /**\n * App feature to write into `bundle-info.app-feature`. Defaults to `'hos_normal_app'`\n * when `apl='normal'`, otherwise `'hos_system_app'`.\n */\n appFeature?: AppFeature;\n /**\n * Permission names to write into the profile's `acls.allowed-acls`. Required for\n * apps that request permissions above their `apl` (e.g. a system_basic app\n * requesting `ohos.permission.CAPTURE_SCREEN`). When omitted, the template's\n * existing `allowed-acls` is left alone.\n */\n acls?: string[];\n /**\n * Privileges to write into the profile's `app-privilege-capabilities`, e.g.\n * `AllowAppUsePrivilegeExtension` for an app that declares a privileged extension\n * ability (else install fails with 9568344 \"not allow use privilege extension\"),\n * `AllowAppMultiProcess` or `AllowAppDesktopIconHide`. When omitted, the\n * template's value is left alone.\n */\n appPrivilegeCapabilities?: string[];\n /**\n * Keystore passwords written into the profile sign step and the build-profile\n * signingConfigs. Defaults to `'123456'` (the SDK's bundled OpenHarmony.p12\n * password). Only override when supplying a matching custom keystore.\n */\n passwords?: SigningPasswords;\n /**\n * Override the bundled application cert chain (application-release kind only).\n * When set, this file is copied to `signatures/OpenHarmonyApplication.cer`\n * instead of the inlined cert. May also be sourced from `config.applicationCertPath`.\n */\n applicationCertPath?: string;\n /** Optional logger; defaults to no-op. */\n logger?: Logger;\n}\n\nfunction copyFilesToProject(\n projectDir: string,\n paths: { keystore: string; profileCert: string; unsignedProfileTemplate: string },\n kind: SigningKind,\n logger: Logger,\n applicationCertPath?: string,\n): void {\n logger.info('[sign] Copying signing material into project...');\n const signaturesDir = path.join(projectDir, 'signatures');\n fs.mkdirSync(signaturesDir, { recursive: true });\n\n fs.copyFileSync(paths.keystore, path.join(signaturesDir, 'OpenHarmony.p12'));\n fs.copyFileSync(paths.profileCert, path.join(signaturesDir, 'OpenHarmonyProfileRelease.pem'));\n fs.copyFileSync(paths.unsignedProfileTemplate, path.join(signaturesDir, 'UnsgnedReleasedProfileTemplate.json'));\n\n if (kind === 'application-release') {\n const dest = path.join(signaturesDir, 'OpenHarmonyApplication.cer');\n if (applicationCertPath) {\n fs.copyFileSync(applicationCertPath, dest);\n } else {\n fs.writeFileSync(dest, OPEN_HARMONY_APPLICATION_CERT);\n }\n }\n}\n\n/**\n * Pick the app-feature value: explicit override wins; otherwise `hos_normal_app` for\n * apl=normal, `hos_system_app` for system_basic/system_core.\n * @internal exposed for tests.\n */\nexport function resolveAppFeature(apl: Apl, override?: AppFeature): AppFeature {\n if (override) return override;\n return apl === 'normal' ? 'hos_normal_app' : 'hos_system_app';\n}\n\n/**\n * Read the third certificate (the leaf) from a 3-cert PEM chain. The chain is\n * stored root → intermediate → leaf, so the distribution-certificate we want\n * is the third block.\n */\nfunction extractLeafCertificate(chainPath: string): string {\n const certContent = fs.readFileSync(chainPath, 'utf-8');\n const parts = certContent.split('-----END CERTIFICATE-----');\n if (parts.length < 3) {\n throw new OniroError(`${chainPath} does not contain enough certificates.`);\n }\n return parts[2]!.trim() + '\\n-----END CERTIFICATE-----\\n';\n}\n\n/** @internal exposed for tests. */\nexport function modifyProfileTemplate(\n projectDir: string,\n apl: Apl,\n appFeature: AppFeature,\n logger: Logger,\n options: { kind?: SigningKind; acls?: string[]; appPrivilegeCapabilities?: string[] } = {},\n): void {\n const kind = options.kind ?? pickSigningKind(apl);\n logger.info(`[sign] Modifying profile template (apl=${apl}, app-feature=${appFeature}, kind=${kind})...`);\n const appJsonPath = path.join(projectDir, 'AppScope/app.json5');\n const profileTemplatePath = path.join(projectDir, 'signatures/UnsgnedReleasedProfileTemplate.json');\n\n if (!fs.existsSync(appJsonPath)) {\n throw new OniroError(`${appJsonPath} does not exist.`);\n }\n\n let appJson: { app?: { bundleName?: string } };\n try {\n appJson = JSON5.parse(fs.readFileSync(appJsonPath, 'utf-8'));\n } catch (e) {\n throw new OniroError(`Error parsing ${appJsonPath}: ${(e as Error).message}`, e);\n }\n\n let profileTemplate: {\n 'bundle-info'?: {\n 'bundle-name'?: string;\n 'distribution-certificate'?: string;\n apl?: string;\n 'app-feature'?: string;\n };\n acls?: { 'allowed-acls'?: string[] };\n 'app-privilege-capabilities'?: string[];\n };\n try {\n profileTemplate = JSON.parse(fs.readFileSync(profileTemplatePath, 'utf-8'));\n } catch (e) {\n throw new OniroError(`Error parsing ${profileTemplatePath}: ${(e as Error).message}`, e);\n }\n\n if (!appJson.app?.bundleName) {\n throw new OniroError('app.json5 does not contain app.bundleName.');\n }\n if (!profileTemplate['bundle-info']) {\n throw new OniroError('UnsgnedReleasedProfileTemplate.json is missing the bundle-info section.');\n }\n\n profileTemplate['bundle-info']['bundle-name'] = appJson.app.bundleName;\n profileTemplate['bundle-info']['apl'] = apl;\n profileTemplate['bundle-info']['app-feature'] = appFeature;\n\n const distCertChainPath = path.join(\n projectDir,\n 'signatures',\n SIGNING_KIND_CONFIG[kind].certBasename,\n );\n profileTemplate['bundle-info']['distribution-certificate'] = extractLeafCertificate(distCertChainPath);\n\n if (options.acls !== undefined) {\n profileTemplate.acls = profileTemplate.acls ?? {};\n profileTemplate.acls['allowed-acls'] = options.acls;\n }\n if (options.appPrivilegeCapabilities !== undefined) {\n profileTemplate['app-privilege-capabilities'] = options.appPrivilegeCapabilities;\n }\n\n fs.writeFileSync(profileTemplatePath, JSON.stringify(profileTemplate, null, 2));\n}\n\nfunction generateP7bFile(\n projectDir: string,\n paths: { signTool: string; profileCert: string; keystore: string },\n logger: Logger,\n passwords: SigningPasswords,\n): void {\n logger.info('[sign] Generating P7b profile via hap-sign-tool...');\n const signaturesDir = path.join(projectDir, 'signatures');\n const profileTemplatePath = path.join(signaturesDir, 'UnsgnedReleasedProfileTemplate.json');\n const outputProfilePath = path.join(signaturesDir, 'app1-profile.p7b');\n\n // The profile itself is always signed by the Profile Release key, regardless\n // of the HAP signing kind. The profile's `distribution-certificate` field\n // (set by modifyProfileTemplate) is what tells BMS which cert will sign the HAP.\n const args = [\n '-jar', paths.signTool,\n 'sign-profile',\n '-keyAlias', 'openharmony application profile release',\n '-signAlg', 'SHA256withECDSA',\n '-mode', 'localSign',\n '-profileCertFile', paths.profileCert,\n '-inFile', profileTemplatePath,\n '-keystoreFile', paths.keystore,\n '-outFile', outputProfilePath,\n '-keyPwd', passwords.key,\n '-keystorePwd', passwords.store,\n ];\n\n try {\n execFileSync('java', args, { stdio: 'inherit' });\n } catch (e) {\n throw new OniroError(\n `hap-sign-tool failed. Ensure a JDK (with keytool/java) is on PATH. Underlying error: ${(e as Error).message}`,\n e,\n );\n }\n}\n\n/**\n * Read all `products[*].signingConfig` names from the project's build-profile.json5.\n * Returns the unique names in declaration order. Falls back to `['default']` when\n * the file is missing or has no products.\n * @internal exposed for tests.\n */\nexport function detectSigningConfigNames(projectDir: string): string[] {\n const buildProfilePath = path.join(projectDir, 'build-profile.json5');\n if (!fs.existsSync(buildProfilePath)) return ['default'];\n\n let parsed: { app?: { products?: Array<{ signingConfig?: unknown }> } };\n try {\n parsed = JSON5.parse(fs.readFileSync(buildProfilePath, 'utf-8'));\n } catch {\n return ['default'];\n }\n\n const products = parsed.app?.products;\n if (!Array.isArray(products) || products.length === 0) return ['default'];\n\n const names: string[] = [];\n for (const product of products) {\n const name = product.signingConfig;\n if (typeof name === 'string' && name.length > 0 && !names.includes(name)) {\n names.push(name);\n }\n }\n return names.length > 0 ? names : ['default'];\n}\n\n/** @internal exposed for tests. Needs `signatures/material` (see {@link createMaterial}). */\nexport function updateBuildProfile(projectDir: string, kind: SigningKind, logger: Logger, passwords: SigningPasswords): void {\n logger.info('[sign] Writing signing configs into build-profile.json5...');\n const materialDir = path.join(projectDir, 'signatures', 'material');\n const buildProfilePath = path.join(projectDir, 'build-profile.json5');\n\n const encryptedStorePassword = encryptPwd(passwords.store, materialDir);\n const encryptedKeyPassword = encryptPwd(passwords.key, materialDir);\n\n let buildProfile: { app?: { signingConfigs?: unknown[]; products?: Array<{ signingConfig?: unknown }> } } = { app: {} };\n if (fs.existsSync(buildProfilePath)) {\n try {\n buildProfile = JSON5.parse(fs.readFileSync(buildProfilePath, 'utf-8'));\n } catch (e) {\n throw new OniroError(`Error parsing ${buildProfilePath}: ${(e as Error).message}`, e);\n }\n }\n\n const { hapKeyAlias, certBasename } = SIGNING_KIND_CONFIG[kind];\n const configNames = detectSigningConfigNames(projectDir);\n logger.info(`[sign] Writing signingConfigs entries: ${configNames.join(', ')}`);\n\n buildProfile.app = buildProfile.app ?? {};\n buildProfile.app.signingConfigs = configNames.map((name) => ({\n name,\n material: {\n certpath: `./signatures/${certBasename}`,\n storePassword: encryptedStorePassword,\n keyAlias: hapKeyAlias,\n keyPassword: encryptedKeyPassword,\n profile: './signatures/app1-profile.p7b',\n signAlg: 'SHA256withECDSA',\n storeFile: './signatures/OpenHarmony.p12',\n },\n }));\n // A product that names no signingConfig builds unsigned HAPs even with one defined.\n for (const product of buildProfile.app.products ?? []) {\n if (typeof product.signingConfig !== 'string' || product.signingConfig === '') {\n product.signingConfig = configNames[0];\n logger.info(`[sign] Pointing a product with no signingConfig at \"${configNames[0]}\".`);\n }\n }\n\n // Intentionally strict JSON (not JSON5) — keeps the file readable by VS Code's JSON parser.\n fs.writeFileSync(buildProfilePath, JSON.stringify(buildProfile, null, 2));\n}\n\nfunction prepareMaterialDirectory(projectDir: string, logger: Logger): void {\n logger.info('[sign] Generating fresh signing material...');\n const materialDir = path.join(projectDir, 'signatures', 'material');\n if (fs.existsSync(materialDir)) {\n fs.rmSync(materialDir, { recursive: true, force: true });\n }\n createMaterial(materialDir);\n}\n\n/**\n * Generate signing configs for an OpenHarmony project: copies certs, signs the profile,\n * generates the signing material, and writes the resulting `signingConfigs` entry into\n * `build-profile.json5`.\n *\n * Requires `java` on PATH (the OpenHarmony hap-sign-tool ships as a .jar).\n */\nexport function generateSigningConfigs(options: GenerateSigningConfigsOptions): void {\n const { projectDir, sdkHome } = options;\n const logger = options.logger ?? noopLogger;\n const apl: Apl = options.apl ?? 'normal';\n if (!APL_VALUES.includes(apl)) {\n throw new OniroError(`Invalid apl '${apl}'. Expected one of: ${APL_VALUES.join(', ')}.`);\n }\n const appFeature: AppFeature = resolveAppFeature(apl, options.appFeature);\n if (!APP_FEATURE_VALUES.includes(appFeature)) {\n throw new OniroError(\n `Invalid appFeature '${appFeature}'. Expected one of: ${APP_FEATURE_VALUES.join(', ')}.`,\n );\n }\n\n const sdkVersion = detectProjectSdkVersion(projectDir, logger);\n if (!sdkVersion) {\n throw new OniroError(\n 'Could not detect project SDK version (compileSdkVersion missing in build-profile.json5).',\n );\n }\n\n const sdkPath = path.join(sdkHome, String(sdkVersion));\n if (!fs.existsSync(sdkPath)) {\n throw new SdkNotInstalledError(String(sdkVersion), sdkPath, ALL_SDKS.find((s) => s.api === String(sdkVersion))?.version);\n }\n\n const paths = {\n signTool: path.join(sdkPath, 'toolchains/lib/hap-sign-tool.jar'),\n keystore: path.join(sdkPath, 'toolchains/lib/OpenHarmony.p12'),\n profileCert: path.join(sdkPath, 'toolchains/lib/OpenHarmonyProfileRelease.pem'),\n unsignedProfileTemplate: path.join(sdkPath, 'toolchains/lib/UnsgnedReleasedProfileTemplate.json'),\n };\n\n const kind = pickSigningKind(apl);\n const passwords = options.passwords ?? DEFAULT_PASSWORDS;\n\n logger.info('[sign] Starting signing configuration generation...');\n copyFilesToProject(projectDir, paths, kind, logger, options.applicationCertPath);\n modifyProfileTemplate(projectDir, apl, appFeature, logger, {\n kind,\n acls: options.acls,\n appPrivilegeCapabilities: options.appPrivilegeCapabilities,\n });\n generateP7bFile(projectDir, paths, logger, passwords);\n prepareMaterialDirectory(projectDir, logger);\n updateBuildProfile(projectDir, kind, logger, passwords);\n logger.info('[sign] Signing configuration generated successfully.');\n}\n","/**\n * PEM-encoded certificate chain for the OpenHarmony Application Release key.\n *\n * Root-CA → Application-CA → Application-Release leaf. This is the public\n * OpenHarmony test PKI that ships with system app source trees (e.g.\n * `applications/standard/launcher/signature/OpenHarmonyApplication.cer`). It\n * pairs with the private key stored under alias `OpenHarmony Application Release`\n * in the SDK's `OpenHarmony.p12` keystore.\n *\n * Used to sign HAPs that request privileged permissions (apl >= system_basic).\n * For apl=normal the existing `OpenHarmonyProfileRelease.pem` chain — already\n * shipped in the SDK — is used instead.\n */\nexport const OPEN_HARMONY_APPLICATION_CERT = `-----BEGIN CERTIFICATE-----\nMIICRDCCAcmgAwIBAgIED+E4izAMBggqhkjOPQQDAwUAMGgxCzAJBgNVBAYTAkNO\nMRQwEgYDVQQKEwtPcGVuSGFybW9ueTEZMBcGA1UECxMQT3Blbkhhcm1vbnkgVGVh\nbTEoMCYGA1UEAxMfT3Blbkhhcm1vbnkgQXBwbGljYXRpb24gUm9vdCBDQTAeFw0y\nMTAyMDIxMjE0MThaFw00OTEyMzExMjE0MThaMGgxCzAJBgNVBAYTAkNOMRQwEgYD\nVQQKEwtPcGVuSGFybW9ueTEZMBcGA1UECxMQT3Blbkhhcm1vbnkgVGVhbTEoMCYG\nA1UEAxMfT3Blbkhhcm1vbnkgQXBwbGljYXRpb24gUm9vdCBDQTB2MBAGByqGSM49\nAgEGBSuBBAAiA2IABE023XmRaw2DnO8NSsb+KG/uY0FtS3u5LQucdr3qWVnRW5ui\nQIL6ttNZBEeLTUeYcJZCpayg9Llf+1SmDA7dY4iP2EcRo4UN3rilovtfFfsmH4ty\n3SApHVFzWUl+NwdH8KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwHQYDVR0OBBYEFBc6EKGrGXzlAE+s0Zgnsphadw7NMAwGCCqGSM49BAMDBQAD\nZwAwZAIwd1p3JzHN93eoPped1li0j64npgqNzwy4OrkehYAqNXpcpaEcLZ7UxW8E\nI2lZJ3SbAjAkqySHb12sIwdSFKSN9KCMMEo/eUT5dUXlcKR2nZz0MJdxT5F51qcX\n1CumzkcYhgU=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICYTCCAeWgAwIBAgIEHmXAPTAMBggqhkjOPQQDAwUAMGgxCzAJBgNVBAYTAkNO\nMRQwEgYDVQQKEwtPcGVuSGFybW9ueTEZMBcGA1UECxMQT3Blbkhhcm1vbnkgVGVh\nbTEoMCYGA1UEAxMfT3Blbkhhcm1vbnkgQXBwbGljYXRpb24gUm9vdCBDQTAeFw0y\nMTAyMDIxMjE1MzJaFw00OTEyMzExMjE1MzJaMGMxCzAJBgNVBAYTAkNOMRQwEgYD\nVQQKEwtPcGVuSGFybW9ueTEZMBcGA1UECxMQT3Blbkhhcm1vbnkgVGVhbTEjMCEG\nA1UEAxMaT3Blbkhhcm1vbnkgQXBwbGljYXRpb24gQ0EwdjAQBgcqhkjOPQIBBgUr\ngQQAIgNiAAQhnu7Hna8XNa2KyqRf5+lBJScE4xqf89N0g0OuqAb2re8nGsvWkw26\nuDekfnBYicd+G3Cydqa2zFIwV7Talyg2ULW3r8KbGpyl84mJEPPRmCGJ+H9gtCsf\n+OrJ4Y76LVWjYzBhMB8GA1UdIwQYMBaAFBc6EKGrGXzlAE+s0Zgnsphadw7NMA8G\nA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTbhrciFtUL\noUu33SV7ufEFfaItRzAMBggqhkjOPQQDAwUAA2gAMGUCMG3cXjiDmXTvf7D4Omhf\nqcc2nuO+EMfWE+N9ZhBP5UhV34mAGWi3SfLU6rcV0urWEQIxAMYIb3epOnKhUrcm\nLfu1WKzFlpYQwmw73RaCHP2I3k6NcuWOYeNwWXSNZ8o0nzvaLg==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICMzCCAbegAwIBAgIEaOC/zDAMBggqhkjOPQQDAwUAMGMxCzAJBgNVBAYTAkNO\nMRQwEgYDVQQKEwtPcGVuSGFybW9ueTEZMBcGA1UECxMQT3Blbkhhcm1vbnkgVGVh\nbTEjMCEGA1UEAxMaT3Blbkhhcm1vbnkgQXBwbGljYXRpb24gQ0EwHhcNMjEwMjAy\nMTIxOTMxWhcNNDkxMjMxMTIxOTMxWjBoMQswCQYDVQQGEwJDTjEUMBIGA1UEChML\nT3Blbkhhcm1vbnkxGTAXBgNVBAsTEE9wZW5IYXJtb255IFRlYW0xKDAmBgNVBAMT\nH09wZW5IYXJtb255IEFwcGxpY2F0aW9uIFJlbGVhc2UwWTATBgcqhkjOPQIBBggq\nhkjOPQMBBwNCAATbYOCQQpW5fdkYHN45v0X3AHax12jPBdEDosFRIZ1eXmxOYzSG\nJwMfsHhUU90E8lI0TXYZnNmgM1sovubeQqATo1IwUDAfBgNVHSMEGDAWgBTbhrci\nFtULoUu33SV7ufEFfaItRzAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFPtxruhl\ncRBQsJdwcZqLu9oNUVgaMAwGCCqGSM49BAMDBQADaAAwZQIxAJta0PQ2p4DIu/ps\nLMdLCDgQ5UH1l0B4PGhBlMgdi2zf8nk9spazEQI/0XNwpft8QAIwHSuA2WelVi/o\nzAlF08DnbJrOOtOnQq5wHOPlDYB4OtUzOYJk9scotrEnJxJzGsh/\n-----END CERTIFICATE-----\n`;\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport { defaultPaths } from '../ports/config.js';\nimport type { ProgressReporter } from '../ports/progress.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { getEmulatorDir } from '../sdk/paths.js';\nimport { downloadFile } from '../sdk/download.js';\nimport { extractZipWithProgress } from '../sdk/extract.js';\nimport { createInstallTempDir, removeTempWorkDir, toSpaceError } from '../sdk/tmp.js';\n\nexport interface InstallEmulatorOptions {\n config: ConfigProvider;\n progress?: ProgressReporter;\n abortSignal?: AbortSignal;\n logger?: Logger;\n /**\n * Scratch directory for the downloaded ZIP. Overrides the `tmpDir` config key and\n * the default location next to the install target.\n */\n tmpDir?: string;\n}\n\n/**\n * Download and extract the Oniro emulator into the configured `emulatorDir`.\n */\nexport async function installEmulator(opts: InstallEmulatorOptions): Promise<void> {\n const { config, progress, abortSignal } = opts;\n const logger = opts.logger ?? noopLogger;\n\n const url = config.get('emulatorUrl', defaultPaths.emulatorUrl);\n const emulatorDir = getEmulatorDir(config);\n const what = 'the emulator install';\n const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({\n config,\n override: opts.tmpDir,\n installRoot: path.dirname(emulatorDir),\n prefix: 'oniro-emulator-',\n logger,\n });\n const tmpZip = path.join(tmpDir, 'oniro_emulator.zip');\n\n try {\n fs.mkdirSync(emulatorDir, { recursive: true });\n\n progress?.report({ message: 'Downloading emulator...', increment: 0 });\n await downloadFile({ url, dest: tmpZip, progress, abortSignal, start: 0, range: 50, what, tmpRoot });\n\n progress?.report({ message: 'Extracting emulator...', increment: 0 });\n await extractZipWithProgress({ zipPath: tmpZip, dest: emulatorDir, progress, start: 50, range: 45, logger });\n\n const runSh = path.join(emulatorDir, 'images', 'run.sh');\n if (fs.existsSync(runSh)) {\n fs.chmodSync(runSh, 0o755);\n }\n progress?.report({ message: 'Finalizing installation...', increment: 5 });\n } catch (err) {\n throw toSpaceError(err, tmpRoot, what);\n } finally {\n removeTempWorkDir(tmpDir, tmpRoot);\n }\n}\n\n/**\n * Heuristic: the emulator is considered installed if either bundled launcher\n * (`images/run.sh` or `images/run.bat`) is present, so a Windows-only build is\n * detected too.\n */\nexport function isEmulatorInstalled(config: ConfigProvider): boolean {\n const imagesDir = path.join(getEmulatorDir(config), 'images');\n return fs.existsSync(path.join(imagesDir, 'run.sh')) || fs.existsSync(path.join(imagesDir, 'run.bat'));\n}\n\nexport function removeEmulator(config: ConfigProvider): void {\n const emulatorDir = getEmulatorDir(config);\n if (fs.existsSync(emulatorDir)) {\n fs.rmSync(emulatorDir, { recursive: true, force: true });\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { CancelledError, OniroError } from '../ports/errors.js';\nimport { getEmulatorDir } from '../sdk/paths.js';\nimport { hdcExec, runProcess } from '../hdc/exec.js';\nimport { isEmulatorInstalled } from './install.js';\n\nconst PID_FILE = path.join(os.tmpdir(), 'oniro_emulator.pid');\n\n/**\n * Try to connect hdc to the emulator. Resolves true on success, false otherwise.\n */\nexport async function attemptHdcConnection(\n config: ConfigProvider,\n address = '127.0.0.1:55555',\n logger: Logger = noopLogger,\n): Promise<boolean> {\n try {\n await hdcExec({ config, args: ['start', '-r'], logger });\n await hdcExec({ config, args: ['tconn', address], logger });\n const targets = await hdcExec({ config, args: ['list', 'targets'], logger });\n return targets.stdout.includes(address);\n } catch (err) {\n logger.warn(`hdc connection attempt failed: ${(err as Error).message}`);\n return false;\n }\n}\n\ninterface LauncherSpec {\n /** Executable to spawn (e.g. `bash` on POSIX, `cmd.exe` on Windows). */\n command: string;\n /** Args, including the launcher script path. */\n args: readonly string[];\n /** Working directory (images dir). */\n cwd: string;\n}\n\n/**\n * Pick the right bundled launcher for the current OS. Prefers run.bat on Windows\n * and run.sh elsewhere; falls back to the other if only one is present.\n */\nfunction resolveLauncher(\n imagesPath: string,\n headless: boolean,\n connect: string | undefined,\n): LauncherSpec {\n const runSh = path.join(imagesPath, 'run.sh');\n const runBat = path.join(imagesPath, 'run.bat');\n const extra: string[] = [];\n if (headless) extra.push('--headless');\n if (connect) extra.push('--connect', connect);\n\n if (os.platform() === 'win32') {\n if (fs.existsSync(runBat)) {\n return { command: 'cmd.exe', args: ['/c', runBat, ...extra], cwd: imagesPath };\n }\n if (fs.existsSync(runSh)) {\n return { command: 'bash', args: [runSh, ...extra], cwd: imagesPath };\n }\n throw new OniroError(`No emulator launcher (run.bat or run.sh) found in ${imagesPath}.`);\n }\n\n if (fs.existsSync(runSh)) {\n return { command: 'bash', args: [runSh, ...extra], cwd: imagesPath };\n }\n if (fs.existsSync(runBat)) {\n return { command: 'bash', args: [runBat, ...extra], cwd: imagesPath };\n }\n throw new OniroError(`No emulator launcher (run.sh or run.bat) found in ${imagesPath}.`);\n}\n\nexport interface StartEmulatorOptions {\n config: ConfigProvider;\n logger?: Logger;\n /** Pass --headless to the bundled launcher (VNC + telnet serial, no local window). */\n headless?: boolean;\n /**\n * Override the launcher's host:port for hdc port forwarding. Defaults to the\n * launcher's own default (typically `127.0.0.1:55555`). Use `0.0.0.0:55555`\n * on hosts where QEMU refuses to bind the hostfwd to 127.0.0.1 (e.g. some\n * CI runners with restricted loopback bindings).\n */\n connect?: string;\n /**\n * Redirect launcher stdout/stderr to this file. Default: discard\n * (/dev/null on POSIX, NUL on Windows). Use a real path in CI so you can\n * surface qemu output on failure.\n */\n logFile?: string;\n /**\n * If > 0, block until hdc connects to the running emulator, up to this many\n * seconds. 0 (default) returns as soon as the launcher process is spawned.\n */\n waitForHdcSeconds?: number;\n /** Poll interval for the hdc wait, ms. Default 5000. */\n hdcPollIntervalMs?: number;\n abortSignal?: AbortSignal;\n}\n\n/**\n * Launch the Oniro emulator in the background via the bundled run.sh/run.bat.\n *\n * The launcher process is detached + unref'd so callers can exit while the\n * emulator keeps running. A PID file is written to the OS temp dir so\n * `stopEmulator` and rerun-detection logic can find the process later.\n */\nexport async function startEmulator(opts: StartEmulatorOptions): Promise<void> {\n const { config } = opts;\n const logger = opts.logger ?? noopLogger;\n\n // Detect a still-running emulator from a previous run (POSIX only — Windows\n // PID semantics with process groups make this unreliable to check by hand).\n if (os.platform() !== 'win32' && fs.existsSync(PID_FILE)) {\n try {\n const pid = Number(fs.readFileSync(PID_FILE, 'utf8').trim());\n if (Number.isFinite(pid) && pid > 0) {\n try {\n process.kill(pid, 0);\n logger.info(`Emulator already running (PID ${pid}); not starting another.`);\n if (opts.waitForHdcSeconds && opts.waitForHdcSeconds > 0) {\n await waitForHdc(config, opts.waitForHdcSeconds, opts.hdcPollIntervalMs ?? 5000, logger, opts.abortSignal);\n }\n return;\n } catch {\n // Stale PID file — fall through and launch a fresh one.\n }\n }\n } catch (err) {\n logger.warn(`Could not read PID file: ${(err as Error).message}`);\n }\n }\n\n const imagesPath = path.join(getEmulatorDir(config), 'images');\n if (!fs.existsSync(imagesPath)) {\n throw new OniroError(`Emulator images directory not found at ${imagesPath}. Run \\`oniro-app emulator install\\` first.`);\n }\n const launcher = resolveLauncher(imagesPath, opts.headless === true, opts.connect);\n\n // Open the log target. Default to OS-level null sink so the child process\n // doesn't keep the parent's stdout/stderr file descriptors alive.\n const logPath = opts.logFile ?? (os.platform() === 'win32' ? 'NUL' : '/dev/null');\n const logFd = fs.openSync(logPath, 'a');\n\n let child;\n try {\n child = spawn(launcher.command, [...launcher.args], {\n cwd: launcher.cwd,\n detached: true,\n stdio: ['ignore', logFd, logFd],\n windowsHide: true,\n });\n } finally {\n fs.closeSync(logFd);\n }\n\n // Catch synchronous spawn failures (e.g. bash not found on PATH).\n if (!child.pid) {\n throw new OniroError(`Failed to spawn launcher (${launcher.command} ${launcher.args.join(' ')}).`);\n }\n\n // Record PID + detach. The launcher script `exec`s into qemu so this PID\n // remains valid for the whole emulator lifetime.\n fs.writeFileSync(PID_FILE, String(child.pid));\n child.unref();\n logger.info(`Emulator launched (PID ${child.pid}). Logs: ${logPath}`);\n\n // Watch for an immediate failure (e.g. KVM unavailable → run.sh exits ~instantly\n // with a friendly error). We hold a reference to the exit event but won't await\n // it if the child stays alive.\n const earlyExit = new Promise<number | null>((resolve) => {\n child.once('exit', (code) => resolve(code));\n child.once('error', () => resolve(-1));\n });\n const liveness = new Promise<'alive'>((resolve) => setTimeout(() => resolve('alive'), 2000));\n const outcome = await Promise.race([earlyExit, liveness]);\n if (outcome !== 'alive') {\n const tail = readTail(logPath, 4000);\n throw new OniroError(\n `Emulator launcher exited with code ${outcome} before reaching steady state. Tail of ${logPath}:\\n${tail}`,\n );\n }\n\n if (opts.waitForHdcSeconds && opts.waitForHdcSeconds > 0) {\n await waitForHdc(config, opts.waitForHdcSeconds, opts.hdcPollIntervalMs ?? 5000, logger, opts.abortSignal, logPath);\n }\n}\n\nasync function waitForHdc(\n config: ConfigProvider,\n timeoutSeconds: number,\n pollIntervalMs: number,\n logger: Logger,\n abortSignal?: AbortSignal,\n logPathForDiagnostics?: string,\n): Promise<void> {\n const deadline = Date.now() + timeoutSeconds * 1000;\n let attempt = 0;\n while (Date.now() < deadline) {\n if (abortSignal?.aborted) throw new CancelledError('hdc wait cancelled.');\n attempt++;\n if (await attemptHdcConnection(config, undefined, noopLogger)) {\n logger.info(`hdc connected on attempt ${attempt}.`);\n return;\n }\n // Every ~6 attempts, log a heartbeat with the latest emulator log tail so\n // a hung guest is debuggable from a single command's output stream.\n if (attempt % 6 === 0) {\n logger.info(`hdc not yet ready (attempt ${attempt}, ${Math.max(0, deadline - Date.now()) / 1000 | 0}s remaining).`);\n if (logPathForDiagnostics) {\n const tail = readTail(logPathForDiagnostics, 1200);\n if (tail.trim()) logger.debug(`emulator log tail:\\n${tail}`);\n }\n }\n await new Promise((r) => setTimeout(r, pollIntervalMs));\n }\n const tail = logPathForDiagnostics ? readTail(logPathForDiagnostics, 4000) : '';\n throw new OniroError(`hdc did not connect within ${timeoutSeconds}s.${tail ? `\\nTail of emulator log:\\n${tail}` : ''}`);\n}\n\nfunction readTail(filePath: string, bytes: number): string {\n try {\n const stat = fs.statSync(filePath);\n const start = Math.max(0, stat.size - bytes);\n const fd = fs.openSync(filePath, 'r');\n try {\n const buf = Buffer.alloc(stat.size - start);\n fs.readSync(fd, buf, 0, buf.length, start);\n return buf.toString('utf8');\n } finally {\n fs.closeSync(fd);\n }\n } catch {\n return '';\n }\n}\n\nexport async function stopEmulator(logger: Logger = noopLogger): Promise<void> {\n // Prefer killing the recorded PID; fall back to a broad kill for stragglers.\n if (fs.existsSync(PID_FILE)) {\n try {\n const pid = Number(fs.readFileSync(PID_FILE, 'utf8').trim());\n if (Number.isFinite(pid) && pid > 0) {\n try {\n process.kill(pid, 'SIGTERM');\n logger.info(`Sent SIGTERM to emulator PID ${pid}.`);\n } catch (err) {\n logger.warn(`Could not signal PID ${pid}: ${(err as Error).message}`);\n }\n }\n } catch (err) {\n logger.warn(`Could not read PID file: ${(err as Error).message}`);\n }\n }\n\n // pkill / taskkill exit non-zero when nothing matched — runProcess resolves on any\n // exit code, so we simply ignore that. The try/catch only guards a missing binary.\n const [killCmd, ...killArgs] = os.platform() === 'win32'\n ? ['taskkill', '/IM', 'qemu-system-x86_64.exe', '/F']\n : ['pkill', '-f', 'qemu-system-x86_64'];\n try {\n await runProcess({ command: killCmd!, args: killArgs, logger });\n } catch (err) {\n logger.warn(`[emulator] could not run ${killCmd}: ${(err as Error).message}`);\n }\n\n fs.rm(PID_FILE, { force: true }, (err) => {\n if (err) logger.warn(`Could not remove PID file: ${err.message}`);\n });\n}\n\nexport interface EmulatorStatus {\n installed: boolean;\n /** The configured emulator directory. */\n dir: string;\n /** Whether an emulator QEMU process is alive. */\n running: boolean;\n /** The hdc address checked for `connected`. */\n address: string;\n /** hdc lists `address` as a Connected target. */\n connected: boolean;\n}\n\n/**\n * Whether a `qemu-system-x86_64` process is alive: the PID file from `startEmulator`\n * (POSIX only, as there), else a process-table scan.\n */\nasync function isQemuRunning(logger: Logger): Promise<boolean> {\n if (os.platform() !== 'win32') {\n try {\n const pid = Number(fs.readFileSync(PID_FILE, 'utf8').trim());\n if (Number.isFinite(pid) && pid > 0) {\n process.kill(pid, 0);\n return true;\n }\n } catch {\n // No PID file, or the process is gone: scan the process table.\n }\n }\n const [cmd, ...args] = os.platform() === 'win32'\n ? ['tasklist', '/FI', 'IMAGENAME eq qemu-system-x86_64.exe', '/NH']\n : ['pgrep', '-f', 'qemu-system-x86_64'];\n try {\n const res = await runProcess({ command: cmd!, args, timeoutMs: 10_000, logger });\n return os.platform() === 'win32' ? /qemu-system-x86_64/i.test(res.stdout) : res.code === 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Report on the Oniro emulator without starting it: installed, running, and whether\n * hdc sees it at `address` (default `127.0.0.1:55555`). Other emulators, such as\n * DevEco Studio's HarmonyOS emulator, are not covered: they appear in `listDevices`.\n */\nexport async function getEmulatorStatus(\n config: ConfigProvider,\n opts: { address?: string; logger?: Logger } = {},\n): Promise<EmulatorStatus> {\n const logger = opts.logger ?? noopLogger;\n const address = opts.address ?? '127.0.0.1:55555';\n const dir = getEmulatorDir(config);\n let connected = false;\n try {\n const targets = await hdcExec({ config, args: ['list', 'targets', '-v'], timeoutMs: 10_000, logger });\n connected = targets.stdout.split('\\n').some((l) => l.trim().startsWith(address) && /\\bConnected\\b/.test(l));\n } catch {\n // No hdc: not connected.\n }\n return {\n installed: isEmulatorInstalled(config),\n dir,\n running: await isQemuRunning(logger),\n address,\n connected,\n };\n}\n","import * as fs from 'node:fs';\nimport type { ChildProcess } from 'node:child_process';\nimport { StringDecoder } from 'node:string_decoder';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { CancelledError, CommandFailedError, OniroError } from '../ports/errors.js';\nimport { getHdcPath } from '../sdk/paths.js';\nimport { killProcessTree, needsCmdWrapper, spawnCompat } from './spawnCompat.js';\n\n/** Result of a spawned command. `code` is the process exit code (-1 if it was killed). */\nexport interface HdcExecResult {\n code: number;\n stdout: string;\n stderr: string;\n}\n\n/** Streamed output callback, invoked per stdout/stderr chunk as it arrives. */\nexport type OutputSink = (chunk: string, stream: 'stdout' | 'stderr') => void;\n\n/** Message of an unknown thrown value, for uniform spawn-failure reporting. */\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nexport interface RunProcessOptions {\n /** Executable to spawn. */\n command: string;\n /** Args passed verbatim (spawn runs with `shell: false`, so no shell parsing). */\n args: readonly string[];\n cwd?: string;\n env?: NodeJS.ProcessEnv;\n /** Kill the process after this many ms and reject. Default 60_000. */\n timeoutMs?: number;\n /** Abort the process; rejects with CancelledError. */\n abortSignal?: AbortSignal;\n /** Receive stdout/stderr chunks as they arrive (in addition to the buffered result). */\n onOutput?: OutputSink;\n /** Reserved for future scoped diagnostics; the buffered result is returned regardless. */\n logger?: Logger;\n}\n\n/**\n * Spawn an arbitrary process with `shell: false` and collect its output. The\n * single low-level primitive every other command in the package builds on —\n * because args are passed as an array and never interpolated into a shell\n * string, command construction is injection-safe by construction.\n *\n * The one exception is a Windows batch wrapper (`.bat`/`.cmd`, how the\n * OpenHarmony command-line tools ship there), which the OS cannot execute\n * directly: those go through `cmd.exe` with every argument individually\n * escaped — see {@link spawnCompat}. The array-in, no-word-splitting contract\n * is preserved.\n *\n * Resolves with `{ code, stdout, stderr }` for ANY exit code (callers opt into\n * throw-on-non-zero via {@link ensureOk}). Rejects only on spawn failure\n * (e.g. missing binary), timeout, or abort.\n */\nexport function runProcess(opts: RunProcessOptions): Promise<HdcExecResult> {\n const { command, args, cwd, env, onOutput } = opts;\n const timeoutMs = opts.timeoutMs ?? 60_000;\n const { abortSignal } = opts;\n\n return new Promise<HdcExecResult>((resolve, reject) => {\n if (abortSignal?.aborted) {\n reject(new CancelledError(`Command aborted before start: ${command}`));\n return;\n }\n\n // A batch wrapper runs through cmd.exe, which cannot report ENOENT for the\n // wrapper itself — it would exit 1 with \"is not recognized as an internal\n // or external command\". Check up front so a missing tool keeps surfacing as\n // a spawn failure on Windows too.\n if (needsCmdWrapper(command) && !fs.existsSync(command)) {\n reject(new OniroError(`Failed to spawn ${command}: ENOENT (no such file)`));\n return;\n }\n\n let child: ChildProcess;\n try {\n child = spawnCompat(command, args, { cwd, env });\n } catch (err) {\n // spawn() can also fail synchronously (EINVAL, EACCES). Report it the\n // same way as the asynchronous 'error' event so callers see one message.\n reject(new OniroError(`Failed to spawn ${command}: ${errorMessage(err)}`, err));\n return;\n }\n\n let stdout = '';\n let stderr = '';\n let settled = false;\n let timedOut = false;\n const stdoutDecoder = new StringDecoder('utf8');\n const stderrDecoder = new StringDecoder('utf8');\n\n const cleanup = (): void => {\n clearTimeout(timer);\n abortSignal?.removeEventListener('abort', onAbort);\n };\n\n const onAbort = (): void => {\n if (settled) return;\n settled = true;\n cleanup();\n killProcessTree(child);\n reject(new CancelledError(`Command aborted: ${command} ${args.join(' ')}`));\n };\n\n const timer = setTimeout(() => {\n timedOut = true;\n killProcessTree(child);\n }, timeoutMs);\n\n abortSignal?.addEventListener('abort', onAbort, { once: true });\n\n child.stdout?.on('data', (d: Buffer) => {\n const s = stdoutDecoder.write(d);\n stdout += s;\n if (s) onOutput?.(s, 'stdout');\n });\n child.stderr?.on('data', (d: Buffer) => {\n const s = stderrDecoder.write(d);\n stderr += s;\n if (s) onOutput?.(s, 'stderr');\n });\n\n child.on('error', (err) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(new OniroError(`Failed to spawn ${command}: ${err.message}`, err));\n });\n\n child.on('close', (code) => {\n if (settled) return;\n settled = true;\n cleanup();\n const stdoutTail = stdoutDecoder.end();\n const stderrTail = stderrDecoder.end();\n stdout += stdoutTail;\n stderr += stderrTail;\n if (stdoutTail) onOutput?.(stdoutTail, 'stdout');\n if (stderrTail) onOutput?.(stderrTail, 'stderr');\n if (timedOut) {\n reject(\n new OniroError(\n `Command timed out after ${timeoutMs}ms: ${command} ${args.join(' ')}` +\n (stderr.trim() ? `\\n${stderr.trim()}` : ''),\n ),\n );\n return;\n }\n resolve({ code: code ?? -1, stdout, stderr });\n });\n });\n}\n\n/**\n * The device to address: an explicit serial wins, then the `ONIRO_DEVICE_SERIAL` /\n * `DEVICE_SERIAL` env vars. `auto`, or nothing at all, leaves the choice to hdc,\n * which only works while a single target is connected.\n */\nexport function resolveDeviceSerial(explicit?: string, env: NodeJS.ProcessEnv = process.env): string | undefined {\n if (explicit && explicit !== 'auto') return explicit;\n const fromEnv = env.ONIRO_DEVICE_SERIAL || env.DEVICE_SERIAL;\n return fromEnv && fromEnv !== 'auto' ? fromEnv : undefined;\n}\n\n/** `['-t', <serial>]` for the device {@link resolveDeviceSerial} picks, or `[]` to let hdc choose. */\nexport function hdcTargetArgs(explicit?: string): string[] {\n const serial = resolveDeviceSerial(explicit);\n return serial ? ['-t', serial] : [];\n}\n\n/**\n * hdc subcommands served by the hdc server itself rather than a device. They only\n * take `-t` when the caller names a device explicitly, never from the env var.\n */\nconst HOST_COMMANDS = new Set(['list', 'tconn', 'start', 'kill', 'version', 'checkserver']);\n\n/** The `-t <serial>` prefix for `hdc <args...>`, following {@link HdcExecOptions.deviceSerial}'s rules. */\nexport function hdcTargetArgsFor(args: readonly string[], explicit?: string): string[] {\n if (HOST_COMMANDS.has(args[0] ?? '')) return explicit ? ['-t', explicit] : [];\n return hdcTargetArgs(explicit);\n}\n\n/**\n * The `[Fail]…` line hdc printed instead of running the command, or null. hdc\n * exits 0 even then: `[Fail]ExecuteCommand need connect-key?` (several targets\n * and no `-t`), `[Fail]Not match target founded` (unknown serial), a failed file\n * transfer. Only the first line of output counts, so device-side output further\n * down that happens to contain the marker is left alone. Pure/testable.\n */\nexport function hdcClientFailure(output: string): string | null {\n const first = output.split(/\\r?\\n/).find((l) => l.trim() !== '')?.trim() ?? '';\n return first.startsWith('[Fail]') ? first : null;\n}\n\nexport interface HdcExecOptions {\n config: ConfigProvider;\n /** Args passed to hdc verbatim, e.g. `['shell','aa','start','-a',ability,'-b',bundle]`. */\n args: readonly string[];\n /**\n * Device serial; prepends `['-t', serial]`. When unset, `ONIRO_DEVICE_SERIAL`\n * applies (see {@link resolveDeviceSerial}), except for hdc server commands\n * such as `list targets` and `tconn`.\n */\n deviceSerial?: string;\n /** Default 60_000. */\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n onOutput?: OutputSink;\n logger?: Logger;\n}\n\n/**\n * Run `hdc [-t <serial>] <args...>`. Resolves with `{ code, stdout, stderr }`\n * for any exit code; use {@link ensureOk} to throw on non-zero. A `[Fail]` line\n * from hdc itself is reported as exit code 1 (see {@link hdcClientFailure}).\n */\nexport async function hdcExec(opts: HdcExecOptions): Promise<HdcExecResult> {\n const hdc = getHdcPath(opts.config);\n const res = await runProcess({\n command: hdc,\n args: [...hdcTargetArgsFor(opts.args, opts.deviceSerial), ...opts.args],\n timeoutMs: opts.timeoutMs,\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n logger: opts.logger,\n });\n if (res.code === 0 && hdcClientFailure(`${res.stdout}\\n${res.stderr}`)) return { ...res, code: 1 };\n return res;\n}\n\nexport interface HdcShellOptions extends Omit<HdcExecOptions, 'args'> {\n /** A single shell command, run as `hdc shell <command>` (one argv element — not host word-split). */\n command: string;\n}\n\n/** Convenience wrapper for `hdc shell <command>`. */\nexport function shell(opts: HdcShellOptions): Promise<HdcExecResult> {\n const { command, ...rest } = opts;\n return hdcExec({ ...rest, args: ['shell', command] });\n}\n\n/**\n * Throw a typed {@link CommandFailedError} when `result.code !== 0`, otherwise\n * return the result unchanged. Lets callers opt into throw-semantics.\n */\nexport function ensureOk(result: HdcExecResult, command: string): HdcExecResult {\n if (result.code !== 0) {\n throw new CommandFailedError(command, result.code, withTargetHint(result.stderr.trim() || result.stdout.trim()));\n }\n return result;\n}\n\n/** Append how to pick a device when hdc refused to choose between several. */\nfunction withTargetHint(detail: string): string {\n if (!/need connect-key|Not match target/i.test(detail)) return detail;\n return (\n `${detail}\\nMore than one target is connected, or the serial is unknown: pass --device <serial> ` +\n 'or set ONIRO_DEVICE_SERIAL to one listed by `oniro-app devices`.'\n );\n}\n\n/** Matches the exit-code marker {@link shellChecked} appends. */\nconst REMOTE_RC_RE = /__ONIRO_RC=(-?\\d+)__/g;\n\n/**\n * Parse the exit-code marker appended by {@link shellChecked}. Pure/testable.\n * Returns the remote exit code plus stdout with every marker occurrence\n * stripped, or `null` when no marker is present (the command was killed/timed\n * out, or the device shell never reached the trailing `echo`).\n */\nexport function parseRemoteExit(stdout: string): { code: number; stdout: string } | null {\n let code: number | null = null;\n for (const m of stdout.matchAll(REMOTE_RC_RE)) code = Number(m[1]);\n if (code === null) return null;\n return { code, stdout: stdout.replace(REMOTE_RC_RE, '').replace(/[ \\t\\r\\n]+$/, '') };\n}\n\n/**\n * Like {@link shell}, but recovers the REMOTE command's exit status.\n *\n * `hdc shell \"<cmd>\"` reports hdc's OWN exit code (≈ always 0) regardless of\n * whether `<cmd>` succeeded on the device — so on-device failures (`uinput`\n * rejecting its args, a `bm install` error, a missing binary) otherwise look\n * like success. We append an exit-code marker, parse it back out, and report\n * it as `code`, with the marker stripped from stdout. Pair with\n * {@link ensureRemoteOk} to throw on a non-zero remote exit.\n */\nexport async function shellChecked(opts: HdcShellOptions): Promise<HdcExecResult> {\n const { command, ...rest } = opts;\n const res = await hdcExec({ ...rest, args: ['shell', `${command}; echo \"__ONIRO_RC=$?__\"`] });\n const parsed = parseRemoteExit(res.stdout);\n if (!parsed) return res; // marker missing — fall back to hdc's own exit code\n return { code: parsed.code, stdout: parsed.stdout, stderr: res.stderr };\n}\n\n/**\n * Throw a typed {@link CommandFailedError} on a non-zero result, preferring\n * stderr but falling back to stdout for the detail — device tools like\n * `uinput`/`uitest` print their errors to stdout, not stderr.\n */\nexport function ensureRemoteOk(result: HdcExecResult, command: string): HdcExecResult {\n if (result.code !== 0) {\n throw new CommandFailedError(command, result.code, withTargetHint(result.stderr.trim() || result.stdout.trim()));\n }\n return result;\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { hdcExec, resolveDeviceSerial } from './exec.js';\n\nexport interface DeviceInfo {\n /** Connect key — a USB serial or a `host:port` for a TCP target. */\n serial: string;\n /** 'Connected' | 'Ready' | 'Offline' | 'Unauthorized' | … | 'Unknown' when not reported. */\n status: string;\n /** 'USB' | 'TCP' | … when reported by `-v`. */\n connection?: string;\n /** Device model, populated by getDeviceInfo (not by the bare target list). */\n model?: string;\n}\n\n// Recognised tokens in `hdc list targets -v` rows. Parsing is positional-agnostic\n// (we scan the row's tokens) so it tolerates hdc version differences in column order.\nconst STATUS_TOKENS = new Set([\n 'Connected',\n 'Ready',\n 'Offline',\n 'Unauthorized',\n 'Authorizing',\n 'Disconnected',\n 'Recovery',\n]);\nconst CONNECTION_TOKENS = new Set(['USB', 'TCP', 'UART', 'BT', 'UNKNOWN']);\n\n/**\n * Parse the output of `hdc list targets -v` into structured rows. The first token\n * of each non-empty row is the connect key (serial); connection/status are matched\n * by keyword among the remaining tokens. `[Empty]` (no devices) yields `[]`.\n */\nexport function parseDeviceList(stdout: string): DeviceInfo[] {\n const devices: DeviceInfo[] = [];\n for (const line of stdout.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('[Empty]')) continue;\n const cols = trimmed.split(/\\s+/);\n const serial = cols[0];\n if (!serial) continue;\n const rest = cols.slice(1);\n const connection = rest.find((c) => CONNECTION_TOKENS.has(c));\n const status = rest.find((c) => STATUS_TOKENS.has(c)) ?? 'Unknown';\n const info: DeviceInfo = { serial, status };\n if (connection) info.connection = connection;\n devices.push(info);\n }\n return devices;\n}\n\n/** List connected hdc targets via `hdc list targets -v`. Empty list when none. */\nexport async function listDevices(\n config: ConfigProvider,\n opts: { timeoutMs?: number; logger?: Logger } = {},\n): Promise<DeviceInfo[]> {\n const res = await hdcExec({\n config,\n args: ['list', 'targets', '-v'],\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n return parseDeviceList(res.stdout);\n}\n\n/**\n * Resolve which device serial to address: an explicit `serial` wins, then the\n * `ONIRO_DEVICE_SERIAL` / `DEVICE_SERIAL` env vars, then the single connected\n * device. Throws when none or more than one is connected and nothing was specified.\n */\nexport async function selectDevice(\n config: ConfigProvider,\n serial?: string,\n opts: { timeoutMs?: number; logger?: Logger } = {},\n): Promise<string> {\n const resolved = resolveDeviceSerial(serial);\n if (resolved) return resolved;\n\n const usable = (await listDevices(config, opts)).filter(\n (d) => d.status === 'Connected' || d.status === 'Unknown',\n );\n if (usable.length === 1) return usable[0]!.serial;\n if (usable.length === 0) {\n throw new OniroError('No connected device found. Connect a device/emulator or set ONIRO_DEVICE_SERIAL.');\n }\n throw new OniroError(\n `Multiple devices connected (${usable.map((d) => d.serial).join(', ')}). ` +\n 'Set ONIRO_DEVICE_SERIAL to choose one.',\n );\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { shell, ensureOk } from './exec.js';\n\nexport interface ParamOptions {\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * `param get` prints this instead of a value for an unset property (and still\n * exits 0), e.g. `Get parameter \"const.product.os.dist.name\" fail! errNum is:106!`\n * on OpenHarmony.\n */\nconst PARAM_MISSING_RE = /^Get parameter \".*\" fail!/;\n\n/** Read a system property via `hdc shell param get <key>`. Returns the trimmed value; throws when it is unset. */\nexport async function paramGet(config: ConfigProvider, key: string, opts: ParamOptions = {}): Promise<string> {\n const res = await shell({\n config,\n command: `param get ${key}`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n ensureOk(res, `hdc shell param get ${key}`);\n const value = res.stdout.trim();\n if (PARAM_MISSING_RE.test(value)) throw new OniroError(`System parameter ${key} is not set: ${value}`);\n return value;\n}\n\nconst PARAM_SEPARATOR = '__ONIRO_PARAM__';\n\n/**\n * Split the output of {@link paramGetMany}'s single shell call back into one value\n * per key; unset properties come back undefined. Pure/testable.\n */\nexport function parseParamValues(keys: readonly string[], stdout: string): Record<string, string | undefined> {\n const parts = stdout.split(PARAM_SEPARATOR);\n const values: Record<string, string | undefined> = {};\n keys.forEach((key, i) => {\n const value = parts[i]?.trim();\n values[key] = value && !PARAM_MISSING_RE.test(value) ? value : undefined;\n });\n return values;\n}\n\n/** Read several system properties in one `hdc shell` round trip. Unset properties come back undefined. */\nexport async function paramGetMany(\n config: ConfigProvider,\n keys: readonly string[],\n opts: ParamOptions = {},\n): Promise<Record<string, string | undefined>> {\n const res = await shell({\n config,\n command: keys.map((k) => `param get ${k}; echo ${PARAM_SEPARATOR}`).join('; '),\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n ensureOk(res, 'hdc shell param get …');\n return parseParamValues(keys, res.stdout);\n}\n\n/**\n * Set a system property via `hdc shell param set <key> <value>`. The canonical\n * reboot path is `paramSet(config, 'ohos.startup.powerctrl', 'reboot')`.\n */\nexport async function paramSet(\n config: ConfigProvider,\n key: string,\n value: string,\n opts: ParamOptions = {},\n): Promise<void> {\n const res = await shell({\n config,\n command: `param set ${key} ${value}`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n ensureOk(res, `hdc shell param set ${key} ${value}`);\n}\n","import * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { toLongPath } from '../sdk/paths.js';\nimport { hdcExec, ensureOk, ensureRemoteOk, shellChecked, type OutputSink } from './exec.js';\n\n/**\n * A host path in the form hdc understands: absolute, with native separators and,\n * on Windows, no 8.3 short names. hdc treats a forward-slash Windows path such as\n * `C:/Users/me/x.txt` as relative and joins it onto the current directory. The\n * last component may not exist yet (a `recv` destination).\n */\nexport function normaliseLocalPath(local: string): string {\n const abs = path.resolve(local);\n const long = toLongPath(abs);\n return long !== abs ? long : path.join(toLongPath(path.dirname(abs)), path.basename(abs));\n}\n\n/**\n * Reject a device path that a Windows shell already rewrote into a host path:\n * Git Bash turns `/data/local/tmp/x` into `C:/Program Files/Git/data/local/tmp/x`\n * before the CLI sees it. Device paths never start with a drive letter.\n */\nexport function assertDevicePath(remote: string): void {\n if (/^[A-Za-z]:[\\\\/]/.test(remote)) {\n throw new OniroError(\n `The device path ${remote} is a Windows path. Git Bash rewrites arguments that start with /: ` +\n 'run the command with MSYS_NO_PATHCONV=1, or from PowerShell or cmd.',\n );\n }\n}\n\n/** Where `hdc shell` sees an app's el2 sandbox; the app itself sees it as `/data/storage/el2/base`. */\nexport function appSandboxDir(bundle: string): string {\n return `/data/app/el2/100/base/${bundle}`;\n}\n\n/** Quote a string for the device's POSIX shell. */\nfunction shQuote(s: string): string {\n return `'${s.replace(/'/g, `'\\\\''`)}'`;\n}\n\nexport interface SendFileOptions {\n config: ConfigProvider;\n /** Local source path. */\n local: string;\n /**\n * Remote destination path on the device. With `bundle`, a relative path is\n * resolved inside that app's sandbox (`files/x` is the app's application-level\n * filesDir, `haps/entry/files/x` the entry module's).\n */\n remote: string;\n /**\n * Push into this app's sandbox and give the file to the app's user afterwards:\n * hdc writes files as root, which the app cannot read until they are chowned.\n */\n bundle?: string;\n deviceSerial?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n onOutput?: OutputSink;\n logger?: Logger;\n}\n\n/**\n * Push a local file to the device via `hdc file send <local> <remote>`. Returns\n * the device path the file was written to.\n */\nexport async function sendFile(opts: SendFileOptions): Promise<string> {\n assertDevicePath(opts.remote);\n const local = normaliseLocalPath(opts.local);\n const sandbox = opts.bundle ? appSandboxDir(opts.bundle) : undefined;\n const remote = sandbox && !opts.remote.startsWith('/') ? path.posix.join(sandbox, opts.remote) : opts.remote;\n if (sandbox && !remote.startsWith(`${sandbox}/`)) {\n throw new OniroError(`${remote} is outside the sandbox of ${opts.bundle} (${sandbox}).`);\n }\n const device = { config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger };\n\n if (sandbox) {\n const mkdir = `mkdir -p ${shQuote(path.posix.dirname(remote))}`;\n ensureRemoteOk(await shellChecked({ ...device, command: mkdir }), `hdc shell ${mkdir}`);\n }\n const res = await hdcExec({\n ...device,\n args: ['file', 'send', local, remote],\n timeoutMs: opts.timeoutMs ?? 600_000,\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n });\n ensureOk(res, `hdc file send ${local} ${remote}`);\n\n if (sandbox) {\n // Everything in the sandbox belongs to the app, so hand over the whole top-level\n // directory the file went into: that covers the parents mkdir created too.\n const top = path.posix.join(sandbox, path.posix.relative(sandbox, remote).split('/')[0]!);\n const chown = `chown -R \"$(stat -c %u:%g ${shQuote(sandbox)})\" ${shQuote(top)}`;\n ensureRemoteOk(await shellChecked({ ...device, command: chown }), `hdc shell ${chown}`);\n }\n return remote;\n}\n\nexport interface RecvFileOptions {\n config: ConfigProvider;\n /** Remote source path on the device. */\n remote: string;\n /** Local destination path. */\n local: string;\n deviceSerial?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n onOutput?: OutputSink;\n logger?: Logger;\n}\n\n/** Pull a file from the device via `hdc file recv <remote> <local>`. */\nexport async function recvFile(opts: RecvFileOptions): Promise<void> {\n assertDevicePath(opts.remote);\n const local = normaliseLocalPath(opts.local);\n const res = await hdcExec({\n config: opts.config,\n args: ['file', 'recv', opts.remote, local],\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 600_000,\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n logger: opts.logger,\n });\n ensureOk(res, `hdc file recv ${opts.remote} ${local}`);\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { shell } from './exec.js';\n\nexport interface DisplaySize {\n width: number;\n height: number;\n}\n\nexport interface DisplaySizeOptions {\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * Resolve the device's render resolution from `hidumper -s 10 -a screen`\n * (`render resolution=WxH`). Returns null when unavailable. This is the W/H\n * source for screenshots and the 0–1 normalization of layout bounds — no image\n * decoding is involved.\n */\nexport async function getDisplaySize(config: ConfigProvider, opts: DisplaySizeOptions = {}): Promise<DisplaySize | null> {\n const res = await shell({\n config,\n command: 'hidumper -s 10 -a screen',\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n if (res.code !== 0) return null;\n const m = res.stdout.match(/render resolution=(\\d+)x(\\d+)/);\n if (!m) return null;\n return { width: Number(m[1]), height: Number(m[2]) };\n}\n","import type { Logger } from '../ports/logger.js';\nimport { CancelledError, OniroError } from '../ports/errors.js';\n\nexport interface WaitForConditionOptions {\n /** Resolves true when the condition is satisfied. Called once per poll. */\n probe: () => Promise<boolean>;\n /** Overall deadline. */\n timeoutMs: number;\n /** Poll interval. Default 2000. */\n pollMs?: number;\n /** Abort the wait; rejects with CancelledError. */\n abortSignal?: AbortSignal;\n /** Called every `heartbeatEvery` attempts (default 6) with progress info. */\n onHeartbeat?: (attempt: number, remainingMs: number) => void;\n heartbeatEvery?: number;\n logger?: Logger;\n /** Message for the timeout error. */\n timeoutMessage?: string;\n}\n\n/** Sleep `ms`, rejecting early (CancelledError) if `signal` aborts. */\nfunction delay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(new CancelledError('Wait cancelled.'));\n return;\n }\n const onAbort = (): void => {\n cleanup();\n reject(new CancelledError('Wait cancelled.'));\n };\n const cleanup = (): void => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n };\n const timer = setTimeout(() => {\n cleanup();\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/**\n * Generic deadline + poll + heartbeat loop. Calls `probe()` every `pollMs` until\n * it resolves true (→ resolve) or the deadline passes (→ throw OniroError).\n * A probe that throws is treated as \"not yet\" (the loop keeps polling) — this is\n * what lets device waits tolerate transient hdc disconnects mid-reboot. Aborting\n * the signal rejects with CancelledError.\n *\n * Extracted from the emulator hdc-wait loop so device lifecycle helpers share it.\n */\nexport async function waitForCondition(opts: WaitForConditionOptions): Promise<void> {\n const pollMs = opts.pollMs ?? 2000;\n const heartbeatEvery = opts.heartbeatEvery ?? 6;\n const deadline = Date.now() + opts.timeoutMs;\n let attempt = 0;\n\n while (Date.now() < deadline) {\n if (opts.abortSignal?.aborted) throw new CancelledError('Wait cancelled.');\n attempt++;\n\n let ok = false;\n try {\n ok = await opts.probe();\n } catch {\n ok = false; // transient failure (e.g. hdc disconnect) — keep polling\n }\n if (ok) return;\n\n if (opts.onHeartbeat && attempt % heartbeatEvery === 0) {\n opts.onHeartbeat(attempt, Math.max(0, deadline - Date.now()));\n }\n await delay(pollMs, opts.abortSignal);\n }\n\n throw new OniroError(opts.timeoutMessage ?? `Condition not met within ${opts.timeoutMs}ms.`);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ChildProcess } from 'node:child_process';\nimport type { ConfigProvider } from '../ports/config.js';\nimport { defaultPaths } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger, scopedLogger } from '../ports/logger.js';\nimport { CommandFailedError, OniroError } from '../ports/errors.js';\nimport { getHdcPath } from '../sdk/paths.js';\nimport { discoverHaps, pickHap } from '../build/discoverHaps.js';\nimport { killProcessTree, spawnCompat } from './spawnCompat.js';\nimport { hdcExec, hdcTargetArgs, shell, ensureOk, type HdcExecResult } from './exec.js';\nimport { getBundleName, getMainAbility } from './project.js';\n\nexport interface InstallAppOptions {\n config: ConfigProvider;\n projectDir: string;\n /**\n * Explicit path (absolute, or relative to projectDir) to the `.hap`. Falls back\n * to the `hapPath` config key, then to the well-known signed entry HAP, then to\n * the HAPs the build produced (signed first, else unsigned). A `*-signed.hap`\n * that does not exist falls back to its `*-unsigned.hap` sibling.\n */\n hapPath?: string;\n deviceSerial?: string;\n logger?: Logger;\n}\n\nexport interface InstallAppResult {\n installed: boolean;\n /** Bundle name read from the project's AppScope/app.json5, or '' if unavailable. */\n bundleName: string;\n /** The resolved absolute HAP path that was installed. */\n hapPath: string;\n /** Combined stdout+stderr from the install, trimmed. */\n output: string;\n}\n\n/**\n * The bundle manager's rejection in `hdc install` output, or null when the\n * install went through. hdc exits 0 either way: success prints `msg:install\n * bundle successfully.`, a rejection `msg:error: failed to install bundle.`\n * with a `code:95xxxxx`. Pure/testable.\n */\nexport function detectInstallFailure(output: string): string | null {\n return /\\[Fail\\]|msg:\\s*error|error:\\s*failed to install|code:\\s*95\\d{5}/i.test(output) ? output.trim() : null;\n}\n\n/** The HAP an install is about to push, and how it was chosen. */\nexport interface InstallCandidate {\n path: string;\n /** True when no signed HAP was found and this unsigned one was taken instead. */\n fallback?: boolean;\n}\n\n/** Whether a HAP is an `*-unsigned.hap`, by its file name as hvigor writes it. */\nexport function isUnsignedHap(hapPath: string): boolean {\n return path.basename(hapPath).includes('unsigned');\n}\n\n/**\n * The bundle manager's reason from rejected `hdc install` output, e.g. `code\n * 9568320: no signature file`, else the output's first line. Pure/testable.\n */\nexport function installFailureReason(output: string): string {\n const code = /code:\\s*(\\d+)/i.exec(output);\n if (!code) return output.trim().split(/\\r?\\n/)[0] ?? '';\n const message = /error:\\s*([^\\r\\n]+)/i.exec(output.slice(code.index + code[0].length))?.[1]?.trim().replace(/\\.$/, '');\n return message ? `code ${code[1]}: ${message}` : `code ${code[1]}`;\n}\n\n/**\n * The message for a target that rejected an unsigned HAP: what was tried, the\n * bundle manager's reason, and, when the reason is the missing signature, how to\n * sign for the target. Pure/testable.\n */\nexport function unsignedHapRejection(output: string, hap: InstallCandidate): string {\n const name = path.basename(hap.path);\n const reason = installFailureReason(output);\n const what = hap.fallback\n ? `No signed HAP was found, so the unsigned ${name} was tried, and the target rejected it (${reason}).`\n : `The target rejected the unsigned ${name} (${reason}).`;\n if (!/9568320|signature|pkcs7/i.test(reason)) return what;\n return (\n `${what} This target installs only signed HAPs. Sign the project for it, build again, and install the signed HAP: ` +\n '`oniro-app sign` for an OpenHarmony device or the Oniro emulator, `oniro-app sign --harmonyos` for a HarmonyOS device.'\n );\n}\n\n/**\n * Throw when hdc or the bundle manager rejected an install: a typed\n * {@link CommandFailedError}, or, when the bundle manager turned down an unsigned\n * `hap`, an {@link OniroError} explaining {@link unsignedHapRejection why}.\n */\nexport function ensureInstallOk(result: HdcExecResult, command: string, hap?: InstallCandidate): HdcExecResult {\n const output = `${result.stdout}\\n${result.stderr}`;\n if (hap && isUnsignedHap(hap.path) && /code:\\s*95\\d{5}/i.test(output)) {\n throw new OniroError(unsignedHapRejection(output, hap), new CommandFailedError(command, result.code || 1, output.trim()));\n }\n ensureOk(result, command);\n const failure = detectInstallFailure(output);\n if (failure) throw new CommandFailedError(command, 1, failure);\n return result;\n}\n\n/**\n * An existing HAP at `hapPath`, or, when that is a `*-signed.hap` that does not\n * exist, its `*-unsigned.hap` sibling. Undefined when neither exists.\n */\nexport function existingHapOrUnsigned(hapPath: string): InstallCandidate | undefined {\n if (fs.existsSync(hapPath)) return { path: hapPath };\n const sibling = hapPath.replace(/-signed\\.hap$/i, '-unsigned.hap');\n return sibling !== hapPath && fs.existsSync(sibling) ? { path: sibling, fallback: true } : undefined;\n}\n\nasync function resolveInstallHap(opts: InstallAppOptions, logger: Logger): Promise<InstallCandidate> {\n const warnIfFallback = (hap: InstallCandidate): InstallCandidate => {\n if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path.basename(hap.path)}.`);\n return hap;\n };\n const configured = opts.hapPath ?? opts.config.get('hapPath', '');\n const relative = configured || defaultPaths.hapPath;\n const hapPath = path.isAbsolute(relative) ? relative : path.join(opts.projectDir, relative);\n if (configured) {\n const hap = existingHapOrUnsigned(hapPath);\n if (!hap) throw new OniroError(`HAP file not found at: ${hapPath}. Build the app first.`);\n return warnIfFallback(hap);\n }\n if (fs.existsSync(hapPath)) return { path: hapPath };\n // No explicit HAP and no signed entry HAP: take what the build produced, a\n // signed HAP first, then the entry's unsigned one, then any unsigned one.\n const haps = await discoverHaps({ projectDir: opts.projectDir });\n const anySigned = Object.values(haps).some((m) => m.signed.length > 0);\n const entryUnsigned = anySigned ? undefined : existingHapOrUnsigned(hapPath);\n if (entryUnsigned) return warnIfFallback(entryUnsigned);\n const picked = pickHap(haps);\n if (!picked) throw new OniroError(`No HAP found under ${opts.projectDir}. Build the app first (\\`oniro-app build\\`).`);\n return warnIfFallback({ path: picked.path, fallback: !picked.signed });\n}\n\nexport async function installApp(opts: InstallAppOptions): Promise<InstallAppResult> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n const hap = await resolveInstallHap(opts, logger);\n const hapPath = hap.path;\n\n const result = await hdcExec({\n config: opts.config,\n args: ['install', hapPath],\n deviceSerial: opts.deviceSerial,\n timeoutMs: 300_000,\n });\n if (result.stdout.trim()) logger.info(result.stdout.trim());\n if (result.stderr.trim()) logger.warn(result.stderr.trim());\n ensureInstallOk(result, `hdc install ${hapPath}`, hap);\n\n let bundleName = '';\n try {\n bundleName = getBundleName(opts.projectDir);\n } catch {\n // bundleName is informational; a HAP from a project without AppScope still installs.\n }\n return { installed: true, bundleName, hapPath, output: `${result.stdout}${result.stderr}`.trim() };\n}\n\n/**\n * Whether `bm dump -n <bundle>` finds the bundle on the device. A missing bundle\n * prints `error: failed to get information…`; an installed one, `<bundle>:` and\n * its JSON.\n */\nexport async function isBundleInstalled(opts: BundleOptions): Promise<boolean> {\n const safe = opts.bundle.replace(/'/g, `'\\\\''`);\n const res = await shell({\n config: opts.config,\n command: `bm dump -n '${safe}'`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 15_000,\n logger: opts.logger,\n });\n ensureOk(res, `hdc shell bm dump -n ${opts.bundle}`);\n return res.stdout.includes('{') && !/failed to get information/i.test(res.stdout);\n}\n\nexport interface LaunchAppOptions {\n config: ConfigProvider;\n /** Project mode: resolve bundle + main ability from the project. Required unless `bundleName` is given. */\n projectDir?: string;\n /**\n * Bundle mode: launch an already-installed app directly by bundle name (no\n * project needed). When set, `projectDir` is ignored. If `abilityName` is\n * omitted, the main ability is resolved from the device via `bm dump -n`.\n */\n bundleName?: string;\n /** Override the module name if it isn't the default `entry` (project mode). */\n moduleName?: string;\n /** Explicit ability to launch; defaults to the module's mainElement / first visible ability (project mode) or the installed bundle's main ability (bundle mode). */\n abilityName?: string;\n deviceSerial?: string;\n logger?: Logger;\n}\n\n/**\n * `aa start` exits 0 even when the launch is refused — a locked screen\n * (`Error Code:10106102`), a missing ability, a permission denial, etc. The failure\n * only shows up in its output. Returns the offending text when the output indicates a\n * failed launch, or null when it looks like a success.\n */\nexport function detectAaStartFailure(output: string): string | null {\n return /failed to start ability|Error Code:\\s*\\d|Error Message:/i.test(output) ? output.trim() : null;\n}\n\n/**\n * Parse the main ability of an installed bundle from `bm dump -n <bundle>`\n * output. Pure/testable. The output is a bundle-name prefix line followed by a\n * JSON blob; we take the entry module's `mainElementName` (fallback\n * `mainAbility`), or the first module that declares one. Returns null when the\n * bundle isn't installed or the output is unparseable.\n */\nexport function parseMainAbilityFromBmDump(stdout: string): string | null {\n const start = stdout.indexOf('{');\n if (start < 0) return null;\n let info: { hapModuleInfos?: Array<{ mainElementName?: string; mainAbility?: string; moduleType?: number | string }> };\n try {\n info = JSON.parse(stdout.slice(start));\n } catch {\n return null;\n }\n const mods = Array.isArray(info?.hapModuleInfos) ? info.hapModuleInfos : [];\n const abilityOf = (m: { mainElementName?: string; mainAbility?: string }): string | undefined =>\n (m?.mainElementName || m?.mainAbility) || undefined;\n const isEntry = (m: { moduleType?: number | string }): boolean =>\n m?.moduleType === 1 || m?.moduleType === '1' || m?.moduleType === 'entry';\n const entry = mods.find((m) => isEntry(m) && abilityOf(m));\n const any = mods.find((m) => abilityOf(m));\n return (entry && abilityOf(entry)) || (any && abilityOf(any)) || null;\n}\n\n/** Resolve an installed bundle's main ability off the device via `bm dump -n`. */\nasync function resolveInstalledMainAbility(opts: {\n config: ConfigProvider;\n bundle: string;\n deviceSerial?: string;\n logger?: Logger;\n}): Promise<string> {\n const res = await shell({\n config: opts.config,\n command: `bm dump -n ${opts.bundle}`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: 15_000,\n logger: opts.logger,\n });\n const ability = parseMainAbilityFromBmDump(res.stdout);\n if (!ability) {\n throw new OniroError(\n `Could not determine the main ability for installed bundle ${opts.bundle} ` +\n `(is it installed?). Pass an explicit ability instead.`,\n );\n }\n return ability;\n}\n\nexport async function launchApp(opts: LaunchAppOptions): Promise<void> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n let bundleName: string;\n let mainAbility: string;\n if (opts.bundleName) {\n // Bundle mode: launch an already-installed app directly (no project).\n bundleName = opts.bundleName;\n mainAbility =\n opts.abilityName ??\n (await resolveInstalledMainAbility({\n config: opts.config,\n bundle: bundleName,\n deviceSerial: opts.deviceSerial,\n logger: opts.logger,\n }));\n } else {\n if (!opts.projectDir) throw new OniroError('launchApp requires either bundleName or projectDir.');\n bundleName = getBundleName(opts.projectDir);\n mainAbility = getMainAbility(opts.projectDir, opts.moduleName, opts.abilityName);\n }\n // Pass ability/bundle as discrete argv elements (shell:false), never interpolated\n // into a host shell string — this is the injection fix vs the old `aa start -a ${x}`.\n const result = await hdcExec({\n config: opts.config,\n args: ['shell', 'aa', 'start', '-a', mainAbility, '-b', bundleName],\n deviceSerial: opts.deviceSerial,\n });\n if (result.stdout.trim()) logger.info(result.stdout.trim());\n if (result.stderr.trim()) logger.warn(result.stderr.trim());\n ensureOk(result, `hdc shell aa start -a ${mainAbility} -b ${bundleName}`);\n // `aa start` reports launch failures in its output, not its exit code — surface them\n // instead of silently reporting success.\n const failure = detectAaStartFailure(`${result.stdout}\\n${result.stderr}`);\n if (failure) {\n throw new OniroError(`Failed to launch ${bundleName} (${mainAbility}): ${failure}`);\n }\n}\n\nexport interface RunningProcess {\n pid: string;\n name: string;\n}\n\n/**\n * List running processes via `hdc track-jpid`. Times out after `timeoutMs`.\n * When `targetProcessName` is set, resolves to that process's PID early; otherwise\n * resolves to the full list collected within the timeout window.\n */\nexport function listRunningProcesses(\n config: ConfigProvider,\n options: { targetProcessName?: string; timeoutMs?: number; deviceSerial?: string; logger?: Logger } = {},\n): Promise<RunningProcess[] | string> {\n const logger = options.logger ?? noopLogger;\n const timeoutMs = options.timeoutMs ?? 1000;\n const hdc = getHdcPath(config);\n\n return new Promise((resolve, reject) => {\n // `hdc` may be a batch wrapper on Windows (an `hdcPath` override pointing at\n // a proxy/tunnel script), which a bare spawn cannot execute — spawnCompat\n // routes those through cmd.exe. It can also throw synchronously, so the\n // failure is funnelled into the same rejection as the 'error' event below.\n let proc: ChildProcess;\n try {\n proc = spawnCompat(hdc, [...hdcTargetArgs(options.deviceSerial), 'track-jpid']);\n } catch (err) {\n reject(new OniroError(`Failed to spawn ${hdc}: ${err instanceof Error ? err.message : String(err)}`, err));\n return;\n }\n const processes: RunningProcess[] = [];\n let resolved = false;\n\n proc.stdout?.on('data', (data: Buffer) => {\n for (const line of data.toString().split(/\\r?\\n/).filter(Boolean)) {\n const match = line.match(/^(\\d+)\\s+(.+)$/);\n if (!match) continue;\n const pid = match[1]!;\n const name = match[2]!;\n processes.push({ pid, name });\n if (options.targetProcessName && name === options.targetProcessName && !resolved) {\n resolved = true;\n killProcessTree(proc);\n resolve(pid);\n return;\n }\n }\n });\n\n proc.stderr?.on('data', (data: Buffer) => {\n logger.warn(`[hdc track-jpid] ${data.toString()}`);\n });\n\n proc.on('error', (err) => {\n if (!resolved) {\n resolved = true;\n reject(err);\n }\n });\n\n const timeout = setTimeout(() => {\n if (resolved) return;\n resolved = true;\n killProcessTree(proc);\n if (options.targetProcessName) {\n reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));\n } else {\n resolve(processes);\n }\n }, timeoutMs);\n\n proc.on('close', () => {\n clearTimeout(timeout);\n if (resolved) return;\n resolved = true;\n if (options.targetProcessName) {\n reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));\n } else {\n resolve(processes);\n }\n });\n });\n}\n\nexport async function findAppProcessId(config: ConfigProvider, projectDir: string, logger?: Logger): Promise<string> {\n const bundleName = getBundleName(projectDir);\n const result = await listRunningProcesses(config, { targetProcessName: bundleName, logger });\n return result as string;\n}\n\nexport interface BundleOptions {\n config: ConfigProvider;\n bundle: string;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * Non-throwing companion to {@link listRunningProcesses}: resolve a running\n * process for a bundle, or `null` when it isn't running. Suitable for \"is X\n * running?\" checks (e.g. the pre/post-install pid comparison in applyChanges).\n *\n * `pidof` matches the bundle's main (UIAbility) process. When that isn't found,\n * we fall back to `track-jpid` to also catch **extension-ability** processes,\n * which run under a separate process name `\"<bundle>:<ext>\"` (e.g. a\n * ServiceExtension, FormExtension, UIExtension or input method). Without this,\n * \"verify the running process took the change\" silently reported nothing for an\n * app whose only live process is an extension.\n */\nexport async function findRunningProcess(opts: BundleOptions): Promise<RunningProcess | null> {\n const safe = opts.bundle.replace(/'/g, `'\\\\''`);\n const res = await shell({\n config: opts.config,\n command: `pidof '${safe}'`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 10_000,\n logger: opts.logger,\n });\n const pid = res.stdout.trim().split(/\\s+/).filter(Boolean)[0];\n if (res.code === 0 && pid && /^\\d+$/.test(pid)) return { pid, name: opts.bundle };\n\n // Fallback: the bundle may only be alive as an extension process. track-jpid\n // names them \"<bundle>/<bundle>:<ext>\" (vs bare \"<bundle>\" for the main).\n try {\n const list = await listRunningProcesses(opts.config, {\n timeoutMs: 1200,\n deviceSerial: opts.deviceSerial,\n logger: opts.logger,\n });\n if (Array.isArray(list)) {\n const mine = (name: string): boolean =>\n name === opts.bundle || name.startsWith(`${opts.bundle}/`) || name.startsWith(`${opts.bundle}:`);\n const match = list.find((p) => p.name === opts.bundle) ?? list.find((p) => mine(p.name));\n if (match) return match;\n }\n } catch {\n // best-effort; fall through to \"not running\"\n }\n return null;\n}\n\n/** Uninstall an app by bundle name (`hdc uninstall <bundle>`). */\nexport async function uninstallApp(opts: BundleOptions): Promise<void> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n const res = await hdcExec({\n config: opts.config,\n args: ['uninstall', opts.bundle],\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 120_000,\n });\n if (res.stdout.trim()) logger.info(res.stdout.trim());\n if (res.stderr.trim()) logger.warn(res.stderr.trim());\n ensureOk(res, `hdc uninstall ${opts.bundle}`);\n}\n\n/** Force-stop an app (`hdc shell aa force-stop <bundle>`). */\nexport async function forceStop(opts: BundleOptions): Promise<void> {\n const res = await shell({\n config: opts.config,\n command: `aa force-stop ${opts.bundle}`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 30_000,\n logger: opts.logger,\n });\n ensureOk(res, `hdc shell aa force-stop ${opts.bundle}`);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { OniroError } from '../ports/errors.js';\n\nexport interface ModuleHaps {\n signed: string[];\n unsigned: string[];\n}\n\nexport interface DiscoverHapsOptions {\n projectDir: string;\n /** Max directory recursion depth. Default 8. */\n maxDepth?: number;\n}\n\n/**\n * The build module a HAP belongs to, parsed from its filename\n * (`<module>-<target>-<buildMode>-{signed,unsigned}.hap`): the segment before\n * the first dash. This is the build module NAME — what `--module` refers to and\n * what hvigor stamps into the filename — which, unlike the first path segment,\n * is robust to nested project layouts (e.g. systemui's\n * `product/phone/<folder>/build/.../phone_gestureNavigation-...-signed.hap`,\n * where the module folder is not a top-level directory under projectDir).\n */\nfunction moduleOfHap(hapFileName: string): string {\n const dash = hapFileName.indexOf('-');\n return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\\.hap$/i, '');\n}\n\n/**\n * Walk a project's build outputs and group `*-signed.hap` / `*-unsigned.hap`\n * by build module name (parsed from the HAP filename). Skips `node_modules` /\n * `oh_modules` / `.git`. Ported from the proven MCP `findHaps`, extended with\n * per-module grouping so multi-module projects can install the right HAP.\n * Each list is newest first, so a fresh build wins over HAPs committed to the\n * repository. Empty object when nothing is built.\n */\nexport async function discoverHaps(opts: DiscoverHapsOptions): Promise<Record<string, ModuleHaps>> {\n const { projectDir } = opts;\n const maxDepth = opts.maxDepth ?? 8;\n const result: Record<string, ModuleHaps> = {};\n\n const walk = async (dir: string, depth: number): Promise<void> => {\n if (depth > maxDepth) return;\n const entries = await fs.promises.readdir(dir, { withFileTypes: true }).catch(() => [] as fs.Dirent[]);\n for (const e of entries) {\n const full = path.join(dir, e.name);\n if (e.isDirectory()) {\n if (e.name === 'node_modules' || e.name === 'oh_modules' || e.name === '.git') continue;\n await walk(full, depth + 1);\n } else if (e.isFile() && e.name.endsWith('.hap')) {\n const moduleName = moduleOfHap(e.name);\n const bucket = (result[moduleName] ??= { signed: [], unsigned: [] });\n if (e.name.includes('unsigned')) bucket.unsigned.push(full);\n else if (e.name.includes('signed')) bucket.signed.push(full);\n }\n }\n };\n\n await walk(projectDir, 0);\n const mtime = (p: string): number => fs.statSync(p).mtimeMs;\n for (const bucket of Object.values(result)) {\n bucket.signed.sort((a, b) => mtime(b) - mtime(a));\n bucket.unsigned.sort((a, b) => mtime(b) - mtime(a));\n }\n return result;\n}\n\nexport interface PickedHap {\n module: string;\n path: string;\n /** False for an `*-unsigned.hap`, which targets that verify signatures reject. */\n signed: boolean;\n}\n\n/**\n * The HAP to install from {@link discoverHaps} output: a module's newest signed\n * HAP, else its newest unsigned one. Without `module`, the single module that\n * has a signed HAP, else the single one that has any HAP. Null when nothing is\n * built; throws when several modules qualify and none was named.\n */\nexport function pickHap(haps: Record<string, ModuleHaps>, module?: string): PickedHap | null {\n const pick = (name: string): PickedHap | null => {\n const signed = haps[name]?.signed[0];\n if (signed) return { module: name, path: signed, signed: true };\n const unsigned = haps[name]?.unsigned[0];\n return unsigned ? { module: name, path: unsigned, signed: false } : null;\n };\n if (module) return pick(module);\n const names = Object.keys(haps);\n const withSigned = names.filter((n) => haps[n]!.signed.length > 0);\n const candidates = withSigned.length > 0 ? withSigned : names.filter((n) => haps[n]!.unsigned.length > 0);\n if (candidates.length === 0) return null;\n if (candidates.length > 1) {\n throw new OniroError(`Multiple modules have built HAPs (${candidates.join(', ')}). Pass a module to choose.`);\n }\n return pick(candidates[0]!);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport JSON5 from 'json5';\nimport { OniroError } from '../ports/errors.js';\n\nfunction readJson5<T>(filePath: string): T {\n const content = fs.readFileSync(filePath, 'utf-8');\n return JSON5.parse(content) as T;\n}\n\n/**\n * Read the project's bundle name from `AppScope/app.json5`.\n */\nexport function getBundleName(projectDir: string): string {\n const appJsonPath = path.join(projectDir, 'AppScope', 'app.json5');\n if (!fs.existsSync(appJsonPath)) {\n throw new OniroError(`Could not find app.json5 at ${appJsonPath}`);\n }\n const appJson = readJson5<{ app?: { bundleName?: string } }>(appJsonPath);\n if (!appJson.app?.bundleName) {\n throw new OniroError('bundleName not found in app.json5');\n }\n return appJson.app.bundleName;\n}\n\n/**\n * Read the ability to launch from `<module>/src/main/module.json5`. Defaults to\n * `entry` for the module folder name. Resolution order:\n * 1. `abilityName`, if given and present in `module.abilities[]`.\n * 2. `module.mainElement`.\n * 3. The first `visible` ability, then the first ability, from `module.abilities[]`.\n * Modules with multiple abilities can be targeted explicitly via `abilityName`.\n */\nexport function getMainAbility(projectDir: string, moduleName = 'entry', abilityName?: string): string {\n const moduleJsonPath = path.join(projectDir, moduleName, 'src', 'main', 'module.json5');\n if (!fs.existsSync(moduleJsonPath)) {\n throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);\n }\n const moduleJson = readJson5<{\n module?: { mainElement?: string; abilities?: Array<{ name?: string; visible?: boolean }> };\n }>(moduleJsonPath);\n const module = moduleJson.module ?? {};\n\n if (abilityName) {\n const match = module.abilities?.find((a) => a.name === abilityName);\n if (match?.name) return match.name;\n throw new OniroError(`Ability \"${abilityName}\" not found in module.json5 at ${moduleJsonPath}`);\n }\n\n if (module.mainElement) return module.mainElement;\n\n const abilities = module.abilities ?? [];\n const visible = abilities.find((a) => a.visible && a.name);\n if (visible?.name) return visible.name;\n const first = abilities.find((a) => a.name);\n if (first?.name) return first.name;\n\n throw new OniroError('mainElement not found in module.json5');\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger, scopedLogger } from '../ports/logger.js';\nimport { hdcExec, shell } from './exec.js';\nimport { paramSet } from './param.js';\nimport { findRunningProcess } from './app.js';\nimport { waitForCondition } from './wait.js';\n\n/** Probe whether the device responds to a trivial shell command. */\nasync function isReachable(config: ConfigProvider, deviceSerial?: string): Promise<boolean> {\n try {\n const res = await shell({ config, command: 'echo oniro_ping', deviceSerial, timeoutMs: 5_000 });\n return res.code === 0 && res.stdout.includes('oniro_ping');\n } catch {\n return false;\n }\n}\n\n/**\n * A TCP/network hdc target — \"host:port\", e.g. the emulator's `127.0.0.1:55555`.\n * USB serials (e.g. `emulator-5554`) have no `:port` suffix.\n */\nconst TCP_SERIAL_RE = /^.+:\\d+$/;\n\n/**\n * Polls in a row on which `hdc tconn` says a TCP target is already connected while it\n * does not answer, before the hdc server is restarted.\n */\nconst WEDGED_POLLS_BEFORE_RESTART = 3;\n\n/**\n * Re-establish the hdc connection to a TCP target, best-effort. hdc auto-reconnects\n * a USB device when it re-enumerates, but a TCP target must be reconnected explicitly\n * with `hdc tconn` after the session drops — which is exactly what a reboot does, so\n * without this a post-reboot `waitForBundle`/`waitForBoot` polls a dead socket until it\n * times out. A no-op for USB serials or when no serial is given, so it is safe to call\n * before every poll; failure is swallowed (the device may still be down, and the probe\n * that follows reports not-ready so we simply poll again).\n *\n * After a reboot the hdc server can also wedge on the old session: it keeps the target\n * \"Connected\", answers `tconn` with \"Target is connected, repeat operation\" and fails\n * every command (\"session is dead\") until the server restarts. Seen intermittently\n * with the OpenHarmony 7.0 emulator. So the returned function counts the polls on\n * which tconn claims a connection the target does not answer, and after\n * {@link WEDGED_POLLS_BEFORE_RESTART} of them in a row restarts the server with\n * `hdc start -r`, as `attemptHdcConnection` does, and reconnects. The count lives in\n * the closure, so create one reconnector per wait.\n */\nfunction tcpReconnector(config: ConfigProvider, deviceSerial: string | undefined, logger: Logger): () => Promise<void> {\n let wedgedPolls = 0;\n return async () => {\n if (!deviceSerial || !TCP_SERIAL_RE.test(deviceSerial)) return;\n let claimsConnected = false;\n try {\n const res = await hdcExec({ config, args: ['tconn', deviceSerial], timeoutMs: 5_000, logger });\n claimsConnected = /already connected|repeat operation/i.test(`${res.stdout}\\n${res.stderr}`);\n } catch {\n /* still down — the following probe reports not-ready and we poll again */\n }\n // A healthy session also answers \"repeat operation\"; only an unreachable one counts.\n if (!claimsConnected || (await isReachable(config, deviceSerial))) {\n wedgedPolls = 0;\n return;\n }\n if (++wedgedPolls < WEDGED_POLLS_BEFORE_RESTART) return;\n wedgedPolls = 0;\n logger.warn(`hdc reports ${deviceSerial} as connected but it does not answer; restarting the hdc server.`);\n try {\n await hdcExec({ config, args: ['start', '-r'], timeoutMs: 15_000, logger });\n await hdcExec({ config, args: ['tconn', deviceSerial], timeoutMs: 5_000, logger });\n } catch {\n /* the next poll tries again */\n }\n };\n}\n\nexport interface WaitForBundleOptions {\n config: ConfigProvider;\n bundle: string;\n deviceSerial?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/**\n * Poll `pidof <bundle>` until the bundle has a clean numeric pid. Empty/failed\n * pidof responses (including while the device is unreachable) do NOT count.\n */\nexport async function waitForBundle(opts: WaitForBundleOptions): Promise<void> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n const timeoutMs = opts.timeoutMs ?? 180_000;\n const reconnectIfTcp = tcpReconnector(opts.config, opts.deviceSerial, logger);\n await waitForCondition({\n probe: async () => {\n await reconnectIfTcp();\n return (\n (await findRunningProcess({ config: opts.config, bundle: opts.bundle, deviceSerial: opts.deviceSerial, timeoutMs: 8_000 })) !== null\n );\n },\n timeoutMs,\n pollMs: 2_000,\n abortSignal: opts.abortSignal,\n onHeartbeat: (attempt, remaining) =>\n logger.info(`waiting for ${opts.bundle} (attempt ${attempt}, ${Math.floor(remaining / 1000)}s left)`),\n timeoutMessage: `Bundle ${opts.bundle} did not start within ${timeoutMs}ms.`,\n });\n}\n\nexport interface WaitForBootOptions {\n config: ConfigProvider;\n /** Require a clean numeric pid for this process/bundle name before returning. */\n untilPidOf?: string;\n deviceSerial?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/**\n * Poll until the device responds AND (when `untilPidOf` is set) that process has\n * a clean numeric pid. Tolerates the transient hdc disconnect during a reboot.\n */\nexport async function waitForBoot(opts: WaitForBootOptions): Promise<void> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n const timeoutMs = opts.timeoutMs ?? 180_000;\n const reconnectIfTcp = tcpReconnector(opts.config, opts.deviceSerial, logger);\n await waitForCondition({\n probe: async () => {\n await reconnectIfTcp();\n if (!(await isReachable(opts.config, opts.deviceSerial))) return false;\n if (!opts.untilPidOf) return true;\n return (\n (await findRunningProcess({ config: opts.config, bundle: opts.untilPidOf, deviceSerial: opts.deviceSerial, timeoutMs: 8_000 })) !== null\n );\n },\n timeoutMs,\n pollMs: 2_000,\n abortSignal: opts.abortSignal,\n onHeartbeat: (attempt, remaining) =>\n logger.info(`waiting for boot (attempt ${attempt}, ${Math.floor(remaining / 1000)}s left)`),\n timeoutMessage: `Device did not boot within ${timeoutMs}ms.`,\n });\n}\n\nexport interface RebootOptions {\n config: ConfigProvider;\n /** 'system' (default) reboots via param set; bootloader/recovery via `reboot <mode>`. */\n mode?: 'system' | 'bootloader' | 'recovery';\n /** When set (system mode), block until this bundle has a clean numeric pid after the reboot. */\n waitForBundle?: string;\n deviceSerial?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/**\n * Reboot the device. System reboots use `param set ohos.startup.powerctrl reboot`\n * (the path that works when force-stopping systemui is blocked); bootloader/\n * recovery use `hdc shell reboot <mode>`. A reboot frequently tears down the hdc\n * connection before the command returns, so command failure here is tolerated.\n *\n * When `waitForBundle` is set (system mode), waits for the device to drop and\n * come back with the bundle running — so it doesn't return on the pre-reboot pid.\n * A TCP target (e.g. an emulator at `127.0.0.1:55555`) is reconnected via\n * `hdc tconn` during that wait, since hdc does not auto-reconnect TCP sessions\n * across a reboot the way it does USB devices — pass the address as `deviceSerial`.\n */\nexport async function reboot(opts: RebootOptions): Promise<void> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'hdc');\n const mode = opts.mode ?? 'system';\n const timeoutMs = opts.timeoutMs ?? 180_000;\n\n logger.info(`Rebooting device (${mode})...`);\n try {\n if (mode === 'system') {\n await paramSet(opts.config, 'ohos.startup.powerctrl', 'reboot', {\n deviceSerial: opts.deviceSerial,\n timeoutMs: 15_000,\n logger: opts.logger,\n });\n } else {\n await shell({ config: opts.config, command: `reboot ${mode}`, deviceSerial: opts.deviceSerial, timeoutMs: 15_000 });\n }\n } catch (err) {\n // Expected: the reboot tore down hdc before the command returned cleanly.\n logger.debug(`reboot command did not return cleanly: ${(err as Error).message}`);\n }\n\n if (mode !== 'system' || !opts.waitForBundle) return;\n\n // Wait for the device to actually go down first (best-effort) so the subsequent\n // bundle wait can't match the pre-reboot process, then wait for it to return.\n try {\n await waitForCondition({\n probe: async () => !(await isReachable(opts.config, opts.deviceSerial)),\n timeoutMs: Math.min(timeoutMs, 30_000),\n pollMs: 1_500,\n abortSignal: opts.abortSignal,\n timeoutMessage: 'device did not become unreachable',\n });\n } catch {\n // Device may reboot too fast to observe the down state — proceed to wait for it.\n }\n\n await waitForBundle({\n config: opts.config,\n bundle: opts.waitForBundle,\n deviceSerial: opts.deviceSerial,\n timeoutMs,\n abortSignal: opts.abortSignal,\n logger: opts.logger,\n });\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { randomBytes } from 'node:crypto';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { shell, ensureOk } from './exec.js';\nimport { recvFile } from './files.js';\nimport { getDisplaySize } from './display.js';\n\nexport interface Screenshot {\n /** Raw JPEG bytes, exactly as `snapshot_display` wrote them (no decode/resize). */\n pixels: Buffer;\n /** Device render width/height from hidumper; 0 when it couldn't be resolved. */\n width: number;\n height: number;\n}\n\nexport interface ScreenshotOptions {\n config: ConfigProvider;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\nfunction tmpName(ext: string): string {\n return path.join(os.tmpdir(), `oniro_screen_${randomBytes(6).toString('hex')}.${ext}`);\n}\n\n/**\n * Capture the screen via on-device `snapshot_display`, pull the JPEG bytes back,\n * and return them raw alongside the device resolution. The agent-facing grid\n * overlay / downscale / base64 encoding stays in the MCP — core does no image\n * decoding and adds no image dependency.\n */\nexport async function takeScreenshot(opts: ScreenshotOptions): Promise<Screenshot> {\n const remote = '/data/local/tmp/oniro_screenshot.jpeg';\n const timeoutMs = opts.timeoutMs ?? 30_000;\n\n const cap = await shell({ config: opts.config, command: `snapshot_display -f ${remote}`, deviceSerial: opts.deviceSerial, timeoutMs });\n ensureOk(cap, `snapshot_display -f ${remote}`);\n\n const local = tmpName('jpeg');\n try {\n await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });\n const pixels = await fs.promises.readFile(local);\n const size = (await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial })) ?? { width: 0, height: 0 };\n return { pixels, width: size.width, height: size.height };\n } finally {\n fs.promises.unlink(local).catch(() => {});\n void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {});\n }\n}\n\nexport interface CaptureBurstOptions {\n config: ConfigProvider;\n count: number;\n /** Delay between device-side captures, ms. */\n intervalMs: number;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * Capture `count` frames `intervalMs` apart in a single device-side loop, then\n * pull each frame back. Returns the raw JPEG buffers in order. The MCP composites\n * these into a contact sheet + per-frame diff; core just returns the frames.\n */\nexport async function captureBurst(opts: CaptureBurstOptions): Promise<Buffer[]> {\n const count = Math.max(1, Math.floor(opts.count));\n const remoteDir = `/data/local/tmp/oniro_burst_${randomBytes(6).toString('hex')}`;\n const sleepSec = opts.intervalMs > 0 ? (opts.intervalMs / 1000).toFixed(3) : '0';\n // One device-side loop so the frames are device-timed, not gated on host roundtrips.\n const loop =\n `mkdir -p ${remoteDir}; i=0; while [ $i -lt ${count} ]; do ` +\n `snapshot_display -f ${remoteDir}/f$i.jpeg; ` +\n `[ ${count} -gt 1 ] && sleep ${sleepSec}; i=$((i+1)); done`;\n const cap = await shell({ config: opts.config, command: loop, deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 120_000 });\n ensureOk(cap, 'snapshot_display burst');\n\n const frames: Buffer[] = [];\n try {\n for (let i = 0; i < count; i++) {\n const local = tmpName(`burst_${i}.jpeg`);\n try {\n await recvFile({ config: opts.config, remote: `${remoteDir}/f${i}.jpeg`, local, deviceSerial: opts.deviceSerial });\n frames.push(await fs.promises.readFile(local));\n } finally {\n fs.promises.unlink(local).catch(() => {});\n }\n }\n } finally {\n void shell({ config: opts.config, command: `rm -rf ${remoteDir}`, deviceSerial: opts.deviceSerial }).catch(() => {});\n }\n return frames;\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { shellChecked, ensureRemoteOk } from './exec.js';\n\nexport type InputType =\n | 'click'\n | 'doubleClick'\n | 'longClick'\n | 'swipe'\n | 'drag'\n | 'fling'\n | 'keyEvent'\n | 'inputText';\n\nexport interface SendInputOptions {\n config: ConfigProvider;\n type: InputType;\n /** Pixel coordinates. The %→px conversion lives in the MCP, not core. */\n pxX?: number;\n pxY?: number;\n pxX2?: number;\n pxY2?: number;\n /** Velocity for swipe/drag/fling. */\n speed?: number;\n /** Key for keyEvent: a KeyCode id, a name (Back, Delete, Enter, …), or a combo like `Ctrl+A`. See {@link resolveKeyEvent}. */\n key?: string | number;\n /** Text for inputText. */\n text?: string;\n deviceSerial?: string;\n logger?: Logger;\n}\n\n// uitest accepts these key names itself.\nconst UITEST_KEY_NAMES = ['Back', 'Home', 'Power'];\n\n// OpenHarmony KeyCode ids (@ohos.multimodalInput.keyCode) for keys addressed by name.\nconst KEY_IDS: Record<string, number> = {\n back: 2,\n home: 1,\n power: 18,\n volumeup: 16,\n volumedown: 17,\n up: 2012,\n down: 2013,\n left: 2014,\n right: 2015,\n alt: 2045,\n shift: 2047,\n tab: 2049,\n space: 2050,\n enter: 2054,\n delete: 2055,\n backspace: 2055,\n pageup: 2068,\n pagedown: 2069,\n escape: 2070,\n esc: 2070,\n forwarddelete: 2071,\n ctrl: 2072,\n meta: 2076,\n movehome: 2081,\n moveend: 2082,\n};\n\nfunction keyId(name: string): number {\n const k = name.trim().toLowerCase();\n if (/^\\d+$/.test(k)) return Number(k);\n if (/^[a-z]$/.test(k)) return 2017 + (k.charCodeAt(0) - 97); // KEYCODE_A..KEYCODE_Z\n const id = KEY_IDS[k];\n if (id === undefined) {\n throw new OniroError(\n `Unknown key \"${name}\". Use a numeric KeyCode id, a letter, or one of: ` +\n `${Object.keys(KEY_IDS).join(', ')}. Combine up to three with \"+\", e.g. Ctrl+A.`,\n );\n }\n return id;\n}\n\n/**\n * Resolve a key spec to `uitest uiInput keyEvent` arguments. Accepts uitest's\n * own names (Back/Home/Power), numeric KeyCode ids, named keys (Delete, Enter,\n * Tab, Escape, MoveHome, …), single letters, and combos of up to three keys\n * joined by \"+\" (e.g. `Ctrl+A`) or given as space-separated ids. Pure.\n */\nexport function resolveKeyEvent(key: string | number): string {\n const spec = String(key).trim();\n if (spec === '') throw new OniroError('send input \"keyEvent\" requires a key.');\n const native = UITEST_KEY_NAMES.find((n) => n.toLowerCase() === spec.toLowerCase());\n if (native) return native;\n const parts = spec.includes('+') ? spec.split('+') : spec.split(/\\s+/);\n if (parts.length > 3) throw new OniroError(`uitest injects at most three keys at once; got \"${spec}\".`);\n return parts.map(keyId).join(' ');\n}\n\nfunction reqNum(value: number | undefined, name: string, type: string): number {\n if (value === undefined || Number.isNaN(value)) {\n throw new OniroError(`send input \"${type}\" requires a numeric ${name}.`);\n }\n return value;\n}\n\n/**\n * Build the `uitest uiInput …` command for an input action, in pixel space.\n * Pure (no I/O) so it is unit-testable. Mirrors the proven MCP construction\n * minus the percentage→pixel step.\n */\nexport function buildInputCommand(opts: SendInputOptions): string {\n switch (opts.type) {\n case 'click':\n case 'doubleClick':\n case 'longClick':\n return `uitest uiInput ${opts.type} ${reqNum(opts.pxX, 'pxX', opts.type)} ${reqNum(opts.pxY, 'pxY', opts.type)}`;\n case 'swipe':\n case 'drag':\n case 'fling': {\n const base =\n `uitest uiInput ${opts.type} ${reqNum(opts.pxX, 'pxX', opts.type)} ${reqNum(opts.pxY, 'pxY', opts.type)} ` +\n `${reqNum(opts.pxX2, 'pxX2', opts.type)} ${reqNum(opts.pxY2, 'pxY2', opts.type)}`;\n return opts.speed !== undefined ? `${base} ${opts.speed}` : base;\n }\n case 'keyEvent':\n if (opts.key === undefined || opts.key === '') throw new OniroError('send input \"keyEvent\" requires a key.');\n return `uitest uiInput keyEvent ${resolveKeyEvent(opts.key)}`;\n case 'inputText': {\n const t = String(opts.text ?? '').replace(/'/g, `'\\\\''`);\n if (opts.pxX !== undefined && opts.pxY !== undefined) {\n return `uitest uiInput inputText ${opts.pxX} ${opts.pxY} '${t}'`;\n }\n return `uitest uiInput text '${t}'`;\n }\n }\n}\n\n/** Inject a UI input action via `uitest uiInput` (pixel coordinates). */\nexport async function sendInput(opts: SendInputOptions): Promise<void> {\n const cmd = buildInputCommand(opts);\n const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 30_000, logger: opts.logger });\n ensureRemoteOk(res, `hdc shell ${cmd}`);\n}\n\nexport interface Waypoint {\n /** Pixel x. */\n x: number;\n /** Pixel y. */\n y: number;\n /** Time in ms relative to the gesture start. */\n t: number;\n}\n\nexport interface SendGestureOptions {\n config: ConfigProvider;\n waypoints: Waypoint[];\n /** Hold at the first point before moving (ms). Honored via the raw-touch path. */\n holdStartMs?: number;\n /** Hold at the last point before lifting (ms). Honored via the raw-touch path. */\n holdEndMs?: number;\n deviceSerial?: string;\n logger?: Logger;\n}\n\n/**\n * Build the chained `uitest uiInput drag` commands for a multi-segment path.\n * Per segment, speed is derived from the waypoint time deltas (px/s). Pure.\n */\nexport function buildGestureCommands(waypoints: Waypoint[]): string[] {\n if (waypoints.length < 2) {\n throw new OniroError('sendGesture requires at least two waypoints.');\n }\n const cmds: string[] = [];\n for (let i = 1; i < waypoints.length; i++) {\n const a = waypoints[i - 1]!;\n const b = waypoints[i]!;\n const dt = b.t - a.t;\n const dist = Math.hypot(b.x - a.x, b.y - a.y);\n let cmd = `uitest uiInput drag ${a.x} ${a.y} ${b.x} ${b.y}`;\n if (dt > 0 && dist > 0) cmd += ` ${Math.round(dist / (dt / 1000))}`;\n cmds.push(cmd);\n }\n return cmds;\n}\n\nexport interface RawTouchEvent {\n type: 'down' | 'move' | 'up';\n x: number;\n y: number;\n /** Time in ms relative to the gesture start. */\n t: number;\n}\n\nexport interface SendRawTouchOptions {\n config: ConfigProvider;\n events: RawTouchEvent[];\n deviceSerial?: string;\n logger?: Logger;\n}\n\n/**\n * Build a single `uinput -T` touch operation sequence from down/move/up events,\n * interleaving `-i <ms>` intervals from the event time deltas. Pure.\n */\nexport function buildRawTouchCommand(events: RawTouchEvent[]): string {\n if (events.length === 0) throw new OniroError('sendRawTouch requires at least one event.');\n const ops: string[] = [];\n let prev: RawTouchEvent | null = null;\n for (const ev of events) {\n if (prev && ev.t > prev.t) ops.push(`-i ${ev.t - prev.t}`);\n if (ev.type === 'down') ops.push(`-d ${ev.x} ${ev.y}`);\n else if (ev.type === 'up') ops.push(`-u ${ev.x} ${ev.y}`);\n else ops.push(`-m ${prev ? `${prev.x} ${prev.y} ` : ''}${ev.x} ${ev.y}`);\n prev = ev;\n }\n return `uinput -T ${ops.join(' ')}`;\n}\n\n/** Expand a waypoint path (+ optional holds) into raw down/move/up events for\n * the `uinput` escape hatch ({@link sendRawTouch} / {@link buildRawTouchCommand}). */\nexport function waypointsToRawEvents(waypoints: Waypoint[], holdStartMs = 0, holdEndMs = 0): RawTouchEvent[] {\n if (waypoints.length < 2) throw new OniroError('sendGesture requires at least two waypoints.');\n const first = waypoints[0]!;\n const events: RawTouchEvent[] = [{ type: 'down', x: first.x, y: first.y, t: 0 }];\n for (let i = 1; i < waypoints.length; i++) {\n const w = waypoints[i]!;\n events.push({ type: 'move', x: w.x, y: w.y, t: w.t + holdStartMs });\n }\n const last = waypoints[waypoints.length - 1]!;\n events.push({ type: 'up', x: last.x, y: last.y, t: last.t + holdStartMs + holdEndMs });\n return events;\n}\n\n// `uitest uiInput swipe/drag` accepts a velocity in [200, 40000] px/s.\nconst UITEST_VELOCITY_MIN = 200;\nconst UITEST_VELOCITY_MAX = 40000;\n\nexport interface GestureUitestOptions {\n /** A leading press-hold; when > 0 the stroke uses `drag` (press-and-hold,\n * then move) instead of `swipe`. uitest has no arbitrary hold duration. */\n holdStartMs?: number;\n}\n\n/**\n * Build a single continuous `uitest uiInput` stroke for a waypoint path. Pure.\n *\n * uitest has no polyline or stationary-hold primitive, so the path is collapsed\n * to first→last (gesture-nav strokes are straight lines) with the velocity\n * derived from the total elapsed time and clamped to uitest's range. A\n * requested `holdStartMs` maps to `drag` (which presses-and-holds before\n * moving — uitest's nearest equivalent to a leading hold); otherwise `swipe`.\n */\nexport function buildGestureUitestCommand(waypoints: Waypoint[], opts: GestureUitestOptions = {}): string {\n if (waypoints.length < 2) throw new OniroError('sendGesture requires at least two waypoints.');\n const a = waypoints[0]!;\n const b = waypoints[waypoints.length - 1]!;\n const dist = Math.hypot(b.x - a.x, b.y - a.y);\n const dtMs = b.t - a.t;\n const op = (opts.holdStartMs ?? 0) > 0 ? 'drag' : 'swipe';\n let cmd = `uitest uiInput ${op} ${a.x} ${a.y} ${b.x} ${b.y}`;\n if (dtMs > 0 && dist > 0) {\n const v = Math.round(dist / (dtMs / 1000));\n cmd += ` ${Math.max(UITEST_VELOCITY_MIN, Math.min(UITEST_VELOCITY_MAX, v))}`;\n }\n return cmd;\n}\n\n/**\n * Drive a swipe-style gesture via a single continuous `uitest uiInput` stroke —\n * the MMI-injection path that `inputMonitor`-based services (gesture-nav,\n * systemui overlays) actually observe. Preferred over raw `uinput`, whose\n * kernel virtual-device events do not reach `inputMonitor` on some native-boot\n * devices (and whose multi-op form some on-device `uinput` builds reject).\n *\n * uitest has no polyline or stationary-hold primitive: a multi-waypoint path is\n * collapsed to first→last, `holdStartMs` maps to `drag` (press-hold-then-move),\n * and `holdEndMs` has no equivalent (ignored). For true press-time control use\n * {@link sendRawTouch} (raw `uinput`) — accepting the device caveats above.\n */\nexport async function sendGesture(opts: SendGestureOptions): Promise<void> {\n if ((opts.holdEndMs ?? 0) > 0) {\n opts.logger?.warn(\n 'sendGesture: hold-end has no uitest equivalent and is ignored; use sendRawTouch for a trailing hold.',\n );\n }\n if (opts.waypoints.length > 2) {\n opts.logger?.debug(\n `sendGesture: ${opts.waypoints.length} waypoints collapsed to first→last (uitest has no polyline path).`,\n );\n }\n const cmd = buildGestureUitestCommand(opts.waypoints, { holdStartMs: opts.holdStartMs });\n const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 30_000, logger: opts.logger });\n ensureRemoteOk(res, `hdc shell ${cmd}`);\n}\n\n/**\n * Low-level touch injection via `uinput -T`. The escape hatch when press timing\n * matters (e.g. Quickstep motion-pause), which `uitest uiInput` can't express.\n *\n * WARNING: uinput's gesture form `uinput -T -g x1 y1 x2 y2 [press] [total]`\n * silently no-ops if `press < 500ms` or `total - press < 500ms` (\"press time is\n * out of range\" — it runs nothing). Keep press and post-press windows ≥ 500ms.\n *\n * DEVICE CAVEAT: on some native-boot devices these kernel-`uinput` events never\n * reach MMI `inputMonitor` services (gesture-nav, systemui), and some on-device\n * `uinput` builds reject the multi-op `-d/-m/-u` form with \"wrong number of\n * parameters\". Prefer {@link sendGesture} (uitest) for those; this path now\n * surfaces such failures instead of silently succeeding.\n */\nexport async function sendRawTouch(opts: SendRawTouchOptions): Promise<void> {\n const cmd = buildRawTouchCommand(opts.events);\n const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 30_000, logger: opts.logger });\n ensureRemoteOk(res, `hdc shell ${cmd}`);\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { randomBytes } from 'node:crypto';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { shell, ensureOk } from './exec.js';\nimport { recvFile } from './files.js';\nimport { getDisplaySize, type DisplaySize } from './display.js';\nimport { getImeBundles, findKeyboardWindow } from './ime.js';\n\n/** A raw `uitest dumpLayout` node (attributes are strings). */\nexport interface RawLayoutNode {\n attributes?: Record<string, string>;\n children?: RawLayoutNode[];\n}\n\n/** A pruned, 0–1-normalized layout node. */\nexport interface LayoutNode {\n /** bounds [x1,y1,x2,y2] normalized to 0–1 of the display. */\n b?: [number, number, number, number];\n /** center [x,y] normalized to 0–1. */\n c?: [number, number];\n type?: string;\n text?: string;\n desc?: string;\n /** Placeholder text, e.g. an empty TextInput's \"you@example.com\". */\n hint?: string;\n id?: string;\n key?: string;\n bundle?: string;\n click?: boolean;\n check?: boolean;\n checked?: boolean;\n sel?: boolean;\n focus?: boolean;\n scroll?: boolean;\n longClick?: boolean;\n /** The component is disabled (`enabled: false`). */\n disabled?: boolean;\n /** The node's center is painted over by a later filled node (an overlay, a\n * dialog scrim, the soft keyboard), so a tap there would land on that instead. */\n covered?: boolean;\n children?: LayoutNode[];\n}\n\n/** The soft keyboard, when an input-method window is on screen. */\nexport interface KeyboardState {\n shown: boolean;\n /** Bundle of the input-method window. */\n bundle?: string;\n /** Bounds [x1,y1,x2,y2] normalized to 0–1 of the display. */\n b?: [number, number, number, number];\n}\n\nexport interface DumpLayoutResult {\n display: DisplaySize | null;\n tree: LayoutNode;\n /** Present when the dump was asked to detect the soft keyboard. */\n keyboard?: KeyboardState;\n}\n\n/** Parse a uitest bounds string `\"[x1,y1][x2,y2]\"` into a tuple, or null. */\nexport function parseBounds(s: string | undefined): [number, number, number, number] | null {\n const m = /^\\[(-?\\d+),(-?\\d+)\\]\\[(-?\\d+),(-?\\d+)\\]$/.exec(s ?? '');\n if (!m) return null;\n return [Number(m[1]), Number(m[2]), Number(m[3]), Number(m[4])];\n}\n\n// Container types that almost never carry useful info on their own.\nconst STRUCTURAL_TYPES = new Set([\n 'Stack', 'Column', 'Row', 'Flex', '__Common__', 'Grid', 'GridItem',\n 'List', 'ListItem', 'Scroll', 'Swiper', 'SwiperContent', 'Navigator',\n 'Tabs', 'TabContent', 'RelativeContainer', 'WaterFlow', 'FlowItem',\n]);\n\nconst FLAG_MAP: ReadonlyArray<[string, keyof LayoutNode]> = [\n ['clickable', 'click'],\n ['checkable', 'check'],\n ['checked', 'checked'],\n ['selected', 'sel'],\n ['focused', 'focus'],\n ['scrollable', 'scroll'],\n ['longClickable', 'longClick'],\n];\n\n/** Alpha (0–255) of a uitest `#AARRGGBB` / `#RRGGBB` color; 0 when absent or malformed. */\nfunction colorAlpha(color: string | undefined): number {\n const m = /^#([0-9a-f]{2})?[0-9a-f]{6}$/i.exec(color ?? '');\n if (!m) return 0;\n return m[1] === undefined ? 255 : parseInt(m[1], 16);\n}\n\n/** Whether a node paints a visible fill over whatever was drawn before it. */\nfunction paintsFill(a: Record<string, string>): boolean {\n if (a.visible === 'false') return false;\n if (a.opacity !== undefined && a.opacity !== '' && !(Number(a.opacity) > 0)) return false;\n return colorAlpha(a.backgroundColor) > 0;\n}\n\n/**\n * Find nodes whose center is painted over by a later node with a visible\n * background fill — a full-screen overlay, a dialog scrim, a sticky bar, or the\n * soft-keyboard window. Paint order is depth-first, siblings ordered by\n * `zIndex`, windows in dump order; ancestors and descendants never cover a node.\n *\n * A heuristic: only background fills count (an Image or Text drawn on top does\n * not), which is what overlays in practice use.\n */\nexport function findCoveredNodes(root: RawLayoutNode): Set<RawLayoutNode> {\n interface Painted {\n node: RawLayoutNode;\n bounds: [number, number, number, number] | null;\n /** Index just past this node's last descendant in `order`. */\n end: number;\n }\n const order: Painted[] = [];\n const fills: number[] = [];\n const visit = (n: RawLayoutNode): void => {\n const a = n.attributes ?? {};\n const entry: Painted = { node: n, bounds: parseBounds(a.bounds), end: 0 };\n if (entry.bounds && paintsFill(a)) fills.push(order.length);\n order.push(entry);\n const kids = (n.children ?? [])\n .map((c, i) => ({ c, i, z: Number(c.attributes?.zIndex) || 0 }))\n .sort((p, q) => p.z - q.z || p.i - q.i);\n for (const k of kids) visit(k.c);\n entry.end = order.length;\n };\n visit(root);\n\n const covered = new Set<RawLayoutNode>();\n for (const p of order) {\n if (!p.bounds) continue;\n const cx = (p.bounds[0] + p.bounds[2]) / 2;\n const cy = (p.bounds[1] + p.bounds[3]) / 2;\n for (const j of fills) {\n if (j < p.end) continue;\n const q = order[j]!.bounds!;\n if (cx >= q[0] && cx < q[2] && cy >= q[1] && cy < q[3]) {\n covered.add(p.node);\n break;\n }\n }\n }\n return covered;\n}\n\n/**\n * Prune a raw `uitest dumpLayout` tree into a compact, signal-bearing tree with\n * bounds/center normalized to 0–1 of the display. Structural wrapper nodes with\n * no signal collapse into their children. Returns a node, a flat list of nodes\n * (collapsed wrapper with multiple children), or null (nothing useful). Ported\n * from the proven MCP `pruneNode`; `covered` (from {@link findCoveredNodes})\n * marks nodes hidden under an overlay.\n */\nexport function pruneLayout(\n node: RawLayoutNode,\n display: DisplaySize | null,\n covered?: ReadonlySet<RawLayoutNode>,\n): LayoutNode | LayoutNode[] | null {\n const a = node.attributes ?? {};\n const px = parseBounds(a.bounds);\n const out: LayoutNode = {};\n if (px && display) {\n const w = display.width || 1;\n const h = display.height || 1;\n out.b = [\n +(px[0] / w).toFixed(3),\n +(px[1] / h).toFixed(3),\n +(px[2] / w).toFixed(3),\n +(px[3] / h).toFixed(3),\n ];\n out.c = [+(((px[0] + px[2]) / 2) / w).toFixed(3), +(((px[1] + px[3]) / 2) / h).toFixed(3)];\n }\n if (a.type && !STRUCTURAL_TYPES.has(a.type)) out.type = a.type;\n if (a.text) out.text = a.text;\n if (a.description) out.desc = a.description;\n if (a.hint) out.hint = a.hint;\n if (a.id) out.id = a.id;\n if (a.key && a.key !== a.id) out.key = a.key;\n if (a.bundleName) out.bundle = a.bundleName;\n for (const [attr, short] of FLAG_MAP) {\n if (a[attr] === 'true') (out[short] as boolean) = true;\n }\n if (a.enabled === 'false') out.disabled = true;\n if (covered?.has(node)) out.covered = true;\n\n const children: LayoutNode[] = [];\n for (const c of node.children ?? []) {\n const pc = pruneLayout(c, display, covered);\n if (pc) {\n if (Array.isArray(pc)) children.push(...pc);\n else children.push(pc);\n }\n }\n\n const hasSignal = Boolean(\n out.text || out.desc || out.hint || out.id || out.key || out.click ||\n out.scroll || out.check || out.longClick || out.bundle ||\n (out.type && out.type !== 'root'),\n );\n\n if (!hasSignal && children.length === 0) return null;\n // Collapse structural wrappers: pass children up to the parent.\n if (!hasSignal) return children.length === 1 ? children[0]! : children;\n\n if (children.length) out.children = children;\n return out;\n}\n\n/** A pruned layout node without children, tagged with the window it belongs to. */\nexport interface FlatLayoutNode extends Omit<LayoutNode, 'children'> {\n /** Bundle of the enclosing window (the nearest node carrying `bundle`). */\n window?: string;\n}\n\n/** Flatten a pruned layout tree into a depth-first (paint-order) list. */\nexport function flattenLayout(tree: LayoutNode): FlatLayoutNode[] {\n const out: FlatLayoutNode[] = [];\n const visit = (n: LayoutNode, window: string | undefined): void => {\n const { children, ...rest } = n;\n const win = n.bundle ?? window;\n if (Object.keys(rest).length > 0) out.push({ ...rest, ...(win ? { window: win } : {}) });\n for (const c of children ?? []) visit(c, win);\n };\n visit(tree, undefined);\n return out;\n}\n\n/** Selects layout nodes by what an agent can read off the screen. */\nexport interface LayoutSelector {\n /** Matches `text`, `desc`, or `hint`: case-insensitive exact matches win; otherwise substring matches. */\n text?: string;\n /** Matches `id` or `key` exactly. */\n id?: string;\n /** Restricts to a component type (e.g. `Button`, `TextInput`); case-insensitive. */\n type?: string;\n}\n\n/** Throw unless `selector` constrains something: a non-blank text, an id, or a type. */\nexport function assertLayoutSelector(selector: LayoutSelector): void {\n if (selector.text === undefined && selector.id === undefined && selector.type === undefined) {\n throw new OniroError('A layout selector needs a text, id, or type.');\n }\n if (selector.text !== undefined && selector.text.trim() === '') {\n throw new OniroError('A layout selector text must not be blank.');\n }\n}\n\n/**\n * The tree without the windows owned by `bundle` — e.g. the soft keyboard, whose\n * keys (\"Done\", \"9\") would otherwise match element selectors. Pure.\n */\nexport function withoutWindow(tree: LayoutNode, bundle: string): LayoutNode {\n const children = (tree.children ?? []).filter((c) => c.bundle !== bundle).map((c) => withoutWindow(c, bundle));\n return tree.children ? { ...tree, children } : tree;\n}\n\n/**\n * Find the nodes matching `selector` in a pruned layout tree, in paint order.\n * For `text`, exact (case-insensitive, trimmed) matches are returned when any\n * exist; otherwise substring matches. Covered nodes are included — callers\n * decide what to do with them (see {@link pickTarget}).\n */\nexport function findLayoutNodes(tree: LayoutNode, selector: LayoutSelector): FlatLayoutNode[] {\n assertLayoutSelector(selector);\n const type = selector.type?.toLowerCase();\n const nodes = flattenLayout(tree).filter(\n (n) =>\n (type === undefined || n.type?.toLowerCase() === type) &&\n (selector.id === undefined || n.id === selector.id || n.key === selector.id),\n );\n if (selector.text === undefined) return nodes;\n\n const want = selector.text.trim().toLowerCase();\n const labels = (n: FlatLayoutNode): string[] =>\n [n.text, n.desc, n.hint].filter((s): s is string => !!s).map((s) => s.trim().toLowerCase());\n const exact = nodes.filter((n) => labels(n).some((l) => l === want));\n if (exact.length > 0) return exact;\n return nodes.filter((n) => labels(n).some((l) => l.includes(want)));\n}\n\nfunction describeSelector(s: LayoutSelector): string {\n const parts: string[] = [];\n if (s.text !== undefined) parts.push(`text \"${s.text}\"`);\n if (s.id !== undefined) parts.push(`id \"${s.id}\"`);\n if (s.type !== undefined) parts.push(`type ${s.type}`);\n return parts.join(', ');\n}\n\n/** One-line summary of a node, used in errors and logs. */\nexport function describeLayoutNode(n: FlatLayoutNode): string {\n const label = n.text ?? n.desc ?? (n.hint !== undefined ? `hint: ${n.hint}` : undefined);\n const at = n.c ? ` at ${n.c[0].toFixed(3)},${n.c[1].toFixed(3)}` : '';\n return `${n.type ?? 'node'}${label !== undefined ? ` \"${label}\"` : ''}${n.id ? ` #${n.id}` : ''}${at}`;\n}\n\nconst area = (b: [number, number, number, number] | undefined): number => (b ? (b[2] - b[0]) * (b[3] - b[1]) : 0);\n\n/** `outer` is larger than `inner` and contains its center. */\nfunction enclosesTarget(outer: FlatLayoutNode, inner: FlatLayoutNode): boolean {\n const b = outer.b;\n const c = inner.c;\n if (!b || !c) return false;\n return c[0] >= b[0] && c[0] <= b[2] && c[1] >= b[1] && c[1] <= b[3] && area(b) > area(inner.b);\n}\n\n/** Why {@link pickTarget} could not choose a node. */\nexport type PickTargetFailure = 'none' | 'covered' | 'ambiguous';\n\nexport class TargetNotFoundError extends OniroError {\n constructor(\n message: string,\n readonly reason: PickTargetFailure,\n ) {\n super(message);\n this.name = 'TargetNotFoundError';\n }\n}\n\n/**\n * Choose the single node to act on for `selector`. Covered nodes are skipped;\n * clickable matches are preferred over plain ones (a \"Sign in\" Button over the\n * \"Sign in\" title); a match nested inside another clickable match collapses\n * into it. `index` picks among what remains, in paint order. Throws\n * {@link TargetNotFoundError} when nothing (or more than one node) qualifies.\n */\nexport function pickTarget(tree: LayoutNode, selector: LayoutSelector, index?: number): FlatLayoutNode {\n const matches = findLayoutNodes(tree, selector).filter((n) => n.c !== undefined);\n const what = describeSelector(selector);\n if (matches.length === 0) {\n throw new TargetNotFoundError(`No on-screen element matches ${what}. Run \\`oniro-app dump layout --flat\\` to see what is there.`, 'none');\n }\n const visible = matches.filter((n) => !n.covered);\n if (visible.length === 0) {\n throw new TargetNotFoundError(\n `Found ${matches.length} element(s) matching ${what}, but each is covered by an overlay ` +\n `(dialog, keyboard, or another layer): ${matches.map(describeLayoutNode).join('; ')}.`,\n 'covered',\n );\n }\n const clickable = visible.filter((n) => n.click);\n const preferred = clickable.length > 0 ? clickable : visible;\n // A label nested inside a clickable match (a Button's own Text) is the same target.\n const candidates = preferred.filter((n) => !preferred.some((o) => o !== n && o.click && enclosesTarget(o, n)));\n if (index !== undefined) {\n const picked = candidates[index];\n if (!picked) {\n throw new TargetNotFoundError(`Index ${index} is out of range: ${candidates.length} element(s) match ${what}.`, 'ambiguous');\n }\n return picked;\n }\n if (candidates.length > 1) {\n throw new TargetNotFoundError(\n `${candidates.length} elements match ${what}; pass an index to choose: ` +\n candidates.map((n, i) => `[${i}] ${describeLayoutNode(n)}`).join('; '),\n 'ambiguous',\n );\n }\n return candidates[0]!;\n}\n\nexport interface DumpLayoutOptions {\n config: ConfigProvider;\n /** Filter to a single window/bundle (`uitest dumpLayout -b '<bundle>'`). */\n bundleName?: string;\n /** When false, return the parsed-but-unpruned tree. Default true. */\n prune?: boolean;\n /**\n * Also report whether the soft keyboard is on screen (one extra `hidumper` call).\n * Ignored with `bundleName`, which filters the keyboard window out of the dump.\n */\n detectKeyboard?: boolean;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * Dump the current on-screen layout via `uitest dumpLayout`, pull the JSON, and\n * return a pruned, 0–1-normalized tree (or the raw parsed tree when `prune:false`).\n */\nexport async function dumpLayout(opts: DumpLayoutOptions): Promise<DumpLayoutResult> {\n const timeoutMs = opts.timeoutMs ?? 30_000;\n const bundleArg = opts.bundleName ? ` -b '${opts.bundleName.replace(/'/g, `'\\\\''`)}'` : '';\n const dump = await shell({ config: opts.config, command: `uitest dumpLayout${bundleArg}`, deviceSerial: opts.deviceSerial, timeoutMs });\n ensureOk(dump, 'uitest dumpLayout');\n\n const m = dump.stdout.match(/saved to:\\s*(\\S+)/i);\n if (!m) throw new OniroError(`Could not parse dumpLayout output:\\n${dump.stdout}`);\n const remote = m[1]!;\n const local = path.join(os.tmpdir(), `oniro_layout_${randomBytes(6).toString('hex')}.json`);\n\n try {\n await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });\n const parsed = JSON.parse(await fs.promises.readFile(local, 'utf8')) as RawLayoutNode;\n const display = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial });\n\n if (opts.prune === false) {\n return { display, tree: parsed as unknown as LayoutNode };\n }\n const prunedRaw = pruneLayout(parsed, display, findCoveredNodes(parsed));\n const tree: LayoutNode = Array.isArray(prunedRaw) ? { children: prunedRaw } : prunedRaw ?? { children: [] };\n if (!opts.detectKeyboard || opts.bundleName) return { display, tree };\n\n const imeBundles = await getImeBundles(opts.config, { deviceSerial: opts.deviceSerial, logger: opts.logger });\n const kb = findKeyboardWindow(tree, imeBundles);\n const keyboard: KeyboardState = kb ? { shown: true, bundle: kb.bundle, ...(kb.b ? { b: kb.b } : {}) } : { shown: false };\n return { display, tree, keyboard };\n } finally {\n fs.promises.unlink(local).catch(() => {});\n void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {});\n }\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { shell } from './exec.js';\nimport type { LayoutNode } from './dump.js';\n\n/** System ability id of the input method service, for `hidumper -s`. */\nconst INPUT_METHOD_SA_ID = 3703;\n\n// Used when hidumper can't list the installed input methods.\nconst IME_BUNDLE_FALLBACK = /inputmethod|keyboard|(^|\\.)ime(\\.|$)/i;\n\n/**\n * Extract input-method bundle names from `hidumper -s 3703 -a -a` output, whose\n * `imeList` entries look like `\"ime\": \"com.example.kikakeyboard/ServiceExtAbility\"`.\n * The current IME comes first. Pure.\n */\nexport function parseImeBundles(output: string): string[] {\n const current: string[] = [];\n const others: string[] = [];\n const entry = /\\{[^{}]*\"ime\"\\s*:\\s*\"([^\"/]+)\\/[^\"]*\"[^{}]*\\}/g;\n for (const m of output.matchAll(entry)) {\n const bundle = m[1]!;\n const list = /\"isCurrentIme\"\\s*:\\s*\"true\"/.test(m[0]) ? current : others;\n if (!current.includes(bundle) && !others.includes(bundle)) list.push(bundle);\n }\n return [...current, ...others];\n}\n\n/**\n * List the installed input-method bundles (current first). Empty when hidumper\n * fails or times out, so keyboard detection never fails the caller.\n */\nexport async function getImeBundles(\n config: ConfigProvider,\n opts: { deviceSerial?: string; logger?: Logger } = {},\n): Promise<string[]> {\n try {\n const res = await shell({\n config,\n command: `hidumper -s ${INPUT_METHOD_SA_ID} -a '-a'`,\n deviceSerial: opts.deviceSerial,\n timeoutMs: 10_000,\n logger: opts.logger,\n });\n if (res.code === 0) return parseImeBundles(res.stdout);\n } catch (err) {\n opts.logger?.debug(`could not list input methods: ${err instanceof Error ? err.message : String(err)}`);\n }\n return [];\n}\n\n/**\n * Find the input-method window in a pruned layout tree. uitest lists the soft\n * keyboard as its own window (a node carrying the IME's `bundle`) only while it\n * is shown. With no known IME bundles, falls back to a name heuristic. Pure.\n */\nexport function findKeyboardWindow(tree: LayoutNode, imeBundles: readonly string[]): LayoutNode | null {\n const isIme = (bundle: string): boolean =>\n imeBundles.length > 0 ? imeBundles.includes(bundle) : IME_BUNDLE_FALLBACK.test(bundle);\n const stack: LayoutNode[] = [tree];\n while (stack.length > 0) {\n const n = stack.shift()!;\n if (n.bundle && isIme(n.bundle)) return n;\n stack.push(...(n.children ?? []));\n }\n return null;\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport {\n assertLayoutSelector,\n dumpLayout,\n findLayoutNodes,\n pickTarget,\n withoutWindow,\n TargetNotFoundError,\n type DumpLayoutResult,\n type FlatLayoutNode,\n type LayoutSelector,\n} from './dump.js';\nimport { getDisplaySize, type DisplaySize } from './display.js';\nimport { sendInput, type InputType } from './input.js';\nimport { waitForCondition } from './wait.js';\n\n/** `uitest uiInput` actions plus the composite ones built on top of them. */\nexport type UiInputType = InputType | 'clearText' | 'hideKeyboard';\n\n// Give a just-tapped field time to take focus (and the IME to attach) before typing.\nconst FOCUS_SETTLE_MS = 400;\n// Let the layout reflow after the soft keyboard closes.\nconst KEYBOARD_SETTLE_MS = 400;\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** The app's elements: the tree minus the soft-keyboard window, whose keys are not targets. */\nfunction targetTree(layout: DumpLayoutResult): DumpLayoutResult['tree'] {\n const kb = layout.keyboard;\n return kb?.shown && kb.bundle ? withoutWindow(layout.tree, kb.bundle) : layout.tree;\n}\n\n/** A 0–1 fraction of a display dimension as a pixel inside it (1.0 maps to the last pixel). */\nfunction fractionToPixel(f: number, size: number): number {\n return Math.min(size - 1, Math.round(f * size));\n}\n\ninterface DeviceOptions {\n config: ConfigProvider;\n deviceSerial?: string;\n logger?: Logger;\n}\n\nfunction pressBack(opts: DeviceOptions): Promise<void> {\n return sendInput({ config: opts.config, type: 'keyEvent', key: 'Back', deviceSerial: opts.deviceSerial, logger: opts.logger });\n}\n\n/**\n * Dismiss the soft keyboard with Back — only when it is actually on screen, since\n * Back without a keyboard navigates away. Returns whether a keyboard was dismissed.\n */\nexport async function hideKeyboard(opts: DeviceOptions): Promise<boolean> {\n const { keyboard } = await dumpLayout({ ...opts, detectKeyboard: true });\n if (!keyboard?.shown) return false;\n await pressBack(opts);\n await sleep(KEYBOARD_SETTLE_MS);\n return true;\n}\n\nexport interface LocateTargetOptions extends DeviceOptions {\n selector: LayoutSelector;\n /** Picks among several matching elements (see {@link pickTarget}). */\n index?: number;\n /**\n * When the soft keyboard is up and the target is missing, covered, or matches\n * only a non-clickable label (the button may be hidden below the keyboard),\n * dismiss the keyboard and look again. Default true.\n */\n hideKeyboard?: boolean;\n}\n\nexport interface LocatedTarget {\n node: FlatLayoutNode;\n /** Center of the element in device pixels. */\n x: number;\n y: number;\n display: DisplaySize;\n /** The soft keyboard was dismissed to reach the element. */\n keyboardHidden: boolean;\n}\n\n/**\n * Resolve a selector against the live layout to one element and its pixel\n * center. Keys on the soft keyboard are not candidates.\n */\nexport async function locateTarget(opts: LocateTargetOptions): Promise<LocatedTarget> {\n assertLayoutSelector(opts.selector);\n const dumpOpts = { config: opts.config, detectKeyboard: true, deviceSerial: opts.deviceSerial, logger: opts.logger };\n let layout = await dumpLayout(dumpOpts);\n // Without the display size no node has a position, and every match would look missing.\n if (!layout.display) throw new OniroError('Could not read the display size to locate the element.');\n let keyboardHidden = false;\n let node: FlatLayoutNode | undefined;\n let failure: unknown;\n try {\n node = pickTarget(targetTree(layout), opts.selector, opts.index);\n } catch (err) {\n if (!(err instanceof TargetNotFoundError) || err.reason === 'ambiguous') throw err;\n failure = err;\n }\n if ((!node || !node.click) && layout.keyboard?.shown && opts.hideKeyboard !== false) {\n opts.logger?.debug('target not reachable while the keyboard is up; dismissing it and looking again');\n await pressBack(opts);\n await sleep(KEYBOARD_SETTLE_MS);\n keyboardHidden = true;\n layout = await dumpLayout(dumpOpts);\n if (!layout.display) throw new OniroError('Could not read the display size to locate the element.');\n node = pickTarget(targetTree(layout), opts.selector, opts.index);\n }\n if (!node) throw failure;\n if (!node.c) throw new OniroError('The element has no on-screen position.');\n const x = fractionToPixel(node.c[0], layout.display.width);\n const y = fractionToPixel(node.c[1], layout.display.height);\n return { node, x, y, display: layout.display, keyboardHidden };\n}\n\nexport interface PerformInputOptions extends DeviceOptions {\n type: UiInputType;\n /** Start point in device pixels. */\n pxX?: number;\n pxY?: number;\n /** End point in device pixels (swipe/drag/fling). */\n pxX2?: number;\n pxY2?: number;\n /** Start point as 0–1 fractions of the display. */\n fx?: number;\n fy?: number;\n /** End point as 0–1 fractions of the display. */\n fx2?: number;\n fy2?: number;\n /** Start point: the center of the element matching this selector. */\n target?: LayoutSelector;\n /** Picks among several elements matching `target`. */\n targetIndex?: number;\n /** Velocity for swipe/drag/fling. */\n speed?: number;\n /** Key for keyEvent (see `resolveKeyEvent`). */\n key?: string | number;\n /** Text for inputText. */\n text?: string;\n /** inputText: clear the field before typing. */\n clear?: boolean;\n /** Dismiss the soft keyboard after the action, if it is up. */\n hideKeyboard?: boolean;\n}\n\nexport interface PerformInputResult {\n /** Resolved start point in device pixels, when the action has one. */\n x?: number;\n y?: number;\n /** The element `target` resolved to. */\n target?: FlatLayoutNode;\n /** The soft keyboard was dismissed (to reach the target, or because it was asked to). */\n keyboardHidden: boolean;\n}\n\nfunction fraction(value: number | undefined, name: string): number | undefined {\n if (value === undefined) return undefined;\n if (!(value >= 0 && value <= 1)) throw new OniroError(`${name} must be a fraction between 0 and 1; got ${value}.`);\n return value;\n}\n\nfunction pair<T>(a: T | undefined, b: T | undefined, names: string): [T, T] | undefined {\n if (a === undefined && b === undefined) return undefined;\n if (a === undefined || b === undefined) throw new OniroError(`Give both ${names}.`);\n return [a, b];\n}\n\n/**\n * Perform a UI input action. Beyond the raw `uitest uiInput` primitives, this\n * resolves the start point from an element selector (`target`), 0–1 display\n * fractions, or pixels; clears text fields (Ctrl+A, Delete); and dismisses the\n * soft keyboard only when it is up.\n */\nexport async function performInput(opts: PerformInputOptions): Promise<PerformInputResult> {\n const device: DeviceOptions = { config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger };\n const startFx = pair(fraction(opts.fx, '--fx'), fraction(opts.fy, '--fy'), '--fx and --fy');\n const startPx = pair(opts.pxX, opts.pxY, '--x and --y');\n const endFx = pair(fraction(opts.fx2, '--fx2'), fraction(opts.fy2, '--fy2'), '--fx2 and --fy2');\n const endPx = pair(opts.pxX2, opts.pxY2, '--x2 and --y2');\n if ([opts.target, startFx, startPx].filter((s) => s !== undefined).length > 1) {\n throw new OniroError('Give the start point one way: a target, fractions (--fx/--fy), or pixels (--x/--y).');\n }\n if (endFx && endPx) throw new OniroError('Give the end point one way: fractions (--fx2/--fy2) or pixels (--x2/--y2).');\n\n let display: DisplaySize | null | undefined;\n const toPx = async ([fx, fy]: [number, number]): Promise<[number, number]> => {\n display ??= await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial, logger: opts.logger });\n if (!display) throw new OniroError('Could not read the display size to convert fractions to pixels.');\n return [fractionToPixel(fx, display.width), fractionToPixel(fy, display.height)];\n };\n\n const result: PerformInputResult = { keyboardHidden: false };\n let start = startPx;\n if (opts.target) {\n const located = await locateTarget({ ...device, selector: opts.target, index: opts.targetIndex });\n display = located.display;\n start = [located.x, located.y];\n result.target = located.node;\n result.keyboardHidden = located.keyboardHidden;\n } else if (startFx) {\n start = await toPx(startFx);\n }\n const end = endFx ? await toPx(endFx) : endPx;\n if (start) [result.x, result.y] = start;\n\n const tapToFocus = async (): Promise<void> => {\n if (!start) return;\n await sendInput({ ...device, type: 'click', pxX: start[0], pxY: start[1] });\n await sleep(FOCUS_SETTLE_MS);\n };\n const clearFocused = async (): Promise<void> => {\n await sendInput({ ...device, type: 'keyEvent', key: 'Ctrl+A' });\n await sendInput({ ...device, type: 'keyEvent', key: 'Delete' });\n };\n\n switch (opts.type) {\n case 'hideKeyboard':\n result.keyboardHidden = (await hideKeyboard(device)) || result.keyboardHidden;\n return result;\n case 'clearText':\n await tapToFocus();\n await clearFocused();\n break;\n case 'inputText':\n if (opts.clear) {\n await tapToFocus();\n await clearFocused();\n await sendInput({ ...device, type: 'inputText', text: opts.text });\n } else {\n await sendInput({ ...device, type: 'inputText', pxX: start?.[0], pxY: start?.[1], text: opts.text });\n }\n break;\n default:\n await sendInput({\n ...device,\n type: opts.type,\n pxX: start?.[0],\n pxY: start?.[1],\n pxX2: end?.[0],\n pxY2: end?.[1],\n speed: opts.speed,\n key: opts.key,\n text: opts.text,\n });\n }\n\n if (opts.hideKeyboard) result.keyboardHidden = (await hideKeyboard(device)) || result.keyboardHidden;\n return result;\n}\n\nexport interface WaitForTargetOptions extends DeviceOptions {\n selector: LayoutSelector;\n /** Wait until no uncovered element matches, instead of until one does. */\n gone?: boolean;\n timeoutMs: number;\n /** Poll interval. Default 500 (each poll is a full layout dump). */\n pollMs?: number;\n abortSignal?: AbortSignal;\n}\n\n/**\n * Poll the layout until an uncovered element matches `selector` (resolving with\n * it), or with `gone`, until none does (resolving null). Keys on the soft\n * keyboard are ignored. Throws on timeout.\n */\nexport async function waitForTarget(opts: WaitForTargetOptions): Promise<FlatLayoutNode | null> {\n const { selector } = opts;\n assertLayoutSelector(selector);\n let found = null as FlatLayoutNode | null;\n await waitForCondition({\n probe: async () => {\n const layout = await dumpLayout({\n config: opts.config,\n detectKeyboard: true,\n deviceSerial: opts.deviceSerial,\n logger: opts.logger,\n });\n found = findLayoutNodes(targetTree(layout), selector).find((n) => !n.covered) ?? null;\n return opts.gone ? found === null : found !== null;\n },\n timeoutMs: opts.timeoutMs,\n pollMs: opts.pollMs ?? 500,\n abortSignal: opts.abortSignal,\n logger: opts.logger,\n timeoutMessage: opts.gone\n ? `An element matching the selector was still on screen after ${opts.timeoutMs}ms.`\n : `No element matching the selector appeared within ${opts.timeoutMs}ms.`,\n });\n return opts.gone ? null : found;\n}\n","import * as fs from 'node:fs';\nimport type { ChildProcess, ChildProcessWithoutNullStreams } from 'node:child_process';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { CancelledError, OniroError } from '../ports/errors.js';\nimport { getHdcPath } from '../sdk/paths.js';\nimport { killProcessTree, spawnCompat } from './spawnCompat.js';\nimport { ensureOk, hdcTargetArgs, shell } from './exec.js';\nimport { findRunningProcess } from './app.js';\n\nexport type HilogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'FATAL';\n\n/** A parsed line of `hdc shell hilog` output. */\nexport interface HilogEntry {\n /** \"MM-DD HH:MM:SS.mmm\". The device timestamp; no year. */\n time: string;\n pid: string;\n tid: string;\n /** Short level letter as printed by hilog: D, I, W, E (F is rare). */\n level: 'D' | 'I' | 'W' | 'E' | 'F';\n tag: string;\n message: string;\n}\n\nexport interface SetHilogLevelOptions {\n config: ConfigProvider;\n level: HilogLevel;\n deviceSerial?: string;\n logger?: Logger;\n}\n\n/**\n * Set the hilog buffer level on the connected device. Resolves when the\n * underlying `hdc shell hilog -b <LEVEL>` exits successfully; rejects with\n * the stderr text if the command fails.\n */\nexport function setHilogLevel(opts: SetHilogLevelOptions): Promise<void> {\n const logger = opts.logger ?? noopLogger;\n const hdc = getHdcPath(opts.config);\n return new Promise((resolve, reject) => {\n // `hdc` may be a batch wrapper on Windows (an `hdcPath` override pointing at\n // a proxy/tunnel script), which a bare spawn cannot execute — spawnCompat\n // routes those through cmd.exe. It can also throw synchronously, so the\n // failure is funnelled into the same rejection as the 'error' event below.\n let child: ChildProcess;\n try {\n child = spawnCompat(hdc, [...hdcTargetArgs(opts.deviceSerial), 'shell', 'hilog', '-b', opts.level]);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`[hilog] failed to spawn hdc: ${msg}`);\n reject(err instanceof Error ? err : new Error(msg));\n return;\n }\n let stderr = '';\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n child.once('error', (err) => {\n logger.error(`[hilog] failed to spawn hdc: ${err.message}`);\n reject(err);\n });\n child.once('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n const msg = stderr.trim() || `hdc shell hilog -b ${opts.level} exited with code ${code}`;\n logger.error(`[hilog] ${msg}`);\n reject(new Error(msg));\n }\n });\n });\n}\n\nexport interface StreamHilogOptions {\n config: ConfigProvider;\n /** Restrict the stream to a single process id (passed as `-P <pid>`). */\n processId?: string;\n /** Filter by hilog domain, e.g. '0xD003900' (passed as `-D <domain>`). */\n domain?: string | number;\n /** Address a specific device (`-t <serial>`); defaults to `ONIRO_DEVICE_SERIAL`. */\n deviceSerial?: string;\n}\n\n/**\n * Spawn `hdc [-t serial] shell hilog [-P <pid>] [-D <domain>]` and return the\n * child process. The caller owns the stdout/stderr streams (typically wired\n * through `parseHilogLine`) and is responsible for killing the process when\n * streaming should stop.\n */\nexport function streamHilog(opts: StreamHilogOptions): ChildProcessWithoutNullStreams {\n const hdc = getHdcPath(opts.config);\n const args: string[] = [...hdcTargetArgs(opts.deviceSerial)];\n args.push('shell', 'hilog');\n if (opts.processId && opts.processId.trim() !== '') {\n args.push('-P', opts.processId.trim());\n }\n if (opts.domain !== undefined && `${opts.domain}` !== '') {\n args.push('-D', `${opts.domain}`);\n }\n // Keeps the published non-null-stdio signature rather than pushing `?.` onto\n // every consumer. Sound because no stdio option is passed: both spawnCompat\n // branches inherit spawn's default `stdio: 'pipe'`, so the streams exist.\n return spawnCompat(hdc, args) as ChildProcessWithoutNullStreams;\n}\n\n// `\\S+` is greedy on the tag so values like `C01406/OHOS::RS` aren't split at\n// the first internal colon — the regex backtracks to the last `:` followed by\n// whitespace, which is the actual tag/message separator hilog emits.\nconst HILOG_LINE_RE = /^(\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3})\\s+(\\d+)\\s+(\\d+)\\s+([DIWEF])\\s+(\\S+):\\s+(.*)$/;\n\n/**\n * Parse a single line of `hdc shell hilog` output into structured fields.\n * Returns null when the line doesn't match the expected hilog format (e.g.\n * banners, blank lines, or partial chunks).\n */\nexport function parseHilogLine(line: string): HilogEntry | null {\n const match = HILOG_LINE_RE.exec(line);\n if (!match) return null;\n return {\n time: match[1]!,\n pid: match[2]!,\n tid: match[3]!,\n level: match[4]! as HilogEntry['level'],\n tag: match[5]!.trim(),\n message: match[6]!,\n };\n}\n\n/** The searchable text a pattern is tested against: `\"<tag>: <message>\"`. */\nfunction entryText(e: HilogEntry): string {\n return `${e.tag}: ${e.message}`;\n}\n\n/** Collapse consecutive duplicate entries (same level/tag/message), ignoring time/pid. */\nexport function dedupEntries(entries: HilogEntry[]): HilogEntry[] {\n const out: HilogEntry[] = [];\n let lastKey = '';\n for (const e of entries) {\n const key = `${e.level}|${e.tag}|${e.message}`;\n if (key === lastKey) continue;\n out.push(e);\n lastKey = key;\n }\n return out;\n}\n\n/** Resolve a bundle name to its pid for `-P` filtering, or undefined if not running. */\nasync function resolveProcessId(\n config: ConfigProvider,\n bundle: string | undefined,\n deviceSerial?: string,\n): Promise<string | undefined> {\n if (!bundle) return undefined;\n const proc = await findRunningProcess({ config, bundle, deviceSerial });\n return proc?.pid;\n}\n\nexport interface WaitForLogOptions {\n config: ConfigProvider;\n /** Tested against `\"<tag>: <message>\"` of each parsed line. */\n pattern: RegExp;\n timeoutMs: number;\n /** Restrict to a bundle's pid (resolved via pidof; re-resolved on each reconnect). */\n bundle?: string;\n domain?: string | number;\n deviceSerial?: string;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/**\n * Resolve with the first hilog entry whose `\"<tag>: <message>\"` matches `pattern`.\n * The underlying stream is auto-respawned if it dies before the deadline, so the\n * wait survives a reboot mid-observation. Rejects on timeout (OniroError) or\n * abort (CancelledError).\n */\nexport function waitForLog(opts: WaitForLogOptions): Promise<HilogEntry> {\n return new Promise<HilogEntry>((resolve, reject) => {\n const deadline = Date.now() + opts.timeoutMs;\n let settled = false;\n let child: ChildProcessWithoutNullStreams | null = null;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let buf = '';\n\n const cleanup = (): void => {\n clearTimeout(timer);\n if (reconnectTimer) clearTimeout(reconnectTimer);\n opts.abortSignal?.removeEventListener('abort', onAbort);\n if (child) {\n // A batch wrapper's own death would leave the hdc process it launched\n // streaming; tear down the whole tree.\n killProcessTree(child);\n child = null;\n }\n };\n const finish = (entry: HilogEntry): void => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(entry);\n };\n const fail = (err: Error): void => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(err);\n };\n const failWith = (err: unknown): void => fail(err instanceof Error ? err : new Error(String(err)));\n const onAbort = (): void => fail(new CancelledError('waitForLog cancelled.'));\n const timer = setTimeout(\n () => fail(new OniroError(`No log line matched ${String(opts.pattern)} within ${opts.timeoutMs}ms.`)),\n opts.timeoutMs,\n );\n opts.abortSignal?.addEventListener('abort', onAbort, { once: true });\n\n const spawnStream = async (): Promise<void> => {\n if (settled) return;\n const processId = await resolveProcessId(opts.config, opts.bundle, opts.deviceSerial);\n if (settled) return;\n const stream = streamHilog({ config: opts.config, processId, domain: opts.domain, deviceSerial: opts.deviceSerial });\n child = stream;\n stream.stdout.on('data', (d: Buffer) => {\n buf += d.toString();\n const lines = buf.split(/\\r?\\n/);\n buf = lines.pop() ?? '';\n for (const line of lines) {\n const entry = parseHilogLine(line);\n if (entry && opts.pattern.test(entryText(entry))) {\n finish(entry);\n return;\n }\n }\n });\n const onEnd = (): void => {\n if (settled || child !== stream) return;\n child = null;\n if (Date.now() < deadline) {\n // Auto-reconnect (survives a reboot) until the deadline.\n reconnectTimer = setTimeout(() => void spawnStream().catch(failWith), 1_000);\n }\n };\n stream.once('close', onEnd);\n stream.once('error', onEnd);\n };\n\n // spawnStream can reject (device lookup, or a synchronous spawn failure);\n // surface it as this promise's rejection instead of an unhandled one.\n void spawnStream().catch(failWith);\n });\n}\n\nexport interface WatchLogOptions {\n config: ConfigProvider;\n pattern: RegExp;\n /** How long to collect matching entries. */\n durationMs: number;\n bundle?: string;\n domain?: string | number;\n deviceSerial?: string;\n /** Collapse consecutive duplicate lines. Default true. */\n dedup?: boolean;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/** Collect all hilog entries matching `pattern` for `durationMs`. Deduped by default. */\nexport function watchLog(opts: WatchLogOptions): Promise<HilogEntry[]> {\n return new Promise<HilogEntry[]>((resolve, reject) => {\n const matches: HilogEntry[] = [];\n let settled = false;\n let child: ChildProcessWithoutNullStreams | null = null;\n let buf = '';\n\n const cleanup = (): void => {\n clearTimeout(timer);\n opts.abortSignal?.removeEventListener('abort', onAbort);\n if (child) {\n // A batch wrapper's own death would leave the hdc process it launched\n // streaming; tear down the whole tree.\n killProcessTree(child);\n child = null;\n }\n };\n const done = (): void => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(opts.dedup === false ? matches : dedupEntries(matches));\n };\n const onAbort = (): void => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(new CancelledError('watchLog cancelled.'));\n };\n const timer = setTimeout(done, opts.durationMs);\n opts.abortSignal?.addEventListener('abort', onAbort, { once: true });\n\n void (async () => {\n const processId = await resolveProcessId(opts.config, opts.bundle, opts.deviceSerial);\n if (settled) return;\n const stream = streamHilog({ config: opts.config, processId, domain: opts.domain, deviceSerial: opts.deviceSerial });\n child = stream;\n stream.stdout.on('data', (d: Buffer) => {\n buf += d.toString();\n const lines = buf.split(/\\r?\\n/);\n buf = lines.pop() ?? '';\n for (const line of lines) {\n const entry = parseHilogLine(line);\n if (entry && opts.pattern.test(entryText(entry))) matches.push(entry);\n }\n });\n // A device lookup or synchronous spawn failure used to surface as an\n // unhandled rejection while watchLog quietly resolved empty at the deadline.\n })().catch((err: unknown) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(err instanceof Error ? err : new Error(String(err)));\n });\n });\n}\n\nexport interface CaptureLogOptions {\n config: ConfigProvider;\n /** File the hilog lines are appended to. */\n file: string;\n /** Stop after this long. Default: run until `abortSignal` fires. */\n durationMs?: number;\n /** Keep only the lines this matches. Default: every line. */\n pattern?: RegExp;\n /** Clear the device's log buffer first (`hilog -r`), so the file covers only this session. */\n clear?: boolean;\n domain?: string | number;\n deviceSerial?: string;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\nexport interface CaptureLogResult {\n file: string;\n /** Lines written to `file`. */\n lines: number;\n /** How many times the stream dropped and was respawned. */\n reconnects: number;\n}\n\n/**\n * Stream hilog into `file` until `durationMs` passes or `abortSignal` fires. The\n * device's log buffer is small (256 KB per type by default) and chatty components\n * such as ArkWeb wrap it within seconds, so a dump taken at the end of a session\n * loses its start; a capture running throughout does not. Each chunk is written\n * synchronously, so killing the process keeps what was captured. The stream is\n * respawned when it drops (a reboot, a lost connection). Resolves at the deadline\n * or on abort.\n */\nexport async function captureLog(opts: CaptureLogOptions): Promise<CaptureLogResult> {\n const logger = opts.logger ?? noopLogger;\n if (opts.clear) {\n const res = await shell({ config: opts.config, command: 'hilog -r', deviceSerial: opts.deviceSerial, timeoutMs: 10_000, logger });\n ensureOk(res, 'hdc shell hilog -r');\n }\n const fd = fs.openSync(opts.file, 'a');\n let lines = 0;\n let reconnects = 0;\n\n try {\n await new Promise<void>((resolve, reject) => {\n const deadline = opts.durationMs !== undefined ? Date.now() + opts.durationMs : Infinity;\n let settled = false;\n let child: ChildProcessWithoutNullStreams | null = null;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let buf = '';\n // Cleared once the capture ends: the killed stream can still emit a chunk,\n // which must not reach the file descriptor closed below.\n let open = true;\n\n const write = (line: string): void => {\n if (!open || (opts.pattern && !opts.pattern.test(line))) return;\n fs.writeSync(fd, `${line}\\n`);\n lines++;\n };\n const cleanup = (): void => {\n if (timer) clearTimeout(timer);\n if (reconnectTimer) clearTimeout(reconnectTimer);\n opts.abortSignal?.removeEventListener('abort', finish);\n if (buf.trim()) write(buf.trimEnd());\n buf = '';\n open = false;\n if (child) {\n child.stdout.removeAllListeners('data');\n killProcessTree(child);\n child = null;\n }\n };\n function finish(): void {\n if (settled) return;\n settled = true;\n cleanup();\n resolve();\n }\n const fail = (err: unknown): void => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(err instanceof Error ? err : new Error(String(err)));\n };\n const timer = opts.durationMs !== undefined ? setTimeout(finish, opts.durationMs) : undefined;\n if (opts.abortSignal?.aborted) {\n finish();\n return;\n }\n opts.abortSignal?.addEventListener('abort', finish, { once: true });\n\n const spawnStream = (): void => {\n if (settled) return;\n const stream = streamHilog({ config: opts.config, domain: opts.domain, deviceSerial: opts.deviceSerial });\n child = stream;\n stream.stdout.on('data', (d: Buffer) => {\n buf += d.toString();\n const parts = buf.split(/\\r?\\n/);\n buf = parts.pop() ?? '';\n for (const line of parts) write(line);\n });\n const onEnd = (): void => {\n if (settled || child !== stream) return;\n child = null;\n if (Date.now() >= deadline) return;\n reconnects++;\n logger.warn(`[hilog] stream ended; reconnecting (${reconnects}).`);\n reconnectTimer = setTimeout(() => {\n try {\n spawnStream();\n } catch (err) {\n fail(err);\n }\n }, 2_000);\n };\n stream.once('close', onEnd);\n stream.once('error', onEnd);\n };\n spawnStream();\n });\n } finally {\n fs.closeSync(fd);\n }\n return { file: opts.file, lines, reconnects };\n}\n\nexport interface DumpLogOptions {\n config: ConfigProvider;\n /** Cap the result to the last N lines (device-side `tail -n`). */\n lines?: number;\n /** Restrict to a bundle's running pid (no output if it isn't running). */\n bundle?: string;\n /** Extended-regex string applied device-side via `grep -E`. */\n grep?: string;\n domain?: string | number;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/**\n * One-shot `hilog -x` dump, optionally filtered by domain, bundle pid, and a\n * grep regex, capped to the last `lines`. Mirrors the proven MCP get_logs\n * pipeline. Returns parsed entries.\n */\nexport async function dumpLog(opts: DumpLogOptions): Promise<HilogEntry[]> {\n let pipe = 'hilog -x';\n if (opts.domain !== undefined && `${opts.domain}` !== '') pipe += ` -D ${opts.domain}`;\n if (opts.bundle) {\n const proc = await findRunningProcess({ config: opts.config, bundle: opts.bundle, deviceSerial: opts.deviceSerial });\n if (!proc) return [];\n pipe += ` | grep -E '\\\\b${proc.pid}\\\\b'`;\n }\n if (opts.grep) {\n const safeGrep = opts.grep.replace(/'/g, `'\\\\''`);\n pipe += ` | grep -E '${safeGrep}'`;\n }\n if (opts.lines && opts.lines > 0) pipe += ` | tail -n ${Math.floor(opts.lines)}`;\n\n const res = await shell({\n config: opts.config,\n command: pipe,\n deviceSerial: opts.deviceSerial,\n timeoutMs: opts.timeoutMs ?? 30_000,\n logger: opts.logger,\n });\n return res.stdout\n .split(/\\r?\\n/)\n .map((line) => parseHilogLine(line))\n .filter((e): e is HilogEntry => e !== null);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ChildProcess } from 'node:child_process';\nimport { killProcessTree, spawnCompat } from '../hdc/spawnCompat.js';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { CancelledError, CmdToolsNotInstalledError, OniroError } from '../ports/errors.js';\nimport { getHvigorwPath, getOhosBaseSdkHome, getCmdToolsPath, toLongPath } from '../sdk/paths.js';\nimport { detectRuntimeOs } from '../harmonyos/target.js';\nimport { findHarmonyOsTool, requireHarmonyOsSdk } from '../harmonyos/sdk.js';\n\nexport interface RunHvigorwOptions {\n config: ConfigProvider;\n projectDir: string;\n /** Forwarded as `-p product=<product>`. Default `default`. */\n product?: string;\n /** Forwarded as `-p module=<module>` when set. */\n module?: string;\n /** Forwarded as `-p buildMode=<mode>` when set. */\n buildMode?: string;\n /** hvigor task to run. Default `assembleHap`. */\n task?: string;\n /** Extra raw args appended after the standard ones. */\n extraArgs?: readonly string[];\n /**\n * Build modules in parallel. Default `true`. Pass `false` to add `--no-parallel`\n * for projects that require serial builds.\n */\n parallel?: boolean;\n /** Abort the build; rejects with CancelledError and kills the hvigorw process. */\n abortSignal?: AbortSignal;\n logger?: Logger;\n /**\n * Optional callback for each stdout/stderr chunk, lets callers stream output\n * to a terminal or webview without buffering. Lines also flow through `logger`.\n */\n onOutput?: (chunk: string, stream: 'stdout' | 'stderr') => void;\n}\n\nexport interface RunHvigorwResult {\n exitCode: number;\n}\n\n/**\n * Build the hvigorw argv. Pure (no I/O) so it is unit-testable. `--no-parallel`\n * is added ONLY when `parallel === false` — builds are parallel by default.\n */\nexport function buildHvigorwArgs(opts: {\n task?: string;\n product?: string;\n module?: string;\n buildMode?: string;\n parallel?: boolean;\n extraArgs?: readonly string[];\n}): string[] {\n const args: string[] = [opts.task ?? 'assembleHap', '--mode', 'module'];\n args.push('-p', `product=${opts.product ?? 'default'}`);\n if (opts.module) args.push('-p', `module=${opts.module}`);\n if (opts.buildMode) args.push('-p', `buildMode=${opts.buildMode}`);\n args.push('--stacktrace', '--no-daemon');\n if (opts.parallel === false) args.push('--no-parallel');\n if (opts.extraArgs?.length) args.push(...opts.extraArgs);\n return args;\n}\n\n/**\n * Run the project's `hvigorw` wrapper. Replaces the extension's vscode-tasks indirection\n * and the bash CLI's chained `clean` + `assembleHap` calls with a single direct spawn.\n */\nexport function runHvigorw(opts: RunHvigorwOptions): Promise<RunHvigorwResult> {\n const { config } = opts;\n // hvigor resolves each module's `srcPath` against the project dir it is given\n // and fails on a Windows 8.3 short path, so hand it the long form.\n const projectDir = toLongPath(opts.projectDir);\n const logger = opts.logger ?? noopLogger;\n\n if (!fs.existsSync(path.join(projectDir, 'build-profile.json5'))) {\n throw new OniroError(`Not an OpenHarmony project: ${projectDir} (build-profile.json5 not found).`);\n }\n\n let hvigorw: string;\n let sdkEnv: NodeJS.ProcessEnv;\n if (detectRuntimeOs(projectDir, opts.product) === 'HarmonyOS') {\n // Nothing comes from the OpenHarmony command-line tools: the SDK is passed as\n // DEVECO_SDK_HOME, and hvigorw is the project's own or the HarmonyOS install's.\n const sdk = requireHarmonyOsSdk({ config, logger });\n sdkEnv = { DEVECO_SDK_HOME: sdk.sdkPath };\n const resolved = getHvigorwPath(config, projectDir);\n hvigorw = resolved.startsWith(projectDir) ? resolved : (findHarmonyOsTool(sdk, 'hvigorw') ?? resolved);\n logger.info(`[build] Building for HarmonyOS against the SDK at ${sdk.sdkPath}.`);\n } else {\n if (!fs.existsSync(getCmdToolsPath(config))) {\n throw new CmdToolsNotInstalledError(getCmdToolsPath(config));\n }\n sdkEnv = { OHOS_BASE_SDK_HOME: getOhosBaseSdkHome(config) };\n hvigorw = getHvigorwPath(config, projectDir);\n }\n\n if (!fs.existsSync(hvigorw)) {\n throw new OniroError(`hvigorw wrapper not found at ${hvigorw}.`);\n }\n const args = buildHvigorwArgs(opts);\n\n // Ensure hvigorw is executable on POSIX (project-local copies often aren't after a fresh clone).\n if (process.platform !== 'win32') {\n try { fs.chmodSync(hvigorw, 0o755); } catch { /* best effort */ }\n }\n\n const env: NodeJS.ProcessEnv = { ...process.env, ...sdkEnv };\n\n return new Promise((resolve, reject) => {\n if (opts.abortSignal?.aborted) {\n reject(new CancelledError('hvigorw build cancelled.'));\n return;\n }\n logger.info(`[build] ${hvigorw} ${args.join(' ')}`);\n // On Windows hvigorw is a .bat wrapper, which spawnCompat routes through\n // cmd.exe — a direct spawn there throws `EINVAL` on Node 20.12.2+.\n let child: ChildProcess;\n try {\n child = spawnCompat(hvigorw, args, { cwd: projectDir, env });\n } catch (err) {\n // spawn() can fail synchronously; report it like the 'error' event below\n // instead of letting a bare OS error escape to the CLI.\n reject(new OniroError(`Failed to start hvigorw: ${err instanceof Error ? err.message : String(err)}`, err));\n return;\n }\n let settled = false;\n const cleanup = (): void => opts.abortSignal?.removeEventListener('abort', onAbort);\n const onAbort = (): void => {\n if (settled) return;\n settled = true;\n cleanup();\n killProcessTree(child);\n reject(new CancelledError('hvigorw build cancelled.'));\n };\n opts.abortSignal?.addEventListener('abort', onAbort, { once: true });\n child.stdout?.on('data', (chunk: Buffer) => {\n const text = chunk.toString();\n opts.onOutput?.(text, 'stdout');\n logger.info(text.trimEnd());\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n const text = chunk.toString();\n opts.onOutput?.(text, 'stderr');\n logger.warn(text.trimEnd());\n });\n child.on('error', (err) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(new OniroError(`Failed to start hvigorw: ${err.message}`, err));\n });\n child.on('close', (code) => {\n if (settled) return;\n settled = true;\n cleanup();\n const exitCode = code ?? 1;\n if (exitCode === 0) resolve({ exitCode });\n else reject(new OniroError(`hvigorw exited with code ${exitCode}`));\n });\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport JSON5 from 'json5';\n\n/**\n * Which runtime a project targets. OpenHarmony projects build against the public\n * OpenHarmony SDK; HarmonyOS projects build against Huawei's HarmonyOS SDK and\n * need an AGC-issued certificate to sign (see `harmonyos/signing`).\n */\nexport type RuntimeOs = 'OpenHarmony' | 'HarmonyOS';\n\n/**\n * Detect the runtime a project targets from `build-profile.json5`.\n *\n * HarmonyOS only when the product declares `runtimeOS: \"HarmonyOS\"`, which DevEco\n * Studio writes for every HarmonyOS project. Anything else — no such field, or a\n * missing or unreadable profile — is OpenHarmony, so existing projects behave\n * exactly as they did before HarmonyOS support. Reads the named product, else the\n * first one.\n */\nexport function detectRuntimeOs(projectDir: string, productName?: string): RuntimeOs {\n let products: Array<{ name?: unknown; runtimeOS?: unknown }> = [];\n try {\n const parsed = JSON5.parse(fs.readFileSync(path.join(projectDir, 'build-profile.json5'), 'utf-8')) as {\n app?: { products?: unknown };\n };\n if (Array.isArray(parsed.app?.products)) products = parsed.app.products;\n } catch {\n return 'OpenHarmony';\n }\n const product = products.find((p) => p.name === productName) ?? products[0];\n return product?.runtimeOS === 'HarmonyOS' ? 'HarmonyOS' : 'OpenHarmony';\n}\n\n/**\n * HarmonyOS SDK releases, mapping API level to the release version DevEco writes\n * into `compileSdkVersion`, for when the installed SDK does not name the requested\n * level itself. Only releases read from a real `sdk/default/sdk-pkg.json` are listed.\n */\nexport const HARMONYOS_SDK_VERSIONS: ReadonlyMap<number, string> = new Map([\n [12, '5.0.0'],\n [13, '5.0.1'],\n [14, '5.0.2'],\n [15, '5.0.3'],\n [16, '5.0.4'],\n [17, '5.0.5'],\n [18, '5.1.0'],\n [19, '5.1.1'],\n [20, '6.0.0'],\n [21, '6.0.1'],\n [24, '6.1.1'],\n]);\n\n/**\n * The `\"<version>(<api>)\"` label a HarmonyOS product declares for an API level, or\n * undefined when no HarmonyOS release is known for it.\n */\nexport function harmonyOsSdkLabelForApi(api: number): string | undefined {\n const version = HARMONYOS_SDK_VERSIONS.get(api);\n return version ? `${version}(${api})` : undefined;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { runProcess, ensureOk, type HdcExecResult, type OutputSink } from '../hdc/exec.js';\nimport { getOhpmPath } from '../sdk/paths.js';\n\nexport interface RunOhpmOptions {\n config: ConfigProvider;\n projectDir: string;\n args: readonly string[];\n /**\n * Explicit ohpm binary. HarmonyOS projects pass the one from their own install;\n * when omitted the OpenHarmony command-line tools' ohpm is used.\n */\n ohpmPath?: string;\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n onOutput?: OutputSink;\n logger?: Logger;\n}\n\n/** Run `ohpm <args>` in the project directory. Resolves with the raw result (any exit code). */\nexport function runOhpm(opts: RunOhpmOptions): Promise<HdcExecResult> {\n return runProcess({\n command: opts.ohpmPath ?? getOhpmPath(opts.config),\n args: [...opts.args],\n cwd: opts.projectDir,\n timeoutMs: opts.timeoutMs ?? 600_000,\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n logger: opts.logger,\n });\n}\n\n/**\n * Install dependencies (`ohpm install --all`) only when `oh_modules/` is missing.\n * Returns `{ installed: true }` when it ran. Throws CommandFailedError if the\n * install ran and failed.\n */\nexport async function ensureOhModules(opts: {\n config: ConfigProvider;\n projectDir: string;\n /** See {@link RunOhpmOptions.ohpmPath}. */\n ohpmPath?: string;\n abortSignal?: AbortSignal;\n onOutput?: OutputSink;\n logger?: Logger;\n}): Promise<{ installed: boolean }> {\n if (fs.existsSync(path.join(opts.projectDir, 'oh_modules'))) {\n return { installed: false };\n }\n const res = await runOhpm({\n config: opts.config,\n projectDir: opts.projectDir,\n ohpmPath: opts.ohpmPath,\n args: ['install', '--all'],\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n logger: opts.logger,\n });\n ensureOk(res, 'ohpm install --all');\n return { installed: true };\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { runProcess } from '../hdc/exec.js';\nimport { getCmdToolsBin } from '../sdk/paths.js';\n\nexport interface CodelinterFinding {\n file: string;\n line: number;\n /** Column, when the report gives one. */\n column?: number;\n /** `error`, `warning`, `suggestion` or `info` (codelinter's `warn` reads as `warning`). */\n severity: string;\n /** Rule code/id when present in the output, else ''. */\n code: string;\n message: string;\n}\n\n/** codelinter's own totals, from its `-Defects: N; Errors: N; Warns: N; Suggestions: N;` line. */\nexport interface CodelinterSummary {\n defects: number;\n errors: number;\n warnings: number;\n suggestions: number;\n}\n\nexport interface CodelinterReport {\n findings: CodelinterFinding[];\n /** The totals codelinter printed (all zero for \"No defects found\"), or null when it printed none. */\n summary: CodelinterSummary | null;\n /**\n * codelinter's remarks about the run itself rather than the code, e.g. \"The type of\n * command line tools does not match that of the project\".\n */\n notices: string[];\n /** True when codelinter warned that the report may be incomplete. */\n incomplete: boolean;\n}\n\nexport interface CodelinterResult extends CodelinterReport {\n /** codelinter process exit code: 1 whenever it found any defect, warnings included. */\n code: number;\n /** Combined stdout+stderr, with colour codes and progress-bar redraws removed. */\n raw: string;\n}\n\n/** Legacy one-line shape: `<file>:<line>[:<col>]: <severity>: <message> [<rule>]`. */\nconst FINDING_RE = /^(.*?):(\\d+):(?:(\\d+):)?\\s*(error|warning|warn|suggestion|info)\\b[:\\s-]*(.*)$/i;\nconst TRAILING_CODE_RE = /[([]([\\w@/.\\-]+)[)\\]]\\s*$/;\n/** Table shape: a `<file>(<count>)` header, then `<line>:<col> <severity> <message> <rule>` rows. */\nconst FILE_HEADER_RE = /^(.+\\.\\w+)\\((\\d+)\\)$/;\nconst ROW_RE = /^(\\d+):(\\d+)\\s+(error|warning|warn|suggestion|info)\\s+(.*)$/i;\nconst RULE_RE = /^@?[\\w.-]+(?:\\/[\\w.-]+)+$/;\nconst SUMMARY_RE = /Defects:\\s*(\\d+);\\s*Errors:\\s*(\\d+);\\s*Warns:\\s*(\\d+);\\s*Suggestions:\\s*(\\d+)/i;\nconst NOTICE_RE = /does not match that of the project|error occurred during linting|incomplete report/i;\nconst ANSI_RE = /\\x1b\\[[0-9;]*[A-Za-z]/g;\n\n/**\n * codelinter output as plain lines: colour codes stripped, and of each line redrawn\n * with `\\r` (its progress bar) only the final state kept.\n */\nexport function cleanCodelinterOutput(output: string): string {\n return output\n .replace(ANSI_RE, '')\n .split('\\n')\n .map((line) => (line.split('\\r').filter((s) => s.trim() !== '').pop() ?? '').trimEnd())\n .join('\\n');\n}\n\nfunction normaliseSeverity(s: string): string {\n const lower = s.toLowerCase();\n return lower === 'warn' ? 'warning' : lower;\n}\n\n/**\n * Parse a codelinter report. Pure/testable. Understands the table codelinter prints\n * (a `<file>(<count>)` header followed by `<line>:<col> <severity> <message> <rule>`\n * rows, then a `-Defects: …` summary) and the one-line\n * `<file>:<line>[:<col>]: <severity>: <message> [<rule>]` shape. Other lines are ignored.\n */\nexport function parseCodelinterReport(output: string): CodelinterReport {\n const findings: CodelinterFinding[] = [];\n const notices: string[] = [];\n let summary: CodelinterSummary | null = null;\n let file = '';\n\n for (const rawLine of cleanCodelinterOutput(output).split('\\n')) {\n const line = rawLine.trim();\n if (!line) continue;\n\n const row = ROW_RE.exec(line);\n if (row) {\n // A row before any file header has nothing to attach to.\n if (!file) continue;\n const columns = row[4]!.trim().split(/\\s{2,}/);\n const last = columns[columns.length - 1]!;\n const code = columns.length > 1 && RULE_RE.test(last) ? last : '';\n const message = (code ? columns.slice(0, -1) : columns).join(' ').trim();\n findings.push({\n file,\n line: Number(row[1]),\n column: Number(row[2]),\n severity: normaliseSeverity(row[3]!),\n code,\n message,\n });\n continue;\n }\n const header = FILE_HEADER_RE.exec(line);\n if (header) {\n file = header[1]!;\n continue;\n }\n const legacy = FINDING_RE.exec(line);\n if (legacy) {\n let message = legacy[5]!.trim();\n let code = '';\n const codeMatch = TRAILING_CODE_RE.exec(message);\n if (codeMatch) {\n code = codeMatch[1]!;\n message = message.slice(0, codeMatch.index).trim();\n }\n const finding: CodelinterFinding = {\n file: legacy[1]!.trim(),\n line: Number(legacy[2]),\n severity: normaliseSeverity(legacy[4]!),\n code,\n message,\n };\n if (legacy[3]) finding.column = Number(legacy[3]);\n findings.push(finding);\n continue;\n }\n const totals = SUMMARY_RE.exec(line);\n if (totals) {\n summary = {\n defects: Number(totals[1]),\n errors: Number(totals[2]),\n warnings: Number(totals[3]),\n suggestions: Number(totals[4]),\n };\n continue;\n }\n if (/no defects found/i.test(line)) {\n summary = { defects: 0, errors: 0, warnings: 0, suggestions: 0 };\n continue;\n }\n if (NOTICE_RE.test(line)) notices.push(line);\n }\n\n return { findings, summary, notices, incomplete: notices.length > 0 };\n}\n\n/** The findings of a codelinter report; see {@link parseCodelinterReport}. */\nexport function parseCodelinterFindings(output: string): CodelinterFinding[] {\n return parseCodelinterReport(output).findings;\n}\n\nexport interface RunCodelinterOptions {\n config: ConfigProvider;\n projectDir: string;\n /** Files/globs to lint; when omitted, codelinter is run with no file args. */\n files?: readonly string[];\n timeoutMs?: number;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\n/** Run the OpenHarmony codelinter and return the parsed report + the cleaned raw output. */\nexport async function runCodelinter(opts: RunCodelinterOptions): Promise<CodelinterResult> {\n const res = await runProcess({\n command: getCmdToolsBin(opts.config, 'codelinter'),\n args: opts.files?.length ? [...opts.files] : [],\n cwd: opts.projectDir,\n timeoutMs: opts.timeoutMs ?? 600_000,\n abortSignal: opts.abortSignal,\n logger: opts.logger,\n });\n const raw = `${res.stdout}${res.stderr}`;\n return { code: res.code, ...parseCodelinterReport(raw), raw: cleanCodelinterOutput(raw) };\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger, scopedLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { runHvigorw } from './runHvigorw.js';\nimport { ensureOhModules } from './ohpm.js';\nimport { discoverHaps, type ModuleHaps } from './discoverHaps.js';\nimport { toLongPath } from '../sdk/paths.js';\nimport { findMissingProjectSdk } from '../sdk/detectProjectSdk.js';\nimport { detectRuntimeOs } from '../harmonyos/target.js';\nimport { findHarmonyOsSdk, findHarmonyOsTool } from '../harmonyos/sdk.js';\n\n/** How much of the build output is kept for {@link diagnoseBuildFailure}, from the end. */\nconst DIAGNOSIS_OUTPUT_LIMIT = 2_000_000;\n\n/**\n * A hint for build output whose cause the compiler errors do not name, or\n * undefined. Pure/testable.\n */\nexport function diagnoseBuildFailure(output: string): string | undefined {\n if (/is not exported from Kit|has no exported member .*@systemapi/i.test(output)) {\n return (\n 'The project calls system APIs (`@systemapi`), which the public SDK leaves out. Build against the ' +\n 'full OpenHarmony SDK: unpack its components into <root>/<os>/<api> of a separate SDK root and set ' +\n 'ONIRO_SDK_ROOT_DIR to that root. Installing such an app also needs privileged signing ' +\n '(`oniro-app sign --apl system_core --acls … --app-privilege-capabilities …`).'\n );\n }\n if (/00308018|SDK path does not exist|SDK license agreement is not accepted/i.test(output)) {\n return 'hvigor cannot find the SDK the project compiles against: check `oniro-app sdk list` against compileSdkVersion.';\n }\n return undefined;\n}\n\nexport interface BuildHapOptions {\n config: ConfigProvider;\n projectDir: string;\n product?: string;\n module?: string;\n /** Forwarded as hvigor `buildMode` (e.g. release, debug). */\n mode?: string;\n /** hvigor task. Default `assembleHap`. */\n task?: string;\n /** Run `ohpm install --all` first when `oh_modules/` is missing. Default true. */\n autoInstallDeps?: boolean;\n /** Build modules in parallel. Default true (see runHvigorw). */\n parallel?: boolean;\n abortSignal?: AbortSignal;\n onOutput?: (chunk: string, stream: 'stdout' | 'stderr') => void;\n logger?: Logger;\n}\n\nexport interface BuildHapResult {\n exitCode: number;\n durationMs: number;\n /** Built HAPs grouped by module folder. */\n discoveredHaps: Record<string, ModuleHaps>;\n warnings: string[];\n}\n\n/**\n * High-level build orchestration: ensure deps → run hvigorw → discover the\n * produced HAPs. The single call the CLI and MCP want; `runHvigorw` stays a raw\n * single-spawn primitive.\n */\nexport async function buildHap(opts: BuildHapOptions): Promise<BuildHapResult> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'build');\n const warnings: string[] = [];\n const start = Date.now();\n // Normalise once so ohpm, hvigor and HAP discovery all agree on the project\n // dir, and the returned artifact paths come back in long form.\n const projectDir = toLongPath(opts.projectDir);\n const isHarmonyOs = detectRuntimeOs(projectDir, opts.product) === 'HarmonyOS';\n\n // Fail before ohpm and hvigor run, with the release to install, rather than on\n // hvigor's own late and vaguer error.\n const missingSdk = isHarmonyOs ? null : findMissingProjectSdk(opts.config, projectDir);\n if (missingSdk) throw missingSdk;\n\n if (opts.autoInstallDeps !== false) {\n // HarmonyOS projects install dependencies with their own install's ohpm.\n const harmonySdk = isHarmonyOs ? findHarmonyOsSdk({ config: opts.config, logger: opts.logger }) : null;\n const r = await ensureOhModules({\n config: opts.config,\n projectDir,\n ohpmPath: (harmonySdk && findHarmonyOsTool(harmonySdk, 'ohpm')) ?? undefined,\n abortSignal: opts.abortSignal,\n onOutput: opts.onOutput,\n logger: opts.logger,\n });\n if (r.installed) logger.info('ran ohpm install --all (oh_modules was missing)');\n }\n\n let output = '';\n let exitCode: number;\n try {\n ({ exitCode } = await runHvigorw({\n config: opts.config,\n projectDir,\n product: opts.product,\n module: opts.module,\n buildMode: opts.mode,\n task: opts.task,\n parallel: opts.parallel,\n abortSignal: opts.abortSignal,\n onOutput: (chunk, stream) => {\n output = (output + chunk).slice(-DIAGNOSIS_OUTPUT_LIMIT);\n opts.onOutput?.(chunk, stream);\n },\n logger: opts.logger,\n }));\n } catch (err) {\n const hint = diagnoseBuildFailure(output);\n if (hint && err instanceof OniroError) throw new OniroError(`${err.message}\\n${hint}`, err);\n throw err;\n }\n\n const discoveredHaps = await discoverHaps({ projectDir });\n const anySigned = Object.values(discoveredHaps).some((m) => m.signed.length > 0);\n if (!anySigned) {\n warnings.push(\n isHarmonyOs\n ? 'No signed HAPs found. The HarmonyOS emulator installs the unsigned HAP as it is; for a device, ' +\n 'run `oniro-app sign --harmonyos` to have AppGallery Connect issue a certificate and profile.'\n : 'No signed HAPs found: most OpenHarmony targets reject unsigned HAPs. Run `oniro-app sign` ' +\n 'to generate local signing material, then build again.',\n );\n }\n\n return { exitCode, durationMs: Date.now() - start, discoveredHaps, warnings };\n}\n","/**\n * Conservative project-folder-name validator (no path separators, conservative charset).\n */\nexport function isValidProjectName(name: string): boolean {\n if (!name) return false;\n if (name.includes('/') || name.includes('\\\\')) return false;\n return /^[A-Za-z0-9._-]+$/.test(name);\n}\n\n/**\n * Bundle-name validator. Allows reverse-DNS style identifiers like `com.example.myapp`.\n */\nexport function isValidBundleName(bundleName: string): boolean {\n return /^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z][A-Za-z0-9_]*)+$/.test(bundleName);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nexport interface TemplateOption {\n id: string;\n label: string;\n description: string;\n defaultModuleName: string;\n}\n\ninterface TemplateMeta {\n id?: string;\n label?: string;\n description?: string;\n defaultModuleName?: string;\n}\n\nfunction toHumanTemplateName(folderName: string): string {\n return folderName.replace(/([a-z])([A-Z])/g, '$1 $2');\n}\n\n/**\n * Enumerate templates inside `templateRoot`. Each direct subfolder is a template;\n * per-template metadata (label/description/defaultModuleName) may live in a\n * `template.json` file alongside the template content.\n *\n * Callers own the template root — the CLI ships its own under\n * `<cli-package>/templates/`, the VS Code extension uses `extensionPath/template`.\n */\nexport function listTemplates(templateRoot: string): TemplateOption[] {\n if (!fs.existsSync(templateRoot)) return [];\n const entries = fs.readdirSync(templateRoot, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory())\n .map((e) => {\n const dir = path.join(templateRoot, e.name);\n const metaPath = path.join(dir, 'template.json');\n let meta: TemplateMeta = {};\n if (fs.existsSync(metaPath)) {\n try {\n meta = JSON.parse(fs.readFileSync(metaPath, 'utf8')) as TemplateMeta;\n } catch {\n // Ignore malformed template metadata.\n }\n }\n return {\n id: e.name,\n label: meta.label ?? toHumanTemplateName(e.name),\n description: meta.description ?? '',\n defaultModuleName: (meta.defaultModuleName ?? 'entry').trim() || 'entry',\n };\n })\n .sort((a, b) => a.label.localeCompare(b.label));\n}\n\n/**\n * Verify that a template directory contains the files required by the scaffold pipeline.\n * Returns the list of missing relative paths, or [] if the template is complete.\n */\nexport function validateTemplateLayout(templateDir: string, defaultModuleName: string): string[] {\n const required = [\n 'build-profile.json5',\n path.join('AppScope', 'app.json5'),\n path.join(defaultModuleName, 'src', 'main', 'module.json5'),\n path.join(defaultModuleName, 'oh-package.json5'),\n 'hvigorfile.ts',\n ];\n return required.filter((rel) => !fs.existsSync(path.join(templateDir, rel)));\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { getOhosBaseSdkHome } from '../sdk/paths.js';\nimport { HARMONYOS_SDK_VERSIONS, detectRuntimeOs, harmonyOsSdkLabelForApi } from '../harmonyos/target.js';\nimport { findHarmonyOsSdk } from '../harmonyos/sdk.js';\nimport { listTemplates, validateTemplateLayout } from './templates.js';\nimport { isValidBundleName, isValidProjectName } from './validators.js';\nimport { readJson5File, readJsonFile, writeJson5File, writeJsonFile } from './jsonHelpers.js';\n\nconst IGNORED_DIRS = new Set(['oh_modules', 'node_modules', 'build', '.hvigor']);\n\nexport interface CreateScaffoldOptions {\n config: ConfigProvider;\n templateId: string;\n projectName: string;\n bundleName: string;\n /** Parent directory that will contain the new project folder. */\n location: string;\n sdkApi: number;\n /** Module folder name. Defaults to the template's `defaultModuleName`. */\n moduleName?: string;\n /** Absolute path to the directory containing template subfolders. */\n templateRoot: string;\n /** If the destination exists, remove it before scaffolding instead of throwing. */\n overwrite?: boolean;\n logger?: Logger;\n}\n\nexport interface CreateScaffoldResult {\n projectDir: string;\n}\n\n/**\n * Async existence check.\n */\nasync function pathExists(p: string): Promise<boolean> {\n try {\n await fs.promises.access(p);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Recursively copy a template directory, skipping symlinks and template metadata.\n */\nasync function copyDirRecursive(srcDir: string, destDir: string): Promise<void> {\n await fs.promises.mkdir(destDir, { recursive: true });\n const entries = await fs.promises.readdir(srcDir, { withFileTypes: true });\n for (const entry of entries) {\n const src = path.join(srcDir, entry.name);\n const dest = path.join(destDir, entry.name);\n if (entry.isDirectory()) {\n await copyDirRecursive(src, dest);\n } else if (entry.isSymbolicLink()) {\n continue;\n } else if (entry.isFile()) {\n if (entry.name === 'template.json') continue;\n await fs.promises.copyFile(src, dest);\n }\n }\n}\n\n/**\n * Normalize every .json5 file in `projectDir` to strict JSON formatting (quoted keys).\n * Keeps JSON5 parsers happy while letting VS Code's built-in JSON parser handle them.\n */\nasync function normalizeJson5ToJson(projectDir: string, logger: Logger): Promise<void> {\n const stack: string[] = [projectDir];\n while (stack.length > 0) {\n const currentDir = stack.pop()!;\n const entries = await fs.promises.readdir(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name)) continue;\n stack.push(fullPath);\n continue;\n }\n if (!entry.isFile() || !entry.name.endsWith('.json5')) continue;\n try {\n const parsed = readJson5File<unknown>(fullPath);\n writeJson5File(fullPath, parsed);\n } catch (err) {\n logger.warn(`Failed to normalize ${fullPath}: ${String(err)}`);\n }\n }\n }\n}\n\nfunction toJavaPropertiesPath(p: string): string {\n return process.platform === 'win32' ? p.replace(/\\\\/g, '\\\\\\\\') : p;\n}\n\nfunction createOrUpdateLocalProperties(projectDir: string, sdkDir: string): void {\n const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}\\n`;\n fs.writeFileSync(path.join(projectDir, 'local.properties'), content, 'utf8');\n}\n\nfunction renameIfExists(fromPath: string, toPath: string): void {\n if (fs.existsSync(fromPath) && fromPath !== toPath) {\n fs.renameSync(fromPath, toPath);\n }\n}\n\n/**\n * Apply user-selected names/versions to template files. Mirrors the writes done by\n * the extension's `updateTemplateConfigs` so a scaffold is identical regardless of\n * which frontend produced it.\n */\nfunction updateTemplateConfigs(\n projectDir: string,\n args: {\n projectName: string;\n bundleName: string;\n /** A plain API level for OpenHarmony; `\"<version>(<api>)\"` for HarmonyOS. */\n sdkVersion: number | string;\n moduleName: string;\n },\n sdkBaseDir: string,\n): void {\n // 1) AppScope/app.json5 -> bundleName\n const appJsonPath = path.join(projectDir, 'AppScope', 'app.json5');\n if (fs.existsSync(appJsonPath)) {\n const appJson = readJson5File<{ app?: { bundleName?: string } }>(appJsonPath);\n appJson.app = appJson.app ?? {};\n appJson.app.bundleName = args.bundleName;\n writeJson5File(appJsonPath, appJson);\n }\n\n // 2) AppScope/resources/base/element/string.json -> app_name = projectName\n const stringsPath = path.join(projectDir, 'AppScope', 'resources', 'base', 'element', 'string.json');\n if (fs.existsSync(stringsPath)) {\n const strings = readJsonFile<{ string?: Array<{ name?: string; value?: string }> }>(stringsPath);\n if (Array.isArray(strings.string)) {\n const appName = strings.string.find((s) => s.name === 'app_name');\n if (appName) appName.value = args.projectName;\n }\n writeJsonFile(stringsPath, strings);\n }\n\n // 3) build-profile.json5 -> sdk + module name + srcPath\n const buildProfilePath = path.join(projectDir, 'build-profile.json5');\n if (fs.existsSync(buildProfilePath)) {\n const buildProfile = readJson5File<{\n app?: { products?: Array<{ compileSdkVersion?: number | string; compatibleSdkVersion?: number | string }> };\n modules?: Array<{ name?: string; srcPath?: string }>;\n }>(buildProfilePath);\n buildProfile.app = buildProfile.app ?? {};\n if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {\n buildProfile.app.products[0]!.compileSdkVersion = args.sdkVersion;\n buildProfile.app.products[0]!.compatibleSdkVersion = args.sdkVersion;\n }\n if (Array.isArray(buildProfile.modules) && buildProfile.modules.length > 0) {\n buildProfile.modules[0]!.name = args.moduleName;\n buildProfile.modules[0]!.srcPath = `./${args.moduleName}`;\n }\n writeJson5File(buildProfilePath, buildProfile);\n }\n\n // 4) <module>/src/main/module.json5 -> module.name\n const moduleJsonPath = path.join(projectDir, args.moduleName, 'src', 'main', 'module.json5');\n if (fs.existsSync(moduleJsonPath)) {\n const moduleJson = readJson5File<{ module?: { name?: string } }>(moduleJsonPath);\n moduleJson.module = moduleJson.module ?? {};\n moduleJson.module.name = args.moduleName;\n writeJson5File(moduleJsonPath, moduleJson);\n }\n\n // 5) <module>/oh-package.json5 -> name\n const moduleOhPackagePath = path.join(projectDir, args.moduleName, 'oh-package.json5');\n if (fs.existsSync(moduleOhPackagePath)) {\n const pkg = readJson5File<{ name?: string }>(moduleOhPackagePath);\n pkg.name = args.moduleName;\n writeJson5File(moduleOhPackagePath, pkg);\n }\n\n // 6) .vscode/settings.json — useful for users who do open the project in VS Code.\n const vscodeDir = path.join(projectDir, '.vscode');\n fs.mkdirSync(vscodeDir, { recursive: true });\n const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;\n writeJsonFile(path.join(vscodeDir, 'settings.json'), {\n 'oniro.hapPath': hapPath,\n 'files.associations': { '*.json5': 'jsonc' },\n });\n\n // 7) local.properties — sdk.dir must point at the OS base SDK home (containing API folders),\n // NOT a specific API folder, otherwise hvigor double-nests the lookup.\n createOrUpdateLocalProperties(projectDir, sdkBaseDir);\n}\n\n/**\n * Scaffold a new Oniro/OpenHarmony project from a template. Returns the absolute path\n * to the created project directory.\n */\nexport async function createScaffold(opts: CreateScaffoldOptions): Promise<CreateScaffoldResult> {\n const logger = opts.logger ?? noopLogger;\n\n if (!isValidProjectName(opts.projectName)) {\n throw new OniroError(`Invalid project name '${opts.projectName}'. Use letters/numbers/._- and no slashes.`);\n }\n if (!isValidBundleName(opts.bundleName)) {\n throw new OniroError(`Invalid bundle name '${opts.bundleName}'. Example: com.example.myapplication`);\n }\n if (!opts.location || !(await pathExists(opts.location))) {\n throw new OniroError(`Location does not exist: ${opts.location}`);\n }\n\n const templateDir = path.join(opts.templateRoot, opts.templateId);\n if (!(await pathExists(templateDir))) {\n throw new OniroError(`Template not found: ${templateDir}`);\n }\n\n const templates = listTemplates(opts.templateRoot);\n const selected = templates.find((t) => t.id === opts.templateId);\n const defaultModuleName = selected?.defaultModuleName ?? 'entry';\n const moduleName = (opts.moduleName ?? defaultModuleName).trim() || defaultModuleName;\n\n const missing = validateTemplateLayout(templateDir, defaultModuleName);\n if (missing.length > 0) {\n throw new OniroError(`Template '${opts.templateId}' is missing required files:\\n- ${missing.join('\\n- ')}`);\n }\n\n // HarmonyOS templates declare the SDK as \"<version>(<api>)\" and build against the\n // HarmonyOS SDK; OpenHarmony ones take the plain API level and the OpenHarmony SDK.\n let sdkVersion: number | string = opts.sdkApi;\n let sdkBaseDir = getOhosBaseSdkHome(opts.config);\n if (detectRuntimeOs(templateDir) === 'HarmonyOS') {\n const harmonySdk = findHarmonyOsSdk({ config: opts.config, logger });\n // The installed SDK names its own release, which covers API levels newer than the table.\n const label = harmonySdk?.version?.endsWith(`(${opts.sdkApi})`)\n ? harmonySdk.version\n : harmonyOsSdkLabelForApi(opts.sdkApi);\n if (!label) {\n throw new OniroError(\n `No HarmonyOS release is known for API ${opts.sdkApi}. Known: ${[...HARMONYOS_SDK_VERSIONS.keys()].join(', ')}` +\n (harmonySdk?.version ? `, and the installed SDK's ${harmonySdk.version}.` : '.'),\n );\n }\n sdkVersion = label;\n if (!harmonySdk) {\n logger.warn('[create] No HarmonyOS SDK found; set ONIRO_HARMONYOS_SDK_PATH before building.');\n } else {\n sdkBaseDir = harmonySdk.sdkPath;\n if (harmonySdk.version && harmonySdk.version !== label) {\n // hvigor fails with \"SDK component missing\" when compileSdkVersion names another release.\n logger.warn(\n `[create] The HarmonyOS SDK at ${harmonySdk.sdkPath} is ${harmonySdk.version}, so a project ` +\n `declaring ${label} will not build against it. Install ${label}, or create with the installed API level.`,\n );\n }\n }\n }\n\n const projectDir = path.join(opts.location, opts.projectName);\n if (await pathExists(projectDir)) {\n if (!opts.overwrite) {\n throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);\n }\n await fs.promises.rm(projectDir, { recursive: true, force: true });\n }\n\n logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);\n await copyDirRecursive(templateDir, projectDir);\n\n if (moduleName !== defaultModuleName) {\n renameIfExists(path.join(projectDir, defaultModuleName), path.join(projectDir, moduleName));\n }\n\n updateTemplateConfigs(\n projectDir,\n {\n projectName: opts.projectName,\n bundleName: opts.bundleName,\n sdkVersion,\n moduleName,\n },\n sdkBaseDir,\n );\n\n await normalizeJson5ToJson(projectDir, logger);\n\n return { projectDir };\n}\n","import * as fs from 'node:fs';\nimport JSON5 from 'json5';\n\nexport function readJson5File<T>(filePath: string): T {\n return JSON5.parse(fs.readFileSync(filePath, 'utf8')) as T;\n}\n\n/**\n * Write strict JSON content (quoted keys) to a `.json5` file. Keeps the file\n * compatible with VS Code's JSON parser while remaining valid JSON5.\n */\nexport function writeJson5File(filePath: string, value: unknown): void {\n fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\\n', 'utf8');\n}\n\nexport function readJsonFile<T>(filePath: string): T {\n return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T;\n}\n\nexport function writeJsonFile(filePath: string, value: unknown): void {\n fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\\n', 'utf8');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { OniroError } from '../ports/errors.js';\nimport { readJson5File } from './jsonHelpers.js';\n\nexport interface ProjectModule {\n name: string;\n /** Source path relative to the project root (e.g. `./entry`). */\n srcPath: string;\n /** Target names declared under the module (often empty). */\n targets: string[];\n}\n\ninterface BuildProfile {\n modules?: Array<{ name?: string; srcPath?: string; targets?: Array<{ name?: string }> }>;\n}\n\n/**\n * Read the `modules[]` declared in `build-profile.json5` so callers can target a\n * specific module in a multi-module project.\n */\nexport function listModules(opts: { projectDir: string }): ProjectModule[] {\n const buildProfile = path.join(opts.projectDir, 'build-profile.json5');\n if (!fs.existsSync(buildProfile)) {\n throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);\n }\n const parsed = readJson5File<BuildProfile>(buildProfile);\n return (parsed.modules ?? [])\n .filter((m): m is { name: string; srcPath?: string; targets?: Array<{ name?: string }> } => Boolean(m.name))\n .map((m) => ({\n name: m.name,\n srcPath: m.srcPath ?? `./${m.name}`,\n targets: (m.targets ?? []).map((t) => t.name).filter((n): n is string => Boolean(n)),\n }));\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { OniroError } from '../ports/errors.js';\nimport { readJson5File } from './jsonHelpers.js';\n\nexport interface AbilityInfo {\n name: string;\n type?: string;\n visible?: boolean;\n srcEntry?: string;\n}\n\ninterface ModuleJson {\n module?: { abilities?: Array<{ name?: string; type?: string; visible?: boolean; srcEntry?: string }> };\n}\n\n/**\n * Read all abilities declared in a module's `module.json5` `abilities[]`.\n * Defaults to the `entry` module folder.\n */\nexport function listAbilities(opts: { projectDir: string; moduleName?: string }): AbilityInfo[] {\n const moduleName = opts.moduleName ?? 'entry';\n const moduleJsonPath = path.join(opts.projectDir, moduleName, 'src', 'main', 'module.json5');\n if (!fs.existsSync(moduleJsonPath)) {\n throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);\n }\n const parsed = readJson5File<ModuleJson>(moduleJsonPath);\n return (parsed.module?.abilities ?? [])\n .filter((a): a is { name: string; type?: string; visible?: boolean; srcEntry?: string } => Boolean(a.name))\n .map((a) => ({ name: a.name, type: a.type, visible: a.visible, srcEntry: a.srcEntry }));\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { getOhosBaseSdkHome } from '../sdk/paths.js';\nimport { generateSigningConfigs, type Apl, type AppFeature, type SigningPasswords } from '../sign/generateSigningConfigs.js';\nimport { readJson5File } from './jsonHelpers.js';\n\nexport interface PrepareSigningOptions {\n config: ConfigProvider;\n projectDir: string;\n // Forwarded to the fresh-generate fallback:\n apl?: Apl;\n appFeature?: AppFeature;\n acls?: string[];\n appPrivilegeCapabilities?: string[];\n passwords?: SigningPasswords;\n logger?: Logger;\n}\n\nexport interface PrepareSigningResult {\n source: 'present' | 'fresh';\n}\n\n/** A project has usable signing material if `signatures/` exists AND build-profile declares signingConfigs. */\nfunction hasSigningArtifacts(dir: string): boolean {\n if (!fs.existsSync(path.join(dir, 'signatures'))) return false;\n const buildProfile = path.join(dir, 'build-profile.json5');\n if (!fs.existsSync(buildProfile)) return false;\n try {\n const parsed = readJson5File<{ app?: { signingConfigs?: unknown[] } }>(buildProfile);\n return Array.isArray(parsed.app?.signingConfigs) && parsed.app!.signingConfigs!.length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Ensure a project has signing material: a no-op when `signatures/` +\n * signingConfigs already exist ('present'), otherwise generate them via\n * {@link generateSigningConfigs} ('fresh', which needs java + the SDK).\n */\nexport function prepareSigning(opts: PrepareSigningOptions): PrepareSigningResult {\n if (hasSigningArtifacts(opts.projectDir)) {\n return { source: 'present' };\n }\n generateSigningConfigs({\n projectDir: opts.projectDir,\n sdkHome: getOhosBaseSdkHome(opts.config),\n apl: opts.apl,\n appFeature: opts.appFeature,\n acls: opts.acls,\n appPrivilegeCapabilities: opts.appPrivilegeCapabilities,\n passwords: opts.passwords,\n logger: opts.logger,\n });\n return { source: 'fresh' };\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { shell } from '../hdc/exec.js';\n\nexport interface HidumperOptions {\n config: ConfigProvider;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\nexport interface ScreenDump {\n width: number;\n height: number;\n /** Raw hidumper screen output. */\n raw: string;\n}\n\n/** `hidumper -s 10 -a screen` → parsed render resolution + raw text, or null. */\nexport async function dumpScreen(opts: HidumperOptions): Promise<ScreenDump | null> {\n const res = await shell({ config: opts.config, command: 'hidumper -s 10 -a screen', deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 10_000, logger: opts.logger });\n if (res.code !== 0) return null;\n const m = res.stdout.match(/render resolution=(\\d+)x(\\d+)/);\n if (!m) return null;\n return { width: Number(m[1]), height: Number(m[2]), raw: res.stdout };\n}\n\n/** `hidumper -s WindowManagerService -a -a` — windows in z-order with surface presence. */\nexport async function dumpWindow(opts: HidumperOptions): Promise<string> {\n const res = await shell({ config: opts.config, command: 'hidumper -s WindowManagerService -a -a', deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 15_000, logger: opts.logger });\n return res.stdout;\n}\n\n/** `hidumper -s RenderService -a allInfo` — composition state / refresh rate. */\nexport async function dumpRenderService(opts: HidumperOptions): Promise<string> {\n const res = await shell({ config: opts.config, command: 'hidumper -s RenderService -a allInfo', deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 15_000, logger: opts.logger });\n return res.stdout;\n}\n","import type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { paramGetMany } from '../hdc/param.js';\nimport { dumpScreen } from './hidumper.js';\n\nexport interface DeviceFullInfo {\n serial: string;\n model?: string;\n manufacturer?: string;\n brand?: string;\n /** `HarmonyOS` when the device reports a HarmonyOS distribution, else `OpenHarmony` (Oniro included). */\n osFamily?: 'HarmonyOS' | 'OpenHarmony';\n /** Distribution name (`const.product.os.dist.name`): `HarmonyOS`; unset on OpenHarmony. */\n osDistName?: string;\n /** Distribution version (`const.product.os.dist.version`), e.g. `6.1.0` on HarmonyOS. */\n osDistVersion?: string;\n osFullName?: string;\n osReleaseType?: string;\n sdkApiVersion?: string;\n buildVersion?: string;\n /** CPU ABIs (`const.product.cpu.abilist`), e.g. `arm64-v8a` or `x86_64`: native libraries must match. */\n abi?: string;\n /** `phone`, `tablet`, `wearable`, `default`, … */\n deviceType?: string;\n display: { width: number; height: number } | null;\n}\n\ntype ParamField = Exclude<keyof DeviceFullInfo, 'serial' | 'display' | 'osFamily'>;\n\n// The MCP get_device_info property set, plus what picking a target for an app needs.\nconst PROPS: ReadonlyArray<[ParamField, string]> = [\n ['model', 'const.product.model'],\n ['manufacturer', 'const.product.manufacturer'],\n ['brand', 'const.product.brand'],\n ['osDistName', 'const.product.os.dist.name'],\n ['osDistVersion', 'const.product.os.dist.version'],\n ['osFullName', 'const.ohos.fullname'],\n ['osReleaseType', 'const.ohos.releasetype'],\n ['sdkApiVersion', 'const.ohos.apiversion'],\n ['buildVersion', 'const.product.software.version'],\n ['abi', 'const.product.cpu.abilist'],\n ['deviceType', 'const.product.devicetype'],\n];\n\nexport interface GetDeviceInfoOptions {\n config: ConfigProvider;\n deviceSerial?: string;\n timeoutMs?: number;\n logger?: Logger;\n}\n\n/** Collate device properties (one `param get` round trip) and the display resolution. */\nexport async function getDeviceInfo(opts: GetDeviceInfoOptions): Promise<DeviceFullInfo> {\n const info: DeviceFullInfo = { serial: opts.deviceSerial ?? '(default)', display: null };\n\n try {\n const values = await paramGetMany(\n opts.config,\n PROPS.map(([, prop]) => prop),\n { deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 10_000, logger: opts.logger },\n );\n for (const [field, prop] of PROPS) {\n const value = values[prop];\n if (value) info[field] = value;\n }\n } catch {\n // Missing properties are left undefined rather than failing the whole collation.\n }\n if (info.osDistName || info.osFullName) {\n info.osFamily = /harmonyos/i.test(info.osDistName ?? '') ? 'HarmonyOS' : 'OpenHarmony';\n }\n\n const screen = await dumpScreen({ config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger });\n if (screen) info.display = { width: screen.width, height: screen.height };\n return info;\n}\n","import StreamZip from 'node-stream-zip';\n\n// node-stream-zip's types are thin; this is the minimal shape we use (mirrors sdk/extract.ts).\ninterface ZipEntry {\n name: string;\n isDirectory: boolean;\n}\ninterface StreamZipAsync {\n entries(): Promise<Record<string, ZipEntry>>;\n close(): Promise<void>;\n}\n\nexport interface HapAssetDiff {\n /** File paths present in the new HAP but not the installed one. */\n addedAssetPaths: string[];\n /** File paths present in the installed HAP but not the new one. */\n removedAssetPaths: string[];\n}\n\n/** Pure set-diff of two file-name listings, sorted. */\nexport function diffEntryNames(installed: Iterable<string>, next: Iterable<string>): HapAssetDiff {\n const installedSet = new Set(installed);\n const nextSet = new Set(next);\n return {\n addedAssetPaths: [...nextSet].filter((n) => !installedSet.has(n)).sort(),\n removedAssetPaths: [...installedSet].filter((n) => !nextSet.has(n)).sort(),\n };\n}\n\nasync function listFileEntries(hapPath: string): Promise<string[]> {\n const zip = new (StreamZip as unknown as { async: new (cfg: { file: string }) => StreamZipAsync }).async({ file: hapPath });\n try {\n const entries = await zip.entries();\n return Object.values(entries)\n .filter((e) => !e.isDirectory)\n .map((e) => e.name);\n } finally {\n await zip.close();\n }\n}\n\n/**\n * Diff the file manifests of two HAP (zip) archives. Drives the ACE-extractor\n * cache-invalidation reboot decision in `applyChanges`: when the new HAP adds or\n * renames file paths vs the installed one, the path-keyed asset cache can serve\n * stale \"GetAsset failed\" errors until a reboot.\n */\nexport async function diffHapAssets(opts: { installedHap: string; newHap: string }): Promise<HapAssetDiff> {\n const [installed, next] = await Promise.all([listFileEntries(opts.installedHap), listFileEntries(opts.newHap)]);\n return diffEntryNames(installed, next);\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../ports/config.js';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger, scopedLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\nimport { hdcExec } from '../hdc/exec.js';\nimport {\n ensureInstallOk,\n existingHapOrUnsigned,\n findRunningProcess,\n isBundleInstalled,\n uninstallApp,\n type InstallCandidate,\n} from '../hdc/app.js';\nimport { reboot } from '../hdc/lifecycle.js';\nimport { discoverHaps, pickHap } from '../build/discoverHaps.js';\nimport { diffHapAssets } from './diffHapAssets.js';\n\nexport type InstallMethod = 'replace' | 'uninstall-install' | 'refuse';\n\n/**\n * P0-5a decision: how to install given whether `hdc install -r` reported a\n * sign-info-inconsistent error (9568332). System bundles are NOT silently\n * uninstalled (that can brick the device) unless explicitly allowed.\n */\nexport function decideInstallMethod(s: {\n signInfoInconsistent: boolean;\n isSystemBundle: boolean;\n allowUninstall: boolean;\n}): InstallMethod {\n if (!s.signInfoInconsistent) return 'replace';\n if (s.isSystemBundle && !s.allowUninstall) return 'refuse';\n return 'uninstall-install';\n}\n\nexport interface RebootDecision {\n reboot: boolean;\n reason: 'asset-cache' | 'pid-unchanged' | 'none';\n}\n\n/**\n * P0-5b/c decision: whether to reboot after installing. Reboot when the HAP's\n * asset paths changed (ACE extractor cache is path-keyed and survives a process\n * kill), or when a persistent/system bundle's process didn't restart.\n */\nexport function decideReboot(s: {\n assetsChanged: boolean;\n isSystemBundle: boolean;\n preInstallPid: number | null;\n postInstallPid: number | null;\n}): RebootDecision {\n if (s.assetsChanged) return { reboot: true, reason: 'asset-cache' };\n if (s.isSystemBundle && s.preInstallPid !== null && s.postInstallPid === s.preInstallPid) {\n return { reboot: true, reason: 'pid-unchanged' };\n }\n return { reboot: false, reason: 'none' };\n}\n\nconst SIGN_INFO_INCONSISTENT = /9568332|sign.*info.*inconsistent/i;\n\nexport interface ApplyChangesOptions {\n config: ConfigProvider;\n bundle: string;\n /** Explicit HAP path. If omitted, resolved from projectDir (+ module) via discoverHaps. */\n hapPath?: string;\n projectDir?: string;\n module?: string;\n /** Local path to the currently-installed HAP; enables the asset-cache diff/reboot. */\n installedHapPath?: string;\n /** Persistent/system bundle (e.g. systemui). Default false. */\n isSystemBundle?: boolean;\n /** Permit uninstalling a system bundle on sign-info mismatch (dangerous). Default false. */\n allowUninstall?: boolean;\n deviceSerial?: string;\n abortSignal?: AbortSignal;\n logger?: Logger;\n}\n\nexport interface ApplyChangesResult {\n method: 'replace' | 'uninstall-install' | 'reboot';\n preInstallPid: number | null;\n postInstallPid: number | null;\n replaced: boolean;\n /** True when an asset-path change forced the reboot. */\n cacheCleared: boolean;\n}\n\nasync function pidOf(config: ConfigProvider, bundle: string, deviceSerial?: string): Promise<number | null> {\n const proc = await findRunningProcess({ config, bundle, deviceSerial });\n return proc ? Number(proc.pid) : null;\n}\n\nasync function resolveHap(opts: ApplyChangesOptions, logger: Logger): Promise<InstallCandidate> {\n let hap: InstallCandidate | undefined;\n if (opts.hapPath) {\n const hapPath =\n !path.isAbsolute(opts.hapPath) && opts.projectDir ? path.join(opts.projectDir, opts.hapPath) : opts.hapPath;\n hap = existingHapOrUnsigned(hapPath);\n if (!hap) throw new OniroError(`HAP not found at ${hapPath}.`);\n } else {\n if (!opts.projectDir) throw new OniroError('applyChanges requires hapPath or projectDir.');\n const picked = pickHap(await discoverHaps({ projectDir: opts.projectDir }), opts.module);\n if (!picked) throw new OniroError(`No HAP found${opts.module ? ` for module ${opts.module}` : ''}. Build first.`);\n hap = { path: picked.path, fallback: !picked.signed };\n }\n if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path.basename(hap.path)}.`);\n return hap;\n}\n\n/**\n * Install a HAP and verify the running process took the change. Handles the\n * three failure modes the naive \"install the most recent signed HAP\" deploy\n * ignores: sign-info-inconsistent on `-r`, asset-cache invalidation, and a\n * persistent bundle that didn't restart. See {@link decideInstallMethod} /\n * {@link decideReboot} for the (pure, tested) branch logic.\n */\nexport async function applyChanges(opts: ApplyChangesOptions): Promise<ApplyChangesResult> {\n const logger = scopedLogger(opts.logger ?? noopLogger, 'apply');\n const { config, bundle, deviceSerial } = opts;\n const isSystemBundle = opts.isSystemBundle ?? false;\n const allowUninstall = opts.allowUninstall ?? false;\n\n const hap = await resolveHap(opts, logger);\n const hapPath = hap.path;\n logger.info(`installing ${hapPath}`);\n\n // Asset-path diff (best-effort; only when the caller supplies the installed HAP).\n let assetsChanged = false;\n if (opts.installedHapPath && fs.existsSync(opts.installedHapPath)) {\n try {\n const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });\n assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;\n } catch (err) {\n logger.debug(`asset diff skipped: ${(err as Error).message}`);\n }\n }\n\n const preInstallPid = await pidOf(config, bundle, deviceSerial);\n\n // Attempt a replace install, then decide based on the sign-info signal.\n const replaceRes = await hdcExec({ config, args: ['install', '-r', hapPath], deviceSerial, timeoutMs: 300_000 });\n const signInfoInconsistent = SIGN_INFO_INCONSISTENT.test(`${replaceRes.stdout}${replaceRes.stderr}`);\n const decision = decideInstallMethod({ signInfoInconsistent, isSystemBundle, allowUninstall });\n\n let installMethod: 'replace' | 'uninstall-install';\n if (decision === 'refuse') {\n throw new OniroError(\n `Refusing to reinstall system bundle ${bundle}: signing certs are inconsistent (9568332). ` +\n 'Align the signing certs first — uninstalling a system bundle can brick the device. ' +\n 'Pass allowUninstall to override.',\n );\n }\n if (decision === 'uninstall-install') {\n logger.warn(`sign-info inconsistent for ${bundle}; uninstalling then installing fresh.`);\n await uninstallApp({ config, bundle, deviceSerial });\n ensureInstallOk(\n await hdcExec({ config, args: ['install', hapPath], deviceSerial, timeoutMs: 300_000 }),\n `hdc install ${hapPath}`,\n hap,\n );\n installMethod = 'uninstall-install';\n } else {\n ensureInstallOk(replaceRes, `hdc install -r ${hapPath}`, hap);\n installMethod = 'replace';\n }\n\n // hdc's own exit code says nothing about the bundle manager's verdict, so\n // confirm the bundle is there before reporting success.\n if (!(await isBundleInstalled({ config, bundle, deviceSerial }))) {\n throw new OniroError(\n `hdc reported ${path.basename(hapPath)} as installed, but bm dump does not list ${bundle}. ` +\n 'Check that the HAP was built from this project (its bundleName must match).',\n );\n }\n\n let postInstallPid = await pidOf(config, bundle, deviceSerial);\n const rebootDecision = decideReboot({ assetsChanged, isSystemBundle, preInstallPid, postInstallPid });\n\n let method: ApplyChangesResult['method'] = installMethod;\n let cacheCleared = false;\n if (rebootDecision.reboot) {\n logger.info(`rebooting (${rebootDecision.reason}) to apply changes to ${bundle}.`);\n await reboot({ config, waitForBundle: bundle, deviceSerial, abortSignal: opts.abortSignal, logger: opts.logger });\n postInstallPid = await pidOf(config, bundle, deviceSerial);\n method = 'reboot';\n cacheCleared = rebootDecision.reason === 'asset-cache';\n }\n\n return { method, preInstallPid, postInstallPid, replaced: installMethod === 'replace', cacheCleared };\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/auth/auth-config.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n *\n * These are private, undocumented Huawei endpoints and can change without notice.\n */\n\n/** Client ID the DevEco CLI registers as with the Huawei login service. */\nexport const HUAWEI_APP_ID = '1009';\n\n/** Version string the temp-token exchange expects. */\nexport const HUAWEI_API_VERSION = '1.0.0';\n\n/** How long to wait for the user to finish signing in in their browser. */\nexport const LOGIN_TIMEOUT_MS = 600_000;\n\nexport type HuaweiSiteCode = 'CN' | 'EU' | 'SG' | 'RU';\n\nexport interface HuaweiSite {\n code: HuaweiSiteCode;\n /** `siteId` as reported by the login callback. */\n siteId: string;\n /** The token exchange's `site` parameter. The European site's is `DE`, not `EU`. */\n siteParam: string;\n /** Sign-in page and `authrouter` token endpoints. */\n loginUrl: string;\n /** AppGallery Connect certificate, device and profile calls. */\n agcBaseUrl: string;\n language: string;\n}\n\n/**\n * Regional endpoints.\n *\n * Upstream hardcodes the Chinese-mainland hosts and refuses any other `siteId`.\n * DevEco Studio resolves every host through Huawei's Global Routing Service (GRS),\n * service `com.huawei.devecostudio.region`, by the user's country; these are its\n * answers for keys `spaceintroduce` (sign-in, token exchange) and `agcsign`\n * (signing). If a region stops working, diff against\n *\n * POST https://grs.dbankcloud.com/grs/2.0/router?issue_country=<ISO>&app_name=devecostudio\n *\n * The `siteId` → `site` mapping is DevEco Studio's own (1 CN, 5 SG, 7 DE, 8 RU).\n */\nexport const HUAWEI_SITES: Readonly<Record<HuaweiSiteCode, HuaweiSite>> = {\n CN: {\n code: 'CN',\n siteId: '1',\n siteParam: 'CN',\n loginUrl: 'https://cn.devecostudio.huawei.com',\n agcBaseUrl: 'https://connect-api.cloud.huawei.com',\n language: 'zh_CN',\n },\n SG: {\n code: 'SG',\n siteId: '5',\n siteParam: 'SG',\n loginUrl: 'https://sg.devecostudio.huawei.com',\n agcBaseUrl: 'https://connect-api-dra.cloud.huawei.com',\n language: 'zh_CN',\n },\n EU: {\n code: 'EU',\n siteId: '7',\n siteParam: 'DE',\n loginUrl: 'https://de.devecostudio.huawei.com',\n agcBaseUrl: 'https://connect-api-dre.cloud.huawei.com',\n language: 'de_DE',\n },\n RU: {\n code: 'RU',\n siteId: '8',\n siteParam: 'RU',\n loginUrl: 'https://ru.devecostudio.huawei.com',\n agcBaseUrl: 'https://connect-api-drru.cloud.huawei.com',\n language: 'ru_RU',\n },\n};\n\n/** The team list is served from one host for every region (GRS key `agcups`). */\nexport const AGC_TEAMS_URL = 'https://connect-api.cloud.huawei.com/api/ups/user-permission-service/v1/user-team-list';\n\n/**\n * Resolve the `siteId` the login callback reports, or null for one this table does\n * not know — sending an account's token to another region's hosts gets it refused.\n */\nexport function siteForId(siteId: string): HuaweiSite | null {\n return Object.values(HUAWEI_SITES).find((s) => s.siteId === siteId) ?? null;\n}\n\n/** Paths shared by every region; only the host differs. */\nexport const AUTH_PATHS = {\n /** The browser authenticates here, then redirects to the loopback server. */\n AUTH_APPLY: 'console/DevEcoIDE/apply',\n /** Exchanges the browser's temp token for a JWT. */\n TEMP_TOKEN_CHECK: 'authrouter/auth/api/temptoken/check',\n /** Validates a JWT and, with `refresh`, mints an AGC access token. */\n JWT_TOKEN_CHECK: 'authrouter/auth/api/jwToken/check',\n LOGIN_SUCCESS: 'console/DevEcoCLI/loginSuccess',\n LOGIN_FAILED: 'console/DevEcoCLI/loginFailed',\n LOGOUT: 'authrouter/auth/api/logout',\n /**\n * Whether an account without real-name verification accepted the developer\n * agreement, which is what lets it sign. From DevEco Studio (`space.agr.url`).\n */\n UNREALNAME_AGREEMENT: 'authrouter/unrealname/agreement',\n} as const;\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/auth/utils/local-crypto.ts`, `src/auth/utils/token-storage.ts`),\n * Copyright (c) 2026 Huawei Device Co., Ltd., licensed under the MIT License.\n * See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport type { ConfigProvider } from '../../ports/config.js';\nimport { defaultPaths } from '../../ports/config.js';\nimport type { Logger } from '../../ports/logger.js';\nimport { noopLogger } from '../../ports/logger.js';\nimport { OniroError } from '../../ports/errors.js';\n\nconst ALGORITHM = 'aes-256-gcm';\nconst KEY_LENGTH = 32;\nconst IV_LENGTH = 12;\nconst TOKEN_FILE = 'token.enc';\nconst KEY_FILE = 'kek.bin';\nconst DIR_MODE = 0o700;\nconst FILE_MODE = 0o600;\n\ninterface EncryptedBlob {\n version: 1;\n algorithm: typeof ALGORITHM;\n ciphertext: string;\n iv: string;\n authTag: string;\n}\n\nfunction encrypt(key: Buffer, plaintext: Buffer): EncryptedBlob {\n const iv = crypto.randomBytes(IV_LENGTH);\n const cipher = crypto.createCipheriv(ALGORITHM, key, iv);\n const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n return {\n version: 1,\n algorithm: ALGORITHM,\n ciphertext: ciphertext.toString('base64'),\n iv: iv.toString('base64'),\n authTag: cipher.getAuthTag().toString('base64'),\n };\n}\n\nfunction decrypt(key: Buffer, blob: EncryptedBlob): Buffer {\n const decipher = crypto.createDecipheriv(ALGORITHM, key, Buffer.from(blob.iv, 'base64'));\n decipher.setAuthTag(Buffer.from(blob.authTag, 'base64'));\n return Buffer.concat([decipher.update(Buffer.from(blob.ciphertext, 'base64')), decipher.final()]);\n}\n\nfunction isEncryptedBlob(value: unknown): value is EncryptedBlob {\n if (!value || typeof value !== 'object') return false;\n const b = value as Partial<EncryptedBlob>;\n return (\n b.algorithm === ALGORITHM &&\n typeof b.ciphertext === 'string' &&\n typeof b.iv === 'string' &&\n typeof b.authTag === 'string'\n );\n}\n\nfunction permissionHint(dir: string): string {\n return process.platform === 'win32'\n ? `Permission denied writing ${dir}. Grant write permission to that directory.`\n : `Permission denied writing ${dir}. Try: chown -R \"$(whoami)\" ${dir}`;\n}\n\nfunction ensureDir(dir: string): void {\n try {\n fs.mkdirSync(dir, { recursive: true, mode: DIR_MODE });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'EACCES') {\n throw new OniroError(permissionHint(dir), err);\n }\n throw err;\n }\n}\n\n/**\n * A signed-in account: the durable credential plus its region, since every later\n * request goes to that region's hosts and only the login callback reports it.\n */\nexport interface StoredSession {\n jwtToken: string;\n /** `siteId` from the login callback. */\n siteId: string;\n}\n\nexport interface TokenStore {\n save(session: StoredSession): void;\n load(): StoredSession | null;\n clear(): void;\n /** Where the encrypted token lives — surfaced by `auth status`. */\n readonly tokenPath: string;\n}\n\nexport interface CreateTokenStoreOptions {\n config: ConfigProvider;\n logger?: Logger;\n}\n\n/**\n * Persist the Huawei account JWT under the configured auth directory\n * (`ONIRO_HARMONYOS_AUTH_DIR`, default `~/.oniro/harmonyos`).\n *\n * The token is encrypted with a random key kept in a *different* directory, so a\n * stray copy of one of them — a config-dir backup, a synced dotfile repo — does not\n * yield the token. Both live on the same disk, so this is no defence against a local\n * attacker who can read the user's whole home. Treat the token as a credential.\n */\nexport function createTokenStore(opts: CreateTokenStoreOptions): TokenStore {\n const logger = opts.logger ?? noopLogger;\n const authDir = opts.config.get('harmonyosAuthDir', defaultPaths.harmonyosAuthDir());\n const tokenPath = path.join(authDir, TOKEN_FILE);\n const keyPath = path.join(os.homedir(), '.local', 'share', 'oniro-app', 'keys', KEY_FILE);\n\n function loadOrCreateKey(): Buffer {\n if (fs.existsSync(keyPath)) {\n const existing = fs.readFileSync(keyPath);\n if (existing.length === KEY_LENGTH) return existing;\n logger.warn('[harmonyos] The token key file was malformed; regenerating (you will need to log in again).');\n }\n ensureDir(path.dirname(keyPath));\n const key = crypto.randomBytes(KEY_LENGTH);\n fs.writeFileSync(keyPath, key, { mode: FILE_MODE });\n return key;\n }\n\n return {\n tokenPath,\n\n save(session: StoredSession): void {\n if (!session.jwtToken) throw new OniroError('Refusing to store an empty token.');\n const payload = Buffer.from(JSON.stringify(session), 'utf8');\n const blob = encrypt(loadOrCreateKey(), payload);\n ensureDir(authDir);\n fs.writeFileSync(tokenPath, JSON.stringify(blob, null, 2), { mode: FILE_MODE });\n },\n\n load(): StoredSession | null {\n if (!fs.existsSync(tokenPath)) return null;\n try {\n const blob: unknown = JSON.parse(fs.readFileSync(tokenPath, 'utf8'));\n if (!isEncryptedBlob(blob)) return null;\n const { jwtToken, siteId } = JSON.parse(decrypt(loadOrCreateKey(), blob).toString('utf8')) as Partial<StoredSession>;\n return typeof jwtToken === 'string' && jwtToken && typeof siteId === 'string' ? { jwtToken, siteId } : null;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n // A permissions problem is transient and the user can fix it; anything else\n // means the stored token is unusable, so drop it rather than failing every\n // later command with the same decrypt error.\n if (code === 'EACCES' || code === 'EPERM') {\n logger.warn(`[harmonyos] Cannot read ${tokenPath}: ${permissionHint(authDir)}`);\n return null;\n }\n logger.debug(`[harmonyos] Discarding unreadable token at ${tokenPath}.`);\n try {\n fs.rmSync(tokenPath, { force: true });\n } catch {\n // Best effort.\n }\n return null;\n }\n },\n\n clear(): void {\n try {\n fs.rmSync(tokenPath, { force: true });\n } catch (err) {\n throw new OniroError(`Failed to remove ${tokenPath}.`, err);\n }\n },\n };\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/auth/login/login-service.ts`, `src/auth/utils/token-checker.ts`,\n * `src/auth/login/user-info-fetcher.ts`, `src/auth/team/team-service.ts`),\n * Copyright (c) 2026 Huawei Device Co., Ltd., licensed under the MIT License.\n * See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as crypto from 'node:crypto';\nimport type { ConfigProvider } from '../../ports/config.js';\nimport type { Logger } from '../../ports/logger.js';\nimport { noopLogger } from '../../ports/logger.js';\nimport { OniroError } from '../../ports/errors.js';\nimport { createHttpClient, describeResponse, type HarmonyOsHttpClient } from '../http.js';\nimport { createTokenStore, type TokenStore } from './tokenStore.js';\nimport {\n AGC_TEAMS_URL,\n AUTH_PATHS,\n HUAWEI_APP_ID,\n HUAWEI_API_VERSION,\n HUAWEI_SITES,\n LOGIN_TIMEOUT_MS,\n siteForId,\n type HuaweiSite,\n} from './endpoints.js';\nimport { startCallbackServer } from './callbackServer.js';\nimport { openBrowser } from './browser.js';\nimport type { AgcAuthInfo, DeveloperAgreementStatus, HuaweiTeam, HuaweiUserInfo } from './types.js';\n\nexport interface HarmonyOsSessionOptions {\n config: ConfigProvider;\n logger?: Logger;\n http?: HarmonyOsHttpClient;\n tokenStore?: TokenStore;\n /** Called with the sign-in URL before the browser opens, so a CLI can print it. */\n onLoginUrl?: (url: string) => void;\n}\n\nexport interface HarmonyOsSession {\n login(opts?: { timeoutMs?: number }): Promise<HuaweiUserInfo>;\n /** Resolves false when there was no session to end. */\n logout(): Promise<boolean>;\n /** The signed-in account, or null. `refresh` mints a fresh AGC access token. */\n getUserInfo(opts?: { refresh?: boolean }): Promise<HuaweiUserInfo | null>;\n listTeams(): Promise<HuaweiTeam[]>;\n /** Credentials for AGC calls. Throws when signed out, or when the account may not sign. */\n resolveAgcAuth(opts?: { teamId?: string }): Promise<AgcAuthInfo>;\n /** Whether the account accepted the developer agreement; null when undeterminable. */\n getDeveloperAgreement(user: HuaweiUserInfo): Promise<DeveloperAgreementStatus | null>;\n readonly tokenPath: string;\n}\n\n/** Response of `jwToken/check`. */\ninterface TokenCheckResponse {\n status?: boolean;\n userInfo?: { accessToken?: string; userId?: string; name?: string; nationalCode?: string; realName?: unknown };\n}\n\nconst NOT_SIGNED_IN = 'Not signed in. Run `oniro-app auth login` first.';\n\nexport function createHarmonyOsSession(opts: HarmonyOsSessionOptions): HarmonyOsSession {\n const logger = opts.logger ?? noopLogger;\n const http = opts.http ?? createHttpClient({ logger });\n const store = opts.tokenStore ?? createTokenStore({ config: opts.config, logger });\n\n /** Exchange the browser's short-lived temp token for the durable JWT. */\n async function exchangeTempToken(site: HuaweiSite, tempToken: string): Promise<string> {\n const response = await http.get(`${site.loginUrl}/${AUTH_PATHS.TEMP_TOKEN_CHECK}`, {\n query: {\n // The page sometimes appends extra `&`-joined parameters to the token.\n tempToken: tempToken.split('&')[0],\n site: site.siteParam,\n version: HUAWEI_API_VERSION,\n appid: HUAWEI_APP_ID,\n },\n });\n const jwtToken = response.data.trim();\n if (response.statusCode === 200 && /^[^.]+\\.[^.]+\\.[^.]+$/.test(jwtToken)) return jwtToken;\n\n // Any token the endpoint will not redeem — expired, reused, or sent to the\n // wrong region — gets the same empty 200, so there is no reason to report.\n throw new OniroError(\n `${site.loginUrl} would not exchange the login token for a session (${describeResponse(response)}). ` +\n 'Login tokens are single-use and short-lived; run `oniro-app auth login` again.',\n );\n }\n\n /** Validate the JWT with its region; null when it is no longer valid. */\n async function userFromJwt(site: HuaweiSite, jwtToken: string, refresh: boolean): Promise<HuaweiUserInfo | null> {\n const response = await http.get(`${site.loginUrl}/${AUTH_PATHS.JWT_TOKEN_CHECK}`, {\n headers: { refresh: String(refresh), jwtToken },\n });\n let info: TokenCheckResponse;\n try {\n if (response.statusCode !== 200) throw new Error();\n info = JSON.parse(response.data) as TokenCheckResponse;\n } catch {\n throw new OniroError(`Could not validate the session with ${site.loginUrl} (${describeResponse(response)}).`);\n }\n const user = info.userInfo;\n if (!info.status || !user?.accessToken) return null;\n return {\n userId: user.userId ?? '',\n userName: user.name ?? '',\n accessToken: user.accessToken,\n countryCode: user.nationalCode ?? '',\n siteCode: site.code,\n isRealName: String(user.realName) === 'true',\n };\n }\n\n async function getUserInfo(o: { refresh?: boolean } = {}): Promise<HuaweiUserInfo | null> {\n const stored = store.load();\n const site = stored && siteForId(stored.siteId);\n const user = site ? await userFromJwt(site, stored.jwtToken, o.refresh ?? false) : null;\n if (stored && !user) {\n logger.debug('[harmonyos] The stored session is no longer valid; clearing it.');\n store.clear();\n }\n return user;\n }\n\n async function requireUser(): Promise<HuaweiUserInfo> {\n const user = await getUserInfo({ refresh: true });\n if (!user) throw new OniroError(NOT_SIGNED_IN);\n return user;\n }\n\n async function getDeveloperAgreement(user: HuaweiUserInfo): Promise<DeveloperAgreementStatus | null> {\n try {\n const response = await http.get(`${HUAWEI_SITES[user.siteCode].loginUrl}/${AUTH_PATHS.UNREALNAME_AGREEMENT}`, {\n headers: { accessToken: user.accessToken },\n });\n const payload = JSON.parse(response.data) as {\n success?: unknown;\n body?: { signedFlag?: unknown; signLastestFlag?: unknown };\n };\n if (response.statusCode !== 200 || String(payload.success) !== 'true' || !payload.body) return null;\n return { signed: payload.body.signedFlag === true, latest: payload.body.signLastestFlag === true };\n } catch {\n return null;\n }\n }\n\n return {\n tokenPath: store.tokenPath,\n getUserInfo,\n getDeveloperAgreement,\n\n async login(o = {}): Promise<HuaweiUserInfo> {\n // Sign-in starts on the Chinese-mainland page, which redirects every account to\n // its own region's; the callback then reports which region that was.\n const start = HUAWEI_SITES.CN.loginUrl;\n const clientSecret = crypto.randomUUID().replace(/-/g, '');\n const server = await startCallbackServer({\n clientSecret,\n baseUrl: start,\n successPath: AUTH_PATHS.LOGIN_SUCCESS,\n failedPath: AUTH_PATHS.LOGIN_FAILED,\n });\n\n try {\n const loginUrl = `${start}/${AUTH_PATHS.AUTH_APPLY}?port=${server.port}&appid=${HUAWEI_APP_ID}&code=${clientSecret}`;\n opts.onLoginUrl?.(loginUrl);\n // Not awaited: some launchers exit only when the browser does.\n openBrowser(loginUrl).catch((err: Error) => {\n // Headless hosts have no browser; the URL was surfaced via onLoginUrl.\n logger.warn(`[harmonyos] Could not open a browser automatically: ${err.message}`);\n });\n\n const callback = await server.waitForCallback(o.timeoutMs ?? LOGIN_TIMEOUT_MS);\n const site = siteForId(callback.siteId);\n if (!site) {\n throw new OniroError(`The account belongs to a Huawei region oniro-app does not know (siteId ${callback.siteId}).`);\n }\n\n const jwtToken = await exchangeTempToken(site, callback.tempToken);\n const user = await userFromJwt(site, jwtToken, false);\n if (!user) throw new OniroError('Login did not yield a usable session. Try again.');\n store.save({ jwtToken, siteId: site.siteId });\n logger.info(`[harmonyos] Signed in as ${user.userName || user.userId} (${site.code}).`);\n return user;\n } finally {\n await server.stop();\n }\n },\n\n async logout(): Promise<boolean> {\n const stored = store.load();\n if (!stored) return false;\n const site = siteForId(stored.siteId);\n try {\n if (site) {\n await http.post(`${site.loginUrl}/${AUTH_PATHS.LOGOUT}`, {\n query: { jwtToken: stored.jwtToken },\n timeoutMs: 5_000,\n });\n }\n } catch {\n // Telling the server is best effort; clearing locally is what signs out here.\n } finally {\n store.clear();\n }\n return true;\n },\n\n async listTeams(): Promise<HuaweiTeam[]> {\n const user = await requireUser();\n const response = await http.get(AGC_TEAMS_URL, {\n headers: {\n oauth2Token: user.accessToken,\n uid: user.userId,\n source: 'cli',\n lang: HUAWEI_SITES[user.siteCode].language,\n },\n timeoutMs: 15_000,\n });\n if (response.statusCode === 401) {\n throw new OniroError('The session has expired. Run `oniro-app auth login` again.');\n }\n if (response.statusCode !== 200) {\n throw new OniroError(`Could not list AGC teams (${describeResponse(response)}).`);\n }\n return parseTeamList(response.data);\n },\n\n async resolveAgcAuth(o: { teamId?: string } = {}): Promise<AgcAuthInfo> {\n const user = await requireUser();\n // Real-name verification is not required: like DevEco Studio, an unverified\n // account — the norm outside the Chinese mainland — may sign once it has\n // accepted the developer agreement. Studio accepts it from a dialog; a CLI\n // must not accept legal terms silently, so it only checks.\n if (!user.isRealName) {\n const agreement = await getDeveloperAgreement(user);\n if (agreement && !(agreement.signed && agreement.latest)) {\n throw new OniroError(\n 'This Huawei account has not accepted the current HUAWEI Developer Basic Service Agreement, which ' +\n 'accounts without real-name verification need before AppGallery Connect issues signing material. ' +\n 'Accept it in AppGallery Connect (https://developer.huawei.com/consumer/en/service/josp/agc/index.html) ' +\n 'or by running automatic signing once in DevEco Studio, then try again.',\n );\n }\n // When the status cannot be read, AGC is the authority and refuses by itself.\n }\n return {\n uid: user.userId,\n // Personal accounts sign under their own user id; `--team-id` picks another team.\n teamId: o.teamId ?? user.userId,\n accessToken: user.accessToken,\n baseUrl: HUAWEI_SITES[user.siteCode].agcBaseUrl,\n };\n },\n };\n}\n\n/**\n * Parse the AGC team list. Failures arrive as HTTP 200 with a non-zero `ret.code`.\n *\n * @internal exposed for tests.\n */\nexport function parseTeamList(body: string): HuaweiTeam[] {\n let payload: { ret?: { code?: number; msg?: string }; teams?: unknown };\n try {\n payload = JSON.parse(body);\n } catch {\n return [];\n }\n if (payload.ret && payload.ret.code !== 0) {\n throw new OniroError(\n `AppGallery Connect refused the team list (code ${payload.ret.code}${payload.ret.msg ? `: ${payload.ret.msg}` : ''}).`,\n );\n }\n if (!Array.isArray(payload.teams)) return [];\n return payload.teams\n .map((t: { id?: unknown; name?: unknown }) => ({ id: String(t?.id ?? ''), name: String(t?.name ?? '') }))\n .filter((t) => t.id);\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/utils/http-client.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport { EnvHttpProxyAgent, fetch, type Response } from 'undici';\nimport type { Logger } from '../ports/logger.js';\nimport { noopLogger } from '../ports/logger.js';\nimport { OniroError } from '../ports/errors.js';\n\n/**\n * Upstream's request headers, kept identical: these are private endpoints, and\n * matching the client they were built for removes one variable when they misbehave.\n */\nconst DEFAULT_HEADERS = {\n 'user-agent':\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',\n 'accept-language': 'zh-CN',\n accept: 'application/json, text/plain, */*',\n};\n\nconst DEFAULT_TIMEOUT_MS = 20_000;\n\nexport interface HttpResponse {\n /** Body as text. Several endpoints send JSON under a non-JSON content type. */\n data: string;\n statusCode: number;\n /** Reason phrase. Some AGC errors are reported only here. Empty over HTTP/2. */\n statusText: string;\n}\n\nexport interface HttpRequestOptions {\n headers?: Record<string, string>;\n query?: Record<string, unknown>;\n /** Sent as JSON. */\n body?: unknown;\n timeoutMs?: number;\n}\n\n/**\n * `get`, `post` and `delete` resolve for any HTTP status: AGC reports failures\n * through the status, the reason phrase and the body, so callers read all three.\n * `getBinary` is for downloads and rejects on a non-2xx status.\n */\nexport interface HarmonyOsHttpClient {\n get(url: string, opts?: HttpRequestOptions): Promise<HttpResponse>;\n post(url: string, opts?: HttpRequestOptions): Promise<HttpResponse>;\n delete(url: string, opts?: HttpRequestOptions): Promise<HttpResponse>;\n getBinary(url: string, opts?: HttpRequestOptions): Promise<Buffer>;\n}\n\n/** Query parameters that carry credentials for the user's Huawei account. */\nconst SENSITIVE_PARAMS = new Set(['temptoken', 'jwttoken', 'code', 'oauth2token', 'accesstoken']);\n\n/**\n * A log-safe form of a URL: credential-bearing query values become `***`.\n *\n * @internal exposed for tests.\n */\nexport function redactUrl(url: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return url;\n }\n for (const key of [...parsed.searchParams.keys()]) {\n if (SENSITIVE_PARAMS.has(key.toLowerCase())) parsed.searchParams.set(key, '***');\n }\n return parsed.toString();\n}\n\n/**\n * A short, log-safe preview of a response body. Suppressed entirely when it looks\n * like a bare JWT, so a credential cannot leak into an error message.\n *\n * @internal exposed for tests.\n */\nexport function previewBody(body: string, limit = 300): string {\n const trimmed = body.trim();\n if (!trimmed) return '(empty body)';\n if (/^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/.test(trimmed)) return '(a token-shaped value)';\n const collapsed = trimmed.replace(/\\s+/g, ' ');\n return collapsed.length > limit ? `${collapsed.slice(0, limit)}…` : collapsed;\n}\n\n/** `HTTP 500 Internal Server Error: <body preview>`, for error messages. */\nexport function describeResponse(response: HttpResponse): string {\n const status = `HTTP ${response.statusCode}${response.statusText ? ` ${response.statusText}` : ''}`;\n return `${status}: ${previewBody(response.data)}`;\n}\n\nfunction buildUrl(url: string, query?: Record<string, unknown>): string {\n if (!query) return url;\n const parsed = new URL(url);\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== null) parsed.searchParams.set(key, String(value));\n }\n return parsed.toString();\n}\n\n/** The HTTP client for the HarmonyOS auth and signing flows. */\nexport function createHttpClient(opts: { logger?: Logger } = {}): HarmonyOsHttpClient {\n const logger = opts.logger ?? noopLogger;\n // Node's own fetch ignores HTTPS_PROXY / HTTP_PROXY / NO_PROXY; this agent honours them.\n const dispatcher = new EnvHttpProxyAgent();\n\n async function send(method: string, url: string, options: HttpRequestOptions): Promise<Response> {\n const target = buildUrl(url, options.query);\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const headers: Record<string, string> = { ...DEFAULT_HEADERS, ...options.headers };\n let body: string | undefined;\n if (options.body !== undefined) {\n body = JSON.stringify(options.body);\n headers['content-type'] = 'application/json';\n }\n\n // The query string can carry credentials, so only the redacted URL is logged.\n logger.debug(`[harmonyos] ${method} ${redactUrl(target)}`);\n try {\n return await fetch(target, {\n method,\n headers,\n body,\n signal: AbortSignal.timeout(timeoutMs),\n dispatcher,\n });\n } catch (err) {\n const reason =\n err instanceof Error && err.name === 'TimeoutError'\n ? `timed out after ${timeoutMs}ms`\n : err instanceof Error\n ? err.message\n : String(err);\n throw new OniroError(\n `${method} ${redactUrl(target)} failed: ${reason}. ` +\n 'Check the network connection and any proxy configuration (HTTPS_PROXY / HTTP_PROXY).',\n err,\n );\n }\n }\n\n async function request(method: string, url: string, options: HttpRequestOptions = {}): Promise<HttpResponse> {\n const response = await send(method, url, options);\n return { data: await response.text(), statusCode: response.status, statusText: response.statusText };\n }\n\n return {\n get: (url, o) => request('GET', url, o),\n post: (url, o) => request('POST', url, o),\n delete: (url, o) => request('DELETE', url, o),\n async getBinary(url, o = {}) {\n const response = await send('GET', url, o);\n if (!response.ok) {\n throw new OniroError(`Download of ${redactUrl(response.url || url)} failed (HTTP ${response.status}).`);\n }\n return Buffer.from(await response.arrayBuffer());\n },\n };\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/auth/login/local-auth-server.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as http from 'node:http';\nimport * as crypto from 'node:crypto';\nimport type { AddressInfo } from 'node:net';\nimport { CancelledError, OniroError } from '../../ports/errors.js';\n\n/** What the login page hands back once the user has signed in. */\nexport interface LoginCallback {\n tempToken: string;\n /** The account's region; see `siteForId`. */\n siteId: string;\n}\n\nconst CALLBACK_PATH = '/callback';\nconst MAX_BODY_BYTES = 65_536;\n\nexport interface CallbackServer {\n /** Port the loopback listener bound to. Handed to the login page as `?port=`. */\n readonly port: number;\n /** Resolves with the browser's callback, including one that arrived before this was called. */\n waitForCallback(timeoutMs: number): Promise<LoginCallback>;\n stop(): Promise<void>;\n}\n\n/**\n * Constant-time compare of the `code` parameter against the secret this process\n * generated. Without it any local page could POST a token of its own choosing to\n * the loopback port while a login is in flight.\n */\nfunction codeMatches(code: string | null, secret: string): boolean {\n const a = Buffer.from(code ?? '', 'utf8');\n const b = Buffer.from(secret, 'utf8');\n return a.length === b.length && crypto.timingSafeEqual(a, b);\n}\n\nfunction isQuit(quit: string | null): boolean {\n return quit === 'true' || quit === 'access_denied' || quit === 'quit';\n}\n\nexport interface StartCallbackServerOptions {\n /** Secret echoed back by the login page; proves the callback is ours. */\n clientSecret: string;\n /** Host the browser is redirected to after the callback is handled. */\n baseUrl: string;\n successPath: string;\n failedPath: string;\n}\n\n/**\n * Start a loopback HTTP server that receives the browser's login callback.\n *\n * Bound to 127.0.0.1 on an OS-assigned port: the login page is told which port\n * to redirect to, so nothing needs to be reserved or configured.\n */\nexport async function startCallbackServer(\n opts: StartCallbackServerOptions,\n): Promise<CallbackServer> {\n // Settled by the first valid callback, whenever it arrives: the browser can come\n // back before anyone is waiting for it.\n let resolveCallback!: (value: LoginCallback) => void;\n let rejectCallback!: (reason: Error) => void;\n const callback = new Promise<LoginCallback>((resolve, reject) => {\n resolveCallback = resolve;\n rejectCallback = reject;\n });\n // A cancellation nobody waits for yet must not surface as an unhandled rejection.\n callback.catch(() => {});\n\n const server = http.createServer((req, res) => {\n // Reject requests that did not address us by our own loopback authority —\n // cheap defence against DNS-rebinding onto the callback port.\n const host = (req.headers.host ?? '').toLowerCase();\n const port = (server.address() as AddressInfo | null)?.port;\n if (host !== `127.0.0.1:${port}` && host !== `localhost:${port}`) {\n res.writeHead(400);\n res.end('Bad Host');\n return;\n }\n\n const url = new URL(req.url ?? '', `http://${host}`);\n if (url.pathname !== CALLBACK_PATH) {\n res.writeHead(404);\n res.end('Not Found');\n return;\n }\n\n const finish = (params: URLSearchParams) => {\n if (!codeMatches(params.get('code'), opts.clientSecret)) {\n res.writeHead(400);\n res.end('Bad Request');\n return;\n }\n if (isQuit(params.get('quit'))) {\n res.writeHead(302, { Location: `${opts.baseUrl}/${opts.failedPath}` });\n res.end();\n rejectCallback(new CancelledError('Login was cancelled in the browser.'));\n return;\n }\n const tempToken = params.get('tempToken');\n const siteId = params.get('siteId');\n if (!tempToken || !siteId) {\n res.writeHead(400);\n res.end('Bad Request');\n return;\n }\n res.writeHead(302, { Location: `${opts.baseUrl}/${opts.successPath}` });\n res.end();\n resolveCallback({ tempToken, siteId });\n };\n\n if (req.method === 'POST') {\n let body = '';\n let size = 0;\n req.on('data', (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_BODY_BYTES) {\n req.destroy(new Error('Request body too large'));\n return;\n }\n body += chunk.toString();\n });\n req.on('end', () => finish(body.trim() ? new URLSearchParams(body) : url.searchParams));\n } else {\n finish(url.searchParams);\n }\n });\n\n // Keep-alive would hold the process open after the single callback we care about.\n server.keepAliveTimeout = 1;\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', (err) => reject(new OniroError('Failed to start the local login callback server.', err)));\n server.listen(0, '127.0.0.1', resolve);\n });\n\n const port = (server.address() as AddressInfo).port;\n\n return {\n port,\n\n waitForCallback(timeoutMs: number): Promise<LoginCallback> {\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new OniroError(`Timed out after ${Math.round(timeoutMs / 1000)}s waiting for the browser login to complete.`)),\n timeoutMs,\n );\n });\n return Promise.race([callback, timeout]).finally(() => clearTimeout(timer));\n },\n\n stop(): Promise<void> {\n return new Promise<void>((resolve) => {\n server.closeAllConnections?.();\n // The browser may still be holding the redirect response; do not let a slow\n // client keep the CLI alive.\n const timer = setTimeout(resolve, 100);\n server.close(() => {\n clearTimeout(timer);\n resolve();\n });\n });\n },\n };\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/auth/login/browser.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport { spawn } from 'node:child_process';\nimport { OniroError } from '../../ports/errors.js';\n\nfunction isSafeUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return ['http:', 'https:'].includes(parsed.protocol) && parsed.hostname !== '' && !url.includes('\"');\n } catch {\n return false;\n }\n}\n\n/** `start` on Windows goes through cmd, where these are shell metacharacters. */\nfunction escapeForCmd(s: string): string {\n return s.replace(/[&|<>()^%!]/g, (c) => `^${c}`);\n}\n\n/**\n * Open `url` in the user's default browser. Resolves once the launcher exits\n * successfully.\n *\n * Some launchers (`xdg-open` without a desktop environment, `$BROWSER`) only exit\n * when the browser does, so callers should not wait on this before carrying on;\n * the launcher is detached so it neither keeps this process alive nor dies with it.\n * Headless environments (CI, a remote shell) have no browser to open; the caller\n * is expected to print the URL as well so the user can open it themselves.\n */\nexport function openBrowser(url: string): Promise<void> {\n if (!isSafeUrl(url)) {\n return Promise.reject(new OniroError(`Refusing to open unsafe URL: ${JSON.stringify(url)}`));\n }\n\n const [command, args] =\n process.platform === 'win32'\n ? ['cmd', ['/c', 'start', '\"\"', escapeForCmd(url)]]\n : process.platform === 'darwin'\n ? ['open', [url]]\n : ['xdg-open', [url]];\n\n const child = spawn(command as string, args as string[], {\n stdio: 'ignore',\n shell: false,\n detached: true,\n windowsHide: true,\n });\n child.unref();\n\n return new Promise<void>((resolve, reject) => {\n child.on('error', (err) => reject(new OniroError(`Failed to open a browser (${command}).`, err)));\n child.on('exit', (code) =>\n code === 0 ? resolve() : reject(new OniroError(`Browser launcher '${command}' exited with code ${code}.`)),\n );\n });\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/config/signature.ts`, `src/signature/cert-api.ts`,\n * `src/signature/device-manager.ts`, `src/signature/generate-profile.ts`),\n * Copyright (c) 2026 Huawei Device Co., Ltd., licensed under the MIT License.\n * See packages/core/src/harmonyos/NOTICE.md.\n */\nimport { OniroError } from '../../ports/errors.js';\n\n/** Raised when AppGallery Connect rejects a request, or its output does not check out. */\nexport class AgcError extends OniroError {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly retCode?: string,\n ) {\n super(message);\n this.name = 'AgcError';\n }\n}\n\n/** User-facing messages for the signing failure modes; each says what to do next. */\nexport const SIGNING_ERRORS = {\n FORBIDDEN:\n 'This account has no AppGallery Connect permission for the selected team. Ask the team administrator for access, or pass --team-id for a team you do have access to (`oniro-app auth team list`).',\n UNAUTHORIZED: 'AppGallery Connect rejected the access token. Run `oniro-app auth login` again.',\n NETWORK:\n 'Could not reach AppGallery Connect. Check the network connection and any proxy configuration (HTTPS_PROXY / HTTP_PROXY).',\n USER_NOT_HARMONY:\n 'This Huawei account is not enrolled for HarmonyOS development. Request HarmonyOS access for it in AppGallery Connect.',\n CERT_REQUEST: 'AppGallery Connect did not issue the debug certificate.',\n CERT_LIMIT:\n 'This team has reached its debug-certificate limit. Delete an unused certificate in AppGallery Connect and retry.',\n DEVICE_ADD: 'AppGallery Connect did not register the device.',\n DEVICE_LIMIT: 'This team has reached its device limit. Remove an unused device in AppGallery Connect and retry.',\n DEVICE_NAME_REPEAT: 'A device with that name is already registered. Retry.',\n DEVICE_NONE:\n 'No device is connected and none is registered to this team, but a debug profile must name at least one. Connect a device and retry.',\n PROFILE_ADD: 'AppGallery Connect did not issue the provisioning profile.',\n PROFILE_NAME_REPEAT: 'A provisioning profile with that name already exists in AppGallery Connect. Retry.',\n PROVISION_LIMIT:\n 'This team has reached its debug-profile limit. Delete unused profiles in AppGallery Connect and retry.',\n CERT_INVALID: 'AppGallery Connect returned an unreadable certificate. Retry with --force.',\n CERT_EXPIRED: 'The signing certificate is outside its validity window. Check the system clock, then retry with --force.',\n CERT_PROFILE_MISMATCH:\n 'The provisioning profile was not issued for the downloaded certificate. Retry with --force.',\n KEYSTORE_CERT_MISMATCH:\n 'The local keystore does not hold the key the downloaded certificate was issued for. Retry with --force.',\n BUNDLE_NAME_INVALID:\n 'Invalid bundle name. It must be 7–128 characters, start with a letter, and have at least three dot-separated segments (for example com.example.app).',\n} as const;\n\n/** AGC `ret.code` values that have a specific remedy. */\nconst RET_CODE_ERRORS: Readonly<Record<string, string>> = {\n '205389872': SIGNING_ERRORS.CERT_LIMIT,\n '205389904': SIGNING_ERRORS.USER_NOT_HARMONY,\n '205389859': SIGNING_ERRORS.DEVICE_LIMIT,\n '205389857': SIGNING_ERRORS.DEVICE_NAME_REPEAT,\n '205389938': SIGNING_ERRORS.PROVISION_LIMIT,\n '205389830': SIGNING_ERRORS.PROFILE_NAME_REPEAT,\n};\n\n/** Reason phrase of the 403 Huawei's proxy answers with when it blocks the caller. */\nconst PROXY_BLOCKED = 'Openproxy_Blocked_URL_list';\n\n/** The `ret` envelope around every AGC response. It is occasionally a JSON string itself. */\nexport function readRet(body: string): { code?: unknown; msg?: unknown } | null {\n try {\n let ret = (JSON.parse(body) as { ret?: unknown }).ret;\n if (typeof ret === 'string') ret = JSON.parse(ret);\n return ret && typeof ret === 'object' ? (ret as { code?: unknown; msg?: unknown }) : null;\n } catch {\n return null;\n }\n}\n\nexport type AgcOperation = 'cert' | 'device' | 'profile';\n\nconst FALLBACK: Record<AgcOperation, string> = {\n cert: SIGNING_ERRORS.CERT_REQUEST,\n device: SIGNING_ERRORS.DEVICE_ADD,\n profile: SIGNING_ERRORS.PROFILE_ADD,\n};\n\n/**\n * Map an AGC failure onto an actionable error. AGC fails through the HTTP status,\n * the reason phrase, or a non-zero `ret.code` under HTTP 200; all three are read.\n */\nexport function mapAgcError(\n operation: AgcOperation,\n statusCode: number | undefined,\n reasonPhrase: string,\n body: string,\n): AgcError {\n if (statusCode === 403) {\n return new AgcError(reasonPhrase === PROXY_BLOCKED ? SIGNING_ERRORS.NETWORK : SIGNING_ERRORS.FORBIDDEN, 403);\n }\n if (statusCode === 401) return new AgcError(SIGNING_ERRORS.UNAUTHORIZED, 401);\n\n const ret = readRet(body);\n const retCode = ret?.code === undefined ? undefined : String(ret.code);\n const msg = typeof ret?.msg === 'string' && ret.msg.trim() ? ret.msg : undefined;\n return new AgcError((retCode && RET_CODE_ERRORS[retCode]) || msg || FALLBACK[operation], statusCode, retCode);\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/signature/generate-profile.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as fs from 'node:fs';\nimport { X509Certificate } from 'node:crypto';\nimport forge from 'node-forge';\nimport { AgcError, SIGNING_ERRORS } from './errors.js';\n\n/** The fields of a provisioning profile that decide whether it can be reused. */\nexport interface ProvisionProfileInfo {\n bundleName?: string;\n /** The AGC team the profile was issued to. */\n developerId?: string;\n notAfter?: Date;\n /** Uppercased UDIDs the debug profile is valid for. */\n deviceIds: string[];\n aclPermissions: string[];\n /** PEM of the certificate the profile was issued for. */\n developmentCertificate?: string;\n}\n\n/**\n * The JSON payload of a `.p7b` profile. The file is PKCS#7 signed data carrying\n * the JSON in the clear, so it is found by scanning for the balanced object that\n * has `bundle-info` — node-forge cannot parse the EC certificates around it.\n *\n * @internal exposed for tests.\n */\nexport function extractProfileJson(buffer: Buffer): string | null {\n const text = buffer.toString('latin1');\n for (let start = text.indexOf('{'); start !== -1; start = text.indexOf('{', start + 1)) {\n let depth = 0;\n let inString = false;\n let escaped = false;\n for (let i = start; i < text.length; i++) {\n const ch = text[i]!;\n if (escaped) escaped = false;\n else if (inString) {\n if (ch === '\\\\') escaped = true;\n else if (ch === '\"') inString = false;\n } else if (ch === '\"') inString = true;\n else if (ch === '{') depth++;\n else if (ch === '}' && --depth === 0) {\n // The payload is UTF-8; re-decode so non-ASCII survives.\n const json = Buffer.from(text.slice(start, i + 1), 'latin1').toString('utf8');\n try {\n if ('bundle-info' in (JSON.parse(json) as object)) return json;\n } catch {\n // Some other brace pair in the binary framing; keep scanning.\n }\n break;\n }\n }\n }\n return null;\n}\n\n/** Read a `.p7b` profile; null when it is missing or unreadable, which means \"regenerate\". */\nexport function readProvisionProfile(profilePath: string): ProvisionProfileInfo | null {\n let raw: {\n validity?: { 'not-after'?: unknown };\n 'bundle-info'?: { 'bundle-name'?: unknown; 'developer-id'?: unknown; 'development-certificate'?: unknown };\n 'debug-info'?: { 'device-ids'?: unknown };\n acls?: { 'allowed-acls'?: unknown };\n };\n try {\n const json = extractProfileJson(fs.readFileSync(profilePath));\n if (!json) return null;\n raw = JSON.parse(json);\n } catch {\n return null;\n }\n const str = (v: unknown) => (typeof v === 'string' ? v : undefined);\n const strings = (v: unknown) => (Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : []);\n const notAfter = raw.validity?.['not-after'];\n const bundle = raw['bundle-info'] ?? {};\n return {\n bundleName: str(bundle['bundle-name']),\n developerId: str(bundle['developer-id']),\n // Epoch seconds.\n notAfter: typeof notAfter === 'number' ? new Date(notAfter * 1000) : undefined,\n deviceIds: strings(raw['debug-info']?.['device-ids']).map((d) => d.toUpperCase()),\n aclPermissions: strings(raw.acls?.['allowed-acls']),\n developmentCertificate: str(bundle['development-certificate']),\n };\n}\n\nfunction parseCertificate(pem: string): X509Certificate {\n try {\n return new X509Certificate(pem);\n } catch {\n throw new AgcError(SIGNING_ERRORS.CERT_INVALID);\n }\n}\n\n/**\n * Whether the p12 holds the key `certificate` certifies, by comparing public keys.\n *\n * node-forge reads the PKCS#12 container, which Node cannot. Not the certificate\n * inside it, though: forge parses only RSA certificates, and hap-sign-tool makes\n * ECC keys, so forge hands back the raw ASN.1 for Node's X.509 parser. Any read\n * failure, a wrong password included, is \"no\".\n *\n * @internal exposed for tests.\n */\nexport function keystoreHoldsKey(\n p12Path: string,\n keyAlias: string,\n keyPwd: string,\n certificate: X509Certificate,\n): boolean {\n try {\n const der = forge.util.createBuffer(fs.readFileSync(p12Path).toString('binary'));\n const p12 = forge.pkcs12.pkcs12FromAsn1(forge.asn1.fromDer(der), keyPwd);\n const certBag = forge.pki.oids.certBag ?? '1.2.840.113549.1.12.10.1.3';\n const wanted = certificate.publicKey.export({ type: 'spki', format: 'der' });\n return (p12.getBags({ bagType: certBag })[certBag] ?? []).some((bag) => {\n if (bag.attributes?.friendlyName?.[0]?.toLowerCase() !== keyAlias.toLowerCase()) return false;\n const asn1 = bag.cert ? forge.pki.certificateToAsn1(bag.cert) : bag.asn1;\n if (!asn1) return false;\n const bagCert = new X509Certificate(Buffer.from(forge.asn1.toDer(asn1).getBytes(), 'binary'));\n return bagCert.publicKey.export({ type: 'spki', format: 'der' }).equals(wanted);\n });\n } catch {\n return false;\n }\n}\n\n/**\n * Check that the downloaded certificate chain is in date, that the profile was\n * issued for its leaf certificate, and that the keystore holds the certified key.\n * A mismatch here would otherwise surface much later, as an install failure.\n */\nexport function verifySigningMaterial(opts: {\n profilePath: string;\n cerPath: string;\n p12Path: string;\n keyAlias: string;\n keyPwd: string;\n now?: Date;\n}): void {\n const pems = fs.readFileSync(opts.cerPath, 'utf8').match(/-----BEGIN CERTIFICATE-----[\\s\\S]*?-----END CERTIFICATE-----/g);\n const chain = (pems ?? []).map(parseCertificate);\n const leaf = chain.find((c) => !c.ca) ?? chain.at(-1);\n if (!leaf) throw new AgcError(SIGNING_ERRORS.CERT_INVALID);\n\n const now = opts.now ?? new Date();\n if (chain.some((c) => now < new Date(c.validFrom) || now > new Date(c.validTo))) {\n throw new AgcError(SIGNING_ERRORS.CERT_EXPIRED);\n }\n\n const issuedFor = readProvisionProfile(opts.profilePath)?.developmentCertificate;\n if (!issuedFor || parseCertificate(issuedFor).fingerprint256 !== leaf.fingerprint256) {\n throw new AgcError(SIGNING_ERRORS.CERT_PROFILE_MISMATCH);\n }\n if (!keystoreHoldsKey(opts.p12Path, opts.keyAlias, opts.keyPwd, leaf)) {\n throw new AgcError(SIGNING_ERRORS.KEYSTORE_CERT_MISMATCH);\n }\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/commands/signature.ts`, `src/signature/generate-certificate.ts`,\n * `src/signature/re-generate-sign.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport JSON5 from 'json5';\nimport type { ConfigProvider } from '../../ports/config.js';\nimport type { Logger } from '../../ports/logger.js';\nimport { noopLogger } from '../../ports/logger.js';\nimport { OniroError } from '../../ports/errors.js';\nimport { createMaterial, encryptPwd, getKey } from '../../sign/encryptKey.js';\nimport { getBundleName } from '../../hdc/project.js';\nimport { isValidBundleName } from '../../project/validators.js';\nimport { createHttpClient, type HarmonyOsHttpClient } from '../http.js';\nimport { requireHarmonyOsSdk } from '../sdk.js';\nimport type { HarmonyOsSession } from '../auth/session.js';\nimport { createAgcClient } from './agc.js';\nimport { collectLocalDevices, registerDevices } from './devices.js';\nimport { AgcError, SIGNING_ERRORS } from './errors.js';\nimport { KEY_ALIAS, SIGN_ALG, generateKeystoreAndCsr } from './keystore.js';\nimport { resolveSigningMaterialPaths, type SigningMaterialPaths } from './paths.js';\nimport { readProvisionProfile, verifySigningMaterial } from './profile.js';\nimport { collectAclPermissions } from './project.js';\n\ninterface BuildProfile {\n app?: {\n signingConfigs?: Array<{ name?: string; type?: string; material?: Record<string, string> }>;\n products?: Array<{ name?: string; signingConfig?: string; bundleName?: string }>;\n };\n}\n\n/**\n * Why the existing material cannot be reused, or null when it can. Reuse matters:\n * every regeneration spends a slot of the team's small certificate quota.\n *\n * @internal exposed for tests.\n */\nexport function shouldRegenerate(input: {\n paths: SigningMaterialPaths;\n buildProfile: BuildProfile;\n productName: string;\n bundleName: string;\n teamId: string;\n connectedUdids: string[];\n aclPermissions: string[];\n force?: boolean;\n now?: Date;\n}): string | null {\n if (input.force) return '--force was passed';\n const missing = Object.values(input.paths).find((file) => !fs.existsSync(file));\n if (missing) return `${missing} is missing`;\n\n // The keystore password only exists, encrypted, in the project's signingConfig; a\n // fresh checkout reusing the material from ~/.ohos/config cannot recover it.\n const config = input.buildProfile.app?.signingConfigs?.find((c) => c.name === input.productName);\n if (config?.type !== 'HarmonyOS' || config.material?.profile !== input.paths.profilePath) {\n return 'build-profile.json5 has no signingConfig for this material';\n }\n\n const profile = readProvisionProfile(input.paths.profilePath);\n if (!profile) return 'the provisioning profile could not be read';\n if (profile.bundleName !== input.bundleName) return `the profile is for bundle '${profile.bundleName}'`;\n if (profile.developerId && profile.developerId !== input.teamId) {\n return `the profile was issued to team '${profile.developerId}'`;\n }\n if (profile.notAfter && profile.notAfter <= (input.now ?? new Date())) return 'the profile has expired';\n const unnamed = input.connectedUdids.filter((udid) => !profile.deviceIds.includes(udid.toUpperCase()));\n if (unnamed.length > 0) return `${unnamed.length} connected device(s) are not named in the profile`;\n const acls = input.aclPermissions.filter((p) => !profile.aclPermissions.includes(p));\n if (acls.length > 0) return `the profile lacks ACL permission(s) ${acls.join(', ')}`;\n return null;\n}\n\n/**\n * Point `productName` at a HarmonyOS signingConfig for `paths`, replacing any config\n * of that name and leaving every other one alone. The keystore and key share one\n * password, so one ciphertext serves both.\n *\n * @internal exposed for tests.\n */\nexport function writeSigningConfig(opts: {\n buildProfilePath: string;\n buildProfile: BuildProfile;\n productName: string;\n paths: SigningMaterialPaths;\n encryptedPassword: string;\n}): void {\n const app = (opts.buildProfile.app ??= {});\n const entry = {\n name: opts.productName,\n // `type` is what makes hvigor treat this as HarmonyOS signing material.\n type: 'HarmonyOS',\n material: {\n certpath: opts.paths.cerPath,\n keyAlias: KEY_ALIAS,\n keyPassword: opts.encryptedPassword,\n profile: opts.paths.profilePath,\n signAlg: SIGN_ALG,\n storeFile: opts.paths.p12Path,\n storePassword: opts.encryptedPassword,\n },\n };\n app.signingConfigs = [...(app.signingConfigs ?? []).filter((c) => c.name !== opts.productName), entry];\n for (const product of app.products ?? []) {\n if (product.name === opts.productName) product.signingConfig = opts.productName;\n }\n // Strict JSON, like the OpenHarmony signing path: still valid JSON5.\n fs.writeFileSync(opts.buildProfilePath, JSON.stringify(opts.buildProfile, null, 2));\n}\n\nexport interface HarmonyOsAutoSignOptions {\n config: ConfigProvider;\n session: HarmonyOsSession;\n projectDir: string;\n /** Default `default`. */\n productName?: string;\n /** AGC team. Defaults to the signed-in account's own id. */\n teamId?: string;\n /** Regenerate even when the existing material is still valid. */\n force?: boolean;\n http?: HarmonyOsHttpClient;\n logger?: Logger;\n}\n\nexport interface HarmonyOsSigningResult {\n bundleName: string;\n teamId: string;\n paths: SigningMaterialPaths;\n /** False when still-valid material was reused without asking AGC for anything. */\n regenerated: boolean;\n /** UDIDs the profile is valid for. */\n deviceIds: string[];\n}\n\n/**\n * Sign a HarmonyOS project with the signed-in Huawei developer account, the way\n * DevEco Studio's automatic signing does: generate a keystore and CSR, have AGC\n * issue a debug certificate, register connected devices, issue a debug profile\n * naming the team's devices, and write the encrypted signingConfig.\n */\nexport async function harmonyOsAutoSign(opts: HarmonyOsAutoSignOptions): Promise<HarmonyOsSigningResult> {\n const logger = opts.logger ?? noopLogger;\n const productName = opts.productName ?? 'default';\n const projectDir = path.resolve(opts.projectDir);\n const buildProfilePath = path.join(projectDir, 'build-profile.json5');\n\n let buildProfile: BuildProfile;\n try {\n buildProfile = JSON5.parse(fs.readFileSync(buildProfilePath, 'utf-8')) as BuildProfile;\n } catch (err) {\n throw new OniroError(`Could not read ${buildProfilePath}: ${(err as Error).message}`, err);\n }\n const product = buildProfile.app?.products?.find((p) => p.name === productName);\n if (!product) throw new OniroError(`${buildProfilePath} declares no product named '${productName}'.`);\n // A product may override the app's bundle name. Validated before anything reaches\n // AGC, so a bad name costs no certificate.\n const bundleName = product.bundleName || getBundleName(projectDir);\n if (!isValidBundleName(bundleName) || bundleName.split('.').length < 3 || bundleName.length < 7 || bundleName.length > 128) {\n throw new AgcError(SIGNING_ERRORS.BUNDLE_NAME_INVALID);\n }\n\n const sdk = requireHarmonyOsSdk({ config: opts.config, logger });\n const auth = await opts.session.resolveAgcAuth({ teamId: opts.teamId });\n const aclPermissions = collectAclPermissions(projectDir, logger);\n const paths = resolveSigningMaterialPaths(opts.config, productName, projectDir);\n logger.info(`[harmonyos] Signing ${bundleName} (product '${productName}', team ${auth.teamId}).`);\n\n const connected = await collectLocalDevices(opts.config, logger);\n const result = (regenerated: boolean): HarmonyOsSigningResult => ({\n bundleName,\n teamId: auth.teamId,\n paths,\n regenerated,\n deviceIds: readProvisionProfile(paths.profilePath)?.deviceIds ?? [],\n });\n\n const reason = shouldRegenerate({\n paths,\n buildProfile,\n productName,\n bundleName,\n teamId: auth.teamId,\n connectedUdids: connected.map((d) => d.udid),\n aclPermissions,\n force: opts.force,\n });\n if (!reason) {\n logger.info('[harmonyos] Reusing the existing signing material, which is still valid.');\n return result(false);\n }\n logger.info(`[harmonyos] Regenerating signing material: ${reason}.`);\n\n // Before anything is deleted: a profile must name at least one device.\n const agc = createAgcClient(opts.http ?? createHttpClient({ logger }), auth);\n const deviceIds = await registerDevices(agc, connected, logger);\n for (const file of Object.values(paths)) fs.rmSync(file, { force: true });\n\n // AGC will not issue a second certificate under one name, so ours is replaced.\n // The name is oniro-app's own: upstream uses DevEco Studio's `auto_debug_`, and\n // replacing that certificate would revoke the material Studio signs with.\n const certName = `oniro_debug_${auth.teamId.replace(/[\\\\/.:]/g, '')}.cer`;\n const stale = (await agc.listCertificates()).find((c) => c.certName === certName);\n if (stale) {\n logger.info(`[harmonyos] Replacing the previous '${certName}' certificate in AppGallery Connect...`);\n await agc.deleteCertificate(stale.id);\n }\n\n const { keyPwd, csr } = await generateKeystoreAndCsr({ sdk, p12Path: paths.p12Path, csrPath: paths.csrPath, logger });\n logger.info('[harmonyos] Requesting a debug certificate from AppGallery Connect...');\n await agc.addCertificate(certName, csr);\n const cert = (await agc.listCertificates()).find((c) => c.certName === certName);\n if (!cert) throw new AgcError(SIGNING_ERRORS.CERT_REQUEST);\n await agc.download('cert', cert.certObjectId, paths.cerPath);\n\n logger.info('[harmonyos] Issuing the debug provisioning profile...');\n const profile = await agc.addDebugProfile({\n provisionName: `oniro_${crypto.randomBytes(6).toString('hex')}`,\n bundleName,\n certId: cert.id,\n deviceIds,\n aclPermissions,\n });\n try {\n await agc.download('profile', profile.provisionFileUrl, paths.profilePath);\n } finally {\n // The file is what the build needs; the AGC record would only use up the team's quota.\n await agc.deleteProfile(profile.id).catch((err: Error) => {\n logger.debug(`[harmonyos] Could not delete profile ${profile.id} from AppGallery Connect: ${err.message}`);\n });\n }\n try {\n verifySigningMaterial({ ...paths, keyAlias: KEY_ALIAS, keyPwd });\n } catch (err) {\n fs.rmSync(paths.profilePath, { force: true });\n throw err;\n }\n\n // The OpenHarmony signing path's encryption, with its material next to the keystores.\n // Shared by every project there, so existing material is kept.\n const materialDir = path.join(path.dirname(paths.p12Path), 'material');\n try {\n getKey(materialDir);\n } catch {\n createMaterial(materialDir);\n }\n writeSigningConfig({ buildProfilePath, buildProfile, productName, paths, encryptedPassword: encryptPwd(keyPwd, materialDir) });\n logger.info(`[harmonyos] Wrote signingConfigs['${productName}'] to ${buildProfilePath}.`);\n return result(true);\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/signature/cert-api.ts`, `src/signature/device-manager.ts`,\n * `src/signature/generate-profile.ts`, `src/signature/download.ts`),\n * Copyright (c) 2026 Huawei Device Co., Ltd., licensed under the MIT License.\n * See packages/core/src/harmonyos/NOTICE.md.\n *\n * These are private, undocumented AppGallery Connect endpoints.\n */\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { ChecksumMismatchError } from '../../ports/errors.js';\nimport type { AgcAuthInfo } from '../auth/types.js';\nimport type { HarmonyOsHttpClient, HttpRequestOptions } from '../http.js';\nimport { mapAgcError, readRet, type AgcOperation } from './errors.js';\n\nconst ENDPOINTS = {\n CERT_LIST: '/api/cps/harmony-cert-manage/v1/cert/list',\n CERT_ADD: '/api/cps/harmony-cert-manage/v1/cert/add',\n CERT_DELETE: '/api/cps/harmony-cert-manage/v1/cert/delete',\n /** Exchanges an object id for a short-lived signed download URL. */\n OBJECT_URL: '/api/amis/app-manage/v1/objects/url/reapply',\n DEVICE_LIST: '/api/cps/device-manage/v1/device/list',\n DEVICE_ADD: '/api/cps/device-manage/v1/device/add',\n /** Debug (\"test\") provisioning profiles — the only kind oniro-app issues. */\n PROVISION_ADD: '/api/cps/provision-manage/v1/ide/test/provision/add',\n PROVISION_DELETE: '/api/cps/provision-manage/v1/provision/delete',\n} as const;\n\n/** AGC device-type codes, by the device kind `hdc` reports. */\nconst DEVICE_TYPE_CODES: Record<string, number> = { liteWearable: 1, wearable: 2, tv: 3, phone: 4 };\n\nexport interface AgcCertificate {\n id: string;\n certName: string;\n /** Object-store handle, exchanged for a download URL. */\n certObjectId: string;\n}\n\nexport interface AgcDevice {\n id: string;\n udid: string;\n}\n\nexport type AgcClient = ReturnType<typeof createAgcClient>;\n\n/** The AppGallery Connect signing endpoints, bound to one account and team. */\nexport function createAgcClient(http: HarmonyOsHttpClient, auth: AgcAuthInfo) {\n /** Call an endpoint and return its body; any failure form becomes an AgcError. */\n async function call<T>(\n operation: AgcOperation,\n method: 'get' | 'post' | 'delete',\n endpoint: string,\n opts: Omit<HttpRequestOptions, 'headers'> = {},\n ): Promise<T> {\n const response = await http[method](`${auth.baseUrl}${endpoint}`, {\n ...opts,\n headers: { uid: auth.uid, teamId: auth.teamId, oauth2Token: auth.accessToken },\n });\n if (response.statusCode !== 200 || readRet(response.data)?.code !== 0) {\n throw mapAgcError(operation, response.statusCode, response.statusText, response.data);\n }\n return JSON.parse(response.data) as T;\n }\n\n return {\n async listCertificates(): Promise<AgcCertificate[]> {\n return (await call<{ certList?: AgcCertificate[] }>('cert', 'post', ENDPOINTS.CERT_LIST)).certList ?? [];\n },\n\n async addCertificate(certName: string, csr: string): Promise<void> {\n // certType 1 is a debug certificate.\n await call('cert', 'post', ENDPOINTS.CERT_ADD, { body: { csr, certName, certType: '1' } });\n },\n\n async deleteCertificate(certId: string): Promise<void> {\n await call('cert', 'delete', ENDPOINTS.CERT_DELETE, { body: { certIds: [certId] } });\n },\n\n /** Every device registered to the team, across pages. */\n async listDevices(): Promise<AgcDevice[]> {\n const pageSize = 100;\n const devices: AgcDevice[] = [];\n for (let start = 1; ; start++) {\n const page = await call<{ list?: AgcDevice[]; totalCount?: number }>('device', 'get', ENDPOINTS.DEVICE_LIST, {\n query: { encodeFlag: 0, start, pageSize },\n });\n devices.push(...(page.list ?? []));\n if (!page.list?.length || devices.length >= (page.totalCount ?? 0)) return devices;\n }\n },\n\n async addDevice(udid: string, deviceKind: string): Promise<void> {\n // AGC rejects duplicate device names, so the name is made unique.\n const deviceName = `oniro_app_device_${crypto.randomBytes(4).toString('hex')}`;\n await call('device', 'post', ENDPOINTS.DEVICE_ADD, {\n body: { deviceName, udid, deviceType: String(DEVICE_TYPE_CODES[deviceKind] ?? DEVICE_TYPE_CODES.phone) },\n });\n },\n\n /** Issue a debug profile; returns its id and object handle. */\n async addDebugProfile(opts: {\n provisionName: string;\n bundleName: string;\n certId: string;\n deviceIds: string[];\n aclPermissions: string[];\n }): Promise<{ id: string; provisionFileUrl: string }> {\n return call('profile', 'post', ENDPOINTS.PROVISION_ADD, {\n body: {\n provisionName: opts.provisionName,\n packageName: opts.bundleName,\n certList: [opts.certId],\n deviceList: opts.deviceIds,\n ...(opts.aclPermissions.length ? { aclPermissionList: opts.aclPermissions } : {}),\n },\n });\n },\n\n async deleteProfile(id: string): Promise<void> {\n await call('profile', 'delete', ENDPOINTS.PROVISION_DELETE, { query: { id } });\n },\n\n /**\n * Download a certificate or profile object to `dest`, checking the digest AGC\n * supplies with the URL. Nothing is written unless it matches.\n */\n async download(operation: AgcOperation, objectId: string, dest: string): Promise<void> {\n const { urlsInfo } = await call<{ urlsInfo?: Array<{ newUrl: string; sha256: string }> }>(\n operation,\n 'post',\n ENDPOINTS.OBJECT_URL,\n { body: { sourceUrls: objectId } },\n );\n const target = urlsInfo?.[0];\n if (!target) throw mapAgcError(operation, 200, '', '');\n\n const buffer = await http.getBinary(target.newUrl, { timeoutMs: 60_000 });\n const actual = crypto.createHash('sha256').update(buffer).digest('hex');\n if (target.sha256 && actual !== target.sha256.toLowerCase()) {\n throw new ChecksumMismatchError(target.sha256, actual);\n }\n fs.mkdirSync(path.dirname(dest), { recursive: true, mode: 0o700 });\n fs.writeFileSync(dest, buffer, { mode: 0o600 });\n },\n };\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/signature/device-manager.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport type { ConfigProvider } from '../../ports/config.js';\nimport type { Logger } from '../../ports/logger.js';\nimport { hdcExec } from '../../hdc/exec.js';\nimport { listDevices } from '../../hdc/devices.js';\nimport type { AgcClient } from './agc.js';\nimport { AgcError, SIGNING_ERRORS } from './errors.js';\n\n/**\n * The 64-hex UDID from `bm get -u` output, uppercased, or '' when there is none.\n * The wording around it varies by release, so any 64-hex token is accepted.\n *\n * @internal exposed for tests.\n */\nexport function parseUdid(stdout: string): string {\n return stdout.match(/\\b[A-Fa-f0-9]{64}\\b/)?.[0].toUpperCase() ?? '';\n}\n\n/**\n * The AGC device kind for a `hw_sc.build.os.deviceType` value. Anything else,\n * including an inaccessible property, is a phone.\n *\n * @internal exposed for tests.\n */\nexport function parseDeviceKind(stdout: string): string {\n return ['liteWearable', 'wearable', 'tv'].find((kind) => stdout.includes(kind)) ?? 'phone';\n}\n\nexport interface LocalDevice {\n serial: string;\n /** Uppercased. */\n udid: string;\n kind: string;\n}\n\n/** UDID and kind of every connected device; one that will not answer is skipped. */\nexport async function collectLocalDevices(config: ConfigProvider, logger: Logger): Promise<LocalDevice[]> {\n const devices: LocalDevice[] = [];\n for (const target of await listDevices(config, { logger, timeoutMs: 15_000 })) {\n if (target.status !== 'Connected') continue;\n const shell = async (...args: string[]) =>\n (await hdcExec({ config, deviceSerial: target.serial, args: ['shell', ...args], timeoutMs: 15_000, logger }))\n .stdout;\n try {\n const udid = parseUdid(await shell('bm', 'get', '-u'));\n if (!udid) {\n logger.warn(`[harmonyos] ${target.serial} did not report a UDID; skipping it.`);\n continue;\n }\n devices.push({ serial: target.serial, udid, kind: parseDeviceKind(await shell('getprop', 'hw_sc.build.os.deviceType')) });\n } catch (err) {\n logger.warn(`[harmonyos] Could not read ${target.serial}: ${(err as Error).message}`);\n }\n }\n return devices;\n}\n\n/**\n * Register the connected devices the team does not know yet, and return the ids of\n * every device registered to the team.\n *\n * The profile names every registered device, not only the connected ones, so it\n * stays valid across devices — and no device needs to be connected at all once the\n * team has some registered (from another machine, or by DevEco Studio).\n */\nexport async function registerDevices(agc: AgcClient, connected: LocalDevice[], logger: Logger): Promise<string[]> {\n let devices = await agc.listDevices();\n const registered = new Set(devices.map((d) => d.udid.toUpperCase()));\n\n const unregistered = connected.filter((d) => !registered.has(d.udid));\n for (const device of unregistered) {\n logger.info(`[harmonyos] Registering ${device.serial} with AppGallery Connect...`);\n await agc.addDevice(device.udid, device.kind);\n }\n if (unregistered.length > 0) devices = await agc.listDevices();\n\n const deviceIds = devices.map((d) => d.id);\n if (deviceIds.length === 0) throw new AgcError(SIGNING_ERRORS.DEVICE_NONE);\n if (connected.length === 0) {\n logger.warn(\n `[harmonyos] No device is connected; the profile will name the ${deviceIds.length} device(s) already registered to this team.`,\n );\n }\n return deviceIds;\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/signature/signature-tool.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Logger } from '../../ports/logger.js';\nimport { OniroError } from '../../ports/errors.js';\nimport { runProcess } from '../../hdc/exec.js';\nimport type { HarmonyOsSdk } from '../sdk.js';\nimport { findJava } from '../java.js';\n\n/** Alias of the key pair inside the generated p12. */\nexport const KEY_ALIAS = 'debugKey';\nexport const SIGN_ALG = 'SHA256withECDSA';\n\n/**\n * hap-sign-tool argv with password values masked, for logging.\n *\n * @internal exposed for tests.\n */\nexport function redactArgs(args: readonly string[]): string[] {\n return args.map((arg, i) => (args[i - 1] === '-keyPwd' || args[i - 1] === '-keystorePwd' ? '******' : arg));\n}\n\n/**\n * Generate the local p12 keystore and the CSR AGC turns into a certificate.\n * Returns the random keystore password in the clear; the caller encrypts it\n * before it reaches `build-profile.json5`, and it is never logged.\n */\nexport async function generateKeystoreAndCsr(opts: {\n sdk: HarmonyOsSdk;\n p12Path: string;\n csrPath: string;\n logger: Logger;\n}): Promise<{ keyPwd: string; csr: string }> {\n const jar = path.join(opts.sdk.sdkPath, 'default', 'openharmony', 'toolchains', 'lib', 'hap-sign-tool.jar');\n if (!fs.existsSync(jar)) {\n throw new OniroError(`hap-sign-tool.jar not found at ${jar}; the HarmonyOS SDK looks incomplete.`);\n }\n const java = findJava(opts.sdk);\n const keyPwd = crypto.randomBytes(12).toString('base64url').replaceAll(/[-_]/g, '');\n fs.mkdirSync(path.dirname(opts.p12Path), { recursive: true, mode: 0o700 });\n\n const run = async (what: string, args: string[]) => {\n const argv = ['-jar', jar, ...args, '-keyAlias', KEY_ALIAS, '-keystoreFile', opts.p12Path, '-keystorePwd', keyPwd, '-keyPwd', keyPwd];\n opts.logger.debug(`[harmonyos] ${java} ${redactArgs(argv).join(' ')}`);\n const result = await runProcess({ command: java, args: argv, timeoutMs: 120_000, logger: opts.logger });\n if (result.code !== 0) {\n const detail = (result.stderr || result.stdout || '').trim();\n throw new OniroError(`hap-sign-tool failed to ${what} (exit ${result.code}).${detail ? `\\n${detail}` : ''}`);\n }\n };\n\n opts.logger.info('[harmonyos] Generating the local keystore and certificate signing request...');\n await run('generate the key pair', ['generate-keypair', '-keyAlg', 'ECC', '-keySize', 'NIST-P-256']);\n await run('generate the CSR', ['generate-csr', '-subject', 'CN=DebugKey', '-signAlg', SIGN_ALG, '-outFile', opts.csrPath]);\n return { keyPwd, csr: fs.readFileSync(opts.csrPath, 'utf8') };\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { OniroError } from '../ports/errors.js';\nimport type { HarmonyOsSdk } from './sdk.js';\n\nconst JAVA_BIN = process.platform === 'win32' ? 'java.exe' : 'java';\n\n/**\n * Locate a Java runtime for `hap-sign-tool.jar`: `JAVA_HOME`, then the JetBrains\n * Runtime DevEco Studio bundles (so Studio users need no separate JDK), then `PATH`.\n */\nexport function findJava(sdk?: HarmonyOsSdk, env: NodeJS.ProcessEnv = process.env): string {\n const candidates = [\n env.JAVA_HOME && path.join(env.JAVA_HOME, 'bin', JAVA_BIN),\n sdk && path.join(sdk.installRoot, 'jbr', 'bin', JAVA_BIN),\n // macOS: the JBR is itself a bundle inside Studio's Contents.\n sdk && path.join(sdk.installRoot, 'jbr', 'Contents', 'Home', 'bin', JAVA_BIN),\n ...(env.PATH ?? '').split(path.delimiter).map((dir) => dir && path.join(dir, JAVA_BIN)),\n ];\n const found = candidates.find((c): c is string => !!c && fs.existsSync(c));\n if (found) return found;\n throw new OniroError(\n 'No Java runtime found. HarmonyOS signing runs the SDK\\'s hap-sign-tool.jar, which needs one: ' +\n 'install a JDK and set JAVA_HOME, or install DevEco Studio, whose bundled runtime is used automatically.',\n );\n}\n","/*\n * Portions of this file are adapted from openharmony-sig/deveco-cli\n * (`src/signature/signature-tool.ts`), Copyright (c) 2026 Huawei Device Co., Ltd.,\n * licensed under the MIT License. See packages/core/src/harmonyos/NOTICE.md.\n */\nimport * as crypto from 'node:crypto';\nimport * as path from 'node:path';\nimport type { ConfigProvider } from '../../ports/config.js';\nimport { defaultPaths } from '../../ports/config.js';\n\n/** The four files of a HarmonyOS signing setup. */\nexport interface SigningMaterialPaths {\n p12Path: string;\n csrPath: string;\n cerPath: string;\n profilePath: string;\n}\n\n/** @internal exposed for tests. */\nexport function sanitizeNamePart(raw?: string): string {\n const safe = (raw?.trim() ?? '').replace(/[\\\\/:*?\"<>|=.-]+/g, '_');\n return safe.slice(0, 64) || 'default';\n}\n\n/**\n * Where the material for a (product, project) pair lives: `harmonyosSigningDir`\n * (default `~/.ohos/config`, as DevEco Studio uses), named after Studio's pattern.\n * Keyed by project *path*, so two checkouts of one app never share a keystore.\n */\nexport function resolveSigningMaterialPaths(\n config: ConfigProvider,\n productName: string | undefined,\n projectRoot: string,\n): SigningMaterialPaths {\n const hash = crypto.createHash('sha256').update(projectRoot, 'utf8').digest('base64url').replaceAll(/[-_]/g, '');\n const base = path.join(\n config.get('harmonyosSigningDir', defaultPaths.harmonyosSigningDir()),\n `${sanitizeNamePart(productName)}_${path.basename(projectRoot)}_${hash}=`,\n );\n return { p12Path: `${base}.p12`, csrPath: `${base}.csr`, cerPath: `${base}.cer`, profilePath: `${base}.p7b` };\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport JSON5 from 'json5';\nimport type { Logger } from '../../ports/logger.js';\nimport { noopLogger } from '../../ports/logger.js';\nimport { listModules } from '../../project/listModules.js';\nimport { ACL_PERMISSIONS } from './aclPermissionList.js';\n\n/** Read `requestPermissions[].name` out of one module config, if present. */\nfunction readRequestedPermissions(moduleConfigPath: string): string[] {\n if (!fs.existsSync(moduleConfigPath)) return [];\n try {\n const parsed = JSON5.parse(fs.readFileSync(moduleConfigPath, 'utf-8')) as {\n module?: { requestPermissions?: Array<{ name?: unknown }> };\n };\n return (parsed.module?.requestPermissions ?? [])\n .map((p) => p?.name)\n .filter((n): n is string => typeof n === 'string' && n.length > 0);\n } catch {\n return [];\n }\n}\n\n/**\n * Collect the ACL-gated permissions the project requests.\n *\n * These must be named in the provisioning profile or the HAP is refused at install\n * time. Both `src/main` and `src/ohosTest` are scanned, since a test module's\n * permissions are equally gated.\n */\nexport function collectAclPermissions(\n projectDir: string,\n logger: Logger = noopLogger,\n): string[] {\n const requested = new Set<string>();\n\n for (const module of listModules({ projectDir })) {\n const moduleRoot = path.resolve(projectDir, module.srcPath);\n for (const sourceSet of ['main', 'ohosTest']) {\n for (const name of readRequestedPermissions(\n path.join(moduleRoot, 'src', sourceSet, 'module.json5'),\n )) {\n requested.add(name);\n }\n }\n }\n\n const acls = [...requested].filter((p) => ACL_PERMISSIONS.has(p)).sort();\n if (acls.length > 0) {\n logger.info(`[harmonyos] Project requests ${acls.length} ACL permission(s): ${acls.join(', ')}`);\n }\n return acls;\n}\n","/*\n * The permission list below is data from openharmony-sig/deveco-cli\n * (`src/resources/aclPermission/aclPermissionsInfo.json`), Copyright (c) 2026\n * Huawei Device Co., Ltd., licensed under the MIT License.\n * See packages/core/src/harmonyos/NOTICE.md.\n */\n\n/**\n * HarmonyOS permissions that are ACL-gated: an app requesting one needs it listed\n * in its provisioning profile, or installation is refused on-device.\n */\nexport const ACL_PERMISSIONS: ReadonlySet<string> = new Set([\n 'ohos.permission.ACCESS_DDK_HID',\n 'ohos.permission.ACCESS_DDK_SCSI_PERIPHERAL',\n 'ohos.permission.ACCESS_DDK_USB',\n 'ohos.permission.ACCESS_DDK_USB_SERIAL',\n 'ohos.permission.ACCESS_DISK_PHY_INFO',\n 'ohos.permission.ACCESS_FIDO2_ONLINEAUTH',\n 'ohos.permission.ACCESS_NET_TRACE_INFO',\n 'ohos.permission.ACCESS_USER_FULL_DISK',\n 'ohos.permission.ACCESS_VIRTUAL_SCREEN',\n 'ohos.permission.CUSTOMIZE_SAVE_BUTTON',\n 'ohos.permission.CUSTOM_SCREEN_RECORDING',\n 'ohos.permission.DLP_GET_HIDE_STATUS',\n 'ohos.permission.FILE_ACCESS_PERSIST',\n 'ohos.permission.GET_ABILITY_INFO',\n 'ohos.permission.GET_ETHERNET_LOCAL_MAC',\n 'ohos.permission.GET_IP_MAC_INFO',\n 'ohos.permission.GET_WIFI_LOCAL_MAC',\n 'ohos.permission.GET_WIFI_PEERS_MAC',\n 'ohos.permission.HOOK_KEY_EVENT',\n 'ohos.permission.INPUT_MONITORING',\n 'ohos.permission.INTERCEPT_INPUT_EVENT',\n 'ohos.permission.KEEP_BACKGROUND_RUNNING_SYSTEM',\n 'ohos.permission.LINKTURBO',\n 'ohos.permission.MANAGE_APN_SETTING',\n 'ohos.permission.MANAGE_PASTEBOARD_APP_SHARE_OPTION',\n 'ohos.permission.MANAGE_SCREEN_TIME_GUARD',\n 'ohos.permission.MANAGE_UDMF_APP_SHARE_OPTION',\n 'ohos.permission.PERSISTENT_BLUETOOTH_PEERS_MAC',\n 'ohos.permission.PERSONAL_MANAGE_RESTRICTIONS',\n 'ohos.permission.PRELOAD_FILE',\n 'ohos.permission.READ_AUDIO',\n 'ohos.permission.READ_CONTACTS',\n 'ohos.permission.READ_IMAGEVIDEO',\n 'ohos.permission.READ_LOCAL_DEVICE_NAME',\n 'ohos.permission.READ_PASTEBOARD',\n 'ohos.permission.READ_WRITE_DESKTOP_DIRECTORY',\n 'ohos.permission.READ_WRITE_DOCUMENTS_DIRECTORY',\n 'ohos.permission.READ_WRITE_DOWNLOAD_DIRECTORY',\n 'ohos.permission.READ_WRITE_USB_DEV',\n 'ohos.permission.READ_WRITE_USER_FILE',\n 'ohos.permission.SET_PAC_URL',\n 'ohos.permission.SET_SYSTEMSHARE_APPLAUNCHTRUSTLIST',\n 'ohos.permission.SHORT_TERM_WRITE_IMAGEVIDEO',\n 'ohos.permission.START_PROVISIONING_MESSAGE',\n 'ohos.permission.SUBSCRIBE_NOTIFICATION',\n 'ohos.permission.SYSTEM_FLOAT_WINDOW',\n 'ohos.permission.USE_FLOAT_BALL',\n 'ohos.permission.USE_FRAUD_APP_PICKER',\n 'ohos.permission.USE_FRAUD_CALL_LOG_PICKER',\n 'ohos.permission.USE_FRAUD_MESSAGES_PICKER',\n 'ohos.permission.WEB_NATIVE_MESSAGING',\n 'ohos.permission.WRITE_AUDIO',\n 'ohos.permission.WRITE_CONTACTS',\n 'ohos.permission.WRITE_IMAGEVIDEO',\n 'ohos.permission.atomicService.MANAGE_STORAGE',\n 'ohos.permission.kernel.ALLOW_EXECUTABLE_FORT_MEMORY',\n 'ohos.permission.kernel.ALLOW_WRITABLE_CODE_MEMORY',\n 'ohos.permission.kernel.DISABLE_CODE_MEMORY_PROTECTION',\n 'ohos.permission.kernel.DISABLE_GOTPLT_RO_PROTECTION',\n]);\n\n","declare const __PKG_VERSION__: string;\nexport const VERSION = __PKG_VERSION__;\n\nexport * from './ports/index.js';\nexport * from './sdk/index.js';\nexport * from './cmdTools/index.js';\nexport * from './sign/index.js';\nexport * from './emulator/index.js';\nexport * from './hdc/index.js';\nexport * from './build/index.js';\nexport * from './project/index.js';\nexport * from './device/index.js';\nexport * from './install/index.js';\nexport * from './harmonyos/index.js';\n"],"mappings":"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","names":["platform","os","platform","fs","os","path","os","path","platform","fs","path","fs","os","path","fs","path","resolve","fs","os","path","pipeline","promisify","pipelineAsync","promisify","pipeline","fs","path","fs","path","fs","path","fs","n","fs","os","path","path","platform","platform","fs","path","crypto","fs","path","JSON5","JSON5","fs","path","fs","os","path","spawn","fs","resolve","spawn","resolve","tail","path","resolve","fs","path","fs","path","fs","path","JSON5","JSON5","relative","resolve","fs","os","path","randomBytes","randomBytes","fs","os","path","randomBytes","randomBytes","resolve","x","fs","resolve","fs","path","fs","path","JSON5","resolve","fs","path","fs","path","fs","path","fs","JSON5","fs","path","fs","path","fs","path","StreamZip","fs","path","fs","os","path","crypto","encrypt","decrypt","crypto","http","crypto","resolve","port","spawn","spawn","resolve","http","fs","x","crypto","fs","path","JSON5","crypto","fs","path","http","shell","crypto","fs","path","fs","path","crypto","path","fs","path","JSON5","JSON5","JSON5"]}
|