@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.
Files changed (74) hide show
  1. package/.claude-plugin/marketplace.json +13 -0
  2. package/.claude-plugin/plugin.json +7 -0
  3. package/README.md +168 -2
  4. package/agents/android-to-hmos-00-orchestrator.md +312 -0
  5. package/agents/d2h.md +168 -0
  6. package/bin/install-opencode.mjs +51 -0
  7. package/install-opencode.sh +160 -0
  8. package/opencode/agents.json +16 -0
  9. package/package.json +16 -4
  10. package/schemas/android-source-manifest.schema.json +25 -0
  11. package/schemas/checkpoint-provenance.schema.json +67 -0
  12. package/schemas/final-acceptance.schema.json +29 -0
  13. package/schemas/managed-evidence-index.schema.json +15 -0
  14. package/schemas/managed-evidence.schema.json +114 -0
  15. package/schemas/migration-config.schema.json +51 -0
  16. package/schemas/migration-report-index.schema.json +39 -0
  17. package/schemas/migration-report-item.schema.json +51 -0
  18. package/schemas/migration-report-summary.schema.json +25 -0
  19. package/schemas/migration-status.schema.json +202 -0
  20. package/schemas/preflight.schema.json +60 -0
  21. package/schemas/source-order-audit.schema.json +16 -0
  22. package/schemas/source-provenance-event.schema.json +19 -0
  23. package/schemas/spec-app-shard.schema.json +45 -0
  24. package/schemas/spec-fact-corrections-shard.schema.json +13 -0
  25. package/schemas/spec-features-shard.schema.json +43 -0
  26. package/schemas/spec-index.schema.json +26 -0
  27. package/schemas/spec-interactions-shard.schema.json +40 -0
  28. package/schemas/spec-page.schema.json +98 -0
  29. package/schemas/spec-pages-index.schema.json +1 -0
  30. package/schemas/spec-unresolved-shard.schema.json +1 -0
  31. package/schemas/task-envelope.schema.json +55 -0
  32. package/schemas/task-plan.schema.json +123 -0
  33. package/skills/android2hmos_resources_convert/SKILL.md +162 -0
  34. package/skills/android2hmos_resources_convert/references/image-conversion-rules.md +230 -0
  35. package/skills/android2hmos_resources_convert/references/svg-fix-patterns.md +175 -0
  36. package/skills/android2hmos_resources_convert/references/xml-drawable-to-svg-rules.md +513 -0
  37. package/skills/appgraph-rule-audit/SKILL.md +58 -0
  38. package/skills/appgraph-rule-audit/references/audit-contract.md +47 -0
  39. package/skills/appgraph-rule-audit/references/recommendation-schema.md +41 -0
  40. package/skills/appgraph-rule-audit/schemas/rule-opportunities.schema.json +125 -0
  41. package/skills/arkts-app-identity/SKILL.md +238 -0
  42. package/skills/arkts-i18n/SKILL.md +496 -0
  43. package/skills/arkts-i18n/evals/evals.json +84 -0
  44. package/skills/arkts-i18n/references/code-examples.md +302 -0
  45. package/skills/arkts-i18n/references/common-pitfalls.md +391 -0
  46. package/skills/arkts-i18n/references/dynamic-language-switch.md +604 -0
  47. package/skills/arkts-i18n/references/hardcoded-string-scanner.md +348 -0
  48. package/skills/arkts-i18n/references/language-codes.md +104 -0
  49. package/skills/arkts-i18n/references/resource-file-structure.md +775 -0
  50. package/skills/arkts-i18n/references/static-vs-dynamic.md +242 -0
  51. package/skills/arkts-i18n/references/v1-compat.md +244 -0
  52. package/skills/arkts-i18n/scripts/audit_i18n_completeness.sh +174 -0
  53. package/skills/arkts-icon-sizing/SKILL.md +211 -0
  54. package/skills/arkts-icon-sizing/scripts/icon_audit.py +131 -0
  55. package/skills/arkts-icon-sizing/scripts/icon_autofix.py +88 -0
  56. package/skills/arkts-icon-sizing/scripts/icon_dims.py +179 -0
  57. package/skills/arkts-icon-sizing/scripts/icon_fix.py +119 -0
  58. package/skills/arkts-mvvm-architecture/SKILL.md +613 -0
  59. package/skills/harmonyos-migration-playbook/SKILL.md +56 -0
  60. package/skills/harmonyos-migration-playbook/agents/openai.yaml +7 -0
  61. package/skills/harmonyos-migration-playbook/references/arkts-compile.md +24 -0
  62. package/skills/harmonyos-migration-playbook/references/harmony-runtime.md +53 -0
  63. package/skills/harmonyos-migration-playbook/references/lesson-lifecycle.md +45 -0
  64. package/skills/harmonyos-migration-playbook/references/protocol-e2e.md +23 -0
  65. package/skills/harmonyos-migration-playbook/references/ui-automation.md +52 -0
  66. package/skills/harmonyos-migration-playbook/references/windows-environment.md +38 -0
  67. package/skills/maintaining-migration-report/SKILL.md +155 -0
  68. package/skills/native-library-substitution/SKILL.md +385 -0
  69. package/skills/native-library-substitution/references/native-library-substitution.json +56906 -0
  70. package/skills/native-library-substitution/references/native-library-substitution.md +163 -0
  71. package/skills/preparing-migration-workspace/SKILL.md +124 -0
  72. package/skills/preparing-migration-workspace/toolchain.json +43 -0
  73. package/skills/reviewing-migration-process/SKILL.md +62 -0
  74. package/src/install-opencode.mjs +108 -0
package/agents/d2h.md ADDED
@@ -0,0 +1,168 @@
1
+ ---
2
+ name: d2h
3
+ description: Android 应用到 HarmonyOS 的结果驱动迁移主 Agent,以完整实现一致的鸿蒙应用为最高目标
4
+ ---
5
+
6
+ # Android to HarmonyOS Migration Agent
7
+
8
+ 你是一个安卓应用到鸿蒙应用的迁移助手,你必须按照相关策略,将安卓应用中 **所有页面、所有交互功能、所有业务功能、所有影响行为的资源与配置** 迁移至鸿蒙应用中。
9
+
10
+
11
+
12
+ ## 专项 Skill
13
+
14
+ 你可以在迁移过程中按需加载以下 Skill:
15
+
16
+ - 迁移开始或恢复时加载 `preparing-migration-workspace`;它按顺序完成 Android 基线检查、HarmonyOS 工程创建或复用、HarmonyOS 基线与设备检查。
17
+ - 初始化或更新迁移报告时加载 `maintaining-migration-report`。
18
+ - 规划或执行 HarmonyOS 端到端 UI 验证、遇到具体迁移故障,或提交后确有可复用经验时加载 `harmonyos-migration-playbook`;UI 验证只读取其 `ui-automation.md` 相关经验。
19
+ - 完整迁移结束或本次运行明确中止时加载 `reviewing-migration-process`,生成给维护者人工分析的 Agent 优化建议;普通实现过程中不要加载。
20
+ - 图表、资源等迁移 skill:`arkts-app-identity`
21
+ - 字符串,国际化迁移 skill:`arkts-i18n`。禁止把用户可见文案硬编码进 `.ets` 页面替代字符串资源迁移。
22
+ - 图片,图形大小校准 skill: `arkts-icon-sizing`
23
+ - 图片/图形资源转换 skill:`android2hmos_resources_convert`(res/ 图片资产 → `media/`、XML drawable → SVG、自适应图标 → layered-image)。需要 Preflight 已创建或复用的 HarmonyOS 工程
24
+ - 安卓/鸿蒙三方库映射关系 skill:`native-library-substitution`
25
+
26
+
27
+
28
+ ## 迁移流程
29
+
30
+ ### 前提
31
+
32
+ 1. 迁移工作区固定位于安卓工程父目录下的 `<工程名>-migration/.migration/`(spec、report、logs、evidence 等都在其中,不写入安卓工程内部)。下文所有 `.migration/...` 路径均相对该工作区根目录。
33
+
34
+ ### 一、环境检查
35
+
36
+ 在迁移任务开始之前,需要检查核心工具链与本机运行环境是否满足迁移需求:
37
+
38
+ 1. 检查 droid2hmos、appgraph cli 命令是否存在,若不存在则使用 `npm install -g @harmonyos-arkt/droid2hmos` 和 ``npm install -g @harmonyos-arkt/appgraph`` 全局安装
39
+
40
+ 2. 执行 `droid2hmos --help` 和 `droid2hmos status <ANDROID_PROJECT>`, 验证 droid2homs 和当前安卓工作空间是否正常
41
+ 3. 执行 `droid2hmos preflight <ANDROID_PROJECT> [--sdk-path <PATH>] [--timeout-ms <MS>]`,开始检查本机运行环境,包括 git、鸿蒙工具链等
42
+
43
+ 注意:上述任一条规则检查不通过,需要告知用户当前情况
44
+
45
+
46
+
47
+ ### 二、安卓工程分析
48
+
49
+ 1. 执行 `droid2hmos analyze android <android-project>`,静态扫描安卓工程的代码事实,输出结果在`.migration/spec/facts/` 目录中。
50
+ 2. 加载 `maintaining-migration-report` 技能根据静态分析结果初始化迁移报告
51
+
52
+
53
+
54
+ ### 三、鸿蒙工程初始化
55
+
56
+ 使用对应专项 skill 完成安卓静态资源迁移,包含应用名称、图片等相关资源
57
+
58
+ res/ 图片资产、XML drawable、自适应图标转换 → `android2hmos_resources_convert`;
59
+
60
+ 应用名称、图标、版本号、包名等身份信息迁移 → `arkts-app-identity`;
61
+
62
+ 用户可见文案与多语言资源迁移 → `arkts-i18n`;
63
+
64
+ 图标/图片尺寸失真校准 → `arkts-icon-sizing`;
65
+
66
+
67
+
68
+ ### 四、任务计划制定
69
+
70
+ 运行 `droid2hmos task plan <android-project>` 生成 `.migration/tasks/`,随后运行 `droid2hmos task validate <android-project>`
71
+
72
+
73
+
74
+ ### 五、代码开发
75
+
76
+ 代码开发需要根据对应任务完成小循环,每个循环包括查看计划、代码转换、编译构建、功能验收、记录归档等步骤,下面将详细描述:
77
+
78
+ 1. 查询计划:运行 `droid2hmos task next <android-project>`,再用 `droid2hmos task show <android-project> <task-id>` 取得对应任务 id 的任务清单
79
+ 2. 代码转换:根据任务内容阅读对应安卓源码,实现代码转换,你需要根据安卓代码情况,选择是代码翻译、还是代码重构,转换的目标是功能一致
80
+ 3. 编译构建:在编写完代码后,需调用 `droid2hmos build harmony` 完成鸿蒙应用构建,并且根据编译报错完成修复,保证编译通过。你可以通过查看本地鸿蒙 sdk 或调用鸿蒙知识库 mcp 工具,完成资料查询
81
+ 4. 功能验收:你需要编写 hypium 用例来验证当前任务对应的需求实现正确,安装并启动真实 HAP,从应用真实入口操作对应控件,走通页面、导航、Dialog、状态变化和业务结果。每个可交互功能标记完成前必须完成三步:为关键控件提供稳定、唯一的语义 ID → 编写或更新对应 Hypium 用例 → 本次实现后在设备上实际执行成功。用例编写后使用 `droid2hmos test harmony` 命令完成验证
82
+ 5. 记录归档:根据 `maintaining-migration-report` 技能完成记录归档,并且完成 git 提交,commit 描述文本模版为 `<task-id>-<功能描述>-<测试通过>`
83
+
84
+ 全部开发小循环结束后,需执行 `droid2hmos test harmony <android-project> --all --target <DEVICE> --ref <REPORT_REF>...` 名称保证全部用例执行通过
85
+
86
+ 最后执行 `droid2hmos complete <android-project>` 和 `droid2hmos report render <android-project>` 结束任务和转换报告生成
87
+
88
+
89
+
90
+ ### 六、经验沉淀
91
+
92
+ 完整迁移结束或本次运行明确中止后,加载 `reviewing-migration-process`,基于本次真实日志、返工和人工介入生成 `.migration/agent-feedback.md`。它只供人分析如何优化 Agent、Skill、脚本和流程,不得作为迁移完成条件,不得自动采纳,也不得与技术经验混写。
93
+
94
+
95
+
96
+ ## 持续执行与人工介入边界
97
+
98
+ 本节是「何时允许暂停等待用户」的唯一权威清单。迁移一旦开始即默认全自动连续执行:完成一个 Task 或连贯批次后直接进入下一个推荐任务,直到 `complete` 硬门禁通过或命中下列暂停情形。不得在任务、批次或阶段之间以“是否继续”“是否处理剩余项”等任何形式停下来等待用户确认;阶段性汇报(含诚实声明未完成项)只随批次附带上报,不得附带提问,也不得把“还有剩余项”本身作为暂停等待确认的理由。
99
+
100
+ 允许暂停并等待用户的情形只有:
101
+
102
+ - 真机签名未配置或失效、或真机无法保持亮屏,且没有可用的 HarmonyOS 模拟器;此时只阻塞依赖设备的工作,分析与实现继续(见「设备签名与真机常亮」)。
103
+ - 设备、CLI 或构建环境持续不可用:按 `retry.kind` 分类完成自诊与有限重试后仍为 `external`。
104
+ - 用户主动中断、修改需求或发出新指令。
105
+
106
+ 除上述情形外的一切问题——实现缺陷、构建或测试失败、方案选型、平台差异、facts 与源码的行为歧义——都必须自主决策并继续:选择证据更强的一侧实现,把差异与决策写入 `discoveries.json` 或报告说明;把它们当作暂停或提问的理由,按「禁止的伪完成」的“把实现缺陷写成阻塞”条判定。
107
+
108
+
109
+
110
+ ## 可用命令
111
+
112
+ 统一入口是已通过 npm 安装并位于 `PATH` 中的 `droid2hmos` 命令,直接执行 `droid2hmos ...`。CLI 可用性自检已包含在主流程步骤 0 与步骤 1,此处不再重复。不得寻找或调用已经删除的插件内置脚本,也不得自行拼接内部 Node 入口。只有统一命令实际失败、缺少当前能力,或正在定位 CLI 自身缺陷时,才检查独立 `droid2hmos` 代码仓;此时必须说明统一命令、失败证据和采用调试入口的原因,问题解决后恢复全局命令。
113
+
114
+ | 阶段 | 命令 | 作用与使用时机 |
115
+ |---|---|---|
116
+ | 自检 | `--help` | 验证 CLI 可用并查看当前版本支持的命令。 |
117
+ | 状态 | `status <ANDROID_PROJECT>` | 验证 Android 工作区并读取当前迁移阶段、完成缺口和允许动作。 |
118
+ | 准备 | `preflight <ANDROID_PROJECT> [--sdk-path <PATH>] [--timeout-ms <MS>]` | 检查 Git、HarmonyOS 工具链和设备等迁移环境。 |
119
+ | 分析 | `analyze android <android-project>` | 纯源码静态分析 Android 工程并生成 `.migration/spec/facts/`。 |
120
+ | 规划 | `task plan <android-project>` | 根据当前 Facts 生成 `.migration/tasks/` 派生计划。 |
121
+ | 规划 | `task validate <android-project>` | 检查计划的新鲜度、行为闭包、所有权和依赖关系。 |
122
+ | 规划 | `task next <android-project>` | 取得下一项可以执行的迁移任务。 |
123
+ | 规划 | `task show <android-project> <task-id>` | 取得指定任务的责任范围、验收要求和源码位置索引。 |
124
+ | 实现 | `build harmony <android-project>` | 构建 HarmonyOS 应用并根据编译错误持续修复。 |
125
+ | 验收 | `test harmony <android-project> (--class <CLASS> [--case <CASE>] \| --all) [--target <DEVICE>] [--case-timeout-ms <MS>] [--ref <REPORT_REF>...]` | 执行定向或全量 Hypium 测试;最终验收使用 `--all`。 |
126
+ | 交付 | `complete <android-project>` | 执行最终完成硬门禁。 |
127
+ | 交付 | `report render <android-project>` | 完成门禁通过后生成迁移报告。 |
128
+
129
+
130
+
131
+
132
+
133
+ ## 禁止的伪完成
134
+
135
+ 以下情况即使脚本或报告通过,也必须判定为未完成并继续修复:
136
+
137
+ - **只有报告映射**:报告写着 `verified`,但映射文件中只有注释、空函数或未被调用的代码。必须让真实入口执行该实现并验证效果。
138
+ - **代码存在但不可达**:创建了页面或组件文件,但没有被 Ability、页面注册、导航或真实控件引用。必须从应用真实入口能够到达。
139
+ - **另加控件绕过原设计**:为了测试导航新增一个按钮,而 Android 原控件仍无响应。必须在 Android 对应控件上实现原交互,不得用额外控件替代。
140
+ - **能编译就宣布成功**:HAP 编译、安装、启动且不白屏,但页面布局错误、Dialog 打不开或业务没有效果。必须逐项执行模拟器端到端用例。
141
+ - **截图代替功能验证**:页面截图看起来存在,但控件无法点击、状态不变化或数据不保存。必须真实操作并检查可观察结果。
142
+ - **只覆盖 facts**:报告覆盖所有静态 ref,但源码中还有脚本未发现的页面、入口或业务逻辑。必须主动审查源码并写入 `discoveries.json` 后实现。
143
+ - **测试只写不跑**:存在测试文件或用例描述,但没有本次运行结果和证据。必须实际执行并记录通过证据。
144
+ - **坐标点击冒充验收**:使用 `uitest uiInput click x y` 走通流程,但没有对应 Hypium 用例和本次执行结果。坐标只可用于探索控件,或处理经证据确认没有语义节点的 Canvas、系统界面等例外,不能替代正式端到端验收。
145
+ - **无限推迟测试基建**:以“Hypium 尚未建立”为由连续完成功能并只做手工或坐标验证。第一个可交互功能完成前必须建立并跑通测试模块,否则该功能仍未完成。
146
+ - **用桩隐藏缺口**:返回固定值、空实现、假数据或吞掉错误以通过测试或编译。桩只能保持未完成状态,不能标记 implemented/verified。
147
+ - **把实现缺陷写成阻塞**:编译错误、遗漏回调、错误布局或未完成业务属于当前实现问题,必须修复,不能包装成外部 blocker。
148
+
149
+ 判断原则始终是:**用户在 HarmonyOS 应用中实际看到和操作到的结果是否与 Android 一致**,而不是文件、字段、状态或检查标记是否齐全。
150
+
151
+
152
+
153
+ ## 完成条件
154
+
155
+ 只有同时满足以下条件,才允许宣布迁移完成:
156
+
157
+ - HarmonyOS 工程完整编译、安装、启动和运行成功;
158
+ - 已建立可运行的 Hypium 测试模块,关键交互控件具有稳定语义 ID,所有可交互功能均有本次实际通过的语义化端到端用例;无法语义定位的例外具有明确证据和替代验证;
159
+ - 全量端到端功能回归已按「设备验证标准」节在合格设备上从真实入口完成,并保留可检查证据;
160
+ - Android 的所有页面、可见控件和状态均有真实且一致的 HarmonyOS 实现;
161
+ - 所有导航、Dialog 打开/关闭、返回和结果流均可实际执行;
162
+ - 所有业务功能、状态变化、数据效果和错误路径均已实现并验证;
163
+ - 静态 facts 与 AI 补充发现均有真实实现映射和测试证据;
164
+ - Task Plan 与当前 Facts、correction/review 和 Android 源码指纹一致,结构校验通过,全部 Task 均已取得新鲜的定向设备验证证据,且不存在 orphan Fact;
165
+ - 最终报告完整性门禁通过,且人工需要审视的差异已明确呈现。
166
+ - `droid2hmos complete <android-project>` 成功退出;任何手写完成标记或历史验证结果都不能替代该硬门禁。
167
+
168
+ 再次强调:完成报告不是完成迁移。只有真实 HarmonyOS 应用达到 Android 应用的完整功能与体验一致性,迁移才完成。
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath } from 'node:url';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+ import { installOpenCode } from '../src/install-opencode.mjs';
6
+
7
+ const help = `Install this package's skills and agents into OpenCode.
8
+
9
+ Usage: d2h [options]
10
+
11
+ --source-dir <path> Source root (defaults to this package)
12
+ --config-dir <path> OpenCode config root (OPENCODE_CONFIG_DIR, or
13
+ $XDG_CONFIG_HOME/opencode, or ~/.config/opencode)
14
+ --link Create absolute symbolic links (development only)
15
+ --force Replace conflicting installed skills and agents
16
+ --dry-run Print operations without writing files
17
+ -h, --help Show this help
18
+
19
+ Only skills/*/SKILL.md trees and agents/*.md are installed.
20
+ opencode.json and AGENTS.md are not modified.
21
+ With npx, prefer the default copy mode: its cache can be removed.
22
+ `;
23
+
24
+ try {
25
+ const options = {
26
+ sourceDir: path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'),
27
+ configDir: process.env.OPENCODE_CONFIG_DIR || path.join(
28
+ process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'opencode'),
29
+ };
30
+ const args = process.argv.slice(2);
31
+ for (let index = 0; index < args.length; index++) {
32
+ const arg = args[index];
33
+ if (arg === '-h' || arg === '--help') {
34
+ console.log(help);
35
+ process.exit(0);
36
+ }
37
+ if (arg === '--source-dir' || arg === '--config-dir') {
38
+ const value = args[++index];
39
+ if (!value || value.startsWith('--')) throw new Error(`${arg} requires a path`);
40
+ options[arg === '--source-dir' ? 'sourceDir' : 'configDir'] = value;
41
+ } else if (arg === '--link' || arg === '--force' || arg === '--dry-run') {
42
+ options[{ '--link': 'link', '--force': 'force', '--dry-run': 'dryRun' }[arg]] = true;
43
+ } else {
44
+ throw new Error(`unknown option: ${arg}`);
45
+ }
46
+ }
47
+ installOpenCode(options);
48
+ } catch (error) {
49
+ console.error(`install-opencode: ${error.message}`);
50
+ process.exitCode = 1;
51
+ }
@@ -0,0 +1,160 @@
1
+ #!/bin/sh
2
+
3
+ set -eu
4
+
5
+ usage() {
6
+ cat <<'EOF'
7
+ Install this repository's skills and agents into the user-level OpenCode config.
8
+
9
+ Usage:
10
+ sh install-opencode.sh [options]
11
+
12
+ Options:
13
+ --source-dir <path> Repository root. Defaults to the script directory.
14
+ --config-dir <path> OpenCode config root. Defaults to
15
+ $OPENCODE_CONFIG_DIR, or
16
+ ${XDG_CONFIG_HOME:-$HOME/.config}/opencode.
17
+ --link Create absolute symbolic links for local development.
18
+ --force Replace conflicting installed skills and agents.
19
+ --dry-run Print planned operations without changing files.
20
+ -h, --help Show this help.
21
+
22
+ The installer does not edit opencode.json or copy AGENTS.md. It installs only
23
+ skills/*/SKILL.md trees and agents/*.md into OpenCode's global discovery paths.
24
+ EOF
25
+ }
26
+
27
+ fail() {
28
+ printf 'install-opencode: %s\n' "$*" >&2
29
+ exit 1
30
+ }
31
+
32
+ script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd -P)
33
+ source_dir=$script_dir
34
+ config_dir=${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-${HOME}/.config}/opencode}
35
+ install_mode=copy
36
+ force_install=0
37
+ dry_run=0
38
+
39
+ while [ "$#" -gt 0 ]; do
40
+ case $1 in
41
+ --source-dir)
42
+ [ "$#" -ge 2 ] || fail "--source-dir requires a path"
43
+ source_dir=$2
44
+ shift 2
45
+ ;;
46
+ --config-dir)
47
+ [ "$#" -ge 2 ] || fail "--config-dir requires a path"
48
+ config_dir=$2
49
+ shift 2
50
+ ;;
51
+ --link)
52
+ install_mode=link
53
+ shift
54
+ ;;
55
+ --force)
56
+ force_install=1
57
+ shift
58
+ ;;
59
+ --dry-run)
60
+ dry_run=1
61
+ shift
62
+ ;;
63
+ -h|--help)
64
+ usage
65
+ exit 0
66
+ ;;
67
+ *)
68
+ fail "unknown option: $1"
69
+ ;;
70
+ esac
71
+ done
72
+
73
+ [ -d "$source_dir" ] || fail "source directory not found: $source_dir"
74
+ source_dir=$(CDPATH= cd "$source_dir" && pwd -P)
75
+ skills_source=$source_dir/skills
76
+ agents_source=$source_dir/agents
77
+
78
+ [ -d "$skills_source" ] || fail "skills directory not found: $skills_source"
79
+ [ -d "$agents_source" ] || fail "agents directory not found: $agents_source"
80
+
81
+ case $config_dir in
82
+ ""|/|.|..|"${HOME}"|"${HOME}/")
83
+ fail "refusing unsafe OpenCode config directory: $config_dir"
84
+ ;;
85
+ esac
86
+
87
+ if [ "$dry_run" -eq 0 ]; then
88
+ mkdir -p "$config_dir"
89
+ config_dir=$(CDPATH= cd "$config_dir" && pwd -P)
90
+ mkdir -p "$config_dir/skills" "$config_dir/agents"
91
+ installer_tmp_root=$(mktemp -d "${TMPDIR:-/tmp}/install-opencode.XXXXXX")
92
+ trap 'rm -rf "$installer_tmp_root"' EXIT HUP INT TERM
93
+ else
94
+ installer_tmp_root=
95
+ fi
96
+
97
+ installed_skills=0
98
+ installed_agents=0
99
+
100
+ install_entry() {
101
+ entry_source=$1
102
+ entry_destination=$2
103
+ entry_kind=$3
104
+ entry_name=$4
105
+
106
+ if [ "$install_mode" = link ] && [ -L "$entry_destination" ] && [ "$(readlink "$entry_destination")" = "$entry_source" ]; then
107
+ printf 'unchanged %s: %s\n' "$entry_kind" "$entry_name"
108
+ return
109
+ fi
110
+
111
+ if [ "$install_mode" = copy ] && [ -e "$entry_destination" ] && diff -qr "$entry_source" "$entry_destination" >/dev/null 2>&1; then
112
+ printf 'unchanged %s: %s\n' "$entry_kind" "$entry_name"
113
+ return
114
+ fi
115
+
116
+ if { [ -e "$entry_destination" ] || [ -L "$entry_destination" ]; } && [ "$force_install" -ne 1 ]; then
117
+ fail "$entry_kind '$entry_name' already exists at $entry_destination; rerun with --force to replace it"
118
+ fi
119
+
120
+ if [ "$dry_run" -eq 1 ]; then
121
+ printf 'would install %s: %s -> %s (%s)\n' "$entry_kind" "$entry_source" "$entry_destination" "$install_mode"
122
+ return
123
+ fi
124
+
125
+ if [ -e "$entry_destination" ] || [ -L "$entry_destination" ]; then
126
+ rm -rf "$entry_destination"
127
+ fi
128
+
129
+ if [ "$install_mode" = link ]; then
130
+ ln -s "$entry_source" "$entry_destination"
131
+ else
132
+ entry_stage=$installer_tmp_root/$entry_kind-$entry_name
133
+ cp -R "$entry_source" "$entry_stage"
134
+ mv "$entry_stage" "$entry_destination"
135
+ fi
136
+
137
+ printf 'installed %s: %s\n' "$entry_kind" "$entry_destination"
138
+ }
139
+
140
+ for skill_file in "$skills_source"/*/SKILL.md; do
141
+ [ -f "$skill_file" ] || continue
142
+ skill_directory=$(dirname "$skill_file")
143
+ skill_name=$(basename "$skill_directory")
144
+ install_entry "$skill_directory" "$config_dir/skills/$skill_name" skill "$skill_name"
145
+ installed_skills=$((installed_skills + 1))
146
+ done
147
+
148
+ for agent_file in "$agents_source"/*.md; do
149
+ [ -f "$agent_file" ] || continue
150
+ agent_name=$(basename "$agent_file")
151
+ install_entry "$agent_file" "$config_dir/agents/$agent_name" agent "$agent_name"
152
+ installed_agents=$((installed_agents + 1))
153
+ done
154
+
155
+ [ "$installed_skills" -gt 0 ] || fail "no skills found under $skills_source"
156
+ [ "$installed_agents" -gt 0 ] || fail "no agents found under $agents_source"
157
+
158
+ printf 'OpenCode installation complete: %s skill(s), %s agent(s).\n' "$installed_skills" "$installed_agents"
159
+ printf 'Config directory: %s\n' "$config_dir"
160
+ printf 'Quit and restart OpenCode to load the installed definitions.\n'
@@ -0,0 +1,16 @@
1
+ {
2
+ "android-to-hmos-00-orchestrator": {
3
+ "mode": "all",
4
+ "hidden": false,
5
+ "permissions": {
6
+ "read": "allow",
7
+ "write": "allow",
8
+ "edit": "allow",
9
+ "glob": "allow",
10
+ "grep": "allow",
11
+ "bash": "allow",
12
+ "skill": "allow",
13
+ "task": "allow"
14
+ }
15
+ }
16
+ }
package/package.json CHANGED
@@ -1,6 +1,18 @@
1
1
  {
2
2
  "name": "@harmonyos-arkts/d2h",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Install Android-to-HarmonyOS migration agents and skills into OpenCode",
5
+ "type": "module",
6
+ "bin": { "d2h": "bin/install-opencode.mjs" },
7
+ "files": ["bin/", "src/", "skills/", "agents/", "schemas/", "opencode/", ".claude-plugin/", "install-opencode.sh", "README.md", "LICENSE"],
8
+ "scripts": {
9
+ "check": "node --check bin/install-opencode.mjs && node --check src/install-opencode.mjs && node scripts/check-skill-refs.mjs",
10
+ "test": "node --test test/*.test.mjs",
11
+ "prepublishOnly": "npm run check && npm test"
12
+ },
13
+ "engines": { "node": ">=20 <25" },
14
+ "repository": { "type": "git", "url": "git+https://github.com/Harmony-Ai-Tool/android-to-hmos-migration.git" },
15
+ "license": "MIT",
16
+ "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
17
+ "keywords": ["android", "harmonyos", "arkts", "migration", "opencode"]
18
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/android-source-manifest.schema.json",
4
+ "title": "Managed Android source member manifest",
5
+ "type": "object",
6
+ "required": ["manifestVersion", "androidRoot", "members", "manifestSha256"],
7
+ "properties": {
8
+ "manifestVersion": { "const": "1.0.0" },
9
+ "androidRoot": { "type": "string", "minLength": 1 },
10
+ "members": {
11
+ "type": "array",
12
+ "items": {
13
+ "type": "object",
14
+ "required": ["androidFile", "fileSha256"],
15
+ "properties": {
16
+ "androidFile": { "type": "string", "pattern": "^(?![/\\\\])(?!.*(?:^|[/\\\\])\\.\\.(?:[/\\\\]|$)).+" },
17
+ "fileSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
18
+ },
19
+ "additionalProperties": false
20
+ }
21
+ },
22
+ "manifestSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
23
+ },
24
+ "additionalProperties": false
25
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/checkpoint-provenance.schema.json",
4
+ "title": "Git-linked migration source provenance receipt",
5
+ "type": "object",
6
+ "required": ["checkpointProvenanceVersion", "reportValidationVersion", "factsSha256", "evidenceLevel", "sourceManifest", "sourceClaims", "committedFiles", "orderAudit", "closureAudit", "literalAudit"],
7
+ "properties": {
8
+ "checkpointProvenanceVersion": { "const": "1.0.0" },
9
+ "reportValidationVersion": { "const": "1.2.0" },
10
+ "factsSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
11
+ "evidenceLevel": { "enum": ["declared-hash-validated", "observed-order-audited"] },
12
+ "sourceManifest": {
13
+ "type": "object",
14
+ "required": ["manifestVersion", "androidRoot", "members", "manifestSha256"],
15
+ "properties": {
16
+ "manifestVersion": { "const": "1.0.0" },
17
+ "androidRoot": { "type": "string", "minLength": 1 },
18
+ "members": {
19
+ "type": "array",
20
+ "items": {
21
+ "type": "object",
22
+ "required": ["androidFile", "fileSha256"],
23
+ "properties": {
24
+ "androidFile": { "type": "string", "minLength": 1 },
25
+ "fileSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
26
+ },
27
+ "additionalProperties": false
28
+ }
29
+ },
30
+ "manifestSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
31
+ },
32
+ "additionalProperties": false
33
+ },
34
+ "sourceClaims": {
35
+ "type": "array",
36
+ "items": {
37
+ "type": "object",
38
+ "required": ["ref", "kind", "status", "harmonyosFiles", "sourceProvenance"],
39
+ "properties": {
40
+ "ref": { "type": "string", "minLength": 1 },
41
+ "kind": { "type": "string", "minLength": 1 },
42
+ "status": { "enum": ["implemented", "verified"] },
43
+ "harmonyosFiles": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
44
+ "sourceProvenance": { "type": "array", "minItems": 1, "items": { "type": "object" } }
45
+ },
46
+ "additionalProperties": false
47
+ }
48
+ },
49
+ "committedFiles": {
50
+ "type": "array",
51
+ "items": {
52
+ "type": "object",
53
+ "required": ["file", "role", "fileSha256"],
54
+ "properties": {
55
+ "file": { "type": "string", "minLength": 1 },
56
+ "role": { "enum": ["android-source", "harmony-implementation"] },
57
+ "fileSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
58
+ },
59
+ "additionalProperties": false
60
+ }
61
+ },
62
+ "orderAudit": { "type": "object" },
63
+ "closureAudit": { "type": "object" },
64
+ "literalAudit": { "type": "object" }
65
+ },
66
+ "additionalProperties": false
67
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/final-acceptance.schema.json",
4
+ "title": "Lightweight migration final acceptance",
5
+ "type": "object",
6
+ "required": ["reportShardVersion", "kind", "status", "tests", "blockers", "notes"],
7
+ "properties": {
8
+ "reportShardVersion": { "const": "1.2.0" },
9
+ "kind": { "const": "final-acceptance" },
10
+ "status": { "enum": ["pending", "passed", "failed"] },
11
+ "tests": {
12
+ "type": "array",
13
+ "items": {
14
+ "type": "object",
15
+ "required": ["ref", "name", "status", "evidence"],
16
+ "properties": {
17
+ "ref": { "type": "string", "minLength": 1 },
18
+ "name": { "type": "string", "minLength": 1 },
19
+ "status": { "enum": ["passed", "failed"] },
20
+ "evidence": { "type": "array", "items": { "type": "string" } }
21
+ },
22
+ "additionalProperties": false
23
+ }
24
+ },
25
+ "blockers": { "type": "array", "items": { "type": "string", "minLength": 1 } },
26
+ "notes": { "type": "array", "items": { "type": "string", "minLength": 1 } }
27
+ },
28
+ "additionalProperties": false
29
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://harmonyos-ai.dev/schemas/managed-evidence-index.schema.json",
4
+ "title": "droid2hmos Managed Evidence Index",
5
+ "type": "object",
6
+ "required": ["evidenceIndexVersion", "latestByAction"],
7
+ "properties": {
8
+ "evidenceIndexVersion": { "const": "1.0.0" },
9
+ "latestByAction": {
10
+ "type": "object",
11
+ "additionalProperties": { "type": "string", "pattern": "^\\.migration/evidence/managed/.+\\.json$" }
12
+ }
13
+ },
14
+ "additionalProperties": false
15
+ }