- Fix dependency_update.yml syntax error (uses: after run:) - Restrict scope_guard.py allowlist: ai:impl no longer allows all tools/, ai:qa no longer allows tools/gates/, ai:docs no longer allows specs/ - Fix signing key exposure in release_signing.yml and supply_chain.yml by using env://COSIGN_KEY instead of inline secret interpolation - Fix specify_init.py hyphen normalization bug (multiple consecutive hyphens) - Add explicit permissions blocks to 15 workflows for least-privilege - Add file existence checks and encoding error handling to compose_codex_prompt.py - Fix schops.py: backup_file() error handling, delimiter-aware lib_id matching Co-Authored-By: Claude Opus 4.6 <[email protected]>
52 lines
1.4 KiB
Python
52 lines
1.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Create a spec folder using .specify templates.
|
|
|
|
This is a tiny bridge so you can keep a Spec-Kit-ish layout while staying
|
|
compatible with the repo's `specs/<name>/` convention.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
def sanitize(name: str) -> str:
|
|
name = name.strip().lower()
|
|
# Keep only alphanumeric, hyphens, underscores; replace spaces with hyphens
|
|
name = re.sub(r"[^\w\s-]", "", name)
|
|
name = re.sub(r"[\s-]+", "-", name).strip("-")
|
|
return name or "spec"
|
|
|
|
|
|
def main() -> int:
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--name", required=True, help="feature/epic name")
|
|
args = ap.parse_args()
|
|
|
|
repo = Path(__file__).resolve().parents[2]
|
|
templates = repo / ".specify" / "templates"
|
|
if not templates.exists():
|
|
raise SystemExit("missing .specify/templates")
|
|
|
|
spec_name = sanitize(args.name)
|
|
dst = repo / "specs" / spec_name
|
|
dst.mkdir(parents=True, exist_ok=True)
|
|
|
|
for fname in ("00_prd.md", "01_tech_plan.md", "02_tasks.md"):
|
|
src = templates / fname
|
|
if not src.exists():
|
|
continue
|
|
text = src.read_text(encoding="utf-8").replace("<FEATURE>", spec_name)
|
|
out = dst / fname
|
|
if not out.exists():
|
|
out.write_text(text, encoding="utf-8")
|
|
|
|
print(dst)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|