name: ci on: push: branches: ['**'] pull_request: workflow_dispatch: # 门禁与本地一致:产物新鲜度 + 类型棘轮 + 全部回归套件 + manifest 校验 + 空白/冲突标记。 # (套件数量以 scripts/run-all.mjs 为准 —— 不要在这里写死数字,写死过就会过期。) # 任何一条红了就不要再合 —— 见 AGENTS.md §3 与 §6.2(禁止为了让门禁变绿而放宽断言)。 concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: gates: runs-on: ubuntu-latest timeout-minutes: 25 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 # 版本取自 package.json 的 packageManager - uses: actions/setup-node@v4 with: # 与 package.json 的 engines.node(^22.19.0 || >=24.0.0)对齐 node-version: '24' cache: pnpm - name: Install (frozen lockfile) run: pnpm install --frozen-lockfile - name: Typecheck (ratchet — 只许变少) run: pnpm run typecheck - name: Syntax check every runtime entry run: | for f in lib/*.js scripts/*.mjs; do node --check "$f"; done # ⚠️ 这里**故意不先 build**。`npm test` 的第一步是 scripts/check-build-fresh.mjs, # 它把 src/ 编译到临时目录再和提交进来的 lib/ 逐字节比对。若 CI 先跑 # `pnpm run build`,lib/ 会被就地覆盖,那条门禁就变成恒真、失去判别力。 - name: Regression suites + build freshness # 失败时把输出尾部变成 annotation:CI **日志**对无 token 的 API 不可读 # (`/actions/jobs//logs` 返回 403),而 annotation 可读 —— 这让门禁失败 # 在外部也能定位。这是 AGENTS.md §3「门禁诊断可用」的延伸。 run: | set +e out=$(npm test 2>&1) status=$? set -e echo "$out" if [ "$status" -ne 0 ]; then printf '%s\n' "$out" | grep -E '^(FAIL |[0-9]+/[0-9]+ SUITES FAILED)' | head -6 | while IFS= read -r line; do echo "::error::$line" done tail_escaped=$(printf '%s\n' "$out" | tail -22 | sed 's/%/%25/g; s/\r//g' | awk 'BEGIN{ORS="%0A"} {print}') echo "::error::门禁失败输出尾部:%0A$tail_escaped" fi exit "$status" - name: Manifest schema check (pinned dsh-std Community v0.15) run: | set +e out=$(node scripts/check-manifest.mjs 2>&1) status=$? set -e echo "$out" if echo "$out" | grep -q 'SKIP'; then # AGENTS.md §3:SKIP 明确「不是通过」。CI 里没有 vendor 基线, # 所以这里只是警告,不要把它当成校验成功。 echo "::warning::dsh-plugin.json 校验被跳过(SKIP ≠ 通过)。要真校验需设置 DSH_STD_MANIFEST 指向 pinned @dsh-std/manifest。" fi exit $status - name: Whitespace, conflict markers, prose and doc budgets # 本地与 CI 跑同一批脚本(判据不会两边不一致)。脚本各自排除:产物 lib/、历史层台账 # docs/audit-ledger.md(审计编号与轮次在该层是合法证据)。 run: | node scripts/check-whitespace.mjs node scripts/check-prose.mjs node scripts/doc-budgets.mjs