@harmonyos-arkts/d2h 0.0.0-stage → 0.1.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/.claude-plugin/marketplace.json +13 -0
- package/.claude-plugin/plugin.json +7 -0
- package/README.md +168 -2
- package/agents/android-to-hmos-00-orchestrator.md +312 -0
- package/agents/d2h.md +168 -0
- package/bin/install-opencode.mjs +51 -0
- package/install-opencode.sh +160 -0
- package/opencode/agents.json +16 -0
- package/package.json +16 -4
- package/schemas/android-source-manifest.schema.json +25 -0
- package/schemas/checkpoint-provenance.schema.json +67 -0
- package/schemas/final-acceptance.schema.json +29 -0
- package/schemas/managed-evidence-index.schema.json +15 -0
- package/schemas/managed-evidence.schema.json +114 -0
- package/schemas/migration-config.schema.json +51 -0
- package/schemas/migration-report-index.schema.json +39 -0
- package/schemas/migration-report-item.schema.json +51 -0
- package/schemas/migration-report-summary.schema.json +25 -0
- package/schemas/migration-status.schema.json +202 -0
- package/schemas/preflight.schema.json +60 -0
- package/schemas/source-order-audit.schema.json +16 -0
- package/schemas/source-provenance-event.schema.json +19 -0
- package/schemas/spec-app-shard.schema.json +45 -0
- package/schemas/spec-fact-corrections-shard.schema.json +13 -0
- package/schemas/spec-features-shard.schema.json +43 -0
- package/schemas/spec-index.schema.json +26 -0
- package/schemas/spec-interactions-shard.schema.json +40 -0
- package/schemas/spec-page.schema.json +98 -0
- package/schemas/spec-pages-index.schema.json +1 -0
- package/schemas/spec-unresolved-shard.schema.json +1 -0
- package/schemas/task-envelope.schema.json +55 -0
- package/schemas/task-plan.schema.json +123 -0
- package/skills/android2hmos_resources_convert/SKILL.md +162 -0
- package/skills/android2hmos_resources_convert/references/image-conversion-rules.md +230 -0
- package/skills/android2hmos_resources_convert/references/svg-fix-patterns.md +175 -0
- package/skills/android2hmos_resources_convert/references/xml-drawable-to-svg-rules.md +513 -0
- package/skills/appgraph-rule-audit/SKILL.md +58 -0
- package/skills/appgraph-rule-audit/references/audit-contract.md +47 -0
- package/skills/appgraph-rule-audit/references/recommendation-schema.md +41 -0
- package/skills/appgraph-rule-audit/schemas/rule-opportunities.schema.json +125 -0
- package/skills/arkts-app-identity/SKILL.md +238 -0
- package/skills/arkts-i18n/SKILL.md +496 -0
- package/skills/arkts-i18n/evals/evals.json +84 -0
- package/skills/arkts-i18n/references/code-examples.md +302 -0
- package/skills/arkts-i18n/references/common-pitfalls.md +391 -0
- package/skills/arkts-i18n/references/dynamic-language-switch.md +604 -0
- package/skills/arkts-i18n/references/hardcoded-string-scanner.md +348 -0
- package/skills/arkts-i18n/references/language-codes.md +104 -0
- package/skills/arkts-i18n/references/resource-file-structure.md +775 -0
- package/skills/arkts-i18n/references/static-vs-dynamic.md +242 -0
- package/skills/arkts-i18n/references/v1-compat.md +244 -0
- package/skills/arkts-i18n/scripts/audit_i18n_completeness.sh +174 -0
- package/skills/arkts-icon-sizing/SKILL.md +211 -0
- package/skills/arkts-icon-sizing/scripts/icon_audit.py +131 -0
- package/skills/arkts-icon-sizing/scripts/icon_autofix.py +88 -0
- package/skills/arkts-icon-sizing/scripts/icon_dims.py +179 -0
- package/skills/arkts-icon-sizing/scripts/icon_fix.py +119 -0
- package/skills/arkts-mvvm-architecture/SKILL.md +613 -0
- package/skills/harmonyos-migration-playbook/SKILL.md +56 -0
- package/skills/harmonyos-migration-playbook/agents/openai.yaml +7 -0
- package/skills/harmonyos-migration-playbook/references/arkts-compile.md +24 -0
- package/skills/harmonyos-migration-playbook/references/harmony-runtime.md +53 -0
- package/skills/harmonyos-migration-playbook/references/lesson-lifecycle.md +45 -0
- package/skills/harmonyos-migration-playbook/references/protocol-e2e.md +23 -0
- package/skills/harmonyos-migration-playbook/references/ui-automation.md +52 -0
- package/skills/harmonyos-migration-playbook/references/windows-environment.md +38 -0
- package/skills/maintaining-migration-report/SKILL.md +155 -0
- package/skills/native-library-substitution/SKILL.md +385 -0
- package/skills/native-library-substitution/references/native-library-substitution.json +56906 -0
- package/skills/native-library-substitution/references/native-library-substitution.md +163 -0
- package/skills/preparing-migration-workspace/SKILL.md +124 -0
- package/skills/preparing-migration-workspace/toolchain.json +43 -0
- package/skills/reviewing-migration-process/SKILL.md +62 -0
- package/src/install-opencode.mjs +108 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Native Library Substitution 单一映射表
|
|
2
|
+
|
|
3
|
+
**数据版本**: 3.0.0
|
|
4
|
+
**更新日期**: 2026-04-22
|
|
5
|
+
|
|
6
|
+
## 数据概览
|
|
7
|
+
|
|
8
|
+
| 统计项 | 数量 |
|
|
9
|
+
|--------|------|
|
|
10
|
+
| 总映射数 | 2678 |
|
|
11
|
+
| 有安卓库的映射 | 1005 |
|
|
12
|
+
| 鸿蒙原生库(无安卓库) | 1673 |
|
|
13
|
+
| 唯一安卓库数 | 852 |
|
|
14
|
+
| 唯一ohpm包数 | 2537 |
|
|
15
|
+
|
|
16
|
+
## source_availability 分布
|
|
17
|
+
|
|
18
|
+
| 状态 | 数量 | 说明 |
|
|
19
|
+
|------|------|------|
|
|
20
|
+
| COMMERCIAL_PUBLIC | 175 | 闭源商业SDK(来自工作簿) |
|
|
21
|
+
| open_source | 2503 | 开源库 |
|
|
22
|
+
| not_set | 0 | 未设置 |
|
|
23
|
+
|
|
24
|
+
## source_type 分布
|
|
25
|
+
|
|
26
|
+
| 来源类型 | 数量 | 说明 |
|
|
27
|
+
|----------|------|------|
|
|
28
|
+
| 鸿蒙原生库 | 1321 | 鸿蒙原生开发,无对应安卓库 |
|
|
29
|
+
| TS/JS迁移库 | 790 | 从npm生态迁移 |
|
|
30
|
+
| 安卓鸿蒙化库 | 432 | 直接从安卓库移植 |
|
|
31
|
+
| C++/C鸿蒙化库 | 133 | 从C++生态迁移 |
|
|
32
|
+
|
|
33
|
+
## category 分布
|
|
34
|
+
|
|
35
|
+
| Category | 数量 | 说明 |
|
|
36
|
+
|----------|------|------|
|
|
37
|
+
| other | 1527 | 其他 |
|
|
38
|
+
| ui | 370 | UI组件 |
|
|
39
|
+
| utils | 213 | 工具类 |
|
|
40
|
+
| network | 209 | 网络请求 |
|
|
41
|
+
| media | 89 | 音视频 |
|
|
42
|
+
| auth | 61 | 登录认证 |
|
|
43
|
+
| notification | 60 | 推送通知 |
|
|
44
|
+
| storage | 60 | 存储文件 |
|
|
45
|
+
| location | 50 | 地图定位 |
|
|
46
|
+
| analytics | 17 | 统计分析 |
|
|
47
|
+
| payment | 16 | 支付 |
|
|
48
|
+
| security | 4 | 安全加密 |
|
|
49
|
+
| im | 1 | 即时通讯 |
|
|
50
|
+
| social | 1 | 社交分享 |
|
|
51
|
+
|
|
52
|
+
## 闭源库示例(COMMERCIAL_PUBLIC)
|
|
53
|
+
|
|
54
|
+
| 安卓库 | 鸿蒙包 | install_command |
|
|
55
|
+
|--------|--------|-----------------|
|
|
56
|
+
| com.tencent.mm.opensdk:wechat-sdk-androi | @tencent/wechat_open_sdk | `ohpm install @tencent/wechat_open_sdk` |
|
|
57
|
+
| com.sensorsdata.analytics.abtesting:Sens | @sensorsdata/analytics | `ohpm install @sensorsdata/analytics` |
|
|
58
|
+
| cn.admobiletop.adsuyi.ad.adapter:tianmu | @admobile/tianmu | `ohpm install @admobile/tianmu` |
|
|
59
|
+
| cn.admobiletop.adsuyi.ad:core | @admobile/tianmu | `ohpm install @admobile/tianmu` |
|
|
60
|
+
| io.hyphenate:hyphenate-chat | @easemob/chatsdk | `ohpm install @easemob/chatsdk` |
|
|
61
|
+
| com.aliyun.auikits.android:ARTCAICallKit | @aliyun_video_cloud/alivcsdk_artc | `ohpm install @aliyun_video_cloud/alivcsdk_artc` |
|
|
62
|
+
| com.aliyun.iot.aep.sdk:push | @aliyun/push | `ohpm install @aliyun/push` |
|
|
63
|
+
| com.aliyun.rum:alibabacloud-android-rum- | @alibabacloud_rum/harmony_sdk | `ohpm install @alibabacloud_rum/harmony_sdk` |
|
|
64
|
+
| com.alibaba.mtl:app-monitor-sdk | @alibabacloud_rum/harmony_sdk | `ohpm install @alibabacloud_rum/harmony_sdk` |
|
|
65
|
+
| com.aliyun.ams:alicloud-apm-crash-analys | @aliyun/apm | `ohpm install @aliyun/apm` |
|
|
66
|
+
| com.aliyun.dpa:oss-android-sdk | @aliyun/oss | `ohpm install @aliyun/oss` |
|
|
67
|
+
| afservicesdk | @cashier_alipay/cashiersdk | `ohpm install @cashier_alipay/cashiersdk` |
|
|
68
|
+
| com.alipay.sdk:alipaysdk-android | @cashier_alipay/cashiersdk | `ohpm install @cashier_alipay/cashiersdk` |
|
|
69
|
+
| io.github.yidun:livedetect | @yidun/alive | `ohpm install @yidun/alive` |
|
|
70
|
+
| io.github.aliyun-sls:aliyun-log-android- | @aliyun/logger | `ohpm install @aliyun/logger` |
|
|
71
|
+
| com.aliyun.ams:alicloud-android-push | @aliyun/push | `ohpm install @aliyun/push` |
|
|
72
|
+
| com.aliyun.ams:alicloud-android-third-pu | @aliyun/push | `ohpm install @aliyun/push` |
|
|
73
|
+
| com.aliyun.ams:alicloud-android-third-pu | @aliyun/push | `ohpm install @aliyun/push` |
|
|
74
|
+
| com.amap.api:3dmap | @amap/amap_lbs_map3d | `ohpm install @amap/amap_lbs_map3d` |
|
|
75
|
+
| com.amap.api:location | @amap/amap_lbs_location | `ohpm install @amap/amap_lbs_location` |
|
|
76
|
+
| com.amap.api:search | @amap/amap_lbs_search | `ohpm install @amap/amap_lbs_search` |
|
|
77
|
+
| com.amap.api:3dmap-location-search | @amap/amap_lbs_map3d | `ohpm install @amap/amap_lbs_map3d` |
|
|
78
|
+
| com.amap.api:navi-3dmap | @amap/amap_lbs_map3d | `ohpm install @amap/amap_lbs_map3d` |
|
|
79
|
+
| com.umeng.umsdk:analytics | @umeng/analytics | `ohpm install @umeng/analytics` |
|
|
80
|
+
| com.umeng.umsdk:common | @umeng/common | `ohpm install @umeng/common` |
|
|
81
|
+
| BaiduLBS_Android | @bdmap/navi_map | `ohpm install @bdmap/navi_map` |
|
|
82
|
+
| com.baidubce.mediasdk:brtc | @baiduplayer/baidurtcsdk | `ohpm install @baiduplayer/baidurtcsdk` |
|
|
83
|
+
| com.getui:gtsdk | @getui/push | `ohpm install @getui/push` |
|
|
84
|
+
| com.bonree.sdk.jar | @bonree/agent | `ohpm install @bonree/agent` |
|
|
85
|
+
| com.tencent.bugly:crashreport | bugly | `ohpm install bugly` |
|
|
86
|
+
|
|
87
|
+
*共 175 条闭源库映射*
|
|
88
|
+
|
|
89
|
+
## 高置信度映射示例(安卓鸿蒙化库)
|
|
90
|
+
|
|
91
|
+
| 安卓库 | 鸿蒙包 | category | install_command |
|
|
92
|
+
|--------|--------|----------|-----------------|
|
|
93
|
+
| AJCaptcha 安卓实现版本 | @scca/verification | other | `ohpm install @scca/verification` |
|
|
94
|
+
| ARouter | @ohos/arouteronactivityresult | other | `ohpm install @ohos/arouteronactivityresult` |
|
|
95
|
+
| ARouter | hrouter | other | `ohpm install hrouter` |
|
|
96
|
+
| Android Beacon Library (AltBea | @ohos/beacon-library | other | `ohpm install @ohos/beacon-library` |
|
|
97
|
+
| Android BottomSheet | @hld/bottomsheet | other | `ohpm install @hld/bottomsheet` |
|
|
98
|
+
| Android Jetpack Paging3 | @jackiehou/experimental-paging | other | `ohpm install @jackiehou/experimental-paging` |
|
|
99
|
+
| Android Room | @hzzmkjyxgs/zmwlthmosdb | other | `ohpm install @hzzmkjyxgs/zmwlthmosdb` |
|
|
100
|
+
| Android TabLayout(com.google.a | @zyc/tablayout | other | `ohpm install @zyc/tablayout` |
|
|
101
|
+
| Android XLog | @ohos-port/xlog-ts | other | `ohpm install @ohos-port/xlog-ts` |
|
|
102
|
+
| Android-Debug-Database | @hadss/debug-db | other | `ohpm install @hadss/debug-db` |
|
|
103
|
+
| AndroidImageEditor | @zhongjh/image_edit | other | `ohpm install @zhongjh/image_edit` |
|
|
104
|
+
| AndroidUtilCode | @android_x/utilcode | other | `ohpm install @android_x/utilcode` |
|
|
105
|
+
| AndroidUtilCode | @ilye/utilcode | other | `ohpm install @ilye/utilcode` |
|
|
106
|
+
| AndroidUtilCode | @ranran/utilcode | other | `ohpm install @ranran/utilcode` |
|
|
107
|
+
| AndroidVideoCache | @changjing/drm | media | `ohpm install @changjing/drm` |
|
|
108
|
+
| AndroidVideoCache (com.danikul | @ohos/video-cache | media | `ohpm install @ohos/video-cache` |
|
|
109
|
+
| Apache Batik | @ohos/xmlgraphicsbatik | other | `ohpm install @ohos/xmlgraphicsbatik` |
|
|
110
|
+
| Apache Cordova Android | @boc/cordova | other | `ohpm install @boc/cordova` |
|
|
111
|
+
| AppCan Android Engine | @appcan/engine | other | `ohpm install @appcan/engine` |
|
|
112
|
+
| DBFlow | @ohos/dataorm | other | `ohpm install @ohos/dataorm` |
|
|
113
|
+
|
|
114
|
+
*共 340 条高置信度安卓鸿蒙化库映射*
|
|
115
|
+
|
|
116
|
+
## 鸿蒙原生库示例(无安卓库)
|
|
117
|
+
|
|
118
|
+
| 鸿蒙包 | 组织 | category | install_command |
|
|
119
|
+
|--------|------|----------|-----------------|
|
|
120
|
+
| @pura/harmony-utils | pura | notification | `ohpm install @pura/harmony-utils` |
|
|
121
|
+
| @pura/harmony-dialog | pura | ui | `ohpm install @pura/harmony-dialog` |
|
|
122
|
+
| @ibestservices/ibest-ui | ibestservices | ui | `ohpm install @ibestservices/ibest-ui` |
|
|
123
|
+
| @abner/refresh | abner | ui | `ohpm install @abner/refresh` |
|
|
124
|
+
| @hzw/zrouter | hzw | other | `ohpm install @hzw/zrouter` |
|
|
125
|
+
| cjcalendar | | ui | `ohpm install cjcalendar` |
|
|
126
|
+
| @hadss/hmrouter | hadss | other | `ohpm install @hadss/hmrouter` |
|
|
127
|
+
| @esky/barrage | esky | media | `ohpm install @esky/barrage` |
|
|
128
|
+
| @ibestservices/ibest-ui-v2 | ibestservices | ui | `ohpm install @ibestservices/ibest-ui-v2` |
|
|
129
|
+
| @ohos/pulltorefresh | ohos | ui | `ohpm install @ohos/pulltorefresh` |
|
|
130
|
+
| @mcui/mccharts | mcui | utils | `ohpm install @mcui/mccharts` |
|
|
131
|
+
| @maple/navigationbarview | maple | location | `ohpm install @maple/navigationbarview` |
|
|
132
|
+
| @abner/dialog | abner | ui | `ohpm install @abner/dialog` |
|
|
133
|
+
| @zyl/wxcommonlibhar | zyl | payment | `ohpm install @zyl/wxcommonlibhar` |
|
|
134
|
+
| @ibestservices/ibest-orm | ibestservices | storage | `ohpm install @ibestservices/ibest-orm` |
|
|
135
|
+
| @ohasasugar/hp-richtext | ohasasugar | ui | `ohpm install @ohasasugar/hp-richtext` |
|
|
136
|
+
| @zyl/commonlibhar | zyl | media | `ohpm install @zyl/commonlibhar` |
|
|
137
|
+
| @abner/datastore | abner | storage | `ohpm install @abner/datastore` |
|
|
138
|
+
| @visactor/harmony-vchart | visactor | other | `ohpm install @visactor/harmony-vchart` |
|
|
139
|
+
| @liushengyi/smartdb | liushengyi | storage | `ohpm install @liushengyi/smartdb` |
|
|
140
|
+
|
|
141
|
+
*共 1673 条鸿蒙原生库*
|
|
142
|
+
|
|
143
|
+
## 数据结构
|
|
144
|
+
|
|
145
|
+
每条映射记录包含15个字段:
|
|
146
|
+
|
|
147
|
+
| 字段 | 类型 | 说明 |
|
|
148
|
+
|------|------|------|
|
|
149
|
+
| android_lib | string/null | 安卓库标识符(鸿蒙原生库为null) |
|
|
150
|
+
| android_platform | string | android / ios / ohos_native |
|
|
151
|
+
| android_description | string/null | 安卓库功能描述 |
|
|
152
|
+
| ohpm_package | string | 鸿蒙包名 |
|
|
153
|
+
| ohpm_org | string | ohpm组织名 |
|
|
154
|
+
| ohpm_description | string | 鸿蒙包功能描述 |
|
|
155
|
+
| ohpm_keywords | array | 鸿蒙包关键词 |
|
|
156
|
+
| ohpm_repo_url | string | 鸿蒙包源码仓库 |
|
|
157
|
+
| ohpm_homepage | string | 鸿蒙包文档主页 |
|
|
158
|
+
| source_type | string | 安卓鸿蒙化库/TS迁移库/鸿蒙原生库 |
|
|
159
|
+
| source_availability | string | COMMERCIAL_PUBLIC/open_source |
|
|
160
|
+
| confidence | string | high/medium/low |
|
|
161
|
+
| install_command | string | ohpm install命令 |
|
|
162
|
+
| category | string | media/network/notification等 |
|
|
163
|
+
| inference_reason | string | 映射关系说明 |
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: preparing-migration-workspace
|
|
3
|
+
description: 在 Android 转 HarmonyOS 迁移开始或恢复时,通过 droid2hmos 执行统一 Preflight,并依据 CLI 返回结果和报告决定是否进入事实扫描与实现。也用于配置、Git checkpoint、构建测试、AppGraph 分析和设备检查。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 准备迁移工作区
|
|
7
|
+
|
|
8
|
+
本 Skill 只编排 `droid2hmos` 和独立的 `appgraph` CLI,不直接调用 Node 脚本、Gradle、Hvigor、Hypium、ADB 或 HDC。不要在 `ohos/` 尚不存在时猜测 HarmonyOS 构建配置。
|
|
9
|
+
|
|
10
|
+
迁移产物(`.migration/`)统一位于安卓工程父目录下的 `<工程名>-migration/.migration/`,由 CLI 自动创建和维护,不写入安卓工程内部。创建 `.migration/` 时 CLI 会自动在工作区根目录生成 `.gitignore`(内容 `.migration/`),防止迁移产物被上层 Git 仓库提交到远端。下文所有 `.migration/...` 路径均相对该工作区根目录。
|
|
11
|
+
|
|
12
|
+
开始或恢复时先获取只读事实快照:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
droid2hmos status <ANDROID_PROJECT>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
使用 `completion.unmet` 识别缺口,使用 `allowedActions` 选择当前可安全调用的命令。`phase` 只解释当前现场,不是必须手工推进的状态;不得创建或编辑 `.migration/state.json`。
|
|
19
|
+
|
|
20
|
+
传入路径必须是 Android Gradle 工程根目录:根目录应有 Gradle 标记,并且应用模块中应有 `AndroidManifest.xml`。如果 `workspace.projectPresent=false` 且 `workspace.projectCandidates` 非空,说明传入的是包装目录;改用列出的明确候选工程,不得在包装目录初始化第二套 `.migration` 或 HarmonyOS 工程。
|
|
21
|
+
|
|
22
|
+
## 首次执行
|
|
23
|
+
|
|
24
|
+
运行统一门禁:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
droid2hmos preflight <ANDROID_PROJECT> [--sdk-path <PATH>] [--timeout-ms <MS>]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`preflight` 负责选择检查项、判定检查项是否阻塞,并生成完整结果,包括:
|
|
31
|
+
|
|
32
|
+
- Android UI 技术栈支持性;
|
|
33
|
+
- Git 仓库、分支、`HEAD` 和工作区干净状态;
|
|
34
|
+
- Git、Node.js 20-24、npm、Python 3.10+、JDK、Android SDK 和 DevEco 工具链;
|
|
35
|
+
- `appgraph --version` 及迁移分析能力健康检查;
|
|
36
|
+
- `.migration/config.json` 初始化和校验;
|
|
37
|
+
- Android 基线状态及设备检查;
|
|
38
|
+
- 已有 HarmonyOS 工程复用,或在目标为空时创建可编译工程壳;
|
|
39
|
+
- HarmonyOS SDK 探测、应用 HAP 基线构建和必须通过的 HDC 设备检查;
|
|
40
|
+
- `.migration/preflight-report.json` 原子生成。
|
|
41
|
+
|
|
42
|
+
已有 HarmonyOS 工程不得被覆盖。只想校验现有工程、不允许初始化工程壳时加 `--no-init-harmony`。命令失败后读取报告中的 `failedChecks`、`retry` 和对应日志;只有 `transient/bounded` 允许在给出的上限内原样重试,其余失败必须先改变输入或环境,不得绕过门禁继续事实扫描或实现。
|
|
43
|
+
|
|
44
|
+
环境类门禁(`toolchain`、`devecocli-auth`、`appgraph`、`harmony-sdk`、`harmony-device`)只探测一次:它们依赖本机工具、华为账号授权或物理设备,原样重跑 `preflight` 不会自愈。这类失败会返回 `retry.kind=external` 且带 `remediation`;必须把 `remediation` 明确转述给用户、等待用户修改环境,不得在同一环境下连续重跑 `preflight`。其余(非环境类)失败在按 `retry` 指引改变输入后重跑。
|
|
45
|
+
|
|
46
|
+
本 Skill 不单独定义或重算任何子检查门禁。命令成功且报告总体结果为 `passed` 时继续。
|
|
47
|
+
|
|
48
|
+
## 语言资源基线清点
|
|
49
|
+
|
|
50
|
+
Preflight 通过后、进入事实扫描与批次规划前,对 Android 工程做一次只读语言清点(文件枚举,不涉及构建):列出各应用模块 `src/*/res/` 下带语言/地区限定符的 `values-<locale>` 目录(如 `values-zh`、`values-en-rUS`、`values-b+es+419`;排除 `night`、`land`、`v<N>`、`sw<N>dp` 等非语言限定符),记录语言清单与数量。该清点结果是规划的强制输入:
|
|
51
|
+
|
|
52
|
+
- 语言数 > 1:实现批次必须包含 i18n 资源迁移批次,该批次开始前加载 `arkts-i18n` skill,按其目录规范迁移全部语言;
|
|
53
|
+
- 语言数 = 1:也须在写入首个字符串资源前加载 `arkts-i18n` 确认资源组织方式;
|
|
54
|
+
- 任何情况下不得把用户可见文案硬编码进页面代码来替代字符串资源迁移。
|
|
55
|
+
|
|
56
|
+
## 配置与测试
|
|
57
|
+
|
|
58
|
+
需要显式提供项目特有的 Android 命令时,先运行:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
droid2hmos config init <ANDROID_PROJECT> [--harmony-project <PATH>] [--android-build <COMMAND>] [--android-test <COMMAND>]
|
|
62
|
+
droid2hmos config validate <ANDROID_PROJECT>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
配置中只保存 Android 侧有限命令和能够确认的路径。不得保存或猜测 `harmonyBuild`、`harmonyTest`、module、product 或 target;HarmonyOS 参数由 CLI 从真实工程配置解析。
|
|
66
|
+
|
|
67
|
+
`androidBuild` 默认为 null:迁移流程不编译 Android 工程,`analyze android` 是纯源码静态分析且不要求 APK。只有用户明确要求 Android/HarmonyOS 双端运行对照时,才通过 `--android-build` 显式配置构建命令;未配置时执行 `droid2hmos build android` 会返回引导提示而非自动探测。
|
|
68
|
+
|
|
69
|
+
在首次 Preflight 之后需要针对性诊断或验证时使用:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
droid2hmos build <android|harmony|all> <ANDROID_PROJECT> [--timeout-ms <MS>]
|
|
73
|
+
droid2hmos test android <ANDROID_PROJECT> [--task <TASK>] [--timeout-ms <MS>]
|
|
74
|
+
droid2hmos test harmony <ANDROID_PROJECT> (--class <CLASS> [--case <CASE>] | --all) [--target <DEVICE>] [--case-timeout-ms <MS>] [--ref <REPORT_REF>...]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Android 测试只有在 `.migration/config.json` 已声明可执行的 `androidTest` 时运行。HarmonyOS 测试只有在已有 Hypium 测试资产时运行;没有测试资产时记录缺口,并在第一个可交互功能验收前建立。多个 HDC 目标可响应时必须显式传 `--target`,防止证据偶然落在另一台设备。`--case-timeout-ms` 控制单个 Hypium 用例超时,`--ref` 只声明该测试实际断言的报告项。CLI 会解析 Hypium 摘要:失败、错误、忽略、零执行或缺少摘要即使 HDC 退出码为零也视为失败。
|
|
78
|
+
|
|
79
|
+
Hvigor 返回成功但没有刷新输出时,CLI 只复用不早于各自构建输入的既有应用/ohosTest HAP;应用源码变化只要求应用 HAP 更新,不会强制无关的 ohosTest HAP 重打。产物比对应源码或构建配置旧时必须失败并要求修复构建,而不是安装过期包。
|
|
80
|
+
|
|
81
|
+
## 分析与设备诊断
|
|
82
|
+
|
|
83
|
+
Android 和 HarmonyOS 分析统一使用:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
droid2hmos analyze <android|harmony|all> <ANDROID_PROJECT>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
CLI 负责调用 PATH 中的 `appgraph`,HarmonyOS 分析自动读取配置里的 SDK 路径。只有统一命令失败且需要定位工具缺陷时,才直接运行 `appgraph --version` 或查看其帮助;不得自行拼接内部分析参数作为正常工作流。
|
|
90
|
+
|
|
91
|
+
需要单独复查设备时使用:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
droid2hmos device check <android|harmony>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Android 设备缺失是可记录的增强项;HarmonyOS 设备必须可被发现且 Shell 可响应,否则停止需要设备证据的流程。
|
|
98
|
+
|
|
99
|
+
## 恢复执行与 Git checkpoint
|
|
100
|
+
|
|
101
|
+
恢复迁移时不得重新初始化已有 `ohos/`。先运行:
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
droid2hmos status <ANDROID_PROJECT>
|
|
105
|
+
droid2hmos checkpoint status <ANDROID_PROJECT>
|
|
106
|
+
droid2hmos config validate <ANDROID_PROJECT>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
然后只重跑快照显示为缺失或因源码指纹变化而失效的 `build`、`test`、`device check` 或 `analyze`。如果工具链、AppGraph、工程壳或基础环境可能变化,则重新运行完整 `preflight`。`.migration/` 运行态文件不会让重复 Preflight 自己判定工作区变脏;已有配置中尚未纳入 Git 的 HarmonyOS 目录可作为上次预检生成物忽略,但首次运行前就存在的未跟踪 `ohos/` 和该目录内已有的 tracked 变更仍然阻塞,不能借此隐藏用户改动。
|
|
110
|
+
|
|
111
|
+
完成一个经验证的迁移单元后,只提交明确列出的文件:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
droid2hmos checkpoint create <ANDROID_PROJECT> --message <MESSAGE> --include <PATH> [--include <PATH>...]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
仅在调用者明确要求纳入全部相关变更时使用 `--all`。即使使用 `--all`,`.migration/` 运行态和证据归档也不会进入提交。不得处理、覆盖或删除用户已有改动;生成的 AppGraph、命令日志和预检日志不进入检查点。显式路径暂存失败时命令会撤销本次新加入暂存区的文件,并保留调用前已经暂存的内容。
|
|
118
|
+
|
|
119
|
+
## 继续条件
|
|
120
|
+
|
|
121
|
+
- `droid2hmos preflight` 成功退出;
|
|
122
|
+
- `.migration/preflight-report.json` 已生成且总体结果为 `passed`。
|
|
123
|
+
|
|
124
|
+
各检查项的 `required`、`status` 和最终阻塞关系以本次 CLI 输出及报告为唯一依据,Skill 不重复推导通过条件。
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"orchestrator": {
|
|
3
|
+
"command": "droid2hmos",
|
|
4
|
+
"preflight": ["preflight"],
|
|
5
|
+
"requiredCapabilities": [
|
|
6
|
+
"status",
|
|
7
|
+
"complete",
|
|
8
|
+
"config init",
|
|
9
|
+
"config validate",
|
|
10
|
+
"checkpoint status",
|
|
11
|
+
"checkpoint create",
|
|
12
|
+
"build android",
|
|
13
|
+
"build harmony",
|
|
14
|
+
"test android",
|
|
15
|
+
"test harmony",
|
|
16
|
+
"device check android",
|
|
17
|
+
"device check harmony",
|
|
18
|
+
"analyze android",
|
|
19
|
+
"analyze harmony",
|
|
20
|
+
"evidence capture",
|
|
21
|
+
"evidence flow",
|
|
22
|
+
"evidence compare",
|
|
23
|
+
"report init",
|
|
24
|
+
"report update",
|
|
25
|
+
"report validate",
|
|
26
|
+
"report render",
|
|
27
|
+
"mock init",
|
|
28
|
+
"service start",
|
|
29
|
+
"service status",
|
|
30
|
+
"service stop",
|
|
31
|
+
"logs list",
|
|
32
|
+
"logs show",
|
|
33
|
+
"logs failures",
|
|
34
|
+
"logs stats"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"appgraph": {
|
|
38
|
+
"command": "appgraph",
|
|
39
|
+
"versionProbe": ["--version"],
|
|
40
|
+
"healthProbe": ["spec-analysis", "--help"],
|
|
41
|
+
"managedBy": "droid2hmos preflight"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewing-migration-process
|
|
3
|
+
description: Review a completed or explicitly stopped Android-to-HarmonyOS migration and write concise, evidence-backed suggestions for humans who maintain the migration Agent, Skills, scripts, and workflow. Do not use for ordinary implementation progress or technical migration lessons.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Review the migration process
|
|
7
|
+
|
|
8
|
+
Create or update `<android-project>-migration/.migration/agent-feedback.md` (in the sibling migration workspace next to the Android project, not inside it) only when the migration has completed or the current run has explicitly stopped. The file is a human review input, not a migration gate and not an instruction source for later migration Agents.
|
|
9
|
+
|
|
10
|
+
## Scope
|
|
11
|
+
|
|
12
|
+
Record problems in the migration system itself:
|
|
13
|
+
|
|
14
|
+
- workflow stalls, excessive latency, or avoidable human intervention;
|
|
15
|
+
- repeated reads, builds, installs, tests, or reverted implementation attempts;
|
|
16
|
+
- Agent decisions that violated task boundaries or diverged from Android evidence;
|
|
17
|
+
- missing, unreliable, or unclear scripts and tool outputs;
|
|
18
|
+
- inputs that were too large, duplicated, missing, or provided too late;
|
|
19
|
+
- concrete changes that could improve an Agent prompt, Skill, script, input artifact, workflow, or gate.
|
|
20
|
+
|
|
21
|
+
Do not repeat application implementation status or the migration report. Do not place reusable Android/HarmonyOS technical solutions here; verified technical migration knowledge belongs in `.migration/experience/lessons.md`. A single incident may produce both records only when their perspectives differ: this file describes how the migration system should improve, while the lesson describes a verified technical solution.
|
|
22
|
+
|
|
23
|
+
## Evidence and judgment
|
|
24
|
+
|
|
25
|
+
- Before writing the review, inspect the managed execution record with `droid2hmos logs stats <android-project>` and `droid2hmos logs failures <android-project>`. Use `droid2hmos logs list <android-project> [YYYY-MM-DD]` and `droid2hmos logs show <android-project> <run-id>` only for runs relevant to a finding.
|
|
26
|
+
- Run `droid2hmos checkpoint status <android-project>` to record whether the run ended with explained changes or an unexpected dirty worktree.
|
|
27
|
+
- Base every finding on an observed command, log, artifact, commit, rework, or user intervention from this run.
|
|
28
|
+
- Separate observation from inferred root cause. Mark an uncertain cause as a hypothesis.
|
|
29
|
+
- Do not write generic advice such as “be more careful”. Name the exact optimization target and proposed change.
|
|
30
|
+
- Do not automatically modify the plugin based on this file. A human decides whether to accept each suggestion.
|
|
31
|
+
- Merge duplicate symptoms into one finding. Keep at most the five highest-impact findings.
|
|
32
|
+
- If there is no evidence-backed improvement, write `本次未发现需要提交给 Agent 维护者的优化建议。`
|
|
33
|
+
|
|
34
|
+
## Output
|
|
35
|
+
|
|
36
|
+
Use concise Chinese Markdown:
|
|
37
|
+
|
|
38
|
+
```markdown
|
|
39
|
+
# Agent 优化建议
|
|
40
|
+
|
|
41
|
+
## 本次运行概况
|
|
42
|
+
|
|
43
|
+
- 结果:完成 | 中止
|
|
44
|
+
- 主要耗时或阻塞:
|
|
45
|
+
- 人工介入:
|
|
46
|
+
|
|
47
|
+
## 优先建议
|
|
48
|
+
|
|
49
|
+
### AF-001:简短问题名称
|
|
50
|
+
|
|
51
|
+
- 优先级:P0 | P1 | P2
|
|
52
|
+
- 阶段:
|
|
53
|
+
- 现象:
|
|
54
|
+
- 证据:日志、命令、文件或提交路径
|
|
55
|
+
- 影响:
|
|
56
|
+
- 根因:已确认 | 假设,并说明原因
|
|
57
|
+
- 优化位置:Agent | Skill | 脚本/工具 | 输入产物 | 流程 | 门禁
|
|
58
|
+
- 建议:可执行的修改
|
|
59
|
+
- 通用性:仅本项目 | 多项目通用
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use P0 only when the issue can block the whole workflow, corrupt work, or falsely declare migration success. Keep the overview factual; do not calculate metrics that were not captured by tools.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
|
|
5
|
+
function stat(file) {
|
|
6
|
+
try { return fs.lstatSync(file); } catch (error) {
|
|
7
|
+
if (error.code === 'ENOENT') return null;
|
|
8
|
+
throw error;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function sameTree(source, destination) {
|
|
13
|
+
const left = stat(source);
|
|
14
|
+
const right = stat(destination);
|
|
15
|
+
if (!left || !right) return false;
|
|
16
|
+
if (left.isSymbolicLink() || right.isSymbolicLink()) {
|
|
17
|
+
if (!left.isSymbolicLink() || !right.isSymbolicLink()) return false;
|
|
18
|
+
return fs.readlinkSync(source) === fs.readlinkSync(destination);
|
|
19
|
+
}
|
|
20
|
+
if (left.isDirectory() && right.isDirectory()) {
|
|
21
|
+
const names = fs.readdirSync(source).sort();
|
|
22
|
+
const otherNames = fs.readdirSync(destination).sort();
|
|
23
|
+
return names.length === otherNames.length && names.every((name, index) =>
|
|
24
|
+
name === otherNames[index] && sameTree(path.join(source, name), path.join(destination, name)));
|
|
25
|
+
}
|
|
26
|
+
return left.isFile() && right.isFile() && fs.readFileSync(source).equals(fs.readFileSync(destination));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function contains(parent, child) {
|
|
30
|
+
const relative = path.relative(parent, child);
|
|
31
|
+
return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Resolve existing ancestors too, including a config directory beneath a junction.
|
|
35
|
+
function resolvedLocation(directory) {
|
|
36
|
+
if (fs.existsSync(directory)) return fs.realpathSync(directory);
|
|
37
|
+
const parent = path.dirname(directory);
|
|
38
|
+
return parent === directory ? directory : path.join(resolvedLocation(parent), path.basename(directory));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function installOpenCode({ sourceDir, configDir, link = false, force = false, dryRun = false, log = console.log }) {
|
|
42
|
+
if (!configDir || ['.', '..'].includes(configDir)) throw new Error(`refusing unsafe OpenCode config directory: ${configDir}`);
|
|
43
|
+
const sourceRoot = fs.realpathSync(path.resolve(sourceDir));
|
|
44
|
+
const configRoot = resolvedLocation(path.resolve(configDir));
|
|
45
|
+
if (configRoot === path.parse(configRoot).root || configRoot === fs.realpathSync(os.homedir()) ||
|
|
46
|
+
contains(sourceRoot, configRoot) || contains(configRoot, sourceRoot)) {
|
|
47
|
+
throw new Error(`refusing unsafe OpenCode config directory: ${configDir}`);
|
|
48
|
+
}
|
|
49
|
+
const entries = [];
|
|
50
|
+
for (const kind of ['skills', 'agents']) {
|
|
51
|
+
const source = path.join(sourceRoot, kind);
|
|
52
|
+
if (!fs.statSync(source).isDirectory()) throw new Error(`${kind} directory not found: ${source}`);
|
|
53
|
+
const destinationRoot = path.join(configRoot, kind);
|
|
54
|
+
if (stat(destinationRoot)?.isSymbolicLink()) throw new Error(`refusing linked installation directory: ${destinationRoot}`);
|
|
55
|
+
let count = 0;
|
|
56
|
+
for (const name of fs.readdirSync(source).sort()) {
|
|
57
|
+
const entrySource = path.join(source, name);
|
|
58
|
+
if (kind === 'skills' ? !fs.existsSync(path.join(entrySource, 'SKILL.md')) :
|
|
59
|
+
!name.endsWith('.md') || !fs.statSync(entrySource).isFile()) continue;
|
|
60
|
+
count++;
|
|
61
|
+
const destination = path.join(destinationRoot, name);
|
|
62
|
+
let unchanged = false;
|
|
63
|
+
if (link && stat(destination)?.isSymbolicLink()) {
|
|
64
|
+
unchanged = path.resolve(path.dirname(destination), fs.readlinkSync(destination)) === entrySource;
|
|
65
|
+
} else if (!link) {
|
|
66
|
+
unchanged = sameTree(entrySource, destination);
|
|
67
|
+
}
|
|
68
|
+
if (!unchanged && stat(destination) && !force) {
|
|
69
|
+
throw new Error(`${kind} '${name}' already exists at ${destination}; rerun with --force to replace it`);
|
|
70
|
+
}
|
|
71
|
+
entries.push({ kind, name, source: entrySource, destination, unchanged });
|
|
72
|
+
}
|
|
73
|
+
if (!count) throw new Error(`no ${kind} found under ${source}`);
|
|
74
|
+
}
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
if (entry.unchanged) { log(`unchanged ${entry.kind}: ${entry.name}`); continue; }
|
|
77
|
+
if (dryRun) { log(`would install ${entry.kind}: ${entry.source} -> ${entry.destination} (${link ? 'link' : 'copy'})`); continue; }
|
|
78
|
+
const parent = path.dirname(entry.destination);
|
|
79
|
+
fs.mkdirSync(parent, { recursive: true });
|
|
80
|
+
if (!contains(configRoot, fs.realpathSync(parent))) throw new Error(`installation escaped config directory: ${parent}`);
|
|
81
|
+
const staging = fs.mkdtempSync(path.join(parent, '.migration-install-'));
|
|
82
|
+
const staged = path.join(staging, 'new');
|
|
83
|
+
const backup = path.join(staging, 'backup');
|
|
84
|
+
try {
|
|
85
|
+
if (link) fs.symlinkSync(entry.source, staged, process.platform === 'win32' && entry.kind === 'skills' ? 'junction' : undefined);
|
|
86
|
+
else fs.cpSync(entry.source, staged, { recursive: true });
|
|
87
|
+
if (stat(entry.destination)) fs.renameSync(entry.destination, backup);
|
|
88
|
+
try { fs.renameSync(staged, entry.destination); } catch (error) {
|
|
89
|
+
if (stat(backup)) fs.renameSync(backup, entry.destination);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
} finally {
|
|
93
|
+
// If restoring a replaced entry also failed, retain its backup for recovery.
|
|
94
|
+
if (stat(backup) && !stat(entry.destination)) {
|
|
95
|
+
log(`installation backup retained: ${backup}`);
|
|
96
|
+
} else {
|
|
97
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
log(`installed ${entry.kind}: ${entry.destination}`);
|
|
101
|
+
}
|
|
102
|
+
const skills = entries.filter(entry => entry.kind === 'skills').length;
|
|
103
|
+
const agents = entries.filter(entry => entry.kind === 'agents').length;
|
|
104
|
+
log(`${dryRun ? 'OpenCode installation preview' : 'OpenCode installation complete'}: ${skills} skill(s), ${agents} agent(s).`);
|
|
105
|
+
log(`Config directory: ${configRoot}`);
|
|
106
|
+
if (!dryRun) log('Quit and restart OpenCode to load the installed definitions.');
|
|
107
|
+
return { skills, agents, configRoot };
|
|
108
|
+
}
|