From 18f8c898f8036c8367e3f82be14e111e1a79e56e Mon Sep 17 00:00:00 2001 From: bastien Date: Mon, 28 Sep 2026 14:54:52 +0200 Subject: [PATCH] feat(superpowers): vendor the 7 wired skills at v6.4.1, drop the plugin plugins.lock.json gains a superpowers entry (obra/superpowers @ 5bf4e78, path skills, per-skill file lists, always_on) that lib/vendor-skills.sh fetches byte-for-byte: brainstorming, writing-plans, subagent-driven-development, test-driven-development, requesting-code-review, using-git-worktrees, writing-skills. install-plugins STEP 8e vendors it, update-all refreshes it at the pin, link.sh links the seven, .gitignore ignores them. The plugin is no longer installed or protected: its 8 other skills duplicated personal flows and its SessionStart injection cost ~900 tokens per start, clear and compact. detect_superpowers is one file test on the linked skill; doctor and session-start stop charging the injection. doctor-vendored gains an always_on class (third lock column) so always-on externals are link-checked instead of reported parked. --- .gitignore | 23 ++++++++++ doctor.sh | 10 ++--- hooks/session-start.sh | 3 +- install-plugins.sh | 36 ++++++++------- lib/detect-plugins.sh | 12 ++--- lib/doctor-vendored.sh | 73 ++++++++++++++++++++++--------- lib/profile.sh | 14 +++--- lib/tests/doctor-vendored.test.sh | 33 +++++++++++--- lib/vendor-skills.sh | 3 ++ link.sh | 4 +- plugins.lock.json | 17 +++++++ update-all.sh | 10 +++-- 12 files changed, 170 insertions(+), 68 deletions(-) diff --git a/.gitignore b/.gitignore index aa05165..30f5f05 100644 --- a/.gitignore +++ b/.gitignore @@ -74,6 +74,15 @@ skills/scroll-scrubbed-visual-sequence skills/scroll-scrubbed-word-reveal skills/scroll-progress-timeline +# superpowers, vendored (plugins.lock.json 'superpowers') +skills/brainstorming +skills/writing-plans +skills/subagent-driven-development +skills/test-driven-development +skills/requesting-code-review +skills/using-git-worktrees +skills/writing-skills + # Impeccable — NOT a symlink: `impeccable skills install --scope=global` # writes the skill dir (and its ~15 MB engine binary) straight in through the # ~/.claude/skills symlink. Machine-owned, regenerated by make plugin/update. @@ -206,6 +215,20 @@ skills-external/scroll-scrubbed-visual-sequence/ skills-external/scroll-scrubbed-word-reveal/ skills-external/scroll-progress-timeline/ +# superpowers, vendored (plugins.lock.json 'superpowers') — machine-owned, +# curl'd at the commit pinned in plugins.lock.json by install-plugins.sh +# Step 8e (when absent) and re-fetched at the SAME commit by update-all.sh, +# through the shared lib/vendor-skills.sh helper. Not vendored: this is a +# pin, not a tracked snapshot — bump the commit deliberately to pick up an +# upstream edit. +skills-external/brainstorming/ +skills-external/writing-plans/ +skills-external/subagent-driven-development/ +skills-external/test-driven-development/ +skills-external/requesting-code-review/ +skills-external/using-git-worktrees/ +skills-external/writing-skills/ + # 21st.dev skill pack — machine-owned: `21st skills install` output, staged by # install-plugins.sh Step 8.7 (the installer refuses to write through the # ~/.claude/skills symlink, so it runs under a throwaway HOME and the skills diff --git a/doctor.sh b/doctor.sh index e0b430a..2712d1b 100644 --- a/doctor.sh +++ b/doctor.sh @@ -223,9 +223,9 @@ else fi if detect_superpowers; then - pass "Superpowers plugin detected" + pass "superpowers skills linked (brainstorming found); per-skill check under Vendored skills" else - fail "Superpowers not detected — orchestrators (/init-project, /ship-feature) will fail" + fail "superpowers skills not linked — run: make plugin && make link" fi if detect_context7; then @@ -417,10 +417,10 @@ SKILL_DESC_TOKENS=$((SKILL_DESC_CHARS / 4)) # Plugin passive cost estimates (tokens) — session-start injections and # hook prompts that never show up as a skill description above. gstack, # context7 (find-docs) and graphifyy dropped 2026-09-28 (skill-catalog -# prune): their skills sit under ~/.claude/skills and are already counted -# by the stats above — a separate constant here double-counted them. +# prune); superpowers dropped the same day (tier 2, vendored instead): +# their skills sit under ~/.claude/skills and are already counted by the +# stats above — a separate constant here double-counted them. PLUGIN_TOKENS=0 -if detect_superpowers 2>/dev/null; then PLUGIN_TOKENS=$((PLUGIN_TOKENS + 1500)); fi if detect_uiux_pro_max 2>/dev/null; then PLUGIN_TOKENS=$((PLUGIN_TOKENS + 670)); fi TOTAL_TOKENS=$((CLAUDE_MD_TOKENS + SKILL_DESC_TOKENS + PLUGIN_TOKENS)) diff --git a/hooks/session-start.sh b/hooks/session-start.sh index 4bc1c2e..3ab0237 100644 --- a/hooks/session-start.sh +++ b/hooks/session-start.sh @@ -118,8 +118,9 @@ esac # Quick passive token cost estimate # Only count plugins that are ACTIVE (detected as ON), not just installed +# superpowers dropped 2026-09-28 (tier 2 of the skill-catalog prune): its +# 7 vendored skills are counted by the skill catalog, not a plugin cost. _passive_t=0 -detect_superpowers 2>/dev/null && _passive_t=$((_passive_t + 800)) # Token costs for toggle plugins — map display name to cost declare -A _plugin_costs=( diff --git a/install-plugins.sh b/install-plugins.sh index e9dfc67..5e2a0a0 100644 --- a/install-plugins.sh +++ b/install-plugins.sh @@ -487,8 +487,8 @@ install_plugin() { # copies the plugin into ~/.claude/plugins/cache — it does NOT register # it in settings.json's enabledPlugins map. Without an explicit enable, # the plugin sits dormant. Use this for plugins that should be ALWAYS ON -# (security-guidance, superpowers). Idempotent: skips if already -# present in enabledPlugins. +# (security-guidance). Idempotent: skips if already present in +# enabledPlugins. enable_plugin() { local name="$1" local source="$2" @@ -531,13 +531,10 @@ install_plugin "pr-review-toolkit" "claude-code-plugins" echo "" -# Superpowers (always on) -info "Adding Superpowers marketplace..." -claude plugin marketplace add obra/superpowers-marketplace 2>/dev/null || true -install_plugin "superpowers" "superpowers-marketplace" -enable_plugin "superpowers" "superpowers-marketplace" - -echo "" +# Superpowers plugin removed 2026-09-28 (tier 2 of the skill-catalog prune): +# its 7 wired skills are vendored in Step 8e (plugins.lock.json +# 'superpowers'); a still-cached plugin is uninstalled by hand once +# (claude plugin uninstall superpowers@superpowers-marketplace), never here # UI/UX Pro Max (toggle) info "Adding UI/UX Pro Max marketplace..." @@ -909,21 +906,25 @@ fi echo "" # ── Step 8e: Agent Skills (addyosmani/agent-skills) + Mengto scroll -# skills (MengTo/Skills) — both commit-pinned, vendored the emil-design-eng -# way (curl → skills-external//, symlinked by link.sh) through the -# shared lib/vendor-skills.sh helper. Shas/paths/file-lists live in -# plugins.lock.json ("agent-skills" / "mengto-skills" entries), never -# hardcoded here. -echo "── Step 8e: Agent Skills + Mengto scroll skills (pinned commit) ──" +# skills (MengTo/Skills) + superpowers (obra/superpowers) — all +# commit-pinned, vendored the emil-design-eng way (curl → +# skills-external//, symlinked by link.sh) through the shared +# lib/vendor-skills.sh helper. Shas/paths/file-lists live in +# plugins.lock.json ("agent-skills" / "mengto-skills" / "superpowers" +# entries), never hardcoded here. +echo "── Step 8e: Agent Skills + Mengto scroll skills + superpowers (pinned commit) ──" echo "" # shellcheck source=lib/vendor-skills.sh disable=SC1091 source "$REPO/lib/vendor-skills.sh" EXT_SKILL_NAMES=(observability-and-instrumentation deprecation-and-migration ci-cd-and-automation scroll-world-storytelling build-threejs-scroll-worlds scroll-scrubbed-visual-sequence scroll-scrubbed-word-reveal - scroll-progress-timeline) + scroll-progress-timeline brainstorming writing-plans + subagent-driven-development test-driven-development + requesting-code-review using-git-worktrees writing-skills) vendor_pinned_skills agent-skills vendor_pinned_skills mengto-skills +vendor_pinned_skills superpowers for _ext_skill in "${EXT_SKILL_NAMES[@]}"; do if [ -L "$HOME/.claude/skills/$_ext_skill" ]; then ok "$_ext_skill symlink OK" @@ -1207,7 +1208,7 @@ echo "" echo " ALWAYS ON (installed at user scope):" echo " ✅ security-guidance — regex hints on Edit/Write + out-of-band LLM reviews on commit/push (Stop review off via ENABLE_STOP_REVIEW=0; quota, not context) [claude-code-plugins]" echo " ✅ rtk — token compression hook (0 tokens)" -echo " ✅ superpowers — brainstorm/plan/implement/debug workflow" +echo " ✅ superpowers skills — 7 vendored (brainstorming, writing-plans, subagent-driven-development, test-driven-development, requesting-code-review, using-git-worktrees, writing-skills), pinned v6.4.1, curl → symlink, no plugin, no session injection" echo "" echo " TOGGLE (plugin state = settings.json enabledPlugins; skills/CLIs = profiles):" echo " 🔄 gstack — disabled by default (toggle: lib/toggle-external.sh enable gstack)" @@ -1232,6 +1233,7 @@ echo " Frontend Design at: ~/.claude/skills/frontend-design/ (symlink → skill echo " Design Motion Principles at: ~/.claude/skills/design-motion-principles/ (symlink → skills-external)" echo " Agent Skills trio at: ~/.claude/skills/{observability-and-instrumentation,deprecation-and-migration,ci-cd-and-automation}/ (symlink → skills-external)" echo " Mengto scroll skills at: ~/.claude/skills/{scroll-world-storytelling,build-threejs-scroll-worlds,scroll-scrubbed-visual-sequence,scroll-scrubbed-word-reveal,scroll-progress-timeline}/ (symlink → skills-external)" +echo " Superpowers skills at: ~/.claude/skills/{brainstorming,writing-plans,subagent-driven-development,test-driven-development,requesting-code-review,using-git-worktrees,writing-skills}/ (symlink → skills-external)" echo " npx skills at: ~/.agents/skills/ (symlinked into ~/.claude/skills/)" echo "" echo " → Restart Claude Code — plugins load automatically" diff --git a/lib/detect-plugins.sh b/lib/detect-plugins.sh index 638904c..6707450 100644 --- a/lib/detect-plugins.sh +++ b/lib/detect-plugins.sh @@ -16,14 +16,10 @@ detect_rtk() { } detect_superpowers() { - # Fast check: filesystem (plugin cache) - local cache_dir="$HOME/.claude/plugins/cache" - if [ -d "$cache_dir" ]; then - compgen -G "$cache_dir"/*superpowers* &>/dev/null && return 0 - fi - # Slow fallback: CLI (only if fast check fails) - claude plugin list 2>/dev/null | grep -qi "superpowers" && return 0 - return 1 + # superpowers = 7 vendored skills since 2026-09-28; the plugin is gone. + # One file test on the linked vendored skill: proves vendored AND + # linked in one shot — no plugin cache glob, no `claude plugin list`. + [ -f "$HOME/.claude/skills/brainstorming/SKILL.md" ] } diff --git a/lib/doctor-vendored.sh b/lib/doctor-vendored.sh index 6cd9602..acbfcf5 100644 --- a/lib/doctor-vendored.sh +++ b/lib/doctor-vendored.sh @@ -5,8 +5,8 @@ # EXTERNAL_SKILLS array). doctor.sh's "GStack submodule" section only # covers the gstack submodule — this covers the OTHER external skill # packs (emil-design-eng, the agent-skills trio, the five Mengto scroll -# skills, and any name link.sh links with no lock entry at all, e.g. -# frontend-design, design-motion-principles). +# skills, the seven superpowers skills, and any name link.sh links with +# no lock entry at all, e.g. frontend-design, design-motion-principles). # # One entry point, `check_vendored_skills # [profile_file]`, sourced and called by doctor.sh. Two things checked @@ -21,7 +21,9 @@ # is passed — the "could not resolve the active profile" case), # the /skills/ symlink points at # /skills-external/. A name absent from the profile is -# reported parked, not failed. +# reported parked, not failed — unless its lock entry is +# "always_on": true (the superpowers entry is), in which case the +# symlink is checked regardless of the profile (see _dv_check_link). # # Lock parsing via python3 argv (never string-spliced) — same pattern as # lib/vendor-skills.sh's _vendor_read_lock. link.sh's EXTERNAL_SKILLS @@ -61,11 +63,14 @@ fi # _dv_lock_expectations — prints "\t" for every # skill named under a plugins.lock.json entry whose "managed_by" is -# "curl": a bare list defaults each name to ["SKILL.md"]; a dict names -# its own per-skill file list; an entry with neither (the -# emil-design-eng single-file "path" shape) is itself the skill name, -# file "SKILL.md" (the literal "path" value is upstream layout, not the -# local dest — never used here). Reads the lockfile via argv only. +# "curl", plus a THIRD column "\t1" when that entry is "always_on": true +# (the superpowers entry is) — read by _dv_is_always_on, ignored by the +# $1==n {print $2} awk in _dv_check_files: a bare list defaults each name +# to ["SKILL.md"]; a dict names its own per-skill file list; an entry +# with neither (the emil-design-eng single-file "path" shape) is itself +# the skill name, file "SKILL.md" (the literal "path" value is upstream +# layout, not the local dest — never used here). Reads the lockfile via +# argv only. # Every curl-managed entry's shape is validated ("skills" null, a list # of str, or a dict of str -> list of str; "path" a str when present) # BEFORE it is used, so a malformed entry is the same clean failure as @@ -118,12 +123,13 @@ for key, entry in data.items(): sys.exit(1) if not valid_skills(skills): sys.exit(1) + suffix = "\t1" if entry.get("always_on") is True else "" if skills is None: - print(f"{key}\tSKILL.md") + print(f"{key}\tSKILL.md{suffix}") continue for name, files in skill_files(skills).items(): for file in files: - print(f"{name}\t{file}") + print(f"{name}\t{file}{suffix}") PY } @@ -196,16 +202,30 @@ allowlist — skipped" [ "$all_ok" -eq 1 ] } -# _dv_check_link — when -# is non-empty and does not list , reports it -# parked (info), not failed. Otherwise (listed, or no was -# passed — active profile could not be resolved, every external is then -# expected linked) checks the /skills/ symlink points -# at /skills-external/. +# _dv_is_always_on — true when (the +# "\t[\t1]" lines from _dv_lock_expectations) carries the +# always_on third column for 's lock entry. +_dv_is_always_on() { + local name="$1" lock_out="$2" + awk -F'\t' -v n="$name" '$1 == n && $3 == 1 { found=1 } \ + END { exit !found }' <<< "$lock_out" +} + +# _dv_check_link — +# when is "1" (the name's lock entry is "always_on": true), +# the symlink is checked whatever says — never parked. +# Otherwise, when is non-empty and does not list , +# reports it parked (info), not failed. Otherwise (listed, always_on, or +# no was passed — active profile could not be resolved, +# every external is then expected linked) checks the +# /skills/ symlink points at +# /skills-external/. _dv_check_link() { - local claude_home="$1" repo="$2" name="$3" profile_file="$4" + local claude_home="$1" repo="$2" name="$3" profile_file="$4" \ + always_on="$5" local link target label - if [ -n "$profile_file" ] && ! _dv_profile_has "$profile_file" "$name"; then + if [ "$always_on" != "1" ] && [ -n "$profile_file" ] \ + && ! _dv_profile_has "$profile_file" "$name"; then label="$(basename "$profile_file" .profile)" info "$name: parked by profile $label" return @@ -220,6 +240,20 @@ lib/profile.sh apply )" fi } +# _dv_check_name — +# per-name dispatch for check_vendored_skills's loop: files first (the +# link check runs only when every expected file is present, same as +# before), then the symlink, passing _dv_is_always_on's verdict as +# _dv_check_link's 5th param. +_dv_check_name() { + local repo="$1" claude_home="$2" name="$3" profile_file="$4" lock_out="$5" + local always_on="" + _dv_is_always_on "$name" "$lock_out" && always_on=1 + _dv_check_files "$repo" "$name" "$lock_out" \ + && _dv_check_link "$claude_home" "$repo" "$name" "$profile_file" \ + "$always_on" +} + # check_vendored_skills [profile_file] — see the # file header. Either the lock or link.sh being unreadable (or a # malformed lock entry — _dv_lock_expectations rc 1) is a warn, never a @@ -251,7 +285,6 @@ check skipped" item-name allowlist — skipped" continue fi - _dv_check_files "$repo" "$name" "$lock_out" \ - && _dv_check_link "$claude_home" "$repo" "$name" "$profile_file" + _dv_check_name "$repo" "$claude_home" "$name" "$profile_file" "$lock_out" done <<< "$names" } diff --git a/lib/profile.sh b/lib/profile.sh index f4d0618..8dbb0d5 100755 --- a/lib/profile.sh +++ b/lib/profile.sh @@ -18,8 +18,10 @@ # and MCPs in the MANAGED_* allowlists are disabled when the profile # does not list them — nothing outside those lists is ever auto-toggled. # -# Always-on plugins (never toggled by `set`): security-guidance, -# superpowers + rtk hook + .claude internal. The script refuses to disable +# Always-on plugins (never toggled by `set`): security-guidance + rtk +# hook + .claude internal. superpowers is vendored skills now, not a +# plugin (never in PROTECTED_PLUGINS, never in MANAGED_EXTERNALS — same +# always-on class as darwin-skill). The script refuses to disable # anything in PROTECTED_PLUGINS. # # Usage: @@ -61,9 +63,10 @@ DEFAULT_PROFILE="full" # profile in force when none is selected (cache absent, source "$(dirname "${BASH_SOURCE[0]}")/gstack-removed.sh" # Plugins that are toggle-managed by `set`. Anything NOT in this list is -# never auto-disabled — protects always-on plugins (security-guidance, -# superpowers) and unrelated user plugins. Add a plugin here only when its -# enabled state is meaningfully driven by task type. +# never auto-disabled — protects always-on plugins (security-guidance; +# superpowers is vendored skills now, not a plugin) and unrelated user +# plugins. Add a plugin here only when its enabled state is meaningfully +# driven by task type. MANAGED_PLUGINS=( "ui-ux-pro-max@ui-ux-pro-max-skill" "plugin-dev@claude-code-plugins" @@ -106,7 +109,6 @@ MANAGED_MCPS=() # MANAGED_PLUGINS allowlist.) PROTECTED_PLUGINS=( "security-guidance@claude-code-plugins" - "superpowers@superpowers-marketplace" ) GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; BLUE='\033[0;34m'; NC='\033[0m' diff --git a/lib/tests/doctor-vendored.test.sh b/lib/tests/doctor-vendored.test.sh index 7ee2006..639f079 100644 --- a/lib/tests/doctor-vendored.test.sh +++ b/lib/tests/doctor-vendored.test.sh @@ -17,9 +17,11 @@ # "skills" is neither null/list/dict degrading the same way with no # Python traceback leaking (LOCK_MALFORMED_ENTRY, rc 0), the # profile-name allowlist rejecting a path-traversal value -# (REJECTS_BAD_PROFILE_NAME), and the item-name allowlist rejecting a +# (REJECTS_BAD_PROFILE_NAME), the item-name allowlist rejecting a # link.sh entry with a ".." segment — warned and skipped, not failed -# (REJECTS_BAD_NAME). +# (REJECTS_BAD_NAME), and an "always_on": true lock entry's name, absent +# from the profile and with no symlink, checked (and failed) instead of +# reported parked (ALWAYS_ON_LINK_CHECKED). set -u ROOT="$(cd "$(dirname "$0")/../.." && pwd)" LIB="$ROOT/lib/doctor-vendored.sh" @@ -57,6 +59,11 @@ cat > "$REPO/plugins.lock.json" <<'JSON' "dict-entry": { "managed_by": "curl", "skills": {"dict-skill": ["SKILL.md", "references/notes.md"]} + }, + "always-on-entry": { + "managed_by": "curl", + "always_on": true, + "skills": ["always-on-skill"] } } JSON @@ -66,25 +73,27 @@ cat > "$REPO/link.sh" <<'SH' #!/usr/bin/env bash EXTERNAL_SKILLS=(ok-skill missing-skill dict-skill active-nolink-skill active-wronglink-skill - parked-skill noprofile-skill) + parked-skill noprofile-skill always-on-skill) SH # ── skills-external/ tree: every name's SKILL.md present, except # missing-skill (nothing at all) and dict-skill's references/notes.md. +# always-on-skill has its SKILL.md too — only its symlink is missing. for n in ok-skill dict-skill active-nolink-skill active-wronglink-skill \ - parked-skill noprofile-skill; do + parked-skill noprofile-skill always-on-skill; do mkdir -p "$REPO/skills-external/$n" echo "v1" > "$REPO/skills-external/$n/SKILL.md" done # ── claude_home symlinks: ok-skill correct, active-wronglink-skill -# points elsewhere, active-nolink-skill and noprofile-skill have none. +# points elsewhere, active-nolink-skill, noprofile-skill and +# always-on-skill have none. ln -sf "$REPO/skills-external/ok-skill" "$CLAUDE_HOME/skills/ok-skill" mkdir -p "$WORK/elsewhere" ln -sf "$WORK/elsewhere" "$CLAUDE_HOME/skills/active-wronglink-skill" -# ── active.profile: lists everything EXCEPT parked-skill and -# noprofile-skill (both proven absent from it). +# ── active.profile: lists everything EXCEPT parked-skill, +# noprofile-skill and always-on-skill (all three proven absent from it). cat > "$REPO/active.profile" <<'PROF' # DESC: fixture profile ok-skill external @@ -132,6 +141,16 @@ check_bool SYMLINK_PARKED \ grep -qF 'parked-skill: symlink missing/wrong' \ && echo 1 || echo 0)" +# ── always-on-skill: absent from active.profile (same as parked-skill) +# but its lock entry is "always_on": true — checked (and failed, no +# symlink) instead of reported parked. +check_bool ALWAYS_ON_LINK_CHECKED \ + "$(printf '%s' "$out1" | \ + grep -qF 'always-on-skill: symlink missing/wrong' \ + && ! printf '%s' "$out1" | \ + grep -qF 'always-on-skill: parked by profile' \ + && echo 1 || echo 0)" + # ── No profile file passed at all: noprofile-skill (absent from # active.profile, parked above) must now be treated as expected-linked. out2="$(check_vendored_skills "$REPO" "$CLAUDE_HOME" 2>&1)" diff --git a/lib/vendor-skills.sh b/lib/vendor-skills.sh index 8880703..72f4af7 100644 --- a/lib/vendor-skills.sh +++ b/lib/vendor-skills.sh @@ -18,6 +18,9 @@ # `skills` as a bare list defaults every named skill to `["SKILL.md"]` and # `path` to "skills" (the agent-skills shape); `skills` as a dict carries an # explicit per-skill file list (references/*, etc.) and `path` is required. +# `"always_on": true` (optional) is ignored by this helper (fetch is the +# same either way) — lib/doctor-vendored.sh reads it to expect the +# entry's skills linked regardless of the active profile. # # Raw URL: https://raw.githubusercontent.com///// # /. VENDOR_BASE_URL overrides the "https://…/" prefix diff --git a/link.sh b/link.sh index 3da8d76..57abf20 100644 --- a/link.sh +++ b/link.sh @@ -79,7 +79,9 @@ EXTERNAL_SKILLS=(emil-design-eng frontend-design design-motion-principles observability-and-instrumentation deprecation-and-migration ci-cd-and-automation scroll-world-storytelling build-threejs-scroll-worlds scroll-scrubbed-visual-sequence scroll-scrubbed-word-reveal - scroll-progress-timeline) + scroll-progress-timeline brainstorming writing-plans + subagent-driven-development test-driven-development + requesting-code-review using-git-worktrees writing-skills) for _ext_skill in "${EXTERNAL_SKILLS[@]}"; do if [ -d "$REPO/skills-external/$_ext_skill" ]; then if [ -L "$CLAUDE/skills/$_ext_skill" ] && [ "$(readlink "$CLAUDE/skills/$_ext_skill")" = "$REPO/skills-external/$_ext_skill" ]; then diff --git a/plugins.lock.json b/plugins.lock.json index 07b34b4..ecc14fb 100644 --- a/plugins.lock.json +++ b/plugins.lock.json @@ -64,6 +64,23 @@ "managed_by": "curl", "note": "Five scroll-choreography skills from MengTo/Skills (agent-skills/web-design), vendored the agent-skills way but with an explicit per-skill file list (SKILL.md + REFERENCES.md, or references/*.md + references/scroll-conductor.js for build-threejs-scroll-worlds) instead of the SKILL.md-only default. Never vendored: demo/, agents/, or any binary asset upstream ships alongside each skill. Text-only, byte-for-byte copies (Codex-isms in the source text stay). Bump the commit deliberately to pick up an upstream edit; install-plugins.sh Step 8e and update-all.sh 7.3 both read it from here via lib/vendor-skills.sh's vendor_pinned_skills(), never hardcoded." }, + "superpowers": { + "source": "https://github.com/obra/superpowers", + "commit": "5bf4e78011075bcfc0dc295f0724994cd123ee71", + "path": "skills", + "skills": { + "brainstorming": ["SKILL.md", "spec-document-reviewer-prompt.md", "visual-companion.md", "scripts/frame-template.html", "scripts/helper.js", "scripts/server.cjs", "scripts/start-server.sh", "scripts/stop-server.sh"], + "writing-plans": ["SKILL.md", "plan-document-reviewer-prompt.md"], + "subagent-driven-development": ["SKILL.md", "implementer-prompt.md", "re-review-prompt.md", "task-reviewer-prompt.md", "scripts/review-package", "scripts/sdd-workspace", "scripts/task-brief"], + "test-driven-development": ["SKILL.md", "writing-good-tests.md"], + "requesting-code-review": ["SKILL.md", "code-reviewer.md"], + "using-git-worktrees": ["SKILL.md"], + "writing-skills": ["SKILL.md", "anthropic-best-practices.md", "examples/CLAUDE_MD_TESTING.md", "graphviz-conventions.dot", "persuasion-principles.md", "render-graphs.js", "testing-skills-with-subagents.md"] + }, + "managed_by": "curl", + "always_on": true, + "note": "Seven superpowers skills vendored byte-for-byte at the v6.4.1 tag commit (obra/superpowers), always on (no profile lists them). Bump the commit deliberately. Scripts inside run as `bash scripts/`, no exec bit needed. Upstream cross-references to the plugin prefix and to the 8 non-vendored skills stay in the text; CLAUDE.global.md Skill routing maps them." + }, "impeccable": { "source": "npm:impeccable", "version": "4.1.0", diff --git a/update-all.sh b/update-all.sh index 5929c9b..bc9f24f 100644 --- a/update-all.sh +++ b/update-all.sh @@ -377,9 +377,10 @@ else info "design-motion-principles not installed — skipping" fi -# ── 7.3. Update Agent Skills + Mengto scroll skills (pinned commit) ── -# Both re-fetched at the SAME pinned commit (never advances the pin) via -# the shared lib/vendor-skills.sh helper — see install-plugins.sh Step 8e. +# ── 7.3. Update Agent Skills + Mengto scroll skills + superpowers +# (pinned commit) — all three re-fetched at the SAME pinned commit +# (never advances the pin) via the shared lib/vendor-skills.sh helper — +# see install-plugins.sh Step 8e. echo "" echo "── Updating Agent Skills (addyosmani/agent-skills)..." # shellcheck source=lib/vendor-skills.sh disable=SC1091 @@ -388,6 +389,9 @@ vendor_pinned_skills agent-skills refresh echo "" echo "── Updating Mengto scroll skills (MengTo/Skills)..." vendor_pinned_skills mengto-skills refresh +echo "" +echo "── Updating superpowers skills (obra/superpowers)..." +vendor_pinned_skills superpowers refresh # ── Impeccable (design detector + skill + subagents) ── # Global scope: the installer writes through the ~/.claude/{skills,agents}