M CHANGELOG.md => CHANGELOG.md +10 -0
@@ 1,5 1,15 @@
# Changelog
+## 0.6.0.1 — 2026-03-17
+
+- **`/gstack-upgrade` now catches stale vendored copies automatically.** If your global gstack is up to date but the vendored copy in your project is behind, `/gstack-upgrade` detects the mismatch and syncs it. No more manually asking "did we vendor it?" — it just tells you and offers to update.
+- **Upgrade sync is safer.** If `./setup` fails while syncing a vendored copy, gstack restores the previous version from backup instead of leaving a broken install.
+
+### For contributors
+
+- Standalone usage section in `gstack-upgrade/SKILL.md.tmpl` now references Steps 2 and 4.5 (DRY) instead of duplicating detection/sync bash blocks. Added one new version-comparison bash block.
+- Update check fallback in standalone mode now matches the preamble pattern (global path → local path → `|| true`).
+
## 0.6.0 — 2026-03-17
- **100% test coverage is the key to great vibe coding.** gstack now bootstraps test frameworks from scratch when your project doesn't have one. Detects your runtime, researches the best framework, asks you to pick, installs it, writes 3-5 real tests for your actual code, sets up CI/CD (GitHub Actions), creates TESTING.md, and adds test culture instructions to CLAUDE.md. Every Claude Code session after that writes tests naturally.
M VERSION => VERSION +1 -1
@@ 1,1 1,1 @@
-0.6.0
+0.6.0.1
M gstack-upgrade/SKILL.md => gstack-upgrade/SKILL.md +26 -2
@@ 156,6 156,13 @@ rm -rf "$LOCAL_GSTACK.bak"
```
Tell user: "Also updated vendored copy at `$LOCAL_GSTACK` — commit `.claude/skills/gstack/` when you're ready."
+If `./setup` fails, restore from backup and warn the user:
+```bash
+rm -rf "$LOCAL_GSTACK"
+mv "$LOCAL_GSTACK.bak" "$LOCAL_GSTACK"
+```
+Tell user: "Sync failed — restored previous version at `$LOCAL_GSTACK`. Run `/gstack-upgrade` manually to retry."
+
### Step 5: Write marker + clear cache
```bash
@@ 193,9 200,26 @@ When invoked directly as `/gstack-upgrade` (not from a preamble):
1. Force a fresh update check (bypass cache):
```bash
-~/.claude/skills/gstack/bin/gstack-update-check --force
+~/.claude/skills/gstack/bin/gstack-update-check --force 2>/dev/null || \
+.claude/skills/gstack/bin/gstack-update-check --force 2>/dev/null || true
```
Use the output to determine if an upgrade is available.
2. If `UPGRADE_AVAILABLE <old> <new>`: follow Steps 2-6 above.
-3. If no output (up to date): tell the user "You're already on the latest version (v{version})."
+
+3. If no output (primary is up to date): check for a stale local vendored copy.
+
+Run the Step 2 bash block above to detect the primary install type and directory (`INSTALL_TYPE` and `INSTALL_DIR`). Then run the Step 4.5 detection bash block above to check for a local vendored copy (`LOCAL_GSTACK`).
+
+**If `LOCAL_GSTACK` is empty** (no local vendored copy): tell the user "You're already on the latest version (v{version})."
+
+**If `LOCAL_GSTACK` is non-empty**, compare versions:
+```bash
+PRIMARY_VER=$(cat "$INSTALL_DIR/VERSION" 2>/dev/null || echo "unknown")
+LOCAL_VER=$(cat "$LOCAL_GSTACK/VERSION" 2>/dev/null || echo "unknown")
+echo "PRIMARY=$PRIMARY_VER LOCAL=$LOCAL_VER"
+```
+
+**If versions differ:** follow the Step 4.5 sync bash block above to update the local copy from the primary. Tell user: "Global v{PRIMARY_VER} is up to date. Updated local vendored copy from v{LOCAL_VER} → v{PRIMARY_VER}. Commit `.claude/skills/gstack/` when you're ready."
+
+**If versions match:** tell the user "You're on the latest version (v{PRIMARY_VER}). Global and local vendored copy are both up to date."
M gstack-upgrade/SKILL.md.tmpl => gstack-upgrade/SKILL.md.tmpl +26 -2
@@ 154,6 154,13 @@ rm -rf "$LOCAL_GSTACK.bak"
```
Tell user: "Also updated vendored copy at `$LOCAL_GSTACK` — commit `.claude/skills/gstack/` when you're ready."
+If `./setup` fails, restore from backup and warn the user:
+```bash
+rm -rf "$LOCAL_GSTACK"
+mv "$LOCAL_GSTACK.bak" "$LOCAL_GSTACK"
+```
+Tell user: "Sync failed — restored previous version at `$LOCAL_GSTACK`. Run `/gstack-upgrade` manually to retry."
+
### Step 5: Write marker + clear cache
```bash
@@ 191,9 198,26 @@ When invoked directly as `/gstack-upgrade` (not from a preamble):
1. Force a fresh update check (bypass cache):
```bash
-~/.claude/skills/gstack/bin/gstack-update-check --force
+~/.claude/skills/gstack/bin/gstack-update-check --force 2>/dev/null || \
+.claude/skills/gstack/bin/gstack-update-check --force 2>/dev/null || true
```
Use the output to determine if an upgrade is available.
2. If `UPGRADE_AVAILABLE <old> <new>`: follow Steps 2-6 above.
-3. If no output (up to date): tell the user "You're already on the latest version (v{version})."
+
+3. If no output (primary is up to date): check for a stale local vendored copy.
+
+Run the Step 2 bash block above to detect the primary install type and directory (`INSTALL_TYPE` and `INSTALL_DIR`). Then run the Step 4.5 detection bash block above to check for a local vendored copy (`LOCAL_GSTACK`).
+
+**If `LOCAL_GSTACK` is empty** (no local vendored copy): tell the user "You're already on the latest version (v{version})."
+
+**If `LOCAL_GSTACK` is non-empty**, compare versions:
+```bash
+PRIMARY_VER=$(cat "$INSTALL_DIR/VERSION" 2>/dev/null || echo "unknown")
+LOCAL_VER=$(cat "$LOCAL_GSTACK/VERSION" 2>/dev/null || echo "unknown")
+echo "PRIMARY=$PRIMARY_VER LOCAL=$LOCAL_VER"
+```
+
+**If versions differ:** follow the Step 4.5 sync bash block above to update the local copy from the primary. Tell user: "Global v{PRIMARY_VER} is up to date. Updated local vendored copy from v{LOCAL_VER} → v{PRIMARY_VER}. Commit `.claude/skills/gstack/` when you're ready."
+
+**If versions match:** tell the user "You're on the latest version (v{PRIMARY_VER}). Global and local vendored copy are both up to date."