@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
|
@@ -6,6 +6,8 @@ from codecgc_artifact_roots import discover_flow_directory
|
|
|
6
6
|
from codecgc_artifact_roots import flow_root
|
|
7
7
|
from codecgc_artifact_roots import execution_root
|
|
8
8
|
from codecgc_artifact_roots import normalize_artifact_class
|
|
9
|
+
from codecgc_path_contract import normalize_audit_path_fields
|
|
10
|
+
from codecgc_path_contract import normalize_persisted_project_path
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
WORKSPACE = Path(__file__).resolve().parents[1]
|
|
@@ -35,11 +37,11 @@ def build_expected_artifact_file(source: dict[str, Any], artifact_class: str) ->
|
|
|
35
37
|
artifact_slug = str(source.get("artifact_slug", "")).strip()
|
|
36
38
|
if artifact_type not in {"feature", "issue"} or not artifact_slug:
|
|
37
39
|
current = str(source.get("artifact_file", "")).strip()
|
|
38
|
-
return replace_repo_name(current) if current else current
|
|
40
|
+
return normalize_persisted_project_path(replace_repo_name(current)) if current else current
|
|
39
41
|
|
|
40
42
|
base_slug = artifact_slug[11:] if len(artifact_slug) > 11 and artifact_slug[4] == "-" else artifact_slug
|
|
41
43
|
checklist_name = f"{base_slug}-checklist.yaml" if artifact_type == "feature" else f"{base_slug}-fix.yaml"
|
|
42
|
-
return
|
|
44
|
+
return normalize_persisted_project_path(flow_root(artifact_type, artifact_class) / artifact_slug / checklist_name)
|
|
43
45
|
|
|
44
46
|
|
|
45
47
|
def normalize_audit_record(data: dict[str, Any]) -> tuple[dict[str, Any], str]:
|
|
@@ -55,7 +57,7 @@ def normalize_audit_record(data: dict[str, Any]) -> tuple[dict[str, Any], str]:
|
|
|
55
57
|
source["artifact_file"] = build_expected_artifact_file(source, artifact_class)
|
|
56
58
|
source["artifact_class"] = artifact_class
|
|
57
59
|
data["source"] = source
|
|
58
|
-
return data, artifact_class
|
|
60
|
+
return normalize_audit_path_fields(data), artifact_class
|
|
59
61
|
|
|
60
62
|
|
|
61
63
|
def normalize_file(path: Path) -> tuple[Path, bool]:
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const path = require("node:path");
|
|
5
|
-
|
|
6
|
-
function shouldRunUserInstall() {
|
|
3
|
+
function isGlobalInstall() {
|
|
7
4
|
const globalFlag = String(process.env.npm_config_global || "").toLowerCase();
|
|
8
5
|
const localPrefix = String(process.env.npm_config_local_prefix || "");
|
|
9
6
|
const prefix = String(process.env.npm_config_prefix || "");
|
|
@@ -11,64 +8,17 @@ function shouldRunUserInstall() {
|
|
|
11
8
|
if (globalFlag === "true") {
|
|
12
9
|
return true;
|
|
13
10
|
}
|
|
14
|
-
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function findPython() {
|
|
21
|
-
const override = String(process.env.CODECGC_PYTHON_COMMAND || "").trim();
|
|
22
|
-
const candidates = override
|
|
23
|
-
? [override]
|
|
24
|
-
: (process.platform === "win32" ? ["python", "py"] : ["python3", "python"]);
|
|
25
|
-
|
|
26
|
-
for (const command of candidates) {
|
|
27
|
-
const probe = spawnSync(command, ["--version"], {
|
|
28
|
-
encoding: "utf8",
|
|
29
|
-
shell: false,
|
|
30
|
-
});
|
|
31
|
-
if (probe.status === 0) {
|
|
32
|
-
return command;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return "";
|
|
11
|
+
return Boolean(prefix && localPrefix && prefix !== localPrefix);
|
|
36
12
|
}
|
|
37
13
|
|
|
38
14
|
function main() {
|
|
39
|
-
if (!
|
|
15
|
+
if (!isGlobalInstall()) {
|
|
40
16
|
return 0;
|
|
41
17
|
}
|
|
42
18
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
console.warn("[codecgc] Run `cgc-install --mode user` after installing Python.");
|
|
47
|
-
return 0;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const repoRoot = path.resolve(__dirname, "..");
|
|
51
|
-
const installScript = path.join(repoRoot, "scripts", "install_codecgc.py");
|
|
52
|
-
const result = spawnSync(
|
|
53
|
-
python,
|
|
54
|
-
[installScript, "--mode", "user", "--format", "summary"],
|
|
55
|
-
{
|
|
56
|
-
cwd: repoRoot,
|
|
57
|
-
stdio: "inherit",
|
|
58
|
-
shell: false,
|
|
59
|
-
env: {
|
|
60
|
-
...process.env,
|
|
61
|
-
PYTHONIOENCODING: process.env.PYTHONIOENCODING || "utf-8",
|
|
62
|
-
PYTHONUTF8: process.env.PYTHONUTF8 || "1",
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
if (result.status !== 0) {
|
|
68
|
-
console.warn("[codecgc] Automatic Claude integration did not complete during npm install.");
|
|
69
|
-
console.warn("[codecgc] You can retry manually with `cgc-install --mode user`.");
|
|
70
|
-
}
|
|
71
|
-
|
|
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-install` from each target project to create project-local .mcp.json, .claude/, and model-routing.yaml.");
|
|
72
22
|
return 0;
|
|
73
23
|
}
|
|
74
24
|
|
|
@@ -4,6 +4,8 @@ from pathlib import Path
|
|
|
4
4
|
|
|
5
5
|
from codecgc_console_io import configure_utf8_stdio
|
|
6
6
|
from codecgc_console_io import print_json
|
|
7
|
+
from codecgc_path_contract import normalize_persisted_project_path
|
|
8
|
+
from codecgc_path_contract import resolve_project_path
|
|
7
9
|
from codecgc_review_control import evaluate_review
|
|
8
10
|
from write_codecgc_review import load_json
|
|
9
11
|
from write_codecgc_review import render_review_decision
|
|
@@ -33,10 +35,11 @@ def main() -> int:
|
|
|
33
35
|
args = parser.parse_args()
|
|
34
36
|
|
|
35
37
|
try:
|
|
36
|
-
|
|
38
|
+
audit_file = resolve_project_path(args.audit_file)
|
|
39
|
+
audit = load_json(audit_file)
|
|
37
40
|
values = evaluate_review(audit, args.decision, args.risk, args.next_step)
|
|
38
41
|
writeback = write_review(
|
|
39
|
-
audit_path=
|
|
42
|
+
audit_path=audit_file,
|
|
40
43
|
decision=args.decision,
|
|
41
44
|
risks=args.risk,
|
|
42
45
|
next_step=args.next_step,
|
|
@@ -44,7 +47,7 @@ def main() -> int:
|
|
|
44
47
|
)
|
|
45
48
|
result = {
|
|
46
49
|
"success": True,
|
|
47
|
-
"audit_file":
|
|
50
|
+
"audit_file": normalize_persisted_project_path(audit_file),
|
|
48
51
|
"requested_decision": args.decision,
|
|
49
52
|
"final_decision": values["final_decision"],
|
|
50
53
|
"accepted": values["accepted"],
|
|
@@ -13,6 +13,7 @@ from codecgc_artifact_roots import normalize_artifact_class
|
|
|
13
13
|
from codecgc_command_surface import to_public_command
|
|
14
14
|
from codecgc_console_io import configure_utf8_stdio
|
|
15
15
|
from codecgc_console_io import print_json
|
|
16
|
+
from codecgc_path_contract import normalize_persisted_project_path
|
|
16
17
|
from codecgc_routing_paths import resolve_active_routing_file
|
|
17
18
|
from codecgc_runtime_paths import PACKAGE_ROOT
|
|
18
19
|
from codecgc_step_control import is_test_codecgc_block
|
|
@@ -23,6 +24,10 @@ WORKSPACE = PACKAGE_ROOT
|
|
|
23
24
|
ROUTING_FILE = resolve_active_routing_file()
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
def display_path(path: Path | None) -> str:
|
|
28
|
+
return normalize_persisted_project_path(path) if path else ""
|
|
29
|
+
|
|
30
|
+
|
|
26
31
|
def attach_route_summary(result: dict[str, Any]) -> dict[str, Any]:
|
|
27
32
|
review = result.get("review", {}) if isinstance(result.get("review"), dict) else {}
|
|
28
33
|
current_step = result.get("current_step", {}) if isinstance(result.get("current_step"), dict) else {}
|
|
@@ -189,16 +194,28 @@ def find_audit_for_task_id(task_id: str, artifact_class: str) -> tuple[Path | No
|
|
|
189
194
|
return audit_path, audit
|
|
190
195
|
|
|
191
196
|
|
|
192
|
-
def
|
|
193
|
-
text =
|
|
197
|
+
def parse_review_metadata(markdown: str) -> dict[str, Any]:
|
|
198
|
+
text = str(markdown or "")
|
|
194
199
|
decision_match = re.search(
|
|
195
200
|
r"## [45]\. (?:Review Decision|审核结论)\s+[\r\n]+- (?:审核结果:\s*)?(accepted|changes-requested|通过|需修改)",
|
|
196
201
|
text,
|
|
197
202
|
)
|
|
198
203
|
if not decision_match:
|
|
199
204
|
decision_match = re.search(r"- (?:Final decision|最终决策): (accepted|changes-requested|通过|需修改)", text)
|
|
205
|
+
if not decision_match:
|
|
206
|
+
decision_match = re.search(
|
|
207
|
+
r"-\s*(?:Review decision|审核决策|审核结果|瀹℃牳é崇瓥):\s*(accepted|changes-requested|通过|需修改)",
|
|
208
|
+
text,
|
|
209
|
+
flags=re.IGNORECASE,
|
|
210
|
+
)
|
|
200
211
|
task_match = re.search(r"- (?:Reviewed task_id|审核 task_id): (.+)", text)
|
|
201
212
|
step_match = re.search(r"- (?:Reviewed step_number|审核 step_number|审核步骤序号): (\d+)", text)
|
|
213
|
+
if not step_match:
|
|
214
|
+
step_match = re.search(
|
|
215
|
+
r"-\s*(?:Reviewed step_number|审核 step_number|审核步骤序号|瀹℃牳å§ãƒ©î€ƒæ´å¿“彿):\s*(\d+)",
|
|
216
|
+
text,
|
|
217
|
+
flags=re.IGNORECASE,
|
|
218
|
+
)
|
|
202
219
|
action_kind_match = re.search(r"- (?:Review action kind|审核动作类型): (.+)", text)
|
|
203
220
|
fallback_stage_match = re.search(r"- (?:Review fallback stage|审核回退阶段): (.+)", text)
|
|
204
221
|
policy_reason_match = re.search(r"- (?:Review policy reason|审核策略原因): (.+)", text)
|
|
@@ -214,6 +231,10 @@ def extract_review_metadata(path: Path) -> dict[str, Any]:
|
|
|
214
231
|
}
|
|
215
232
|
|
|
216
233
|
|
|
234
|
+
def extract_review_metadata(path: Path) -> dict[str, Any]:
|
|
235
|
+
return parse_review_metadata(load_text(path))
|
|
236
|
+
|
|
237
|
+
|
|
217
238
|
def review_matches_step(review: dict[str, Any], step: dict[str, Any]) -> bool:
|
|
218
239
|
return (
|
|
219
240
|
str(review.get("task_id", "")) == str(step.get("task_id", ""))
|
|
@@ -265,7 +286,7 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
265
286
|
"flow": "feature",
|
|
266
287
|
"slug": slug,
|
|
267
288
|
"artifact_class": artifact_class,
|
|
268
|
-
"directory":
|
|
289
|
+
"directory": display_path(directory),
|
|
269
290
|
"recommended_command": "cgc-plan",
|
|
270
291
|
"reason": "当前功能开发工作流骨架不完整。",
|
|
271
292
|
"next": "补齐或修复缺失的功能开发产物文件。",
|
|
@@ -277,7 +298,7 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
277
298
|
"flow": "feature",
|
|
278
299
|
"slug": slug,
|
|
279
300
|
"artifact_class": artifact_class,
|
|
280
|
-
"directory":
|
|
301
|
+
"directory": display_path(directory),
|
|
281
302
|
"recommended_command": "cgc-plan",
|
|
282
303
|
"reason": "当前功能开发工作流已存在,但还不可执行。",
|
|
283
304
|
"next": "继续细化设计,并补上有效的 CodeCGC 步骤契约。",
|
|
@@ -289,7 +310,7 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
289
310
|
"flow": "feature",
|
|
290
311
|
"slug": slug,
|
|
291
312
|
"artifact_class": artifact_class,
|
|
292
|
-
"directory":
|
|
313
|
+
"directory": display_path(directory),
|
|
293
314
|
"recommended_command": "cgc-plan",
|
|
294
315
|
"reason": "当前功能开发清单里仍然存在仅规划用途的拆分或路由确认步骤。",
|
|
295
316
|
"next": "先完成必须的拆分或路由澄清,再执行剩余的限定范围步骤。",
|
|
@@ -302,7 +323,7 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
302
323
|
"flow": "feature",
|
|
303
324
|
"slug": slug,
|
|
304
325
|
"artifact_class": artifact_class,
|
|
305
|
-
"directory":
|
|
326
|
+
"directory": display_path(directory),
|
|
306
327
|
"recommended_command": "cgc-plan",
|
|
307
328
|
"reason": "当前功能开发清单仍以不可执行的占位步骤开头。",
|
|
308
329
|
"next": "先澄清范围、归属和目标路径,再尝试执行该功能开发工作流。",
|
|
@@ -335,7 +356,7 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
335
356
|
"flow": "feature",
|
|
336
357
|
"slug": slug,
|
|
337
358
|
"artifact_class": artifact_class,
|
|
338
|
-
"directory":
|
|
359
|
+
"directory": display_path(directory),
|
|
339
360
|
"review": review,
|
|
340
361
|
"current_step": None,
|
|
341
362
|
"audit_path": "",
|
|
@@ -348,7 +369,7 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
348
369
|
"flow": "feature",
|
|
349
370
|
"slug": slug,
|
|
350
371
|
"artifact_class": artifact_class,
|
|
351
|
-
"directory":
|
|
372
|
+
"directory": display_path(directory),
|
|
352
373
|
"review": review,
|
|
353
374
|
"current_step": None,
|
|
354
375
|
"audit_path": "",
|
|
@@ -363,6 +384,7 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
363
384
|
"step_number": int(next_step.get("step_number", 0) or 0),
|
|
364
385
|
"task_id": str(next_step.get("task_id", "")),
|
|
365
386
|
"kind": str(next_step.get("kind", "")),
|
|
387
|
+
"step_type": str(next_step.get("step_type", "")),
|
|
366
388
|
"target_paths": next_step.get("target_paths", []),
|
|
367
389
|
"task_summary": str(next_step.get("task_summary", "")),
|
|
368
390
|
}
|
|
@@ -372,7 +394,7 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
372
394
|
"task_id": current_step["task_id"],
|
|
373
395
|
"task_summary": current_step["task_summary"],
|
|
374
396
|
"target_paths": current_step["target_paths"],
|
|
375
|
-
"step_type": "test" if "-test-step-" in current_step["task_id"] else "",
|
|
397
|
+
"step_type": current_step["step_type"] or ("test" if "-test-step-" in current_step["task_id"] else ""),
|
|
376
398
|
}
|
|
377
399
|
):
|
|
378
400
|
return {
|
|
@@ -380,25 +402,29 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
380
402
|
"flow": "feature",
|
|
381
403
|
"slug": slug,
|
|
382
404
|
"artifact_class": artifact_class,
|
|
383
|
-
"directory":
|
|
405
|
+
"directory": display_path(directory),
|
|
384
406
|
"review": review,
|
|
385
407
|
"current_step": current_step,
|
|
386
|
-
"audit_path":
|
|
408
|
+
"audit_path": display_path(audit_path),
|
|
387
409
|
"recommended_command": "cgc-test",
|
|
388
410
|
"reason": "当前功能开发工作流正在等待测试步骤执行。",
|
|
389
411
|
"next": "执行当前测试步骤。",
|
|
390
412
|
}
|
|
391
413
|
|
|
392
|
-
if
|
|
414
|
+
if (
|
|
415
|
+
review_for_current_step
|
|
416
|
+
and review.get("decision") == "changes-requested"
|
|
417
|
+
and not (audit and audit_is_ready_for_review(audit, next_step))
|
|
418
|
+
):
|
|
393
419
|
return {
|
|
394
420
|
"success": True,
|
|
395
421
|
"flow": "feature",
|
|
396
422
|
"slug": slug,
|
|
397
423
|
"artifact_class": artifact_class,
|
|
398
|
-
"directory":
|
|
424
|
+
"directory": display_path(directory),
|
|
399
425
|
"review": review,
|
|
400
426
|
"current_step": current_step,
|
|
401
|
-
"audit_path":
|
|
427
|
+
"audit_path": display_path(audit_path),
|
|
402
428
|
"recommended_command": "cgc-build",
|
|
403
429
|
"reason": "当前功能开发步骤在审核后仍需继续补充修改。",
|
|
404
430
|
"next": "完成要求的后续修改后,重新执行当前功能开发步骤。",
|
|
@@ -411,10 +437,10 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
411
437
|
"flow": "feature",
|
|
412
438
|
"slug": slug,
|
|
413
439
|
"artifact_class": artifact_class,
|
|
414
|
-
"directory":
|
|
440
|
+
"directory": display_path(directory),
|
|
415
441
|
"review": review,
|
|
416
442
|
"current_step": current_step,
|
|
417
|
-
"audit_path":
|
|
443
|
+
"audit_path": display_path(audit_path),
|
|
418
444
|
"recommended_command": "cgc-review",
|
|
419
445
|
"reason": "当前功能开发步骤已有执行证据,但还没有对应的审核结论。",
|
|
420
446
|
"next": f"审核最新审计产物 {audit_path},并回写验收结论。",
|
|
@@ -424,10 +450,10 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
424
450
|
"flow": "feature",
|
|
425
451
|
"slug": slug,
|
|
426
452
|
"artifact_class": artifact_class,
|
|
427
|
-
"directory":
|
|
453
|
+
"directory": display_path(directory),
|
|
428
454
|
"review": review,
|
|
429
455
|
"current_step": current_step,
|
|
430
|
-
"audit_path":
|
|
456
|
+
"audit_path": display_path(audit_path),
|
|
431
457
|
"recommended_command": "cgc-build",
|
|
432
458
|
"reason": "当前功能开发步骤还没有“通过”审核结论。",
|
|
433
459
|
"next": "执行或继续推进当前待执行的功能开发步骤。",
|
|
@@ -438,7 +464,7 @@ def route_feature(slug: str) -> dict[str, Any]:
|
|
|
438
464
|
"flow": "feature",
|
|
439
465
|
"slug": slug,
|
|
440
466
|
"artifact_class": artifact_class,
|
|
441
|
-
"directory":
|
|
467
|
+
"directory": display_path(directory),
|
|
442
468
|
"review": review,
|
|
443
469
|
"current_step": current_step,
|
|
444
470
|
"audit_path": "",
|
|
@@ -472,7 +498,7 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
472
498
|
"flow": "issue",
|
|
473
499
|
"slug": slug,
|
|
474
500
|
"artifact_class": artifact_class,
|
|
475
|
-
"directory":
|
|
501
|
+
"directory": display_path(directory),
|
|
476
502
|
"recommended_command": "cgc-plan",
|
|
477
503
|
"reason": "Issue 工作流骨架不完整。",
|
|
478
504
|
"next": "补齐或修复缺失的 issue 产物文件。",
|
|
@@ -484,7 +510,7 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
484
510
|
"flow": "issue",
|
|
485
511
|
"slug": slug,
|
|
486
512
|
"artifact_class": artifact_class,
|
|
487
|
-
"directory":
|
|
513
|
+
"directory": display_path(directory),
|
|
488
514
|
"recommended_command": "cgc-plan",
|
|
489
515
|
"reason": "当前问题修复工作流已存在,但还不可执行。",
|
|
490
516
|
"next": "继续细化修复范围,并补上有效的 CodeCGC 步骤契约。",
|
|
@@ -496,7 +522,7 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
496
522
|
"flow": "issue",
|
|
497
523
|
"slug": slug,
|
|
498
524
|
"artifact_class": artifact_class,
|
|
499
|
-
"directory":
|
|
525
|
+
"directory": display_path(directory),
|
|
500
526
|
"recommended_command": "cgc-plan",
|
|
501
527
|
"reason": "当前问题修复清单里仍然存在仅规划用途的拆分或路由确认步骤。",
|
|
502
528
|
"next": "先完成必须的拆分或路由澄清,再执行剩余的限定范围修复步骤。",
|
|
@@ -509,7 +535,7 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
509
535
|
"flow": "issue",
|
|
510
536
|
"slug": slug,
|
|
511
537
|
"artifact_class": artifact_class,
|
|
512
|
-
"directory":
|
|
538
|
+
"directory": display_path(directory),
|
|
513
539
|
"recommended_command": "cgc-plan",
|
|
514
540
|
"reason": "当前问题修复清单仍以不可执行的占位步骤开头。",
|
|
515
541
|
"next": "先澄清修复范围、归属和目标路径,再尝试执行该问题修复工作流。",
|
|
@@ -542,7 +568,7 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
542
568
|
"flow": "issue",
|
|
543
569
|
"slug": slug,
|
|
544
570
|
"artifact_class": artifact_class,
|
|
545
|
-
"directory":
|
|
571
|
+
"directory": display_path(directory),
|
|
546
572
|
"review": review,
|
|
547
573
|
"current_step": None,
|
|
548
574
|
"audit_path": "",
|
|
@@ -555,7 +581,7 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
555
581
|
"flow": "issue",
|
|
556
582
|
"slug": slug,
|
|
557
583
|
"artifact_class": artifact_class,
|
|
558
|
-
"directory":
|
|
584
|
+
"directory": display_path(directory),
|
|
559
585
|
"review": review,
|
|
560
586
|
"current_step": None,
|
|
561
587
|
"audit_path": "",
|
|
@@ -570,6 +596,7 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
570
596
|
"step_number": int(next_step.get("step_number", 0) or 0),
|
|
571
597
|
"task_id": str(next_step.get("task_id", "")),
|
|
572
598
|
"kind": str(next_step.get("kind", "")),
|
|
599
|
+
"step_type": str(next_step.get("step_type", "")),
|
|
573
600
|
"target_paths": next_step.get("target_paths", []),
|
|
574
601
|
"task_summary": str(next_step.get("task_summary", "")),
|
|
575
602
|
}
|
|
@@ -579,7 +606,7 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
579
606
|
"task_id": current_step["task_id"],
|
|
580
607
|
"task_summary": current_step["task_summary"],
|
|
581
608
|
"target_paths": current_step["target_paths"],
|
|
582
|
-
"step_type": "test" if "-test-step-" in current_step["task_id"] else "",
|
|
609
|
+
"step_type": current_step["step_type"] or ("test" if "-test-step-" in current_step["task_id"] else ""),
|
|
583
610
|
}
|
|
584
611
|
):
|
|
585
612
|
return {
|
|
@@ -587,25 +614,29 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
587
614
|
"flow": "issue",
|
|
588
615
|
"slug": slug,
|
|
589
616
|
"artifact_class": artifact_class,
|
|
590
|
-
"directory":
|
|
617
|
+
"directory": display_path(directory),
|
|
591
618
|
"review": review,
|
|
592
619
|
"current_step": current_step,
|
|
593
|
-
"audit_path":
|
|
620
|
+
"audit_path": display_path(audit_path),
|
|
594
621
|
"recommended_command": "cgc-test",
|
|
595
622
|
"reason": "当前问题修复工作流正在等待测试步骤执行。",
|
|
596
623
|
"next": "执行当前测试步骤。",
|
|
597
624
|
}
|
|
598
625
|
|
|
599
|
-
if
|
|
626
|
+
if (
|
|
627
|
+
review_for_current_step
|
|
628
|
+
and review.get("decision") == "changes-requested"
|
|
629
|
+
and not (audit and audit_is_ready_for_review(audit, next_step))
|
|
630
|
+
):
|
|
600
631
|
return {
|
|
601
632
|
"success": True,
|
|
602
633
|
"flow": "issue",
|
|
603
634
|
"slug": slug,
|
|
604
635
|
"artifact_class": artifact_class,
|
|
605
|
-
"directory":
|
|
636
|
+
"directory": display_path(directory),
|
|
606
637
|
"review": review,
|
|
607
638
|
"current_step": current_step,
|
|
608
|
-
"audit_path":
|
|
639
|
+
"audit_path": display_path(audit_path),
|
|
609
640
|
"recommended_command": "cgc-fix",
|
|
610
641
|
"reason": "当前问题修复步骤在审核后仍需继续补充修改。",
|
|
611
642
|
"next": "完成要求的后续修复后,重新执行当前问题修复步骤。",
|
|
@@ -618,10 +649,10 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
618
649
|
"flow": "issue",
|
|
619
650
|
"slug": slug,
|
|
620
651
|
"artifact_class": artifact_class,
|
|
621
|
-
"directory":
|
|
652
|
+
"directory": display_path(directory),
|
|
622
653
|
"review": review,
|
|
623
654
|
"current_step": current_step,
|
|
624
|
-
"audit_path":
|
|
655
|
+
"audit_path": display_path(audit_path),
|
|
625
656
|
"recommended_command": "cgc-review",
|
|
626
657
|
"reason": "当前问题修复步骤已有执行证据,但还没有对应的审核结论。",
|
|
627
658
|
"next": f"审核最新审计产物 {audit_path},并回写修复结论。",
|
|
@@ -631,10 +662,10 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
631
662
|
"flow": "issue",
|
|
632
663
|
"slug": slug,
|
|
633
664
|
"artifact_class": artifact_class,
|
|
634
|
-
"directory":
|
|
665
|
+
"directory": display_path(directory),
|
|
635
666
|
"review": review,
|
|
636
667
|
"current_step": current_step,
|
|
637
|
-
"audit_path":
|
|
668
|
+
"audit_path": display_path(audit_path),
|
|
638
669
|
"recommended_command": "cgc-fix",
|
|
639
670
|
"reason": "当前问题修复步骤还没有“通过”审核结论。",
|
|
640
671
|
"next": "执行或继续推进当前待执行的问题修复步骤。",
|
|
@@ -645,7 +676,7 @@ def route_issue(slug: str) -> dict[str, Any]:
|
|
|
645
676
|
"flow": "issue",
|
|
646
677
|
"slug": slug,
|
|
647
678
|
"artifact_class": artifact_class,
|
|
648
|
-
"directory":
|
|
679
|
+
"directory": display_path(directory),
|
|
649
680
|
"review": review,
|
|
650
681
|
"current_step": current_step,
|
|
651
682
|
"audit_path": "",
|
|
@@ -7,6 +7,9 @@ from codecgc_console_io import configure_utf8_stdio
|
|
|
7
7
|
from codecgc_console_io import print_json
|
|
8
8
|
from codecgc_flow_control import build_execution_result
|
|
9
9
|
from codecgc_flow_control import build_not_ready_result
|
|
10
|
+
from codecgc_policy import load_policy
|
|
11
|
+
from codecgc_policy import validate_executor_target
|
|
12
|
+
from codecgc_routing_paths import resolve_active_routing_file
|
|
10
13
|
from codecgc_session_recovery import resolve_session_id_from_task
|
|
11
14
|
from codecgc_step_control import get_step_metadata
|
|
12
15
|
from codecgc_step_control import select_next_executable_step
|
|
@@ -62,6 +65,31 @@ def main() -> int:
|
|
|
62
65
|
print_json(result)
|
|
63
66
|
return 1
|
|
64
67
|
|
|
68
|
+
try:
|
|
69
|
+
policy_result = validate_executor_target(
|
|
70
|
+
str(selected.get("kind", "")),
|
|
71
|
+
[str(path) for path in selected.get("target_paths", [])],
|
|
72
|
+
load_policy(resolve_active_routing_file()),
|
|
73
|
+
)
|
|
74
|
+
if not policy_result.get("allowed"):
|
|
75
|
+
result = {
|
|
76
|
+
"success": False,
|
|
77
|
+
"flow": "feature",
|
|
78
|
+
"slug": args.slug,
|
|
79
|
+
"state": "not-ready",
|
|
80
|
+
"failure_type": "policy",
|
|
81
|
+
"route": route,
|
|
82
|
+
"selected_step": selected,
|
|
83
|
+
"policy": policy_result,
|
|
84
|
+
"recommended_command": to_public_command("cgc-plan"),
|
|
85
|
+
"next": "Adjust target_paths or split the task before build execution.",
|
|
86
|
+
}
|
|
87
|
+
print_json(result)
|
|
88
|
+
return 1
|
|
89
|
+
except Exception as error:
|
|
90
|
+
print_json({"success": False, "error": str(error), "failure_type": "policy"}, file=sys.stderr)
|
|
91
|
+
return 1
|
|
92
|
+
|
|
65
93
|
effective_session_id = args.session_id.strip()
|
|
66
94
|
if not effective_session_id:
|
|
67
95
|
effective_session_id = resolve_session_id_from_task(
|
|
@@ -7,6 +7,9 @@ from codecgc_console_io import configure_utf8_stdio
|
|
|
7
7
|
from codecgc_console_io import print_json
|
|
8
8
|
from codecgc_flow_control import build_execution_result
|
|
9
9
|
from codecgc_flow_control import build_not_ready_result
|
|
10
|
+
from codecgc_policy import load_policy
|
|
11
|
+
from codecgc_policy import validate_executor_target
|
|
12
|
+
from codecgc_routing_paths import resolve_active_routing_file
|
|
10
13
|
from codecgc_session_recovery import resolve_session_id_from_task
|
|
11
14
|
from codecgc_step_control import get_step_metadata
|
|
12
15
|
from codecgc_step_control import select_next_executable_step
|
|
@@ -62,6 +65,31 @@ def main() -> int:
|
|
|
62
65
|
print_json(result)
|
|
63
66
|
return 1
|
|
64
67
|
|
|
68
|
+
try:
|
|
69
|
+
policy_result = validate_executor_target(
|
|
70
|
+
str(selected.get("kind", "")),
|
|
71
|
+
[str(path) for path in selected.get("target_paths", [])],
|
|
72
|
+
load_policy(resolve_active_routing_file()),
|
|
73
|
+
)
|
|
74
|
+
if not policy_result.get("allowed"):
|
|
75
|
+
result = {
|
|
76
|
+
"success": False,
|
|
77
|
+
"flow": "issue",
|
|
78
|
+
"slug": args.slug,
|
|
79
|
+
"state": "not-ready",
|
|
80
|
+
"failure_type": "policy",
|
|
81
|
+
"route": route,
|
|
82
|
+
"selected_step": selected,
|
|
83
|
+
"policy": policy_result,
|
|
84
|
+
"recommended_command": to_public_command("cgc-plan"),
|
|
85
|
+
"next": "Adjust target_paths or split the task before fix execution.",
|
|
86
|
+
}
|
|
87
|
+
print_json(result)
|
|
88
|
+
return 1
|
|
89
|
+
except Exception as error:
|
|
90
|
+
print_json({"success": False, "error": str(error), "failure_type": "policy"}, file=sys.stderr)
|
|
91
|
+
return 1
|
|
92
|
+
|
|
65
93
|
effective_session_id = args.session_id.strip()
|
|
66
94
|
if not effective_session_id:
|
|
67
95
|
effective_session_id = resolve_session_id_from_task(
|
|
@@ -14,6 +14,8 @@ from codecgc_executor_registry import build_executor_env
|
|
|
14
14
|
from codecgc_executor_registry import get_executor_config
|
|
15
15
|
from codecgc_file_evidence import snapshot_workspace
|
|
16
16
|
from codecgc_file_evidence import verify_workspace_changes
|
|
17
|
+
from codecgc_path_contract import normalize_audit_path_fields
|
|
18
|
+
from codecgc_path_contract import normalize_persisted_project_path
|
|
17
19
|
from codecgc_runtime_paths import PACKAGE_ROOT
|
|
18
20
|
from codecgc_runtime_paths import PROJECT_ROOT
|
|
19
21
|
from mcp import ClientSession
|
|
@@ -215,7 +217,7 @@ def build_audit_record(
|
|
|
215
217
|
if not isinstance(reported_changed_files, list):
|
|
216
218
|
reported_changed_files = []
|
|
217
219
|
|
|
218
|
-
|
|
220
|
+
record = {
|
|
219
221
|
"product": "CodeCGC",
|
|
220
222
|
"version": 1,
|
|
221
223
|
"mode": mode,
|
|
@@ -262,6 +264,7 @@ def build_audit_record(
|
|
|
262
264
|
},
|
|
263
265
|
},
|
|
264
266
|
}
|
|
267
|
+
return normalize_audit_path_fields(record, PROJECT_WORKSPACE)
|
|
265
268
|
|
|
266
269
|
|
|
267
270
|
def write_audit_file(audit_root: Path, audit_record: dict[str, Any]) -> Path:
|
|
@@ -379,7 +382,7 @@ async def run_task(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
379
382
|
"result": task_result,
|
|
380
383
|
"audit": {
|
|
381
384
|
"written": not args.skip_audit_write,
|
|
382
|
-
"path":
|
|
385
|
+
"path": normalize_persisted_project_path(audit_path) if audit_path else "",
|
|
383
386
|
},
|
|
384
387
|
}
|
|
385
388
|
return sanitize_for_json(output)
|
|
@@ -7,6 +7,9 @@ from codecgc_console_io import configure_utf8_stdio
|
|
|
7
7
|
from codecgc_console_io import print_json
|
|
8
8
|
from codecgc_flow_control import build_execution_result
|
|
9
9
|
from codecgc_flow_control import build_not_ready_result
|
|
10
|
+
from codecgc_policy import load_policy
|
|
11
|
+
from codecgc_policy import validate_executor_target
|
|
12
|
+
from codecgc_routing_paths import resolve_active_routing_file
|
|
10
13
|
from codecgc_session_recovery import resolve_session_id_from_task
|
|
11
14
|
from codecgc_step_control import get_step_metadata
|
|
12
15
|
from codecgc_step_control import select_next_executable_step
|
|
@@ -63,6 +66,31 @@ def main() -> int:
|
|
|
63
66
|
print_json(result)
|
|
64
67
|
return 1
|
|
65
68
|
|
|
69
|
+
try:
|
|
70
|
+
policy_result = validate_executor_target(
|
|
71
|
+
str(selected.get("kind", "")),
|
|
72
|
+
[str(path) for path in selected.get("target_paths", [])],
|
|
73
|
+
load_policy(resolve_active_routing_file()),
|
|
74
|
+
)
|
|
75
|
+
if not policy_result.get("allowed"):
|
|
76
|
+
result = {
|
|
77
|
+
"success": False,
|
|
78
|
+
"flow": args.flow,
|
|
79
|
+
"slug": args.slug,
|
|
80
|
+
"state": "not-ready",
|
|
81
|
+
"failure_type": "policy",
|
|
82
|
+
"route": route,
|
|
83
|
+
"selected_step": selected,
|
|
84
|
+
"policy": policy_result,
|
|
85
|
+
"recommended_command": to_public_command("cgc-plan"),
|
|
86
|
+
"next": "Adjust target_paths or split the task before test execution.",
|
|
87
|
+
}
|
|
88
|
+
print_json(result)
|
|
89
|
+
return 1
|
|
90
|
+
except Exception as error:
|
|
91
|
+
print_json({"success": False, "error": str(error), "failure_type": "policy"}, file=sys.stderr)
|
|
92
|
+
return 1
|
|
93
|
+
|
|
66
94
|
effective_session_id = args.session_id.strip()
|
|
67
95
|
if not effective_session_id:
|
|
68
96
|
effective_session_id = resolve_session_id_from_task(
|