refactor(packaging): split per-skill outputs by format and keep bundle

This commit is contained in:
2026-03-19 15:20:52 +01:00
parent db40497f8d
commit a15b1813f8
71 changed files with 81 additions and 61 deletions

View File

@@ -60,8 +60,10 @@ def iter_skill_dirs(skills_root: Path) -> list[Path]:
]
def ensure_clean_output(output_dir: Path) -> tuple[Path, Path]:
def ensure_clean_output(output_dir: Path) -> tuple[Path, Path, Path, Path]:
per_skill_dir = output_dir / "per-skill"
per_skill_skill_dir = per_skill_dir / "skill"
per_skill_zip_dir = per_skill_dir / "zip"
bundles_dir = output_dir / "bundles"
if per_skill_dir.exists():
@@ -69,9 +71,10 @@ def ensure_clean_output(output_dir: Path) -> tuple[Path, Path]:
if bundles_dir.exists():
shutil.rmtree(bundles_dir)
per_skill_dir.mkdir(parents=True, exist_ok=True)
per_skill_skill_dir.mkdir(parents=True, exist_ok=True)
per_skill_zip_dir.mkdir(parents=True, exist_ok=True)
bundles_dir.mkdir(parents=True, exist_ok=True)
return per_skill_dir, bundles_dir
return per_skill_dir, per_skill_skill_dir, per_skill_zip_dir, bundles_dir
def add_directory_to_zip(zip_file: ZipFile, source_dir: Path, arc_prefix: str | None = None) -> None:
@@ -84,9 +87,13 @@ def add_directory_to_zip(zip_file: ZipFile, source_dir: Path, arc_prefix: str |
zip_file.write(file_path, relative)
def create_skill_archives(skill: SkillRecord, per_skill_dir: Path) -> tuple[Path, Path]:
skill_file = per_skill_dir / f"{skill.package_name}.skill"
zip_file = per_skill_dir / f"{skill.package_name}.zip"
def create_skill_archives(
skill: SkillRecord,
per_skill_skill_dir: Path,
per_skill_zip_dir: Path,
) -> tuple[Path, Path]:
skill_file = per_skill_skill_dir / f"{skill.package_name}.skill"
zip_file = per_skill_zip_dir / f"{skill.package_name}.zip"
with ZipFile(skill_file, "w", compression=ZIP_DEFLATED) as zf:
add_directory_to_zip(zf, skill.source_path)
@@ -146,13 +153,15 @@ def build_index(
f"- Generated (UTC): **{ts}**",
f"- Skills root: `{skills_root}`",
f"- Valid skills packaged: **{len(valid_skills)}**",
f"- Per-skill formats: `.skill` + `.zip`",
"- Per-skill formats: `.skill` and `.zip` in separate folders",
f"- Bundle: [`{bundle_path.name}`](bundles/{bundle_path.name})",
f"- Validation status: **{'PASS' if all_ok else 'FAIL'}**",
"",
"## Quick Links",
"",
"- [Per-skill packages](per-skill/)",
"- [Per-skill root](per-skill/)",
"- [Per-skill `.skill`](per-skill/skill/)",
"- [Per-skill `.zip`](per-skill/zip/)",
f"- [Bundle archive](bundles/{bundle_path.name})",
"- [Upload markdown exports](upload-md/)",
"- [Skill sources](../skill/)",
@@ -166,8 +175,8 @@ def build_index(
for skill in sorted(valid_skills, key=lambda item: item.package_name):
source_rel = f"../skill/{skill.source_dir_name}/SKILL.md"
markdown_rel = f"upload-md/{skill.package_name}.md"
skill_rel = f"per-skill/{skill.package_name}.skill"
zip_rel = f"per-skill/{skill.package_name}.zip"
skill_rel = f"per-skill/skill/{skill.package_name}.skill"
zip_rel = f"per-skill/zip/{skill.package_name}.zip"
markdown_cell = (
f"[`{skill.package_name}.md`]({markdown_rel})"
@@ -214,6 +223,8 @@ def build_index(
"## Output Paths",
"",
"- [`package/per-skill/`](per-skill/)",
"- [`package/per-skill/skill/`](per-skill/skill/)",
"- [`package/per-skill/zip/`](per-skill/zip/)",
"- [`package/bundles/`](bundles/)",
"- [`package/upload-md/`](upload-md/)",
]
@@ -222,7 +233,7 @@ def build_index(
def package_skills(skills_root: Path, output_dir: Path, bundle_name: str, spot_check_count: int) -> int:
per_skill_dir, bundles_dir = ensure_clean_output(output_dir)
per_skill_dir, per_skill_skill_dir, per_skill_zip_dir, bundles_dir = ensure_clean_output(output_dir)
skipped: list[str] = []
warnings: list[str] = []
@@ -268,7 +279,7 @@ def package_skills(skills_root: Path, output_dir: Path, bundle_name: str, spot_c
)
for skill in valid_skills:
create_skill_archives(skill, per_skill_dir)
create_skill_archives(skill, per_skill_skill_dir, per_skill_zip_dir)
bundle_path = bundles_dir / bundle_name
with ZipFile(bundle_path, "w", compression=ZIP_DEFLATED) as zf:
@@ -278,7 +289,7 @@ def package_skills(skills_root: Path, output_dir: Path, bundle_name: str, spot_c
validations: list[tuple[bool, str]] = []
expected = 2 * len(valid_skills)
produced = len(list(per_skill_dir.glob("*.skill"))) + len(list(per_skill_dir.glob("*.zip")))
produced = len(list(per_skill_skill_dir.glob("*.skill"))) + len(list(per_skill_zip_dir.glob("*.zip")))
validations.append(
(
expected == produced,
@@ -288,8 +299,8 @@ def package_skills(skills_root: Path, output_dir: Path, bundle_name: str, spot_c
check_items = valid_skills[: max(0, spot_check_count)]
for skill in check_items:
skill_archive = per_skill_dir / f"{skill.package_name}.skill"
zip_archive = per_skill_dir / f"{skill.package_name}.zip"
skill_archive = per_skill_skill_dir / f"{skill.package_name}.skill"
zip_archive = per_skill_zip_dir / f"{skill.package_name}.zip"
validations.append(validate_archive_contains_skill_md(skill_archive))
validations.append(validate_archive_contains_skill_md(zip_archive))
@@ -315,7 +326,9 @@ def package_skills(skills_root: Path, output_dir: Path, bundle_name: str, spot_c
print(f"Valid skills: {len(valid_skills)}")
print(f"Skipped: {len(skipped)}")
print(f"Warnings: {len(warnings)}")
print(f"Per-skill output: {per_skill_dir}")
print(f"Per-skill output root: {per_skill_dir}")
print(f"Per-skill .skill output: {per_skill_skill_dir}")
print(f"Per-skill .zip output: {per_skill_zip_dir}")
print(f"Bundle output: {bundle_path}")
print(f"Index: {index_path}")
all_ok = all(ok for ok, _ in validations)