Skip to content

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

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

fix(uninstall): clean up per-skill directories with nested SKILL.md symlinks#902
mvanhorn wants to merge 1 commit intogarrytan:mainfrom
mvanhorn:fix/896-uninstall-prefix-mode-cleanup

Conversation

@mvanhorn
Copy link
Copy Markdown
Contributor

@mvanhorn mvanhorn commented Apr 8, 2026

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
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