---
description: "Update the pipeline to the latest published npm release: registry check, npm pack, install, migrate. Use when the installed pipeline is behind and should be brought to the latest version."
description-tr: "Pipeline'ı npm'deki son yayına günceller: registry kontrolü, npm pack, install, migrate."
allowed-tools: Bash, Read, Write, AskUserQuestion
parameters: []
gui: button
destructive: false
confirm: none
---

## After the install, check it

```bash
node "$HOME/.claude/scripts/doctor.mjs"
```

An update is the moment the layout changes, so it is the moment a layout check is
worth most: a script that moved, a host tree that did not get the copy, a version
stamp that disagrees with the package. Report the result in `outputLanguage`.
Exit 2 means the update left the install in a state a run will fail from - say
that, do not report "updated" and stop.

# multi-agent update

Update the pipeline in one command. The npm registry is the single update channel: the latest published release is downloaded and installed. Existing preferences are preserved; only skill / script / schema files are refreshed.

A git clone of the pipeline repo is a maintainer workspace, kept in sync by `/multi-agent:sync` - it is never consulted here. A fix that only exists on `main` reaches users when a release is published, not before.

## Steps

Every fenced block below runs in a fresh shell, so no variable survives from one
block to the next. Step 1 writes the values the later steps need to a state file,
and every later block that needs them starts by sourcing it.

1. **Resolve the package and both versions**:
   ```bash
   STATE="${TMPDIR:-/tmp}/multi-agent-update.env"
   PKG="@{npm-scope}/multi-agent-pipeline"
   REG="https://registry.npmjs.org"
   UPD_DIR="${TMPDIR:-/tmp}/multi-agent-update"
   CUR=$(tr -d '[:space:]' < "$HOME/.claude/.pipeline-version" 2>/dev/null)
   [ -n "$CUR" ] || CUR="unknown"
   # Read the registry directly - `npm view` can answer from a stale local cache.
   LATEST=$(curl -fsS "$REG/$(printf '%s' "$PKG" | sed 's|/|%2F|')/latest" \
     | node -pe 'JSON.parse(require("fs").readFileSync(0,"utf8")).version' 2>/dev/null)
   if [ -z "$LATEST" ]; then
     echo "Registry unreachable ($REG) - check your network and retry."
     exit 1
   fi
   # dist-tags.required is the supported-version floor (absent on most releases).
   REQUIRED=$(curl -fsS -H 'Accept: application/vnd.npm.install-v1+json' \
     "$REG/$(printf '%s' "$PKG" | sed 's|/|%2F|')" \
     | node -pe 'JSON.parse(require("fs").readFileSync(0,"utf8"))["dist-tags"].required || ""' 2>/dev/null)
   printf 'PKG=%q\nREG=%q\nUPD_DIR=%q\nCUR=%q\nLATEST=%q\n' \
     "$PKG" "$REG" "$UPD_DIR" "$CUR" "$LATEST" > "$STATE"
   echo "Current: v$CUR   Latest: v$LATEST${REQUIRED:+   Required floor: v$REQUIRED}"
   ```

   This command is never blocked by the floor  -  it is the remedy for it. The
   line above is where the floor is reported, so the user sees why a run halted.

2. **Stop early when already current.** When the line below prints, skip
   step 3 (no download, no reinstall) and continue at step 4b, so the stack
   plugins are still refreshed:
   ```bash
   . "${TMPDIR:-/tmp}/multi-agent-update.env" || { echo "Run step 1 first."; exit 1; }
   [ "$CUR" = "$LATEST" ] && echo "✓ Already up to date: v$LATEST"
   ```

3. **Download the release and install**:
   ```bash
   . "${TMPDIR:-/tmp}/multi-agent-update.env" || { echo "Run step 1 first."; exit 1; }
   rm -rf "$UPD_DIR" && mkdir -p "$UPD_DIR"
   # `--registry` does NOT override a scope mapping. A user-level .npmrc line
   # like `@scope:registry=https://npm.pkg.github.com` wins over it, so the
   # download hits the wrong registry, fails with `notarget`, and `--silent`
   # hides why. Pin the SCOPE, which is the setting that actually loses.
   SCOPE=$(printf '%s' "$PKG" | sed -n 's|^@\([^/]*\)/.*|\1|p')
   PACK_OUT=$(npm pack "$PKG@$LATEST" ${SCOPE:+"--@${SCOPE}:registry=$REG"} \
     --registry "$REG" --pack-destination "$UPD_DIR" 2>&1) || {
     echo "Download failed for $PKG@$LATEST:"; printf '%s\n' "$PACK_OUT"
     echo "If this says 'notarget', an .npmrc scope mapping is routing @${SCOPE} elsewhere:"
     echo "  npm config get @${SCOPE}:registry"
     exit 1
   }
   # Never glob into tar: an older tarball left in $UPD_DIR would be extracted
   # instead, and the run would install the version it was trying to leave.
   TGZ="$UPD_DIR/$(printf '%s' "$PACK_OUT" | tail -1 | tr -d '[:space:]')"
   [ -f "$TGZ" ] || { echo "npm pack reported no tarball; aborting."; exit 1; }
   tar -xzf "$TGZ" -C "$UPD_DIR"
   node "$UPD_DIR/package/install.js" --installed
   ```

   `--installed` refreshes exactly the CLI targets that already carry a version
   stamp (`$HOME/.claude/.pipeline-version`, `$HOME/.copilot/.pipeline-version`,
   `$HOME/.codex/.pipeline-version`) and adds none: an update never installs
   Copilot CLI or Codex CLI on a machine that only had Claude Code. With no stamp
   at all it installs Claude Code. Each refreshed target gets the new version
   stamp.

4b. **Update the stack plugins** (catalog refresh, then every installed plugin in its own scope):
   ```bash
   REFRESH_LOG="${TMPDIR:-/tmp}/multi-agent-plugin-refresh.log"
   bash "$HOME/.claude/scripts/plugin-refresh.sh" {owner} > "$REFRESH_LOG" 2>&1
   rc=$?
   cat "$REFRESH_LOG"
   echo "plugin-refresh exit: $rc"
   ```
   A non-zero exit means a step failed and the CLI's own error is already on screen. Report it to the user; do not retry silently. The log feeds step 6, which tells the user what each updated plugin brought.

4c. **Prune retired adapter files** (Cursor / Antigravity / Copilot Chat were removed in v10.7.0 - the pipeline targets Claude Code, Copilot CLI and Codex CLI):
   ```bash
   # Per-project adapter files (.cursor/, .agent/, .github/copilot-instructions.md)
   # live in your repos and are left untouched - remove them manually if you like.
   echo "  -> no global adapter files to prune"
   ```

   > **Do NOT delete `$HOME/.codex/prompts/multi-agent.md`.** The Codex installer
   > writes it and it backs the `/multi-agent` slash command on Codex CLI.

5. **Migrate preferences** (if there is an old schema):
   ```bash
   if [ -f "$HOME/.claude/scripts/migrate-prefs.mjs" ]; then
     node "$HOME/.claude/scripts/migrate-prefs.mjs"
   fi
   ```

5b. **Auto-configure operational reporting.** One call, the same one
   `/multi-agent:setup` and a first run make, so a machine is registered by
   whichever of the three runs first.

   ```bash
   node "$HOME/.claude/scripts/usage-register.mjs" --json
   ```

   It requests a per-machine **write-only** token when none resolves, stores it
   only in the credential store, and flips `usageLog.enabled` on. `usageLog.optOut:
   true` blocks it permanently. Offline, endpoint down or ingest disabled leaves
   reporting off with one status line - never an error. Contract and the data it
   sends: `$HOME/.claude/multi-agent-refs/features/usage-reporting.md`.

   If its JSON line says `"needsPersonalAccount":true`, offer once: `gh auth login`,
   or an SSH key on the personal account (the "Personal account" step in
   `$HOME/.claude/multi-agent-refs/features/usage-reporting.md`).

6. **Tell the user what the update brought.** Read the notes, then write the summary yourself:
   ```bash
   . "${TMPDIR:-/tmp}/multi-agent-update.env" || { echo "Run step 1 first."; exit 1; }
   NEW=$(tr -d '[:space:]' < "$HOME/.claude/.pipeline-version" 2>/dev/null)
   NOTES="$UPD_DIR/package/pipeline/scripts/release-notes.mjs"
   [ -f "$NOTES" ] || NOTES="$HOME/.claude/scripts/release-notes.mjs"
   LOG="$UPD_DIR/package/CHANGELOG.md"
   [ -f "$LOG" ] || LOG=/nonexistent
   node "$NOTES" --changelog "$LOG" --from "$CUR" --to "$NEW" \
     --plugins-dir "$HOME/.claude/plugins/marketplaces/multi-agent-plugins/plugins" \
     --plugin-refresh-log "${TMPDIR:-/tmp}/multi-agent-plugin-refresh.log"
   ```

   The JSON holds every release between the old and the new version (not only
   the last one) and, for each plugin the refresh moved, that plugin's releases.
   Turn it into a short note in `outputLanguage`, written for the person using
   the pipeline, not for its maintainers:

   - First line: `✓ Updated: v<CUR> → v<NEW>`, then one line per updated plugin
     (`ai-ios-toolkit 0.20.0 → 0.21.0`).
   - Then up to four groups, each only when it has entries: **New** (added),
     **Fixed**, **Changed**, **Removed** (Turkish: Yeni, Düzeltilen, Değişen,
     Kaldırılan). Put security entries first under Fixed.
   - One plain sentence per item about what the user notices or can now do.
     Merge items that say the same thing; leave out internal-only entries
     (smoke tests, CI, refactors, budgets, docs) unless they change what a user
     sees. At most about eight items per group; when more were dropped, say how
     many and that the full list is in the CHANGELOG.
   - Use only what the JSON says. Never invent a feature or a fix, and never
     guess why something changed.
   - Last line, when anything needs action: what to do (restart Claude Code for
     plugin changes, run a command a release asks for).

   With empty notes and no plugin updates, print only the version line.

7. **Smoke test (optional)** - the release tarball ships exactly two smokes for this purpose:
   ```bash
   . "${TMPDIR:-/tmp}/multi-agent-update.env" || { echo "Run step 1 first."; exit 1; }
   echo ""
   echo "Verification:"
   bash "$UPD_DIR/package/pipeline/scripts/smoke-schema-validation.sh" 2>&1 | tail -1
   bash "$UPD_DIR/package/pipeline/scripts/smoke-cross-cli-behavior.sh" 2>&1 | tail -1
   rm -rf "$UPD_DIR" "${TMPDIR:-/tmp}/multi-agent-update.env"
   ```

## Output

```
Current: v15.6.0   Latest: v15.7.0
  -> npm pack @{npm-scope}/multi-agent-pipeline@15.7.0
  -> node install.js --installed (Claude Code; no Copilot CLI or Codex CLI stamp, not installed)
  -> migrate-prefs.mjs (0 changes  -  already v2.6.0)

✓ Updated: v15.6.0 → v15.7.0
  ai-ios-toolkit 0.19.0 → 0.20.0

New
  - iOS design review: critiques a screen against the HIG from screenshots.
Fixed
  - The usage report reads the tracker as it is written.
Restart Claude Code to load the updated plugins.

Verification:
  schema-validation: 27/27 pass
  cross-cli-behavior: 14/14 pass
```
