diff --git a/.github/styles/Zrr/Terms.yml b/.github/styles/Zrr/Terms.yml new file mode 100644 index 0000000..9a246c3 --- /dev/null +++ b/.github/styles/Zrr/Terms.yml @@ -0,0 +1,8 @@ +extends: substitution +message: "Use '%s' instead of '%s'." +level: error +ignorecase: false +swap: + Github: GitHub + Javascript: JavaScript + Typescript: TypeScript diff --git a/.github/workflows/ci-links.yml b/.github/workflows/ci-links.yml new file mode 100644 index 0000000..ff0521d --- /dev/null +++ b/.github/workflows/ci-links.yml @@ -0,0 +1,43 @@ +name: "CI - Link Checks" + +on: + push: + branches: + - main + paths: + - "AGENTS.md" + - "README.md" + - ".github/workflows/ci-links.yml" + pull_request: + branches: + - main + paths: + - "AGENTS.md" + - "README.md" + - ".github/workflows/ci-links.yml" + workflow_dispatch: + +permissions: + contents: read + +jobs: + links: + name: links + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Check links with lychee + uses: lycheeverse/lychee-action@v2 + with: + args: >- + --exclude-loopback + --exclude 'https://vite-plus.dev/.*' + --no-progress + 'README.md' + 'AGENTS.md' + fail: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci-pr-checks.yml b/.github/workflows/ci-pr-checks.yml new file mode 100644 index 0000000..281b7bc --- /dev/null +++ b/.github/workflows/ci-pr-checks.yml @@ -0,0 +1,29 @@ +name: "CI - PR Checks" + +on: + pull_request: + types: + - opened + - edited + - reopened + - synchronize + +permissions: + contents: read + pull-requests: read + +concurrency: + group: pr-checks-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + title: + name: PR title + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Check PR title + uses: zrr1999/zendev/actions/validate-title@v0.0.5 + with: + text: ${{ github.event.pull_request.title }} diff --git a/.github/workflows/ci-static-checks.yml b/.github/workflows/ci-static-checks.yml new file mode 100644 index 0000000..6ddfa69 --- /dev/null +++ b/.github/workflows/ci-static-checks.yml @@ -0,0 +1,33 @@ +name: "CI - Static Checks" + +on: + push: + branches: + - main + pull_request: + branches: + - main + +concurrency: + group: ci-static-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + prek: + name: prek + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: j178/prek-action@v2 + with: + install-only: true + + - uses: voidzero-dev/setup-vp@v1 + with: + cache: true + + - uses: j178/prek-action@v2 diff --git a/.github/workflows/ci-typos.yml b/.github/workflows/ci-typos.yml new file mode 100644 index 0000000..500ad87 --- /dev/null +++ b/.github/workflows/ci-typos.yml @@ -0,0 +1,42 @@ +name: "CI - Typos" + +on: + push: + branches: + - main + paths: + - ".github/**" + - ".vale.ini" + - "_typos.toml" + - "AGENTS.md" + - "README.md" + - "apps/blog/data/blog/**" + pull_request: + branches: + - main + paths: + - ".github/**" + - ".vale.ini" + - "_typos.toml" + - "AGENTS.md" + - "README.md" + - "apps/blog/data/blog/**" + workflow_dispatch: + +permissions: + contents: read + +jobs: + typos: + name: typos + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Run typos + uses: crate-ci/typos@master + with: + config: ./_typos.toml + files: ".github AGENTS.md README.md apps/blog/data/blog .vale.ini _typos.toml" diff --git a/.github/workflows/ci-vale.yml b/.github/workflows/ci-vale.yml new file mode 100644 index 0000000..b45da86 --- /dev/null +++ b/.github/workflows/ci-vale.yml @@ -0,0 +1,46 @@ +name: "CI - Vale" + +on: + push: + branches: + - main + paths: + - ".vale.ini" + - ".github/styles/**" + - "apps/blog/data/blog/**/*.md" + - "hosting" + - "hosting/**/*.md" + pull_request: + branches: + - main + paths: + - ".vale.ini" + - ".github/styles/**" + - "apps/blog/data/blog/**/*.md" + - "hosting" + - "hosting/**/*.md" + workflow_dispatch: + +permissions: + contents: read + checks: write + +jobs: + vale: + name: vale + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + submodules: recursive + + - name: Run Vale + uses: vale-cli/vale-action@v2.1.1 + with: + files: '["apps/blog/data/blog", "hosting"]' + reporter: github-check + fail_on_error: true + filter_mode: nofilter + vale_flags: "--glob=*.md" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 5f1d1e6..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Deploy to Vercel - -on: - push: - branches: [main] - pull_request: - branches: [main] - workflow_dispatch: - -permissions: - contents: write - id-token: write - -concurrency: - group: "pages" - cancel-in-progress: true - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout 🛎️ - uses: actions/checkout@v6 - with: - submodules: recursive - - name: Setup pnpm - uses: pnpm/action-setup@v6 - - name: Setup Node.js - uses: actions/setup-node@v6 - with: - node-version: "24" - cache: "pnpm" - - name: Install and Build 🔧 - run: | - pnpm install - pnpm run build - - name: Create blog domain branch 🌿 - if: github.event_name != 'pull_request' - uses: peaceiris/actions-gh-pages@v4 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./apps/blog/dist/ - publish_branch: blog - force_orphan: true - commit_message: ":rocket: deploy: " - user_name: "github-actions" - user_email: "github-actions@github.com" - - name: Create slides domain branch 🌿 - if: github.event_name != 'pull_request' - uses: peaceiris/actions-gh-pages@v4 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./apps/slides/dist/ - publish_branch: slides - force_orphan: true - commit_message: ":rocket: deploy: " - user_name: "github-actions" - user_email: "github-actions@github.com" - - name: Create root domain branch 🌿 - if: github.event_name != 'pull_request' - uses: peaceiris/actions-gh-pages@v4 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./apps/root/dist/ - publish_branch: root - force_orphan: true - commit_message: ":rocket: deploy: " - user_name: "github-actions" - user_email: "github-actions@github.com" diff --git a/.gitignore b/.gitignore index db09a60..0a51671 100644 --- a/.gitignore +++ b/.gitignore @@ -18,11 +18,10 @@ pnpm-debug.log* # environment variables .env .env.production -.turbo - # macOS-specific files .DS_Store .vscode/ .cursor/ .vite-hooks/ +.learnings/ diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 0000000..5d0f546 --- /dev/null +++ b/.vale.ini @@ -0,0 +1,5 @@ +StylesPath = .github/styles +MinAlertLevel = error + +[*.md] +BasedOnStyles = Zrr diff --git a/AGENTS.md b/AGENTS.md index 511bd04..31e54a2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,9 +4,9 @@ AI 代理配置、工作流程与项目规范。项目概览见 [README](./READM ## 项目结构 -- `apps/root/` - 个人主页(sixbones.dev) -- `apps/blog/` - 博客(blog.sixbones.dev) -- `apps/slides/` - 幻灯片(slides.sixbones.dev) +- `apps/root/` - 个人主页(`zrr.dev`,`sixbones.dev` 永久重定向到此) +- `apps/blog/` - 博客(`blog.zrr.dev`,`blog.sixbones.dev` 永久重定向到此) +- `apps/slides/` - 幻灯片(`slides.zrr.dev`,`slides.sixbones.dev` 永久重定向到此) ## 可用代理 @@ -45,8 +45,10 @@ AI 代理配置、工作流程与项目规范。项目概览见 [README](./READM ## 配置 -- `package.json` / `turbo.json` - 依赖与构建 -- `.github/workflows/` - CI/CD +- `package.json`(根目录脚本通过 pnpm `--filter './apps/*'` 在各 app 上执行 dev/build 等)与 `pnpm-workspace.yaml` +- Git **pre-commit** 由 **[prek](https://github.com/j178/prek)** 管理:`prek.toml`(与 spore 仓库对齐的 `pre-commit-hooks`、tombi、actionlint、typos、zendev、`vp check --fix`)。克隆后 `pnpm install` 会执行 `prepare` → `prek install`;首次建议再运行 `prek install-hooks`。需本机已安装 `prek`(例如 `uv tool install prek` 或 `uvx prek` 相关用法)。 +- **版本锁定(代理改依赖前必读)**:Astro 与各 app 保持一致且当前固定为 **`6.1.8`**;Vite+ 栈通过 workspace **catalog + overrides** 固定为 **`0.1.18`**。将 Astro 升到 **6.1.10+ / 6.2** 或将 vite-plus 升到 **0.1.19+** 前,须在本地跑通 **`pnpm run build`**,否则可能遇到 vite-plus-core 在 `generateBundle` 中的 **`Not implemented`**。`@astrojs/internal-helpers` 由 override 固定在 **`0.9.0`** 以匹配 markdown 集成。说明见 [README 工具链版本说明](./README.md#工具链版本说明)。 +- `.github/workflows/` - CI / 校验(不负责生产部署);含与 spore 类似的 **`ci-static-checks.yml`**(`setup-vp` + `prek-action`)、**`ci-pr-checks.yml`**(zendev PR 标题)及按路径触发的 typos、vale、外链、workflow 校验等 - `.github/agents/` - 代理配置(若存在) ## 常用命令 @@ -65,8 +67,8 @@ AI 代理配置、工作流程与项目规范。项目概览见 [README](./READM ## 工作流程 -- **代码优化**:分析 → 识别机会 → 格式化 → `vp check` / `vp test` → 提交 -- **文档更新**:审查 → 更新内容 → 验证格式 → 提交 +- **代码优化**:分析 → 识别机会 → 在仓库根运行 `vp fmt` / `vp check`(或各包 `vp fmt`)→ `vp test` → 提交 +- **文档更新**:审查 → 更新内容 → 在相关包目录运行 `vp fmt . --check` 或通过根目录 `vp check` → 提交 - **测试维护**:分析覆盖率 → 补充用例 → `vp test` → 提交 ## 最佳实践 @@ -75,6 +77,13 @@ AI 代理配置、工作流程与项目规范。项目概览见 [README](./READM - 遵循常规提交规范,单次提交保持最小化 - 审查代理更改时验证测试通过、文档同步 +## 部署模型 + +- 生产环境统一使用 **Cloudflare Workers Static Assets**:各应用在 `apps/*/wrangler.jsonc` 中配置 `assets.directory`(构建产物 `dist`)与 `routes`(`custom_domain: true`);构建后执行 `wrangler deploy`。仓库根提供 `vp run deploy:cf:root` / `deploy:cf:blog` / `deploy:cf:slides`(先 `pnpm --filter` build 再部署)。构建命令、输出目录与 Worker 名见 [README 部署模型](./README.md#部署模型)。 +- 预期 **3 个 Worker**,名称与 `wrangler.jsonc` 中 `name` 一致:`zrr-website-root`、`zrr-website-blog`、`zrr-website-slides`。不再使用 **Cloudflare Pages** 作为主发布与自定义域名入口。 +- CI 若执行 `wrangler deploy`,可使用 `CLOUDFLARE_API_TOKEN` 等凭据,但**不得将密钥提交进仓库**;不要恢复依赖 Pages orphan branch 的发布流水线。 +- 旧域名 `sixbones.dev`、`blog.sixbones.dev`、`slides.sixbones.dev` 必须继续保留为 `308` 永久重定向入口,并将请求转发到新的公开域名。 + ## 博客编写规范 文章位于 `apps/blog/data/blog/`,使用 Markdown。 @@ -184,14 +193,26 @@ These commands map to their corresponding tools. For example, `vp dev --port 300 - **Using the package manager directly:** Do not use pnpm, npm, or Yarn directly. Vite+ can handle all package manager operations. - **Always use Vite commands to run tools:** Don't attempt to run `vp vitest` or `vp oxlint`. They do not exist. Use `vp test` and `vp lint` instead. -- **Running scripts:** Vite+ commands take precedence over `package.json` scripts. If there is a `test` script defined in `scripts` that conflicts with the built-in `vp test` command, run it using `vp run test`. +- **Running scripts:** Vite+ built-in commands (`vp dev`, `vp build`, `vp test`, etc.) always run the Vite+ built-in tool, not any `package.json` script of the same name. To run a custom script that shares a name with a built-in command, use `vp run