66 lines
1.8 KiB
Python
66 lines
1.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Parse run-scoped BOOTSTRAP.md into structured configuration."""
|
|
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
from typing import Any, Dict
|
|
import re
|
|
|
|
import yaml
|
|
|
|
|
|
BOOTSTRAP_FRONT_MATTER_RE = re.compile(
|
|
r"^---\s*\n(.*?)\n---\s*\n?(.*)$",
|
|
re.DOTALL,
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class BootstrapConfig:
|
|
"""Structured configuration extracted from BOOTSTRAP.md."""
|
|
|
|
values: Dict[str, Any] = field(default_factory=dict)
|
|
prompt_body: str = ""
|
|
|
|
def get(self, key: str, default: Any = None) -> Any:
|
|
return self.values.get(key, default)
|
|
|
|
def agent_override(self, agent_id: str) -> Dict[str, Any]:
|
|
overrides = self.values.get("agent_overrides", {})
|
|
if not isinstance(overrides, dict):
|
|
return {}
|
|
override = overrides.get(agent_id, {})
|
|
return override if isinstance(override, dict) else {}
|
|
|
|
|
|
def load_bootstrap_config(bootstrap_path: Path) -> BootstrapConfig:
|
|
"""Load structured bootstrap config and free-form prompt body."""
|
|
if not bootstrap_path.exists():
|
|
return BootstrapConfig()
|
|
|
|
raw = bootstrap_path.read_text(encoding="utf-8").strip()
|
|
if not raw:
|
|
return BootstrapConfig()
|
|
|
|
match = BOOTSTRAP_FRONT_MATTER_RE.match(raw)
|
|
if not match:
|
|
return BootstrapConfig(prompt_body=raw)
|
|
|
|
front_matter = match.group(1).strip()
|
|
body = match.group(2).strip()
|
|
parsed = yaml.safe_load(front_matter) or {}
|
|
if not isinstance(parsed, dict):
|
|
parsed = {}
|
|
|
|
return BootstrapConfig(values=parsed, prompt_body=body)
|
|
|
|
|
|
def get_bootstrap_config_for_run(
|
|
project_root: Path,
|
|
config_name: str,
|
|
) -> BootstrapConfig:
|
|
"""Load BOOTSTRAP.md from the run workspace."""
|
|
return load_bootstrap_config(
|
|
project_root / "runs" / config_name / "BOOTSTRAP.md",
|
|
)
|