mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-08 13:39:45 +08:00
fix: top-level skill dirs so Claude discovers unprefixed names (#761)
* fix: top-level skill dirs so Claude discovers unprefixed names Replace directory symlinks (gstack/qa → qa) with real directories containing a SKILL.md symlink. Claude Code auto-prefixes skills nested under a parent dir symlink, so /plan-ceo-review became "Unknown skill" even with skill_prefix=false. Real dirs fix this. Also syncs package.json version to match VERSION file and updates test assertions to match the new mkdir + ln approach. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: update symlink references to new top-level directory pattern Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: regression tests for top-level skill directory structure Verifies the invariant that setup/relink creates real directories (not symlinks) at the top level, with SKILL.md symlinks inside. This prevents Claude Code from auto-prefixing skills with gstack- when using --no-prefix. Tests added: - unprefixed skills must be real dirs with SKILL.md symlinks - prefixed skills must also be real dirs with SKILL.md symlinks - old directory symlinks get upgraded to real directories - cleanup functions handle both old symlinks and new dir pattern - link function removes old directory symlinks before mkdir Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: namespace isolation tests for first install + mode switching Verifies the core invariant: when you pick a prefix mode, ONLY that mode's entries exist. Zero pollution from the other mode. - first install --no-prefix: only flat names, zero gstack-* leaks - first install --prefix: only gstack-* names, zero flat leaks - non-TTY defaults to flat names - switching prefix→no-prefix removes ALL gstack-* entries - switching no-prefix→prefix removes ALL flat entries Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: upgrade migration system — versioned fix scripts for broken state Adds gstack-upgrade/migrations/ directory with version-keyed bash scripts that run automatically during /gstack-upgrade (Step 4.75, after ./setup). Each script is idempotent and handles state fixes that setup alone can't cover. First migration: v0.15.2.0.sh runs gstack-relink to fix stale directory symlinks from pre-v0.15.2.0 installs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: migration script validation + v0.15.2.0 end-to-end fix test Tests that migration scripts are executable, parse without syntax errors, follow the v{VERSION}.sh naming convention, and that v0.15.2.0 actually fixes stale directory symlinks by converting them to real directories. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: upgrade migration guide in CONTRIBUTING.md + CLAUDE.md pointer CONTRIBUTING.md: new "Upgrade migrations" section documenting when and how to add migration scripts for broken on-disk state. CLAUDE.md: added note under vendored symlink awareness pointing to CONTRIBUTING.md's migration section when worried about broken installs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -40,8 +40,8 @@ No setup needed. Learnings are logged automatically. View them with `/learn`.
|
||||
ln -sfn /path/to/your/gstack-fork .claude/skills/gstack
|
||||
cd .claude/skills/gstack && bun install && bun run build && ./setup
|
||||
```
|
||||
Setup creates the per-skill symlinks (`qa -> gstack/qa`, etc.) and asks your
|
||||
prefix preference. Pass `--no-prefix` to skip the prompt and use short names.
|
||||
Setup creates per-skill directories with SKILL.md symlinks inside (`qa/SKILL.md -> gstack/qa/SKILL.md`)
|
||||
and asks your prefix preference. Pass `--no-prefix` to skip the prompt and use short names.
|
||||
5. **Fix the issue** — your changes are live immediately in this project
|
||||
6. **Test by actually using gstack** — do the thing that annoyed you, verify it's fixed
|
||||
7. **Open a PR from your fork**
|
||||
@@ -64,9 +64,11 @@ your local edits instead of the global install.
|
||||
gstack/ <- your working tree
|
||||
├── .claude/skills/ <- created by dev-setup (gitignored)
|
||||
│ ├── gstack -> ../../ <- symlink back to repo root
|
||||
│ ├── review -> gstack/review <- short names (default)
|
||||
│ ├── ship -> gstack/ship <- or gstack-review, gstack-ship if --prefix
|
||||
│ └── ... <- one symlink per skill
|
||||
│ ├── review/ <- real directory (short name, default)
|
||||
│ │ └── SKILL.md -> gstack/review/SKILL.md
|
||||
│ ├── ship/ <- or gstack-review/, gstack-ship/ if --prefix
|
||||
│ │ └── SKILL.md -> gstack/ship/SKILL.md
|
||||
│ └── ... <- one directory per skill
|
||||
├── review/
|
||||
│ └── SKILL.md <- edit this, test with /review
|
||||
├── ship/
|
||||
@@ -77,7 +79,9 @@ gstack/ <- your working tree
|
||||
└── ...
|
||||
```
|
||||
|
||||
Skill symlink names depend on your prefix setting (`~/.gstack/config.yaml`).
|
||||
Setup creates real directories (not symlinks) at the top level with a SKILL.md
|
||||
symlink inside. This ensures Claude discovers them as top-level skills, not nested
|
||||
under `gstack/`. Names depend on your prefix setting (`~/.gstack/config.yaml`).
|
||||
Short names (`/review`, `/ship`) are the default. Run `./setup --prefix` if you
|
||||
prefer namespaced names (`/gstack-review`, `/gstack-ship`).
|
||||
|
||||
@@ -320,7 +324,7 @@ ln -sfn /path/to/your/gstack-checkout .claude/skills/gstack
|
||||
### Step 2: Run setup to create per-skill symlinks
|
||||
|
||||
The `gstack` symlink alone isn't enough. Claude Code discovers skills through
|
||||
individual symlinks (`qa -> gstack/qa`, `ship -> gstack/ship`, etc.), not through
|
||||
individual top-level directories (`qa/SKILL.md`, `ship/SKILL.md`, etc.), not through
|
||||
the `gstack/` directory itself. Run `./setup` to create them:
|
||||
|
||||
```bash
|
||||
@@ -344,8 +348,8 @@ Remove the project-local symlink. Claude Code falls back to `~/.claude/skills/gs
|
||||
rm .claude/skills/gstack
|
||||
```
|
||||
|
||||
The per-skill symlinks (`qa`, `ship`, etc.) still point to `gstack/...`, so they'll
|
||||
resolve to the global install automatically.
|
||||
The per-skill directories (`qa/`, `ship/`, etc.) contain SKILL.md symlinks that point
|
||||
to `gstack/...`, so they'll resolve to the global install automatically.
|
||||
|
||||
### Switching prefix mode
|
||||
|
||||
@@ -388,6 +392,56 @@ When community PRs accumulate, batch them into themed waves:
|
||||
|
||||
See [PR #205](../../pull/205) (v0.8.3) for the first wave as an example.
|
||||
|
||||
## Upgrade migrations
|
||||
|
||||
When a release changes on-disk state (directory structure, config format, stale
|
||||
files) in ways that `./setup` alone can't fix, add a migration script so existing
|
||||
users get a clean upgrade.
|
||||
|
||||
### When to add a migration
|
||||
|
||||
- Changed how skill directories are created (symlinks vs real dirs)
|
||||
- Renamed or moved config keys in `~/.gstack/config.yaml`
|
||||
- Need to delete orphaned files from a previous version
|
||||
- Changed the format of `~/.gstack/` state files
|
||||
|
||||
Don't add a migration for: new features (users get them automatically), new
|
||||
skills (setup discovers them), or code-only changes (no on-disk state).
|
||||
|
||||
### How to add one
|
||||
|
||||
1. Create `gstack-upgrade/migrations/v{VERSION}.sh` where `{VERSION}` matches
|
||||
the VERSION file for the release that needs the fix.
|
||||
2. Make it executable: `chmod +x gstack-upgrade/migrations/v{VERSION}.sh`
|
||||
3. The script must be **idempotent** (safe to run multiple times) and
|
||||
**non-fatal** (failures are logged but don't block the upgrade).
|
||||
4. Include a comment block at the top explaining what changed, why the
|
||||
migration is needed, and which users are affected.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Migration: v0.15.2.0 — Fix skill directory structure
|
||||
# Affected: users who installed with --no-prefix before v0.15.2.0
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
"$SCRIPT_DIR/bin/gstack-relink" 2>/dev/null || true
|
||||
```
|
||||
|
||||
### How it runs
|
||||
|
||||
During `/gstack-upgrade`, after `./setup` completes (Step 4.75), the upgrade
|
||||
skill scans `gstack-upgrade/migrations/` and runs every `v*.sh` script whose
|
||||
version is newer than the user's old version. Scripts run in version order.
|
||||
Failures are logged but never block the upgrade.
|
||||
|
||||
### Testing migrations
|
||||
|
||||
Migrations are tested as part of `bun test` (tier 1, free). The test suite
|
||||
verifies that all migration scripts in `gstack-upgrade/migrations/` are
|
||||
executable and parse without syntax errors.
|
||||
|
||||
## Shipping your changes
|
||||
|
||||
When you're happy with your skill edits:
|
||||
|
||||
Reference in New Issue
Block a user