Files
zhu1090093659 30ab8692a9 chore(sdk): advance the plugin cohort to 0.1.7-rc.2
Move every family manifest, the plugin scaffold and the shared workspace
package onto the 0.1.7-rc.2 cohort, together with the surfaces that state
the same fact:

- the dsh.engines.dsh floors and the matching @deepseek-ai/dsh host peers
- the release-age exclusion ledger and the two packageExtensions keys
- the root README badges, the CI/release mount-smoke pins and the
  docs/publish-prep.md and docs/plugins.md prose

Two rc.2 facts were verified against the published artifacts rather than
inferred from the version number:

- the shell's frozen static module table is unchanged (the same nine
  specifiers in the dsh-web-frontend rc.2 dist bundle), so
  shared/web-platform.ts keeps its list and only its provenance comment
  moves; the new dsh-client-shortcuts is an ordinary client plugin, not a
  static module
- @deepseek-ai/dsh-client-ui-primitives@0.1.7-rc.2 imports a further
  undeclared face, @deepseek-ai/dsh-util-code-language, so the
  primitives packageExtensions patch gains that pin

The satellite peer floors in pnpm-lock.yaml still read >=0.1.7-rc.1: they
belong to the satellite packages and move when those repositories release
the aligned version.
2026-09-24 22:26:05 +08:00

232 lines
8.6 KiB
YAML

name: Release
# Tag-triggered release pipeline: pushing a vX.Y.Z tag is the single release
# switch. The workflow verifies every package version equals the tag version
# (the tag is the version source of truth) and runs the full gate. The npm
# publish lane sits behind the NPM_PUBLISH_ENABLED switch (workflow env
# below): while it is 'false', a tag push stops at the mount smoke plus the
# GitHub Release and nothing reaches npm.
#
# The lane is enabled: the @deepseek-ai/* alpha.2 cohort the family tracks
# is published to npm (alpha dist-tag), so the family's @deepseek-ai/*
# dependency ranges resolve from the registry. With NPM_PUBLISH_ENABLED
# 'true', a tag push publishes every family package in dependency order and
# runs the post-publish strict-registry smoke assertion.
#
# Publishing requires the repository secret NPM_TOKEN (npm automation token
# for the @linxin666 scope).
on:
push:
tags:
- 'v*'
env:
# Single switch for the npm publish lane. Decision record:
# .agents/notes/implemented/process/2026-08-28-pause-release-npm-publish-unstable-dsh-alpha.md
NPM_PUBLISH_ENABLED: 'true'
permissions:
contents: write
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
publish:
name: Build, test, gated npm publish
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@v5
with:
# Full history so scripts/release-notes.mjs can walk back to the
# previous v* tag and build the release notes commit range.
fetch-depth: 0
- name: Lint GitHub Actions workflows
uses: docker://rhysd/actionlint:latest
- name: Setup pnpm
uses: pnpm/action-setup@v5
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: 22
cache: pnpm
# --ignore-scripts: the consistency checks compare COMMITTED bundle
# artifacts against the committed sources; a fresh build embeds the
# checkout's absolute path into every bundle (CSS-module hashes and
# \0dsh-css region markers), so rebuilt bytes differ per machine. The
# explicit Build step still verifies everything builds.
- name: Install dependencies
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Typecheck
run: pnpm typecheck
- name: Build
run: pnpm build
- name: Tests
run: pnpm test
- name: Script tests
run: pnpm test:scripts
- name: Aggregate package consistency
run: pnpm aggregate:check
# Publish-safety gate (issue #70 class): no published lib bundle may
# import a devDependencies-only package. Runs in CI on every PR; the
# tag pipeline must enforce it too, before anything reaches npm.
- name: Runtime dependency guard
run: pnpm runtime-deps:check
- name: Extract tag version
id: tag
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
- name: Verify package versions match the tag
run: node scripts/verify-version.mjs "${{ steps.tag.outputs.version }}"
# Generated before publish: a notes failure must abort the run
# before anything reaches npm (a failed publish cannot be re-run
# for an already-published version).
#
# Bilingual convention (v0.2.6+): the maintainer commits the split-view
# notes at docs/release-notes/<tag>.md together with the release
# commit; the pipeline prefers that file. The notes show Chinese by
# default with the English version behind a <details> toggle. The
# scripts/release-notes.mjs draft (authored subjects in both views) is
# only a fallback when the committed file is missing.
- name: Generate release notes
run: |
NOTES_FILE="docs/release-notes/${GITHUB_REF_NAME}.md"
if [ -f "$NOTES_FILE" ]; then
cp "$NOTES_FILE" "$RUNNER_TEMP/release-notes.md"
else
node scripts/release-notes.mjs "$GITHUB_REF_NAME" > "$RUNNER_TEMP/release-notes.md"
fi
# Hand the notes to the release job (job 2): they must exist before
# anything downstream runs (a notes failure aborts the run), and the
# release job consumes them after the mount smoke.
- name: Upload release notes artifact
uses: actions/upload-artifact@v4
with:
name: release-notes
path: ${{ runner.temp }}/release-notes.md
if-no-files-found: error
# Publish with the explicit "latest" dist-tag so that installing the
# package without a version (or with @latest) always resolves to the
# newest release, never a stale earlier one. Gated on the
# NPM_PUBLISH_ENABLED switch.
- name: Publish packages to npm
if: env.NPM_PUBLISH_ENABLED == 'true'
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
pnpm -r publish --no-git-checks --access public --registry=https://registry.npmjs.org/ --tag latest
# pnpm's per-package success lines are not a trust boundary: the
# registry can lag minutes behind a publish (v0.3.18) or lose a version
# silently, and the mount smoke's auto rewrite would paper over a
# missing family dependency with a workspace tarball. Assert every
# family version resolves from the registry, retrying propagation lag,
# before the mount smoke and the GitHub Release run.
- name: Verify published versions on the registry
if: env.NPM_PUBLISH_ENABLED == 'true'
run: node scripts/verify-registry.mjs "${{ steps.tag.outputs.version }}"
# Dual-publish the final legacy aggregate name for the transition
# window. The legacy tarball is derived from the fresh current package,
# carries the old browser loader id, and announces dsh.migrate so the
# plugin-manager and Doctor can migrate existing profiles automatically.
- name: Publish legacy aggregate package
if: env.NPM_PUBLISH_ENABLED == 'true'
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
node scripts/publish-legacy-aggregate.mjs "${{ steps.tag.outputs.version }}"
# The GitHub Release is created by the verify-release job only after
# the mount smoke passes; a failed smoke leaves the tag without a
# release for inspection instead of shipping a bad consumer path
# silently.
verify-release:
name: Mount smoke + GitHub Release
needs: publish
runs-on: ubuntu-latest
timeout-minutes: 30
env:
DSH_TELEMETRY_DISABLED: '1'
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup pnpm
uses: pnpm/action-setup@v5
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: 22
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile --ignore-scripts
# Pin the DSH CLI the lane mounts into (same pin as ci.yml's
# plugin-mount lane).
- name: Install dsh CLI (pinned)
run: npm install -g @deepseek-ai/dsh@0.1.7-rc.2
# The aggregate tarball must be produced from a fresh build.
- name: Build
run: pnpm build
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install Playwright Chromium
timeout-minutes: 10
run: pnpm exec playwright install chromium
# The auto rewrite in scripts/e2e-mount-rewrite keeps the consumer
# assertion honest in both states: with the npm lane enabled every
# family dependency is published, so the tarball stays on the registry
# path (npm-strict consumer install); with the lane paused every packed
# version is unpublished, so each family dependency is packed from the
# workspace and installed as a file: tarball — the smoke then validates
# this tag's own builds.
- name: Mount + headless-render smoke
run: bash scripts/e2e-mount.sh
- name: Download release notes artifact
uses: actions/download-artifact@v4
with:
name: release-notes
path: ${{ runner.temp }}
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "$GITHUB_REF_NAME" \
--notes-file "$RUNNER_TEMP/release-notes.md" \
--title "dsh-web $GITHUB_REF_NAME"