Files
codestable__codestable/.codestable/tools/codestable-dod-runner.py
Wyatt Fang 30fecaae5e release(codestable): ship skill workflow v1.0.2 (#41)
收敛 CodeStable 主入口、runtime preflight、goal driver 与 skill 工程化评测闭环。

- 根 cs 对行动请求同轮直转,咨询与介绍保持非执行
- feature/issue/refactor/epic/docs 按仓库事实恢复,旧 stage skill 保留兼容薄壳
- repo-local runtime 支持版本检测、安全自动同步和显式 refresh-runtime
- 完成 Codex/Claude marketplace 1.0.2、升级文档和回归/评测证据

验证:215 tests passed;package/runtime/diff checks passed;独立 review 与 QA 无 unresolved blocking/important findings。
2026-07-10 15:23:56 +08:00

88 lines
3.4 KiB
Python

#!/usr/bin/env python3
"""Run checklist dod.commands and report real exit codes."""
from __future__ import annotations
import os
import sys
from pathlib import Path
from typing import Any
if os.environ.get("PYTHONDONTWRITEBYTECODE") != "1":
os.environ["PYTHONDONTWRITEBYTECODE"] = "1"
os.execvpe(sys.executable, [sys.executable, *sys.argv], os.environ)
sys.dont_write_bytecode = True
from codestable_gate_common import gate_result, load_yaml, main_exit, parse_args, repo_root, run_command
def clear_previous_json_out(json_out: str | None) -> None:
if not json_out:
return
path = Path(json_out)
if (path.exists() or path.is_symlink()) and not (path.is_dir() and not path.is_symlink()):
path.unlink()
def collect_commands(checklist: dict[str, Any]) -> list[dict[str, Any]]:
# Authoritative schema: top-level `dod.commands` (cs-feat-design reference §"DoD
# Contract" — `dod` is a top-level checklist key alongside `steps`/`checks`).
# If present, it is the single source — do NOT also pull step-level commands,
# or a checklist carrying both would execute each command twice.
top_commands = (checklist.get("dod") or {}).get("commands") or []
if top_commands:
return list(top_commands)
# Backward-compat: no top-level dod → fall back to step-level `dod.commands`.
commands: list[dict[str, Any]] = []
for step in checklist.get("steps", []) or []:
dod = step.get("dod") or {}
for command in dod.get("commands", []) or []:
commands.append(command)
return commands
def main() -> None:
parser = parse_args("Run explicit checklist dod.commands using real subprocess exit codes.")
parser.add_argument("--checklist", required=True, help="Path to checklist YAML")
parser.add_argument("--only", action="append", default=[], help="Run only this command id; repeatable")
parser.add_argument("--stage", default="implementation.before_review")
args = parser.parse_args()
clear_previous_json_out(args.json_out)
checklist_path = Path(args.checklist)
if not checklist_path.exists():
result = gate_result("dod-runner", args.stage, "blocked", [f"checklist not found: {checklist_path}"])
main_exit(result, args.json_out)
checklist = load_yaml(checklist_path)
commands = collect_commands(checklist)
if args.only:
requested = set(args.only)
commands = [command for command in commands if command.get("id") in requested]
if not commands:
result = gate_result("dod-runner", args.stage, "skipped", warnings=["no matching dod.commands found"])
main_exit(result, args.json_out)
root = repo_root()
evidence = []
blocking = []
warnings = []
for command in commands:
run = run_command(str(command.get("command", "")), root)
run["id"] = command.get("id")
run["core"] = bool(command.get("core"))
run["failure_handling"] = command.get("failure_handling")
evidence.append(run)
if run["exit_code"] != 0 and run["core"]:
blocking.append(f"{command.get('id')}: command failed with exit {run['exit_code']}")
elif run["exit_code"] != 0:
warnings.append(f"{command.get('id')}: non-core command failed with exit {run['exit_code']}")
status = "failed" if blocking else "passed"
result = gate_result("dod-runner", args.stage, status, blocking, warnings, evidence)
main_exit(result, args.json_out)
if __name__ == "__main__":
main()