← Files MakeBox for EtsyARCHIVED FILE

scripts/package-release.py

5.37 KB · Nov 3, 2026 · 19:17 UTC

↓ Download file

#!/usr/bin/env python3
"""Build Claude/Codex connected and standalone archives without credentials or network."""
import argparse
import json
import shutil
import zipfile
from pathlib import Path

PARTS = ("README.md", "CHANGELOG.md", "LICENSE", "ОПИС-УКРАЇНСЬКОЮ.md", "assets", "agents",
         "agent-packs", "skills", "references", "templates", "checklists", "examples", "scripts", "tests")


def main():
    p = argparse.ArgumentParser(description=__doc__)
    p.add_argument("--output", type=Path, required=True)
    p.add_argument("--codex-manifest", type=Path, required=True, help="Existing public metadata manifest, not reviewer credentials")
    args = p.parse_args()
    root = Path(__file__).resolve().parents[1]
    claude = json.loads((root / ".claude-plugin/plugin.json").read_text())
    codex = json.loads(args.codex_manifest.read_text())
    version = claude["version"]
    args.output.mkdir(parents=True, exist_ok=True)
    for runtime in ("claude", "codex"):
        for mode in ("connected", "standalone"):
            label = f"makebox-etsy-{runtime}-{mode}-{version}"
            stage = args.output / label
            if stage.exists():
                raise SystemExit(f"Refusing to overwrite existing package stage: {stage}")
            package = stage / "makebox-etsy"
            package.mkdir(parents=True)
            for part in PARTS:
                source = root / part
                if source.is_dir():
                    shutil.copytree(source, package / part, ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))
                else:
                    shutil.copy2(source, package / part)
            config = json.loads((root / ".mcp.json").read_text()) if mode == "connected" else {"mcpServers": {}}
            (package / ".mcp.json").write_text(json.dumps(config, indent=2) + "\n")
            metadata = json.loads(json.dumps(claude if runtime == "claude" else codex))
            metadata["version"] = version
            metadata["description"] = claude["description"]
            if mode == "standalone":
                metadata["name"] = "makebox-etsy-standalone"
            if runtime == "claude":
                if mode == "standalone":
                    metadata["displayName"] = "MakeBox for Etsy — Standalone"
                folder = ".claude-plugin"
            else:
                folder = ".codex-plugin"
                interface = metadata.setdefault("interface", {})
                interface["shortDescription"] = "Create better Etsy listings"
                interface["longDescription"] = (
                    "An Etsy SEO strategist for complete copy-ready listings, factual audits, keyword evidence, "
                    "options, personalization, shipping/packaging and digital contents. Works from pasted text, photos "
                    "or CSVs without a connector. The coordinating skill carries the expert role. "
                    + ("The optional MakeBox MCP connection adds live Etsy reads and exactly authorized operations, with authoritative readback. "
                       if mode == "connected" else "This standalone package includes no MCP connection or live shop access. ")
                    + "It does not guarantee rank or sales, and the connector does not generate images or video.")
                interface["defaultPrompt"] = ["Create a complete Etsy listing from these product facts.",
                                              "Improve this pasted listing without losing specifications.",
                                              "Analyze my keyword CSV and explain which phrases fit my product."]
                ext = metadata.setdefault("extensions", {}).setdefault("com.openai", {})
                ext["onboardingSkill"] = "./skills/makebox-shop-manager/SKILL.md"
                ext.setdefault("publication", {})["release_notes"] = f"Version {version}: detailed Etsy strategist role, seven workflows, 1024-character personalization, fixed optional-text fees and verified direct Etsy execution."
                if mode == "connected":
                    metadata["mcpServers"] = "./.mcp.json"
                    review = ext.get("review", {})
                    for case in review.get("test_cases", {}).get("positive", []):
                        if "optimize_listing" in case.get("tools_triggered", ""):
                            case["tools_triggered"] = "list_listings, get_listing"
                            case["expected_behavior"] = "Read this seller's listing and prepare an original chat-authored proposal. No paid internal generation and no Etsy write."
                else:
                    metadata.pop("mcpServers", None)
                    ext.pop("review", None)
                    interface["displayName"] = "MakeBox for Etsy — Standalone"
                    interface["capabilities"] = ["Prepare complete listing copy", "Audit pasted listings", "Analyze supplied keyword evidence", "Plan product settings"]
            (package / folder).mkdir()
            (package / folder / "plugin.json").write_text(json.dumps(metadata, indent=2, ensure_ascii=False) + "\n")
            with zipfile.ZipFile(args.output / f"{label}.zip", "w", zipfile.ZIP_DEFLATED) as archive:
                for file in sorted(package.rglob("*")):
                    if file.is_file():
                        archive.write(file, file.relative_to(stage))
            print(args.output / f"{label}.zip")


if __name__ == "__main__":
    main()

SHA-256: b108ba328cfdcefe00a5e068527a00d0e9c8eb8d0f5d5c87ac2f179d2201c42f