From 2c5a70c3b3426ca5370e00a1d4130b70e5588b24 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 27 May 2026 11:49:23 +0800 Subject: [PATCH] chore: add public brand hygiene gate --- README.md | 1 + docs/operations.md | 11 +++++- docs/release-readiness.md | 2 +- package.json | 3 +- scripts/check-brand-hygiene.mjs | 69 +++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 scripts/check-brand-hygiene.mjs diff --git a/README.md b/README.md index e4122d889..95068ff59 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ http://localhost:3001/settings pnpm dev pnpm lint pnpm check:logs +pnpm check:brand pnpm check:artifacts pnpm check:quality pnpm exec tsc --noEmit --pretty false diff --git a/docs/operations.md b/docs/operations.md index 93f2d9917..cc658d196 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -7,6 +7,7 @@ ```bash pnpm lint pnpm check:logs +pnpm check:brand pnpm exec tsc --noEmit --pretty false git diff --check pnpm check:artifacts @@ -22,7 +23,7 @@ pnpm check:quality ## CI -`.github/workflows/lint.yml` 是基础质量门禁,运行 `pnpm check:quality`,负责 lint、日志治理、类型检查、diff hygiene 和 tracked 污染物检查。 +`.github/workflows/lint.yml` 是基础质量门禁,运行 `pnpm check:quality`,负责 lint、日志治理、公开交付面品牌治理、类型检查、diff hygiene 和 tracked 污染物检查。 CI 和本地提交前检查复用同一个入口,避免规则漂移。 @@ -46,6 +47,14 @@ logger.error("event failed", error); `pnpm check:logs` 会检查已治理文件是否重新引入裸 console,并验证 token、API Key、URL、base64、password 等敏感值不会明文输出。 +## 品牌与模板残留治理 + +```bash +pnpm check:brand +``` + +`pnpm check:brand` 只扫描 README、核心 docs、GitHub 模板、workflow 和 package metadata 等公开交付入口。历史方案文档和兼容性 runtime key 不在本门禁范围内,避免为了改名破坏旧用户数据或研发记录。 + ## 首页性能烟测 ```bash diff --git a/docs/release-readiness.md b/docs/release-readiness.md index 6af5fd29f..55b802cdf 100644 --- a/docs/release-readiness.md +++ b/docs/release-readiness.md @@ -13,7 +13,7 @@ SMOKE_BASE_URL=http://127.0.0.1:3001 pnpm smoke:routes 预期: -- `pnpm check:quality` 通过 lint、日志脱敏门禁、类型检查、diff hygiene 和 tracked 污染物检查。 +- `pnpm check:quality` 通过 lint、日志脱敏门禁、公开交付面品牌治理、类型检查、diff hygiene 和 tracked 污染物检查。 - `pnpm smoke:routes` 验证 `/` 返回 200。 - `/classic` 和 `/chat/test-id` 重定向到 `/`。 - `/settings` 未登录重定向到 `/login?callbackUrl=%2Fsettings`。 diff --git a/package.json b/package.json index 120b72d38..35c9a4aa7 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "lint": "npx ultracite@latest check", "check:logs": "node scripts/check-log-hygiene.mjs && tsx scripts/check-log-redaction.ts", "check:artifacts": "node scripts/check-tracked-artifacts.mjs", - "check:quality": "pnpm lint && pnpm check:logs && pnpm exec tsc --noEmit --pretty false && git diff --check && pnpm check:artifacts", + "check:brand": "node scripts/check-brand-hygiene.mjs", + "check:quality": "pnpm lint && pnpm check:logs && pnpm check:brand && pnpm exec tsc --noEmit --pretty false && git diff --check && pnpm check:artifacts", "smoke:routes": "node scripts/smoke-routes.mjs", "format": "npx ultracite@latest fix", "db:generate": "drizzle-kit generate", diff --git a/scripts/check-brand-hygiene.mjs b/scripts/check-brand-hygiene.mjs new file mode 100644 index 000000000..f4e948632 --- /dev/null +++ b/scripts/check-brand-hygiene.mjs @@ -0,0 +1,69 @@ +#!/usr/bin/env node + +import { readFileSync } from "node:fs"; + +const expectedPackageName = "yedir-ai"; + +const governedFiles = [ + "package.json", + "README.md", + "CHANGELOG.md", + "SECURITY.md", + "CONTRIBUTING.md", + "SUPPORT.md", + "CODE_OF_CONDUCT.md", + ".env.example", + "docs/architecture.md", + "docs/deployment.md", + "docs/operations.md", + "docs/release-readiness.md", + ".github/CODEOWNERS", + ".github/PULL_REQUEST_TEMPLATE.md", + ".github/dependabot.yml", + ".github/ISSUE_TEMPLATE/bug_report.yml", + ".github/ISSUE_TEMPLATE/config.yml", + ".github/ISSUE_TEMPLATE/feature_request.yml", + ".github/workflows/lint.yml", + ".github/workflows/playwright.yml", +]; + +const forbiddenPatterns = [ + { pattern: /\bai-chatbot\b/i, reason: "legacy package/repository name" }, + { pattern: /chat-sdk\.dev/i, reason: "template documentation URL" }, + { pattern: /Next\.js AI Chatbot/i, reason: "template project name" }, + { pattern: /Chat SDK/i, reason: "template positioning" }, + { pattern: /Deploy Your Own/i, reason: "template deployment copy" }, + { pattern: /Vercel templates?/i, reason: "template marketplace copy" }, + { pattern: /build:skip-prerender/i, reason: "build bypass script" }, + { pattern: /Build fallback/i, reason: "build bypass output" }, + { pattern: /next build --no-lint/i, reason: "build bypass command" }, +]; + +const violations = []; + +const packageJson = JSON.parse(readFileSync("package.json", "utf8")); +if (packageJson.name !== expectedPackageName) { + violations.push( + `package.json: expected package name "${expectedPackageName}", received "${packageJson.name}"` + ); +} + +for (const file of governedFiles) { + const source = readFileSync(file, "utf8"); + const lines = source.split(/\r?\n/); + lines.forEach((line, index) => { + for (const { pattern, reason } of forbiddenPatterns) { + if (pattern.test(line)) { + violations.push(`${file}:${index + 1}: ${reason}: ${line.trim()}`); + } + } + }); +} + +if (violations.length > 0) { + console.error("Brand hygiene check failed. Keep public delivery surfaces aligned with yedir-ai."); + console.error(violations.join("\n")); + process.exit(1); +} + +console.log(`Brand hygiene check passed for ${governedFiles.length} files.`);