[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71GTYXNPCYMPF424RNT71XA":3,"skill-same:01M71GTYXNPCYMPF424RNT71XA":70},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":32,"linkOnly":33,"markdownContent":34,"markdownBody":35,"frontMatter":36,"refName":42,"commitSha":43,"skillDirectory":44,"forksCount":45,"repositoryHtmlUrl":46,"repositoryHomepageUrl":6,"ownerHtmlUrl":47,"ownerBlogUrl":48,"ownerDescription":49,"updatedAt":50,"install":51,"resources":63},"01M71GTYXNPCYMPF424RNT71XA","vibe-upgrade",null,"Upgrade the installed vibestack pack to the latest release, run version migrations, and show what changed.","timurgaleev\u002Fvibestack","timurgaleev","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F32696429?v=4","01M71GMS53Z9B4JQTCQEFXAE9E","Timur Galeev","01M71GMS5S1Q7BEYB3Z7GY3E85",8,"MIT","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Fskills\u002Fvibe-upgrade\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31],"upgrade","vibe upgrade","vibe","show","Bash","run","read","release","true","version","migrations","latest","pack","2026-11-10 10:12:30",false,"---\nname: vibe-upgrade\ndescription: |\n  Upgrade the installed vibestack pack to the latest release, run version migrations, and show what changed.\nallowed-tools:\n  - Bash\n  - Read\n  - AskUserQuestion\ndisable-model-invocation: true\n---\n\nIf this session was compacted, the copy of this skill in context may be cut off.\nRead `${CLAUDE_SKILL_DIR}\u002FSKILL.md` from disk and resume at the step you are on.\n\n## When to invoke\n\nOnly when the user types `\u002Fvibe-upgrade`. Upgrading rewrites the installed pack, so a\npassing \"update\" in conversation, or an `UPDATE:` line from `vibe-update-check`, is not a\nrequest to run it — point to the command instead. A typed run that starts from an\n`UPDATE:` line follows the **Inline upgrade flow** below; otherwise **Standalone usage**.\n\n# \u002Fvibe-upgrade — Update vibestack to the latest release\n\nClaude Code ships a built-in `\u002Fupgrade`, so this skill stays namespaced as\n`\u002Fvibe-upgrade`. Binaries live in `~\u002F.vibestack\u002Fbin\u002F` (`vibe-config`,\n`vibe-update-check`) and mutable state lives under `~\u002F.vibestack\u002F`.\n\n## Inline upgrade flow\n\nThis section is referenced by skill preambles when they detect an available\nupdate (`UPDATE:` line from `vibe-update-check`).\n\n### Step 1: Ask the user (or auto-upgrade)\n\nFirst, check whether auto-upgrade is enabled:\n\n```bash\n_AUTO=\"\"\n[ \"${VIBESTACK_AUTO_UPGRADE:-}\" = \"1\" ] && _AUTO=\"true\"\n[ -z \"$_AUTO\" ] && _AUTO=$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" get auto_upgrade 2>\u002Fdev\u002Fnull || true)\necho \"AUTO_UPGRADE=$_AUTO\"\n```\n\n**If `AUTO_UPGRADE=true` or `AUTO_UPGRADE=1`:** Skip the question. Log\n\"Auto-upgrading vibestack v{old} → v{new}...\" and proceed directly to Step 2.\nThe upgrade blocks in Step 4 roll back automatically if `.\u002Finstall` fails during\nan auto-upgrade. Report what the block actually printed: on `RESTORED` warn\n\"Auto-upgrade failed — restored the previous version. Run `\u002Fvibe-upgrade`\nmanually to retry.\"; on `RESTORE_FAILED` say the previous version could **not**\nbe restored and relay the recovery line it printed. Never claim a restore the\nblock did not report.\n\n**Otherwise**, use AskUserQuestion:\n- Question: \"vibestack **v{new}** is available (you're on v{old}). Upgrade now?\"\n- Options: [\"Yes, upgrade now\", \"Always keep me up to date\", \"Not now\", \"Never ask again\"]\n\n**If \"Yes, upgrade now\":** Proceed to Step 2.\n\n**If \"Always keep me up to date\":**\n```bash\n\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" set auto_upgrade true\n```\nTell the user: \"Auto-upgrade enabled. Future updates install automatically.\" Then\nproceed to Step 2.\n\n**If \"Not now\":** Write a snooze marker with escalating backoff (first snooze =\n24h, second = 48h, third+ = 1 week), then continue with the skill the user\noriginally invoked. Do not mention the upgrade again this session.\n\n```bash\n_SNOOZE_FILE=\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fupdate-snoozed\"\n_REMOTE_VER=\"{new}\"\n_CUR_LEVEL=0\nif [ -f \"$_SNOOZE_FILE\" ]; then\n  _SNOOZED_VER=$(awk '{print $(1)}' \"$_SNOOZE_FILE\")\n  if [ \"$_SNOOZED_VER\" = \"$_REMOTE_VER\" ]; then\n    _CUR_LEVEL=$(awk '{print $(2)}' \"$_SNOOZE_FILE\")\n    case \"$_CUR_LEVEL\" in *[!0-9]*) _CUR_LEVEL=0 ;; esac\n  fi\nfi\n_NEW_LEVEL=$((_CUR_LEVEL + 1))\n[ \"$_NEW_LEVEL\" -gt 3 ] && _NEW_LEVEL=3\nmkdir -p \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\"\necho \"$_REMOTE_VER $_NEW_LEVEL $(date +%s)\" > \"$_SNOOZE_FILE\"\n```\nNote: substitute `{new}` (the remote version from the update-check result) for\n`_REMOTE_VER`. Tell the user the snooze duration (\"Next reminder in 24h\", or 48h,\nor 1 week, matching the level). Tip: \"Enable automatic upgrades with\n`\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" set auto_upgrade true`.\"\n\n**If \"Never ask again\":**\n```bash\n\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" set update_check false\n```\nTell the user: \"Update checks disabled. Re-enable with\n`\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" set update_check true`.\" Continue with the current\nskill.\n\n### Step 2: Locate the install\n\nEach installed skill's `bin` is a symlink back into the cloned repo\n(`\u003Ccheckout>\u002Fskills\u002F\u003Cname>\u002Fbin`); resolve one to find the primary checkout. Fall\nback to common clone paths. Then note whether it's a git checkout (normal) or a\nplain directory.\n\n```bash\nREPO=\"\"\nfor _l in \"$HOME\"\u002F.claude\u002Fskills\u002F*\u002Fbin \"$HOME\"\u002F.cursor\u002Fskills\u002F*\u002Fbin \"$HOME\"\u002F.kiro\u002Fskills\u002F*\u002Fbin \"$HOME\"\u002F.agents\u002Fskills\u002F*\u002Fbin \"${COPILOT_HOME:-$HOME\u002F.copilot}\"\u002Fskills\u002F*\u002Fbin; do\n  [ -L \"$_l\" ] || continue\n  _T=\"$(readlink \"$_l\")\"; _C=\"${_T%\u002Fskills\u002F*\u002Fbin}\"\n  [ \"$_C\" != \"$_T\" ] && [ -f \"$_C\u002Finstall\" ] && [ -f \"$_C\u002FVERSION\" ] && REPO=\"$_C\" && break\ndone\nif [ -z \"$REPO\" ] || [ ! -f \"$REPO\u002Finstall\" ]; then\n  for d in \"$HOME\u002F.claude\u002Fskills\u002Fvibestack\" \"$HOME\u002Fdata\u002Fvibestack\" \"$HOME\u002Fvibestack\" \"$HOME\u002Fcode\u002Fvibestack\"; do\n    [ -f \"$d\u002Finstall\" ] && [ -f \"$d\u002FVERSION\" ] && REPO=\"$d\" && break\n  done\nfi\nif [ -z \"$REPO\" ] || [ ! -f \"$REPO\u002Finstall\" ]; then\n  echo \"REPO_NOT_FOUND\"\nelif [ -d \"$REPO\u002F.git\" ]; then\n  echo \"REPO=$REPO INSTALL_TYPE=global-git\"\nelse\n  echo \"REPO=$REPO INSTALL_TYPE=vendored\"\nfi\n```\n\nIf `REPO_NOT_FOUND`: check for a project-local vendored copy (Step 2.5). If there\nis none either, ask the user where they cloned vibestack, then continue with that\npath. The `REPO` and `INSTALL_TYPE` printed above are used in all later steps.\n\n### Step 2.5: Detect a project-local vendored copy\n\nA team can commit a vibestack checkout into a project so teammates get it without\na global install. Detect one distinct from the primary `REPO`, and read team mode.\nReplace `\u003CREPO>` with the `REPO` Step 2 printed (an empty string on `REPO_NOT_FOUND`):\n\n```bash\nREPO='\u003CREPO>'\n_ROOT=$(git rev-parse --show-toplevel 2>\u002Fdev\u002Fnull || true)\nLOCAL_VIBESTACK=\"\"\nif [ -n \"$_ROOT\" ]; then\n  for cand in \"$_ROOT\u002F.vibestack\" \"$_ROOT\u002Fvendor\u002Fvibestack\" \"$_ROOT\u002Ftools\u002Fvibestack\"; do\n    if [ -f \"$cand\u002Finstall\" ] && [ -f \"$cand\u002FVERSION\" ]; then\n      _RESOLVED_LOCAL=$(cd \"$cand\" && pwd -P)\n      _RESOLVED_PRIMARY=$([ -n \"$REPO\" ] && cd \"$REPO\" 2>\u002Fdev\u002Fnull && pwd -P || echo \"\")\n      if [ \"$_RESOLVED_LOCAL\" != \"$_RESOLVED_PRIMARY\" ]; then\n        LOCAL_VIBESTACK=\"$cand\"; break\n      fi\n    fi\n  done\nfi\n_TEAM_MODE=$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" get team_mode 2>\u002Fdev\u002Fnull || echo \"false\")\necho \"_ROOT=$_ROOT\"\necho \"LOCAL_VIBESTACK=$LOCAL_VIBESTACK\"\necho \"TEAM_MODE=$_TEAM_MODE\"\n```\n\nIf `REPO_NOT_FOUND` but `LOCAL_VIBESTACK` is non-empty, treat `LOCAL_VIBESTACK` as\n`REPO` for the upgrade — the vendored copy is the only install here.\n\n### Step 3: Save old version\n\n```bash\nREPO='\u003CREPO>'\nOLD_VERSION=$(cat \"$REPO\u002FVERSION\" 2>\u002Fdev\u002Fnull || echo \"unknown\")\necho \"OLD_VERSION=$OLD_VERSION\"\n```\n\nCarry `OLD_VERSION` into the later steps (substitute the printed value).\n\nEvery bash block runs in a fresh shell, so nothing set in one block survives\ninto the next. Each block from here on opens with placeholder assignments such as\n`REPO='\u003CREPO>'`: replace every `\u003CREPO>`, `\u003CREPLAY>`, `\u003COLD_VERSION>`,\n`\u003CLOCAL_VIBESTACK>` and `\u003C_ROOT>` with the value the earlier step printed on its\n`NAME=` line. The mutating blocks check them first and print\n`NOT_A_VIBESTACK_INSTALL` (or `REPLAY_UNKNOWN`) instead of running `git`, `mv`\nor `rm` against an empty or wrong path.\n\n### Step 3.5: Record how the pack was installed\n\nThe upgrade re-runs `.\u002Finstall` exactly as it was originally run — the same\nruntimes, the same scope, config only where config was deployed. It never uses\n`--yes`, which means \"all five runtimes\" and would widen a Claude-only install\ninto Cursor, Kiro, Codex and Copilot CLI. The choices are read from what the install left\nbehind: the `.vibestack-manifest` in each skills root, and the config manifests\nunder `~\u002F.local\u002Fstate\u002Fvibekit\u002F`. Substitute `REPO` (Step 2) and `_ROOT` (Step\n2.5). The result is a small replay script, printed so the user can see it.\nThe optional plugin flags (`--deliberation`, `--caveman`, `--ponytail`) leave no\nmanifest, so they are not replayed; plugins already installed stay in place. Tell\nthe user to re-run `.\u002Finstall --only=config` with those flags if they want them\nrefreshed too.\n\n```bash\nREPO='\u003CREPO>'\n_ROOT='\u003C_ROOT>'\n_VH=\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\"\nREPLAY=\"$_VH\u002Fupgrade-replay.sh\"\n_STATE=\"${XDG_STATE_HOME:-$HOME\u002F.local\u002Fstate}\u002Fvibekit\"\n_USER_T=\"\"; _CFG_T=\"\"; _PROJ_T=\"\"\nfor t in claude cursor kiro codex copilot; do\n  case \"$t\" in\n    claude) r=\"$HOME\u002F.claude\u002Fskills\"; rel=\".claude\u002Fskills\" ;;\n    cursor) r=\"$HOME\u002F.cursor\u002Fskills\"; rel=\".cursor\u002Fskills\" ;;\n    kiro)   r=\"$HOME\u002F.kiro\u002Fskills\";   rel=\".kiro\u002Fskills\" ;;\n    codex)  r=\"$HOME\u002F.agents\u002Fskills\"; rel=\".agents\u002Fskills\" ;;\n    copilot) r=\"${COPILOT_HOME:-$HOME\u002F.copilot}\u002Fskills\"; rel=\".github\u002Fskills\" ;;\n  esac\n  if [ -f \"$r\u002F.vibestack-manifest\" ] || [ -f \"$r\u002Fvibe-upgrade\u002FSKILL.md\" ] \\\n     || { [ \"$t\" = codex ] && [ -f \"${CODEX_HOME:-$HOME\u002F.codex}\u002Fskills\u002Fvibe-upgrade\u002FSKILL.md\" ]; }; then\n    _USER_T=\"$_USER_T,$t\"\n  fi\n  [ -f \"$_STATE\u002Fmanifest_$t\" ] && _CFG_T=\"$_CFG_T,$t\"\n  # A project-scope install in the current repo that links back into this checkout.\n  if [ -n \"${_ROOT:-}\" ] && [ -f \"$_ROOT\u002F$rel\u002F.vibestack-manifest\" ] \\\n     && [ \"$(cd \"$_ROOT\u002F$rel\" && pwd -P)\" != \"$(cd \"$r\" 2>\u002Fdev\u002Fnull && pwd -P)\" ]; then\n    for l in \"$_ROOT\u002F$rel\"\u002F*\u002Fbin; do\n      [ -L \"$l\" ] || continue\n      case \"$(readlink \"$l\")\" in \"$REPO\"\u002Fskills\u002F*) _PROJ_T=\"$_PROJ_T,$t\"; break ;; esac\n    done\n  fi\ndone\n_USER_T=\"${_USER_T#,}\"; _CFG_T=\"${_CFG_T#,}\"; _PROJ_T=\"${_PROJ_T#,}\"\nif [ -z \"$_USER_T$_PROJ_T$_CFG_T\" ]; then\n  echo \"REPLAY_UNKNOWN — no install manifest found; cannot tell which runtimes to refresh\"\n  exit 1\nfi\n# RTK follows what the first install did, not what is on PATH: the config phase\n# leaves its hook in Claude's settings, and --no-rtk leaves none.\n_RTK=\" --no-rtk\"; grep -q 'rtk' \"$HOME\u002F.claude\u002Fsettings.json\" 2>\u002Fdev\u002Fnull && _RTK=\"\"\nmkdir -p \"$_VH\" || { echo \"REPLAY_UNWRITABLE $_VH\"; exit 1; }\n{\n  echo '#!\u002Fusr\u002Fbin\u002Fenv bash'\n  echo '# Re-runs the original .\u002Finstall choices from the checkout given as ${1}.'\n  echo 'cd \"${1}\" || exit 1'\n  if [ -n \"$_USER_T\" ]; then echo \".\u002Finstall --only=skills --target=$_USER_T || exit 1\"; fi\n  if [ -n \"$_PROJ_T\" ]; then\n    printf '.\u002Finstall --only=skills --scope=project --project-root=%q --target=%s || exit 1\\n' \"$_ROOT\" \"$_PROJ_T\"\n  fi\n  if [ -n \"$_CFG_T\" ]; then echo \".\u002Finstall --only=config --target=$_CFG_T$_RTK || exit 1\"; fi\n} > \"$REPLAY\" || { echo \"REPLAY_UNWRITABLE $REPLAY\"; exit 1; }\necho \"REPLAY=$REPLAY\"\nsed -n '4,$p' \"$REPLAY\"\n```\n\nOn `REPLAY_UNKNOWN`: nothing has changed yet. In an auto-upgrade, stop (see the\nstop rule below). Interactively, ask the user which runtimes vibestack is\ninstalled into and whether they used `--with-config`, then write `$REPLAY` with\nthose `.\u002Finstall --only=... --target=...` lines and continue. Project-scope\ninstalls in other repos are not visible from here — mention that they can be\nrefreshed by running `.\u002Finstall --scope=project ...` in each one.\n\n### Stop rule (applies to Steps 3.5 through 4.5)\n\nEvery block in Steps 3.5 through 4.5 prints exactly one outcome token. Only these\nmean success: `REPLAY=` (Step 3.5), `INSTALL_OK`, `VENDORED_UPGRADE_OK`,\n`SYNC_OK`, `VENDORED_REMOVED` (Step 4.5). Any other token — including\n`REPLAY_UNKNOWN`, `REPLAY_UNWRITABLE`, `FETCH_FAILED`, `PULL_BLOCKED`,\n`INSTALL_FAILED`, `RESTORED`, `RESTORE_FAILED`, `NOT_A_VIBESTACK_INSTALL`,\n`STALE_BACKUP`, `MKTEMP_FAILED`, `CLONE_FAILED`, `SWAP_FAILED`, `SYNC_FAILED`,\n`SYNC_SKIPPED` — or a block that printed no token, means **stop**:\n\n- Do **not** run Step 4.75 (migrations), Step 5 (marker), or Step 6 (what's new),\n  and never print the \"upgraded!\" banner.\n- Report the token and every line the block printed (recorded SHA, backup path,\n  recovery command) to the user verbatim.\n- In the inline flow, then continue with the skill the user originally invoked,\n  on the version that is actually installed.\n\nStep 4.5 is the partial case: the primary already upgraded, so a `SYNC_FAILED`,\n`SYNC_SKIPPED` or `SKIP` there does not stop Steps 4.75–6 — say the vendored copy\nwas not refreshed or removed.\n\n### Step 4: Upgrade the primary\n\nUse `REPO` and `INSTALL_TYPE` from Step 2 and `REPLAY` from Step 3.5.\n\n**For a git checkout (`global-git`):** fast-forward pull, then replay the\ninstall. Never force-push and never hard-reset — a blocked pull is reported, not\nforced, and the checkout is often a working clone with edits in it. If the\ninstall fails during an auto-upgrade, move back to the pre-pull commit with\n`git reset --keep` (which refuses rather than discard uncommitted changes) and\nreplay the install of the known-good version. Interactively, stop with the\nrecorded commit instead and let the user decide.\n\n```bash\nREPO='\u003CREPO>'\nREPLAY='\u003CREPLAY>'\ncase \"${REPO:-}\" in \u002F?*) : ;; *) echo \"NOT_A_VIBESTACK_INSTALL — REPO is empty or relative; set it to the path from Step 2\"; exit 1 ;; esac\n[ -f \"$REPO\u002Finstall\" ] && [ -f \"$REPO\u002FVERSION\" ] && [ -d \"$REPO\u002Fskills\" ] \\\n  || { echo \"NOT_A_VIBESTACK_INSTALL $REPO\"; exit 1; }\n[ -n \"${REPLAY:-}\" ] && [ -f \"$REPLAY\" ] || { echo \"REPLAY_UNKNOWN — REPLAY is unset or missing; re-run Step 3.5\"; exit 1; }\n_TOP=\"$(git -C \"$REPO\" rev-parse --show-toplevel 2>\u002Fdev\u002Fnull || true)\"\nif [ -z \"$_TOP\" ] || [ \"$(cd \"$_TOP\" && pwd -P)\" != \"$(cd \"$REPO\" && pwd -P)\" ]; then\n  echo \"NOT_A_VIBESTACK_INSTALL $REPO is not the top of its own git checkout\"; exit 1\nfi\ncd \"$REPO\" || exit 1\n_AUTO=\"\"\n[ \"${VIBESTACK_AUTO_UPGRADE:-}\" = \"1\" ] && _AUTO=\"true\"\n[ -z \"$_AUTO\" ] && _AUTO=$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" get auto_upgrade 2>\u002Fdev\u002Fnull || true)\nPREV_SHA=\"$(git rev-parse HEAD 2>\u002Fdev\u002Fnull || true)\"\nBR=\"$(git symbolic-ref --short HEAD 2>\u002Fdev\u002Fnull || echo main)\"\ngit fetch --quiet origin || { echo \"FETCH_FAILED — could not fetch origin in $REPO; nothing changed\"; exit 1; }\nif ! git pull --quiet --ff-only origin \"$BR\"; then\n  echo \"PULL_BLOCKED — local changes or non-fast-forward. Stash\u002Fcommit first, then re-run \u002Fvibe-upgrade. Not forcing.\"\n  exit 1\nfi\nif bash \"$REPLAY\" \"$REPO\"; then\n  echo \"INSTALL_OK $(cat VERSION 2>\u002Fdev\u002Fnull || echo unknown)\"\n  exit 0\nfi\nif { [ \"$_AUTO\" = \"true\" ] || [ \"$_AUTO\" = \"1\" ]; } && [ -n \"$PREV_SHA\" ]; then\n  if ! git reset --quiet --keep \"$PREV_SHA\"; then\n    echo \"RESTORE_FAILED — could not move $REPO back to $PREV_SHA without touching local changes.\"\n    echo \"  Recover by hand: run git -C \\\"$REPO\\\" status, commit or stash the files it lists,\"\n    echo \"  then: git -C \\\"$REPO\\\" reset --keep $PREV_SHA && bash \\\"$REPLAY\\\" \\\"$REPO\\\"\"\n    exit 1\n  fi\n  if bash \"$REPLAY\" \"$REPO\"; then\n    echo \"RESTORED $PREV_SHA — the new version failed to install; the previous version is installed again\"\n  else\n    echo \"RESTORE_FAILED — checkout is back at $PREV_SHA, but re-installing it also failed.\"\n    echo \"  Recover by hand: bash \\\"$REPLAY\\\" \\\"$REPO\\\"\"\n  fi\n  exit 1\nfi\necho \"INSTALL_FAILED — the checkout is now at $(git rev-parse --short HEAD 2>\u002Fdev\u002Fnull); the previous commit was $PREV_SHA.\"\necho \"  To go back: git -C \\\"$REPO\\\" reset --keep $PREV_SHA && bash \\\"$REPLAY\\\" \\\"$REPO\\\"\"\nexit 1\n```\n\n**For a plain vendored primary (`vendored`, no `.git`):** clone a fresh copy next\nto it, swap it in with a backup, replay the install, and put the backup back on\nfailure. Each move is checked, and the live install is never deleted — on a\nfailure it is either still in place or still at `$REPO.bak`.\n\n```bash\nREPO='\u003CREPO>'\nREPLAY='\u003CREPLAY>'\ncase \"${REPO:-}\" in \u002F?*) : ;; *) echo \"NOT_A_VIBESTACK_INSTALL — REPO is empty or relative; set it to the path from Step 2\"; exit 1 ;; esac\n[ -f \"$REPO\u002Finstall\" ] && [ -f \"$REPO\u002FVERSION\" ] && [ -d \"$REPO\u002Fskills\" ] || { echo \"NOT_A_VIBESTACK_INSTALL $REPO\"; exit 1; }\n[ -n \"${REPLAY:-}\" ] && [ -f \"$REPLAY\" ] || { echo \"REPLAY_UNKNOWN — REPLAY is unset or missing; re-run Step 3.5\"; exit 1; }\nif [ -e \"$REPO.bak\" ] || [ -L \"$REPO.bak\" ]; then\n  echo \"STALE_BACKUP — $REPO.bak is left over from an interrupted upgrade. Check which copy you want, move or delete $REPO.bak, then re-run \u002Fvibe-upgrade.\"\n  exit 1\nfi\nTMP_DIR=\"$(mktemp -d \"$(dirname \"$REPO\")\u002F.vibestack-upgrade.XXXXXX\")\" && [ -d \"$TMP_DIR\" ] \\\n  || { echo \"MKTEMP_FAILED — could not create a staging directory next to $REPO; nothing changed\"; exit 1; }\nif ! git clone --quiet --depth 1 https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack.git \"$TMP_DIR\u002Fvibestack\" \\\n   || [ ! -f \"$TMP_DIR\u002Fvibestack\u002Finstall\" ]; then\n  rm -rf \"$TMP_DIR\"; echo \"CLONE_FAILED — nothing changed\"; exit 1\nfi\nif ! mv \"$REPO\" \"$REPO.bak\"; then\n  rm -rf \"$TMP_DIR\"; echo \"SWAP_FAILED — could not move $REPO aside; nothing changed\"; exit 1\nfi\nif [ -e \"$REPO\" ] || ! mv \"$TMP_DIR\u002Fvibestack\" \"$REPO\"; then\n  if [ ! -e \"$REPO\" ] && mv \"$REPO.bak\" \"$REPO\"; then\n    rm -rf \"$TMP_DIR\"; echo \"SWAP_FAILED — could not move the new copy in; previous install is back at $REPO\"\n  else\n    echo \"SWAP_FAILED — RESTORE_FAILED: the previous install is kept at $REPO.bak and the new copy at $TMP_DIR. Move $REPO.bak back to $REPO by hand.\"\n  fi\n  exit 1\nfi\nif bash \"$REPLAY\" \"$REPO\"; then\n  rm -rf \"$REPO.bak\" \"$TMP_DIR\"\n  echo \"VENDORED_UPGRADE_OK $(cat \"$REPO\u002FVERSION\" 2>\u002Fdev\u002Fnull || echo unknown)\"\n  exit 0\nfi\n# The new copy failed to install: park it, put the backup back, re-install it.\nif mv \"$REPO\" \"$TMP_DIR\u002Ffailed\" && mv \"$REPO.bak\" \"$REPO\"; then\n  rm -rf \"$TMP_DIR\"\n  if bash \"$REPLAY\" \"$REPO\"; then\n    echo \"RESTORED — the new version failed to install; the previous version is installed again\"\n  else\n    echo \"RESTORE_FAILED — the previous copy is back at $REPO, but re-installing it failed. Recover: bash \\\"$REPLAY\\\" \\\"$REPO\\\"\"\n  fi\nelse\n  echo \"RESTORE_FAILED — the previous install is kept at $REPO.bak (the failed new copy is at $REPO or $TMP_DIR\u002Ffailed). Move $REPO.bak back to $REPO by hand.\"\nfi\nexit 1\n```\n\n### Step 4.5: Sync a project-local vendored copy\n\nOnly when Step 2.5 found `LOCAL_VIBESTACK` separate from the freshly-upgraded\n`REPO`. Behavior depends on `TEAM_MODE`.\n\n**If `LOCAL_VIBESTACK` is non-empty AND `TEAM_MODE` is `true`:** remove the\nvendored copy — team mode uses the global install as the single source of truth.\n\n```bash\n_ROOT='\u003C_ROOT>'\nLOCAL_VIBESTACK='\u003CLOCAL_VIBESTACK>'\n# Guard: refuse to run without a concrete vendored-copy path (never rm an empty\n# or root path). Both must be set and LOCAL_VIBESTACK must live under _ROOT.\ncase \"${_ROOT:-}\" in \u002F?*) : ;; *) echo \"SKIP — _ROOT is empty or relative; set it to the repo root from Step 2.5\"; exit 0 ;; esac\ncase \"${LOCAL_VIBESTACK:-}\" in \"$_ROOT\"\u002F?*) : ;; *) echo \"SKIP — no valid vendored copy under repo root\"; exit 0 ;; esac\n[ -f \"$LOCAL_VIBESTACK\u002Finstall\" ] && [ -f \"$LOCAL_VIBESTACK\u002FVERSION\" ] \\\n  || { echo \"SKIP — $LOCAL_VIBESTACK is not a vibestack copy\"; exit 0; }\ncd \"$_ROOT\" || { echo \"SYNC_FAILED — cannot enter $_ROOT\"; exit 1; }\n_REL=\"${LOCAL_VIBESTACK#$_ROOT\u002F}\"\ngit rm -r --cached \"$_REL\" 2>\u002Fdev\u002Fnull || true\nif ! grep -qF \"$_REL\u002F\" .gitignore 2>\u002Fdev\u002Fnull; then\n  echo \"$_REL\u002F\" >> .gitignore\nfi\nrm -rf \"$LOCAL_VIBESTACK\" || { echo \"SYNC_FAILED — could not remove $LOCAL_VIBESTACK\"; exit 1; }\necho \"VENDORED_REMOVED $LOCAL_VIBESTACK\"\n```\nOn `VENDORED_REMOVED` tell the user: \"Removed vendored copy at `$LOCAL_VIBESTACK` (team mode active —\nthe global install is the source of truth). Commit the `.gitignore` change when\nready.\"\n\n**If `LOCAL_VIBESTACK` is non-empty AND `TEAM_MODE` is NOT `true`:** refresh the\nvendored copy's files from the freshly-upgraded primary (with a backup restore on\nfailure). The global install is already up to date, so this only re-stages the\ncommitted copy — teammates run `.\u002Finstall` from it themselves. The new copy is\nstaged completely before the live one is moved, and every move is checked.\n\n```bash\nREPO='\u003CREPO>'\nLOCAL_VIBESTACK='\u003CLOCAL_VIBESTACK>'\ncase \"${LOCAL_VIBESTACK:-}\" in \u002F?*) : ;; *) echo \"SYNC_SKIPPED — no valid vendored copy path\"; exit 1 ;; esac\ncase \"${REPO:-}\" in \u002F?*) : ;; *) echo \"SYNC_SKIPPED — REPO is empty or relative; set it to the path from Step 2\"; exit 1 ;; esac\n[ -f \"$REPO\u002Finstall\" ] && [ -f \"$REPO\u002FVERSION\" ] && [ -d \"$REPO\u002Fskills\" ] \\\n  || { echo \"SYNC_SKIPPED — $REPO is not a vibestack install\"; exit 1; }\n[ -f \"$LOCAL_VIBESTACK\u002Finstall\" ] && [ -f \"$LOCAL_VIBESTACK\u002FVERSION\" ] \\\n  || { echo \"SYNC_SKIPPED — $LOCAL_VIBESTACK is not a vibestack copy\"; exit 1; }\nif [ -e \"$LOCAL_VIBESTACK.bak\" ] || [ -L \"$LOCAL_VIBESTACK.bak\" ]; then\n  echo \"SYNC_SKIPPED — $LOCAL_VIBESTACK.bak is left over from an interrupted sync; move or delete it, then re-run \u002Fvibe-upgrade\"\n  exit 1\nfi\n_STAGE=\"$(mktemp -d \"$(dirname \"$LOCAL_VIBESTACK\")\u002F.vibestack-sync.XXXXXX\")\" && [ -d \"$_STAGE\" ] \\\n  || { echo \"SYNC_FAILED — could not create a staging directory; vendored copy unchanged\"; exit 1; }\nif ! { mkdir \"$_STAGE\u002Fcopy\" && cp -R \"$REPO\u002F.\" \"$_STAGE\u002Fcopy\u002F\" && rm -rf \"$_STAGE\u002Fcopy\u002F.git\"; }; then\n  rm -rf \"$_STAGE\"; echo \"SYNC_FAILED — could not stage the new copy; vendored copy unchanged\"; exit 1\nfi\nif ! mv \"$LOCAL_VIBESTACK\" \"$LOCAL_VIBESTACK.bak\"; then\n  rm -rf \"$_STAGE\"; echo \"SYNC_FAILED — could not move the vendored copy aside; unchanged\"; exit 1\nfi\nif [ ! -e \"$LOCAL_VIBESTACK\" ] && mv \"$_STAGE\u002Fcopy\" \"$LOCAL_VIBESTACK\"; then\n  rm -rf \"$LOCAL_VIBESTACK.bak\" \"$_STAGE\"\n  echo \"SYNC_OK\"\nelif [ ! -e \"$LOCAL_VIBESTACK\" ] && mv \"$LOCAL_VIBESTACK.bak\" \"$LOCAL_VIBESTACK\"; then\n  rm -rf \"$_STAGE\"; echo \"SYNC_FAILED — restored the previous version at $LOCAL_VIBESTACK\"; exit 1\nelse\n  echo \"SYNC_FAILED — the previous vendored copy is kept at $LOCAL_VIBESTACK.bak; move it back by hand\"; exit 1\nfi\n```\nOn `SYNC_OK` tell the user: \"Also refreshed the vendored copy at\n`$LOCAL_VIBESTACK` — commit it when you're ready.\" On `SYNC_FAILED` or\n`SYNC_SKIPPED` relay the printed line and say the vendored copy was not\nrefreshed; run `\u002Fvibe-upgrade` manually to retry once it is resolved.\n\n### Step 4.75: Run version migrations\n\nOnly after Step 4 printed `INSTALL_OK` or `VENDORED_UPGRADE_OK` (see the stop\nrule), run any migration scripts for versions between the\nold and new version. Migrations handle state fixes `.\u002Finstall` alone can't cover\n(stale config, orphaned files, directory-structure changes). Substitute\n`OLD_VERSION` and `REPO` from earlier steps. Each migration gets the install\ndirectory as `VIBESTACK_INSTALL_DIR`, so it works for a project-local copy as\nwell as the global checkout.\n\n```bash\nREPO='\u003CREPO>'\nOLD_VERSION='\u003COLD_VERSION>'\ncase \"${REPO:-}\" in \u002F?*) : ;; *) echo \"MIGRATIONS_SKIPPED — REPO is empty or relative; set it to the path from Step 2\"; exit 1 ;; esac\ncase \"${OLD_VERSION:-}\" in ''|'\u003C'*) echo \"MIGRATIONS_SKIPPED — OLD_VERSION is unset; set it to the value printed by Step 3\"; exit 1 ;; esac\nMIGRATIONS_DIR=\"$REPO\u002Fskills\u002Fvibe-upgrade\u002Fmigrations\"\nif [ -d \"$MIGRATIONS_DIR\" ]; then\n  for migration in $(find \"$MIGRATIONS_DIR\" -maxdepth 1 -name 'v*.sh' -type f 2>\u002Fdev\u002Fnull | sort -V); do\n    m_ver=\"$(basename \"$migration\" .sh | sed 's\u002F^v\u002F\u002F')\"\n    if [ \"$OLD_VERSION\" != \"unknown\" ] && [ \"$(printf '%s\\n%s' \"$OLD_VERSION\" \"$m_ver\" | sort -V | head -1)\" = \"$OLD_VERSION\" ] && [ \"$OLD_VERSION\" != \"$m_ver\" ]; then\n      echo \"Running migration $m_ver...\"\n      VIBESTACK_INSTALL_DIR=\"$REPO\" bash \"$migration\" || echo \"  Warning: migration $m_ver had errors (non-fatal)\"\n    fi\n  done\nfi\n```\n\nMigrations are idempotent bash scripts in `skills\u002Fvibe-upgrade\u002Fmigrations\u002F`, each\nnamed `v{VERSION}.sh`, run only when upgrading from an older version. See\n`skills\u002Fvibe-upgrade\u002Fmigrations\u002FREADME.md` for how to add one.\n\n### Step 5: Write marker + clear cache\n\nOnly after a successful Step 4. The marker drives the next session's what's-new\nmessage, so writing it after a failed or rolled-back upgrade would announce a\nversion that is not installed.\n\n```bash\nOLD_VERSION='\u003COLD_VERSION>'\nmkdir -p \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\"\necho \"$OLD_VERSION\" > \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fjust-upgraded-from\"\nrm -f \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002F.update-check-stamp\" \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002F.update-check-failed\"\nrm -f \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fupdate-snoozed\"\n```\n\n### Step 6: Show what's new\n\nRead `$REPO\u002FCHANGELOG.md`. Find every version entry between the old and new\nversion and summarize as 5–7 bullets grouped by theme. Focus on user-facing\nchanges; skip internal refactors unless significant.\n\n```\nvibestack v{new} — upgraded from v{old}!\n\nWhat's new:\n- [bullet 1]\n- [bullet 2]\n- ...\n\nHappy shipping!\n```\n\nNote that a new agent session may be needed if the host doesn't hot-reload skills.\n\n### Step 7: Continue\n\nAfter showing what's new, continue with whatever skill the user originally\ninvoked. The upgrade is done — no further action needed.\n\n---\n\n## Standalone usage\n\nWhen invoked directly as `\u002Fvibe-upgrade` (not from a preamble), the user has\nalready opted in — skip the Step 1 question and go straight to the upgrade.\n\n1. Force a fresh update check (bypasses the once\u002Fday throttle, snooze, and the\n   `update_check` gate):\n```bash\n\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-update-check\" --force 2>\u002Fdev\u002Fnull || true\n```\nAn `UPDATE: vibestack \u003Cnew> is available (you have \u003Cold>)` line means an upgrade\nis available; no output means the primary is already current. A\n`CHECK_FAILED \u003Creason>` line means the update status is **unknown** — the remote\ncould not be read. Never report \"already on the latest version\" in that case.\nTell the user the check failed and why (the line names the remote and the\ncheckout), then use AskUserQuestion: \"Try the upgrade anyway?\" with options\n[\"Yes, run the upgrade\", \"No, stop here\"]. On yes, continue as in point 2 —\npulling an already-current checkout is harmless. On no, stop.\n\n2. **If an update is available:** run Step 2 and Step 2.5 to locate the install,\n   then follow Steps 3–6 (skip Step 1 — the invocation is the consent), obeying\n   the stop rule.\n\n3. **If no update** (primary is current): run Step 2 and Step 2.5 to check for a\n   stale project-local vendored copy.\n\n   - **`LOCAL_VIBESTACK` empty** (no vendored copy): tell the user \"You're already\n     on the latest version (v{version}).\"\n   - **`LOCAL_VIBESTACK` non-empty AND `TEAM_MODE` is `true`:** remove it with the\n     team-mode removal block in Step 4.5. Tell the user: \"Global v{version} is up\n     to date. Removed the stale vendored copy (team mode active). Commit the\n     `.gitignore` change when ready.\"\n   - **`LOCAL_VIBESTACK` non-empty AND `TEAM_MODE` is NOT `true`:** compare\n     versions:\n     ```bash\n     REPO='\u003CREPO>'\n     LOCAL_VIBESTACK='\u003CLOCAL_VIBESTACK>'\n     PRIMARY_VER=$(cat \"$REPO\u002FVERSION\" 2>\u002Fdev\u002Fnull || echo \"unknown\")\n     LOCAL_VER=$(cat \"$LOCAL_VIBESTACK\u002FVERSION\" 2>\u002Fdev\u002Fnull || echo \"unknown\")\n     echo \"PRIMARY=$PRIMARY_VER LOCAL=$LOCAL_VER\"\n     ```\n     - **Versions differ:** run the non-team sync block in Step 4.5. Tell the user:\n       \"Global v{PRIMARY_VER} is up to date. Refreshed the local vendored copy from\n       v{LOCAL_VER} → v{PRIMARY_VER}. Commit it when you're ready.\"\n     - **Versions match:** tell the user \"You're on the latest version\n       (v{PRIMARY_VER}). Global and vendored copy are both up to date.\"\n\n**Never force-push, and never hard-reset.** A blocked pull is reported, not\noverridden. The only reset is the scoped auto-upgrade rollback in Step 4 — a\n`git reset --keep` to the commit you were just on, which refuses rather than\ndiscard local changes. Never re-install with `--yes`; always replay the original\ninstall from Step 3.5.\n","If this session was compacted, the copy of this skill in context may be cut off.\nRead `${CLAUDE_SKILL_DIR}\u002FSKILL.md` from disk and resume at the step you are on.\n\n## When to invoke\n\nOnly when the user types `\u002Fvibe-upgrade`. Upgrading rewrites the installed pack, so a\npassing \"update\" in conversation, or an `UPDATE:` line from `vibe-update-check`, is not a\nrequest to run it — point to the command instead. A typed run that starts from an\n`UPDATE:` line follows the **Inline upgrade flow** below; otherwise **Standalone usage**.\n\n# \u002Fvibe-upgrade — Update vibestack to the latest release\n\nClaude Code ships a built-in `\u002Fupgrade`, so this skill stays namespaced as\n`\u002Fvibe-upgrade`. Binaries live in `~\u002F.vibestack\u002Fbin\u002F` (`vibe-config`,\n`vibe-update-check`) and mutable state lives under `~\u002F.vibestack\u002F`.\n\n## Inline upgrade flow\n\nThis section is referenced by skill preambles when they detect an available\nupdate (`UPDATE:` line from `vibe-update-check`).\n\n### Step 1: Ask the user (or auto-upgrade)\n\nFirst, check whether auto-upgrade is enabled:\n\n```bash\n_AUTO=\"\"\n[ \"${VIBESTACK_AUTO_UPGRADE:-}\" = \"1\" ] && _AUTO=\"true\"\n[ -z \"$_AUTO\" ] && _AUTO=$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" get auto_upgrade 2>\u002Fdev\u002Fnull || true)\necho \"AUTO_UPGRADE=$_AUTO\"\n```\n\n**If `AUTO_UPGRADE=true` or `AUTO_UPGRADE=1`:** Skip the question. Log\n\"Auto-upgrading vibestack v{old} → v{new}...\" and proceed directly to Step 2.\nThe upgrade blocks in Step 4 roll back automatically if `.\u002Finstall` fails during\nan auto-upgrade. Report what the block actually printed: on `RESTORED` warn\n\"Auto-upgrade failed — restored the previous version. Run `\u002Fvibe-upgrade`\nmanually to retry.\"; on `RESTORE_FAILED` say the previous version could **not**\nbe restored and relay the recovery line it printed. Never claim a restore the\nblock did not report.\n\n**Otherwise**, use AskUserQuestion:\n- Question: \"vibestack **v{new}** is available (you're on v{old}). Upgrade now?\"\n- Options: [\"Yes, upgrade now\", \"Always keep me up to date\", \"Not now\", \"Never ask again\"]\n\n**If \"Yes, upgrade now\":** Proceed to Step 2.\n\n**If \"Always keep me up to date\":**\n```bash\n\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" set auto_upgrade true\n```\nTell the user: \"Auto-upgrade enabled. Future updates install automatically.\" Then\nproceed to Step 2.\n\n**If \"Not now\":** Write a snooze marker with escalating backoff (first snooze =\n24h, second = 48h, third+ = 1 week), then continue with the skill the user\noriginally invoked. Do not mention the upgrade again this session.\n\n```bash\n_SNOOZE_FILE=\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fupdate-snoozed\"\n_REMOTE_VER=\"{new}\"\n_CUR_LEVEL=0\nif [ -f \"$_SNOOZE_FILE\" ]; then\n  _SNOOZED_VER=$(awk '{print $(1)}' \"$_SNOOZE_FILE\")\n  if [ \"$_SNOOZED_VER\" = \"$_REMOTE_VER\" ]; then\n    _CUR_LEVEL=$(awk '{print $(2)}' \"$_SNOOZE_FILE\")\n    case \"$_CUR_LEVEL\" in *[!0-9]*) _CUR_LEVEL=0 ;; esac\n  fi\nfi\n_NEW_LEVEL=$((_CUR_LEVEL + 1))\n[ \"$_NEW_LEVEL\" -gt 3 ] && _NEW_LEVEL=3\nmkdir -p \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\"\necho \"$_REMOTE_VER $_NEW_LEVEL $(date +%s)\" > \"$_SNOOZE_FILE\"\n```\nNote: substitute `{new}` (the remote version from the update-check result) for\n`_REMOTE_VER`. Tell the user the snooze duration (\"Next reminder in 24h\", or 48h,\nor 1 week, matching the level). Tip: \"Enable automatic upgrades with\n`\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" set auto_upgrade true`.\"\n\n**If \"Never ask again\":**\n```bash\n\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" set update_check false\n```\nTell the user: \"Update checks disabled. Re-enable with\n`\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" set update_check true`.\" Continue with the current\nskill.\n\n### Step 2: Locate the install\n\nEach installed skill's `bin` is a symlink back into the cloned repo\n(`\u003Ccheckout>\u002Fskills\u002F\u003Cname>\u002Fbin`); resolve one to find the primary checkout. Fall\nback to common clone paths. Then note whether it's a git checkout (normal) or a\nplain directory.\n\n```bash\nREPO=\"\"\nfor _l in \"$HOME\"\u002F.claude\u002Fskills\u002F*\u002Fbin \"$HOME\"\u002F.cursor\u002Fskills\u002F*\u002Fbin \"$HOME\"\u002F.kiro\u002Fskills\u002F*\u002Fbin \"$HOME\"\u002F.agents\u002Fskills\u002F*\u002Fbin \"${COPILOT_HOME:-$HOME\u002F.copilot}\"\u002Fskills\u002F*\u002Fbin; do\n  [ -L \"$_l\" ] || continue\n  _T=\"$(readlink \"$_l\")\"; _C=\"${_T%\u002Fskills\u002F*\u002Fbin}\"\n  [ \"$_C\" != \"$_T\" ] && [ -f \"$_C\u002Finstall\" ] && [ -f \"$_C\u002FVERSION\" ] && REPO=\"$_C\" && break\ndone\nif [ -z \"$REPO\" ] || [ ! -f \"$REPO\u002Finstall\" ]; then\n  for d in \"$HOME\u002F.claude\u002Fskills\u002Fvibestack\" \"$HOME\u002Fdata\u002Fvibestack\" \"$HOME\u002Fvibestack\" \"$HOME\u002Fcode\u002Fvibestack\"; do\n    [ -f \"$d\u002Finstall\" ] && [ -f \"$d\u002FVERSION\" ] && REPO=\"$d\" && break\n  done\nfi\nif [ -z \"$REPO\" ] || [ ! -f \"$REPO\u002Finstall\" ]; then\n  echo \"REPO_NOT_FOUND\"\nelif [ -d \"$REPO\u002F.git\" ]; then\n  echo \"REPO=$REPO INSTALL_TYPE=global-git\"\nelse\n  echo \"REPO=$REPO INSTALL_TYPE=vendored\"\nfi\n```\n\nIf `REPO_NOT_FOUND`: check for a project-local vendored copy (Step 2.5). If there\nis none either, ask the user where they cloned vibestack, then continue with that\npath. The `REPO` and `INSTALL_TYPE` printed above are used in all later steps.\n\n### Step 2.5: Detect a project-local vendored copy\n\nA team can commit a vibestack checkout into a project so teammates get it without\na global install. Detect one distinct from the primary `REPO`, and read team mode.\nReplace `\u003CREPO>` with the `REPO` Step 2 printed (an empty string on `REPO_NOT_FOUND`):\n\n```bash\nREPO='\u003CREPO>'\n_ROOT=$(git rev-parse --show-toplevel 2>\u002Fdev\u002Fnull || true)\nLOCAL_VIBESTACK=\"\"\nif [ -n \"$_ROOT\" ]; then\n  for cand in \"$_ROOT\u002F.vibestack\" \"$_ROOT\u002Fvendor\u002Fvibestack\" \"$_ROOT\u002Ftools\u002Fvibestack\"; do\n    if [ -f \"$cand\u002Finstall\" ] && [ -f \"$cand\u002FVERSION\" ]; then\n      _RESOLVED_LOCAL=$(cd \"$cand\" && pwd -P)\n      _RESOLVED_PRIMARY=$([ -n \"$REPO\" ] && cd \"$REPO\" 2>\u002Fdev\u002Fnull && pwd -P || echo \"\")\n      if [ \"$_RESOLVED_LOCAL\" != \"$_RESOLVED_PRIMARY\" ]; then\n        LOCAL_VIBESTACK=\"$cand\"; break\n      fi\n    fi\n  done\nfi\n_TEAM_MODE=$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" get team_mode 2>\u002Fdev\u002Fnull || echo \"false\")\necho \"_ROOT=$_ROOT\"\necho \"LOCAL_VIBESTACK=$LOCAL_VIBESTACK\"\necho \"TEAM_MODE=$_TEAM_MODE\"\n```\n\nIf `REPO_NOT_FOUND` but `LOCAL_VIBESTACK` is non-empty, treat `LOCAL_VIBESTACK` as\n`REPO` for the upgrade — the vendored copy is the only install here.\n\n### Step 3: Save old version\n\n```bash\nREPO='\u003CREPO>'\nOLD_VERSION=$(cat \"$REPO\u002FVERSION\" 2>\u002Fdev\u002Fnull || echo \"unknown\")\necho \"OLD_VERSION=$OLD_VERSION\"\n```\n\nCarry `OLD_VERSION` into the later steps (substitute the printed value).\n\nEvery bash block runs in a fresh shell, so nothing set in one block survives\ninto the next. Each block from here on opens with placeholder assignments such as\n`REPO='\u003CREPO>'`: replace every `\u003CREPO>`, `\u003CREPLAY>`, `\u003COLD_VERSION>`,\n`\u003CLOCAL_VIBESTACK>` and `\u003C_ROOT>` with the value the earlier step printed on its\n`NAME=` line. The mutating blocks check them first and print\n`NOT_A_VIBESTACK_INSTALL` (or `REPLAY_UNKNOWN`) instead of running `git`, `mv`\nor `rm` against an empty or wrong path.\n\n### Step 3.5: Record how the pack was installed\n\nThe upgrade re-runs `.\u002Finstall` exactly as it was originally run — the same\nruntimes, the same scope, config only where config was deployed. It never uses\n`--yes`, which means \"all five runtimes\" and would widen a Claude-only install\ninto Cursor, Kiro, Codex and Copilot CLI. The choices are read from what the install left\nbehind: the `.vibestack-manifest` in each skills root, and the config manifests\nunder `~\u002F.local\u002Fstate\u002Fvibekit\u002F`. Substitute `REPO` (Step 2) and `_ROOT` (Step\n2.5). The result is a small replay script, printed so the user can see it.\nThe optional plugin flags (`--deliberation`, `--caveman`, `--ponytail`) leave no\nmanifest, so they are not replayed; plugins already installed stay in place. Tell\nthe user to re-run `.\u002Finstall --only=config` with those flags if they want them\nrefreshed too.\n\n```bash\nREPO='\u003CREPO>'\n_ROOT='\u003C_ROOT>'\n_VH=\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\"\nREPLAY=\"$_VH\u002Fupgrade-replay.sh\"\n_STATE=\"${XDG_STATE_HOME:-$HOME\u002F.local\u002Fstate}\u002Fvibekit\"\n_USER_T=\"\"; _CFG_T=\"\"; _PROJ_T=\"\"\nfor t in claude cursor kiro codex copilot; do\n  case \"$t\" in\n    claude) r=\"$HOME\u002F.claude\u002Fskills\"; rel=\".claude\u002Fskills\" ;;\n    cursor) r=\"$HOME\u002F.cursor\u002Fskills\"; rel=\".cursor\u002Fskills\" ;;\n    kiro)   r=\"$HOME\u002F.kiro\u002Fskills\";   rel=\".kiro\u002Fskills\" ;;\n    codex)  r=\"$HOME\u002F.agents\u002Fskills\"; rel=\".agents\u002Fskills\" ;;\n    copilot) r=\"${COPILOT_HOME:-$HOME\u002F.copilot}\u002Fskills\"; rel=\".github\u002Fskills\" ;;\n  esac\n  if [ -f \"$r\u002F.vibestack-manifest\" ] || [ -f \"$r\u002Fvibe-upgrade\u002FSKILL.md\" ] \\\n     || { [ \"$t\" = codex ] && [ -f \"${CODEX_HOME:-$HOME\u002F.codex}\u002Fskills\u002Fvibe-upgrade\u002FSKILL.md\" ]; }; then\n    _USER_T=\"$_USER_T,$t\"\n  fi\n  [ -f \"$_STATE\u002Fmanifest_$t\" ] && _CFG_T=\"$_CFG_T,$t\"\n  # A project-scope install in the current repo that links back into this checkout.\n  if [ -n \"${_ROOT:-}\" ] && [ -f \"$_ROOT\u002F$rel\u002F.vibestack-manifest\" ] \\\n     && [ \"$(cd \"$_ROOT\u002F$rel\" && pwd -P)\" != \"$(cd \"$r\" 2>\u002Fdev\u002Fnull && pwd -P)\" ]; then\n    for l in \"$_ROOT\u002F$rel\"\u002F*\u002Fbin; do\n      [ -L \"$l\" ] || continue\n      case \"$(readlink \"$l\")\" in \"$REPO\"\u002Fskills\u002F*) _PROJ_T=\"$_PROJ_T,$t\"; break ;; esac\n    done\n  fi\ndone\n_USER_T=\"${_USER_T#,}\"; _CFG_T=\"${_CFG_T#,}\"; _PROJ_T=\"${_PROJ_T#,}\"\nif [ -z \"$_USER_T$_PROJ_T$_CFG_T\" ]; then\n  echo \"REPLAY_UNKNOWN — no install manifest found; cannot tell which runtimes to refresh\"\n  exit 1\nfi\n# RTK follows what the first install did, not what is on PATH: the config phase\n# leaves its hook in Claude's settings, and --no-rtk leaves none.\n_RTK=\" --no-rtk\"; grep -q 'rtk' \"$HOME\u002F.claude\u002Fsettings.json\" 2>\u002Fdev\u002Fnull && _RTK=\"\"\nmkdir -p \"$_VH\" || { echo \"REPLAY_UNWRITABLE $_VH\"; exit 1; }\n{\n  echo '#!\u002Fusr\u002Fbin\u002Fenv bash'\n  echo '# Re-runs the original .\u002Finstall choices from the checkout given as ${1}.'\n  echo 'cd \"${1}\" || exit 1'\n  if [ -n \"$_USER_T\" ]; then echo \".\u002Finstall --only=skills --target=$_USER_T || exit 1\"; fi\n  if [ -n \"$_PROJ_T\" ]; then\n    printf '.\u002Finstall --only=skills --scope=project --project-root=%q --target=%s || exit 1\\n' \"$_ROOT\" \"$_PROJ_T\"\n  fi\n  if [ -n \"$_CFG_T\" ]; then echo \".\u002Finstall --only=config --target=$_CFG_T$_RTK || exit 1\"; fi\n} > \"$REPLAY\" || { echo \"REPLAY_UNWRITABLE $REPLAY\"; exit 1; }\necho \"REPLAY=$REPLAY\"\nsed -n '4,$p' \"$REPLAY\"\n```\n\nOn `REPLAY_UNKNOWN`: nothing has changed yet. In an auto-upgrade, stop (see the\nstop rule below). Interactively, ask the user which runtimes vibestack is\ninstalled into and whether they used `--with-config`, then write `$REPLAY` with\nthose `.\u002Finstall --only=... --target=...` lines and continue. Project-scope\ninstalls in other repos are not visible from here — mention that they can be\nrefreshed by running `.\u002Finstall --scope=project ...` in each one.\n\n### Stop rule (applies to Steps 3.5 through 4.5)\n\nEvery block in Steps 3.5 through 4.5 prints exactly one outcome token. Only these\nmean success: `REPLAY=` (Step 3.5), `INSTALL_OK`, `VENDORED_UPGRADE_OK`,\n`SYNC_OK`, `VENDORED_REMOVED` (Step 4.5). Any other token — including\n`REPLAY_UNKNOWN`, `REPLAY_UNWRITABLE`, `FETCH_FAILED`, `PULL_BLOCKED`,\n`INSTALL_FAILED`, `RESTORED`, `RESTORE_FAILED`, `NOT_A_VIBESTACK_INSTALL`,\n`STALE_BACKUP`, `MKTEMP_FAILED`, `CLONE_FAILED`, `SWAP_FAILED`, `SYNC_FAILED`,\n`SYNC_SKIPPED` — or a block that printed no token, means **stop**:\n\n- Do **not** run Step 4.75 (migrations), Step 5 (marker), or Step 6 (what's new),\n  and never print the \"upgraded!\" banner.\n- Report the token and every line the block printed (recorded SHA, backup path,\n  recovery command) to the user verbatim.\n- In the inline flow, then continue with the skill the user originally invoked,\n  on the version that is actually installed.\n\nStep 4.5 is the partial case: the primary already upgraded, so a `SYNC_FAILED`,\n`SYNC_SKIPPED` or `SKIP` there does not stop Steps 4.75–6 — say the vendored copy\nwas not refreshed or removed.\n\n### Step 4: Upgrade the primary\n\nUse `REPO` and `INSTALL_TYPE` from Step 2 and `REPLAY` from Step 3.5.\n\n**For a git checkout (`global-git`):** fast-forward pull, then replay the\ninstall. Never force-push and never hard-reset — a blocked pull is reported, not\nforced, and the checkout is often a working clone with edits in it. If the\ninstall fails during an auto-upgrade, move back to the pre-pull commit with\n`git reset --keep` (which refuses rather than discard uncommitted changes) and\nreplay the install of the known-good version. Interactively, stop with the\nrecorded commit instead and let the user decide.\n\n```bash\nREPO='\u003CREPO>'\nREPLAY='\u003CREPLAY>'\ncase \"${REPO:-}\" in \u002F?*) : ;; *) echo \"NOT_A_VIBESTACK_INSTALL — REPO is empty or relative; set it to the path from Step 2\"; exit 1 ;; esac\n[ -f \"$REPO\u002Finstall\" ] && [ -f \"$REPO\u002FVERSION\" ] && [ -d \"$REPO\u002Fskills\" ] \\\n  || { echo \"NOT_A_VIBESTACK_INSTALL $REPO\"; exit 1; }\n[ -n \"${REPLAY:-}\" ] && [ -f \"$REPLAY\" ] || { echo \"REPLAY_UNKNOWN — REPLAY is unset or missing; re-run Step 3.5\"; exit 1; }\n_TOP=\"$(git -C \"$REPO\" rev-parse --show-toplevel 2>\u002Fdev\u002Fnull || true)\"\nif [ -z \"$_TOP\" ] || [ \"$(cd \"$_TOP\" && pwd -P)\" != \"$(cd \"$REPO\" && pwd -P)\" ]; then\n  echo \"NOT_A_VIBESTACK_INSTALL $REPO is not the top of its own git checkout\"; exit 1\nfi\ncd \"$REPO\" || exit 1\n_AUTO=\"\"\n[ \"${VIBESTACK_AUTO_UPGRADE:-}\" = \"1\" ] && _AUTO=\"true\"\n[ -z \"$_AUTO\" ] && _AUTO=$(\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-config\" get auto_upgrade 2>\u002Fdev\u002Fnull || true)\nPREV_SHA=\"$(git rev-parse HEAD 2>\u002Fdev\u002Fnull || true)\"\nBR=\"$(git symbolic-ref --short HEAD 2>\u002Fdev\u002Fnull || echo main)\"\ngit fetch --quiet origin || { echo \"FETCH_FAILED — could not fetch origin in $REPO; nothing changed\"; exit 1; }\nif ! git pull --quiet --ff-only origin \"$BR\"; then\n  echo \"PULL_BLOCKED — local changes or non-fast-forward. Stash\u002Fcommit first, then re-run \u002Fvibe-upgrade. Not forcing.\"\n  exit 1\nfi\nif bash \"$REPLAY\" \"$REPO\"; then\n  echo \"INSTALL_OK $(cat VERSION 2>\u002Fdev\u002Fnull || echo unknown)\"\n  exit 0\nfi\nif { [ \"$_AUTO\" = \"true\" ] || [ \"$_AUTO\" = \"1\" ]; } && [ -n \"$PREV_SHA\" ]; then\n  if ! git reset --quiet --keep \"$PREV_SHA\"; then\n    echo \"RESTORE_FAILED — could not move $REPO back to $PREV_SHA without touching local changes.\"\n    echo \"  Recover by hand: run git -C \\\"$REPO\\\" status, commit or stash the files it lists,\"\n    echo \"  then: git -C \\\"$REPO\\\" reset --keep $PREV_SHA && bash \\\"$REPLAY\\\" \\\"$REPO\\\"\"\n    exit 1\n  fi\n  if bash \"$REPLAY\" \"$REPO\"; then\n    echo \"RESTORED $PREV_SHA — the new version failed to install; the previous version is installed again\"\n  else\n    echo \"RESTORE_FAILED — checkout is back at $PREV_SHA, but re-installing it also failed.\"\n    echo \"  Recover by hand: bash \\\"$REPLAY\\\" \\\"$REPO\\\"\"\n  fi\n  exit 1\nfi\necho \"INSTALL_FAILED — the checkout is now at $(git rev-parse --short HEAD 2>\u002Fdev\u002Fnull); the previous commit was $PREV_SHA.\"\necho \"  To go back: git -C \\\"$REPO\\\" reset --keep $PREV_SHA && bash \\\"$REPLAY\\\" \\\"$REPO\\\"\"\nexit 1\n```\n\n**For a plain vendored primary (`vendored`, no `.git`):** clone a fresh copy next\nto it, swap it in with a backup, replay the install, and put the backup back on\nfailure. Each move is checked, and the live install is never deleted — on a\nfailure it is either still in place or still at `$REPO.bak`.\n\n```bash\nREPO='\u003CREPO>'\nREPLAY='\u003CREPLAY>'\ncase \"${REPO:-}\" in \u002F?*) : ;; *) echo \"NOT_A_VIBESTACK_INSTALL — REPO is empty or relative; set it to the path from Step 2\"; exit 1 ;; esac\n[ -f \"$REPO\u002Finstall\" ] && [ -f \"$REPO\u002FVERSION\" ] && [ -d \"$REPO\u002Fskills\" ] || { echo \"NOT_A_VIBESTACK_INSTALL $REPO\"; exit 1; }\n[ -n \"${REPLAY:-}\" ] && [ -f \"$REPLAY\" ] || { echo \"REPLAY_UNKNOWN — REPLAY is unset or missing; re-run Step 3.5\"; exit 1; }\nif [ -e \"$REPO.bak\" ] || [ -L \"$REPO.bak\" ]; then\n  echo \"STALE_BACKUP — $REPO.bak is left over from an interrupted upgrade. Check which copy you want, move or delete $REPO.bak, then re-run \u002Fvibe-upgrade.\"\n  exit 1\nfi\nTMP_DIR=\"$(mktemp -d \"$(dirname \"$REPO\")\u002F.vibestack-upgrade.XXXXXX\")\" && [ -d \"$TMP_DIR\" ] \\\n  || { echo \"MKTEMP_FAILED — could not create a staging directory next to $REPO; nothing changed\"; exit 1; }\nif ! git clone --quiet --depth 1 https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack.git \"$TMP_DIR\u002Fvibestack\" \\\n   || [ ! -f \"$TMP_DIR\u002Fvibestack\u002Finstall\" ]; then\n  rm -rf \"$TMP_DIR\"; echo \"CLONE_FAILED — nothing changed\"; exit 1\nfi\nif ! mv \"$REPO\" \"$REPO.bak\"; then\n  rm -rf \"$TMP_DIR\"; echo \"SWAP_FAILED — could not move $REPO aside; nothing changed\"; exit 1\nfi\nif [ -e \"$REPO\" ] || ! mv \"$TMP_DIR\u002Fvibestack\" \"$REPO\"; then\n  if [ ! -e \"$REPO\" ] && mv \"$REPO.bak\" \"$REPO\"; then\n    rm -rf \"$TMP_DIR\"; echo \"SWAP_FAILED — could not move the new copy in; previous install is back at $REPO\"\n  else\n    echo \"SWAP_FAILED — RESTORE_FAILED: the previous install is kept at $REPO.bak and the new copy at $TMP_DIR. Move $REPO.bak back to $REPO by hand.\"\n  fi\n  exit 1\nfi\nif bash \"$REPLAY\" \"$REPO\"; then\n  rm -rf \"$REPO.bak\" \"$TMP_DIR\"\n  echo \"VENDORED_UPGRADE_OK $(cat \"$REPO\u002FVERSION\" 2>\u002Fdev\u002Fnull || echo unknown)\"\n  exit 0\nfi\n# The new copy failed to install: park it, put the backup back, re-install it.\nif mv \"$REPO\" \"$TMP_DIR\u002Ffailed\" && mv \"$REPO.bak\" \"$REPO\"; then\n  rm -rf \"$TMP_DIR\"\n  if bash \"$REPLAY\" \"$REPO\"; then\n    echo \"RESTORED — the new version failed to install; the previous version is installed again\"\n  else\n    echo \"RESTORE_FAILED — the previous copy is back at $REPO, but re-installing it failed. Recover: bash \\\"$REPLAY\\\" \\\"$REPO\\\"\"\n  fi\nelse\n  echo \"RESTORE_FAILED — the previous install is kept at $REPO.bak (the failed new copy is at $REPO or $TMP_DIR\u002Ffailed). Move $REPO.bak back to $REPO by hand.\"\nfi\nexit 1\n```\n\n### Step 4.5: Sync a project-local vendored copy\n\nOnly when Step 2.5 found `LOCAL_VIBESTACK` separate from the freshly-upgraded\n`REPO`. Behavior depends on `TEAM_MODE`.\n\n**If `LOCAL_VIBESTACK` is non-empty AND `TEAM_MODE` is `true`:** remove the\nvendored copy — team mode uses the global install as the single source of truth.\n\n```bash\n_ROOT='\u003C_ROOT>'\nLOCAL_VIBESTACK='\u003CLOCAL_VIBESTACK>'\n# Guard: refuse to run without a concrete vendored-copy path (never rm an empty\n# or root path). Both must be set and LOCAL_VIBESTACK must live under _ROOT.\ncase \"${_ROOT:-}\" in \u002F?*) : ;; *) echo \"SKIP — _ROOT is empty or relative; set it to the repo root from Step 2.5\"; exit 0 ;; esac\ncase \"${LOCAL_VIBESTACK:-}\" in \"$_ROOT\"\u002F?*) : ;; *) echo \"SKIP — no valid vendored copy under repo root\"; exit 0 ;; esac\n[ -f \"$LOCAL_VIBESTACK\u002Finstall\" ] && [ -f \"$LOCAL_VIBESTACK\u002FVERSION\" ] \\\n  || { echo \"SKIP — $LOCAL_VIBESTACK is not a vibestack copy\"; exit 0; }\ncd \"$_ROOT\" || { echo \"SYNC_FAILED — cannot enter $_ROOT\"; exit 1; }\n_REL=\"${LOCAL_VIBESTACK#$_ROOT\u002F}\"\ngit rm -r --cached \"$_REL\" 2>\u002Fdev\u002Fnull || true\nif ! grep -qF \"$_REL\u002F\" .gitignore 2>\u002Fdev\u002Fnull; then\n  echo \"$_REL\u002F\" >> .gitignore\nfi\nrm -rf \"$LOCAL_VIBESTACK\" || { echo \"SYNC_FAILED — could not remove $LOCAL_VIBESTACK\"; exit 1; }\necho \"VENDORED_REMOVED $LOCAL_VIBESTACK\"\n```\nOn `VENDORED_REMOVED` tell the user: \"Removed vendored copy at `$LOCAL_VIBESTACK` (team mode active —\nthe global install is the source of truth). Commit the `.gitignore` change when\nready.\"\n\n**If `LOCAL_VIBESTACK` is non-empty AND `TEAM_MODE` is NOT `true`:** refresh the\nvendored copy's files from the freshly-upgraded primary (with a backup restore on\nfailure). The global install is already up to date, so this only re-stages the\ncommitted copy — teammates run `.\u002Finstall` from it themselves. The new copy is\nstaged completely before the live one is moved, and every move is checked.\n\n```bash\nREPO='\u003CREPO>'\nLOCAL_VIBESTACK='\u003CLOCAL_VIBESTACK>'\ncase \"${LOCAL_VIBESTACK:-}\" in \u002F?*) : ;; *) echo \"SYNC_SKIPPED — no valid vendored copy path\"; exit 1 ;; esac\ncase \"${REPO:-}\" in \u002F?*) : ;; *) echo \"SYNC_SKIPPED — REPO is empty or relative; set it to the path from Step 2\"; exit 1 ;; esac\n[ -f \"$REPO\u002Finstall\" ] && [ -f \"$REPO\u002FVERSION\" ] && [ -d \"$REPO\u002Fskills\" ] \\\n  || { echo \"SYNC_SKIPPED — $REPO is not a vibestack install\"; exit 1; }\n[ -f \"$LOCAL_VIBESTACK\u002Finstall\" ] && [ -f \"$LOCAL_VIBESTACK\u002FVERSION\" ] \\\n  || { echo \"SYNC_SKIPPED — $LOCAL_VIBESTACK is not a vibestack copy\"; exit 1; }\nif [ -e \"$LOCAL_VIBESTACK.bak\" ] || [ -L \"$LOCAL_VIBESTACK.bak\" ]; then\n  echo \"SYNC_SKIPPED — $LOCAL_VIBESTACK.bak is left over from an interrupted sync; move or delete it, then re-run \u002Fvibe-upgrade\"\n  exit 1\nfi\n_STAGE=\"$(mktemp -d \"$(dirname \"$LOCAL_VIBESTACK\")\u002F.vibestack-sync.XXXXXX\")\" && [ -d \"$_STAGE\" ] \\\n  || { echo \"SYNC_FAILED — could not create a staging directory; vendored copy unchanged\"; exit 1; }\nif ! { mkdir \"$_STAGE\u002Fcopy\" && cp -R \"$REPO\u002F.\" \"$_STAGE\u002Fcopy\u002F\" && rm -rf \"$_STAGE\u002Fcopy\u002F.git\"; }; then\n  rm -rf \"$_STAGE\"; echo \"SYNC_FAILED — could not stage the new copy; vendored copy unchanged\"; exit 1\nfi\nif ! mv \"$LOCAL_VIBESTACK\" \"$LOCAL_VIBESTACK.bak\"; then\n  rm -rf \"$_STAGE\"; echo \"SYNC_FAILED — could not move the vendored copy aside; unchanged\"; exit 1\nfi\nif [ ! -e \"$LOCAL_VIBESTACK\" ] && mv \"$_STAGE\u002Fcopy\" \"$LOCAL_VIBESTACK\"; then\n  rm -rf \"$LOCAL_VIBESTACK.bak\" \"$_STAGE\"\n  echo \"SYNC_OK\"\nelif [ ! -e \"$LOCAL_VIBESTACK\" ] && mv \"$LOCAL_VIBESTACK.bak\" \"$LOCAL_VIBESTACK\"; then\n  rm -rf \"$_STAGE\"; echo \"SYNC_FAILED — restored the previous version at $LOCAL_VIBESTACK\"; exit 1\nelse\n  echo \"SYNC_FAILED — the previous vendored copy is kept at $LOCAL_VIBESTACK.bak; move it back by hand\"; exit 1\nfi\n```\nOn `SYNC_OK` tell the user: \"Also refreshed the vendored copy at\n`$LOCAL_VIBESTACK` — commit it when you're ready.\" On `SYNC_FAILED` or\n`SYNC_SKIPPED` relay the printed line and say the vendored copy was not\nrefreshed; run `\u002Fvibe-upgrade` manually to retry once it is resolved.\n\n### Step 4.75: Run version migrations\n\nOnly after Step 4 printed `INSTALL_OK` or `VENDORED_UPGRADE_OK` (see the stop\nrule), run any migration scripts for versions between the\nold and new version. Migrations handle state fixes `.\u002Finstall` alone can't cover\n(stale config, orphaned files, directory-structure changes). Substitute\n`OLD_VERSION` and `REPO` from earlier steps. Each migration gets the install\ndirectory as `VIBESTACK_INSTALL_DIR`, so it works for a project-local copy as\nwell as the global checkout.\n\n```bash\nREPO='\u003CREPO>'\nOLD_VERSION='\u003COLD_VERSION>'\ncase \"${REPO:-}\" in \u002F?*) : ;; *) echo \"MIGRATIONS_SKIPPED — REPO is empty or relative; set it to the path from Step 2\"; exit 1 ;; esac\ncase \"${OLD_VERSION:-}\" in ''|'\u003C'*) echo \"MIGRATIONS_SKIPPED — OLD_VERSION is unset; set it to the value printed by Step 3\"; exit 1 ;; esac\nMIGRATIONS_DIR=\"$REPO\u002Fskills\u002Fvibe-upgrade\u002Fmigrations\"\nif [ -d \"$MIGRATIONS_DIR\" ]; then\n  for migration in $(find \"$MIGRATIONS_DIR\" -maxdepth 1 -name 'v*.sh' -type f 2>\u002Fdev\u002Fnull | sort -V); do\n    m_ver=\"$(basename \"$migration\" .sh | sed 's\u002F^v\u002F\u002F')\"\n    if [ \"$OLD_VERSION\" != \"unknown\" ] && [ \"$(printf '%s\\n%s' \"$OLD_VERSION\" \"$m_ver\" | sort -V | head -1)\" = \"$OLD_VERSION\" ] && [ \"$OLD_VERSION\" != \"$m_ver\" ]; then\n      echo \"Running migration $m_ver...\"\n      VIBESTACK_INSTALL_DIR=\"$REPO\" bash \"$migration\" || echo \"  Warning: migration $m_ver had errors (non-fatal)\"\n    fi\n  done\nfi\n```\n\nMigrations are idempotent bash scripts in `skills\u002Fvibe-upgrade\u002Fmigrations\u002F`, each\nnamed `v{VERSION}.sh`, run only when upgrading from an older version. See\n`skills\u002Fvibe-upgrade\u002Fmigrations\u002FREADME.md` for how to add one.\n\n### Step 5: Write marker + clear cache\n\nOnly after a successful Step 4. The marker drives the next session's what's-new\nmessage, so writing it after a failed or rolled-back upgrade would announce a\nversion that is not installed.\n\n```bash\nOLD_VERSION='\u003COLD_VERSION>'\nmkdir -p \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\"\necho \"$OLD_VERSION\" > \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fjust-upgraded-from\"\nrm -f \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002F.update-check-stamp\" \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002F.update-check-failed\"\nrm -f \"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fupdate-snoozed\"\n```\n\n### Step 6: Show what's new\n\nRead `$REPO\u002FCHANGELOG.md`. Find every version entry between the old and new\nversion and summarize as 5–7 bullets grouped by theme. Focus on user-facing\nchanges; skip internal refactors unless significant.\n\n```\nvibestack v{new} — upgraded from v{old}!\n\nWhat's new:\n- [bullet 1]\n- [bullet 2]\n- ...\n\nHappy shipping!\n```\n\nNote that a new agent session may be needed if the host doesn't hot-reload skills.\n\n### Step 7: Continue\n\nAfter showing what's new, continue with whatever skill the user originally\ninvoked. The upgrade is done — no further action needed.\n\n---\n\n## Standalone usage\n\nWhen invoked directly as `\u002Fvibe-upgrade` (not from a preamble), the user has\nalready opted in — skip the Step 1 question and go straight to the upgrade.\n\n1. Force a fresh update check (bypasses the once\u002Fday throttle, snooze, and the\n   `update_check` gate):\n```bash\n\"${VIBESTACK_HOME:-$HOME\u002F.vibestack}\u002Fbin\u002Fvibe-update-check\" --force 2>\u002Fdev\u002Fnull || true\n```\nAn `UPDATE: vibestack \u003Cnew> is available (you have \u003Cold>)` line means an upgrade\nis available; no output means the primary is already current. A\n`CHECK_FAILED \u003Creason>` line means the update status is **unknown** — the remote\ncould not be read. Never report \"already on the latest version\" in that case.\nTell the user the check failed and why (the line names the remote and the\ncheckout), then use AskUserQuestion: \"Try the upgrade anyway?\" with options\n[\"Yes, run the upgrade\", \"No, stop here\"]. On yes, continue as in point 2 —\npulling an already-current checkout is harmless. On no, stop.\n\n2. **If an update is available:** run Step 2 and Step 2.5 to locate the install,\n   then follow Steps 3–6 (skip Step 1 — the invocation is the consent), obeying\n   the stop rule.\n\n3. **If no update** (primary is current): run Step 2 and Step 2.5 to check for a\n   stale project-local vendored copy.\n\n   - **`LOCAL_VIBESTACK` empty** (no vendored copy): tell the user \"You're already\n     on the latest version (v{version}).\"\n   - **`LOCAL_VIBESTACK` non-empty AND `TEAM_MODE` is `true`:** remove it with the\n     team-mode removal block in Step 4.5. Tell the user: \"Global v{version} is up\n     to date. Removed the stale vendored copy (team mode active). Commit the\n     `.gitignore` change when ready.\"\n   - **`LOCAL_VIBESTACK` non-empty AND `TEAM_MODE` is NOT `true`:** compare\n     versions:\n     ```bash\n     REPO='\u003CREPO>'\n     LOCAL_VIBESTACK='\u003CLOCAL_VIBESTACK>'\n     PRIMARY_VER=$(cat \"$REPO\u002FVERSION\" 2>\u002Fdev\u002Fnull || echo \"unknown\")\n     LOCAL_VER=$(cat \"$LOCAL_VIBESTACK\u002FVERSION\" 2>\u002Fdev\u002Fnull || echo \"unknown\")\n     echo \"PRIMARY=$PRIMARY_VER LOCAL=$LOCAL_VER\"\n     ```\n     - **Versions differ:** run the non-team sync block in Step 4.5. Tell the user:\n       \"Global v{PRIMARY_VER} is up to date. Refreshed the local vendored copy from\n       v{LOCAL_VER} → v{PRIMARY_VER}. Commit it when you're ready.\"\n     - **Versions match:** tell the user \"You're on the latest version\n       (v{PRIMARY_VER}). Global and vendored copy are both up to date.\"\n\n**Never force-push, and never hard-reset.** A blocked pull is reported, not\noverridden. The only reset is the scoped auto-upgrade rollback in Step 4 — a\n`git reset --keep` to the commit you were just on, which refuses rather than\ndiscard local changes. Never re-install with `--yes`; always replay the original\ninstall from Step 3.5.\n",{"name":5,"description":37,"allowed-tools":38,"disable-model-invocation":41},"Upgrade the installed vibestack pack to the latest release, run version migrations, and show what changed.\n",[23,39,40],"Read","AskUserQuestion",true,"main","777ec643a83c17a0955856b2eb7f596601709fda","skills\u002Fvibe-upgrade",0,"https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack","https:\u002F\u002Fgithub.com\u002Ftimurgaleev","https:\u002F\u002Ftgaleev.com\u002F","Forward Deployed Engineer \u002F\r\nAWS Community Builder \u002F Cloud Architect ","2026-11-11 04:50:32",{"source":8,"skillName":5,"commands":52,"prompt":62,"zipAvailable":41},[53,56,59],{"tool":54,"command":55},"npx","npx skills add timurgaleev\u002Fvibestack --skill vibe-upgrade",{"tool":57,"command":58},"bunx","bunx skills add timurgaleev\u002Fvibestack --skill vibe-upgrade",{"tool":60,"command":61},"pnpm","pnpm dlx skills add timurgaleev\u002Fvibestack --skill vibe-upgrade","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Fskills\u002Fvibe-upgrade\u002FSKILL.md",[64],{"path":65,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":68,"sourceHtmlUrl":69},"migrations\u002FREADME.md","REFERENCE","参考文档",1064,"https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Fskills\u002Fvibe-upgrade\u002Fmigrations\u002FREADME.md",[71,77,83,89,95,101],{"skillNo":72,"name":73,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":74,"categories":75,"keywords":76,"publishedAt":32},"01M71GVHCCSQCCPVM8XPSPTA73","docs","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F15-backtick-info-string\u002Fskills\u002Fdocs\u002FSKILL.md",[],[73],{"skillNo":78,"name":79,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":82,"publishedAt":32},"01M71GVFT1S5MRNM0AYRT2E6VQ","fences","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F14-indented-tilde-fence\u002Fskills\u002Ffences\u002FSKILL.md",[],[79],{"skillNo":84,"name":85,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":32},"01M71GVEYB54K1S83FGRNKN8CF","dirty","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F10-check-with-drift\u002Fskills\u002Fdirty\u002FSKILL.md",[],[85],{"skillNo":90,"name":91,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":94,"publishedAt":32},"01M71GVDX9PMND1337C4388DK4","clean","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F09-check-no-drift\u002Fskills\u002Fclean\u002FSKILL.md",[],[91],{"skillNo":96,"name":97,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":100,"publishedAt":32},"01M71GVC3VM66F1ZQT2G8JXDR0","bare","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F08-no-frontmatter\u002Fskills\u002Fbare\u002FSKILL.md",[],[97],{"skillNo":102,"name":103,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":106,"publishedAt":32},"01M71GV9T8DAYZT0PX52QX0TE1","idem","https:\u002F\u002Fgithub.com\u002Ftimurgaleev\u002Fvibestack\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frender\u002F07-idempotent-rerender\u002Fskills\u002Fidem\u002FSKILL.md",[],[103]]