ccg-ros2-workflow 1.4.0 → 2.1.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.
- package/LICENSE +21 -0
- package/README.md +128 -241
- package/bin/ccg.mjs +2 -0
- package/bin/codeagent-wrapper-darwin-amd64 +0 -0
- package/bin/codeagent-wrapper-darwin-arm64 +0 -0
- package/bin/codeagent-wrapper-linux-amd64 +0 -0
- package/bin/codeagent-wrapper-linux-arm64 +0 -0
- package/bin/codeagent-wrapper-windows-amd64.exe +0 -0
- package/bin/codeagent-wrapper-windows-arm64.exe +0 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +173 -0
- package/dist/index.d.mts +229 -0
- package/dist/index.d.ts +229 -0
- package/dist/index.mjs +12 -0
- package/dist/shared/ccg-ros2-workflow.CpLJvcLP.mjs +2274 -0
- package/package.json +85 -22
- package/templates/commands/agents/planner.md +345 -0
- package/templates/commands/agents/system-integrator.md +397 -0
- package/{src/commands/ccg → templates/commands}/analyze.md +17 -17
- package/{src/commands/ccg → templates/commands}/backend.md +25 -25
- package/{src/commands/ccg → templates/commands}/debug.md +12 -12
- package/{src/commands/ccg → templates/commands}/execute.md +24 -23
- package/{src/commands/ccg → templates/commands}/feat.md +21 -21
- package/{src/commands/ccg → templates/commands}/frontend.md +26 -26
- package/{src/commands/ccg → templates/commands}/optimize.md +24 -24
- package/{src/commands/ccg → templates/commands}/plan.md +20 -19
- package/{src/commands/ccg → templates/commands}/review.md +9 -9
- package/templates/commands/spec-impl.md +123 -0
- package/templates/commands/spec-init.md +91 -0
- package/templates/commands/spec-plan.md +109 -0
- package/templates/commands/spec-research.md +104 -0
- package/templates/commands/spec-review.md +120 -0
- package/{src/commands/ccg → templates/commands}/test.md +23 -23
- package/templates/commands/workflow.md +193 -0
- package/{src/commands/ccg → templates/commands}/worktree.md +8 -8
- package/templates/prompts/claude/analyzer.md +59 -0
- package/templates/prompts/claude/architect.md +54 -0
- package/templates/prompts/claude/debugger.md +71 -0
- package/templates/prompts/claude/optimizer.md +73 -0
- package/templates/prompts/claude/reviewer.md +63 -0
- package/templates/prompts/claude/tester.md +69 -0
- package/templates/prompts/codex/analyzer.md +50 -0
- package/templates/prompts/codex/architect.md +46 -0
- package/templates/prompts/codex/debugger.md +66 -0
- package/templates/prompts/codex/optimizer.md +74 -0
- package/templates/prompts/codex/reviewer.md +66 -0
- package/templates/prompts/codex/tester.md +55 -0
- package/templates/prompts/gemini/analyzer.md +53 -0
- package/templates/prompts/gemini/architect.md +47 -0
- package/templates/prompts/gemini/debugger.md +70 -0
- package/templates/prompts/gemini/frontend.md +56 -0
- package/templates/prompts/gemini/optimizer.md +77 -0
- package/templates/prompts/gemini/reviewer.md +73 -0
- package/templates/prompts/gemini/tester.md +61 -0
- package/bin/cli.js +0 -903
- package/src/agents/ccg/planner.md +0 -358
- package/src/agents/ccg/system-integrator.md +0 -627
- package/src/codeagent-wrapper.sh +0 -86
- package/src/commands/ccg/workflow.md +0 -212
- package/src/config.toml +0 -36
- package/src/prompts/claude/analyzer.md +0 -25
- package/src/prompts/claude/architect.md +0 -25
- package/src/prompts/claude/debugger.md +0 -24
- package/src/prompts/claude/optimizer.md +0 -25
- package/src/prompts/claude/reviewer.md +0 -26
- package/src/prompts/claude/tester.md +0 -24
- package/src/prompts/codex/analyzer.md +0 -32
- package/src/prompts/codex/architect.md +0 -42
- package/src/prompts/codex/debugger.md +0 -24
- package/src/prompts/codex/optimizer.md +0 -25
- package/src/prompts/codex/reviewer.md +0 -32
- package/src/prompts/codex/tester.md +0 -24
- package/src/prompts/gemini/analyzer.md +0 -32
- package/src/prompts/gemini/architect.md +0 -34
- package/src/prompts/gemini/debugger.md +0 -24
- package/src/prompts/gemini/frontend.md +0 -25
- package/src/prompts/gemini/optimizer.md +0 -25
- package/src/prompts/gemini/reviewer.md +0 -32
- package/src/prompts/gemini/tester.md +0 -24
- /package/{src/agents/ccg → templates/commands/agents}/get-current-datetime.md +0 -0
- /package/{src/agents/ccg → templates/commands/agents}/init-architect.md +0 -0
- /package/{src/commands/ccg → templates/commands}/clean-branches.md +0 -0
- /package/{src/commands/ccg → templates/commands}/commit.md +0 -0
- /package/{src/commands/ccg → templates/commands}/enhance.md +0 -0
- /package/{src/commands/ccg → templates/commands}/init.md +0 -0
- /package/{src/commands/ccg → templates/commands}/rollback.md +0 -0
|
@@ -0,0 +1,2274 @@
|
|
|
1
|
+
import ansis from 'ansis';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import { exec } from 'node:child_process';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { join, dirname } from 'pathe';
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import i18next from 'i18next';
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
import { parse, stringify } from 'smol-toml';
|
|
12
|
+
|
|
13
|
+
const version = "2.1.0";
|
|
14
|
+
|
|
15
|
+
function isWindows() {
|
|
16
|
+
return process.platform === "win32";
|
|
17
|
+
}
|
|
18
|
+
function getMcpCommand(command) {
|
|
19
|
+
const needsWrapping = ["npx", "uvx", "node", "npm", "pnpm", "yarn"];
|
|
20
|
+
if (isWindows() && needsWrapping.includes(command)) {
|
|
21
|
+
return ["cmd", "/c", command];
|
|
22
|
+
}
|
|
23
|
+
return [command];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getClaudeCodeConfigPath() {
|
|
27
|
+
return join(homedir(), ".claude.json");
|
|
28
|
+
}
|
|
29
|
+
async function readClaudeCodeConfig() {
|
|
30
|
+
const configPath = getClaudeCodeConfigPath();
|
|
31
|
+
try {
|
|
32
|
+
if (!await fs.pathExists(configPath)) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const content = await fs.readFile(configPath, "utf-8");
|
|
36
|
+
return JSON.parse(content);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error("Failed to read Claude Code config:", error);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function writeClaudeCodeConfig(config) {
|
|
43
|
+
const configPath = getClaudeCodeConfigPath();
|
|
44
|
+
try {
|
|
45
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new Error(`Failed to write Claude Code config: ${error}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function applyPlatformCommand(config) {
|
|
51
|
+
if (isWindows() && config.command) {
|
|
52
|
+
if (config.command === "cmd") {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const mcpCmd = getMcpCommand(config.command);
|
|
56
|
+
if (mcpCmd[0] === "cmd") {
|
|
57
|
+
const originalArgs = config.args || [];
|
|
58
|
+
config.command = mcpCmd[0];
|
|
59
|
+
config.args = [...mcpCmd.slice(1), ...originalArgs];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function buildMcpServerConfig(baseConfig, apiKey, placeholder = "YOUR_API_KEY", envVarName) {
|
|
64
|
+
const config = JSON.parse(JSON.stringify(baseConfig));
|
|
65
|
+
applyPlatformCommand(config);
|
|
66
|
+
{
|
|
67
|
+
return config;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function repairCorruptedMcpArgs(config) {
|
|
71
|
+
if (!isWindows() || config.command !== "cmd" || !config.args) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const args = config.args;
|
|
75
|
+
let repaired = false;
|
|
76
|
+
if (args[0] === "cmd") {
|
|
77
|
+
args.shift();
|
|
78
|
+
repaired = true;
|
|
79
|
+
}
|
|
80
|
+
if (args[0] !== "/c") {
|
|
81
|
+
return repaired;
|
|
82
|
+
}
|
|
83
|
+
if (args.length >= 3 && args[1] === args[2]) {
|
|
84
|
+
args.splice(2, 1);
|
|
85
|
+
repaired = true;
|
|
86
|
+
}
|
|
87
|
+
return repaired;
|
|
88
|
+
}
|
|
89
|
+
function fixWindowsMcpConfig(config) {
|
|
90
|
+
if (!isWindows() || !config.mcpServers) {
|
|
91
|
+
return config;
|
|
92
|
+
}
|
|
93
|
+
const fixed = JSON.parse(JSON.stringify(config));
|
|
94
|
+
for (const [serverName, serverConfig] of Object.entries(fixed.mcpServers || {})) {
|
|
95
|
+
if (serverConfig && typeof serverConfig === "object" && "command" in serverConfig) {
|
|
96
|
+
const mcpConfig = serverConfig;
|
|
97
|
+
repairCorruptedMcpArgs(mcpConfig);
|
|
98
|
+
applyPlatformCommand(mcpConfig);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return fixed;
|
|
102
|
+
}
|
|
103
|
+
function mergeMcpServers(existing, newServers) {
|
|
104
|
+
const config = existing || { mcpServers: {} };
|
|
105
|
+
if (!config.mcpServers) {
|
|
106
|
+
config.mcpServers = {};
|
|
107
|
+
}
|
|
108
|
+
Object.assign(config.mcpServers, newServers);
|
|
109
|
+
return config;
|
|
110
|
+
}
|
|
111
|
+
async function backupClaudeCodeConfig() {
|
|
112
|
+
const configPath = getClaudeCodeConfigPath();
|
|
113
|
+
try {
|
|
114
|
+
if (!await fs.pathExists(configPath)) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
const backupDir = join(homedir(), ".claude", "backup");
|
|
118
|
+
await fs.ensureDir(backupDir);
|
|
119
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
120
|
+
const backupPath = join(backupDir, `claude-config-${timestamp}.json`);
|
|
121
|
+
await fs.copy(configPath, backupPath);
|
|
122
|
+
return backupPath;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error("Failed to backup Claude Code config:", error);
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async function diagnoseMcpConfig() {
|
|
129
|
+
const issues = [];
|
|
130
|
+
const configPath = getClaudeCodeConfigPath();
|
|
131
|
+
if (!await fs.pathExists(configPath)) {
|
|
132
|
+
issues.push("\u274C ~/.claude.json does not exist");
|
|
133
|
+
return issues;
|
|
134
|
+
}
|
|
135
|
+
const config = await readClaudeCodeConfig();
|
|
136
|
+
if (!config) {
|
|
137
|
+
issues.push("\u274C Failed to parse ~/.claude.json");
|
|
138
|
+
return issues;
|
|
139
|
+
}
|
|
140
|
+
if (!config.mcpServers || Object.keys(config.mcpServers).length === 0) {
|
|
141
|
+
issues.push("\u26A0\uFE0F No MCP servers configured");
|
|
142
|
+
return issues;
|
|
143
|
+
}
|
|
144
|
+
if (isWindows()) {
|
|
145
|
+
for (const [name, server] of Object.entries(config.mcpServers)) {
|
|
146
|
+
if (server.command && ["npx", "uvx", "node"].includes(server.command)) {
|
|
147
|
+
if (server.command !== "cmd") {
|
|
148
|
+
issues.push(`\u274C ${name}: Command not properly wrapped for Windows (should use cmd /c)`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (issues.length === 0) {
|
|
154
|
+
issues.push("\u2705 MCP configuration looks good");
|
|
155
|
+
}
|
|
156
|
+
return issues;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const __filename$2 = fileURLToPath(import.meta.url);
|
|
160
|
+
const __dirname$2 = dirname(__filename$2);
|
|
161
|
+
function findPackageRoot$1(startDir) {
|
|
162
|
+
let dir = startDir;
|
|
163
|
+
for (let i = 0; i < 5; i++) {
|
|
164
|
+
if (fs.existsSync(join(dir, "package.json"))) {
|
|
165
|
+
return dir;
|
|
166
|
+
}
|
|
167
|
+
dir = dirname(dir);
|
|
168
|
+
}
|
|
169
|
+
return startDir;
|
|
170
|
+
}
|
|
171
|
+
const PACKAGE_ROOT$1 = findPackageRoot$1(__dirname$2);
|
|
172
|
+
const WORKFLOW_CONFIGS = [
|
|
173
|
+
{
|
|
174
|
+
id: "workflow",
|
|
175
|
+
name: "\u5B8C\u6574\u5F00\u53D1\u5DE5\u4F5C\u6D41",
|
|
176
|
+
nameEn: "Full Development Workflow",
|
|
177
|
+
category: "development",
|
|
178
|
+
commands: ["workflow"],
|
|
179
|
+
defaultSelected: true,
|
|
180
|
+
order: 1,
|
|
181
|
+
description: "\u5B8C\u65747\u9636\u6BB5ROS2\u5F00\u53D1\u5DE5\u4F5C\u6D41\uFF08\u7814\u7A76\u2192\u6784\u601D\u2192\u8BA1\u5212\u2192\u6267\u884C\u2192\u4F18\u5316\u2192\u8BC4\u5BA1\u2192\u90E8\u7F72\uFF09",
|
|
182
|
+
descriptionEn: "Full 7-phase ROS2 development workflow"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: "plan",
|
|
186
|
+
name: "\u591A\u6A21\u578B\u534F\u4F5C\u89C4\u5212",
|
|
187
|
+
nameEn: "Multi-Model Planning",
|
|
188
|
+
category: "development",
|
|
189
|
+
commands: ["plan"],
|
|
190
|
+
defaultSelected: true,
|
|
191
|
+
order: 1.5,
|
|
192
|
+
description: "\u4E0A\u4E0B\u6587\u68C0\u7D22 + \u53CC\u6A21\u578B\u5206\u6790 \u2192 \u751F\u6210 Step-by-step \u5B9E\u65BD\u8BA1\u5212",
|
|
193
|
+
descriptionEn: "Context retrieval + dual-model analysis \u2192 Step-by-step plan"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: "execute",
|
|
197
|
+
name: "\u591A\u6A21\u578B\u534F\u4F5C\u6267\u884C",
|
|
198
|
+
nameEn: "Multi-Model Execution",
|
|
199
|
+
category: "development",
|
|
200
|
+
commands: ["execute"],
|
|
201
|
+
defaultSelected: true,
|
|
202
|
+
order: 1.6,
|
|
203
|
+
description: "\u6839\u636E\u8BA1\u5212\u83B7\u53D6\u539F\u578B \u2192 Claude \u91CD\u6784\u5B9E\u65BD \u2192 \u591A\u6A21\u578B\u5BA1\u8BA1\u4EA4\u4ED8",
|
|
204
|
+
descriptionEn: "Get prototype from plan \u2192 Claude refactor \u2192 Multi-model audit"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
id: "frontend",
|
|
208
|
+
name: "\u4E0A\u5C42\u5E94\u7528\u4E13\u9879",
|
|
209
|
+
nameEn: "Upper-layer Application Tasks",
|
|
210
|
+
category: "development",
|
|
211
|
+
commands: ["frontend"],
|
|
212
|
+
defaultSelected: true,
|
|
213
|
+
order: 2,
|
|
214
|
+
description: "\u4E0A\u5C42\u5E94\u7528\u4E13\u9879\uFF08Gemini\u4E3B\u5BFC\uFF1ALaunch/Python/\u914D\u7F6E/RViz\uFF09",
|
|
215
|
+
descriptionEn: "Upper-layer application tasks (Gemini-led: Launch/Python/Config/RViz)"
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
id: "backend",
|
|
219
|
+
name: "\u5E95\u5C42\u63A7\u5236\u4E13\u9879",
|
|
220
|
+
nameEn: "Low-level Control Tasks",
|
|
221
|
+
category: "development",
|
|
222
|
+
commands: ["backend"],
|
|
223
|
+
defaultSelected: true,
|
|
224
|
+
order: 3,
|
|
225
|
+
description: "\u5E95\u5C42\u63A7\u5236\u4E13\u9879\uFF08Codex\u4E3B\u5BFC\uFF1AC++/\u786C\u4EF6\u9A71\u52A8/\u5B9E\u65F6\u63A7\u5236\uFF09",
|
|
226
|
+
descriptionEn: "Low-level control tasks (Codex-led: C++/Hardware/Realtime)"
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
id: "feat",
|
|
230
|
+
name: "\u667A\u80FD\u529F\u80FD\u5F00\u53D1",
|
|
231
|
+
nameEn: "Smart Feature Development",
|
|
232
|
+
category: "development",
|
|
233
|
+
commands: ["feat"],
|
|
234
|
+
defaultSelected: true,
|
|
235
|
+
order: 4,
|
|
236
|
+
description: "\u667A\u80FD\u529F\u80FD\u5F00\u53D1 - \u81EA\u52A8\u89C4\u5212\u3001\u8BBE\u8BA1\u3001\u5B9E\u65BD",
|
|
237
|
+
descriptionEn: "Smart feature development - auto plan, design, implement"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
id: "analyze",
|
|
241
|
+
name: "\u6280\u672F\u5206\u6790",
|
|
242
|
+
nameEn: "Technical Analysis",
|
|
243
|
+
category: "development",
|
|
244
|
+
commands: ["analyze"],
|
|
245
|
+
defaultSelected: true,
|
|
246
|
+
order: 5,
|
|
247
|
+
description: "\u53CC\u6A21\u578B\u6280\u672F\u5206\u6790\uFF0C\u4EC5\u5206\u6790\u4E0D\u4FEE\u6539\u4EE3\u7801",
|
|
248
|
+
descriptionEn: "Dual-model technical analysis, analysis only"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
id: "debug",
|
|
252
|
+
name: "\u95EE\u9898\u8BCA\u65AD",
|
|
253
|
+
nameEn: "Debug",
|
|
254
|
+
category: "development",
|
|
255
|
+
commands: ["debug"],
|
|
256
|
+
defaultSelected: true,
|
|
257
|
+
order: 6,
|
|
258
|
+
description: "\u591A\u6A21\u578B\u8BCA\u65AD + \u4FEE\u590D",
|
|
259
|
+
descriptionEn: "Multi-model diagnosis + fix"
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
id: "optimize",
|
|
263
|
+
name: "\u6027\u80FD\u4F18\u5316",
|
|
264
|
+
nameEn: "Performance Optimization",
|
|
265
|
+
category: "development",
|
|
266
|
+
commands: ["optimize"],
|
|
267
|
+
defaultSelected: true,
|
|
268
|
+
order: 7,
|
|
269
|
+
description: "\u591A\u6A21\u578B\u6027\u80FD\u4F18\u5316",
|
|
270
|
+
descriptionEn: "Multi-model performance optimization"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
id: "test",
|
|
274
|
+
name: "\u6D4B\u8BD5\u751F\u6210",
|
|
275
|
+
nameEn: "Test Generation",
|
|
276
|
+
category: "development",
|
|
277
|
+
commands: ["test"],
|
|
278
|
+
defaultSelected: true,
|
|
279
|
+
order: 8,
|
|
280
|
+
description: "\u667A\u80FD\u8DEF\u7531\u6D4B\u8BD5\u751F\u6210",
|
|
281
|
+
descriptionEn: "Smart routing test generation"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: "review",
|
|
285
|
+
name: "\u4EE3\u7801\u5BA1\u67E5",
|
|
286
|
+
nameEn: "Code Review",
|
|
287
|
+
category: "development",
|
|
288
|
+
commands: ["review"],
|
|
289
|
+
defaultSelected: true,
|
|
290
|
+
order: 9,
|
|
291
|
+
description: "\u53CC\u6A21\u578B\u4EE3\u7801\u5BA1\u67E5\uFF0C\u65E0\u53C2\u6570\u65F6\u81EA\u52A8\u5BA1\u67E5 git diff",
|
|
292
|
+
descriptionEn: "Dual-model code review, auto-review git diff when no args"
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
id: "enhance",
|
|
296
|
+
name: "Prompt \u589E\u5F3A",
|
|
297
|
+
nameEn: "Prompt Enhancement",
|
|
298
|
+
category: "development",
|
|
299
|
+
commands: ["enhance"],
|
|
300
|
+
defaultSelected: true,
|
|
301
|
+
order: 9.5,
|
|
302
|
+
description: "ace-tool Prompt \u589E\u5F3A\u5DE5\u5177",
|
|
303
|
+
descriptionEn: "ace-tool prompt enhancement"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
id: "init-project",
|
|
307
|
+
name: "\u9879\u76EE\u521D\u59CB\u5316",
|
|
308
|
+
nameEn: "Project Init",
|
|
309
|
+
category: "init",
|
|
310
|
+
commands: ["init"],
|
|
311
|
+
defaultSelected: true,
|
|
312
|
+
order: 10,
|
|
313
|
+
description: "\u521D\u59CB\u5316\u9879\u76EE AI \u4E0A\u4E0B\u6587\uFF0C\u751F\u6210 CLAUDE.md",
|
|
314
|
+
descriptionEn: "Initialize project AI context, generate CLAUDE.md"
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
id: "commit",
|
|
318
|
+
name: "Git \u63D0\u4EA4",
|
|
319
|
+
nameEn: "Git Commit",
|
|
320
|
+
category: "git",
|
|
321
|
+
commands: ["commit"],
|
|
322
|
+
defaultSelected: true,
|
|
323
|
+
order: 20,
|
|
324
|
+
description: "\u667A\u80FD\u751F\u6210 conventional commit \u4FE1\u606F",
|
|
325
|
+
descriptionEn: "Smart conventional commit message generation"
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
id: "rollback",
|
|
329
|
+
name: "Git \u56DE\u6EDA",
|
|
330
|
+
nameEn: "Git Rollback",
|
|
331
|
+
category: "git",
|
|
332
|
+
commands: ["rollback"],
|
|
333
|
+
defaultSelected: true,
|
|
334
|
+
order: 21,
|
|
335
|
+
description: "\u4EA4\u4E92\u5F0F\u56DE\u6EDA\u5206\u652F\u5230\u5386\u53F2\u7248\u672C",
|
|
336
|
+
descriptionEn: "Interactive rollback to historical version"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
id: "clean-branches",
|
|
340
|
+
name: "Git \u6E05\u7406\u5206\u652F",
|
|
341
|
+
nameEn: "Git Clean Branches",
|
|
342
|
+
category: "git",
|
|
343
|
+
commands: ["clean-branches"],
|
|
344
|
+
defaultSelected: true,
|
|
345
|
+
order: 22,
|
|
346
|
+
description: "\u5B89\u5168\u6E05\u7406\u5DF2\u5408\u5E76\u6216\u8FC7\u671F\u5206\u652F",
|
|
347
|
+
descriptionEn: "Safely clean merged or stale branches"
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
id: "worktree",
|
|
351
|
+
name: "Git Worktree",
|
|
352
|
+
nameEn: "Git Worktree",
|
|
353
|
+
category: "git",
|
|
354
|
+
commands: ["worktree"],
|
|
355
|
+
defaultSelected: true,
|
|
356
|
+
order: 23,
|
|
357
|
+
description: "\u7BA1\u7406 Git worktree",
|
|
358
|
+
descriptionEn: "Manage Git worktree"
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
id: "spec-init",
|
|
362
|
+
name: "OpenSpec \u521D\u59CB\u5316",
|
|
363
|
+
nameEn: "OpenSpec Init",
|
|
364
|
+
category: "spec",
|
|
365
|
+
commands: ["spec-init"],
|
|
366
|
+
defaultSelected: true,
|
|
367
|
+
order: 30,
|
|
368
|
+
description: "\u521D\u59CB\u5316 OpenSpec \u73AF\u5883 + \u9A8C\u8BC1\u591A\u6A21\u578B MCP \u5DE5\u5177",
|
|
369
|
+
descriptionEn: "Initialize OpenSpec environment with multi-model MCP validation"
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
id: "spec-research",
|
|
373
|
+
name: "\u9700\u6C42\u7814\u7A76",
|
|
374
|
+
nameEn: "Spec Research",
|
|
375
|
+
category: "spec",
|
|
376
|
+
commands: ["spec-research"],
|
|
377
|
+
defaultSelected: true,
|
|
378
|
+
order: 31,
|
|
379
|
+
description: "\u9700\u6C42 \u2192 \u7EA6\u675F\u96C6\uFF08\u5E76\u884C\u63A2\u7D22 + OpenSpec \u63D0\u6848\uFF09",
|
|
380
|
+
descriptionEn: "Transform requirements into constraint sets via parallel exploration"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
id: "spec-plan",
|
|
384
|
+
name: "\u96F6\u51B3\u7B56\u89C4\u5212",
|
|
385
|
+
nameEn: "Spec Plan",
|
|
386
|
+
category: "spec",
|
|
387
|
+
commands: ["spec-plan"],
|
|
388
|
+
defaultSelected: true,
|
|
389
|
+
order: 32,
|
|
390
|
+
description: "\u591A\u6A21\u578B\u5206\u6790 \u2192 \u6D88\u9664\u6B67\u4E49 \u2192 \u96F6\u51B3\u7B56\u53EF\u6267\u884C\u8BA1\u5212",
|
|
391
|
+
descriptionEn: "Refine proposals into zero-decision executable plans"
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
id: "spec-impl",
|
|
395
|
+
name: "\u89C4\u8303\u9A71\u52A8\u5B9E\u73B0",
|
|
396
|
+
nameEn: "Spec Implementation",
|
|
397
|
+
category: "spec",
|
|
398
|
+
commands: ["spec-impl"],
|
|
399
|
+
defaultSelected: true,
|
|
400
|
+
order: 33,
|
|
401
|
+
description: "\u6309\u89C4\u8303\u6267\u884C + \u591A\u6A21\u578B\u534F\u4F5C + \u5F52\u6863",
|
|
402
|
+
descriptionEn: "Execute changes via multi-model collaboration with spec compliance"
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
id: "spec-review",
|
|
406
|
+
name: "\u5F52\u6863\u524D\u5BA1\u67E5",
|
|
407
|
+
nameEn: "Spec Review",
|
|
408
|
+
category: "spec",
|
|
409
|
+
commands: ["spec-review"],
|
|
410
|
+
defaultSelected: true,
|
|
411
|
+
order: 34,
|
|
412
|
+
description: "\u53CC\u6A21\u578B\u4EA4\u53C9\u5BA1\u67E5 \u2192 Critical \u5FC5\u987B\u4FEE\u590D \u2192 \u5141\u8BB8\u5F52\u6863",
|
|
413
|
+
descriptionEn: "Multi-model compliance review before archiving"
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
id: "team-research",
|
|
417
|
+
name: "Teams \u9700\u6C42\u7814\u7A76",
|
|
418
|
+
nameEn: "Agent Teams Research",
|
|
419
|
+
category: "team",
|
|
420
|
+
commands: ["team-research"],
|
|
421
|
+
defaultSelected: true,
|
|
422
|
+
order: 40,
|
|
423
|
+
description: "\u5E76\u884C\u63A2\u7D22\u4EE3\u7801\u5E93\uFF0C\u4EA7\u51FA\u7EA6\u675F\u96C6\uFF08Codex\u5E95\u5C42 + Gemini\u4E0A\u5C42\u540C\u65F6\u8FD0\u884C\uFF09",
|
|
424
|
+
descriptionEn: "Parallel codebase exploration, output constraint sets (Codex + Gemini)"
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
id: "team-plan",
|
|
428
|
+
name: "Teams \u96F6\u51B3\u7B56\u89C4\u5212",
|
|
429
|
+
nameEn: "Agent Teams Plan",
|
|
430
|
+
category: "team",
|
|
431
|
+
commands: ["team-plan"],
|
|
432
|
+
defaultSelected: true,
|
|
433
|
+
order: 41,
|
|
434
|
+
description: "\u53CC\u6A21\u578B\u5E76\u884C\u5206\u6790\uFF0C\u4EA7\u51FA Builder \u53EF\u673A\u68B0\u6267\u884C\u7684\u8BE6\u7EC6\u8BA1\u5212",
|
|
435
|
+
descriptionEn: "Dual-model parallel analysis, output zero-decision execution plan"
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
id: "team-exec",
|
|
439
|
+
name: "Teams \u5E76\u884C\u5B9E\u65BD",
|
|
440
|
+
nameEn: "Agent Teams Exec",
|
|
441
|
+
category: "team",
|
|
442
|
+
commands: ["team-exec"],
|
|
443
|
+
defaultSelected: true,
|
|
444
|
+
order: 42,
|
|
445
|
+
description: "\u8BFB\u53D6\u8BA1\u5212\u6587\u4EF6\uFF0Cspawn Builder teammates \u5E76\u884C\u5199\u4EE3\u7801\uFF08\u9700\u542F\u7528 Agent Teams\uFF09",
|
|
446
|
+
descriptionEn: "Read plan file, spawn Builder teammates for parallel implementation"
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
id: "team-review",
|
|
450
|
+
name: "Teams \u4EA4\u53C9\u5BA1\u67E5",
|
|
451
|
+
nameEn: "Agent Teams Review",
|
|
452
|
+
category: "team",
|
|
453
|
+
commands: ["team-review"],
|
|
454
|
+
defaultSelected: true,
|
|
455
|
+
order: 43,
|
|
456
|
+
description: "\u53CC\u6A21\u578B\u4EA4\u53C9\u5BA1\u67E5\u5E76\u884C\u5B9E\u65BD\u4EA7\u51FA\uFF0C\u5206\u7EA7\u5904\u7406 Critical/Warning/Info",
|
|
457
|
+
descriptionEn: "Dual-model cross-review of parallel implementation output"
|
|
458
|
+
}
|
|
459
|
+
];
|
|
460
|
+
function getWorkflowConfigs() {
|
|
461
|
+
return WORKFLOW_CONFIGS.sort((a, b) => a.order - b.order);
|
|
462
|
+
}
|
|
463
|
+
function getWorkflowById(id) {
|
|
464
|
+
return WORKFLOW_CONFIGS.find((w) => w.id === id);
|
|
465
|
+
}
|
|
466
|
+
function getAllCommandIds() {
|
|
467
|
+
return WORKFLOW_CONFIGS.map((w) => w.id);
|
|
468
|
+
}
|
|
469
|
+
({
|
|
470
|
+
full: {
|
|
471
|
+
workflows: WORKFLOW_CONFIGS.map((w) => w.id)
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
function injectConfigVariables(content, config) {
|
|
475
|
+
let processed = content;
|
|
476
|
+
const routing = config.routing || {};
|
|
477
|
+
const frontendModels = routing.frontend?.models || ["gemini"];
|
|
478
|
+
const frontendPrimary = routing.frontend?.primary || "gemini";
|
|
479
|
+
processed = processed.replace(/\{\{FRONTEND_MODELS\}\}/g, JSON.stringify(frontendModels));
|
|
480
|
+
processed = processed.replace(/\{\{FRONTEND_PRIMARY\}\}/g, frontendPrimary);
|
|
481
|
+
const backendModels = routing.backend?.models || ["codex"];
|
|
482
|
+
const backendPrimary = routing.backend?.primary || "codex";
|
|
483
|
+
processed = processed.replace(/\{\{BACKEND_MODELS\}\}/g, JSON.stringify(backendModels));
|
|
484
|
+
processed = processed.replace(/\{\{BACKEND_PRIMARY\}\}/g, backendPrimary);
|
|
485
|
+
const reviewModels = routing.review?.models || ["codex", "gemini"];
|
|
486
|
+
processed = processed.replace(/\{\{REVIEW_MODELS\}\}/g, JSON.stringify(reviewModels));
|
|
487
|
+
const routingMode = routing.mode || "smart";
|
|
488
|
+
processed = processed.replace(/\{\{ROUTING_MODE\}\}/g, routingMode);
|
|
489
|
+
const liteModeFlag = config.liteMode ? "--lite " : "";
|
|
490
|
+
processed = processed.replace(/\{\{LITE_MODE_FLAG\}\}/g, liteModeFlag);
|
|
491
|
+
return processed;
|
|
492
|
+
}
|
|
493
|
+
function replaceHomePathsInTemplate(content, installDir) {
|
|
494
|
+
const userHome = homedir();
|
|
495
|
+
const ccgDir = join(installDir, ".ccg");
|
|
496
|
+
const binDir = join(installDir, "bin");
|
|
497
|
+
const claudeDir = installDir;
|
|
498
|
+
const normalizePath2 = (path) => path.replace(/\\/g, "/");
|
|
499
|
+
let processed = content;
|
|
500
|
+
processed = processed.replace(/~\/\.claude\/\.ccg/g, normalizePath2(ccgDir));
|
|
501
|
+
const wrapperName = isWindows() ? "codeagent-wrapper.exe" : "codeagent-wrapper";
|
|
502
|
+
const wrapperPath = `${normalizePath2(binDir)}/${wrapperName}`;
|
|
503
|
+
processed = processed.replace(/~\/\.claude\/bin\/codeagent-wrapper/g, wrapperPath);
|
|
504
|
+
processed = processed.replace(/~\/\.claude\/bin/g, normalizePath2(binDir));
|
|
505
|
+
processed = processed.replace(/~\/\.claude/g, normalizePath2(claudeDir));
|
|
506
|
+
processed = processed.replace(/~\//g, `${normalizePath2(userHome)}/`);
|
|
507
|
+
return processed;
|
|
508
|
+
}
|
|
509
|
+
async function installWorkflows(workflowIds, installDir, force = false, config) {
|
|
510
|
+
const installConfig = {
|
|
511
|
+
routing: config?.routing || {
|
|
512
|
+
mode: "smart",
|
|
513
|
+
frontend: { models: ["gemini"], primary: "gemini" },
|
|
514
|
+
backend: { models: ["codex"], primary: "codex" },
|
|
515
|
+
review: { models: ["codex", "gemini"] }
|
|
516
|
+
},
|
|
517
|
+
liteMode: config?.liteMode || false
|
|
518
|
+
};
|
|
519
|
+
const result = {
|
|
520
|
+
success: true,
|
|
521
|
+
installedCommands: [],
|
|
522
|
+
installedPrompts: [],
|
|
523
|
+
errors: [],
|
|
524
|
+
configPath: ""
|
|
525
|
+
};
|
|
526
|
+
const commandsDir = join(installDir, "commands", "ccg");
|
|
527
|
+
const ccgConfigDir = join(installDir, ".ccg");
|
|
528
|
+
const promptsDir = join(ccgConfigDir, "prompts");
|
|
529
|
+
await fs.ensureDir(commandsDir);
|
|
530
|
+
await fs.ensureDir(ccgConfigDir);
|
|
531
|
+
await fs.ensureDir(promptsDir);
|
|
532
|
+
const templateDir = join(PACKAGE_ROOT$1, "templates");
|
|
533
|
+
for (const workflowId of workflowIds) {
|
|
534
|
+
const workflow = getWorkflowById(workflowId);
|
|
535
|
+
if (!workflow) {
|
|
536
|
+
result.errors.push(`Unknown workflow: ${workflowId}`);
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
for (const cmd of workflow.commands) {
|
|
540
|
+
const srcFile = join(templateDir, "commands", `${cmd}.md`);
|
|
541
|
+
const destFile = join(commandsDir, `${cmd}.md`);
|
|
542
|
+
try {
|
|
543
|
+
if (await fs.pathExists(srcFile)) {
|
|
544
|
+
if (force || !await fs.pathExists(destFile)) {
|
|
545
|
+
let templateContent = await fs.readFile(srcFile, "utf-8");
|
|
546
|
+
templateContent = injectConfigVariables(templateContent, installConfig);
|
|
547
|
+
const processedContent = replaceHomePathsInTemplate(templateContent, installDir);
|
|
548
|
+
await fs.writeFile(destFile, processedContent, "utf-8");
|
|
549
|
+
result.installedCommands.push(cmd);
|
|
550
|
+
}
|
|
551
|
+
} else {
|
|
552
|
+
const placeholder = `---
|
|
553
|
+
description: "${workflow.descriptionEn}"
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
# /ccg:${cmd}
|
|
557
|
+
|
|
558
|
+
${workflow.description}
|
|
559
|
+
|
|
560
|
+
> This command is part of CCG multi-model collaboration system.
|
|
561
|
+
`;
|
|
562
|
+
await fs.writeFile(destFile, placeholder, "utf-8");
|
|
563
|
+
result.installedCommands.push(cmd);
|
|
564
|
+
}
|
|
565
|
+
} catch (error) {
|
|
566
|
+
result.errors.push(`Failed to install ${cmd}: ${error}`);
|
|
567
|
+
result.success = false;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
const agentsSrcDir = join(templateDir, "commands", "agents");
|
|
572
|
+
const agentsDestDir = join(installDir, "agents", "ccg");
|
|
573
|
+
if (await fs.pathExists(agentsSrcDir)) {
|
|
574
|
+
try {
|
|
575
|
+
await fs.ensureDir(agentsDestDir);
|
|
576
|
+
const agentFiles = await fs.readdir(agentsSrcDir);
|
|
577
|
+
for (const file of agentFiles) {
|
|
578
|
+
if (file.endsWith(".md")) {
|
|
579
|
+
const srcFile = join(agentsSrcDir, file);
|
|
580
|
+
const destFile = join(agentsDestDir, file);
|
|
581
|
+
if (force || !await fs.pathExists(destFile)) {
|
|
582
|
+
let templateContent = await fs.readFile(srcFile, "utf-8");
|
|
583
|
+
templateContent = injectConfigVariables(templateContent, installConfig);
|
|
584
|
+
const processedContent = replaceHomePathsInTemplate(templateContent, installDir);
|
|
585
|
+
await fs.writeFile(destFile, processedContent, "utf-8");
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
} catch (error) {
|
|
590
|
+
result.errors.push(`Failed to install agents: ${error}`);
|
|
591
|
+
result.success = false;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
const promptsTemplateDir = join(templateDir, "prompts");
|
|
595
|
+
if (await fs.pathExists(promptsTemplateDir)) {
|
|
596
|
+
const modelDirs = ["codex", "gemini", "claude"];
|
|
597
|
+
for (const model of modelDirs) {
|
|
598
|
+
const srcModelDir = join(promptsTemplateDir, model);
|
|
599
|
+
const destModelDir = join(promptsDir, model);
|
|
600
|
+
if (await fs.pathExists(srcModelDir)) {
|
|
601
|
+
try {
|
|
602
|
+
await fs.ensureDir(destModelDir);
|
|
603
|
+
const files = await fs.readdir(srcModelDir);
|
|
604
|
+
for (const file of files) {
|
|
605
|
+
if (file.endsWith(".md")) {
|
|
606
|
+
const srcFile = join(srcModelDir, file);
|
|
607
|
+
const destFile = join(destModelDir, file);
|
|
608
|
+
if (force || !await fs.pathExists(destFile)) {
|
|
609
|
+
const templateContent = await fs.readFile(srcFile, "utf-8");
|
|
610
|
+
const processedContent = replaceHomePathsInTemplate(templateContent, installDir);
|
|
611
|
+
await fs.writeFile(destFile, processedContent, "utf-8");
|
|
612
|
+
result.installedPrompts.push(`${model}/${file.replace(".md", "")}`);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
} catch (error) {
|
|
617
|
+
result.errors.push(`Failed to install ${model} prompts: ${error}`);
|
|
618
|
+
result.success = false;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
const skillsTemplateDir = join(templateDir, "skills");
|
|
624
|
+
const skillsDestDir = join(installDir, "skills");
|
|
625
|
+
if (await fs.pathExists(skillsTemplateDir)) {
|
|
626
|
+
try {
|
|
627
|
+
const skillDirs = await fs.readdir(skillsTemplateDir);
|
|
628
|
+
for (const skillName of skillDirs) {
|
|
629
|
+
const srcSkillDir = join(skillsTemplateDir, skillName);
|
|
630
|
+
const destSkillDir = join(skillsDestDir, skillName);
|
|
631
|
+
const stat = await fs.stat(srcSkillDir);
|
|
632
|
+
if (stat.isDirectory()) {
|
|
633
|
+
await fs.ensureDir(destSkillDir);
|
|
634
|
+
const files = await fs.readdir(srcSkillDir);
|
|
635
|
+
for (const file of files) {
|
|
636
|
+
const srcFile = join(srcSkillDir, file);
|
|
637
|
+
const destFile = join(destSkillDir, file);
|
|
638
|
+
if (force || !await fs.pathExists(destFile)) {
|
|
639
|
+
const templateContent = await fs.readFile(srcFile, "utf-8");
|
|
640
|
+
const processedContent = replaceHomePathsInTemplate(templateContent, installDir);
|
|
641
|
+
await fs.writeFile(destFile, processedContent, "utf-8");
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
} catch (error) {
|
|
647
|
+
result.errors.push(`Failed to install skills: ${error}`);
|
|
648
|
+
result.success = false;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
try {
|
|
652
|
+
const binDir = join(installDir, "bin");
|
|
653
|
+
await fs.ensureDir(binDir);
|
|
654
|
+
const platform = process.platform;
|
|
655
|
+
const arch = process.arch;
|
|
656
|
+
let binaryName;
|
|
657
|
+
if (platform === "darwin") {
|
|
658
|
+
binaryName = arch === "arm64" ? "codeagent-wrapper-darwin-arm64" : "codeagent-wrapper-darwin-amd64";
|
|
659
|
+
} else if (platform === "linux") {
|
|
660
|
+
binaryName = arch === "arm64" ? "codeagent-wrapper-linux-arm64" : "codeagent-wrapper-linux-amd64";
|
|
661
|
+
} else if (platform === "win32") {
|
|
662
|
+
binaryName = arch === "arm64" ? "codeagent-wrapper-windows-arm64.exe" : "codeagent-wrapper-windows-amd64.exe";
|
|
663
|
+
} else {
|
|
664
|
+
result.errors.push(`Unsupported platform: ${platform}`);
|
|
665
|
+
result.success = false;
|
|
666
|
+
result.configPath = commandsDir;
|
|
667
|
+
return result;
|
|
668
|
+
}
|
|
669
|
+
const srcBinary = join(PACKAGE_ROOT$1, "bin", binaryName);
|
|
670
|
+
const destBinary = join(binDir, platform === "win32" ? "codeagent-wrapper.exe" : "codeagent-wrapper");
|
|
671
|
+
if (await fs.pathExists(srcBinary)) {
|
|
672
|
+
await fs.copy(srcBinary, destBinary);
|
|
673
|
+
if (platform !== "win32") {
|
|
674
|
+
await fs.chmod(destBinary, 493);
|
|
675
|
+
}
|
|
676
|
+
try {
|
|
677
|
+
const { execSync } = await import('node:child_process');
|
|
678
|
+
execSync(`"${destBinary}" --version`, { stdio: "pipe" });
|
|
679
|
+
result.binPath = binDir;
|
|
680
|
+
result.binInstalled = true;
|
|
681
|
+
} catch (verifyError) {
|
|
682
|
+
result.errors.push(`Binary verification failed: ${verifyError}`);
|
|
683
|
+
result.success = false;
|
|
684
|
+
}
|
|
685
|
+
} else {
|
|
686
|
+
result.errors.push(`Binary not found in package: ${binaryName}`);
|
|
687
|
+
result.success = false;
|
|
688
|
+
}
|
|
689
|
+
} catch (error) {
|
|
690
|
+
result.errors.push(`Failed to install codeagent-wrapper: ${error}`);
|
|
691
|
+
result.success = false;
|
|
692
|
+
}
|
|
693
|
+
result.configPath = commandsDir;
|
|
694
|
+
return result;
|
|
695
|
+
}
|
|
696
|
+
async function uninstallWorkflows(installDir) {
|
|
697
|
+
const result = {
|
|
698
|
+
success: true,
|
|
699
|
+
removedCommands: [],
|
|
700
|
+
removedPrompts: [],
|
|
701
|
+
removedAgents: [],
|
|
702
|
+
removedSkills: [],
|
|
703
|
+
removedBin: false,
|
|
704
|
+
errors: []
|
|
705
|
+
};
|
|
706
|
+
const commandsDir = join(installDir, "commands", "ccg");
|
|
707
|
+
join(installDir, ".ccg", "prompts");
|
|
708
|
+
const agentsDir = join(installDir, "agents", "ccg");
|
|
709
|
+
const skillsDir = join(installDir, "skills", "multi-model-collaboration");
|
|
710
|
+
const binDir = join(installDir, "bin");
|
|
711
|
+
const ccgConfigDir = join(installDir, ".ccg");
|
|
712
|
+
if (await fs.pathExists(commandsDir)) {
|
|
713
|
+
try {
|
|
714
|
+
const files = await fs.readdir(commandsDir);
|
|
715
|
+
for (const file of files) {
|
|
716
|
+
if (file.endsWith(".md")) {
|
|
717
|
+
result.removedCommands.push(file.replace(".md", ""));
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
await fs.remove(commandsDir);
|
|
721
|
+
} catch (error) {
|
|
722
|
+
result.errors.push(`Failed to remove commands directory: ${error}`);
|
|
723
|
+
result.success = false;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (await fs.pathExists(agentsDir)) {
|
|
727
|
+
try {
|
|
728
|
+
const files = await fs.readdir(agentsDir);
|
|
729
|
+
for (const file of files) {
|
|
730
|
+
result.removedAgents.push(file.replace(".md", ""));
|
|
731
|
+
}
|
|
732
|
+
await fs.remove(agentsDir);
|
|
733
|
+
} catch (error) {
|
|
734
|
+
result.errors.push(`Failed to remove agents directory: ${error}`);
|
|
735
|
+
result.success = false;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
if (await fs.pathExists(skillsDir)) {
|
|
739
|
+
try {
|
|
740
|
+
const files = await fs.readdir(skillsDir);
|
|
741
|
+
for (const file of files) {
|
|
742
|
+
result.removedSkills.push(file);
|
|
743
|
+
}
|
|
744
|
+
await fs.remove(skillsDir);
|
|
745
|
+
} catch (error) {
|
|
746
|
+
result.errors.push(`Failed to remove skills: ${error}`);
|
|
747
|
+
result.success = false;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
if (await fs.pathExists(binDir)) {
|
|
751
|
+
try {
|
|
752
|
+
const wrapperName = process.platform === "win32" ? "codeagent-wrapper.exe" : "codeagent-wrapper";
|
|
753
|
+
const wrapperPath = join(binDir, wrapperName);
|
|
754
|
+
if (await fs.pathExists(wrapperPath)) {
|
|
755
|
+
await fs.remove(wrapperPath);
|
|
756
|
+
result.removedBin = true;
|
|
757
|
+
}
|
|
758
|
+
} catch (error) {
|
|
759
|
+
result.errors.push(`Failed to remove binary: ${error}`);
|
|
760
|
+
result.success = false;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
if (await fs.pathExists(ccgConfigDir)) {
|
|
764
|
+
try {
|
|
765
|
+
await fs.remove(ccgConfigDir);
|
|
766
|
+
result.removedPrompts.push("ALL_PROMPTS_AND_CONFIGS");
|
|
767
|
+
} catch (error) {
|
|
768
|
+
result.errors.push(`Failed to remove .ccg directory: ${error}`);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return result;
|
|
772
|
+
}
|
|
773
|
+
async function uninstallAceTool() {
|
|
774
|
+
try {
|
|
775
|
+
const existingConfig = await readClaudeCodeConfig();
|
|
776
|
+
if (!existingConfig) {
|
|
777
|
+
return {
|
|
778
|
+
success: true,
|
|
779
|
+
message: "No ~/.claude.json found, nothing to remove"
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
if (!existingConfig.mcpServers || !existingConfig.mcpServers["ace-tool"]) {
|
|
783
|
+
return {
|
|
784
|
+
success: true,
|
|
785
|
+
message: "ace-tool MCP not found in config"
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
await backupClaudeCodeConfig();
|
|
789
|
+
delete existingConfig.mcpServers["ace-tool"];
|
|
790
|
+
await writeClaudeCodeConfig(existingConfig);
|
|
791
|
+
return {
|
|
792
|
+
success: true,
|
|
793
|
+
message: "ace-tool MCP removed from ~/.claude.json"
|
|
794
|
+
};
|
|
795
|
+
} catch (error) {
|
|
796
|
+
return {
|
|
797
|
+
success: false,
|
|
798
|
+
message: `Failed to uninstall ace-tool: ${error}`
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
async function installAceTool(config) {
|
|
803
|
+
const { baseUrl, token } = config;
|
|
804
|
+
try {
|
|
805
|
+
let existingConfig = await readClaudeCodeConfig();
|
|
806
|
+
if (!existingConfig) {
|
|
807
|
+
existingConfig = { mcpServers: {} };
|
|
808
|
+
}
|
|
809
|
+
if (existingConfig.mcpServers && Object.keys(existingConfig.mcpServers).length > 0) {
|
|
810
|
+
const backupPath = await backupClaudeCodeConfig();
|
|
811
|
+
if (backupPath) {
|
|
812
|
+
console.log(` \u2713 Backup created: ${backupPath}`);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
const args = ["-y", "ace-tool@latest"];
|
|
816
|
+
if (baseUrl) {
|
|
817
|
+
args.push("--base-url", baseUrl);
|
|
818
|
+
}
|
|
819
|
+
if (token) {
|
|
820
|
+
args.push("--token", token);
|
|
821
|
+
}
|
|
822
|
+
const aceToolConfig = buildMcpServerConfig({
|
|
823
|
+
type: "stdio",
|
|
824
|
+
command: "npx",
|
|
825
|
+
args
|
|
826
|
+
});
|
|
827
|
+
let mergedConfig = mergeMcpServers(existingConfig, {
|
|
828
|
+
"ace-tool": aceToolConfig
|
|
829
|
+
});
|
|
830
|
+
if (isWindows()) {
|
|
831
|
+
mergedConfig = fixWindowsMcpConfig(mergedConfig);
|
|
832
|
+
console.log(" \u2713 Applied Windows MCP configuration fixes");
|
|
833
|
+
}
|
|
834
|
+
await writeClaudeCodeConfig(mergedConfig);
|
|
835
|
+
return {
|
|
836
|
+
success: true,
|
|
837
|
+
message: isWindows() ? "ace-tool MCP configured successfully with Windows compatibility" : "ace-tool MCP configured successfully",
|
|
838
|
+
configPath: join(homedir(), ".claude.json")
|
|
839
|
+
};
|
|
840
|
+
} catch (error) {
|
|
841
|
+
return {
|
|
842
|
+
success: false,
|
|
843
|
+
message: `Failed to configure ace-tool: ${error}`
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
async function installAceToolRs(config) {
|
|
848
|
+
const { baseUrl, token } = config;
|
|
849
|
+
try {
|
|
850
|
+
let existingConfig = await readClaudeCodeConfig();
|
|
851
|
+
if (!existingConfig) {
|
|
852
|
+
existingConfig = { mcpServers: {} };
|
|
853
|
+
}
|
|
854
|
+
if (existingConfig.mcpServers && Object.keys(existingConfig.mcpServers).length > 0) {
|
|
855
|
+
const backupPath = await backupClaudeCodeConfig();
|
|
856
|
+
if (backupPath) {
|
|
857
|
+
console.log(` \u2713 Backup created: ${backupPath}`);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
const args = ["ace-tool-rs"];
|
|
861
|
+
if (baseUrl) {
|
|
862
|
+
args.push("--base-url", baseUrl);
|
|
863
|
+
}
|
|
864
|
+
if (token) {
|
|
865
|
+
args.push("--token", token);
|
|
866
|
+
}
|
|
867
|
+
const aceToolRsConfig = buildMcpServerConfig({
|
|
868
|
+
type: "stdio",
|
|
869
|
+
command: "npx",
|
|
870
|
+
args,
|
|
871
|
+
env: {
|
|
872
|
+
RUST_LOG: "info"
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
let mergedConfig = mergeMcpServers(existingConfig, {
|
|
876
|
+
"ace-tool": aceToolRsConfig
|
|
877
|
+
});
|
|
878
|
+
if (isWindows()) {
|
|
879
|
+
mergedConfig = fixWindowsMcpConfig(mergedConfig);
|
|
880
|
+
console.log(" \u2713 Applied Windows MCP configuration fixes");
|
|
881
|
+
}
|
|
882
|
+
await writeClaudeCodeConfig(mergedConfig);
|
|
883
|
+
return {
|
|
884
|
+
success: true,
|
|
885
|
+
message: isWindows() ? "ace-tool-rs MCP configured successfully with Windows compatibility" : "ace-tool-rs MCP configured successfully",
|
|
886
|
+
configPath: join(homedir(), ".claude.json")
|
|
887
|
+
};
|
|
888
|
+
} catch (error) {
|
|
889
|
+
return {
|
|
890
|
+
success: false,
|
|
891
|
+
message: `Failed to configure ace-tool-rs: ${error}`
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
async function configMcp() {
|
|
897
|
+
console.log();
|
|
898
|
+
console.log(ansis.cyan.bold(` \u914D\u7F6E MCP \u5DE5\u5177`));
|
|
899
|
+
console.log();
|
|
900
|
+
const { action } = await inquirer.prompt([{
|
|
901
|
+
type: "list",
|
|
902
|
+
name: "action",
|
|
903
|
+
message: "\u9009\u62E9\u64CD\u4F5C",
|
|
904
|
+
choices: [
|
|
905
|
+
{ name: `${ansis.green("\u279C")} \u5B89\u88C5/\u66F4\u65B0 ace-tool MCP ${ansis.gray("(Node.js \u5B9E\u73B0)")}`, value: "install-ace-tool" },
|
|
906
|
+
{ name: `${ansis.green("\u279C")} \u5B89\u88C5/\u66F4\u65B0 ace-tool-rs MCP ${ansis.yellow("(\u63A8\u8350)")} ${ansis.gray("(Rust \u5B9E\u73B0)")}`, value: "install-ace-tool-rs" },
|
|
907
|
+
{ name: `${ansis.red("\u2715")} \u5378\u8F7D MCP \u914D\u7F6E`, value: "uninstall" },
|
|
908
|
+
new inquirer.Separator(),
|
|
909
|
+
{ name: `${ansis.gray("\u8FD4\u56DE")}`, value: "cancel" }
|
|
910
|
+
]
|
|
911
|
+
}]);
|
|
912
|
+
if (action === "cancel") {
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
if (action === "uninstall") {
|
|
916
|
+
await handleUninstall();
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
const isAceToolRs = action === "install-ace-tool-rs";
|
|
920
|
+
const toolName = isAceToolRs ? "ace-tool-rs" : "ace-tool";
|
|
921
|
+
console.log();
|
|
922
|
+
console.log(ansis.cyan(`\u{1F4D6} \u83B7\u53D6 ${toolName} \u8BBF\u95EE\u65B9\u5F0F\uFF1A`));
|
|
923
|
+
console.log(` ${ansis.gray("\u2022")} ${ansis.cyan("\u5B98\u65B9\u670D\u52A1")}: ${ansis.underline("https://augmentcode.com/")}`);
|
|
924
|
+
console.log(` ${ansis.gray("\u2022")} ${ansis.cyan("\u4E2D\u8F6C\u670D\u52A1")} ${ansis.yellow("(\u65E0\u9700\u6CE8\u518C)")}: ${ansis.underline("https://linux.do/t/topic/1291730")}`);
|
|
925
|
+
console.log();
|
|
926
|
+
const aceAnswers = await inquirer.prompt([
|
|
927
|
+
{
|
|
928
|
+
type: "input",
|
|
929
|
+
name: "baseUrl",
|
|
930
|
+
message: `Base URL ${ansis.gray("(\u4F7F\u7528\u4E2D\u8F6C\u670D\u52A1\u65F6\u5FC5\u586B\uFF0C\u5B98\u65B9\u670D\u52A1\u7559\u7A7A)")}`
|
|
931
|
+
},
|
|
932
|
+
{
|
|
933
|
+
type: "password",
|
|
934
|
+
name: "token",
|
|
935
|
+
message: `Token ${ansis.gray("(\u5FC5\u586B)")}`,
|
|
936
|
+
validate: (input) => input.trim() !== "" || "\u8BF7\u8F93\u5165 Token"
|
|
937
|
+
}
|
|
938
|
+
]);
|
|
939
|
+
console.log();
|
|
940
|
+
console.log(ansis.yellow(`\u23F3 \u6B63\u5728\u914D\u7F6E ${toolName} MCP...`));
|
|
941
|
+
console.log();
|
|
942
|
+
const installFn = isAceToolRs ? installAceToolRs : installAceTool;
|
|
943
|
+
const result = await installFn({
|
|
944
|
+
baseUrl: aceAnswers.baseUrl?.trim() || void 0,
|
|
945
|
+
token: aceAnswers.token.trim()
|
|
946
|
+
});
|
|
947
|
+
if (result.success) {
|
|
948
|
+
console.log(ansis.green(`\u2713 ${toolName} MCP \u914D\u7F6E\u6210\u529F\uFF01`));
|
|
949
|
+
if (result.configPath) {
|
|
950
|
+
console.log(ansis.gray(` \u914D\u7F6E\u6587\u4EF6: ${result.configPath}`));
|
|
951
|
+
}
|
|
952
|
+
console.log();
|
|
953
|
+
console.log(ansis.cyan("\u{1F4A1} \u63D0\u793A\uFF1A"));
|
|
954
|
+
console.log(ansis.gray(" 1. \u91CD\u542F Claude Code CLI \u4F7F\u914D\u7F6E\u751F\u6548"));
|
|
955
|
+
console.log(ansis.gray(" 2. \u8FD0\u884C /ccg:dev \u547D\u4EE4\u6D4B\u8BD5 MCP \u529F\u80FD"));
|
|
956
|
+
} else {
|
|
957
|
+
console.log(ansis.red(`\u2717 ${toolName} MCP \u914D\u7F6E\u5931\u8D25`));
|
|
958
|
+
console.log(ansis.gray(` \u9519\u8BEF\u4FE1\u606F: ${result.message}`));
|
|
959
|
+
}
|
|
960
|
+
console.log();
|
|
961
|
+
}
|
|
962
|
+
async function handleUninstall() {
|
|
963
|
+
console.log();
|
|
964
|
+
const { confirm } = await inquirer.prompt([{
|
|
965
|
+
type: "confirm",
|
|
966
|
+
name: "confirm",
|
|
967
|
+
message: "\u786E\u5B9A\u8981\u5378\u8F7D ace-tool MCP \u5417\uFF1F",
|
|
968
|
+
default: false
|
|
969
|
+
}]);
|
|
970
|
+
if (!confirm) {
|
|
971
|
+
console.log(ansis.gray("\u5DF2\u53D6\u6D88"));
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
console.log();
|
|
975
|
+
console.log(ansis.yellow("\u23F3 \u6B63\u5728\u5378\u8F7D ace-tool MCP..."));
|
|
976
|
+
const result = await uninstallAceTool();
|
|
977
|
+
if (result.success) {
|
|
978
|
+
console.log(ansis.green("\u2713 ace-tool MCP \u5DF2\u5378\u8F7D"));
|
|
979
|
+
console.log();
|
|
980
|
+
} else {
|
|
981
|
+
console.log(ansis.red("\u2717 \u5378\u8F7D\u5931\u8D25"));
|
|
982
|
+
console.log(ansis.gray(` \u9519\u8BEF\u4FE1\u606F: ${result.message}`));
|
|
983
|
+
console.log();
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
const i18n = i18next;
|
|
988
|
+
const zhCN = {
|
|
989
|
+
common: {
|
|
990
|
+
yes: "\u662F",
|
|
991
|
+
no: "\u5426",
|
|
992
|
+
confirm: "\u786E\u8BA4",
|
|
993
|
+
cancel: "\u53D6\u6D88",
|
|
994
|
+
back: "\u8FD4\u56DE",
|
|
995
|
+
exit: "\u9000\u51FA",
|
|
996
|
+
success: "\u6210\u529F",
|
|
997
|
+
error: "\u9519\u8BEF",
|
|
998
|
+
warning: "\u8B66\u544A",
|
|
999
|
+
info: "\u4FE1\u606F",
|
|
1000
|
+
loading: "\u52A0\u8F7D\u4E2D...",
|
|
1001
|
+
processing: "\u5904\u7406\u4E2D...",
|
|
1002
|
+
completed: "\u5DF2\u5B8C\u6210",
|
|
1003
|
+
failed: "\u5931\u8D25"
|
|
1004
|
+
},
|
|
1005
|
+
cli: {
|
|
1006
|
+
help: {
|
|
1007
|
+
commands: "\u547D\u4EE4",
|
|
1008
|
+
commandDescriptions: {
|
|
1009
|
+
showMenu: "\u663E\u793A\u4EA4\u4E92\u5F0F\u83DC\u5355\uFF08\u9ED8\u8BA4\uFF09",
|
|
1010
|
+
initConfig: "\u521D\u59CB\u5316 CCG-ROS2 \u591A\u6A21\u578B\u534F\u4F5C\u7CFB\u7EDF"
|
|
1011
|
+
},
|
|
1012
|
+
shortcuts: "\u5FEB\u6377\u65B9\u5F0F:",
|
|
1013
|
+
shortcutDescriptions: {
|
|
1014
|
+
quickInit: "\u5FEB\u901F\u521D\u59CB\u5316"
|
|
1015
|
+
},
|
|
1016
|
+
options: "\u9009\u9879",
|
|
1017
|
+
optionDescriptions: {
|
|
1018
|
+
displayLanguage: "\u663E\u793A\u8BED\u8A00",
|
|
1019
|
+
forceOverwrite: "\u5F3A\u5236\u8986\u76D6\u73B0\u6709\u914D\u7F6E",
|
|
1020
|
+
displayHelp: "\u663E\u793A\u5E2E\u52A9\u4FE1\u606F",
|
|
1021
|
+
displayVersion: "\u663E\u793A\u7248\u672C\u53F7",
|
|
1022
|
+
skipAllPrompts: "\u8DF3\u8FC7\u6240\u6709\u4EA4\u4E92\u5F0F\u63D0\u793A\uFF08\u975E\u4EA4\u4E92\u6A21\u5F0F\uFF09",
|
|
1023
|
+
frontendModels: "\u4E0A\u5C42\u5E94\u7528\u6A21\u578B\uFF08\u9017\u53F7\u5206\u9694\uFF09",
|
|
1024
|
+
backendModels: "\u5E95\u5C42\u63A7\u5236\u6A21\u578B\uFF08\u9017\u53F7\u5206\u9694\uFF09",
|
|
1025
|
+
collaborationMode: "\u534F\u4F5C\u6A21\u5F0F (parallel/smart/sequential)",
|
|
1026
|
+
workflows: "\u8981\u5B89\u88C5\u7684\u5DE5\u4F5C\u6D41",
|
|
1027
|
+
installDir: "\u5B89\u88C5\u76EE\u5F55"
|
|
1028
|
+
},
|
|
1029
|
+
nonInteractiveMode: "\u975E\u4EA4\u4E92\u6A21\u5F0F:",
|
|
1030
|
+
examples: "\u793A\u4F8B",
|
|
1031
|
+
exampleDescriptions: {
|
|
1032
|
+
showInteractiveMenu: "\u663E\u793A\u4EA4\u4E92\u5F0F\u83DC\u5355",
|
|
1033
|
+
runFullInitialization: "\u8FD0\u884C\u5B8C\u6574\u521D\u59CB\u5316",
|
|
1034
|
+
customModels: "\u81EA\u5B9A\u4E49\u6A21\u578B\u914D\u7F6E",
|
|
1035
|
+
parallelMode: "\u4F7F\u7528\u5E76\u884C\u534F\u4F5C\u6A21\u5F0F"
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
},
|
|
1039
|
+
init: {
|
|
1040
|
+
welcome: "\u6B22\u8FCE\u4F7F\u7528 CCG-ROS2 \u591A\u6A21\u578B\u534F\u4F5C\u7CFB\u7EDF",
|
|
1041
|
+
selectLanguage: "\u8BF7\u9009\u62E9\u8BED\u8A00",
|
|
1042
|
+
selectFrontendModels: "\u9009\u62E9\u4E0A\u5C42\u5E94\u7528\u4EFB\u52A1\u4F7F\u7528\u7684\u6A21\u578B\uFF08\u53EF\u591A\u9009\uFF09",
|
|
1043
|
+
selectBackendModels: "\u9009\u62E9\u5E95\u5C42\u63A7\u5236\u4EFB\u52A1\u4F7F\u7528\u7684\u6A21\u578B\uFF08\u53EF\u591A\u9009\uFF09",
|
|
1044
|
+
selectMode: "\u9009\u62E9\u534F\u4F5C\u6A21\u5F0F",
|
|
1045
|
+
selectWorkflows: "\u9009\u62E9\u8981\u5B89\u88C5\u7684\u5DE5\u4F5C\u6D41\uFF08\u53EF\u591A\u9009\uFF09",
|
|
1046
|
+
confirmInstall: "\u786E\u8BA4\u5B89\u88C5\u4EE5\u4E0A\u914D\u7F6E\uFF1F",
|
|
1047
|
+
installing: "\u6B63\u5728\u5B89\u88C5...",
|
|
1048
|
+
installSuccess: "\u5B89\u88C5\u6210\u529F\uFF01",
|
|
1049
|
+
installFailed: "\u5B89\u88C5\u5931\u8D25",
|
|
1050
|
+
installCancelled: "\u5B89\u88C5\u5DF2\u53D6\u6D88",
|
|
1051
|
+
installedCommands: "\u5DF2\u5B89\u88C5\u547D\u4EE4:",
|
|
1052
|
+
installedPrompts: "\u5DF2\u5B89\u88C5\u89D2\u8272\u63D0\u793A\u8BCD:",
|
|
1053
|
+
installedBinary: "\u5DF2\u5B89\u88C5\u4E8C\u8FDB\u5236\u6587\u4EF6:",
|
|
1054
|
+
installationErrors: "\u5B89\u88C5\u8FC7\u7A0B\u4E2D\u51FA\u73B0\u9519\u8BEF:",
|
|
1055
|
+
pathWarning: "\u9700\u8981\u5C06 codeagent-wrapper \u6DFB\u52A0\u5230 PATH \u624D\u80FD\u4F7F\u7528",
|
|
1056
|
+
autoConfigurePathPrompt: "\u662F\u5426\u81EA\u52A8\u914D\u7F6E PATH \u73AF\u5883\u53D8\u91CF\uFF1F",
|
|
1057
|
+
pathConfigured: "PATH \u5DF2\u6DFB\u52A0\u5230 {{file}}",
|
|
1058
|
+
pathAlreadyConfigured: "PATH \u5DF2\u914D\u7F6E\u5728 {{file}} \u4E2D",
|
|
1059
|
+
pathConfigFailed: "\u81EA\u52A8\u914D\u7F6E\u5931\u8D25",
|
|
1060
|
+
restartShellPrompt: "\u8BF7\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u4F7F\u914D\u7F6E\u751F\u6548:",
|
|
1061
|
+
manualConfigInstructions: "\u8BF7\u624B\u52A8\u6DFB\u52A0\u4EE5\u4E0B\u547D\u4EE4\u5230 {{file}}:",
|
|
1062
|
+
windowsPathInstructions: "Windows \u7528\u6237 - \u624B\u52A8\u6DFB\u52A0\u5230\u7CFB\u7EDF\u73AF\u5883\u53D8\u91CF:",
|
|
1063
|
+
windowsStep1: '\u6309 Win+X\uFF0C\u9009\u62E9"\u7CFB\u7EDF"',
|
|
1064
|
+
windowsStep2: '\u70B9\u51FB"\u9AD8\u7EA7\u7CFB\u7EDF\u8BBE\u7F6E" \u2192 "\u73AF\u5883\u53D8\u91CF"',
|
|
1065
|
+
windowsStep3: '\u5728"\u7528\u6237\u53D8\u91CF"\u4E2D\u627E\u5230 Path\uFF0C\u70B9\u51FB"\u7F16\u8F91"\uFF0C\u6DFB\u52A0:',
|
|
1066
|
+
windowsStep4: '\u70B9\u51FB"\u786E\u5B9A"\u4FDD\u5B58\uFF0C\u91CD\u542F\u7EC8\u7AEF',
|
|
1067
|
+
orUsePowerShell: "\u6216\u5728 PowerShell (\u7BA1\u7406\u5458) \u4E2D\u8FD0\u884C:",
|
|
1068
|
+
addToShellConfig: "\u8BF7\u6DFB\u52A0\u4EE5\u4E0B\u547D\u4EE4\u5230 {{file}} \u5E76\u91CD\u542F\u7EC8\u7AEF",
|
|
1069
|
+
configSavedTo: "\u914D\u7F6E\u5DF2\u4FDD\u5B58\u81F3:",
|
|
1070
|
+
validation: {
|
|
1071
|
+
selectAtLeastOne: "\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u4E2A\u6A21\u578B"
|
|
1072
|
+
},
|
|
1073
|
+
summary: {
|
|
1074
|
+
title: "\u914D\u7F6E\u6458\u8981:",
|
|
1075
|
+
frontendModels: "\u4E0A\u5C42\u5E94\u7528\u6A21\u578B:",
|
|
1076
|
+
backendModels: "\u5E95\u5C42\u63A7\u5236\u6A21\u578B:",
|
|
1077
|
+
collaboration: "\u534F\u4F5C\u6A21\u5F0F:",
|
|
1078
|
+
workflows: "\u5DE5\u4F5C\u6D41:",
|
|
1079
|
+
selected: "\u4E2A\u5DF2\u9009\u62E9"
|
|
1080
|
+
},
|
|
1081
|
+
modes: {
|
|
1082
|
+
parallel: "\u5E76\u884C\u6A21\u5F0F - \u540C\u65F6\u8C03\u7528\u591A\u4E2A\u6A21\u578B",
|
|
1083
|
+
smart: "\u667A\u80FD\u6A21\u5F0F - \u6839\u636E\u4EFB\u52A1\u7C7B\u578B\u81EA\u52A8\u9009\u62E9",
|
|
1084
|
+
sequential: "\u987A\u5E8F\u6A21\u5F0F - \u4F9D\u6B21\u8C03\u7528\u6A21\u578B"
|
|
1085
|
+
},
|
|
1086
|
+
models: {
|
|
1087
|
+
codex: "Codex - \u64C5\u957F\u5E95\u5C42\u63A7\u5236\u3001C++\u3001\u786C\u4EF6\u9A71\u52A8\u3001\u5B9E\u65F6\u7B97\u6CD5",
|
|
1088
|
+
gemini: "Gemini - \u64C5\u957F\u4E0A\u5C42\u5E94\u7528\u3001Launch\u3001Python\u3001RViz\u914D\u7F6E",
|
|
1089
|
+
claude: "Claude - \u64C5\u957F\u7F16\u6392\u3001\u91CD\u6784\u3001\u6587\u6863\u751F\u6210"
|
|
1090
|
+
},
|
|
1091
|
+
workflows: {
|
|
1092
|
+
dev: "\u5B8C\u6574\u5F00\u53D1\u5DE5\u4F5C\u6D41 (/ccg:dev)",
|
|
1093
|
+
frontend: "\u4E0A\u5C42\u5E94\u7528\u4EFB\u52A1 (/ccg:frontend)",
|
|
1094
|
+
backend: "\u5E95\u5C42\u63A7\u5236\u4EFB\u52A1 (/ccg:backend)",
|
|
1095
|
+
review: "\u4EE3\u7801\u5BA1\u67E5 (/ccg:review)",
|
|
1096
|
+
analyze: "\u6280\u672F\u5206\u6790 (/ccg:analyze)",
|
|
1097
|
+
commit: "Git \u667A\u80FD\u63D0\u4EA4 (/ccg:commit)",
|
|
1098
|
+
rollback: "Git \u56DE\u6EDA (/ccg:rollback)",
|
|
1099
|
+
cleanBranches: "\u6E05\u7406\u5206\u652F (/ccg:clean-branches)",
|
|
1100
|
+
worktree: "Worktree \u7BA1\u7406 (/ccg:worktree)",
|
|
1101
|
+
init: "\u9879\u76EE\u521D\u59CB\u5316 (/ccg:init)"
|
|
1102
|
+
},
|
|
1103
|
+
aceTool: {
|
|
1104
|
+
title: "ace-tool MCP \u914D\u7F6E",
|
|
1105
|
+
description: "\u8F7B\u91CF\u7EA7\u4EE3\u7801\u68C0\u7D22\u548C Prompt \u589E\u5F3A\u5DE5\u5177",
|
|
1106
|
+
getToken: "\u83B7\u53D6 Token",
|
|
1107
|
+
configure: "\u662F\u5426\u914D\u7F6E ace-tool MCP\uFF1F",
|
|
1108
|
+
baseUrl: "API Base URL:",
|
|
1109
|
+
token: "API Token:",
|
|
1110
|
+
installing: "\u6B63\u5728\u914D\u7F6E ace-tool MCP...",
|
|
1111
|
+
failed: "ace-tool \u914D\u7F6E\u5931\u8D25\uFF08\u53EF\u7A0D\u540E\u624B\u52A8\u914D\u7F6E\uFF09"
|
|
1112
|
+
},
|
|
1113
|
+
aceToolRs: {
|
|
1114
|
+
title: "ace-tool-rs MCP \u914D\u7F6E",
|
|
1115
|
+
description: "Rust \u5B9E\u73B0\u7684 ace-tool\uFF0C\u66F4\u8F7B\u91CF\u3001\u66F4\u5FEB\u901F",
|
|
1116
|
+
getToken: "\u83B7\u53D6 Token",
|
|
1117
|
+
configure: "\u662F\u5426\u914D\u7F6E ace-tool-rs MCP\uFF1F",
|
|
1118
|
+
baseUrl: "API Base URL:",
|
|
1119
|
+
token: "API Token:",
|
|
1120
|
+
installing: "\u6B63\u5728\u914D\u7F6E ace-tool-rs MCP...",
|
|
1121
|
+
failed: "ace-tool-rs \u914D\u7F6E\u5931\u8D25\uFF08\u53EF\u7A0D\u540E\u624B\u52A8\u914D\u7F6E\uFF09"
|
|
1122
|
+
}
|
|
1123
|
+
},
|
|
1124
|
+
menu: {
|
|
1125
|
+
title: "CCG-ROS2 \u4E3B\u83DC\u5355",
|
|
1126
|
+
options: {
|
|
1127
|
+
init: "\u521D\u59CB\u5316 CCG-ROS2 \u914D\u7F6E",
|
|
1128
|
+
update: "\u66F4\u65B0\u5DE5\u4F5C\u6D41",
|
|
1129
|
+
uninstall: "\u5378\u8F7D CCG-ROS2",
|
|
1130
|
+
help: "\u5E2E\u52A9",
|
|
1131
|
+
exit: "\u9000\u51FA"
|
|
1132
|
+
},
|
|
1133
|
+
help: {
|
|
1134
|
+
title: "CCG-ROS2 \u547D\u4EE4:",
|
|
1135
|
+
hint: "\u66F4\u591A\u4FE1\u606F\u8BF7\u8FD0\u884C: npx ccg-ros2-workflow --help",
|
|
1136
|
+
descriptions: {
|
|
1137
|
+
dev: "\u5B8C\u6574\u4E03\u9636\u6BB5ROS2\u5F00\u53D1\u5DE5\u4F5C\u6D41",
|
|
1138
|
+
frontend: "\u4E0A\u5C42\u5E94\u7528\u4EFB\u52A1 \u2192 Gemini",
|
|
1139
|
+
backend: "\u5E95\u5C42\u63A7\u5236\u4EFB\u52A1 \u2192 Codex",
|
|
1140
|
+
review: "\u53CC\u6A21\u578B\u4EE3\u7801\u5BA1\u67E5",
|
|
1141
|
+
analyze: "\u53CC\u6A21\u578B\u6280\u672F\u5206\u6790",
|
|
1142
|
+
commit: "Git \u667A\u80FD\u63D0\u4EA4",
|
|
1143
|
+
rollback: "Git \u4EA4\u4E92\u5F0F\u56DE\u6EDA"
|
|
1144
|
+
}
|
|
1145
|
+
},
|
|
1146
|
+
uninstall: {
|
|
1147
|
+
confirm: "\u786E\u5B9A\u8981\u5378\u8F7D CCG-ROS2 \u5417\uFF1F\u8FD9\u5C06\u5F3A\u5236\u79FB\u9664\u6240\u6709\u547D\u4EE4\u76EE\u5F55\u3001\u914D\u7F6E\u6587\u4EF6\u548C\u6570\u636E\u3002",
|
|
1148
|
+
alsoRemoveAceTool: "\u540C\u65F6\u79FB\u9664 ace-tool MCP \u914D\u7F6E\uFF1F",
|
|
1149
|
+
uninstalling: "\u6B63\u5728\u5378\u8F7D...",
|
|
1150
|
+
success: "\u5378\u8F7D\u6210\u529F\uFF01",
|
|
1151
|
+
removedCommands: "\u5DF2\u79FB\u9664\u547D\u4EE4:",
|
|
1152
|
+
removedAceTool: "ace-tool MCP \u914D\u7F6E\u5DF2\u79FB\u9664",
|
|
1153
|
+
cancelled: "\u5378\u8F7D\u5DF2\u53D6\u6D88",
|
|
1154
|
+
failed: "\u5378\u8F7D\u5931\u8D25"
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
const en = {
|
|
1159
|
+
common: {
|
|
1160
|
+
yes: "Yes",
|
|
1161
|
+
no: "No",
|
|
1162
|
+
confirm: "Confirm",
|
|
1163
|
+
cancel: "Cancel",
|
|
1164
|
+
back: "Back",
|
|
1165
|
+
exit: "Exit",
|
|
1166
|
+
success: "Success",
|
|
1167
|
+
error: "Error",
|
|
1168
|
+
warning: "Warning",
|
|
1169
|
+
info: "Info",
|
|
1170
|
+
loading: "Loading...",
|
|
1171
|
+
processing: "Processing...",
|
|
1172
|
+
completed: "Completed",
|
|
1173
|
+
failed: "Failed"
|
|
1174
|
+
},
|
|
1175
|
+
cli: {
|
|
1176
|
+
help: {
|
|
1177
|
+
commands: "Commands",
|
|
1178
|
+
commandDescriptions: {
|
|
1179
|
+
showMenu: "Show interactive menu (default)",
|
|
1180
|
+
initConfig: "Initialize CCG-ROS2 multi-model collaboration system"
|
|
1181
|
+
},
|
|
1182
|
+
shortcuts: "Shortcuts:",
|
|
1183
|
+
shortcutDescriptions: {
|
|
1184
|
+
quickInit: "Quick init"
|
|
1185
|
+
},
|
|
1186
|
+
options: "Options",
|
|
1187
|
+
optionDescriptions: {
|
|
1188
|
+
displayLanguage: "Display language",
|
|
1189
|
+
forceOverwrite: "Force overwrite existing configuration",
|
|
1190
|
+
displayHelp: "Display help",
|
|
1191
|
+
displayVersion: "Display version",
|
|
1192
|
+
skipAllPrompts: "Skip all interactive prompts (non-interactive mode)",
|
|
1193
|
+
frontendModels: "Upper-layer application models (comma-separated)",
|
|
1194
|
+
backendModels: "Low-level control models (comma-separated)",
|
|
1195
|
+
collaborationMode: "Collaboration mode (parallel/smart/sequential)",
|
|
1196
|
+
workflows: "Workflows to install",
|
|
1197
|
+
installDir: "Installation directory"
|
|
1198
|
+
},
|
|
1199
|
+
nonInteractiveMode: "Non-interactive mode:",
|
|
1200
|
+
examples: "Examples",
|
|
1201
|
+
exampleDescriptions: {
|
|
1202
|
+
showInteractiveMenu: "Show interactive menu",
|
|
1203
|
+
runFullInitialization: "Run full initialization",
|
|
1204
|
+
customModels: "Custom model configuration",
|
|
1205
|
+
parallelMode: "Use parallel collaboration mode"
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
},
|
|
1209
|
+
init: {
|
|
1210
|
+
welcome: "Welcome to CCG-ROS2 Multi-Model Collaboration System",
|
|
1211
|
+
selectLanguage: "Select language",
|
|
1212
|
+
selectFrontendModels: "Select models for upper-layer application tasks (multi-select)",
|
|
1213
|
+
selectBackendModels: "Select models for low-level control tasks (multi-select)",
|
|
1214
|
+
selectMode: "Select collaboration mode",
|
|
1215
|
+
selectWorkflows: "Select workflows to install (multi-select)",
|
|
1216
|
+
confirmInstall: "Confirm installation with above configuration?",
|
|
1217
|
+
installing: "Installing...",
|
|
1218
|
+
installSuccess: "Installation successful!",
|
|
1219
|
+
installFailed: "Installation failed",
|
|
1220
|
+
installCancelled: "Installation cancelled",
|
|
1221
|
+
installedCommands: "Installed Commands:",
|
|
1222
|
+
installedPrompts: "Installed Role Prompts:",
|
|
1223
|
+
installedBinary: "Installed Binary:",
|
|
1224
|
+
installationErrors: "Installation Errors:",
|
|
1225
|
+
pathWarning: "codeagent-wrapper needs to be added to PATH",
|
|
1226
|
+
autoConfigurePathPrompt: "Automatically configure PATH environment variable?",
|
|
1227
|
+
pathConfigured: "PATH has been added to {{file}}",
|
|
1228
|
+
pathAlreadyConfigured: "PATH is already configured in {{file}}",
|
|
1229
|
+
pathConfigFailed: "Auto-configuration failed",
|
|
1230
|
+
restartShellPrompt: "Run the following command to apply changes:",
|
|
1231
|
+
manualConfigInstructions: "Please manually add the following to {{file}}:",
|
|
1232
|
+
windowsPathInstructions: "Windows Users - Manually add to System Environment Variables:",
|
|
1233
|
+
windowsStep1: 'Press Win+X, select "System"',
|
|
1234
|
+
windowsStep2: 'Click "Advanced system settings" \u2192 "Environment Variables"',
|
|
1235
|
+
windowsStep3: 'Find "Path" in User variables, click "Edit", add:',
|
|
1236
|
+
windowsStep4: 'Click "OK" to save, restart terminal',
|
|
1237
|
+
orUsePowerShell: "Or run in PowerShell (Admin):",
|
|
1238
|
+
addToShellConfig: "Add the following command to {{file}} and restart your terminal",
|
|
1239
|
+
configSavedTo: "Config saved to:",
|
|
1240
|
+
validation: {
|
|
1241
|
+
selectAtLeastOne: "Please select at least one model"
|
|
1242
|
+
},
|
|
1243
|
+
summary: {
|
|
1244
|
+
title: "Configuration Summary:",
|
|
1245
|
+
frontendModels: "Upper-layer Models:",
|
|
1246
|
+
backendModels: "Low-level Models:",
|
|
1247
|
+
collaboration: "Collaboration:",
|
|
1248
|
+
workflows: "Workflows:",
|
|
1249
|
+
selected: "selected"
|
|
1250
|
+
},
|
|
1251
|
+
modes: {
|
|
1252
|
+
parallel: "Parallel - Call multiple models simultaneously",
|
|
1253
|
+
smart: "Smart - Auto-select based on task type",
|
|
1254
|
+
sequential: "Sequential - Call models one by one"
|
|
1255
|
+
},
|
|
1256
|
+
models: {
|
|
1257
|
+
codex: "Codex - Low-level control, C++, hardware drivers, realtime algorithms",
|
|
1258
|
+
gemini: "Gemini - Upper-layer application, Launch, Python, RViz config",
|
|
1259
|
+
claude: "Claude - Orchestration, refactoring, documentation"
|
|
1260
|
+
},
|
|
1261
|
+
workflows: {
|
|
1262
|
+
dev: "Full development workflow (/ccg:dev)",
|
|
1263
|
+
frontend: "Upper-layer application tasks (/ccg:frontend)",
|
|
1264
|
+
backend: "Low-level control tasks (/ccg:backend)",
|
|
1265
|
+
review: "Code review (/ccg:review)",
|
|
1266
|
+
analyze: "Technical analysis (/ccg:analyze)",
|
|
1267
|
+
commit: "Git smart commit (/ccg:commit)",
|
|
1268
|
+
rollback: "Git rollback (/ccg:rollback)",
|
|
1269
|
+
cleanBranches: "Clean branches (/ccg:clean-branches)",
|
|
1270
|
+
worktree: "Worktree management (/ccg:worktree)",
|
|
1271
|
+
init: "Project initialization (/ccg:init)"
|
|
1272
|
+
},
|
|
1273
|
+
aceTool: {
|
|
1274
|
+
title: "ace-tool MCP Configuration",
|
|
1275
|
+
description: "Lightweight codebase retrieval and prompt enhancement tool",
|
|
1276
|
+
getToken: "Get Token",
|
|
1277
|
+
configure: "Configure ace-tool MCP?",
|
|
1278
|
+
baseUrl: "API Base URL:",
|
|
1279
|
+
token: "API Token:",
|
|
1280
|
+
installing: "Configuring ace-tool MCP...",
|
|
1281
|
+
failed: "ace-tool configuration failed (can be configured manually later)"
|
|
1282
|
+
},
|
|
1283
|
+
aceToolRs: {
|
|
1284
|
+
title: "ace-tool-rs MCP Configuration",
|
|
1285
|
+
description: "Rust implementation of ace-tool, more lightweight and faster",
|
|
1286
|
+
getToken: "Get Token",
|
|
1287
|
+
configure: "Configure ace-tool-rs MCP?",
|
|
1288
|
+
baseUrl: "API Base URL:",
|
|
1289
|
+
token: "API Token:",
|
|
1290
|
+
installing: "Configuring ace-tool-rs MCP...",
|
|
1291
|
+
failed: "ace-tool-rs configuration failed (can be configured manually later)"
|
|
1292
|
+
}
|
|
1293
|
+
},
|
|
1294
|
+
menu: {
|
|
1295
|
+
title: "CCG-ROS2 Main Menu",
|
|
1296
|
+
options: {
|
|
1297
|
+
init: "Initialize CCG-ROS2 configuration",
|
|
1298
|
+
update: "Update workflows",
|
|
1299
|
+
uninstall: "Uninstall CCG-ROS2",
|
|
1300
|
+
help: "Help",
|
|
1301
|
+
exit: "Exit"
|
|
1302
|
+
},
|
|
1303
|
+
help: {
|
|
1304
|
+
title: "CCG-ROS2 Commands:",
|
|
1305
|
+
hint: "For more information, run: npx ccg-ros2-workflow --help",
|
|
1306
|
+
descriptions: {
|
|
1307
|
+
dev: "Complete 7-phase ROS2 development workflow",
|
|
1308
|
+
frontend: "Upper-layer application tasks \u2192 Gemini",
|
|
1309
|
+
backend: "Low-level control tasks \u2192 Codex",
|
|
1310
|
+
review: "Dual-model code review",
|
|
1311
|
+
analyze: "Dual-model technical analysis",
|
|
1312
|
+
commit: "Git smart commit",
|
|
1313
|
+
rollback: "Git interactive rollback"
|
|
1314
|
+
}
|
|
1315
|
+
},
|
|
1316
|
+
uninstall: {
|
|
1317
|
+
confirm: "Are you sure you want to uninstall CCG-ROS2? This will force remove all command directories, config files and data.",
|
|
1318
|
+
alsoRemoveAceTool: "Also remove ace-tool MCP configuration?",
|
|
1319
|
+
uninstalling: "Uninstalling...",
|
|
1320
|
+
success: "Uninstallation successful!",
|
|
1321
|
+
removedCommands: "Removed commands:",
|
|
1322
|
+
removedAceTool: "ace-tool MCP configuration removed",
|
|
1323
|
+
cancelled: "Uninstallation cancelled",
|
|
1324
|
+
failed: "Uninstallation failed"
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
async function initI18n(lang = "zh-CN") {
|
|
1329
|
+
if (!i18n.isInitialized) {
|
|
1330
|
+
await i18n.init({
|
|
1331
|
+
lng: lang,
|
|
1332
|
+
fallbackLng: "en",
|
|
1333
|
+
resources: {
|
|
1334
|
+
"zh-CN": { translation: zhCN, ...zhCN },
|
|
1335
|
+
en: { translation: en, ...en }
|
|
1336
|
+
},
|
|
1337
|
+
interpolation: {
|
|
1338
|
+
escapeValue: false
|
|
1339
|
+
}
|
|
1340
|
+
});
|
|
1341
|
+
} else if (i18n.language !== lang) {
|
|
1342
|
+
await i18n.changeLanguage(lang);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
async function changeLanguage(lang) {
|
|
1346
|
+
await i18n.changeLanguage(lang);
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
const CCG_DIR = join(homedir(), ".claude", ".ccg");
|
|
1350
|
+
const CONFIG_FILE = join(CCG_DIR, "config.toml");
|
|
1351
|
+
function getCcgDir() {
|
|
1352
|
+
return CCG_DIR;
|
|
1353
|
+
}
|
|
1354
|
+
function getConfigPath() {
|
|
1355
|
+
return CONFIG_FILE;
|
|
1356
|
+
}
|
|
1357
|
+
async function ensureCcgDir() {
|
|
1358
|
+
await fs.ensureDir(CCG_DIR);
|
|
1359
|
+
}
|
|
1360
|
+
async function readCcgConfig() {
|
|
1361
|
+
try {
|
|
1362
|
+
if (await fs.pathExists(CONFIG_FILE)) {
|
|
1363
|
+
const content = await fs.readFile(CONFIG_FILE, "utf-8");
|
|
1364
|
+
return parse(content);
|
|
1365
|
+
}
|
|
1366
|
+
} catch {
|
|
1367
|
+
}
|
|
1368
|
+
return null;
|
|
1369
|
+
}
|
|
1370
|
+
async function writeCcgConfig(config) {
|
|
1371
|
+
await ensureCcgDir();
|
|
1372
|
+
const content = stringify(config);
|
|
1373
|
+
await fs.writeFile(CONFIG_FILE, content, "utf-8");
|
|
1374
|
+
}
|
|
1375
|
+
function createDefaultConfig(options) {
|
|
1376
|
+
return {
|
|
1377
|
+
general: {
|
|
1378
|
+
version: version,
|
|
1379
|
+
language: options.language,
|
|
1380
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1381
|
+
},
|
|
1382
|
+
ros2: {
|
|
1383
|
+
distro: "humble",
|
|
1384
|
+
// ROS2 Humble Hawksbill (LTS)
|
|
1385
|
+
target: "physical_robot"
|
|
1386
|
+
// 目标平台: physical_robot | simulation | desktop
|
|
1387
|
+
},
|
|
1388
|
+
routing: options.routing,
|
|
1389
|
+
workflows: {
|
|
1390
|
+
installed: options.installedWorkflows
|
|
1391
|
+
},
|
|
1392
|
+
paths: {
|
|
1393
|
+
commands: join(homedir(), ".claude", "commands", "ccg"),
|
|
1394
|
+
prompts: join(CCG_DIR, "prompts"),
|
|
1395
|
+
// v1.4.0: 移到配置目录
|
|
1396
|
+
backup: join(CCG_DIR, "backup")
|
|
1397
|
+
},
|
|
1398
|
+
mcp: {
|
|
1399
|
+
provider: options.mcpProvider || "ace-tool",
|
|
1400
|
+
setup_url: "https://augmentcode.com/"
|
|
1401
|
+
},
|
|
1402
|
+
performance: {
|
|
1403
|
+
liteMode: options.liteMode || false
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1407
|
+
function createDefaultRouting() {
|
|
1408
|
+
return {
|
|
1409
|
+
frontend: {
|
|
1410
|
+
models: ["gemini"],
|
|
1411
|
+
primary: "gemini",
|
|
1412
|
+
strategy: "parallel"
|
|
1413
|
+
},
|
|
1414
|
+
backend: {
|
|
1415
|
+
models: ["codex"],
|
|
1416
|
+
primary: "codex",
|
|
1417
|
+
strategy: "parallel"
|
|
1418
|
+
},
|
|
1419
|
+
review: {
|
|
1420
|
+
models: ["codex", "gemini"],
|
|
1421
|
+
strategy: "parallel"
|
|
1422
|
+
},
|
|
1423
|
+
mode: "smart"
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
async function migrateToV1_4_0() {
|
|
1428
|
+
const result = {
|
|
1429
|
+
success: true,
|
|
1430
|
+
migratedFiles: [],
|
|
1431
|
+
errors: [],
|
|
1432
|
+
skipped: []
|
|
1433
|
+
};
|
|
1434
|
+
const oldCcgDir = join(homedir(), ".ccg");
|
|
1435
|
+
const newCcgDir = join(homedir(), ".claude", ".ccg");
|
|
1436
|
+
const oldPromptsDir = join(homedir(), ".claude", "prompts", "ccg");
|
|
1437
|
+
const newPromptsDir = join(newCcgDir, "prompts");
|
|
1438
|
+
try {
|
|
1439
|
+
await fs.ensureDir(newCcgDir);
|
|
1440
|
+
if (await fs.pathExists(oldCcgDir)) {
|
|
1441
|
+
const files = await fs.readdir(oldCcgDir);
|
|
1442
|
+
for (const file of files) {
|
|
1443
|
+
const srcFile = join(oldCcgDir, file);
|
|
1444
|
+
const destFile = join(newCcgDir, file);
|
|
1445
|
+
try {
|
|
1446
|
+
if (await fs.pathExists(destFile)) {
|
|
1447
|
+
result.skipped.push(`~/.ccg/${file} (already exists in new location)`);
|
|
1448
|
+
continue;
|
|
1449
|
+
}
|
|
1450
|
+
await fs.copy(srcFile, destFile);
|
|
1451
|
+
result.migratedFiles.push(`~/.ccg/${file} \u2192 ~/.claude/.ccg/${file}`);
|
|
1452
|
+
} catch (error) {
|
|
1453
|
+
result.errors.push(`Failed to migrate ${file}: ${error}`);
|
|
1454
|
+
result.success = false;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
try {
|
|
1458
|
+
const remaining = await fs.readdir(oldCcgDir);
|
|
1459
|
+
if (remaining.length === 0) {
|
|
1460
|
+
await fs.remove(oldCcgDir);
|
|
1461
|
+
result.migratedFiles.push("Removed old ~/.ccg/ directory");
|
|
1462
|
+
} else {
|
|
1463
|
+
result.skipped.push(`~/.ccg/ (not empty, keeping for safety)`);
|
|
1464
|
+
}
|
|
1465
|
+
} catch (error) {
|
|
1466
|
+
result.skipped.push(`~/.ccg/ (could not remove: ${error})`);
|
|
1467
|
+
}
|
|
1468
|
+
} else {
|
|
1469
|
+
result.skipped.push("~/.ccg/ (does not exist, nothing to migrate)");
|
|
1470
|
+
}
|
|
1471
|
+
if (await fs.pathExists(oldPromptsDir)) {
|
|
1472
|
+
try {
|
|
1473
|
+
if (await fs.pathExists(newPromptsDir)) {
|
|
1474
|
+
result.skipped.push("~/.claude/prompts/ccg/ (already exists in new location)");
|
|
1475
|
+
} else {
|
|
1476
|
+
await fs.copy(oldPromptsDir, newPromptsDir);
|
|
1477
|
+
result.migratedFiles.push("~/.claude/prompts/ccg/ \u2192 ~/.claude/.ccg/prompts/");
|
|
1478
|
+
await fs.remove(oldPromptsDir);
|
|
1479
|
+
result.migratedFiles.push("Removed old ~/.claude/prompts/ccg/ directory");
|
|
1480
|
+
const promptsParentDir = join(homedir(), ".claude", "prompts");
|
|
1481
|
+
const remaining = await fs.readdir(promptsParentDir);
|
|
1482
|
+
if (remaining.length === 0) {
|
|
1483
|
+
await fs.remove(promptsParentDir);
|
|
1484
|
+
result.migratedFiles.push("Removed empty ~/.claude/prompts/ directory");
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
} catch (error) {
|
|
1488
|
+
result.errors.push(`Failed to migrate prompts: ${error}`);
|
|
1489
|
+
result.success = false;
|
|
1490
|
+
}
|
|
1491
|
+
} else {
|
|
1492
|
+
result.skipped.push("~/.claude/prompts/ccg/ (does not exist, nothing to migrate)");
|
|
1493
|
+
}
|
|
1494
|
+
} catch (error) {
|
|
1495
|
+
result.errors.push(`Migration failed: ${error}`);
|
|
1496
|
+
result.success = false;
|
|
1497
|
+
}
|
|
1498
|
+
return result;
|
|
1499
|
+
}
|
|
1500
|
+
async function needsMigration() {
|
|
1501
|
+
const oldCcgDir = join(homedir(), ".ccg");
|
|
1502
|
+
const oldPromptsDir = join(homedir(), ".claude", "prompts", "ccg");
|
|
1503
|
+
const oldConfigFile = join(homedir(), ".claude", "commands", "ccg", "_config.md");
|
|
1504
|
+
const hasOldCcgDir = await fs.pathExists(oldCcgDir);
|
|
1505
|
+
const hasOldPromptsDir = await fs.pathExists(oldPromptsDir);
|
|
1506
|
+
const hasOldConfigFile = await fs.pathExists(oldConfigFile);
|
|
1507
|
+
return hasOldCcgDir || hasOldPromptsDir || hasOldConfigFile;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
async function init(options = {}) {
|
|
1511
|
+
console.log();
|
|
1512
|
+
console.log(ansis.cyan.bold(` CCG-ROS2 - Claude + Codex + Gemini`));
|
|
1513
|
+
console.log(ansis.gray(` ROS2 \u591A\u6A21\u578B\u534F\u4F5C\u5F00\u53D1\u5DE5\u4F5C\u6D41`));
|
|
1514
|
+
console.log();
|
|
1515
|
+
const language = "zh-CN";
|
|
1516
|
+
const frontendModels = ["gemini"];
|
|
1517
|
+
const backendModels = ["codex"];
|
|
1518
|
+
const mode = "smart";
|
|
1519
|
+
const selectedWorkflows = getAllCommandIds();
|
|
1520
|
+
let liteMode = false;
|
|
1521
|
+
let mcpProvider = "ace-tool";
|
|
1522
|
+
let aceToolBaseUrl = "";
|
|
1523
|
+
let aceToolToken = "";
|
|
1524
|
+
if (options.skipMcp) {
|
|
1525
|
+
mcpProvider = "skip";
|
|
1526
|
+
} else if (!options.skipPrompt) {
|
|
1527
|
+
console.log();
|
|
1528
|
+
console.log(ansis.cyan.bold(` \u{1F527} MCP \u5DE5\u5177\u914D\u7F6E`));
|
|
1529
|
+
console.log();
|
|
1530
|
+
const { selectedMcp } = await inquirer.prompt([{
|
|
1531
|
+
type: "list",
|
|
1532
|
+
name: "selectedMcp",
|
|
1533
|
+
message: "\u9009\u62E9 MCP \u5DE5\u5177",
|
|
1534
|
+
choices: [
|
|
1535
|
+
{
|
|
1536
|
+
name: `ace-tool ${ansis.gray("(Node.js \u5B9E\u73B0) - \u4E00\u952E\u5B89\u88C5\uFF0C\u542B Prompt \u589E\u5F3A + \u4EE3\u7801\u68C0\u7D22")}`,
|
|
1537
|
+
value: "ace-tool"
|
|
1538
|
+
},
|
|
1539
|
+
{
|
|
1540
|
+
name: `ace-tool-rs ${ansis.green("(\u63A8\u8350)")} ${ansis.gray("(Rust \u5B9E\u73B0) - \u66F4\u8F7B\u91CF\u3001\u66F4\u5FEB\u901F")}`,
|
|
1541
|
+
value: "ace-tool-rs"
|
|
1542
|
+
},
|
|
1543
|
+
{
|
|
1544
|
+
name: `\u8DF3\u8FC7 ${ansis.gray("- \u7A0D\u540E\u624B\u52A8\u914D\u7F6E\uFF08\u53EF\u9009 auggie \u7B49\u5176\u4ED6 MCP\uFF09")}`,
|
|
1545
|
+
value: "skip"
|
|
1546
|
+
}
|
|
1547
|
+
],
|
|
1548
|
+
default: "ace-tool-rs"
|
|
1549
|
+
}]);
|
|
1550
|
+
mcpProvider = selectedMcp;
|
|
1551
|
+
if (selectedMcp === "ace-tool" || selectedMcp === "ace-tool-rs") {
|
|
1552
|
+
const toolName = selectedMcp === "ace-tool-rs" ? "ace-tool-rs" : "ace-tool";
|
|
1553
|
+
const toolDesc = selectedMcp === "ace-tool-rs" ? i18n.t("init:aceToolRs.description") : i18n.t("init:aceTool.description");
|
|
1554
|
+
console.log();
|
|
1555
|
+
console.log(ansis.cyan.bold(` \u{1F527} ${toolName} MCP \u914D\u7F6E`));
|
|
1556
|
+
console.log(ansis.gray(` ${toolDesc}`));
|
|
1557
|
+
console.log();
|
|
1558
|
+
const { skipToken } = await inquirer.prompt([{
|
|
1559
|
+
type: "confirm",
|
|
1560
|
+
name: "skipToken",
|
|
1561
|
+
message: "\u662F\u5426\u8DF3\u8FC7 Token \u914D\u7F6E\uFF1F\uFF08\u53EF\u7A0D\u540E\u8FD0\u884C npx ccg config mcp \u914D\u7F6E\uFF09",
|
|
1562
|
+
default: false
|
|
1563
|
+
}]);
|
|
1564
|
+
if (!skipToken) {
|
|
1565
|
+
console.log();
|
|
1566
|
+
console.log(ansis.cyan(` \u{1F4D6} \u83B7\u53D6 ace-tool \u8BBF\u95EE\u65B9\u5F0F\uFF1A`));
|
|
1567
|
+
console.log();
|
|
1568
|
+
console.log(` ${ansis.gray("\u2022")} ${ansis.cyan("\u5B98\u65B9\u670D\u52A1")}: ${ansis.underline("https://augmentcode.com/")}`);
|
|
1569
|
+
console.log(` ${ansis.gray("\u6CE8\u518C\u8D26\u53F7\u540E\u83B7\u53D6 Token")}`);
|
|
1570
|
+
console.log();
|
|
1571
|
+
console.log(` ${ansis.gray("\u2022")} ${ansis.cyan("\u4E2D\u8F6C\u670D\u52A1")} ${ansis.yellow("(\u65E0\u9700\u6CE8\u518C)")}: ${ansis.underline("https://linux.do/t/topic/1291730")}`);
|
|
1572
|
+
console.log(` ${ansis.gray("linux.do \u793E\u533A\u63D0\u4F9B\u7684\u514D\u8D39\u4E2D\u8F6C\u670D\u52A1")}`);
|
|
1573
|
+
console.log();
|
|
1574
|
+
const aceAnswers = await inquirer.prompt([
|
|
1575
|
+
{
|
|
1576
|
+
type: "input",
|
|
1577
|
+
name: "baseUrl",
|
|
1578
|
+
message: `Base URL ${ansis.gray("(\u4F7F\u7528\u4E2D\u8F6C\u670D\u52A1\u65F6\u5FC5\u586B\uFF0C\u5B98\u65B9\u670D\u52A1\u7559\u7A7A)")}`,
|
|
1579
|
+
default: ""
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
type: "password",
|
|
1583
|
+
name: "token",
|
|
1584
|
+
message: `Token ${ansis.gray("(\u5FC5\u586B)")}`,
|
|
1585
|
+
mask: "*",
|
|
1586
|
+
validate: (input) => input.trim() !== "" || "\u8BF7\u8F93\u5165 Token"
|
|
1587
|
+
}
|
|
1588
|
+
]);
|
|
1589
|
+
aceToolBaseUrl = aceAnswers.baseUrl || "";
|
|
1590
|
+
aceToolToken = aceAnswers.token || "";
|
|
1591
|
+
} else {
|
|
1592
|
+
console.log();
|
|
1593
|
+
console.log(ansis.yellow(` \u2139\uFE0F \u5DF2\u8DF3\u8FC7 Token \u914D\u7F6E`));
|
|
1594
|
+
console.log(ansis.gray(` \u2022 ace-tool MCP \u5C06\u4E0D\u4F1A\u81EA\u52A8\u5B89\u88C5`));
|
|
1595
|
+
console.log(ansis.gray(` \u2022 \u53EF\u7A0D\u540E\u8FD0\u884C ${ansis.cyan("npx ccg config mcp")} \u914D\u7F6E Token`));
|
|
1596
|
+
console.log(ansis.gray(` \u2022 \u83B7\u53D6 Token: ${ansis.cyan("https://augmentcode.com/")}`));
|
|
1597
|
+
console.log();
|
|
1598
|
+
}
|
|
1599
|
+
} else {
|
|
1600
|
+
console.log();
|
|
1601
|
+
console.log(ansis.yellow(` \u2139\uFE0F \u5DF2\u8DF3\u8FC7 MCP \u914D\u7F6E`));
|
|
1602
|
+
console.log(ansis.gray(` \u2022 \u53EF\u7A0D\u540E\u624B\u52A8\u914D\u7F6E\u4EFB\u4F55 MCP \u670D\u52A1`));
|
|
1603
|
+
console.log();
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
if (!options.skipPrompt) {
|
|
1607
|
+
const existingConfig = await readCcgConfig();
|
|
1608
|
+
const currentLiteMode = existingConfig?.performance?.liteMode || false;
|
|
1609
|
+
console.log();
|
|
1610
|
+
const { enableWebUI } = await inquirer.prompt([{
|
|
1611
|
+
type: "confirm",
|
|
1612
|
+
name: "enableWebUI",
|
|
1613
|
+
message: `\u542F\u7528 Web UI \u5B9E\u65F6\u8F93\u51FA\uFF1F${ansis.gray("(\u7981\u7528\u53EF\u52A0\u901F\u54CD\u5E94)")}`,
|
|
1614
|
+
default: !currentLiteMode
|
|
1615
|
+
// Default to current setting (inverted)
|
|
1616
|
+
}]);
|
|
1617
|
+
liteMode = !enableWebUI;
|
|
1618
|
+
} else {
|
|
1619
|
+
const existingConfig = await readCcgConfig();
|
|
1620
|
+
if (existingConfig?.performance?.liteMode !== void 0) {
|
|
1621
|
+
liteMode = existingConfig.performance.liteMode;
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
const routing = {
|
|
1625
|
+
frontend: {
|
|
1626
|
+
models: frontendModels,
|
|
1627
|
+
primary: "gemini",
|
|
1628
|
+
strategy: "fallback"
|
|
1629
|
+
},
|
|
1630
|
+
backend: {
|
|
1631
|
+
models: backendModels,
|
|
1632
|
+
primary: "codex",
|
|
1633
|
+
strategy: "fallback"
|
|
1634
|
+
},
|
|
1635
|
+
review: {
|
|
1636
|
+
models: ["codex", "gemini"],
|
|
1637
|
+
strategy: "parallel"
|
|
1638
|
+
},
|
|
1639
|
+
mode
|
|
1640
|
+
};
|
|
1641
|
+
console.log();
|
|
1642
|
+
console.log(ansis.yellow("\u2501".repeat(50)));
|
|
1643
|
+
console.log(ansis.bold(` ${i18n.t("init:summary.title")}`));
|
|
1644
|
+
console.log();
|
|
1645
|
+
console.log(` ${ansis.cyan("\u76EE\u6807\u5E73\u53F0")} ${ansis.green("ROS2 Humble")} \u7269\u7406\u673A\u5668\u4EBA`);
|
|
1646
|
+
console.log(` ${ansis.cyan("\u6A21\u578B\u8DEF\u7531")} ${ansis.green("Gemini")} (\u4E0A\u5C42\u5E94\u7528) + ${ansis.blue("Codex")} (\u5E95\u5C42\u63A7\u5236)`);
|
|
1647
|
+
console.log(` ${ansis.cyan("\u547D\u4EE4\u6570\u91CF")} ${ansis.yellow(selectedWorkflows.length.toString())} \u4E2A`);
|
|
1648
|
+
console.log(` ${ansis.cyan("MCP \u5DE5\u5177")} ${mcpProvider === "ace-tool" || mcpProvider === "ace-tool-rs" ? aceToolToken ? ansis.green(mcpProvider) : ansis.yellow(`${mcpProvider} (\u5F85\u914D\u7F6E)`) : ansis.gray("\u8DF3\u8FC7")}`);
|
|
1649
|
+
console.log(` ${ansis.cyan("Web UI")} ${liteMode ? ansis.gray("\u7981\u7528") : ansis.green("\u542F\u7528")}`);
|
|
1650
|
+
console.log(ansis.yellow("\u2501".repeat(50)));
|
|
1651
|
+
console.log();
|
|
1652
|
+
if (!options.skipPrompt && !options.force) {
|
|
1653
|
+
const { confirmed } = await inquirer.prompt([{
|
|
1654
|
+
type: "confirm",
|
|
1655
|
+
name: "confirmed",
|
|
1656
|
+
message: i18n.t("init:confirmInstall"),
|
|
1657
|
+
default: true
|
|
1658
|
+
}]);
|
|
1659
|
+
if (!confirmed) {
|
|
1660
|
+
console.log(ansis.yellow(i18n.t("init:installCancelled")));
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
const spinner = ora(i18n.t("init:installing")).start();
|
|
1665
|
+
try {
|
|
1666
|
+
if (await needsMigration()) {
|
|
1667
|
+
spinner.text = "Migrating from v1.3.x to v1.4.0...";
|
|
1668
|
+
const migrationResult = await migrateToV1_4_0();
|
|
1669
|
+
if (migrationResult.migratedFiles.length > 0) {
|
|
1670
|
+
spinner.info(ansis.cyan("Migration completed:"));
|
|
1671
|
+
console.log();
|
|
1672
|
+
for (const file of migrationResult.migratedFiles) {
|
|
1673
|
+
console.log(` ${ansis.green("\u2713")} ${file}`);
|
|
1674
|
+
}
|
|
1675
|
+
if (migrationResult.skipped.length > 0) {
|
|
1676
|
+
console.log();
|
|
1677
|
+
console.log(ansis.gray(" Skipped:"));
|
|
1678
|
+
for (const file of migrationResult.skipped) {
|
|
1679
|
+
console.log(` ${ansis.gray("\u25CB")} ${file}`);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
console.log();
|
|
1683
|
+
spinner.start(i18n.t("init:installing"));
|
|
1684
|
+
}
|
|
1685
|
+
if (migrationResult.errors.length > 0) {
|
|
1686
|
+
spinner.warn(ansis.yellow("Migration completed with errors:"));
|
|
1687
|
+
for (const error of migrationResult.errors) {
|
|
1688
|
+
console.log(` ${ansis.red("\u2717")} ${error}`);
|
|
1689
|
+
}
|
|
1690
|
+
console.log();
|
|
1691
|
+
spinner.start(i18n.t("init:installing"));
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
await ensureCcgDir();
|
|
1695
|
+
const config = createDefaultConfig({
|
|
1696
|
+
language,
|
|
1697
|
+
routing,
|
|
1698
|
+
installedWorkflows: selectedWorkflows,
|
|
1699
|
+
mcpProvider,
|
|
1700
|
+
liteMode
|
|
1701
|
+
});
|
|
1702
|
+
await writeCcgConfig(config);
|
|
1703
|
+
const installDir = options.installDir || join(homedir(), ".claude");
|
|
1704
|
+
const result = await installWorkflows(selectedWorkflows, installDir, options.force, {
|
|
1705
|
+
routing,
|
|
1706
|
+
liteMode
|
|
1707
|
+
});
|
|
1708
|
+
if ((mcpProvider === "ace-tool" || mcpProvider === "ace-tool-rs") && aceToolToken) {
|
|
1709
|
+
const toolName = mcpProvider === "ace-tool-rs" ? "ace-tool-rs" : "ace-tool";
|
|
1710
|
+
const installFn = mcpProvider === "ace-tool-rs" ? installAceToolRs : installAceTool;
|
|
1711
|
+
spinner.text = mcpProvider === "ace-tool-rs" ? i18n.t("init:aceToolRs.installing") : i18n.t("init:aceTool.installing");
|
|
1712
|
+
const aceResult = await installFn({
|
|
1713
|
+
baseUrl: aceToolBaseUrl,
|
|
1714
|
+
token: aceToolToken
|
|
1715
|
+
});
|
|
1716
|
+
if (aceResult.success) {
|
|
1717
|
+
spinner.succeed(ansis.green(i18n.t("init:installSuccess")));
|
|
1718
|
+
console.log();
|
|
1719
|
+
console.log(` ${ansis.green("\u2713")} ${toolName} MCP ${ansis.gray(`\u2192 ${aceResult.configPath}`)}`);
|
|
1720
|
+
} else {
|
|
1721
|
+
spinner.warn(ansis.yellow(mcpProvider === "ace-tool-rs" ? i18n.t("init:aceToolRs.failed") : i18n.t("init:aceTool.failed")));
|
|
1722
|
+
console.log(ansis.gray(` ${aceResult.message}`));
|
|
1723
|
+
}
|
|
1724
|
+
} else if ((mcpProvider === "ace-tool" || mcpProvider === "ace-tool-rs") && !aceToolToken) {
|
|
1725
|
+
const toolName = mcpProvider === "ace-tool-rs" ? "ace-tool-rs" : "ace-tool";
|
|
1726
|
+
spinner.succeed(ansis.green(i18n.t("init:installSuccess")));
|
|
1727
|
+
console.log();
|
|
1728
|
+
console.log(` ${ansis.yellow("\u26A0")} ${toolName} MCP \u672A\u5B89\u88C5 ${ansis.gray("(Token \u672A\u63D0\u4F9B)")}`);
|
|
1729
|
+
console.log(` ${ansis.gray("\u2192")} \u7A0D\u540E\u8FD0\u884C ${ansis.cyan("npx ccg config mcp")} \u5B8C\u6210\u914D\u7F6E`);
|
|
1730
|
+
} else {
|
|
1731
|
+
spinner.succeed(ansis.green(i18n.t("init:installSuccess")));
|
|
1732
|
+
}
|
|
1733
|
+
console.log();
|
|
1734
|
+
console.log(ansis.cyan(` ${i18n.t("init:installedCommands")}`));
|
|
1735
|
+
result.installedCommands.forEach((cmd) => {
|
|
1736
|
+
console.log(` ${ansis.green("\u2713")} /ccg:${cmd}`);
|
|
1737
|
+
});
|
|
1738
|
+
if (result.installedPrompts.length > 0) {
|
|
1739
|
+
console.log();
|
|
1740
|
+
console.log(ansis.cyan(` ${i18n.t("init:installedPrompts")}`));
|
|
1741
|
+
const grouped = {};
|
|
1742
|
+
result.installedPrompts.forEach((p) => {
|
|
1743
|
+
const [model, role] = p.split("/");
|
|
1744
|
+
if (!grouped[model])
|
|
1745
|
+
grouped[model] = [];
|
|
1746
|
+
grouped[model].push(role);
|
|
1747
|
+
});
|
|
1748
|
+
Object.entries(grouped).forEach(([model, roles]) => {
|
|
1749
|
+
console.log(` ${ansis.green("\u2713")} ${model}: ${roles.join(", ")}`);
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
if (result.errors.length > 0) {
|
|
1753
|
+
console.log();
|
|
1754
|
+
console.log(ansis.red(` \u26A0 ${i18n.t("init:installationErrors")}`));
|
|
1755
|
+
result.errors.forEach((error) => {
|
|
1756
|
+
console.log(` ${ansis.red("\u2717")} ${error}`);
|
|
1757
|
+
});
|
|
1758
|
+
}
|
|
1759
|
+
if (result.binInstalled && result.binPath) {
|
|
1760
|
+
console.log();
|
|
1761
|
+
console.log(ansis.cyan(` ${i18n.t("init:installedBinary")}`));
|
|
1762
|
+
console.log(` ${ansis.green("\u2713")} codeagent-wrapper ${ansis.gray(`\u2192 ${result.binPath}`)}`);
|
|
1763
|
+
const platform = process.platform;
|
|
1764
|
+
if (platform === "win32") {
|
|
1765
|
+
const windowsPath = result.binPath.replace(/\//g, "\\").replace(/\\$/, "");
|
|
1766
|
+
try {
|
|
1767
|
+
const { execSync } = await import('node:child_process');
|
|
1768
|
+
const psFlags = "-NoProfile -NonInteractive -ExecutionPolicy Bypass";
|
|
1769
|
+
const currentPath = execSync(`powershell ${psFlags} -Command "[System.Environment]::GetEnvironmentVariable('PATH', 'User')"`, { encoding: "utf-8" }).trim();
|
|
1770
|
+
const currentPathNorm = currentPath.toLowerCase().replace(/\\$/g, "");
|
|
1771
|
+
const windowsPathNorm = windowsPath.toLowerCase();
|
|
1772
|
+
if (!currentPathNorm.includes(windowsPathNorm) && !currentPathNorm.includes(".claude\\bin")) {
|
|
1773
|
+
const escapedPath = windowsPath.replace(/'/g, "''");
|
|
1774
|
+
const psScript = currentPath ? `$p=[System.Environment]::GetEnvironmentVariable('PATH','User');[System.Environment]::SetEnvironmentVariable('PATH',($p+';'+'${escapedPath}'),'User')` : `[System.Environment]::SetEnvironmentVariable('PATH','${escapedPath}','User')`;
|
|
1775
|
+
execSync(`powershell ${psFlags} -Command "${psScript}"`, { stdio: "pipe" });
|
|
1776
|
+
console.log(` ${ansis.green("\u2713")} PATH ${ansis.gray("\u2192 \u7528\u6237\u73AF\u5883\u53D8\u91CF")}`);
|
|
1777
|
+
}
|
|
1778
|
+
} catch {
|
|
1779
|
+
}
|
|
1780
|
+
} else if (!options.skipPrompt) {
|
|
1781
|
+
const exportCommand = `export PATH="${result.binPath}:$PATH"`;
|
|
1782
|
+
const shell = process.env.SHELL || "";
|
|
1783
|
+
const isZsh = shell.includes("zsh");
|
|
1784
|
+
const isBash = shell.includes("bash");
|
|
1785
|
+
const isMacDefaultZsh = process.platform === "darwin" && !shell;
|
|
1786
|
+
if (isZsh || isBash || isMacDefaultZsh) {
|
|
1787
|
+
const shellRc = isZsh || isMacDefaultZsh ? join(homedir(), ".zshrc") : join(homedir(), ".bashrc");
|
|
1788
|
+
const shellRcDisplay = isZsh || isMacDefaultZsh ? "~/.zshrc" : "~/.bashrc";
|
|
1789
|
+
try {
|
|
1790
|
+
let rcContent = "";
|
|
1791
|
+
if (await fs.pathExists(shellRc)) {
|
|
1792
|
+
rcContent = await fs.readFile(shellRc, "utf-8");
|
|
1793
|
+
}
|
|
1794
|
+
if (rcContent.includes(result.binPath) || rcContent.includes("/.claude/bin")) {
|
|
1795
|
+
console.log(` ${ansis.green("\u2713")} PATH ${ansis.gray(`\u2192 ${shellRcDisplay} (\u5DF2\u914D\u7F6E)`)}`);
|
|
1796
|
+
} else {
|
|
1797
|
+
const configLine = `
|
|
1798
|
+
# CCG multi-model collaboration system
|
|
1799
|
+
${exportCommand}
|
|
1800
|
+
`;
|
|
1801
|
+
await fs.appendFile(shellRc, configLine, "utf-8");
|
|
1802
|
+
console.log(` ${ansis.green("\u2713")} PATH ${ansis.gray(`\u2192 ${shellRcDisplay}`)}`);
|
|
1803
|
+
}
|
|
1804
|
+
} catch {
|
|
1805
|
+
}
|
|
1806
|
+
} else {
|
|
1807
|
+
console.log(` ${ansis.yellow("\u26A0")} PATH ${ansis.gray("\u2192 \u8BF7\u624B\u52A8\u6DFB\u52A0\u5230 shell \u914D\u7F6E:")}`);
|
|
1808
|
+
console.log(` ${ansis.cyan(exportCommand)}`);
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
if (mcpProvider === "skip" || (mcpProvider === "ace-tool" || mcpProvider === "ace-tool-rs") && !aceToolToken) {
|
|
1813
|
+
console.log();
|
|
1814
|
+
console.log(ansis.cyan.bold(` \u{1F4D6} MCP \u670D\u52A1\u9009\u9879`));
|
|
1815
|
+
console.log();
|
|
1816
|
+
console.log(ansis.gray(` \u5982\u9700\u4F7F\u7528\u4EE3\u7801\u68C0\u7D22\u548C Prompt \u589E\u5F3A\u529F\u80FD\uFF0C\u53EF\u9009\u62E9\u4EE5\u4E0B MCP \u670D\u52A1\uFF1A`));
|
|
1817
|
+
console.log();
|
|
1818
|
+
console.log(` ${ansis.green("1.")} ${ansis.cyan("ace-tool")} ${ansis.gray("(\u63A8\u8350)")}: ${ansis.underline("https://augmentcode.com/")}`);
|
|
1819
|
+
console.log(` ${ansis.gray("\u4E00\u952E\u5B89\u88C5\uFF0C\u542B Prompt \u589E\u5F3A + \u4EE3\u7801\u68C0\u7D22")}`);
|
|
1820
|
+
console.log();
|
|
1821
|
+
console.log(` ${ansis.green("2.")} ${ansis.cyan("ace-tool \u4E2D\u8F6C\u670D\u52A1")} ${ansis.yellow("(\u65E0\u9700\u6CE8\u518C)")}: ${ansis.underline("https://linux.do/t/topic/1291730")}`);
|
|
1822
|
+
console.log(` ${ansis.gray("linux.do \u793E\u533A\u63D0\u4F9B\u7684\u514D\u8D39\u4E2D\u8F6C\u670D\u52A1")}`);
|
|
1823
|
+
console.log();
|
|
1824
|
+
}
|
|
1825
|
+
console.log();
|
|
1826
|
+
} catch (error) {
|
|
1827
|
+
spinner.fail(ansis.red(i18n.t("init:installFailed")));
|
|
1828
|
+
console.error(error);
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
const execAsync$2 = promisify(exec);
|
|
1833
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
1834
|
+
const __dirname$1 = dirname(__filename$1);
|
|
1835
|
+
function findPackageRoot(startDir) {
|
|
1836
|
+
let dir = startDir;
|
|
1837
|
+
for (let i = 0; i < 5; i++) {
|
|
1838
|
+
if (fs.existsSync(join(dir, "package.json"))) {
|
|
1839
|
+
return dir;
|
|
1840
|
+
}
|
|
1841
|
+
dir = dirname(dir);
|
|
1842
|
+
}
|
|
1843
|
+
return startDir;
|
|
1844
|
+
}
|
|
1845
|
+
const PACKAGE_ROOT = findPackageRoot(__dirname$1);
|
|
1846
|
+
async function getCurrentVersion() {
|
|
1847
|
+
try {
|
|
1848
|
+
const pkgPath = join(PACKAGE_ROOT, "package.json");
|
|
1849
|
+
const pkg = await fs.readJSON(pkgPath);
|
|
1850
|
+
return pkg.version || "0.0.0";
|
|
1851
|
+
} catch {
|
|
1852
|
+
return "0.0.0";
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
async function getLatestVersion(packageName = "ccg-workflow") {
|
|
1856
|
+
try {
|
|
1857
|
+
const { stdout } = await execAsync$2(`npm view ${packageName} version`);
|
|
1858
|
+
return stdout.trim();
|
|
1859
|
+
} catch {
|
|
1860
|
+
return null;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
function compareVersions(v1, v2) {
|
|
1864
|
+
const parts1 = v1.split(".").map(Number);
|
|
1865
|
+
const parts2 = v2.split(".").map(Number);
|
|
1866
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
1867
|
+
const num1 = parts1[i] || 0;
|
|
1868
|
+
const num2 = parts2[i] || 0;
|
|
1869
|
+
if (num1 > num2)
|
|
1870
|
+
return 1;
|
|
1871
|
+
if (num1 < num2)
|
|
1872
|
+
return -1;
|
|
1873
|
+
}
|
|
1874
|
+
return 0;
|
|
1875
|
+
}
|
|
1876
|
+
async function checkForUpdates() {
|
|
1877
|
+
const currentVersion = await getCurrentVersion();
|
|
1878
|
+
const latestVersion = await getLatestVersion();
|
|
1879
|
+
if (!latestVersion) {
|
|
1880
|
+
return {
|
|
1881
|
+
hasUpdate: false,
|
|
1882
|
+
currentVersion,
|
|
1883
|
+
latestVersion: null
|
|
1884
|
+
};
|
|
1885
|
+
}
|
|
1886
|
+
const hasUpdate = compareVersions(latestVersion, currentVersion) > 0;
|
|
1887
|
+
return {
|
|
1888
|
+
hasUpdate,
|
|
1889
|
+
currentVersion,
|
|
1890
|
+
latestVersion
|
|
1891
|
+
};
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
const execAsync$1 = promisify(exec);
|
|
1895
|
+
async function update() {
|
|
1896
|
+
console.log();
|
|
1897
|
+
console.log(ansis.cyan.bold("\u{1F504} \u68C0\u67E5\u66F4\u65B0..."));
|
|
1898
|
+
console.log();
|
|
1899
|
+
const spinner = ora("\u6B63\u5728\u68C0\u67E5\u6700\u65B0\u7248\u672C...").start();
|
|
1900
|
+
try {
|
|
1901
|
+
const { hasUpdate, currentVersion, latestVersion } = await checkForUpdates();
|
|
1902
|
+
const config = await readCcgConfig();
|
|
1903
|
+
const localVersion = config?.general?.version || "0.0.0";
|
|
1904
|
+
const needsWorkflowUpdate = compareVersions(currentVersion, localVersion) > 0;
|
|
1905
|
+
spinner.stop();
|
|
1906
|
+
if (!latestVersion) {
|
|
1907
|
+
console.log(ansis.red("\u274C \u65E0\u6CD5\u8FDE\u63A5\u5230 npm registry\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5"));
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1910
|
+
console.log(`\u5F53\u524D\u7248\u672C: ${ansis.yellow(`v${currentVersion}`)}`);
|
|
1911
|
+
console.log(`\u6700\u65B0\u7248\u672C: ${ansis.green(`v${latestVersion}`)}`);
|
|
1912
|
+
if (localVersion !== "0.0.0") {
|
|
1913
|
+
console.log(`\u672C\u5730\u5DE5\u4F5C\u6D41: ${ansis.gray(`v${localVersion}`)}`);
|
|
1914
|
+
}
|
|
1915
|
+
console.log();
|
|
1916
|
+
const effectiveNeedsUpdate = hasUpdate || needsWorkflowUpdate;
|
|
1917
|
+
let defaultConfirm = effectiveNeedsUpdate;
|
|
1918
|
+
let message;
|
|
1919
|
+
if (hasUpdate) {
|
|
1920
|
+
message = `\u53D1\u73B0\u65B0\u7248\u672C v${latestVersion} (\u5F53\u524D: v${currentVersion})\uFF0C\u662F\u5426\u66F4\u65B0\uFF1F`;
|
|
1921
|
+
defaultConfirm = true;
|
|
1922
|
+
} else if (needsWorkflowUpdate) {
|
|
1923
|
+
message = `\u68C0\u6D4B\u5230\u672C\u5730\u5DE5\u4F5C\u6D41\u7248\u672C (v${localVersion}) \u4F4E\u4E8E\u5F53\u524D\u7248\u672C (v${currentVersion})\uFF0C\u662F\u5426\u66F4\u65B0\uFF1F`;
|
|
1924
|
+
defaultConfirm = true;
|
|
1925
|
+
} else {
|
|
1926
|
+
message = `\u5F53\u524D\u5DF2\u662F\u6700\u65B0\u7248\u672C (v${currentVersion})\u3002\u662F\u5426\u5F3A\u5236\u91CD\u65B0\u5B89\u88C5/\u4FEE\u590D\u5DE5\u4F5C\u6D41\uFF1F`;
|
|
1927
|
+
defaultConfirm = false;
|
|
1928
|
+
}
|
|
1929
|
+
const { confirmUpdate } = await inquirer.prompt([{
|
|
1930
|
+
type: "confirm",
|
|
1931
|
+
name: "confirmUpdate",
|
|
1932
|
+
message,
|
|
1933
|
+
default: defaultConfirm
|
|
1934
|
+
}]);
|
|
1935
|
+
if (!confirmUpdate) {
|
|
1936
|
+
console.log(ansis.gray("\u5DF2\u53D6\u6D88\u66F4\u65B0"));
|
|
1937
|
+
return;
|
|
1938
|
+
}
|
|
1939
|
+
const fromVersion = needsWorkflowUpdate ? localVersion : currentVersion;
|
|
1940
|
+
await performUpdate(fromVersion, latestVersion || currentVersion, hasUpdate || needsWorkflowUpdate);
|
|
1941
|
+
} catch (error) {
|
|
1942
|
+
spinner.stop();
|
|
1943
|
+
console.log(ansis.red(`\u274C \u66F4\u65B0\u5931\u8D25: ${error}`));
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
async function checkIfGlobalInstall$1() {
|
|
1947
|
+
try {
|
|
1948
|
+
const { stdout } = await execAsync$1("npm list -g ccg-workflow --depth=0", { timeout: 5e3 });
|
|
1949
|
+
return stdout.includes("ccg-workflow@");
|
|
1950
|
+
} catch {
|
|
1951
|
+
return false;
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
async function performUpdate(fromVersion, toVersion, isNewVersion) {
|
|
1955
|
+
console.log();
|
|
1956
|
+
console.log(ansis.yellow.bold("\u2699\uFE0F \u5F00\u59CB\u66F4\u65B0..."));
|
|
1957
|
+
console.log();
|
|
1958
|
+
const isGlobalInstall = await checkIfGlobalInstall$1();
|
|
1959
|
+
if (isGlobalInstall && !isNewVersion) {
|
|
1960
|
+
console.log(ansis.cyan("\u2139\uFE0F \u68C0\u6D4B\u5230\u4F60\u662F\u901A\u8FC7 npm \u5168\u5C40\u5B89\u88C5\u7684"));
|
|
1961
|
+
console.log();
|
|
1962
|
+
console.log(ansis.green("\u2713 \u5F53\u524D\u5305\u7248\u672C\u5DF2\u662F\u6700\u65B0 (v" + toVersion + ")"));
|
|
1963
|
+
console.log(ansis.yellow("\u2699\uFE0F \u4EC5\u9700\u66F4\u65B0\u5DE5\u4F5C\u6D41\u6587\u4EF6"));
|
|
1964
|
+
console.log();
|
|
1965
|
+
} else if (isGlobalInstall && isNewVersion) {
|
|
1966
|
+
console.log(ansis.yellow("\u26A0\uFE0F \u68C0\u6D4B\u5230\u4F60\u662F\u901A\u8FC7 npm \u5168\u5C40\u5B89\u88C5\u7684"));
|
|
1967
|
+
console.log();
|
|
1968
|
+
console.log("\u63A8\u8350\u7684\u66F4\u65B0\u65B9\u5F0F\uFF1A");
|
|
1969
|
+
console.log();
|
|
1970
|
+
console.log(ansis.cyan(" npm install -g ccg-workflow@latest"));
|
|
1971
|
+
console.log();
|
|
1972
|
+
console.log(ansis.gray("\u8FD9\u5C06\u540C\u65F6\u66F4\u65B0\u547D\u4EE4\u548C\u5DE5\u4F5C\u6D41\u6587\u4EF6"));
|
|
1973
|
+
console.log();
|
|
1974
|
+
const { useNpmUpdate } = await inquirer.prompt([{
|
|
1975
|
+
type: "confirm",
|
|
1976
|
+
name: "useNpmUpdate",
|
|
1977
|
+
message: "\u6539\u7528 npm \u66F4\u65B0\uFF08\u63A8\u8350\uFF09\uFF1F",
|
|
1978
|
+
default: true
|
|
1979
|
+
}]);
|
|
1980
|
+
if (useNpmUpdate) {
|
|
1981
|
+
console.log();
|
|
1982
|
+
console.log(ansis.cyan("\u8BF7\u5728\u65B0\u7684\u7EC8\u7AEF\u7A97\u53E3\u4E2D\u8FD0\u884C\uFF1A"));
|
|
1983
|
+
console.log();
|
|
1984
|
+
console.log(ansis.cyan.bold(" npm install -g ccg-workflow@latest"));
|
|
1985
|
+
console.log();
|
|
1986
|
+
console.log(ansis.gray("(\u8FD0\u884C\u5B8C\u6210\u540E\uFF0C\u5F53\u524D\u7248\u672C\u5C06\u81EA\u52A8\u66F4\u65B0)"));
|
|
1987
|
+
console.log();
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
console.log();
|
|
1991
|
+
console.log(ansis.yellow("\u26A0\uFE0F \u7EE7\u7EED\u4F7F\u7528\u5185\u7F6E\u66F4\u65B0\uFF08\u4EC5\u66F4\u65B0\u5DE5\u4F5C\u6D41\u6587\u4EF6\uFF09"));
|
|
1992
|
+
console.log(ansis.gray("\u6CE8\u610F\uFF1A\u8FD9\u4E0D\u4F1A\u66F4\u65B0 ccg \u547D\u4EE4\u672C\u8EAB"));
|
|
1993
|
+
console.log();
|
|
1994
|
+
}
|
|
1995
|
+
let spinner = ora("\u6B63\u5728\u4E0B\u8F7D\u6700\u65B0\u7248\u672C...").start();
|
|
1996
|
+
try {
|
|
1997
|
+
if (process.platform === "win32") {
|
|
1998
|
+
spinner.text = "\u6B63\u5728\u6E05\u7406 npx \u7F13\u5B58...";
|
|
1999
|
+
try {
|
|
2000
|
+
await execAsync$1("npx clear-npx-cache", { timeout: 1e4 });
|
|
2001
|
+
} catch {
|
|
2002
|
+
const npxCachePath = join(homedir(), ".npm", "_npx");
|
|
2003
|
+
try {
|
|
2004
|
+
const fs = await import('fs-extra');
|
|
2005
|
+
await fs.remove(npxCachePath);
|
|
2006
|
+
} catch {
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
spinner.text = "\u6B63\u5728\u4E0B\u8F7D\u6700\u65B0\u7248\u672C...";
|
|
2011
|
+
await execAsync$1(`npx --yes ccg-workflow@latest --version`, { timeout: 6e4 });
|
|
2012
|
+
spinner.succeed("\u6700\u65B0\u7248\u672C\u4E0B\u8F7D\u5B8C\u6210");
|
|
2013
|
+
} catch (error) {
|
|
2014
|
+
spinner.fail("\u4E0B\u8F7D\u6700\u65B0\u7248\u672C\u5931\u8D25");
|
|
2015
|
+
console.log(ansis.red(`\u9519\u8BEF: ${error}`));
|
|
2016
|
+
return;
|
|
2017
|
+
}
|
|
2018
|
+
if (await needsMigration()) {
|
|
2019
|
+
spinner = ora("\u68C0\u6D4B\u5230\u65E7\u7248\u672C\u914D\u7F6E\uFF0C\u6B63\u5728\u8FC1\u79FB...").start();
|
|
2020
|
+
const migrationResult = await migrateToV1_4_0();
|
|
2021
|
+
if (migrationResult.migratedFiles.length > 0) {
|
|
2022
|
+
spinner.info(ansis.cyan("\u914D\u7F6E\u8FC1\u79FB\u5B8C\u6210:"));
|
|
2023
|
+
console.log();
|
|
2024
|
+
for (const file of migrationResult.migratedFiles) {
|
|
2025
|
+
console.log(` ${ansis.green("\u2713")} ${file}`);
|
|
2026
|
+
}
|
|
2027
|
+
if (migrationResult.skipped.length > 0) {
|
|
2028
|
+
console.log();
|
|
2029
|
+
console.log(ansis.gray(" \u5DF2\u8DF3\u8FC7:"));
|
|
2030
|
+
for (const file of migrationResult.skipped) {
|
|
2031
|
+
console.log(` ${ansis.gray("\u25CB")} ${file}`);
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
console.log();
|
|
2035
|
+
}
|
|
2036
|
+
if (migrationResult.errors.length > 0) {
|
|
2037
|
+
spinner.warn(ansis.yellow("\u8FC1\u79FB\u5B8C\u6210\uFF0C\u4F46\u6709\u90E8\u5206\u9519\u8BEF:"));
|
|
2038
|
+
for (const error of migrationResult.errors) {
|
|
2039
|
+
console.log(` ${ansis.red("\u2717")} ${error}`);
|
|
2040
|
+
}
|
|
2041
|
+
console.log();
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
spinner = ora("\u6B63\u5728\u5220\u9664\u65E7\u5DE5\u4F5C\u6D41...").start();
|
|
2045
|
+
try {
|
|
2046
|
+
const installDir = join(homedir(), ".claude");
|
|
2047
|
+
const uninstallResult = await uninstallWorkflows(installDir);
|
|
2048
|
+
if (uninstallResult.success) {
|
|
2049
|
+
spinner.succeed("\u65E7\u5DE5\u4F5C\u6D41\u5DF2\u5220\u9664");
|
|
2050
|
+
} else {
|
|
2051
|
+
spinner.warn("\u90E8\u5206\u6587\u4EF6\u5220\u9664\u5931\u8D25\uFF0C\u7EE7\u7EED\u5B89\u88C5...");
|
|
2052
|
+
for (const error of uninstallResult.errors) {
|
|
2053
|
+
console.log(ansis.yellow(` \u2022 ${error}`));
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
} catch (error) {
|
|
2057
|
+
spinner.warn(`\u5220\u9664\u65E7\u5DE5\u4F5C\u6D41\u65F6\u51FA\u9519: ${error}\uFF0C\u7EE7\u7EED\u5B89\u88C5...`);
|
|
2058
|
+
}
|
|
2059
|
+
spinner = ora("\u6B63\u5728\u5B89\u88C5\u65B0\u7248\u672C\u5DE5\u4F5C\u6D41\u548C\u4E8C\u8FDB\u5236...").start();
|
|
2060
|
+
try {
|
|
2061
|
+
await execAsync$1(`npx --yes ccg-workflow@latest init --force --skip-mcp --skip-prompt`, {
|
|
2062
|
+
timeout: 12e4,
|
|
2063
|
+
env: {
|
|
2064
|
+
...process.env,
|
|
2065
|
+
CCG_UPDATE_MODE: "true"
|
|
2066
|
+
// Signal to init that this is an update
|
|
2067
|
+
}
|
|
2068
|
+
});
|
|
2069
|
+
spinner.succeed("\u65B0\u7248\u672C\u5B89\u88C5\u6210\u529F");
|
|
2070
|
+
const config = await readCcgConfig();
|
|
2071
|
+
if (config?.workflows?.installed) {
|
|
2072
|
+
console.log();
|
|
2073
|
+
console.log(ansis.cyan(`\u5DF2\u5B89\u88C5 ${config.workflows.installed.length} \u4E2A\u547D\u4EE4:`));
|
|
2074
|
+
for (const cmd of config.workflows.installed) {
|
|
2075
|
+
console.log(` ${ansis.gray("\u2022")} /ccg:${cmd}`);
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
} catch (error) {
|
|
2079
|
+
spinner.fail("\u5B89\u88C5\u65B0\u7248\u672C\u5931\u8D25");
|
|
2080
|
+
console.log(ansis.red(`\u9519\u8BEF: ${error}`));
|
|
2081
|
+
console.log();
|
|
2082
|
+
console.log(ansis.yellow("\u8BF7\u5C1D\u8BD5\u624B\u52A8\u8FD0\u884C:"));
|
|
2083
|
+
console.log(ansis.cyan(" npx ccg-workflow@latest"));
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
console.log();
|
|
2087
|
+
console.log(ansis.green.bold("\u2705 \u66F4\u65B0\u5B8C\u6210\uFF01"));
|
|
2088
|
+
console.log();
|
|
2089
|
+
if (isNewVersion) {
|
|
2090
|
+
console.log(ansis.gray(`\u4ECE v${fromVersion} \u5347\u7EA7\u5230 v${toVersion}`));
|
|
2091
|
+
} else {
|
|
2092
|
+
console.log(ansis.gray(`\u91CD\u65B0\u5B89\u88C5\u4E86 v${toVersion}`));
|
|
2093
|
+
}
|
|
2094
|
+
console.log();
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
const execAsync = promisify(exec);
|
|
2098
|
+
async function showMainMenu() {
|
|
2099
|
+
while (true) {
|
|
2100
|
+
console.log();
|
|
2101
|
+
console.log(ansis.cyan.bold(` CCG-ROS2 - Claude + Codex + Gemini`));
|
|
2102
|
+
console.log(ansis.gray(" ROS2 Multi-Model Collaboration System"));
|
|
2103
|
+
console.log();
|
|
2104
|
+
const { action } = await inquirer.prompt([{
|
|
2105
|
+
type: "list",
|
|
2106
|
+
name: "action",
|
|
2107
|
+
message: i18n.t("menu:title"),
|
|
2108
|
+
choices: [
|
|
2109
|
+
{ name: `${ansis.green("\u279C")} ${i18n.t("menu:options.init")}`, value: "init" },
|
|
2110
|
+
{ name: `${ansis.blue("\u279C")} ${i18n.t("menu:options.update")}`, value: "update" },
|
|
2111
|
+
{ name: `${ansis.cyan("\u2699")} \u914D\u7F6E MCP`, value: "config-mcp" },
|
|
2112
|
+
{ name: `${ansis.magenta("\u279C")} ${i18n.t("menu:options.uninstall")}`, value: "uninstall" },
|
|
2113
|
+
{ name: `${ansis.yellow("?")} ${i18n.t("menu:options.help")}`, value: "help" },
|
|
2114
|
+
new inquirer.Separator(),
|
|
2115
|
+
{ name: `${ansis.red("\u2715")} ${i18n.t("menu:options.exit")}`, value: "exit" }
|
|
2116
|
+
]
|
|
2117
|
+
}]);
|
|
2118
|
+
switch (action) {
|
|
2119
|
+
case "init":
|
|
2120
|
+
await init();
|
|
2121
|
+
break;
|
|
2122
|
+
case "update":
|
|
2123
|
+
await update();
|
|
2124
|
+
break;
|
|
2125
|
+
case "config-mcp":
|
|
2126
|
+
await configMcp();
|
|
2127
|
+
break;
|
|
2128
|
+
case "uninstall":
|
|
2129
|
+
await uninstall();
|
|
2130
|
+
break;
|
|
2131
|
+
case "help":
|
|
2132
|
+
showHelp();
|
|
2133
|
+
break;
|
|
2134
|
+
case "exit":
|
|
2135
|
+
console.log(ansis.gray("\u518D\u89C1\uFF01"));
|
|
2136
|
+
return;
|
|
2137
|
+
}
|
|
2138
|
+
console.log();
|
|
2139
|
+
await inquirer.prompt([{
|
|
2140
|
+
type: "input",
|
|
2141
|
+
name: "continue",
|
|
2142
|
+
message: ansis.gray("\u6309 Enter \u8FD4\u56DE\u4E3B\u83DC\u5355...")
|
|
2143
|
+
}]);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
function showHelp() {
|
|
2147
|
+
console.log();
|
|
2148
|
+
console.log(ansis.cyan.bold(i18n.t("menu:help.title")));
|
|
2149
|
+
console.log();
|
|
2150
|
+
console.log(ansis.yellow.bold(" ROS2 \u5F00\u53D1\u5DE5\u4F5C\u6D41:"));
|
|
2151
|
+
console.log(` ${ansis.green("/ccg:workflow")} \u5B8C\u65747\u9636\u6BB5ROS2\u5F00\u53D1\u5DE5\u4F5C\u6D41`);
|
|
2152
|
+
console.log(` ${ansis.green("/ccg:plan")} \u591A\u6A21\u578B\u534F\u4F5C\u89C4\u5212\uFF08Phase 1-2\uFF09`);
|
|
2153
|
+
console.log(` ${ansis.green("/ccg:execute")} \u591A\u6A21\u578B\u534F\u4F5C\u6267\u884C\uFF08Phase 3-5\uFF09`);
|
|
2154
|
+
console.log(` ${ansis.green("/ccg:frontend")} \u4E0A\u5C42\u5E94\u7528\u4E13\u9879 \u2192 Gemini\uFF08Launch/Python/RViz\uFF09`);
|
|
2155
|
+
console.log(` ${ansis.green("/ccg:backend")} \u5E95\u5C42\u63A7\u5236\u4E13\u9879 \u2192 Codex\uFF08C++/\u786C\u4EF6/\u5B9E\u65F6\uFF09`);
|
|
2156
|
+
console.log(` ${ansis.green("/ccg:feat")} \u667A\u80FD\u529F\u80FD\u5F00\u53D1`);
|
|
2157
|
+
console.log(` ${ansis.green("/ccg:analyze")} ${i18n.t("menu:help.descriptions.analyze")}`);
|
|
2158
|
+
console.log(` ${ansis.green("/ccg:debug")} \u95EE\u9898\u8BCA\u65AD + \u4FEE\u590D`);
|
|
2159
|
+
console.log(` ${ansis.green("/ccg:optimize")} \u6027\u80FD\u4F18\u5316`);
|
|
2160
|
+
console.log(` ${ansis.green("/ccg:test")} \u6D4B\u8BD5\u751F\u6210`);
|
|
2161
|
+
console.log(` ${ansis.green("/ccg:review")} ${i18n.t("menu:help.descriptions.review")}`);
|
|
2162
|
+
console.log();
|
|
2163
|
+
console.log(ansis.yellow.bold(" OpenSpec \u89C4\u8303\u9A71\u52A8:"));
|
|
2164
|
+
console.log(` ${ansis.green("/ccg:spec-init")} \u521D\u59CB\u5316 OpenSpec \u73AF\u5883`);
|
|
2165
|
+
console.log(` ${ansis.green("/ccg:spec-research")} \u9700\u6C42\u7814\u7A76 \u2192 \u7EA6\u675F\u96C6`);
|
|
2166
|
+
console.log(` ${ansis.green("/ccg:spec-plan")} \u591A\u6A21\u578B\u5206\u6790 \u2192 \u96F6\u51B3\u7B56\u8BA1\u5212`);
|
|
2167
|
+
console.log(` ${ansis.green("/ccg:spec-impl")} \u89C4\u8303\u9A71\u52A8\u5B9E\u73B0`);
|
|
2168
|
+
console.log(` ${ansis.green("/ccg:spec-review")} \u5F52\u6863\u524D\u53CC\u6A21\u578B\u5BA1\u67E5`);
|
|
2169
|
+
console.log();
|
|
2170
|
+
console.log(ansis.yellow.bold(" Git \u5DE5\u5177:"));
|
|
2171
|
+
console.log(` ${ansis.green("/ccg:commit")} ${i18n.t("menu:help.descriptions.commit")}`);
|
|
2172
|
+
console.log(` ${ansis.green("/ccg:rollback")} ${i18n.t("menu:help.descriptions.rollback")}`);
|
|
2173
|
+
console.log(` ${ansis.green("/ccg:clean-branches")} \u6E05\u7406\u5DF2\u5408\u5E76\u5206\u652F`);
|
|
2174
|
+
console.log(` ${ansis.green("/ccg:worktree")} Git Worktree \u7BA1\u7406`);
|
|
2175
|
+
console.log();
|
|
2176
|
+
console.log(ansis.yellow.bold(" \u9879\u76EE\u7BA1\u7406:"));
|
|
2177
|
+
console.log(` ${ansis.green("/ccg:init")} \u521D\u59CB\u5316\u9879\u76EE CLAUDE.md`);
|
|
2178
|
+
console.log();
|
|
2179
|
+
console.log(ansis.gray(i18n.t("menu:help.hint")));
|
|
2180
|
+
console.log();
|
|
2181
|
+
}
|
|
2182
|
+
async function checkIfGlobalInstall() {
|
|
2183
|
+
try {
|
|
2184
|
+
const { stdout } = await execAsync("npm list -g ccg-workflow --depth=0", { timeout: 5e3 });
|
|
2185
|
+
return stdout.includes("ccg-workflow@");
|
|
2186
|
+
} catch {
|
|
2187
|
+
return false;
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
async function uninstall() {
|
|
2191
|
+
console.log();
|
|
2192
|
+
const isGlobalInstall = await checkIfGlobalInstall();
|
|
2193
|
+
if (isGlobalInstall) {
|
|
2194
|
+
console.log(ansis.yellow("\u26A0\uFE0F \u68C0\u6D4B\u5230\u4F60\u662F\u901A\u8FC7 npm \u5168\u5C40\u5B89\u88C5\u7684"));
|
|
2195
|
+
console.log();
|
|
2196
|
+
console.log("\u5B8C\u6574\u5378\u8F7D\u9700\u8981\u4E24\u6B65\uFF1A");
|
|
2197
|
+
console.log(` ${ansis.cyan("1. \u79FB\u9664\u5DE5\u4F5C\u6D41\u6587\u4EF6")} (\u5373\u5C06\u6267\u884C)`);
|
|
2198
|
+
console.log(` ${ansis.cyan("2. \u5378\u8F7D npm \u5168\u5C40\u5305")} (\u9700\u8981\u624B\u52A8\u6267\u884C)`);
|
|
2199
|
+
console.log();
|
|
2200
|
+
}
|
|
2201
|
+
const { confirm } = await inquirer.prompt([{
|
|
2202
|
+
type: "confirm",
|
|
2203
|
+
name: "confirm",
|
|
2204
|
+
message: isGlobalInstall ? "\u7EE7\u7EED\u5378\u8F7D\u5DE5\u4F5C\u6D41\u6587\u4EF6\uFF1F" : i18n.t("menu:uninstall.confirm"),
|
|
2205
|
+
default: false
|
|
2206
|
+
}]);
|
|
2207
|
+
if (!confirm) {
|
|
2208
|
+
console.log(ansis.gray(i18n.t("menu:uninstall.cancelled")));
|
|
2209
|
+
return;
|
|
2210
|
+
}
|
|
2211
|
+
const { removeAceTool } = await inquirer.prompt([{
|
|
2212
|
+
type: "confirm",
|
|
2213
|
+
name: "removeAceTool",
|
|
2214
|
+
message: i18n.t("menu:uninstall.alsoRemoveAceTool"),
|
|
2215
|
+
default: false
|
|
2216
|
+
}]);
|
|
2217
|
+
console.log();
|
|
2218
|
+
console.log(ansis.yellow(i18n.t("menu:uninstall.uninstalling")));
|
|
2219
|
+
const installDir = join(homedir(), ".claude");
|
|
2220
|
+
const result = await uninstallWorkflows(installDir);
|
|
2221
|
+
if (result.success) {
|
|
2222
|
+
console.log(ansis.green("\u2705 \u5DE5\u4F5C\u6D41\u6587\u4EF6\u5DF2\u79FB\u9664"));
|
|
2223
|
+
if (result.removedCommands.length > 0) {
|
|
2224
|
+
console.log();
|
|
2225
|
+
console.log(ansis.cyan(i18n.t("menu:uninstall.removedCommands")));
|
|
2226
|
+
for (const cmd of result.removedCommands) {
|
|
2227
|
+
console.log(` ${ansis.gray("\u2022")} /ccg:${cmd}`);
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
if (result.removedAgents.length > 0) {
|
|
2231
|
+
console.log();
|
|
2232
|
+
console.log(ansis.cyan("\u5DF2\u79FB\u9664\u5B50\u667A\u80FD\u4F53:"));
|
|
2233
|
+
for (const agent of result.removedAgents) {
|
|
2234
|
+
console.log(` ${ansis.gray("\u2022")} ${agent}`);
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
if (result.removedSkills.length > 0) {
|
|
2238
|
+
console.log();
|
|
2239
|
+
console.log(ansis.cyan("\u5DF2\u79FB\u9664 Skills:"));
|
|
2240
|
+
console.log(` ${ansis.gray("\u2022")} multi-model-collaboration`);
|
|
2241
|
+
}
|
|
2242
|
+
if (result.removedBin) {
|
|
2243
|
+
console.log();
|
|
2244
|
+
console.log(ansis.cyan("\u5DF2\u79FB\u9664\u4E8C\u8FDB\u5236\u6587\u4EF6:"));
|
|
2245
|
+
console.log(` ${ansis.gray("\u2022")} codeagent-wrapper`);
|
|
2246
|
+
}
|
|
2247
|
+
if (isGlobalInstall) {
|
|
2248
|
+
console.log();
|
|
2249
|
+
console.log(ansis.yellow.bold("\u{1F538} \u6700\u540E\u4E00\u6B65\uFF1A\u5378\u8F7D npm \u5168\u5C40\u5305"));
|
|
2250
|
+
console.log();
|
|
2251
|
+
console.log("\u8BF7\u5728\u65B0\u7684\u7EC8\u7AEF\u7A97\u53E3\u4E2D\u8FD0\u884C\uFF1A");
|
|
2252
|
+
console.log();
|
|
2253
|
+
console.log(ansis.cyan.bold(" npm uninstall -g ccg-workflow"));
|
|
2254
|
+
console.log();
|
|
2255
|
+
console.log(ansis.gray("(\u5B8C\u6210\u540E ccg \u547D\u4EE4\u5C06\u5F7B\u5E95\u79FB\u9664)"));
|
|
2256
|
+
}
|
|
2257
|
+
} else {
|
|
2258
|
+
console.log(ansis.red(i18n.t("menu:uninstall.failed")));
|
|
2259
|
+
for (const error of result.errors) {
|
|
2260
|
+
console.log(ansis.red(` ${error}`));
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
if (removeAceTool) {
|
|
2264
|
+
const aceResult = await uninstallAceTool();
|
|
2265
|
+
if (aceResult.success) {
|
|
2266
|
+
console.log(ansis.green(i18n.t("menu:uninstall.removedAceTool")));
|
|
2267
|
+
} else {
|
|
2268
|
+
console.log(ansis.red(aceResult.message));
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
console.log();
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
export { isWindows as A, readClaudeCodeConfig as B, fixWindowsMcpConfig as C, writeClaudeCodeConfig as D, configMcp as E, version as F, checkForUpdates as a, compareVersions as b, changeLanguage as c, createDefaultConfig as d, createDefaultRouting as e, getConfigPath as f, getCcgDir as g, getCurrentVersion as h, getLatestVersion as i, getWorkflowById as j, getWorkflowConfigs as k, i18n as l, init as m, initI18n as n, installAceTool as o, installAceToolRs as p, installWorkflows as q, migrateToV1_4_0 as r, needsMigration as s, readCcgConfig as t, showMainMenu as u, uninstallAceTool as v, uninstallWorkflows as w, update as x, writeCcgConfig as y, diagnoseMcpConfig as z };
|