You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
chore(scripts): script per-server release notes with a reporter Thanks section (release:notes) - #5064
Adds scripts/release-notes.mjs (npm run release:notes), a tested helper that writes a milestone release's notes per server. It replaces the shell recipe in the release skill's step 5a. It is modeled on the Inspector's helper (modelcontextprotocol/inspector#2591) and adapted to a release that publishes seven packages at seven versions.
The notes it produces:
## Packages every package at the merge SHA, its version, published / unchanged (registry-checked)
## <package> <version> one per PUBLISHED package
### What's Changed the PRs that change files under its src/<dir>/ (a rename's source counts too)
## Repository every PR no published section took (CI, docs, skills, an unchanged server)
## New Contributors / Full Changelog GitHub's trailer, verbatim
Release ledger: [<merge branch>](<ledger url>)
## Known issues only from --known-issue
## Thanks for helping us improve one release-wide list, laid out as the Inspector's release notes are
PR list: releases/generate-notes, from the latest published Release (asked of GitHub, never sorted out of the mixed tag list) to --merge-sha.
Bucketing: a PR goes under each published package whose src/<dir>/ it changes. Anything left over goes under Repository, so no generated PR is dropped. The generated body is parsed strictly: a line it doesn't recognize throws rather than being skipped, and the ## New Contributors lines (which also end in /pull/N) are never mistaken for PR entries.
Thanks: one ## Thanks for helping us improve section for the whole release, in the same layout as the Inspector's release notes (* @user (#1, #2), most issues first, then by name). It credits the author of every issue the listed PRs close (closingIssuesReferences, paginated, plus Closes/Fixes/Resolves #N outside code, quotes and comments). Maintainers (admin/maintain/write), bots, deleted accounts, PR numbers and other repos' issues are excluded. The section is left out when nobody remains.
Packages table: manifests are read at --merge-sha through one GraphQL tree query, so no checkout of the merge commit is needed. Each version is checked against npm or PyPI. An answer other than 200 or 404 aborts the run (the old recipe's UNKNOWN).
Existing tag: every run refuses a milestone tag that already exists, because GitHub would then build the notes and the Release from that tag's commit, not --merge-sha.
Modes: the default is a preview that prints the notes and creates nothing. --draft creates a draft Release tagged --milestone at --merge-sha. It refuses a SHA that is not on main (compare API) and a tag that already has a Release or draft. There is no --publish. Publishing starts release.yml, so it stays the maintainer's act (step 5b now publishes the draft).
Fail fast: a non-zero gh exit, GraphQL errors, a missing node, an unknown permission value, an unrecognized generated line or a registry failure throws before anything is created.
Deviations from the issue, at the maintainer's direction
One Thanks section, not one per server. Item 5 asked for a Thanks subsection in each package section. On review, the maintainer asked for the Inspector's layout instead: a single release-wide list.
Outside-PR credit (item 6) stays a documented manual step. An earlier commit added a machine-readable Credit: @login line; the maintainer judged it unnecessary, so it is removed. The release skill's step 5a again says to add those people to the draft's Thanks by hand, and the harvest docs keep their v2/main wording.
Server Details
Server: none (repository-wide)
Changes: release tooling (scripts/), the release skill's step 5, RELEASING.md step 5, the AGENTS.md tree
Motivation and Context
The current Release's notes list only package names: no PRs, no issues, no contributors. Step 5a improved on that with one flat, untested shell list for the whole repo. A reader of a release wants to know what changed in the server they use. Under the issue-only contribution model, the people to credit are the issue reporters, per server. See #5056.
How Has This Been Tested?
No server behavior changes, so the evidence is unit tests plus a live preview rather than client runs.
Unit tests: scripts/release-notes.test.mjs, 38 tests in npm run test:scripts, at about 99.6% line coverage of the script (only the CLI entry lines are not exercised). They cover:
bucketing for one server, several servers and none, including a file renamed out of a server's directory
sections only for published packages
the Repository catch-all, with an unchanged server's PR falling through to it
the release-wide Thanks: its exact layout and position, each reporter listed once across servers, and every exclusion
keyword parsing and masking
pagination of closing refs
the generated-body parser rejecting unknown lines
a failed lookup at each of ten stages, a 503 from a registry, an unknown permission, GraphQL errors and missing nodes, each aborting with nothing created
--draft's exact gh release create call (SHA target, milestone tag, no --latest), and the refusals (SHA not on main, existing Release or draft, existing tag in any mode)
Acceptance probe: a preview of v2.0.0 (#4968). The v2.0.0 merge PR hasn't merged yet, so this preview targets the current origin/v2/main head (b5cea9df), from the latest published Release 2026.8.31:
Result: exit 0 in about 2.5 minutes, nothing created. 87 generated PRs were bucketed into five published sections (server-everything, -filesystem, -memory and -sequential-thinking at 1.0.0, and mcp-server-fetch 0.6.3) plus Repository. mcp-server-git and mcp-server-time read as unchanged because their versions are already on PyPI, so they get no section and their PRs fall under Repository.
Against the milestone, I took the v2.0.0 milestone's closed issues (83) whose authors have read permission (24 issues, 20 people) and compared them with the issue numbers in the preview's Thanks section (28 people, 33 issues):
Gate (npm run local:gate, under Node 22.23.3 on macOS): every stage passes except one pre-existing, macOS-only test, src/timetest_get_current_time_errors[arguments5-expected5]. That test expects europe/warsaw to be rejected, but on macOS's case-insensitive filesystem zoneinfo resolves it. It fails identically on v2/main without this branch, and it is tracked in #5060 (v2.1.0). It fails validate:py and coverage:py for time; fetch and git pass both. The stages the && chain skipped after it were run on their own: verify:skills:cli and smoke exit 0. This PR touches no server. CI (Linux) is the authoritative run.
The script tests also ran under the local Node 26: they passed, as did every other stage up to a separate Node 26–only EISDIR-message mismatch in a memory test (not this branch; Node 22 passes it).
Breaking Changes
None. No server, published package or client configuration changes.
Types of changes
Bug fix (non-breaking change which fixes an issue)
New feature (non-breaking change which adds functionality): release tooling
Breaking change (fix or feature that would cause existing functionality to change)
I have documented all environment variables and configuration options (the CLI flags are in the script header and the release skill's step 5a)
Additional context
The README and the project-structure skill describe scripts/ generically and list no individual script, so the per-script listing updated is the AGENTS.md tree.
The release skill is name-only, and no skill description changed, so skills:eval does not apply.
The helper uses only gh and fetch, with no git, so it gives the same result from any checkout.
…s section (release:notes)
Add scripts/release-notes.mjs (npm run release:notes), modeled on the
Inspector's helper and adapted to a seven-package release. It builds the
Packages table at the merge SHA (registry-checked), one section per
published package with its PRs and the community reporters it thanks, a
Repository catch-all so no generated PR is dropped, GitHub's trailer, the
ledger line and any known issues. Outside-PR authors are credited from a
maintainer-written `Credit: @login` line. Preview by default; --draft
creates the draft Release at the merge SHA; publishing stays manual.
The release skill's step 5a uses the helper in place of the shell
recipe, and 5b publishes the draft. The harvest instructions adopt the
Credit line.
Closes#5056
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.
This PR includes no changesets
When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types
…drop Credit lines
Thanks is now a single `## Thanks for helping us improve` list at the end
of the notes, laid out as the Inspector's release notes are, rather than a
subsection per server. The maintainer-written `Credit: @login` convention
is removed: outside-PR authors are added to the draft's Thanks by hand, as
before, and the harvest docs are back to their v2/main wording.
From Copilot's review: refuse a milestone tag that already exists (GitHub
would use its commit, not --merge-sha), and count a rename's source path
when bucketing a PR by server.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 1 (3 findings), answered in each thread:
Existing milestone tag: fixed in d3bd74d. Every run refuses an exact existing refs/tags/<milestone> before generating anything.
Renamed files: fixed in d3bd74d. A rename's previous_filename now counts toward the server bucket.
Login casing in Thanks: no longer applies. It came from Credit: lines, which d3bd74d removes at the maintainer's direction, so logins now come only from issue authors' canonical spelling.
The same commit also moves Thanks to one release-wide section in the Inspector's layout (maintainer request); the PR body explains that change. Requesting round 2.
HTML comments incorrectly mask references inside code
scripts/release-notes.mjs:408
HTML comments are removed before code is recognized. For example, a body containing The delimiter is followed by the inline code span <!--, then a prose Closes #1 line, returns no issue numbers. An opener inside fenced code has the same effect: it consumes the remaining body as an unclosed comment. If the closing reference exists only in the body, the reporter disappears from Thanks. Use context-aware masking so comment delimiters inside code remain literal, and add regression cases for both inline and fenced code.
The inline-code regex accepts part of a longer backtick run as a closing delimiter. For a body containing a two-backtick span with a three-backtick run inside it, followed by a prose Closes #1 line and another inline span, subsequent matches consume the closing reference. This silently omits reporter credit when the reference exists only in the body. Require complete opening and closing backtick runs of equal length, and add a regression test for this sequence.
Copilot round 2: 0 open findings, and all 3 from round 1 are marked resolved. The review body adds two "previously missed" notes with no inline thread, answered here:
HTML-comment masking runs before code masking (proseOf, a <!-- inside an inline or fenced code span swallows a later Closes #N): declined as out of scope.
The inline-code regex can close on part of a longer backtick run: declined for the same reason.
Both need pathological Markdown in a PR body. Both matter only for a closing reference that exists in the body alone, but every PR in this repo is linked explicitly with addCloseIssueReferences, and closingIssuesReferences is the primary source. proseOf is ported unchanged from the Inspector's shipped helper (modelcontextprotocol/inspector#2591). Making it exact needs a real Markdown tokenizer, which is hardening #5056 did not ask for, and not worth an issue on its own.
The loop stops here: this round holds only declined findings, and nothing was pushed in response to it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5056
Description
Adds
scripts/release-notes.mjs(npm run release:notes), a tested helper that writes a milestone release's notes per server. It replaces the shell recipe in the release skill's step 5a. It is modeled on the Inspector's helper (modelcontextprotocol/inspector#2591) and adapted to a release that publishes seven packages at seven versions.The notes it produces:
releases/generate-notes, from the latest published Release (asked of GitHub, never sorted out of the mixed tag list) to--merge-sha.src/<dir>/it changes. Anything left over goes under Repository, so no generated PR is dropped. The generated body is parsed strictly: a line it doesn't recognize throws rather than being skipped, and the## New Contributorslines (which also end in/pull/N) are never mistaken for PR entries.## Thanks for helping us improvesection for the whole release, in the same layout as the Inspector's release notes (* @user (#1, #2), most issues first, then by name). It credits the author of every issue the listed PRs close (closingIssuesReferences, paginated, plusCloses/Fixes/Resolves #Noutside code, quotes and comments). Maintainers (admin/maintain/write), bots, deleted accounts, PR numbers and other repos' issues are excluded. The section is left out when nobody remains.--merge-shathrough one GraphQL tree query, so no checkout of the merge commit is needed. Each version is checked against npm or PyPI. An answer other than 200 or 404 aborts the run (the old recipe'sUNKNOWN).--merge-sha.--draftcreates a draft Release tagged--milestoneat--merge-sha. It refuses a SHA that is not onmain(compare API) and a tag that already has a Release or draft. There is no--publish. Publishing startsrelease.yml, so it stays the maintainer's act (step 5b now publishes the draft).ghexit, GraphQLerrors, a missing node, an unknown permission value, an unrecognized generated line or a registry failure throws before anything is created.Deviations from the issue, at the maintainer's direction
Credit: @loginline; the maintainer judged it unnecessary, so it is removed. The release skill's step 5a again says to add those people to the draft's Thanks by hand, and the harvest docs keep theirv2/mainwording.Server Details
scripts/), thereleaseskill's step 5,RELEASING.mdstep 5, theAGENTS.mdtreeMotivation and Context
The current Release's notes list only package names: no PRs, no issues, no contributors. Step 5a improved on that with one flat, untested shell list for the whole repo. A reader of a release wants to know what changed in the server they use. Under the issue-only contribution model, the people to credit are the issue reporters, per server. See #5056.
How Has This Been Tested?
No server behavior changes, so the evidence is unit tests plus a live preview rather than client runs.
Unit tests:
scripts/release-notes.test.mjs, 38 tests innpm run test:scripts, at about 99.6% line coverage of the script (only the CLI entry lines are not exercised). They cover:--draft's exactgh release createcall (SHA target, milestone tag, no--latest), and the refusals (SHA not onmain, existing Release or draft, existing tag in any mode)Acceptance probe: a preview of v2.0.0 (#4968). The v2.0.0 merge PR hasn't merged yet, so this preview targets the current
origin/v2/mainhead (b5cea9df), from the latest published Release2026.8.31:Result: exit 0 in about 2.5 minutes, nothing created. 87 generated PRs were bucketed into five published sections (
server-everything,-filesystem,-memoryand-sequential-thinkingat 1.0.0, andmcp-server-fetch0.6.3) plus Repository.mcp-server-gitandmcp-server-timeread as unchanged because their versions are already on PyPI, so they get no section and their PRs fall under Repository.Against the milestone, I took the v2.0.0 milestone's closed issues (83) whose authors have
readpermission (24 issues, 20 people) and compared them with the issue numbers in the preview's Thanks section (28 people, 33 issues):Gate (
npm run local:gate, under Node 22.23.3 on macOS): every stage passes except one pre-existing, macOS-only test,src/timetest_get_current_time_errors[arguments5-expected5]. That test expectseurope/warsawto be rejected, but on macOS's case-insensitive filesystemzoneinforesolves it. It fails identically onv2/mainwithout this branch, and it is tracked in #5060 (v2.1.0). It failsvalidate:pyandcoverage:pyfortime;fetchandgitpass both. The stages the&&chain skipped after it were run on their own:verify:skills:cliandsmokeexit 0. This PR touches no server. CI (Linux) is the authoritative run.The script tests also ran under the local Node 26: they passed, as did every other stage up to a separate Node 26–only EISDIR-message mismatch in a
memorytest (not this branch; Node 22 passes it).Breaking Changes
None. No server, published package or client configuration changes.
Types of changes
Checklist
main)RELEASING.md,AGENTS.mdand the skills are updated)npm run changeset) if this changes what a TypeScript server publishes (not applicable: nothing published changes)Additional context
project-structureskill describescripts/generically and list no individual script, so the per-script listing updated is theAGENTS.mdtree.releaseskill is name-only, and no skill description changed, soskills:evaldoes not apply.ghandfetch, with nogit, so it gives the same result from any checkout.🤖 Generated with Claude Code