feat(doctor): check the vendored external skills

lib/doctor-vendored.sh check_vendored_skills: every curl-pinned lock entry
has its files under skills-external/ (list, dict, single-path shapes),
every link.sh EXTERNAL_SKILLS name is symlinked into ~/.claude/skills when
the active profile lists it, parked names reported not failed, hints make
plugin / make link. Lock shape-validated (warn, never a traceback), profile
and item names allowlisted before becoming paths. Suite: 11 cases.
This commit is contained in:
bastien
2026-09-28 04:11:16 +02:00
parent dbcfbe9221
commit 6394fa79fc
4 changed files with 508 additions and 1 deletions
+34
View File
@@ -22,6 +22,8 @@ VERSION=$(cat "$REPO/version.txt" 2>/dev/null || echo "unknown")
source "$REPO/lib/detect-plugins.sh"
# shellcheck source=lib/gstack-playwright.sh disable=SC1091
source "$REPO/lib/gstack-playwright.sh"
# shellcheck source=lib/doctor-vendored.sh disable=SC1091
source "$REPO/lib/doctor-vendored.sh"
echo ""
echo "═══ claude-config doctor (v${VERSION}) ═══"
@@ -117,6 +119,38 @@ fi
echo ""
# ────────────────────────────────────────────────────────────
# 2b. Vendored skills (curl-pinned externals: plugins.lock.json's
# managed_by:curl entries + link.sh's EXTERNAL_SKILLS array — the OTHER
# externals the GStack section above does not cover)
# ────────────────────────────────────────────────────────────
echo "── Vendored skills ──"
# Mirrors lib/profile.sh's active_profile() (read_cache + the
# blank/"none" -> DEFAULT_PROFILE fallback) without sourcing profile.sh
# itself (its main() would run unconditionally) and without ever
# invoking `claude`.
_dv_active_profile=$(head -n1 "$REPO/.active-profile" 2>/dev/null \
| tr -d '[:space:]')
[ -z "$_dv_active_profile" ] && _dv_active_profile="none"
[ "$_dv_active_profile" = "none" ] && _dv_active_profile="full"
# .active-profile's value is spliced into a lib/profiles/ path below —
# reject anything outside the profile-name allowlist before that splice.
if ! _dv_valid_profile_name "$_dv_active_profile"; then
warn ".active-profile has invalid value \"$_dv_active_profile\" — \
falling back to profile full"
_dv_active_profile="full"
fi
_dv_profile_file="$REPO/lib/profiles/$_dv_active_profile.profile"
if [ -f "$_dv_profile_file" ]; then
check_vendored_skills "$REPO" "$HOME/.claude" "$_dv_profile_file"
else
# Active profile unresolved — every external is expected linked.
check_vendored_skills "$REPO" "$HOME/.claude"
fi
unset _dv_active_profile _dv_profile_file
echo ""
# ── Playwright browsers (read-only report; NOT nested under gstack — 2 of
# the 3 registered installs are gsd-pi, not gstack) ──
echo "── Playwright browsers ──"