Skip to main content

publish-website

将当前会话中生成的 Web 项目发布为线上托管应用。负责环境信息获取、项目类型探测、前端构建(复用 deploy-website 的探测规则)、基于应用内容自动生成元数据、静态资源打包,并通过 multipart 表单 POST 到 showcase API 完成上传。支持纯静态、Node.js 前端、以及容器化后端项目。

Quellinformationen

Repository
chaitin/MonkeyCodeProjectTemplate
Letzte Quellaktivität
27. Juli 2026 um 13:32
Erkannte Sprache von SKILL.md
Chinesisch
Sterne
1
Forks
1

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
publish-website
description
将当前会话中生成的 Web 项目发布为线上托管应用。负责环境信息获取、项目类型探测、前端构建(复用 deploy-website 的探测规则)、基于应用内容自动生成元数据、静态资源打包,并通过 multipart 表单 POST 到 showcase API 完成上传。支持纯静态、Node.js 前端、以及容器化后端项目。
arguments
[{"name":"workspace","description":"待发布项目的绝对路径,默认使用当前工作目录","required":false}]
# 发布应用(Publish Website) 将纯前端项目或带后端的容器化项目发布为线上应用。本 Skill 以严格的流水线方式执行——**不得跳过步骤**,**不得在未完成时声称成功**。 ## 触发准入(本 Skill 只服务于「用户主动要求的正式发布」) `publish-website` 是**面向公开作品集的正式发布通道**,不是开发调试期的预览工具。每次执行都会占用管理员审核资源并让站点公开曝光,因此**必须**由用户在**最新一条消息**中**明确要求**才可触发;未明确要求时一律改走 `deploy-website` 本地部署 + 平台在线预览。 ### 允许触发的条件(必须全部满足) 1. 用户在**最新一条消息**中明确提出「发布 / 上线 / publish-website / 用 publish-website 技能发布」等语义等价的指令,且明确指向本 Skill 2. 该指令**不是**由 Skill 或模型自身在对话中提出的建议/追问所诱导(例如模型不能问「要发布吗?」再据此触发) ### 严禁的触发方式 - **不得**因为「本会话已经 publish 过一次」就在后续任意消息里自动重新 publish;即便用户只是继续调整代码、修 bug、改文案、优化样式,只要最新消息里没有再次明确要求发布,就**不得**重新走 publish 流程 - **不得**把「代码有更新」「站点内容有变化」「已经发布过所以顺手再发一次」当作重新触发本 Skill 的理由 - **不得**在完成一次成功发布后主动追问「要不要再发布一次 / 要不要把最新改动同步上去」——这会诱导用户误触发正式发布 - 用户在开发过程中的所有**中间版本验证**都应通过 `deploy-website` 本地部署 + 平台在线预览完成,本 Skill 不负责中间版本的展示 ### 命中「重复触发」时的处理动作 当模型判断「本会话此前已成功执行过 publish-website,用户最新消息只是继续调整而未明确要求再次发布」时,**不得**进入流水线,应改为: 1. 在回复中提示:「本次调整属于中间版本迭代,建议先通过 `/deploy-website` 在平台内做在线预览确认效果;确认满意后再明确告诉我『用 publish-website 发布最新版本』,我再走正式发布流程更新线上版本」 2. 按需调用 `/deploy-website` 完成本地部署与预览 3. 结束,不得继续执行本 Skill 的任何后续步骤 ## 流水线总览 1. 获取环境信息(client_id) 2. 探测项目类型并自动判定 kind(static / backend)(复用 `deploy-website` 探测规则;后端覆盖 Node-Express、FastAPI、Django+gunicorn、Spring Boot jar、Go、Rust 等) 3. 根据判定结果分流到 static / backend 子流水线 4. 准备产物: - static 分支:必要时构建前端,准备静态产物 - backend 分支(步骤 3b):生成 Dockerfile、build、run、healthcheck、save 镜像 5. 基于应用内容自动生成应用名称与描述,再向用户逐项确认;询问应用作者 6. 打包为 `/tmp/dist.zip`(static 分支)或确认 `/tmp/showcase-image.tar.gz`(backend 分支) 7. 确定 `ticket`(首次提交需询问用户是否复用既有应用) 8. 通过 multipart 表单 POST 到 showcase API,缓存返回的 `ticket`,向用户返回 `site_url` 服务端注册与管理员审核发生在 Skill 执行结束**之后**,不属于本 Skill 的职责范围。 ### 关于 `ticket`(应用更新密钥) - `ticket` 是 showcase 服务用来识别"同一个应用"的凭证:首次创建会下发一个 `ticket`,后续若想**更新**该应用而不是新建,需在请求体中带上同一个 `ticket` - **会话级缓存**:当前会话中**首次**成功创建应用后拿到的 `ticket`,必须缓存于会话上下文(例如记在内存/笔记中),同一会话内后续每次提交都自动使用该 `ticket`,**不得**再向用户询问 - 仅当**本会话从未提交过应用**时,才需要询问用户是不是要复用其他任务中创建的应用(步骤 7a) - **跨 kind 切换**:同一 `ticket` 可以从 `static` 切换为 `backend`(或反之),服务端会将原应用整体替换为新 kind 并重新进入待审核状态;在用户确认时必须明确告知「将把原应用从 X 切换为 Y,并重新进入待审核状态」 --- ## 步骤 1 —— 获取环境信息 执行 `hostname` 命令获取当前主机名,作为后续上传请求中的 `client_id`: ```bash hostname ``` 将输出的字符串原样记录为 `client_id`。**不得**自行编造或使用其他值;若命令失败,终止并向用户报告。 --- ## 步骤 1b —— 发布内容合规性预检(硬约束) 在进入 kind 判定之前,必须先判断当前工作目录是否属于以下**禁止发布**的站点类型。命中任意一条 → **立即终止**发布,向用户说明原因并建议改用其他渠道分发;**不得**继续后续任何步骤。 ### 禁止发布的站点类型清单 1. **软件下载/分发类站点**:以提供 `.apk` / `.ipa` / `.exe` / `.dmg` / `.msi` / `.pkg` 等可执行安装包下载为主要目的的站点 - 判定信号:站点目录下存在上述扩展名的二进制文件、页面文案主打「下载」「安装包」「客户端下载」「Download APK / IPA / EXE / DMG」等 - 理由:showcase 是 Web 应用作品集,不承担软件分发/托管职责,也无法承担分发链路上的安全与合规责任 2. **直接发布开源 CMS / 网站面板类项目**:未做任何二次开发、直接把开源建站系统或运维面板搬上来的 - 常见特征(含但不限于):WordPress、Joomla、Drupal、Typecho、Ghost、Halo、DedeCMS、帝国 CMS、织梦、PHPMyAdmin、宝塔面板、1Panel、cPanel、Plesk、Webmin 等 - 判定信号:目录结构、`readme` / `LICENSE` / `composer.json` / `package.json` 中出现上述项目名,或首页明显是这些系统的默认后台/安装向导 - 理由:这类项目本身就是通用平台,直接发布不构成"用户作品",且往往自带账号体系、文件上传、插件市场,与「单容器 / 无外网 / 无持久化 / 公开可见」的运行约束严重冲突 ### 处理动作 命中上述任一条时,向用户明确回复: > 检测到当前项目属于「软件下载分发 / 开源 CMS 或网站面板直接发布」类型,MonkeyCode-AI 用户作品集不接收此类站点,本次发布已取消。 然后**立即结束**本 Skill,**不得**再询问用户是否继续,**不得**进入后续任何步骤。 --- ## 步骤 2 —— 自动判定 kind(static / backend) 由 Skill **基于工作目录扫描**,自动判定本次发布的 kind: 判定规则(按优先级): 1. 工作目录中存在以下任一**后端特征**之一 → 判定为 `backend`: - `requirements.txt` / `pyproject.toml` 含 `fastapi` / `uvicorn` / `django` / `flask` / `gunicorn` - `manage.py` - 顶层 `pom.xml` / `build.gradle`(Spring Boot 等 JVM 项目) - `go.mod` - `Cargo.toml`(且非纯 wasm 前端) - `composer.json`(PHP) - `Gemfile` 含 `rails` / `sinatra` - `package.json` 中出现 `express` / `fastify` / `koa` / `hapi` / `nest` 等后端框架依赖 2. 仅有 `index.html` / 静态 HTML 文件 → 判定为 `static` 3. 存在 `package.json` 且无后端框架依赖(Vite / CRA / Next 静态导出 / Vue / Astro / Nuxt SSG 等纯前端项目) → 判定为 `static` 4. 探测不出来 → 询问用户「按纯前端发布」还是「按容器化后端发布」,**仅此一次**作为兜底 判定完成后分流: - `static` → **static 子流水线**(步骤 3 → 4 → 5 → 6 → 7 → 8) - `backend` → **backend 子流水线**(步骤 3 → 3b → 5 → 7 → 8;步骤 4/6 由 3b 取代) ### 进入 static 分支前必须告知用户(硬约束) 判定为 `static` 后,**进入步骤 3 之前** 必须在对话中明确告知以下平台限制: > **⚠ 即将将本应用发布到 [MonkeyCode-AI 用户作品集](https://showcase.monkeycode-ai.online/)。线上运行时有以下两条限制,请确认是否继续发布:** > > 1. **数据只能保存在浏览器**:纯前端应用没有任何服务端持久层,可用的存储仅限当前浏览器的 `localStorage` / `sessionStorage` / `IndexedDB`。用户换浏览器、清缓存、换设备后数据都不会跟随;多个用户之间不会共享数据。 > 2. **公开可见**:应用发布后会在 用户作品集 (showcase.monkeycode-ai.online) 列表公开可见,所有人都可以访问到你发布的应用。 然后用 `question` 工具,要求用户确认,选项为「继续发布」/「取消」。 - 用户选「继续发布」 → 进入步骤 3 - 用户选「取消」 → 终止本次发布 ### 进入 backend 分支前必须告知用户(硬约束) 只告诉用户 **与线上运行阶段相关** 的注意事项,不暴露任何 镜像 build 阶段细节(Dockerfile 怎么写、是否用 supervisord、依赖如何下载等都是 Skill 自己处理的事,与用户无关)。 判定为 `backend` 后,**进入步骤 3b 之前** 必须在对话中明确告知以下平台限制: > **⚠ 即将以容器方式,将本应用发布到 [MonkeyCode-AI 用户作品集](https://showcase.monkeycode-ai.online/)。线上运行时有以下四条限制,请确认是否继续发布:** > > 1. **单容器**:平台只调度一个容器。如果应用依赖数据库、对象存储、缓存、队列等组件,会与业务一起塞在同一个容器里运行,不支持外部独立服务。 > 2. **无外部网络**:容器无法访问公网与任何外部服务。远程数据库、S3、第三方 API、OAuth / 支付 / 微信、CDN、外部 LLM 等都不可达。业务在线上启动后,只能被外部访问,不应也不能访问互联网。 > 3. **无持久化存储**:服务更新、异常重启或被运维重建容器时,文件系统会被重置,所有运行时写入(SQLite、用户上传、日志、缓存等)都会丢失。 > 4. **公开可见**:应用发布后会在 用户作品集 (showcase.monkeycode-ai.online) 列表公开可见,所有人都可以访问到你发布的应用。 然后用 `question` 工具,要求用户确认,选项为「继续发布」/「取消」。 - 用户选「继续发布」 → 进入步骤 3b - 用户选「取消」 → 终止本次发布 --- ## 步骤 3 —— 探测项目类型 复用 `deploy-website` 中的探测逻辑。根据步骤 2 的自动判定结果分流: ### static 分支(kind=static) | 探测结果 | 走向 | |---|---| | 存在 `package.json`(Node 项目) | → **Node 构建分支**(步骤 4 分支 B/C) | | 仅有 `index.html` / 静态 HTML 文件 | → **静态分支**(步骤 4 分支 A) | #### 包管理器探测(仅 Node 项目) 优先级顺序: 1. `pnpm-lock.yaml` → `pnpm` 2. `yarn.lock` → `yarn` 3. `package-lock.json` → `npm` 4. 都没有 → 默认 `npm` #### 构建命令解析(仅 Node 项目) 按优先级: 1. `package.json` 的 `scripts.build` → `<pkgMgr> run build` 2. 已知框架默认产物目录——Vite/CRA/Astro → `dist`,Next.js 静态导出 → `out`,react-scripts → `build` 3. README 兜底:扫描 `README*` 中包含关键字 `build` / `compile` / `dist` 的命令并提取 4. 以上都失败 → **询问用户**指定构建命令,不要猜测 #### 预期产物目录 记录预期的输出目录(`dist` / `out` / `build`),供步骤 4 使用。 ### backend 分支(kind=backend) 探测项目语言/框架,至少覆盖以下场景: | 探测特征 | 推断类型 | |---|---| | `package.json` 中出现 `express` / `fastify` / `koa` / `hapi` | Node-Express 系 | | `requirements.txt` / `pyproject.toml` 中含 `fastapi` / `uvicorn` | FastAPI | | `manage.py` + `requirements.txt` 含 `django` + `gunicorn` | Django + gunicorn | | 顶层 `pom.xml` / `build.gradle` 且产物为 `*.jar`(Spring Boot) | Spring Boot jar | | `go.mod` | Go | | `Cargo.toml` | Rust | | 其他 | 询问用户基础镜像与启动命令,不要猜测 | 记录推断结果,供步骤 3b 生成 Dockerfile 使用。 --- ## 步骤 3b —— backend 子流水线 > 仅当步骤 2 自动判定为 `backend` 且用户在告知运行时四条限制后选择「继续发布」时执行。完成后跳过步骤 4/6 直接进入步骤 5、7、8。 ### 3b.0 平台限制(生成 Dockerfile 前必须遵守) showcase 平台对 backend 容器有四条硬约束,必须同时满足,否则镜像无法正常运行。 #### A. 单容器 + 进程编排(按需 supervisord) - 平台只调度**一个容器**,不支持 docker-compose / k8s pod / sidecar - 进程编排策略**按附加组件需求二选一**(Skill 在 3b.1 自行判定): - **单进程方案(默认)**:业务本身无 DB / 对象存储 / 缓存 / 队列等附加依赖,是一个无状态后端进程 → **直接 `ENTRYPOINT` / `CMD` 拉起业务进程**,不要引入 supervisord - **多进程方案**:业务依赖 DB / 对象存储 / 缓存 / 队列等附加组件 → 这些组件**全部打入同一镜像**,由 **supervisord** 与业务进程一起拉起、守护、按 `priority` 排序 - 多进程方案下附加组件的本地化: - 关系型 DB(PostgreSQL / MySQL / MariaDB)→ 整体打入镜像,初始 schema 在 builder stage 灌进数据目录 - 对象存储(MinIO / SeaweedFS)→ 整体打入镜像,bucket 在容器启动脚本里初始化 - Redis / Memcached / Elasticsearch / RabbitMQ 等 → 同理,全部本地拉起 - 业务代码连接附加组件时**必须走 `127.0.0.1` / `localhost` / Unix socket**,不得使用外部 host 名或外部 endpoint #### B. 容器无外部网络(运行时离线) 容器运行时**完全切断公网与外网访问**: - 出站 DNS、TCP、UDP 均不可达;远程 DB、远程 S3、远程 Redis、第三方 API、OAuth IdP、CDN、`pip` / `npm` / `apt` 等**全部不可用** - 镜像必须做到**完全自包含**:所有运行时需要的资源在 **builder stage 提前下载并 COPY 进 runtime stage**,包括但不限于: - 业务依赖包(已经在 builder 装好,runtime 直接拷 venv / node_modules / target/release / vendor) - 模型权重、embedding 文件、tokenizer - 字体、字典、地理库、本地化资源 - DB 初始 schema(`*.sql`)与种子数据 - 静态前端产物(如果是前后端一体镜像) - HTTPS 根证书(如果业务以前是直连公网 CA 校验,现在改为只信任内部证书或干脆走内网 HTTP) - 对外暴露:**仅 `service_port` 一个端口**,由平台反向代理对外提供 HTTP 服务 #### C. 容器无持久化存储 - 服务更新发布、容器异常崩溃、运维侧重启都会**重建容器**(旧实例销毁、新实例从镜像启动) - 不挂载任何 volume / bind mount,对文件系统的所有写入在重建时丢失 - 容器内打包的 DB / 对象存储**也会一并清零**——重启后必须由 supervisord 启动脚本重新执行初始化 schema + 种子数据 Dockerfile **不得** `VOLUME` 声明数据目录(声明无效,反而误导用户)。 如果项目**强依赖**外部持久层或外部 API(如必须连真实的微信 / 支付 / 外部 LLM),需再次告知用户「相关功能部署后可能无法正常使用」,用户认同后才能继续构建和发布。 #### D. 资源上限 - CPU:1 核 - 内存:1 GiB(含 swap) - 镜像 tar.gz:≤ 500 MB 打包 DB、对象存储、模型等附加组件时务必尽可能按此上限裁剪。 ### 3b.1 生成 Dockerfile AI 基于步骤 3 的探测结果生成**多阶段 alpine** `Dockerfile`,写入 `/tmp/Dockerfile`,该 Dockerfile 专门用于构建被发布到 showcase 上的容器镜像。**不得**把这个 Dockerfile 写到用户工作目录。 硬性写法约束: - 最终(runtime)stage 必须基于 alpine 或 alpine 风味的语言镜像(如 `eclipse-temurin:21-alpine-jdk`) - runtime stage **原则上禁止** `apt-get` / `dnf` / `yum`,如果必须安装软件包,在安装完后必须执行清理操作(如 `apt clean`) - **禁止** `ADD <url>` —— 所有外部资源在 builder stage 用 `RUN curl/wget` 显式落盘 - 必须多阶段;runtime stage 只 `COPY --from=builder` 编译产物 / 运行时依赖(含模型权重、字体、初始化 SQL、根证书等运行时资源),不得在 runtime 跑任何联网命令 - 进程编排策略按 3b.0 §A 自动选择:单进程方案 `CMD ["业务命令", ...]`;多进程方案 `CMD ["/usr/bin/supervisord","-c","/etc/supervisord.conf","-n"]`(配置见 3b.1.a) - `CMD` 必须为 exec 形式(JSON 数组) - 必须 `EXPOSE <service_port>`,且与 multipart 字段 `service_port` 一致;附加组件端口(DB / Redis / MinIO 等)只走 127.0.0.1,**不得 EXPOSE** - **所有 `FROM` 引用的 Docker Hub 镜像必须加 `registry.monkeycode-ai.online/` 代理前缀**: - 无 namespace 的官方镜像(`alpine` / `node` / `python` / `golang` / `nginx` / `rust` / `caddy` 等)必须插入 `library/`:`FROM registry.monkeycode-ai.online/library/alpine:3.20` - 已有 namespace 的镜像(如 `eclipse-temurin/...`)**不要**再插 `library/`:`FROM registry.monkeycode-ai.online/eclipse-temurin:21-alpine-jdk` - `FROM scratch` **不走**代理,保留原样 - 该前缀只在生成 Dockerfile 时注入;showcase 服务端 load 镜像后引用本地 image id,不再受代理影响 #### 3b.1.a supervisord 配置(仅多进程方案) > 仅当业务有附加组件依赖(DB / 对象存储 / 缓存 / 队列等)时启用本节;单进程方案跳过本节,直接在 runtime stage 写 `CMD ["业务命令", ...]` 即可。 runtime stage 必须安装 supervisord 并提供配置文件: ```dockerfile # runtime stage 内 RUN apk add --no-cache supervisor COPY supervisord.conf /etc/supervisord.conf COPY --from=builder /app /app EXPOSE <service_port> CMD ["/usr/bin/supervisord","-c","/etc/supervisord.conf","-n"] ``` `supervisord.conf` 最小模板(按项目实际附加组件增删 `[program:*]` 段,并用 `priority` 控制启动顺序,数字越小越早启动): ```ini [supervisord] nodaemon=true user=root logfile=/dev/stdout logfile_maxbytes=0 pidfile=/run/supervisord.pid [program:postgres] priority=10 command=/usr/local/bin/docker-entrypoint.sh postgres user=postgres autostart=true autorestart=true stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 [program:app] priority=50 command=/app/start.sh autostart=true autorestart=true stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 ``` `/app/start.sh` 中业务进程启动前要做: 1. 等待附加组件就绪(`pg_isready` / `redis-cli ping` / 探活脚本,最长等 30s) 2. 幂等地灌入初始 schema 与种子数据(从 builder 阶段烤进镜像的 `*.sql`) 3. 再 `exec` 业务进程(保留 PID 1 子进程语义,方便 supervisord 回收) > supervisord 配置文件 `supervisord.conf` 和启动脚本 `start.sh` 由 Skill **生成到 `/tmp/`** 后 `COPY` 进镜像,**不得**写入用户工作目录。 #### 3b.1.b 附加组件打包指引(仅多进程方案) | 组件 | 推荐做法 | |---|---| | PostgreSQL | builder stage 装好 `postgresql` + 初始化 `initdb`;runtime stage 用 `apk add postgresql`;supervisord 启动 `postgres -D /var/lib/postgresql/data`;schema 从 builder COPY,启动脚本里 `psql -f` 灌入 | | MySQL/MariaDB | runtime stage `apk add mariadb mariadb-client`;`mysql_install_db --user=mysql` 在 builder 完成;supervisord 启动 `mysqld --user=mysql` | | Redis | runtime stage `apk add redis`;supervisord 启动 `redis-server --bind 127.0.0.1 --save ""`(关闭持久化或写到容器内临时目录) | | MinIO | builder stage `wget` 拉 minio 二进制;runtime COPY;supervisord 启动 `minio server /data --address 127.0.0.1:9000`;bucket 在启动脚本里用 `mc` 初始化 | | Elasticsearch / Kafka 等重量级组件 | 1 GiB 内存装不下,**告知用户改造为轻量替代**(如改用 SQLite FTS / Redis Streams / NATS embedded)或终止本次发布 | #### 依赖下载镜像约定(builder stage 必须遵守) 构建环境默认在国内,直连官方源大概率超时。**builder stage 凡是要下载依赖,必须先切到以下国内镜像**,按语言对号入座: | 生态 | 镜像 | Dockerfile 写法 | |---|---|---| | Go | goproxy.cn | `ENV GOPROXY=https://goproxy.cn,direct` | | Node (npm/pnpm) | npmmirror.com | `RUN npm config set registry https://registry.npmmirror.com`(pnpm 同样读 npm 配置;yarn 用 `yarn config set registry https://registry.npmmirror.com`) | | Python (pip) | 清华 TUNA PyPI | `RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt` | | Rust (cargo) | 清华 TUNA crates.io | 见下方 config.toml 片段 | | Java (Maven) | 阿里云 | `settings.xml` mirror 指到 `https://maven.aliyun.com/repository/public`,或 Gradle `repositories { maven { url "https://maven.aliyun.com/repository/public" } }` | | Alpine apk | 清华 TUNA | `RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories` | | Debian/Ubuntu apt | 清华 TUNA | `RUN sed -i 's@deb.debian.org@mirrors.tuna.tsinghua.edu.cn@g' /etc/apt/sources.list.d/debian.sources`(老镜像没有 `.sources` 文件时改 `/etc/apt/sources.list`) | Rust 的 cargo 镜像配置(builder stage 内):
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen