Build once, optionally recon, then dispatch N find+grade cycles.
(
target: TargetConfig,
args,
agent_env: dict[str, str],
results_root: Path,
)
| 648 | |
| 649 | |
| 650 | async def _run_all( |
| 651 | target: TargetConfig, |
| 652 | args, |
| 653 | agent_env: dict[str, str], |
| 654 | results_root: Path, |
| 655 | ) -> list[tuple[Path, RunResult]]: |
| 656 | """Build once, optionally recon, then dispatch N find+grade cycles.""" |
| 657 | system_prompt = build_system_prompt(args.engagement_context) |
| 658 | |
| 659 | # ── Build (once, shared by all runs) ────────────────────────────────────────── |
| 660 | print(color(f"[build] Building {target.image_tag} from {target.dockerfile_dir} ...", "dim")) |
| 661 | t0 = time.time() |
| 662 | try: |
| 663 | docker_ops.build(target.dockerfile_dir, target.image_tag) |
| 664 | except Exception as e: |
| 665 | results_root.mkdir(parents=True, exist_ok=True) |
| 666 | err = RunResult( |
| 667 | target=target.name, status="build_failed", |
| 668 | crash=None, verdict=None, |
| 669 | error=f"{type(e).__name__}: {e}", |
| 670 | ) |
| 671 | return [(results_root, err)] |
| 672 | print(f"[build] done in {time.time() - t0:.1f}s") |
| 673 | |
| 674 | # ── Focus areas (optional auto-discover via recon) ─────────────────────────── |
| 675 | # focus_areas.json is the checkpoint of record: written on every fresh run, |
| 676 | # read on every resume regardless of --auto-focus, so a resumed run_NNN gets |
| 677 | # the same i % len() assignment as the original. |
| 678 | results_root.mkdir(parents=True, exist_ok=True) |
| 679 | focus_areas = list(target.focus_areas) |
| 680 | focus_ckpt = results_root / "focus_areas.json" |
| 681 | if args.resume and focus_ckpt.exists(): |
| 682 | try: |
| 683 | focus_areas = json.loads(focus_ckpt.read_text()) |
| 684 | print(f"[resume] {len(focus_areas)} focus area(s) from {focus_ckpt}\n") |
| 685 | except (OSError, json.JSONDecodeError): |
| 686 | print(f"[resume] {focus_ckpt} unreadable; falling back to config.yaml list\n") |
| 687 | focus_ckpt.unlink(missing_ok=True) |
| 688 | elif args.auto_focus: |
| 689 | print(color("[recon] Auto-discovering focus areas ...", "recon")) |
| 690 | discovered, _ = await run_recon( |
| 691 | target, model=args.model, agent_env=agent_env, |
| 692 | max_turns=args.recon_max_turns, |
| 693 | transcript_path=str(results_root / "recon_transcript.jsonl"), |
| 694 | system_prompt=system_prompt, |
| 695 | ) |
| 696 | if discovered: |
| 697 | focus_areas = discovered |
| 698 | print(color(f"[recon] Discovered {len(discovered)} focus area(s):", "bold")) |
| 699 | for a in discovered: |
| 700 | print(color(f" - {a}", "bold")) |
| 701 | else: |
| 702 | print("[recon] No focus areas discovered; using config.yaml list") |
| 703 | print() |
| 704 | if not focus_ckpt.exists(): |
| 705 | focus_ckpt.write_text(json.dumps(focus_areas, indent=2)) |
| 706 | |
| 707 | # ── Dispatch ───────────────────────────────────────────────────────────────────────────── |
no test coverage detected