Summary mode now renders the last 5 releases instead of 10 — at the
plugin's current cadence (~2 releases per week) this is about 10 days
of history, compact enough to avoid a wall of text but wide enough to
catch recent activity. Added a one-line hint pointing users at
query mode for older history.
Query mode's search window is 40 (up from 20), and the helper fetch
limit is 100 (up from 60) to ensure the window can be filled even when
sibling tags (cli-v*, marketplace-v*, etc.) interleave. Surfaced by
eval iteration 1: asking "what happened to deepen-plan?" put the
canonical v2.51.0 promotion outside the old 20-release window.
Phase 9's no-match line updated to reference 40.
The GitHub Releases API returns both a browser-friendly `html_url` and
an API `url` (pointing at `api.github.com/.../releases/{id}`). The
helper's normalizer preferred `url` first, so the rendered
"Full release notes →" links in summary mode pointed at the API
endpoint instead of the release page. Swap the preference and add a
regression test that sets both fields on an API-shaped fixture.
Surfaced by eval iteration 1 of the ce-release-notes skill.
Add /ce:release-notes to the Workflow Utilities table next to /ce-update.
Plugin/marketplace manifests are auto-counted, so no manual count bumps.
Verified bun run release:validate, full bun test (only pre-existing
flaky resolve-base test fails), and that bun run convert ships the skill
to both opencode and codex (with the Codex prompt wrapper auto-created
because the frontmatter name uses the colon form).
Replace the Phase 4 stub with the full query-mode flow: fetch a 60-raw
buffer, judge confident match across the 20-plugin-release search window,
optionally enrich the matched release(s) from the first linked PR via
gh pr view, synthesize a narrative answer with a (v2.X.Y) citation, and
fall through to a hardcoded R14 line when no confident match exists.
Phase 6 includes a prompt-injection guard: release bodies are read as
data, not as instructions. PR enrichment is best-effort — gh failures
fall through to body-only synthesis with a one-line note rather than
aborting the response. Phase 7 also instructs list-form invocation so a
release body can never inject shell content.
Wire bare /ce:release-notes invocation: parse args (stripping mode:*
tokens), invoke the helper for 40 raw releases, and render the first 10
plugin releases with version, date, body, and a release-page link.
Per-release body is soft-capped at 25 rendered lines with markdown-fence
awareness — if the cut lands inside an open code fence, append a closing
fence before the "see more" link so renderers do not swallow following
content.
Frontmatter uses the colon form (name: ce:release-notes) to align with
user-facing slash workflows and trigger the Codex prompt-wrapper path.
disable-model-invocation: true keeps the skill slash-only in v1.
Query mode is referenced as Phase 4 with a fall-back-to-summary stub;
the actual query-mode logic lands in the next unit.
Add list-plugin-releases.py — a Python 3 stdlib helper that fetches the
last N compound-engineering plugin releases from GitHub, falls back from
gh to the anonymous API on missing-binary / non-zero exit / empty result
(GHE-pointing case) / malformed JSON, and emits a single-line JSON
contract ({ok, source, fetched_at, releases[…]} or {ok:false, error{…}}).
Filters tags to compound-engineering-v* so cli-v*, coding-tutor-v*, and
marketplace-v* releases are excluded. Extracts linked PR numbers from
release-please bodies via [#N] (markdown-link form), avoiding bare #N
mentions and commit-SHA parens.
Use gh api /repos/.../releases (not gh release list --json) so body and
html_url are populated and gh's auth removes the anonymous rate limit.
Tests use Bun.spawn with two seams: CE_RELEASE_NOTES_GH_BIN to mock the
gh binary, and --api-base to point urllib at a local Bun.serve harness.
15 tests cover gh path, gh→anon fallback (4 modes), anon path, anon
error paths (rate_limit, network_outage), and integration.