66 lines
2.1 KiB
Python
Executable File
66 lines
2.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
def load_readiness(path: Path) -> dict:
|
|
return json.loads(path.read_text(encoding="utf-8"))
|
|
|
|
|
|
def harden_markdown(original: str, readiness: dict) -> str:
|
|
template = (readiness.get("recommended_template") or "").strip()
|
|
if not template:
|
|
return original
|
|
|
|
missing = readiness.get("missing_actions") or []
|
|
missing_lines = "\n".join([f"- [{m.get('type','?')}] `{m.get('key','?')}`: {m.get('action','')}" for m in missing])
|
|
|
|
addendum = (
|
|
"\n\n---\n\n"
|
|
"## Planning Hardening Addendum\n\n"
|
|
"This section is auto-generated to make the spec execution-ready for Whetstone.\n\n"
|
|
"### Detected Gaps\n"
|
|
f"{missing_lines if missing_lines else '- none'}\n\n"
|
|
"### Recommended Scaffold\n\n"
|
|
f"{template}\n"
|
|
)
|
|
|
|
if "## Planning Hardening Addendum" in original:
|
|
return original
|
|
return original.rstrip() + addendum
|
|
|
|
|
|
def main() -> None:
|
|
ap = argparse.ArgumentParser(description="Generate hardened markdown spec scaffold from planning readiness output.")
|
|
ap.add_argument("--spec", required=True, help="Input markdown spec path")
|
|
ap.add_argument("--readiness", required=True, help="Readiness JSON path from spec_planning_readiness.py")
|
|
ap.add_argument("--out", required=True, help="Output hardened markdown path")
|
|
args = ap.parse_args()
|
|
|
|
spec_path = Path(args.spec)
|
|
readiness_path = Path(args.readiness)
|
|
out_path = Path(args.out)
|
|
|
|
original = spec_path.read_text(encoding="utf-8")
|
|
readiness = load_readiness(readiness_path)
|
|
hardened = harden_markdown(original, readiness)
|
|
|
|
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
out_path.write_text(hardened, encoding="utf-8")
|
|
|
|
report = {
|
|
"input_spec": str(spec_path),
|
|
"readiness_json": str(readiness_path),
|
|
"output_spec": str(out_path),
|
|
"missing_count": len(readiness.get("missing_actions") or []),
|
|
"added_addendum": hardened != original,
|
|
}
|
|
print(json.dumps(report, indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|