bot-forge 1.0.2

Rust CLI for installing agent skills and developer tools from configurable forms.
Documentation
#!/usr/bin/env python3
import pathlib
import re
import tomllib

root = pathlib.Path(__file__).resolve().parent.parent
config = tomllib.loads((root / "catalogs/rust-dev.toml").read_text())
readme = (root / "README.md").read_text()
groups = dict(config.get("groups", {}))
for name, tools in config.get("cargo-toolsets", {}).items():
    groups[name] = sorted(tools)

def expand_entry(item):
    return groups[item.removeprefix("group:")] if item.startswith("group:") else [item]


def expand_profile(name, visiting=None):
    visiting = set() if visiting is None else visiting
    if name in visiting:
        raise SystemExit(f"profile inheritance cycle: {name}")
    visiting.add(name)
    result = []
    definition = config["profiles"][name]
    for parent in definition.get("inherits", []):
        for item in expand_profile(parent, visiting):
            if item not in result:
                result.append(item)
    for entry in definition.get("components", []):
        for item in expand_entry(entry):
            if item not in result:
                result.append(item)
    visiting.remove(name)
    return result


effective_profiles = {}
for profile in config["profiles"]:
    match = re.search(
        rf"<!-- default-profile:{profile} -->\n(.*?)\n<!-- /default-profile:{profile} -->",
        readme,
        re.DOTALL,
    )
    if not match:
        raise SystemExit(f"README missing generated profile block: {profile}")
    components = []
    for item in config["profiles"][profile].get("components", []):
        components.extend(expand_entry(item))
    expected = ", ".join(f"`{item}`" for item in components) if components else "(默认不追加工具)"
    if match.group(1).strip() != expected:
        raise SystemExit(f"README profile {profile} differs from rust-dev catalog")
    effective_profiles[profile] = expand_profile(profile)

expected_chain = ["minimal", "standard", "advanced"]
if list(config["profiles"]) != expected_chain:
    raise SystemExit(f"default profile order differs: {list(config['profiles'])}")
for parent, child in zip(expected_chain, expected_chain[1:]):
    if not set(effective_profiles[parent]) < set(effective_profiles[child]):
        raise SystemExit(f"profile {child} must strictly extend {parent}")

apt = tomllib.loads((root / "bot-forge.toml").read_text()).get("apt_mirror", {})
apt_state = "enabled" if apt.get("uri") or apt.get("rules") else "disabled"
if f"<!-- default-apt:{apt_state} -->" not in readme:
    raise SystemExit(f"README default APT state differs from bot-forge.toml ({apt_state})")

print("README profile and APT facts match the default configuration.")