#!/usr/bin/env python3 import argparse import json from datetime import date from pathlib import Path from typing import Any try: import yaml except ImportError: # pragma: no cover yaml = None from skill_ir_paths import find_skill_ir as find_skill_ir_document from compile_skill_targets import TARGET_TRANSFORMS, target_native_contract, target_permission_contract ROOT = Path(__file__).resolve().parent.parent COMPILER_SCHEMA_VERSION = "1.0" COMPILER_NAME = "yao-skill-ir-compiler" def display_path(path: Path, root: Path = ROOT) -> str: try: return str(path.resolve().relative_to(root.resolve())) except ValueError: return str(path.resolve()) def load_json(path: Path) -> dict[str, Any]: if not path.exists(): return {} try: payload = json.loads(path.read_text(encoding="utf-8")) except json.JSONDecodeError: return {} return payload if isinstance(payload, dict) else {} def load_yaml(path: Path) -> dict[str, Any]: if not path.exists() or yaml is None: return {} payload = yaml.safe_load(path.read_text(encoding="utf-8")) or {} return payload if isinstance(payload, dict) else {} def read_frontmatter(path: Path) -> dict[str, Any]: if not path.exists(): return {} text = path.read_text(encoding="utf-8", errors="replace") if not text.startswith("---"): return {} parts = text.split("---", 2) if len(parts) < 3: return {} if yaml is not None: payload = yaml.safe_load(parts[1]) or {} return payload if isinstance(payload, dict) else {} data: dict[str, Any] = {} for line in parts[1].splitlines(): if ":" not in line: continue key, value = line.split(":", 1) data[key.strip()] = value.strip().strip('"') return data def find_skill_ir(skill_dir: Path, name: str) -> tuple[dict[str, Any], str]: return find_skill_ir_document(skill_dir, name, fallback_source="frontmatter-fallback") def count_list(payload: dict[str, Any], key: str) -> int: value = payload.get(key, []) return len(value) if isinstance(value, list) else 0 def list_or_empty(payload: dict[str, Any], key: str) -> list[str]: value = payload.get(key, []) return [str(item) for item in value] if isinstance(value, list) else [] def resource_counts(resources: dict[str, Any]) -> dict[str, int]: return {key: count_list(resources, key) for key in ("references", "scripts", "assets", "reports")} def eval_counts(eval_plan: dict[str, Any]) -> dict[str, int]: return { "trigger": count_list(eval_plan, "trigger"), "output": count_list(eval_plan, "output"), "adversarial": count_list(eval_plan, "adversarial"), "baseline": 1 if eval_plan.get("baseline") else 0, } def scripts_with_flag(scripts: list[dict[str, Any]], flag: str) -> list[str]: return [str(item.get("path")) for item in scripts if item.get(flag)] def capability(name: str, scripts: list[str], review_reason: str) -> dict[str, Any]: return { "required": bool(scripts), "script_count": len(scripts), "scripts": scripts, "review_reason": review_reason if scripts else "", } def permission_contract(skill_dir: Path) -> dict[str, Any]: trust_path = skill_dir / "reports" / "security_trust_report.json" trust = load_json(trust_path) scripts = trust.get("scripts", []) if isinstance(trust.get("scripts"), list) else [] network_scripts = scripts_with_flag(scripts, "uses_network") file_write_scripts = scripts_with_flag(scripts, "uses_file_write") subprocess_scripts = scripts_with_flag(scripts, "uses_subprocess") interactive_scripts = scripts_with_flag(scripts, "uses_input") capabilities = { "network": capability("network", network_scripts, "Outbound hosts must match security/network_policy.json."), "file_write": capability("file_write", file_write_scripts, "Scripts write local files or generated artifacts."), "subprocess": capability("subprocess", subprocess_scripts, "Scripts spawn local commands and need operator review."), "interactive": capability("interactive", interactive_scripts, "Scripts prompt for user input or credentials."), } declared = [name for name, item in capabilities.items() if item["required"]] help_smoke = trust.get("help_smoke", {}) if isinstance(trust.get("help_smoke"), dict) else {} network_policy = trust.get("network_policy", {}) if isinstance(trust.get("network_policy"), dict) else {} summary = trust.get("summary", {}) if isinstance(trust.get("summary"), dict) else {} return { "schema_version": "1.0", "source": display_path(trust_path, skill_dir) if trust else "missing-security-trust-report", "source_available": bool(trust), "declared_capabilities": declared, "review_required": bool(declared), "capabilities": capabilities, "network_policy": { "source": network_policy.get("path", "security/network_policy.json"), "covered_scripts": network_policy.get("covered_scripts", []), "missing_scripts": network_policy.get("missing_scripts", []), "mismatches": network_policy.get("mismatches", []), }, "help_smoke": { "enabled": bool(help_smoke.get("enabled")), "checked_count": int(help_smoke.get("checked_count", 0) or 0), "failed_count": int(help_smoke.get("failed_count", 0) or 0), "failed_scripts": help_smoke.get("failed_scripts", []), }, "trust_summary": { "secret_findings": int(summary.get("secret_findings", 0) or 0), "network_script_count": int(summary.get("network_script_count", len(network_scripts)) or 0), "file_write_script_count": int(summary.get("file_write_script_count", len(file_write_scripts)) or 0), "subprocess_script_count": len(subprocess_scripts), "interactive_script_count": int(summary.get("interactive_script_count", len(interactive_scripts)) or 0), "help_smoke_failed_count": int(summary.get("help_smoke_failed_count", 0) or 0), }, } def load_sources(skill_dir: Path) -> dict[str, Any]: skill_dir = skill_dir.resolve() frontmatter = read_frontmatter(skill_dir / "SKILL.md") manifest = load_json(skill_dir / "manifest.json") interface_doc = load_yaml(skill_dir / "agents" / "interface.yaml") name = str(frontmatter.get("name") or manifest.get("name") or skill_dir.name) ir, ir_source = find_skill_ir(skill_dir, name) return { "skill_dir": skill_dir, "frontmatter": frontmatter, "manifest": manifest, "interface_doc": interface_doc, "interface": interface_doc.get("interface", {}), "compatibility": interface_doc.get("compatibility", {}), "ir": ir, "ir_source": ir_source, } def declared_targets(sources: dict[str, Any]) -> list[str]: ir = sources["ir"] compatibility = sources["compatibility"] manifest = sources["manifest"] candidates = ( ir.get("targets") if isinstance(ir.get("targets"), list) else manifest.get("target_platforms") or compatibility.get("adapter_targets") or [] ) targets = [] for item in candidates: value = str(item).strip() if value and value not in targets: targets.append(value) return targets or ["generic"] def semantic_source(sources: dict[str, Any]) -> dict[str, Any]: skill_dir = sources["skill_dir"] frontmatter = sources["frontmatter"] manifest = sources["manifest"] interface = sources["interface"] compatibility = sources["compatibility"] ir = sources["ir"] trigger = ir.get("trigger_surface", {}) if isinstance(ir.get("trigger_surface"), dict) else {} workflow = ir.get("workflow", {}) if isinstance(ir.get("workflow"), dict) else {} resources = ir.get("resources", {}) if isinstance(ir.get("resources"), dict) else {} eval_plan = ir.get("eval_plan", {}) if isinstance(ir.get("eval_plan"), dict) else {} description = str(trigger.get("description") or frontmatter.get("description") or "") name = str(ir.get("name") or frontmatter.get("name") or manifest.get("name") or skill_dir.name) permissions = permission_contract(skill_dir) return { "name": name, "title": str(ir.get("title") or interface.get("display_name") or name), "version": str(manifest.get("version") or frontmatter.get("version") or "1.0.0"), "description": description, "job_to_be_done": str(ir.get("job_to_be_done") or description), "trigger": { "description": description, "should_trigger": list_or_empty(trigger, "should_trigger"), "should_not_trigger": list_or_empty(trigger, "should_not_trigger"), "edge_cases": list_or_empty(trigger, "edge_cases"), }, "workflow": { "steps": list_or_empty(workflow, "steps"), "decision_points": list_or_empty(workflow, "decision_points"), "failure_modes": list_or_empty(workflow, "failure_modes"), }, "resources": { "references": list_or_empty(resources, "references"), "scripts": list_or_empty(resources, "scripts"), "assets": list_or_empty(resources, "assets"), "reports": list_or_empty(resources, "reports"), "counts": resource_counts(resources), }, "eval_plan": { "trigger": list_or_empty(eval_plan, "trigger"), "output": list_or_empty(eval_plan, "output"), "adversarial": list_or_empty(eval_plan, "adversarial"), "baseline": str(eval_plan.get("baseline") or ""), "counts": eval_counts(eval_plan), }, "risk": ir.get("risk", {}) if isinstance(ir.get("risk"), dict) else {}, "governance": ir.get("governance", {}) if isinstance(ir.get("governance"), dict) else {}, "runtime": { "activation": compatibility.get("activation", {}) if isinstance(compatibility.get("activation"), dict) else {}, "execution": compatibility.get("execution", {}) if isinstance(compatibility.get("execution"), dict) else {}, "trust": compatibility.get("trust", {}) if isinstance(compatibility.get("trust"), dict) else {}, "adapter_targets": compatibility.get("adapter_targets", []), "canonical_format": compatibility.get("canonical_format", "agent-skills"), }, "permissions": permissions, "source_files_count": count_list(ir, "source_files") if ir else 0, } def compile_target_contract(skill_dir: Path, target: str) -> dict[str, Any]: sources = load_sources(skill_dir) compatibility = sources["compatibility"] degradation = compatibility.get("degradation", {}) if isinstance(compatibility.get("degradation"), dict) else {} declared = declared_targets(sources) failures: list[str] = [] warnings: list[str] = [] profile = TARGET_TRANSFORMS.get(target) if profile is None: failures.append(f"Unsupported compiler target: {target}") profile = { "adapter_mode": "unsupported", "generated_files": [], "metadata_mapping": {}, "preserved_semantics": [], "unsupported_features": [], } if target not in declared and not (target in {"agent-skills", "vscode"} and "agent-skills-compatible" in declared): warnings.append(f"Target is not declared in Skill IR or interface metadata: {target}") if not sources["ir"]: warnings.append("Skill IR is missing; compiler used frontmatter fallback") contract = semantic_source(sources) permissions = contract["permissions"] target_permissions = target_permission_contract(target, permissions) target_native = target_native_contract(target, profile, contract, target_permissions) contract["target"] = target contract["target_permission_contract"] = target_permissions contract["target_native_contract"] = target_native contract["degradation_strategy"] = degradation.get(target, degradation.get("generic", "neutral-source")) contract["target_runtime"] = { "adapter_mode": profile["adapter_mode"], "generated_files": profile["generated_files"], "metadata_mapping": profile["metadata_mapping"], "preserved_semantics": profile["preserved_semantics"], "native_surface": target_native["native_surface"], } return { "schema_version": COMPILER_SCHEMA_VERSION, "target": target, "status": "block" if failures else ("warn" if warnings else "pass"), "compiler": { "name": COMPILER_NAME, "schema_version": COMPILER_SCHEMA_VERSION, "source": "skill-ir" if sources["ir"] else "frontmatter-fallback", "ir_source": sources["ir_source"], "ir_schema_version": str(sources["ir"].get("schema_version") or "none"), }, "source": { "skill_dir": display_path(sources["skill_dir"]), "canonical_metadata": "agents/interface.yaml" if (sources["skill_dir"] / "agents" / "interface.yaml").exists() else "missing", "declared_targets": declared, }, "compiled_contract": contract, "permission_contract": permissions, "target_permission_contract": target_permissions, "target_native_contract": target_native, "target_transform": { "target": target, "adapter_mode": profile["adapter_mode"], "generated_files": profile["generated_files"], "metadata_mapping": profile["metadata_mapping"], "preserved_semantics": profile["preserved_semantics"], "degradation_strategy": contract["degradation_strategy"], "permission_representation": target_permissions["representation"], "native_surface": target_native["native_surface"], "activation_policy": target_native["activation"]["policy"], "resource_strategy": target_native["resources"]["strategy"], "script_strategy": target_native["scripts"]["strategy"], "permission_enforcement": target_native["permissions"]["enforcement"], }, "unsupported_features": list(profile.get("unsupported_features", [])), "warnings": warnings, "failures": failures, } def compile_targets(skill_dir: Path, targets: list[str] | None = None, generated_at: str | None = None) -> dict[str, Any]: sources = load_sources(skill_dir) selected = targets or declared_targets(sources) compiled = [compile_target_contract(skill_dir, target) for target in selected] failures = [failure for item in compiled for failure in item["failures"]] warnings = [warning for item in compiled for warning in item["warnings"]] return { "schema_version": COMPILER_SCHEMA_VERSION, "ok": not failures, "generated_at": generated_at or str(date.today()), "skill_dir": display_path(Path(skill_dir).resolve()), "summary": { "target_count": len(compiled), "pass_count": sum(1 for item in compiled if item["status"] == "pass"), "warn_count": sum(1 for item in compiled if item["status"] == "warn"), "block_count": sum(1 for item in compiled if item["status"] == "block"), "failure_count": len(failures), "warning_count": len(warnings), }, "targets": compiled, "failures": failures, "warnings": warnings, } def render_markdown(report: dict[str, Any]) -> str: summary = report["summary"] lines = [ "# Compiled Targets", "", f"- OK: `{report['ok']}`", f"- Targets: `{summary['target_count']}`", f"- Pass: `{summary['pass_count']}`", f"- Warn: `{summary['warn_count']}`", f"- Block: `{summary['block_count']}`", "", "## Target Transforms", "", "| Target | Status | Native Surface | Adapter Mode | Permissions | Degradation | Generated Files |", "| --- | --- | --- | --- | --- | --- | --- |", ] for item in report["targets"]: transform = item["target_transform"] files = ", ".join(transform.get("generated_files", [])) or "none" permissions = ", ".join(item.get("target_permission_contract", {}).get("declared_capabilities", [])) or "none" lines.append( f"| `{item['target']}` | `{item['status']}` | {transform.get('native_surface', '')} | `{transform.get('adapter_mode', '')}` | `{permissions}` | `{transform.get('degradation_strategy', '')}` | {files} |" ) lines.extend(["", "## Native Behavior Contracts", ""]) for item in report["targets"]: native = item.get("target_native_contract", {}) permissions = native.get("permissions", {}) review = native.get("review", {}) lines.extend( [ f"### {item['target']}", "", f"- Native surface: {native.get('native_surface', '')}", f"- Activation: {native.get('activation', {}).get('policy', '')}", f"- Resources: {native.get('resources', {}).get('strategy', '')}", f"- Scripts: {native.get('scripts', {}).get('strategy', '')}", f"- Permission enforcement: `{permissions.get('enforcement', '')}`; native enforcement `{permissions.get('native_enforcement')}`", f"- Review artifacts: {', '.join(review.get('artifacts', [])) or 'none'}", "", ] ) lines.extend(["", "## Failures", ""]) lines.extend([f"- {item}" for item in report["failures"]] or ["- None"]) lines.extend(["", "## Warnings", ""]) lines.extend([f"- {item}" for item in report["warnings"]] or ["- None"]) return "\n".join(lines).strip() + "\n" def render_compile_report( skill_dir: Path, targets: list[str] | None = None, output_json: Path | None = None, output_md: Path | None = None, generated_at: str | None = None, ) -> dict[str, Any]: skill_dir = skill_dir.resolve() reports = skill_dir / "reports" reports.mkdir(parents=True, exist_ok=True) output_json = output_json or reports / "compiled_targets.json" output_md = output_md or reports / "compiled_targets.md" report = compile_targets(skill_dir, targets=targets, generated_at=generated_at) report["artifacts"] = { "json": display_path(output_json), "markdown": display_path(output_md), } output_json.parent.mkdir(parents=True, exist_ok=True) output_json.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") output_md.write_text(render_markdown(report), encoding="utf-8") return report def main() -> None: parser = argparse.ArgumentParser(description="Compile Skill IR into target-specific semantic contracts.") parser.add_argument("skill_dir", nargs="?", default=".") parser.add_argument("--target", action="append", default=[]) parser.add_argument("--output-json") parser.add_argument("--output-md") parser.add_argument("--generated-at") args = parser.parse_args() payload = render_compile_report( Path(args.skill_dir), targets=args.target or None, output_json=Path(args.output_json).resolve() if args.output_json else None, output_md=Path(args.output_md).resolve() if args.output_md else None, generated_at=args.generated_at, ) print(json.dumps(payload, ensure_ascii=False, indent=2)) raise SystemExit(0 if payload["ok"] else 2) if __name__ == "__main__": main()