@buaa_smat/hometrans 0.1.15 → 0.1.17
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.md +108 -99
- package/agents/build-fixer.md +15 -14
- package/agents/code-reviewer.md +3 -3
- package/agents/logic-coder.md +1 -1
- package/agents/logic-context-builder.md +1 -1
- package/agents/self-tester.md +16 -13
- package/dist/cli/config-store.js +127 -29
- package/dist/cli/config.js +9 -2
- package/dist/cli/init.js +431 -248
- package/dist/cli/uninstall.js +103 -8
- package/dist/context/index.js +19 -2
- package/env-requirements.json +19 -23
- package/package.json +1 -1
- package/resource/choose_editor.png +0 -0
- package/resource/set_environment.png +0 -0
- package/resource/set_multimodel.png +0 -0
- package/resource/set_sdk.png +0 -0
- package/skills/hmos-batch-ui-align/SKILL.md +8 -6
- package/skills/hmos-convert-pipeline/SKILL.md +7 -7
- package/skills/hmos-fix-build-errors/SKILL.md +4 -3
- package/skills/hmos-incremental-ui-align/README.md +9 -12
- package/skills/hmos-incremental-ui-align/SKILL.md +9 -9
- package/skills/hmos-incremental-ui-align/scripts/__pycache__/app_feature_verify.cpython-314.pyc +0 -0
- package/skills/hmos-incremental-ui-align/scripts/app_feature_verify.py +128 -29
- package/skills/hmos-incremental-ui-align/scripts/navigation-capure.md +37 -37
- package/skills/hmos-incremental-ui-align/scripts/page_capture.py +7 -2
- package/skills/hmos-integration-test/README.md +3 -3
- package/skills/hmos-integration-test/SKILL.md +7 -7
- package/skills/hmos-spec-generate/SKILL.md +45 -52
- package/tools/test-tools/autotest/README.md +10 -11
- package/tools/test-tools/autotest/self_test_runner.py +40 -12
- package/resource/common_config.png +0 -0
- package/resource/integration_test_config.png +0 -0
- package/resource/set_env.png +0 -0
- package/resource/ui_align_config.png +0 -0
- package/skills/hmos-resources-convert/tools/apktool.bat +0 -85
|
@@ -14,11 +14,10 @@ HarmonyOS 应用自测执行器。负责把自然语言写的测试用例(`tes
|
|
|
14
14
|
|
|
15
15
|
| 工具 | 用途 | 验证命令 |
|
|
16
16
|
|------|------|----------|
|
|
17
|
-
| `uv` | Python 包管理 / 启动 `harmony-autotest` | `uv --version` |
|
|
17
|
+
| `uv` | Python 包管理 / 启动 `harmony-autotest` / 提供 Python 解释器 | `uv --version` |
|
|
18
18
|
| `hdc` | 设备连接 / 安装 HAP | `hdc version` |
|
|
19
|
-
| `python` ≥ 3.10 | 入口脚本 | `python --version` |
|
|
20
19
|
|
|
21
|
-
> `uv sync`(从本地 `tools/test-tools/` 目录加载 6 个 whl)由 `self_test_runner.py` 自动执行,无需手动 `pip install`。
|
|
20
|
+
> 入口脚本经 `uv run --no-project python self_test_runner.py` 运行 —— uv 自带 Python(≥ 3.10),无需单独安装 Python。`uv sync`(从本地 `tools/test-tools/` 目录加载 6 个 whl)由 `self_test_runner.py` 自动执行,无需手动 `pip install`。
|
|
22
21
|
|
|
23
22
|
### 2. 配置 `autotest`(在 `~/.hometrans/config.json` 中)
|
|
24
23
|
|
|
@@ -45,8 +44,8 @@ AutoTest 配置不再使用本目录下的 `config.yaml`,而是集中存放在
|
|
|
45
44
|
}
|
|
46
45
|
```
|
|
47
46
|
|
|
48
|
-
- `ht init` 的
|
|
49
|
-
-
|
|
47
|
+
- `ht init` 的 **模型配置** 环节会展示该块默认内容并提示填写 `api_key`(及 `name`/`base_url`/`provider`),写入 `~/.hometrans/config.json` 的 `autotest.unified_model`,并导出为 `HOMETRANS_MODEL_*` 环境变量(与 UI 对齐共用同一个模型)。
|
|
48
|
+
- 模型字段解析链路「环境变量 → config.json → 报错」:`self_test_runner.py` 跑用例前用 OS 环境变量 `HOMETRANS_MODEL_API_KEY` / `HOMETRANS_MODEL_NAME` / `HOMETRANS_MODEL_BASE_URL` 覆盖 config.json 里 `unified_model` 的对应字段(api_key 兼容老版本 `TEST_API_KEY` 作兜底;`provider` 不导出为环境变量,始终取 config.json,默认 openai);覆盖后 api_key 仍是占位符/空才报错退出。
|
|
50
49
|
- 运行时 `self_test_runner.py` 读取该块、物化成本次任务专属的临时 YAML(`task_<ts>/autotest_config.yaml`)再交给 `AutoTest.batch`,缺 `agent_mode` 时默认补 `"single"`。
|
|
51
50
|
- 默认单层模式只需填 `unified_model.api_key`;如需双层模式,可在 `autotest` 块里手动加 `execute_model` / `decision_model`(各自含 `api_key`)并把 `agent_mode` 设为 `"layered"`。
|
|
52
51
|
|
|
@@ -128,7 +127,7 @@ agent 内部用的就是这个脚本,开发自测时可以直接调:
|
|
|
128
127
|
cd agents/test-tools/autotest
|
|
129
128
|
|
|
130
129
|
# 启动一次自测(前台同步做准备 + 后台启动 batch,立即返回 PID)
|
|
131
|
-
python self_test_runner.py run \
|
|
130
|
+
uv run --no-project python self_test_runner.py run \
|
|
132
131
|
--testcases <path-to-testcases.json> \
|
|
133
132
|
--hap <path-to-app.hap> \
|
|
134
133
|
--bundle-name com.example.xxx \
|
|
@@ -137,14 +136,14 @@ python self_test_runner.py run \
|
|
|
137
136
|
--output-dir <out>
|
|
138
137
|
|
|
139
138
|
# 轮询状态(agent 每 60s 查一次)
|
|
140
|
-
python self_test_runner.py status --task-dir <out>/task --output-dir <out>
|
|
139
|
+
uv run --no-project python self_test_runner.py status --task-dir <out>/task --output-dir <out>
|
|
141
140
|
|
|
142
141
|
# 强行终止后台 batch
|
|
143
|
-
python self_test_runner.py kill --task-dir <out>/task
|
|
142
|
+
uv run --no-project python self_test_runner.py kill --task-dir <out>/task
|
|
144
143
|
|
|
145
144
|
# 重置本地状态(杀残留进程 + 删 .venv + 删本目录残留中间产物)
|
|
146
145
|
# 用它代替手工 `rm -rf .venv` / `uv cache clean`,不会动全局 uv 缓存
|
|
147
|
-
python self_test_runner.py clean
|
|
146
|
+
uv run --no-project python self_test_runner.py clean
|
|
148
147
|
```
|
|
149
148
|
|
|
150
149
|
### `report_tool.py` — 单独重渲染报告
|
|
@@ -215,7 +214,7 @@ agents/test-tools/autotest/
|
|
|
215
214
|
## 六、常见问题
|
|
216
215
|
|
|
217
216
|
**Q: `autotest 配置缺失 / api_key 没填`**
|
|
218
|
-
A: 跑 `ht init`
|
|
217
|
+
A: 跑 `ht init` 配置统一模型,它会写入 `~/.hometrans/config.json` 的 `autotest.unified_model` 并导出 `HOMETRANS_MODEL_*` 环境变量;或手动把 `autotest.unified_model.api_key` 改成真实 key;或设置 OS 环境变量 `HOMETRANS_MODEL_API_KEY`(兼容老版本 `TEST_API_KEY`)后重试。
|
|
219
218
|
|
|
220
219
|
**Q: `uv sync` 卡住或失败**
|
|
221
220
|
A: 6 个 whl 改为从本地 `tools/test-tools/` 目录加载(`pyproject.toml` 的 `[tool.uv.sources]` 用相对路径 `../*.whl`)。失败时确认这 6 个 whl 文件存在于上一级目录;其余依赖仍从清华 PyPI 镜像拉取,需基本网络。也可以 `--force-reinit` 强制重建。
|
|
@@ -224,7 +223,7 @@ A: 6 个 whl 改为从本地 `tools/test-tools/` 目录加载(`pyproject.toml`
|
|
|
224
223
|
A: 不会。`self_test_runner.py run` 启动时会扫描并 kill 残留的 `AutoTest.batch` / `hypium_mcp` / `harmony_autotest` 进程(不止靠 PID 文件,按命令行名兜底),并自动清掉本目录顶层的 `tmp_hypium/` / `hypium_mcp.log` 等遗留中间产物。`task/` 目录在 agent 流程里也会被清空。
|
|
225
224
|
|
|
226
225
|
**Q: 想彻底重置一遍本地状态再跑?**
|
|
227
|
-
A: 跑一次 `python self_test_runner.py clean`:杀残留 → 删 `.venv` → 删 `tmp_hypium/` / `hypium_mcp.log` / `batch.pid` / `batch_stdout.log`。**不要**手工 `uv cache clean`——全局缓存清空后重装 6 个 whl 要从 gitcode 重新拉(1–3 分钟);这 6 个 whl 现在从本地加载、不走网络,但其余依赖仍走缓存,保留缓存的话 `uv sync` 只需几秒。
|
|
226
|
+
A: 跑一次 `uv run --no-project python self_test_runner.py clean`:杀残留 → 删 `.venv` → 删 `tmp_hypium/` / `hypium_mcp.log` / `batch.pid` / `batch_stdout.log`。**不要**手工 `uv cache clean`——全局缓存清空后重装 6 个 whl 要从 gitcode 重新拉(1–3 分钟);这 6 个 whl 现在从本地加载、不走网络,但其余依赖仍走缓存,保留缓存的话 `uv sync` 只需几秒。
|
|
228
227
|
|
|
229
228
|
**Q: 想自己改 `testcases.json` 后再跑?**
|
|
230
229
|
A: 改完后跑一遍校验,再交给 `self-tester`(`setup=false`):
|
|
@@ -333,9 +333,15 @@ def get_uv():
|
|
|
333
333
|
|
|
334
334
|
|
|
335
335
|
def _uv_env():
|
|
336
|
+
# Isolate inner uv calls (`uv sync`, `uv run --project`) from the outer
|
|
337
|
+
# `uv run --no-project` context that launches this script: drop the
|
|
338
|
+
# recursion marker and any inherited VIRTUAL_ENV so the inner uv always
|
|
339
|
+
# targets SCRIPT_DIR/.venv, never the launcher's ephemeral environment.
|
|
336
340
|
env = os.environ.copy()
|
|
337
341
|
env["UV_NO_PROGRESS"] = "1"
|
|
338
342
|
env["RUST_LOG"] = "off"
|
|
343
|
+
env.pop("UV_RUN_RECURSION_DEPTH", None)
|
|
344
|
+
env.pop("VIRTUAL_ENV", None)
|
|
339
345
|
return env
|
|
340
346
|
|
|
341
347
|
|
|
@@ -433,8 +439,9 @@ def load_autotest_config(explicit: str | None) -> dict:
|
|
|
433
439
|
"""从 `~/.hometrans/config.json` 读取 `autotest` 配置并校验。
|
|
434
440
|
|
|
435
441
|
- 缺文件 / 缺 `autotest` 字段 → 报错退出,提示运行 `ht init`。
|
|
436
|
-
-
|
|
437
|
-
|
|
442
|
+
- 模型字段优先用 OS 环境变量 HOMETRANS_MODEL_* 覆盖 config.json
|
|
443
|
+
(api_key 兼容老版本 TEST_API_KEY 作兜底)。
|
|
444
|
+
- 覆盖后仍有未填的 api_key → 报错退出。
|
|
438
445
|
- 缺 `agent_mode` 时默认补 "single"。
|
|
439
446
|
返回可直接物化成 YAML 的 dict。
|
|
440
447
|
"""
|
|
@@ -462,16 +469,34 @@ def load_autotest_config(explicit: str | None) -> dict:
|
|
|
462
469
|
# 深拷贝,避免改动原始 dict(虽然这里只读不写回)
|
|
463
470
|
autotest = json.loads(json.dumps(autotest))
|
|
464
471
|
|
|
465
|
-
#
|
|
466
|
-
|
|
472
|
+
# 统一配置链路「环境变量 → config.json → 报错」:UI 对齐与自测共用同一个多模态
|
|
473
|
+
# 模型,由 `ht init` 导出为 HOMETRANS_MODEL_*。环境变量优先级最高——存在即覆盖
|
|
474
|
+
# config.json 里 unified_model 的对应字段;缺失时才用 config.json 的值。
|
|
475
|
+
# provider 不导出为环境变量(默认 openai),始终取 config.json 的值。
|
|
476
|
+
env_model = {
|
|
477
|
+
"api_key": (
|
|
478
|
+
os.environ.get("HOMETRANS_MODEL_API_KEY", "").strip()
|
|
479
|
+
or os.environ.get("TEST_API_KEY", "").strip() # 兼容老版本
|
|
480
|
+
),
|
|
481
|
+
"name": os.environ.get("HOMETRANS_MODEL_NAME", "").strip(),
|
|
482
|
+
"base_url": os.environ.get("HOMETRANS_MODEL_BASE_URL", "").strip(),
|
|
483
|
+
}
|
|
484
|
+
um = autotest.get("unified_model")
|
|
485
|
+
if isinstance(um, dict):
|
|
486
|
+
for field in ("api_key", "name", "base_url"):
|
|
487
|
+
if env_model[field]:
|
|
488
|
+
um[field] = env_model[field]
|
|
489
|
+
# api_key 为各端点共用:环境变量存在时一并覆盖 execute/decision 双层模式的端点。
|
|
490
|
+
if env_model["api_key"]:
|
|
491
|
+
for _name, model in _model_dicts(autotest):
|
|
492
|
+
model["api_key"] = env_model["api_key"]
|
|
493
|
+
|
|
494
|
+
# 覆盖后仍为占位符/空的 api_key → 收集后报错(链路最后一层:提示用户配置)。
|
|
467
495
|
missing = []
|
|
468
496
|
for name, model in _model_dicts(autotest):
|
|
469
497
|
cur = str(model.get("api_key", "")).strip()
|
|
470
498
|
if not cur or cur == API_KEY_PLACEHOLDER:
|
|
471
|
-
|
|
472
|
-
model["api_key"] = env_key
|
|
473
|
-
else:
|
|
474
|
-
missing.append(f"{name}.api_key")
|
|
499
|
+
missing.append(f"{name}.api_key")
|
|
475
500
|
|
|
476
501
|
if not list(_model_dicts(autotest)):
|
|
477
502
|
logger.error(
|
|
@@ -484,7 +509,7 @@ def load_autotest_config(explicit: str | None) -> dict:
|
|
|
484
509
|
logger.error(
|
|
485
510
|
f"autotest 配置中以下 api_key 仍为占位符/空:{', '.join(missing)}。\n"
|
|
486
511
|
f"请在 {config_path} 的 autotest 配置里填入真实 api_key,"
|
|
487
|
-
f"或设置 OS 环境变量
|
|
512
|
+
f"或设置 OS 环境变量 HOMETRANS_MODEL_API_KEY 后重试(可运行 `ht init` 一并配置)。"
|
|
488
513
|
)
|
|
489
514
|
sys.exit(1)
|
|
490
515
|
|
|
@@ -536,8 +561,9 @@ def cmd_run(args):
|
|
|
536
561
|
msg = (
|
|
537
562
|
f"Refusing to run: this script is executing inside {target_venv}, "
|
|
538
563
|
f"which it is about to delete and recreate (Windows file locks will leave "
|
|
539
|
-
f"the venv in a broken state). Invoke
|
|
540
|
-
f"`python self_test_runner.py run ...`
|
|
564
|
+
f"the venv in a broken state). Invoke it so the interpreter stays OUT of "
|
|
565
|
+
f"that venv, e.g. `uv run --no-project python self_test_runner.py run ...` "
|
|
566
|
+
f"(NOT plain `uv run python ...`, which would execute inside the project venv)."
|
|
541
567
|
)
|
|
542
568
|
logger.error(msg)
|
|
543
569
|
print(json.dumps({"status": "ERROR", "reason": msg}))
|
|
@@ -622,7 +648,9 @@ def cmd_run(args):
|
|
|
622
648
|
|
|
623
649
|
# 后台启动 AutoTest.batch
|
|
624
650
|
logger.info("=== Step 3: 后台启动 AutoTest.batch ===")
|
|
625
|
-
|
|
651
|
+
# _uv_env() so the detached `uv run --project` also stays isolated from
|
|
652
|
+
# the outer `uv run --no-project` launcher context.
|
|
653
|
+
batch_env = _uv_env()
|
|
626
654
|
batch_env["PYTHONIOENCODING"] = "utf-8"
|
|
627
655
|
batch_env["PYTHONUTF8"] = "1"
|
|
628
656
|
batch_env["PYTHONUNBUFFERED"] = "1"
|
|
Binary file
|
|
Binary file
|
package/resource/set_env.png
DELETED
|
Binary file
|
|
Binary file
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
@echo off
|
|
2
|
-
setlocal
|
|
3
|
-
set BASENAME=apktool_
|
|
4
|
-
chcp 65001 2>nul >nul
|
|
5
|
-
|
|
6
|
-
set java_exe=java.exe
|
|
7
|
-
|
|
8
|
-
if defined JAVA_HOME (
|
|
9
|
-
set "java_exe=%JAVA_HOME%\bin\java.exe"
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
rem Find the highest version .jar available in the same directory as the script
|
|
13
|
-
setlocal EnableDelayedExpansion
|
|
14
|
-
pushd "%~dp0"
|
|
15
|
-
if exist apktool.jar (
|
|
16
|
-
set BASENAME=apktool
|
|
17
|
-
goto skipversioned
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
set BASENAME=apktool
|
|
21
|
-
set max_major=0
|
|
22
|
-
set max_minor=0
|
|
23
|
-
set max_patch=0
|
|
24
|
-
|
|
25
|
-
rem Loop through all versioned .jar files matching the basename
|
|
26
|
-
for %%F in (%BASENAME%*.jar) do (
|
|
27
|
-
set "filename=%%~nF"
|
|
28
|
-
|
|
29
|
-
rem Extract version part (apktool-X.Y.Z)
|
|
30
|
-
for /f "tokens=2 delims=_-" %%A in ("!filename!") do (
|
|
31
|
-
for /f "tokens=1,2,3 delims=." %%B in ("%%A") do (
|
|
32
|
-
set "major=%%B"
|
|
33
|
-
set "minor=%%C"
|
|
34
|
-
set "patch=%%D"
|
|
35
|
-
|
|
36
|
-
rem Set Default minor/patch to 0
|
|
37
|
-
if "!minor!"=="" set "minor=0"
|
|
38
|
-
if "!patch!"=="" set "patch=0"
|
|
39
|
-
|
|
40
|
-
rem Compare major version
|
|
41
|
-
if !major! gtr !max_major! (
|
|
42
|
-
set "max_major=!major!"
|
|
43
|
-
set "max_minor=!minor!"
|
|
44
|
-
set "max_patch=!patch!"
|
|
45
|
-
) else if !major! == !max_major! (
|
|
46
|
-
rem Compare minor version
|
|
47
|
-
if !minor! gtr !max_minor! (
|
|
48
|
-
set "max_minor=!minor!"
|
|
49
|
-
set "max_patch=!patch!"
|
|
50
|
-
) else if !minor! == !max_minor! (
|
|
51
|
-
rem Compare patch version
|
|
52
|
-
if !patch! gtr !max_patch! (
|
|
53
|
-
set "max_patch=!patch!"
|
|
54
|
-
)
|
|
55
|
-
)
|
|
56
|
-
)
|
|
57
|
-
)
|
|
58
|
-
)
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
rem Construct full version string
|
|
62
|
-
set "max=_!max_major!.!max_minor!.!max_patch!"
|
|
63
|
-
|
|
64
|
-
:skipversioned
|
|
65
|
-
popd
|
|
66
|
-
setlocal DisableDelayedExpansion
|
|
67
|
-
|
|
68
|
-
rem Find out if the commandline is a parameterless .jar or directory, for fast unpack/repack
|
|
69
|
-
if "%~1"=="" goto load
|
|
70
|
-
if not "%~2"=="" goto load
|
|
71
|
-
set ATTR=%~a1
|
|
72
|
-
if "%ATTR:~0,1%"=="d" (
|
|
73
|
-
rem Directory, rebuild
|
|
74
|
-
set fastCommand=b
|
|
75
|
-
)
|
|
76
|
-
if "%ATTR:~0,1%"=="-" if "%~x1"==".apk" (
|
|
77
|
-
rem APK file, unpack
|
|
78
|
-
set fastCommand=d
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
:load
|
|
82
|
-
"%java_exe%" -jar -Xmx1024M -Duser.language=en -Dfile.encoding=UTF8 -Djdk.util.zip.disableZip64ExtraFieldValidation=true -Djdk.nio.zipfs.allowDotZipEntry=true "%~dp0%BASENAME%%max%.jar" %fastCommand% %*
|
|
83
|
-
|
|
84
|
-
rem Pause when ran non interactively
|
|
85
|
-
for %%i in (%cmdcmdline%) do if /i "%%~i"=="/c" pause & exit /b
|