@@ -1,135 +0,0 @@
---
name: deploy-publish-check
description: 当 NianCode 发布部署角色检查学习者软件项目的构建准备、Docker 部署、项目 zip 打包、根目录 works-publish.json、部署与上传页面交接、发布步骤、回滚计划、作品广场提交准备和部署报告时使用。
---
# 部署发布检查
使用这个 skill, 判断学习者项目是否已经准备好通过 Docker 发布。
## 给学生看的说话规则
必须使用 `youth-plain-language` 。讲 Docker、zip、上传接口时, 先说明它们在作品发布里分别做什么, 再给具体下一步。
## 工作流程
1. 确认发布目标,以及是否明确允许外部发布。
2. 检查代码、Demo、素材、宣传文案和构建命令。
3. 创建或维护 `Dockerfile` ,确保项目可以构建为 Docker 镜像。
4. 创建或维护 `docker-compose.yml` ,确保项目可以通过 Docker Compose 启动。
5. 检查 `niancode.yml` 使用 `runtime: compose` ,并声明公开服务和 `8080` 端口;同时确认公开服务进程监听容器内 `0.0.0.0:8080` 。
6. 在合适时运行 Docker Compose 配置检查、构建、启动或冒烟检查。
7. 发布获准时,把当前项目打成 `.zip` 包,并检查 zip 根目录包含 `niancode.yml` 、`docker-compose.yml` 和 compose 构建引用到的 Dockerfile。
8. 执行结构化机器检查: manifest、Compose services/public service/端口/build context、volume、禁止的运行时安装/构建、Dockerfile 构建阶段、Node/Python 锁文件、Vite `base: "./"` 、构建入口资源路径、浏览器存储降级、环境变量安全默认值、密钥/缓存/路径/大小/文件数量;游戏或画布项目额外检查根节点全屏和响应式画布布局。
9. 如果本机有 Docker, 运行 `docker compose config` 、`build --pull=false` 、`up -d` 、动态端口检查、HTTP smoke、日志检查和清理; 解压到全新目录后再重复一遍。如果本机没有 Docker, 逐项写 `status: BLOCKED` 、`execution: unavailable` 和原因,不要把未执行写成 PASS, 也不要要求用户去服务器接管。
10. 如果本机有浏览器,在不带 `allow-same-origin` 的 sandbox iframe 中执行浏览器 smoke; 任何白屏、未捕获 `SecurityError` 或启动失败都标为 BLOCKED。游戏或画布项目必须再执行桌面、移动和一次 resize/全屏变化 smoke, 检查主画布是否达到最大等比尺寸。浏览器不可用时同样写 `execution: unavailable` ,不能伪造画布证据。
11. 在项目根目录创建或更新 `works-publish.json` ,写清作品信息、版本信息和 zip 路径。
12. 在项目根目录创建 `works-deploy-check.json` ,绑定当前 zip 的 SHA-256, 并用 `PASS` 、`SKIPPED` 、`BLOCKED` 记录所有必填机器检查项;真实执行成功写 PASS, 环境能力缺失写 SKIPPED, 或在明确云端交接时写 BLOCKED + `execution: unavailable` ,确定性失败写 BLOCKED; 总状态按 `BLOCKED > SKIPPED > PASS` 聚合。
13. 把 `works-publish.json` 、`works-deploy-check.json` 和 zip 路径交给“部署与上传”页面读取;如果“构建产品”已登记 `works-cloud-deploy.json` ,交给 Main 云端部署协调器,它会在静态复核通过和登录态有效时自动调用 Works Square 远端构建接口;如果没有登录态,记录下一步。
14. 准备发布步骤和回滚步骤。
15. 产出部署报告。
## 发布保护规则
- 在发布目标和权限明确前,不要判定为可发布。
- 必须使用 Docker 部署。不能把本地开发服务器、直接打开 HTML 文件或手工命令当作最终部署方式。
- 使用最新构建、冒烟检查、预览或文件检查作为证据。
- 记录准确命令和观察结果。
- 检查密钥、私有路径、个人数据或未完成占位内容。
- 缺少 `Dockerfile` 或 `docker-compose.yml` 时,不能判定为可发布;应先创建或要求补齐这两个文件。
- 交给 Main 的云端部署协调器提交时,`.zip` 包必须在根目录包含 `niancode.yml` 和 `docker-compose.yml` ,并包含 compose 构建引用到的 `Dockerfile` 或其它 Dockerfile。
- zip 根目录必须直接包含 `niancode.yml` 和 `docker-compose.yml` ,不能是 `project/niancode.yml` 或其它外层目录套壳。
- 最小 `niancode.yml` 必须声明 `runtime: compose` 、`compose.file: docker-compose.yml` 、`compose.public_service` 和 `compose.public_port: 8080` 。
- `docker-compose.yml` 的公开服务必须发布容器端口 `8080` ,服务进程必须监听 `0.0.0.0:8080` ,并使用 `127.0.0.1::8080` 动态宿主机端口;固定宿主机端口和非 loopback 发布都不能判定为可发布。
- 不能只准备 `Dockerfile` 。作品广场 builder 和 runner 会按 Docker Compose 路径构建、启动和清理项目。
- 所有服务禁止 bind mount、Docker socket、`privileged` 、host network、host pid、host ipc 和固定宿主机端口;只允许顶层声明的命名卷保存运行数据。
- Compose `command` / `entrypoint` 不得安装依赖、同步依赖或构建项目;这些动作必须写在 Dockerfile 的 build 阶段。
- Compose 只能使用非敏感环境变量或 `${NAME:-safe-default}` 安全默认值;不得依赖宿主机未明确注入的业务变量,不得使用 `env_file: .env` 。真实 `.env*` 文件全部排除,`.env.example` 只允许无敏感示例。
- 如果项目是游戏或画布项目,`html` 、`body` 、`#app` /`#game-container` 必须占满 iframe, Phaser 使用 `FIT` /`CENTER_BOTH` 或等价缩放,其他引擎必须在 viewport/全屏变化后重新布局;桌面或移动任一实际 canvas 尺寸比最大等比预期小超过 5% 就是 BLOCKED。
- 实际成功才写 `PASS` ;仅因当前环境没有 Docker、Playwright、Puppeteer 或浏览器自动化而未执行时写 `SKIPPED` ,或在明确云端交接时写 `BLOCKED` + `execution: unavailable` ,保留原命令和缺失能力;命令执行失败或项目检查发现问题写 `BLOCKED` 。`SKIPPED` 允许上传但必须提示未验证风险;云端模式只能把明确 unavailable 的动态检查交给 Works Square 远端复核。
- 上传文件名必须以 `.zip` 结尾; zip 原始大小最大 `50MB` ,解压后总大小最大 `200MB` ,文件数量最大 `2000` 。
- 打包时默认排除 `.git/` 、`node_modules/` 、`.venv/` 、`venv/` 、`.next/cache/` 、`.pytest_cache/` 、真实 `.env` 、证书、私钥和无关本地构建产物。
- 缺少项目根目录 `works-publish.json` 、缺少必填字段或 `zip_file_path` 不是 `.zip` 时,不能判定为可发布。
- 缺少 zip 包路径或项目根目录 `works-publish.json` 时,不能判定为可交接;应先打包并写好交接文件。
- 缺少 `works-deploy-check.json` 、schema 不支持、zip SHA-256 不匹配、静态检查失败或任一确定性必填 check 为 `BLOCKED` ,不能判定为可交接;仅环境能力缺失的 `SKIPPED` 或明确 unavailable 可交接但必须提示风险并交给云端复核。
- Works Square 远端提交失败、缺少访问令牌或缺少登录态时,不要宣称发布完成;保留交接文件,记录 `waiting_for_login` /`failed` 和原因, Main 会在登录态恢复后继续。
- 发布部署角色负责准备 zip 包、`works-publish.json` 和 `works-deploy-check.json` ; “部署与上传”页面的“构建产品”负责明确授权一次云端提交, Main 负责正式提交, 不要要求用户手动填写字段、SSH 或服务器。
- 标记为可发布前,必须包含回滚或恢复步骤。
## 云端部署与交接规则
- “部署与上传”页面的“构建产品”按钮会登记一次 `works-cloud-deploy.json` 云端部署意图; 页面只展示状态, Main 负责正式提交。
- “远程上传”在本项目中特指 Works Square 后端 HTTP 上传接口,不是 SSH、SFTP、rsync 或自备服务器部署。
- Main 会通过受控边界先确保项目元数据存在,再调用上游接口:`POST /api/projects/{appId}/versions/upload` 。
- Agent 不接触 `accessToken` ,不能在 shell、聊天或报告中打印令牌。
- `works-cloud-deploy.json` 的 `submitted` 只表示远端已接受并返回 `version_id` ; `queued` 、`building` 、`reviewing` 都不等于已公开。
- 不要询问 SSH 主机、用户名、端口或目标路径。
- 如果没有云端部署意图,完成文件后说明需要从“部署与上传”页面点击“构建产品”授权一次提交;如果暂时没有登录态,保留交接文件并等待 Main 自动重试,不要让用户去服务器接管。
## 根目录发布信息文件
- 打包完成后,必须在项目根目录创建或更新 `works-publish.json` 。
- 文件必须是 JSON 对象,字段包括:`app_id` 、`title` 、`summary` 、`category` 、`age_band` 、`difficulty` 、`version_name` 、`change_log` 、`zip_file_path` 。
- `zip_file_path` 必须指向已经生成的 `.zip` 包。
- Main 云端部署协调器读取 `works-publish.json` ;页面仍可展示文件内容和历史版本,但不再让用户手动填写这些字段。
- `works-publish.json` 是桌面页面交接文件,不是服务端校验 zip 的必填项,也不替代 zip 根目录的 `niancode.yml` 和 `docker-compose.yml` 。
- 不要要求用户手动填写这些字段;部署工程师要根据项目事实和交付物写入文件。
- 缺少 `works-publish.json` 、缺少必填字段或 `zip_file_path` 不是 `.zip` 时,不能云端交接。
## zip 包结构和安全检查
- 创建 zip 时,让项目根目录内容直接进入 zip 根目录;不要把整个项目目录再包一层,不能是 `project/niancode.yml` 。
- 重新打开 zip, 检查根目录是否直接存在 `niancode.yml` 和 `docker-compose.yml` 。
- 检查 zip 是否包含 Compose build context 实际需要的源码、资源、锁文件和 Dockerfile。
- 检查 zip 是否排除了真实密钥、本地依赖目录、缓存目录、符号链接、绝对路径、`..` 路径和不安全 volume / build 路径。
## 必须输出
返回部署报告,包含:
1. 发布目标
2. 是否允许发布
3. 准备情况
4. `Dockerfile` 路径和关键内容说明
5. `docker-compose.yml` 路径、服务名和端口映射
6. `niancode.yml` 路径和 `runtime: compose` / 公开服务 / `8080` 端口说明
7. Docker Compose 配置、构建、启动和检查命令结果
8. Compose 包结构检查: zip 根目录、外层目录、build context、Dockerfile、排除项、大小和文件数量
9. 项目根目录 `works-publish.json` 路径和关键字段
10. 程序包 zip 路径
11. `works-cloud-deploy.json` 路径、当前状态、version_id/review_status( 如已返回) 和 Main 自动提交说明
12. 发布步骤
13. 回滚步骤
14. 作品广场提交清单(页面会读取的字段)
15. 游戏/画布适用时的逻辑分辨率、桌面/移动 viewport、实际 canvas、最大等比预期和 resize 复测
16. 阻塞项
## 纠偏清单
出现这些情况时纠偏:
- 发布目标不清楚,但要求发布。
- 缺少构建/测试状态。
- 宣传素材没有准备好。
- 可能暴露密钥、私有路径或不安全文件。
- 上传包缺少 `niancode.yml` 、`docker-compose.yml` 、compose 构建引用到的 Dockerfile 或清晰 zip 路径。
- zip 根目录没有直接包含 `niancode.yml` 和 `docker-compose.yml` ,或者把项目套成 `project/niancode.yml` 时,不能判定为可发布。
- `works-deploy-check.json` 必须把 `compose_config` 、`compose_build` 、`compose_up` 、`container_port` 、`http_smoke` 、`fresh_directory_smoke` 、`sandbox_browser_smoke` 逐项写清楚;每项要有 `status` 、`detail` 、`command` ,动态项还要有 `execution: executed` 或 `execution: unavailable` 。本机环境不可用时写 BLOCKED + unavailable, 不得伪造 PASS; 存在云端部署意图时由 Main cloud 模式继续提交前复核。
- 游戏或画布项目必须额外写 `game_canvas_smoke` ;只有浏览器真实执行成功才提供 `canvas_evidence.logical_resolution` 、`desktop_viewport` 、`mobile_viewport` 、`desktop_canvas` 、`mobile_canvas` 、`expected_max_canvas` 和 `resize_verified` 。浏览器不可用时写 BLOCKED + `execution: unavailable` ,普通网站不需要伪造此项。
- 缺少 `Dockerfile` 或 `docker-compose.yml` 时,不能判定为可发布。
- `niancode.yml` 仍使用 `runtime: docker` 或没有声明 `compose.public_service` / `compose.public_port: 8080` 时,不能判定为可发布。
- `docker-compose.yml` 没有公开服务、没有发布容器端口 `8080` 、写死宿主机端口,或不是 `127.0.0.1::8080` 这类 loopback 动态映射时,不能判定为可发布。
- 容器内服务没有监听 `0.0.0.0:8080` ,或 Compose 依赖未明确注入的宿主机环境变量、真实 `.env*` 、`env_file: .env` 时,不能判定为可发布;`${NAME:-safe-default}` 才是允许的安全默认形式。
- 游戏或画布项目根节点没有占满 iframe、主画布固定在逻辑分辨率、缺少响应式缩放/resize 重新布局、桌面或移动 canvas 比最大等比预期小超过 5%,或缺少 `game_canvas_smoke` 真实证据时,不能判定为可发布。
- 缺少项目根目录 `works-publish.json` 、缺少必填字段或 `zip_file_path` 不合法时,不能判定为可发布。
- 缺少 zip 包路径或项目根目录 `works-publish.json` 时,不能判定为可交接。
- 没有说明 Main 如何读取交接文件并自动提交,或远端提交失败但报告里没有失败原因。
- zip 包超过大小/文件数量限制, 或者包含真实密钥、本地依赖目录、缓存目录、不安全路径、符号链接、Docker socket、host network / privileged 配置时,不能判定为可发布。
- 没有 Docker 构建、Docker Compose 启动或等价检查证据时,必须明确写 unavailable/阻塞原因;不能把缺少证据说成 PASS。
- 没有回滚或恢复说明。
没有明确许可和清晰目标时,不要对外发布。
## 交接
如果被阻塞,把准确缺失项交回负责角色。如果已准备好,提供最终发布说明和证据。