-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathidstack-doctor
More file actions
executable file
·182 lines (169 loc) · 6.09 KB
/
Copy pathidstack-doctor
File metadata and controls
executable file
·182 lines (169 loc) · 6.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/usr/bin/env bash
# idstack install doctor — diagnose plugin install + legacy conflicts.
#
# Answers: "is /idstack:<skill> going to work, and if not, exactly what
# do I run?" without the user having to know about smoke-test.
#
# Usage:
# idstack-doctor # check user-scope install
# idstack-doctor --local # also check project-scope legacy paths
#
# Exit code: 0 if all green, 1 if any problem is detected.
set -u
# This script lives at <repo>/bin/idstack-doctor — resolve the repo root from
# its own location so the diagnosis works regardless of where the repo sits.
IDSTACK_DIR="$(cd "$(dirname "$0")/.." && pwd -P)"
SCOPE="global"
LEGACY_BASE="$HOME/.claude"
# Match --local in any position, not just $1. Robust if other flags get added.
if [[ " ${*:-} " == *" --local "* ]]; then
SCOPE="local"
LEGACY_BASE="$(pwd)/.claude"
fi
LEGACY_SKILLS_DIR="$LEGACY_BASE/skills"
LEGACY_DIR="$LEGACY_SKILLS_DIR/idstack"
PROBLEMS=0
note_problem() { PROBLEMS=$((PROBLEMS + 1)); }
SKILLS="needs-analysis learning-objectives course-quality-review course-import \
assessment-design course-builder course-export accessibility-review red-team \
pipeline learn"
echo "idstack doctor ($SCOPE)"
echo " repo: $IDSTACK_DIR"
echo ""
# 1. Plugin + marketplace manifests in the repo
echo "Plugin manifests:"
plugin_manifest="$IDSTACK_DIR/.claude-plugin/plugin.json"
market_manifest="$IDSTACK_DIR/.claude-plugin/marketplace.json"
if [ -f "$plugin_manifest" ]; then
version=$(grep -o '"version": *"[^"]*"' "$plugin_manifest" | head -n1 | sed 's/.*"\([^"]*\)"$/\1/')
if [ -n "$version" ]; then
echo " plugin.json present (version $version)"
else
echo " PROBLEM: could not parse version from $plugin_manifest"
note_problem
fi
else
echo " PROBLEM: missing $plugin_manifest"
note_problem
fi
if [ -f "$market_manifest" ]; then
echo " marketplace.json present"
else
echo " PROBLEM: missing $market_manifest"
echo " Claude Code installs plugins through a marketplace manifest;"
echo " without it, ./setup cannot register the plugin."
note_problem
fi
echo ""
# 2. Skill files reachable in the repo
echo "Skill files:"
missing_skills=0
for skill in $SKILLS; do
if [ ! -f "$IDSTACK_DIR/skills/$skill/SKILL.md" ]; then
echo " MISSING: skills/$skill/SKILL.md"
missing_skills=$((missing_skills + 1))
fi
done
if [ "$missing_skills" = "0" ]; then
echo " all 11 SKILL.md files present"
else
echo " PROBLEM: $missing_skills SKILL.md file(s) missing under skills/"
note_problem
fi
echo ""
# 3. Claude Code install state — the marketplace flow records the plugin in
# Claude Code's own registry; a bare symlink is not enough on current versions.
echo "Claude Code install:"
if command -v claude >/dev/null 2>&1; then
plugin_list=$(claude plugin list 2>/dev/null || true)
if echo "$plugin_list" | grep -q "idstack@idstack"; then
if echo "$plugin_list" | grep -A4 "idstack@idstack" | grep -qi "enabled"; then
echo " idstack@idstack installed and enabled"
else
echo " PROBLEM: idstack@idstack is installed but not enabled."
echo " Fix: claude plugin enable idstack@idstack"
note_problem
fi
else
echo " PROBLEM: idstack@idstack is not installed."
echo " Fix: run ./setup from the repo, or manually:"
echo " claude plugin marketplace add \"$IDSTACK_DIR\""
echo " claude plugin install idstack@idstack"
note_problem
fi
else
echo " WARNING: 'claude' not found on PATH — cannot verify the install."
echo " Install Claude Code, then run ./setup from the repo."
fi
echo ""
# 4. Legacy / vestigial install conflicts.
echo "Legacy install conflicts:"
legacy_problem=0
# Vestigial bare symlink from the pre-marketplace setup method. Harmless on
# current Claude Code (ignored), but worth removing so it stops confusing
# diagnostics. Informational, not counted as a problem.
for plugins_base in "$HOME/.claude/plugins" "$(pwd)/.claude/plugins"; do
vestigial="$plugins_base/idstack"
if [ -L "$vestigial" ]; then
echo " NOTE: vestigial symlink at $vestigial (pre-marketplace install method)."
echo " Harmless — ./setup removes it. Or: rm \"$vestigial\""
fi
done
# Pre-v2.0.1.0 dispatcher install — the failure mode that surfaced as
# "Unknown skill: idstack:course-import" / "Unknown skill: course-import".
if [ -L "$LEGACY_DIR" ]; then
target=$(readlink "$LEGACY_DIR")
echo " PROBLEM: legacy symlink at $LEGACY_DIR -> $target"
echo " Fix: rm \"$LEGACY_DIR\""
legacy_problem=1
elif [ -d "$LEGACY_DIR" ]; then
signature=""
if [ -f "$LEGACY_DIR/SKILL.md" ] && grep -q '^name: idstack' "$LEGACY_DIR/SKILL.md" 2>/dev/null; then
signature="dispatcher SKILL.md"
fi
if [ -f "$LEGACY_DIR/VERSION" ]; then
v=$(tr -d '[:space:]' < "$LEGACY_DIR/VERSION")
# Uses shared classifier to identify pre-v2.0.1.0 versions. Mirrors setup.
# Covered by test/test-version-classifier.sh.
class=$("$IDSTACK_DIR/bin/idstack-version-classifier" "$v")
if [ "$class" = "legacy" ]; then
signature="${signature:+$signature, }VERSION=$v"
fi
fi
if [ -n "$signature" ]; then
echo " PROBLEM: pre-v2.0.1.0 install at $LEGACY_DIR ($signature)"
echo " This shadows /idstack:<skill> namespacing — slash"
echo " commands resolve to a broken dispatcher."
echo " Fix: rm -rf \"$LEGACY_DIR\" (then restart Claude Code)"
legacy_problem=1
else
echo " WARNING: directory at $LEGACY_DIR is not a recognized idstack install."
echo " Not auto-removed. Inspect and remove manually if unwanted."
fi
fi
# Pre-v2 individual skill symlinks pointing into idstack.
for skill in $SKILLS; do
link="$LEGACY_SKILLS_DIR/$skill"
if [ -L "$link" ]; then
t=$(readlink "$link" 2>/dev/null || true)
if [[ "$t" == *"idstack"* ]]; then
echo " PROBLEM: pre-v2 skill symlink $link -> $t"
echo " Fix: rm \"$link\""
legacy_problem=1
fi
fi
done
if [ "$legacy_problem" = "0" ]; then
echo " none detected"
else
note_problem
fi
echo ""
# 5. Final verdict
if [ "$PROBLEMS" = "0" ]; then
echo "OK"
exit 0
else
echo "BROKEN ($PROBLEMS problem group(s) above)"
exit 1
fi