Files
codewhale/docs/RELEASE_RUNBOOK.md
T
Hunter Bown 1f00ac6311 chore(release): drop auto npm publish, document manual flow, trim research PDF
- Remove the `publish-npm` job from `release.yml`. It has been failing on
  every release with `npm error code EOTP` because the configured `NPM_TOKEN`
  doesn't bypass 2FA. Manual publish from a developer machine is the actual
  ship path; codify that.
- Update `docs/RELEASE_RUNBOOK.md` "npm Wrapper Release" to describe the
  manual flow (`npm publish --access public` + OTP) and explain why the auto
  path is gone, with a recovery note for future Trusted-Publishing migration.
- Refresh stale cross-reference comment in `publish-npm.yml` (the workflow
  remains as inert plumbing for an eventual Trusted Publishing setup).
- Stop tracking `docs/DeepSeek_V4.pdf` (4.4 MB). It was never referenced
  outside test fixture filenames; the tests synthesize their own fake PDF.
  Add to `.gitignore` so a local copy can sit there without nagging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:26:10 -05:00

182 lines
7.7 KiB
Markdown

# DeepSeek TUI Release Runbook
This runbook is the source of truth for shipping Rust crates, GitHub release assets,
and the `deepseek-tui` npm wrapper.
Current packaging note:
- `deepseek-tui` is the live runtime and TUI package shipped to users today.
- `deepseek-tui-core` is a supporting workspace crate for the extraction/parity effort, not a replacement for the shipping runtime.
## Canonical Publish Targets
- End-user crates:
- `deepseek-tui`
- `deepseek-tui-cli`
- Supporting crates published from this workspace:
- `deepseek-config`
- `deepseek-protocol`
- `deepseek-state`
- `deepseek-agent`
- `deepseek-execpolicy`
- `deepseek-hooks`
- `deepseek-mcp`
- `deepseek-tools`
- `deepseek-core`
- `deepseek-app-server`
- `deepseek-tui-core`
- `deepseek-cli` on crates.io is an unrelated crate and is not part of this release flow.
## Version Coordination
- Rust crates inherit the shared workspace version from [Cargo.toml](../Cargo.toml).
- Internal path dependency versions should match the shared workspace version; stale older pins are release blockers once the workspace version moves.
- The npm wrapper version lives in [npm/deepseek-tui/package.json](../npm/deepseek-tui/package.json).
- `deepseekBinaryVersion` controls which GitHub release binaries the npm wrapper downloads.
- Packaging-only npm releases are allowed:
- bump the npm package version
- leave `deepseekBinaryVersion` pinned to the previously released Rust binaries
- rerun `npm pack` smoke checks before `npm publish`
## Preflight
Run these from the repository root before cutting a tag:
```bash
./scripts/release/check-versions.sh # version drift between workspace, npm, lockfile
cargo fmt --all -- --check
cargo check --workspace --all-targets --locked
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
cargo test --workspace --all-features --locked
cargo publish --dry-run --locked --allow-dirty -p deepseek-tui
./scripts/release/publish-crates.sh dry-run
```
`check-versions.sh` also runs in CI on every push/PR (the `versions` job in
`.github/workflows/ci.yml`), so drift between `Cargo.toml`, the per-crate
manifests, `npm/deepseek-tui/package.json`, and `Cargo.lock` is caught before
release time rather than at it.
`publish-crates.sh dry-run` performs a full `cargo publish --dry-run` for crates
without unpublished workspace dependencies and a packaging preflight for dependent
workspace crates. That avoids false negatives from crates.io not yet containing the
new workspace version while still validating package contents before publish.
For npm wrapper verification:
```bash
cargo build --release --locked -p deepseek-tui-cli -p deepseek-tui
node scripts/release/prepare-local-release-assets.js
python3 -m http.server 8123 --directory target/npm-release-assets
cd npm/deepseek-tui
DEEPSEEK_TUI_FORCE_DOWNLOAD=1 DEEPSEEK_TUI_RELEASE_BASE_URL=http://127.0.0.1:8123/ npm pack
```
Then install the generated tarball in a clean temp directory and smoke the entrypoints:
```bash
tmpdir="$(mktemp -d)"
cd "${tmpdir}"
npm init -y
DEEPSEEK_TUI_FORCE_DOWNLOAD=1 DEEPSEEK_TUI_RELEASE_BASE_URL=http://127.0.0.1:8123/ npm install /path/to/deepseek-tui-*.tgz
DEEPSEEK_TUI_FORCE_DOWNLOAD=1 DEEPSEEK_TUI_RELEASE_BASE_URL=http://127.0.0.1:8123/ npx --no-install deepseek --help
DEEPSEEK_TUI_FORCE_DOWNLOAD=1 DEEPSEEK_TUI_RELEASE_BASE_URL=http://127.0.0.1:8123/ npx --no-install deepseek-tui --help
```
To exercise `npm run release:check` locally as well, regenerate the local asset
directory with a full asset matrix fixture before starting the server:
```bash
DEEPSEEK_TUI_PREPARE_ALL_ASSETS=1 node scripts/release/prepare-local-release-assets.js
cd npm/deepseek-tui
DEEPSEEK_TUI_VERSION=X.Y.Z DEEPSEEK_TUI_RELEASE_BASE_URL=http://127.0.0.1:8123/ npm run release:check
```
Set `DEEPSEEK_TUI_VERSION` to the npm package version you are verifying for that local run.
The CI workflow runs the same tarball install + smoke test on Linux and macOS.
## Rust Crates Release
1. Update the workspace version in [Cargo.toml](../Cargo.toml).
2. Tag the release as `vX.Y.Z`.
3. Let `.github/workflows/crates-publish.yml` verify the workspace version and dry-run each crate.
4. Publish crates in this order:
- `deepseek-config`
- `deepseek-protocol`
- `deepseek-state`
- `deepseek-agent`
- `deepseek-execpolicy`
- `deepseek-hooks`
- `deepseek-mcp`
- `deepseek-tools`
- `deepseek-core`
- `deepseek-app-server`
- `deepseek-tui-core`
- `deepseek-tui-cli`
- `deepseek-tui`
5. Wait for each published crate version to appear on crates.io before publishing dependents.
The publish helper is idempotent for reruns: already-published crate versions are skipped.
## GitHub Release Assets
`.github/workflows/release.yml` builds these binaries:
- `deepseek-linux-x64`
- `deepseek-macos-x64`
- `deepseek-macos-arm64`
- `deepseek-windows-x64.exe`
- `deepseek-tui-linux-x64`
- `deepseek-tui-macos-x64`
- `deepseek-tui-macos-arm64`
- `deepseek-tui-windows-x64.exe`
The release job also uploads `deepseek-artifacts-sha256.txt`. The npm installer and
release verification script both depend on that checksum manifest.
## npm Wrapper Release
**The npm publish step is manual.** `release.yml` no longer runs `npm publish`
because the npm account requires 2FA OTP on every publish, and an automation
token that bypasses 2FA has not been provisioned. The GitHub Release flow
remains fully automated; only the npm wrapper publish requires a developer
on a workstation with `npm login` and an authenticator app.
### Steps
1. Set the npm package version in [npm/deepseek-tui/package.json](../npm/deepseek-tui/package.json) to match the workspace `Cargo.toml`. CI's version-drift guard will catch mismatches before tag.
2. Set `deepseekBinaryVersion` to the GitHub release tag that should supply binaries.
3. Push the version bump to `main`. `auto-tag.yml` creates the matching `vX.Y.Z` tag, and `release.yml` builds the binary matrix and drafts the GitHub Release.
4. **Wait for the GitHub Release to finalize** with all eight signed binaries plus `deepseek-artifacts-sha256.txt`. The npm `prepublishOnly` hook (`scripts/verify-release-assets.js`) requires every asset to be present.
5. From a developer machine, publish the npm wrapper manually:
```bash
cd npm/deepseek-tui
npm publish --access public
# (you will be prompted for the npm OTP from your authenticator)
```
### Why not automated?
- `release.yml`'s old `publish-npm` job used `secrets.NPM_TOKEN`, but npm's 2FA-by-default policy means a publish token must be either an automation token with "Bypass 2FA for token authentication" enabled OR an account-level 2FA-disabled state. We don't have either configured.
- The `publish-npm.yml` workflow remains as inert plumbing for a future move to npm Trusted Publishing (OIDC). It only fires on `workflow_dispatch` and only works once Trusted Publishing is configured for *that* workflow filename on the npm side.
### If you fix the token later
To re-enable automated publish: provision an npm automation token with "Bypass 2FA for token authentication" enabled, store it as repo secret `NPM_TOKEN`, and revert this section's "manual" framing along with re-adding the `publish-npm` job in `release.yml`.
## Recovery and Rollback
- Crates publish partially:
- rerun `./scripts/release/publish-crates.sh publish`
- already-published crate versions will be skipped
- GitHub assets missing or checksum manifest incomplete:
- fix `.github/workflows/release.yml`
- retag or upload corrected assets before `npm publish`
- npm packaging-only problem:
- bump only the npm package version
- keep `deepseekBinaryVersion` on the last known-good Rust release
- repack and republish the wrapper
- A bad npm publish cannot be overwritten:
- publish a new npm version with corrected metadata or install logic