@oniroproject/oniro-app 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +117 -2
  2. package/dist/oniro-app.js +104 -9
  3. package/dist/oniro-app.js.map +1 -1
  4. package/package.json +2 -2
  5. package/templates/HarmonyOSApp/AppScope/app.json5 +10 -0
  6. package/templates/HarmonyOSApp/AppScope/resources/base/element/string.json +8 -0
  7. package/templates/HarmonyOSApp/AppScope/resources/base/media/background.png +0 -0
  8. package/templates/HarmonyOSApp/AppScope/resources/base/media/foreground.png +0 -0
  9. package/templates/HarmonyOSApp/AppScope/resources/base/media/layered_image.json +7 -0
  10. package/templates/HarmonyOSApp/build-profile.json5 +35 -0
  11. package/templates/HarmonyOSApp/entry/build-profile.json5 +33 -0
  12. package/templates/HarmonyOSApp/entry/hvigorfile.ts +6 -0
  13. package/templates/HarmonyOSApp/entry/obfuscation-rules.txt +23 -0
  14. package/templates/HarmonyOSApp/entry/oh-package.json5 +10 -0
  15. package/templates/HarmonyOSApp/entry/src/main/ets/entryability/EntryAbility.ets +48 -0
  16. package/templates/HarmonyOSApp/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets +16 -0
  17. package/templates/HarmonyOSApp/entry/src/main/ets/pages/Index.ets +23 -0
  18. package/templates/HarmonyOSApp/entry/src/main/module.json5 +50 -0
  19. package/templates/HarmonyOSApp/entry/src/main/resources/base/element/color.json +8 -0
  20. package/templates/HarmonyOSApp/entry/src/main/resources/base/element/float.json +8 -0
  21. package/templates/HarmonyOSApp/entry/src/main/resources/base/element/string.json +16 -0
  22. package/templates/HarmonyOSApp/entry/src/main/resources/base/media/background.png +0 -0
  23. package/templates/HarmonyOSApp/entry/src/main/resources/base/media/foreground.png +0 -0
  24. package/templates/HarmonyOSApp/entry/src/main/resources/base/media/layered_image.json +7 -0
  25. package/templates/HarmonyOSApp/entry/src/main/resources/base/media/startIcon.png +0 -0
  26. package/templates/HarmonyOSApp/entry/src/main/resources/base/profile/backup_config.json +3 -0
  27. package/templates/HarmonyOSApp/entry/src/main/resources/base/profile/main_pages.json +5 -0
  28. package/templates/HarmonyOSApp/entry/src/main/resources/dark/element/color.json +8 -0
  29. package/templates/HarmonyOSApp/entry/src/mock/mock-config.json5 +2 -0
  30. package/templates/HarmonyOSApp/entry/src/ohosTest/ets/test/Ability.test.ets +35 -0
  31. package/templates/HarmonyOSApp/entry/src/ohosTest/ets/test/List.test.ets +5 -0
  32. package/templates/HarmonyOSApp/entry/src/ohosTest/module.json5 +11 -0
  33. package/templates/HarmonyOSApp/entry/src/test/List.test.ets +5 -0
  34. package/templates/HarmonyOSApp/entry/src/test/LocalUnit.test.ets +33 -0
  35. package/templates/HarmonyOSApp/hvigor/hvigor-config.json5 +23 -0
  36. package/templates/HarmonyOSApp/hvigorfile.ts +6 -0
  37. package/templates/HarmonyOSApp/oh-package.json5 +10 -0
  38. package/templates/HarmonyOSApp/template.json +6 -0
package/README.md CHANGED
@@ -103,7 +103,7 @@ All flags are required except where a default is shown (non-interactive). On suc
103
103
  | `--bundle <bundleName>` | Bundle name in reverse-DNS form, e.g. `com.example.myapp`. |
104
104
  | `--location <dir>` | Parent directory the new project folder is created in. |
105
105
  | `--sdk <api>` | Target SDK API level (e.g. `18`, `20`). |
106
- | `--template <id>` | Template id (default `EmptyAbility`). |
106
+ | `--template <id>` | Template id (default `EmptyAbility`; `HarmonyOSApp` targets HarmonyOS). |
107
107
  | `--module <name>` | Module folder name (defaults to the template default, usually `entry`). |
108
108
  | `--overwrite` | Replace the destination if it already exists. |
109
109
 
@@ -113,6 +113,17 @@ All flags are required except where a default is shown (non-interactive). On suc
113
113
  | --- | --- |
114
114
  | `templates list [--json]` | List the project templates shipped with the CLI. |
115
115
 
116
+ #### `auth` — sign in to a Huawei developer account
117
+
118
+ Only needed for HarmonyOS signing; see [HarmonyOS apps](#harmonyos-apps).
119
+
120
+ | Command | Description |
121
+ | --- | --- |
122
+ | `auth login [--timeout <s>]` | Sign in via the browser (default timeout 600s). |
123
+ | `auth logout` | Delete the locally stored token. |
124
+ | `auth status [--json]` | Show the signed-in account; exits non-zero when signed out. |
125
+ | `auth team list [--json]` | List AGC teams. |
126
+
116
127
  #### `sign` — generate signing keys, certs, and `signingConfigs`
117
128
 
118
129
  `sign [project-dir]` (defaults to the current directory). Requires `java` on `PATH`. Rewrites only the `signingConfigs` block of `build-profile.json5` (other keys are preserved). The generated profile uses the SDK's built-in development cert (`issuer=pki_internal`) and its validity window — **dev/local builds only, not distribution.** See [Signing apps that need system permissions](#signing-apps-that-need-system-permissions) for `--apl` / `--acls`.
@@ -123,6 +134,10 @@ All flags are required except where a default is shown (non-interactive). On suc
123
134
  | `--app-feature <feature>` | `hos_normal_app` or `hos_system_app`. Defaults follow `--apl`. |
124
135
  | `--acls <list>` | Comma-separated permissions to write into the profile's `acls.allowed-acls`. |
125
136
  | `--bootstrap` | No-op if signing material is already present; otherwise generate it. |
137
+ | `--harmonyos` | Sign a HarmonyOS project via AppGallery Connect instead of the offline flow. See [HarmonyOS apps](#harmonyos-apps). |
138
+ | `--team-id <id>` | With `--harmonyos`: AGC team to sign under. |
139
+ | `--product <name>` | With `--harmonyos`: product to sign (default `default`). |
140
+ | `--force` | With `--harmonyos`: regenerate even when the existing material is still valid. |
126
141
  | `--store-password <pwd>` / `--key-password <pwd>` | Keystore passwords (default `123456`, the SDK keystore password). |
127
142
 
128
143
  #### `build` — build the app via `hvigorw`
@@ -195,7 +210,7 @@ These commands target a connected device or emulator over `hdc`. Most accept `--
195
210
  | `--mode <mode>` | `system` (default), `bootloader`, or `recovery`. |
196
211
  | `--wait-bundle <bundle>` | After a system reboot, wait until this bundle is running again. |
197
212
  | `--timeout <ms>` | Max time to wait for the bundle (default `180000`). |
198
- | `--device <serial>` | Target device serial. For a TCP target (an emulator at `host:port`), passing this reconnects the session across the reboot. |
213
+ | `--device <serial>` | Target device serial. For a TCP target (an emulator at `host:port`), passing this reconnects the session across the reboot, restarting the hdc server if it keeps the dead session. |
199
214
 
200
215
  #### `wait` — wait for a device condition
201
216
 
@@ -300,6 +315,9 @@ The CLI reads paths and URLs from environment variables. All are optional; defau
300
315
  | `ONIRO_EMULATOR_URL` | Latest `oniro_emulator.zip` | Emulator download URL |
301
316
  | `ONIRO_TMP_DIR` | `<install root>/.oniro-tmp` | Scratch directory for download/extract temporaries (see [Temporary space](#temporary-space)) |
302
317
  | `ONIRO_APPLICATION_CERT_PATH` | (unset) | External application-cert chain to use when signing system apps |
318
+ | `ONIRO_HARMONYOS_SDK_PATH` | autodetected | HarmonyOS SDK: a DevEco Studio or HarmonyOS command-line-tools install, or its `sdk` directory |
319
+ | `ONIRO_HARMONYOS_AUTH_DIR` | `~/.oniro/harmonyos` | Where the encrypted Huawei account token is stored |
320
+ | `ONIRO_HARMONYOS_SIGNING_DIR` | `~/.ohos/config` | Where generated HarmonyOS signing material (p12/csr/cer/p7b) is written |
303
321
  | `ONIRO_DEBUG` | (unset) | Set to `1` for full stack traces on error |
304
322
 
305
323
  ### Temporary space
@@ -332,6 +350,103 @@ through.
332
350
 
333
351
  **Command-line tools on Windows / macOS.** The Huawei mirror only publishes a Linux build of the command-line tools. On Windows and macOS you must either download the ZIP manually from the Huawei developer portal and install it with `oniro-app cmdtools install --from-zip path/to/commandline-tools-<platform>.zip`, or host the archive yourself and set `ONIRO_CMD_TOOLS_URL_WINDOWS` / `ONIRO_CMD_TOOLS_URL_MAC` so `cmdtools install` can fetch it.
334
352
 
353
+ ## HarmonyOS apps
354
+
355
+ `oniro-app` builds and signs **HarmonyOS** projects as well as OpenHarmony ones. A project
356
+ is HarmonyOS when its product declares `runtimeOS: "HarmonyOS"` in `build-profile.json5`, as
357
+ DevEco Studio writes; every other project is OpenHarmony and behaves exactly as before.
358
+
359
+ The two paths differ in one way that matters:
360
+
361
+ | | OpenHarmony | HarmonyOS |
362
+ | --- | --- | --- |
363
+ | SDK | `oniro-app sdk install` downloads it | Ships inside DevEco Studio or the HarmonyOS command-line tools. Found automatically in Studio's default location or at the command-line-tools path; otherwise set `ONIRO_HARMONYOS_SDK_PATH` |
364
+ | Signing | `oniro-app sign` — fully offline, uses the SDK's development certificate | `oniro-app sign --harmonyos` — AppGallery Connect issues the certificate and profile |
365
+ | Account | none | a Huawei developer account (`oniro-app auth login`) |
366
+ | Network | none | required |
367
+ | Device | not required | one registered to the AGC team — a debug profile names the devices it is valid for |
368
+
369
+ ### Workflow
370
+
371
+ ```bash
372
+ oniro-app auth login # once per machine
373
+ oniro-app create --name MyApp --bundle com.example.myapp \
374
+ --location ~/projects --sdk 24 --template HarmonyOSApp
375
+ cd ~/projects/MyApp
376
+ oniro-app sign --harmonyos # registers any connected device
377
+ oniro-app build
378
+ oniro-app app install && oniro-app app launch
379
+ ```
380
+
381
+ Pass `--sdk` the API level of the installed HarmonyOS SDK (`apiVersion` in its
382
+ `default/sdk-pkg.json`). hvigor builds a HarmonyOS project only against the release its
383
+ `compileSdkVersion` names ("SDK component missing" otherwise), so `create` writes the
384
+ installed SDK's release, e.g. `6.1.1(24)`, and warns when `--sdk` asks for another one.
385
+
386
+ ### `oniro-app auth`
387
+
388
+ | Command | What it does |
389
+ | --- | --- |
390
+ | `auth login [--timeout <s>]` | Opens the Huawei sign-in page and waits for the browser to redirect back to a loopback port. The URL is also printed, so a headless host can be signed in from another machine. |
391
+ | `auth logout` | Deletes the locally stored token. |
392
+ | `auth status [--json]` | Prints the signed-in account, and warns when it is not allowed to sign. Exits non-zero when signed out. |
393
+ | `auth team list [--json]` | Lists AGC teams; pass an id to `sign --harmonyos --team-id`. |
394
+
395
+ The token is stored encrypted under `ONIRO_HARMONYOS_AUTH_DIR`. It is a credential: the
396
+ directory is created `0700` and the files `0600`.
397
+
398
+ ### `oniro-app sign --harmonyos`
399
+
400
+ Mirrors DevEco Studio's automatic signing:
401
+
402
+ 1. generates a local p12 keystore and a CSR (via the SDK's `hap-sign-tool.jar`, so a JDK is needed — DevEco Studio's bundled JBR is used when present);
403
+ 2. has AppGallery Connect issue a debug certificate for that CSR;
404
+ 3. registers every connected device's UDID with the team — no device is needed when the team already has some registered (from another machine, or by DevEco Studio);
405
+ 4. issues a debug provisioning profile naming that certificate, all of the team's registered devices, and any ACL-gated permissions the project requests;
406
+ 5. writes an encrypted `signingConfigs` entry into `build-profile.json5`, leaving other entries untouched.
407
+
408
+ Material lands in `ONIRO_HARMONYOS_SIGNING_DIR` (default `~/.ohos/config`, the directory
409
+ DevEco Studio also uses) and is **reused**, without contacting AGC for anything, while it is
410
+ still valid: same bundle name and team, unexpired, naming the attached devices and requested
411
+ permissions, and wired into this project's `build-profile.json5`. Certificates are a small
412
+ per-team quota; `--force` regenerates anyway.
413
+
414
+ The AGC certificate is named `oniro_debug_<team>.cer`, distinct from DevEco Studio's
415
+ `auto_debug_<team>.cer`: each tool replaces only its own certificate when regenerating, so
416
+ using both on one team does not revoke the other's signing material.
417
+
418
+ | Flag | Meaning |
419
+ | --- | --- |
420
+ | `--harmonyos` | Use the AGC path instead of the offline OpenHarmony one |
421
+ | `--team-id <id>` | AGC team to issue under (default: the account's own id) |
422
+ | `--product <name>` | Product to sign (default `default`) |
423
+ | `--force` | Regenerate even when the existing material is still valid |
424
+
425
+ ### Account regions
426
+
427
+ Accounts from every Huawei region can sign. Sign-in redirects to the account's own region,
428
+ which then decides the hosts every later call goes to — the ones DevEco Studio resolves
429
+ through Huawei's routing service:
430
+
431
+ | Region | Sign-in host | AGC signing host |
432
+ | --- | --- | --- |
433
+ | `CN` | `cn.devecostudio.huawei.com` | `connect-api.cloud.huawei.com` |
434
+ | `EU` | `de.devecostudio.huawei.com` | `connect-api-dre.cloud.huawei.com` |
435
+ | `SG` | `sg.devecostudio.huawei.com` | `connect-api-dra.cloud.huawei.com` |
436
+ | `RU` | `ru.devecostudio.huawei.com` | `connect-api-drru.cloud.huawei.com` |
437
+
438
+ The whole flow has been run with an `EU` account. Huawei's own CLI accepts only `CN` accounts.
439
+
440
+ ### Limitations
441
+
442
+ - **Real-name verification is not required**, but an account without it must have accepted
443
+ the current HUAWEI Developer Basic Service Agreement — in AppGallery Connect, or by running
444
+ automatic signing once in DevEco Studio. `oniro-app auth status --json` reports it as
445
+ `developerAgreement`; `oniro-app` checks it but never accepts it for you.
446
+ - A refusal from AGC surfaces as a permissions or not-enrolled error, not as a crash.
447
+ - The AGC endpoints are private and undocumented, and can change without notice. See
448
+ `packages/core/src/harmonyos/NOTICE.md` for provenance and attribution.
449
+
335
450
  ## Signing apps that need system permissions
336
451
 
337
452
  `oniro-app sign` defaults to `--apl normal` / `--app-feature hos_normal_app`, which is fine for ordinary apps. Apps that request permissions above `normal` (anything with `system_basic` or `system_core` availability — e.g. `ohos.permission.GET_WIFI_INFO_INTERNAL`, `ohos.permission.ACCESS_PIN_AUTH`) need a higher APL, otherwise `bm install` fails with `grant request permissions failed`.
package/dist/oniro-app.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/bin/oniro-app.ts
4
4
  import { Command as Command4 } from "commander";
5
- import { OniroError } from "@oniroproject/core";
5
+ import { OniroError as OniroError2 } from "@oniroproject/core";
6
6
 
7
7
  // src/commands/sdk.ts
8
8
  import * as fs from "fs";
@@ -73,7 +73,10 @@ var ENV_VAR_BY_KEY = {
73
73
  emulatorUrl: "ONIRO_EMULATOR_URL",
74
74
  tmpDir: "ONIRO_TMP_DIR",
75
75
  sdkUrlBase: "ONIRO_SDK_URL_BASE",
76
- applicationCertPath: "ONIRO_APPLICATION_CERT_PATH"
76
+ applicationCertPath: "ONIRO_APPLICATION_CERT_PATH",
77
+ harmonyosSdkPath: "ONIRO_HARMONYOS_SDK_PATH",
78
+ harmonyosAuthDir: "ONIRO_HARMONYOS_AUTH_DIR",
79
+ harmonyosSigningDir: "ONIRO_HARMONYOS_SIGNING_DIR"
77
80
  };
78
81
  function createEnvConfig(env = process.env) {
79
82
  return {
@@ -252,7 +255,9 @@ function registerEmulatorCommand(program) {
252
255
  import * as path2 from "path";
253
256
  import { buildHap } from "@oniroproject/core";
254
257
  function registerBuildCommand(program) {
255
- program.command("build [project-dir]").description("Build an OpenHarmony app via hvigorw. Defaults to the current directory.").option("--product <product>", "hvigor product name", "default").option("--module <module>", "restrict the build to a specific module").option("--mode <mode>", "hvigor build mode (e.g. release, debug)").option("--task <task>", "hvigor task to run", "assembleHap").option("--no-deps", "skip the automatic `ohpm install --all` when oh_modules/ is missing").option("--no-parallel", "build modules serially (default: parallel)").option("--json", "emit the build result (discovered HAPs, warnings) as JSON").action(async (projectDir, opts) => {
258
+ program.command("build [project-dir]").description(
259
+ 'Build an OpenHarmony or HarmonyOS app via hvigorw. Defaults to the current directory. Projects declaring runtimeOS "HarmonyOS" build against the HarmonyOS SDK (ONIRO_HARMONYOS_SDK_PATH or an installed DevEco Studio).'
260
+ ).option("--product <product>", "hvigor product name", "default").option("--module <module>", "restrict the build to a specific module").option("--mode <mode>", "hvigor build mode (e.g. release, debug)").option("--task <task>", "hvigor task to run", "assembleHap").option("--no-deps", "skip the automatic `ohpm install --all` when oh_modules/ is missing").option("--no-parallel", "build modules serially (default: parallel)").option("--json", "emit the build result (discovered HAPs, warnings) as JSON").action(async (projectDir, opts) => {
256
261
  const { config, logger } = getRuntime();
257
262
  const dir = path2.resolve(projectDir ?? process.cwd());
258
263
  logger.info(`Building project at ${dir}...`);
@@ -285,7 +290,11 @@ import * as path3 from "path";
285
290
  import {
286
291
  APL_VALUES,
287
292
  APP_FEATURE_VALUES,
293
+ OniroError,
294
+ createHarmonyOsSession,
295
+ detectRuntimeOs,
288
296
  generateSigningConfigs,
297
+ harmonyOsAutoSign,
289
298
  prepareSigning,
290
299
  getOhosBaseSdkHome
291
300
  } from "@oniroproject/core";
@@ -298,7 +307,9 @@ function registerSignCommand(program) {
298
307
  "Generate signing keys, certificates, and signingConfigs for an OpenHarmony project.",
299
308
  "Requires java on PATH. The generated profile uses the SDK's built-in development",
300
309
  "cert (issuer=pki_internal) and its bundled validity window \u2014 dev/local builds only.",
301
- "Overwrites the `signingConfigs` block in build-profile.json5 (other keys preserved)."
310
+ "Overwrites the `signingConfigs` block in build-profile.json5 (other keys preserved).",
311
+ "HarmonyOS projects need --harmonyos instead, which has AppGallery Connect issue the",
312
+ "certificate and profile for a signed-in Huawei account (`oniro-app auth login`)."
302
313
  ].join(" ")
303
314
  ).addOption(
304
315
  new Option(
@@ -315,10 +326,31 @@ function registerSignCommand(program) {
315
326
  "--acls <list>",
316
327
  "Comma-separated permission names to write into the profile's acls.allowed-acls. Required for apps that request permissions above their apl (e.g. a system_basic app requesting ohos.permission.CAPTURE_SCREEN). Example: --acls ohos.permission.REBOOT,ohos.permission.INJECT_INPUT_EVENT"
317
328
  ).argParser(parseAclsList)
318
- ).option("--bootstrap", "No-op if signing material is already present; otherwise generate it.").option("--store-password <pwd>", "Keystore store password (default 123456 \u2014 the SDK keystore password).").option("--key-password <pwd>", "Keystore key password (default 123456 \u2014 the SDK keystore password).").action(
319
- (projectDir, opts) => {
329
+ ).option(
330
+ "--harmonyos",
331
+ "Sign a HarmonyOS project through AppGallery Connect. Needs `oniro-app auth login`, and a connected device unless the team already has devices registered."
332
+ ).option("--team-id <id>", "With --harmonyos: the AGC team to sign under. Default: the account's own (`oniro-app auth team list`).").option("--product <name>", "With --harmonyos: the product to sign. Default `default`.").option("--force", "With --harmonyos: regenerate the certificate and profile even when they are still valid.").option("--bootstrap", "No-op if signing material is already present; otherwise generate it.").option("--store-password <pwd>", "Keystore store password (default 123456 \u2014 the SDK keystore password).").option("--key-password <pwd>", "Keystore key password (default 123456 \u2014 the SDK keystore password).").action(
333
+ async (projectDir, opts) => {
320
334
  const { config, logger } = getRuntime();
321
335
  const dir = path3.resolve(projectDir ?? process.cwd());
336
+ if (opts.harmonyos) {
337
+ const result = await harmonyOsAutoSign({
338
+ config,
339
+ session: createHarmonyOsSession({ config, logger }),
340
+ projectDir: dir,
341
+ productName: opts.product,
342
+ teamId: opts.teamId,
343
+ force: opts.force,
344
+ logger
345
+ });
346
+ logger.info(`Signing configs ready for ${result.bundleName} (profile names ${result.deviceIds.length} device(s)).`);
347
+ return;
348
+ }
349
+ if (detectRuntimeOs(dir, opts.product) === "HarmonyOS") {
350
+ throw new OniroError(
351
+ `${dir} targets HarmonyOS, which needs a certificate from AppGallery Connect: run \`oniro-app auth login\` once, then \`oniro-app sign --harmonyos\`.`
352
+ );
353
+ }
322
354
  const passwords = opts.storePassword || opts.keyPassword ? { store: opts.storePassword ?? "123456", key: opts.keyPassword ?? "123456" } : void 0;
323
355
  if (opts.bootstrap) {
324
356
  const result = prepareSigning({
@@ -349,6 +381,68 @@ function registerSignCommand(program) {
349
381
  );
350
382
  }
351
383
 
384
+ // src/commands/auth.ts
385
+ import { HUAWEI_SITES, createHarmonyOsSession as createHarmonyOsSession2 } from "@oniroproject/core";
386
+ function session() {
387
+ const { config, logger } = getRuntime();
388
+ return createHarmonyOsSession2({
389
+ config,
390
+ logger,
391
+ onLoginUrl: (url) => process.stderr.write(`Opening the Huawei sign-in page. If no browser opens, visit:
392
+ ${url}
393
+ `)
394
+ });
395
+ }
396
+ function registerAuthCommand(program) {
397
+ const auth = program.command("auth").description(
398
+ "Sign in to a Huawei developer account, which HarmonyOS signing (`oniro-app sign --harmonyos`) needs. OpenHarmony signing needs no account. The token is stored encrypted under ONIRO_HARMONYOS_AUTH_DIR (default ~/.oniro/harmonyos)."
399
+ );
400
+ auth.command("login").description("Sign in through the browser, which redirects back to a loopback port on this machine.").option("--timeout <seconds>", "How long to wait for the browser sign-in. Default 600.", (v) => Number(v)).action(async (opts) => {
401
+ const user = await session().login(opts.timeout ? { timeoutMs: Math.max(1, opts.timeout) * 1e3 } : void 0);
402
+ process.stdout.write(`${user.userName || user.userId}
403
+ `);
404
+ });
405
+ auth.command("logout").description("Sign out and delete the stored token.").action(async () => {
406
+ const signedOut = await session().logout();
407
+ getRuntime().logger.info(signedOut ? "Signed out." : "Not signed in; nothing to do.");
408
+ });
409
+ auth.command("status").description("Show the signed-in account. Exits non-zero when not signed in.").option("--json", "Emit the account details as JSON.").action(async (opts) => {
410
+ const s = session();
411
+ const user = await s.getUserInfo({ refresh: true });
412
+ if (!user) {
413
+ process.stderr.write("Not signed in. Run `oniro-app auth login`.\n");
414
+ process.exitCode = 1;
415
+ return;
416
+ }
417
+ const agreement = user.isRealName ? null : await s.getDeveloperAgreement(user);
418
+ if (opts.json) {
419
+ const { userId, userName, countryCode, siteCode, isRealName } = user;
420
+ const agcBaseUrl = HUAWEI_SITES[siteCode].agcBaseUrl;
421
+ const status = { userId, userName, countryCode, site: siteCode, agcBaseUrl, isRealName, developerAgreement: agreement, tokenPath: s.tokenPath };
422
+ process.stdout.write(`${JSON.stringify(status, null, 2)}
423
+ `);
424
+ return;
425
+ }
426
+ process.stdout.write(`${user.userName || user.userId} (${user.userId}) [${user.siteCode}]
427
+ `);
428
+ if (agreement && !(agreement.signed && agreement.latest)) {
429
+ process.stderr.write(
430
+ "[warn] This account has neither real-name verification nor the current HUAWEI Developer Basic Service Agreement accepted, so AppGallery Connect will not issue signing material. Accept the agreement in AppGallery Connect or DevEco Studio.\n"
431
+ );
432
+ }
433
+ });
434
+ auth.command("team").description("AGC teams this account belongs to.").command("list").description("List the AGC teams this account belongs to, for `oniro-app sign --harmonyos --team-id <id>`.").option("--json", "Emit the team list as JSON.").action(async (opts) => {
435
+ const teams = await session().listTeams();
436
+ if (opts.json) {
437
+ process.stdout.write(`${JSON.stringify(teams, null, 2)}
438
+ `);
439
+ return;
440
+ }
441
+ for (const t of teams) process.stdout.write(`${t.id} ${t.name}
442
+ `);
443
+ });
444
+ }
445
+
352
446
  // src/commands/app.ts
353
447
  import * as path4 from "path";
354
448
  import { installApp, launchApp, uninstallApp, forceStop, applyChanges, getBundleName } from "@oniroproject/core";
@@ -443,7 +537,7 @@ function getBundledTemplateRoot() {
443
537
 
444
538
  // src/commands/create.ts
445
539
  function registerCreateCommand(program) {
446
- program.command("create").description("Scaffold a new Oniro/OpenHarmony app from a template. All flags are required (non-interactive).").requiredOption("--name <name>", "Project folder name (letters, digits, ._- only)").requiredOption("--bundle <bundleName>", "Bundle name in reverse-DNS form, e.g. com.example.myapp").requiredOption("--location <dir>", "Parent directory where the new project folder will be created").requiredOption("--sdk <api>", "Target SDK API level (e.g. 18, 20)").option("--template <id>", "Template id", "EmptyAbility").option("--module <name>", "Module folder name (defaults to the template default, usually `entry`)").option("--overwrite", "Replace the destination if it already exists").action(async (opts) => {
540
+ program.command("create").description("Scaffold a new Oniro/OpenHarmony or HarmonyOS app from a template. All flags are required (non-interactive).").requiredOption("--name <name>", "Project folder name (letters, digits, ._- only)").requiredOption("--bundle <bundleName>", "Bundle name in reverse-DNS form, e.g. com.example.myapp").requiredOption("--location <dir>", "Parent directory where the new project folder will be created").requiredOption("--sdk <api>", "Target SDK API level (e.g. 18, 20)").option("--template <id>", "Template id", "EmptyAbility").option("--module <name>", "Module folder name (defaults to the template default, usually `entry`)").option("--overwrite", "Replace the destination if it already exists").action(async (opts) => {
447
541
  const { config, logger } = getRuntime();
448
542
  if (!isValidProjectName(opts.name)) {
449
543
  throw new Error(`Invalid --name '${opts.name}'. Use letters/numbers/._- and no slashes.`);
@@ -901,7 +995,7 @@ function registerInputCommand(program) {
901
995
  }
902
996
 
903
997
  // src/bin/oniro-app.ts
904
- var CLI_VERSION = "0.10.0";
998
+ var CLI_VERSION = "0.12.0";
905
999
  function buildProgram() {
906
1000
  const program = new Command4().name("oniro-app").description(
907
1001
  "Cross-platform CLI for Oniro/OpenHarmony app development.\n\nDesigned for non-interactive use (CI, scripts, agents): every command\ntakes explicit flags, results go to stdout, progress/logs go to stderr,\nand a non-zero exit code indicates failure."
@@ -911,6 +1005,7 @@ function buildProgram() {
911
1005
  registerEmulatorCommand(program);
912
1006
  registerBuildCommand(program);
913
1007
  registerSignCommand(program);
1008
+ registerAuthCommand(program);
914
1009
  registerAppCommand(program);
915
1010
  registerCreateCommand(program);
916
1011
  registerTemplatesCommand(program);
@@ -930,7 +1025,7 @@ async function main() {
930
1025
  try {
931
1026
  await program.parseAsync(process.argv);
932
1027
  } catch (err) {
933
- const message = err instanceof OniroError ? err.message : err instanceof Error ? err.message : String(err);
1028
+ const message = err instanceof OniroError2 ? err.message : err instanceof Error ? err.message : String(err);
934
1029
  process.stderr.write(`[error] ${message}
935
1030
  `);
936
1031
  if (process.env.ONIRO_DEBUG === "1" && err instanceof Error && err.stack) {