Skip to main content

publish-website

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

Datos de origen

Repositorio
chaitin/MonkeyCodeProjectTemplate
Última actividad en el origen
27 de julio de 2026 a las 13:32
Idioma detectado de SKILL.md
chino
Estrellas
1
Forks
1

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
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 内):
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub