@buaa_smat/hometrans 0.1.9 → 0.1.11

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.
@@ -17,7 +17,7 @@ import chalk from 'chalk';
17
17
  import inquirer from 'inquirer';
18
18
  import { modify, applyEdits } from 'jsonc-parser';
19
19
  import { expandHome, loadHomeTransConfig, } from './config-store.js';
20
- import { dirExists, prettyHome } from './init.js';
20
+ import { dirExists, isPromptAbort, prettyHome } from './init.js';
21
21
  const execFileAsync = promisify(execFile);
22
22
  const __filename = fileURLToPath(import.meta.url);
23
23
  const __dirname = path.dirname(__filename);
@@ -291,14 +291,25 @@ export async function uninstallCommand() {
291
291
  if (plan.deletions.length === 0 && plan.modifications.length === 0) {
292
292
  return;
293
293
  }
294
- const { proceed } = await inquirer.prompt([
295
- {
296
- type: 'confirm',
297
- name: 'proceed',
298
- message: 'Continue?',
299
- default: false,
300
- },
301
- ]);
294
+ let proceed;
295
+ try {
296
+ ({ proceed } = await inquirer.prompt([
297
+ {
298
+ type: 'confirm',
299
+ name: 'proceed',
300
+ message: 'Continue?',
301
+ default: false,
302
+ },
303
+ ]));
304
+ }
305
+ catch (err) {
306
+ // Ctrl-C / Esc at the confirm prompt — cancel cleanly, no stack trace.
307
+ if (isPromptAbort(err)) {
308
+ console.log(chalk.yellow('\n Uninstall cancelled. No files modified.\n'));
309
+ process.exit(130);
310
+ }
311
+ throw err;
312
+ }
302
313
  if (!proceed) {
303
314
  console.log(chalk.yellow('\n Uninstall cancelled. No files modified.\n'));
304
315
  return;
@@ -13,6 +13,29 @@ import {
13
13
  import fs from "node:fs/promises";
14
14
  import path from "node:path";
15
15
  import os from "node:os";
16
+ function deriveSdkPaths(devecoSdkHome) {
17
+ const home = devecoSdkHome.trim().replace(/[\\/]+$/, "");
18
+ if (!home) {
19
+ return { DEVECO_SDK_HOME: "", DEVECO_PATH: "", OHOS_SDK_PATH: "", HMS_SDK_PATH: "" };
20
+ }
21
+ return {
22
+ DEVECO_SDK_HOME: home,
23
+ DEVECO_PATH: path.dirname(home),
24
+ OHOS_SDK_PATH: path.join(home, "default", "openharmony", "ets"),
25
+ HMS_SDK_PATH: path.join(home, "default", "hms", "ets")
26
+ };
27
+ }
28
+ function sdkHomeFromLegacyPaths(env) {
29
+ const tryStrip = (p, suffix) => {
30
+ if (!p) return "";
31
+ const norm = p.replace(/[\\/]+$/, "").split(/[\\/]/);
32
+ if (norm.length <= suffix.length) return "";
33
+ const tail = norm.slice(-suffix.length).map((s) => s.toLowerCase());
34
+ if (tail.join("/") !== suffix.join("/")) return "";
35
+ return norm.slice(0, -suffix.length).join(path.sep);
36
+ };
37
+ return tryStrip(env.OHOS_SDK_PATH, ["default", "openharmony", "ets"]) || tryStrip(env.HMS_SDK_PATH, ["default", "hms", "ets"]);
38
+ }
16
39
  function getConfigDir() {
17
40
  return path.join(os.homedir(), ".hometrans");
18
41
  }
@@ -73,6 +96,19 @@ function defaultEditors() {
73
96
  path: "~/.codex/config.toml",
74
97
  section: "mcp_servers.hometrans"
75
98
  }
99
+ },
100
+ {
101
+ // CodeBuddy(腾讯):与 Claude Code 同构的 .codebuddy/ 目录,
102
+ // 全局安装映射到 ~/.codebuddy/{skills,agents},MCP 走 mcpServers JSON。
103
+ name: "CodeBuddy",
104
+ markerDir: "~/.codebuddy",
105
+ skillsDir: "~/.codebuddy/skills",
106
+ agentsDir: "~/.codebuddy/agents",
107
+ mcp: {
108
+ format: "jsonc-object",
109
+ path: "~/.codebuddy/mcp.json",
110
+ keyPath: ["mcpServers", "hometrans"]
111
+ }
76
112
  }
77
113
  ];
78
114
  }
@@ -86,9 +122,12 @@ async function fileExists(p) {
86
122
  }
87
123
  function defaultEnv() {
88
124
  return {
125
+ DEVECO_SDK_HOME: "",
126
+ DEVECO_PATH: "",
89
127
  OHOS_SDK_PATH: "",
90
128
  HMS_SDK_PATH: "",
91
129
  TEST_API_KEY: "",
130
+ GLM_API_KEY: "",
92
131
  TOOL_PATH: ""
93
132
  };
94
133
  }
@@ -132,8 +171,41 @@ async function loadHomeTransConfig() {
132
171
  delete anyParsed.sdkPaths;
133
172
  delete anyParsed.params;
134
173
  delete anyParsed.tool_path;
174
+ let envDirty = false;
175
+ if (!config.env.DEVECO_SDK_HOME) {
176
+ const migrated = sdkHomeFromLegacyPaths(config.env);
177
+ if (migrated) {
178
+ config.env.DEVECO_SDK_HOME = migrated;
179
+ envDirty = true;
180
+ }
181
+ }
182
+ if (config.env.DEVECO_SDK_HOME) {
183
+ const derived = deriveSdkPaths(config.env.DEVECO_SDK_HOME);
184
+ for (const key of ["DEVECO_PATH", "OHOS_SDK_PATH", "HMS_SDK_PATH"]) {
185
+ if (!config.env[key]) {
186
+ config.env[key] = derived[key];
187
+ envDirty = true;
188
+ }
189
+ }
190
+ }
191
+ if (envDirty) {
192
+ await saveHomeTransConfig(config);
193
+ }
194
+ const existingNames = new Set(config.editors.map((e) => e.name));
195
+ const missingEditors = defaultEditors().filter(
196
+ (e) => !existingNames.has(e.name)
197
+ );
198
+ if (missingEditors.length > 0) {
199
+ config.editors.push(...missingEditors);
200
+ await saveHomeTransConfig(config);
201
+ }
135
202
  return config;
136
203
  }
204
+ async function saveHomeTransConfig(config) {
205
+ const configPath = getConfigPath();
206
+ await fs.mkdir(getConfigDir(), { recursive: true });
207
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
208
+ }
137
209
 
138
210
  // src/context/analysis/ArkTsGitInfoAnalysis.ts
139
211
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buaa_smat/hometrans",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
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
@@ -17,12 +17,17 @@ Parse `$ARGUMENTS` as positional tokens:
17
17
 
18
18
  - **Arg 1** (`android-project-path`): Path to the Android source project (required)
19
19
  - **Arg 2** (`harmonyos-project-path`): Path to the target HarmonyOS project directory (required)
20
- - **Arg 3** (`assets-output-path`): Directory to store all output/report files (required)
21
- - **Arg 4** (`max-rounds-review`): Maximum number of Stage 3→3a→3b code-review-fix rounds to run (optional, default `2`). Must be a positive integer `>= 1`.
22
- - **Arg 5** (`max-rounds-test`): Maximum number of Stage 4→4a→4b self-test rounds to run (optional, default `2`). Must be a positive integer `>= 1`.
23
- - **Arg 6** (`skip-test`): `true` or `false` (optional, default `false`). When `true`, skip Stage 4 / 4a / 4b (Self-Testing Loop) entirely. Use this when no real HarmonyOS device is available for on-device testing. To pass this arg, provide explicit values for Args 4 and 5 first.
20
+ - **Arg 3** (`spec-file-path`): Path to the requirement spec document (required). This is the plan/spec that drives Stage 1 logic development and Stage 3 code review — both stages read it directly from this path.
21
+ - **Arg 4** (`assets-output-path`): Directory to store all output/report files (optional). When omitted, default to `<harmonyos-project-path>/.hometrans_output` create the directory if it does not exist.
22
+ - **Arg 5** (`test-case-path`): Path to the self-test case file driving the Stage 4 self-testing loop (optional). When omitted, default to `OUTPUT/test_case.md`. If the resolved file does not exist, the Stage 4 loop is skipped (see Loop Setup).
23
+ - **Arg 6** (`pre-test-case-path`): Path to the pre-test case file (optional). When omitted, default to `OUTPUT/pre_test_case.md`. Only passed to the self-tester when the resolved file exists.
24
+ - **Arg 7** (`max-rounds-review`): Maximum number of Stage 3→3a→3b code-review-fix rounds to run (optional, default `2`). Must be a positive integer `>= 1`.
25
+ - **Arg 8** (`max-rounds-test`): Maximum number of Stage 4→4a→4b self-test rounds to run (optional, default `2`). Must be a positive integer `>= 1`.
26
+ - **Arg 9** (`skip-test`): `true` or `false` (optional, default `false`). When `true`, skip Stage 4 / 4a / 4b (Self-Testing Loop) entirely. Use this when no real HarmonyOS device is available for on-device testing.
24
27
 
25
- If any required argument is missing, ask the user before proceeding. If `max-rounds-review` or `max-rounds-test` is provided but is not a positive integer, ask the user before proceeding. If `skip-test` is provided but is not `true` or `false`, ask the user before proceeding.
28
+ Args are positional: to pass any optional arg, provide explicit values for all optional args before it (e.g., passing `test-case-path` requires an explicit `assets-output-path`; passing `skip-test` requires explicit Args 4–8).
29
+
30
+ If any required argument is missing, ask the user before proceeding. If `spec-file-path` does not exist or is not a readable file, ask the user before proceeding. If `max-rounds-review` or `max-rounds-test` is provided but is not a positive integer, ask the user before proceeding. If `skip-test` is provided but is not `true` or `false`, ask the user before proceeding.
26
31
 
27
32
  Define shorthand variables for the instructions below:
28
33
 
@@ -30,7 +35,10 @@ Define shorthand variables for the instructions below:
30
35
  |----------|---------|
31
36
  | `ANDROID` | android-project-path |
32
37
  | `HMOS` | harmonyos-project-path |
33
- | `OUTPUT` | assets-output-path (resolved or generated) |
38
+ | `SPEC` | spec-file-path — requirement spec document, consumed directly by Stage 1 (`spec-file`) and Stage 3 (`test-case-path`) |
39
+ | `OUTPUT` | assets-output-path; defaults to `HMOS/.hometrans_output` when not provided (created on demand) |
40
+ | `TEST_CASE` | test-case-path; defaults to `OUTPUT/test_case.md` when not provided |
41
+ | `PRE_TEST_CASE` | pre-test-case-path; defaults to `OUTPUT/pre_test_case.md` when not provided |
34
42
  | `MAX_ROUNDS_REVIEW` | max-rounds-review — positive integer (default `2`). Controls Stage 3→3a→3b code-review-fix loop. |
35
43
  | `MAX_ROUNDS_TEST` | max-rounds-test — positive integer (default `2`). Controls Stage 4→4a→4b self-test loop. |
36
44
  | `SKIP_TEST` | skip-test — `true` or `false` (default `false`). When `true`, skip Stage 4 / 4a / 4b entirely (no real device available). |
@@ -147,7 +155,7 @@ Prompt format (applies to both Stage 1 and Stage 1a): ONLY the key-value lines b
147
155
  ```
148
156
  Agent(
149
157
  subagent_type="logic-context-builder",
150
- prompt="harmonyos-project-path: HMOS\nspec-file: OUTPUT/plan.md\noutput-path: OUTPUT/logic"
158
+ prompt="harmonyos-project-path: HMOS\nspec-file: SPEC\noutput-path: OUTPUT/logic"
151
159
  )
152
160
  ```
153
161
  2. Verify `OUTPUT/logic/plan.md` exists.
@@ -200,7 +208,7 @@ For each `review_round` from `1..MAX_ROUNDS_REVIEW`, set `REVIEW_ROUND_DIR = OUT
200
208
  - `harmonyos-project-path`: `HMOS`
201
209
  - `commit-id`: For Round 1, use `REVIEW_COMMIT_ID`. For Round 2+, review the project holistically (omit `commit-id` or pass `none`) since fixes have modified the codebase beyond the original commit scope.
202
210
  - `output-path`: `REVIEW_ROUND_DIR`
203
- - `test-case-path`: `OUTPUT/plan.md`
211
+ - `test-case-path`: `SPEC`
204
212
  3. If a valid `commit-id` is available, the agent will automatically call the `extract_commit_context` MCP tool to extract commit-scoped code context before reviewing. If the MCP call fails, the agent falls back to direct git-diff analysis. If no `commit-id` is available, the agent reviews the project holistically without commit-scoped extraction.
205
213
  4. The agent writes `REVIEW_ROUND_DIR/code-review-report.md` with per-scenario verdicts.
206
214
  5. **Extract defect stats**: Read `REVIEW_ROUND_DIR/code-review-report.md`, extract the verdict breakdown (PASS/PARTIAL/FAIL/UNABLE TO VERIFY counts) and overall verdict.
@@ -277,7 +285,7 @@ Treat Stage 4 → 4a → 4b as a loop that runs up to `MAX_ROUNDS_TEST` times.
277
285
 
278
286
  1. **Locate the initial HAP file**: Use the `.hap` mirrored to `OUTPUT/` by the Stage 3 review loop finalization (or from Stage 2 if the review loop did not produce one). The default location is `OUTPUT/entry-default-signed.hap`. If that file does not exist, search for `*-signed.hap` files in `OUTPUT/` and use the first match. If no `.hap` is found in `OUTPUT/`, fall back to searching `HMOS/entry/build/default/outputs/default/`.
279
287
  2. Store the resolved path as `CURRENT_HAP`.
280
- 3. **`OUTPUT/test_case.md` existence guard**: If `OUTPUT/test_case.md` does not exist, mark Stage 4 / 4a / 4b as failed with note "No test case file available" and skip the loop entirely.
288
+ 3. **`TEST_CASE` existence guard**: If `TEST_CASE` does not exist, mark Stage 4 / 4a / 4b as failed with note "No test case file available" and skip the loop entirely.
281
289
  4. Initialize loop state:
282
290
  - `round = 1`
283
291
  - `rounds_executed = 0`
@@ -297,8 +305,8 @@ For each `round` from `1..MAX_ROUNDS_TEST`, set `ROUND_DIR = OUTPUT/round-{round
297
305
  3. Input (round 1):
298
306
  - `hap-path`: `CURRENT_HAP`
299
307
  - `output-path`: `OUTPUT` (the ROOT — the agent always writes here)
300
- - `test-case-path`: `OUTPUT/test_case.md`
301
- - `pre-test-case-path`: `OUTPUT/pre_test_case.md` (only include this line when the file exists)
308
+ - `test-case-path`: `TEST_CASE`
309
+ - `pre-test-case-path`: `PRE_TEST_CASE` (only include this line when the file exists)
302
310
  - `setup`: `true`
303
311
  4. Input (round 2+):
304
312
  - `hap-path`: `CURRENT_HAP`
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: hmos-fix-build-errors
3
3
  description: Build a HarmonyOS project via CLI and automatically fix compile errors in a loop until the build succeeds. Default unsigned HAP; pass --signed to build a signed HAP (signing config must already exist in the project's build-profile.json5).
4
- argument-hint: <harmonyos-project-path> <deveco-studio-path> [--signed]
4
+ argument-hint: <harmonyos-project-path> [deveco-studio-path] [--signed]
5
5
  allowed-tools: Agent, Read, Write, Edit, Glob, Grep, Bash
6
6
  type: tool
7
7
  domain: engineering
@@ -12,8 +12,8 @@ domain: engineering
12
12
  Automatically build a HarmonyOS NEXT project from the command line, parse compile errors, fix them, and retry — repeating until the build succeeds.
13
13
 
14
14
  - **HarmonyOS Project**: `$ARGUMENTS[0]` (the HarmonyOS project root, e.g. `D:/MyHmosApp`)
15
- - **DevEco Studio Path**: `$ARGUMENTS[1]` (DevEco Studio installation root, e.g. `D:/DevEco Studio`)
16
- - **--signed** (optional): `$ARGUMENTS[2]` if set to `--signed`, the build produces a **signed HAP**. If omitted, the build produces an **unsigned HAP** (default).
15
+ - **DevEco Studio Path** (optional): `$ARGUMENTS[1]` (DevEco Studio installation root, e.g. `D:/DevEco Studio`) — when omitted, resolved automatically (see Step 0.2)
16
+ - **--signed** (optional): if any argument equals `--signed`, the build produces a **signed HAP**. If omitted, the build produces an **unsigned HAP** (default).
17
17
 
18
18
  ---
19
19
 
@@ -21,12 +21,20 @@ 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. **Verify DevEco installation** Check that `$ARGUMENTS[1]` contains:
24
+ 2. **Resolve `<deveco-path>`**stop at the first source that yields a valid path:
25
+ 1. `$ARGUMENTS[1]` if provided (and not `--signed`).
26
+ 2. `~/.hometrans/config.json` (on Windows `%USERPROFILE%\.hometrans\config.json`): `env.DEVECO_PATH`; else parent dir of `env.DEVECO_SDK_HOME`; else strip the trailing `/sdk/default/openharmony/ets` from `env.OHOS_SDK_PATH` (legacy).
27
+ 3. Environment variables, same precedence: `DEVECO_PATH` → parent of `DEVECO_SDK_HOME` → strip suffix from `OHOS_SDK_PATH`.
28
+ 4. **Ask the user** for the DevEco Studio install path (suggest running `ht init` to persist it).
29
+
30
+ **Verify the resolved `<deveco-path>`** contains:
25
31
  - `tools/node/node.exe`
26
32
  - `tools/hvigor/bin/hvigorw.js`
27
33
  - `tools/ohpm/bin/ohpm`
28
34
  - `sdk/` directory
29
35
 
36
+ If verification fails for a config/env-sourced path, treat that source as invalid and continue down the list; if it fails for a user-supplied path, report what is missing and ask again.
37
+
30
38
  3. **Set up `local.properties`** — Ensure the project root has `local.properties` with:
31
39
  ```properties
32
40
  hwsdk.dir=<deveco-path>/sdk
@@ -40,7 +48,7 @@ Automatically build a HarmonyOS NEXT project from the command line, parse compil
40
48
  "<deveco-path>/tools/ohpm/bin/ohpm" install
41
49
  ```
42
50
 
43
- 5. **Determine Build Mode** — Check if `$ARGUMENTS[2]` equals `--signed`:
51
+ 5. **Determine Build Mode** — Check if any argument equals `--signed` (it may be `$ARGUMENTS[1]` when the DevEco path is omitted, or `$ARGUMENTS[2]` when it is provided):
44
52
  - **If NOT `--signed`** → **Unsigned build mode**. Ensure `build-profile.json5` does NOT have `signingConfigs` or `signingConfig` references in products (remove them if present). Go to Step 1.
45
53
  - **If `--signed`** → **Signed build mode**. Proceed to Step 0.5 to validate signing config.
46
54
 
@@ -17,7 +17,13 @@ You are writing ArkTS codes.
17
17
  - 不要做和用户需求无关的其他修改
18
18
  -
19
19
  ## Step 0: Load Config
20
- The user MUST provide a `config-path` when invoking this skill (e.g., `config-path: D:\path\to\config.json`). The config file must exist before running verify with a Read, and if it's missing or unreadable, ask the user for a valid path. Refer to `config-example.json` in this skill's directory for the expected schema.
20
+ Resolve the config file in this orderstop at the first hit:
21
+
22
+ 1. **`config-path` argument** if the user provided one (e.g., `config-path: D:\path\to\config.json`).
23
+ 2. **`config.json` in this skill's own directory** — `ht init` seeds it from `config-example.json` and fills `glm_api_key` + `hmos_sdk_dir` from `~/.hometrans/config.json`.
24
+ 3. Neither exists → **ask the user** for a valid path.
25
+
26
+ Verify the resolved file with a Read; if it's missing or unreadable, fall through to the next source (or ask the user). Refer to `config-example.json` in this skill's directory for the expected schema.
21
27
 
22
28
  Config fields:
23
29
 
@@ -33,6 +39,14 @@ Config fields:
33
39
  | `glm_api_key` | Zhipu GLM API key for phone-agent |
34
40
  | `capture_output_dir` | Base directory for captured page data |
35
41
 
42
+ **Fallbacks for `hmos_sdk_dir` and `glm_api_key`** when empty or missing in the resolved config — stop at the first hit:
43
+
44
+ 1. `~/.hometrans/config.json` (on Windows `%USERPROFILE%\.hometrans\config.json`): `hmos_sdk_dir` = `<env.DEVECO_SDK_HOME>/default`; `glm_api_key` = `env.GLM_API_KEY`.
45
+ 2. Environment variables: derive `hmos_sdk_dir` from `DEVECO_SDK_HOME` (append `/default`); `glm_api_key` from `GLM_API_KEY`.
46
+ 3. **Ask the user** (suggest running `ht init` to persist them).
47
+
48
+ Validate that `hmos_sdk_dir` exists on disk before use; if it doesn't, continue down the fallback list.
49
+
36
50
  ## Step 1: Capture All Related Pages on Android & HarmonyOS Devices
37
51
 
38
52
  Read `scripts/navigation-capure.md` to learn the usage of `scripts/app_feature_verify.py` (navigation) and `scripts/page_capture.py` (capture).