expo-harmony-toolkit 1.5.2 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <div align="center">
2
2
  <h1>Expo Harmony Toolkit</h1>
3
3
  <p><strong>A HarmonyOS migration, admission, and UI-stack build toolkit for Managed/CNG Expo projects.</strong></p>
4
- <p>One validated UI-stack matrix, explicit dependency admission rules, managed Harmony sidecar scaffolding, and a toolkit-driven <code>doctor → init → bundle → build-hap</code> path.</p>
4
+ <p>One verified UI-stack matrix, additive preview/experimental capability tiers, managed Harmony sidecar scaffolding, and a toolkit-driven <code>doctor → init → bundle → build-hap</code> path.</p>
5
5
  <p>
6
6
  <a href="./README.md">简体中文</a> ·
7
7
  <a href="./README.en.md">English</a>
@@ -9,13 +9,14 @@
9
9
  <p>
10
10
  <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/actions/workflows/ci.yml"><img alt="Checks" src="https://img.shields.io/badge/checks-passing-16a34a?style=flat-square&logo=githubactions&logoColor=white"></a>
11
11
  <a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-0f766e?style=flat-square"></a>
12
- <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.5.2-111827?style=flat-square"></a>
12
+ <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.6.0-111827?style=flat-square"></a>
13
13
  <a href="./docs/support-matrix.md"><img alt="Matrix" src="https://img.shields.io/badge/matrix-expo55--rnoh082--ui--stack-2563eb?style=flat-square"></a>
14
14
  <img alt="Input" src="https://img.shields.io/badge/input-Managed%2FCNG-059669?style=flat-square">
15
15
  </p>
16
16
  <p>
17
17
  <a href="./docs/support-matrix.md">Support Matrix</a> ·
18
18
  <a href="./docs/cli-build.md">CLI Build Guide</a> ·
19
+ <a href="./docs/official-native-capabilities-sample.md">Official Native Capabilities Sample</a> ·
19
20
  <a href="./docs/official-ui-stack-sample.md">Official UI Stack Sample</a> ·
20
21
  <a href="./docs/npm-release.md">npm Release Notes</a> ·
21
22
  <a href="./docs/roadmap.md">Roadmap</a>
@@ -23,14 +24,14 @@
23
24
  </div>
24
25
 
25
26
  > [!IMPORTANT]
26
- > `v1.5.2` continues to make one formal public promise only: `expo55-rnoh082-ui-stack`. This is not a claim that arbitrary Expo applications can be published to HarmonyOS unchanged.
27
+ > Starting with `v1.6`, the toolkit exposes `verified + preview + experimental` support tiers. `expo55-rnoh082-ui-stack` remains the only `verified` public matrix, while `expo-file-system` and `expo-image-picker` move into `preview`. This is still not a claim that arbitrary Expo apps can be published to HarmonyOS unchanged.
27
28
 
28
29
  > [!TIP]
29
30
  > The two validated `@react-native-oh-tpl/*` adapters in the public matrix are currently consumed via exact Git URLs and commits. For repository development and the official UI-stack sample, prefer `pnpm install --ignore-scripts` so adapter prepare hooks do not fail on private upstream resources.
30
31
 
31
32
  ## Overview
32
33
 
33
- `expo-harmony-toolkit` provides a constrained, verifiable Expo-to-Harmony toolchain:
34
+ `expo-harmony-toolkit` provides a constrained, verifiable Expo-to-Harmony toolchain and now starts exposing preview-tier native capability bridges:
34
35
 
35
36
  - Expo config plugin entrypoint `app.plugin.js`
36
37
  - `expo-harmony doctor`
@@ -46,20 +47,23 @@
46
47
 
47
48
  | Item | Status |
48
49
  | --- | --- |
49
- | Current version | `v1.5.2` |
50
- | Public matrix | `expo55-rnoh082-ui-stack` |
50
+ | Current version | `v1.6.0` |
51
+ | Support model | `verified + preview + experimental` |
52
+ | Public `verified` matrix | `expo55-rnoh082-ui-stack` |
51
53
  | Supported input | Managed/CNG Expo projects |
52
- | Validated JS/UI capabilities | `expo-router`, `expo-linking`, `expo-constants`, `react-native-reanimated`, `react-native-svg` |
54
+ | `verified` JS/UI capabilities | `expo-router`, `expo-linking`, `expo-constants`, `react-native-reanimated`, `react-native-svg` |
55
+ | `preview` native capabilities | `expo-file-system`, `expo-image-picker` |
56
+ | `experimental` capabilities | `expo-location`, `expo-camera`, `expo-notifications`, `react-native-gesture-handler` |
53
57
  | Build path | `doctor -> init -> bundle -> build-hap` |
54
58
  | Primary sample | `examples/official-ui-stack-sample` |
59
+ | Preview sample | `examples/official-native-capabilities-sample` |
55
60
  | Regression baselines | `examples/official-app-shell-sample`, `examples/official-minimal-sample` |
56
61
 
57
62
  <details>
58
- <summary><strong>Currently out of scope</strong></summary>
63
+ <summary><strong>Still outside the verified public promise</strong></summary>
59
64
 
60
65
  - bare Expo
61
- - `expo-image-picker`
62
- - `expo-file-system`
66
+ - `expo-file-system` and `expo-image-picker` remain `preview`
63
67
  - `expo-location`
64
68
  - `expo-camera`
65
69
  - `expo-notifications`
@@ -130,6 +134,7 @@ Notes:
130
134
  cd /path/to/app
131
135
  pnpm exec expo-harmony doctor --project-root .
132
136
  pnpm exec expo-harmony doctor --project-root . --strict
137
+ pnpm exec expo-harmony doctor --project-root . --target-tier preview
133
138
  ```
134
139
 
135
140
  2. Generate or refresh the managed Harmony sidecar:
@@ -157,24 +162,20 @@ pnpm exec expo-harmony build-hap --mode release
157
162
  Common decision points:
158
163
 
159
164
  - Want to know whether the current project still matches the public matrix: run `doctor --strict`
165
+ - Want to know whether the project at least falls into preview / experimental tiers: run `doctor --target-tier preview` or `doctor --target-tier experimental`
160
166
  - Changed dependencies, Expo config, or plugin wiring: run `sync-template`
161
167
  - Only want to verify JavaScript/UI portability: run `bundle`
162
168
  - About to open DevEco Studio or build a HAP locally: run `env` first
163
169
 
164
170
  ## Support Matrix
165
171
 
166
- `v1.5.2` stays on one public matrix: `expo55-rnoh082-ui-stack`.
172
+ `v1.6` moves to tiered support:
167
173
 
168
- - Expo SDK: `55`
169
- - React: `19.1.1`
170
- - React Native: `0.82.1`
171
- - RNOH and `@react-native-oh/react-native-harmony-cli`: `0.82.18`
172
- - App Shell packages: `expo-router`, `expo-linking`, `expo-constants`
173
- - UI stack packages: `react-native-reanimated`, `react-native-svg`
174
- - Harmony adapters: the matching `@react-native-oh-tpl/*` exact Git specifiers
175
- - Native identifier: at least `android.package` or `ios.bundleIdentifier`
174
+ - `verified`: the only public matrix remains `expo55-rnoh082-ui-stack`
175
+ - `preview`: `expo-file-system`, `expo-image-picker`
176
+ - `experimental`: `expo-location`, `expo-camera`, `expo-notifications`, `react-native-gesture-handler`
176
177
 
177
- `react-native-gesture-handler` is no longer part of the public matrix. It remains a manual exploration path until the current `@react-native-oh-tpl/react-native-gesture-handler` and `@react-native-oh/react-native-harmony@0.82.18` runtime pairing passes on-device validation.
178
+ `doctor --strict` still means `verified` only. `doctor --target-tier preview` allows the same runtime matrix plus preview-tier capabilities, but that does not promote them into the formal public promise.
178
179
 
179
180
  See [docs/support-matrix.md](./docs/support-matrix.md) for the full allowlist, pairing rules, exact specifiers, issue codes, and release gates.
180
181
 
@@ -182,6 +183,8 @@ See [docs/support-matrix.md](./docs/support-matrix.md) for the full allowlist, p
182
183
 
183
184
  - `examples/official-ui-stack-sample`
184
185
  The primary public sample for `v1.5.0`, covering router, linking, constants, SVG, reanimated, and Harmony sidecar build flow.
186
+ - `examples/official-native-capabilities-sample`
187
+ The new preview sample for `v1.6`, covering the `expo-file-system` and `expo-image-picker` bridge, permission generation, and bundle-time alias flow.
185
188
  - `examples/official-app-shell-sample`
186
189
  The `v1.1` App Shell regression baseline that protects router behavior while UI-stack support is finalized.
187
190
  - `examples/official-minimal-sample`
@@ -189,6 +192,7 @@ See [docs/support-matrix.md](./docs/support-matrix.md) for the full allowlist, p
189
192
 
190
193
  See:
191
194
 
195
+ - [Official Native Capabilities Sample Guide](./docs/official-native-capabilities-sample.md)
192
196
  - [Official UI Stack Sample Guide](./docs/official-ui-stack-sample.md)
193
197
  - [Official App Shell Sample Guide](./docs/official-app-shell-sample.md)
194
198
  - [Official Minimal Sample Guide](./docs/official-minimal-sample.md)
@@ -199,6 +203,7 @@ See:
199
203
  | --- | --- |
200
204
  | `expo-harmony doctor` | Inspect Expo config and dependencies and produce a migration report |
201
205
  | `expo-harmony doctor --strict` | Run the formal matrix admission gate |
206
+ | `expo-harmony doctor --target-tier preview` | Evaluate whether the project fits at least the preview support tier |
202
207
  | `expo-harmony init` | Generate Harmony sidecar files, autolinking artifacts, metadata, and package scripts |
203
208
  | `expo-harmony sync-template` | Reapply managed templates and report drift |
204
209
  | `expo-harmony env` | Check the local DevEco / hvigor / hdc / signing environment |
@@ -242,6 +247,7 @@ Manual Harmony acceptance still requires:
242
247
  - pressing the home-screen motion rail triggers visible animation
243
248
  - routing still works after the animation completes
244
249
  - `Build Debug Hap(s)` succeeds
250
+ - `official-native-capabilities-sample` at least proves preview route bundling and generated Harmony permissions
245
251
 
246
252
  See [docs/npm-release.md](./docs/npm-release.md) and [docs/signing-and-release.md](./docs/signing-and-release.md).
247
253
 
@@ -249,6 +255,7 @@ See [docs/npm-release.md](./docs/npm-release.md) and [docs/signing-and-release.m
249
255
 
250
256
  - [Support Matrix](./docs/support-matrix.md)
251
257
  - [CLI Build Guide](./docs/cli-build.md)
258
+ - [Official Native Capabilities Sample Guide](./docs/official-native-capabilities-sample.md)
252
259
  - [Official UI Stack Sample Guide](./docs/official-ui-stack-sample.md)
253
260
  - [Official App Shell Sample Guide](./docs/official-app-shell-sample.md)
254
261
  - [Official Minimal Sample Guide](./docs/official-minimal-sample.md)
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <div align="center">
2
2
  <h1>Expo Harmony Toolkit</h1>
3
3
  <p><strong>面向 Managed/CNG Expo 项目的 HarmonyOS 迁移、准入检查与 UI-stack 构建工具链。</strong></p>
4
- <p>One validated UI-stack matrix, explicit dependency admission rules, managed Harmony sidecar scaffolding, and a toolkit-driven <code>doctor → init → bundle → build-hap</code> path.</p>
4
+ <p>One verified UI-stack matrix, additive preview/experimental capability tiers, managed Harmony sidecar scaffolding, and a toolkit-driven <code>doctor → init → bundle → build-hap</code> path.</p>
5
5
  <p>
6
6
  <a href="./README.md">简体中文</a> ·
7
7
  <a href="./README.en.md">English</a>
@@ -9,13 +9,14 @@
9
9
  <p>
10
10
  <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/actions/workflows/ci.yml"><img alt="Checks" src="https://img.shields.io/badge/checks-passing-16a34a?style=flat-square&logo=githubactions&logoColor=white"></a>
11
11
  <a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-0f766e?style=flat-square"></a>
12
- <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.5.2-111827?style=flat-square"></a>
12
+ <a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.6.0-111827?style=flat-square"></a>
13
13
  <a href="./docs/support-matrix.md"><img alt="Matrix" src="https://img.shields.io/badge/matrix-expo55--rnoh082--ui--stack-2563eb?style=flat-square"></a>
14
14
  <img alt="Input" src="https://img.shields.io/badge/input-Managed%2FCNG-059669?style=flat-square">
15
15
  </p>
16
16
  <p>
17
17
  <a href="./docs/support-matrix.md">支持矩阵</a> ·
18
18
  <a href="./docs/cli-build.md">CLI 构建指南</a> ·
19
+ <a href="./docs/official-native-capabilities-sample.md">官方 Native Capabilities Sample</a> ·
19
20
  <a href="./docs/official-ui-stack-sample.md">官方 UI Stack Sample</a> ·
20
21
  <a href="./docs/npm-release.md">npm 发布说明</a> ·
21
22
  <a href="./docs/roadmap.md">路线图</a>
@@ -23,14 +24,14 @@
23
24
  </div>
24
25
 
25
26
  > [!IMPORTANT]
26
- > `v1.5.2` 继续只对 `expo55-rnoh082-ui-stack` 做正式公开承诺。这不是“任意 Expo 项目都能原样发布到 HarmonyOS”的声明,而是对一条受限、可验证矩阵的稳定承诺。
27
+ > `v1.6` 开始,toolkit 采用 `verified + preview + experimental` 三层支持模型。`expo55-rnoh082-ui-stack` 仍是唯一 `verified` 公开矩阵;`expo-file-system` 与 `expo-image-picker` 进入 `preview`,但这仍然不是“任意 Expo 项目都能原样发布到 HarmonyOS”的声明。
27
28
 
28
29
  > [!TIP]
29
30
  > 由于当前公开矩阵内的两套 `@react-native-oh-tpl/*` adapter 依赖以 Git URL + exact commit 形式接入,仓库开发和官方 UI-stack sample 推荐使用 `pnpm install --ignore-scripts`,避免 Git adapter 在 prepare 阶段拉取私有资源而中断安装。
30
31
 
31
32
  ## 概览
32
33
 
33
- `expo-harmony-toolkit` 提供一条围绕 Expo 到 HarmonyOS 迁移的受限、可验证工具链:
34
+ `expo-harmony-toolkit` 提供一条围绕 Expo 到 HarmonyOS 迁移的受限、可验证工具链,并开始公开 preview 层的原生能力桥接骨架:
34
35
 
35
36
  - Expo config plugin 根入口 `app.plugin.js`
36
37
  - `expo-harmony doctor`
@@ -46,20 +47,23 @@
46
47
 
47
48
  | 项目 | 说明 |
48
49
  | --- | --- |
49
- | 当前版本 | `v1.5.2` |
50
- | 唯一公开矩阵 | `expo55-rnoh082-ui-stack` |
50
+ | 当前版本 | `v1.6.0` |
51
+ | 支持模型 | `verified + preview + experimental` |
52
+ | 唯一 `verified` 公开矩阵 | `expo55-rnoh082-ui-stack` |
51
53
  | 输入范围 | Managed/CNG Expo 项目 |
52
- | 已验证 JS/UI 能力 | `expo-router`、`expo-linking`、`expo-constants`、`react-native-reanimated`、`react-native-svg` |
54
+ | `verified` JS/UI 能力 | `expo-router`、`expo-linking`、`expo-constants`、`react-native-reanimated`、`react-native-svg` |
55
+ | `preview` 原生能力 | `expo-file-system`、`expo-image-picker` |
56
+ | `experimental` 能力 | `expo-location`、`expo-camera`、`expo-notifications`、`react-native-gesture-handler` |
53
57
  | 构建链 | `doctor -> init -> bundle -> build-hap` |
54
58
  | 主 sample | `examples/official-ui-stack-sample` |
59
+ | preview sample | `examples/official-native-capabilities-sample` |
55
60
  | 回归基线 | `examples/official-app-shell-sample`、`examples/official-minimal-sample` |
56
61
 
57
62
  <details>
58
- <summary><strong>当前不在承诺范围</strong></summary>
63
+ <summary><strong>当前仍不在 verified 正式承诺范围</strong></summary>
59
64
 
60
65
  - bare Expo
61
- - `expo-image-picker`
62
- - `expo-file-system`
66
+ - `expo-file-system`、`expo-image-picker` 仍只属于 `preview`
63
67
  - `expo-location`
64
68
  - `expo-camera`
65
69
  - `expo-notifications`
@@ -130,6 +134,7 @@ pnpm install --ignore-scripts
130
134
  cd /path/to/app
131
135
  pnpm exec expo-harmony doctor --project-root .
132
136
  pnpm exec expo-harmony doctor --project-root . --strict
137
+ pnpm exec expo-harmony doctor --project-root . --target-tier preview
133
138
  ```
134
139
 
135
140
  2. 生成或刷新受管 Harmony sidecar:
@@ -157,24 +162,20 @@ pnpm exec expo-harmony build-hap --mode release
157
162
  常见使用判断:
158
163
 
159
164
  - 想知道当前项目是否还在公开矩阵里:跑 `doctor --strict`
165
+ - 想知道项目是否只落在 preview / experimental:跑 `doctor --target-tier preview` 或 `doctor --target-tier experimental`
160
166
  - 刚改过依赖、Expo 配置或插件:先跑 `sync-template`
161
167
  - 只想验证 JS/UI 侧是否能打包:跑 `bundle`
162
168
  - 准备进 DevEco Studio 或本机构建 HAP:先跑 `env`
163
169
 
164
170
  ## 支持矩阵
165
171
 
166
- `v1.5.2` 继续坚持单矩阵路线:`expo55-rnoh082-ui-stack`。
172
+ `v1.6` 开始改成支持分层:
167
173
 
168
- - Expo SDK:`55`
169
- - React:`19.1.1`
170
- - React Native:`0.82.1`
171
- - RNOH / `@react-native-oh/react-native-harmony-cli`:`0.82.18`
172
- - App Shell 依赖:`expo-router`、`expo-linking`、`expo-constants`
173
- - UI stack 依赖:`react-native-reanimated`、`react-native-svg`
174
- - Harmony adapter:对应两项 `@react-native-oh-tpl/*` exact Git specifier
175
- - 原生标识:至少配置 `android.package` 或 `ios.bundleIdentifier`
174
+ - `verified`:唯一公开矩阵仍是 `expo55-rnoh082-ui-stack`
175
+ - `preview`:`expo-file-system`、`expo-image-picker`
176
+ - `experimental`:`expo-location`、`expo-camera`、`expo-notifications`、`react-native-gesture-handler`
176
177
 
177
- 当前不再把 `react-native-gesture-handler` 放进公开矩阵。它仍可作为手动探索项,但当前 `@react-native-oh-tpl/react-native-gesture-handler` `@react-native-oh/react-native-harmony@0.82.18` 的设备侧 runtime 组合还没有通过正式验收。
178
+ `doctor --strict` 继续只代表 `verified`。`doctor --target-tier preview` 会在同一 runtime matrix 下额外放行 preview 能力,但这不等于它们已经进入正式承诺。
178
179
 
179
180
  完整白名单、配对规则、exact specifier、issue code 与 release gate 见 [docs/support-matrix.md](./docs/support-matrix.md)。
180
181
 
@@ -182,6 +183,8 @@ pnpm exec expo-harmony build-hap --mode release
182
183
 
183
184
  - `examples/official-ui-stack-sample`
184
185
  当前唯一对外主 sample,同时覆盖 router、linking、constants、SVG、reanimated 和 Harmony sidecar 构建链。
186
+ - `examples/official-native-capabilities-sample`
187
+ v1.6 新增的 preview sample,用来承接 `expo-file-system` 与 `expo-image-picker` 的 bridge、permission 与 bundle 骨架验收。
185
188
  - `examples/official-app-shell-sample`
186
189
  `v1.1` App Shell 回归基线,用来防止 UI-stack 收口引入 router 退化。
187
190
  - `examples/official-minimal-sample`
@@ -190,6 +193,7 @@ pnpm exec expo-harmony build-hap --mode release
190
193
  详见:
191
194
 
192
195
  - [官方 UI Stack sample 指南](./docs/official-ui-stack-sample.md)
196
+ - [官方 Native Capabilities sample 指南](./docs/official-native-capabilities-sample.md)
193
197
  - [官方 App Shell sample 指南](./docs/official-app-shell-sample.md)
194
198
  - [官方最小 sample 指南](./docs/official-minimal-sample.md)
195
199
 
@@ -199,6 +203,7 @@ pnpm exec expo-harmony build-hap --mode release
199
203
  | --- | --- |
200
204
  | `expo-harmony doctor` | 扫描 Expo 配置与依赖,输出迁移报告 |
201
205
  | `expo-harmony doctor --strict` | 将当前矩阵准入检查作为正式 gate 执行 |
206
+ | `expo-harmony doctor --target-tier preview` | 在同一 runtime matrix 下评估项目是否至少落在 `preview` 能力层 |
202
207
  | `expo-harmony init` | 生成 Harmony sidecar、autolinking 产物、metadata 与 package scripts |
203
208
  | `expo-harmony sync-template` | 再次应用受管模板并检查 drift |
204
209
  | `expo-harmony env` | 检查 DevEco / hvigor / hdc / signing 本地环境 |
@@ -242,6 +247,7 @@ pnpm exec expo-harmony build-hap --mode release
242
247
  - 点击首页 motion rail 后能触发可见动画
243
248
  - 动画完成后路由跳转仍正常
244
249
  - `Build Debug Hap(s)` 成功
250
+ - `official-native-capabilities-sample` 至少完成 preview route 的 bundle 与 permission 产物检查
245
251
 
246
252
  详见 [docs/npm-release.md](./docs/npm-release.md) 与 [docs/signing-and-release.md](./docs/signing-and-release.md)。
247
253
 
@@ -249,6 +255,7 @@ pnpm exec expo-harmony build-hap --mode release
249
255
 
250
256
  - [支持矩阵](./docs/support-matrix.md)
251
257
  - [CLI 构建指南](./docs/cli-build.md)
258
+ - [官方 Native Capabilities sample 指南](./docs/official-native-capabilities-sample.md)
252
259
  - [官方 UI Stack sample 指南](./docs/official-ui-stack-sample.md)
253
260
  - [官方 App Shell sample 指南](./docs/official-app-shell-sample.md)
254
261
  - [官方最小 sample 指南](./docs/official-minimal-sample.md)
package/build/cli.js CHANGED
@@ -25,7 +25,8 @@ async function run(argv = process.argv) {
25
25
  .command('doctor')
26
26
  .description('Inspect an Expo project and classify dependencies against the Harmony migration matrix')
27
27
  .option('-p, --project-root <path>', 'path to the Expo project')
28
- .option('--strict', 'return a non-zero exit code when the project falls outside the validated v1.5 matrix')
28
+ .option('--strict', 'return a non-zero exit code when the project falls outside the validated verified matrix')
29
+ .option('--target-tier <tier>', 'evaluate the project against verified, preview, or experimental support tiers')
29
30
  .option('--json', 'print JSON instead of a human-readable report')
30
31
  .option('-o, --output <path>', 'write the JSON report to a file')
31
32
  .action(doctor_1.runDoctorCommand);
@@ -1,7 +1,9 @@
1
+ import { DoctorTargetTier } from '../types';
1
2
  export interface DoctorCommandOptions {
2
3
  projectRoot?: string;
3
4
  strict?: boolean;
4
5
  json?: boolean;
5
6
  output?: string;
7
+ targetTier?: DoctorTargetTier | string;
6
8
  }
7
9
  export declare function runDoctorCommand(options: DoctorCommandOptions): Promise<void>;
@@ -9,7 +9,8 @@ const constants_1 = require("../core/constants");
9
9
  const report_1 = require("../core/report");
10
10
  async function runDoctorCommand(options) {
11
11
  const projectRoot = path_1.default.resolve(options.projectRoot ?? process.cwd());
12
- const report = await (0, report_1.buildDoctorReport)(projectRoot);
12
+ const targetTier = resolveDoctorTargetTier(options.targetTier, Boolean(options.strict));
13
+ const report = await (0, report_1.buildDoctorReport)(projectRoot, { targetTier });
13
14
  if (options.output) {
14
15
  await (0, report_1.writeDoctorReport)(projectRoot, report, path_1.default.resolve(options.output));
15
16
  }
@@ -22,3 +23,15 @@ async function runDoctorCommand(options) {
22
23
  }
23
24
  process.stdout.write((0, report_1.renderDoctorReport)(report) + '\n');
24
25
  }
26
+ function resolveDoctorTargetTier(targetTier, strict) {
27
+ if (strict) {
28
+ return 'verified';
29
+ }
30
+ if (!targetTier) {
31
+ return 'verified';
32
+ }
33
+ if (targetTier === 'verified' || targetTier === 'preview' || targetTier === 'experimental') {
34
+ return targetTier;
35
+ }
36
+ throw new Error(`Unsupported doctor target tier: ${targetTier}`);
37
+ }
@@ -1,6 +1,6 @@
1
1
  export declare const TOOLKIT_PACKAGE_NAME = "expo-harmony-toolkit";
2
2
  export declare const CLI_NAME = "expo-harmony";
3
- export declare const TOOLKIT_VERSION = "1.5.2";
3
+ export declare const TOOLKIT_VERSION = "1.6.0";
4
4
  export declare const TEMPLATE_VERSION = "rnoh-0.82.18";
5
5
  export declare const RNOH_VERSION = "0.82.18";
6
6
  export declare const RNOH_CLI_VERSION = "0.82.18";
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DESIRED_PACKAGE_SCRIPTS = exports.HARMONY_RUNTIME_PRELUDE_RELATIVE_PATH = exports.HARMONY_ROUTER_ENTRY_FILENAME = exports.STRICT_ENV_EXIT_CODE = exports.STRICT_DOCTOR_EXIT_CODE = exports.DEFAULT_HVIGOR_PLUGIN_FILENAME = exports.PREBUILD_METADATA_FILENAME = exports.TOOLKIT_CONFIG_FILENAME = exports.BUILD_REPORT_FILENAME = exports.ENV_REPORT_FILENAME = exports.DOCTOR_REPORT_FILENAME = exports.MANIFEST_FILENAME = exports.GENERATED_SHIMS_DIR = exports.GENERATED_DIR = exports.SUPPORTED_EXPO_SDKS = exports.RNOH_CLI_VERSION = exports.RNOH_VERSION = exports.TEMPLATE_VERSION = exports.TOOLKIT_VERSION = exports.CLI_NAME = exports.TOOLKIT_PACKAGE_NAME = void 0;
4
4
  exports.TOOLKIT_PACKAGE_NAME = 'expo-harmony-toolkit';
5
5
  exports.CLI_NAME = 'expo-harmony';
6
- exports.TOOLKIT_VERSION = '1.5.2';
6
+ exports.TOOLKIT_VERSION = '1.6.0';
7
7
  exports.TEMPLATE_VERSION = 'rnoh-0.82.18';
8
8
  exports.RNOH_VERSION = '0.82.18';
9
9
  exports.RNOH_CLI_VERSION = '0.82.18';
@@ -1,4 +1,6 @@
1
- import { DoctorReport } from '../types';
2
- export declare function buildDoctorReport(projectRoot: string): Promise<DoctorReport>;
1
+ import { DoctorTargetTier, DoctorReport } from '../types';
2
+ export declare function buildDoctorReport(projectRoot: string, options?: {
3
+ targetTier?: DoctorTargetTier;
4
+ }): Promise<DoctorReport>;
3
5
  export declare function writeDoctorReport(projectRoot: string, report: DoctorReport, outputPath?: string): Promise<string>;
4
6
  export declare function renderDoctorReport(report: DoctorReport): string;
@@ -12,18 +12,21 @@ const semver_1 = __importDefault(require("semver"));
12
12
  const constants_1 = require("./constants");
13
13
  const dependencyCatalog_1 = require("../data/dependencyCatalog");
14
14
  const validatedMatrices_1 = require("../data/validatedMatrices");
15
+ const capabilities_1 = require("../data/capabilities");
15
16
  const uiStack_1 = require("../data/uiStack");
16
17
  const metadata_1 = require("./metadata");
17
18
  const project_1 = require("./project");
18
19
  const constants_2 = require("./constants");
19
20
  const DEFAULT_RECORD = {
20
21
  status: 'unknown',
22
+ supportTier: 'unsupported',
21
23
  note: 'This dependency is not in the current compatibility catalog yet.',
22
24
  };
23
- async function buildDoctorReport(projectRoot) {
25
+ async function buildDoctorReport(projectRoot, options = {}) {
24
26
  const loadedProject = await (0, project_1.loadProject)(projectRoot);
25
27
  const expoSdkVersion = (0, project_1.detectExpoSdkVersion)(loadedProject.packageJson);
26
28
  const matrix = validatedMatrices_1.VALIDATED_RELEASE_MATRICES[validatedMatrices_1.DEFAULT_VALIDATED_MATRIX_ID];
29
+ const targetTier = options.targetTier ?? 'verified';
27
30
  const expoPlugins = (0, project_1.collectExpoPlugins)(loadedProject.expoConfig);
28
31
  const expoSchemes = (0, project_1.collectExpoSchemes)(loadedProject.expoConfig);
29
32
  const dependencyRecords = new Map();
@@ -37,7 +40,19 @@ async function buildDoctorReport(projectRoot) {
37
40
  }
38
41
  }
39
42
  const dependencies = [...dependencyRecords.values()].sort((left, right) => left.name.localeCompare(right.name));
40
- const blockingIssues = await collectBlockingIssues(loadedProject.projectRoot, loadedProject.expoConfig, loadedProject.packageJson, expoPlugins, expoSchemes, expoSdkVersion, dependencies, matrix);
43
+ const blockingIssues = await collectBlockingIssues(loadedProject.projectRoot, loadedProject.expoConfig, loadedProject.packageJson, expoPlugins, expoSchemes, expoSdkVersion, dependencies, matrix, targetTier);
44
+ const capabilities = (0, capabilities_1.getCapabilityDefinitionsForProject)(loadedProject.packageJson).map((definition) => ({
45
+ id: definition.id,
46
+ packageName: definition.packageName,
47
+ status: definition.status,
48
+ supportTier: definition.supportTier,
49
+ note: definition.note,
50
+ docsUrl: definition.docsUrl,
51
+ nativePackageNames: [...definition.nativePackageNames],
52
+ harmonyPermissions: [...definition.harmonyPermissions],
53
+ sampleRoute: definition.sampleRoute,
54
+ acceptanceChecklist: [...definition.acceptanceChecklist],
55
+ }));
41
56
  const blockingDependencyNames = new Set(blockingIssues
42
57
  .filter((issue) => issue.code.startsWith('dependency.') && issue.subject)
43
58
  .map((issue) => issue.subject));
@@ -58,6 +73,7 @@ async function buildDoctorReport(projectRoot) {
58
73
  rnohVersion: constants_1.RNOH_VERSION,
59
74
  rnohCliVersion: constants_1.RNOH_CLI_VERSION,
60
75
  expoSdkVersion,
76
+ targetTier,
61
77
  expoConfig: {
62
78
  name: loadedProject.expoConfig.name ?? null,
63
79
  slug: loadedProject.expoConfig.slug ?? null,
@@ -74,6 +90,13 @@ async function buildDoctorReport(projectRoot) {
74
90
  manual: resolvedDependencies.filter((dependency) => dependency.status === 'manual').length,
75
91
  unknown: resolvedDependencies.filter((dependency) => dependency.status === 'unknown').length,
76
92
  },
93
+ supportSummary: {
94
+ verified: resolvedDependencies.filter((dependency) => dependency.supportTier === 'verified').length,
95
+ preview: resolvedDependencies.filter((dependency) => dependency.supportTier === 'preview').length,
96
+ experimental: resolvedDependencies.filter((dependency) => dependency.supportTier === 'experimental').length,
97
+ unsupported: resolvedDependencies.filter((dependency) => dependency.supportTier === 'unsupported').length,
98
+ },
99
+ capabilities,
77
100
  blockingIssues,
78
101
  advisories,
79
102
  warnings,
@@ -92,19 +115,29 @@ function renderDoctorReport(report) {
92
115
  `Config: ${report.appConfigPath ?? 'not found'}`,
93
116
  `Expo SDK: ${report.expoSdkVersion ?? 'unknown'} (recognized ${constants_1.SUPPORTED_EXPO_SDKS.join(', ')})`,
94
117
  `Matrix: ${report.matrixId ?? 'none'}`,
118
+ `Target tier: ${report.targetTier}`,
95
119
  `Eligibility: ${report.eligibility}`,
96
120
  `Schemes: ${report.expoConfig.schemes.join(', ') || 'none'}`,
97
121
  `Plugins: ${report.expoConfig.plugins.join(', ') || 'none'}`,
98
122
  `RNOH template: ${report.templateVersion} / runtime ${report.rnohVersion}`,
99
123
  `Summary: ${report.summary.supported} supported, ${report.summary.manual} manual, ${report.summary.unknown} unknown (${report.summary.total} total)`,
124
+ `Support tiers: ${report.supportSummary.verified} verified, ${report.supportSummary.preview} preview, ${report.supportSummary.experimental} experimental, ${report.supportSummary.unsupported} unsupported`,
100
125
  '',
101
126
  `Dependencies:`,
102
127
  ...report.dependencies.map((dependency) => {
103
128
  const replacement = dependency.replacement ? ` | replacement: ${dependency.replacement}` : '';
104
129
  const blocking = dependency.blocking ? ' | blocking: yes' : '';
105
- return `- [${dependency.status}] ${dependency.name}@${dependency.version} (${dependency.source}) - ${dependency.note}${replacement}${blocking}`;
130
+ return `- [${dependency.status}/${dependency.supportTier}] ${dependency.name}@${dependency.version} (${dependency.source}) - ${dependency.note}${replacement}${blocking}`;
106
131
  }),
107
132
  ];
133
+ if (report.capabilities.length > 0) {
134
+ sections.push('', 'Capabilities:', ...report.capabilities.map((capability) => {
135
+ const permissions = capability.harmonyPermissions.length > 0
136
+ ? ` | permissions: ${capability.harmonyPermissions.join(', ')}`
137
+ : '';
138
+ return `- [${capability.status}/${capability.supportTier}] ${capability.packageName} -> ${capability.nativePackageNames.join(', ') || 'toolkit-managed bridge'} | sample: ${capability.sampleRoute}${permissions}`;
139
+ }));
140
+ }
108
141
  if (report.blockingIssues.length > 0) {
109
142
  sections.push('', 'Blocking issues:', ...report.blockingIssues.map((issue) => `- ${issue.code}: ${issue.message}${issue.subject ? ` (${issue.subject})` : ''}`));
110
143
  }
@@ -123,13 +156,14 @@ function createDependencyRecord(name, version, source) {
123
156
  version,
124
157
  source,
125
158
  status: matrixRecord.status,
159
+ supportTier: matrixRecord.supportTier,
126
160
  blocking: false,
127
161
  note: matrixRecord.note,
128
162
  replacement: matrixRecord.replacement,
129
163
  docsUrl: matrixRecord.docsUrl,
130
164
  };
131
165
  }
132
- async function collectBlockingIssues(projectRoot, expoConfig, packageJson, expoPlugins, expoSchemes, expoSdkVersion, dependencies, matrix) {
166
+ async function collectBlockingIssues(projectRoot, expoConfig, packageJson, expoPlugins, expoSchemes, expoSdkVersion, dependencies, matrix, targetTier) {
133
167
  const issues = [];
134
168
  const dependencyMap = new Map(dependencies.map((dependency) => [dependency.name, dependency]));
135
169
  if (expoSdkVersion !== matrix.expoSdkVersion) {
@@ -167,10 +201,10 @@ async function collectBlockingIssues(projectRoot, expoConfig, packageJson, expoP
167
201
  }
168
202
  }
169
203
  for (const dependency of dependencies) {
170
- if (!matrix.allowedDependencies.includes(dependency.name)) {
204
+ if (!isDependencyAllowedForTargetTier(dependency.name, matrix, targetTier)) {
171
205
  issues.push({
172
206
  code: 'dependency.not_allowed',
173
- message: `${dependency.name} is outside the validated ${matrix.id} allowlist.`,
207
+ message: `${dependency.name} is outside the ${targetTier} support tier for ${matrix.id}.`,
174
208
  subject: dependency.name,
175
209
  });
176
210
  }
@@ -282,6 +316,12 @@ function buildWarnings(expoConfig, expoSdkVersion, dependencies) {
282
316
  if (dependencies.some((dependency) => dependency.status === 'manual')) {
283
317
  warnings.push('Manual-review dependencies were detected. They remain outside the current validated matrix even though the toolkit can still scaffold exploratory files.');
284
318
  }
319
+ if (dependencies.some((dependency) => dependency.supportTier === 'preview')) {
320
+ warnings.push('Preview-tier dependencies were detected. The toolkit can scaffold and bundle them, but runtime behavior is not part of the verified public promise yet.');
321
+ }
322
+ if (dependencies.some((dependency) => dependency.supportTier === 'experimental')) {
323
+ warnings.push('Experimental-tier dependencies were detected. Expect bridge drift, runtime gaps, or additional manual validation before claiming release readiness.');
324
+ }
285
325
  if (dependencies.some((dependency) => dependency.status === 'unknown')) {
286
326
  warnings.push('Unknown dependencies were detected. The toolkit can scaffold the project, but runtime portability is not guaranteed.');
287
327
  }
@@ -294,6 +334,16 @@ function buildAdvisories(expoConfig) {
294
334
  }
295
335
  return advisories;
296
336
  }
337
+ function isDependencyAllowedForTargetTier(dependencyName, matrix, targetTier) {
338
+ if (matrix.allowedDependencies.includes(dependencyName)) {
339
+ return true;
340
+ }
341
+ const capability = capabilities_1.CAPABILITY_BY_PACKAGE[dependencyName];
342
+ if (!capability) {
343
+ return false;
344
+ }
345
+ return (0, capabilities_1.isSupportTierAllowed)(capability.supportTier, targetTier);
346
+ }
297
347
  function matchesVersionRange(rawVersion, range) {
298
348
  const coerced = semver_1.default.coerce(rawVersion);
299
349
  if (!coerced) {