From aee77ad72b48762f0bae1c42299e62338c0a3ea9 Mon Sep 17 00:00:00 2001 From: wasabeef Date: Fri, 15 May 2026 15:05:26 +0900 Subject: [PATCH 1/4] chore(release): add release helper command Why Release prep currently depends on a manual checklist for package metadata, generated bundles, release note preview, commit creation, and tag creation. A repeatable command reduces the chance of cutting a tag before the package version and dist bundle are ready. User impact Maintainers can run one command to prepare the version bump and tag, then opt into pushing when ready to trigger the release workflow. Verification node --check scripts/release.mjs node scripts/release.mjs --help node scripts/release.mjs 1.0.6 --pus node scripts/release.mjs 1.0.6 extra npm run release -- 1.0.6 --dry-run --allow-non-main --allow-dirty --skip-checks npm -w packages/cli run build npm -w packages/cli run typecheck npm -w packages/cli run lint npm -w packages/cli test Release note: skip --- AGENTS.md | 4 +- CLAUDE.md | 4 +- docs/architecture.md | 20 +++- docs/engineering.md | 2 +- package.json | 3 +- scripts/release.mjs | 218 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 243 insertions(+), 8 deletions(-) create mode 100644 scripts/release.mjs diff --git a/AGENTS.md b/AGENTS.md index 9e5fc050..8c45e7af 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -145,7 +145,7 @@ Each `UserPromptSubmit` increments a turn counter. File changes inherit the curr - **Keep release notes human-sized.** A multi-commit PR should normally produce one clear release bullet per user-visible change, not one bullet per review fix. Put the public wording on the primary implementation commit with `Release note: `, and add `Release note: skip` to follow-up commits such as `address review findings`, `tighten fallback`, `bound window`, or generated bundle syncs unless they describe a distinct user-visible outcome. - **Write release notes as natural English sentences.** The generator capitalizes the first character as a safety net, but do not rely on that to fix awkward wording. Prefer `Release note: Codex commits made from cmux sessions are now recorded reliably.` over `Release note: recover codex env sessions`. - **PR titles should be release-summary quality.** Write PR titles as a user-facing outcome, not an implementation step. Even though GitHub Releases are generated from commits, a good PR title is the easiest review-time signal that the eventual release note will be understandable. -- **Preview release notes before merging release-sensitive PRs.** If `git-cliff --config .github/cliff.toml --latest --strip header` reads like an implementation log, rewrite commit subjects/bodies before merge or tag. Do not leave low-level cleanup commits visible just because tests pass. +- **Preview release notes before merging release-sensitive PRs.** If `git-cliff --config .github/cliff.toml --latest --strip header` reads like an implementation log, rewrite commit subjects/bodies before merge. Before tagging, use the release command below so the preview targets the next version. - **Do not rely on merge commits for release copy.** Release notes include merged PR links from `Merge pull request...` commits, but the user-facing bullets still come from implementation commits and `Release note:` lines. Version bumps and generated bundle sync commits stay hidden. - **Structural vs behavioral changes** must not be mixed in a single commit. Renames/reformats separate from feature/fix commits. - **Before committing**, all four checks must pass (run from `packages/cli/`): @@ -153,7 +153,7 @@ Each `UserPromptSubmit` increments a turn counter. File changes inherit the curr 2. `npm run typecheck` — tsc --noEmit 3. `npm run lint` — biome check 4. `npm test` — node:test (requires build first) -- **Version bumps** go in a dedicated `chore: bump version to x.y.z` commit. Tag `vx.y.z` triggers the release workflow (test → GitHub Release → npm publish). +- **Version bumps** go in a dedicated `chore: bump version to x.y.z` commit. Prefer `npm run release -- x.y.z` to prepare the bump commit and tag; add `--push` only when ready to trigger the release workflow (test → GitHub Release → npm publish). ## Constraints diff --git a/CLAUDE.md b/CLAUDE.md index b1e32d16..98a1fefe 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -145,7 +145,7 @@ Each `UserPromptSubmit` increments a turn counter. File changes inherit the curr - **Keep release notes human-sized.** A multi-commit PR should normally produce one clear release bullet per user-visible change, not one bullet per review fix. Put the public wording on the primary implementation commit with `Release note: `, and add `Release note: skip` to follow-up commits such as `address review findings`, `tighten fallback`, `bound window`, or generated bundle syncs unless they describe a distinct user-visible outcome. - **Write release notes as natural English sentences.** The generator capitalizes the first character as a safety net, but do not rely on that to fix awkward wording. Prefer `Release note: Codex commits made from cmux sessions are now recorded reliably.` over `Release note: recover codex env sessions`. - **PR titles should be release-summary quality.** Write PR titles as a user-facing outcome, not an implementation step. Even though GitHub Releases are generated from commits, a good PR title is the easiest review-time signal that the eventual release note will be understandable. -- **Preview release notes before merging release-sensitive PRs.** If `git-cliff --config .github/cliff.toml --latest --strip header` reads like an implementation log, rewrite commit subjects/bodies before merge or tag. Do not leave low-level cleanup commits visible just because tests pass. +- **Preview release notes before merging release-sensitive PRs.** If `git-cliff --config .github/cliff.toml --latest --strip header` reads like an implementation log, rewrite commit subjects/bodies before merge. Before tagging, use the release command below so the preview targets the next version. - **Do not rely on merge commits for release copy.** Release notes include merged PR links from `Merge pull request...` commits, but the user-facing bullets still come from implementation commits and `Release note:` lines. Version bumps and generated bundle sync commits stay hidden. - **Structural vs behavioral changes** must not be mixed in a single commit. Renames/reformats separate from feature/fix commits. - **Before committing**, all four checks must pass (run from `packages/cli/`): @@ -153,7 +153,7 @@ Each `UserPromptSubmit` increments a turn counter. File changes inherit the curr 2. `npm run typecheck` — tsc --noEmit 3. `npm run lint` — biome check 4. `npm test` — node:test (requires build first) -- **Version bumps** go in a dedicated `chore: bump version to x.y.z` commit. Tag `vx.y.z` triggers the release workflow (test → GitHub Release → npm publish). +- **Version bumps** go in a dedicated `chore: bump version to x.y.z` commit. Prefer `npm run release -- x.y.z` to prepare the bump commit and tag; add `--push` only when ready to trigger the release workflow (test → GitHub Release → npm publish). ## Constraints diff --git a/docs/architecture.md b/docs/architecture.md index 5e8bf07d..8338581e 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -617,15 +617,31 @@ should still be written as a clear sentence in the commit body. The canonical npm package is `agent-note`. The workflow also publishes `@wasabeef/agentnote` from the same built `dist/` as a reserved alias package, but end-user documentation should continue to point to `agent-note`. -Release steps: +Preferred release command: + +```bash +npm run release -- X.Y.Z # prepare local version-bump commit and tag +npm run release -- X.Y.Z --push # also push main and vX.Y.Z +``` + +The command updates `packages/cli/package.json`, syncs the `packages/cli` entry +in `package-lock.json`, rebuilds `packages/cli/dist/cli.js`, runs the release +checks, prints the `git-cliff` release note preview, commits +`chore: bump version to X.Y.Z`, and creates the annotated `vX.Y.Z` tag. Without +`--push`, the release stays local so the generated notes can be inspected before +triggering `release.yml`. + +Manual fallback steps: 1. Update the CLI package version in `packages/cli/package.json`. 2. Keep the workspace lockfile in sync. At minimum, update the `packages/cli` entry in `package-lock.json` so the committed workspace metadata matches the published package version. 3. Run the release checks locally: - `npm -w packages/cli run build` + - `npm -w packages/cli run typecheck` + - `npm -w packages/cli run lint` - `npm -w packages/cli test` 4. Review the generated release note locally before tagging: - - `git-cliff --config .github/cliff.toml --latest --strip header` + - `git-cliff --config .github/cliff.toml --unreleased --tag vX.Y.Z --strip header` 5. If the generated note reads like an implementation log, rewrite the relevant commit subjects or add `Release note:` / `Release note: skip` lines before tagging. diff --git a/docs/engineering.md b/docs/engineering.md index 737f05cc..67d7de1f 100644 --- a/docs/engineering.md +++ b/docs/engineering.md @@ -112,7 +112,7 @@ subject as public copy unless the commit type is intentionally internal. - Keep multi-commit PRs readable in the generated release note. Review-fix follow-up commits in a multi-commit PR should usually use `Release note: skip` unless they describe a distinct user-visible change. - The release generator capitalizes the first character of each bullet as a safety net. Still write natural English yourself; this only fixes mechanical lower-case commit subjects. - A PR title is not the release-note source, but it should still read like the top-level release summary for the PR. If the title would be a bad release bullet, improve it before opening or merging the PR. -- Before tagging, run `git-cliff --config .github/cliff.toml --latest --strip header`. If the output reads like an implementation log, rewrite commit subjects/bodies before cutting the release. +- Before tagging, prefer `npm run release -- x.y.z` so the version bump, build, tests, release note preview, commit, and tag are produced by one repeatable command. If running the steps manually, run `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header` and rewrite commit subjects/bodies before cutting the release if the output reads like an implementation log. Good commit body shape: diff --git a/package.json b/package.json index 0097f267..e69ec5c8 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "dashboard:restore-notes": "npm run workflow:restore-notes --prefix packages/dashboard", "dashboard:sync-notes": "npm run workflow:sync-notes --prefix packages/dashboard", "dashboard:build-pages": "npm run workflow:build-pages --prefix packages/dashboard", - "dashboard:persist-notes": "npm run workflow:persist-notes --prefix packages/dashboard" + "dashboard:persist-notes": "npm run workflow:persist-notes --prefix packages/dashboard", + "release": "node scripts/release.mjs" }, "workspaces": [ "packages/cli", diff --git a/scripts/release.mjs b/scripts/release.mjs new file mode 100644 index 00000000..031fa387 --- /dev/null +++ b/scripts/release.mjs @@ -0,0 +1,218 @@ +#!/usr/bin/env node + +import { execFileSync } from "node:child_process"; +import { readFileSync, writeFileSync } from "node:fs"; + +const CLI_PACKAGE_PATH = "packages/cli/package.json"; +const LOCKFILE_PATH = "package-lock.json"; +const CLI_DIST_PATH = "packages/cli/dist/cli.js"; +const KNOWN_FLAGS = new Set([ + "--push", + "--dry-run", + "--skip-checks", + "--allow-dirty", + "--allow-non-main", + "--help", + "-h", +]); +const RELEASE_CHECKS = [ + ["npm", ["-w", "packages/cli", "run", "build"]], + ["npm", ["-w", "packages/cli", "run", "typecheck"]], + ["npm", ["-w", "packages/cli", "run", "lint"]], + ["npm", ["-w", "packages/cli", "test"]], +]; + +function printUsage() { + console.log(`Usage: + npm run release -- [--push] + +Examples: + npm run release -- 1.0.6 + npm run release -- 1.0.6 --push + npm run release -- 1.0.6 --dry-run --allow-non-main --allow-dirty + +Options: + --push Push main and the release tag after creating them locally. + --dry-run Print the planned release without editing files, committing, or tagging. + --skip-checks Skip local build/typecheck/lint/test checks. + --allow-dirty Allow a dirty working tree before the release command starts. + --allow-non-main Allow running from a branch other than main. + --help Show this help. +`); +} + +function run(command, args, opts = {}) { + const printable = [command, ...args].join(" "); + if (opts.dryRun) { + console.log(`$ ${printable}`); + return ""; + } + console.log(`$ ${printable}`); + return execFileSync(command, args, { encoding: "utf8", stdio: ["ignore", "pipe", "inherit"] }); +} + +function readJson(path) { + return JSON.parse(readFileSync(path, "utf8")); +} + +function writeJson(path, value, dryRun) { + if (dryRun) return; + writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`); +} + +function normalizeVersion(input) { + const version = input.startsWith("v") ? input.slice(1) : input; + if (!/^\d+\.\d+\.\d+$/.test(version)) { + throw new Error(`Release version must be x.y.z, got: ${input}`); + } + return version; +} + +function gitOutput(args) { + return execFileSync("git", args, { encoding: "utf8" }).trim(); +} + +function assertCleanWorktree(allowDirty) { + if (allowDirty) return; + const status = gitOutput(["status", "--porcelain"]); + if (status) { + throw new Error( + "Working tree must be clean before release. Commit/stash changes or pass --allow-dirty.", + ); + } +} + +function assertMainBranch(allowNonMain) { + if (allowNonMain) return; + const branch = gitOutput(["branch", "--show-current"]); + if (branch !== "main") { + throw new Error(`Release command must run on main, current branch is: ${branch}`); + } +} + +function assertTagAvailable(tag) { + const existing = gitOutput(["tag", "--list", tag]); + if (existing) throw new Error(`Local tag already exists: ${tag}`); +} + +function updateVersions(version, dryRun) { + const cliPackage = readJson(CLI_PACKAGE_PATH); + cliPackage.version = version; + writeJson(CLI_PACKAGE_PATH, cliPackage, dryRun); + + const lockfile = readJson(LOCKFILE_PATH); + const packages = lockfile.packages; + const cliPackageLock = packages?.["packages/cli"]; + if (!cliPackageLock) { + throw new Error("package-lock.json is missing packages/cli metadata."); + } + cliPackageLock.version = version; + writeJson(LOCKFILE_PATH, lockfile, dryRun); +} + +function previewReleaseNotes(tag) { + console.log("\nRelease note preview:\n"); + const output = execFileSync( + "git-cliff", + ["--config", ".github/cliff.toml", "--unreleased", "--tag", tag, "--strip", "header"], + { encoding: "utf8", stdio: ["ignore", "pipe", "inherit"] }, + ); + console.log(output.trim()); + console.log(""); +} + +function commitAndTag(version, tag, dryRun) { + run("git", ["add", CLI_PACKAGE_PATH, LOCKFILE_PATH], { dryRun }); + run("git", ["add", "-f", CLI_DIST_PATH], { dryRun }); + run( + "git", + [ + "commit", + "-m", + `chore: bump version to ${version}`, + "-m", + [ + "Why", + `Prepare the CLI package for the v${version} release. The release workflow publishes the committed package version, so package metadata and the bundled CLI must match the tag.`, + "", + "User impact", + `The v${version} npm package and GitHub release will publish the changes already merged on main.`, + "", + "Verification", + "npm -w packages/cli run build", + "npm -w packages/cli run typecheck", + "npm -w packages/cli run lint", + "npm -w packages/cli test", + `git-cliff --config .github/cliff.toml --unreleased --tag ${tag} --strip header`, + "", + "Release note: skip", + ].join("\n"), + ], + { dryRun }, + ); + run("git", ["tag", "-a", tag, "-m", tag], { dryRun }); +} + +function parseArgs(argv) { + const flags = new Set(argv.filter((arg) => arg.startsWith("-"))); + const positional = argv.filter((arg) => !arg.startsWith("-")); + for (const flag of flags) { + if (!KNOWN_FLAGS.has(flag)) { + throw new Error(`Unknown option: ${flag}`); + } + } + if (positional.length > 1) { + throw new Error(`Expected one version argument, got: ${positional.join(" ")}`); + } + return { + version: positional[0] ?? null, + push: flags.has("--push"), + dryRun: flags.has("--dry-run"), + skipChecks: flags.has("--skip-checks"), + allowDirty: flags.has("--allow-dirty"), + allowNonMain: flags.has("--allow-non-main"), + help: flags.has("--help") || flags.has("-h"), + }; +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help || !args.version) { + printUsage(); + process.exit(args.help ? 0 : 1); + } + + const version = normalizeVersion(args.version); + const tag = `v${version}`; + + assertMainBranch(args.allowNonMain); + assertCleanWorktree(args.allowDirty); + assertTagAvailable(tag); + + console.log(`Preparing ${tag}${args.dryRun ? " (dry run)" : ""}`); + updateVersions(version, args.dryRun); + + if (!args.skipChecks) { + for (const [command, commandArgs] of RELEASE_CHECKS) { + run(command, commandArgs, { dryRun: args.dryRun }); + } + } + + previewReleaseNotes(tag); + commitAndTag(version, tag, args.dryRun); + + if (args.push) { + run("git", ["push", "origin", "main"], { dryRun: args.dryRun }); + run("git", ["push", "origin", tag], { dryRun: args.dryRun }); + } else { + console.log(`Local release commit and ${tag} tag are ready.`); + console.log(`Run: git push origin main && git push origin ${tag}`); + } +} + +try { + main(); +} catch (error) { + console.error(`release: ${error instanceof Error ? error.message : String(error)}`); + process.exit(1); +} From 51975a26852db3733eeaf596d0d4b227f69e78f6 Mon Sep 17 00:00:00 2001 From: wasabeef Date: Fri, 15 May 2026 16:04:19 +0900 Subject: [PATCH 2/4] chore(release): add agent release skill Why Release work is fragile enough that agents should follow the same guarded workflow as humans. A repo-local skill and command make the release command discoverable from Codex, Claude, Cursor, and Gemini. User impact Maintainers can ask an agent to prepare or publish an Agent Note release and get the same version bump, release note preview, tag, workflow monitoring, and npm verification steps. Verification git diff --check shasum .codex/skills/agentnote-release/SKILL.md .claude/skills/agentnote-release/SKILL.md .cursor/skills/agentnote-release/SKILL.md .gemini/skills/agentnote-release/SKILL.md shasum .codex/commands/release.md .claude/commands/release.md .cursor/commands/release.md .gemini/commands/release.md npm run release -- 1.0.6 --dry-run --allow-non-main --allow-dirty --skip-checks Release note: skip --- .claude/commands/release.md | 14 ++++++ .claude/skills/agentnote-release/SKILL.md | 58 +++++++++++++++++++++++ .codex/commands/release.md | 14 ++++++ .codex/skills/agentnote-release/SKILL.md | 58 +++++++++++++++++++++++ .cursor/commands/release.md | 14 ++++++ .cursor/skills/agentnote-release/SKILL.md | 58 +++++++++++++++++++++++ .gemini/commands/release.md | 14 ++++++ .gemini/skills/agentnote-release/SKILL.md | 58 +++++++++++++++++++++++ docs/architecture.md | 4 ++ 9 files changed, 292 insertions(+) create mode 100644 .claude/commands/release.md create mode 100644 .claude/skills/agentnote-release/SKILL.md create mode 100644 .codex/commands/release.md create mode 100644 .codex/skills/agentnote-release/SKILL.md create mode 100644 .cursor/commands/release.md create mode 100644 .cursor/skills/agentnote-release/SKILL.md create mode 100644 .gemini/commands/release.md create mode 100644 .gemini/skills/agentnote-release/SKILL.md diff --git a/.claude/commands/release.md b/.claude/commands/release.md new file mode 100644 index 00000000..03fa09bd --- /dev/null +++ b/.claude/commands/release.md @@ -0,0 +1,14 @@ +--- +description: Prepare or publish an Agent Note release with the repo-local release command. +argument-hint: [--push|--dry-run] +--- + +# Agent Note Release + +Use the repo-local `agentnote-release` skill. + +1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. +2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. +3. Run `npm run release -- --dry-run --allow-non-main --allow-dirty --skip-checks` for a rehearsal, `npm run release -- ` for local preparation, or `npm run release -- --push` when the user explicitly wants to publish. +4. Verify the release workflow, GitHub Release, and both npm packages after pushing. +5. Report the commands run and final release status. diff --git a/.claude/skills/agentnote-release/SKILL.md b/.claude/skills/agentnote-release/SKILL.md new file mode 100644 index 00000000..115f05d2 --- /dev/null +++ b/.claude/skills/agentnote-release/SKILL.md @@ -0,0 +1,58 @@ +--- +name: agentnote-release +description: Prepare and publish Agent Note releases with the repo-local release command, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. +--- + +# Agent Note Release Workflow + +Use this skill when the task asks to release Agent Note, bump a version, cut a tag, publish npm packages, or verify a release. + +## Prepare + +1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. +2. Switch to `main` and pull the latest changes before an actual release. +3. Check the working tree. Do not release with unrelated dirty files. +4. If the user only wants a rehearsal, use `--dry-run`; do not create commits or tags. + +## Release + +Prefer the repo-local command: + +```bash +npm run release -- --push +``` + +Without `--push`, the command prepares the local version-bump commit and annotated tag but does not publish them: + +```bash +npm run release -- +``` + +The command updates package metadata, runs the CLI build/typecheck/lint/test checks, previews the next release notes with `git-cliff --unreleased --tag`, creates the dedicated `chore: bump version to ` commit, and creates the annotated `v` tag. + +## Guardrails + +- Do not manually push a release tag before the package version bump commit is on `main`. +- Do not use `--push` until the release note preview is acceptable. +- If release notes look like an implementation log, fix commit subjects or `Release note:` bodies before tagging. +- If the command fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. +- Keep release plumbing commits hidden with `Release note: skip`. + +## Verify + +After pushing a release tag: + +1. Watch the release workflow until completion. +2. Verify the GitHub Release exists for `v`. +3. Verify npm publishes both `agent-note@` and `@wasabeef/agentnote@`. +4. If release notes need copy edits after publication, update the GitHub Release body directly and keep the source commit guidance for future releases. + +## Report + +End with: + +- Version released or prepared +- Commands run +- Workflow status +- GitHub Release URL +- npm package versions confirmed diff --git a/.codex/commands/release.md b/.codex/commands/release.md new file mode 100644 index 00000000..03fa09bd --- /dev/null +++ b/.codex/commands/release.md @@ -0,0 +1,14 @@ +--- +description: Prepare or publish an Agent Note release with the repo-local release command. +argument-hint: [--push|--dry-run] +--- + +# Agent Note Release + +Use the repo-local `agentnote-release` skill. + +1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. +2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. +3. Run `npm run release -- --dry-run --allow-non-main --allow-dirty --skip-checks` for a rehearsal, `npm run release -- ` for local preparation, or `npm run release -- --push` when the user explicitly wants to publish. +4. Verify the release workflow, GitHub Release, and both npm packages after pushing. +5. Report the commands run and final release status. diff --git a/.codex/skills/agentnote-release/SKILL.md b/.codex/skills/agentnote-release/SKILL.md new file mode 100644 index 00000000..115f05d2 --- /dev/null +++ b/.codex/skills/agentnote-release/SKILL.md @@ -0,0 +1,58 @@ +--- +name: agentnote-release +description: Prepare and publish Agent Note releases with the repo-local release command, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. +--- + +# Agent Note Release Workflow + +Use this skill when the task asks to release Agent Note, bump a version, cut a tag, publish npm packages, or verify a release. + +## Prepare + +1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. +2. Switch to `main` and pull the latest changes before an actual release. +3. Check the working tree. Do not release with unrelated dirty files. +4. If the user only wants a rehearsal, use `--dry-run`; do not create commits or tags. + +## Release + +Prefer the repo-local command: + +```bash +npm run release -- --push +``` + +Without `--push`, the command prepares the local version-bump commit and annotated tag but does not publish them: + +```bash +npm run release -- +``` + +The command updates package metadata, runs the CLI build/typecheck/lint/test checks, previews the next release notes with `git-cliff --unreleased --tag`, creates the dedicated `chore: bump version to ` commit, and creates the annotated `v` tag. + +## Guardrails + +- Do not manually push a release tag before the package version bump commit is on `main`. +- Do not use `--push` until the release note preview is acceptable. +- If release notes look like an implementation log, fix commit subjects or `Release note:` bodies before tagging. +- If the command fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. +- Keep release plumbing commits hidden with `Release note: skip`. + +## Verify + +After pushing a release tag: + +1. Watch the release workflow until completion. +2. Verify the GitHub Release exists for `v`. +3. Verify npm publishes both `agent-note@` and `@wasabeef/agentnote@`. +4. If release notes need copy edits after publication, update the GitHub Release body directly and keep the source commit guidance for future releases. + +## Report + +End with: + +- Version released or prepared +- Commands run +- Workflow status +- GitHub Release URL +- npm package versions confirmed diff --git a/.cursor/commands/release.md b/.cursor/commands/release.md new file mode 100644 index 00000000..03fa09bd --- /dev/null +++ b/.cursor/commands/release.md @@ -0,0 +1,14 @@ +--- +description: Prepare or publish an Agent Note release with the repo-local release command. +argument-hint: [--push|--dry-run] +--- + +# Agent Note Release + +Use the repo-local `agentnote-release` skill. + +1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. +2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. +3. Run `npm run release -- --dry-run --allow-non-main --allow-dirty --skip-checks` for a rehearsal, `npm run release -- ` for local preparation, or `npm run release -- --push` when the user explicitly wants to publish. +4. Verify the release workflow, GitHub Release, and both npm packages after pushing. +5. Report the commands run and final release status. diff --git a/.cursor/skills/agentnote-release/SKILL.md b/.cursor/skills/agentnote-release/SKILL.md new file mode 100644 index 00000000..115f05d2 --- /dev/null +++ b/.cursor/skills/agentnote-release/SKILL.md @@ -0,0 +1,58 @@ +--- +name: agentnote-release +description: Prepare and publish Agent Note releases with the repo-local release command, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. +--- + +# Agent Note Release Workflow + +Use this skill when the task asks to release Agent Note, bump a version, cut a tag, publish npm packages, or verify a release. + +## Prepare + +1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. +2. Switch to `main` and pull the latest changes before an actual release. +3. Check the working tree. Do not release with unrelated dirty files. +4. If the user only wants a rehearsal, use `--dry-run`; do not create commits or tags. + +## Release + +Prefer the repo-local command: + +```bash +npm run release -- --push +``` + +Without `--push`, the command prepares the local version-bump commit and annotated tag but does not publish them: + +```bash +npm run release -- +``` + +The command updates package metadata, runs the CLI build/typecheck/lint/test checks, previews the next release notes with `git-cliff --unreleased --tag`, creates the dedicated `chore: bump version to ` commit, and creates the annotated `v` tag. + +## Guardrails + +- Do not manually push a release tag before the package version bump commit is on `main`. +- Do not use `--push` until the release note preview is acceptable. +- If release notes look like an implementation log, fix commit subjects or `Release note:` bodies before tagging. +- If the command fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. +- Keep release plumbing commits hidden with `Release note: skip`. + +## Verify + +After pushing a release tag: + +1. Watch the release workflow until completion. +2. Verify the GitHub Release exists for `v`. +3. Verify npm publishes both `agent-note@` and `@wasabeef/agentnote@`. +4. If release notes need copy edits after publication, update the GitHub Release body directly and keep the source commit guidance for future releases. + +## Report + +End with: + +- Version released or prepared +- Commands run +- Workflow status +- GitHub Release URL +- npm package versions confirmed diff --git a/.gemini/commands/release.md b/.gemini/commands/release.md new file mode 100644 index 00000000..03fa09bd --- /dev/null +++ b/.gemini/commands/release.md @@ -0,0 +1,14 @@ +--- +description: Prepare or publish an Agent Note release with the repo-local release command. +argument-hint: [--push|--dry-run] +--- + +# Agent Note Release + +Use the repo-local `agentnote-release` skill. + +1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. +2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. +3. Run `npm run release -- --dry-run --allow-non-main --allow-dirty --skip-checks` for a rehearsal, `npm run release -- ` for local preparation, or `npm run release -- --push` when the user explicitly wants to publish. +4. Verify the release workflow, GitHub Release, and both npm packages after pushing. +5. Report the commands run and final release status. diff --git a/.gemini/skills/agentnote-release/SKILL.md b/.gemini/skills/agentnote-release/SKILL.md new file mode 100644 index 00000000..115f05d2 --- /dev/null +++ b/.gemini/skills/agentnote-release/SKILL.md @@ -0,0 +1,58 @@ +--- +name: agentnote-release +description: Prepare and publish Agent Note releases with the repo-local release command, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. +--- + +# Agent Note Release Workflow + +Use this skill when the task asks to release Agent Note, bump a version, cut a tag, publish npm packages, or verify a release. + +## Prepare + +1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. +2. Switch to `main` and pull the latest changes before an actual release. +3. Check the working tree. Do not release with unrelated dirty files. +4. If the user only wants a rehearsal, use `--dry-run`; do not create commits or tags. + +## Release + +Prefer the repo-local command: + +```bash +npm run release -- --push +``` + +Without `--push`, the command prepares the local version-bump commit and annotated tag but does not publish them: + +```bash +npm run release -- +``` + +The command updates package metadata, runs the CLI build/typecheck/lint/test checks, previews the next release notes with `git-cliff --unreleased --tag`, creates the dedicated `chore: bump version to ` commit, and creates the annotated `v` tag. + +## Guardrails + +- Do not manually push a release tag before the package version bump commit is on `main`. +- Do not use `--push` until the release note preview is acceptable. +- If release notes look like an implementation log, fix commit subjects or `Release note:` bodies before tagging. +- If the command fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. +- Keep release plumbing commits hidden with `Release note: skip`. + +## Verify + +After pushing a release tag: + +1. Watch the release workflow until completion. +2. Verify the GitHub Release exists for `v`. +3. Verify npm publishes both `agent-note@` and `@wasabeef/agentnote@`. +4. If release notes need copy edits after publication, update the GitHub Release body directly and keep the source commit guidance for future releases. + +## Report + +End with: + +- Version released or prepared +- Commands run +- Workflow status +- GitHub Release URL +- npm package versions confirmed diff --git a/docs/architecture.md b/docs/architecture.md index 8338581e..1e5e20d1 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -631,6 +631,10 @@ checks, prints the `git-cliff` release note preview, commits `--push`, the release stays local so the generated notes can be inspected before triggering `release.yml`. +Repo-local Agent skills and commands mirror this workflow for Codex, Claude, +Cursor, and Gemini. Use the `agentnote-release` skill or `/release` command +when asking an agent to prepare or publish a release. + Manual fallback steps: 1. Update the CLI package version in `packages/cli/package.json`. From a833ca028923a94277e4e4507b36d1c6b4d138b1 Mon Sep 17 00:00:00 2001 From: wasabeef Date: Fri, 15 May 2026 16:47:24 +0900 Subject: [PATCH 3/4] chore(release): keep release workflow in skills Why The release workflow is maintainer guidance rather than a public CLI feature. Keeping it as repo-local Markdown skills matches the CodeRabbit workflow pattern and avoids maintaining an extra release script. User impact Agents can still prepare or publish releases through /release, while the source of truth stays in Markdown and explicitly maps x.y.z inputs to vx.y.z git tags. Verification git diff --check node -e "JSON.parse(require('fs').readFileSync('package.json','utf8')); console.log('package.json ok')" git-cliff --config .github/cliff.toml --unreleased --tag v1.0.6 --strip header npm -w packages/cli run typecheck Release note: skip --- .claude/commands/release.md | 9 +- .claude/skills/agentnote-release/SKILL.md | 33 ++-- .codex/commands/release.md | 9 +- .codex/skills/agentnote-release/SKILL.md | 33 ++-- .cursor/commands/release.md | 9 +- .cursor/skills/agentnote-release/SKILL.md | 33 ++-- .gemini/commands/release.md | 9 +- .gemini/skills/agentnote-release/SKILL.md | 33 ++-- AGENTS.md | 2 +- CLAUDE.md | 2 +- docs/architecture.md | 32 ++-- docs/engineering.md | 2 +- package.json | 3 +- scripts/release.mjs | 218 ---------------------- 14 files changed, 102 insertions(+), 325 deletions(-) delete mode 100644 scripts/release.mjs diff --git a/.claude/commands/release.md b/.claude/commands/release.md index 03fa09bd..7ab4cfc2 100644 --- a/.claude/commands/release.md +++ b/.claude/commands/release.md @@ -1,5 +1,5 @@ --- -description: Prepare or publish an Agent Note release with the repo-local release command. +description: Prepare or publish an Agent Note release with the repo-local Markdown workflow. argument-hint: [--push|--dry-run] --- @@ -9,6 +9,7 @@ Use the repo-local `agentnote-release` skill. 1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. 2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. -3. Run `npm run release -- --dry-run --allow-non-main --allow-dirty --skip-checks` for a rehearsal, `npm run release -- ` for local preparation, or `npm run release -- --push` when the user explicitly wants to publish. -4. Verify the release workflow, GitHub Release, and both npm packages after pushing. -5. Report the commands run and final release status. +3. Normalize the version: package metadata uses `x.y.z`; the git tag is always `vx.y.z`. +4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --unreleased --tag vx.y.z`, commit, tag, and push only when publishing. +5. Verify the release workflow, GitHub Release, and both npm packages after pushing. +6. Report the commands run and final release status. diff --git a/.claude/skills/agentnote-release/SKILL.md b/.claude/skills/agentnote-release/SKILL.md index 115f05d2..114914fe 100644 --- a/.claude/skills/agentnote-release/SKILL.md +++ b/.claude/skills/agentnote-release/SKILL.md @@ -1,6 +1,6 @@ --- name: agentnote-release -description: Prepare and publish Agent Note releases with the repo-local release command, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. +description: Prepare and publish Agent Note releases with the repo-local Markdown workflow, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. --- # Agent Note Release Workflow @@ -9,33 +9,32 @@ Use this skill when the task asks to release Agent Note, bump a version, cut a t ## Prepare -1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. +1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. Use `x.y.z` for package metadata and `vx.y.z` for the git tag. 2. Switch to `main` and pull the latest changes before an actual release. 3. Check the working tree. Do not release with unrelated dirty files. -4. If the user only wants a rehearsal, use `--dry-run`; do not create commits or tags. +4. If the user only wants a rehearsal or passes `--dry-run`, do not edit files, commit, tag, or push; only inspect state, run safe checks when useful, and preview the release notes. ## Release -Prefer the repo-local command: +Follow these steps instead of relying on a release script: -```bash -npm run release -- --push -``` - -Without `--push`, the command prepares the local version-bump commit and annotated tag but does not publish them: - -```bash -npm run release -- -``` - -The command updates package metadata, runs the CLI build/typecheck/lint/test checks, previews the next release notes with `git-cliff --unreleased --tag`, creates the dedicated `chore: bump version to ` commit, and creates the annotated `v` tag. +1. Update `packages/cli/package.json` to `x.y.z`. +2. Update `package-lock.json` so `packages["packages/cli"].version` is also `x.y.z`. +3. Run `npm -w packages/cli run build`. +4. Run `npm -w packages/cli run typecheck`. +5. Run `npm -w packages/cli run lint`. +6. Run `npm -w packages/cli test`. +7. Preview release notes with `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header`. +8. Stage `packages/cli/package.json`, `package-lock.json`, and the rebuilt `packages/cli/dist/cli.js`. +9. Commit only those release files as `chore: bump version to x.y.z` with `Release note: skip`. +10. Create the annotated tag with `git tag -a vx.y.z -m vx.y.z`. +11. Push `main` and `vx.y.z` only when ready to publish. ## Guardrails - Do not manually push a release tag before the package version bump commit is on `main`. -- Do not use `--push` until the release note preview is acceptable. - If release notes look like an implementation log, fix commit subjects or `Release note:` bodies before tagging. -- If the command fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. +- If any step fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. - Keep release plumbing commits hidden with `Release note: skip`. ## Verify diff --git a/.codex/commands/release.md b/.codex/commands/release.md index 03fa09bd..7ab4cfc2 100644 --- a/.codex/commands/release.md +++ b/.codex/commands/release.md @@ -1,5 +1,5 @@ --- -description: Prepare or publish an Agent Note release with the repo-local release command. +description: Prepare or publish an Agent Note release with the repo-local Markdown workflow. argument-hint: [--push|--dry-run] --- @@ -9,6 +9,7 @@ Use the repo-local `agentnote-release` skill. 1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. 2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. -3. Run `npm run release -- --dry-run --allow-non-main --allow-dirty --skip-checks` for a rehearsal, `npm run release -- ` for local preparation, or `npm run release -- --push` when the user explicitly wants to publish. -4. Verify the release workflow, GitHub Release, and both npm packages after pushing. -5. Report the commands run and final release status. +3. Normalize the version: package metadata uses `x.y.z`; the git tag is always `vx.y.z`. +4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --unreleased --tag vx.y.z`, commit, tag, and push only when publishing. +5. Verify the release workflow, GitHub Release, and both npm packages after pushing. +6. Report the commands run and final release status. diff --git a/.codex/skills/agentnote-release/SKILL.md b/.codex/skills/agentnote-release/SKILL.md index 115f05d2..114914fe 100644 --- a/.codex/skills/agentnote-release/SKILL.md +++ b/.codex/skills/agentnote-release/SKILL.md @@ -1,6 +1,6 @@ --- name: agentnote-release -description: Prepare and publish Agent Note releases with the repo-local release command, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. +description: Prepare and publish Agent Note releases with the repo-local Markdown workflow, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. --- # Agent Note Release Workflow @@ -9,33 +9,32 @@ Use this skill when the task asks to release Agent Note, bump a version, cut a t ## Prepare -1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. +1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. Use `x.y.z` for package metadata and `vx.y.z` for the git tag. 2. Switch to `main` and pull the latest changes before an actual release. 3. Check the working tree. Do not release with unrelated dirty files. -4. If the user only wants a rehearsal, use `--dry-run`; do not create commits or tags. +4. If the user only wants a rehearsal or passes `--dry-run`, do not edit files, commit, tag, or push; only inspect state, run safe checks when useful, and preview the release notes. ## Release -Prefer the repo-local command: +Follow these steps instead of relying on a release script: -```bash -npm run release -- --push -``` - -Without `--push`, the command prepares the local version-bump commit and annotated tag but does not publish them: - -```bash -npm run release -- -``` - -The command updates package metadata, runs the CLI build/typecheck/lint/test checks, previews the next release notes with `git-cliff --unreleased --tag`, creates the dedicated `chore: bump version to ` commit, and creates the annotated `v` tag. +1. Update `packages/cli/package.json` to `x.y.z`. +2. Update `package-lock.json` so `packages["packages/cli"].version` is also `x.y.z`. +3. Run `npm -w packages/cli run build`. +4. Run `npm -w packages/cli run typecheck`. +5. Run `npm -w packages/cli run lint`. +6. Run `npm -w packages/cli test`. +7. Preview release notes with `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header`. +8. Stage `packages/cli/package.json`, `package-lock.json`, and the rebuilt `packages/cli/dist/cli.js`. +9. Commit only those release files as `chore: bump version to x.y.z` with `Release note: skip`. +10. Create the annotated tag with `git tag -a vx.y.z -m vx.y.z`. +11. Push `main` and `vx.y.z` only when ready to publish. ## Guardrails - Do not manually push a release tag before the package version bump commit is on `main`. -- Do not use `--push` until the release note preview is acceptable. - If release notes look like an implementation log, fix commit subjects or `Release note:` bodies before tagging. -- If the command fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. +- If any step fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. - Keep release plumbing commits hidden with `Release note: skip`. ## Verify diff --git a/.cursor/commands/release.md b/.cursor/commands/release.md index 03fa09bd..7ab4cfc2 100644 --- a/.cursor/commands/release.md +++ b/.cursor/commands/release.md @@ -1,5 +1,5 @@ --- -description: Prepare or publish an Agent Note release with the repo-local release command. +description: Prepare or publish an Agent Note release with the repo-local Markdown workflow. argument-hint: [--push|--dry-run] --- @@ -9,6 +9,7 @@ Use the repo-local `agentnote-release` skill. 1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. 2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. -3. Run `npm run release -- --dry-run --allow-non-main --allow-dirty --skip-checks` for a rehearsal, `npm run release -- ` for local preparation, or `npm run release -- --push` when the user explicitly wants to publish. -4. Verify the release workflow, GitHub Release, and both npm packages after pushing. -5. Report the commands run and final release status. +3. Normalize the version: package metadata uses `x.y.z`; the git tag is always `vx.y.z`. +4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --unreleased --tag vx.y.z`, commit, tag, and push only when publishing. +5. Verify the release workflow, GitHub Release, and both npm packages after pushing. +6. Report the commands run and final release status. diff --git a/.cursor/skills/agentnote-release/SKILL.md b/.cursor/skills/agentnote-release/SKILL.md index 115f05d2..114914fe 100644 --- a/.cursor/skills/agentnote-release/SKILL.md +++ b/.cursor/skills/agentnote-release/SKILL.md @@ -1,6 +1,6 @@ --- name: agentnote-release -description: Prepare and publish Agent Note releases with the repo-local release command, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. +description: Prepare and publish Agent Note releases with the repo-local Markdown workflow, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. --- # Agent Note Release Workflow @@ -9,33 +9,32 @@ Use this skill when the task asks to release Agent Note, bump a version, cut a t ## Prepare -1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. +1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. Use `x.y.z` for package metadata and `vx.y.z` for the git tag. 2. Switch to `main` and pull the latest changes before an actual release. 3. Check the working tree. Do not release with unrelated dirty files. -4. If the user only wants a rehearsal, use `--dry-run`; do not create commits or tags. +4. If the user only wants a rehearsal or passes `--dry-run`, do not edit files, commit, tag, or push; only inspect state, run safe checks when useful, and preview the release notes. ## Release -Prefer the repo-local command: +Follow these steps instead of relying on a release script: -```bash -npm run release -- --push -``` - -Without `--push`, the command prepares the local version-bump commit and annotated tag but does not publish them: - -```bash -npm run release -- -``` - -The command updates package metadata, runs the CLI build/typecheck/lint/test checks, previews the next release notes with `git-cliff --unreleased --tag`, creates the dedicated `chore: bump version to ` commit, and creates the annotated `v` tag. +1. Update `packages/cli/package.json` to `x.y.z`. +2. Update `package-lock.json` so `packages["packages/cli"].version` is also `x.y.z`. +3. Run `npm -w packages/cli run build`. +4. Run `npm -w packages/cli run typecheck`. +5. Run `npm -w packages/cli run lint`. +6. Run `npm -w packages/cli test`. +7. Preview release notes with `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header`. +8. Stage `packages/cli/package.json`, `package-lock.json`, and the rebuilt `packages/cli/dist/cli.js`. +9. Commit only those release files as `chore: bump version to x.y.z` with `Release note: skip`. +10. Create the annotated tag with `git tag -a vx.y.z -m vx.y.z`. +11. Push `main` and `vx.y.z` only when ready to publish. ## Guardrails - Do not manually push a release tag before the package version bump commit is on `main`. -- Do not use `--push` until the release note preview is acceptable. - If release notes look like an implementation log, fix commit subjects or `Release note:` bodies before tagging. -- If the command fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. +- If any step fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. - Keep release plumbing commits hidden with `Release note: skip`. ## Verify diff --git a/.gemini/commands/release.md b/.gemini/commands/release.md index 03fa09bd..7ab4cfc2 100644 --- a/.gemini/commands/release.md +++ b/.gemini/commands/release.md @@ -1,5 +1,5 @@ --- -description: Prepare or publish an Agent Note release with the repo-local release command. +description: Prepare or publish an Agent Note release with the repo-local Markdown workflow. argument-hint: [--push|--dry-run] --- @@ -9,6 +9,7 @@ Use the repo-local `agentnote-release` skill. 1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. 2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. -3. Run `npm run release -- --dry-run --allow-non-main --allow-dirty --skip-checks` for a rehearsal, `npm run release -- ` for local preparation, or `npm run release -- --push` when the user explicitly wants to publish. -4. Verify the release workflow, GitHub Release, and both npm packages after pushing. -5. Report the commands run and final release status. +3. Normalize the version: package metadata uses `x.y.z`; the git tag is always `vx.y.z`. +4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --unreleased --tag vx.y.z`, commit, tag, and push only when publishing. +5. Verify the release workflow, GitHub Release, and both npm packages after pushing. +6. Report the commands run and final release status. diff --git a/.gemini/skills/agentnote-release/SKILL.md b/.gemini/skills/agentnote-release/SKILL.md index 115f05d2..114914fe 100644 --- a/.gemini/skills/agentnote-release/SKILL.md +++ b/.gemini/skills/agentnote-release/SKILL.md @@ -1,6 +1,6 @@ --- name: agentnote-release -description: Prepare and publish Agent Note releases with the repo-local release command, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. +description: Prepare and publish Agent Note releases with the repo-local Markdown workflow, including version bump validation, release note preview, tag creation, workflow monitoring, and npm/GitHub verification. --- # Agent Note Release Workflow @@ -9,33 +9,32 @@ Use this skill when the task asks to release Agent Note, bump a version, cut a t ## Prepare -1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. +1. Confirm the target version from the user request, accepting either `x.y.z` or `vx.y.z`. Use `x.y.z` for package metadata and `vx.y.z` for the git tag. 2. Switch to `main` and pull the latest changes before an actual release. 3. Check the working tree. Do not release with unrelated dirty files. -4. If the user only wants a rehearsal, use `--dry-run`; do not create commits or tags. +4. If the user only wants a rehearsal or passes `--dry-run`, do not edit files, commit, tag, or push; only inspect state, run safe checks when useful, and preview the release notes. ## Release -Prefer the repo-local command: +Follow these steps instead of relying on a release script: -```bash -npm run release -- --push -``` - -Without `--push`, the command prepares the local version-bump commit and annotated tag but does not publish them: - -```bash -npm run release -- -``` - -The command updates package metadata, runs the CLI build/typecheck/lint/test checks, previews the next release notes with `git-cliff --unreleased --tag`, creates the dedicated `chore: bump version to ` commit, and creates the annotated `v` tag. +1. Update `packages/cli/package.json` to `x.y.z`. +2. Update `package-lock.json` so `packages["packages/cli"].version` is also `x.y.z`. +3. Run `npm -w packages/cli run build`. +4. Run `npm -w packages/cli run typecheck`. +5. Run `npm -w packages/cli run lint`. +6. Run `npm -w packages/cli test`. +7. Preview release notes with `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header`. +8. Stage `packages/cli/package.json`, `package-lock.json`, and the rebuilt `packages/cli/dist/cli.js`. +9. Commit only those release files as `chore: bump version to x.y.z` with `Release note: skip`. +10. Create the annotated tag with `git tag -a vx.y.z -m vx.y.z`. +11. Push `main` and `vx.y.z` only when ready to publish. ## Guardrails - Do not manually push a release tag before the package version bump commit is on `main`. -- Do not use `--push` until the release note preview is acceptable. - If release notes look like an implementation log, fix commit subjects or `Release note:` bodies before tagging. -- If the command fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. +- If any step fails after a local commit or tag, inspect the repository state before retrying; do not create duplicate tags. - Keep release plumbing commits hidden with `Release note: skip`. ## Verify diff --git a/AGENTS.md b/AGENTS.md index 8c45e7af..2647bf61 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -153,7 +153,7 @@ Each `UserPromptSubmit` increments a turn counter. File changes inherit the curr 2. `npm run typecheck` — tsc --noEmit 3. `npm run lint` — biome check 4. `npm test` — node:test (requires build first) -- **Version bumps** go in a dedicated `chore: bump version to x.y.z` commit. Prefer `npm run release -- x.y.z` to prepare the bump commit and tag; add `--push` only when ready to trigger the release workflow (test → GitHub Release → npm publish). +- **Version bumps** go in a dedicated `chore: bump version to x.y.z` commit. Prefer the repo-local `agentnote-release` skill or `/release` command; `x.y.z` and `vx.y.z` inputs both create the `vx.y.z` tag. Push the tag only when ready to trigger the release workflow (test → GitHub Release → npm publish). ## Constraints diff --git a/CLAUDE.md b/CLAUDE.md index 98a1fefe..b4363a07 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -153,7 +153,7 @@ Each `UserPromptSubmit` increments a turn counter. File changes inherit the curr 2. `npm run typecheck` — tsc --noEmit 3. `npm run lint` — biome check 4. `npm test` — node:test (requires build first) -- **Version bumps** go in a dedicated `chore: bump version to x.y.z` commit. Prefer `npm run release -- x.y.z` to prepare the bump commit and tag; add `--push` only when ready to trigger the release workflow (test → GitHub Release → npm publish). +- **Version bumps** go in a dedicated `chore: bump version to x.y.z` commit. Prefer the repo-local `agentnote-release` skill or `/release` command; `x.y.z` and `vx.y.z` inputs both create the `vx.y.z` tag. Push the tag only when ready to trigger the release workflow (test → GitHub Release → npm publish). ## Constraints diff --git a/docs/architecture.md b/docs/architecture.md index 1e5e20d1..369af5d9 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -617,25 +617,18 @@ should still be written as a clear sentence in the commit body. The canonical npm package is `agent-note`. The workflow also publishes `@wasabeef/agentnote` from the same built `dist/` as a reserved alias package, but end-user documentation should continue to point to `agent-note`. -Preferred release command: +Preferred release workflow: -```bash -npm run release -- X.Y.Z # prepare local version-bump commit and tag -npm run release -- X.Y.Z --push # also push main and vX.Y.Z -``` - -The command updates `packages/cli/package.json`, syncs the `packages/cli` entry -in `package-lock.json`, rebuilds `packages/cli/dist/cli.js`, runs the release -checks, prints the `git-cliff` release note preview, commits -`chore: bump version to X.Y.Z`, and creates the annotated `vX.Y.Z` tag. Without -`--push`, the release stays local so the generated notes can be inspected before -triggering `release.yml`. +Use the repo-local `agentnote-release` skill or `/release` command when asking +Codex, Claude, Cursor, or Gemini to prepare or publish a release. The skill is a +Markdown workflow on purpose: it keeps release policy near the agent +instructions without adding another release script to maintain. -Repo-local Agent skills and commands mirror this workflow for Codex, Claude, -Cursor, and Gemini. Use the `agentnote-release` skill or `/release` command -when asking an agent to prepare or publish a release. +The requested version may be written as either `X.Y.Z` or `vX.Y.Z`. The package +version is always `X.Y.Z`, and the git tag is always the annotated `vX.Y.Z` +tag. -Manual fallback steps: +Release steps: 1. Update the CLI package version in `packages/cli/package.json`. 2. Keep the workspace lockfile in sync. At minimum, update the `packages/cli` entry in `package-lock.json` so the committed workspace metadata matches the published package version. @@ -649,8 +642,11 @@ Manual fallback steps: 5. If the generated note reads like an implementation log, rewrite the relevant commit subjects or add `Release note:` / `Release note: skip` lines before tagging. -6. Commit the version bump to `main`. -7. Create and push the matching git tag, for example `vX.Y.Z`. +6. Stage `packages/cli/package.json`, `package-lock.json`, and the rebuilt + `packages/cli/dist/cli.js`. +7. Commit the version bump to `main` as `chore: bump version to X.Y.Z` with + `Release note: skip`. +8. Create and push the matching git tag, for example `vX.Y.Z`. Important: diff --git a/docs/engineering.md b/docs/engineering.md index 67d7de1f..2299b792 100644 --- a/docs/engineering.md +++ b/docs/engineering.md @@ -112,7 +112,7 @@ subject as public copy unless the commit type is intentionally internal. - Keep multi-commit PRs readable in the generated release note. Review-fix follow-up commits in a multi-commit PR should usually use `Release note: skip` unless they describe a distinct user-visible change. - The release generator capitalizes the first character of each bullet as a safety net. Still write natural English yourself; this only fixes mechanical lower-case commit subjects. - A PR title is not the release-note source, but it should still read like the top-level release summary for the PR. If the title would be a bad release bullet, improve it before opening or merging the PR. -- Before tagging, prefer `npm run release -- x.y.z` so the version bump, build, tests, release note preview, commit, and tag are produced by one repeatable command. If running the steps manually, run `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header` and rewrite commit subjects/bodies before cutting the release if the output reads like an implementation log. +- Before tagging, prefer the repo-local `agentnote-release` skill or `/release` command so agents follow the same version bump, build, tests, release note preview, commit, and `vx.y.z` tag workflow. The skill accepts `x.y.z` or `vx.y.z`, but the package version is always `x.y.z` and the git tag is always `vx.y.z`. If running the steps manually, run `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header` and rewrite commit subjects/bodies before cutting the release if the output reads like an implementation log. Good commit body shape: diff --git a/package.json b/package.json index e69ec5c8..0097f267 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,7 @@ "dashboard:restore-notes": "npm run workflow:restore-notes --prefix packages/dashboard", "dashboard:sync-notes": "npm run workflow:sync-notes --prefix packages/dashboard", "dashboard:build-pages": "npm run workflow:build-pages --prefix packages/dashboard", - "dashboard:persist-notes": "npm run workflow:persist-notes --prefix packages/dashboard", - "release": "node scripts/release.mjs" + "dashboard:persist-notes": "npm run workflow:persist-notes --prefix packages/dashboard" }, "workspaces": [ "packages/cli", diff --git a/scripts/release.mjs b/scripts/release.mjs deleted file mode 100644 index 031fa387..00000000 --- a/scripts/release.mjs +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/env node - -import { execFileSync } from "node:child_process"; -import { readFileSync, writeFileSync } from "node:fs"; - -const CLI_PACKAGE_PATH = "packages/cli/package.json"; -const LOCKFILE_PATH = "package-lock.json"; -const CLI_DIST_PATH = "packages/cli/dist/cli.js"; -const KNOWN_FLAGS = new Set([ - "--push", - "--dry-run", - "--skip-checks", - "--allow-dirty", - "--allow-non-main", - "--help", - "-h", -]); -const RELEASE_CHECKS = [ - ["npm", ["-w", "packages/cli", "run", "build"]], - ["npm", ["-w", "packages/cli", "run", "typecheck"]], - ["npm", ["-w", "packages/cli", "run", "lint"]], - ["npm", ["-w", "packages/cli", "test"]], -]; - -function printUsage() { - console.log(`Usage: - npm run release -- [--push] - -Examples: - npm run release -- 1.0.6 - npm run release -- 1.0.6 --push - npm run release -- 1.0.6 --dry-run --allow-non-main --allow-dirty - -Options: - --push Push main and the release tag after creating them locally. - --dry-run Print the planned release without editing files, committing, or tagging. - --skip-checks Skip local build/typecheck/lint/test checks. - --allow-dirty Allow a dirty working tree before the release command starts. - --allow-non-main Allow running from a branch other than main. - --help Show this help. -`); -} - -function run(command, args, opts = {}) { - const printable = [command, ...args].join(" "); - if (opts.dryRun) { - console.log(`$ ${printable}`); - return ""; - } - console.log(`$ ${printable}`); - return execFileSync(command, args, { encoding: "utf8", stdio: ["ignore", "pipe", "inherit"] }); -} - -function readJson(path) { - return JSON.parse(readFileSync(path, "utf8")); -} - -function writeJson(path, value, dryRun) { - if (dryRun) return; - writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`); -} - -function normalizeVersion(input) { - const version = input.startsWith("v") ? input.slice(1) : input; - if (!/^\d+\.\d+\.\d+$/.test(version)) { - throw new Error(`Release version must be x.y.z, got: ${input}`); - } - return version; -} - -function gitOutput(args) { - return execFileSync("git", args, { encoding: "utf8" }).trim(); -} - -function assertCleanWorktree(allowDirty) { - if (allowDirty) return; - const status = gitOutput(["status", "--porcelain"]); - if (status) { - throw new Error( - "Working tree must be clean before release. Commit/stash changes or pass --allow-dirty.", - ); - } -} - -function assertMainBranch(allowNonMain) { - if (allowNonMain) return; - const branch = gitOutput(["branch", "--show-current"]); - if (branch !== "main") { - throw new Error(`Release command must run on main, current branch is: ${branch}`); - } -} - -function assertTagAvailable(tag) { - const existing = gitOutput(["tag", "--list", tag]); - if (existing) throw new Error(`Local tag already exists: ${tag}`); -} - -function updateVersions(version, dryRun) { - const cliPackage = readJson(CLI_PACKAGE_PATH); - cliPackage.version = version; - writeJson(CLI_PACKAGE_PATH, cliPackage, dryRun); - - const lockfile = readJson(LOCKFILE_PATH); - const packages = lockfile.packages; - const cliPackageLock = packages?.["packages/cli"]; - if (!cliPackageLock) { - throw new Error("package-lock.json is missing packages/cli metadata."); - } - cliPackageLock.version = version; - writeJson(LOCKFILE_PATH, lockfile, dryRun); -} - -function previewReleaseNotes(tag) { - console.log("\nRelease note preview:\n"); - const output = execFileSync( - "git-cliff", - ["--config", ".github/cliff.toml", "--unreleased", "--tag", tag, "--strip", "header"], - { encoding: "utf8", stdio: ["ignore", "pipe", "inherit"] }, - ); - console.log(output.trim()); - console.log(""); -} - -function commitAndTag(version, tag, dryRun) { - run("git", ["add", CLI_PACKAGE_PATH, LOCKFILE_PATH], { dryRun }); - run("git", ["add", "-f", CLI_DIST_PATH], { dryRun }); - run( - "git", - [ - "commit", - "-m", - `chore: bump version to ${version}`, - "-m", - [ - "Why", - `Prepare the CLI package for the v${version} release. The release workflow publishes the committed package version, so package metadata and the bundled CLI must match the tag.`, - "", - "User impact", - `The v${version} npm package and GitHub release will publish the changes already merged on main.`, - "", - "Verification", - "npm -w packages/cli run build", - "npm -w packages/cli run typecheck", - "npm -w packages/cli run lint", - "npm -w packages/cli test", - `git-cliff --config .github/cliff.toml --unreleased --tag ${tag} --strip header`, - "", - "Release note: skip", - ].join("\n"), - ], - { dryRun }, - ); - run("git", ["tag", "-a", tag, "-m", tag], { dryRun }); -} - -function parseArgs(argv) { - const flags = new Set(argv.filter((arg) => arg.startsWith("-"))); - const positional = argv.filter((arg) => !arg.startsWith("-")); - for (const flag of flags) { - if (!KNOWN_FLAGS.has(flag)) { - throw new Error(`Unknown option: ${flag}`); - } - } - if (positional.length > 1) { - throw new Error(`Expected one version argument, got: ${positional.join(" ")}`); - } - return { - version: positional[0] ?? null, - push: flags.has("--push"), - dryRun: flags.has("--dry-run"), - skipChecks: flags.has("--skip-checks"), - allowDirty: flags.has("--allow-dirty"), - allowNonMain: flags.has("--allow-non-main"), - help: flags.has("--help") || flags.has("-h"), - }; -} - -function main() { - const args = parseArgs(process.argv.slice(2)); - if (args.help || !args.version) { - printUsage(); - process.exit(args.help ? 0 : 1); - } - - const version = normalizeVersion(args.version); - const tag = `v${version}`; - - assertMainBranch(args.allowNonMain); - assertCleanWorktree(args.allowDirty); - assertTagAvailable(tag); - - console.log(`Preparing ${tag}${args.dryRun ? " (dry run)" : ""}`); - updateVersions(version, args.dryRun); - - if (!args.skipChecks) { - for (const [command, commandArgs] of RELEASE_CHECKS) { - run(command, commandArgs, { dryRun: args.dryRun }); - } - } - - previewReleaseNotes(tag); - commitAndTag(version, tag, args.dryRun); - - if (args.push) { - run("git", ["push", "origin", "main"], { dryRun: args.dryRun }); - run("git", ["push", "origin", tag], { dryRun: args.dryRun }); - } else { - console.log(`Local release commit and ${tag} tag are ready.`); - console.log(`Run: git push origin main && git push origin ${tag}`); - } -} - -try { - main(); -} catch (error) { - console.error(`release: ${error instanceof Error ? error.message : String(error)}`); - process.exit(1); -} From 5ca071cb7093b451ba29452fcc3d8cf0f110f9c1 Mon Sep 17 00:00:00 2001 From: wasabeef Date: Fri, 15 May 2026 18:08:50 +0900 Subject: [PATCH 4/4] docs(release): address release skill review Why CodeRabbit found two places where the release workflow docs could diverge from the canonical maintainer process: abbreviated git-cliff previews and ambiguous lockfile update guidance. User impact Agents following /release now use the same git-cliff command everywhere and run npm install to synchronize package-lock.json instead of implying manual lockfile edits. Verification git diff --check node -e "JSON.parse(require('fs').readFileSync('package.json','utf8')); console.log('package.json ok')" git-cliff --config .github/cliff.toml --unreleased --tag v1.0.6 --strip header npm -w packages/cli run typecheck shasum .codex/skills/agentnote-release/SKILL.md .claude/skills/agentnote-release/SKILL.md .cursor/skills/agentnote-release/SKILL.md .gemini/skills/agentnote-release/SKILL.md shasum .codex/commands/release.md .claude/commands/release.md .cursor/commands/release.md .gemini/commands/release.md Release note: skip --- .claude/commands/release.md | 2 +- .claude/skills/agentnote-release/SKILL.md | 2 +- .codex/commands/release.md | 2 +- .codex/skills/agentnote-release/SKILL.md | 2 +- .cursor/commands/release.md | 2 +- .cursor/skills/agentnote-release/SKILL.md | 2 +- .gemini/commands/release.md | 2 +- .gemini/skills/agentnote-release/SKILL.md | 2 +- docs/architecture.md | 3 ++- 9 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.claude/commands/release.md b/.claude/commands/release.md index 7ab4cfc2..695b5d81 100644 --- a/.claude/commands/release.md +++ b/.claude/commands/release.md @@ -10,6 +10,6 @@ Use the repo-local `agentnote-release` skill. 1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. 2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. 3. Normalize the version: package metadata uses `x.y.z`; the git tag is always `vx.y.z`. -4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --unreleased --tag vx.y.z`, commit, tag, and push only when publishing. +4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header`, commit, tag, and push only when publishing. 5. Verify the release workflow, GitHub Release, and both npm packages after pushing. 6. Report the commands run and final release status. diff --git a/.claude/skills/agentnote-release/SKILL.md b/.claude/skills/agentnote-release/SKILL.md index 114914fe..9d622ca2 100644 --- a/.claude/skills/agentnote-release/SKILL.md +++ b/.claude/skills/agentnote-release/SKILL.md @@ -19,7 +19,7 @@ Use this skill when the task asks to release Agent Note, bump a version, cut a t Follow these steps instead of relying on a release script: 1. Update `packages/cli/package.json` to `x.y.z`. -2. Update `package-lock.json` so `packages["packages/cli"].version` is also `x.y.z`. +2. Run `npm install` from the repository root so npm updates `package-lock.json` and synchronizes `packages["packages/cli"].version` to `x.y.z`. 3. Run `npm -w packages/cli run build`. 4. Run `npm -w packages/cli run typecheck`. 5. Run `npm -w packages/cli run lint`. diff --git a/.codex/commands/release.md b/.codex/commands/release.md index 7ab4cfc2..695b5d81 100644 --- a/.codex/commands/release.md +++ b/.codex/commands/release.md @@ -10,6 +10,6 @@ Use the repo-local `agentnote-release` skill. 1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. 2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. 3. Normalize the version: package metadata uses `x.y.z`; the git tag is always `vx.y.z`. -4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --unreleased --tag vx.y.z`, commit, tag, and push only when publishing. +4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header`, commit, tag, and push only when publishing. 5. Verify the release workflow, GitHub Release, and both npm packages after pushing. 6. Report the commands run and final release status. diff --git a/.codex/skills/agentnote-release/SKILL.md b/.codex/skills/agentnote-release/SKILL.md index 114914fe..9d622ca2 100644 --- a/.codex/skills/agentnote-release/SKILL.md +++ b/.codex/skills/agentnote-release/SKILL.md @@ -19,7 +19,7 @@ Use this skill when the task asks to release Agent Note, bump a version, cut a t Follow these steps instead of relying on a release script: 1. Update `packages/cli/package.json` to `x.y.z`. -2. Update `package-lock.json` so `packages["packages/cli"].version` is also `x.y.z`. +2. Run `npm install` from the repository root so npm updates `package-lock.json` and synchronizes `packages["packages/cli"].version` to `x.y.z`. 3. Run `npm -w packages/cli run build`. 4. Run `npm -w packages/cli run typecheck`. 5. Run `npm -w packages/cli run lint`. diff --git a/.cursor/commands/release.md b/.cursor/commands/release.md index 7ab4cfc2..695b5d81 100644 --- a/.cursor/commands/release.md +++ b/.cursor/commands/release.md @@ -10,6 +10,6 @@ Use the repo-local `agentnote-release` skill. 1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. 2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. 3. Normalize the version: package metadata uses `x.y.z`; the git tag is always `vx.y.z`. -4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --unreleased --tag vx.y.z`, commit, tag, and push only when publishing. +4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header`, commit, tag, and push only when publishing. 5. Verify the release workflow, GitHub Release, and both npm packages after pushing. 6. Report the commands run and final release status. diff --git a/.cursor/skills/agentnote-release/SKILL.md b/.cursor/skills/agentnote-release/SKILL.md index 114914fe..9d622ca2 100644 --- a/.cursor/skills/agentnote-release/SKILL.md +++ b/.cursor/skills/agentnote-release/SKILL.md @@ -19,7 +19,7 @@ Use this skill when the task asks to release Agent Note, bump a version, cut a t Follow these steps instead of relying on a release script: 1. Update `packages/cli/package.json` to `x.y.z`. -2. Update `package-lock.json` so `packages["packages/cli"].version` is also `x.y.z`. +2. Run `npm install` from the repository root so npm updates `package-lock.json` and synchronizes `packages["packages/cli"].version` to `x.y.z`. 3. Run `npm -w packages/cli run build`. 4. Run `npm -w packages/cli run typecheck`. 5. Run `npm -w packages/cli run lint`. diff --git a/.gemini/commands/release.md b/.gemini/commands/release.md index 7ab4cfc2..695b5d81 100644 --- a/.gemini/commands/release.md +++ b/.gemini/commands/release.md @@ -10,6 +10,6 @@ Use the repo-local `agentnote-release` skill. 1. Use the provided version argument, accepting `x.y.z` or `vx.y.z`. 2. For an actual release, switch to `main`, pull, and ensure unrelated dirty files are not present. 3. Normalize the version: package metadata uses `x.y.z`; the git tag is always `vx.y.z`. -4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --unreleased --tag vx.y.z`, commit, tag, and push only when publishing. +4. Follow the skill's manual release steps: update package metadata, rebuild, run checks, preview with `git-cliff --config .github/cliff.toml --unreleased --tag vx.y.z --strip header`, commit, tag, and push only when publishing. 5. Verify the release workflow, GitHub Release, and both npm packages after pushing. 6. Report the commands run and final release status. diff --git a/.gemini/skills/agentnote-release/SKILL.md b/.gemini/skills/agentnote-release/SKILL.md index 114914fe..9d622ca2 100644 --- a/.gemini/skills/agentnote-release/SKILL.md +++ b/.gemini/skills/agentnote-release/SKILL.md @@ -19,7 +19,7 @@ Use this skill when the task asks to release Agent Note, bump a version, cut a t Follow these steps instead of relying on a release script: 1. Update `packages/cli/package.json` to `x.y.z`. -2. Update `package-lock.json` so `packages["packages/cli"].version` is also `x.y.z`. +2. Run `npm install` from the repository root so npm updates `package-lock.json` and synchronizes `packages["packages/cli"].version` to `x.y.z`. 3. Run `npm -w packages/cli run build`. 4. Run `npm -w packages/cli run typecheck`. 5. Run `npm -w packages/cli run lint`. diff --git a/docs/architecture.md b/docs/architecture.md index 369af5d9..132062bc 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -631,7 +631,8 @@ tag. Release steps: 1. Update the CLI package version in `packages/cli/package.json`. -2. Keep the workspace lockfile in sync. At minimum, update the `packages/cli` entry in `package-lock.json` so the committed workspace metadata matches the published package version. +2. Run `npm install` from the repository root so npm updates `package-lock.json` + and synchronizes the `packages/cli` entry with the new package version. 3. Run the release checks locally: - `npm -w packages/cli run build` - `npm -w packages/cli run typecheck`