71 lines
2.7 KiB
Python
71 lines
2.7 KiB
Python
"""Deterministic builder for the single Pi-facing Thoth session skill."""
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
|
|
HARNESS_ROOT = Path(__file__).resolve().parents[1]
|
|
SKILL_ROOT = HARNESS_ROOT / ".pi" / "skills" / "tht-sessione"
|
|
MODULE_ROOT = SKILL_ROOT / "modules"
|
|
TEMPLATE_PATH = SKILL_ROOT / "projection.md.tmpl"
|
|
PROJECTION_PATH = SKILL_ROOT / "SKILL.md"
|
|
|
|
# This tuple is the composition contract. Never derive it from directory order.
|
|
FRAGMENT_ORDER = (
|
|
("{{DISAMBIGUATION_OPEN_AMBIGUITY}}", "disambiguation/open-ambiguity.md"),
|
|
("{{DISAMBIGUATION_INSTRUCTIONS}}", "disambiguation/phase-1.md"),
|
|
("{{MEMORY_INSTRUCTIONS}}", "memory/phase-2.md"),
|
|
("{{DISAMBIGUATION_REWRITING_INSTRUCTIONS}}", "disambiguation/phase-3.md"),
|
|
("{{MEMORY_SOLVED_SEARCH_F4}}", "memory/solved-search-f4.md"),
|
|
("{{DISAMBIGUATION_SCHEMA_GROUNDING}}", "disambiguation/schema-grounding.md"),
|
|
("{{MEMORY_SOLVED_SEARCH_F6}}", "memory/solved-search-f6.md"),
|
|
("{{MEMORY_SOLVED_SEARCH_F7}}", "memory/solved-search-f7.md"),
|
|
("{{MEMORY_PROMOTION_F8}}", "memory/phase-8-promotion.md"),
|
|
("{{MEMORY_SOLVED_FINALIZATION}}", "memory/solved-finalization.md"),
|
|
)
|
|
|
|
|
|
def render_projection(*, template: bytes | None = None) -> bytes:
|
|
projection = TEMPLATE_PATH.read_bytes() if template is None else template
|
|
for marker_text, filename in FRAGMENT_ORDER:
|
|
marker = marker_text.encode()
|
|
if projection.count(marker) != 1:
|
|
raise ValueError(f"projection placeholder {marker_text} must occur exactly once")
|
|
fragment = (MODULE_ROOT / filename).read_bytes().rstrip(b"\n")
|
|
projection = projection.replace(marker, fragment)
|
|
return projection
|
|
|
|
|
|
def projection_is_current(path: Path = PROJECTION_PATH) -> bool:
|
|
return path.exists() and path.read_bytes() == render_projection()
|
|
|
|
|
|
def write_projection(path: Path = PROJECTION_PATH) -> None:
|
|
path.write_bytes(render_projection())
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
action = parser.add_mutually_exclusive_group(required=True)
|
|
action.add_argument("--check", action="store_true", help="fail if SKILL.md is stale")
|
|
action.add_argument("--write", action="store_true", help="regenerate SKILL.md")
|
|
args = parser.parse_args(argv)
|
|
|
|
if args.write:
|
|
write_projection()
|
|
print(f"generated {PROJECTION_PATH}")
|
|
return 0
|
|
if projection_is_current():
|
|
print(f"up to date: {PROJECTION_PATH}")
|
|
return 0
|
|
print(
|
|
f"stale projection: run `python -m tht.pi_skill_projection --write` from {HARNESS_ROOT}",
|
|
file=sys.stderr,
|
|
)
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|