#!/usr/bin/env python3 """Check sitrep-panel's package files without external dependencies.""" from __future__ import annotations import ast import json import re from pathlib import Path ROOT = Path(__file__).resolve().parent.parent SKILL = (ROOT / "SKILL.md").read_text(encoding="utf-8") README = (ROOT / "README.md").read_text(encoding="utf-8") AGENTS = (ROOT / "AGENTS.md").read_text(encoding="utf-8") TEMPLATE = (ROOT / "assets" / "template.html").read_text(encoding="utf-8") PLUGIN = json.loads((ROOT / ".claude-plugin" / "plugin.json").read_text(encoding="utf-8")) MARKETPLACE = json.loads((ROOT / ".claude-plugin" / "marketplace.json").read_text(encoding="utf-8")) SERVE_PY = (ROOT / "scripts" / "serve.py").read_text(encoding="utf-8") def require_match(match: re.Match[str] | None, message: str) -> re.Match[str]: if match is None: raise SystemExit(message) return match def require(condition: bool, message: str) -> None: if not condition: raise SystemExit(message) # --- SKILL.md frontmatter --------------------------------------------------- yaml_metadata = require_match( re.match(r"\A---\n(.*?)\n---\n", SKILL, re.DOTALL), "SKILL.md must begin with YAML metadata", ).group(1) require( re.search(r"(?m)^name:\s*sitrep-panel\s*$", yaml_metadata) is not None, "SKILL.md metadata must set name: sitrep-panel", ) require( re.search(r"(?m)^description:", yaml_metadata) is not None, "SKILL.md metadata must set a description", ) require( re.search(r"(?m)^license:\s*MIT\s*$", yaml_metadata) is not None, "SKILL.md metadata must set license: MIT", ) skill_version = require_match( re.search(r'(?m)^\s+version:\s*["\']([^"\']+)["\']\s*$', yaml_metadata), "Add metadata.version to SKILL.md", ).group(1) # --- version consistency across README / plugin.json / marketplace.json --- readme_version = require_match( re.search(r"(?m)^- \*\*([0-9]+\.[0-9]+\.[0-9]+)\*\*", README), "Add a version entry to README.md's Versions section", ).group(1) require( skill_version == readme_version == PLUGIN["version"], f"Version mismatch: SKILL.md={skill_version} README.md={readme_version} plugin.json={PLUGIN['version']}", ) require(PLUGIN["name"] == "sitrep-panel", "plugin.json name must be sitrep-panel") require(PLUGIN["license"] == "MIT", "plugin.json license must be MIT") require( any(p["name"] == "sitrep-panel" for p in MARKETPLACE["plugins"]), "marketplace.json must list a sitrep-panel plugin entry", ) # --- AGENTS.md exists and isn't a stub -------------------------------------- require(len(AGENTS.strip()) > 200, "AGENTS.md looks empty or too short") # --- template.html has the ids the SKILL.md protocol depends on ------------ for element_id in ( "board", "board-todo", "board-progress", "board-done", "board-blocked", "current-work-body", "shots-body", "entries", "updated-badge", "theme-toggle", "section-nav", ): require(f'id="{element_id}"' in TEMPLATE, f'template.html is missing id="{element_id}"') for token in ("{{TITLE}}", "{{SUBTITLE}}"): require(token in TEMPLATE, f"template.html is missing the {token} placeholder") require("meta.json" in TEMPLATE, "template.html must poll meta.json for live-reload") require("data-theme" in TEMPLATE, "template.html must support a manual light/dark toggle") # --- serve.py is at least syntactically valid Python ------------------------ try: ast.parse(SERVE_PY, filename="scripts/serve.py") except SyntaxError as exc: # pragma: no cover - fails loud on purpose raise SystemExit(f"scripts/serve.py has a syntax error: {exc}") from exc require("SERVING http://localhost" in SERVE_PY, "serve.py must print the SERVING line callers parse") print("sitrep-panel package checks passed.")