# aaden-cli 私有通道运维手册（POS-46 第 2 期）

## 发版
推 `x.y.z` tag → `publish.yml`：npm 发 latest，同一个 tgz 用 KMS 签名后传到 `s3://aaden-cli-releases/releases/<版本>/`，
`stable/manifest.json` 的 `current` 换成新版（旧 current 挪进 `previous`）。默认先灰度，满 `promoteAfterHours`（24）小时云端当全量。

## 立即全量
Actions → 「私有通道放量 / 回滚」→ Use workflow from 选一个 x.y.z tag → action = promote。

## 回滚
清单里的 `rollback`（同一个 workflow，action = rollback）只会把 `current` 换回 `previous`，**拦住的只是还没升上去的设备**。
设备端 self-update 默认拒绝装比本机低的版本，所以已经装了新版的设备不会自己退回去。要让它们回去，只有三种办法：

1. **下发 `CLI_BACK_TO_NPM`**（ERP 设备命令，超管）：设备执行 `aaden-cli self-update --back-to-npm`，链接指回 npm 装的那份，
   crontab 恢复成切换前的备份，通道标记写 `npm`。npm 那份不在会用 `npm i -g --force aaden-cli` 重装（最多约 14 分钟）。
2. **到设备上手动** `sudo aaden-cli self-update --allow-downgrade`：按清单（回滚后的 current）装回低版本，仍走签名校验。
   设备已经被看门狗切回过 npm 时要再加 `--force`。
3. **发一个更高的修复版**（推新的 x.y.z tag）：设备照常升级，不需要降级。

试点期间优先用 1（最快、和 npm 时代行为一致），多台同时出问题用 3。

## 看门狗
切到私有通道时 self-update 会装 `/usr/local/sbin/aaden-cli-watchdog` 和 `/etc/cron.d/aaden-cli-watchdog`（root，每 10 分钟一轮）。
链接指向 `/opt/aaden-cli` 时，下面任一条成立就触发：
- 连续 2 轮 `aaden-cli --version` 跑不出版本号（每轮失败隔 30 秒重试一次才算失败）；
- do-log 连续 12 轮（约 2 小时）没跑完过：看 `/var/tmp/aaden-cli-do-log.<uid>.ok` 的修改时间有没有变，轮数记在
  `/run/aaden-cli-watchdog.state`（开机清空 = 开机后 2 小时宽限）。不比墙钟，时钟跳变不会误判；断网、门店 PHP 挂了 do-log 照样写标记，不算。

触发后，如果 npm 那份能跑，就把链接指回它，再用 npm 那份跑 `self-update --back-to-npm` 收尾（和下发 CLI_BACK_TO_NPM 同一段代码：
恢复 crontab、通道标记写 `npm`），原因写进 `/etc/aaden/config/cli-watchdog-fallback`；npm 那份太老没有这个命令时只把标记写成 `npm`，
crontab 要人工看。npm 那份也不能跑就只记日志。日志：`/var/log/aaden-cli-watchdog.log`。

被看门狗（或 CLI_BACK_TO_NPM）切回 npm 的设备，通道标记是 `npm`：之后 self-update 不加 `--force` 不会再切回私有通道；
回滚办法 2（手动 `--allow-downgrade`）在这种设备上也要同时加 `--force`。

## 核对一台设备
```bash
readlink /usr/local/bin/aaden-cli /opt/aaden-cli/current
cat /etc/aaden/config/cli-channel
sudo crontab -l | grep -n 'aaden-cli'
cat /etc/cron.d/aaden-cli-watchdog; tail /var/log/aaden-cli-watchdog.log
ls -l --time-style=+%F_%T /var/tmp/aaden-cli-do-log.*.ok; cat /run/aaden-cli-watchdog.state
```
