# 一条命令发版（`npm run push`）操作手册

> **一句话**：改完代码，在项目根目录执行 `npm run push`，
> 它会一路走完「打包 → 切 8 个分片 → 更新下载站 → 发布上线」，
> 你只需要等它打完最后的地址。
>
> **不需要任何云存储凭据。** 升级包和页面一起发，一个地方就够了。

---

## 一、发版到底做了什么

```
npm run push
   │
   ├─ [1] 打包        比对文件差异，生成增量升级包（zip），算出 sha256
   ├─ [2] 更新下载站   把包切成 8 个分片写进下载站目录，改写页面版本/SHA256/变更说明
   └─ [3] 发布上线     用同一个发布脚本把整个目录推上去
```

**包跟着下载站一起发布** —— 所以站点后台的「升级源地址」直接填下载站地址就行，
不用再去开云存储、传文件、配 CORS。

---

## 二、一次性准备

```bash
cd <你的项目目录>
npm install
```

就这一步。没有 `.env`、没有 AccessKey、没有 bucket。

---

## 三、日常发版：三步

```bash
npm run test:all     # ① 回归，要求 0 失败
npm run preview      # ② 可选：先看看下载页会被改成什么样（不联网不发布）
npm run push         # ③ 正式发版
```

### 第 ② 步能看到什么

```
【顶部徽章】   应用 1.1.26 / 升级包 20261013-v42 / 安装包 20261013-v9
【升级包按钮】 下载 avc-upgrade-20261013-v42.zip（31 KB）
【版本变更标题】版本变更（1.1.6 → 1.1.26）
【版本说明插入】✓ 已插入，摘要：发版不再需要 OSS 凭据（重要）
```

任何一项是 ✗ 就先别发 —— 多半是下载页被手工改过、结构对不上。

### 第 ③ 步的正常输出

```
[1] 生成增量升级包
  ✓ 产出 avc-upgrade-20261013-v42.zip
    应用版本 1.1.26 / 包版本 20261013-v42 / 31 KB / 1 个文件

[2] 更新下载站（/workspace/avc-download）
  ✓ latest.json 已更新
  ✓ 8 个分片已生成（拼装校验通过）
  ✓ index.html 已更新：badge-应用版本、badge-升级包版本、…
  ✓ index.html 已插入本版本说明

[3] 发布下载站到线上
  ✓ 已发布上线：https://……
  ✓ 线上校验通过
```

---

## 四、常用参数

| 参数 | 作用 |
|---|---|
| `--full` | 出全量包（默认增量，约几十 KB） |
| `--dry-run` | 只打包，不切分片、不发布 |
| `--site-only` | 不重新打包，用 `release/` 里最新的包重推下载站 |
| `--site-only --install <zip>` | 重推时顺便更新安装包 |
| `--no-install` | 本次**不**更新全新安装包（只发升级包） |
| `--install <zip>` | 用指定的安装包文件（不再自动打一份） |
| `--dir <路径>` | 指定下载站目录（默认自动探测） |
| `--keep` | 保留临时产物目录，便于排查 |

### 关于「全新安装包」会自动跟随版本

下载站上有两个包：**升级包**（`avc-upgrade-*`，已有站点升级用）和
**全新安装包**（`avc-install-*`，新站点从零部署用）。

正常发版（`npm run push`）现在会**自动重打一份全新安装包**并同步到下载页，
让「全新安装」和「升级」始终是同一个版本 —— 新部署的用户装完即是最新版，
不必再升级一次。

> 以前默认只管升级包，安装包会长期停在老版本；要更新得手工加 `--install`。
> 现在默认跟随，省事也不容易忘。不想更新就加 `--no-install`。

两个包各自独立编号（`data/install-version.json` 与 `data/upgrade-version.json`），
同一天里序号通常不同，属正常现象。

---

## 五、两个容易踩的坑

### 坑 1：CHANGELOG 里没有本次版本号那一节

打包脚本会**先把应用版本递增**（1.1.25 → 1.1.26），再去 CHANGELOG 里找
`## 1.1.26` 这一节。**找不到就跳过版本说明**，你会看到：

```
⚠ index.html 版本说明未插入（定位失败，已跳过，不影响发版）
```

结果：页面徽章到了新版本，但「版本变更」区没有新条目。

**办法**：发版前先在 `CHANGELOG.md` 里按当前版本号写好一节，再跑 `npm run push`。

### 坑 2：站点「检查更新」拉不到新包

后台「系统升级」页会显示**升级源地址**。现在应该是**下载站地址**：

```
https://a58375f42ae0370ad.app.workbuddy.host/
```

如果它还指着老的 `.../avc-releases`（阿里云 OSS 目录），那是早期方案的遗留，
检查更新会失败。改法：在「系统设置 → 升级源地址」改成下载站地址，保存。

---

## 六、下载页上的包怎么下的

页面上的下载按钮不是直接下大 zip，而是**把 8 个分片依次拉下来、在浏览器里拼回完整包**，
拼完再校验 sha256 —— 对不上就报错，不会让你装到半个包。

分片名固定是 `part_upgrade_00` ~ `part_upgrade_07`（安装包同理，`part_install_*`）。
**片数不能变**，页面里写死了 8 项；发版脚本也永远切 8 片。
