@buaa_smat/hometrans 0.1.15 → 0.1.16

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 (35) hide show
  1. package/README.md +54 -89
  2. package/agents/build-fixer.md +15 -14
  3. package/agents/code-reviewer.md +3 -3
  4. package/agents/logic-coder.md +1 -1
  5. package/agents/logic-context-builder.md +1 -1
  6. package/agents/self-tester.md +16 -13
  7. package/dist/cli/config-store.js +127 -29
  8. package/dist/cli/config.js +9 -2
  9. package/dist/cli/init.js +367 -248
  10. package/dist/cli/uninstall.js +12 -7
  11. package/dist/context/index.js +19 -2
  12. package/env-requirements.json +19 -23
  13. package/package.json +1 -1
  14. package/resource/choose_editor.png +0 -0
  15. package/resource/set_environment.png +0 -0
  16. package/resource/set_multimodel.png +0 -0
  17. package/resource/set_sdk.png +0 -0
  18. package/skills/hmos-batch-ui-align/SKILL.md +6 -6
  19. package/skills/hmos-convert-pipeline/SKILL.md +7 -7
  20. package/skills/hmos-fix-build-errors/SKILL.md +4 -3
  21. package/skills/hmos-incremental-ui-align/README.md +9 -12
  22. package/skills/hmos-incremental-ui-align/SKILL.md +9 -9
  23. package/skills/hmos-incremental-ui-align/scripts/__pycache__/app_feature_verify.cpython-314.pyc +0 -0
  24. package/skills/hmos-incremental-ui-align/scripts/app_feature_verify.py +128 -29
  25. package/skills/hmos-incremental-ui-align/scripts/navigation-capure.md +37 -37
  26. package/skills/hmos-incremental-ui-align/scripts/page_capture.py +7 -2
  27. package/skills/hmos-integration-test/README.md +3 -3
  28. package/skills/hmos-integration-test/SKILL.md +7 -7
  29. package/skills/hmos-spec-generate/SKILL.md +45 -52
  30. package/tools/test-tools/autotest/README.md +10 -11
  31. package/tools/test-tools/autotest/self_test_runner.py +40 -12
  32. package/resource/common_config.png +0 -0
  33. package/resource/integration_test_config.png +0 -0
  34. package/resource/set_env.png +0 -0
  35. package/resource/ui_align_config.png +0 -0
package/README.md CHANGED
@@ -2,32 +2,31 @@
2
2
 
3
3
 
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D%2022-339933.svg?logo=node.js&logoColor=white)](https://nodejs.org/en/download)
6
+
7
+ [![Claude Code](https://img.shields.io/badge/Claude_Code-supported-blueviolet.svg)](#选择本地editor)
8
+ [![Cursor](https://img.shields.io/badge/Cursor-supported-blueviolet.svg)](#选择本地editor)
9
+ [![OpenCode](https://img.shields.io/badge/OpenCode-supported-blueviolet.svg)](#选择本地editor)
10
+ [![DevEco Code](https://img.shields.io/badge/DevEco_Code-supported-blueviolet.svg)](#选择本地editor)
11
+ [![Codex](https://img.shields.io/badge/Codex-supported-blueviolet.svg)](#选择本地editor)
12
+ [![CodeBuddy](https://img.shields.io/badge/CodeBuddy-supported-blueviolet.svg)](#选择本地editor)
5
13
 
6
14
  本文档为完整的Android到HarmonyOS迁移流程指导。
7
15
 
8
16
  ---
9
17
 
10
- ## 步骤0:安装依赖
11
-
12
- ### 0.1安装依赖并连接设备
13
-
14
- 按以下顺序安装(`ht init` 会逐项检测,并提示缺失项对各skill的影响)。各依赖下方均列出了「被依赖」的步骤:如果你不需要执行某依赖所对应的步骤,则可以不安装该依赖(相应skill会显示为受限或不可用,但不影响其它步骤)。
18
+ ## 安装DevEco Studio以及Android Studio
15
19
 
16
- 1. **安装DevEco Studio** — 下载地址:<https://developer.huawei.com/consumer/cn/download/>。安装完成后,配置以下 **PATH环境变量**(`<DevEco安装目录>` 指DevEco Studio的安装根目录):
20
+ 1. **安装DevEco Studio** — 下载地址:<https://developer.huawei.com/consumer/cn/download/>。安装完成后,配置以下 **PATH环境变量**:
17
21
 
18
22
  | 工具 | PATH中加入的目录 |
19
23
  |------|------------------|
20
- | node / npm / npx | `<DevEco安装目录>\tools\node` |
21
24
  | java | `<DevEco安装目录>\jbr\bin` |
22
25
  | hdc | `<DevEco安装目录>\sdk\default\openharmony\toolchains` |
23
26
 
24
- 验证方式:执行 `node -v`、`java -version`、`hdc -v` 均返回正常
27
+ 验证方式:执行 `java -version`、`hdc -v` 均返回正常
28
+
25
29
 
26
- 被依赖:
27
- - 资源转换skill(java可选,缺失时回退读取源码 `res/`)
28
- - 步骤1.2UI对齐(必需)
29
- - 步骤3逻辑代码转换流水线(必需,构建/评审修复)
30
- - 集成测试skill(必需,真机调试)
31
30
  2. **安装Android Studio** — 下载地址:<https://developer.android.com/studio>,并在 **SDK Manager** 中安装SDK。
32
31
 
33
32
  验证方式:执行 `adb version` 返回正常
@@ -35,96 +34,62 @@
35
34
  被依赖:
36
35
  - 步骤1.1UI迁移(可选,仅自动抓取页面快照时需要)
37
36
  - 步骤1.2UI对齐(必需)
38
- 3. **安装uv** — 安装指引:<https://docs.astral.sh/uv/getting-started/installation/>。
39
37
 
40
- 验证方式:执行 `uv --version` 返回正常
38
+ ## 安装Node.js
41
39
 
42
- 被依赖:
43
- - 步骤3逻辑代码转换流水线的自测阶段(可经 `skip_test` 跳过)
44
- - 集成测试skill(必需,AutoTest在uv下运行)
45
- 4. **安装python** — 安装指引:<https://www.python.org/downloads/>,要求 ≥ 3.10。
40
+ 安装 **Node.js(版本需 >= 22)** — 下载地址:<https://nodejs.org/en/download>。
46
41
 
47
- 验证方式:执行 `python --version` 返回正常
42
+ 验证方式:执行 `node -v`、`npm -v`、`npx -v` 均返回正常,且 `node -v` 显示版本不低于 22
48
43
 
49
- 被依赖:
50
- - 步骤1.1UI迁移(必需,页面快照解析脚本)
51
- - 步骤1.2UI对齐(必需,双端页面采集脚本)
52
- 5. **安装 [GitNexus](https://github.com/abhigyanpatwari/GitNexus)** — 执行 `npm install -g gitnexus && gitnexus setup`
44
+ ## 安装HomeTrans
53
45
 
54
- 验证方式:执行 `gitnexus --version` 返回正常
46
+ 执行 `npm install -g @buaa_smat/hometrans`。
55
47
 
56
- 被依赖:
57
- - 步骤2生成需求规格(必需)
58
- 6. **连接设备** — 连接安卓和鸿蒙真机,或启动模拟器
48
+ 验证方式:执行 `hometrans --version` 或 `ht --version` 返回正常
59
49
 
60
- 被依赖:
61
- - 安卓真机/模拟器 — 步骤1 UI迁移
62
- - 鸿蒙真机/模拟器 — 步骤1.2UI对齐
63
- - 鸿蒙**真机** — 步骤3流水线自测阶段、集成测试skill
50
+ ## 环境初始化
64
51
 
65
- ### 0.2安装hometrans
52
+ 执行 `hometrans init` 或 `ht init`。
66
53
 
67
- 执行 `npm install -g @buaa_smat/hometrans`。
54
+ > 如果在PowerShell下运行,命令需要加上 `.cmd` 后缀,如 `hometrans.cmd --version`、`ht.cmd init`。
68
55
 
69
- 验证方式:执行 `hometrans --version` 或 `ht --version` 返回正常
56
+ ### 选择本地editor:
57
+ ![choose_editor.png](https://raw.gitcode.com/SMAT/HomeTrans/raw/main/resource/choose_editor.png)
70
58
 
71
- 然后执行 `hometrans init` 或 `ht init`。
59
+ ### 参数配置:
72
60
 
61
+ #### 配置鸿蒙SDK:
62
+ ![set_sdk.png](https://raw.gitcode.com/SMAT/HomeTrans/raw/main/resource/set_sdk.png)
73
63
 
74
- > 如果在PowerShell下运行,命令需要加上 `.cmd` 后缀,如 `hometrans.cmd --version`、`ht.cmd init`。
64
+ #### 配置多模态模型(不执行UI对齐以及集成测试可以跳过该配置):
65
+ ![set_multimodel.png](https://raw.gitcode.com/SMAT/HomeTrans/raw/main/resource/set_multimodel.png)
66
+
67
+ | 参数 | 含义 |
68
+ |-----------------|---------|
69
+ | `model_api_key` | 用于模型API请求认证的令牌 |
70
+ | `model_name` | 多模态(视觉)模型的名字 |
71
+ | `model_base_url` | 模型API服务的基础地址 |
72
+
73
+ ##### 配置参考
74
+
75
+ 前往[阿里云百炼平台](https://bailian.console.aliyun.com/)开通服务并申请 API Key,选用 Qwen 系列多模态(视觉)模型(如 `qwen3.5-plus`)。
76
+
77
+ | 参数 | 取值 |
78
+ |---|-----------------------------------------------------|
79
+ | `model_api_key` | 百炼控制台申请的 API Key(形如 `sk-xxxxxxxx`) |
80
+ | `model_name` | `qwen3.5-plus` |
81
+ | `model_base_url` | `https://dashscope.aliyuncs.com/compatible-mode/v1` |
82
+
83
+ #### 将配置信息添加到环境变量:
84
+ ![set_environment.png](https://raw.gitcode.com/SMAT/HomeTrans/raw/main/resource/set_environment.png)
75
85
 
76
- ### 0.2.1选择本地editor:
77
- ![choose_editor.png](resource/choose_editor.png)
78
-
79
- ### 0.2.2通用配置:
80
- ![common_config.png](resource/common_config.png)
81
- - `DEVECO_SDK_HOME` — DevEco Studio的sdk目录,其余路径由它派生并校验存在。示例:
82
-
83
- ```text
84
- + DEVECO_SDK_HOME : <DevEco安装目录>\sdk
85
- + DEVECO_HOME : <DevEco安装目录>
86
- + OHOS_SDK_PATH : <DevEco安装目录>\sdk\default\openharmony\ets
87
- + HMS_SDK_PATH : <DevEco安装目录>\sdk\default\hms\ets
88
- ```
89
- ### 0.2.3 UI对齐配置(如果不执行步骤1.2UI对齐,则可以不配置):
90
- ![ui_align_config.png](resource/ui_align_config.png)
91
- - `GLM_API_KEY` — UI对齐中过程中GLM phone agent所用的LLM API key。
92
-
93
- 申请方式:在[智谱官方网站](https://bigmodel.cn/apikey/platform)注册用户后,申请一个API KEY即可,调用的是免费的auto-glm模型,无需充值。
94
-
95
- ### 0.2.4集成测试配置(如果不执行步骤3的自测阶段与集成测试skill,则可以不配置):
96
- ![integration_test_config.png](resource/integration_test_config.png)
97
- - `autotest api_key` — 集成测试agent执行测试用例(真机自测)所用的多模态大模型API key。各配置项含义如下,`init` 环节只配置前4项,其余参数在`config.json`中配置。
98
-
99
- | 参数 | 示例 / 默认值 | 含义 |
100
- |-------------------|--------------|------|
101
- | `name` | `""` | 多模态(视觉)模型的名字 |
102
- | `base_url` | `""` | 模型API服务的基础地址 |
103
- | `api_key` | (需填写) | 用于模型API请求认证的令牌 |
104
- | `provider` | `openai` | 模型API服务的提供方标识,如openai;Azure服务填azure |
105
- | `temperature` | `0.1` | 采样温度 |
106
- | `top_p` | `0.9` | 核采样阈值 |
107
- | `frequency_penalty` | `0.5` | 重复惩罚 |
108
- | `device_sn` | `null` | 设备序列号;`null` 表示自动选用当前连接的设备 |
109
- | `ip` | `127.0.0.1` | 设备连接IP(hdc) |
110
- | `port` | `8710` | 设备连接端口(hdc) |
111
- | `device_log_level` | `debug` | 设备日志级别:debug/info/... |
112
- | `max_steps` | `50` | 单条用例最大执行步数 |
113
- | `verbose` | `true` | 是否输出详细日志 |
114
- | `lang` | `zh` | 输出语言:zh/en |
115
- | `enable_preprocess` | `false` | 执行前是否先用unified_model把用例拆成步骤序列(多一次LLM调用,默认关) |
116
- | `debug_mode` | `null` | 调试会话:`null` 关闭 / `memory` 内存 / `file` 存盘并跑完后起调试服务(:5000) |
117
-
118
- ### 0.2.5将配置信息添加到环境变量:
119
- ![set_env.png](resource/set_env.png)
120
-
121
- ### 0.3准备项目
86
+ ### 准备项目
122
87
 
123
88
  准备 **Android源项目** 与 **HarmonyOS目标项目目录**。
124
89
 
125
90
  ---
126
91
  ## 迁移流程
127
- ![migration_process.svg](resource/migration_process.svg)
92
+ ![migration_process.svg](https://raw.gitcode.com/SMAT/HomeTrans/raw/main/resource/migration_process.svg)
128
93
 
129
94
  ---
130
95
 
@@ -132,7 +97,7 @@
132
97
 
133
98
  ### 1.1UI迁移(`hmos-batch-ui-align`)
134
99
 
135
- > 📦 依赖:python(必需,页面快照解析脚本);Android Studio + 安卓真机/模拟器(可选,仅自动抓取页面快照时需要)。
100
+ > 📦 依赖:uv(必需,页面快照解析脚本经 `uv run` 运行,uv 自带 Python);Android Studio + 安卓真机/模拟器(可选,仅自动抓取页面快照时需要)。
136
101
 
137
102
  ```
138
103
  /hmos-batch-ui-align android_project_dir=<安卓项目路径> harmony_project_dir=<鸿蒙项目路径> ui_info_root=<页面快照目录>
@@ -157,7 +122,7 @@
157
122
 
158
123
  ### 1.2UI对齐(`hmos-incremental-ui-align`,按需)
159
124
 
160
- > 📦 依赖:DevEco Studio、Android Studio、python(必需,双端页面采集脚本);安卓真机/模拟器 + 鸿蒙真机/模拟器(必需)。
125
+ > 📦 依赖:DevEco Studio、Android Studio、uv(必需,双端页面采集脚本经 `uv run` 运行,uv 自带 Python);安卓真机/模拟器 + 鸿蒙真机/模拟器(必需)。
161
126
 
162
127
  ```
163
128
  /hmos-incremental-ui-align android_project_dir=<安卓工程路径> harmony_project_dir=<鸿蒙工程路径>
@@ -183,7 +148,7 @@
183
148
 
184
149
  ## 步骤2:生成需求规格(`hmos-spec-generate`)
185
150
 
186
- > 📦 依赖:GitNexus(必需)。
151
+ > 📦 依赖:homegraph(必需)。
187
152
 
188
153
  > 👤 前置:用户编写 `REQ.txt` 文件 — 以自然语言描述原始需求,如有多个需求则在文件中使用空行进行分隔,需求中建议包含页面跳转路径的说明以及业务逻辑的描述。
189
154
 
@@ -231,13 +196,13 @@
231
196
  | 产物 | 位置 | 说明 |
232
197
  |------|------|------|
233
198
  | `<feature>-SPEC.md` | `spec_output_dir` | 每个REQ对应一份原子场景规格文档 |
234
- | `.trace/<feature>.md` | `spec_output_dir/.trace/` | 每个REQ对应的代码trace(GitNexus探索结果) |
199
+ | `.trace/<feature>.md` | `spec_output_dir/.trace/` | 每个REQ对应的代码trace(homegraph探索结果) |
235
200
 
236
201
  ---
237
202
 
238
203
  ## 步骤3:逻辑代码转换流水线(`hmos-convert-pipeline`)
239
204
 
240
- > 📦 依赖:DevEco Studio(必需,构建/评审修复);uv + 鸿蒙真机(集成测试阶段需要,可经 `skip_test` 跳过)。
205
+ > 📦 依赖:DevEco Studio(必需,构建/评审修复);uv + 鸿蒙真机(集成测试阶段需要,可经 `skip_test` 跳过;uv 经 `uv run` 运行 `self_test_runner.py` 并自带 Python)。
241
206
 
242
207
  > 👤 前置:
243
208
  > 1. 如果执行集成测试,需要**编写测试用例文档**输出前置测试用例(非必须,用于测试用例的环境准备等)通过pre_test_case_path参数传递,测试用例通过test_case_path参数传递。
@@ -29,24 +29,25 @@ Execute a build-fix loop: resolve environment → validate project → build →
29
29
 
30
30
  The build requires the **DevEco Studio installation path**, from which Node.js, hvigor, and ohpm are derived.
31
31
 
32
- ### 0a. Read the DevEco environment variables
32
+ ### 0a. Read the DevEco config values
33
33
 
34
- Read these **directly from the OS environment** `ht init` persists them as machine environment variables (`echo "$VAR"` on macOS/Linux; `$env:VAR` in PowerShell on Windows):
34
+ Resolve each value along the standard chain — **OS environment variable first, then `~/.hometrans/config.json` (its `env.*` block), then ask the user**. `ht init` persists these both as machine environment variables and in config.json (read env vars with `echo "$VAR"` on macOS/Linux; `$env:VAR` in PowerShell on Windows):
35
35
 
36
- | Variable | Meaning |
37
- |---|---|
38
- | `DEVECO_SDK_HOME` | DevEco sdk dir, e.g. `D:/DevEco Studio/sdk` — single source of truth |
39
- | `DEVECO_HOME` | DevEco install root, e.g. `D:/DevEco Studio` |
40
- | `OHOS_SDK_PATH` | `<DEVECO_SDK_HOME>/default/openharmony/ets` |
41
- | `HMS_SDK_PATH` | `<DEVECO_SDK_HOME>/default/hms/ets` |
36
+ | Variable | config.json fallback | Meaning |
37
+ |---|---|---|
38
+ | `DEVECO_SDK_HOME` | `env.DEVECO_SDK_HOME` | DevEco sdk dir, e.g. `D:/DevEco Studio/sdk` — single source of truth |
39
+ | `DEVECO_HOME` | `env.DEVECO_HOME` | DevEco install root, e.g. `D:/DevEco Studio` |
40
+ | `OHOS_SDK_PATH` | `env.OHOS_SDK_PATH` | `<DEVECO_SDK_HOME>/default/openharmony/ets` |
41
+ | `HMS_SDK_PATH` | `env.HMS_SDK_PATH` | `<DEVECO_SDK_HOME>/default/hms/ets` |
42
42
 
43
- ### 0b. Resolve the DevEco root `<deveco>` — env vars first, then auto-detect, then ask
43
+ ### 0b. Resolve the DevEco root `<deveco>` — env vars config.json auto-detect ask
44
44
 
45
45
  Stop at the **first** source that yields a path:
46
46
 
47
- 1. **Environment variables**: `DEVECO_HOME` if non-empty → that is `<deveco>`; else `DEVECO_SDK_HOME` → `<deveco>` is its **parent directory**; else (legacy) strip the trailing `/sdk/default/openharmony/ets` from `OHOS_SDK_PATH` (or `/sdk/default/hms/ets` from `HMS_SDK_PATH`) to get `<deveco>`.
48
- 2. **Auto-detect** (0c below).
49
- 3. If both fail, **ask the user** for the DevEco Studio install path (suggest running `ht init` to persist it as an environment variable).
47
+ 1. **OS environment variables**: `DEVECO_HOME` if non-empty → that is `<deveco>`; else `DEVECO_SDK_HOME` → `<deveco>` is its **parent directory**; else (legacy) strip the trailing `/sdk/default/openharmony/ets` from `OHOS_SDK_PATH` (or `/sdk/default/hms/ets` from `HMS_SDK_PATH`) to get `<deveco>`.
48
+ 2. **`~/.hometrans/config.json`**: apply the same derivation to `env.DEVECO_HOME` / `env.DEVECO_SDK_HOME` (read with `uv run --no-project python -c "import json;from pathlib import Path;p=Path.home()/'.hometrans'/'config.json';print((json.loads(p.read_text(encoding='utf-8')).get('env') or {}).get('DEVECO_HOME','') if p.exists() else '')"`).
49
+ 3. **Auto-detect** (0c below).
50
+ 4. If all fail, **ask the user** for the DevEco Studio install path (suggest running `ht init` to persist it as an environment variable).
50
51
 
51
52
  > Example: `DEVECO_SDK_HOME = D:/DevEco Studio/sdk` → `<deveco> = D:/DevEco Studio`.
52
53
 
@@ -58,9 +59,9 @@ From `<deveco>`, derive:
58
59
 
59
60
  Verify these files exist. If they do, use them and skip auto-detection. If an env-sourced path does **not** exist on disk, treat that source as invalid and continue down the resolution order.
60
61
 
61
- ### 0c. Auto-detect if env vars are missing or invalid
62
+ ### 0c. Auto-detect if env vars and config.json are missing or invalid
62
63
 
63
- If the environment variables do not yield a valid install, auto-detect:
64
+ If neither the environment variables nor `~/.hometrans/config.json` yield a valid install, auto-detect:
64
65
 
65
66
  1. **Find DevEco Studio installation**:
66
67
  - Search common locations: `D:\DevEco Studio`, `C:\DevEco Studio`, `C:\Program Files\DevEco Studio`
@@ -33,10 +33,10 @@ Before starting the review, extract the code context for the commit via the `ext
33
33
  - `projectPath`: `<harmony_project_dir>` (absolute path to the HarmonyOS project root containing the `.git` directory)
34
34
  - `commitId`: `<commit_id>` (the git commit to analyze — diffs against its first parent)
35
35
  - `mode`: `"default"` (builds full call graph for call-chain context)
36
- - `ohosSdkPath` / `hmsSdkPath`: the OpenHarmony / HMS SDK ETS directory paths. Resolve each **from the OS environment**, stopping at the first hit:
36
+ - `ohosSdkPath` / `hmsSdkPath`: the OpenHarmony / HMS SDK ETS directory paths. Resolve each along the standard chain — **OS environment variable → `~/.hometrans/config.json` → ask the user** — stopping at the first hit:
37
37
  1. `OHOS_SDK_PATH` / `HMS_SDK_PATH` environment variables; if those are empty but `DEVECO_SDK_HOME` is set, derive them as `<DEVECO_SDK_HOME>/default/openharmony/ets` and `<DEVECO_SDK_HOME>/default/hms/ets`.
38
- 2. Omit the parameter to let the tool read `OHOS_SDK_PATH` / `HMS_SDK_PATH` from the environment itself.
39
- 3. If the environment provides no path that exists on disk, **ask the user** for the DevEco `sdk` directory (and suggest running `ht init` to persist it as an environment variable).
38
+ 2. Omit the parameter to let the `extract_commit_context` tool resolve them itself — it reads `OHOS_SDK_PATH` / `HMS_SDK_PATH` from the OS environment, then falls back to `env.OHOS_SDK_PATH` / `env.HMS_SDK_PATH` in `~/.hometrans/config.json`.
39
+ 3. If neither the environment nor `~/.hometrans/config.json` provides a path that exists on disk, **ask the user** for the DevEco `sdk` directory (and suggest running `ht init` to persist it as an environment variable).
40
40
 
41
41
  2. **On success** — the tool returns the affected code context (diffs, call graphs, impacted files). Treat this response as the **code context** for the review.
42
42
 
@@ -16,7 +16,7 @@ min-model: sonnet
16
16
 
17
17
  Platform context query:
18
18
 
19
- python3 {scripts}/platform_context_query.py \
19
+ uv run --no-project python {scripts}/platform_context_query.py \
20
20
  --request {output_path}/platform-context-request.json \
21
21
  --out-dir {output_path}/platform-context-{N}
22
22
 
@@ -16,7 +16,7 @@ min-model: sonnet
16
16
 
17
17
  Platform context query:
18
18
 
19
- python3 {scripts}/platform_context_query.py \
19
+ uv run --no-project python {scripts}/platform_context_query.py \
20
20
  --request {output_path}/platform-context-request.json \
21
21
  --out-dir {output_path}/platform-context-{N}
22
22
 
@@ -38,16 +38,19 @@ You are a self-tester for HarmonyOS applications. You run a single pipeline: par
38
38
 
39
39
  ### AutoTest Directory Locator
40
40
 
41
- Used independently by S5 and T4. The AutoTest tools are installed by `ht init` under the HomeTrans tools dir; resolve their location from config rather than searching the filesystem.
41
+ Used independently by S5 and T4. The AutoTest tools are installed by `ht init` under the HomeTrans tools dir; resolve their location along the standard config chain — **OS environment variable → `~/.hometrans/config.json` → filesystem walk-up** — rather than searching the filesystem first.
42
42
 
43
- **Primaryread `HOMETRANS_TOOL_PATH` directly from the OS environment.** The autotest dir is `<HOMETRANS_TOOL_PATH>/test-tools/autotest`:
43
+ **Tier 1 OS environment variable `HOMETRANS_TOOL_PATH`; Tier 2 `env.HOMETRANS_TOOL_PATH` in `~/.hometrans/config.json`.** The autotest dir is `<tool_path>/test-tools/autotest`:
44
44
 
45
45
  ```bash
46
46
  tool_path="$HOMETRANS_TOOL_PATH"
47
+ if [ -z "$tool_path" ]; then \
48
+ tool_path="$(uv run --no-project python -c "import json,os; from pathlib import Path; cfg=Path.home()/'.hometrans'/'config.json'; print((json.loads(cfg.read_text(encoding='utf-8')).get('env') or {}).get('HOMETRANS_TOOL_PATH','') if cfg.exists() else '')" 2>/dev/null)"; \
49
+ fi
47
50
  if [ -n "$tool_path" ] && [ -d "$tool_path/test-tools/autotest" ]; then echo "$tool_path/test-tools/autotest"; fi
48
51
  ```
49
52
 
50
- If the `HOMETRANS_TOOL_PATH` environment variable is unset or invalid, **fall back** to walking up from `<output_path>` for a sibling `test-tools/autotest` (then `agents/test-tools/autotest` for legacy layouts) — **anchor the search at `<output_path>`, the sub-agent cwd is not guaranteed**:
53
+ If neither the env var nor `~/.hometrans/config.json` yields a valid tool path, **fall back** (Tier 3) to walking up from `<output_path>` for a sibling `test-tools/autotest` (then `agents/test-tools/autotest` for legacy layouts) — **anchor the search at `<output_path>`, the sub-agent cwd is not guaranteed**:
51
54
 
52
55
  ```bash
53
56
  d="<output_path>"; while [ "$d" != "/" ] && [ "$d" != "" ]; do \
@@ -195,7 +198,7 @@ cd "<autotest_dir>" && uv run python testcases_tool.py generate "<output_path>/_
195
198
  **Sanity-check `[PRE]` ordering** — run this command **if and only if** a `pre_test_case.md` was found and extracted in S4.1. If no pre-cases were extracted, skip this step entirely (the assertion would spuriously fail on an empty `pre` list):
196
199
 
197
200
  ```bash
198
- python -c "import json,sys; d=json.load(open(sys.argv[1],encoding='utf-8')); pre=[i for i,c in enumerate(d) if c['case_name'].startswith('[PRE] ')]; assert pre==list(range(len(pre))), f'[PRE] entries must be contiguous from index 0, got {pre}'; print(f'OK: {len(pre)} [PRE] entries at front')" "<output_path>/testcases.json"
201
+ uv run --no-project python -c "import json,sys; d=json.load(open(sys.argv[1],encoding='utf-8')); pre=[i for i,c in enumerate(d) if c['case_name'].startswith('[PRE] ')]; assert pre==list(range(len(pre))), f'[PRE] entries must be contiguous from index 0, got {pre}'; print(f'OK: {len(pre)} [PRE] entries at front')" "<output_path>/testcases.json"
199
202
  ```
200
203
 
201
204
  If assertion fails, edit `_extracted.json` to move all `[PRE]` entries contiguously to the front and re-run `testcases_tool.py`.
@@ -219,7 +222,7 @@ test -f "<hap_path>" && mkdir -p "<output_path>" && test -f "<output_path>/testc
219
222
  If `setup=false`, additionally verify each JSON parses and `testcases.json` is non-empty:
220
223
 
221
224
  ```bash
222
- python -c "import json,sys; t=json.load(open(sys.argv[1],encoding='utf-8')); m=json.load(open(sys.argv[2],encoding='utf-8')); assert isinstance(t,list) and len(t)>0, 'testcases.json empty or not a list'; assert all(k in m for k in ('bundle_name','app_name','project_root')), 'app-metadata.json missing required fields'; print('OK')" "<output_path>/testcases.json" "<output_path>/app-metadata.json"
225
+ uv run --no-project python -c "import json,sys; t=json.load(open(sys.argv[1],encoding='utf-8')); m=json.load(open(sys.argv[2],encoding='utf-8')); assert isinstance(t,list) and len(t)>0, 'testcases.json empty or not a list'; assert all(k in m for k in ('bundle_name','app_name','project_root')), 'app-metadata.json missing required fields'; print('OK')" "<output_path>/testcases.json" "<output_path>/app-metadata.json"
223
226
  ```
224
227
 
225
228
  If any check fails, write a `self-test-report.md` using the sentinel format from Shared Utilities. The `reason:` line names the specific failure, e.g.:
@@ -246,17 +249,17 @@ Record the device serial number.
246
249
 
247
250
  ### T4 — Locate AutoTest Directory & Verify autotest config
248
251
 
249
- Find the `test-tools/autotest` directory using the **AutoTest Directory Locator** in Shared Utilities (OS env var `HOMETRANS_TOOL_PATH` → walk up from `<output_path>`). If not found, write a `self-test-report.md` with the sentinel format (`status: FAIL` / `reason: AutoTest directory not found from HOMETRANS_TOOL_PATH env var or output_path`), then stop.
252
+ Find the `test-tools/autotest` directory using the **AutoTest Directory Locator** in Shared Utilities (OS env var `HOMETRANS_TOOL_PATH` → `env.HOMETRANS_TOOL_PATH` in `~/.hometrans/config.json` → walk up from `<output_path>`). If not found, write a `self-test-report.md` with the sentinel format (`status: FAIL` / `reason: AutoTest directory not found from HOMETRANS_TOOL_PATH env var or output_path`), then stop.
250
253
 
251
254
  Set `<autotest_dir>` to the found path.
252
255
 
253
- The AutoTest configuration now lives in the `autotest` block of `~/.hometrans/config.json` (it replaced the old `config.yaml`). `self_test_runner.py` reads it at run time and materializes a transient YAML for `AutoTest.batch` — you do **not** create or edit any YAML. Just verify the config is usable: the `autotest` block exists with a real `api_key`, **or** the `TEST_API_KEY` OS environment variable is set (the runner uses it to fill a placeholder/empty key).
256
+ The model config is shared with UI alignment and resolved along the standard chain **env var → `~/.hometrans/config.json` ask**. `self_test_runner.py` reads it at run time (env `HOMETRANS_MODEL_API_KEY` overrides `autotest.unified_model.api_key`; legacy `TEST_API_KEY` still honored as a fallback) and materializes a transient YAML for `AutoTest.batch` — you do **not** create or edit any YAML. Just verify the api_key is usable: the `HOMETRANS_MODEL_API_KEY` (or legacy `TEST_API_KEY`) OS environment variable is set, **or** the `autotest` block in `~/.hometrans/config.json` has a real (non-placeholder) `api_key`.
254
257
 
255
258
  ```bash
256
- python -c "import json,os,sys; from pathlib import Path; cfg=Path.home()/'.hometrans'/'config.json'; tp=os.environ.get('HOMETRANS_TOOL_PATH'); cand=(Path(tp).parent/'config.json') if tp else None; cfg=cand if (cand and cand.exists()) else cfg; at=(json.loads(cfg.read_text(encoding='utf-8')).get('autotest') or {}) if cfg.exists() else {}; real=any(isinstance(at.get(k),dict) and str(at[k].get('api_key','')).strip() not in ('','YOUR_API_KEY_HERE') for k in ('unified_model','execute_model','decision_model')); print('OK' if (real or os.environ.get('TEST_API_KEY','').strip()) else 'MISSING')"
259
+ uv run --no-project python -c "import json,os,sys; from pathlib import Path; cfg=Path.home()/'.hometrans'/'config.json'; tp=os.environ.get('HOMETRANS_TOOL_PATH'); cand=(Path(tp).parent/'config.json') if tp else None; cfg=cand if (cand and cand.exists()) else cfg; at=(json.loads(cfg.read_text(encoding='utf-8')).get('autotest') or {}) if cfg.exists() else {}; real=any(isinstance(at.get(k),dict) and str(at[k].get('api_key','')).strip() not in ('','YOUR_API_KEY_HERE') for k in ('unified_model','execute_model','decision_model')); env=os.environ.get('HOMETRANS_MODEL_API_KEY','').strip() or os.environ.get('TEST_API_KEY','').strip(); print('OK' if (env or real) else 'MISSING')"
257
260
  ```
258
261
 
259
- If this does not print `OK` (no `autotest` block with a real `api_key`, and no `TEST_API_KEY` in the OS environment), write `self-test-report.md` with the sentinel format (`status: FAIL` / `reason: autotest api_key not configured — set TEST_API_KEY env var or run ht init`), then stop.
262
+ If this does not print `OK` (no `HOMETRANS_MODEL_API_KEY` in the OS environment, and no `autotest` block with a real `api_key`), write `self-test-report.md` with the sentinel format (`status: FAIL` / `reason: model api_key not configured — set HOMETRANS_MODEL_API_KEY env var or run ht init`), then stop.
260
263
 
261
264
  ### T5 — Clean Task Directory
262
265
 
@@ -267,7 +270,7 @@ rm -rf "<output_path>/task" && echo "Task directory cleaned" || echo "Task direc
267
270
  ### T6 — Run self_test_runner.py
268
271
 
269
272
  > 🚨 **MANDATORY**: Environment setup, HAP installation, and test execution are all handled by a **single invocation** of `self_test_runner.py run`. The script synchronously executes:
270
- > 1. Read & validate the `autotest` config from `~/.hometrans/config.json` (filling the api_key from `TEST_API_KEY` if needed) and materialize a transient YAML for AutoTest.batch
273
+ > 1. Read & validate the `autotest` config from `~/.hometrans/config.json` (env `HOMETRANS_MODEL_API_KEY` overrides the api_key; legacy `TEST_API_KEY` honored as a fallback) and materialize a transient YAML for AutoTest.batch
271
274
  > 2. `uv sync` — installs `harmony-autotest` + `hypium_mcp`
272
275
  > 3. `hdc uninstall` + `hdc install -r`
273
276
  >
@@ -281,7 +284,7 @@ rm -rf "<output_path>/task" && echo "Task directory cleaned" || echo "Task direc
281
284
  > - ❌ Writing a shell loop or Python loop to iterate over cases yourself
282
285
 
283
286
  ```bash
284
- cd "<autotest_dir>" && python self_test_runner.py run --testcases "<output_path>/testcases.json" --hap "<hap_path>" --bundle-name "<bundle_name>" --category "<app_name>" --task-dir "<output_path>/task" --output-dir "<output_path>"
287
+ cd "<autotest_dir>" && uv run --no-project python self_test_runner.py run --testcases "<output_path>/testcases.json" --hap "<hap_path>" --bundle-name "<bundle_name>" --category "<app_name>" --task-dir "<output_path>/task" --output-dir "<output_path>"
285
288
  ```
286
289
 
287
290
  Record the `pid` and `task_subdir` from the output.
@@ -291,7 +294,7 @@ Record the `pid` and `task_subdir` from the output.
291
294
  Each poll MUST include `sleep 60`. **Use `timeout: 120000` on each Bash call** so the 60-second sleep plus the status command have headroom and the status check itself isn't truncated:
292
295
 
293
296
  ```bash
294
- sleep 60 && cd "<autotest_dir>" && python self_test_runner.py status --task-dir "<output_path>/task" --output-dir "<output_path>"
297
+ sleep 60 && cd "<autotest_dir>" && uv run --no-project python self_test_runner.py status --task-dir "<output_path>/task" --output-dir "<output_path>"
295
298
  ```
296
299
 
297
300
  | `status` | Meaning | Exit code | Action |
@@ -310,7 +313,7 @@ sleep 60 && cd "<autotest_dir>" && python self_test_runner.py status --task-dir
310
313
 
311
314
  **Polling rules:**
312
315
  - Max iterations: **N_cases × 6** (each case takes ~6 minutes). For 8 cases → max 48 polls. If still `RUNNING` after that, kill and write TIMEOUT report.
313
- - **Timeout kill**: `cd "<autotest_dir>" && python self_test_runner.py kill --task-dir "<output_path>/task"`. This verifies the PID belongs to an `AutoTest.batch` process before terminating it.
316
+ - **Timeout kill**: `cd "<autotest_dir>" && uv run --no-project python self_test_runner.py kill --task-dir "<output_path>/task"`. This verifies the PID belongs to an `AutoTest.batch` process before terminating it.
314
317
  - **CRASHED**: Write CRASHED report with sentinel (`status: FAIL` / `reason: AutoTest batch crashed`). Include the `log_tail` from the status response. `task_results.jsonl` is unavailable.
315
318
  - **TIMEOUT**: After killing, write TIMEOUT report with sentinel (`status: FAIL` / `reason: AutoTest batch timed out after N polls`) and include partial results from `task_results.jsonl` if any cases finished.
316
319