@buaa_smat/hometrans 0.1.13 → 0.1.15

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 (88) hide show
  1. package/README.md +194 -136
  2. package/agents/build-fixer.md +38 -48
  3. package/agents/code-reviewer.md +20 -20
  4. package/agents/logic-coder.md +8 -8
  5. package/agents/logic-context-builder.md +5 -5
  6. package/agents/review-fixer.md +16 -16
  7. package/agents/self-test-fixer.md +15 -15
  8. package/agents/self-tester.md +56 -55
  9. package/agents/spec-generator.md +16 -16
  10. package/dist/cli/config-store.js +120 -9
  11. package/dist/cli/config.js +4 -4
  12. package/dist/cli/env-vars.js +129 -0
  13. package/dist/cli/init.js +315 -276
  14. package/dist/cli/uninstall.js +152 -17
  15. package/dist/context/index.js +10 -197
  16. package/env-requirements.json +181 -181
  17. package/package.json +1 -1
  18. package/resource/choose_editor.png +0 -0
  19. package/resource/common_config.png +0 -0
  20. package/resource/integration_test_config.png +0 -0
  21. package/resource/migration_process.svg +94 -0
  22. package/resource/migration_process_transparent.svg +93 -0
  23. package/resource/set_env.png +0 -0
  24. package/resource/ui_align_config.png +0 -0
  25. package/skills/hmos-batch-ui-align/SKILL.md +10 -0
  26. package/skills/hmos-batch-ui-align/references/conversion-procedure.md +180 -180
  27. package/skills/hmos-batch-ui-align/references/mappings/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +2533 -2533
  28. package/skills/hmos-batch-ui-align/references/mappings/android-to-harmonyOS-ui-interaction-mapping-reference.md +555 -555
  29. package/skills/hmos-batch-ui-align/references/mappings/android-to-harmonyOS-ui-layout-mapping-reference.md +117 -117
  30. package/skills/hmos-batch-ui-align/references/mvvm/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md +648 -648
  31. package/skills/hmos-batch-ui-align/references/mvvm/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md +2088 -2088
  32. package/skills/hmos-batch-ui-align/references/mvvm/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md +1033 -1033
  33. package/skills/hmos-batch-ui-align/references/mvvm/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md +1183 -1183
  34. package/skills/hmos-batch-ui-align/references/mvvm/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md +576 -576
  35. package/skills/hmos-batch-ui-align/references/mvvm/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md +297 -297
  36. package/skills/hmos-batch-ui-align/references/mvvm/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md +395 -395
  37. package/skills/hmos-batch-ui-align/references/mvvm/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md +902 -902
  38. package/skills/hmos-batch-ui-align/references/mvvm/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md +106 -106
  39. package/skills/hmos-batch-ui-align/references/mvvm/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md +1178 -1178
  40. package/skills/hmos-batch-ui-align/references/mvvm/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md +911 -911
  41. package/skills/hmos-batch-ui-align/references/mvvm/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +354 -354
  42. package/skills/hmos-batch-ui-align/references/mvvm//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md +11 -11
  43. package/skills/hmos-convert-pipeline/SKILL.md +63 -49
  44. package/skills/hmos-fix-build-errors/SKILL.md +5 -6
  45. package/skills/hmos-fix-build-errors/references/arkts-strict-patterns.md +219 -219
  46. package/skills/hmos-fix-build-errors/references/known-patterns.md +157 -157
  47. package/skills/hmos-fix-build-errors/references/rdb-entity-pattern.md +131 -131
  48. package/skills/hmos-incremental-ui-align/{readme.md → README.md} +28 -21
  49. package/skills/hmos-incremental-ui-align/SKILL.md +46 -27
  50. package/skills/hmos-incremental-ui-align/diff_analysis.md +52 -52
  51. package/skills/hmos-incremental-ui-align/page_align.md +62 -62
  52. package/skills/hmos-incremental-ui-align/references/Comparison_Template.md +2 -2
  53. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md +648 -648
  54. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md +2088 -2088
  55. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md +1033 -1033
  56. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md +1183 -1183
  57. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md +576 -576
  58. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md +297 -297
  59. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md +395 -395
  60. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md +902 -902
  61. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md +106 -106
  62. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md +1178 -1178
  63. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/MVVM/346/250/241/345/274/217V1.md +911 -911
  64. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +354 -354
  65. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md +11 -11
  66. package/skills/hmos-incremental-ui-align/references/UI_Analysis_Template.md +3 -3
  67. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +2533 -2533
  68. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-interaction-mapping-reference.md +555 -555
  69. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-layout-mapping-reference.md +117 -117
  70. package/skills/hmos-incremental-ui-align/scripts/navigation-capure.md +37 -37
  71. package/skills/hmos-integration-test/{readme.md → README.md} +38 -38
  72. package/skills/hmos-integration-test/SKILL.md +63 -52
  73. package/skills/hmos-resources-convert/SKILL.md +5 -5
  74. package/skills/hmos-resources-convert/references/conversion-rules.md +663 -663
  75. package/skills/hmos-resources-convert/references/dependency-analysis-rules.md +388 -388
  76. package/skills/hmos-resources-convert/references/resource-mapping-rules.md +457 -457
  77. package/skills/hmos-resources-convert/references/xml-drawable-to-svg-rules.md +513 -513
  78. package/skills/hmos-spec-generate/SKILL.md +19 -19
  79. package/skills/hmos-spec-generate/references/android-platform-tokens.md +105 -105
  80. package/skills/hmos-spec-generate/references/spec-sample-1.md +78 -78
  81. package/skills/hmos-spec-generate/references/spec-sample-2.md +58 -58
  82. package/skills/hmos-spec-generate/references/spec-sample-3.md +116 -116
  83. package/skills/hmos-spec-generate/references/step4-report-template.md +33 -33
  84. package/tools/test-tools/autotest/README.md +33 -17
  85. package/tools/test-tools/autotest/self_test_runner.py +109 -15
  86. package/resource/hometrans_config.png +0 -0
  87. package/skills/hmos-incremental-ui-align/config-example.json +0 -11
  88. package/tools/test-tools/autotest/config.yaml.example +0 -58
@@ -16,11 +16,16 @@ import { promisify } from 'node:util';
16
16
  import chalk from 'chalk';
17
17
  import inquirer from 'inquirer';
18
18
  import { modify, applyEdits } from 'jsonc-parser';
19
- import { expandHome, loadHomeTransConfig, } from './config-store.js';
20
- import { dirExists, isPromptAbort, prettyHome } from './init.js';
19
+ import { expandHome, getConfigDir, loadHomeTransConfig, } from './config-store.js';
20
+ import { dirExists, isPromptAbort, prettyHome, MACHINE_ENV_KEYS } from './init.js';
21
+ import { removeEnvVars } from './env-vars.js';
21
22
  const execFileAsync = promisify(execFile);
22
23
  const __filename = fileURLToPath(import.meta.url);
23
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);
28
+ }
24
29
  /* ------------------------------------------------------------------ */
25
30
  /* Bundled content discovery */
26
31
  /* ------------------------------------------------------------------ */
@@ -85,7 +90,7 @@ async function tryRemoveJsoncKey(filePath, keyPath) {
85
90
  const edits = modify(raw, keyPath, undefined, { formattingOptions });
86
91
  if (edits.length === 0)
87
92
  return null;
88
- return applyEdits(raw, edits);
93
+ return { oldContent: raw, newContent: applyEdits(raw, edits) };
89
94
  }
90
95
  async function tryRemoveTomlSection(filePath, sectionHeader) {
91
96
  let raw;
@@ -116,7 +121,7 @@ async function tryRemoveTomlSection(filePath, sectionHeader) {
116
121
  let content = result.join('\n').replace(/\n{3,}/g, '\n\n').trimEnd();
117
122
  if (content.length > 0)
118
123
  content += '\n';
119
- return content;
124
+ return { oldContent: raw, newContent: content };
120
125
  }
121
126
  /* ------------------------------------------------------------------ */
122
127
  /* Plan building */
@@ -165,13 +170,14 @@ async function buildPlanForEditor(editor, skillNames, agentEntries, plan) {
165
170
  if (!mcp.path || !mcp.keyPath)
166
171
  break;
167
172
  const configPath = expandHome(mcp.path);
168
- const newContent = await tryRemoveJsoncKey(configPath, mcp.keyPath);
169
- if (newContent !== null) {
173
+ const change = await tryRemoveJsoncKey(configPath, mcp.keyPath);
174
+ if (change !== null) {
170
175
  plan.modifications.push({
171
176
  display: `${editor.name}: ${prettyHome(configPath)}`,
172
177
  absPath: configPath,
173
178
  reason: 'Remove hometrans MCP entry',
174
- newContent,
179
+ oldContent: change.oldContent,
180
+ newContent: change.newContent,
175
181
  });
176
182
  }
177
183
  break;
@@ -180,13 +186,14 @@ async function buildPlanForEditor(editor, skillNames, agentEntries, plan) {
180
186
  plan.codexRemove = true;
181
187
  if (mcp.path && mcp.section) {
182
188
  const configPath = expandHome(mcp.path);
183
- const newContent = await tryRemoveTomlSection(configPath, mcp.section);
184
- if (newContent !== null) {
189
+ const change = await tryRemoveTomlSection(configPath, mcp.section);
190
+ if (change !== null) {
185
191
  plan.modifications.push({
186
192
  display: `${editor.name}: ${prettyHome(configPath)}`,
187
193
  absPath: configPath,
188
194
  reason: 'Remove hometrans MCP section',
189
- newContent,
195
+ oldContent: change.oldContent,
196
+ newContent: change.newContent,
190
197
  });
191
198
  }
192
199
  }
@@ -196,13 +203,14 @@ async function buildPlanForEditor(editor, skillNames, agentEntries, plan) {
196
203
  if (!mcp.path || !mcp.section)
197
204
  break;
198
205
  const configPath = expandHome(mcp.path);
199
- const newContent = await tryRemoveTomlSection(configPath, mcp.section);
200
- if (newContent !== null) {
206
+ const change = await tryRemoveTomlSection(configPath, mcp.section);
207
+ if (change !== null) {
201
208
  plan.modifications.push({
202
209
  display: `${editor.name}: ${prettyHome(configPath)}`,
203
210
  absPath: configPath,
204
211
  reason: 'Remove hometrans MCP section',
205
- newContent,
212
+ oldContent: change.oldContent,
213
+ newContent: change.newContent,
206
214
  });
207
215
  }
208
216
  break;
@@ -211,12 +219,92 @@ async function buildPlanForEditor(editor, skillNames, agentEntries, plan) {
211
219
  break;
212
220
  }
213
221
  }
222
+ /** Line-based diff via an LCS table. Files here are small config files. */
223
+ function diffLines(oldLines, newLines) {
224
+ const n = oldLines.length;
225
+ const m = newLines.length;
226
+ const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
227
+ for (let i = n - 1; i >= 0; i--) {
228
+ for (let j = m - 1; j >= 0; j--) {
229
+ dp[i][j] =
230
+ oldLines[i] === newLines[j]
231
+ ? dp[i + 1][j + 1] + 1
232
+ : Math.max(dp[i + 1][j], dp[i][j + 1]);
233
+ }
234
+ }
235
+ const out = [];
236
+ let i = 0;
237
+ let j = 0;
238
+ while (i < n && j < m) {
239
+ if (oldLines[i] === newLines[j]) {
240
+ out.push({ type: ' ', text: oldLines[i] });
241
+ i++;
242
+ j++;
243
+ }
244
+ else if (dp[i + 1][j] >= dp[i][j + 1]) {
245
+ out.push({ type: '-', text: oldLines[i] });
246
+ i++;
247
+ }
248
+ else {
249
+ out.push({ type: '+', text: newLines[j] });
250
+ j++;
251
+ }
252
+ }
253
+ while (i < n)
254
+ out.push({ type: '-', text: oldLines[i++] });
255
+ while (j < m)
256
+ out.push({ type: '+', text: newLines[j++] });
257
+ return out;
258
+ }
259
+ /**
260
+ * Render a unified, git-style diff with `context` unchanged lines around each
261
+ * change; long unchanged runs collapse to a `⋮` marker. Returns coloured,
262
+ * pre-indented lines ready to print.
263
+ */
264
+ function renderDiff(oldContent, newContent, context = 3) {
265
+ const diff = diffLines(oldContent.split('\n'), newContent.split('\n'));
266
+ const keep = new Array(diff.length).fill(false);
267
+ for (let k = 0; k < diff.length; k++) {
268
+ if (diff[k].type === ' ')
269
+ continue;
270
+ const from = Math.max(0, k - context);
271
+ const to = Math.min(diff.length - 1, k + context);
272
+ for (let c = from; c <= to; c++)
273
+ keep[c] = true;
274
+ }
275
+ const lines = [];
276
+ let gapOpen = false;
277
+ for (let k = 0; k < diff.length; k++) {
278
+ if (!keep[k]) {
279
+ if (!gapOpen) {
280
+ lines.push(chalk.gray(' ⋮'));
281
+ gapOpen = true;
282
+ }
283
+ continue;
284
+ }
285
+ gapOpen = false;
286
+ const { type, text } = diff[k];
287
+ if (type === '-')
288
+ lines.push(chalk.red(` - ${text}`));
289
+ else if (type === '+')
290
+ lines.push(chalk.green(` + ${text}`));
291
+ else
292
+ lines.push(chalk.gray(` ${text}`));
293
+ }
294
+ return lines;
295
+ }
214
296
  /* ------------------------------------------------------------------ */
215
297
  /* Render */
216
298
  /* ------------------------------------------------------------------ */
299
+ function isPlanEmpty(plan) {
300
+ return (plan.deletions.length === 0 &&
301
+ plan.modifications.length === 0 &&
302
+ plan.envVars.length === 0 &&
303
+ plan.configDir === null);
304
+ }
217
305
  function renderPlan(plan) {
218
306
  console.log(chalk.bold('\nHomeTrans uninstall plan\n'));
219
- if (plan.deletions.length === 0 && plan.modifications.length === 0) {
307
+ if (isPlanEmpty(plan)) {
220
308
  console.log(chalk.gray(' Nothing to uninstall — no hometrans files found in configured editors.\n'));
221
309
  return;
222
310
  }
@@ -231,9 +319,27 @@ function renderPlan(plan) {
231
319
  console.log(chalk.yellow.bold(` Will be modified (${plan.modifications.length} files):`));
232
320
  for (const m of plan.modifications) {
233
321
  console.log(` ${chalk.yellow('~')} ${m.display} ${chalk.gray(`(${m.reason})`)}`);
322
+ for (const line of renderDiff(m.oldContent, m.newContent)) {
323
+ console.log(line);
324
+ }
325
+ console.log('');
326
+ }
327
+ }
328
+ if (plan.envVars.length > 0) {
329
+ console.log(chalk.red.bold(` Environment variables to remove (${plan.envVars.length}):`));
330
+ console.log(chalk.gray(process.platform === 'win32'
331
+ ? ' (Windows: deleted from the per-user environment)'
332
+ : ' (macOS/Linux: the hometrans export block is removed from your shell profile)'));
333
+ for (const name of plan.envVars) {
334
+ console.log(` ${chalk.red('-')} ${name}`);
234
335
  }
235
336
  console.log('');
236
337
  }
338
+ if (plan.configDir) {
339
+ console.log(chalk.red.bold(' Config directory to delete:'));
340
+ console.log(` ${chalk.red('-')} ${prettyHome(plan.configDir)}/`);
341
+ console.log('');
342
+ }
237
343
  }
238
344
  /* ------------------------------------------------------------------ */
239
345
  /* Execute */
@@ -241,6 +347,7 @@ function renderPlan(plan) {
241
347
  async function executePlan(plan) {
242
348
  let deleted = 0;
243
349
  let modified = 0;
350
+ let envNote = null;
244
351
  for (const mod of plan.modifications) {
245
352
  await fs.writeFile(mod.absPath, mod.newContent, 'utf-8');
246
353
  modified++;
@@ -264,7 +371,20 @@ async function executePlan(plan) {
264
371
  // best-effort
265
372
  }
266
373
  }
267
- return { deleted, modified };
374
+ // Remove machine environment variables (names captured from config.json env)
375
+ // before deleting the config directory that holds config.json.
376
+ if (plan.envVars.length > 0) {
377
+ envNote = await removeEnvVars(plan.envVars);
378
+ }
379
+ if (plan.configDir) {
380
+ try {
381
+ await fs.rm(plan.configDir, { recursive: true, force: true });
382
+ }
383
+ catch {
384
+ // best-effort
385
+ }
386
+ }
387
+ return { deleted, modified, envNote };
268
388
  }
269
389
  /* ------------------------------------------------------------------ */
270
390
  /* Entry point */
@@ -278,17 +398,26 @@ export async function uninstallCommand() {
278
398
  console.log(chalk.gray(' Reinstall hometrans or manually remove skill/agent directories from your editors.\n'));
279
399
  return;
280
400
  }
281
- const { editors } = await loadHomeTransConfig();
401
+ const { editors, env } = await loadHomeTransConfig();
282
402
  const plan = {
283
403
  deletions: [],
284
404
  modifications: [],
285
405
  codexRemove: false,
406
+ envVars: [],
407
+ configDir: null,
286
408
  };
287
409
  for (const editor of editors) {
288
410
  await buildPlanForEditor(editor, skillNames, agentEntries, plan);
289
411
  }
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);
415
+ const configDir = getConfigDir();
416
+ if (await dirExists(configDir)) {
417
+ plan.configDir = configDir;
418
+ }
290
419
  renderPlan(plan);
291
- if (plan.deletions.length === 0 && plan.modifications.length === 0) {
420
+ if (isPlanEmpty(plan)) {
292
421
  return;
293
422
  }
294
423
  let proceed;
@@ -317,5 +446,11 @@ export async function uninstallCommand() {
317
446
  const summary = await executePlan(plan);
318
447
  console.log('');
319
448
  console.log(chalk.green(` Uninstalled: ${summary.deleted} entries deleted, ${summary.modified} files modified.`));
449
+ if (summary.envNote) {
450
+ console.log(chalk.green(` Environment variables: ${summary.envNote}`));
451
+ }
452
+ if (plan.configDir) {
453
+ console.log(chalk.green(` Removed config directory: ${prettyHome(plan.configDir)}/`));
454
+ }
320
455
  console.log('');
321
456
  }
@@ -10,38 +10,8 @@ import {
10
10
  } from "arkanalyzer";
11
11
 
12
12
  // src/cli/config-store.ts
13
- import fs from "node:fs/promises";
14
13
  import path from "node:path";
15
14
  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
- }
39
- function getConfigDir() {
40
- return path.join(os.homedir(), ".hometrans");
41
- }
42
- function getConfigPath() {
43
- return path.join(getConfigDir(), "config.json");
44
- }
45
15
  function expandHome(p) {
46
16
  if (!p) return p;
47
17
  if (p === "~") return os.homedir();
@@ -50,162 +20,6 @@ function expandHome(p) {
50
20
  }
51
21
  return p;
52
22
  }
53
- function defaultEditors() {
54
- return [
55
- {
56
- name: "Claude Code",
57
- markerDir: "~/.claude",
58
- skillsDir: "~/.claude/skills",
59
- agentsDir: "~/.claude/agents",
60
- mcp: {
61
- format: "jsonc-object",
62
- path: "~/.claude.json",
63
- keyPath: ["mcpServers", "hometrans"]
64
- }
65
- },
66
- {
67
- name: "Cursor",
68
- markerDir: "~/.cursor",
69
- skillsDir: "~/.cursor/skills",
70
- agentsDir: "~/.cursor/agents",
71
- mcp: {
72
- format: "jsonc-object",
73
- path: "~/.cursor/mcp.json",
74
- keyPath: ["mcpServers", "hometrans"]
75
- }
76
- },
77
- {
78
- name: "OpenCode",
79
- markerDir: "~/.config/opencode",
80
- skillsDir: "~/.config/opencode/skills",
81
- agentsDir: "~/.config/opencode/agents",
82
- mcp: {
83
- format: "jsonc-command-array",
84
- path: "~/.config/opencode/opencode.json",
85
- keyPath: ["mcp", "hometrans"]
86
- }
87
- },
88
- {
89
- name: "Codex",
90
- markerDir: "~/.codex",
91
- // Codex 复用 Agent Skills 公共目录,agent 定义独立。
92
- skillsDir: "~/.agents/skills",
93
- agentsDir: "~/.codex/agents",
94
- mcp: {
95
- format: "codex-cli",
96
- path: "~/.codex/config.toml",
97
- section: "mcp_servers.hometrans"
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
- }
112
- }
113
- ];
114
- }
115
- async function fileExists(p) {
116
- try {
117
- await fs.access(p);
118
- return true;
119
- } catch {
120
- return false;
121
- }
122
- }
123
- function defaultEnv() {
124
- return {
125
- DEVECO_SDK_HOME: "",
126
- DEVECO_PATH: "",
127
- OHOS_SDK_PATH: "",
128
- HMS_SDK_PATH: "",
129
- TEST_API_KEY: "",
130
- GLM_API_KEY: "",
131
- TOOL_PATH: ""
132
- };
133
- }
134
- async function loadHomeTransConfig() {
135
- const configPath = getConfigPath();
136
- if (!await fileExists(configPath)) {
137
- const config2 = {
138
- editors: defaultEditors(),
139
- env: defaultEnv()
140
- };
141
- await fs.mkdir(getConfigDir(), { recursive: true });
142
- await fs.writeFile(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
143
- return config2;
144
- }
145
- const raw = await fs.readFile(configPath, "utf-8");
146
- let parsed;
147
- try {
148
- parsed = JSON.parse(raw);
149
- } catch (err) {
150
- throw new Error(
151
- `Failed to parse ${configPath}: ${err.message}. Fix the JSON or delete the file to restore defaults.`
152
- );
153
- }
154
- if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.editors)) {
155
- throw new Error(
156
- `Invalid config.json shape at ${configPath}: top-level must be { "editors": [...] }.`
157
- );
158
- }
159
- const config = parsed;
160
- const anyParsed = parsed;
161
- const legacyParams = anyParsed.params ?? anyParsed.sdkPaths;
162
- const legacyToolPath = typeof anyParsed.tool_path === "string" ? anyParsed.tool_path : void 0;
163
- config.env = {
164
- ...defaultEnv(),
165
- ...legacyParams ?? {},
166
- ...config.env ?? {}
167
- };
168
- if (legacyToolPath && !config.env.TOOL_PATH) {
169
- config.env.TOOL_PATH = legacyToolPath;
170
- }
171
- delete anyParsed.sdkPaths;
172
- delete anyParsed.params;
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
- }
202
- return config;
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
- }
209
23
 
210
24
  // src/context/analysis/ArkTsGitInfoAnalysis.ts
211
25
  import {
@@ -218,12 +32,12 @@ import {
218
32
  parseJsonText
219
33
  } from "arkanalyzer";
220
34
  import path3 from "path";
221
- import fs3 from "fs";
35
+ import fs2 from "fs";
222
36
 
223
37
  // src/context/utils/util.ts
224
38
  import LoggerMod, { LOG_MODULE_TYPE } from "arkanalyzer/lib/utils/logger.js";
225
39
  import path2 from "path";
226
- import fs2 from "fs";
40
+ import fs from "fs";
227
41
  var Logger = LoggerMod.default ?? LoggerMod;
228
42
  var logger = Logger.getLogger(LOG_MODULE_TYPE.DEFAULT, "util");
229
43
  function safePush(target, source, maxBatchSize = 1e4) {
@@ -233,21 +47,21 @@ function safePush(target, source, maxBatchSize = 1e4) {
233
47
  }
234
48
  }
235
49
  function getAllFiles(dirPath, exts, filenameArr = [], visited = /* @__PURE__ */ new Set()) {
236
- if (!fs2.existsSync(dirPath)) {
50
+ if (!fs.existsSync(dirPath)) {
237
51
  logger.error(`'${dirPath}' is not exist, please check!`);
238
52
  return filenameArr;
239
53
  }
240
- const realSrc = fs2.realpathSync(dirPath);
54
+ const realSrc = fs.realpathSync(dirPath);
241
55
  if (visited.has(realSrc)) {
242
56
  return filenameArr;
243
57
  }
244
58
  visited.add(realSrc);
245
- fs2.readdirSync(realSrc).forEach((fileName) => {
59
+ fs.readdirSync(realSrc).forEach((fileName) => {
246
60
  if (shouldSkipFile(fileName)) {
247
61
  return;
248
62
  }
249
63
  const realFile = path2.resolve(realSrc, fileName);
250
- if (fs2.statSync(realFile).isDirectory()) {
64
+ if (fs.statSync(realFile).isDirectory()) {
251
65
  getAllFiles(realFile, exts, filenameArr, visited);
252
66
  } else {
253
67
  if (exts.length === 0) {
@@ -442,7 +256,7 @@ var ArkTsGitInfoAnalysis = class {
442
256
  const jsonItems = [];
443
257
  const results = getAllFiles(resourcePath, [fileName]);
444
258
  for (const result of results) {
445
- const configText = fs3.readFileSync(result, "utf8");
259
+ const configText = fs2.readFileSync(result, "utf8");
446
260
  const json = parseJsonText(configText);
447
261
  jsonItems.push({ path: result, content: json });
448
262
  }
@@ -779,12 +593,11 @@ function loadSdks(ohosSdkPath, hmsSdkPath) {
779
593
  async function extractCommitContext(input) {
780
594
  const { projectPath, commitId } = input;
781
595
  const mode = input.mode ?? "default";
782
- const config = await loadHomeTransConfig();
783
596
  const ohosSdkPath = expandHome(
784
- input.ohosSdkPath ?? config.env.OHOS_SDK_PATH ?? process.env.OHOS_SDK_PATH ?? ""
597
+ input.ohosSdkPath ?? process.env.OHOS_SDK_PATH ?? ""
785
598
  );
786
599
  const hmsSdkPath = expandHome(
787
- input.hmsSdkPath ?? config.env.HMS_SDK_PATH ?? process.env.HMS_SDK_PATH ?? ""
600
+ input.hmsSdkPath ?? process.env.HMS_SDK_PATH ?? ""
788
601
  );
789
602
  if (!projectPath) {
790
603
  throw new Error("extractCommitContext: projectPath is required");
@@ -794,7 +607,7 @@ async function extractCommitContext(input) {
794
607
  }
795
608
  if (!ohosSdkPath && !hmsSdkPath) {
796
609
  throw new Error(
797
- "extractCommitContext: ohosSdkPath/hmsSdkPath not provided. Set params.OHOS_SDK_PATH / params.HMS_SDK_PATH in ~/.hometrans/config.json (view with `ht config`), pass them as tool input, or set OHOS_SDK_PATH / HMS_SDK_PATH env vars (e.g. D:\\DevEco Studio\\sdk\\default\\openharmony\\ets)."
610
+ "extractCommitContext: OHOS_SDK_PATH / HMS_SDK_PATH not found in the OS environment. Run `ht init` to set them as machine environment variables (and open a new terminal), or pass ohosSdkPath / hmsSdkPath as tool input (e.g. D:\\DevEco Studio\\sdk\\default\\openharmony\\ets)."
798
611
  );
799
612
  }
800
613
  console.error(