---
name: prepare-release
description: Prepare a release by running lint + tests, bumping the package.json version, and appending a version summary to README.md. Use when the user asks to "prepare a release", "cut a release", or invokes /prepare-release. Stops immediately on lint/test failure so the user can fix issues before continuing.
---

# Prepare Release

## When to use

- User asks to prepare / cut a release.
- User invokes `/prepare-release`.
- Immediately before the release commit — this skill stages no files and creates no commit; hand off to `/git-commit` afterwards.

## Release model

The release content is the union of **(a)** commits since the last tag and **(b)** uncommitted user-facing changes in the working tree. Both are valid sources; the typical flow is that the fix being released sits uncommitted alongside the version bump and README update, and the user then commits them all together in a single release commit.

Consequences:
- Do **not** object to uncommitted changes in the working tree — they are expected and are part of what is being released. Treat them as release content, not as a blocker.
- Do **not** require at least one committed change since the last tag. The release may consist entirely of working-tree changes that have not yet been committed.
- When drafting the README bullets in step 5, summarise the user-facing changes visible across **both** sources (committed commits since the last tag **and** the diff of the working tree before this skill began modifying it).
- The only changes this skill itself creates are in `package.json`, `package-lock.json`, and `README.md`. Everything else in the working tree was already the user's in-progress release content.

## Arguments

- `patch` (default) — bumps the patch component, e.g. `3.26.1` → `3.26.2`.
- `minor` — bumps the minor component and resets patch, e.g. `3.26.1` → `3.27.0`.
- `major` — bumps the major component and resets minor/patch, e.g. `3.26.1` → `4.0.0`.

If the user supplies anything else, stop and ask for clarification.

## Workflow

Run steps in order. **If any step fails, stop immediately, report the failure, and do not proceed.** Do not modify `package.json`, `package-lock.json`, or `README.md` until lint and tests pass.

### 1. Pre-flight checks (parallel)

- `git status --short` — capture the working tree state. Per the release model above, treat uncommitted changes as part of the release content, not as a blocker. Still surface the list to the user so they can spot anything that looks unintended (e.g. a modified file they don't remember touching) before the eventual release commit.
- `git rev-parse --abbrev-ref HEAD` — confirm the current branch. If it is not `master`, warn the user and ask whether to continue.
- `git log --oneline $(git describe --tags --abbrev=0 2>/dev/null || git log --format=%H | tail -1)..HEAD` — collect commits since the last tag (or since the beginning if no tags exist). These feed the README summary in step 5 alongside the working-tree diff.
- `git diff` and `git diff --cached` — capture the uncommitted user-facing changes. These also feed the README summary in step 5.
- Read current version from `package.json`.

Only stop at pre-flight if **both** the commit list and the uncommitted diff are empty — in that case there is genuinely nothing to release.

### 2. Lint

Run `npm run lint`. **Stop on non-zero exit.** Report the linter output verbatim and do not continue.

### 3. Tests

Run `npm test`. **Stop on non-zero exit.**

Exception: the `Subagent` tests in `test/subagent.test.js` require a locally-running AgentX master (`snmpd`) and will fail with `ECONNREFUSED` if one is not present. If the only failures are Subagent `ECONNREFUSED` failures, report them and ask the user whether to proceed (they may have intentionally skipped running snmpd). All other failures are hard stops.

### 4. Bump version

Run `npm version <patch|minor|major> --no-git-tag-version`. This updates both `package.json` and `package-lock.json` atomically without creating a commit or tag. Capture the new version string for the README entry.

If the argument was omitted, default to `patch`.

### 5. Append README version summary

- Read `README.md`.
- Locate the `# License` heading near the end.
- Insert a new version section **immediately before** `# License`, separated by a blank line above and below, in exactly this format:

```
# Version X.Y.Z - DD/MM/YYYY

 * <concise user-facing summary of change 1>

 * <concise user-facing summary of change 2>
```

Notes:
- Date is **today's date** in `DD/MM/YYYY` (day/month/year) — use the date from the environment, not a hardcoded value.
- Each bullet begins with a single space, then `*`, then a space. There is a blank line between bullets (match the style of the existing entries).
- Bullets describe **user-visible changes** — not refactors, lint fixes, test additions, or internal tidy-ups. Write them like release notes, not commit subjects. Draw from **both** the commit list gathered in step 1 and the uncommitted working-tree diff; merge/reword where helpful so each line stands on its own.
- If there is only one user-visible change, include just one bullet.
- Do not touch any other part of `README.md`.

### 6. Summary

Report to the user, concisely:
- New version number.
- Bullets added to `README.md`.
- The full list of uncommitted files now staged for the release commit — both the pre-existing working-tree changes and the three files this skill modified (`package.json`, `package-lock.json`, `README.md`). Flag anything that looks unexpected.

Do **not** run `git add`, `git commit`, `git tag`, or `npm publish` — those are the user's decision. The next step is typically `/git-commit`.

## Things to watch for

- If `npm version` fails because the working tree is dirty, it has not been run with `--no-git-tag-version` correctly — re-check the command.
- If the README insertion point (`# License`) cannot be found, stop and ask the user — do not guess.
- If the lint or test commands are missing from `package.json`, stop and report.
- Never bypass a failing check with `--no-verify`, `SKIP=`, or similar; the user must fix the underlying issue.
