@buaa_smat/hometrans 0.1.8 → 0.1.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # hometrans
2
2
 
3
- > Skill + agent installer for the **HomeTrans** Android-to-HarmonyOS conversion toolkit. One command (`ht init`) distributes **7 skills**, **9 subagents** (with a script bundle + on-device test tooling), and an **MCP server** into Claude Code, Cursor, OpenCode, and Codex.
3
+ > Skill + agent installer for the **HomeTrans** Android-to-HarmonyOS conversion toolkit. One command (`ht init`) distributes **7 skills**, **9 subagents** (with a script bundle + on-device test tooling), and an **MCP server** into Claude Code, Cursor, OpenCode, Codex, and CodeBuddy.
4
4
 
5
5
  ---
6
6
 
@@ -23,7 +23,7 @@ After running `ht init`, follow these steps to complete the installation:
23
23
 
24
24
  ### Step 1: Choose your target editor
25
25
 
26
- `ht init` automatically detects supported editors (Claude Code, Cursor, OpenCode, Codex) and presents an interactive selection prompt. Use **Space** to toggle and **Enter** to confirm.
26
+ `ht init` automatically detects supported editors (Claude Code, Cursor, OpenCode, Codex, CodeBuddy) and presents an interactive selection prompt. Use **Space** to toggle and **Enter** to confirm.
27
27
 
28
28
  ![Choose target editor](resource/choose_editor.png)
29
29
 
@@ -37,6 +37,19 @@ After confirming your editor selection, HomeTrans installs all bundled **skills*
37
37
 
38
38
  ---
39
39
 
40
+ ## Dependencies
41
+
42
+ Install GitNexus (code knowledge graph dependency required by the migration agents):
43
+
44
+ ```bash
45
+ npm install -g gitnexus
46
+ gitnexus setup
47
+ ```
48
+
49
+ For more details, see the official GitNexus repository: <https://github.com/abhigyanpatwari/GitNexus>
50
+
51
+ ---
52
+
40
53
  ## HarmonyOS Migration Guide
41
54
 
42
55
  鸿蒙软件迁移指导,提供完整的 Android 到 HarmonyOS 迁移流程:
@@ -154,12 +167,13 @@ After confirming your editor selection, HomeTrans installs all bundled **skills*
154
167
 
155
168
  ### Target directories
156
169
 
157
- | Editor | Marker | Skills target | Agents target |
158
- |--------|--------|---------------|---------------|
159
- | Claude Code | `~/.claude/` | `~/.claude/skills/` | `~/.claude/agents/` |
160
- | Cursor | `~/.cursor/` | `~/.cursor/skills/` | `~/.cursor/agents/` |
161
- | OpenCode | `~/.config/opencode/` | `~/.config/opencode/skills/` | `~/.config/opencode/agents/` |
162
- | Codex | `~/.codex/` | `~/.agents/skills/` | `~/.codex/agents/` |
170
+ | Editor | Marker | Skills target | Agents target | MCP config |
171
+ |--------|--------|---------------|---------------|------------|
172
+ | Claude Code | `~/.claude/` | `~/.claude/skills/` | `~/.claude/agents/` | `~/.claude.json` → `mcpServers.hometrans` |
173
+ | Cursor | `~/.cursor/` | `~/.cursor/skills/` | `~/.cursor/agents/` | `~/.cursor/mcp.json` → `mcpServers.hometrans` |
174
+ | OpenCode | `~/.config/opencode/` | `~/.config/opencode/skills/` | `~/.config/opencode/agents/` | `~/.config/opencode/opencode.json` → `mcp.hometrans` |
175
+ | Codex | `~/.codex/` | `~/.agents/skills/` | `~/.codex/agents/` | `codex mcp add` → `~/.codex/config.toml` `[mcp_servers.hometrans]` |
176
+ | CodeBuddy | `~/.codebuddy/` | `~/.codebuddy/skills/` | `~/.codebuddy/agents/` | `~/.codebuddy/mcp.json` → `mcpServers.hometrans` |
163
177
 
164
178
  ---
165
179
 
@@ -0,0 +1,171 @@
1
+ /**
2
+ * 全局配置存储:~/.hometrans/config.json
3
+ *
4
+ * 当前包含 editors 配置(Claude Code / Cursor / OpenCode / Codex / CodeBuddy),后续可扩展
5
+ * 其它顶层字段。首次 setup 时若文件不存在则写入默认值;之后用户可手动编辑。
6
+ * `ht config` 只读不改。
7
+ */
8
+ import fs from 'node:fs/promises';
9
+ import path from 'node:path';
10
+ import os from 'node:os';
11
+ export function getConfigDir() {
12
+ return path.join(os.homedir(), '.hometrans');
13
+ }
14
+ export function getConfigPath() {
15
+ return path.join(getConfigDir(), 'config.json');
16
+ }
17
+ /** 工具目录:~/.hometrans/tools,`ht init` 把打包的 tools/ 拷贝到此。 */
18
+ export function getToolsDir() {
19
+ return path.join(getConfigDir(), 'tools');
20
+ }
21
+ /** 把 ~/foo 展开为 $HOME/foo;非 ~ 开头原样返回。 */
22
+ export function expandHome(p) {
23
+ if (!p)
24
+ return p;
25
+ if (p === '~')
26
+ return os.homedir();
27
+ if (p.startsWith('~/') || p.startsWith('~\\')) {
28
+ return path.join(os.homedir(), p.slice(2));
29
+ }
30
+ return p;
31
+ }
32
+ export function defaultEditors() {
33
+ return [
34
+ {
35
+ name: 'Claude Code',
36
+ markerDir: '~/.claude',
37
+ skillsDir: '~/.claude/skills',
38
+ agentsDir: '~/.claude/agents',
39
+ mcp: {
40
+ format: 'jsonc-object',
41
+ path: '~/.claude.json',
42
+ keyPath: ['mcpServers', 'hometrans'],
43
+ },
44
+ },
45
+ {
46
+ name: 'Cursor',
47
+ markerDir: '~/.cursor',
48
+ skillsDir: '~/.cursor/skills',
49
+ agentsDir: '~/.cursor/agents',
50
+ mcp: {
51
+ format: 'jsonc-object',
52
+ path: '~/.cursor/mcp.json',
53
+ keyPath: ['mcpServers', 'hometrans'],
54
+ },
55
+ },
56
+ {
57
+ name: 'OpenCode',
58
+ markerDir: '~/.config/opencode',
59
+ skillsDir: '~/.config/opencode/skills',
60
+ agentsDir: '~/.config/opencode/agents',
61
+ mcp: {
62
+ format: 'jsonc-command-array',
63
+ path: '~/.config/opencode/opencode.json',
64
+ keyPath: ['mcp', 'hometrans'],
65
+ },
66
+ },
67
+ {
68
+ name: 'Codex',
69
+ markerDir: '~/.codex',
70
+ // Codex 复用 Agent Skills 公共目录,agent 定义独立。
71
+ skillsDir: '~/.agents/skills',
72
+ agentsDir: '~/.codex/agents',
73
+ mcp: {
74
+ format: 'codex-cli',
75
+ path: '~/.codex/config.toml',
76
+ section: 'mcp_servers.hometrans',
77
+ },
78
+ },
79
+ {
80
+ // CodeBuddy(腾讯):与 Claude Code 同构的 .codebuddy/ 目录,
81
+ // 全局安装映射到 ~/.codebuddy/{skills,agents},MCP 走 mcpServers JSON。
82
+ name: 'CodeBuddy',
83
+ markerDir: '~/.codebuddy',
84
+ skillsDir: '~/.codebuddy/skills',
85
+ agentsDir: '~/.codebuddy/agents',
86
+ mcp: {
87
+ format: 'jsonc-object',
88
+ path: '~/.codebuddy/mcp.json',
89
+ keyPath: ['mcpServers', 'hometrans'],
90
+ },
91
+ },
92
+ ];
93
+ }
94
+ async function fileExists(p) {
95
+ try {
96
+ await fs.access(p);
97
+ return true;
98
+ }
99
+ catch {
100
+ return false;
101
+ }
102
+ }
103
+ /**
104
+ * 加载 editors 配置。文件不存在时写入默认值再返回。
105
+ * 解析失败时抛错,避免静默覆盖用户手动修改。
106
+ */
107
+ export function defaultEnv() {
108
+ return {
109
+ OHOS_SDK_PATH: '',
110
+ HMS_SDK_PATH: '',
111
+ TEST_API_KEY: '',
112
+ TOOL_PATH: '',
113
+ };
114
+ }
115
+ export async function loadHomeTransConfig() {
116
+ const configPath = getConfigPath();
117
+ if (!(await fileExists(configPath))) {
118
+ const config = {
119
+ editors: defaultEditors(),
120
+ env: defaultEnv(),
121
+ };
122
+ await fs.mkdir(getConfigDir(), { recursive: true });
123
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
124
+ return config;
125
+ }
126
+ const raw = await fs.readFile(configPath, 'utf-8');
127
+ let parsed;
128
+ try {
129
+ parsed = JSON.parse(raw);
130
+ }
131
+ catch (err) {
132
+ throw new Error(`Failed to parse ${configPath}: ${err.message}. Fix the JSON or delete the file to restore defaults.`);
133
+ }
134
+ if (!parsed || typeof parsed !== 'object' || !Array.isArray(parsed.editors)) {
135
+ throw new Error(`Invalid config.json shape at ${configPath}: top-level must be { "editors": [...] }.`);
136
+ }
137
+ const config = parsed;
138
+ const anyParsed = parsed;
139
+ // Migrate legacy fields into `env`:
140
+ // - `sdkPaths` / `params` held OHOS_SDK_PATH / HMS_SDK_PATH / TEST_API_KEY.
141
+ // - `tool_path` held the tools dir, now env.TOOL_PATH.
142
+ const legacyParams = (anyParsed.params ?? anyParsed.sdkPaths);
143
+ const legacyToolPath = typeof anyParsed.tool_path === 'string' ? anyParsed.tool_path : undefined;
144
+ config.env = {
145
+ ...defaultEnv(),
146
+ ...(legacyParams ?? {}),
147
+ ...(config.env ?? {}),
148
+ };
149
+ if (legacyToolPath && !config.env.TOOL_PATH) {
150
+ config.env.TOOL_PATH = legacyToolPath;
151
+ }
152
+ delete anyParsed.sdkPaths;
153
+ delete anyParsed.params;
154
+ delete anyParsed.tool_path;
155
+ // Append any default editors that this (older) config predates, matched by
156
+ // name. Existing entries are never modified, so manual edits are preserved;
157
+ // we only add editors the user's file is missing (e.g. CodeBuddy shipped
158
+ // after they first ran `ht init`). Persist so the new editor shows up.
159
+ const existingNames = new Set(config.editors.map((e) => e.name));
160
+ const missingEditors = defaultEditors().filter((e) => !existingNames.has(e.name));
161
+ if (missingEditors.length > 0) {
162
+ config.editors.push(...missingEditors);
163
+ await saveHomeTransConfig(config);
164
+ }
165
+ return config;
166
+ }
167
+ export async function saveHomeTransConfig(config) {
168
+ const configPath = getConfigPath();
169
+ await fs.mkdir(getConfigDir(), { recursive: true });
170
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
171
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `ht config` — 打印 editors.json 路径与内容。
3
+ *
4
+ * 该命令只读:用户若要修改 editor 配置,直接编辑这个 JSON 文件即可。
5
+ * 文件不存在时自动写入默认 5 个 editor。
6
+ */
7
+ import fs from 'node:fs/promises';
8
+ import { getConfigPath, loadHomeTransConfig } from './config-store.js';
9
+ export async function configCommand() {
10
+ const configPath = getConfigPath();
11
+ const config = await loadHomeTransConfig();
12
+ const raw = await fs.readFile(configPath, 'utf-8');
13
+ console.log('');
14
+ console.log(' HomeTrans Config');
15
+ console.log(' ================');
16
+ console.log('');
17
+ console.log(` Path: ${configPath}`);
18
+ console.log('');
19
+ // User parameters
20
+ const maskedKey = config.env.TEST_API_KEY
21
+ ? config.env.TEST_API_KEY.slice(0, 4) +
22
+ '***' +
23
+ config.env.TEST_API_KEY.slice(-4)
24
+ : '(not set)';
25
+ console.log(' Parameters:');
26
+ console.log(` OHOS_SDK_PATH : ${config.env.OHOS_SDK_PATH || '(not set)'}`);
27
+ console.log(` HMS_SDK_PATH : ${config.env.HMS_SDK_PATH || '(not set)'}`);
28
+ console.log(` TEST_API_KEY : ${maskedKey}`);
29
+ console.log(` TOOL_PATH : ${config.env.TOOL_PATH || '(not set)'}`);
30
+ console.log('');
31
+ // Full config content
32
+ console.log(' Full Content:');
33
+ console.log('');
34
+ for (const line of raw.replace(/\r?\n$/, '').split(/\r?\n/)) {
35
+ console.log(` ${line}`);
36
+ }
37
+ console.log('');
38
+ console.log(' Edit this file to modify config, then re-run `ht init`.');
39
+ console.log('');
40
+ }
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { createRequire } from 'node:module';
4
+ import chalk from 'chalk';
5
+ import { initCommand } from './init.js';
6
+ import { runMcpServer } from './mcp.js';
7
+ import { configCommand } from './config.js';
8
+ import { uninstallCommand } from './uninstall.js';
9
+ const _require = createRequire(import.meta.url);
10
+ const pkg = _require('../../package.json');
11
+ /**
12
+ * Global Ctrl-C safety net.
13
+ *
14
+ * inquirer intercepts Ctrl-C as a keypress *inside* a prompt (raw mode) and the
15
+ * per-command catches print a tailored "Cancelled" notice there. But Ctrl-C
16
+ * pressed *outside* a prompt — e.g. while `init` is copying files or `uninstall`
17
+ * is deleting — arrives as an OS SIGINT, which Node would otherwise terminate on
18
+ * silently. This handler guarantees a cancel notice in that case too.
19
+ *
20
+ * The MCP server (`ht mcp`) runs over stdio and must keep its own shutdown
21
+ * semantics, so it removes this handler on startup.
22
+ */
23
+ let interrupted = false;
24
+ function onSigint() {
25
+ if (interrupted)
26
+ process.exit(130);
27
+ interrupted = true;
28
+ console.log(chalk.yellow('\n Cancelled by Ctrl-C. No further changes will be made.\n'));
29
+ process.exit(130);
30
+ }
31
+ process.on('SIGINT', onSigint);
32
+ const program = new Command();
33
+ program
34
+ .name('hometrans')
35
+ .description('HomeTrans installer — distribute Android-to-HarmonyOS skills and agents into AI editors')
36
+ .version(pkg.version);
37
+ program
38
+ .command('init')
39
+ .description('Initialize HomeTrans — select editors and install skills, agents, and MCP servers')
40
+ .option('-a, --all', 'Skip interactive selection and configure all editors')
41
+ .action(async (opts) => {
42
+ await initCommand(opts);
43
+ });
44
+ program
45
+ .command('mcp')
46
+ .description('Run the HomeTrans MCP server (stdio)')
47
+ .action(async () => {
48
+ // The MCP server owns its own SIGINT/shutdown handling; drop the CLI net.
49
+ process.off('SIGINT', onSigint);
50
+ await runMcpServer();
51
+ });
52
+ program
53
+ .command('config')
54
+ .description('Show the editors.json path and content (~/.hometrans/editors.json). Edit the file directly to customize editors, then re-run `ht init`.')
55
+ .action(async () => {
56
+ await configCommand();
57
+ });
58
+ program
59
+ .command('uninstall')
60
+ .description('Remove all hometrans skills, agents, and MCP entries from configured editors')
61
+ .action(async () => {
62
+ await uninstallCommand();
63
+ });
64
+ program.parseAsync(process.argv).catch((err) => {
65
+ console.error(err instanceof Error ? err.message : err);
66
+ process.exit(1);
67
+ });