Skip to content

fix(uninstall): clean up per-skill directories with nested SKILL.md symlinks - #902

Closed
mvanhorn wants to merge 1 commit into
garrytan:mainfrom
mvanhorn:fix/896-uninstall-prefix-mode-cleanup
Closed

mvanhorn wants to merge 1 commit into
garrytan:mainfrom
mvanhorn:fix/896-uninstall-prefix-mode-cleanup

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Apr 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

gstack-uninstall left behind per-skill directories that setup creates under ~/.claude/skills/. After gstack-uninstall --keep-state, ~30 empty directories holding broken SKILL.md symlinks into the removed gstack/ tree remained. Covers both issue reports: prefix-mode (gstack-*) from #896 and default-mode (browse/, ship/, etc.) from #1132.

Why this matters

setup (lines 399-404) creates each skill as a real directory with a nested SKILL.md symlink, regardless of prefix setting:

~/.claude/skills/autoplan/              (real dir, default mode)
└── SKILL.md -> ~/.claude/skills/gstack/autoplan/SKILL.md

~/.claude/skills/gstack-autoplan/       (real dir, --prefix mode)
└── SKILL.md -> ~/.claude/skills/gstack/autoplan/SKILL.md

The existing uninstall loop only matched top-level symlinks ([ -L "$_LINK" ]), so neither layout got cleaned up. The final rm -rf "$CLAUDE_SKILLS/gstack" then left the per-skill directories holding broken links.

Fix

Adds a second pass in the CLAUDE_SKILLS block that iterates real directories, checks whether the nested SKILL.md is a symlink pointing into gstack/, and removes the directory when it does. The legacy top-level-symlink pass is preserved so older installs still clean up.

The symlink-target check matches both default (browse/) and prefix (gstack-browse/) layouts because setup writes the same nested SKILL.md symlink pattern in both. Also safer than the earlier gstack-* glob approach, which would have over-removed any unrelated tool whose top-level directory happened to start with gstack-.

Scoped to ~/.claude/skills. The codex/factory/kiro paths use a different install topology and are untouched.

Test

Added test('current setup layout...') in test/uninstall.test.ts covering the real-dir-plus-nested-symlink layout. Runs --force, asserts per-skill directories are gone, confirms a sibling with no SKILL.md survives.

Local verification on a fake HOME:

BEFORE:  ~/.claude/skills/{autoplan, ship, gstack, not-gstack}
AFTER:   ~/.claude/skills/{not-gstack}    (autoplan and ship removed; not-gstack preserved)

bun test test/uninstall.test.ts: 8/8 pass.

Fixes #896, fixes #1132

…links

The uninstall script only removed entries that were themselves top-level
symlinks under ~/.claude/skills. But setup (lines 399-404) creates real
directories there, with each SKILL.md linked to gstack/<skill>/SKILL.md.
After uninstall, ~30 per-skill directories (autoplan, canary, ship, ...)
were left behind holding broken SKILL.md symlinks.

Adds a second pass that inspects the nested SKILL.md in each top-level
directory and removes the directory when that link points into gstack/.
The legacy top-level-symlink pass is preserved for older installs.

Scoped to ~/.claude/skills; the codex/factory/kiro paths use a different
install topology and are untouched.

Fixes garrytan#1132
@mvanhorn
mvanhorn force-pushed the fix/896-uninstall-prefix-mode-cleanup branch from c08c7bc to 2293128 Compare April 22, 2026 13:52
@mvanhorn mvanhorn changed the title fix: clean up prefix-mode gstack-* directories on uninstall fix(uninstall): clean up per-skill directories with nested SKILL.md symlinks Apr 22, 2026
@mvanhorn

Copy link
Copy Markdown
Contributor Author

Thanks for digging through this @dgrant. The symlink-aware uninstall covers both #896 and your #1132 case, so the test/uninstall.test.ts assertions should match what you were hitting locally.

@capy-ai

capy-ai Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Thank you for this fix! The bug it addresses (#896, #1132) has since been fixed on main and the issue is closed, so I'm closing this PR as done. Re-verified against current main (v1.91.12.0). If you think part of your change is still missing, reply and we'll reopen. Really appreciate the contribution.

@capy-ai capy-ai Bot closed this Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Uninstall script doesn't uninstall symlinks properly gstack-uninstall leaves orphaned ~/.claude/skills/gstack-* directories (prefix-mode install)

2 participants