Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 91 additions & 14 deletions skills/detectoracle/scripts/verify.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,95 @@
from __future__ import annotations

import subprocess
import sys
import tempfile
import zipfile
from pathlib import Path

REQUIRED_BUNDLE_ENTRIES = {
"SKILL.md",
"scripts/detectoracle.py",
"scripts/issueoracle.py",
"scripts/lib/version.py",
"scripts/lib/schema.py",
"scripts/lib/env.py",
"scripts/lib/pack_loader.py",
"scripts/lib/pattern_match.py",
"scripts/lib/review.py",
"scripts/lib/github_search.py",
"scripts/lib/issue_filter.py",
}

def verify():

def _run(cmd: list[str], *, cwd: Path):
return subprocess.run(
cmd,
cwd=cwd,
capture_output=True,
text=True,
timeout=30,
)


def _summarize_failure(result) -> str:
stdout = result.stdout.strip()
stderr = result.stderr.strip()
detail = stderr or stdout or "no output"
return f"exit={result.returncode}: {detail}"


def _verify_bundle_archive(bundle_path: Path) -> list[str]:
errors: list[str] = []

if not bundle_path.exists():
return [f"Bundle not found: {bundle_path}"]

try:
with zipfile.ZipFile(bundle_path, "r") as zf:
names = set(zf.namelist())
missing = sorted(REQUIRED_BUNDLE_ENTRIES - names)
if missing:
errors.append(f"Bundle missing required entries: {', '.join(missing)}")
if not any(name.startswith("packs/") for name in names):
errors.append("Bundle missing packs/ content")
if not any(name.startswith("references/") for name in names):
errors.append("Bundle missing references/ content")

if errors:
return errors

with tempfile.TemporaryDirectory() as tmp, zipfile.ZipFile(bundle_path, "r") as zf:
extract_dir = Path(tmp) / "skill"
zf.extractall(extract_dir)
script = extract_dir / "scripts" / "detectoracle.py"
packs_dir = extract_dir / "packs"

diagnose = _run([sys.executable, str(script), "diagnose"], cwd=extract_dir)
if diagnose.returncode != 0:
errors.append(f"Bundle diagnose failed: {_summarize_failure(diagnose)}")

validate = _run(
[sys.executable, str(script), "validate", str(packs_dir)],
cwd=extract_dir,
)
if validate.returncode != 0:
errors.append(f"Bundle validate failed: {_summarize_failure(validate)}")
except zipfile.BadZipFile as e:
errors.append(f"Bundle is not a valid zip archive: {e}")
except Exception as e:
errors.append(f"Bundle smoke test failed: {e}")

return errors


def verify() -> int:
errors = []

scripts_dir = Path(__file__).parent
skill_dir = scripts_dir.parent
repo_root = skill_dir.parents[1]
bundle_path = repo_root / "dist" / "detectoracle.skill"

# Check critical files exist. The main script keeps its legacy file name during the rename.
critical = [
skill_dir / "SKILL.md",
scripts_dir / "detectoracle.py",
Expand All @@ -29,12 +108,10 @@ def verify():
if not f.exists():
errors.append(f"Missing critical file: {f}")

# Try importing key modules
sys.path.insert(0, str(scripts_dir))
try:
from lib import schema

# Test round-trip
p = schema.Pattern(
id="test-pattern",
title="Test",
Expand All @@ -46,27 +123,27 @@ def verify():
)
d = p.model_dump()
p2 = schema.Pattern(**d)
assert p.id == p2.id
if p.id != p2.id:
errors.append("Schema round-trip changed pattern id")
except Exception as e:
errors.append(f"Schema round-trip failed: {e}")

# Check packs
packs_dir = skill_dir / "packs"
if packs_dir.exists():
patterns_found = list(packs_dir.rglob("patterns.yaml"))
if not patterns_found:
errors.append("No pattern packs found")
else:
if not packs_dir.exists():
errors.append("packs/ directory missing")
elif not list(packs_dir.rglob("patterns.yaml")):
errors.append("No pattern packs found")

errors.extend(_verify_bundle_archive(bundle_path))

if errors:
print("DETECTORACLE VERIFY FAILED:")
for e in errors:
print(f" - {e}")
return 1
else:
print("DETECTORACLE VERIFY PASSED")
return 0

print("DETECTORACLE VERIFY PASSED")
return 0


if __name__ == "__main__":
Expand Down