@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.
Files changed (36) hide show
  1. package/README.md +108 -99
  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 +431 -248
  10. package/dist/cli/uninstall.js +103 -8
  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 +8 -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
  36. package/skills/hmos-resources-convert/tools/apktool.bat +0 -85
@@ -22,9 +22,19 @@ import { removeEnvVars } from './env-vars.js';
22
22
  const execFileAsync = promisify(execFile);
23
23
  const __filename = fileURLToPath(import.meta.url);
24
24
  const __dirname = path.dirname(__filename);
25
- /** Names + readable count of env vars that have a non-empty value in config. */
26
- function plannedEnvVarNames(env) {
27
- return MACHINE_ENV_KEYS.filter((k) => (env[k] ?? '').trim().length > 0);
25
+ /**
26
+ * Global Node CLIs that `ht init` installs as a pair (`npm install -g homegraph
27
+ * arkanalyzer`). `ht uninstall` removes the same pair so the two commands stay
28
+ * symmetric.
29
+ */
30
+ const NODE_DEPS = ['homegraph', 'arkanalyzer'];
31
+ /**
32
+ * Machine env var names that `ht init` may have set and that have a non-empty
33
+ * value in config.env: the SDK paths / tool dir plus the mirrored unified model
34
+ * fields (HOMETRANS_MODEL_*, kept in sync with autotest.unified_model on load).
35
+ */
36
+ function plannedEnvVarNames(config) {
37
+ return MACHINE_ENV_KEYS.filter((k) => (config.env[k] ?? '').trim().length > 0);
28
38
  }
29
39
  /* ------------------------------------------------------------------ */
30
40
  /* Bundled content discovery */
@@ -68,6 +78,57 @@ async function listBundledAgentEntries(agentsRoot) {
68
78
  }
69
79
  }
70
80
  /* ------------------------------------------------------------------ */
81
+ /* Global npm dependency removal */
82
+ /* ------------------------------------------------------------------ */
83
+ /**
84
+ * Is `npm` runnable? On Windows the global npm bin is a `.cmd` shim, so the
85
+ * command must run through the shell there (same as init's homegraphVersion()).
86
+ */
87
+ async function npmAvailable() {
88
+ try {
89
+ await execFileAsync('npm', ['--version'], {
90
+ timeout: 15000,
91
+ shell: process.platform === 'win32',
92
+ });
93
+ return true;
94
+ }
95
+ catch {
96
+ return false;
97
+ }
98
+ }
99
+ /**
100
+ * Does `homegraph --version` return normally (exit 0)? Used as the presence
101
+ * probe for the homegraph/arkanalyzer pair — the symmetric counterpart to
102
+ * init's idempotency check, which skips the install when homegraph is already
103
+ * present.
104
+ */
105
+ async function homegraphInstalled() {
106
+ try {
107
+ await execFileAsync('homegraph', ['--version'], {
108
+ timeout: 15000,
109
+ shell: process.platform === 'win32',
110
+ });
111
+ return true;
112
+ }
113
+ catch {
114
+ return false;
115
+ }
116
+ }
117
+ /**
118
+ * Decide which global npm packages to remove. Returns the homegraph/arkanalyzer
119
+ * pair when homegraph is detected on the machine (mirroring init, which installs
120
+ * them together), or an empty list when npm is unavailable or homegraph is not
121
+ * present — so a machine that never ran `ht init`'s dependency install shows
122
+ * nothing to remove here.
123
+ */
124
+ async function detectNodeDepsToRemove() {
125
+ if (!(await npmAvailable()))
126
+ return [];
127
+ if (!(await homegraphInstalled()))
128
+ return [];
129
+ return [...NODE_DEPS];
130
+ }
131
+ /* ------------------------------------------------------------------ */
71
132
  /* MCP config removal helpers */
72
133
  /* ------------------------------------------------------------------ */
73
134
  function detectIndentation(raw) {
@@ -299,6 +360,7 @@ function renderDiff(oldContent, newContent, context = 3) {
299
360
  function isPlanEmpty(plan) {
300
361
  return (plan.deletions.length === 0 &&
301
362
  plan.modifications.length === 0 &&
363
+ plan.npmDeps.length === 0 &&
302
364
  plan.envVars.length === 0 &&
303
365
  plan.configDir === null);
304
366
  }
@@ -325,6 +387,14 @@ function renderPlan(plan) {
325
387
  console.log('');
326
388
  }
327
389
  }
390
+ if (plan.npmDeps.length > 0) {
391
+ console.log(chalk.red.bold(` Global npm packages to remove (${plan.npmDeps.length}):`));
392
+ console.log(chalk.gray(` (will run: npm uninstall -g ${plan.npmDeps.join(' ')})`));
393
+ for (const dep of plan.npmDeps) {
394
+ console.log(` ${chalk.red('-')} ${dep}`);
395
+ }
396
+ console.log('');
397
+ }
328
398
  if (plan.envVars.length > 0) {
329
399
  console.log(chalk.red.bold(` Environment variables to remove (${plan.envVars.length}):`));
330
400
  console.log(chalk.gray(process.platform === 'win32'
@@ -347,6 +417,7 @@ function renderPlan(plan) {
347
417
  async function executePlan(plan) {
348
418
  let deleted = 0;
349
419
  let modified = 0;
420
+ let npmNote = null;
350
421
  let envNote = null;
351
422
  for (const mod of plan.modifications) {
352
423
  await fs.writeFile(mod.absPath, mod.newContent, 'utf-8');
@@ -362,6 +433,22 @@ async function executePlan(plan) {
362
433
  // codex CLI unavailable or failed — TOML path already handled above
363
434
  }
364
435
  }
436
+ // Remove the global npm CLIs installed by `ht init` (homegraph + arkanalyzer).
437
+ // Best-effort: a failure is reported in the note but never aborts the rest of
438
+ // the uninstall.
439
+ if (plan.npmDeps.length > 0) {
440
+ console.log(chalk.gray(` Running: npm uninstall -g ${plan.npmDeps.join(' ')} ...`));
441
+ try {
442
+ await execFileAsync('npm', ['uninstall', '-g', ...plan.npmDeps], {
443
+ timeout: 5 * 60 * 1000,
444
+ shell: process.platform === 'win32',
445
+ });
446
+ npmNote = `removed ${plan.npmDeps.join(', ')}`;
447
+ }
448
+ catch (err) {
449
+ npmNote = `failed (${err.message}) — remove manually: npm uninstall -g ${plan.npmDeps.join(' ')}`;
450
+ }
451
+ }
365
452
  for (const del of plan.deletions) {
366
453
  try {
367
454
  await fs.rm(del.absPath, { recursive: true, force: true });
@@ -384,7 +471,7 @@ async function executePlan(plan) {
384
471
  // best-effort
385
472
  }
386
473
  }
387
- return { deleted, modified, envNote };
474
+ return { deleted, modified, npmNote, envNote };
388
475
  }
389
476
  /* ------------------------------------------------------------------ */
390
477
  /* Entry point */
@@ -398,20 +485,25 @@ export async function uninstallCommand() {
398
485
  console.log(chalk.gray(' Reinstall hometrans or manually remove skill/agent directories from your editors.\n'));
399
486
  return;
400
487
  }
401
- const { editors, env } = await loadHomeTransConfig();
488
+ const config = await loadHomeTransConfig();
489
+ const { editors } = config;
402
490
  const plan = {
403
491
  deletions: [],
404
492
  modifications: [],
405
493
  codexRemove: false,
494
+ npmDeps: [],
406
495
  envVars: [],
407
496
  configDir: null,
408
497
  };
409
498
  for (const editor of editors) {
410
499
  await buildPlanForEditor(editor, skillNames, agentEntries, plan);
411
500
  }
412
- // Env vars to remove come from config.json `env`; the ~/.hometrans dir
413
- // (which holds config.json) is deleted last.
414
- plan.envVars = plannedEnvVarNames(env);
501
+ // Global npm CLIs installed by `ht init` (homegraph + arkanalyzer) — detected
502
+ // the same way init decides whether to (re)install them.
503
+ plan.npmDeps = await detectNodeDepsToRemove();
504
+ // Env vars to remove come from config.json (`env` + the unified model
505
+ // fields); the ~/.hometrans dir (which holds config.json) is deleted last.
506
+ plan.envVars = plannedEnvVarNames(config);
415
507
  const configDir = getConfigDir();
416
508
  if (await dirExists(configDir)) {
417
509
  plan.configDir = configDir;
@@ -446,6 +538,9 @@ export async function uninstallCommand() {
446
538
  const summary = await executePlan(plan);
447
539
  console.log('');
448
540
  console.log(chalk.green(` Uninstalled: ${summary.deleted} entries deleted, ${summary.modified} files modified.`));
541
+ if (summary.npmNote) {
542
+ console.log(chalk.green(` Global npm packages: ${summary.npmNote}`));
543
+ }
449
544
  if (summary.envNote) {
450
545
  console.log(chalk.green(` Environment variables: ${summary.envNote}`));
451
546
  }
@@ -10,8 +10,25 @@ import {
10
10
  } from "arkanalyzer";
11
11
 
12
12
  // src/cli/config-store.ts
13
+ import { readFileSync } from "node:fs";
13
14
  import path from "node:path";
14
15
  import os from "node:os";
16
+ function getConfigDir() {
17
+ return path.join(os.homedir(), ".hometrans");
18
+ }
19
+ function getConfigPath() {
20
+ return path.join(getConfigDir(), "config.json");
21
+ }
22
+ function readConfigEnvFieldSync(key) {
23
+ try {
24
+ const raw = readFileSync(getConfigPath(), "utf-8");
25
+ const parsed = JSON.parse(raw);
26
+ const v = parsed?.env?.[key];
27
+ return typeof v === "string" ? v : "";
28
+ } catch {
29
+ return "";
30
+ }
31
+ }
15
32
  function expandHome(p) {
16
33
  if (!p) return p;
17
34
  if (p === "~") return os.homedir();
@@ -594,10 +611,10 @@ async function extractCommitContext(input) {
594
611
  const { projectPath, commitId } = input;
595
612
  const mode = input.mode ?? "default";
596
613
  const ohosSdkPath = expandHome(
597
- input.ohosSdkPath ?? process.env.OHOS_SDK_PATH ?? ""
614
+ input.ohosSdkPath || process.env.OHOS_SDK_PATH || readConfigEnvFieldSync("OHOS_SDK_PATH")
598
615
  );
599
616
  const hmsSdkPath = expandHome(
600
- input.hmsSdkPath ?? process.env.HMS_SDK_PATH ?? ""
617
+ input.hmsSdkPath || process.env.HMS_SDK_PATH || readConfigEnvFieldSync("HMS_SDK_PATH")
601
618
  );
602
619
  if (!projectPath) {
603
620
  throw new Error("extractCommitContext: projectPath is required");
@@ -27,6 +27,7 @@
27
27
 
28
28
  "tools": {
29
29
  "deveco": {
30
+ "label": "harmony sdk",
30
31
  "source": "env-dir",
31
32
  "envVar": "DEVECO_SDK_HOME",
32
33
  "hint": "set DEVECO_SDK_HOME via `ht init` (DevEco Studio install)"
@@ -46,20 +47,12 @@
46
47
  "fallback": { "base": "DEVECO_SDK_HOME", "segments": ["default", "openharmony", "toolchains"], "exe": "hdc" },
47
48
  "hint": "ships with DevEco: <sdk>/default/openharmony/toolchains"
48
49
  },
49
- "python": {
50
- "source": "path",
51
- "aliases": ["python", "python3", "py"],
52
- "verify": ["--version"],
53
- "versionRegex": "(\\d+\\.\\d+(?:\\.\\d+)?)",
54
- "version": { "min": "3.10.0", "max": null },
55
- "hint": "install Python >= 3.10 and add to PATH (UI-align capture/parse scripts)"
56
- },
57
50
  "uv": {
58
51
  "source": "path",
59
52
  "aliases": ["uv"],
60
53
  "verify": ["--version"],
61
54
  "versionRegex": "(\\d+\\.\\d+(?:\\.\\d+)?)",
62
- "hint": "https://docs.astral.sh/uv (AutoTest runs under uv)"
55
+ "hint": "https://docs.astral.sh/uv — runs every Python script (AutoTest, UI-align, logic) via `uv run` and provides Python ≥ 3.10 on demand (no standalone Python needed)"
63
56
  },
64
57
  "java": {
65
58
  "source": "path",
@@ -70,12 +63,12 @@
70
63
  "fallback": { "base": "DEVECO_HOME", "segments": ["jbr", "bin"], "exe": "java" },
71
64
  "hint": "any JDK 17+, or reuse DevEco jbr: <deveco>/jbr/bin"
72
65
  },
73
- "gitnexus": {
66
+ "homegraph": {
74
67
  "source": "path",
75
- "aliases": ["gitnexus"],
68
+ "aliases": ["homegraph"],
76
69
  "verify": ["--version"],
77
70
  "versionRegex": "(\\d+\\.\\d+(?:\\.\\d+)?)",
78
- "hint": "npm i -g gitnexus && gitnexus setup"
71
+ "hint": "npm install -g homegraph arkanalyzer (code-graph backend for spec generation)"
79
72
  }
80
73
  },
81
74
 
@@ -83,7 +76,7 @@
83
76
  {
84
77
  "name": "hmos-spec-generate",
85
78
  "kind": "skill",
86
- "dependencies": [{ "tool": "gitnexus", "level": "required" }]
79
+ "dependencies": [{ "tool": "homegraph", "level": "required" }]
87
80
  },
88
81
  {
89
82
  "name": "hmos-resources-convert",
@@ -95,20 +88,21 @@
95
88
  "name": "hmos-batch-ui-align",
96
89
  "kind": "skill",
97
90
  "dependencies": [
98
- { "tool": "python", "level": "required", "version": { "min": "3.10.0", "max": null } },
91
+ { "tool": "uv", "level": "required" },
99
92
  { "tool": "adb", "level": "optional" }
100
93
  ],
101
- "note": "adb only for page exploration"
94
+ "note": "android_parse_fast.py runs via `uv run` (uv provides Python); adb only for page exploration"
102
95
  },
103
96
  {
104
97
  "name": "hmos-incremental-ui-align",
105
98
  "kind": "skill",
106
99
  "dependencies": [
107
100
  { "tool": "deveco", "level": "required" },
108
- { "tool": "python", "level": "required", "version": { "min": "3.10.0", "max": null } },
101
+ { "tool": "uv", "level": "required" },
109
102
  { "tool": "hdc", "level": "required" },
110
103
  { "tool": "adb", "level": "required" }
111
- ]
104
+ ],
105
+ "note": "app_feature_verify.py / page_capture.py run via `uv run` (PEP 723 inline deps; uv provides Python)"
112
106
  },
113
107
  {
114
108
  "name": "hmos-integration-test",
@@ -117,7 +111,8 @@
117
111
  { "tool": "deveco", "level": "required" },
118
112
  { "tool": "uv", "level": "required" },
119
113
  { "tool": "hdc", "level": "required" }
120
- ]
114
+ ],
115
+ "note": "self_test_runner.py runs via `uv run --no-project python` (uv provides Python) and then `uv sync`s the AutoTest venv"
121
116
  },
122
117
  {
123
118
  "name": "hmos-fix-build-errors",
@@ -132,22 +127,22 @@
132
127
  { "tool": "uv", "level": "optional" },
133
128
  { "tool": "hdc", "level": "optional" }
134
129
  ],
135
- "note": "test stage skippable via skip_test"
130
+ "note": "test stage skippable via skip_test; when run it needs uv + hdc"
136
131
  },
137
132
  {
138
133
  "name": "logic-context-builder",
139
134
  "kind": "agent",
140
- "dependencies": [{ "tool": "python", "level": "optional" }]
135
+ "dependencies": [{ "tool": "uv", "level": "optional" }]
141
136
  },
142
137
  {
143
138
  "name": "logic-coder",
144
139
  "kind": "agent",
145
- "dependencies": [{ "tool": "python", "level": "optional" }]
140
+ "dependencies": [{ "tool": "uv", "level": "optional" }]
146
141
  },
147
142
  {
148
143
  "name": "spec-generator",
149
144
  "kind": "agent",
150
- "dependencies": [{ "tool": "gitnexus", "level": "required" }]
145
+ "dependencies": [{ "tool": "homegraph", "level": "required" }]
151
146
  },
152
147
  {
153
148
  "name": "build-fixer",
@@ -170,7 +165,8 @@
170
165
  "dependencies": [
171
166
  { "tool": "uv", "level": "required" },
172
167
  { "tool": "hdc", "level": "required" }
173
- ]
168
+ ],
169
+ "note": "invokes `uv run --no-project python self_test_runner.py run/status/kill` (uv provides Python; --no-project keeps the interpreter out of the .venv it rebuilds)"
174
170
  },
175
171
  {
176
172
  "name": "self-test-fixer",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buaa_smat/hometrans",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "HomeTrans (Android-to-HarmonyOS) skill + agent installer. Run `ht init` to distribute conversion skills and subagents into AI editors.",
5
5
  "license": "MIT",
6
6
  "repository": {
Binary file
Binary file
Binary file
Binary file
@@ -9,13 +9,13 @@ Batch-convert a set of Android page snapshots (each snapshot is a `page_NNNN_Act
9
9
 
10
10
  ## Step 0 — Environment Variables Check (run first)
11
11
 
12
- The final build (Step 6, via `hmos_fix_build_errors`) reads the DevEco location **directly from the OS environment variables** (`echo "$VAR"` on macOS/Linux; `$env:VAR` in PowerShell on Windows):
12
+ The final build (Step 6, via `hmos_fix_build_errors`) resolves the DevEco location along the standard chain — **OS environment variable first, then `~/.hometrans/config.json`, then ask the user** (read env vars with `echo "$VAR"` on macOS/Linux; `$env:VAR` in PowerShell on Windows):
13
13
 
14
- | Variable | Needed for | Valid when |
15
- |---|---|---|
16
- | `DEVECO_HOME` *(or `DEVECO_SDK_HOME`)* | Step 6 unified build | resolves to a valid DevEco install |
14
+ | Variable | config.json fallback | Needed for | Valid when |
15
+ |---|---|---|---|
16
+ | `DEVECO_HOME` *(or `DEVECO_SDK_HOME`)* | `env.DEVECO_HOME` / `env.DEVECO_SDK_HOME` | Step 6 unified build | resolves to a valid DevEco install |
17
17
 
18
- If neither `DEVECO_HOME` nor `DEVECO_SDK_HOME` is set, **ask the user** for the DevEco Studio install path before proceeding (suggest running `ht init` to persist it as a machine environment variable).
18
+ If neither the env var nor `~/.hometrans/config.json` yields a valid DevEco install, **ask the user** for the DevEco Studio install path before proceeding (suggest running `ht init` to persist it as a machine environment variable).
19
19
 
20
20
  ## Step 1 — Parse User Request
21
21
 
@@ -27,6 +27,7 @@ Extract 4 paths from the user's message (natural language, no fixed format):
27
27
  | `harmony_project_dir` | HarmonyOS target project root | "target Harmony project", "鸿蒙项目", "output project" |
28
28
  | `ui_info_root` | **Parent directory containing all `page_NNNN_*` subdirectories** | "page screenshots and view tree", "page snapshots", "page folder" |
29
29
  | `pages` (optional) | User-explicitly listed page subset | When user lists `1. .../page_0001_X` ... take these |
30
+ | `apk_path` (optional) | Full path of the Android APK corresponding to `android_project_dir`. Passed through to `hmos-resources-convert` in Step 2 to skip the Gradle build and decompile this APK directly with apktool to extract resources | "APK path", "apk文件", "安卓apk" |
30
31
 
31
32
  **`references_dir` and MVVM document directories always use skill-bundled relative paths** — **do not** accept user-provided overrides:
32
33
 
@@ -41,6 +42,7 @@ Invoke the `hmos-resources-convert` skill with the following parameters:
41
42
  1. **Android project path** = `android_project_dir`
42
43
  2. **HarmonyOS project output path** = `harmony_project_dir`
43
44
  3. **resource_mapping_path** = generate the resource mapping document under `harmony_project_dir` at `${harmony_project_dir}/resource_mapping.md`
45
+ 4. **Android apk path** = `apk_path` — **only if the user provided it**. When passed through, `hmos-resources-convert` skips the Gradle build and decompiles this APK directly with apktool to extract resources. Omit this parameter entirely when `apk_path` was not provided.
44
46
 
45
47
  This skill batch-converts Android resources (strings, colors, drawables, images, etc.) to HarmonyOS resource format and generates the mapping document.
46
48
 
@@ -50,7 +52,7 @@ This skill batch-converts Android resources (strings, colors, drawables, images,
50
52
  2. Otherwise, determine the target App package name (`package`). If the user didn't provide it, extract the `package` attribute from `AndroidManifest.xml` in `android_project_dir`; if still unavailable, ask the user.
51
53
  3. Execute with Bash:
52
54
  ```
53
- python ./scripts/android_parse_fast.py --package <package_name> --output <ui_info_root_absolute_path>
55
+ uv run --no-project python ./scripts/android_parse_fast.py --package <package_name> --output <ui_info_root_absolute_path>
54
56
  ```
55
57
  This script connects to the Android emulator via ADB, BFS-traverses all reachable pages in the App, and for each page saves `screenshot.png`, `view.xml`, `meta.json` into `page_NNNN_ActivityName/` subdirectories. It also generates `index.json` and `report.html` under `ui_info_root`.
56
58
  4. After execution, confirm that `index.json` has been generated under `ui_info_root`. If not, report an error and abort.
@@ -47,15 +47,15 @@ Define shorthand variables for the instructions below:
47
47
 
48
48
  ## Environment Variables Check (run before Stage 1)
49
49
 
50
- The pipeline's sub-agents read their settings **directly from the OS environment variables**. Verify upfront so the long pipeline fails fast (read each from the OS environment: `echo "$VAR"` on macOS/Linux; `$env:VAR` in PowerShell on Windows):
50
+ The pipeline's sub-agents resolve each setting along the standard chain — **OS environment variable first, then `~/.hometrans/config.json`, then ask the user**. Verify upfront so the long pipeline fails fast (read env vars with `echo "$VAR"` on macOS/Linux; `$env:VAR` in PowerShell on Windows):
51
51
 
52
- | Variable | Needed for | Valid when |
53
- |---|---|---|
54
- | `DEVECO_HOME` *(or `DEVECO_SDK_HOME`)* | Stage 2 build + Stage 3a/4b rebuilds | resolves to a valid DevEco install |
55
- | `TEST_API_KEY` | Stage 4 self-test (only when `SKIP_TEST=false`) | non-empty |
56
- | `HOMETRANS_TOOL_PATH` | Stage 4 self-test AutoTest dir; defaults to `~/.hometrans/tools` | path exists on disk |
52
+ | Variable | config.json fallback | Needed for | Valid when |
53
+ |---|---|---|---|
54
+ | `DEVECO_HOME` *(or `DEVECO_SDK_HOME`)* | `env.DEVECO_HOME` / `env.DEVECO_SDK_HOME` | Stage 2 build + Stage 3a/4b rebuilds | resolves to a valid DevEco install |
55
+ | `HOMETRANS_MODEL_API_KEY` *(legacy `TEST_API_KEY` still honored as a fallback)* | `autotest.unified_model.api_key` | Stage 4 self-test (only when `SKIP_TEST=false`) | non-empty / not the placeholder |
56
+ | `HOMETRANS_TOOL_PATH` | `env.HOMETRANS_TOOL_PATH` (defaults to `~/.hometrans/tools`) | Stage 4 self-test AutoTest dir | path exists on disk |
57
57
 
58
- If `DEVECO_HOME`/`DEVECO_SDK_HOME` is missing, **ask the user** for the DevEco Studio install path before starting. When `SKIP_TEST=false`, also require `TEST_API_KEY` if missing, **ask the user** for it (or have them pass `skip_test=true`). Suggest running `ht init` to persist these as machine environment variables.
58
+ For each value, if the env var is unset, fall back to the listed `~/.hometrans/config.json` field. If neither yields a value: for the DevEco path / model api_key, **ask the user** (for the api_key they may instead pass `skip_test=true`). Suggest running `ht init` to persist these as machine environment variables.
59
59
 
60
60
  ---
61
61
 
@@ -21,10 +21,11 @@ Automatically build a HarmonyOS NEXT project from the command line, parse compil
21
21
 
22
22
  1. **Verify project exists** — Check that `$ARGUMENTS[0]` contains a valid HarmonyOS project (look for `build-profile.json5`, `entry/src` directory, `oh-package.json5`).
23
23
 
24
- 2. **Resolve `<deveco-path>`** — read **directly from the OS environment**; stop at the first source that yields a valid path:
24
+ 2. **Resolve `<deveco-path>`** — follow the standard config chain, stopping at the first source that yields a valid path:
25
25
  1. `$ARGUMENTS[1]` if provided (and not `--signed`).
26
- 2. Environment variables (`echo "$VAR"` on macOS/Linux; `$env:VAR` in PowerShell on Windows): `DEVECO_HOME` → parent of `DEVECO_SDK_HOME` → strip the trailing `/sdk/default/openharmony/ets` from `OHOS_SDK_PATH` (legacy).
27
- 3. **Ask the user** for the DevEco Studio install path (suggest running `ht init` to persist it as an environment variable).
26
+ 2. **OS environment variables** (`echo "$VAR"` on macOS/Linux; `$env:VAR` in PowerShell on Windows): `DEVECO_HOME` → parent of `DEVECO_SDK_HOME` → strip the trailing `/sdk/default/openharmony/ets` from `OHOS_SDK_PATH` (legacy).
27
+ 3. **`~/.hometrans/config.json`** read `env.DEVECO_HOME`, else parent of `env.DEVECO_SDK_HOME` (written by `ht init`).
28
+ 4. **Ask the user** for the DevEco Studio install path (suggest running `ht init` to persist it as an environment variable).
28
29
 
29
30
  **Verify the resolved `<deveco-path>`** contains:
30
31
  - `tools/node/node.exe`
@@ -13,7 +13,7 @@ HarmonyOS-Android UI 自动对齐流水线。
13
13
  每多一个页面/弹窗/tab,上述步骤都要重复一遍,非常费时。
14
14
 
15
15
  本 skill 做了三件事:
16
- - 用智谱 GLM 驱动的 phone-agent 自动**寻路**(根据自然语言点到指定页面)
16
+ - phone-agent 自动**寻路**(根据自然语言点到指定页面,模型复用 `~/.hometrans/config.json` 统一配置)
17
17
  - 自动**采集** view tree + 截图(安卓走 adb、鸿蒙走 hdc)
18
18
  - 自动**对比 + 改码**,并按 MVVM 模式把 mock 数据放到 Model 层
19
19
 
@@ -31,12 +31,10 @@ HarmonyOS-Android UI 自动对齐流水线。
31
31
  - 两台设备建议都保持亮屏解锁
32
32
 
33
33
  2. **Python 依赖**
34
- ```bash
35
- pip install openpyxl phone-agent
36
- ```
34
+ 无需手动安装。脚本通过 `uv run` 调用,`openpyxl` / `phone-agent` 已在 `app_feature_verify.py` 顶部的 PEP 723 内联元数据里声明,uv 首次运行时自动解析安装(走清华镜像)。只需确保已安装 `uv`(`uv --version`)。
37
35
 
38
- 3. **智谱 GLM API Key**(phone-agent 调用的模型)
39
- https://open.bigmodel.cn/ 申请,有免费额度。设为 OS 环境变量 `GLM_API_KEY`(`ht init` 可帮你写入机器环境变量)。
36
+ 3. **模型配置**(phone-agent 导航用)
37
+ 与自测共用同一个多模态模型:`ht init` 把模型四要素(api_key / name / base_url / provider)写入 `~/.hometrans/config.json` 的 `autotest.unified_model`,并导出为 `HOMETRANS_MODEL_*` 环境变量。脚本优先读环境变量,缺失时回落 config.json;都没有时兼容老版本的 `GLM_API_KEY`(走智谱 GLM 端点)。无需单独设置 API Key。
40
38
 
41
39
  4. **鸿蒙 SDK 路径**(给改码阶段查 API 用)
42
40
  取自 OS 环境变量 `OHOS_SDK_PATH` / `HMS_SDK_PATH`(为空时由 `DEVECO_SDK_HOME` 派生),由 `ht init` 写入机器环境变量;例如 DevEco Studio 自带的 `E:\DevEco Studio\sdk\default\openharmony\ets`。
@@ -55,9 +53,9 @@ HarmonyOS-Android UI 自动对齐流水线。
55
53
  | `harmony_project_dir` | 是 | 鸿蒙工程根目录(会被直接修改) |
56
54
  | `capture_output_dir` | 否 | 采集产物输出目录(截图/view tree/分析报告)。默认 `<harmony_project_dir>/.hometrans/capture_output` |
57
55
 
58
- **② OS 环境变量直接读取的全局配置**(由 `ht init` 写入机器环境变量,无需每次传):
56
+ **② 全局配置**(统一链路「环境变量 `~/.hometrans/config.json` → 询问用户」,由 `ht init` 同时写入机器环境变量与 config.json,无需每次传):
59
57
 
60
- - GLM key 环境变量 `GLM_API_KEY`
58
+ - 模型配置`HOMETRANS_MODEL_*` 环境变量(缺失时回落 `~/.hometrans/config.json``autotest.unified_model`;与自测共用同一个模型)
61
59
  - 鸿蒙 SDK ETS API 目录 ← 环境变量 `OHOS_SDK_PATH` / `HMS_SDK_PATH`(为空时由 `DEVECO_SDK_HOME` 派生为 `<DEVECO_SDK_HOME>/default/openharmony/ets`、`.../hms/ets`)
62
60
 
63
61
  > **Step 0.0** 会在执行前检查这些环境变量是否存在;缺失时会要求用户输入。
@@ -120,7 +118,7 @@ HarmonyOS-Android UI 自动对齐流水线。
120
118
  skill 会严格按 `SKILL.md` 里的 5 步流水线跑:
121
119
 
122
120
  ### Step 0 · 解析入参
123
- 读取调用入参 `android_project_dir` / `harmony_project_dir` / `capture_output_dir`,并从 OS 环境变量直接读取 `GLM_API_KEY` `OHOS_SDK_PATH` / `HMS_SDK_PATH`(**Step 0.0** 会先做存在性检查,缺失则要求用户输入)。随后 **Step 0.1** 按两个工程目录自动解析两端的 App 显示名与包名(无需手动配置)。
121
+ 读取调用入参 `android_project_dir` / `harmony_project_dir` / `capture_output_dir`,并按统一链路「环境变量 config.json → 询问」解析 `HOMETRANS_MODEL_*`(统一模型,回落 `~/.hometrans/config.json` `autotest.unified_model`)与 `OHOS_SDK_PATH` / `HMS_SDK_PATH`(回落 config.json 的 `env.*`;**Step 0.0** 会先做存在性检查,两层都缺失才要求用户输入)。随后 **Step 0.1** 按两个工程目录自动解析两端的 App 显示名与包名(无需手动配置)。
124
122
 
125
123
  ### Step 1 · 双端页面采集
126
124
  1.1 解析你的需求,拆成一组「基础页」,每个基础页有 `android_nav_path` 和 `hmos_nav_path`
@@ -193,16 +191,15 @@ Agents/hmos-ui-align/
193
191
  ```powershell
194
192
  # 安卓寻路
195
193
  $env:PYTHONIOENCODING="utf-8"
196
- python Agents/hmos-ui-align/scripts/app_feature_verify.py `
194
+ uv run Agents/hmos-ui-align/scripts/app_feature_verify.py `
197
195
  --device adb `
198
196
  --app "Salt Player" `
199
197
  --package "com.salt.music" `
200
198
  --prompt "进入首页-点击AI智能填报-点击专业筛选按钮" `
201
- --api-key "$env:GLM_API_KEY" `
202
199
  --max-steps 15
203
200
 
204
201
  # 安卓采集
205
- python Agents/hmos-ui-align/scripts/page_capture.py --device adb -o ./tmp/android_page_1_xxx
202
+ uv run Agents/hmos-ui-align/scripts/page_capture.py --device adb -o ./tmp/android_page_1_xxx
206
203
 
207
204
  # 鸿蒙同理,把 --device adb 换成 --device hdc
208
205
  ```
@@ -18,7 +18,7 @@ You are writing ArkTS codes.
18
18
 
19
19
  ## Step 0: Resolve Inputs
20
20
 
21
- This skill takes three path inputs from the invocation and reads its other settings **directly from the OS environment variables**.
21
+ This skill takes three path inputs from the invocation and resolves its other settings along the standard chain — **OS environment variable → `~/.hometrans/config.json` → ask the user** (see Step 0.0).
22
22
 
23
23
  ### Skill input arguments (provided by the user when invoking the skill)
24
24
 
@@ -32,17 +32,17 @@ The user may pass them as named args (e.g. `android_project_dir: D:\path\to\andr
32
32
 
33
33
  ### Step 0.0: Environment Variables Check (run first)
34
34
 
35
- Read each variable below **directly from the OS environment** (`echo "$VAR"` on macOS/Linux; `$env:VAR` in PowerShell / `echo %VAR%` in cmd on Windows).
35
+ Resolve each value along the standard chain — **OS environment variable first, then `~/.hometrans/config.json`, then ask the user** (read env vars with `echo "$VAR"` on macOS/Linux; `$env:VAR` in PowerShell / `echo %VAR%` in cmd on Windows).
36
36
 
37
- | Variable | Purpose | Valid when |
38
- |---|---|---|
39
- | `GLM_API_KEY` | Zhipu GLM key for the phone-agent (Step 1 navigation) | non-empty |
40
- | `OHOS_SDK_PATH` | HarmonyOS SDK ETS API reference (Step 3) | path exists on disk |
41
- | `HMS_SDK_PATH` | HMS SDK ETS API reference (Step 3) | path exists on disk |
37
+ | Variable | config.json fallback | Purpose | Valid when |
38
+ |---|---|---|---|
39
+ | `HOMETRANS_MODEL_*` (`HOMETRANS_MODEL_API_KEY` / `HOMETRANS_MODEL_NAME` / `HOMETRANS_MODEL_BASE_URL`) | `autotest.unified_model.{api_key,name,base_url}`(provider 默认 openai,不导出环境变量;再兜底老版本 `GLM_API_KEY` → 智谱 GLM 端点) | 统一多模态模型(UI 对齐 + 自测共用),由 `ht init` 导出 | `HOMETRANS_MODEL_API_KEY` 非空(或 config.json 已配置,或老版本 `GLM_API_KEY` 已设置) |
40
+ | `OHOS_SDK_PATH` | `env.OHOS_SDK_PATH` | HarmonyOS SDK ETS API reference (Step 3) | path exists on disk |
41
+ | `HMS_SDK_PATH` | `env.HMS_SDK_PATH` | HMS SDK ETS API reference (Step 3) | path exists on disk |
42
42
 
43
- For `OHOS_SDK_PATH` / `HMS_SDK_PATH`, if unset but `DEVECO_SDK_HOME` is set, derive them as `<DEVECO_SDK_HOME>/default/openharmony/ets` and `<DEVECO_SDK_HOME>/default/hms/ets`.
43
+ The model config is resolved automatically by `scripts/app_feature_verify.py` (env → config.json), so you don't read it by hand — just confirm `HOMETRANS_MODEL_API_KEY` or `autotest.unified_model.api_key` is set. For `OHOS_SDK_PATH` / `HMS_SDK_PATH`, if both the env var and `~/.hometrans/config.json` are empty but `DEVECO_SDK_HOME` is set (env or `env.DEVECO_SDK_HOME` in config.json), derive them as `<DEVECO_SDK_HOME>/default/openharmony/ets` and `<DEVECO_SDK_HOME>/default/hms/ets`.
44
44
 
45
- For each variable that is still missing/empty (or a path that does not exist), **stop and ask the user to provide a value**, then use what they give for this run. Suggest running `ht init` to persist them as machine environment variables for next time.
45
+ For each value that is still missing/empty (or a path that does not exist) after both the env var and `~/.hometrans/config.json`, **stop and ask the user to provide a value**, then use what they give for this run. Suggest running `ht init` to persist them as machine environment variables for next time.
46
46
 
47
47
  ### Step 0.1: Auto-derive App Names & Package Names
48
48