@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.
Files changed (65) hide show
  1. package/.claude/hooks/route-edit.ps1 +58 -57
  2. package/INSTALLATION.md +117 -484
  3. package/README.md +118 -150
  4. package/bin/cgc-external-status.js +4 -0
  5. package/bin/cgc-start.js +4 -0
  6. package/bin/codecgc.js +141 -20
  7. package/codecgc/compound/codecgc-capability-matrix.md +37 -0
  8. package/codecgc/reference/README.md +69 -0
  9. package/codecgc/reference/maintainer-guide.md +93 -0
  10. package/codecgc/reference/mcp-tool-surface.md +112 -0
  11. package/codecgc/reference/onboarding.md +69 -0
  12. package/codecgc/reference/operation-guide.md +29 -23
  13. package/codecgc/reference/path-contract.md +53 -0
  14. package/codecgc/reference/policy-routing.md +57 -0
  15. package/codecgc/reference/project-structure.md +80 -0
  16. package/codecgc/reference/quickstart.md +108 -0
  17. package/codecgc/reference/real-workflow-loop.md +123 -0
  18. package/codecgc/reference/recovery-loop.md +109 -0
  19. package/codecgc/reference/release-maintenance-playbook.md +4 -1
  20. package/codecgc/reference/troubleshooting.md +112 -0
  21. package/codecgc/roadmap/codecgc-release-maintenance/delivery-plan.md +49 -0
  22. package/codecgc/roadmap/codecgc-release-maintenance/overview.md +41 -0
  23. package/codecgc/roadmap/codecgc-release-maintenance/phases.md +84 -0
  24. package/codecgcmcp/README.md +57 -11
  25. package/codecgcmcp/src/codecgcmcp/server.py +164 -26
  26. package/model-routing.yaml +31 -6
  27. package/package.json +11 -4
  28. package/scripts/audit_codecgc_external_capabilities.py +83 -4
  29. package/scripts/audit_codecgc_historical_audits.py +42 -2
  30. package/scripts/audit_codecgc_package_runtime.py +73 -4
  31. package/scripts/audit_codecgc_release_readiness.py +55 -3
  32. package/scripts/audit_codecgc_workflow_history.py +8 -5
  33. package/scripts/build_codecgc_task.py +62 -45
  34. package/scripts/codecgc_artifact_roots.py +8 -40
  35. package/scripts/codecgc_console_io.py +3 -45
  36. package/scripts/codecgc_executor_registry.py +4 -54
  37. package/scripts/codecgc_path_contract.py +7 -0
  38. package/scripts/codecgc_policy.py +275 -0
  39. package/scripts/codecgc_routing_paths.py +3 -16
  40. package/scripts/codecgc_routing_template.py +11 -135
  41. package/scripts/codecgc_runtime/__init__.py +1 -0
  42. package/scripts/codecgc_runtime/artifacts.py +42 -0
  43. package/scripts/codecgc_runtime/console.py +45 -0
  44. package/scripts/codecgc_runtime/executor_registry.py +55 -0
  45. package/scripts/codecgc_runtime/mcp_config.py +72 -0
  46. package/scripts/codecgc_runtime/path_contract.py +123 -0
  47. package/scripts/codecgc_runtime/paths.py +22 -0
  48. package/scripts/codecgc_runtime/routing_paths.py +16 -0
  49. package/scripts/codecgc_runtime/routing_template.py +169 -0
  50. package/scripts/codecgc_runtime/workflow_runtime.py +72 -0
  51. package/scripts/codecgc_runtime_paths.py +3 -22
  52. package/scripts/codecgc_step_control.py +3 -2
  53. package/scripts/codecgc_workflow_runtime.py +3 -71
  54. package/scripts/entry_codecgc_workflow.py +4 -0
  55. package/scripts/install_codecgc.py +490 -21
  56. package/scripts/normalize_codecgc_audits.py +5 -3
  57. package/scripts/postinstall_codecgc.js +6 -56
  58. package/scripts/review_codecgc_workflow.py +6 -3
  59. package/scripts/route_codecgc_workflow.py +67 -36
  60. package/scripts/run_codecgc_build.py +28 -0
  61. package/scripts/run_codecgc_fix.py +28 -0
  62. package/scripts/run_codecgc_task.py +5 -2
  63. package/scripts/run_codecgc_test.py +28 -0
  64. package/scripts/sync_codecgc_mcp_config.py +4 -54
  65. package/scripts/write_codecgc_review.py +7 -3
@@ -1,17 +1,63 @@
1
1
  # CodeCGC MCP Server
2
2
 
3
- This package contains the first minimal CodeCGC orchestrator MCP server.
3
+ This package contains the CodeCGC orchestrator MCP server.
4
4
 
5
- Current scope:
5
+ The server is the preferred Claude-facing capability layer. The CLI remains available for fallback, CI, and local debugging.
6
6
 
7
- - install
8
- - status
9
- - doctor
10
- - entry
11
- - continue
12
- - explain
13
- - review
14
- - history
15
- - route
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 _as_tool_result(payload: dict[str, Any]) -> CallToolResult:
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(payload, ensure_ascii=True, indent=2),
122
+ text=json.dumps(envelope, ensure_ascii=False, indent=2),
36
123
  )
37
124
  ],
38
- isError=not bool(payload.get("success", True)),
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="Output format. Use summary for normal product-facing replies."),
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
- args = ["--mode", mode, "--format", format]
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 _as_tool_result(run_json_script("install_codecgc.py", *args))
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 _as_tool_result(run_json_script("install_codecgc.py", *args))
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 _as_tool_result(run_json_script("install_codecgc.py", *args))
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 _as_tool_result(run_json_script("entry_codecgc_workflow.py", *args))
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 _as_tool_result(run_json_script("entry_codecgc_workflow.py", *args))
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 _as_tool_result(run_json_script("entry_codecgc_workflow.py", *args))
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 _as_tool_result(run_json_script("review_codecgc_workflow.py", *args))
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 _as_tool_result(run_json_script("audit_codecgc_workflow_history.py", *args))
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 _as_tool_result(run_json_script("route_codecgc_workflow.py", "--flow", flow, "--slug", str(slug).strip()))
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 _as_tool_result(run_json_script("plan_codecgc_workflow.py", *args))
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 _as_tool_result(run_json_script("run_codecgc_build.py", *args))
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 _as_tool_result(run_json_script("run_codecgc_fix.py", *args))
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 _as_tool_result(run_json_script("run_codecgc_test.py", *args))
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 _as_tool_result(run_json_script("audit_codecgc_package_runtime.py", "--format", format))
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 = ["--format", format]
484
- normalized_workspace = _normalize_workspace(workspace)
485
- if normalized_workspace:
486
- args.extend(["--workspace", normalized_workspace])
487
- return _as_tool_result(run_json_script("audit_codecgc_external_capabilities.py", *args))
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 _as_tool_result(run_json_script("audit_codecgc_release_readiness.py", *args))
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 _as_tool_result(run_json_script("audit_codecgc_lifecycle.py", "--format", format))
658
+ return _call_runtime_tool("codecgc.lifecycle", "audit_codecgc_lifecycle.py", "--format", format)
521
659
 
522
660
 
523
661
  def run() -> None:
@@ -1,4 +1,17 @@
1
- version: 1
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
- custom_backend_paths:
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
- frontend_executor: "geminimcp"
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.7",
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 build_summary(result: dict[str, Any]) -> str:
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
- print(build_summary(result))
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