gstack-upgrade
Upgrade gstack to the latest version. Detects global vs vendored install, runs the upgrade, and shows what's new.
Security score
The gstack-upgrade skill was audited on Mar 16, 2026 and we found 20 security issues across 2 threat categories. Review the findings below before installing.
Categories Tested
Security Issues
Command substitution pattern
| 28 | _AUTO="" |
| 29 | [ "${GSTACK_AUTO_UPGRADE:-}" = "1" ] && _AUTO="true" |
| 30 | [ -z "$_AUTO" ] && _AUTO=$(~/.claude/skills/gstack/bin/gstack-config get auto_upgrade 2>/dev/null || true) |
| 31 | echo "AUTO_UPGRADE=$_AUTO" |
| 32 | ``` |
Command substitution pattern
| 52 | _CUR_LEVEL=0 |
| 53 | if [ -f "$_SNOOZE_FILE" ]; then |
| 54 | _SNOOZED_VER=$(awk '{print $1}' "$_SNOOZE_FILE") |
| 55 | if [ "$_SNOOZED_VER" = "$_REMOTE_VER" ]; then |
| 56 | _CUR_LEVEL=$(awk '{print $2}' "$_SNOOZE_FILE") |
Command substitution pattern
| 54 | _SNOOZED_VER=$(awk '{print $1}' "$_SNOOZE_FILE") |
| 55 | if [ "$_SNOOZED_VER" = "$_REMOTE_VER" ]; then |
| 56 | _CUR_LEVEL=$(awk '{print $2}' "$_SNOOZE_FILE") |
| 57 | case "$_CUR_LEVEL" in *[!0-9]*) _CUR_LEVEL=0 ;; esac |
| 58 | fi |
Command substitution pattern
| 58 | fi |
| 59 | fi |
| 60 | _NEW_LEVEL=$((_CUR_LEVEL + 1)) |
| 61 | [ "$_NEW_LEVEL" -gt 3 ] && _NEW_LEVEL=3 |
| 62 | echo "$_REMOTE_VER $_NEW_LEVEL $(date +%s)" > "$_SNOOZE_FILE" |
Command substitution pattern
| 98 | |
| 99 | ```bash |
| 100 | OLD_VERSION=$(cat "$INSTALL_DIR/VERSION" 2>/dev/null || echo "unknown") |
| 101 | ``` |
| 102 |
Command substitution pattern
| 106 | ```bash |
| 107 | cd "$INSTALL_DIR" |
| 108 | STASH_OUTPUT=$(git stash 2>&1) |
| 109 | git fetch origin |
| 110 | git reset --hard origin/main |
Command substitution pattern
| 115 | **For vendored installs** (vendored, vendored-global): |
| 116 | ```bash |
| 117 | PARENT=$(dirname "$INSTALL_DIR") |
| 118 | TMP_DIR=$(mktemp -d) |
| 119 | git clone --depth 1 https://github.com/garrytan/gstack.git "$TMP_DIR/gstack" |
Command substitution pattern
| 129 | |
| 130 | ```bash |
| 131 | _ROOT=$(git rev-parse --show-toplevel 2>/dev/null) |
| 132 | LOCAL_GSTACK="" |
| 133 | if [ -n "$_ROOT" ] && [ -d "$_ROOT/.claude/skills/gstack" ]; then |
Command substitution pattern
| 132 | LOCAL_GSTACK="" |
| 133 | if [ -n "$_ROOT" ] && [ -d "$_ROOT/.claude/skills/gstack" ]; then |
| 134 | _RESOLVED_LOCAL=$(cd "$_ROOT/.claude/skills/gstack" && pwd -P) |
| 135 | _RESOLVED_PRIMARY=$(cd "$INSTALL_DIR" && pwd -P) |
| 136 | if [ "$_RESOLVED_LOCAL" != "$_RESOLVED_PRIMARY" ]; then |
Command substitution pattern
| 133 | if [ -n "$_ROOT" ] && [ -d "$_ROOT/.claude/skills/gstack" ]; then |
| 134 | _RESOLVED_LOCAL=$(cd "$_ROOT/.claude/skills/gstack" && pwd -P) |
| 135 | _RESOLVED_PRIMARY=$(cd "$INSTALL_DIR" && pwd -P) |
| 136 | if [ "$_RESOLVED_LOCAL" != "$_RESOLVED_PRIMARY" ]; then |
| 137 | LOCAL_GSTACK="$_ROOT/.claude/skills/gstack" |
Access to home directory dotfiles
| 28 | _AUTO="" |
| 29 | [ "${GSTACK_AUTO_UPGRADE:-}" = "1" ] && _AUTO="true" |
| 30 | [ -z "$_AUTO" ] && _AUTO=$(~/.claude/skills/gstack/bin/gstack-config get auto_upgrade 2>/dev/null || true) |
| 31 | echo "AUTO_UPGRADE=$_AUTO" |
| 32 | ``` |
Access to home directory dotfiles
| 42 | **If "Always keep me up to date":** |
| 43 | ```bash |
| 44 | ~/.claude/skills/gstack/bin/gstack-config set auto_upgrade true |
| 45 | ``` |
| 46 | Tell user: "Auto-upgrade enabled. Future updates will install automatically." Then proceed to Step 2. |
Access to home directory dotfiles
| 48 | **If "Not now":** Write snooze state with escalating backoff (first snooze = 24h, second = 48h, third+ = 1 week), then continue with the current skill. Do not mention the upgrade again. |
| 49 | ```bash |
| 50 | _SNOOZE_FILE=~/.gstack/update-snoozed |
| 51 | _REMOTE_VER="{new}" |
| 52 | _CUR_LEVEL=0 |
Access to home directory dotfiles
| 64 | Note: `{new}` is the remote version from the `UPGRADE_AVAILABLE` output — substitute it from the update check result. |
| 65 | |
| 66 | Tell user the snooze duration: "Next reminder in 24h" (or 48h or 1 week, depending on level). Tip: "Set `auto_upgrade: true` in `~/.gstack/config.yaml` for automatic upgrades." |
| 67 | |
| 68 | **If "Never ask again":** |
Access to home directory dotfiles
| 68 | **If "Never ask again":** |
| 69 | ```bash |
| 70 | ~/.claude/skills/gstack/bin/gstack-config set update_check false |
| 71 | ``` |
| 72 | Tell user: "Update checks disabled. Run `~/.claude/skills/gstack/bin/gstack-config set update_check true` to re-enable." |
Access to home directory dotfiles
| 70 | ~/.claude/skills/gstack/bin/gstack-config set update_check false |
| 71 | ``` |
| 72 | Tell user: "Update checks disabled. Run `~/.claude/skills/gstack/bin/gstack-config set update_check true` to re-enable." |
| 73 | Continue with the current skill. |
| 74 |
Access to home directory dotfiles
| 154 | |
| 155 | ```bash |
| 156 | mkdir -p ~/.gstack |
| 157 | echo "$OLD_VERSION" > ~/.gstack/just-upgraded-from |
| 158 | rm -f ~/.gstack/last-update-check |
Access to home directory dotfiles
| 155 | ```bash |
| 156 | mkdir -p ~/.gstack |
| 157 | echo "$OLD_VERSION" > ~/.gstack/just-upgraded-from |
| 158 | rm -f ~/.gstack/last-update-check |
| 159 | rm -f ~/.gstack/update-snoozed |
Access to home directory dotfiles
| 156 | mkdir -p ~/.gstack |
| 157 | echo "$OLD_VERSION" > ~/.gstack/just-upgraded-from |
| 158 | rm -f ~/.gstack/last-update-check |
| 159 | rm -f ~/.gstack/update-snoozed |
| 160 | ``` |
Access to home directory dotfiles
| 157 | echo "$OLD_VERSION" > ~/.gstack/just-upgraded-from |
| 158 | rm -f ~/.gstack/last-update-check |
| 159 | rm -f ~/.gstack/update-snoozed |
| 160 | ``` |
| 161 |