#!/usr/bin/env python3 """Provide FESA handoff context at Codex session startup/resume.""" from __future__ import annotations import json import sys from pathlib import Path MAX_SECTION_CHARS = 700 def find_repo_root(start: Path) -> Path: for candidate in (start, *start.parents): if (candidate / "AGENTS.md").exists() and (candidate / "PLAN.md").exists(): return candidate return start def read_text(path: Path) -> str: try: return path.read_text(encoding="utf-8") except OSError: return "" def section(markdown: str, heading: str) -> str: marker = f"## {heading}" start = markdown.find(marker) if start < 0: return "" start = markdown.find("\n", start) if start < 0: return "" end = markdown.find("\n## ", start + 1) body = markdown[start:end if end >= 0 else len(markdown)].strip() body = " ".join(line.strip() for line in body.splitlines() if line.strip()) if len(body) > MAX_SECTION_CHARS: body = body[:MAX_SECTION_CHARS].rstrip() + "..." return body def main() -> int: try: payload = json.load(sys.stdin) except json.JSONDecodeError: payload = {} root = find_repo_root(Path(payload.get("cwd") or ".").resolve()) plan = read_text(root / "PLAN.md") progress = read_text(root / "PROGRESS.md") context_lines = [ "FESA session startup context:", "- Before planning or editing, read AGENTS.md, PROGRESS.md, PLAN.md, and docs/README.md.", "- Keep completed work in PROGRESS.md and future tasks/open decisions in PLAN.md.", ] current_objective = section(plan, "Current Objective") if current_objective: context_lines.append(f"- Current objective: {current_objective}") current_status = section(progress, "Current Status") if current_status: context_lines.append(f"- Current status: {current_status}") blockers = section(progress, "Known Blockers") or section(plan, "Open Questions") if blockers: context_lines.append(f"- Blockers/open questions: {blockers}") json.dump( { "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": "\n".join(context_lines), } }, sys.stdout, ) return 0 if __name__ == "__main__": raise SystemExit(main())