Skip to content
Back to skills

Happy Next Release

ASecurity

Cuts a happy-next release — audits changes, recommends which of CLI, GitHub Release, Docker, iOS App Store and an app OTA update to publish, confirms one release plan, then runs it end to end. Command-only — invoked via /happy-next-release.

  • 61 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added October 25, 2026
developmentgobashnodedockergitapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 25, 2026

npx -y skills add hitosea/happy-next --skill happy-next-release --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Happy Next Release?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Happy Next Release
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/hitosea-happy-next-release/badge)](https://www.skillsdirectory.com/skills/hitosea-happy-next-release)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: happy-next-release
description: Cuts a happy-next release — audits changes, recommends which of CLI, GitHub Release, Docker, iOS App Store and an app OTA update to publish, confirms one release plan, then runs it end to end. Command-only — invoked via /happy-next-release.
disable-model-invocation: true
---

# Happy Next 发布流程

## 总则

流程分四段:**自动检查 → 确认发布计划 → 执行 → 失败处理**。

- 根据审计结果推荐发布线组合,写进发布计划。
- 用户在调用时用自然语言说明了要发什么(如"只发 Docker"、"这次不发 CLI"、"把 v2.15.1 提交到 App Store"),按用户的意思确定发布线,其余流程相同;意思不明确时在发布计划里写出你的理解。
- **只确认一次**:发布计划。用户确认(或修改后确认)即授权执行计划内的全部操作,包括推送 main、合并 PR、npm 发布、创建 tag、GitHub Release、Docker、iOS 提审和 OTA 发布。确认后直接执行,直到完成或遇到停止条件。
- 计划外的操作(计划外的改动、覆盖、重建、删除)需单独确认。

五条发布线:

| 线 | 产物 | 版本 | workflow |
|---|---|---|---|
| CLI | npm `happy-next-cli` | `packages/happy-cli/package.json` 独立版本,由 workflow 提交 | `cli-publish.yml` |
| Release | Android APK/AAB、iOS IPA、macOS Universal、Windows x64/ARM64、`latest.json` | `vX.Y.Z` tag | `release.yml` |
| Docker | `kuaifan/happy-{server,app,voice,docs,web}` | 同一 `vX.Y.Z` tag | `docker-publish.yml` |
| iOS | App Store Connect 上传 | 同一 `vX.Y.Z` tag,提交 Release 里那份 IPA | `ios-submit.yml` |
| OTA | App 的 JS 更新,发给已安装、fingerprint 相同的包 | 无版本号,按 runtime(原生 fingerprint)匹配 | 无,本地 `yarn ota publish`(见 happy-ota 技能(读 `.claude/skills/happy-ota/SKILL.md`)) |

- Release、Docker、iOS 同一次发布共用同一个不可变 tag 和 commit。
- iOS 只提交 Release 已发布的 IPA,必须在 Release 验证通过之后。
- 推送 tag 不会发布任何东西;每条线都要显式触发 workflow。
- OTA 不需要 tag,也不经过商店审核,发布后用户的 App 会自动下载,所以 App 的改动能比 Release / iOS 早几天到达用户手里。

## 每条线的基准

每条线以自己上一次成功发布的版本为基准审计改动:

```bash
# CLI:最近一个 CLI 版本提交
BASE_CLI=$(git log --format=%h --grep='^release: happy-next-cli' -1)

# Release:最近一个正式 GitHub Release 的 tag
BASE_APP=$(gh release list --limit 50 --exclude-drafts --exclude-pre-releases \
  --json tagName -q '.[].tagName' | grep '^v[0-9]' | sort -V | tail -1)

# Docker:最近一次成功的 Docker workflow(run-name 为 "Docker vX.Y.Z")
BASE_DOCKER=$(gh run list --workflow=docker-publish.yml --status success --limit 50 \
  --json displayTitle -q '.[].displayTitle' | sed -n 's/^Docker //p' | sort -V | tail -1)

# iOS:最近一次成功的提审(run-name 为 "iOS App Store vX.Y.Z")
BASE_IOS=$(gh run list --workflow=ios-submit.yml --status success --limit 50 \
  --json displayTitle -q '.[].displayTitle' | sed -n 's/^iOS App Store //p' | sort -V | tail -1)

# 全局最高的 v tag
TOP_TAG=$(git tag --sort=-version:refname | grep '^v[0-9]' | head -1)
```

- 任一基准取不到时**停止**并报告。
- 新 tag 基于 `TOP_TAG` 递增(App 版本号因此可能跳号)。
- 在计划里列出每条线的基准。

---

# 一、自动检查与准备(不询问用户)

## 1. git 前置检查

```bash
git status --short --branch
git branch --show-current
git fetch origin --tags
```

- 工作区有未提交改动:**停止**,报告改动,让用户处理。不得 stash、覆盖或丢弃。
- 不在 `main`:**停止**。
- 本地落后远端:`git pull --ff-only origin main`;无法 fast-forward 则**停止**。
- 本地领先远端:列出未推送提交(`git log origin/main..HEAD --oneline`),写进计划,执行时普通推送。

## 2. 审计改动,推荐发布线

```bash
git log "${BASE_CLI}..HEAD" --oneline --no-merges -- packages/happy-cli packages/happy-wire
git log "${BASE_APP}..HEAD" --oneline --no-merges -- packages/happy-app packages/happy-wire
git log "${BASE_DOCKER}..HEAD" --oneline --no-merges -- \
  packages/happy-server packages/happy-app packages/happy-wire \
  packages/happy-voice packages/happy-docs packages/happy-web \
  Dockerfile.server Dockerfile.webapp docker-compose.yml entrypoint.sh
```

用 `--name-only` 看具体文件后按规则推荐:

| 改动 | 推荐 |
|---|---|
| `happy-cli` 有实际改动 | CLI |
| `happy-app` 有用户可感知改动 | Release + iOS + Docker(`happy-app` 镜像是 App 的 Web 版) |
| 只有 `happy-server` / `happy-voice` / `happy-docs` / `happy-web` / `Dockerfile*` / `docker-compose.yml` / `entrypoint.sh` | 仅 Docker |
| `happy-wire` 实际改动(不含 `modelCatalog.json`) | 按使用方:CLI 用到则含 CLI,server/app 用到则含 Docker/Release |
| `happy-app` 有用户可感知改动,且当前 runtime 等于最近一次 Release 包的 fingerprint | 另加 OTA(见下文「OTA 的判断」) |
| 只有 `modelCatalog.json` | 不发布(合并到 main 即远程生效) |
| 都没有 | 建议不发布,**停止** |

只改测试、注释、开发脚本、内部文档不算用户可感知改动。

**OTA 的判断**(`happy-app` 有用户可感知改动时):按 happy-ota 技能「一、检查」的第 2、3 步,算出当前代码在 EAS production 环境下 iOS 和 Android 的 runtime,再和 `BASE_APP` 那个 Release 的 IPA / APK 里嵌入的 fingerprint 对比:

- 对得上的平台推荐 OTA:用户不用等新包,几分钟内就能收到。同时发 Release 也不冲突,新包本身就带着这些 JS。
- 对不上(原生部分变了),或者 Release 包里没有嵌入 fingerprint(打在自建 OTA 之前):不推荐 OTA,在计划里写明原因。

## 3. Codex CLI 版本

```bash
npm view @openai/codex version
node -p "require('./packages/happy-wire/src/modelCatalog.json').codexCli.version"
```

有新稳定版时写进计划,默认**不升级**,并说明:合并后会远程下发给所有 CLI,新启动的 Codex 会话都使用新版本(已有会话按其记录的版本恢复),需确认兼容性。`codexCli` 只在计划确认升级时修改。

## 4. 模型目录

模型和定价在 `packages/happy-wire/src/modelCatalog.json`,合并到 `main` 后由服务端远程下发给 App 和 CLI。

1. 列出改动该文件的未合并 PR(含每日自动同步的 PR),读其说明,写进计划并建议是否合并:

   ```bash
   gh pr list --state open --json number,title,files \
     --jq '.[] | select(any(.files[]; .path == "packages/happy-wire/src/modelCatalog.json")) | "#\(.number) \(.title)"'
   ```

2. 从各厂商官方渠道获取最新模型信息,与目录(含上述 PR 的改动)对比,例如:
   - Anthropic:Claude 模型概览页和定价页、发布公告
   - OpenAI:模型文档页和定价页;Codex 可用模型以 Codex CLI 发布说明为准
   - Google:Gemini API 模型页和定价页、Gemini CLI 发布说明
3. 按目录现有字段补齐新模型(标签、描述、价格、cache 读写价、fast 价格、effort、上下文窗口),并按目录惯例调整被取代的旧模型。
4. 每项新增、修改、下线都附官方来源链接;来源不明确或互相冲突的不改,在计划里列为"待定"。

此阶段只出改动草稿,不改文件。

## 5. Secrets

只检查名称,不读取值:

```bash
gh secret list --app actions | cut -f1
```

| 线 | 必需 |
|---|---|
| CLI | `NPM_TOKEN` |
| Release | `EXPO_TOKEN`、`TAURI_SIGNING_PRIVATE_KEY`、`TAURI_SIGNING_PRIVATE_KEY_PASSWORD`、`APPLE_CERTIFICATE_BASE64`、`APPLE_CERTIFICATE_PASSWORD`、`APPLE_KEYCHAIN_PASSWORD`、`APPLE_SIGNING_IDENTITY` |
| Docker | `DOCKERHUB_USERNAME`、`DOCKERHUB_TOKEN` |
| iOS | `ASC_API_KEY_ID`、`ASC_API_KEY_P8_BASE64`、`ASC_ISSUER_ID` |

缺任何一个都**停止**。不得让用户在聊天中粘贴私钥、证书或密码。

## 6. 版本号

**CLI**(含 CLI 时):

```bash
node -e "
const v = require('./packages/happy-cli/package.json').version.split('.').map(Number);
console.log('当前: ' + v.join('.'));
console.log('patch: ' + v[0] + '.' + v[1] + '.' + (v[2] + 1));
console.log('minor: ' + v[0] + '.' + (v[1] + 1) + '.0');
console.log('major: ' + (v[0] + 1) + '.0.0');
"
```

**tag**(含 Release / Docker 时):基于 `TOP_TAG` 递增。

规则:`fix/chore/docs` → patch,`feat` → minor,`BREAKING CHANGE` 或 `!:` → major,按对应线审计范围内的提交判断。

确认 tag 和 Release 都不存在(已用过的版本改用更高版本):

```bash
git ls-remote --tags origin "refs/tags/{tag}"
gh release view "{tag}" 2>/dev/null || true
```

只发 iOS 时不新建 tag,目标 tag 必须已有 Release 且含 IPA。

## 7. changelog 和产品文档草稿(含 Release 时)

涉及文件:

1. `packages/happy-app/CHANGELOG.md`
2. `packages/happy-app/sources/changelog/changelog.json`(由脚本生成)
3. `README.md`
4. `README.zh-CN.md`
5. `docs/changes-from-happy.md`
6. `docs/changes-from-happy.zh-CN.md`

规则:

- 审计范围是 `BASE_APP..HEAD`。
- 日志版本:patch 版本合并进当前最高日志版本(日期改为今天,摘要改为新版本号,写明 "also includes … introduced in vX.Y.Z",参照 Version 24);minor/major 新建下一个日志版本。
- `CHANGELOG.md` 按版本记录;其余四个 md 是完整功能总览,不加版本标题,新功能并入相应分组,删去已移除的功能。
- 中英文结构与含义一致;不写只对开发者有意义的实现细节。
- 草稿只放在计划里,此阶段不写文件。

只发 Docker 不写 changelog。

---

# 二、确认发布计划

一次性展示,每项附依据:

- 发布线组合及理由,每条线的基准
- OTA(含 OTA 时):平台、runtime、能收到的包、更新说明 `--message`
- 推送本地未推送的提交(如有)
- 合并哪些 PR
- 模型目录改动(新增 / 修改 / 下线,附来源)和"待定"项
- Codex 是否升级(默认否)
- CLI 版本、tag
- 日志版本,changelog 和总览文档草稿
- Docker `publish_latest`:目标是最高正式版本时 `true`,重建旧版本或补历史镜像时 `false`
- 将执行的 workflow 命令

告知用户:确认即授权执行计划内全部外部发布操作,包括 iOS 提审。用户修改涉及重新审计时,重新展示计划。

---

# 三、执行

每步结束检查结果;遇到停止条件立即停下汇报,不继续后续步骤。

## 1. 同步代码

```bash
git push origin main            # 有未推送提交时
gh pr merge {PR} --squash       # 计划内的 PR
git pull --ff-only origin main
```

## 2. 模型目录和 Codex(有改动时)

按计划修改 `modelCatalog.json`,然后:

```bash
cd packages/happy-wire && yarn build && yarn test
cd ../happy-cli && yarn typecheck
```

通过后只提交该文件并推送(如 `chore(models): …`)。失败则**停止**。

## 3. changelog 和文档(含 Release 时)

按计划写入文件,然后:

```bash
cd packages/happy-app
npx tsx sources/scripts/parseChangelog.ts
yarn typecheck
yarn test --run
```

通过后只提交这六个文件:

```bash
git add \
  packages/happy-app/CHANGELOG.md \
  packages/happy-app/sources/changelog/changelog.json \
  README.md README.zh-CN.md \
  docs/changes-from-happy.md \
  docs/changes-from-happy.zh-CN.md
git commit -m "docs: changelog for {tag}"
git push origin main
```

## 4. CLI(含 CLI 时)

```bash
gh workflow run cli-publish.yml -f version={CLI版本} -f dry-run=false
```

从命令输出的 run URL 取 run ID,后台监听。成功后:

```bash
git pull --ff-only origin main
node -p "require('./packages/happy-cli/package.json').version"
```

CLI 在创建 tag 之前完成,使 tag 包含 CLI 版本提交。

## 5. 创建 tag(含 Release / Docker 时)

```bash
git tag {tag}
git push origin {tag}
```

tag 指向已推送的最新 `main` commit。

## 6. 触发 Release 和 Docker(并行)

```bash
gh workflow run release.yml \
  -f release_tag={tag} \
  -f confirmation=PUBLISH-RELEASE

gh workflow run docker-publish.yml \
  -f release_tag={tag} \
  -f publish_latest={true|false} \
  -f confirmation=PUBLISH-DOCKER
```

后台监听每个 run。结束后用 `gh run view {id} --json conclusion,jobs` 核对结论和每个任务,以此判断成败。

## 7. 验证 Docker

```bash
for img in happy-server happy-app happy-voice happy-docs happy-web; do
  curl -s "https://hub.docker.com/v2/repositories/kuaifan/$img/tags?page_size=4&ordering=last_updated"
done
```

- 存在版本标签(镜像标签不带 `v`,如 `2.15.1`);
- `publish_latest=true` 时 `latest` 与版本标签 digest 相同;
- 架构为 `amd64` 和 `arm64`。

## 8. 验证 Release

```bash
gh release view {tag} --json tagName,assets,url
```

除 `latest.json` 外,所有附件以 `happy-next-{tag}-` 开头:

```text
happy-next-vX.Y.Z-android.apk
happy-next-vX.Y.Z-android.aab
happy-next-vX.Y.Z-ios.ipa
happy-next-vX.Y.Z-macos-universal.dmg
happy-next-vX.Y.Z-macos-universal.zip
happy-next-vX.Y.Z-macos-universal.app.tar.gz
happy-next-vX.Y.Z-macos-universal.app.tar.gz.sig
happy-next-vX.Y.Z-windows-x64-setup.exe
happy-next-vX.Y.Z-windows-x64-setup.exe.sig
happy-next-vX.Y.Z-windows-x64.msi
happy-next-vX.Y.Z-windows-x64.msi.sig
happy-next-vX.Y.Z-windows-arm64-setup.exe
happy-next-vX.Y.Z-windows-arm64-setup.exe.sig
happy-next-vX.Y.Z-windows-arm64.msi
happy-next-vX.Y.Z-windows-arm64.msi.sig
happy-next-vX.Y.Z-desktop-metadata.json
happy-next-vX.Y.Z-sha256sums.txt
latest.json
```

下载 `latest.json`(放在新建的空目录中)并检查:

- version 等于 tag;
- 四个平台键齐全;
- URL 中没有空格或 `%20`;
- 每个 URL 返回 HTTP 200;
- 签名非空。

## 9. iOS 提审(含 iOS 时)

Release 验证通过且含 `happy-next-{tag}-ios.ipa` 后触发:

```bash
gh workflow run ios-submit.yml \
  -f release_tag={tag} \
  -f confirmation=SUBMIT-IOS
```

workflow 下载 Release 中的 IPA,用 App Store Connect API Key 通过 `xcrun altool` 上传。成功只代表上传完成;构建处理、送审和审核状态在 App Store Connect 中另行处理。

## 10. OTA(含 OTA 时)

代码同步完成后(第 1–3 步,main 已推送、工作区干净),按 happy-ota 技能的「三、发布」执行:取凭证、`yarn ota publish`、核对服务器、清理凭证。发布计划已经确认过,这里不再单独确认。输出的 runtime 必须等于计划里的值,不一致就**停止**。OTA 不依赖 Release,可以和第 4–9 步并行,但必须在第 3 步之后,保证 changelog 提交也包含在更新里。

## 11. 汇总报告

逐条列出 npm、GitHub Release、Docker Hub、App Store Connect、OTA(更新 id 和能收到的包)的结果和链接,以及重试情况。没有真机测试的平台标记 **未验证**。

---

# 四、workflow 失败处理

先看失败日志判断原因:

```bash
gh run view {id} --log-failed | tail -200
```

- **网络问题**(拉依赖或资源包失败、超时、`ETIMEDOUT`、`ECONNRESET`、`Could not resolve host`、`Read timed out`、HTTP 5xx、registry/CDN 不可达等):`gh run rerun {id} --failed`,同一个 run **最多重试 3 次**;仍失败则**停止**。
- **偶发超时**(个别测试 `Test timed out`,同一测试本地通过,且其他平台任务跑同一套测试也通过):`gh run rerun {id} --failed`,同一个 run **最多重试 3 次**;仍失败则**停止**,并在汇总里建议修复该测试。
- **其他原因**(编译、类型、测试、签名、证书、校验、权限、配额):**停止**,报告原因和修复建议。

重跑边界:

| workflow | 可重跑 | 不可重跑(停止报告) |
|---|---|---|
| `release.yml` | 各平台 build 任务失败 | `create-release` 失败 |
| `docker-publish.yml` | 任意任务失败 | — |
| `cli-publish.yml` | 日志确认尚未执行 `npm publish` | 已执行 `npm publish` |
| `ios-submit.yml` | 日志确认 IPA 尚未上传成功 | 已上传或状态不明 |

---

# 停止条件

工作区不干净、分支分叉、基准取不到、无可发布改动、缺 Secret、tag 或 Release 已存在、本地校验失败、workflow 失败且不可重试或重试用尽、Release 或 Docker 验证不通过、缺 IPA、OTA 的 runtime 和计划不一致。

停止时说明已完成和未完成的步骤,以及恢复时从哪一步继续。修复后改用更高版本号。

---

# 首次完整桌面升级验收

首次正式验证或 updater 发生变化时,发布两个真实的新版本做升级测试:

1. 发布较低版本 A 的完整 Release。
2. 从 GitHub 下载并安装 A。
3. 确认客户端显示版本 A。
4. 发布较高版本 B 的完整 Release。
5. 等待后台下载,检查未登录和已登录布局中的更新按钮。
6. 点击更新并确认重启到 B。
7. 检查登录状态、本地数据、通知、图片、麦克风和摄像头。
8. Apple Silicon、Intel、Windows x64、Windows ARM64 分别记录;没有真机就标记 **未验证**。

失败时用新的更高版本修复。

# 禁止事项

- 不提交或输出证书、Token、密码、私钥。
- 不使用 `--clobber` 覆盖 Release 附件;不向历史 Release 追加文件。
- 不移动、删除或强推正式 tag;不重用已用过的版本号。
- 不强推 `main`,不 stash 或丢弃用户改动。
- 不把 CI 成功等同于真机验证成功。
- 不在 iOS 线重新构建 IPA;Release 未验证通过不提交 iOS。
- 不手动修改 `app.config.js` 的默认版本。
- 不手动修改 CLI package version。
- 不执行发布计划以外的外部操作。

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.