From 2917fd235da85818f1f6ddd9326fea823464a6e8 Mon Sep 17 00:00:00 2001 From: sck_0 Date: Tue, 27 Jan 2026 10:54:19 +0100 Subject: [PATCH] chore: make README update idempotent Prevent CI from re-introducing duplicate Curated Collections sections by normalizing headers and de-duping inserts. --- README.md | 4 ---- scripts/update_readme.py | 31 ++++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f5f02cfc..d8173b85 100644 --- a/README.md +++ b/README.md @@ -122,10 +122,6 @@ The repository is organized into several key areas of expertise: [Check out our Starter Packs in docs/BUNDLES.md](docs/BUNDLES.md) to find the perfect toolkit for your role. -## 📦 Curated Collections - -[Check out our Starter Packs in docs/BUNDLES.md](docs/BUNDLES.md) to find the perfect toolkit for your role. - ## Full Skill Registry (256/256) > [!NOTE] > **Document Skills**: We provide both **community** and **official Anthropic** versions for DOCX, PDF, PPTX, and XLSX. Locally, the official versions are used by default (via symlinks). In the repository, both versions are available for flexibility. diff --git a/scripts/update_readme.py b/scripts/update_readme.py index b91d3848..f67afbff 100644 --- a/scripts/update_readme.py +++ b/scripts/update_readme.py @@ -47,13 +47,30 @@ def update_readme(): content ) - # 5. Insert Collections / Bundles Section (New in Phase 3) - # This logic checks if "## 📦 Curated Collections" exists. If not, it creates it before Full Registry. - collections_header = "## 📦 Curated Collections" - - if collections_header not in content: - # Insert before Full Skill Registry - content = content.replace("## Full Skill Registry", f"{collections_header}\n\n[Check out our Starter Packs in docs/BUNDLES.md](docs/BUNDLES.md) to find the perfect toolkit for your role.\n\n## Full Skill Registry") + # 5. Ensure Curated Collections section exists (idempotent) + # + # Historical note: we previously used "## 📦 Curated Collections" in some runs. + # If the README already contains "## Curated Collections", inserting the emoji header creates duplicates. + canonical_collections_header = "## Curated Collections" + canonical_collections_body = "[Check out our Starter Packs in docs/BUNDLES.md](docs/BUNDLES.md) to find the perfect toolkit for your role." + + # Normalize any emoji variant to the canonical header + content = content.replace("## 📦 Curated Collections", canonical_collections_header) + + # If the section is missing entirely, insert it right before the Full Skill Registry section + if canonical_collections_header not in content: + registry_header_match = re.search(r'^## Full Skill Registry', content, flags=re.MULTILINE) + if registry_header_match: + insert_block = f"{canonical_collections_header}\n\n{canonical_collections_body}\n\n" + content = content[:registry_header_match.start()] + insert_block + content[registry_header_match.start():] + + # De-dupe repeated Curated Collections blocks (e.g. after a previous buggy insert) + escaped_body = re.escape(canonical_collections_body) + dedupe_pattern = re.compile( + rf'(?:{re.escape(canonical_collections_header)}\s*\n\s*\n{escaped_body}\s*\n\s*){{2,}}', + flags=re.MULTILINE + ) + content = dedupe_pattern.sub(f"{canonical_collections_header}\n\n{canonical_collections_body}\n\n", content) # 6. Generate New Registry Table print("🔄 Generating new registry table...")