ccg-ros2-workflow 1.0.9 → 1.2.0

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 (3) hide show
  1. package/README.md +51 -12
  2. package/bin/cli.js +567 -127
  3. package/package.json +6 -2
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  ROS2 多模型协作开发工具 - 基于 Claude Code CLI
7
7
 
8
- > **v1.0.8** - 根据 Codex+Gemini 双模型分析优化工作流
8
+ > **v1.2.0** - 全新交互式菜单体验,支持更新检查
9
9
 
10
10
  ## 特性
11
11
 
@@ -29,10 +29,13 @@ ccg-ros2-workflow
29
29
  ```
30
30
 
31
31
  安装程序提供以下选项:
32
- 1. 安装工作流
33
- 2. 配置 API 密钥
32
+ 1. 安装/重装工作流
33
+ 2. 更新工作流
34
34
  3. 配置 ace-tool MCP
35
- 4. 卸载工作流
35
+ 4. 配置 API 密钥
36
+ 5. 帮助
37
+ 6. 卸载工作流
38
+ 7. 退出
36
39
 
37
40
  ## 前置依赖
38
41
 
@@ -167,6 +170,10 @@ npm install -g @google/gemini-cli
167
170
  │ ├── gemini/ # analyzer, architect, reviewer, debugger, optimizer, tester, frontend
168
171
  │ └── claude/ # analyzer, architect, reviewer, debugger, optimizer, tester
169
172
  ├── commands/ccg/ # 17 个命令文件
173
+ ├── agents/ccg/ # 3 个 agent 文件
174
+ │ ├── system-integrator.md # ROS2 系统集成设计
175
+ │ ├── planner.md # WBS 任务规划
176
+ │ └── get-current-datetime.md
170
177
  ├── mcp_servers.json # MCP 配置 (ace-tool)
171
178
  └── bin/
172
179
  └── codeagent-wrapper # 模型调用脚本
@@ -176,22 +183,35 @@ npm install -g @google/gemini-cli
176
183
 
177
184
  ace-tool 是 Augment Code 的代码上下文引擎,让 AI 自动理解项目结构。
178
185
 
179
- 安装时选择「配置 ace-tool MCP」会自动添加到 `~/.claude/mcp_servers.json`:
186
+ ### 安装方式
187
+
188
+ 运行安装程序,选择「配置 ace-tool MCP」:
189
+
190
+ ```bash
191
+ npx ccg-ros2-workflow
192
+ # 选择 3. 配置 ace-tool MCP
193
+ # 选择版本:ace-tool (Node.js) 或 ace-tool-rs (Rust,推荐)
194
+ # 输入 Token(从 augmentcode.com 或中转服务获取)
195
+ ```
196
+
197
+ ### 配置示例
180
198
 
181
199
  ```json
182
200
  {
183
201
  "ace-tool": {
184
- "command": "ace-tool",
185
- "args": ["mcp"],
186
- "env": {}
202
+ "command": "npx",
203
+ "args": ["ace-tool-rs", "mcp", "--token", "your-token"],
204
+ "env": { "RUST_LOG": "info" }
187
205
  }
188
206
  }
189
207
  ```
190
208
 
191
- 使用前需要:
192
- 1. 安装 ace-tool CLI(访问 https://augmentcode.com/)
193
- 2. 运行 `ace-tool login` 登录
194
- 3. 重启 Claude Code
209
+ ### Token 获取
210
+
211
+ - **官方服务**: https://augmentcode.com/ 注册获取
212
+ - **中转服务**: 使用第三方中转(需要配置 Base URL)
213
+
214
+ 配置完成后重启 Claude Code 即可使用。
195
215
 
196
216
  ## 语言配置
197
217
 
@@ -222,6 +242,25 @@ MIT
222
242
 
223
243
  ## 更新日志
224
244
 
245
+ ### v1.2.0
246
+ - 全新交互式菜单 (inquirer + chalk)
247
+ - 添加更新检查功能,支持 npm 版本对比
248
+ - 新增 agents 目录,包含 3 个 agent 文件
249
+ - 改进卸载流程,显示详细文件统计
250
+ - 新增帮助命令,展示所有可用 /ccg: 命令
251
+ - 优化安装流程,显示安装摘要
252
+
253
+ ### v1.1.0
254
+ - 支持直接安装 ace-tool,无需手动安装 CLI
255
+ - 支持 ace-tool (Node.js) 和 ace-tool-rs (Rust) 两种版本
256
+ - 支持配置 Token 和 Base URL(中转服务)
257
+ - 使用 npx 自动下载运行,首次使用自动安装
258
+
259
+ ### v1.0.9
260
+ - 提示词文件统一使用英文
261
+ - 保留 "Code comments in Chinese" 指令
262
+ - 语言规范:提示词(英文) / 交互(中文) / 注释(中文)
263
+
225
264
  ### v1.0.8
226
265
  - 基于 Codex+Gemini 双模型交叉验证分析优化
227
266
  - `gemini/architect.md`: 增加 QoS 策略设计 + Node Composition
package/bin/cli.js CHANGED
@@ -2,24 +2,37 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const readline = require('readline');
6
5
  const { execSync } = require('child_process');
7
6
 
7
+ // 延迟加载依赖,避免首次运行时报错
8
+ let inquirer, chalk;
9
+ async function loadDependencies() {
10
+ try {
11
+ inquirer = require('inquirer');
12
+ chalk = require('chalk');
13
+ } catch {
14
+ console.log('正在安装依赖...');
15
+ execSync('npm install inquirer@8.2.6 chalk@4.1.2', { stdio: 'inherit' });
16
+ inquirer = require('inquirer');
17
+ chalk = require('chalk');
18
+ }
19
+ }
20
+
21
+ // 路径常量
8
22
  const CLAUDE_DIR = path.join(process.env.HOME, '.claude');
9
23
  const CCG_DIR = path.join(CLAUDE_DIR, '.ccg');
10
24
  const COMMANDS_DIR = path.join(CLAUDE_DIR, 'commands', 'ccg');
25
+ const AGENTS_DIR = path.join(CLAUDE_DIR, 'agents', 'ccg');
11
26
  const BIN_DIR = path.join(CLAUDE_DIR, 'bin');
12
27
  const MCP_CONFIG_PATH = path.join(CLAUDE_DIR, 'mcp_servers.json');
13
28
  const SRC_DIR = path.join(__dirname, '..', 'src');
29
+ const PACKAGE_NAME = 'ccg-ros2-workflow';
14
30
 
15
- const rl = readline.createInterface({
16
- input: process.stdin,
17
- output: process.stdout
18
- });
31
+ // 版本信息
32
+ const PACKAGE_JSON = require('../package.json');
33
+ const VERSION = PACKAGE_JSON.version;
19
34
 
20
- function question(prompt) {
21
- return new Promise(resolve => rl.question(prompt, resolve));
22
- }
35
+ // ==================== 工具函数 ====================
23
36
 
24
37
  function copyRecursive(src, dest) {
25
38
  if (!fs.existsSync(src)) return;
@@ -44,182 +57,520 @@ function replaceInFile(filePath, replacements) {
44
57
  fs.writeFileSync(filePath, content);
45
58
  }
46
59
 
47
- async function main() {
48
- console.log('\n🤖 CCG-ROS2-Workflow 安装程序');
49
- console.log('================================');
50
- console.log('ROS2 多模型协作开发工具');
51
- console.log('Codex (底层) + Gemini (上层) + Claude (编排)\n');
60
+ function isInstalled() {
61
+ return fs.existsSync(path.join(CCG_DIR, 'config.toml')) ||
62
+ fs.existsSync(COMMANDS_DIR);
63
+ }
52
64
 
53
- // 检查是否已安装
54
- if (fs.existsSync(path.join(CCG_DIR, 'config.toml'))) {
55
- const overwrite = await question('⚠️ 检测到已有安装,是否覆盖? (y/N): ');
56
- if (overwrite.toLowerCase() !== 'y') {
57
- console.log('取消安装');
58
- rl.close();
59
- return;
60
- }
65
+ function getInstalledVersion() {
66
+ const configPath = path.join(CCG_DIR, 'config.toml');
67
+ if (fs.existsSync(configPath)) {
68
+ const content = fs.readFileSync(configPath, 'utf8');
69
+ const match = content.match(/version\s*=\s*"([^"]+)"/);
70
+ if (match) return match[1];
61
71
  }
72
+ return null;
73
+ }
62
74
 
63
- // 选择操作
64
- console.log('\n请选择操作:');
65
- console.log('1. 安装工作流');
66
- console.log('2. 配置 API 密钥');
67
- console.log('3. 配置 ace-tool MCP');
68
- console.log('4. 卸载工作流');
69
- console.log('5. 退出');
75
+ async function checkLatestVersion() {
76
+ try {
77
+ const result = execSync(`npm view ${PACKAGE_NAME} version`, { encoding: 'utf8', timeout: 10000 });
78
+ return result.trim();
79
+ } catch {
80
+ return null;
81
+ }
82
+ }
83
+
84
+ function countFiles(dir, ext = '.md') {
85
+ if (!fs.existsSync(dir)) return 0;
86
+ return fs.readdirSync(dir).filter(f => f.endsWith(ext)).length;
87
+ }
70
88
 
71
- const choice = await question('\n请输入选项 (1-5): ');
89
+ // ==================== 主菜单 ====================
72
90
 
73
- switch (choice) {
74
- case '1':
91
+ async function showMainMenu() {
92
+ console.log('\n' + chalk.cyan.bold('🤖 CCG-ROS2-Workflow'));
93
+ console.log(chalk.gray('━'.repeat(40)));
94
+ console.log(chalk.white('ROS2 多模型协作开发工具'));
95
+ console.log(chalk.gray(`Codex (底层控制) + Gemini (上层集成) + Claude (编排)`));
96
+ console.log(chalk.gray(`版本: ${VERSION}`));
97
+ console.log(chalk.gray('━'.repeat(40)) + '\n');
98
+
99
+ // 检查安装状态
100
+ const installed = isInstalled();
101
+ const installedVersion = getInstalledVersion();
102
+
103
+ if (installed) {
104
+ console.log(chalk.green(`✓ 已安装`) + (installedVersion ? chalk.gray(` (v${installedVersion})`) : ''));
105
+ } else {
106
+ console.log(chalk.yellow(`○ 未安装`));
107
+ }
108
+ console.log('');
109
+
110
+ const choices = [
111
+ { name: chalk.green('1.') + ' 安装/重装工作流', value: 'install' },
112
+ { name: chalk.blue('2.') + ' 更新工作流', value: 'update' },
113
+ { name: chalk.cyan('3.') + ' 配置 ace-tool MCP', value: 'mcp' },
114
+ { name: chalk.magenta('4.') + ' 配置 API 密钥', value: 'api' },
115
+ { name: chalk.yellow('5.') + ' 帮助', value: 'help' },
116
+ { name: chalk.red('6.') + ' 卸载工作流', value: 'uninstall' },
117
+ { name: chalk.gray('7.') + ' 退出', value: 'exit' },
118
+ ];
119
+
120
+ const { action } = await inquirer.prompt([
121
+ {
122
+ type: 'list',
123
+ name: 'action',
124
+ message: '请选择操作:',
125
+ choices,
126
+ }
127
+ ]);
128
+
129
+ switch (action) {
130
+ case 'install':
75
131
  await install();
76
132
  break;
77
- case '2':
78
- await configureApiKeys();
133
+ case 'update':
134
+ await update();
79
135
  break;
80
- case '3':
136
+ case 'mcp':
81
137
  await configureMCP();
82
138
  break;
83
- case '4':
139
+ case 'api':
140
+ await configureApiKeys();
141
+ break;
142
+ case 'help':
143
+ showHelp();
144
+ break;
145
+ case 'uninstall':
84
146
  await uninstall();
85
147
  break;
86
- default:
87
- console.log('退出');
148
+ case 'exit':
149
+ console.log(chalk.gray('再见!'));
150
+ process.exit(0);
88
151
  }
89
152
 
90
- rl.close();
153
+ // 返回主菜单
154
+ await showMainMenu();
91
155
  }
92
156
 
157
+ // ==================== 安装功能 ====================
158
+
93
159
  async function install() {
94
- console.log('\n📦 开始安装...\n');
160
+ console.log('\n' + chalk.cyan.bold('📦 安装工作流'));
161
+ console.log(chalk.gray('━'.repeat(40)) + '\n');
95
162
 
96
- // 创建目录
97
- [CCG_DIR, COMMANDS_DIR, BIN_DIR].forEach(dir => {
163
+ // 检查是否已安装
164
+ if (isInstalled()) {
165
+ const { confirm } = await inquirer.prompt([
166
+ {
167
+ type: 'confirm',
168
+ name: 'confirm',
169
+ message: chalk.yellow('检测到已有安装,是否覆盖?'),
170
+ default: false
171
+ }
172
+ ]);
173
+ if (!confirm) {
174
+ console.log(chalk.gray('取消安装'));
175
+ return;
176
+ }
177
+ }
178
+
179
+ console.log(chalk.blue('→') + ' 创建目录结构...');
180
+ [CCG_DIR, COMMANDS_DIR, AGENTS_DIR, BIN_DIR].forEach(dir => {
98
181
  fs.mkdirSync(dir, { recursive: true });
99
182
  });
100
183
 
101
- // 复制文件
102
- console.log('复制配置文件...');
184
+ console.log(chalk.blue('→') + ' 复制提示词文件...');
103
185
  copyRecursive(path.join(SRC_DIR, 'prompts'), path.join(CCG_DIR, 'prompts'));
186
+ const promptCount = countFiles(path.join(CCG_DIR, 'prompts', 'codex')) +
187
+ countFiles(path.join(CCG_DIR, 'prompts', 'gemini')) +
188
+ countFiles(path.join(CCG_DIR, 'prompts', 'claude'));
189
+ console.log(chalk.gray(` 已复制 ${promptCount} 个提示词文件`));
104
190
 
105
- console.log('复制命令文件...');
191
+ console.log(chalk.blue('→') + ' 复制命令文件...');
106
192
  copyRecursive(path.join(SRC_DIR, 'commands', 'ccg'), COMMANDS_DIR);
193
+ const commandCount = countFiles(COMMANDS_DIR);
194
+ console.log(chalk.gray(` 已复制 ${commandCount} 个命令文件`));
195
+
196
+ console.log(chalk.blue('→') + ' 创建 agents 目录...');
197
+ // 创建 agents 文件
198
+ createAgentFiles();
199
+ const agentCount = countFiles(AGENTS_DIR);
200
+ console.log(chalk.gray(` 已创建 ${agentCount} 个 agent 文件`));
201
+
202
+ console.log(chalk.blue('→') + ' 复制配置文件...');
203
+ const configSrc = path.join(SRC_DIR, 'config.toml');
204
+ const configDest = path.join(CCG_DIR, 'config.toml');
205
+ if (fs.existsSync(configSrc)) {
206
+ let configContent = fs.readFileSync(configSrc, 'utf8');
207
+ // 添加版本信息
208
+ if (!configContent.includes('version')) {
209
+ configContent = `version = "${VERSION}"\n` + configContent;
210
+ }
211
+ fs.writeFileSync(configDest, configContent);
212
+ } else {
213
+ // 创建默认配置
214
+ fs.writeFileSync(configDest, `version = "${VERSION}"\nlanguage = "zh-CN"\n`);
215
+ }
107
216
 
108
- console.log('复制配置...');
109
- fs.copyFileSync(
110
- path.join(SRC_DIR, 'config.toml'),
111
- path.join(CCG_DIR, 'config.toml')
112
- );
113
-
114
- // 复制 codeagent-wrapper 脚本
115
- console.log('安装 codeagent-wrapper...');
217
+ console.log(chalk.blue('') + ' 安装 codeagent-wrapper...');
116
218
  const wrapperSrc = path.join(SRC_DIR, 'codeagent-wrapper.sh');
117
219
  const wrapperDest = path.join(BIN_DIR, 'codeagent-wrapper');
118
- fs.copyFileSync(wrapperSrc, wrapperDest);
119
- fs.chmodSync(wrapperDest, '755');
220
+ if (fs.existsSync(wrapperSrc)) {
221
+ fs.copyFileSync(wrapperSrc, wrapperDest);
222
+ fs.chmodSync(wrapperDest, '755');
223
+ }
120
224
 
121
- // 替换路径
225
+ console.log(chalk.blue('→') + ' 处理路径变量...');
122
226
  const homeDir = process.env.HOME;
123
227
  const filesToUpdate = [
124
- path.join(CCG_DIR, 'config.toml'),
228
+ configDest,
125
229
  ...fs.readdirSync(COMMANDS_DIR)
126
230
  .filter(f => f.endsWith('.md'))
127
231
  .map(f => path.join(COMMANDS_DIR, f))
128
232
  ];
129
-
130
233
  filesToUpdate.forEach(file => {
131
- replaceInFile(file, {
132
- '\\$HOME': homeDir
133
- });
234
+ replaceInFile(file, { '\\$HOME': homeDir });
134
235
  });
135
236
 
136
- console.log('\n✅ 工作流安装完成!\n');
237
+ console.log('\n' + chalk.green.bold('工作流安装完成!') + '\n');
238
+
239
+ // 显示安装摘要
240
+ console.log(chalk.white('安装摘要:'));
241
+ console.log(chalk.gray(` • 命令: ${commandCount} 个`));
242
+ console.log(chalk.gray(` • 提示词: ${promptCount} 个`));
243
+ console.log(chalk.gray(` • Agents: ${agentCount} 个`));
244
+ console.log(chalk.gray(` • 配置: ~/.claude/.ccg/config.toml`));
245
+ console.log('');
137
246
 
138
247
  // 询问是否配置 MCP
139
- const configMcp = await question('是否配置 ace-tool MCP?(推荐,提供代码上下文) (Y/n): ');
140
- if (configMcp.toLowerCase() !== 'n') {
248
+ const { configMcp } = await inquirer.prompt([
249
+ {
250
+ type: 'confirm',
251
+ name: 'configMcp',
252
+ message: '是否配置 ace-tool MCP?' + chalk.gray('(推荐,提供代码上下文)'),
253
+ default: true
254
+ }
255
+ ]);
256
+ if (configMcp) {
141
257
  await configureMCP();
142
258
  }
143
259
 
144
260
  // 询问是否配置 API
145
- const configApi = await question('\n是否配置 API 密钥? (Y/n): ');
146
- if (configApi.toLowerCase() !== 'n') {
261
+ const { configApi } = await inquirer.prompt([
262
+ {
263
+ type: 'confirm',
264
+ name: 'configApi',
265
+ message: '是否配置 API 密钥?',
266
+ default: false
267
+ }
268
+ ]);
269
+ if (configApi) {
147
270
  await configureApiKeys();
148
271
  }
149
272
 
150
- console.log('\n📖 使用方法:');
151
- console.log(' 在 Claude Code 中使用 /ccg:workflow <任务描述>');
152
- console.log(' 查看所有命令:/ccg:<Tab>');
153
- console.log('\n⚠️ 请重启终端或 Claude Code 使配置生效');
273
+ console.log('\n' + chalk.cyan('📖 使用方法:'));
274
+ console.log(chalk.white(' 在 Claude Code 中使用 /ccg:workflow <任务描述>'));
275
+ console.log(chalk.white(' 查看所有命令: /ccg:<Tab>'));
276
+ console.log('\n' + chalk.yellow('⚠️ 请重启 Claude Code 使配置生效'));
154
277
  }
155
278
 
156
- async function configureMCP() {
157
- console.log('\n🔧 配置 ace-tool MCP\n');
158
- console.log('ace-tool 是 Augment Code 的代码上下文引擎');
159
- console.log('它能让 AI 自动理解你的项目结构和代码\n');
279
+ // ==================== 创建 Agent 文件 ====================
160
280
 
161
- // 检查是否已安装 ace-tool
162
- let aceToolInstalled = false;
163
- try {
164
- execSync('which ace-tool', { stdio: 'ignore' });
165
- aceToolInstalled = true;
166
- console.log('✅ 检测到 ace-tool 已安装\n');
167
- } catch {
168
- console.log('⚠️ 未检测到 ace-tool\n');
281
+ function createAgentFiles() {
282
+ const agents = {
283
+ 'system-integrator.md': `---
284
+ description: '系统集成设计师 - ROS2 功能生成系统架构、节点交互和 Launch 配置设计'
285
+ ---
286
+
287
+ # System Integrator - ROS2 系统集成设计
288
+
289
+ ## 角色
290
+
291
+ 你是 ROS2 系统集成设计师,负责设计上层应用架构。
292
+
293
+ ## 职责
294
+
295
+ - 设计节点间通信架构
296
+ - 规划 Launch 文件结构
297
+ - 配置参数管理方案
298
+ - 设计 RViz 可视化配置
299
+
300
+ ## 输出格式
301
+
302
+ \`\`\`markdown
303
+ ## 系统集成设计
304
+
305
+ ### 节点架构
306
+ ### Launch 结构
307
+ ### 参数配置
308
+ ### 可视化配置
309
+ \`\`\`
310
+ `,
311
+ 'planner.md': `---
312
+ description: '任务规划师 - 使用 WBS 方法论分解功能需求为可执行任务'
313
+ ---
314
+
315
+ # Planner - 任务规划
316
+
317
+ ## 角色
318
+
319
+ 你是任务规划师,使用 WBS 方法分解需求。
320
+
321
+ ## 职责
322
+
323
+ - 分解功能需求为子任务
324
+ - 确定任务依赖关系
325
+ - 估算任务复杂度
326
+ - 生成实施计划
327
+
328
+ ## 输出格式
329
+
330
+ \`\`\`markdown
331
+ ## 实施计划
332
+
333
+ ### 任务分解
334
+ ### 依赖关系
335
+ ### 优先级排序
336
+ ### 验收标准
337
+ \`\`\`
338
+ `,
339
+ 'get-current-datetime.md': `---
340
+ description: '获取当前日期时间'
341
+ ---
342
+
343
+ # Get Current Datetime
344
+
345
+ 执行日期命令并返回当前时间。
346
+ `
347
+ };
348
+
349
+ for (const [filename, content] of Object.entries(agents)) {
350
+ fs.writeFileSync(path.join(AGENTS_DIR, filename), content);
351
+ }
352
+ }
353
+
354
+ // ==================== 更新功能 ====================
355
+
356
+ async function update() {
357
+ console.log('\n' + chalk.blue.bold('🔄 检查更新'));
358
+ console.log(chalk.gray('━'.repeat(40)) + '\n');
359
+
360
+ if (!isInstalled()) {
361
+ console.log(chalk.yellow('未检测到安装,请先安装工作流'));
362
+ return;
169
363
  }
170
364
 
171
- if (!aceToolInstalled) {
172
- console.log('安装 ace-tool 的方式:');
173
- console.log('1. 访问 https://augmentcode.com/ 注册账号');
174
- console.log('2. 按照官方指引安装 ace-tool CLI\n');
365
+ const installedVersion = getInstalledVersion() || '未知';
366
+ console.log(chalk.gray(`当前版本: v${installedVersion}`));
367
+ console.log(chalk.gray(`包版本: v${VERSION}`));
368
+
369
+ console.log(chalk.blue('→') + ' 检查 npm 最新版本...');
370
+ const latestVersion = await checkLatestVersion();
175
371
 
176
- const proceed = await question('是否继续配置 MCP?(可以稍后安装 ace-tool) (Y/n): ');
177
- if (proceed.toLowerCase() === 'n') {
372
+ if (latestVersion) {
373
+ console.log(chalk.gray(`最新版本: v${latestVersion}`));
374
+
375
+ if (latestVersion !== VERSION) {
376
+ console.log('\n' + chalk.yellow(`发现新版本 v${latestVersion}`));
377
+ console.log(chalk.gray('运行以下命令更新:'));
378
+ console.log(chalk.cyan(` npx ${PACKAGE_NAME}@latest`));
178
379
  return;
179
380
  }
180
381
  }
181
382
 
383
+ if (installedVersion === VERSION) {
384
+ console.log('\n' + chalk.green('✓ 已是最新版本'));
385
+
386
+ const { reinstall } = await inquirer.prompt([
387
+ {
388
+ type: 'confirm',
389
+ name: 'reinstall',
390
+ message: '是否重新安装工作流文件?',
391
+ default: false
392
+ }
393
+ ]);
394
+
395
+ if (reinstall) {
396
+ await install();
397
+ }
398
+ } else {
399
+ console.log('\n' + chalk.blue('→') + ' 更新工作流文件...');
400
+ await install();
401
+ }
402
+ }
403
+
404
+ // ==================== MCP 配置 ====================
405
+
406
+ async function configureMCP() {
407
+ console.log('\n' + chalk.cyan.bold('🔧 配置 ace-tool MCP'));
408
+ console.log(chalk.gray('━'.repeat(40)));
409
+ console.log(chalk.white('ace-tool 是 Augment Code 的代码上下文引擎'));
410
+ console.log(chalk.gray('它能让 AI 自动理解你的项目结构和代码') + '\n');
411
+
412
+ const { action } = await inquirer.prompt([
413
+ {
414
+ type: 'list',
415
+ name: 'action',
416
+ message: '请选择操作:',
417
+ choices: [
418
+ { name: chalk.green('安装/更新 ace-tool') + chalk.gray(' (Node.js 版本)'), value: 'ace-tool' },
419
+ { name: chalk.green('安装/更新 ace-tool-rs') + chalk.gray(' (Rust 版本,推荐)'), value: 'ace-tool-rs' },
420
+ { name: chalk.red('卸载 ace-tool MCP 配置'), value: 'uninstall' },
421
+ { name: chalk.gray('返回'), value: 'back' },
422
+ ]
423
+ }
424
+ ]);
425
+
426
+ if (action === 'back') return;
427
+
428
+ if (action === 'uninstall') {
429
+ await uninstallMCP();
430
+ return;
431
+ }
432
+
433
+ const pkg = action;
434
+ const pkgName = pkg === 'ace-tool-rs' ? 'ace-tool-rs (Rust)' : 'ace-tool (Node.js)';
435
+
436
+ console.log('\n' + chalk.blue(`📦 配置 ${pkgName}`) + '\n');
437
+
438
+ console.log(chalk.white('获取 Token 的方式:'));
439
+ console.log(chalk.gray(' • 官方服务: https://augmentcode.com/ 注册获取'));
440
+ console.log(chalk.gray(' • 中转服务: 使用第三方中转(需要 Base URL)') + '\n');
441
+
442
+ const { baseUrl, token } = await inquirer.prompt([
443
+ {
444
+ type: 'input',
445
+ name: 'baseUrl',
446
+ message: 'Base URL' + chalk.gray(' (使用官方服务请留空):'),
447
+ default: ''
448
+ },
449
+ {
450
+ type: 'password',
451
+ name: 'token',
452
+ message: 'Token' + chalk.red(' (必填):'),
453
+ mask: '*',
454
+ validate: input => input.trim() ? true : 'Token 不能为空'
455
+ }
456
+ ]);
457
+
458
+ // 构建 MCP 配置
459
+ const args = [pkg, 'mcp'];
460
+ if (baseUrl.trim()) {
461
+ args.push('--base-url', baseUrl.trim());
462
+ }
463
+ args.push('--token', token.trim());
464
+
465
+ const mcpServerConfig = {
466
+ command: 'npx',
467
+ args: args,
468
+ env: pkg === 'ace-tool-rs' ? { RUST_LOG: 'info' } : {}
469
+ };
470
+
182
471
  // 读取或创建 MCP 配置
183
472
  let mcpConfig = {};
184
473
  if (fs.existsSync(MCP_CONFIG_PATH)) {
185
474
  try {
186
475
  mcpConfig = JSON.parse(fs.readFileSync(MCP_CONFIG_PATH, 'utf8'));
187
- console.log('检测到已有 MCP 配置,将添加 ace-tool\n');
476
+
477
+ // 备份现有配置
478
+ const backupDir = path.join(CLAUDE_DIR, 'backup');
479
+ fs.mkdirSync(backupDir, { recursive: true });
480
+ const backupPath = path.join(backupDir, `mcp_servers_${Date.now()}.json`);
481
+ fs.writeFileSync(backupPath, JSON.stringify(mcpConfig, null, 2));
482
+ console.log(chalk.gray(`已备份配置到: ${backupPath}`));
188
483
  } catch {
189
484
  mcpConfig = {};
190
485
  }
191
486
  }
192
487
 
193
488
  // 添加 ace-tool 配置
194
- mcpConfig['ace-tool'] = {
195
- command: 'ace-tool',
196
- args: ['mcp'],
197
- env: {}
198
- };
489
+ mcpConfig['ace-tool'] = mcpServerConfig;
199
490
 
200
491
  // 写入配置
201
492
  fs.mkdirSync(CLAUDE_DIR, { recursive: true });
202
493
  fs.writeFileSync(MCP_CONFIG_PATH, JSON.stringify(mcpConfig, null, 2));
203
494
 
204
- console.log('✅ MCP 配置已写入: ~/.claude/mcp_servers.json\n');
205
- console.log('配置内容:');
206
- console.log(JSON.stringify(mcpConfig['ace-tool'], null, 2));
207
-
208
- console.log('\n📌 后续步骤:');
209
- console.log('1. 确保已安装 ace-tool CLI');
210
- console.log('2. 运行 ace-tool login 登录 Augment 账号');
211
- console.log('3. 重启 Claude Code 使 MCP 生效');
212
- console.log('\n使用方式:');
213
- console.log(' 在 workflow 中自动调用 mcp__ace-tool__search_context');
214
- console.log(' 或手动调用 mcp__ace-tool__enhance_prompt');
495
+ console.log('\n' + chalk.green.bold('✅ MCP 配置已写入') + '\n');
496
+ console.log(chalk.white('配置文件: ~/.claude/mcp_servers.json'));
497
+ console.log(chalk.gray('配置内容:'));
498
+ console.log(chalk.gray(JSON.stringify(mcpServerConfig, null, 2)));
499
+
500
+ console.log('\n' + chalk.cyan('📌 说明:'));
501
+ console.log(chalk.white(` • 使用 npx ${pkg} 自动下载运行`));
502
+ console.log(chalk.white(' 首次运行会自动下载包'));
503
+ console.log(chalk.white(' • 重启 Claude Code 使 MCP 生效'));
215
504
  }
216
505
 
217
- async function configureApiKeys() {
218
- console.log('\n🔑 配置 API 密钥\n');
506
+ async function uninstallMCP() {
507
+ if (!fs.existsSync(MCP_CONFIG_PATH)) {
508
+ console.log(chalk.yellow('未找到 MCP 配置文件'));
509
+ return;
510
+ }
219
511
 
220
- const geminiKey = await question('Gemini API Key (留空跳过): ');
221
- const geminiBaseUrl = await question('Gemini Base URL (留空使用官方): ');
222
- const codexKey = await question('Codex API Key (留空跳过): ');
512
+ const { confirm } = await inquirer.prompt([
513
+ {
514
+ type: 'confirm',
515
+ name: 'confirm',
516
+ message: chalk.red('确定要移除 ace-tool MCP 配置吗?'),
517
+ default: false
518
+ }
519
+ ]);
520
+
521
+ if (!confirm) {
522
+ console.log(chalk.gray('取消卸载'));
523
+ return;
524
+ }
525
+
526
+ try {
527
+ let mcpConfig = JSON.parse(fs.readFileSync(MCP_CONFIG_PATH, 'utf8'));
528
+
529
+ if (!mcpConfig['ace-tool']) {
530
+ console.log(chalk.yellow('MCP 配置中没有 ace-tool'));
531
+ return;
532
+ }
533
+
534
+ delete mcpConfig['ace-tool'];
535
+
536
+ if (Object.keys(mcpConfig).length === 0) {
537
+ fs.unlinkSync(MCP_CONFIG_PATH);
538
+ console.log(chalk.green('✅ 已删除: ~/.claude/mcp_servers.json'));
539
+ } else {
540
+ fs.writeFileSync(MCP_CONFIG_PATH, JSON.stringify(mcpConfig, null, 2));
541
+ console.log(chalk.green('✅ 已从 MCP 配置中移除 ace-tool'));
542
+ }
543
+ } catch (e) {
544
+ console.log(chalk.red('❌ 移除失败:'), e.message);
545
+ }
546
+ }
547
+
548
+ // ==================== API 密钥配置 ====================
549
+
550
+ async function configureApiKeys() {
551
+ console.log('\n' + chalk.magenta.bold('🔑 配置 API 密钥'));
552
+ console.log(chalk.gray('━'.repeat(40)) + '\n');
553
+
554
+ const { geminiKey, geminiBaseUrl, codexKey } = await inquirer.prompt([
555
+ {
556
+ type: 'password',
557
+ name: 'geminiKey',
558
+ message: 'Gemini API Key' + chalk.gray(' (留空跳过):'),
559
+ mask: '*'
560
+ },
561
+ {
562
+ type: 'input',
563
+ name: 'geminiBaseUrl',
564
+ message: 'Gemini Base URL' + chalk.gray(' (留空使用官方):'),
565
+ when: answers => answers.geminiKey
566
+ },
567
+ {
568
+ type: 'password',
569
+ name: 'codexKey',
570
+ message: 'Codex API Key' + chalk.gray(' (留空跳过):'),
571
+ mask: '*'
572
+ }
573
+ ]);
223
574
 
224
575
  // 检测 shell 配置文件
225
576
  const shellRc = fs.existsSync(path.join(process.env.HOME, '.zshrc'))
@@ -238,6 +589,7 @@ async function configureApiKeys() {
238
589
  }
239
590
  if (codexKey) {
240
591
  envVars.push(`export CODEX_API_KEY="${codexKey}"`);
592
+ envVars.push(`export OPENAI_API_KEY="${codexKey}"`);
241
593
  }
242
594
 
243
595
  if (envVars.length > 0) {
@@ -245,51 +597,129 @@ async function configureApiKeys() {
245
597
  if (!rcContent.includes(marker)) {
246
598
  rcContent += `\n${marker}\n${envVars.join('\n')}\n`;
247
599
  fs.writeFileSync(rcPath, rcContent);
248
- console.log(`\n 已添加到 ~/${shellRc}`);
249
- console.log(` 请运行: source ~/${shellRc}`);
600
+ console.log('\n' + chalk.green(`✅ 已添加到 ~/${shellRc}`));
601
+ console.log(chalk.yellow(` 请运行: source ~/${shellRc}`));
250
602
  } else {
251
- console.log(`\n⚠️ ~/${shellRc} 中已存在配置,请手动更新`);
603
+ console.log('\n' + chalk.yellow(`⚠️ ~/${shellRc} 中已存在配置,请手动更新`));
252
604
  }
605
+ } else {
606
+ console.log(chalk.gray('未配置任何密钥'));
253
607
  }
254
608
  }
255
609
 
610
+ // ==================== 帮助 ====================
611
+
612
+ function showHelp() {
613
+ console.log('\n' + chalk.yellow.bold('📖 帮助'));
614
+ console.log(chalk.gray('━'.repeat(40)) + '\n');
615
+
616
+ console.log(chalk.white.bold('可用命令:'));
617
+ console.log(chalk.cyan(' /ccg:workflow') + chalk.gray(' - 完整 7 阶段开发工作流'));
618
+ console.log(chalk.cyan(' /ccg:plan') + chalk.gray(' - 多模型协作规划'));
619
+ console.log(chalk.cyan(' /ccg:execute') + chalk.gray(' - 执行实施计划'));
620
+ console.log(chalk.cyan(' /ccg:feat') + chalk.gray(' - 智能功能开发'));
621
+ console.log(chalk.cyan(' /ccg:frontend') + chalk.gray(' - 上层应用开发 (Gemini 主导)'));
622
+ console.log(chalk.cyan(' /ccg:backend') + chalk.gray(' - 底层控制开发 (Codex 主导)'));
623
+ console.log(chalk.cyan(' /ccg:analyze') + chalk.gray(' - 多模型技术分析'));
624
+ console.log(chalk.cyan(' /ccg:review') + chalk.gray(' - 多模型代码审查'));
625
+ console.log(chalk.cyan(' /ccg:test') + chalk.gray(' - 测试生成'));
626
+ console.log(chalk.cyan(' /ccg:debug') + chalk.gray(' - 问题诊断'));
627
+ console.log(chalk.cyan(' /ccg:optimize') + chalk.gray(' - 性能优化'));
628
+ console.log(chalk.cyan(' /ccg:commit') + chalk.gray(' - 智能 Git 提交'));
629
+ console.log(chalk.cyan(' /ccg:rollback') + chalk.gray(' - Git 回滚'));
630
+
631
+ console.log('\n' + chalk.white.bold('智能路由:'));
632
+ console.log(chalk.gray(' • 控制算法、C++、硬件驱动 → Codex'));
633
+ console.log(chalk.gray(' • Launch、Python、RViz、配置 → Gemini'));
634
+
635
+ console.log('\n' + chalk.white.bold('更多信息:'));
636
+ console.log(chalk.gray(' https://github.com/GuYu-001/ccg-ros2-workflow'));
637
+ }
638
+
639
+ // ==================== 卸载功能 ====================
640
+
256
641
  async function uninstall() {
257
- console.log('\n🗑️ 卸载工作流...\n');
642
+ console.log('\n' + chalk.red.bold('🗑️ 卸载工作流'));
643
+ console.log(chalk.gray('━'.repeat(40)) + '\n');
258
644
 
259
- const confirm = await question('确定要卸载吗?这将删除所有配置文件 (y/N): ');
260
- if (confirm.toLowerCase() !== 'y') {
261
- console.log('取消卸载');
645
+ if (!isInstalled()) {
646
+ console.log(chalk.yellow('未检测到安装'));
647
+ return;
648
+ }
649
+
650
+ // 显示将要删除的内容
651
+ console.log(chalk.white('将要删除:'));
652
+
653
+ const commandCount = countFiles(COMMANDS_DIR);
654
+ const agentCount = countFiles(AGENTS_DIR);
655
+ const promptCount = fs.existsSync(path.join(CCG_DIR, 'prompts'))
656
+ ? countFiles(path.join(CCG_DIR, 'prompts', 'codex')) +
657
+ countFiles(path.join(CCG_DIR, 'prompts', 'gemini')) +
658
+ countFiles(path.join(CCG_DIR, 'prompts', 'claude'))
659
+ : 0;
660
+
661
+ console.log(chalk.gray(` • ${commandCount} 个命令文件`));
662
+ console.log(chalk.gray(` • ${agentCount} 个 agent 文件`));
663
+ console.log(chalk.gray(` • ${promptCount} 个提示词文件`));
664
+ console.log(chalk.gray(` • 配置文件`));
665
+ console.log(chalk.gray(` • codeagent-wrapper`));
666
+ console.log('');
667
+
668
+ const { confirm } = await inquirer.prompt([
669
+ {
670
+ type: 'confirm',
671
+ name: 'confirm',
672
+ message: chalk.red('确定要卸载吗?这将删除所有配置文件'),
673
+ default: false
674
+ }
675
+ ]);
676
+
677
+ if (!confirm) {
678
+ console.log(chalk.gray('取消卸载'));
262
679
  return;
263
680
  }
264
681
 
265
682
  // 删除目录
266
- [CCG_DIR, COMMANDS_DIR].forEach(dir => {
683
+ const dirsToDelete = [CCG_DIR, COMMANDS_DIR, AGENTS_DIR];
684
+ let deletedCount = 0;
685
+
686
+ for (const dir of dirsToDelete) {
267
687
  if (fs.existsSync(dir)) {
268
688
  fs.rmSync(dir, { recursive: true });
269
- console.log(`已删除: ${dir}`);
689
+ console.log(chalk.gray(`已删除: ${dir}`));
690
+ deletedCount++;
270
691
  }
271
- });
692
+ }
272
693
 
273
694
  // 删除 codeagent-wrapper
274
695
  const wrapperPath = path.join(BIN_DIR, 'codeagent-wrapper');
275
696
  if (fs.existsSync(wrapperPath)) {
276
697
  fs.unlinkSync(wrapperPath);
277
- console.log(`已删除: ${wrapperPath}`);
698
+ console.log(chalk.gray(`已删除: ${wrapperPath}`));
699
+ deletedCount++;
278
700
  }
279
701
 
280
702
  // 询问是否删除 MCP 配置
281
703
  if (fs.existsSync(MCP_CONFIG_PATH)) {
282
- const removeMcp = await question('是否删除 MCP 配置? (y/N): ');
283
- if (removeMcp.toLowerCase() === 'y') {
704
+ const { removeMcp } = await inquirer.prompt([
705
+ {
706
+ type: 'confirm',
707
+ name: 'removeMcp',
708
+ message: '是否同时删除 ace-tool MCP 配置?',
709
+ default: false
710
+ }
711
+ ]);
712
+
713
+ if (removeMcp) {
284
714
  try {
285
715
  let mcpConfig = JSON.parse(fs.readFileSync(MCP_CONFIG_PATH, 'utf8'));
286
716
  delete mcpConfig['ace-tool'];
287
717
  if (Object.keys(mcpConfig).length === 0) {
288
718
  fs.unlinkSync(MCP_CONFIG_PATH);
289
- console.log('已删除: ~/.claude/mcp_servers.json');
719
+ console.log(chalk.gray('已删除: ~/.claude/mcp_servers.json'));
290
720
  } else {
291
721
  fs.writeFileSync(MCP_CONFIG_PATH, JSON.stringify(mcpConfig, null, 2));
292
- console.log('已从 MCP 配置中移除 ace-tool');
722
+ console.log(chalk.gray('已从 MCP 配置中移除 ace-tool'));
293
723
  }
294
724
  } catch {
295
725
  // ignore
@@ -297,8 +727,18 @@ async function uninstall() {
297
727
  }
298
728
  }
299
729
 
300
- console.log('\n✅ 卸载完成');
301
- console.log('注意: 环境变量需要手动从 ~/.zshrc 或 ~/.bashrc 中删除');
730
+ console.log('\n' + chalk.green.bold('✅ 卸载完成'));
731
+ console.log(chalk.yellow('注意: 环境变量需要手动从 ~/.zshrc 或 ~/.bashrc 中删除'));
302
732
  }
303
733
 
304
- main().catch(console.error);
734
+ // ==================== 主程序 ====================
735
+
736
+ async function main() {
737
+ await loadDependencies();
738
+ await showMainMenu();
739
+ }
740
+
741
+ main().catch(err => {
742
+ console.error(chalk.red('错误:'), err.message);
743
+ process.exit(1);
744
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccg-ros2-workflow",
3
- "version": "1.0.9",
3
+ "version": "1.2.0",
4
4
  "description": "ROS2 Multi-model Collaborative Development Workflow - Codex (Low-level) + Gemini (High-level) + Claude (Orchestration)",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -31,5 +31,9 @@
31
31
  "files": [
32
32
  "bin/",
33
33
  "src/"
34
- ]
34
+ ],
35
+ "dependencies": {
36
+ "inquirer": "^8.2.6",
37
+ "chalk": "^4.1.2"
38
+ }
35
39
  }