Skip to content

Commit dea7ebc

Browse files
savvidesclaude
andcommitted
fix(setup): install via the plugin marketplace flow, not a bare symlink
./setup symlinked the repo into ~/.claude/plugins/idstack. Current Claude Code (2.1.x) does not discover plugins from bare symlinks — it requires a marketplace registration — so `claude plugin list` showed nothing and /idstack:<skill> never appeared in the slash-command picker. Core fix: - Add .claude-plugin/marketplace.json — the one-plugin marketplace manifest the install flow requires (source: "./", repo root). - setup: Claude branch now runs `claude plugin marketplace add` + `claude plugin install --scope <user|project>` (both idempotent, so re-running setup is safe). --local maps to project scope. Detects when `claude` is missing on PATH and prints manual steps. Removes the now- vestigial bare symlink from prior installs (only ever a symlink, never a real dir). Codex branch unchanged. - bin/idstack-doctor: rewritten to self-locate the repo and check the real signal — `claude plugin list` for idstack@idstack installed+enabled — plus the plugin + marketplace manifests. Keeps legacy-conflict detection; flags the vestigial symlink as an informational note. - test/smoke-test.sh: $IDSTACK_DIR now self-locates the repo instead of assuming ~/.claude/plugins/idstack; legacy-conflict checks gate on "no $1 override" instead of the old plugins-dir path. Adds marketplace.json assertions. - templates/preamble.md: $_IDSTACK detection no longer falls back to the removed bare symlink; the last-ditch branch resolves the marketplace cache dir. Regenerated all 22 skill files (claude + codex). Docs (README, docs/index.html, CONTRIBUTING, CLAUDE.md): install command changes from `git clone … ~/.claude/plugins/idstack && …` to `git clone … && cd idstack && ./setup`; update/troubleshooting text and the doctor reference updated to match. Verified: smoke-test 257/257, idstack-doctor OK, ./setup idempotent end to end, gen-skills --dry-run clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b516169 commit dea7ebc

31 files changed

Lines changed: 273 additions & 168 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "idstack",
3+
"description": "Evidence-based instructional design pipeline — 11 skills backed by peer-reviewed research across 11 domains.",
4+
"owner": {
5+
"name": "Philippos Savvides",
6+
"url": "https://github.com/savvides"
7+
},
8+
"plugins": [
9+
{
10+
"name": "idstack",
11+
"source": "./"
12+
}
13+
]
14+
}

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ An open source set of skills for evidence-based instructional design. Runs in Cl
1010

1111
```bash
1212
./setup # Install idstack — auto-detects Claude Code and codex on PATH
13-
./setup --local # Install to .claude/plugins/ in current project only
13+
./setup --local # Install at project scope (./.claude/) instead of user scope
1414
./setup --codex # Force-install the Codex bundle even if codex isn't on PATH
1515
./setup --no-codex # Skip the Codex install
1616
./test/smoke-test.sh # Verify installation, SKILL.md files, YAML frontmatter, migrations

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ allowed-tools:
4040
---
4141
```
4242

43-
The bare `name` field becomes the slash-command suffix: `name: course-import` is invoked as `/idstack:course-import`. The plugin layout at `~/.claude/plugins/idstack/` handles the `idstack:` namespace; do not prefix the name yourself.
43+
The bare `name` field becomes the slash-command suffix: `name: course-import` is invoked as `/idstack:course-import`. The installed plugin handles the `idstack:` namespace; do not prefix the name yourself.
4444

4545
**2. `{{PREAMBLE}}` placeholder** — this is replaced by `bin/idstack-gen-skills` with the shared preamble (update check, manifest check, context recovery).
4646

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,12 @@ You had a course in Canvas. Now you have an evidence-based audit with specific r
101101
Paste this into your terminal:
102102

103103
```bash
104-
git clone https://github.com/savvides/idstack.git ~/.claude/plugins/idstack
105-
cd ~/.claude/plugins/idstack
104+
git clone https://github.com/savvides/idstack.git
105+
cd idstack
106106
./setup
107107
```
108108

109-
Restart Claude Code if it was already running — plugins load at session start. You should see `/idstack:<skill>` commands in the slash picker.
109+
`./setup` registers the repo as a Claude Code plugin marketplace and installs it. Restart Claude Code if it was already running — plugins load at session start. You should see `/idstack:<skill>` commands in the slash picker.
110110

111111
### Alternative install methods
112112

@@ -115,7 +115,7 @@ Restart Claude Code if it was already running — plugins load at session start.
115115

116116
If you'd rather not touch the terminal, paste this into Claude Code:
117117

118-
> Install idstack: run `git clone https://github.com/savvides/idstack.git ~/.claude/plugins/idstack && cd ~/.claude/plugins/idstack && ./setup`, then tell me it's installed and show me the available skills.
118+
> Install idstack: run `git clone https://github.com/savvides/idstack.git && cd idstack && ./setup`, then tell me it's installed and show me the available skills.
119119
120120
Claude clones the repo, runs setup, and confirms the skills are registered.
121121
</details>
@@ -275,7 +275,7 @@ Any skill works independently. Run `/idstack:pipeline` to chain them all, or inv
275275
+-------------------------------------------------------+
276276
```
277277

278-
Skills are plain Markdown files generated from templates. No build step for users, no dependencies. `./setup` registers the repo as a Claude Code plugin at `~/.claude/plugins/idstack`, which is what gives the namespaced `/idstack:<skill>` commands. Users invoke skills via `/idstack:<skill>`. Each skill reads the shared manifest and session history, runs its evidence-based workflow, writes back its section, and logs the session to the timeline. The pipeline adds context but every skill also works standalone.
278+
Skills are plain Markdown files generated from templates. No build step for users, no dependencies. `./setup` registers the repo as a Claude Code plugin marketplace and installs it, which is what gives the namespaced `/idstack:<skill>` commands. Users invoke skills via `/idstack:<skill>`. Each skill reads the shared manifest and session history, runs its evidence-based workflow, writes back its section, and logs the session to the timeline. The pipeline adds context but every skill also works standalone.
279279

280280
## How it works
281281

@@ -366,7 +366,7 @@ idstack runs locally on your machine. Course data stays in your project folder (
366366
You can, but let the skills manage it. If you do edit it, keep the JSON valid.
367367

368368
**How do I update idstack?**
369-
idstack checks for updates when you run any skill. If a newer version is available, you'll see a notification. Update manually: `cd ~/.claude/plugins/idstack && git pull && ./setup`
369+
idstack checks for updates when you run any skill. If a newer version is available, you'll see a notification. Update manually: `cd <your idstack clone> && git pull && ./setup`
370370
If you downloaded ZIP: download the latest version and run `./setup` again.
371371

372372
**How do I request a feature or report a bug?**
@@ -379,18 +379,18 @@ idstack itself is just text files. But it runs inside Claude Code, which require
379379

380380
**Skill not showing up?** Claude Code loads skills at session start. If you installed while Claude Code was running, restart it (close and reopen). If that doesn't help, run setup again:
381381
```bash
382-
cd ~/.claude/plugins/idstack && ./setup
382+
cd <your idstack clone> && ./setup
383383
```
384384

385385
**Can't import a .imscc cartridge?** Make sure the file is a valid ZIP. Try re-exporting from your LMS with "Course" selected (not just content).
386386

387387
**Canvas API says "token rejected"?** Generate a fresh token: Canvas -> Account -> Settings -> New Access Token. Tokens expire.
388388

389-
**Claude says it can't find idstack skills?** Make sure you've run `./setup` after cloning. Setup registers the repo as a plugin at `~/.claude/plugins/idstack` so Claude Code discovers the namespaced `/idstack:<skill>` commands. Restart Claude Code after install — plugins load at session start.
389+
**Claude says it can't find idstack skills?** Make sure you've run `./setup` after cloning. Setup registers the repo as a plugin marketplace and installs it so Claude Code discovers the namespaced `/idstack:<skill>` commands. Restart Claude Code after install — plugins load at session start.
390390

391-
**Upgrading from v2.0?** v2.0 installed under `~/.claude/skills/idstack`, which only exposed `/idstack` (the dispatcher) — never the 11 namespaced sub-skills. Re-clone to the new location: `git clone https://github.com/savvides/idstack.git ~/.claude/plugins/idstack && cd ~/.claude/plugins/idstack && ./setup`. Setup now detects and removes any pre-v2.0.1.0 install at `~/.claude/skills/idstack` (symlink *or* real directory). If you ran an older setup that only warned, run `./setup` once more — or remove it manually with `rm -rf ~/.claude/skills/idstack`.
391+
**Upgrading from v2.0?** v2.0 installed under `~/.claude/skills/idstack`, which only exposed `/idstack` (the dispatcher) — never the 11 namespaced sub-skills. Clone fresh and run setup: `git clone https://github.com/savvides/idstack.git && cd idstack && ./setup`. Setup now detects and removes any pre-v2.0.1.0 install at `~/.claude/skills/idstack` (symlink *or* real directory). If you ran an older setup that only warned, run `./setup` once more — or remove it manually with `rm -rf ~/.claude/skills/idstack`.
392392

393-
**`/idstack:<skill>` won't autocomplete or returns "Unknown skill"?** Run `bin/idstack-doctor` from the plugin dir (`~/.claude/plugins/idstack`). It checks plugin presence, manifest version, all 11 SKILL.md files, and detects legacy-install conflicts — printing the exact remediation command for whatever it finds.
393+
**`/idstack:<skill>` won't autocomplete or returns "Unknown skill"?** Run `bin/idstack-doctor` from your idstack clone. It checks the plugin + marketplace manifests, the Claude Code install state, all 11 SKILL.md files, and detects legacy-install conflicts — printing the exact remediation command for whatever it finds.
394394

395395
## Contributing
396396

bin/idstack-doctor

Lines changed: 78 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
#!/usr/bin/env bash
2-
# idstack install doctor — diagnose plugin / legacy-install conflicts.
2+
# idstack install doctor — diagnose plugin install + legacy conflicts.
33
#
44
# Answers: "is /idstack:<skill> going to work, and if not, exactly what
55
# do I run?" without the user having to know about smoke-test.
66
#
77
# Usage:
8-
# idstack-doctor # check global install (~/.claude)
9-
# idstack-doctor --local # check local install (./.claude)
8+
# idstack-doctor # check user-scope install
9+
# idstack-doctor --local # also check project-scope legacy paths
1010
#
1111
# Exit code: 0 if all green, 1 if any problem is detected.
1212

1313
set -u
1414

15+
# This script lives at <repo>/bin/idstack-doctor — resolve the repo root from
16+
# its own location so the diagnosis works regardless of where the repo sits.
17+
IDSTACK_DIR="$(cd "$(dirname "$0")/.." && pwd -P)"
18+
1519
SCOPE="global"
16-
CLAUDE_BASE="$HOME/.claude"
20+
LEGACY_BASE="$HOME/.claude"
1721
# Match --local in any position, not just $1. Robust if other flags get added.
1822
if [[ " ${*:-} " == *" --local "* ]]; then
1923
SCOPE="local"
20-
CLAUDE_BASE="$(pwd)/.claude"
24+
LEGACY_BASE="$(pwd)/.claude"
2125
fi
22-
23-
PLUGINS_DIR="$CLAUDE_BASE/plugins"
24-
SKILLS_DIR="$CLAUDE_BASE/skills"
25-
PLUGIN_DIR="$PLUGINS_DIR/idstack"
26-
LEGACY_DIR="$SKILLS_DIR/idstack"
26+
LEGACY_SKILLS_DIR="$LEGACY_BASE/skills"
27+
LEGACY_DIR="$LEGACY_SKILLS_DIR/idstack"
2728

2829
PROBLEMS=0
2930
note_problem() { PROBLEMS=$((PROBLEMS + 1)); }
@@ -33,67 +34,95 @@ assessment-design course-builder course-export accessibility-review red-team \
3334
pipeline learn"
3435

3536
echo "idstack doctor ($SCOPE)"
36-
echo " claude base: $CLAUDE_BASE"
37+
echo " repo: $IDSTACK_DIR"
3738
echo ""
3839

39-
# 1. Plugin presence
40-
echo "Plugin install:"
41-
if [ -e "$PLUGIN_DIR" ]; then
42-
if [ -L "$PLUGIN_DIR" ]; then
43-
target=$(readlink "$PLUGIN_DIR")
44-
resolved=$(cd "$PLUGIN_DIR" 2>/dev/null && pwd -P || echo "BROKEN")
45-
echo " $PLUGIN_DIR -> $target"
46-
if [ "$resolved" = "BROKEN" ]; then
47-
echo " PROBLEM: symlink target is missing or unreadable."
48-
note_problem
49-
fi
50-
elif [ -d "$PLUGIN_DIR" ]; then
51-
echo " $PLUGIN_DIR (real directory)"
40+
# 1. Plugin + marketplace manifests in the repo
41+
echo "Plugin manifests:"
42+
plugin_manifest="$IDSTACK_DIR/.claude-plugin/plugin.json"
43+
market_manifest="$IDSTACK_DIR/.claude-plugin/marketplace.json"
44+
if [ -f "$plugin_manifest" ]; then
45+
version=$(grep -o '"version": *"[^"]*"' "$plugin_manifest" | head -n1 | sed 's/.*"\([^"]*\)"$/\1/')
46+
if [ -n "$version" ]; then
47+
echo " plugin.json present (version $version)"
5248
else
53-
echo " PROBLEM: $PLUGIN_DIR exists but is not a directory or symlink."
54-
note_problem
55-
fi
56-
manifest="$PLUGIN_DIR/.claude-plugin/plugin.json"
57-
if [ -f "$manifest" ]; then
58-
version=$(grep -o '"version": *"[^"]*"' "$manifest" | head -n1 | sed 's/.*"\([^"]*\)"$/\1/')
59-
if [ -n "$version" ]; then
60-
echo " manifest version: $version"
61-
else
62-
echo " PROBLEM: could not parse version from $manifest"
63-
note_problem
64-
fi
65-
else
66-
echo " PROBLEM: missing $manifest"
49+
echo " PROBLEM: could not parse version from $plugin_manifest"
6750
note_problem
6851
fi
6952
else
70-
echo " MISSING: $PLUGIN_DIR"
71-
echo " Run: ./setup (from the idstack repo)"
53+
echo " PROBLEM: missing $plugin_manifest"
54+
note_problem
55+
fi
56+
if [ -f "$market_manifest" ]; then
57+
echo " marketplace.json present"
58+
else
59+
echo " PROBLEM: missing $market_manifest"
60+
echo " Claude Code installs plugins through a marketplace manifest;"
61+
echo " without it, ./setup cannot register the plugin."
7262
note_problem
7363
fi
7464
echo ""
7565

76-
# 2. Skill files reachable
66+
# 2. Skill files reachable in the repo
7767
echo "Skill files:"
7868
missing_skills=0
7969
for skill in $SKILLS; do
80-
if [ ! -f "$PLUGIN_DIR/skills/$skill/SKILL.md" ]; then
70+
if [ ! -f "$IDSTACK_DIR/skills/$skill/SKILL.md" ]; then
8171
echo " MISSING: skills/$skill/SKILL.md"
8272
missing_skills=$((missing_skills + 1))
8373
fi
8474
done
8575
if [ "$missing_skills" = "0" ]; then
86-
echo " all 11 SKILL.md files reachable"
76+
echo " all 11 SKILL.md files present"
8777
else
88-
echo " PROBLEM: $missing_skills SKILL.md file(s) missing under the plugin"
78+
echo " PROBLEM: $missing_skills SKILL.md file(s) missing under skills/"
8979
note_problem
9080
fi
9181
echo ""
9282

93-
# 3. Legacy install detection — the failure mode that surfaced as
94-
# "Unknown skill: idstack:course-import" / "Unknown skill: course-import".
83+
# 3. Claude Code install state — the marketplace flow records the plugin in
84+
# Claude Code's own registry; a bare symlink is not enough on current versions.
85+
echo "Claude Code install:"
86+
if command -v claude >/dev/null 2>&1; then
87+
plugin_list=$(claude plugin list 2>/dev/null || true)
88+
if echo "$plugin_list" | grep -q "idstack@idstack"; then
89+
if echo "$plugin_list" | grep -A4 "idstack@idstack" | grep -qi "enabled"; then
90+
echo " idstack@idstack installed and enabled"
91+
else
92+
echo " PROBLEM: idstack@idstack is installed but not enabled."
93+
echo " Fix: claude plugin enable idstack@idstack"
94+
note_problem
95+
fi
96+
else
97+
echo " PROBLEM: idstack@idstack is not installed."
98+
echo " Fix: run ./setup from the repo, or manually:"
99+
echo " claude plugin marketplace add \"$IDSTACK_DIR\""
100+
echo " claude plugin install idstack@idstack"
101+
note_problem
102+
fi
103+
else
104+
echo " WARNING: 'claude' not found on PATH — cannot verify the install."
105+
echo " Install Claude Code, then run ./setup from the repo."
106+
fi
107+
echo ""
108+
109+
# 4. Legacy / vestigial install conflicts.
95110
echo "Legacy install conflicts:"
96111
legacy_problem=0
112+
113+
# Vestigial bare symlink from the pre-marketplace setup method. Harmless on
114+
# current Claude Code (ignored), but worth removing so it stops confusing
115+
# diagnostics. Informational, not counted as a problem.
116+
for plugins_base in "$HOME/.claude/plugins" "$(pwd)/.claude/plugins"; do
117+
vestigial="$plugins_base/idstack"
118+
if [ -L "$vestigial" ]; then
119+
echo " NOTE: vestigial symlink at $vestigial (pre-marketplace install method)."
120+
echo " Harmless — ./setup removes it. Or: rm \"$vestigial\""
121+
fi
122+
done
123+
124+
# Pre-v2.0.1.0 dispatcher install — the failure mode that surfaced as
125+
# "Unknown skill: idstack:course-import" / "Unknown skill: course-import".
97126
if [ -L "$LEGACY_DIR" ]; then
98127
target=$(readlink "$LEGACY_DIR")
99128
echo " PROBLEM: legacy symlink at $LEGACY_DIR -> $target"
@@ -126,9 +155,9 @@ elif [ -d "$LEGACY_DIR" ]; then
126155
echo " Not auto-removed. Inspect and remove manually if unwanted."
127156
fi
128157
fi
129-
# Pre-v2 individual skill symlinks pointing into idstack
158+
# Pre-v2 individual skill symlinks pointing into idstack.
130159
for skill in $SKILLS; do
131-
link="$SKILLS_DIR/$skill"
160+
link="$LEGACY_SKILLS_DIR/$skill"
132161
if [ -L "$link" ]; then
133162
t=$(readlink "$link" 2>/dev/null || true)
134163
if [[ "$t" == *"idstack"* ]]; then
@@ -145,7 +174,7 @@ else
145174
fi
146175
echo ""
147176

148-
# 4. Final verdict
177+
# 5. Final verdict
149178
if [ "$PROBLEMS" = "0" ]; then
150179
echo "OK"
151180
exit 0

dist/codex/skills/idstack-accessibility-review/SKILL.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@ if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
4747
_IDSTACK="$CLAUDE_PLUGIN_ROOT"
4848
elif [ -n "${IDSTACK_HOME:-}" ]; then
4949
_IDSTACK="$IDSTACK_HOME"
50-
elif [ -d "$HOME/.claude/plugins/idstack" ]; then
51-
_IDSTACK="$HOME/.claude/plugins/idstack"
5250
elif [ -d "$HOME/.agents/plugins/idstack" ]; then
5351
_IDSTACK="$HOME/.agents/plugins/idstack"
5452
elif [ -d "$HOME/.agents/skills/idstack" ]; then
5553
_IDSTACK="$HOME/.agents/skills/idstack"
5654
else
57-
_IDSTACK="$HOME/.claude/plugins/idstack"
55+
# Claude Code caches marketplace plugins under a versioned dir; take the
56+
# highest version present. Empty if idstack was never installed this way —
57+
# every "$_IDSTACK/bin/..." call below is guarded, so that degrades quietly.
58+
_IDSTACK=$(ls -d "$HOME"/.claude/plugins/cache/idstack/idstack/*/ 2>/dev/null | sort | tail -1)
59+
_IDSTACK="${_IDSTACK%/}"
5860
fi
5961
_UPD=$("$_IDSTACK/bin/idstack-update-check" 2>/dev/null || true)
6062
[ -n "$_UPD" ] && echo "$_UPD"

dist/codex/skills/idstack-assessment-design/SKILL.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@ if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
4747
_IDSTACK="$CLAUDE_PLUGIN_ROOT"
4848
elif [ -n "${IDSTACK_HOME:-}" ]; then
4949
_IDSTACK="$IDSTACK_HOME"
50-
elif [ -d "$HOME/.claude/plugins/idstack" ]; then
51-
_IDSTACK="$HOME/.claude/plugins/idstack"
5250
elif [ -d "$HOME/.agents/plugins/idstack" ]; then
5351
_IDSTACK="$HOME/.agents/plugins/idstack"
5452
elif [ -d "$HOME/.agents/skills/idstack" ]; then
5553
_IDSTACK="$HOME/.agents/skills/idstack"
5654
else
57-
_IDSTACK="$HOME/.claude/plugins/idstack"
55+
# Claude Code caches marketplace plugins under a versioned dir; take the
56+
# highest version present. Empty if idstack was never installed this way —
57+
# every "$_IDSTACK/bin/..." call below is guarded, so that degrades quietly.
58+
_IDSTACK=$(ls -d "$HOME"/.claude/plugins/cache/idstack/idstack/*/ 2>/dev/null | sort | tail -1)
59+
_IDSTACK="${_IDSTACK%/}"
5860
fi
5961
_UPD=$("$_IDSTACK/bin/idstack-update-check" 2>/dev/null || true)
6062
[ -n "$_UPD" ] && echo "$_UPD"

dist/codex/skills/idstack-course-builder/SKILL.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@ if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
4747
_IDSTACK="$CLAUDE_PLUGIN_ROOT"
4848
elif [ -n "${IDSTACK_HOME:-}" ]; then
4949
_IDSTACK="$IDSTACK_HOME"
50-
elif [ -d "$HOME/.claude/plugins/idstack" ]; then
51-
_IDSTACK="$HOME/.claude/plugins/idstack"
5250
elif [ -d "$HOME/.agents/plugins/idstack" ]; then
5351
_IDSTACK="$HOME/.agents/plugins/idstack"
5452
elif [ -d "$HOME/.agents/skills/idstack" ]; then
5553
_IDSTACK="$HOME/.agents/skills/idstack"
5654
else
57-
_IDSTACK="$HOME/.claude/plugins/idstack"
55+
# Claude Code caches marketplace plugins under a versioned dir; take the
56+
# highest version present. Empty if idstack was never installed this way —
57+
# every "$_IDSTACK/bin/..." call below is guarded, so that degrades quietly.
58+
_IDSTACK=$(ls -d "$HOME"/.claude/plugins/cache/idstack/idstack/*/ 2>/dev/null | sort | tail -1)
59+
_IDSTACK="${_IDSTACK%/}"
5860
fi
5961
_UPD=$("$_IDSTACK/bin/idstack-update-check" 2>/dev/null || true)
6062
[ -n "$_UPD" ] && echo "$_UPD"

dist/codex/skills/idstack-course-export/SKILL.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@ if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
4747
_IDSTACK="$CLAUDE_PLUGIN_ROOT"
4848
elif [ -n "${IDSTACK_HOME:-}" ]; then
4949
_IDSTACK="$IDSTACK_HOME"
50-
elif [ -d "$HOME/.claude/plugins/idstack" ]; then
51-
_IDSTACK="$HOME/.claude/plugins/idstack"
5250
elif [ -d "$HOME/.agents/plugins/idstack" ]; then
5351
_IDSTACK="$HOME/.agents/plugins/idstack"
5452
elif [ -d "$HOME/.agents/skills/idstack" ]; then
5553
_IDSTACK="$HOME/.agents/skills/idstack"
5654
else
57-
_IDSTACK="$HOME/.claude/plugins/idstack"
55+
# Claude Code caches marketplace plugins under a versioned dir; take the
56+
# highest version present. Empty if idstack was never installed this way —
57+
# every "$_IDSTACK/bin/..." call below is guarded, so that degrades quietly.
58+
_IDSTACK=$(ls -d "$HOME"/.claude/plugins/cache/idstack/idstack/*/ 2>/dev/null | sort | tail -1)
59+
_IDSTACK="${_IDSTACK%/}"
5860
fi
5961
_UPD=$("$_IDSTACK/bin/idstack-update-check" 2>/dev/null || true)
6062
[ -n "$_UPD" ] && echo "$_UPD"

dist/codex/skills/idstack-course-import/SKILL.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@ if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
4747
_IDSTACK="$CLAUDE_PLUGIN_ROOT"
4848
elif [ -n "${IDSTACK_HOME:-}" ]; then
4949
_IDSTACK="$IDSTACK_HOME"
50-
elif [ -d "$HOME/.claude/plugins/idstack" ]; then
51-
_IDSTACK="$HOME/.claude/plugins/idstack"
5250
elif [ -d "$HOME/.agents/plugins/idstack" ]; then
5351
_IDSTACK="$HOME/.agents/plugins/idstack"
5452
elif [ -d "$HOME/.agents/skills/idstack" ]; then
5553
_IDSTACK="$HOME/.agents/skills/idstack"
5654
else
57-
_IDSTACK="$HOME/.claude/plugins/idstack"
55+
# Claude Code caches marketplace plugins under a versioned dir; take the
56+
# highest version present. Empty if idstack was never installed this way —
57+
# every "$_IDSTACK/bin/..." call below is guarded, so that degrades quietly.
58+
_IDSTACK=$(ls -d "$HOME"/.claude/plugins/cache/idstack/idstack/*/ 2>/dev/null | sort | tail -1)
59+
_IDSTACK="${_IDSTACK%/}"
5860
fi
5961
_UPD=$("$_IDSTACK/bin/idstack-update-check" 2>/dev/null || true)
6062
[ -n "$_UPD" ] && echo "$_UPD"

0 commit comments

Comments
 (0)