Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2afb35d1d | ||
|
|
ad17a7c6c0 |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "skills",
|
||||
"description": "Mathias's engineering skills library, plus the hooks and MCP servers that make it enforceable: TDD, clean code, debugging, specs, discovery, CI, and secret hygiene.",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.5",
|
||||
"author": {
|
||||
"name": "Mathias",
|
||||
"url": "https://git.d-ma.be/mathias"
|
||||
|
||||
+55
-2
@@ -180,10 +180,63 @@ if [ -f "$INSTALLED" ]; then
|
||||
|| add WARN plugin "skills@mathias is not installed for Claude Code — /plugin marketplace add https://git.d-ma.be/mathias/skills.git"
|
||||
fi
|
||||
|
||||
# --- Claude Code: which GENERATION of the plugin is installed ---------------
|
||||
# Every check above is about symlink paths, which is the wrong shape for the
|
||||
# plugin: it is the only channel Claude Code has, and Claude Code gates updates
|
||||
# on plugin.json's version. A host that never picked up a release loads all the
|
||||
# skills successfully and is simply a generation behind — silently. Found on
|
||||
# koala 2026-08-29: installed 0.6.0, marketplace clone 0.7.0, repo 0.8.5,
|
||||
# doctor said "clean" (#30).
|
||||
#
|
||||
# Offline by construction, like the rest of doctor: "available" means the
|
||||
# newest manifest already on this host — the active checkout and any
|
||||
# marketplace clone — never a fetch.
|
||||
manifest_version() {
|
||||
[ -f "$1" ] || return 1
|
||||
grep -q '"name"[[:space:]]*:[[:space:]]*"skills"' "$1" || return 1
|
||||
sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$1" | head -1
|
||||
}
|
||||
|
||||
# newer_version a b — echoes whichever sorts higher on major.minor.patch.
|
||||
newer_version() {
|
||||
printf '%s\n%s\n' "$1" "$2" | awk -F. '
|
||||
{ raw[NR] = $0; for (i = 1; i <= 3; i++) n[NR, i] = ($i == "" ? 0 : $i + 0) }
|
||||
END {
|
||||
for (i = 1; i <= 3; i++) {
|
||||
if (n[1, i] > n[2, i]) { print raw[1]; exit }
|
||||
if (n[1, i] < n[2, i]) { print raw[2]; exit }
|
||||
}
|
||||
print raw[1]
|
||||
}'
|
||||
}
|
||||
|
||||
installed_v=''
|
||||
if [ -f "$INSTALLED" ]; then
|
||||
installed_v=$(sed -n '/"skills@mathias"/,/\]/p' "$INSTALLED" \
|
||||
| sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
||||
fi
|
||||
|
||||
available_v=''
|
||||
for manifest in "$CHECKOUT/.claude-plugin/plugin.json" \
|
||||
"$HOME"/.claude/plugins/marketplaces/*/.claude-plugin/plugin.json
|
||||
do
|
||||
v=$(manifest_version "$manifest") || continue
|
||||
[ -n "$v" ] || continue
|
||||
if [ -z "$available_v" ]; then
|
||||
available_v=$v
|
||||
else
|
||||
available_v=$(newer_version "$available_v" "$v")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$installed_v" ] && [ -n "$available_v" ] && [ "$installed_v" != "$available_v" ]; then
|
||||
add FAIL plugin-version "Claude Code has skills@mathias $installed_v installed but $available_v is available on this host — /plugin update skills@mathias (a host stale enough to matter is running the old doctor, so the first detection may need this run by hand)"
|
||||
fi
|
||||
|
||||
# --- output -----------------------------------------------------------------
|
||||
if [ "$JSON" -eq 1 ]; then
|
||||
printf '{"checkout":"%s","expected":%s,"findings":[%s]}\n' \
|
||||
"$CHECKOUT" "$EXPECTED" "${report%,}"
|
||||
printf '{"checkout":"%s","expected":%s,"plugin":{"installed":"%s","available":"%s"},"findings":[%s]}\n' \
|
||||
"$CHECKOUT" "$EXPECTED" "$installed_v" "$available_v" "${report%,}"
|
||||
elif [ "$findings" -gt 0 ]; then
|
||||
printf 'skills doctor — %s finding(s), checkout %s\n\n%s\n' \
|
||||
"$findings" "$CHECKOUT" "$report"
|
||||
|
||||
@@ -133,5 +133,63 @@ mkdir -p "$f/home/.claude/skills"
|
||||
ln -sfn "$f/ck/skills/vanished" "$f/home/.claude/skills/vanished"
|
||||
assert_fails "$f" 'dangling' 'dangling link inside a harness dir is reported'
|
||||
|
||||
# --- 8. Claude Code plugin pinned to an older version than is available -----
|
||||
# The plugin is the ONLY delivery channel for Claude Code, and Claude Code
|
||||
# gates updates on plugin.json's version field. A host that never picked the
|
||||
# new one up loads every skill successfully — just the wrong generation. Found
|
||||
# live on koala 2026-08-29: installed 0.6.0, marketplace 0.7.0, repo 0.8.5,
|
||||
# and doctor said "clean" (#30).
|
||||
|
||||
# installed_state <fixture> <version> — the Claude Code install record.
|
||||
installed_state() {
|
||||
mkdir -p "$1/home/.claude/plugins"
|
||||
cat > "$1/home/.claude/plugins/installed_plugins.json" <<JSON
|
||||
{
|
||||
"version": 2,
|
||||
"plugins": {
|
||||
"skills@mathias": [
|
||||
{
|
||||
"scope": "user",
|
||||
"installPath": "/somewhere/$2",
|
||||
"version": "$2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
JSON
|
||||
}
|
||||
|
||||
# manifest <dir> <version> — a .claude-plugin/plugin.json under <dir>.
|
||||
manifest() {
|
||||
mkdir -p "$1/.claude-plugin"
|
||||
printf '{\n "name": "skills",\n "version": "%s"\n}\n' "$2" > "$1/.claude-plugin/plugin.json"
|
||||
}
|
||||
|
||||
f=$(new_fixture pluginmatch); wire_clean "$f"
|
||||
installed_state "$f" 0.8.0
|
||||
manifest "$f/ck" 0.8.0
|
||||
assert_clean "$f" 'plugin on the current version stays silent'
|
||||
|
||||
f=$(new_fixture pluginstale); wire_clean "$f"
|
||||
installed_state "$f" 0.7.0
|
||||
manifest "$f/ck" 0.8.0
|
||||
assert_fails "$f" '0.7.0' 'stale plugin version is reported'
|
||||
assert_fails "$f" '0.8.0' 'stale plugin report names the available version'
|
||||
|
||||
# A host that only uses the symlink path has no install record at all. That is
|
||||
# a valid configuration and must not fail.
|
||||
f=$(new_fixture pluginabsent); wire_clean "$f"
|
||||
manifest "$f/ck" 0.8.0
|
||||
assert_clean "$f" 'no Claude Code install record is not a fault'
|
||||
|
||||
# The marketplace clone is what Claude Code compares against, so a newer
|
||||
# version there means an update is waiting even when the local checkout agrees
|
||||
# with what is installed.
|
||||
f=$(new_fixture pluginmarket); wire_clean "$f"
|
||||
installed_state "$f" 0.7.0
|
||||
manifest "$f/ck" 0.7.0
|
||||
manifest "$f/home/.claude/plugins/marketplaces/mathias" 0.9.0
|
||||
assert_fails "$f" '0.9.0' 'a newer marketplace clone is reported'
|
||||
|
||||
printf '\ndoctor: %d passed, %d failed\n' "$pass" "$fail"
|
||||
[ "$fail" -eq 0 ]
|
||||
|
||||
Reference in New Issue
Block a user