feat(#815): add /gsd-update --next to install the @next RC channel (#839)

Adds an opt-in --next (alias --rc) flag to /gsd-update targeting the @next RC dist-tag (ADR #660), with a {latest,next} allowlist enforced at three layers, channel-aware version check + banner, and byte-for-byte unchanged default @latest behavior.

Closes #815
This commit is contained in:
Tom Boucher
2026-06-07 20:22:07 -04:00
committed by GitHub
parent 5b4880522b
commit 40d48c0508
12 changed files with 249 additions and 20 deletions

View File

@@ -4,18 +4,20 @@
// Regression guard for bug #3130.
//
// Two failure modes were observed with the pre-fix npx invocation form:
// 1. Cache-stale: bare `npx -y @opengsd/gsd-core@latest` hits npx's local
// cache and may pull an older version instead of @latest.
// 1. Cache-stale: bare `npx -y @opengsd/gsd-core@<tag>` hits npx's local
// cache and may pull an older version instead of the target tag.
// 2. Token-routing: Bash-tool wrappers misroute the `@` token in
// `@opengsd/gsd-core@latest`, causing npm to error with
// "Unknown command: @opengsd/gsd-core@latest".
// `@opengsd/gsd-core@<tag>`, causing npm to error with
// "Unknown command: @opengsd/gsd-core@<tag>".
//
// The robust form is:
// npx -y --package=@opengsd/gsd-core@latest -- gsd-core $ARGS
// npx -y --package=@opengsd/gsd-core@"$TAG" -- gsd-core $ARGS
//
// `--package=` forces a fresh registry fetch, bypassing the npx cache.
// `--` clearly delineates npx flags from the run-command, preventing
// Bash-tool @-token misrouting.
// `$TAG` is a shell variable (latest by default, next under --next/--rc),
// set by the parse_update_channel step (#815).
const { test } = require('node:test');
const assert = require('node:assert/strict');
@@ -28,9 +30,9 @@ const UPDATE_WF = path.join(ROOT, 'gsd-core', 'workflows', 'update.md');
const src = fs.readFileSync(UPDATE_WF, 'utf8');
test('bug #3130: update.md contains no bare npx invocations (cache-stale form)', () => {
// Any occurrence of `npx -y @opengsd/gsd-core@latest` without `--package=`
// Any occurrence of `npx -y @opengsd/gsd-core@<something>` without `--package=`
// is the stale form that triggers the two failure modes.
const stale = (src.match(/npx -y @opengsd\/gsd-core@latest[^\n]*/g) || []);
const stale = (src.match(/npx -y @opengsd\/gsd-core@\S+[^\n]*/g) || []);
assert.deepEqual(
stale,
[],
@@ -40,7 +42,8 @@ test('bug #3130: update.md contains no bare npx invocations (cache-stale form)',
test('bug #3130: update.md has >=3 robust npx invocations (--package= + -- separator)', () => {
// Three sibling invocations: local, global, and unknown/fallback.
const robust = (src.match(/npx -y --package=@opengsd\/gsd-core@latest -- gsd-core/g) || []);
// The tag is now a $TAG variable (latest by default, next under --next/--rc).
const robust = (src.match(/npx -y --package=@opengsd\/gsd-core@\S+ -- gsd-core/g) || []);
assert.ok(
robust.length >= 3,
`Expected >=3 robust npx invocations in update.md, found ${robust.length}`,