@hunyed15/codecgc 0.1.7 → 0.1.8
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/.claude/hooks/route-edit.ps1 +58 -57
- package/INSTALLATION.md +117 -484
- package/README.md +118 -150
- package/bin/cgc-external-status.js +4 -0
- package/bin/cgc-start.js +4 -0
- package/bin/codecgc.js +141 -20
- package/codecgc/compound/codecgc-capability-matrix.md +37 -0
- package/codecgc/reference/README.md +69 -0
- package/codecgc/reference/maintainer-guide.md +93 -0
- package/codecgc/reference/mcp-tool-surface.md +112 -0
- package/codecgc/reference/onboarding.md +69 -0
- package/codecgc/reference/operation-guide.md +29 -23
- package/codecgc/reference/path-contract.md +53 -0
- package/codecgc/reference/policy-routing.md +57 -0
- package/codecgc/reference/project-structure.md +80 -0
- package/codecgc/reference/quickstart.md +108 -0
- package/codecgc/reference/real-workflow-loop.md +123 -0
- package/codecgc/reference/recovery-loop.md +109 -0
- package/codecgc/reference/release-maintenance-playbook.md +4 -1
- package/codecgc/reference/troubleshooting.md +112 -0
- package/codecgc/roadmap/codecgc-release-maintenance/delivery-plan.md +49 -0
- package/codecgc/roadmap/codecgc-release-maintenance/overview.md +41 -0
- package/codecgc/roadmap/codecgc-release-maintenance/phases.md +84 -0
- package/codecgcmcp/README.md +57 -11
- package/codecgcmcp/src/codecgcmcp/server.py +164 -26
- package/model-routing.yaml +31 -6
- package/package.json +11 -4
- package/scripts/audit_codecgc_external_capabilities.py +83 -4
- package/scripts/audit_codecgc_historical_audits.py +42 -2
- package/scripts/audit_codecgc_package_runtime.py +73 -4
- package/scripts/audit_codecgc_release_readiness.py +55 -3
- package/scripts/audit_codecgc_workflow_history.py +8 -5
- package/scripts/build_codecgc_task.py +62 -45
- package/scripts/codecgc_artifact_roots.py +8 -40
- package/scripts/codecgc_console_io.py +3 -45
- package/scripts/codecgc_executor_registry.py +4 -54
- package/scripts/codecgc_path_contract.py +7 -0
- package/scripts/codecgc_policy.py +275 -0
- package/scripts/codecgc_routing_paths.py +3 -16
- package/scripts/codecgc_routing_template.py +11 -135
- package/scripts/codecgc_runtime/__init__.py +1 -0
- package/scripts/codecgc_runtime/artifacts.py +42 -0
- package/scripts/codecgc_runtime/console.py +45 -0
- package/scripts/codecgc_runtime/executor_registry.py +55 -0
- package/scripts/codecgc_runtime/mcp_config.py +72 -0
- package/scripts/codecgc_runtime/path_contract.py +123 -0
- package/scripts/codecgc_runtime/paths.py +22 -0
- package/scripts/codecgc_runtime/routing_paths.py +16 -0
- package/scripts/codecgc_runtime/routing_template.py +169 -0
- package/scripts/codecgc_runtime/workflow_runtime.py +72 -0
- package/scripts/codecgc_runtime_paths.py +3 -22
- package/scripts/codecgc_step_control.py +3 -2
- package/scripts/codecgc_workflow_runtime.py +3 -71
- package/scripts/entry_codecgc_workflow.py +4 -0
- package/scripts/install_codecgc.py +490 -21
- package/scripts/normalize_codecgc_audits.py +5 -3
- package/scripts/postinstall_codecgc.js +6 -56
- package/scripts/review_codecgc_workflow.py +6 -3
- package/scripts/route_codecgc_workflow.py +67 -36
- package/scripts/run_codecgc_build.py +28 -0
- package/scripts/run_codecgc_fix.py +28 -0
- package/scripts/run_codecgc_task.py +5 -2
- package/scripts/run_codecgc_test.py +28 -0
- package/scripts/sync_codecgc_mcp_config.py +4 -54
- package/scripts/write_codecgc_review.py +7 -3
package/codecgcmcp/README.md
CHANGED
|
@@ -1,17 +1,63 @@
|
|
|
1
1
|
# CodeCGC MCP Server
|
|
2
2
|
|
|
3
|
-
This package contains the
|
|
3
|
+
This package contains the CodeCGC orchestrator MCP server.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The server is the preferred Claude-facing capability layer. The CLI remains available for fallback, CI, and local debugging.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
7
|
+
## Current Tool Surface
|
|
8
|
+
|
|
9
|
+
- `codecgc.install`
|
|
10
|
+
- `codecgc.start`
|
|
11
|
+
- `codecgc.status`
|
|
12
|
+
- `codecgc.doctor`
|
|
13
|
+
- `codecgc.entry`
|
|
14
|
+
- `codecgc.continue`
|
|
15
|
+
- `codecgc.explain`
|
|
16
|
+
- `codecgc.review`
|
|
17
|
+
- `codecgc.history`
|
|
18
|
+
- `codecgc.route`
|
|
19
|
+
- `codecgc.plan`
|
|
20
|
+
- `codecgc.build`
|
|
21
|
+
- `codecgc.fix`
|
|
22
|
+
- `codecgc.test`
|
|
23
|
+
- `codecgc.package_audit`
|
|
24
|
+
- `codecgc.external_audit`
|
|
25
|
+
- `codecgc.external_status`
|
|
26
|
+
- `codecgc.release_readiness`
|
|
27
|
+
- `codecgc.lifecycle`
|
|
28
|
+
|
|
29
|
+
## Runtime Boundary
|
|
16
30
|
|
|
17
31
|
This server currently reuses the existing CodeCGC runtime scripts rather than replacing them.
|
|
32
|
+
|
|
33
|
+
The contract is:
|
|
34
|
+
|
|
35
|
+
- MCP tools expose product capabilities to Claude.
|
|
36
|
+
- Runtime scripts own workflow behavior.
|
|
37
|
+
- CLI commands stay as compatibility and maintainer surfaces.
|
|
38
|
+
- MCP responses should be machine-readable JSON payloads.
|
|
39
|
+
- `codecgc.external_status` is the concise panel view; `codecgc.external_audit` is the deeper consistency check.
|
|
40
|
+
|
|
41
|
+
## Response Contract
|
|
42
|
+
|
|
43
|
+
Every tool returns a stable envelope:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"success": true,
|
|
48
|
+
"tool": "codecgc.status",
|
|
49
|
+
"payload": {},
|
|
50
|
+
"error": null,
|
|
51
|
+
"meta": {
|
|
52
|
+
"contract_version": "1.0",
|
|
53
|
+
"payload_success": true,
|
|
54
|
+
"response_shape": "codecgc.mcp.tool_result"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The raw runtime response remains available under `payload`.
|
|
60
|
+
|
|
61
|
+
See `codecgc/reference/mcp-tool-surface.md` for the full contract.
|
|
62
|
+
|
|
63
|
+
Errors include a stable `error.category` field so Claude can distinguish runtime failures, invalid JSON, permission issues, missing scripts, and MCP wrapper exceptions without parsing text.
|
|
@@ -15,6 +15,16 @@ from codecgc_workflow_runtime import run_json_script
|
|
|
15
15
|
|
|
16
16
|
mcp = FastMCP("CodeCGC MCP Server")
|
|
17
17
|
|
|
18
|
+
MCP_CONTRACT_VERSION = "1.0"
|
|
19
|
+
|
|
20
|
+
EXCEPTION_ERROR_CATEGORIES = {
|
|
21
|
+
"JSONDecodeError": "runtime-json-invalid",
|
|
22
|
+
"ValueError": "runtime-json-invalid",
|
|
23
|
+
"TimeoutExpired": "runtime-timeout",
|
|
24
|
+
"FileNotFoundError": "runtime-script-missing",
|
|
25
|
+
"PermissionError": "runtime-permission-denied",
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
|
|
19
29
|
def _append_repeated_flag(args: list[str], flag: str, values: list[str]) -> None:
|
|
20
30
|
for value in values:
|
|
@@ -27,18 +37,106 @@ def _normalize_workspace(workspace: str) -> str:
|
|
|
27
37
|
return str(Path(workspace).expanduser().resolve()) if str(workspace).strip() else ""
|
|
28
38
|
|
|
29
39
|
|
|
30
|
-
def
|
|
40
|
+
def _payload_success(payload: dict[str, Any]) -> bool:
|
|
41
|
+
return bool(payload.get("success", True))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _runtime_error_category(payload: dict[str, Any]) -> str:
|
|
45
|
+
raw_category = str(payload.get("error_category") or payload.get("failure_category") or "").strip()
|
|
46
|
+
if raw_category:
|
|
47
|
+
return raw_category
|
|
48
|
+
returncode = payload.get("returncode")
|
|
49
|
+
if returncode is not None:
|
|
50
|
+
return "runtime-script-failed"
|
|
51
|
+
return "runtime-payload-failed"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _payload_error(tool_name: str, script_name: str, args: tuple[str, ...], payload: dict[str, Any]) -> dict[str, Any] | None:
|
|
55
|
+
if _payload_success(payload):
|
|
56
|
+
return None
|
|
57
|
+
summary = payload.get("summary", {}) if isinstance(payload.get("summary"), dict) else {}
|
|
58
|
+
message = str(
|
|
59
|
+
payload.get("error")
|
|
60
|
+
or summary.get("human_summary")
|
|
61
|
+
or summary.get("recommended_next_action")
|
|
62
|
+
or "Runtime script reported failure."
|
|
63
|
+
)
|
|
64
|
+
return {
|
|
65
|
+
"type": str(payload.get("error_type") or "RuntimeScriptError"),
|
|
66
|
+
"category": _runtime_error_category(payload),
|
|
67
|
+
"message": message,
|
|
68
|
+
"tool": tool_name,
|
|
69
|
+
"script": script_name,
|
|
70
|
+
"args": list(args),
|
|
71
|
+
"returncode": payload.get("returncode"),
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _exception_category(error: Exception) -> str:
|
|
76
|
+
return EXCEPTION_ERROR_CATEGORIES.get(error.__class__.__name__, "mcp-wrapper-exception")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _exception_payload(tool_name: str, script_name: str, args: tuple[str, ...], error: Exception) -> tuple[dict[str, Any], dict[str, Any]]:
|
|
80
|
+
normalized_error = {
|
|
81
|
+
"type": error.__class__.__name__,
|
|
82
|
+
"category": _exception_category(error),
|
|
83
|
+
"message": str(error),
|
|
84
|
+
"tool": tool_name,
|
|
85
|
+
"script": script_name,
|
|
86
|
+
"args": list(args),
|
|
87
|
+
"returncode": None,
|
|
88
|
+
}
|
|
89
|
+
payload = {
|
|
90
|
+
"success": False,
|
|
91
|
+
"mode": "mcp-runtime-call",
|
|
92
|
+
"summary": {
|
|
93
|
+
"ready": False,
|
|
94
|
+
"human_summary": "CodeCGC MCP tool failed before a runtime JSON payload was produced.",
|
|
95
|
+
"recommended_next_action": "Check the runtime script output and MCP server logs.",
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
return payload, normalized_error
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _build_tool_envelope(tool_name: str, payload: dict[str, Any], error: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
102
|
+
success = _payload_success(payload) and error is None
|
|
103
|
+
return {
|
|
104
|
+
"success": success,
|
|
105
|
+
"tool": tool_name,
|
|
106
|
+
"payload": payload,
|
|
107
|
+
"error": error,
|
|
108
|
+
"meta": {
|
|
109
|
+
"contract_version": MCP_CONTRACT_VERSION,
|
|
110
|
+
"payload_success": _payload_success(payload),
|
|
111
|
+
"response_shape": "codecgc.mcp.tool_result",
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _as_tool_result(tool_name: str, payload: dict[str, Any], error: dict[str, Any] | None = None) -> CallToolResult:
|
|
117
|
+
envelope = _build_tool_envelope(tool_name, payload, error)
|
|
31
118
|
return CallToolResult(
|
|
32
119
|
content=[
|
|
33
120
|
TextContent(
|
|
34
121
|
type="text",
|
|
35
|
-
text=json.dumps(
|
|
122
|
+
text=json.dumps(envelope, ensure_ascii=False, indent=2),
|
|
36
123
|
)
|
|
37
124
|
],
|
|
38
|
-
isError=not bool(
|
|
125
|
+
isError=not bool(envelope.get("success", True)),
|
|
39
126
|
)
|
|
40
127
|
|
|
41
128
|
|
|
129
|
+
def _call_runtime_tool(tool_name: str, script_name: str, *args: str, requested_format: str = "") -> CallToolResult:
|
|
130
|
+
try:
|
|
131
|
+
payload = run_json_script(script_name, *args)
|
|
132
|
+
if requested_format:
|
|
133
|
+
payload.setdefault("requested_format", requested_format)
|
|
134
|
+
return _as_tool_result(tool_name, payload, _payload_error(tool_name, script_name, args, payload))
|
|
135
|
+
except Exception as error:
|
|
136
|
+
payload, normalized_error = _exception_payload(tool_name, script_name, args, error)
|
|
137
|
+
return _as_tool_result(tool_name, payload, normalized_error)
|
|
138
|
+
|
|
139
|
+
|
|
42
140
|
@mcp.tool(
|
|
43
141
|
name="codecgc.install",
|
|
44
142
|
description="Install or sync CodeCGC integration for the current project or Claude user profile.",
|
|
@@ -51,7 +149,7 @@ async def codecgc_install(
|
|
|
51
149
|
] = "local",
|
|
52
150
|
format: Annotated[
|
|
53
151
|
Literal["summary", "json"],
|
|
54
|
-
Field(description="
|
|
152
|
+
Field(description="Presentation hint. MCP responses are always returned as JSON payloads."),
|
|
55
153
|
] = "summary",
|
|
56
154
|
workspace: Annotated[
|
|
57
155
|
str,
|
|
@@ -62,13 +160,14 @@ async def codecgc_install(
|
|
|
62
160
|
Field(description="Optional explicit Claude user root for user/user-dry-run modes."),
|
|
63
161
|
] = "",
|
|
64
162
|
) -> CallToolResult:
|
|
65
|
-
|
|
163
|
+
# The MCP surface must always receive machine-readable JSON from the script.
|
|
164
|
+
args = ["--mode", mode, "--format", "json"]
|
|
66
165
|
normalized_workspace = _normalize_workspace(workspace)
|
|
67
166
|
if normalized_workspace:
|
|
68
167
|
args.extend(["--workspace", normalized_workspace])
|
|
69
168
|
if str(user_root).strip():
|
|
70
169
|
args.extend(["--user-root", str(user_root).strip()])
|
|
71
|
-
return
|
|
170
|
+
return _call_runtime_tool("codecgc.install", "install_codecgc.py", *args, requested_format=format)
|
|
72
171
|
|
|
73
172
|
|
|
74
173
|
@mcp.tool(
|
|
@@ -86,7 +185,25 @@ async def codecgc_status(
|
|
|
86
185
|
normalized_workspace = _normalize_workspace(workspace)
|
|
87
186
|
if normalized_workspace:
|
|
88
187
|
args.extend(["--workspace", normalized_workspace])
|
|
89
|
-
return
|
|
188
|
+
return _call_runtime_tool("codecgc.status", "install_codecgc.py", *args)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@mcp.tool(
|
|
192
|
+
name="codecgc.start",
|
|
193
|
+
description="Show the project-local CodeCGC first-run guide and recommended next actions.",
|
|
194
|
+
meta={"version": "0.1.0", "author": "CodeCGC"},
|
|
195
|
+
)
|
|
196
|
+
async def codecgc_start(
|
|
197
|
+
workspace: Annotated[
|
|
198
|
+
str,
|
|
199
|
+
Field(description="Optional target workspace root."),
|
|
200
|
+
] = "",
|
|
201
|
+
) -> CallToolResult:
|
|
202
|
+
args = ["--mode", "start", "--format", "json"]
|
|
203
|
+
normalized_workspace = _normalize_workspace(workspace)
|
|
204
|
+
if normalized_workspace:
|
|
205
|
+
args.extend(["--workspace", normalized_workspace])
|
|
206
|
+
return _call_runtime_tool("codecgc.start", "install_codecgc.py", *args)
|
|
90
207
|
|
|
91
208
|
|
|
92
209
|
@mcp.tool(
|
|
@@ -104,7 +221,7 @@ async def codecgc_doctor(
|
|
|
104
221
|
normalized_workspace = _normalize_workspace(workspace)
|
|
105
222
|
if normalized_workspace:
|
|
106
223
|
args.extend(["--workspace", normalized_workspace])
|
|
107
|
-
return
|
|
224
|
+
return _call_runtime_tool("codecgc.doctor", "install_codecgc.py", *args)
|
|
108
225
|
|
|
109
226
|
|
|
110
227
|
@mcp.tool(
|
|
@@ -152,7 +269,7 @@ async def codecgc_entry(
|
|
|
152
269
|
args.extend(["--audit-file", str(audit_file).strip()])
|
|
153
270
|
if decision:
|
|
154
271
|
args.extend(["--decision", decision])
|
|
155
|
-
return
|
|
272
|
+
return _call_runtime_tool("codecgc.entry", "entry_codecgc_workflow.py", *args)
|
|
156
273
|
|
|
157
274
|
|
|
158
275
|
@mcp.tool(
|
|
@@ -185,7 +302,7 @@ async def codecgc_continue(
|
|
|
185
302
|
args.append("--auto-dispatch")
|
|
186
303
|
if dry_run:
|
|
187
304
|
args.append("--dry-run")
|
|
188
|
-
return
|
|
305
|
+
return _call_runtime_tool("codecgc.continue", "entry_codecgc_workflow.py", *args)
|
|
189
306
|
|
|
190
307
|
|
|
191
308
|
@mcp.tool(
|
|
@@ -212,7 +329,7 @@ async def codecgc_explain(
|
|
|
212
329
|
args.append("--latest")
|
|
213
330
|
if include_fixtures:
|
|
214
331
|
args.append("--include-fixtures")
|
|
215
|
-
return
|
|
332
|
+
return _call_runtime_tool("codecgc.explain", "entry_codecgc_workflow.py", *args)
|
|
216
333
|
|
|
217
334
|
|
|
218
335
|
@mcp.tool(
|
|
@@ -236,7 +353,7 @@ async def codecgc_review(
|
|
|
236
353
|
args.extend(["--next-step", str(next_step).strip()])
|
|
237
354
|
if force:
|
|
238
355
|
args.append("--force")
|
|
239
|
-
return
|
|
356
|
+
return _call_runtime_tool("codecgc.review", "review_codecgc_workflow.py", *args)
|
|
240
357
|
|
|
241
358
|
|
|
242
359
|
@mcp.tool(
|
|
@@ -256,7 +373,7 @@ async def codecgc_history(
|
|
|
256
373
|
args = ["--flow", flow, "--status", str(status).strip() or "all", "--last", str(int(last)), "--format", "json"]
|
|
257
374
|
if include_fixtures:
|
|
258
375
|
args.append("--include-fixtures")
|
|
259
|
-
return
|
|
376
|
+
return _call_runtime_tool("codecgc.history", "audit_codecgc_workflow_history.py", *args)
|
|
260
377
|
|
|
261
378
|
|
|
262
379
|
@mcp.tool(
|
|
@@ -271,7 +388,7 @@ async def codecgc_route(
|
|
|
271
388
|
],
|
|
272
389
|
slug: Annotated[str, "Workflow slug."],
|
|
273
390
|
) -> CallToolResult:
|
|
274
|
-
return
|
|
391
|
+
return _call_runtime_tool("codecgc.route", "route_codecgc_workflow.py", "--flow", flow, "--slug", str(slug).strip())
|
|
275
392
|
|
|
276
393
|
|
|
277
394
|
@mcp.tool(
|
|
@@ -354,7 +471,7 @@ async def codecgc_plan(
|
|
|
354
471
|
args.extend(["--artifact-class", artifact_class])
|
|
355
472
|
if force:
|
|
356
473
|
args.append("--force")
|
|
357
|
-
return
|
|
474
|
+
return _call_runtime_tool("codecgc.plan", "plan_codecgc_workflow.py", *args)
|
|
358
475
|
|
|
359
476
|
|
|
360
477
|
@mcp.tool(
|
|
@@ -385,7 +502,7 @@ async def codecgc_build(
|
|
|
385
502
|
args.append("--dry-run")
|
|
386
503
|
if return_all_messages:
|
|
387
504
|
args.append("--return-all-messages")
|
|
388
|
-
return
|
|
505
|
+
return _call_runtime_tool("codecgc.build", "run_codecgc_build.py", *args)
|
|
389
506
|
|
|
390
507
|
|
|
391
508
|
@mcp.tool(
|
|
@@ -416,7 +533,7 @@ async def codecgc_fix(
|
|
|
416
533
|
args.append("--dry-run")
|
|
417
534
|
if return_all_messages:
|
|
418
535
|
args.append("--return-all-messages")
|
|
419
|
-
return
|
|
536
|
+
return _call_runtime_tool("codecgc.fix", "run_codecgc_fix.py", *args)
|
|
420
537
|
|
|
421
538
|
|
|
422
539
|
@mcp.tool(
|
|
@@ -451,7 +568,7 @@ async def codecgc_test(
|
|
|
451
568
|
args.append("--dry-run")
|
|
452
569
|
if return_all_messages:
|
|
453
570
|
args.append("--return-all-messages")
|
|
454
|
-
return
|
|
571
|
+
return _call_runtime_tool("codecgc.test", "run_codecgc_test.py", *args)
|
|
455
572
|
|
|
456
573
|
|
|
457
574
|
@mcp.tool(
|
|
@@ -465,7 +582,15 @@ async def codecgc_package_audit(
|
|
|
465
582
|
Field(description="Output format."),
|
|
466
583
|
] = "json",
|
|
467
584
|
) -> CallToolResult:
|
|
468
|
-
return
|
|
585
|
+
return _call_runtime_tool("codecgc.package_audit", "audit_codecgc_package_runtime.py", "--format", format)
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def _external_capability_runtime_args(view: str, workspace: str, format: str) -> list[str]:
|
|
589
|
+
args = ["--view", view, "--format", format]
|
|
590
|
+
normalized_workspace = _normalize_workspace(workspace)
|
|
591
|
+
if normalized_workspace:
|
|
592
|
+
args.extend(["--workspace", normalized_workspace])
|
|
593
|
+
return args
|
|
469
594
|
|
|
470
595
|
|
|
471
596
|
@mcp.tool(
|
|
@@ -480,11 +605,24 @@ async def codecgc_external_audit(
|
|
|
480
605
|
Field(description="Output format."),
|
|
481
606
|
] = "json",
|
|
482
607
|
) -> CallToolResult:
|
|
483
|
-
args =
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
608
|
+
args = _external_capability_runtime_args("audit", workspace, format)
|
|
609
|
+
return _call_runtime_tool("codecgc.external_audit", "audit_codecgc_external_capabilities.py", *args)
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
@mcp.tool(
|
|
613
|
+
name="codecgc.external_status",
|
|
614
|
+
description="Render the concise external capability status panel for day-to-day checks.",
|
|
615
|
+
meta={"version": "0.1.0", "author": "CodeCGC"},
|
|
616
|
+
)
|
|
617
|
+
async def codecgc_external_status(
|
|
618
|
+
workspace: Annotated[str, "Optional target workspace root."] = "",
|
|
619
|
+
format: Annotated[
|
|
620
|
+
Literal["summary", "json"],
|
|
621
|
+
Field(description="Output format."),
|
|
622
|
+
] = "summary",
|
|
623
|
+
) -> CallToolResult:
|
|
624
|
+
args = _external_capability_runtime_args("status", workspace, format)
|
|
625
|
+
return _call_runtime_tool("codecgc.external_status", "audit_codecgc_external_capabilities.py", *args)
|
|
488
626
|
|
|
489
627
|
|
|
490
628
|
@mcp.tool(
|
|
@@ -503,7 +641,7 @@ async def codecgc_release_readiness(
|
|
|
503
641
|
normalized_workspace = _normalize_workspace(workspace)
|
|
504
642
|
if normalized_workspace:
|
|
505
643
|
args.extend(["--workspace", normalized_workspace])
|
|
506
|
-
return
|
|
644
|
+
return _call_runtime_tool("codecgc.release_readiness", "audit_codecgc_release_readiness.py", *args)
|
|
507
645
|
|
|
508
646
|
|
|
509
647
|
@mcp.tool(
|
|
@@ -517,7 +655,7 @@ async def codecgc_lifecycle(
|
|
|
517
655
|
Field(description="Output format."),
|
|
518
656
|
] = "json",
|
|
519
657
|
) -> CallToolResult:
|
|
520
|
-
return
|
|
658
|
+
return _call_runtime_tool("codecgc.lifecycle", "audit_codecgc_lifecycle.py", "--format", format)
|
|
521
659
|
|
|
522
660
|
|
|
523
661
|
def run() -> None:
|
package/model-routing.yaml
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
version:
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
orchestration_paths:
|
|
4
|
+
- "codecgc/**"
|
|
5
|
+
- ".claude/commands/**"
|
|
6
|
+
- ".claude/settings.json"
|
|
7
|
+
- ".mcp.json"
|
|
8
|
+
- "model-routing.yaml"
|
|
9
|
+
|
|
10
|
+
docs_paths:
|
|
11
|
+
- "README.md"
|
|
12
|
+
- "INSTALLATION.md"
|
|
13
|
+
- "docs/**"
|
|
14
|
+
- "CHANGELOG.md"
|
|
2
15
|
|
|
3
16
|
frontend_paths:
|
|
4
17
|
- "apps/web/**"
|
|
@@ -9,8 +22,6 @@ frontend_paths:
|
|
|
9
22
|
- "web/**"
|
|
10
23
|
- "frontend/**"
|
|
11
24
|
|
|
12
|
-
custom_frontend_paths:
|
|
13
|
-
|
|
14
25
|
backend_paths:
|
|
15
26
|
- "apps/api/**"
|
|
16
27
|
- "server/**"
|
|
@@ -19,7 +30,19 @@ backend_paths:
|
|
|
19
30
|
- "src/repositories/**"
|
|
20
31
|
- "backend/**"
|
|
21
32
|
|
|
22
|
-
|
|
33
|
+
test_paths:
|
|
34
|
+
frontend:
|
|
35
|
+
- "apps/web/*.test.*"
|
|
36
|
+
- "apps/web/*.spec.*"
|
|
37
|
+
- "apps/web/**/*.test.*"
|
|
38
|
+
- "apps/web/**/*.spec.*"
|
|
39
|
+
- "tests/frontend/**"
|
|
40
|
+
backend:
|
|
41
|
+
- "apps/api/*.test.*"
|
|
42
|
+
- "apps/api/*.spec.*"
|
|
43
|
+
- "apps/api/**/*.test.*"
|
|
44
|
+
- "apps/api/**/*.spec.*"
|
|
45
|
+
- "tests/backend/**"
|
|
23
46
|
|
|
24
47
|
shared_paths:
|
|
25
48
|
- "packages/shared/**"
|
|
@@ -28,7 +51,9 @@ shared_paths:
|
|
|
28
51
|
- "src/types/**"
|
|
29
52
|
|
|
30
53
|
rules:
|
|
31
|
-
|
|
54
|
+
claude_allowed_owners:
|
|
55
|
+
- "orchestration"
|
|
56
|
+
- "docs"
|
|
32
57
|
backend_executor: "codexmcp"
|
|
58
|
+
frontend_executor: "geminimcp"
|
|
33
59
|
shared_policy: "split-first"
|
|
34
|
-
claude_role: "plan-review-accept-only"
|
package/package.json
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hunyed15/codecgc",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Claude-hosted multi-model workflow product shell for CodeCGC.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|
|
8
8
|
"cgc": "bin/cgc.js",
|
|
9
|
+
"cgc-start": "bin/cgc-start.js",
|
|
9
10
|
"cgc-install": "bin/cgc-install.js",
|
|
10
11
|
"cgc-status": "bin/cgc-status.js",
|
|
11
12
|
"cgc-doctor": "bin/cgc-doctor.js",
|
|
12
13
|
"cgc-package-audit": "bin/cgc-package-audit.js",
|
|
13
14
|
"cgc-external-audit": "bin/cgc-external-audit.js",
|
|
15
|
+
"cgc-external-status": "bin/cgc-external-status.js",
|
|
14
16
|
"cgc-release-readiness": "bin/cgc-release-readiness.js",
|
|
15
17
|
"cgc-lifecycle": "bin/cgc-lifecycle.js",
|
|
16
18
|
"cgc-history": "bin/cgc-history.js",
|
|
@@ -25,10 +27,12 @@
|
|
|
25
27
|
"scripts": {
|
|
26
28
|
"postinstall": "node scripts/postinstall_codecgc.js",
|
|
27
29
|
"cgc:help": "node bin/cgc.js --help",
|
|
30
|
+
"cgc:start": "node bin/cgc-start.js --format summary",
|
|
28
31
|
"cgc:status": "node bin/cgc-status.js --format summary",
|
|
29
32
|
"cgc:doctor": "node bin/cgc-doctor.js --format summary",
|
|
30
33
|
"cgc:package-audit": "node bin/cgc-package-audit.js --format summary",
|
|
31
34
|
"cgc:external-audit": "node bin/cgc-external-audit.js --format summary",
|
|
35
|
+
"cgc:external-status": "node bin/cgc-external-status.js --format summary",
|
|
32
36
|
"cgc:release-readiness": "node bin/cgc-release-readiness.js --format summary",
|
|
33
37
|
"cgc:lifecycle": "node bin/cgc-lifecycle.js --format summary",
|
|
34
38
|
"cgc:history": "node bin/cgc-history.js --status open --last 10 --format summary",
|
|
@@ -40,6 +44,7 @@
|
|
|
40
44
|
"files": [
|
|
41
45
|
"bin/",
|
|
42
46
|
"scripts/*.py",
|
|
47
|
+
"scripts/codecgc_runtime/*.py",
|
|
43
48
|
"scripts/postinstall_codecgc.js",
|
|
44
49
|
"scripts/README-codecgc-cli.md",
|
|
45
50
|
".claude/hooks/route-edit.ps1",
|
|
@@ -56,17 +61,19 @@
|
|
|
56
61
|
"codecgc/cgc-review/",
|
|
57
62
|
"codecgc/cgc-roadmap/",
|
|
58
63
|
"codecgc/cgc-test/",
|
|
64
|
+
"codecgc/compound/",
|
|
59
65
|
"codecgc/reference/",
|
|
66
|
+
"codecgc/roadmap/",
|
|
60
67
|
"codecgcmcp/pyproject.toml",
|
|
61
68
|
"codecgcmcp/README.md",
|
|
62
|
-
"codecgcmcp/src/codecgcmcp
|
|
69
|
+
"codecgcmcp/src/codecgcmcp/*.py",
|
|
63
70
|
"codexmcp/pyproject.toml",
|
|
64
71
|
"codexmcp/README.md",
|
|
65
72
|
"codexmcp/LICENSE",
|
|
66
|
-
"codexmcp/src/codexmcp
|
|
73
|
+
"codexmcp/src/codexmcp/*.py",
|
|
67
74
|
"geminimcp/pyproject.toml",
|
|
68
75
|
"geminimcp/README.md",
|
|
69
|
-
"geminimcp/src/geminimcp
|
|
76
|
+
"geminimcp/src/geminimcp/*.py",
|
|
70
77
|
"requirements.txt",
|
|
71
78
|
"INSTALLATION.md",
|
|
72
79
|
"model-routing.yaml",
|
|
@@ -9,6 +9,16 @@ from codecgc_runtime_paths import resolve_workspace_root
|
|
|
9
9
|
|
|
10
10
|
WORKSPACE = Path(__file__).resolve().parents[1]
|
|
11
11
|
REGISTRY_PATH = WORKSPACE / "codecgc" / "reference" / "external-capability-registry.json"
|
|
12
|
+
STATUS_PANEL_CAPABILITY_ORDER = [
|
|
13
|
+
"memos",
|
|
14
|
+
"github-mcp",
|
|
15
|
+
"linear-mcp",
|
|
16
|
+
"sentry-mcp",
|
|
17
|
+
]
|
|
18
|
+
STATUS_PANEL_SUPPORT_CAPABILITY_ORDER = [
|
|
19
|
+
"augment-search",
|
|
20
|
+
"jira-mcp",
|
|
21
|
+
]
|
|
12
22
|
|
|
13
23
|
|
|
14
24
|
def load_registry() -> dict[str, Any]:
|
|
@@ -107,7 +117,7 @@ def normalize_capability_entry(entry: dict[str, Any], workspace_servers: dict[st
|
|
|
107
117
|
}
|
|
108
118
|
|
|
109
119
|
|
|
110
|
-
def audit_external_capabilities(workspace_override: str = "") -> dict[str, Any]:
|
|
120
|
+
def audit_external_capabilities(workspace_override: str = "", view: str = "audit") -> dict[str, Any]:
|
|
111
121
|
registry = load_registry()
|
|
112
122
|
workspace_servers, workspace_root = load_workspace_mcp_servers(workspace_override)
|
|
113
123
|
entries = registry.get("capabilities", [])
|
|
@@ -142,6 +152,8 @@ def audit_external_capabilities(workspace_override: str = "") -> dict[str, Any]:
|
|
|
142
152
|
human_summary = "外部能力登记表存在缺失字段或非法项。"
|
|
143
153
|
elif drift_items:
|
|
144
154
|
human_summary = "外部能力登记表已就绪,但发现本地额外接入漂移。"
|
|
155
|
+
elif view == "status":
|
|
156
|
+
human_summary = "外部能力状态面板已就绪。"
|
|
145
157
|
|
|
146
158
|
recommended_next_action = ""
|
|
147
159
|
if blocking_items:
|
|
@@ -158,12 +170,14 @@ def audit_external_capabilities(workspace_override: str = "") -> dict[str, Any]:
|
|
|
158
170
|
return {
|
|
159
171
|
"success": ready,
|
|
160
172
|
"mode": "external-capability-audit",
|
|
173
|
+
"presentation_view": view,
|
|
161
174
|
"workspace": str(workspace_root),
|
|
162
175
|
"registry_path": str(REGISTRY_PATH),
|
|
163
176
|
"summary": {
|
|
164
177
|
"ready": ready,
|
|
165
178
|
"scope": "外部能力白名单、接入状态声明与本地 MCP 观测状态",
|
|
166
179
|
"human_summary": human_summary,
|
|
180
|
+
"view": view,
|
|
167
181
|
"capability_count": len(normalized),
|
|
168
182
|
"integrated_count": counts["integrated"],
|
|
169
183
|
"planned_count": counts["planned"],
|
|
@@ -178,7 +192,31 @@ def audit_external_capabilities(workspace_override: str = "") -> dict[str, Any]:
|
|
|
178
192
|
}
|
|
179
193
|
|
|
180
194
|
|
|
181
|
-
def
|
|
195
|
+
def _capability_by_id(result: dict[str, Any], capability_id: str) -> dict[str, Any] | None:
|
|
196
|
+
for item in result.get("capabilities", []):
|
|
197
|
+
if not isinstance(item, dict):
|
|
198
|
+
continue
|
|
199
|
+
if str(item.get("id", "")).strip() == capability_id:
|
|
200
|
+
return item
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _format_capability_panel_line(item: dict[str, Any]) -> str:
|
|
205
|
+
status = str(item.get("status", "")).strip()
|
|
206
|
+
status_label = {
|
|
207
|
+
"integrated": "已纳管",
|
|
208
|
+
"planned": "规划中",
|
|
209
|
+
"optional": "可选",
|
|
210
|
+
}.get(status, status or "未知")
|
|
211
|
+
local_label = "已观测" if item.get("local_ready") else "未观测"
|
|
212
|
+
observed = ", ".join(str(value).strip() for value in item.get("observed_servers", []) if str(value).strip()) or "无"
|
|
213
|
+
return (
|
|
214
|
+
f"- {item.get('name', '')} [{item.get('id', '')}]: "
|
|
215
|
+
f"{status_label} | 本地={local_label} | 服务器={observed}"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def build_audit_summary(result: dict[str, Any]) -> str:
|
|
182
220
|
summary = result.get("summary", {}) if isinstance(result.get("summary"), dict) else {}
|
|
183
221
|
lines = [
|
|
184
222
|
f"- 工作区: {result.get('workspace', '')}",
|
|
@@ -249,8 +287,46 @@ def build_summary(result: dict[str, Any]) -> str:
|
|
|
249
287
|
return render_summary_block("CodeCGC 外部能力审计", lines, next_actions)
|
|
250
288
|
|
|
251
289
|
|
|
290
|
+
def build_status_panel(result: dict[str, Any]) -> str:
|
|
291
|
+
summary = result.get("summary", {}) if isinstance(result.get("summary"), dict) else {}
|
|
292
|
+
lines = [
|
|
293
|
+
f"- 工作区: {result.get('workspace', '')}",
|
|
294
|
+
f"- 登记表: {result.get('registry_path', '')}",
|
|
295
|
+
f"- 范围: {summary.get('scope', '')}",
|
|
296
|
+
f"- 摘要: {summary.get('human_summary', '')}",
|
|
297
|
+
f"- 就绪: {'是' if summary.get('ready') else '否'}",
|
|
298
|
+
f"- 正式接入: {summary.get('integrated_count', 0)}",
|
|
299
|
+
f"- 规划中: {summary.get('planned_count', 0)}",
|
|
300
|
+
f"- 可选项: {summary.get('optional_count', 0)}",
|
|
301
|
+
f"- 阻塞项: {summary.get('blocking_count', 0)}",
|
|
302
|
+
f"- 漂移项: {summary.get('drift_count', 0)}",
|
|
303
|
+
"- 正式能力面板:",
|
|
304
|
+
]
|
|
305
|
+
for capability_id in STATUS_PANEL_CAPABILITY_ORDER:
|
|
306
|
+
item = _capability_by_id(result, capability_id)
|
|
307
|
+
if isinstance(item, dict):
|
|
308
|
+
lines.append(_format_capability_panel_line(item))
|
|
309
|
+
lines.append("- 其他受管能力:")
|
|
310
|
+
for capability_id in STATUS_PANEL_SUPPORT_CAPABILITY_ORDER:
|
|
311
|
+
item = _capability_by_id(result, capability_id)
|
|
312
|
+
if isinstance(item, dict):
|
|
313
|
+
lines.append(_format_capability_panel_line(item))
|
|
314
|
+
next_actions = []
|
|
315
|
+
next_action = str(summary.get("recommended_next_action", "")).strip()
|
|
316
|
+
if next_action:
|
|
317
|
+
next_actions.append(next_action)
|
|
318
|
+
next_actions.append("需要更细的登记一致性检查时,再跑 cgc-external-audit")
|
|
319
|
+
return render_summary_block("CodeCGC 外部能力状态面板", lines, next_actions)
|
|
320
|
+
|
|
321
|
+
|
|
252
322
|
def main() -> int:
|
|
253
323
|
parser = argparse.ArgumentParser(description="Audit CodeCGC external capability registry and local MCP observations.")
|
|
324
|
+
parser.add_argument(
|
|
325
|
+
"--view",
|
|
326
|
+
choices=["audit", "status"],
|
|
327
|
+
default="audit",
|
|
328
|
+
help="Rendered summary view. Audit is detailed; status is the concise panel view.",
|
|
329
|
+
)
|
|
254
330
|
parser.add_argument(
|
|
255
331
|
"--format",
|
|
256
332
|
choices=["json", "summary"],
|
|
@@ -264,9 +340,12 @@ def main() -> int:
|
|
|
264
340
|
)
|
|
265
341
|
args = parser.parse_args()
|
|
266
342
|
|
|
267
|
-
result = audit_external_capabilities(args.workspace)
|
|
343
|
+
result = audit_external_capabilities(args.workspace, view=args.view)
|
|
268
344
|
if args.format == "summary":
|
|
269
|
-
|
|
345
|
+
if args.view == "status":
|
|
346
|
+
print(build_status_panel(result))
|
|
347
|
+
else:
|
|
348
|
+
print(build_audit_summary(result))
|
|
270
349
|
else:
|
|
271
350
|
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
272
351
|
return 0 if result.get("success") else 1
|