feat(skill-creator): enhance HTML documentation and improve benchmark packaging validation
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Eval Set Review - __SKILL_NAME_PLACEHOLDER__</title>
|
||||
<!-- Fonts loaded from CDN; falls back to system fonts offline -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@500;600&family=Lora:wght@400;500&display=swap" rel="stylesheet">
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Eval Review</title>
|
||||
<!-- Fonts and SheetJS loaded from CDN; page degrades gracefully offline -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@500;600&family=Lora:wght@400;500&display=swap" rel="stylesheet">
|
||||
@@ -826,8 +827,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ---- XLSX rendering via SheetJS ----
|
||||
// ---- XLSX rendering via SheetJS (degrades to download link if CDN unavailable) ----
|
||||
function renderXlsx(container, b64Data) {
|
||||
if (typeof XLSX === "undefined") {
|
||||
const a = document.createElement("a");
|
||||
a.className = "download-link";
|
||||
a.href = "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64," + b64Data;
|
||||
a.download = "spreadsheet.xlsx";
|
||||
a.textContent = "Download .xlsx (SheetJS unavailable offline)";
|
||||
container.appendChild(a);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const raw = Uint8Array.from(atob(b64Data), c => c.charCodeAt(0));
|
||||
const wb = XLSX.read(raw, { type: "array" });
|
||||
|
||||
@@ -268,10 +268,9 @@ def generate_benchmark(benchmark_dir: Path, skill_name: str = "", skill_path: st
|
||||
"analyzer_model": "<model-name>",
|
||||
"timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
"evals_run": eval_ids,
|
||||
"runs_per_configuration": min(
|
||||
(len(runs) for runs in results.values() if runs),
|
||||
default=0,
|
||||
)
|
||||
"runs_per_configuration": {
|
||||
config: len(runs) for config, runs in results.items() if runs
|
||||
}
|
||||
},
|
||||
"runs": runs,
|
||||
"run_summary": run_summary,
|
||||
@@ -281,6 +280,19 @@ def generate_benchmark(benchmark_dir: Path, skill_name: str = "", skill_path: st
|
||||
return benchmark
|
||||
|
||||
|
||||
def _format_runs_per_config(rpc) -> str:
|
||||
"""Format runs_per_configuration for display (handles both int and dict)."""
|
||||
if isinstance(rpc, int):
|
||||
return f"{rpc} runs each"
|
||||
if isinstance(rpc, dict):
|
||||
counts = sorted(set(rpc.values()))
|
||||
if len(counts) == 1:
|
||||
return f"{counts[0]} runs each"
|
||||
parts = [f"{config}: {n}" for config, n in rpc.items()]
|
||||
return ", ".join(parts)
|
||||
return str(rpc)
|
||||
|
||||
|
||||
def generate_markdown(benchmark: dict) -> str:
|
||||
"""Generate human-readable benchmark.md from benchmark data."""
|
||||
metadata = benchmark["metadata"]
|
||||
@@ -298,7 +310,7 @@ def generate_markdown(benchmark: dict) -> str:
|
||||
"",
|
||||
f"**Model**: {metadata['executor_model']}",
|
||||
f"**Date**: {metadata['timestamp']}",
|
||||
f"**Evals**: {', '.join(map(str, metadata['evals_run']))} ({metadata['runs_per_configuration']} runs each per configuration)",
|
||||
f"**Evals**: {', '.join(map(str, metadata['evals_run']))} ({_format_runs_per_config(metadata['runs_per_configuration'])} per configuration)",
|
||||
"",
|
||||
"## Summary",
|
||||
"",
|
||||
|
||||
@@ -71,9 +71,9 @@ def package_skill(skill_path, output_dir=None):
|
||||
print(f"❌ Error: SKILL.md not found in {skill_path}")
|
||||
return None
|
||||
|
||||
# Run validation before packaging
|
||||
# Run validation before packaging (strict mode catches TODO placeholders)
|
||||
print("🔍 Validating skill...")
|
||||
valid, message = validate_skill(skill_path)
|
||||
valid, message = validate_skill(skill_path, strict=True)
|
||||
if not valid:
|
||||
print(f"❌ Validation failed: {message}")
|
||||
print(" Please fix the validation errors before packaging.")
|
||||
@@ -113,22 +113,21 @@ def package_skill(skill_path, output_dir=None):
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]")
|
||||
print("\nExample:")
|
||||
print(" python utils/package_skill.py skills/public/my-skill")
|
||||
print(" python utils/package_skill.py skills/public/my-skill ./dist")
|
||||
sys.exit(1)
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Package a skill folder into a distributable .skill file"
|
||||
)
|
||||
parser.add_argument("skill_path", help="Path to the skill folder")
|
||||
parser.add_argument("output_dir", nargs="?", default=None,
|
||||
help="Output directory for the .skill file (default: current directory)")
|
||||
args = parser.parse_args()
|
||||
|
||||
skill_path = sys.argv[1]
|
||||
output_dir = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
|
||||
print(f"📦 Packaging skill: {skill_path}")
|
||||
if output_dir:
|
||||
print(f" Output directory: {output_dir}")
|
||||
print(f"📦 Packaging skill: {args.skill_path}")
|
||||
if args.output_dir:
|
||||
print(f" Output directory: {args.output_dir}")
|
||||
print()
|
||||
|
||||
result = package_skill(skill_path, output_dir)
|
||||
result = package_skill(args.skill_path, args.output_dir)
|
||||
|
||||
if result:
|
||||
sys.exit(0)
|
||||
|
||||
Reference in New Issue
Block a user