M CHANGELOG.md => CHANGELOG.md +12 -0
@@ 1,5 1,17 @@
# Changelog
+## [0.15.2.1] - 2026-04-02 — Setup Runs Migrations
+
+`git pull && ./setup` now applies version migrations automatically. Previously, migrations only ran during `/gstack-upgrade`, so users who updated via git pull never got state fixes (like the skill directory restructure from v0.15.1.0). Now `./setup` tracks the last version it ran at and applies any pending migrations on every run.
+
+### Fixed
+
+- **Setup runs pending migrations.** `./setup` now checks `~/.gstack/.last-setup-version` and runs any migration scripts newer than that version. No more broken skill directories after `git pull`.
+- **Space-safe migration loop.** Uses `while read` instead of `for` loop to handle paths with spaces correctly.
+- **Fresh installs skip migrations.** New installs write the version marker without running historical migrations that don't apply to them.
+- **Future migration guard.** Migrations for versions newer than the current VERSION are skipped, preventing premature execution from development branches.
+- **Missing VERSION guard.** If the VERSION file is absent, the version marker isn't written, preventing permanent migration poisoning.
+
## [0.15.2.0] - 2026-04-02 — Voice-Friendly Skill Triggers
Say "run a security check" instead of remembering `/cso`. Skills now have voice-friendly trigger phrases that work with AquaVoice, Whisper, and other speech-to-text tools. No more fighting with acronyms that get transcribed wrong ("CSO" -> "CEO" -> wrong skill).
M VERSION => VERSION +1 -1
@@ 1,1 1,1 @@
-0.15.2.0
+0.15.2.1
M setup => setup +28 -1
@@ 703,7 703,34 @@ if [ "$INSTALL_CODEX" -eq 1 ]; then
create_agents_sidecar "$SOURCE_GSTACK_DIR"
fi
-# 8. First-time welcome + legacy cleanup
+# 8. Run pending version migrations
+# Migrations handle state fixes that ./setup alone can't cover (stale config,
+# orphaned files, directory structure changes). Each migration is idempotent.
+MIGRATIONS_DIR="$SOURCE_GSTACK_DIR/gstack-upgrade/migrations"
+CURRENT_VERSION=$(cat "$SOURCE_GSTACK_DIR/VERSION" 2>/dev/null || echo "unknown")
+LAST_SETUP_VERSION=$(cat "$HOME/.gstack/.last-setup-version" 2>/dev/null || echo "0.0.0.0")
+if [ -d "$MIGRATIONS_DIR" ] && [ "$CURRENT_VERSION" != "unknown" ] && [ "$LAST_SETUP_VERSION" != "$CURRENT_VERSION" ]; then
+ # Fresh install (no marker file) — skip migrations, just write marker
+ if [ ! -f "$HOME/.gstack/.last-setup-version" ]; then
+ : # fall through to marker write below
+ else
+ find "$MIGRATIONS_DIR" -maxdepth 1 -name 'v*.sh' -type f 2>/dev/null | sort -V | while IFS= read -r migration; do
+ m_ver="$(basename "$migration" .sh | sed 's/^v//')"
+ # Run if migration is newer than last setup version AND not newer than current version
+ if [ "$(printf '%s\n%s' "$LAST_SETUP_VERSION" "$m_ver" | sort -V | head -1)" = "$LAST_SETUP_VERSION" ] && [ "$LAST_SETUP_VERSION" != "$m_ver" ] \
+ && [ "$(printf '%s\n%s' "$m_ver" "$CURRENT_VERSION" | sort -V | tail -1)" = "$CURRENT_VERSION" ]; then
+ echo " running migration $m_ver..."
+ bash "$migration" || echo " warning: migration $m_ver had errors (non-fatal)"
+ fi
+ done
+ fi
+fi
+mkdir -p "$HOME/.gstack"
+if [ "$CURRENT_VERSION" != "unknown" ]; then
+ echo "$CURRENT_VERSION" > "$HOME/.gstack/.last-setup-version"
+fi
+
+# 9. First-time welcome + legacy cleanup
if [ ! -f "$HOME/.gstack/.welcome-seen" ]; then
echo " Welcome! Run /gstack-upgrade anytime to stay current."
touch "$HOME/.gstack/.welcome-seen"