@hunyed15/codecgc 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -8
- package/bin/cgc-build.js +1 -1
- package/bin/cgc-doctor.js +1 -1
- package/bin/cgc-entry.js +1 -1
- package/bin/cgc-explain.js +4 -0
- package/bin/cgc-external-audit.js +1 -1
- package/bin/cgc-external-status.js +1 -1
- package/bin/cgc-fix.js +1 -1
- package/bin/cgc-history.js +1 -1
- package/bin/cgc-init.js +1 -1
- package/bin/cgc-lifecycle.js +1 -1
- package/bin/cgc-package-audit.js +1 -1
- package/bin/cgc-plan.js +1 -1
- package/bin/cgc-release-readiness.js +1 -1
- package/bin/cgc-review.js +1 -1
- package/bin/cgc-route.js +1 -1
- package/bin/cgc-start.js +1 -1
- package/bin/cgc-status.js +1 -1
- package/bin/cgc-test.js +1 -1
- package/bin/codecgc.js +44 -1
- package/codecgc/templates/project/CLAUDE.md +28 -6
- package/mcp/codexmcp/src/codexmcp/server.py +37 -3
- package/package.json +2 -1
- package/scripts/codecgc_error_catalog.py +172 -0
- package/scripts/codecgc_error_formatter.py +124 -0
- package/scripts/codecgc_flow_control.py +11 -0
- package/scripts/codecgc_runtime/console.py +9 -0
- package/scripts/codecgc_runtime/workflow_runtime.py +18 -0
- package/scripts/explain_codecgc_error.py +71 -0
- package/scripts/install_codecgc.py +50 -1
- package/scripts/postinstall_codecgc.js +23 -5
package/README.md
CHANGED
|
@@ -25,25 +25,26 @@ CLI 仍然保留,用于本地调试、CI 检查和 MCP 不可用时的回退
|
|
|
25
25
|
|
|
26
26
|
## 安装
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
### 推荐:全局安装(用户级)
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
31
|
npm install -g @hunyed15/codecgc --registry=https://registry.npmjs.org/
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
全局安装后,`cgc-init`、`cgc-status`、`cgc-doctor` 等命令在任何目录都可用。
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
### 项目初始化
|
|
37
|
+
|
|
38
|
+
在项目目录下运行:
|
|
37
39
|
|
|
38
40
|
```bash
|
|
39
41
|
cd your-project
|
|
40
42
|
cgc-init
|
|
41
|
-
cgc-start
|
|
42
|
-
cgc-status
|
|
43
|
-
cgc-doctor
|
|
44
43
|
```
|
|
45
44
|
|
|
46
|
-
|
|
45
|
+
这会初始化项目配置并注册 `/cgc` skill 到 Claude Code。
|
|
46
|
+
|
|
47
|
+
在 Claude 中也可以使用:
|
|
47
48
|
|
|
48
49
|
```text
|
|
49
50
|
/cgc-init
|
|
@@ -52,7 +53,28 @@ cgc-doctor
|
|
|
52
53
|
/cgc-doctor
|
|
53
54
|
```
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
初始化完成后,可以直接使用:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
/cgc "新增一个登录页面"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
或在命令行:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cgc "新增一个登录页面"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 备选:项目级安装
|
|
69
|
+
|
|
70
|
+
如果需要版本隔离(CI、Docker 等场景):
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm install @hunyed15/codecgc
|
|
74
|
+
npx cgc-init
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**注意**:项目级安装需要通过 `npx` 调用命令。推荐使用全局安装以获得更好的用户体验。
|
|
56
78
|
|
|
57
79
|
## 安装后生成的项目文件
|
|
58
80
|
|
package/bin/cgc-build.js
CHANGED
package/bin/cgc-doctor.js
CHANGED
package/bin/cgc-entry.js
CHANGED
package/bin/cgc-fix.js
CHANGED
package/bin/cgc-history.js
CHANGED
package/bin/cgc-init.js
CHANGED
package/bin/cgc-lifecycle.js
CHANGED
package/bin/cgc-package-audit.js
CHANGED
package/bin/cgc-plan.js
CHANGED
package/bin/cgc-review.js
CHANGED
package/bin/cgc-route.js
CHANGED
package/bin/cgc-start.js
CHANGED
package/bin/cgc-status.js
CHANGED
package/bin/cgc-test.js
CHANGED
package/bin/codecgc.js
CHANGED
|
@@ -8,7 +8,7 @@ const path = require("node:path");
|
|
|
8
8
|
const repoRoot = path.resolve(__dirname, "..");
|
|
9
9
|
const invocationCwd = process.cwd();
|
|
10
10
|
const args = process.argv.slice(2);
|
|
11
|
-
const invokedBinary = (process.env.CODECGC_BIN_NAME || path.
|
|
11
|
+
const invokedBinary = (process.env.CODECGC_BIN_NAME || path.parse(process.argv[1] || "cgc").name).toLowerCase();
|
|
12
12
|
const packageJson = JSON.parse(readFileSync(path.join(repoRoot, "package.json"), "utf8"));
|
|
13
13
|
const productVersion = packageJson.version || "0.0.0";
|
|
14
14
|
const DIRECT_COMMANDS = new Set([
|
|
@@ -16,6 +16,7 @@ const DIRECT_COMMANDS = new Set([
|
|
|
16
16
|
"install",
|
|
17
17
|
"status",
|
|
18
18
|
"doctor",
|
|
19
|
+
"explain",
|
|
19
20
|
"package-audit",
|
|
20
21
|
"external-audit",
|
|
21
22
|
"external-status",
|
|
@@ -45,6 +46,7 @@ const helpText = `CodeCGC 命令入口
|
|
|
45
46
|
cgc-init [--mode local|status|doctor|start] [--workspace <dir>]
|
|
46
47
|
cgc-status [--format json|summary]
|
|
47
48
|
cgc-doctor [--format json|summary]
|
|
49
|
+
cgc-explain <error_code> | --list [--format json|summary]
|
|
48
50
|
cgc-package-audit [--format json|summary]
|
|
49
51
|
cgc-external-audit [--format json|summary] [--workspace <dir>]
|
|
50
52
|
cgc-external-status [--format json|summary] [--workspace <dir>]
|
|
@@ -88,6 +90,8 @@ const helpText = `CodeCGC 命令入口
|
|
|
88
90
|
cgc-status
|
|
89
91
|
我想知道运行前置和执行器能不能真正启动
|
|
90
92
|
cgc-doctor
|
|
93
|
+
我想查看某个错误代码的详细说明和修复建议
|
|
94
|
+
cgc-explain executor-crash
|
|
91
95
|
我想确认发布包没有漏掉运行时文件
|
|
92
96
|
cgc-package-audit
|
|
93
97
|
我想确认第三方能力接入策略和本地 MCP 注册状态
|
|
@@ -110,6 +114,7 @@ const helpText = `CodeCGC 命令入口
|
|
|
110
114
|
cgc-init 同步项目级集成面
|
|
111
115
|
cgc-status 检查集成是否就绪,并给出下一步
|
|
112
116
|
cgc-doctor 检查运行前置、执行器导入与项目集成状态
|
|
117
|
+
cgc-explain 查看错误代码的详细说明和修复建议
|
|
113
118
|
cgc-package-audit 检查发布包是否覆盖运行时依赖
|
|
114
119
|
cgc-external-audit 检查外部能力白名单、接入声明与本地 MCP 观测一致性
|
|
115
120
|
cgc-external-status 查看外部能力状态面板与本地 MCP 观测结果
|
|
@@ -151,6 +156,8 @@ const helpText = `CodeCGC 命令入口
|
|
|
151
156
|
cgc-status
|
|
152
157
|
cgc-status --format summary
|
|
153
158
|
cgc-doctor --format summary
|
|
159
|
+
cgc-explain executor-crash
|
|
160
|
+
cgc-explain --list
|
|
154
161
|
cgc-package-audit --format summary
|
|
155
162
|
cgc-external-status --format summary
|
|
156
163
|
cgc-external-audit --format summary
|
|
@@ -163,6 +170,7 @@ const helpText = `CodeCGC 命令入口
|
|
|
163
170
|
环境变量:
|
|
164
171
|
CODECGC_PYTHON_COMMAND 覆盖产品壳与生成的 MCP 配置所使用的 Python 命令
|
|
165
172
|
CODECGC_WORKSPACE_ROOT 当当前 shell 目录不是目标项目根目录时,显式覆盖目标工作区
|
|
173
|
+
CODECGC_ERROR_LEVEL 错误输出详细级别:summary(默认,小白可读)、detail(技术细节)、debug(完整日志)
|
|
166
174
|
`;
|
|
167
175
|
|
|
168
176
|
const startHelpText = `CodeCGC Start
|
|
@@ -270,6 +278,41 @@ const statusHelpText = `CodeCGC 安装状态
|
|
|
270
278
|
同步或修复当前项目集成面。
|
|
271
279
|
cgc-doctor
|
|
272
280
|
检查运行前置、执行器导入和项目集成状态。
|
|
281
|
+
cgc-explain
|
|
282
|
+
查看错误代码的详细说明和修复建议。
|
|
283
|
+
`;
|
|
284
|
+
|
|
285
|
+
const explainHelpText = `CodeCGC Explain
|
|
286
|
+
|
|
287
|
+
用法:
|
|
288
|
+
cgc-explain <error_code>
|
|
289
|
+
cgc-explain --list [--format <summary|json>]
|
|
290
|
+
|
|
291
|
+
用途:
|
|
292
|
+
查看 CodeCGC 错误代码的详细说明、常见原因和修复建议。
|
|
293
|
+
|
|
294
|
+
默认行为:
|
|
295
|
+
传入错误代码时,输出该错误的中文说明和建议操作。
|
|
296
|
+
使用 --list 时,列出所有可用的错误代码。
|
|
297
|
+
|
|
298
|
+
主要参数:
|
|
299
|
+
<error_code>
|
|
300
|
+
要查询的错误代码,例如 executor-crash、scope-error、design-gap。
|
|
301
|
+
--list
|
|
302
|
+
列出所有可用的错误代码。
|
|
303
|
+
--format <summary|json>
|
|
304
|
+
summary 用于人类可读输出,json 用于程序消费。
|
|
305
|
+
|
|
306
|
+
推荐用法:
|
|
307
|
+
cgc-explain executor-crash
|
|
308
|
+
cgc-explain scope-error
|
|
309
|
+
cgc-explain --list
|
|
310
|
+
|
|
311
|
+
相关命令:
|
|
312
|
+
cgc-doctor
|
|
313
|
+
检查运行前置和执行器环境。
|
|
314
|
+
cgc-route
|
|
315
|
+
查看当前工作流状态和推荐命令。
|
|
273
316
|
`;
|
|
274
317
|
|
|
275
318
|
const doctorHelpText = `CodeCGC Doctor
|
|
@@ -53,9 +53,21 @@ cgc-review ...
|
|
|
53
53
|
cgc-route ...
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
##
|
|
56
|
+
## 安装方式
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
**推荐:全局安装 + 项目初始化**
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install -g @hunyed15/codecgc
|
|
62
|
+
cd your-project
|
|
63
|
+
cgc-init
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
全局安装后,`cgc-init`、`cgc-status`、`cgc-doctor` 等命令在任何目录都可用。
|
|
67
|
+
|
|
68
|
+
**项目初始化命令**:
|
|
69
|
+
|
|
70
|
+
在 Claude 中:
|
|
59
71
|
|
|
60
72
|
```text
|
|
61
73
|
/cgc-init
|
|
@@ -64,7 +76,7 @@ CodeCGC 默认使用项目级安装。
|
|
|
64
76
|
/cgc-doctor
|
|
65
77
|
```
|
|
66
78
|
|
|
67
|
-
|
|
79
|
+
在命令行:
|
|
68
80
|
|
|
69
81
|
```bash
|
|
70
82
|
cgc-init
|
|
@@ -73,10 +85,20 @@ cgc-status
|
|
|
73
85
|
cgc-doctor
|
|
74
86
|
```
|
|
75
87
|
|
|
76
|
-
|
|
88
|
+
**备选:项目级安装**
|
|
89
|
+
|
|
90
|
+
适用于 CI、Docker 或需要版本隔离的场景:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm install @hunyed15/codecgc
|
|
94
|
+
npx cgc-init
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**规则**:
|
|
77
98
|
|
|
78
|
-
-
|
|
79
|
-
-
|
|
99
|
+
- `cgc-init` 和 `/cgc-init` 默认写入当前项目,不写入 `~/.claude`。
|
|
100
|
+
- 全局安装提供最佳用户体验,初始化命令全局可用。
|
|
101
|
+
- 项目级安装需要通过 `npx` 调用命令。
|
|
80
102
|
- Windows PowerShell 如拦截 `.ps1` shim,使用 `cgc-init.cmd`、`cgc-status.cmd`、`cgc-doctor.cmd`。
|
|
81
103
|
|
|
82
104
|
## 写入边界
|
|
@@ -20,6 +20,8 @@ import shutil
|
|
|
20
20
|
|
|
21
21
|
mcp = FastMCP("Codex MCP Server-from guda.studio")
|
|
22
22
|
|
|
23
|
+
DEFAULT_CODEX_TIMEOUT_SECONDS = 600
|
|
24
|
+
|
|
23
25
|
# Mirror of model-routing.yaml frontend_paths — keep these hints in sync with
|
|
24
26
|
# edit-guard.js and geminimcp/server.py BACKEND_PATH_HINTS.
|
|
25
27
|
FRONTEND_PATH_HINTS = (
|
|
@@ -177,7 +179,25 @@ def _validate_backend_target_paths(target_paths: List[Path]) -> tuple[bool, List
|
|
|
177
179
|
return True, policy_checks, ""
|
|
178
180
|
|
|
179
181
|
|
|
180
|
-
def
|
|
182
|
+
def _terminate_process_tree(process: subprocess.Popen[str]) -> None:
|
|
183
|
+
"""Terminate a process and its children best-effort."""
|
|
184
|
+
if process.poll() is not None:
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
if os.name == "nt":
|
|
188
|
+
subprocess.run(
|
|
189
|
+
["taskkill", "/PID", str(process.pid), "/T", "/F"],
|
|
190
|
+
stdin=subprocess.DEVNULL,
|
|
191
|
+
stdout=subprocess.DEVNULL,
|
|
192
|
+
stderr=subprocess.DEVNULL,
|
|
193
|
+
check=False,
|
|
194
|
+
)
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
process.kill()
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def run_shell_command(cmd: list[str], timeout_seconds: int = DEFAULT_CODEX_TIMEOUT_SECONDS) -> Generator[str, None, None]:
|
|
181
201
|
"""Execute a command and stream its output line-by-line.
|
|
182
202
|
|
|
183
203
|
Args:
|
|
@@ -204,6 +224,8 @@ def run_shell_command(cmd: list[str]) -> Generator[str, None, None]:
|
|
|
204
224
|
|
|
205
225
|
output_queue: queue.Queue[str | None] = queue.Queue()
|
|
206
226
|
GRACEFUL_SHUTDOWN_DELAY = 0.3
|
|
227
|
+
started_at = time.monotonic()
|
|
228
|
+
timed_out = False
|
|
207
229
|
|
|
208
230
|
def is_turn_completed(line: str) -> bool:
|
|
209
231
|
"""Check if the line indicates turn completion via JSON parsing."""
|
|
@@ -237,13 +259,17 @@ def run_shell_command(cmd: list[str]) -> Generator[str, None, None]:
|
|
|
237
259
|
break
|
|
238
260
|
yield line
|
|
239
261
|
except queue.Empty:
|
|
262
|
+
if timeout_seconds > 0 and time.monotonic() - started_at > timeout_seconds:
|
|
263
|
+
timed_out = True
|
|
264
|
+
_terminate_process_tree(process)
|
|
265
|
+
break
|
|
240
266
|
if process.poll() is not None and not thread.is_alive():
|
|
241
267
|
break
|
|
242
268
|
|
|
243
269
|
try:
|
|
244
270
|
process.wait(timeout=5)
|
|
245
271
|
except subprocess.TimeoutExpired:
|
|
246
|
-
process
|
|
272
|
+
_terminate_process_tree(process)
|
|
247
273
|
process.wait()
|
|
248
274
|
thread.join(timeout=5)
|
|
249
275
|
|
|
@@ -255,6 +281,13 @@ def run_shell_command(cmd: list[str]) -> Generator[str, None, None]:
|
|
|
255
281
|
except queue.Empty:
|
|
256
282
|
break
|
|
257
283
|
|
|
284
|
+
if timed_out:
|
|
285
|
+
raise TimeoutError(
|
|
286
|
+
f"Codex CLI timed out after {timeout_seconds} seconds. "
|
|
287
|
+
"This usually means the CLI was waiting for interactive approval, "
|
|
288
|
+
"network/authentication, or a long-running tool call."
|
|
289
|
+
)
|
|
290
|
+
|
|
258
291
|
|
|
259
292
|
def _execute_codex_session(
|
|
260
293
|
*,
|
|
@@ -268,6 +301,7 @@ def _execute_codex_session(
|
|
|
268
301
|
model: str,
|
|
269
302
|
yolo: bool,
|
|
270
303
|
profile: str,
|
|
304
|
+
timeout_seconds: int = DEFAULT_CODEX_TIMEOUT_SECONDS,
|
|
271
305
|
) -> Dict[str, Any]:
|
|
272
306
|
"""Execute Codex CLI and return the parsed MCP response payload."""
|
|
273
307
|
if not cd.exists():
|
|
@@ -310,7 +344,7 @@ def _execute_codex_session(
|
|
|
310
344
|
err_message = ""
|
|
311
345
|
thread_id: Optional[str] = None
|
|
312
346
|
|
|
313
|
-
for line in run_shell_command(cmd):
|
|
347
|
+
for line in run_shell_command(cmd, timeout_seconds):
|
|
314
348
|
try:
|
|
315
349
|
line_dict = json.loads(line.strip())
|
|
316
350
|
all_messages.append(line_dict)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hunyed15/codecgc",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Claude-hosted multi-model workflow product shell for CodeCGC.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"cgc-init": "bin/cgc-init.js",
|
|
11
11
|
"cgc-status": "bin/cgc-status.js",
|
|
12
12
|
"cgc-doctor": "bin/cgc-doctor.js",
|
|
13
|
+
"cgc-explain": "bin/cgc-explain.js",
|
|
13
14
|
"cgc-package-audit": "bin/cgc-package-audit.js",
|
|
14
15
|
"cgc-external-audit": "bin/cgc-external-audit.js",
|
|
15
16
|
"cgc-external-status": "bin/cgc-external-status.js",
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""Error code classification and explanation for CodeCGC.
|
|
2
|
+
|
|
3
|
+
Provides human-readable explanations and actionable suggestions for common error scenarios.
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Error code to explanation mapping
|
|
11
|
+
ERROR_CATALOG: dict[str, dict[str, str]] = {
|
|
12
|
+
"executor-crash": {
|
|
13
|
+
"title": "执行器内部异常",
|
|
14
|
+
"description": "执行器脚本在运行过程中异常退出,未能完成任务。",
|
|
15
|
+
"common_causes": [
|
|
16
|
+
"执行器环境配置不完整(缺少依赖、路径错误)",
|
|
17
|
+
"执行器超时或资源不足",
|
|
18
|
+
"执行器内部代码错误",
|
|
19
|
+
],
|
|
20
|
+
"suggestions": [
|
|
21
|
+
"运行 cgc-doctor 检查执行器环境配置",
|
|
22
|
+
"查看审计文件中的详细错误日志",
|
|
23
|
+
"如果持续失败,尝试重新安装:cgc-init",
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
"executor-failure": {
|
|
27
|
+
"title": "执行器任务失败",
|
|
28
|
+
"description": "执行器正常运行,但任务执行失败(如代码生成失败、测试未通过)。",
|
|
29
|
+
"common_causes": [
|
|
30
|
+
"目标路径不存在或不可访问",
|
|
31
|
+
"任务契约与实际代码不匹配",
|
|
32
|
+
"执行器返回的结果格式不正确",
|
|
33
|
+
],
|
|
34
|
+
"suggestions": [
|
|
35
|
+
"检查审计文件中的执行器输出",
|
|
36
|
+
"确认目标路径在工作区中存在",
|
|
37
|
+
"如果是路径问题,回到 cgc-plan 修正步骤契约",
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
"scope-error": {
|
|
41
|
+
"title": "任务范围错误",
|
|
42
|
+
"description": "当前步骤包含多个执行器归属的路径,需要拆分。",
|
|
43
|
+
"common_causes": [
|
|
44
|
+
"一个步骤同时包含前端和后端路径",
|
|
45
|
+
"一个步骤包含 shared 或 unknown 路径",
|
|
46
|
+
],
|
|
47
|
+
"suggestions": [
|
|
48
|
+
"运行 cgc-plan 查看拆分建议",
|
|
49
|
+
"按执行器归属(frontend/backend)拆分成独立步骤",
|
|
50
|
+
"shared 路径需要先明确归属或单独处理",
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
"design-gap": {
|
|
54
|
+
"title": "设计缺口",
|
|
55
|
+
"description": "当前步骤引用的路径或配置在路由策略中未覆盖,或目标文件不存在。",
|
|
56
|
+
"common_causes": [
|
|
57
|
+
"目标路径在 model-routing.yaml 中未定义",
|
|
58
|
+
"目标文件在工作区中不存在",
|
|
59
|
+
"路由规则与实际项目结构不匹配",
|
|
60
|
+
],
|
|
61
|
+
"suggestions": [
|
|
62
|
+
"检查 model-routing.yaml 是否覆盖目标路径",
|
|
63
|
+
"确认目标文件在工作区中存在",
|
|
64
|
+
"回到 cgc-plan 修正目标路径或步骤契约",
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
"environment-or-tooling": {
|
|
68
|
+
"title": "环境或工具问题",
|
|
69
|
+
"description": "执行器环境、依赖或外部工具不可用。",
|
|
70
|
+
"common_causes": [
|
|
71
|
+
"执行器 CLI 未安装或不在 PATH 中",
|
|
72
|
+
"执行器超时(网络、认证、长时间运行)",
|
|
73
|
+
"缺少必需的依赖或配置文件",
|
|
74
|
+
],
|
|
75
|
+
"suggestions": [
|
|
76
|
+
"运行 cgc-doctor 检查执行器可用性",
|
|
77
|
+
"检查网络连接和认证状态",
|
|
78
|
+
"确认执行器 CLI 已正确安装",
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
"workflow-state": {
|
|
82
|
+
"title": "工作流状态不满足",
|
|
83
|
+
"description": "当前工作流状态不允许执行请求的操作。",
|
|
84
|
+
"common_causes": [
|
|
85
|
+
"尝试执行 build/fix/test,但工作流还在 needs-planning 状态",
|
|
86
|
+
"尝试 review,但没有可审核的执行结果",
|
|
87
|
+
"工作流已关闭,但尝试继续执行",
|
|
88
|
+
],
|
|
89
|
+
"suggestions": [
|
|
90
|
+
"运行 cgc-route 查看当前工作流状态和推荐命令",
|
|
91
|
+
"按推荐命令顺序执行(plan → build/fix → review)",
|
|
92
|
+
"如果工作流已关闭,使用 /cgc 开始新的工作流",
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
"returned-to-planning": {
|
|
96
|
+
"title": "返回规划阶段",
|
|
97
|
+
"description": "执行器发现问题,需要回到规划阶段修正。",
|
|
98
|
+
"common_causes": [
|
|
99
|
+
"任务范围需要拆分(scope-error)",
|
|
100
|
+
"目标路径或契约有设计缺口(design-gap)",
|
|
101
|
+
],
|
|
102
|
+
"suggestions": [
|
|
103
|
+
"运行 cgc-plan 查看问题详情和修正建议",
|
|
104
|
+
"根据建议修正步骤契约或拆分步骤",
|
|
105
|
+
"修正后重新执行 build/fix",
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def explain_error(error_code: str) -> dict[str, Any]:
|
|
112
|
+
"""Get explanation for an error code.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
error_code: Error code from failure_type field
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Dict with title, description, common_causes, and suggestions
|
|
119
|
+
"""
|
|
120
|
+
if error_code not in ERROR_CATALOG:
|
|
121
|
+
return {
|
|
122
|
+
"error_code": error_code,
|
|
123
|
+
"title": "未知错误类型",
|
|
124
|
+
"description": f"错误代码 '{error_code}' 未在错误分类表中定义。",
|
|
125
|
+
"common_causes": [],
|
|
126
|
+
"suggestions": [
|
|
127
|
+
"查看完整错误信息中的 error 和 next 字段",
|
|
128
|
+
"运行 cgc-doctor 检查环境配置",
|
|
129
|
+
"如果问题持续,请报告此错误代码",
|
|
130
|
+
],
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
explanation = ERROR_CATALOG[error_code].copy()
|
|
134
|
+
explanation["error_code"] = error_code
|
|
135
|
+
return explanation
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def list_error_codes() -> list[str]:
|
|
139
|
+
"""List all available error codes."""
|
|
140
|
+
return sorted(ERROR_CATALOG.keys())
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def format_explanation(explanation: dict[str, Any]) -> str:
|
|
144
|
+
"""Format explanation as human-readable text.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
explanation: Result from explain_error
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Formatted text block
|
|
151
|
+
"""
|
|
152
|
+
lines = [
|
|
153
|
+
f"错误代码: {explanation['error_code']}",
|
|
154
|
+
f"标题: {explanation['title']}",
|
|
155
|
+
"",
|
|
156
|
+
"说明:",
|
|
157
|
+
explanation['description'],
|
|
158
|
+
"",
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
if explanation.get("common_causes"):
|
|
162
|
+
lines.append("常见原因:")
|
|
163
|
+
for cause in explanation["common_causes"]:
|
|
164
|
+
lines.append(f" - {cause}")
|
|
165
|
+
lines.append("")
|
|
166
|
+
|
|
167
|
+
if explanation.get("suggestions"):
|
|
168
|
+
lines.append("建议操作:")
|
|
169
|
+
for suggestion in explanation["suggestions"]:
|
|
170
|
+
lines.append(f" - {suggestion}")
|
|
171
|
+
|
|
172
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Error formatting and leveling for CodeCGC output.
|
|
2
|
+
|
|
3
|
+
Provides three-level error display:
|
|
4
|
+
- summary: User-friendly Chinese message for non-technical users
|
|
5
|
+
- detail: Technical context for developers
|
|
6
|
+
- debug: Full logs and tracebacks for troubleshooting
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def format_error_output(
|
|
14
|
+
result: dict[str, Any],
|
|
15
|
+
*,
|
|
16
|
+
level: str = "summary",
|
|
17
|
+
) -> dict[str, Any]:
|
|
18
|
+
"""Format error output with appropriate detail level.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
result: Raw result dict from workflow execution
|
|
22
|
+
level: Display level - "summary", "detail", or "debug"
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Formatted result with error_display field
|
|
26
|
+
"""
|
|
27
|
+
if result.get("success"):
|
|
28
|
+
return result
|
|
29
|
+
|
|
30
|
+
error_display = _build_error_display(result, level)
|
|
31
|
+
formatted = result.copy()
|
|
32
|
+
formatted["error_display"] = error_display
|
|
33
|
+
formatted["error_level"] = level
|
|
34
|
+
|
|
35
|
+
return formatted
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _build_error_display(result: dict[str, Any], level: str) -> dict[str, Any]:
|
|
39
|
+
"""Build error display structure based on level."""
|
|
40
|
+
display: dict[str, Any] = {
|
|
41
|
+
"level": level,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Summary level: user-friendly Chinese only
|
|
45
|
+
if level == "summary":
|
|
46
|
+
display["message"] = _extract_user_message(result)
|
|
47
|
+
display["suggestion"] = _extract_user_suggestion(result)
|
|
48
|
+
return display
|
|
49
|
+
|
|
50
|
+
# Detail level: add technical context
|
|
51
|
+
if level == "detail":
|
|
52
|
+
display["message"] = _extract_user_message(result)
|
|
53
|
+
display["suggestion"] = _extract_user_suggestion(result)
|
|
54
|
+
display["technical_error"] = result.get("error", "")
|
|
55
|
+
display["failure_type"] = result.get("failure_type", "")
|
|
56
|
+
display["state"] = result.get("state", "")
|
|
57
|
+
display["audit_path"] = result.get("audit_path", "")
|
|
58
|
+
return display
|
|
59
|
+
|
|
60
|
+
# Debug level: everything
|
|
61
|
+
if level == "debug":
|
|
62
|
+
display["message"] = _extract_user_message(result)
|
|
63
|
+
display["suggestion"] = _extract_user_suggestion(result)
|
|
64
|
+
display["technical_error"] = result.get("error", "")
|
|
65
|
+
display["failure_type"] = result.get("failure_type", "")
|
|
66
|
+
display["state"] = result.get("state", "")
|
|
67
|
+
display["audit_path"] = result.get("audit_path", "")
|
|
68
|
+
display["full_result"] = result
|
|
69
|
+
return display
|
|
70
|
+
|
|
71
|
+
# Fallback
|
|
72
|
+
display["message"] = _extract_user_message(result)
|
|
73
|
+
return display
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _extract_user_message(result: dict[str, Any]) -> str:
|
|
77
|
+
"""Extract user-friendly error message."""
|
|
78
|
+
# Check for human_error first (from Phase 1)
|
|
79
|
+
execution = result.get("execution", {})
|
|
80
|
+
if isinstance(execution, dict):
|
|
81
|
+
exec_result = execution.get("result", {})
|
|
82
|
+
if isinstance(exec_result, dict):
|
|
83
|
+
human_error = exec_result.get("human_error", "").strip()
|
|
84
|
+
if human_error:
|
|
85
|
+
return human_error
|
|
86
|
+
|
|
87
|
+
# Check for next field (from flow control)
|
|
88
|
+
next_msg = result.get("next", "").strip()
|
|
89
|
+
if next_msg:
|
|
90
|
+
return next_msg
|
|
91
|
+
|
|
92
|
+
# Check for error field
|
|
93
|
+
error_msg = result.get("error", "").strip()
|
|
94
|
+
if error_msg:
|
|
95
|
+
# If it looks technical, provide generic message
|
|
96
|
+
if "failed with exit code" in error_msg.lower() or "traceback" in error_msg.lower():
|
|
97
|
+
return "执行步骤失败。请查看详细信息或运行 cgc-doctor 检查环境。"
|
|
98
|
+
return error_msg
|
|
99
|
+
|
|
100
|
+
return "执行失败,未提供详细信息。"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _extract_user_suggestion(result: dict[str, Any]) -> str:
|
|
104
|
+
"""Extract user-friendly suggestion."""
|
|
105
|
+
# Check for suggestion field (from Phase 1)
|
|
106
|
+
execution = result.get("execution", {})
|
|
107
|
+
if isinstance(execution, dict):
|
|
108
|
+
exec_result = execution.get("result", {})
|
|
109
|
+
if isinstance(exec_result, dict):
|
|
110
|
+
suggestion = exec_result.get("suggestion", "").strip()
|
|
111
|
+
if suggestion:
|
|
112
|
+
return suggestion
|
|
113
|
+
|
|
114
|
+
# Check for recommended_command
|
|
115
|
+
recommended = result.get("recommended_command", "").strip()
|
|
116
|
+
if recommended:
|
|
117
|
+
return f"建议运行: {recommended}"
|
|
118
|
+
|
|
119
|
+
# Check for next field that contains suggestions
|
|
120
|
+
next_msg = result.get("next", "").strip()
|
|
121
|
+
if next_msg and ("建议" in next_msg or "请" in next_msg or "运行" in next_msg):
|
|
122
|
+
return next_msg
|
|
123
|
+
|
|
124
|
+
return "请稍后重试,或运行 cgc-doctor 检查环境配置。"
|
|
@@ -108,6 +108,17 @@ def classify_execution_failure(execution: dict[str, Any]) -> tuple[str, str, str
|
|
|
108
108
|
"当前步骤引用的目标路径在工作区中不存在,请先回到 cgc-plan 修正目标路径或步骤契约。",
|
|
109
109
|
)
|
|
110
110
|
|
|
111
|
+
if "failed with exit code" in combined:
|
|
112
|
+
human = str(result.get("human_error", "")).strip()
|
|
113
|
+
suggestion = str(result.get("suggestion", "")).strip()
|
|
114
|
+
next_msg = human + "\n" + suggestion if human else "执行器内部异常,请稍后重试。如果持续失败,运行 cgc-doctor 检查环境。"
|
|
115
|
+
return (
|
|
116
|
+
"blocked",
|
|
117
|
+
"executor-crash",
|
|
118
|
+
"",
|
|
119
|
+
next_msg,
|
|
120
|
+
)
|
|
121
|
+
|
|
111
122
|
if outcome == "blocked" or "timeout" in combined or "does not exist" in combined:
|
|
112
123
|
return (
|
|
113
124
|
"blocked",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import os
|
|
4
5
|
import sys
|
|
5
6
|
from typing import Any
|
|
6
7
|
|
|
@@ -20,6 +21,14 @@ def configure_utf8_stdio() -> None:
|
|
|
20
21
|
|
|
21
22
|
def print_json(payload: dict[str, Any], *, file: Any | None = None) -> None:
|
|
22
23
|
target = file or sys.stdout
|
|
24
|
+
|
|
25
|
+
# Apply error formatting if this is an error result
|
|
26
|
+
if not payload.get("success") and "error_display" not in payload:
|
|
27
|
+
error_level = os.environ.get("CODECGC_ERROR_LEVEL", "summary")
|
|
28
|
+
if error_level in {"summary", "detail", "debug"}:
|
|
29
|
+
from codecgc_error_formatter import format_error_output
|
|
30
|
+
payload = format_error_output(payload, level=error_level)
|
|
31
|
+
|
|
23
32
|
text = json.dumps(payload, ensure_ascii=False, indent=2)
|
|
24
33
|
target.write(text)
|
|
25
34
|
target.write("\n")
|
|
@@ -14,6 +14,21 @@ WORKSPACE = PACKAGE_ROOT
|
|
|
14
14
|
PROJECT_WORKSPACE = PROJECT_ROOT
|
|
15
15
|
SCRIPTS_DIR = WORKSPACE / "scripts"
|
|
16
16
|
|
|
17
|
+
_SCRIPT_OPERATION_NAMES = {
|
|
18
|
+
"plan_codecgc_workflow.py": "规划工作流",
|
|
19
|
+
"route_codecgc_workflow.py": "路由检查",
|
|
20
|
+
"run_codecgc_build.py": "构建执行",
|
|
21
|
+
"run_codecgc_fix.py": "修复执行",
|
|
22
|
+
"run_codecgc_test.py": "测试执行",
|
|
23
|
+
"review_codecgc_workflow.py": "审核调度",
|
|
24
|
+
"build_codecgc_task.py": "任务构建",
|
|
25
|
+
"write_codecgc_decision.py": "写入决策",
|
|
26
|
+
"write_codecgc_learning.py": "写入经验",
|
|
27
|
+
"write_codecgc_architecture.py": "写入架构",
|
|
28
|
+
"write_codecgc_requirement.py": "写入需求",
|
|
29
|
+
"init_codecgc_workflow.py": "初始化工作流",
|
|
30
|
+
}
|
|
31
|
+
|
|
17
32
|
|
|
18
33
|
def build_script_command(script_name: str, *args: str) -> list[str]:
|
|
19
34
|
return [sys.executable, str(SCRIPTS_DIR / script_name), *args]
|
|
@@ -63,10 +78,13 @@ def run_json_script(script_name: str, *args: str) -> dict[str, Any]:
|
|
|
63
78
|
parsed.setdefault("returncode", completed.returncode)
|
|
64
79
|
return parsed
|
|
65
80
|
|
|
81
|
+
operation = _SCRIPT_OPERATION_NAMES.get(script_name, script_name)
|
|
66
82
|
return {
|
|
67
83
|
"success": False,
|
|
68
84
|
"returncode": completed.returncode,
|
|
69
85
|
"stdout": stdout,
|
|
70
86
|
"stderr": stderr,
|
|
71
87
|
"error": f"{script_name} failed with exit code {completed.returncode}.",
|
|
88
|
+
"human_error": f"{operation}步骤执行失败(内部脚本异常退出)。",
|
|
89
|
+
"suggestion": "请稍后重试。如果多次失败,运行 cgc-doctor 检查环境配置。",
|
|
72
90
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""cgc-explain: Explain CodeCGC error codes and provide actionable suggestions.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
cgc-explain <error_code>
|
|
5
|
+
cgc-explain --list
|
|
6
|
+
"""
|
|
7
|
+
import argparse
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
from codecgc_console_io import configure_utf8_stdio
|
|
11
|
+
from codecgc_console_io import print_json
|
|
12
|
+
from codecgc_error_catalog import explain_error
|
|
13
|
+
from codecgc_error_catalog import format_explanation
|
|
14
|
+
from codecgc_error_catalog import list_error_codes
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
18
|
+
parser = argparse.ArgumentParser(
|
|
19
|
+
description="Explain CodeCGC error codes and provide actionable suggestions."
|
|
20
|
+
)
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
"error_code",
|
|
23
|
+
nargs="?",
|
|
24
|
+
help="Error code to explain (e.g., executor-crash, scope-error)",
|
|
25
|
+
)
|
|
26
|
+
parser.add_argument(
|
|
27
|
+
"--list",
|
|
28
|
+
action="store_true",
|
|
29
|
+
help="List all available error codes",
|
|
30
|
+
)
|
|
31
|
+
parser.add_argument(
|
|
32
|
+
"--format",
|
|
33
|
+
choices=["json", "summary"],
|
|
34
|
+
default="summary",
|
|
35
|
+
help="Output format",
|
|
36
|
+
)
|
|
37
|
+
return parser
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def main() -> int:
|
|
41
|
+
configure_utf8_stdio()
|
|
42
|
+
parser = build_parser()
|
|
43
|
+
args = parser.parse_args()
|
|
44
|
+
|
|
45
|
+
if args.list:
|
|
46
|
+
codes = list_error_codes()
|
|
47
|
+
if args.format == "json":
|
|
48
|
+
print_json({"success": True, "error_codes": codes})
|
|
49
|
+
else:
|
|
50
|
+
print("可用的错误代码:")
|
|
51
|
+
for code in codes:
|
|
52
|
+
print(f" - {code}")
|
|
53
|
+
print("\n使用 cgc-explain <error_code> 查看详细说明")
|
|
54
|
+
return 0
|
|
55
|
+
|
|
56
|
+
if not args.error_code:
|
|
57
|
+
parser.print_help()
|
|
58
|
+
return 1
|
|
59
|
+
|
|
60
|
+
explanation = explain_error(args.error_code)
|
|
61
|
+
|
|
62
|
+
if args.format == "json":
|
|
63
|
+
print_json({"success": True, "explanation": explanation})
|
|
64
|
+
else:
|
|
65
|
+
print(format_explanation(explanation))
|
|
66
|
+
|
|
67
|
+
return 0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
if __name__ == "__main__":
|
|
71
|
+
sys.exit(main())
|
|
@@ -134,6 +134,27 @@ def build_project_onboarding_text() -> str:
|
|
|
134
134
|
|
|
135
135
|
This file is generated by `cgc-init` for this project. It is intentionally project-relative and should not contain machine-specific install paths.
|
|
136
136
|
|
|
137
|
+
## Installation
|
|
138
|
+
|
|
139
|
+
**Recommended: Global Install + Project Init**
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
npm install -g @hunyed15/codecgc
|
|
143
|
+
cd your-project
|
|
144
|
+
cgc-init
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
After global installation, commands like `cgc-init`, `cgc-status`, `cgc-doctor` are available in any directory.
|
|
148
|
+
|
|
149
|
+
**Alternative: Project-Level Install**
|
|
150
|
+
|
|
151
|
+
For CI, Docker, or version isolation scenarios:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm install @hunyed15/codecgc
|
|
155
|
+
npx cgc-init
|
|
156
|
+
```
|
|
157
|
+
|
|
137
158
|
## First Run
|
|
138
159
|
|
|
139
160
|
Inside Claude:
|
|
@@ -910,10 +931,29 @@ def build_doctor_fix_command(workspace_root: Path) -> str:
|
|
|
910
931
|
return f"cgc-init --workspace {shell_quote(str(workspace_root))}"
|
|
911
932
|
|
|
912
933
|
|
|
934
|
+
def is_global_npm_install() -> bool:
|
|
935
|
+
"""检测当前是否为全局安装的 CodeCGC"""
|
|
936
|
+
try:
|
|
937
|
+
# 检查是否在 npm 全局目录中
|
|
938
|
+
import sys
|
|
939
|
+
executable_path = Path(sys.executable).resolve()
|
|
940
|
+
# 简单启发式:如果在 node_modules/.bin 之外,可能是全局安装
|
|
941
|
+
# 更准确的方法是检查 cgc-init 命令是否在 PATH 中且不需要 npx
|
|
942
|
+
cgc_init_path = shutil.which("cgc-init")
|
|
943
|
+
if cgc_init_path:
|
|
944
|
+
# 如果能直接找到 cgc-init,说明是全局安装
|
|
945
|
+
return True
|
|
946
|
+
except Exception:
|
|
947
|
+
pass
|
|
948
|
+
return False
|
|
949
|
+
|
|
950
|
+
|
|
913
951
|
def build_install_mode_summary(result: dict[str, Any]) -> str:
|
|
914
952
|
mode = str(result.get("mode", "")).strip()
|
|
915
953
|
|
|
916
954
|
if mode == "local":
|
|
955
|
+
is_global = is_global_npm_install()
|
|
956
|
+
|
|
917
957
|
lines = [
|
|
918
958
|
f"- 工作区: {result.get('workspace', '')}",
|
|
919
959
|
"- 范围: 项目级 Claude 与 MCP 集成面",
|
|
@@ -926,8 +966,17 @@ def build_install_mode_summary(result: dict[str, Any]) -> str:
|
|
|
926
966
|
f"- Hook 脚本: {result.get('hook_script', '')}",
|
|
927
967
|
f"- Slash Commands: {result.get('commands_dir', '')}",
|
|
928
968
|
f"- 新手入口: {result.get('onboarding_file', '')}",
|
|
929
|
-
"- 说明: 可选外部能力如 MemOS 不由 cgc-init 自动写入;如需启用,请在 Claude 中单独配置官方 MCP。",
|
|
930
969
|
]
|
|
970
|
+
|
|
971
|
+
if is_global:
|
|
972
|
+
lines.append("- 安装方式: 全局安装(推荐)")
|
|
973
|
+
lines.append("- 说明: 初始化完成。现在可以在 Claude 中使用 /cgc 或在命令行使用 cgc 命令。")
|
|
974
|
+
else:
|
|
975
|
+
lines.append("- 安装方式: 项目级安装")
|
|
976
|
+
lines.append("- 说明: 项目级安装需要通过 npx 调用命令。推荐全局安装:npm install -g @hunyed15/codecgc")
|
|
977
|
+
|
|
978
|
+
lines.append("- 提示: 可选外部能力如 MemOS 不由 cgc-init 自动写入;如需启用,请在 Claude 中单独配置官方 MCP。")
|
|
979
|
+
|
|
931
980
|
next_actions = [
|
|
932
981
|
"cgc-start",
|
|
933
982
|
"cgc-status",
|
|
@@ -12,13 +12,31 @@ function isGlobalInstall() {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function main() {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const isGlobal = isGlobalInstall();
|
|
16
|
+
|
|
17
|
+
if (isGlobal) {
|
|
18
|
+
console.log("");
|
|
19
|
+
console.log("✓ CodeCGC 已全局安装");
|
|
20
|
+
console.log("");
|
|
21
|
+
console.log("下一步:");
|
|
22
|
+
console.log(" 1. 进入项目目录:cd your-project");
|
|
23
|
+
console.log(" 2. 初始化项目:cgc-init");
|
|
24
|
+
console.log(" 3. 查看状态:cgc-status");
|
|
25
|
+
console.log("");
|
|
26
|
+
console.log("初始化后,可在 Claude 中使用 /cgc 或在命令行使用 cgc 命令。");
|
|
27
|
+
console.log("");
|
|
28
|
+
} else {
|
|
29
|
+
console.log("");
|
|
30
|
+
console.log("✓ CodeCGC 已安装到项目");
|
|
31
|
+
console.log("");
|
|
32
|
+
console.log("下一步:");
|
|
33
|
+
console.log(" 运行 'npx cgc-init' 来初始化项目");
|
|
34
|
+
console.log("");
|
|
35
|
+
console.log("提示:推荐全局安装以获得更好的体验:");
|
|
36
|
+
console.log(" npm install -g @hunyed15/codecgc");
|
|
37
|
+
console.log("");
|
|
17
38
|
}
|
|
18
39
|
|
|
19
|
-
console.warn("[codecgc] Global CLI installed.");
|
|
20
|
-
console.warn("[codecgc] CodeCGC no longer writes Claude user-level files during npm install.");
|
|
21
|
-
console.warn("[codecgc] Run `cgc-init` from each target project to create project-local .mcp.json, .claude/, and model-routing.yaml.");
|
|
22
40
|
return 0;
|
|
23
41
|
}
|
|
24
42
|
|