diff --git a/CHANGELOG.md b/CHANGELOG.md index fda29ea8..a3f6ac23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [6.51.1] - 2026-05-20 + +Hotfix: the install-time skills picker hardcoded a 24-skill list in +`scripts/lib/skills.sh:SKILLS_CATALOG`, so the 38 marketing skills added +in v6.51.0 + the humanizer skill added in v6.50.0 were INVISIBLE to the +TUI even though they were correctly mirrored under +`templates/skills-marketplace/` and registered in +`manifest.json:skills_pins` + `templates/skills-catalog.json`. + +User-reported regression — the install picker on a fresh project showed +only the legacy 24 skills, missing all 39 net-new skills from the past +two ships. + +### Fixed + +- **`scripts/lib/skills.sh:SKILLS_CATALOG`** — expanded from 24 names to + 63 (62 mirrored skills + `impeccable` npm-installed special case). The + array now matches `manifest.json:files.skills_marketplace` 1:1, plus + the `impeccable` entry that lives outside the mirror by design. +- Updated SKILLS_CATALOG header comment from "24-skill catalog — + SKILL-01 source of truth" to a description of the actual contract + (mirror dirs + impeccable npm special-case). The vestigial + `REQUIREMENTS.md SKILL-01` reference was already dead (no such file). +- Updated docstring on `skills_catalog_names()` and the variable docs at + the top of the file — no more "24" hardcoded references. + +### Why this slipped + +The previous 3 ships (v6.49.0, v6.50.0, v6.51.0) updated: + +- `manifest.json:skills_pins` (62 entries) +- `manifest.json:files.skills_marketplace` (62 entries) +- `templates/skills-catalog.json` (61 + memo-skill = 62) +- mirror dirs under `templates/skills-marketplace/` + +… but did NOT update `SKILLS_CATALOG` in `scripts/lib/skills.sh`. That +array is what `scripts/install.sh` reads when building the TUI checklist +— it is the single source of truth for picker visibility, separate from +the manifest/catalog files. The drift was silent because `make check` +does not enforce SKILLS_CATALOG ↔ manifest consistency. + +### Memory correction + +The v6.51.0 CHANGELOG + topic file claimed `ab-test-setup` was retained +from the mysticaltech fork "under a distinct name." Re-audit of +`manifest.json:skills_pins` shows `ab-test-setup` was never pinned — +only `analytics-tracking` was kept from mysticaltech. The +`ab-test-setup` claim was a documentation hallucination. The +SKILLS_CATALOG fix in this release does NOT add `ab-test-setup` +because no mirror dir exists for it. + +### Follow-up + +A future release should add a `make check` gate that compares +`SKILLS_CATALOG` against `manifest.json:files.skills_marketplace` to +prevent recurrence. Tracked as deferred work. + ## [6.51.0] - 2026-05-20 Bulk skills-marketplace expansion: 40 marketing skills from the canonical diff --git a/manifest.json b/manifest.json index 337f2191..99c42e39 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "manifest_version": 2, - "version": "6.51.0", + "version": "6.51.1", "updated": "2026-05-20", "build_date": "2026-05-20", "description": "Claude Code Toolkit manifest for smart updates", diff --git a/scripts/init-claude.sh b/scripts/init-claude.sh index b2c35362..38b781e2 100755 --- a/scripts/init-claude.sh +++ b/scripts/init-claude.sh @@ -35,7 +35,7 @@ NC='\033[0m' # `raw.githubusercontent.com/.../v6.24.5/.../init-claude.sh`), leave # TK_TOOLKIT_REF unset and it inherits the bundled default below — # guaranteeing every file in the install comes from the same tag. -TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.0}" +TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.1}" # Audit INF-MED-2 (2026-04-30 deep): allowlist guard — TK_TOOLKIT_REF flows # raw into curl URLs. Reject anything outside the tag/SHA charset, plus any # `..` traversal sequence. Tags / branches / SHAs do not contain `..`. diff --git a/scripts/install-statusline.sh b/scripts/install-statusline.sh index af267313..48d7d3c6 100755 --- a/scripts/install-statusline.sh +++ b/scripts/install-statusline.sh @@ -33,7 +33,7 @@ done : "${YES}" # silence shellcheck SC2034 — no-op stub today # Audit H5: TK_TOOLKIT_REF pins to a tag/SHA (default `main`). -TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.0}" +TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.1}" # Audit INF-MED-2 (2026-04-30 deep): allowlist guard — TK_TOOLKIT_REF flows # raw into curl URLs. Reject anything outside the tag/SHA charset, plus any # `..` traversal sequence. Tags / branches / SHAs do not contain `..`. diff --git a/scripts/install.sh b/scripts/install.sh index 3f89decc..79a999e1 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -40,7 +40,7 @@ export TK_TOOLKIT_REF TK_USER_AGENT # Config # Audit H5: TK_TOOLKIT_REF pins to a tag/SHA (default `main`); TK_REPO_URL # remains the highest-priority override (full URL with ref baked in). -TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.0}" +TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.1}" # Audit INF-MED-2 (2026-04-30 deep): allowlist guard — TK_TOOLKIT_REF flows # raw into curl URLs. Reject anything outside the tag/SHA charset, plus any # `..` traversal sequence. Tags / branches / SHAs do not contain `..`. @@ -1279,7 +1279,7 @@ fi # Mirror of the --mcps branch above; reuses TUI_* globals + print_install_status. # ───────────────────────────────────────────────── if [[ "$SKILLS" -eq 1 ]]; then - # Populate TUI_INSTALLED[] from the 24-skill catalog. + # Populate TUI_INSTALLED[] from SKILLS_CATALOG (sourced from scripts/lib/skills.sh). skills_status_array # Build TUI globals from SKILLS_CATALOG. diff --git a/scripts/lib/skills.sh b/scripts/lib/skills.sh index d6e453bd..24292adc 100644 --- a/scripts/lib/skills.sh +++ b/scripts/lib/skills.sh @@ -3,12 +3,12 @@ # Claude Code Toolkit — Skills Catalog Loader + Detection + Install Helper (v4.5+) # Source this file. Do NOT execute it directly. # Exposes: -# skills_catalog_names — prints 24 skill names one-per-line (alpha sorted) +# skills_catalog_names — prints all catalog skill names one-per-line (alpha sorted) # is_skill_installed — returns 0 (installed) / 1 (not installed) # skills_status_array — populates TUI_INSTALLED[] for install.sh --skills branch # skills_install [--force] — copies skill from mirror to target via cp -R # Globals (write): -# SKILLS_CATALOG[] — 24 curated skill names (alpha order); populated at source time +# SKILLS_CATALOG[] — curated skill names (alpha order); populated at source time # TUI_INSTALLED[] — populated by skills_status_array (parallel to SKILLS_CATALOG) # Test seams: # TK_SKILLS_HOME — override $HOME/.claude/skills/ probe path (used by is_skill_installed) @@ -31,33 +31,75 @@ # shellcheck disable=SC2034 [[ -z "${NC:-}" ]] && NC='\033[0m' -# Curated 24-skill catalog — SKILL-01 source of truth. -# Alphabetical order. Do NOT add or remove without updating REQUIREMENTS.md SKILL-01. +# Curated skills catalog — must stay in sync with manifest.json:files.skills_marketplace. +# Alphabetical order. impeccable is an npm-installed skill (special-cased in +# _skills_description below) — not vendored under templates/skills-marketplace/. +# All other names map to a templates/skills-marketplace// mirror dir. +# Total: 63 (62 mirrored skills + impeccable). # shellcheck disable=SC2034 SKILLS_CATALOG=( + ab-testing + ad-creative + ads ai-models + ai-seo + analytics analytics-tracking + aso chrome-extension-development + churn-prevention + co-marketing + cold-email + community-marketing + competitor-profiling + competitors + content-strategy + copy-editing copywriting + cro + customer-research + directory-submissions docx + emails find-skills firecrawl + free-tools huashu-design + humanizer i18n-localization + image impeccable + launch + lead-magnets + marketing-ideas + marketing-psychology memo-skill next-best-practices notebooklm + onboarding + paywalls pdf + popups + pricing + product-marketing + programmatic-seo + referrals resend + revops + sales-enablement + schema seo-audit shadcn + signup + site-architecture + social stripe-best-practices tailwind-design-system typescript-advanced-types ui-ux-pro-max vercel-composition-patterns vercel-react-best-practices + video webapp-testing ) @@ -74,7 +116,7 @@ _skills_default_mirror_path() { echo "${TK_SKILLS_MIRROR_PATH:-${d}/../../templates/skills-marketplace}" } -# skills_catalog_names — print all 24 skill names from SKILLS_CATALOG, one per line. +# skills_catalog_names — print all skill names from SKILLS_CATALOG, one per line. skills_catalog_names() { printf '%s\n' "${SKILLS_CATALOG[@]}" } diff --git a/scripts/migrate-to-complement.sh b/scripts/migrate-to-complement.sh index 79ba0fc4..9ef0dcae 100755 --- a/scripts/migrate-to-complement.sh +++ b/scripts/migrate-to-complement.sh @@ -57,7 +57,7 @@ CYAN='\033[0;36m' NC='\033[0m' # Audit H5: TK_TOOLKIT_REF pins to a tag/SHA (default `main`). -TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.0}" +TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.1}" # Audit INF-MED-2 (2026-04-30 deep): allowlist guard — TK_TOOLKIT_REF flows # raw into curl URLs. Reject anything outside the tag/SHA charset, plus any # `..` traversal sequence. Tags / branches / SHAs do not contain `..`. diff --git a/scripts/setup-council.sh b/scripts/setup-council.sh index 6f97084e..527f7968 100644 --- a/scripts/setup-council.sh +++ b/scripts/setup-council.sh @@ -16,7 +16,7 @@ CYAN='\033[0;36m' NC='\033[0m' # Audit H5: TK_TOOLKIT_REF pins to a tag/SHA (default `main`). -TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.0}" +TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.1}" # Audit INF-MED-2 (2026-04-30 deep): allowlist guard — TK_TOOLKIT_REF flows # raw into curl URLs. Reject anything outside the tag/SHA charset, plus any # `..` traversal sequence. Tags / branches / SHAs do not contain `..`. diff --git a/scripts/setup-prompt-engineer.sh b/scripts/setup-prompt-engineer.sh index 0b2fbf5b..cb3e6039 100755 --- a/scripts/setup-prompt-engineer.sh +++ b/scripts/setup-prompt-engineer.sh @@ -18,7 +18,7 @@ NC='\033[0m' # TK_TOOLKIT_REF pins to a tag/SHA (default `main`). Mirrors setup-council.sh # to keep allowlist + curl conventions identical. -TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.0}" +TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.1}" if ! [[ "$TK_TOOLKIT_REF" =~ ^[A-Za-z0-9._/-]+$ ]] || [[ "$TK_TOOLKIT_REF" == *..* ]]; then echo "Error: TK_TOOLKIT_REF must match [A-Za-z0-9._/-]+ and must not contain '..' (got: $TK_TOOLKIT_REF)" >&2 exit 1 diff --git a/scripts/setup-security.sh b/scripts/setup-security.sh index 85b333ca..f34d3176 100755 --- a/scripts/setup-security.sh +++ b/scripts/setup-security.sh @@ -46,7 +46,7 @@ done : "${YES}" # silence shellcheck SC2034 — YES consumed by future read blocks # Audit H5: TK_TOOLKIT_REF pins to a tag/SHA (default `main`). -TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.0}" +TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.1}" # Audit INF-MED-2 (2026-04-30 deep): allowlist guard — TK_TOOLKIT_REF flows # raw into curl URLs. Reject anything outside the tag/SHA charset, plus any # `..` traversal sequence. Tags / branches / SHAs do not contain `..`. diff --git a/scripts/tests/test-install-skills.sh b/scripts/tests/test-install-skills.sh index a037989a..d4133d2a 100755 --- a/scripts/tests/test-install-skills.sh +++ b/scripts/tests/test-install-skills.sh @@ -2,16 +2,16 @@ # test-install-skills.sh — Phase 26 hermetic integration test. # # Scenarios (target ≥12 assertions across 6 scenarios): -# S1_catalog_correctness — SKILLS_CATALOG has 24 entries; alphabetical order +# S1_catalog_correctness — SKILLS_CATALOG has 63 entries; alphabetical order # S2_detection_two_state — is_skill_installed returns 0 (installed) / 1 (not installed) # S3_skills_install_basic — skills_install copies one skill from mirror to TK_SKILLS_HOME via cp -R # S4_idempotency_no_force — re-running skills_install on installed skill returns rc=2 (refused, no overwrite) # S5_force_overwrite — skills_install --force on installed skill returns rc=0 (overwritten) -# S6_install_sh_dry_run — install.sh --skills --yes --dry-run produces 24 would-install rows; zero filesystem mutations +# S6_install_sh_dry_run — install.sh --skills --yes --dry-run produces 63 would-install rows; zero filesystem mutations # # Test seam env vars: TK_SKILLS_HOME, TK_SKILLS_MIRROR_PATH, TK_TUI_TTY_SRC # -# Sample skills used in scenarios (3 of 24, per CONTEXT.md test strategy): +# Sample skills used in scenarios (3 of 63, per CONTEXT.md test strategy): # ai-models, pdf, tailwind-design-system # # Usage: bash scripts/tests/test-install-skills.sh @@ -59,17 +59,17 @@ echo "test-install-skills.sh: SKILL-03..05 hermetic suite" echo "" # ───────────────────────────────────────────────── -# S1_catalog_correctness — SKILLS_CATALOG has 24 entries; alphabetical order +# S1_catalog_correctness — SKILLS_CATALOG has 63 entries; alphabetical order # SKILL-01 # ───────────────────────────────────────────────── run_s1_catalog_correctness() { - echo " -- S1_catalog_correctness: 24 entries, alphabetical order, last is webapp-testing --" + echo " -- S1_catalog_correctness: 63 entries, alphabetical order, first ab-testing, last webapp-testing --" SKILLS_CATALOG=() # shellcheck source=/dev/null source "${REPO_ROOT}/scripts/lib/skills.sh" - assert_eq "24" "${#SKILLS_CATALOG[@]}" "S1: catalog contains 24 entries" - assert_eq "ai-models" "${SKILLS_CATALOG[0]}" "S1: alphabetical first entry is ai-models" - assert_eq "webapp-testing" "${SKILLS_CATALOG[23]}" "S1: alphabetical last entry is webapp-testing" + assert_eq "63" "${#SKILLS_CATALOG[@]}" "S1: catalog contains 63 entries" + assert_eq "ab-testing" "${SKILLS_CATALOG[0]}" "S1: alphabetical first entry is ab-testing" + assert_eq "webapp-testing" "${SKILLS_CATALOG[62]}" "S1: alphabetical last entry is webapp-testing" } # ───────────────────────────────────────────────── @@ -289,7 +289,7 @@ run_s5_force_overwrite() { } # ───────────────────────────────────────────────── -# S6_install_sh_dry_run — --skills --yes --dry-run: 24 would-install rows, zero mutations (SKILL-05) +# S6_install_sh_dry_run — --skills --yes --dry-run: 63 would-install rows, zero mutations (SKILL-05) # ───────────────────────────────────────────────── run_s6_install_sh_dry_run() { local SANDBOX @@ -313,7 +313,7 @@ run_s6_install_sh_dry_run() { local would_count would_count=$(printf '%s\n' "$output" | grep -c "would-install" || true) - assert_eq "24" "$would_count" "S6: dry-run prints 24 would-install rows" + assert_eq "63" "$would_count" "S6: dry-run prints 63 would-install rows" # Zero filesystem mutations: SKILLS_HOME should still be empty. local file_count diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index e4d6b3c3..7ee5e71e 100755 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -104,7 +104,7 @@ fi # ───────── constants + log helpers ───────── # Audit H5: TK_TOOLKIT_REF pins to a tag/SHA (default `main`). -TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.0}" +TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.1}" # Audit INF-MED-2 (2026-04-30 deep): allowlist guard — TK_TOOLKIT_REF flows # raw into curl URLs. Reject anything outside the tag/SHA charset, plus any # `..` traversal sequence. Tags / branches / SHAs do not contain `..`. diff --git a/scripts/update-claude.sh b/scripts/update-claude.sh index 7dc93520..d52990b2 100755 --- a/scripts/update-claude.sh +++ b/scripts/update-claude.sh @@ -73,7 +73,7 @@ CYAN='\033[0;36m' NC='\033[0m' # Audit H5: TK_TOOLKIT_REF pins to a tag/SHA (default `main`). -TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.0}" +TK_TOOLKIT_REF="${TK_TOOLKIT_REF:-v6.51.1}" # Audit INF-MED-2 (2026-04-30 deep): allowlist guard — TK_TOOLKIT_REF flows # raw into curl URLs. Reject anything outside the tag/SHA charset, plus any # `..` traversal sequence. Tags / branches / SHAs do not contain `..`.