CtrlK
BlogDocsLog inGet started
Tessl Logo

punkdev/cc2oc

Add and ship OpenCode support for one Claude Code plugin at a time. Includes core migration to a reviewable `opencode-plugin/` adapter, maintainer-facing docs, and follow-up CI/versioning setup for package publishing or skill-copy drift checks.

92

1.25x
Quality

92%

Does it follow best practices?

Impact

97%

1.25x

Average score across 2 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

validate_opencode_package.pyskills/migrate-plugin/scripts/

#!/usr/bin/env python3
"""Validate a generated opencode-plugin package directory."""

from __future__ import annotations

import argparse
import json
from pathlib import Path
from typing import Any

from _common import print_result, rel


FORBIDDEN_FILES_ENTRIES = (".claude", ".cursor", ".opencode", ".agents")


def package_entry_path(package_dir: Path, package_json: dict[str, Any], key: str) -> str | None:
    value = package_json.get(key)
    if isinstance(value, str):
        return value
    if key == "exports" and isinstance(value, dict):
        dot = value.get(".")
        if isinstance(dot, str):
            return dot
        if isinstance(dot, dict):
            for nested_key in ("import", "default", "require"):
                nested = dot.get(nested_key)
                if isinstance(nested, str):
                    return nested
    return None


def path_exists(package_dir: Path, entry: str | None) -> bool:
    if not entry:
        return False
    return (package_dir / entry.lstrip("./")).exists()


def validate_package(root: Path, package_dir_arg: str, allow_harness: bool) -> dict:
    root = root.resolve()
    package_dir = (root / package_dir_arg).resolve()
    package_json_path = package_dir / "package.json"
    checks: list[dict[str, str]] = []
    warnings: list[str] = []
    errors: list[str] = []

    def add_check(text: str, passed: bool, evidence: str) -> None:
        checks.append({"text": text, "passed": str(passed).lower(), "evidence": evidence})
        if not passed:
            errors.append(f"{text}: {evidence}")

    add_check("opencode-plugin package directory exists", package_dir.exists(), rel(package_dir, root))
    add_check("package.json exists", package_json_path.exists(), rel(package_json_path, root))

    package_json: dict[str, Any] = {}
    if package_json_path.exists():
        try:
            package_json = json.loads(package_json_path.read_text(encoding="utf-8"))
        except json.JSONDecodeError as exc:
            errors.append(f"package.json is invalid JSON: {exc}")

    if package_json:
        for field in ("name", "version", "type", "main", "exports", "files", "keywords", "license"):
            add_check(f"package.json has {field}", field in package_json, str(package_json.get(field, "missing")))

        add_check("package type is module", package_json.get("type") == "module", str(package_json.get("type", "missing")))

        keywords = package_json.get("keywords", [])
        add_check("keywords include opencode", isinstance(keywords, list) and "opencode" in keywords, str(keywords))
        add_check("keywords include opencode-plugin", isinstance(keywords, list) and "opencode-plugin" in keywords, str(keywords))

        main_entry = package_entry_path(package_dir, package_json, "main")
        export_entry = package_entry_path(package_dir, package_json, "exports")
        add_check("main entry points to an existing file", path_exists(package_dir, main_entry), main_entry or "missing")
        add_check("exports entry points to an existing file", path_exists(package_dir, export_entry), export_entry or "missing")

        files = package_json.get("files", [])
        if isinstance(files, list):
            forbidden = [entry for entry in files if any(str(entry).startswith(prefix) for prefix in FORBIDDEN_FILES_ENTRIES)]
            add_check("files excludes agent config roots", not forbidden, str(forbidden or files))
        else:
            add_check("files is an array", False, str(files))

        if "repository" not in package_json:
            warnings.append("package.json has no repository field")
        if "homepage" not in package_json:
            warnings.append("package.json has no homepage field")

    harness_dir = root / ".opencode"
    if harness_dir.exists() and not allow_harness:
        warnings.append(".opencode/ exists; only use it as an explicit local dogfooding harness, not as generated package output")

    return {
        "title": "OpenCode Package Validation",
        "summary": {
            "target": str(root),
            "package_dir": rel(package_dir, root),
            "checks_passed": sum(1 for check in checks if check["passed"] == "true"),
            "checks_total": len(checks),
            "status": "fail" if errors else "pass",
        },
        "checks": checks,
        "warnings": warnings,
        "errors": errors,
    }


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("target", nargs="?", default=".", help="Repo root containing opencode-plugin/")
    parser.add_argument("--package-dir", default="opencode-plugin", help="Package directory relative to target")
    parser.add_argument("--allow-harness", action="store_true", help="Do not warn when .opencode/ exists")
    parser.add_argument("--format", choices=("json", "markdown"), default="json")
    args = parser.parse_args()

    result = validate_package(Path(args.target), args.package_dir, args.allow_harness)
    print_result(result, args.format)
    return 1 if result["errors"] else 0


if __name__ == "__main__":
    raise SystemExit(main())

README.md

tile.json