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.
This commit is contained in:
bastien
2026-09-28 14:54:52 +02:00
parent c39c0e1045
commit 18f8c898f8
12 changed files with 170 additions and 68 deletions
+53 -20
View File
@@ -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 <repo> <claude_home>
# [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 <claude_home>/skills/<name> symlink points at
# <repo>/skills-external/<name>. 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 <lockfile> — prints "<name>\t<file>" 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 <claude_home> <repo> <name> <profile_file> — when
# <profile_file> is non-empty and does not list <name>, reports it
# parked (info), not failed. Otherwise (listed, or no <profile_file> was
# passed — active profile could not be resolved, every external is then
# expected linked) checks the <claude_home>/skills/<name> symlink points
# at <repo>/skills-external/<name>.
# _dv_is_always_on <name> <lock_out> — true when <lock_out> (the
# "<name>\t<file>[\t1]" lines from _dv_lock_expectations) carries the
# always_on third column for <name>'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 <claude_home> <repo> <name> <profile_file> <always_on> —
# when <always_on> is "1" (the name's lock entry is "always_on": true),
# the symlink is checked whatever <profile_file> says — never parked.
# Otherwise, when <profile_file> is non-empty and does not list <name>,
# reports it parked (info), not failed. Otherwise (listed, always_on, or
# no <profile_file> was passed — active profile could not be resolved,
# every external is then expected linked) checks the
# <claude_home>/skills/<name> symlink points at
# <repo>/skills-external/<name>.
_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 <profile>)"
fi
}
# _dv_check_name <repo> <claude_home> <name> <profile_file> <lock_out> —
# 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 <repo> <claude_home> [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"
}