diff --git a/CHANGELOG.md b/CHANGELOG.md index f9efd016..704f56d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Realigned README, package metadata, user docs, and GitHub About guidance to the current `1,304+` catalog state and `v8.4.0` release copy. - Automated metadata propagation for curated docs and package copy so `npm run chain` now keeps README, package description, and the main count-sensitive user/maintainer docs aligned when the skill catalog changes. +- Added an explicit `sync:github-about` automation path so GitHub About description, homepage, and topics can be refreshed from the same metadata source instead of being updated manually. ## [8.4.0] - 2026-03-20 - "Discovery, Metadata, and Release Hardening" diff --git a/package.json b/package.json index 484d629f..213881d9 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "index": "node tools/scripts/run-python.js tools/scripts/generate_index.py", "readme": "node tools/scripts/run-python.js tools/scripts/update_readme.py", "sync:metadata": "node tools/scripts/run-python.js tools/scripts/sync_repo_metadata.py", + "sync:github-about": "node tools/scripts/run-python.js tools/scripts/sync_repo_metadata.py --apply-github-about", "chain": "npm run validate && npm run index && npm run sync:metadata", "sync:all": "npm run chain", "catalog": "node tools/scripts/build-catalog.js", diff --git a/tools/scripts/sync_repo_metadata.py b/tools/scripts/sync_repo_metadata.py index ac479bf8..e34a4bb8 100644 --- a/tools/scripts/sync_repo_metadata.py +++ b/tools/scripts/sync_repo_metadata.py @@ -3,6 +3,7 @@ import argparse import json import os import re +import subprocess import sys from pathlib import Path @@ -10,6 +11,29 @@ from update_readme import configure_utf8_output, find_repo_root, load_metadata, ABOUT_DESCRIPTION_RE = re.compile(r'"description"\s*:\s*"([^"]*)"') +GITHUB_HOMEPAGE_URL = "https://sickn33.github.io/antigravity-awesome-skills/" +RECOMMENDED_TOPICS = [ + "agentic-skills", + "agent-skills", + "ai-agents", + "ai-agent-skills", + "awesome-list", + "awesome-lists", + "antigravity", + "antigravity-skills", + "autonomous-coding", + "claude-code", + "claude-code-skills", + "codex-cli", + "codex-skills", + "cursor-skills", + "developer-tools", + "gemini-cli", + "gemini-skills", + "mcp", + "ai-workflows", + "skill-library", +] README_TAGLINE_RE = re.compile( r"^> \*\*Installable GitHub library of \d[\d,]*\+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and other AI coding assistants\.\*\*$", re.MULTILINE, @@ -44,6 +68,55 @@ def build_about_description(metadata: dict) -> str: ) +def build_about_topics() -> list[str]: + return list(RECOMMENDED_TOPICS) + + +def run_cli_command(args: list[str], dry_run: bool = False) -> None: + if dry_run: + print(f"[dry-run] {' '.join(args)}") + return + + subprocess.run(args, check=True) + + +def sync_github_about( + metadata: dict, + dry_run: bool, + runner=run_cli_command, +) -> None: + description = build_about_description(metadata) + repo = metadata["repo"] + + runner( + [ + "gh", + "repo", + "edit", + repo, + "--description", + description, + "--homepage", + GITHUB_HOMEPAGE_URL, + ], + dry_run=dry_run, + ) + + topic_command = [ + "gh", + "api", + f"repos/{repo}/topics", + "--method", + "PUT", + ] + for topic in build_about_topics(): + topic_command.extend(["-f", f"names[]={topic}"]) + runner(topic_command, dry_run=dry_run) + + if not dry_run: + print(f"✅ Synced GitHub About settings for {repo}") + + def replace_if_present(content: str, pattern: re.Pattern[str], replacement: str) -> tuple[str, bool]: updated_content, count = pattern.subn(replacement, content, count=1) return updated_content, count > 0 @@ -271,7 +344,8 @@ def print_manual_github_about(metadata: dict) -> None: description = build_about_description(metadata) print("\nManual GitHub repo settings update:") print(f"- About description: {description}") - print("- Suggested topics: claude-code, cursor, gemini-cli, codex-cli, github-copilot, antigravity") + print(f"- Homepage: {GITHUB_HOMEPAGE_URL}") + print(f"- Suggested topics: {', '.join(build_about_topics())}") def parse_args() -> argparse.Namespace: @@ -284,6 +358,11 @@ def parse_args() -> argparse.Namespace: action="store_true", help="Refresh live star count and updated_at when syncing README metadata.", ) + parser.add_argument( + "--apply-github-about", + action="store_true", + help="Apply the GitHub About description, homepage, and topics to the remote repository via gh CLI.", + ) return parser.parse_args() @@ -300,6 +379,8 @@ def main() -> int: ) package_updated = update_package_description(base_dir, metadata, args.dry_run) docs_updated = sync_curated_docs(base_dir, metadata, args.dry_run) + if args.apply_github_about: + sync_github_about(metadata, dry_run=args.dry_run) print_manual_github_about(readme_metadata) if args.dry_run and not package_updated: diff --git a/tools/scripts/tests/test_sync_repo_metadata.py b/tools/scripts/tests/test_sync_repo_metadata.py index c8943215..f9ad61f7 100644 --- a/tools/scripts/tests/test_sync_repo_metadata.py +++ b/tools/scripts/tests/test_sync_repo_metadata.py @@ -120,6 +120,37 @@ If you want a faster answer than "browse all 1,273+ skills", start with a tool-s self.assertIn("1,304+ agentic skills", description) self.assertIn("installer CLI", description) + def test_sync_github_about_builds_expected_commands(self): + calls = [] + + def fake_runner(args, dry_run=False): + calls.append((args, dry_run)) + + sync_repo_metadata.sync_github_about( + { + "repo": "sickn33/antigravity-awesome-skills", + "total_skills_label": "1,304+", + }, + dry_run=True, + runner=fake_runner, + ) + + self.assertEqual(len(calls), 2) + repo_edit_args, repo_edit_dry_run = calls[0] + topics_args, topics_dry_run = calls[1] + + self.assertTrue(repo_edit_dry_run) + self.assertTrue(topics_dry_run) + self.assertEqual(repo_edit_args[:4], ["gh", "repo", "edit", "sickn33/antigravity-awesome-skills"]) + self.assertIn("--description", repo_edit_args) + self.assertIn("--homepage", repo_edit_args) + self.assertIn("https://sickn33.github.io/antigravity-awesome-skills/", repo_edit_args) + + self.assertEqual(topics_args[:4], ["gh", "api", "repos/sickn33/antigravity-awesome-skills/topics", "--method"]) + self.assertIn("PUT", topics_args) + self.assertIn("names[]=claude-code", topics_args) + self.assertIn("names[]=skill-library", topics_args) + if __name__ == "__main__": unittest.main() diff --git a/walkthrough.md b/walkthrough.md index 3de5ec38..eb59d6c1 100644 --- a/walkthrough.md +++ b/walkthrough.md @@ -126,3 +126,4 @@ - `docs/maintainers/skills-update-guide.md` - Updated the changelog `Unreleased` section so the post-`v8.4.0` main branch state documents both the imported skill families and the docs/About realignment. - Automated the recurring docs metadata maintenance by extending `tools/scripts/sync_repo_metadata.py`, wiring it into `npm run chain`, and adding a regression test so future skill-count/version updates propagate through the curated docs surface without manual patching. +- Added a remote GitHub About sync path (`npm run sync:github-about`) backed by `gh repo edit` + `gh api .../topics` so the public repository metadata can be refreshed from the same source of truth on demand.