#!/usr/bin/env python3 """Prepare the canonical bounded task context for a Blender/WBV2 task.""" from __future__ import annotations import argparse import json import shutil import subprocess from pathlib import Path from wbv2_runtime import CONTROL_ROOT, ROOT, queue_pointer def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("task_id", nargs="?", help="task id; defaults to the authoritative queue pointer") parser.add_argument("--output", type=Path, help="optional copy of the generated task-context.json") args = parser.parse_args() task = args.task_id or queue_pointer().get("task") if not task: parser.error("queue has no current WBV2 task") task_context = CONTROL_ROOT.parent / str(task) / "task-context.json" manifest_path = CONTROL_ROOT.parent / str(task) / "manifest.json" try: manifest = json.loads(manifest_path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError): manifest = {} # Completed manifests bind their task-context hash. Do not regenerate that # file on a status-only resume; a fresh context would be evidence drift. write_context = not (manifest.get("status") == "done" and task_context.is_file()) command = ["node", "tools/web/check-task-context.mjs", "--task", str(task)] if write_context: command.append("--write") result = subprocess.run(command, cwd=ROOT, text=True, capture_output=True, check=False) output = result.stdout or result.stderr if output: print(output, end="" if output.endswith("\n") else "\n") if result.returncode != 0: return result.returncode generated = task_context if args.output: args.output.parent.mkdir(parents=True, exist_ok=True) shutil.copyfile(generated, args.output) print(f"context-copy={args.output}") payload = json.loads(generated.read_text(encoding="utf-8")) totals = payload.get("size", {}) print(f"WBV2 CONTEXT READY: task={task} bytes={totals.get('totalBytes', totals.get('total_bytes', '-'))} output={generated.relative_to(ROOT)}") return 0 if __name__ == "__main__": raise SystemExit(main())