fix: add production runtime RC release channel

Publish signed prerelease artifacts from v2.0.0-rc.* tags, bind bootstrap trust to the immutable RC tag, make missing-release errors actionable, and install the six public skills from the canonical subpath.
This commit is contained in:
Sinabina
2026-07-20 16:51:59 -07:00
parent d6ef673e4d
commit b0047cc525
84 changed files with 367 additions and 140 deletions
+2 -2
View File
@@ -384,7 +384,7 @@ Print this replacement invocation, then dispatch to it exactly:
\`${assignment.replacement}\`
Do not reproduce or summarize the retired specialist here. The canonical dispatcher must load its preserved \`${assignment.source}\` module. If that dispatcher is not installed, tell the user to install it with \`npx skills add time-attack/gstack --skill ${assignment.tree}\`.
Do not reproduce or summarize the retired specialist here. The canonical dispatcher must load its preserved \`${assignment.source}\` module. If that dispatcher is not installed, tell the user to install it with \`npx skills add time-attack/gstack/skills --skill ${assignment.tree}\`.
`);
rows.push(`| \`/${assignment.source}\` | \`${assignment.replacement}\` | \`skills/${assignment.tree}/references/legacy/${assignment.source}.md\` |`);
aliases.push({
@@ -483,7 +483,7 @@ function webContextContract(): string {
'',
'Persist only the explicit choice with `gstack context select host`, `gstack context select local-browser`, or `gstack context select none`. For Context.dev, show `gstack context options`, then use `gstack context setup` and its hidden key prompt; consent and key storage belong to the runtime, never this judgment prompt. Do not infer Context choice or consent.',
'',
'Capability-dependent work follows `references/RUNTIME.md`. Pure judgment never requires the runtime. Skill placement remains owned by `npx skills add time-attack/gstack` and is never inferred from runtime state.',
'Capability-dependent work follows `references/RUNTIME.md`. Pure judgment never requires the runtime. Skill placement remains owned by `npx skills add time-attack/gstack/skills` and is never inferred from runtime state.',
'',
].join('\n');
}
+2 -2
View File
@@ -188,7 +188,7 @@ export function renderLegacyBody(source: string): string {
*/
function portLegacyText(value: string, source: string): string {
if (source === 'gstack-upgrade') {
return `# Legacy upgrade compatibility\n\nThe 1.x host-directory detector, vendored-copy synchronizer, and destructive Git replacement blocks were duplicated installation infrastructure. GStack 2 delegates skill placement and updates to the standard Agent Skills installer and manages the optional shared runtime atomically.\n\n- Update selected skills with \`npx skills add time-attack/gstack\` using the user's existing project/global choice. Never infer or enroll a host.\n- Upgrade a complete local runtime package with \`gstack upgrade --source <complete-gstack-package> --version <version>\`.\n- Roll back the runtime with \`gstack upgrade --rollback\`.\n- Run \`gstack doctor\` after either operation.\n- Do not reset, delete, move, or rewrite a host skill directory. Do not infer Context.dev choice or consent.\n\nThis compatibility module contains no specialist judgment; release readiness and rollback judgment remain in the preserved ship modules.\n`;
return `# Legacy upgrade compatibility\n\nThe 1.x host-directory detector, vendored-copy synchronizer, and destructive Git replacement blocks were duplicated installation infrastructure. GStack 2 delegates skill placement and updates to the standard Agent Skills installer and manages the optional shared runtime atomically.\n\n- Update selected skills with \`npx skills add time-attack/gstack/skills\` using the user's existing project/global choice. Never infer or enroll a host.\n- Upgrade a complete local runtime package with \`gstack upgrade --source <complete-gstack-package> --version <version>\`.\n- Roll back the runtime with \`gstack upgrade --rollback\`.\n- Run \`gstack doctor\` after either operation.\n- Do not reset, delete, move, or rewrite a host skill directory. Do not infer Context.dev choice or consent.\n\nThis compatibility module contains no specialist judgment; release readiness and rollback judgment remain in the preserved ship modules.\n`;
}
let body = value;
@@ -280,7 +280,7 @@ function portLegacyText(value: string, source: string): string {
.replaceAll('$GSTACK_ROOT/lib/redact-audit-log.ts', '$GSTACK_BIN/gstack-redact-audit-log')
.replaceAll('bun $GSTACK_BIN/gstack-redact-audit-log', '$GSTACK_BIN/gstack-redact-audit-log')
.replaceAll('Disk paths stay `$GSTACK_ROOT/[skill-name]/SKILL.md`.', 'Resolve retired names through `references/COMPATIBILITY.md`; skill placement is installer-owned.')
.replaceAll('Tell the user: "Done. Each developer now runs: `cd $GSTACK_ROOT && ./setup --team`"', 'Tell the user: "Done. Each developer installs the selected canonical skills with `npx skills add time-attack/gstack`; the optional runtime remains user-scoped."');
.replaceAll('Tell the user: "Done. Each developer now runs: `cd $GSTACK_ROOT && ./setup --team`"', 'Tell the user: "Done. Each developer installs the selected canonical skills with `npx skills add time-attack/gstack/skills`; the optional runtime remains user-scoped."');
body = body
.replace(/_VENDORED="no"\nif \[ -d "\.agents\/skills\/gstack" \][\s\S]*?echo "VENDORED_GSTACK: \$_VENDORED"/g, '_VENDORED="managed-by-standard-installer"\necho "VENDORED_GSTACK: $_VENDORED"')
+18 -9
View File
@@ -438,6 +438,15 @@ function verifyInstalledCase(
const installedSkills = listInstalledSkills(targetRoot);
const sortedExpected = [...expectedSkills].sort();
record(checks, `${id}.command`, command.exitCode === 0, `exit=${command.exitCode}; signal=${command.signal ?? 'none'}`);
if (sourceSkillSegments.length === 1 && sourceSkillSegments[0] === 'skills') {
const reported = Number(stripTerminalControls(command.stdout).match(/Found\s+(\d+)\s+skills?/)?.[1]);
record(
checks,
`${id}.public-discovery-count`,
reported === PUBLIC_SKILLS.length,
`expected installer to report 6 public skills; found ${Number.isFinite(reported) ? reported : '(unparsed)'}`,
);
}
record(
checks,
`${id}.selected-skills`,
@@ -595,10 +604,10 @@ export function runFullMatrix(options: FullMatrixOptions): InstallMatrixEvidence
const supportsRemoval = /remove\s+\[skills\]/.test(helpCommand.stdout) && /Remove Options/.test(helpCommand.stdout);
const discoveryCommand = execute(
// Exercise the repository root exactly as the documented
// `npx skills add time-attack/gstack` path will after checkout. The
// curated projection alone could hide stray root-level SKILL.md files.
skillsCliArgv(npxExecutable, ['add', repoRoot, '--list']),
// Exercise the documented public source directly. The repository root
// also contains opt-in 1.x compatibility aliases; skills@1.5.19 counts
// those internal entries before applying an explicit --skill filter.
skillsCliArgv(npxExecutable, ['add', path.join(repoRoot, 'skills'), '--list']),
controlProject,
controlEnv,
);
@@ -626,7 +635,7 @@ export function runFullMatrix(options: FullMatrixOptions): InstallMatrixEvidence
entry,
scope,
sourceKind,
sourceArgument: sourceKind === 'source-symlink' ? sourceLink : sourceRoot,
sourceArgument: path.join(sourceKind === 'source-symlink' ? sourceLink : sourceRoot, 'skills'),
sourceRoot,
expectedSkills: PUBLIC_SKILLS,
explicitSelection: false,
@@ -643,7 +652,7 @@ export function runFullMatrix(options: FullMatrixOptions): InstallMatrixEvidence
entry: cursor,
scope: 'project',
sourceKind: 'repository-root',
sourceArgument: repoRoot,
sourceArgument: path.join(repoRoot, 'skills'),
sourceRoot: repoRoot,
expectedSkills: COLLISION_SKILLS,
explicitSelection: true,
@@ -659,7 +668,7 @@ export function runFullMatrix(options: FullMatrixOptions): InstallMatrixEvidence
entry: codex,
scope: 'global',
sourceKind: 'path-with-spaces',
sourceArgument: sourceRoot,
sourceArgument: path.join(sourceRoot, 'skills'),
sourceRoot,
expectedSkills: COLLISION_SKILLS,
explicitSelection: true,
@@ -675,7 +684,7 @@ export function runFullMatrix(options: FullMatrixOptions): InstallMatrixEvidence
entry: openclaw,
scope: 'project',
sourceKind: 'path-with-spaces',
sourceArgument: sourceRoot,
sourceArgument: path.join(sourceRoot, 'skills'),
sourceRoot,
expectedSkills: ['ship'],
explicitSelection: true,
@@ -747,7 +756,7 @@ export function runFullMatrix(options: FullMatrixOptions): InstallMatrixEvidence
platform: process.platform,
architecture: process.arch,
repositoryRoot: repoRoot,
sourceProjection: 'repository-root-and-canonical-projection',
sourceProjection: 'canonical-skills-subpath-and-opt-in-compatibility-root',
cli: {
executable: npxExecutable,
version,