plugin-update · git:20261017.43a1a80 · 2026-10-17 · sha256 1a52359add7f0934
plugin-update git:20261017.43a1a80A
Immutable. This exact content never changes and is served at /api/v1/blob/1a52359add7f0934.
---
name: plugin-update
description: Updates every installed brewcode plugin and mod in one run; shows versions before -> after, what changed and the next steps. Triggers - update plugins, check versions, обнови плагины.
user-invocable: true
disable-model-invocation: true
argument-hint: "[prompt] [update|check|all]"
allowed-tools: [Read, Bash, AskUserQuestion]
model: sonnet
license: MIT
---
# Brewcode Plugin Update
**First output:** the PLAN block below, as plain text, before any tool call.
> Updates every installed claude-brewcode plugin and mod at its own scope without asking what to update,
> offers what is missing in one question, then prints one report: versions before -> after, what changed
> for you, numbered next steps. `/reload-plugins` and the `/plugin` UI are user handoffs, never tool actions.
## Prompt contract
`$ARGUMENTS` is one free-form RU/EN prompt; the mode token may sit anywhere in it.
1. Mode: an explicit mode token wins outright; else the most distinct whole-word keyword hits
(table below). Tie with `check` -> `check`; `update` vs `all` -> the keyword that comes first.
No hit or empty -> `update`.
2. Scope: always every installed claude-brewcode plugin and mod, in every scope; the prompt never
narrows the update (user ruling: updating is automatic). A missing plugin or mod named in the
prompt is still only an offer: the Phase 3 question (`update`) or `all`.
3. Ask: at most ONE `AskUserQuestion` per run, at most 2 questions, only in `update` and only when
Phase 2 lists offers; after the PLAN block, before the first change. The update itself is never
asked about. `check` asks nothing; `all` takes every offer without asking (the word is consent).
Your reply starts with this block, filled from the prompt alone, then Phase 0 runs. Print it once, in
every mode, `check` included (labels and plan values English, INPUT verbatim). A block only in your
thinking or only inside a tool call does not count:
```
PLAN — brewtools:plugin-update
INPUT: <arguments verbatim, or "(empty)">
MODE: <resolved> — <explicit | matched keyword: X | default>
SCOPE: every installed claude-brewcode plugin and mod, every scope; missing ones <update: one question | all: installed | check: listed>
DO: <2-5 imperative bullets, in phase order>
RESULT: <what the user ends up holding>
```
## Modes
| Mode | EN keywords | RU keywords | Mutates? | Behavior |
|------|-------------|-------------|----------|----------|
| `update` | *(empty)*, `update`, `upgrade` | `обнови`, `обновление` | yes | Phases 0-6: updates every outdated installed row; asks once, only when offers exist |
| `check` | `check`, `status` | `проверь`, `статус` | no | Phases 0-2, then the Phase 6 check report; no question, no marketplace refresh |
| `all` | `all`, `everything`, `full` | `всё`, `полностью` | yes | `update` + every offer installed without asking + other marketplaces' rows + prune |
## Critical Rules
- Run every `claude plugin ...` command via the Bash tool, one plugin name per call; show the full
output of every update and install.
- Never suggest `--plugin-dir` to end users: it is a dev-only flag.
- Scratch: Phase 0 makes ONE private `mktemp -d` dir and prints `SCRATCH <path>`; every later `<dir>`
is that literal path (shell variables do not survive between Bash calls). Never pick a dir by glob.
Phase 6 removes it after the report.
- `scripts/update-flow.mjs` builds the plan and the report from `references/update-flow.md` (data:
§3, strings: §5). Print the report verbatim; never re-word it, re-order it or add a table of your own.
- Markers in anything you print: 🟢 done, 🔵 info, offer or next step, 🔴 failed, ⚪ unchanged or not
installed. Fence marker lines (`✅ … OK`, `❌ … degraded`, `❌ … FAILED`, `SCRATCH <dir>`) are for you
only: never copy one into a message.
- Mods need Claude Code 2.1.301 or newer: below that, `plan` offers no mod and the report prints
its update-Claude-Code-first line. Never install a mod outside `offers`.
- The report's Next steps start with `/reload-plugins` on every `update`/`all` run, no-op runs
included; never print a separate reload notice.
- AskUserQuestion: option lists only, no free-text fields.
## Phase 0 — Inventory
The PLAN block is already above in your reply, as plain text; not yet -> print it now, before this first tool call.
**EXECUTE** using Bash tool:
```bash
D="$(mktemp -d "${TMPDIR:-/tmp}/plugin-update.XXXXXX")" && echo "SCRATCH $D" && echo "✅ scratch OK" || echo "❌ scratch FAILED"
```
> **STOP if ❌** — report the error; nothing has changed.
**PRIMARY** (CC 2.1.163+) — **EXECUTE** using Bash tool, `<dir>` = the SCRATCH path:
```bash
unset CLAUDECODE && claude --version > "<dir>/cc.txt"
claude plugin list --json > "<dir>/before.json" && echo "✅ list OK" || echo "❌ list FAILED"
```
A valid JSON array, empty included, is the authoritative inventory; `plan` reads each row's `id`, `version`
(may be `"unknown"`), `scope`, `enabled`, `projectPath` (`project`/`local` rows; other projects too).
Ids ending `@inline`, `@skills-dir` or `@synced` are not marketplace installs and never update.
**FALLBACK** (CC < 2.1.163: ❌ above, or Phase 2 reports `"error":"no-inventory"`) — **EXECUTE** using Bash tool:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/discover-plugins.sh" > "<dir>/before.json" && echo "✅ discover OK" || echo "❌ discover FAILED"
```
Both fail -> inventory unknown (!=missing plugins): Phase 2 offers nothing and updates nothing.
Details: [references/discovery.md](references/discovery.md).
## Phase 1 — Latest Versions
`update` / `all` — **EXECUTE** using Bash tool, marketplace refresh first:
```bash
claude plugin marketplace update claude-brewcode && echo "✅ marketplace update OK" || echo "❌ marketplace update FAILED"
```
Then read the refreshed clone: versions, auto-update flag, release notes path; no network:
```bash
node "${CLAUDE_PLUGIN_ROOT}/skills/plugin-update/scripts/update-flow.mjs" latest > "<dir>/latest.json" && echo "✅ latest OK" || echo "❌ latest FAILED"
```
`check`, or either ❌ above — **EXECUTE** using Bash tool (read-only web fetch, replaces `latest.json`):
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/fetch-latest-versions.sh" > "<dir>/latest.json" && echo "✅ fetch OK" || echo "❌ fetch FAILED"
```
Fetch ❌, or ✅ with every version `unknown` (offline) -> latest unknown: Phase 2 reports
`"error":"no-latest"`; never infer missing or outdated plugins from it. The report never calls a row
with an unknown latest current: its cell is `⚪ latest unknown` and, with no failed row, the title is
`## ⚪ brewcode: latest versions unknown (offline?)` (`check`: `## 🔵 brewcode check: latest versions unknown`).
## Phase 2 — Plan
**EXECUTE** using Bash tool, `<mode>` = the resolved mode:
```bash
node "${CLAUDE_PLUGIN_ROOT}/skills/plugin-update/scripts/update-flow.mjs" plan "<dir>" --mode "<mode>" && echo "✅ plan OK" || echo "❌ plan degraded"
```
One JSON line (`references/update-flow.md` §4):
| Key | Use |
|---|---|
| `update[]` | rows Phase 4 updates, in this order (mods first, placeholders first): `id`, `scope`, `projectPath`, `before`, `latest`; `orphan: true` = a `project`/`local` row whose directory is gone |
| `offers.mods[]` | missing mods, `name` + `value`; empty below Claude Code `offers.ccMin`; `migration` set = the codewords moved to this mod |
| `offers.plugins[]` | missing suite plugins, `name` + `value` |
| `scopes[]` | each distinct installed `scope` + `projectPath`, any marketplace, `user` first: the Phase 5 prune entries |
| `error` | `no-inventory` -> Phase 0 FALLBACK, then this phase again; still `no-inventory` -> Phase 6. `no-latest` -> `update[]` holds every claude-brewcode row; each update is a no-op when current |
rc 2 = a placeholder left unsubstituted: fix the command and re-run. `check` -> Phase 6.
## Phase 3 — One Question
The PLAN block is already printed (your first output): never repeat it. Only in `update` with a non-empty
`offers.mods` or `offers.plugins` -> ONE `AskUserQuestion`, `multiSelect: true`, one question per non-empty
list, in this order:
| Question | Header | Options |
|---|---|---|
| `Install the missing mods?` | `Mods` | per `offers.mods[]`, in order: label `<name>`, description `<value>`; `migration` set -> description `<value> - replaces the codewords you used`; then `Skip` |
| `Install the missing plugins?` | `Plugins` | up to 3 `offers.plugins[]`: label `<name>`, description `<value>`; more than 3 -> one option `Install all N`, description the names; then `Skip` |
Install set = the chosen options. `Skip`, alone or with others, or no answer (declined, headless) ->
nothing from that question; the report then prints each open offer's install command. `all` -> every
offer, no question. No offers -> no question.
## Phase 4 — Update, Then Install
Updates first: one command per Phase 2 `update[]` row, in order; an empty `update[]` runs none. Rows keep
their `id`, `scope` (`user | project | local | managed`) and `projectPath`. `user` / `managed` rows:
```bash
claude plugin update "<id>" --scope "<scope>" && echo "✅ update <id> OK" || echo "❌ update <id> FAILED"
```
`project` / `local` rows resolve from the cwd, so each runs from its own `projectPath`, never the
session cwd (the subshell keeps the session cwd):
```bash
(cd "<projectPath>" && claude plugin update "<id>" --scope "<scope>") && echo "✅ update <id> (<scope> <projectPath>) OK" || echo "❌ update <id> (<scope> <projectPath>) FAILED"
```
`projectPath` absent or not a directory: run nothing for that row; report `orphan <scope> install: <id> at <projectPath>` with the removal command `mkdir -p "<projectPath>" && cd "<projectPath>" && claude plugin uninstall "<id>" --scope "<scope>"`.
Always pass the discovered `--scope`: CLIs before 2.1.281 read omission as `user`. On failure: report the exact error and continue. Reference: [references/update-commands.md](references/update-commands.md), [references/update-prompt.md](references/update-prompt.md).
Then installs: the Phase 3 install set (`all`: every offer), in `offers` order, mods first, one name
per call. Phase 1 marketplace update ❌ -> add the marketplace first:
```bash
claude plugin marketplace add https://github.com/kochetkov-ma/claude-brewcode && echo "✅ marketplace add OK" || echo "❌ marketplace add FAILED"
```
Per name:
```bash
claude plugin install <plugin>@claude-brewcode && echo "✅ install <plugin> OK" || echo "❌ install <plugin> FAILED"
```
Manual install prompt for a fresh machine: [references/install-prompt.md](references/install-prompt.md).
## Phase 5 — Prune, Then the After Snapshot
Prune: `all` only; `update` goes straight to the snapshot. Prune removes only auto-installed
dependencies nothing still requires. Run it once per Phase 2 `scopes[]` entry, in order: `user` from the
session cwd (`<projectPath>` = `.`), `project` / `local` from the entry's own `projectPath` (the scope
resolves from the cwd, as in Phase 4). `projectPath` not a directory -> skip the entry (Phase 4 reports
the orphan). Any other scope (`managed`, `session`, ...) -> report it unsupported, run nothing.
**EXECUTE** using Bash tool per entry, substituting `<scope>` and `<projectPath>`:
```bash
(cd "<projectPath>" && if claude plugin prune --help >/dev/null 2>&1; then claude plugin prune --dry-run --scope "<scope>" || echo "❌ prune --dry-run (<scope> <projectPath>) FAILED"; else echo "skipped: claude plugin prune unavailable"; fi)
```
Show the listed orphans. Empty list or `Nothing to prune` -> the next entry. Otherwise prune that exact
list (typing `all` was the consent):
```bash
(cd "<projectPath>" && claude plugin prune --scope "<scope>" -y) && echo "✅ prune (<scope> <projectPath>) OK" || echo "❌ prune (<scope> <projectPath>) FAILED"
```
Keep `-y`: without a TTY, bare prune removes nothing yet exits 0 - never count that as pruned. No
`prune` in the CLI: skip notice. After the last entry: the snapshot.
`update` / `all` — **EXECUTE** using Bash tool (Phase 0 used the FALLBACK -> run that fence into
`<dir>/after.json` instead):
```bash
unset CLAUDECODE && claude plugin list --json > "<dir>/after.json" && echo "✅ list OK" || echo "❌ list FAILED"
```
A ❌ keeps the file: the report then opens with a 🔴 line that the after list could not be read, is
titled `## 🔴 brewcode: update result unknown (plugin list unreadable)` and shows the versions from
before: After `—`, an outdated row `🔴 not verified, latest Y`.
## Phase 6 — Report
**EXECUTE** using Bash tool, from the project root (the report reads its `.claude/` and the guide INDEX):
```bash
(cd "${CLAUDE_PROJECT_DIR}" && node "${CLAUDE_PLUGIN_ROOT}/skills/plugin-update/scripts/update-flow.mjs" report "<dir>") && echo "✅ report OK" || echo "❌ report degraded"
```
Then remove the scratch dir (the report is already in the tool output), `<dir>` = the SCRATCH path:
```bash
case "<dir>" in */plugin-update.*) rm -rf -- "<dir>" && echo "✅ scratch removed OK" || echo "❌ scratch removed FAILED" ;; *) echo "❌ scratch removed FAILED: not a SCRATCH path" ;; esac
```
Your final message starts with the report text, character for character: no preamble, no re-worded bullet.
Report text, every mode (`check` included) = the report fence output above its `✅ report OK`/`❌ report
degraded` line; that line, the scratch-removed line and `SCRATCH <dir>` are never printed, not even last.
Print the report text verbatim as the answer: title, table (before -> after), lines
for missing mods and plugins (the Claude Code 2.1.301 line, the codewords **Moved** line, install
commands), **What changed for you** between the versions, **Next steps** (1 `/reload-plugins`;
2 `/brewcode:setup-status upgrade`, then in each other project listed; 3 `/brewdoc:my-claude refresh`
when an installation guide is stale) and the auto-update hint. Below it add only `🔴 <command>: <first
error line>` per ❌ of the Phase 1 marketplace update, of a Phase 4 command and of a Phase 5 prune or
its preview, and each orphan's Phase 4 report line with its removal command (its table cell is
`⚪ orphan install`, never a failure).
`❌ report degraded` with markdown above it (rc 1: a latest version unknown, or the after list
unreadable) is still the complete report: print that markdown verbatim, without the `❌` line, then the
🔴 lines; never replace it with a generic failure message.
Auto-update stays a user switch (`/plugin` -> Marketplaces -> claude-brewcode): never patch
`settings.json` or `known_marketplaces.json`. Details: [references/autoupdate-research.md](references/autoupdate-research.md).