# 一键发布

仓库提供一个手动 GitHub Actions 工作流，一次发布四个交付面：

1. `u-space` npm 包
2. `u-space-mcp` npm 包
3. VitePress 文档
4. `/examples/` 在线示例

npm 发布使用 Trusted Publishing/OIDC，不保存 `NPM_TOKEN`，日常发布不再要求输入 OTP。docs 和 examples 使用同一个 Vercel production deployment；`scripts/build-vercel-docs.mjs` 会在文档构建完成后复制 `examples/`，将发布中的 `u-space` 版本写入部署产物的 import map，并用独立 Vite 构建将 Offscreen 示例转换为浏览器可直接执行的主线程 JavaScript、module Worker 和 WASM 资源。

## 一次性配置

### 1. 配置两个 npm Trusted Publisher

分别打开 npmjs.com 上 `u-space` 和 `u-space-mcp` 的 package settings，在 **Trusted Publisher** 中添加相同的 GitHub Actions 配置：

| 字段 | 值 |
| :--- | :--- |
| Organization or user | `spatial-claw` |
| Repository | `u-space` |
| Workflow filename | `release.yml` |
| Environment | 留空 |
| Allowed actions | `npm publish` |

两个包都必须单独配置一次。工作流运行在 GitHub-hosted runner，授予 `id-token: write`，使用 Node.js 24 和满足 Trusted Publishing 要求的 npm 11；package metadata 中的 repository URL 已统一为 `https://github.com/spatial-claw/u-space`。

配置成功后不需要创建 `NPM_TOKEN`。npm 官方也建议在验证 Trusted Publisher 可用后，将传统 publishing access 调整为 “Require two-factor authentication and disallow tokens”。

### 2. 配置 Vercel Token

仓库已经提交 `.vercel/project.json`，因此 GitHub Actions 只需要一个 repository secret：

```bash
gh secret set VERCEL_TOKEN
```

输入有权部署 `u-space` Vercel 项目的 token。工作流会依次运行 `vercel pull`、`vercel build --prod` 和 `vercel deploy --prebuilt --prod`。

工作流已经显式声明 `contents: write` 和 `id-token: write`。因此组织或仓库可以继续保持默认的只读 `GITHUB_TOKEN` 权限；GitHub 会按该 workflow 的最小权限声明授权。工作流需要把版本提交和 release tags 推回 `main`，如果 `main` 启用了 branch protection，还需要允许该 release workflow 写入，或为 `github-actions[bot]` 配置对应 bypass。

## 发布

默认递增两个 npm 包的 patch 版本，并等待 GitHub Actions 完成：

```bash
pnpm release:all
```

也可以显式选择版本级别：

```bash
pnpm release:all patch
pnpm release:all minor
pnpm release:all major
```

不想在本地等待时使用：

```bash
pnpm release:all patch --no-wait
```

也可以打开 GitHub 仓库的 **Actions → Release all → Run workflow**，选择 `patch`、`minor` 或 `major` 后运行。

## 发布顺序

工作流按以下顺序执行：

1. 递增 `u-space` 和 `u-space-mcp` 版本，同步 examples/docs 中的当前版本引用；将更新日志的“未发布”内容归档到新的 `X.Y.Z` 版本标题，并创建新的空“未发布”区。
2. 执行完整测试、库构建、MCP 文档索引构建和 VitePress 构建。
3. 将版本元数据提交并推送到 `main`。
4. 通过 npm OIDC 发布两个包；精确版本已经存在时自动跳过。
5. 构建并部署 docs 和 examples 到 Vercel production；Offscreen TypeScript 入口会通过 `examples/offscreen/vite.config.ts` 单独打包，不会以原始 `.ts` 作为线上运行入口。
6. 推送 `vX.Y.Z` 和 `u-space-mcp-vX.Y.Z` 标签。

`release-all` concurrency group 会阻止两次发布并发运行。

## 失败重试

版本提交已经推送，但 npm 或 Vercel 后续步骤失败时，不要再次选择 `patch`，否则会再递增一次版本。使用 `current` 重试当前提交版本：

```bash
pnpm release:all current
```

工作流会跳过 registry 中已经存在的精确版本，只重试尚未完成的 npm 包、Vercel 部署和标签。

`current` 不会再次修改更新日志，因此重试不会生成重复的版本标题。

本地旧命令 `pnpm release`、`pnpm publish:mcp` 和 `pnpm docs:deploy` 继续保留，但它们不使用 GitHub OIDC，可能请求 npm OTP 或本机 Vercel 登录。

## 参考

- [npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers/)
- [GitHub Actions OIDC](https://docs.github.com/en/actions/reference/security/oidc)
- [Vercel GitHub Actions deployment](https://vercel.com/docs/git/vercel-for-github)
