<purpose>
Check for GMD updates via npm, display changelog for versions between installed and latest, obtain user confirmation, and execute clean installation with cache clearing.
</purpose>

<required_reading>
Read all files referenced by the invoking prompt's execution_context before starting.
</required_reading>

<process>

<step name="get_installed_version">
Detect whether GMD is installed locally or globally by checking both locations and validating install integrity:

```bash
# Check local first (takes priority only if valid)
# Detect runtime config directory (supports Claude, OpenCode, Gemini)
LOCAL_VERSION_FILE="" LOCAL_MARKER_FILE="" LOCAL_DIR=""
for dir in .claude .config/opencode .opencode .gemini; do
  if [ -f "./$dir/get-magic-done/VERSION" ]; then
    LOCAL_VERSION_FILE="./$dir/get-magic-done/VERSION"
    LOCAL_MARKER_FILE="./$dir/get-magic-done/workflows/update.md"
    LOCAL_DIR="$(cd "./$dir" 2>/dev/null && pwd)"
    break
  fi
done
GLOBAL_VERSION_FILE="" GLOBAL_MARKER_FILE="" GLOBAL_DIR=""
for dir in .claude .config/opencode .opencode .gemini; do
  if [ -f "$HOME/$dir/get-magic-done/VERSION" ]; then
    GLOBAL_VERSION_FILE="$HOME/$dir/get-magic-done/VERSION"
    GLOBAL_MARKER_FILE="$HOME/$dir/get-magic-done/workflows/update.md"
    GLOBAL_DIR="$(cd "$HOME/$dir" 2>/dev/null && pwd)"
    break
  fi
done

# Only treat as LOCAL if the resolved paths differ (prevents misdetection when CWD=$HOME)
IS_LOCAL=false
if [ -n "$LOCAL_VERSION_FILE" ] && [ -f "$LOCAL_VERSION_FILE" ] && [ -f "$LOCAL_MARKER_FILE" ] && grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+' "$LOCAL_VERSION_FILE"; then
  if [ -z "$GLOBAL_DIR" ] || [ "$LOCAL_DIR" != "$GLOBAL_DIR" ]; then
    IS_LOCAL=true
  fi
fi

if [ "$IS_LOCAL" = true ]; then
  cat "$LOCAL_VERSION_FILE"
  echo "LOCAL"
elif [ -n "$GLOBAL_VERSION_FILE" ] && [ -f "$GLOBAL_VERSION_FILE" ] && [ -f "$GLOBAL_MARKER_FILE" ] && grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+' "$GLOBAL_VERSION_FILE"; then
  cat "$GLOBAL_VERSION_FILE"
  echo "GLOBAL"
else
  echo "UNKNOWN"
fi
```

Parse output:
- If last line is "LOCAL": local install is valid; installed version is first line; use `--local`
- If last line is "GLOBAL": local missing/invalid, global install is valid; installed version is first line; use `--global`
- If "UNKNOWN": proceed to install step (treat as version 0.0.0)

**If VERSION file missing:**
```
## GMD Update

**Installed version:** Unknown

Your installation doesn't include version tracking.

Running fresh install...
```

Proceed to install step (treat as version 0.0.0 for comparison).
</step>

<step name="check_latest_version">
Check npm for latest version:

```bash
npm view get-magic-done-cc version 2>/dev/null
```

**If npm check fails:**
```
Couldn't check for updates (offline or npm unavailable).

To update manually: `npx get-magic-done-cc --global`
```

Exit.
</step>

<step name="compare_versions">
Compare installed vs latest:

**If installed == latest:**
```
## GMD Update

**Installed:** X.Y.Z
**Latest:** X.Y.Z

You're already on the latest version.
```

Exit.

**If installed > latest:**
```
## GMD Update

**Installed:** X.Y.Z
**Latest:** A.B.C

You're ahead of the latest release (development version?).
```

Exit.
</step>

<step name="show_changes_and_confirm">
**If update available**, fetch and show what's new BEFORE updating:

1. Fetch changelog from GitHub raw URL
2. Extract entries between installed and latest versions
3. Display preview and ask for confirmation:

```
## GMD Update Available

**Installed:** 1.5.10
**Latest:** 1.5.15

### What's New
────────────────────────────────────────────────────────────

## [1.5.15] - 2026-01-20

### Added
- Feature X

## [1.5.14] - 2026-01-18

### Fixed
- Bug fix Y

────────────────────────────────────────────────────────────

⚠️  **Note:** The installer performs a clean install of GMD folders:
- `commands/gmd/` will be wiped and replaced
- `get-magic-done/` will be wiped and replaced
- `agents/gmd-*` files will be replaced
- Orphaned files from the previous version are automatically removed

(Paths are relative to your install location: `C:/Users/Christopher/.claude/` for global, `./.claude/` for local)

Your custom files in other locations are preserved:
- Custom commands not in `commands/gmd/` ✓
- Custom agents not prefixed with `gmd-` ✓
- Custom hooks ✓
- Your CLAUDE.md files ✓

If you've modified any GMD files directly, they'll be automatically backed up to `gmd-local-patches/` and can be reapplied with `/gmd:reapply-patches` after the update.
```

Use AskUserQuestion:
- Question: "Proceed with update?"
- Options:
  - "Yes, update now"
  - "No, cancel"

**If user cancels:** Exit.
</step>

<step name="run_update">
Run the update using the install type detected in step 1:

**If LOCAL install:**
```bash
npx -y get-magic-done-cc@latest --local
```

**If GLOBAL install (or unknown):**
```bash
npx -y get-magic-done-cc@latest --global
```

Capture output. If install fails, show error and exit.

Clear the update cache so statusline indicator disappears:

```bash
# Clear update cache across all runtime directories
for dir in .claude .config/opencode .opencode .gemini; do
  rm -f "./$dir/cache/gmd-update-check.json"
  rm -f "$HOME/$dir/cache/gmd-update-check.json"
done
```

The SessionStart hook (`gmd-check-update.js`) writes to the detected runtime's cache directory, so all paths must be cleared to prevent stale update indicators.
</step>

<step name="display_result">
Format completion message (changelog was already shown in confirmation step):

```
╔═══════════════════════════════════════════════════════════╗
║  GMD Updated: v1.5.10 → v1.5.15                           ║
╚═══════════════════════════════════════════════════════════╝

⚠️  Restart Claude Code to pick up the new commands.

[View full changelog](https://github.com/glittercowboy/get-magic-done/blob/main/CHANGELOG.md)

> **To reconfigure components:** `npx get-magic-done-cc@latest --global`
> (or `--local` for project-specific installs)
```
</step>

<step name="emit_v15_migration_banner">
v1.5 migration banner: emit ONCE per machine; idempotency tracked via the
`.cache/v1.5-banner-shown` marker file. Marker-only gating — no pre-update
version comparison. Fresh installs and upgrade-from-pre-v1.5 paths both see
the banner exactly once on their first `/gmd:update`; subsequent invocations
are silent because the marker is present.

The banner is INFORMATIONAL only. It outputs text and creates a marker file.
It does NOT touch user content, memory files, or any user-owned state beyond
the marker. The banner uses tell-don't-auto-fix language only — it tells the
user the namespace rebranded and points at CHANGELOG.md for the full
pre→post mapping; it does not promise tooling or auto-fix stale references.

```bash
# Detect cache dir from runtime (4-runtime fallback: .claude / .config/opencode / .opencode / .gemini)
CACHE_DIR=""
for dir in .claude .config/opencode .opencode .gemini; do
  if [ -d "$HOME/$dir/get-magic-done" ]; then
    CACHE_DIR="$HOME/$dir/cache"
    break
  fi
done

# Fallback: ./<dir>/cache/ for local installs
if [ -z "$CACHE_DIR" ]; then
  for dir in .claude .config/opencode .opencode .gemini; do
    if [ -d "./$dir/get-magic-done" ]; then
      CACHE_DIR="./$dir/cache"
      break
    fi
  done
fi

MARKER="$CACHE_DIR/v1.5-banner-shown"

# Emit banner ONLY if cache dir resolved AND marker missing — single-emission contract
if [ -n "$CACHE_DIR" ] && [ ! -f "$MARKER" ]; then
  cat <<'BANNER'

================================================================================
  GMD v1.5 — Slash-Namespace Rebrand
================================================================================

GMD's slash invocation pattern changed. What used to be `/gmd-plan-phase`,
`/gmd-execute-phase`, etc. is now `/gmd:plan-phase`, `/gmd:execute-phase`, etc.
(colon, not dash). This unifies every GMD slash command + skill under the same
`/gmd:` namespace.

This is a hard cutover. There are no deprecated `/gmd-<name>` aliases.

If you have personal notes, project memory files, or scripts that reference
the old `/gmd-<skill>` pattern, update them by hand. See CHANGELOG.md for the
full pre→post mapping (~40 commands, alphabetical) and migration guide:

  https://github.com/glittercowboy/get-magic-done/blob/master/CHANGELOG.md

================================================================================

BANNER

  # Mark banner as shown — idempotency contract
  mkdir -p "$CACHE_DIR"
  touch "$MARKER"
fi
```

**Idempotency contract verification:** see `tests/audit-update-banner-idempotency.cjs`
for the self-contained two-call simulation.
</step>

<step name="emit_v157_migration_banner">
v1.5.7 migration banner: emit ONCE per machine; idempotency tracked via the
`.cache/v1.5.7-banner-shown` marker file. Marker-only gating — no pre-update
version comparison. Fresh installs and upgrade-from-pre-v1.5.7 paths both see
the banner exactly once on their first `/gmd:update`; subsequent invocations
are silent because the marker is present.

The banner is INFORMATIONAL only. It explains the v1.5.7 slot reassignment
(Multi-Harness deferred to v1.8; Cross-Model Executor & Verifier shipped in
its place) and points at `/gmd:set-cross-model` + the routing matrix
reference. It does NOT touch user content, memory files, or any user-owned
state beyond the marker.

```bash
# Detect cache dir from runtime (4-runtime fallback: .claude / .config/opencode / .opencode / .gemini)
CACHE_DIR=""
for dir in .claude .config/opencode .opencode .gemini; do
  if [ -d "$HOME/$dir/get-magic-done" ]; then
    CACHE_DIR="$HOME/$dir/cache"
    break
  fi
done

# Fallback: ./<dir>/cache/ for local installs
if [ -z "$CACHE_DIR" ]; then
  for dir in .claude .config/opencode .opencode .gemini; do
    if [ -d "./$dir/get-magic-done" ]; then
      CACHE_DIR="./$dir/cache"
      break
    fi
  done
fi

MARKER="$CACHE_DIR/v1.5.7-banner-shown"

# Emit banner ONLY if cache dir resolved AND marker missing — single-emission contract
if [ -n "$CACHE_DIR" ] && [ ! -f "$MARKER" ]; then
  cat <<'BANNER'

================================================================================
 GMD v1.5.7 — Cross-Model Executor & Verifier
================================================================================

This release ships cross-model routing for gmd-executor + gmd-verifier
(Codex + Gemini at parity). Per-component gates default OFF — flip via
/gmd:set-cross-model when ready.

Slot reassignment: v1.5.7 originally scoped for Multi-Harness Orchestration
(now deferred to v1.8). v1.8 SPEC preserved at .planning/milestones/v1.8-SPEC.md.

Quick start: /gmd:set-cross-model
Docs: references/cross-model-routing-matrix.md

================================================================================

BANNER

  # Mark banner as shown — idempotency contract
  mkdir -p "$CACHE_DIR"
  touch "$MARKER"
fi
```

**Idempotency contract verification:** see `tests/audit-update-banner-idempotency.cjs`
for the self-contained two-call simulation (extends the v1.5 banner test
pattern; marker name swapped to `v1.5.7-banner-shown`).
</step>

<step name="check_local_patches">
After update completes, check if the installer detected and backed up any locally modified files:

Check for gmd-local-patches/backup-meta.json in the config directory.

**If patches found:**

```
Local patches were backed up before the update.
Run /gmd:reapply-patches to merge your modifications into the new version.
```

**If no patches:** Continue normally.
</step>

<step name="detect_obsidian_enable_flip">
Phase 24-02 (v1.3.4 Vault Resolver Hotfix, VAULT-04): detect the obsidian component flipping from disabled → enabled during this update, and — when detected — invoke `/gmd:set-vault-root` before any other vault-* commands run against the project.

**Why:** If the user re-ran the installer or re-configured components such that `components.obsidian.enabled` flipped from `false`/unset to `true`, they have NOT gone through the installer's vault-root prompt for the first time on this project (or they were on a pre-24-02 install that had no prompt). Invoking `/gmd:set-vault-root` surfaces the path they would have been prompted for at install time and eliminates the silent convention fallback that caused the v1.3 resolver mismatch.

**Detection logic (advisory):**

Compare the pre-update `components.obsidian.enabled` state (captured before `npx get-magic-done-cc@latest` ran in `run_update`) against the post-update state. Both live in the global config file at `~/.claude/get-magic-done/config.json` (or the runtime-equivalent at `$HOME/.config/opencode/...` etc.).

```bash
# Before running the update (capture baseline)
OLD_ENABLED=$(jq -r '.components.obsidian.enabled // false' "$HOME/.claude/get-magic-done/config.json" 2>/dev/null || echo "false")

# ... update runs ...

# After the update (read new state)
NEW_ENABLED=$(jq -r '.components.obsidian.enabled // false' "$HOME/.claude/get-magic-done/config.json" 2>/dev/null || echo "false")

if [ "$OLD_ENABLED" != "true" ] && [ "$NEW_ENABLED" = "true" ]; then
  echo "Obsidian component flipped disabled→enabled during this update."
  echo "Invoking /gmd:set-vault-root so the vault root is consciously set."
  # Claude executing this workflow should spawn /gmd:set-vault-root at this point.
fi
```

**When the flip is detected**, before any other vault-* command runs against this project, invoke `/gmd:set-vault-root` (the dual-surface slash command shipped in Phase 24-02). The command prompts the user for the vault root with the SPEC §18.10 convention path as the editable default, then persists the answer to `.planning/config.json` via the shared `bin/lib/planning-config.js::setVaultRoot` helper.

**When the flip is NOT detected**, skip this step. Do not re-prompt users whose obsidian component is already enabled; they've already been through `/gmd:set-vault-root` (or the installer's equivalent hook) on a prior install.

**Note for Claude executing this workflow:** This is an ADVISORY detection step — the actual spawn of `/gmd:set-vault-root` is a natural-language directive you interpret, not an automated shell step. If you detect the flip (or the update didn't cleanly expose the before/after state and you judge from conversation context that obsidian was just enabled), invoke `/gmd:set-vault-root` before proceeding with any vault-* operations.
</step>
</process>

<success_criteria>
- [ ] Installed version read correctly
- [ ] Latest version checked via npm
- [ ] Update skipped if already current
- [ ] Changelog fetched and displayed BEFORE update
- [ ] Clean install warning shown
- [ ] User confirmation obtained
- [ ] Update executed successfully
- [ ] Restart reminder shown
</success_criteria>
