Separate agent entrypoint and avoid documentation-only Docker rebuilds
PROMPT Docker CI and deployment / verify-and-deploy (push) Successful in 18m5s

This commit is contained in:
2026-10-23 16:08:01 +08:00
parent 0a07f120df
commit 1defcf0b0a
6 changed files with 66 additions and 9 deletions
+14 -7
View File
@@ -3,7 +3,17 @@ name: PROMPT Docker CI and deployment
on:
push:
branches: [main]
paths:
- '**'
- '!docs/**'
- '!**/*.md'
- 'public/**'
pull_request:
paths:
- '**'
- '!docs/**'
- '!**/*.md'
- 'public/**'
workflow_dispatch:
jobs:
@@ -17,15 +27,12 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Prepare Docker Engine and Compose
- name: Check preinstalled Docker Engine and Compose
run: |
set -eu
if [ "$(id -u)" -eq 0 ]; then SUDO=""; else SUDO="sudo -n"; fi
if ! command -v docker >/dev/null || ! docker compose version >/dev/null 2>&1; then
$SUDO apt-get update -qq
$SUDO apt-get install -y docker.io docker-compose-v2
fi
$SUDO systemctl enable --now docker
command -v docker
docker compose version
docker info >/dev/null
- name: Validate the Compose configuration
run: docker compose --env-file .env.example config --quiet
- name: Type check, unit tests, production build and smoke test inside Docker
+8 -1
View File
@@ -10,7 +10,14 @@ COPY package.json package-lock.json ./
RUN npm ci
FROM dependencies AS build
COPY . .
# Only build inputs belong here: docs and operational notes must not bust this layer.
COPY tsconfig.json next-env.d.ts next.config.ts postcss.config.mjs ./
COPY src/ ./src/
COPY public/ ./public/
COPY scripts/ ./scripts/
COPY tests/ ./tests/
COPY db/ ./db/
COPY seed/ ./seed/
RUN npm run typecheck && npm test && npm run build && npm run test:smoke
FROM build AS integration
+9
View File
@@ -0,0 +1,9 @@
# 构建与入口
人类默认从 `/` 进入;Agent 从 `/agent` 或 `/agent/index.md` 读取 `text/markdown` 索引,根目录 `/llms.txt` 提供发现链接。索引复用技能目录,技能继续使用 `/skills/<id>/SKILL.md` 和现有子文档 URL,避免复制文档。
`ces-control` 必须预装 Docker、Compose,并允许 Runner 访问持久 Docker daemon。CI 只检查环境,不安装系统包、不启停主机服务。当前服务器没有 buildx,先继续使用 daemon 自带层缓存;不要直接粘贴依赖 GitHub cache 服务的 `type=gha` 参数。后续若换 Docker daemon 或清理缓存,会重新冷构建。
Dockerfile 显式复制构建输入;根 Markdown 和 docs 不再使应用构建层失效。push 和 PR 对纯文档改动使用 paths,但 public 下的 Markdown 属于产品资源,必须构建部署。新添根级构建配置时,需同步 Dockerfile COPY。仍保留类型检查、单元测试、smoke 与完整隔离栈集成测试。
当前页面为 Next.js SSR 与编译组件,改 TSX 仍需 next build。把 HTML 的 COPY 移到最后不能避免编译。独立挂载静态文件会破坏镜像版本与回滚的一致性;只有真正独立、无需编译的内容才适合后续拆成单独发布渠道。
+1 -1
View File
@@ -2,7 +2,7 @@ import type { NextConfig } from "next";
const nextConfig: NextConfig = {
serverExternalPackages: ["playwright-core"],
async rewrites(){return [{source:"/skills/street-people/:doc.md",destination:"/api/skill-docs/street-people/:doc"}]},
async rewrites(){return [{source:"/agent",destination:"/api/agent-index"},{source:"/agent/index.md",destination:"/api/agent-index"},{source:"/skills/street-people/:doc.md",destination:"/api/skill-docs/street-people/:doc"}]},
output: "standalone",
outputFileTracingIncludes: {"/*":["./node_modules/playwright-core/**/*"]},
poweredByHeader: false,
+6
View File
@@ -0,0 +1,6 @@
# PROMPT
> 素材与创作技能网站。
- [Agent 默认入口](/agent/index.md): Markdown 技能索引与任务导航。
- [人类入口](/): 网页浏览与素材管理。
+28
View File
@@ -0,0 +1,28 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { skillCatalog } from "@/content/skills/catalog";
export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "GET" && req.method !== "HEAD") {
res.setHeader("Allow", "GET, HEAD");
return res.status(405).end();
}
const markdown = [
"# PROMPT — Agent 入口",
"",
"人类入口:[/](/)。Agent 默认入口:[/agent/index.md](/agent/index.md)。",
"",
"按任务选择技能,先阅读 SKILL.md,再按其中链接读取子文档、参考图片与上传协议。所有相对链接均以当前网站根地址解析。",
"不要从 HTML 页面猜测上传协议;生成由你自己的工具完成,网站提供文档、校验与素材存储。执行上传前遵循用户授权和对应技能的要求。",
"",
"## 技能目录",
...skillCatalog.map(skill => `- [${skill.title}](/skills/${skill.id}/SKILL.md) — ${skill.description}`),
"",
"## 网站导航",
"- [人类首页](/)",
"- [技能浏览](/tools/skills)",
"",
].join("\n");
res.setHeader("Content-Type", "text/markdown; charset=utf-8");
res.setHeader("Cache-Control", "no-cache");
return req.method === "HEAD" ? res.status(200).end() : res.status(200).send(markdown);
}