# 远程更新第一阶段

当前阶段采用“手动确认更新”：

1. 客户端在商用工作台检查远程更新清单。
2. 发现新版本后，客户点击“下载更新包”。
3. 客户端下载 zip 到本机用户数据目录，并强制校验 `sha256`。
4. 如配置了更新公钥，会验证 Ed25519 签名。
5. 校验通过后，界面显示本地 zip 路径和替换步骤。
6. 客户退出程序，手动解压并替换程序目录。

用户数据不会放在程序目录里。升级只替换程序文件：

- macOS 数据目录：`~/Library/Application Support/Facebook AI Operator`
- Windows 数据目录：`%LOCALAPPDATA%\Facebook AI Operator`

## 客户端配置

在客户机数据目录的 `.env.local` 中配置：

```bash
FACEBOOK_AUTO_UPDATE_MANIFEST_URL=https://updates.example.com/facebook-ai-operator/stable.json
FACEBOOK_AUTO_UPDATE_CHANNEL=stable
FACEBOOK_AUTO_UPDATE_REQUIRE_SIGNATURE=true
FACEBOOK_AUTO_UPDATE_PUBLIC_KEY_PATH=license-keys/update-public.pem
```

如果不单独配置 `FACEBOOK_AUTO_UPDATE_MANIFEST_URL`，客户端会尝试从远程授权服务器派生：

```text
{remoteLicenseServer}/api/updates/facebook-ai-operator/stable.json
```

## 发布流程

1. 更新 `package.json` 的 `version`。
2. 第一次发布前生成更新签名密钥：

```bash
npm run update:keygen
```

生成后：

- `license-keys/update-private.pem` 只留在发布机器。
- `license-keys/update-public.pem` 会随客户端包一起发给客户。

3. 构建生产包：

```bash
npm run build
bash scripts/package-mac-client.sh
bash scripts/package-windows-client.sh
```

4. 生成更新清单。

如果走 `yun_web_update` / `stackforecom.com` 后端托管更新包，不要设置 `FACEBOOK_AUTO_UPDATE_BASE_URL`，让清单里保留相对文件名，后端会自动重写为授权下载接口：

```bash
FACEBOOK_AUTO_UPDATE_PRIVATE_KEY_PATH=license-keys/update-private.pem \
FACEBOOK_AUTO_RELEASE_NOTES="修复发布流程并优化商机采集。" \
npm run release:manifest
```

如果你使用独立静态文件服务器托管 zip，才设置：

```bash
FACEBOOK_AUTO_UPDATE_BASE_URL=https://updates.example.com/facebook-ai-operator \
npm run release:manifest
```

5. 本地联动到 `yun_web_update`：

```bash
npm run release:copy-yun
```

这会把更新文件复制到：

```text
/Users/momo/Project/yun_web_update/backend/uploads/updates/facebook-ai-operator
```

6. 上传或部署这些文件到 HTTPS 更新服务器：

```text
dist/FacebookAIOperator-<version>-client-mac.zip
dist/FacebookAIOperator-<version>-client-windows.zip
dist/updates/stable.json
```

如果 `yun_web_update` backend 已部署在 `https://stackforecom.com`，客户端会默认读取：

```text
https://stackforecom.com/api/updates/facebook-ai-operator/stable.json
```

更新包下载地址由远程 backend 重写为：

```text
https://stackforecom.com/api/updates/facebook-ai-operator/files/<zip 文件名>
```

## 清单格式

```json
{
  "appId": "facebook-ai-operator",
  "channel": "stable",
  "latestVersion": "0.2.1",
  "minSupportedVersion": "0.2.0",
  "publishedAt": "2026-06-05T00:00:00.000Z",
  "notes": "修复发布流程并优化商机采集。",
  "artifacts": {
    "darwin-arm64": {
      "url": "https://updates.example.com/facebook-ai-operator/FacebookAIOperator-0.2.1-client-mac.zip",
      "filename": "FacebookAIOperator-0.2.1-client-mac.zip",
      "sha256": "...",
      "signature": "...",
      "size": 12345678
    }
  }
}
```

## 安全建议

- 更新服务器必须使用 HTTPS。
- 商用环境建议设置 `FACEBOOK_AUTO_UPDATE_REQUIRE_SIGNATURE=true`。
- 更新私钥只放在发布机器，不能随客户端发给客户。
- 打包脚本会排除 `license-keys/update-private.pem`，但发版前仍建议检查压缩包内容确认没有私钥。
- 客户端只内置或配置更新公钥。
- 第一阶段不要静默覆盖运行中的程序，避免升级中断导致客户无法启动。
