@buaa_smat/hometrans 0.1.9 → 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 +9 -8
- package/dist/cli/config-store.js +24 -1
- package/dist/cli/config.js +1 -1
- package/dist/cli/index.js +24 -0
- package/dist/cli/init.js +32 -3
- package/dist/cli/uninstall.js +20 -9
- package/dist/context/index.js +26 -0
- package/package.json +1 -1
- package/tools/test-tools/autotest/uv.lock +3156 -3156
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
|
|
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
|

|
|
29
29
|
|
|
@@ -167,12 +167,13 @@ For more details, see the official GitNexus repository: <https://github.com/abhi
|
|
|
167
167
|
|
|
168
168
|
### Target directories
|
|
169
169
|
|
|
170
|
-
| Editor | Marker | Skills target | Agents target |
|
|
171
|
-
|
|
172
|
-
| Claude Code | `~/.claude/` | `~/.claude/skills/` | `~/.claude/agents/` |
|
|
173
|
-
| Cursor | `~/.cursor/` | `~/.cursor/skills/` | `~/.cursor/agents/` |
|
|
174
|
-
| OpenCode | `~/.config/opencode/` | `~/.config/opencode/skills/` | `~/.config/opencode/agents/` |
|
|
175
|
-
| 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` |
|
|
176
177
|
|
|
177
178
|
---
|
|
178
179
|
|
package/dist/cli/config-store.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 全局配置存储:~/.hometrans/config.json
|
|
3
3
|
*
|
|
4
|
-
* 当前包含 editors 配置(Claude Code / Cursor / OpenCode / Codex),后续可扩展
|
|
4
|
+
* 当前包含 editors 配置(Claude Code / Cursor / OpenCode / Codex / CodeBuddy),后续可扩展
|
|
5
5
|
* 其它顶层字段。首次 setup 时若文件不存在则写入默认值;之后用户可手动编辑。
|
|
6
6
|
* `ht config` 只读不改。
|
|
7
7
|
*/
|
|
@@ -76,6 +76,19 @@ export function defaultEditors() {
|
|
|
76
76
|
section: 'mcp_servers.hometrans',
|
|
77
77
|
},
|
|
78
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
|
+
},
|
|
79
92
|
];
|
|
80
93
|
}
|
|
81
94
|
async function fileExists(p) {
|
|
@@ -139,6 +152,16 @@ export async function loadHomeTransConfig() {
|
|
|
139
152
|
delete anyParsed.sdkPaths;
|
|
140
153
|
delete anyParsed.params;
|
|
141
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
|
+
}
|
|
142
165
|
return config;
|
|
143
166
|
}
|
|
144
167
|
export async function saveHomeTransConfig(config) {
|
package/dist/cli/config.js
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -1,12 +1,34 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
|
+
import chalk from 'chalk';
|
|
4
5
|
import { initCommand } from './init.js';
|
|
5
6
|
import { runMcpServer } from './mcp.js';
|
|
6
7
|
import { configCommand } from './config.js';
|
|
7
8
|
import { uninstallCommand } from './uninstall.js';
|
|
8
9
|
const _require = createRequire(import.meta.url);
|
|
9
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);
|
|
10
32
|
const program = new Command();
|
|
11
33
|
program
|
|
12
34
|
.name('hometrans')
|
|
@@ -23,6 +45,8 @@ program
|
|
|
23
45
|
.command('mcp')
|
|
24
46
|
.description('Run the HomeTrans MCP server (stdio)')
|
|
25
47
|
.action(async () => {
|
|
48
|
+
// The MCP server owns its own SIGINT/shutdown handling; drop the CLI net.
|
|
49
|
+
process.off('SIGINT', onSigint);
|
|
26
50
|
await runMcpServer();
|
|
27
51
|
});
|
|
28
52
|
program
|
package/dist/cli/init.js
CHANGED
|
@@ -19,6 +19,20 @@ function ensureChalkColor() {
|
|
|
19
19
|
chalk.level = 1;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Did the user abort an inquirer prompt with Ctrl-C / Esc?
|
|
24
|
+
* inquirer v14 (@inquirer/core) rejects with an `ExitPromptError` in that case.
|
|
25
|
+
* We must distinguish this from a genuine non-interactive failure (no TTY),
|
|
26
|
+
* otherwise Ctrl-C silently gets swallowed and the install proceeds anyway.
|
|
27
|
+
*/
|
|
28
|
+
export function isPromptAbort(err) {
|
|
29
|
+
return err instanceof Error && err.name === 'ExitPromptError';
|
|
30
|
+
}
|
|
31
|
+
/** Print a cancellation notice and exit with the conventional SIGINT code. */
|
|
32
|
+
function abortInit() {
|
|
33
|
+
console.log(chalk.yellow('\n Cancelled. No changes were made beyond this point.\n'));
|
|
34
|
+
process.exit(130);
|
|
35
|
+
}
|
|
22
36
|
const __filename = fileURLToPath(import.meta.url);
|
|
23
37
|
const __dirname = path.dirname(__filename);
|
|
24
38
|
export async function dirExists(dirPath) {
|
|
@@ -256,13 +270,26 @@ export async function initCommand(options = {}) {
|
|
|
256
270
|
{
|
|
257
271
|
type: 'checkbox',
|
|
258
272
|
name: 'selectedEditors',
|
|
259
|
-
message: 'Select editors to configure
|
|
273
|
+
message: 'Select editors to configure:',
|
|
260
274
|
choices,
|
|
275
|
+
// Append a "ctrl-c cancel" entry to the built-in key help line, reusing
|
|
276
|
+
// @inquirer/checkbox's default formatting (bold key · dim action · dim
|
|
277
|
+
// " • " separator):
|
|
278
|
+
// ↑↓ navigate • space select • a all • i invert • ⏎ submit • ctrl-c cancel
|
|
279
|
+
theme: {
|
|
280
|
+
style: {
|
|
281
|
+
keysHelpTip: (keys) => [...keys, ['ctrl-c', 'cancel']]
|
|
282
|
+
.map(([key, action]) => `${chalk.bold(key)} ${chalk.dim(action)}`)
|
|
283
|
+
.join(chalk.dim(' • ')),
|
|
284
|
+
},
|
|
285
|
+
},
|
|
261
286
|
},
|
|
262
287
|
]);
|
|
263
288
|
selectedEditors = answers.selectedEditors;
|
|
264
289
|
}
|
|
265
|
-
catch {
|
|
290
|
+
catch (err) {
|
|
291
|
+
if (isPromptAbort(err))
|
|
292
|
+
abortInit();
|
|
266
293
|
console.log(chalk.yellow('\n Interactive selection failed. Auto-selecting all detected editors.'));
|
|
267
294
|
console.log(chalk.gray(' Tip: use --all to skip interactive selection.\n'));
|
|
268
295
|
selectedEditors = editors
|
|
@@ -304,7 +331,9 @@ export async function initCommand(options = {}) {
|
|
|
304
331
|
config.env.TEST_API_KEY = answers.TEST_API_KEY.trim();
|
|
305
332
|
await saveHomeTransConfig(config);
|
|
306
333
|
}
|
|
307
|
-
catch {
|
|
334
|
+
catch (err) {
|
|
335
|
+
if (isPromptAbort(err))
|
|
336
|
+
abortInit();
|
|
308
337
|
console.log(chalk.yellow(' Parameter prompts skipped (non-interactive mode).'));
|
|
309
338
|
}
|
|
310
339
|
// Copy bundled tools/ into ~/.hometrans/tools and record env.TOOL_PATH.
|
package/dist/cli/uninstall.js
CHANGED
|
@@ -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
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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;
|
package/dist/context/index.js
CHANGED
|
@@ -73,6 +73,19 @@ function defaultEditors() {
|
|
|
73
73
|
path: "~/.codex/config.toml",
|
|
74
74
|
section: "mcp_servers.hometrans"
|
|
75
75
|
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
// CodeBuddy(腾讯):与 Claude Code 同构的 .codebuddy/ 目录,
|
|
79
|
+
// 全局安装映射到 ~/.codebuddy/{skills,agents},MCP 走 mcpServers JSON。
|
|
80
|
+
name: "CodeBuddy",
|
|
81
|
+
markerDir: "~/.codebuddy",
|
|
82
|
+
skillsDir: "~/.codebuddy/skills",
|
|
83
|
+
agentsDir: "~/.codebuddy/agents",
|
|
84
|
+
mcp: {
|
|
85
|
+
format: "jsonc-object",
|
|
86
|
+
path: "~/.codebuddy/mcp.json",
|
|
87
|
+
keyPath: ["mcpServers", "hometrans"]
|
|
88
|
+
}
|
|
76
89
|
}
|
|
77
90
|
];
|
|
78
91
|
}
|
|
@@ -132,8 +145,21 @@ async function loadHomeTransConfig() {
|
|
|
132
145
|
delete anyParsed.sdkPaths;
|
|
133
146
|
delete anyParsed.params;
|
|
134
147
|
delete anyParsed.tool_path;
|
|
148
|
+
const existingNames = new Set(config.editors.map((e) => e.name));
|
|
149
|
+
const missingEditors = defaultEditors().filter(
|
|
150
|
+
(e) => !existingNames.has(e.name)
|
|
151
|
+
);
|
|
152
|
+
if (missingEditors.length > 0) {
|
|
153
|
+
config.editors.push(...missingEditors);
|
|
154
|
+
await saveHomeTransConfig(config);
|
|
155
|
+
}
|
|
135
156
|
return config;
|
|
136
157
|
}
|
|
158
|
+
async function saveHomeTransConfig(config) {
|
|
159
|
+
const configPath = getConfigPath();
|
|
160
|
+
await fs.mkdir(getConfigDir(), { recursive: true });
|
|
161
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
162
|
+
}
|
|
137
163
|
|
|
138
164
|
// src/context/analysis/ArkTsGitInfoAnalysis.ts
|
|
139
165
|
import {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buaa_smat/hometrans",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
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": {
|