Files
aurora-admin/ROADMAP.md
T
aurora-admin eb25feedaf feat(S6-P21): 组件族参数化(13族/44成员/导航族15文件同源/79→48概念组件)
【本次核心 · S6-P21】
- 族层数据:families.json + 44 份契约注入 family/familyRole/familyParams;
  data.json / data.js / site/details 同步。13 族 / 44 成员 / 35 独立 → 概念组件 79→48。
- 79 个 slug 全保留、集合逐一不变(铁律 5 对外承诺未破);frameworks 仍 395 文件、薄壳仍 79。
- 归族判据为契约中可核对字段(semanticTypeCandidates 重叠 / anatomy 为同一骨架子集 /
  变体维度同构 / doNotInvent 显式从属声明),每族 mergeBasis 写明依据,不按名字猜。
- 实现层合并(导航族端到端切片):tools/gen-family-impl.mjs 从 5 端模板生成
  TopMenu / SideMenu / MixedNavigation 共 15 文件,参数 direction=top|side|mixed;
  三份 CSS md5 完全相同 = 一份样式表服务三个组件。
- 新增 tools/gen-families.mjs、tools/gen-family-impl.mjs、tools/verify-families.mjs、
  tools/lib/family-model.mjs、tools/lib/family-impl/nav-menu/*.tpl。

【同时清掉此前已完成但未提交的批次】
生成物(data.json / data.js / site/sources / site/components 薄壳 / sitemap.xml / tests 报告)
跨阶段交织,无法拆成互相自洽的多个提交,故按既有批量风格合并提交:
- Package:三端可 import(S5-P18)+ 发布到私有 npm 源
- Docs site:导航语言改下拉(S5-P19)、详情页代码块默认展开、中英切换完整性
- Security:生产部署链审计修复(2026-09-19)+ 线上部署
- Theme modes 日间/夜间/自动;S1-P4 data.js 瘦身;S2-P5 暗色;S2-P6 跨端一致性;
  S2-P7 行为断言;S2-P9 FAQ;S3-P8 RTL;S3-P9 契约缺口解释层;S4-P12 发布流程
- 补入 tools/pack-deploy.mjs、run-site-smoke.mjs、verify-*.mjs,.dockerignore、
  安全审计修复与待决策项.md

【验收】
- node tools/verify-families.mjs → OK: 族层端到端一致(13 族 / 44 成员 / 79 组件不变 / 395 文件不变)
- node tools/verify-cross-platform.mjs → 79/79 identical(HEAD 基线 high 44)
- node tools/run-regression.mjs → 100%(79/79 页,1017/1017 断言,N/A 34),连跑 8 次一致,0 超时
- 逐页实测:topmenu / sidemenu / mixednavigation 各 13/13,帧内 direction 参数正确,0 JS 错误
- 零运行时依赖 OK;build-site.ps1 ASCII-only OK

【未纳入】site/components/<slug>/ 平台薄壳 316 个 —— 历史从未跟踪且属构建产物,保持现状。
2026-09-20 03:32:31 +08:00

1303 lines
68 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Aurora Admin · 长期路线图与任务包
> **文档性质**:交给执行模型的工程规划。每个任务包自带验收命令与失败判据,拿到即可开工,不需要再问。
> **基线版本**:v1.4.1(2026-09-11)
> **规划人**:海鸥(规划师角色)
> **更新约定**:任务完成时在本文件对应任务包下追加 `✅ 完成于 <commit>`,不要删原计划。
---
## 〇 · 交接约定(执行模型必读)
### 0.1 铁律(违反即返工)
1. **零运行时依赖不可破**:不引入 npm 运行时依赖。构建/测试脚本用 Node 内置能力或 PowerShell。`package.json` 的 `dependencies` 必须为空(`devDependencies` 可用)。
2. **`build-site.ps1` 必须 ASCII-only**:PS5.1 按 ANSI 读无 BOM 文件,脚本里出现非 ASCII 字面量会被损坏。中文文案放 UTF-8 模板。
3. **改结构要改模板**:`tests/<slug>.html` 是生成物 —— 改它没用。改 `tests/_template.html` / `tests/_index_template.html` 后重跑 `run-tests.ps1`。
4. **改样式要改内嵌层**:演示页的**内嵌 `<style>`** 才是实际生效的样式(v1.4.0 教训:只改 `frameworks/*.css` 可能不生效,因为演示页不一定 link 它)。
5. **`data.json` 是 For Agents 的对外承诺**:可以拆 `data.js`,但 `data.json` 必须保持完整(一次请求拿到全部)。破坏它是 breaking change。
6. **单次改动后必须跑回归**:`tests/_collect.html` 八次连跑,`100% / 0 失败 / 0 超时` 才算过。
### 0.2 禁止事项(做过即需回滚)
| 禁止 | 原因 | 正确做法 |
|---|---|---|
| 在 `frameworks/` 里直接手工改出"更好看"的样式 | `frameworks/` 是规范原文的忠实实现,改动会破坏契约一致性 | 要改样式先改令牌,或走任务包流程 |
| 用 `git reset --hard` / `git checkout .` 清理 | 会丢用户改动 | 用 `git stash` 或定向还原 |
| 删除或改写 `CHANGELOG.md` 的历史条目 | 那是变更事实记录 | 只追加 `[Unreleased]` 或新版本段 |
| 修改 `tests/report.json` 的数值来"通过"验收 | 报告是生成物,改它等于伪造证据 | 修实际问题后重跑生成 |
| 为了通过验收而放宽断言判据 | v1.3.1 曾出现"调松断言刷分"的诱惑 | 断言判据的修正必须附**理由 + 反例** |
| 在规划未涉及的领域顺手重构 | 范围蔓延会让验收失焦 | 写成新任务包追加到本文件 |
### 0.3 环境与工具
| 项 | 说明 |
|---|---|
| 操作系统 | Windows(开发)/ Linux(CI)。跨平台写法见下方「跨平台注意」 |
| Shell | Git Bash(开发)/ bash(CI) |
| Node | ≥ 18(用到 `node:sqlite` 的任务需 ≥ 22) |
| 构建 | `powershell -NoProfile -ExecutionPolicy Bypass -File build-site.ps1`(**Windows 专用**) |
| 回归 | 浏览器打开 `tests/_collect.html`,或 `node tools/run-regression.mjs`(需 playwright) |
| 本地服务 | `node site/dev-server.js`(端口 3311) |
**跨平台注意**:
- 后台启动服务:Windows Git Bash 用 `node site/dev-server.js &`,CI 用 `node site/dev-server.js & sleep 3`。**不要用 `start` 或 `nohup`**。
- 路径分隔符:脚本里统一用 POSIX 风格(`/`),Node 的 `path` 模块会处理。
- PowerShell 脚本**只能在 Windows 跑**。若 CI 需要构建,改写为 Node 脚本或加 `runs-on: windows-latest`。
### 0.4 失败升级路径
执行中遇到阻塞时,按这个顺序处理,**不要停下来等**:
| 情况 | 处理 |
|---|---|
| 验收命令本身有错(路径不对、语法不兼容) | 修正命令使其能真实反映目标,**在交付说明里写明修正了什么、为什么** |
| 目标不可达(如依赖的服务/网络不可用) | 交付最强替代物 + 写明缺什么。例:无法 `npm pack` 则做本地 `npm pack --dry-run` 的等价检查 |
| 发现规划有事实错误(如"某字段占 89%"实际不是) | **以实测为准**,修正规划并在本文件标注「⚠️ 规划修正」 |
| 发现规划未覆盖的新缺口 | 写成新任务包追加到本文件,**不在原任务里顺手修** |
| 连续两次尝试同一路径都失败 | 换策略而非重试。在交付说明里记录两次失败的原因 |
### 0.5 交付说明模板(每个任务包完成时提交)
```markdown
## <任务 ID> 完成说明
**验收输出**(原样粘贴命令输出,不要转述):
```
<命令>
<输出>
```
**改动文件**:
- <路径> — <做了什么>
**规划偏差**(若有):
- <规划里写的> → <实际的>,原因:<...>
**发现的新问题**(若有):
- <描述> → 已追加为任务包 <ID>
**回归**:100%(<总断言>/<通过>)/ 八次连跑一致 / 0 超时
```
---
## 一 · 现状基线(全部为实测数据)
### 1.1 资产规模
| 项 | 数量 | 测量方式 |
|---|---|---|
| 组件 | 79 | `components/index.json` |
| 5 端实现文件 | 395 | `ls frameworks/*.{html,css,jsx,vue2.vue,vue3.vue}` 各 79 |
| 契约 JSON | 79(全量) | `ls .design_library/aurora-admin/components/*.json` |
| 契约 usageHints | 358 条 | 遍历契约累加 |
| 契约 unknowns | 139 条 | 同上(**现成的 FAQ 素材**) |
| 契约 doNotInvent | 101 条 | 同上 |
| 设计令牌 | 75 个 | `site/data.json` → `tokens.length` |
| i18n 字典 | 330 条 | `site/i18n.js` |
| 测试断言 | 961 条(12.2/页) | `tests/report.json` |
| 文档站路由 | 9 个 | home/overview/guide/design/changelog/agents/component/scenario/tests |
### 1.2 质量指标
| 项 | 值 | 说明 |
|---|---|---|
| 回归通过率 | **100%** | 八次连跑一致,0 失败 0 超时 |
| N/A 断言 | 36(3.7%) | 静态组件无交互面、单实例组件无多变体,已逐条核实 |
| 契约保真度 | 93.9% 逐字命中规格 | 余 22 条为同义改写,非发明 |
| 令牌语义错配 | 0 / 1313 处 | 属性与令牌角色全部匹配 |
| i18n 质量 | 0 残留中文、0 未翻译 | 326 条字典 |
| 组件可换肤 | 79/79 | 逐组件改令牌比对样式签名 |
### 1.3 性能基线
| 指标 | 值 | 说明 |
|---|---|---|
| 文档站传输量 | **1247 KB** | 7 个资源 |
| 其中 `data.js` | **1058 KB(85%)** | ← 最大优化目标 |
| `app.js` | 101 KB | 未压缩 |
| `style.css` | 40 KB | 未压缩 |
| DOMContentLoaded | 345 ms | 本地 dev-server,线上更慢 |
| 每详情页额外 | iframe 1 个 | 加载对应演示页 |
### 1.4 实测缺口(按严重度)
| # | 缺口 | 实测证据 | 影响 |
|---|---|---|---|
| **G1** | **无 LICENSE** | `ls LICENSE` → 不存在 | 法律上不可用,对外交付的硬阻塞 |
| **G2** | **无分发机制** | 无 `package.json` / 无 CDN / 无发布流程 | 用户拿不到,只能 clone 仓库 |
| **G3** | **CI 无测试** | `.github/workflows/` 只有 `deploy-pages.yml` | 回归靠手动,质量无持续保障 |
| **G4** | **暗色模式是假的** | 令牌层 `aa-dark` 规则 **0** 条、组件层 **0** 条、仅站点骨架 **7** 条 | CHANGELOG 曾称"补全",实为第 6 次声称≠实现 |
| **G5** | **跨端一致性无验证** | 5 端 395 文件,无任何自动比对 | H5/React/Vue2/Vue3 视觉是否一致**无从知晓** |
| **G6** | **`data.js` 1MB** | 占传输量 85% | 首屏慢,移动端更差 |
| **G7** | **RTL 未支持** | 逻辑属性 0 处 / 物理属性 22 文件 | 阿拉伯语等市场不可用 |
| **G8** | **断言偏结构** | 12 项/页,多为"元素存在",无"点击后发生什么" | 行为回归无覆盖 |
---
## 二 · 长期愿景与阶段划分
### 2.1 目标状态(12 个月)
> **一句话**:从「一个做得很完整的组件库仓库」,变成「一个能被外部团队直接采用的设计系统产品」。
拆成四个可验证的终态:
1. **可交付** —— 有许可证、有分发渠道、有 CI 保障,外部团队 5 分钟内能用上。
2. **可信** —— 关键声称(暗色、跨端一致、无障碍)全部有自动化证据,不靠文档承诺。
3. **完整** —— 覆盖国际化(含 RTL)、无障碍实测、性能预算。
4. **生态** —— 设计工具链打通(Figma)、典型页面可直接复用、有版本发布节奏。
### 2.2 阶段划分与决策依据
| 阶段 | 主题 | 解决 | 决策依据 |
|---|---|---|---|
| **S1** | 可交付 | G1 G2 G3 G6 | 前三个是**对外交付的硬阻塞**:没许可证不能商用,没分发拿不到,没 CI 质量会退化。G6 顺手做(data.js 占 85% 传输量,收益最大) |
| **S2** | 可信 | G4 G5 G8 | 都是「声称了但没证据」。G4 是第 6 次声称≠实现,必须先止血 |
| **S3** | 完整 | G7 + 无障碍实测 | RTL 与无障碍是竞品 7 家里的分水岭(3 家有 RTL) |
| **S4** | 生态 | Figma/模板/发布 | 前两阶段完成后,生态建设才有意义 |
**为什么这个顺序**:S1 是"能不能用",S2 是"能不能信",S3 是"够不够全",S4 是"好不好用"。顺序颠倒会做出没人敢用的产品。
---
## 三 · 任务包
> 格式:**目标 → 依据 → 依赖 → 路径 → 步骤 → 验收 → 失败判据**
> 每个任务包独立可执行,除标注依赖外互不阻塞。
---
### S1-P1 · LICENSE 许可证 | 预算 ~10 min | 优先级 P0
**目标**:仓库根目录存在 `LICENSE`,明确授权范围,移除对外交付的法律阻塞。
**依据**:G1。`CONTRIBUTING.md` 与 `README.md` 都在讲如何贡献与使用,但没有许可证意味着**默认保留所有权利**,外部团队法务不会放行。
**依赖**:无。需用户确认许可证类型(见下方决策点)。
**路径**:`LICENSE`(新建)
**步骤**:
1. 确认许可证类型。若用户未指定,**默认 MIT**(与本项目"零依赖、鼓励复用"的定位一致),并在交付说明里标注"如需变更请告知"。
2. 写入标准 MIT 全文,版权行为 `Copyright (c) 2026 Aurora Admin`。
3. 在 `README.md` 增加 `## 许可证` 段,链接到 `LICENSE`。
4. 在 `CHANGELOG.md` 的 `[Unreleased]` 下追加 `### Added — LICENSE`。
**验收**:
```bash
# 文件存在且包含关键条款
test -f LICENSE && grep -q "MIT License" LICENSE && grep -q "WITHOUT WARRANTY" LICENSE && echo "LICENSE OK"
# README 有链接
grep -q "LICENSE" README.md && echo "README OK"
```
**预期输出**:
```
LICENSE OK
README OK
```
**失败判据**:任一条命令无输出,或 `LICENSE` 里出现非标准条款(自行增删免责声明)。
**决策点(需用户输入)**:许可证类型。MIT 是默认推荐;若项目未来要商业化或要求衍生作品开源,应改 Apache-2.0 或 MPL-2.0。
**✅ 完成(MIT,采用默认选择)** — 验收输出:
```
LICENSE OK
README OK
```
同步改动:`LICENSE`(MIT 全文)、`README.md`(新增「许可证」段 + 版本号更新为 v1.4.1 + 指向本路线图)。
如需改为 Apache-2.0 / MPL-2.0:替换 `LICENSE` 全文,同步 `README.md` 与未来 `package.json` 的 `license` 字段即可,无其他联动。
---
### S1-P2 · npm 分发 | 预算 ~2 h | 优先级 P0
**目标**:`npm install aurora-admin-design` 能拿到令牌 + 组件样式;`<link>` 可直接引 CDN。
**依据**:G2。当前用户只能 clone 整个仓库(5.1MB git + 2.6MB site),对"只想用几个组件"的人成本过高。
**前置验证已完成**(规划阶段实测):
| 假设 | 结果 |
|---|---|
| npm 可用 | ✅ v11.17.0 |
| 包名 `aurora-admin-design` 是否被占用 | ✅ **未被占用**(registry 返回 `{"error":"Not found"}`) |
| `colors_and_type.css` 可否直接作 dist 令牌源 | ✅ 含 `:root`、75 个令牌,可直接用 |
| 零依赖约束下能否构建 dist | ✅ Node 内置能力足够(读写文件 + JSON) |
**依赖**:S1-P1(package.json 需声明 `license` 字段)。
**路径**:
- `package.json`(新建)
- `.npmignore`(新建)
- `tools/build-dist.mjs`(新建,产出分发产物)
- `dist/`(构建产物,加入 `.gitignore`)
**步骤**:
1. 建 `package.json`,关键字段:
```json
{
"name": "aurora-admin-design",
"version": "1.4.1",
"description": "B 端中后台设计系统 · 79 组件 × 5 端 · 零运行时依赖",
"license": "MIT",
"main": "dist/tokens/tokens.css",
"files": ["dist/", "README.md", "LICENSE"],
"scripts": {
"build": "node tools/build-dist.mjs",
"test": "node tools/verify-dist.mjs"
},
"keywords": ["design-system", "admin", "css-variables", "design-tokens"],
"sideEffects": ["*.css"]
}
```
**注意:不声明任何 `dependencies`** —— 这是硬约束。
2. 写 `tools/build-dist.mjs`(Node ESM,零依赖),产出:
- `dist/tokens/tokens.css`、`tokens.json`(复用 `build-site.ps1` 的产出)
- `dist/components/<slug>.css` × 79 + `dist/components/index.css`(聚合)
- `dist/components/<slug>.html` × 79(静态演示)
- `dist/README.md`(用法速查,从主 README 节选)
- `dist/manifest.json`(组件清单 + 版本 + 文件校验和)
3. 写 `.npmignore` 排除 `site/`、`tests/`、`frameworks/*.jsx|vue*`、`.github/`、`*.png`。
4. 在 `README.md` 增加「安装」段,给出 npm / CDN / 直接下载三种方式。
**验收**:
```bash
# 1) 构建产物齐全
node tools/build-dist.mjs
test -f dist/tokens/tokens.css && echo "tokens OK"
test -f dist/components/index.css && echo "aggregate OK"
test $(ls dist/components/*.css | wc -l) -ge 80 && echo "79 components + index OK"
# 2) 无运行时依赖(硬约束)
node -e "const p=require('./package.json'); if(p.dependencies) { console.error('FAIL: 不允许 dependencies'); process.exit(1) } console.log('zero-dep OK')"
# 3) 分发内容不含开发资产
# 注意:不能用 `npm pack | grep -q site/ && echo FAIL || echo OK` —— npm 不可用时 grep 也失败,会误报 OK
if npm pack --dry-run >/tmp/pack.txt 2>&1; then
if grep -qE "site/|tests/" /tmp/pack.txt; then
echo "FAIL: 打包含开发资产"; grep -E "site/|tests/" /tmp/pack.txt | head -3; exit 1
fi
echo "pack contents OK"
else
echo "SKIP: npm 不可用(网络/未安装),此项需在有 npm 的环境补验"
fi
# 4) 产物可用(起本地服务,浏览器打开验证)
node -e "const fs=require('fs');const c=fs.readFileSync('dist/components/index.css','utf8');if(!c.includes('--au-color-brand'))process.exit(1);console.log('css usable OK')"
```
**预期输出**:
```
tokens OK
aggregate OK
79 components + index OK
zero-dep OK
pack contents OK
css usable OK
```
**失败判据**:
- `package.json` 出现任何 `dependencies`
- `npm pack --dry-run` 输出含 `site/` 或 `tests/`
- `dist/components/*.css` 少于 80 个
**已知风险**:`npm pack` 需要网络(首次可能要求登录)。若无网络,跳过第 3 条验收并在交付说明注明。
---
### S1-P3 · CI 回归流水线 | 预算 ~1.5 h | 优先级 P0
**目标**:每次 push/PR 自动跑回归,失败则阻止合并;结果可在 GitHub Actions 页面看到。
**依据**:G3。当前只有部署 workflow,回归靠人工手动跑 `_collect.html`,质量随提交退化不可见。
**依赖**:无(可与 P1/P2 并行)。
**路径**:
- `.github/workflows/regression.yml`(新建)
- `tools/run-regression.mjs`(**已存在**,需改造为无网可用)
**步骤**:
1. 现状:`tools/run-regression.mjs` 依赖 `playwright`(npm 包),与"零依赖"约束冲突。
**解法**:CI 里允许用 `npx playwright`(CI 环境的临时工具,不进 `package.json` 的 dependencies),或用 `devDependencies` + 在文档说明"CI 专用,运行时不依赖"。
**推荐**:把 playwright 放进 `devDependencies`(这是构建期工具,不违反"零运行时依赖")。
2. 写 workflow:
```yaml
name: Regression
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm i -D playwright && npx playwright install --with-deps chromium
- run: node site/dev-server.js &
- run: sleep 3
- run: node tools/run-regression.mjs
- uses: actions/upload-artifact@v4
if: always()
with: { name: regression-report, path: tests/report*.json }
```
3. `run-regression.mjs` 需改造:目前是纯 Node 脚本,要确保它在 Linux 下也能找到报告输出路径(Windows 路径分隔符问题)。
4. 增加失败阈值:`passRate < 100` 时 `process.exit(1)`。
**验收**:
```bash
# 本地模拟 CI 步骤
node site/dev-server.js & sleep 3
node tools/run-regression.mjs
echo "exit=$?"
# 期望 exit=0 且 passRate=100
```
推送后在 GitHub Actions 页面确认 workflow 跑绿(需用户操作)。
**预期输出**:
```
passRate 100% | pages 79 (all-pass 79) | assertions 925/925
written: tests/report.json, tests/report-junit.xml
exit=0
```
**失败判据**:
- workflow 文件语法错误(用 `actionlint` 或 GitHub 页面报错验证)
- 本地模拟跑出 `exit != 0`
- `passRate < 100` 时没有 `exit 1`
**已知风险**:`playwright install` 在 CI 上约需 1-2 分钟,可通过缓存加速(后续优化项)。
---
### S1-P4 · `data.js` 瘦身 | 预算 ~3 h | 优先级 P0
**目标**:`site/data.js` 从 **991 KB 降到 < 150 KB**(实测可达成 ~110 KB)。
**依据**:G6。实测 `data.js` = 1058 KB(传输量),占文档站总传输 **85%**。
**已完成的诊断(无需重做)**:
```
data.json 体积构成(实测)
总计: 991KB
components 974KB 98.3% ← 唯一大头
changelog 12KB 1.2%
tokens 5KB 0.5%
components[] 内部(单组件)
.sources 15.7KB ← 5 端源码全文
.contract 0.8KB
.specLines 0.2KB
.files 0.2KB
其余 <0.1KB
全部组件 .sources 合计: 888KB(占 data.json 的 89.6%)
```
**结论**:`sources` 字段(5 端源码全文,仅供详情页代码区展示)占了 **89.6%**。把它移出 `data.js` 改为按需 fetch,`data.js` 降到 **~110 KB**(−89%)。
**依赖**:无。
**路径**:
- `build-site.ps1`(改造产出:分文件写源码)
- `site/app.js`(改造消费:按需 fetch + loading 态)
- `site/sources/<slug>/<kind>.txt`(新增产出目录,79 × 5 = 395 个文件)
- `site/data.js` / `site/data.json`(产出物,不手改)
**步骤**:
1. **改造 `build-site.ps1`**:
- 新增:把每个组件的 5 端源码写到 `site/sources/<slug>/<kind>.txt`(kind ∈ html/css/jsx/vue2/vue3)
- 修改:`data.js` 里 `components[].sources` 改为 `sourcesRef: "sources/<slug>/"`(只留路径,不留内容)
- **保持 `data.json` 完整**(For Agents 页承诺"一次请求拿到全部",不能破坏 —— 这是硬约束)
2. **改造 `app.js`(见下方「已完成的依赖分析」)**
3. **验证 For Agents 承诺未破**:`data.json` 仍然包含完整 `sources`。
##### 已完成的依赖分析(执行前必读)
`app.js` 里有 **10 处**消费 `c.sources`,分三类,改造难度不同:
**类别 A · 渲染期同步解析(难点,2 处)**
| 位置 | 函数 | 用途 |
|---|---|---|
| `app.js:969-971` | `extractComponentAPI(c)` | 从 vue3/vue2/jsx 源码正则提取 Props/Events/Slots |
| `app.js:1544` | `extractScenarios(c)` | 从 html 源码提取 `<h2>` 场景标题 |
这两个函数**在渲染详情页时同步调用**,依赖源码字符串立即可用。改成 fetch 后必须处理异步。
**推荐解法**:把「源码解析」的产物**预计算进 data.js**,而不是运行时 fetch 后再解析。
- `build-site.ps1` 已经能读源码 → 顺手把 `extractComponentAPI` / `extractScenarios` 的**结果**写进 `data.js`
- `app.js` 改为直接读预计算结果,**这两个函数不再需要源码**
- 源码 fetch 只服务「代码展示」这一处需求
**体积成本已实测**(规划阶段验证过):
```
API 表(79 组件) : 0.2 KB
场景标题(79 组件) : 0.9 KB
合计新增 : 1.0 KB
sources 移除后节省 : 888 KB
净减少 : 887 KB
```
预计算产物只占 **1 KB**(原估 < 30KB,实测乐观 30 倍),代价可忽略。
这样做的好处:① 消除两处异步改造;② 解析逻辑从浏览器移到构建期(更快);③ 详情页首屏不再等源码下载。
**类别 B · 代码展示(3 处,易改)**
| 位置 | 用途 |
|---|---|
| `app.js:1635` | Playground textarea 初值 |
| `app.js:1667` | Playground 复位 |
| `app.js:1714/1722` | 代码区高亮渲染 |
改法:进详情页时 `Promise.all` 拉当前组件 5 个源码文件(或按需拉 tab 切换的那一个),拿到后填充。加 loading 占位。
**类别 C · 判断可用性(2 处,用元数据替代)**
| 位置 | 用途 |
|---|---|
| `app.js:1703-1704` | 判断哪些端有源码(决定 tab 显示) |
| `app.js:1720` | 复制按钮取当前 tab 源码 |
改法:`data.js` 保留一个轻量字段 `sourcesAvailable: ["html","css","jsx","vue2","vue3"]`(79 × 5 个字符串,< 5KB),替代 `sources[k] != null` 的判断。复制按钮改为从已缓存的 fetch 结果取。
##### 分阶段执行建议
1. **阶段 1**:`build-site.ps1` 预计算 API/场景 → 写入 `data.js`;`app.js` 改读预计算结果。此时 `sources` 仍完整(先不瘦身),跑回归确认无回退。
2. **阶段 2**:`build-site.ps1` 分离源码到文件 + `data.js` 只留 `sourcesRef` 与 `sourcesAvailable`;`app.js` 改 fetch。
3. **阶段 3**:跑验收 + 浏览器实测(含断网兜底)。
**验收**:
```bash
# 1) 体积达标(实测应约 110KB)
node -e "
const fs=require('fs');
const core=fs.statSync('site/data.js').size;
console.log('data.js:', (core/1024).toFixed(0)+'KB');
if(core/1024 > 150) { console.error('FAIL: 超过 150KB 预算'); process.exit(1) }
console.log('budget OK');
"
# 2) 源码文件已分离(395 个)
# 注意:目录未创建时 ls 会报错到 stderr,这里显式兜底,让输出可读
n=$(ls site/sources/*/*.txt 2>/dev/null | wc -l)
echo "sources files: $n (期望 395)"
if [ "$n" -ne 395 ]; then
echo "FAIL: 期望 395 个源码文件,实际 $n"
echo " 提示:若目录不存在,说明 build-site.ps1 的分离逻辑未执行"
exit 1
fi
echo "split OK"
# 3) data.json 未缩水(For Agents 承诺不变 —— 硬约束)
node -e "
const d=require('./site/data.json');
const c=d.components.find(x=>x.slug==='button');
if(!c.sources||Object.keys(c.sources).length!==5) { console.error('FAIL: data.json 的 sources 被破坏'); process.exit(1) }
console.log('data.json intact OK');
"
# 4) data.js 里已无源码正文
node -e "
const d=require('./site/data.js')||{};
" 2>/dev/null || node -e "
const fs=require('fs');
const s=fs.readFileSync('site/data.js','utf8');
// 源码正文特征:不应再出现完整 HTML 文档
if(s.includes('<!DOCTYPE html>')) { console.error('FAIL: data.js 仍含源码正文'); process.exit(1) }
console.log('sources removed OK');
"
```
浏览器实测:
- 打开 `#/component/button`,代码演示区正常显示
- Network 面板出现 `sources/button/html.txt` 请求
- 断网/404 情况下显示兜底提示而非空白
**预期输出**:
```
data.js: ~110KB
budget OK
sources files: 395
split OK
data.json intact OK
sources removed OK
```
**失败判据**:
- `data.js` > 150 KB
- `site/sources/` 文件数 ≠ 395
- **`data.json` 的 `sources` 字段被动过**(会破坏 For Agents 承诺)
- 详情页代码区空白或报错
**为什么不直接压缩**:gzip 能压到 ~200KB,但**解析时间**与**内存占用**仍在(1MB JSON 在低端机解析约 100-200ms)。且 Pages 默认已开 gzip,压缩不是增量收益。根治要减体积。
---
### S1-P4b · 首屏资源优化 | 预算 ~2 h | 优先级 P1
**目标**:文档站首屏传输从 1247 KB 降到 **< 300 KB**。
**依据**:P4 完成后 `data.js` ~110KB,但 `app.js` 101KB + `style.css` 40KB 仍是未压缩文本。
**依赖**:S1-P4。
**步骤**:
1. `app.js`(101KB 单文件)按路由拆分:首页逻辑与详情页逻辑分离,详情页按需加载。
2. 关键 CSS 内联(首屏可见部分),其余异步加载。
3. 加入 `build-site.ps1` 的产出:`.min.js` / `.min.css`(用 Node 内置能力做简单压缩:去注释、去多余空白)。
**验收**:
```bash
node -e "
const fs=require('fs');
const files=['site/data.js','site/app.js','site/style.css','site/i18n.js','.design_library/aurora-admin/colors_and_type.css'];
const total=files.reduce((s,f)=>s+fs.statSync(f).size,0);
console.log('首屏资源合计:', (total/1024).toFixed(0)+'KB');
if(total/1024>300){console.error('FAIL: 超过 300KB');process.exit(1)}
console.log('payload OK');
"
```
---
### S2-P5 · 暗色模式真正实现 | 预算 ~1 天 | 优先级 P0
**目标**:`html.aa-dark` 下,**79 个组件的演示页**全部正常反色,对比度仍满足 WCAG AA。
**依据**:G4。实测令牌层 `aa-dark` 规则 **0 条**、组件层 **0 条**,只有站点骨架 7 条。`CHANGELOG.md` 的 v1.1.1 条目称"暗色模式令牌映射补全"—— 这是第 6 次声称≠实现。
**依赖**:S1-P4(体积优化后改 `app.js` 更清爽,非硬依赖)。
**路径**:
- `.design_library/aurora-admin/colors_and_type.css`(加暗色令牌组)
- `site/style.css`(清理原有的 7 条临时规则)
- `frameworks/*.html` 的内嵌样式(若需微调)
- `tests/_runtime.js`(增加暗色断言)
**步骤**:
1. **设计暗色令牌组**(在 `colors_and_type.css` 里加 `html.aa-dark` 块):
- 背景层:`page-bg` `#14161C` → `card-bg` `#1C1F26` → `table-header-bg` `#22262E`(三层递进)
- 文字层:`text-title` `#E8EAED` → `text-body` `#C9CDD4` → `text-secondary` `#9CA3AF` → `text-placeholder` `#6B7280`
- 边框:`border` `#2A2F38`、`border-strong` `#363B45`
- 品牌色:**向白提亮**(`#2F54EB` 在深底上对比度不足),推荐 `#5B7CF5` 系列
- 语义色:同样提亮(`#2E7D0A` → `#4CAF50` 一类)
2. **每个色值都要算对比度**,写脚本验证(复用 v1.3.1 的方法):
```bash
node -e "
// 对每个暗色令牌算 WCAG 对比度,全部 ≥4.5:1(文字)或 ≥3:1(图标)
"
```
3. **演示页反色策略**:v1.4.0 的注释说"演示 iframe 保持浅色,避免样例反色失真"。这条策略要么:
- **A**:改成可配置 —— 站点暗色时演示页也反色(更真实,但要确保反色后不难看)
- **B**:保持浅色,但在设计规范页显式说明这是**有意设计**
**推荐 A**,因为用户开暗色就是想整体变暗,局部刺眼是体验倒退。若选 A,需给演示页传 `?theme=dark` 或用 `postMessage` 通知。
4. **加断言**:`_runtime.js` 增加 `matrix:dark-contrast`,在暗色令牌下重跑对比度检查。
**验收**:
```bash
# 1) 令牌组存在且完整
grep -q "html.aa-dark" .design_library/aurora-admin/colors_and_type.css && echo "dark tokens OK"
node -e "
const css=require('fs').readFileSync('.design_library/aurora-admin/colors_and_type.css','utf8');
const m=css.match(/html\.aa-dark\s*\{([^}]+)\}/s);
if(!m){console.error('FAIL: 无暗色令牌组');process.exit(1)}
const n=(m[1].match(/--au-/g)||[]).length;
console.log('暗色令牌数:', n);
if(n<15){console.error('FAIL: 令牌数不足(预期 ≥15)');process.exit(1)}
"
# 2) 浏览器实测(关键验收)
# 打开 http://127.0.0.1:3311/site/index.html,切暗色模式,
# 逐个打开至少 10 个组件详情页,确认无「白底黑字残留」
```
浏览器实测项:
- 首页 / 总览 / 设计规范 / 组件详情 全部正常反色
- 任意 10 个组件演示页反色后**对比度可读**
- 截图对比(交付说明附 3 张暗色截图)
**预期输出**:
```
dark tokens OK
暗色令牌数: 20+(预期 ≥15)
```
**失败判据**:
- 暗色令牌数 < 15
- 任一页面出现"白底 + 白字"或"黑底 + 黑字"
- 对比度脚本报出 < 4.5:1 的文字
**已知风险**:79 个演示页的内嵌样式是**硬编码过令牌化**的(v1.4.0 完成),所以理论上改令牌就能全局生效 —— 这是 v1.4.0 打下的地基,本次直接受益。
---
### S2-P6 · 跨端一致性自动验证 | 预算 ~1 天 | 优先级 P0
**目标**:能自动回答「H5 / React / Vue2 / Vue3 四个实现是否视觉一致」,并给出差异截图。
**依据**:G5。5 端 395 个文件,但**从来没人验证过它们是否真的一致**。契约里写的"各端视觉一致"是纯声称。
**依赖**:S1-P3(需要 CI 环境跑 Playwright)。
**路径**:
- `tools/verify-cross-platform.mjs`(新建)
- `tools/render-harness/`(新建,把 React/Vue 组件渲染成静态 HTML)
- `tests/cross-platform-report.json`(产出)
**步骤**:
1. **难点**:React/Vue 组件需要构建才能渲染(.jsx/.vue 不能直接在浏览器跑)。
**零依赖解法**:
- 方案 A:用 CDN 版 React/Vue(`<script src="unpkg.com/react">`)+ `@babel/standalone` 在浏览器里编译 JSX。缺点:依赖 CDN 可用性。
- 方案 B:**更推荐** —— 只做**结构性比对**而非像素比对。提取各端的 `className` 集合与 DOM 结构,比对差异。不要求渲染,纯静态分析。
- 方案 C:混合 —— 结构比对为主,挑选 6 个核心组件做像素比对(核心组件的 CDN 依赖可接受)。
2. **推荐方案 B + 抽样 C**:
- 全部 79 组件:静态提取 class 集合与结构骨架,diff 各端
- 6 个核心组件(button/input/select/table/card/modal):CDN 渲染 + 截图比对
3. 输出报告:`{ slug, platforms: {h5:[...classes], react:[...], vue2:[...], vue3:[...]}, diffs:[...], severity }`
**验收**:
```bash
node tools/verify-cross-platform.mjs
node -e "
const r=require('./tests/cross-platform-report.json');
console.log('检查组件:', r.total);
console.log('完全一致:', r.identical);
console.log('有差异 :', r.differing);
console.log('差异样本:', JSON.stringify(r.samples.slice(0,3),null,1));
"
```
**预期输出**:一份报告,明确列出哪些组件的哪些端存在 class/结构差异。
**失败判据**:
- 脚本报错或无输出
- 报告里 `total < 79`
- 差异项没有具体说明(只说"不一致"而不给差异内容)
**重要说明**:**这个任务的产出可能揭露一批真实的不一致**。这不是失败 —— 是这项任务的价值。发现的差异应作为新任务包列出,不在本任务内顺手修(避免范围蔓延)。
**✅ 完成(方案 B:静态结构比对,零依赖零联网)** — 验收输出:
```
检查组件: 79
完全一致: 2
有差异 : 77 (high 44 / medium 22 / low 11)
written: tests/cross-platform-report.json
```
改动文件:`tools/verify-cross-platform.mjs`(新建,class 集合 + 结构骨架双 diff,演示包装类/变量名/模板残留降噪,high/medium/low 分级)→ `tests/cross-platform-report.json`(产出,79 条全量 + samples 3)。
回归:`tests/report.json` 79/79 未动,`site/data.json` 79 组件未动(只读消费)。
发现的新问题 → 已追加为 S2-P6-F1~F4(见下方),不在本任务内修。
### S2-P6-F1 · React 端缺失 `is-disabled` 等状态类(5 组件) | 预算 ~2 h | 优先级 P1
**目标**:`is-disabled`(5x)、`is-active`(3x)在 React 端补齐,与三端共识对齐。
**依据**:`tests/cross-platform-report.json` 的 `missing-consensus` 聚合。React 端多用 `disabled` 属性而非状态类,需确认是「有意用属性替代」还是「遗漏」——若有意,需在契约注明;若遗漏,补类。
**验收**:重跑 `node tools/verify-cross-platform.mjs`,`is-disabled/is-active miss:react` 条数归零或有契约说明。
### S2-P6-F2 · H5 演示页缺失框架端结构类 | 预算 ~2 h | 优先级 P2
**目标**:`col-selection/right/col-fixed/action`(table 系)、`ico/horizontal` 等「三框架端有、H5 演示页缺」的类,核对 H5 演示是否漏了对应变体展示。
**依据**:同上报告。H5 是静态演示页,可能只是没展示该变体(非 bug);但若是变体缺失展示,补演示片段即可。
**验收**:逐项标注「演示缺展示(补)」或「框架端多余(不动)」,`miss:h5` 的 high 条数下降或全部有结论。
### S2-P6-F3 · React 端 Tag/Select/Input 变体类缺失 | 预算 ~2 h | 优先级 P1
**目标**:`aa-tag-dot/aa-tag-custom`、`au-input-lg/sm`、`aa-select-empty` 等 React 端缺失的变体类,核对是未实现该变体还是类名拼写差异。
**依据**:同上报告(input 的 `au-input-lg/sm` 在本轮提取器修复后已证明是「追踪不到」而非「真缺失」的前车之鉴——先复核再修)。
**验收**:逐项复核,有真缺失则补实现;误报则修提取器。
### S2-P6-F4 · P6 报告纳入 CI 门禁 | 预算 ~30 min | 优先级 P2
**目标**:`regression.yml` 追加一步 `node tools/verify-cross-platform.mjs`,`total < 79` 或脚本非零退出时标红(high 差异只告警不阻塞,避免把历史差异变成合并 blocker)。
**依赖**:S1-P3(CI 已存在)。
**验收**:workflow 文件含该步骤且语法正确。
---
### S2-P7 · 行为断言 | 预算 ~1.5 天 | 优先级 P1
**目标**:测试从"元素存在"升级到"交互后发生什么",覆盖点击/输入/键盘的真实行为。
**依据**:G8。当前 12 项/页断言多为结构性(元素存在、有 aria、对比度达标),**没有任何一条验证"点了按钮会怎样"**。
**依赖**:无。
**路径**:
- `tests/_runtime.js`(扩展断言引擎)
- `tests/_behaviors.js`(新建,行为断言库)
**步骤**:
1. 定义行为断言协议(在演示页里声明):
```html
<button data-behavior="click-toggles-class:.aa-modal|is-open">打开弹窗</button>
```
2. 实现常见行为模式:
- `click-toggles-class:<selector>|<class>` — 点击切换类
- `click-sets-attr:<selector>|<attr>|<value>` — 点击设属性
- `input-updates:<selector>|<text>` — 输入后状态变化
- `keyboard-activates:<key>` — 键盘触发
- `focus-trap:<container>` — 弹窗焦点锁定
3. 在 6 个核心组件(button/modal/select/input/table/tabs)的演示页里标注行为断言作为试点。
4. 断言结果并入现有报告结构(`matrix:behavior:*`)。
**验收**:
```bash
# 1) 行为断言库存在且语法正确
node --check tests/_behaviors.js && echo "syntax OK"
# 2) 6 个试点组件有行为断言
grep -l "data-behavior" frameworks/{Button,Modal,Select,Input,Table,Tabs}.html | wc -l
# 期望输出 6
# 3) 回归里出现行为断言
# 跑 _collect.html,检查 report.json 的 failureKinds 含 matrix:behavior:*
```
浏览器实测:点击弹窗按钮后,`is-open` 类被添加(观察 DOM)。
**✅ 完成(6 试点全绿)** — 验收输出:
```
button/modal/select/input/table/tabs 行为断言各 1 条,全部 PASS
全量回归:passRate 100% | pages 79 (all-pass 79) | assertions 1009/1009 | N/A 35
```
改动文件:`tests/_behaviors.js`(新建,8 动词 + 6 试点白名单 + 同步 pump + page-load 幂等缓存)、`tests/_runtime.js`(聚合行为断言 + 重载清缓存)、`tests/_template.html`(引入行为库)、6 演示页 `data-behavior` 标注、79 测试页重生成。
关键修复:回归 runner 的兜底重跑导致 `run()` 执行两次,行为断言第二轮误报——加 page-load 缓存解决(重载演示页后重测)。
规划偏差:试点 6 组件的 `data-behavior` 标注里,button 是纯静态页,为测而加了一个最小加载态切换交互(不破坏视觉)。
**预期输出**:
```
syntax OK
6
```
**失败判据**:
- 试点组件少于 6 个
- 行为断言在回归报告里不出现
- 断言只是"元素存在"换个名字(无实际交互逻辑)
---
### S3-P8 · RTL 支持 | 预算 ~2 天 | 优先级 P1
**目标**:`<html dir="rtl">` 时布局正确镜像,无错位。
**依据**:G7。逻辑属性 **0** 处,物理属性(`margin-left` 等)出现在 **22** 个文件。竞品 7 家里 3 家有 RTL。
**依赖**:S2-P5(暗色完成后改样式更安全,减少冲突)。
**路径**:
- `frameworks/*.css`(22 个含物理属性的文件)
- `frameworks/*.html` 内嵌样式
- `.design_library/aurora-admin/colors_and_type.css`(如需要在文档说明约定)
**步骤**:
1. **批量迁移物理→逻辑属性**:
| 物理 | 逻辑 |
|---|---|
| `margin-left` | `margin-inline-start` |
| `margin-right` | `margin-inline-end` |
| `padding-left/right` | `padding-inline-start/end` |
| `left` / `right`(定位) | `inset-inline-start/end` |
| `text-align: left/right` | `text-align: start/end` |
| `border-left/right` | `border-inline-start/end` |
2. **注意例外**:图标方向类(箭头、返回)需要 `transform: scaleX(-1)` 而非属性迁移。
3. **写一个 RTL 演示页**:`site/scenario/user-management-rtl.html`,用于人工验收。
4. 增加 RTL 断言:`matrix:rtl-safe`,检测是否还有物理属性的残留。
**验收**:
```bash
# 1) 物理属性清零
n=$(grep -l "margin-left\|margin-right\|padding-left\|padding-right" frameworks/*.css 2>/dev/null | wc -l)
echo "剩余物理属性文件: $n"
test "$n" -eq 0 && echo "RTL migration OK"
# 2) 逻辑属性已使用
grep -l "margin-inline\|padding-inline\|inset-inline" frameworks/*.css | wc -l
# 期望 ≥ 22
```
浏览器实测:`user-management-rtl.html` 加 `dir="rtl"`,确认布局镜像无错位(附截图)。
**预期输出**:
```
剩余物理属性文件: 0
RTL migration OK
22+
```
**失败判据**:
- 仍有物理属性残留
- RTL 下出现元素重叠/溢出
- 图标方向错误(如右箭头在 RTL 下仍指右)
**✅ 完成(28 文件迁移 + 14 处人工例外)** — 验收输出:
```
扫描 CSS: 79 个 / 可迁移: 28 个(已写入)
剩余物理属性文件: 0(口径:排除 margin-left:auto 与拼接边框例外,见下)
逻辑属性文件: 19
RTL 实测:button/table/SideMenu 三页 LTR/RTL 均零溢出,0 JS 错误
全量回归:passRate 100% | pages 79 (all-pass 79) | assertions 1009/1009(与 P7 同轮验证)
```
改动文件:`tools/migrate-rtl.mjs`(新建,白名单 dry-run/--write 双模式)、28 个 `frameworks/*.css`(margin/padding/border-inline + text-align start/end)。
人工例外 14 处(脚本跳过并报告):`margin-left:auto` flex 推送(3 处)、按钮组拼接边框(5 处)、`left:0+right:0` 并存居中(4 处)——语义不等价,不机械替换。
规划偏差:验收命令的 `grep -l "margin-left..."` 会把上述例外计入,实际口径为“排除例外后清零”;`user-management-rtl.html` 演示页未建(场景页模板属 P11 范畴),以三代表页实测代替。
---
### S3-P9 · FAQ 页 | 预算 ~1 天 | 优先级 P2
**目标**:新增 `#/faq` 页,自动聚合 139 条 `unknowns` + 101 条 `doNotInvent`,形成可检索的问答。
**依据**:契约里已有 240 条结构化条目,**现成素材没被利用**。Ant Design 每组件 FAQ 是行业惯例。
**依赖**:无。
**路径**:
- `site/app.js`(新增 `renderFaq`)
- `site/index.html`(导航加 FAQ 链接)
- `site/i18n.js`(文案)
**步骤**:
1. `build-site.ps1` 已把 contract 注入 `data.js`(字段 `unknowns` / `doNot`),直接消费即可。
2. 渲染两种视图:
- **按组件**:每个组件列出它的 unknowns("规范未明示")与 doNotInvent("不要自行发明")
- **按分类**:把相似的 unknowns 聚类(如"最大宽度""省略方式"跨多个组件出现)
3. 加搜索过滤(复用 `_runtime` 的思路,纯前端)。
**验收**:
```bash
# 1) 路由可达
curl -s http://127.0.0.1:3311/site/index.html | grep -q 'href="#/faq"' && echo "nav OK"
# 2) 数据完整注入
node -e "
const d=require('./site/data.json');
const u=d.components.reduce((s,c)=>s+((c.contract&&c.contract.unknowns)||[]).length,0);
const dn=d.components.reduce((s,c)=>s+((c.contract&&c.contract.doNot)||[]).length,0);
console.log('unknowns:',u,'doNotInvent:',dn);
if(u<139||dn<101){console.error('FAIL: 契约数据缺失');process.exit(1)}
console.log('data OK');
"
```
浏览器实测:`#/faq` 显示 79 个组件的条目,搜索"宽度"能过滤出相关项。
**预期输出**:
```
nav OK
unknowns: 139 doNotInvent: 101
data OK
```
**失败判据**:条目数少于 139/101,或页面空白。
**✅ 完成(details 懒加载版)** — 验收输出:
```
title: 常见问题 / groups: 80 / items: 240
stat: 共 240 条,79 个组件有条目
search 宽度 -> items: 11 / groups: 11(stat: 命中 11 / 240 条,10 / 79 个组件)
restored: 240 / topnav faq: present / jserrors: none
FAQ BROWSER OK
```
改动文件:`site/app.js`(renderFaq + `#/faq` 路由 + 侧边栏入口)、`site/index.html`(顶栏入口)、`site/style.css`(guide-h3)、`site/i18n.js`(9 条英文)。
规划偏差:契约已在 P4 阶段 D 移出 `data.js`(`site/data.js` 含 unknowns 0 条),故 FAQ 改走 `details/*.json` 批量懒加载(每批 10 个)而非规划写的“直接消费 data.js”。`data.json` 的 139/101 计数仍作为数据源完整性断言。
---
### S4-P10 · Figma 资源 | 预算 ~2 天 | 优先级 P2
**目标**:产出可导入 Figma 的变量集与组件描述,设计师能直接用同一套令牌。
**依据**:竞品标配 Figma/Sketch 资源。本项目已有 `site/tokens/figma.json`(Tokens Studio 格式),但**没有 Figma Variables 原生格式**。
**依赖**:S1-P2(需稳定的令牌导出管线)。
**路径**:
- `tools/export-figma.mjs`(新建)
- `dist/figma/`(产出)
**步骤**:
1. 产出 **Figma Variables JSON**(与 Tokens Studio 格式不同,是 Figma 原生 API 格式):
- 色彩变量 → `{ "color": { "brand": { "type": "COLOR", "value": {...} } } }`
- 数值变量(间距/圆角/字号)→ `FLOAT`
- 建立 Light / Dark **两种 mode**(呼应 S2-P5)
2. 产出组件清单 Markdown(供设计师建组件时参考):每个组件的变体维度 + 尺寸 + 状态。
3. 写导入说明(`dist/figma/README.md`)。
**验收**:
```bash
node tools/export-figma.mjs
node -e "
const v=require('./dist/figma/variables.json');
const colors=Object.keys(v.color||{}).length;
console.log('色彩变量:', colors);
console.log('模式:', Object.keys(v.modes||{}).join(', '));
if(!v.modes||!v.modes.Dark){console.error('FAIL: 缺少 Dark 模式');process.exit(1)}
console.log('figma export OK');
"
```
**预期输出**:
```
色彩变量: 24+
模式: Light, Dark
figma export OK
```
**失败判据**:无 Dark 模式、变量数明显少于令牌数、JSON 不符合 Figma Variables 结构。
---
### S4-P11 · 模板页库 | 预算 ~2 天 | 优先级 P2
**目标**:从 1 个场景页扩展到 5 个典型后台页面模板,展示组件组合用法。
**依据**:现有 `site/scenario/user-management.html` 是唯一的组合示范。模板页是"能否直接用"的关键 —— 用户要的不是组件,是页面。
**依赖**:无。
**路径**:`site/scenario/*.html`(新增 4 个)
**步骤**:
1. 选定 4 个典型场景(覆盖不同组件组合):
- `login.html` — 登录页(输入类组件 + 表单校验)
- `dashboard.html` — 数据看板(图表 + 指标卡 + 表格)
- `order-list.html` — 列表管理(表格 + 筛选 + 分页 + 批量操作)
- `settings.html` — 设置页(Tab + 表单 + 开关组)
2. 每个模板页只用现有令牌与 `components.css`,纯 HTML + 原生 JS(零依赖)。
3. 加到首页入口与 sitemap。
**验收**:每个模板页在浏览器实测可交互(筛选、分页、提交有反馈),附截图。
**失败判据**:页面白屏、交互无效、用了非项目内的样式。
---
### S4-P12 · 版本发布流程 | 预算 ~1 天 | 优先级 P3
**目标**:有明确的 SemVer 发布流程与自动化。
**依赖**:S1-P2。
**步骤**:
1. `tools/release.mjs`:从 CHANGELOG 提取版本 → 更新 `package.json` → 打 tag → 提示推送。
2. 文档化到 `CONTRIBUTING.md`。
**✅ 完成** — 验收输出:
```
package.json: 1.4.1 / CHANGELOG 最新: [1.4.1] 2026-09-11
OK: 版本一致
NOTE: [Unreleased] 段有 1251 字符未发布变更,发版前确认是否纳入本次
OK: build-dist 可调用
```
改动文件:`tools/release.mjs`(新建,检查模式 + `--bump major|minor|patch --date` 提升模式,只做本地准备不自动 push/tag)、`CONTRIBUTING.md`(发布流程 5 步 + 版本号规则)。
规划偏差:原步骤写“打 tag → 提示推送”由脚本做,实际拆为脚本只做本地准备、tag/push 由人按输出清单执行(不可逆的远端动作不自动化)。
---
### S6-P21 · 组件族参数化(同源组件收敛为「1 基座 + N 参数」)| 预算 ~2 天 | 优先级 P1
**目标**:把"同一交互/结构各自手写一遍"的组件收敛为「1 个基座组件 + N 个参数取值」,消除重复身份,同时**不改变组件身份(slug)、不减少 `data.json` 的组件数**。
**依赖**:无(纯新增层,不动既有对外承诺)。
**背景(实测)**:79 个组件里有 44 个能按语义归入 13 个族。判据不是名字相似,而是契约里可核对的四类字段:`semanticTypeCandidates` 重叠、`anatomy` 为同一骨架的子集、变体维度同构、以及 `doNotInvent` 里的显式从属声明 —— 例如 `alertmodal` 与 `confirmmodal` 的 `doNotInvent` 原文写着「弹窗尺寸档位(见 Modal 契约)」,`steps` 与 `steplist` 的 `semanticTypeCandidates` 完全相同(均为 `steps|wizard`)。
**硬约束(决定了实现形态)**:
- `tools/pack-deploy.mjs:137-139` 硬断言 `site/components` 薄壳数 === 79、`frameworks` 实现文件数 === 395;
- `tools/precompute.mjs:38-39` 硬断言 `COMPONENT_COUNT = 79` / `SOURCE_FILE_COUNT = 395`;
- `tools/verify-cross-platform.mjs:695`、`tools/verify-package-import.mjs` 断言 79。
因此「新增族内核文件」与「删除变体文件」两条路都不可行。实现层合并只能走**一份参数化模板 → 生成 N 组自包含产物**(与 `tests/_template.html → tests/<slug>.html × 79` 同一套哲学)。
**步骤**:
1. `tools/lib/family-model.mjs`:13 族 / 44 成员的唯一真源;每族必写 `mergeBasis`(实测依据)与 `paramSurface`(参数名/类型/取值/默认值)。
2. `tools/gen-families.mjs`:生成 `families.json`;对 44 份契约做**定点注入**(只在 `"slug"` 行后插 `family`/`familyRole`/`familyParams`,不重排 JSON、不覆盖他人未提交改动)。
3. `build-site.ps1` + `tools/precompute.mjs`:把族层输出到 `data.json`(顶层 `families` + 每组件 `family` 三元组)、`data.js`、`site/details/<slug>.json`。
4. `tools/lib/family-impl/nav-menu/*.tpl` + `tools/gen-family-impl.mjs`:族实现生成器(带"不覆盖非生成物的脏文件"护栏)。
5. `tools/verify-families.mjs`:端到端验证(模型 ↔ 契约 ↔ data.json ↔ details ↔ 395/79 硬约束)。
**✅ 完成** — 验收输出(原样粘贴):
```
$ node tools/gen-families.mjs --dry-run
[dry-run] 族 13 / 登记成员 44 / 契约改动 44 / 已最新 0
独立组件(不属任何族):35 个 — button select tag breadcrumb tree dropdown popconfirm segmented transfer rate slider collapse …
OK: 族层数据一致
$ npm run build:site
families: 13 families, 44 member components
family layer: 13 families, 44/79 components carry family metadata
thin shells: 79, platform shells: 316, sitemap.xml: 396 urls
all components complete (5-form files + category)
[precompute] 完整性校验:79/79 个组件,395/395 个源文件
[precompute] 数据.js: 1147 KB → 122 KB
$ node tools/verify-families.mjs
族 13 个(其中已参数化实现 1 个)
族成员 44 个组件
独立组件 35 个
概念组件数 13(族)+ 35(独立)= 48 个,替代原本 79 个并列组件
契约注入 44/44
frameworks 395 文件(79 x 5,未增未删)
测试页 79 薄壳
· nav-menu 3 成员 → 1 基座(净减 2)
· table 6 成员 → 1 基座(净减 5)
· masked-input 7 成员 → 1 基座(净减 6)
· modal-shell 5 成员 → 1 基座(净减 4)
· preference-switcher 3 成员 → 1 基座(净减 2)
· card-shell 4 成员 → 1 基座(净减 3)
· feedback-page 3 成员 → 1 基座(净减 2)
· loading-state 3 成员 → 1 基座(净减 2)
· steps / tabs / notice / selection-card / combobox 各 2 成员 → 1 基座(各净减 1)
details 携带族字段:44/44
OK: 族层端到端一致(13 族 / 44 成员 / 79 组件不变 / 395 文件不变)
概念组件:79 → 48(合并掉 31 个重复身份)
$ node tools/gen-family-impl.mjs --only=nav-menu
[write] 族 nav-menu:写入 15 / 已最新 0 / 跳过 0
OK: 族实现与模板一致
$ md5sum frameworks/TopMenu.css frameworks/SideMenu.css frameworks/MixedNavigation.css
9f98c53aa3b2449ecc1fc42e34635129 *frameworks/TopMenu.css
9f98c53aa3b2449ecc1fc42e34635129 *frameworks/SideMenu.css
9f98c53aa3b2449ecc1fc42e34635129 *frameworks/MixedNavigation.css
# 三份逐字节相同 = 一份样式表服务三个组件(差异只在根元素的 data-direction 参数)
$ node tools/verify-cross-platform.mjs
检查组件: 79
完全一致: 79
有差异 : 0 (high 0 / medium 0 / low 0)
# 基线与口径(两个数不能混为一谈,否则会把自己的改动说大成整体改善):
# 已提交 HEAD(tests/cross-platform-report.json) identical 2 / differing 77 / high 44
# 本任务改动前的工作区 identical 79 / differing 0
# 本任务改造后 identical 79 / differing 0(持平)
# 改造中途曾出现 76/79:族模板最初把方向写成对象字面量 { direction: 'side' },Vue 端
# class 提取器会把其中的字符串值收作变体记号,H5/JSX 端不会。探针实验确认后用独立常量
# FAMILY_DIRECTION = 'side' 承载方向,四端恢复 79/79 —— 是改代码对齐既有约定,
# 不是放宽校验脚本。
$ node tools/run-regression.mjs
passRate 100% | pages 79 (all-pass 79) | assertions 1017/1017 | N/A 34
[OK] 全部通过
# 导航族逐页实测(playwright 打开 tests/<slug>.html,点「运行断言」后读帧内真实 DOM)
[topmenu] 总数 13 | 通过 13 | 失败 0 | 跳过 0
帧内: 3 个 .aa-menu / direction=[top,top,top] / 菜单项 30 / role+tabindex 齐备=true / JS 错误: 无
[sidemenu] 总数 13 | 通过 13 | 失败 0 | 跳过 0
帧内: 3 个 .aa-menu / direction=[side,side,side] / 菜单项 30 / role+tabindex 齐备=true / JS 错误: 无
[mixednavigation] 总数 13 | 通过 13 | 失败 0 | 跳过 0
帧内: 3 个 .aa-menu / direction=[mixed,mixed,mixed] / 菜单项 22 / role+tabindex 齐备=true / JS 错误: 无
# mixednavigation 菜单项少 8 个是因为 mixed 的侧栏只渲染当前一级的 children(22 = 一级 5 + 二级 3 + 案例 2/3 各 7)
$ node -e "...零依赖验收(AGENTS.md 铁律 1 原文脚本)"
zero-dep OK
```
**改动文件**:
- `.design_library/aurora-admin/families.json` — 新建,族模型快照(25 202 bytes,build-site 消费)
- `.design_library/aurora-admin/components/*.json` — 44 份各 +3 行(`family`/`familyRole`/`familyParams`),其余字节不变
- `tools/lib/family-model.mjs` — 新建,13 族真源(含 mergeBasis 与 paramSurface)
- `tools/gen-families.mjs` — 新建,契约层生成器(`--dry-run` / `--check` / 幂等)
- `tools/lib/family-impl/nav-menu/menu.{html,css,jsx,vue2,vue3}.tpl` — 新建,导航族 5 端参数化模板
- `tools/gen-family-impl.mjs` — 新建,实现层生成器(脏文件护栏 + `--check`)
- `tools/verify-families.mjs` — 新建,族层端到端验证
- `build-site.ps1` — 读 families.json;`data.json` 增顶层 `families` 与每组件族字段(`families` 以原始 JSON 文本直插,避开 PS 5.1 的 PSCustomObject 序列化与空数组展开两个陷阱;仍为 ASCII-only)
- `tools/precompute.mjs` — `site/details/<slug>.json` 增 `family`/`familyRole`/`familyParams`
- `frameworks/{TopMenu,SideMenu,MixedNavigation}.{html,css,jsx,vue2.vue,vue3.vue}` — 15 个文件改为族模板生成物(三份 CSS md5 相同:一份样式表服务三个组件)
**规划偏差**:
- 原设想「抽一个共享 Menu 内核,三个变体薄壳 import 它」→ 实际不可行:会同时打破 395 文件数、`build-dist` 打包与 `verify-package-import` 的 79 导出断言,并牺牲"单文件可拷贝"。改为**模板生成**:15 个产物保持自包含,重复消除在源头(改一份模板 + 重跑 = 三端同步)。
- 原计划把实现层一次覆盖多族 → 实际只做 `nav-menu` 一族作为端到端切片,其余 12 族先落契约层。原因:实现层每族都要重写 5 端并过 9 项断言矩阵,一次做完无法逐族验证。
- `FAMILY_PARAMS` 从 JSON 字面量改为 JS 对象 + 只保留实现真正消费的参数(`direction`/`collapsed`):JSON 形态会让参数名/枚举值被跨端 class 提取器当成类记号。
**发现的新问题(已登记,未在本任务顺手修)**:
- **S6-P22(建议)**:`tools/verify-cross-platform.mjs` 的 class 提取器端间不对称 —— 同一份代码形态,Vue 端会把 `const X = { k: 'v' }` 的字符串值收作变体记号,H5/JSX 端不会。本次已用「方向独立常量」绕开(四端回到 79/79),但提取器本身未修;下一个族(如 `masked-input` 的 `mask`/`format` 一定是对象字面量里的字符串)还会再撞一次。建议统一三端口径:要么都在对象字面量里展开枚举,要么都不展开。
- **S6-P23(建议)**:其余 12 族的实现层合并(`table` 净减 5、`masked-input` 净减 6 收益最大)。族模板按现有生成器结构新增 `<family>/menu.*.tpl` 即可,数据层无需改动。
- **S6-P24(建议)**:`MixedNavigation.css` 原文件同时写了 `border-inline-start` 与 `border-left-color`(逻辑属性 + 物理属性混用,RTL 下两侧指示条表现不一致);族模板已统一为逻辑属性,但未做 RTL 实测。
**回归**:100%(1017/1017)/ 八次连跑一致 / 0 超时。
---
## 四 · 显式不做(及理由)
> 这份清单同样重要 —— 没有它,执行模型会以为"漏了",或者在错误的时机自作主张。
| 不做 | 理由 | 什么条件下应该做 |
|---|---|---|
| **不引入打包器**(Vite / Rollup / esbuild) | 破除零依赖约束的代价远大于收益;本项目的卖点就是"打开 HTML 就能用" | 若未来要发布 ESM/CJS 模块化包,先评估是否需要独立仓库 |
| **不做像素级视觉回归**(全量) | 79 组件 × 5 端 = 395 张基准图,维护成本极高且易误报(抗锯齿/字体渲染差异) | P6 已包含「6 个核心组件抽样像素比对」,够用 |
| **不做 SSR / SSG** | 文档站是纯静态 SPA,爬虫需求已由 `site/components/*.html` 薄壳 + sitemap 解决 | 若 SEO 成为核心指标,再评估 |
| **不做多主题商店**(Ant Design 式) | 已有 6 套预设 + 令牌导出,改色能力已足够;主题商店是运营功能非工程功能 | 产品化阶段(S4 之后) |
| **不重写 `app.js`** | 2064 行单文件虽不理想,但功能正确、回归 100%。重构风险 > 收益 | 若某任务包因它受阻(如 P4 代码拆分),**局部**改造而非重写 |
| **不改 `frameworks/` 的视觉** | 那是规范原文的忠实实现,改了会破坏契约一致性 | 只有规格原文变更时才同步 |
| **不做 Storybook 集成** | 与零依赖冲突,且 Playground(v1.2.0)已覆盖在线试玩需求 | 不考虑 |
| **不做 React/Vue 单元测试**(Jest/Vitest) | 与零依赖冲突;跨端一致性靠 P6 的静态比对 + 抽样渲染 | 若组件逻辑复杂化到静态分析无法覆盖 |
---
## 五 · 未解问题(需用户或后续规划决策)
> 这些问题我作为规划师**无法单方面决定**,列出供决策。
| # | 问题 | 影响面 | 我的建议 |
|---|---|---|---|
| Q1 | **是否发布到 npm?** 涉及包名占用、发布权、后续维护承诺 | S1-P2 | 建议发。当前无分发渠道是最大阻塞,且 npm 上同名包大概率未被占用 |
| Q2 | **目标用户是谁?** 内部团队 / 开源社区 / 商业化产品,三者的优先级与验收标准不同 | 全局 | 建议先按「内部团队 + 开源复用」定位(对应 S1-S2 的优先级) |
| Q3 | **是否有设计团队协作?** 若没有,S4-P10 的 Figma 产出无人使用 | S4-P10 | 建议推迟到有设计资源时再做,或降级为「Figma Variables JSON 导出」只做工程侧 |
| Q4 | **是否需要 RTL?** 取决于是否有中东/希伯来语市场 | S3-P8 | 若无明确市场,降级为 P2 或推迟。迁移成本高(22 个文件) |
| Q5 | **性能预算的底线是多少?** 我定的 300KB 是经验值 | S1-P4b | 建议以「3G 网络首屏可交互 < 3s」反推预算 |
| Q6 | **暗色模式下演示 iframe 是否反色?** 两种都有道理 | S2-P5 | 建议反色(用户开暗色就是要整体变暗),但需人工验收视觉 |
---
## 六 · 风险登记
| 风险 | 影响 | 缓解 |
|---|---|---|
| 约束冲突:CI 需要 Playwright,但"零依赖" | 中 | 明确区分**运行时依赖**(保持零)与**构建/测试依赖**(可引入 devDependencies),并在 README 写清 |
| S2-P6 暴露大量跨端不一致 | 中 | 已在任务包里说明"发现即价值",差异作为新任务列出,不顺手修 |
| 暗色反色后视觉倒退 | 中 | 强制对比度脚本验证 + 人工截图验收 |
| RTL 迁移破坏现有布局 | 中 | 迁移后跑八次回归;逐文件比对渲染截图 |
| `data.js` 拆分影响 For Agents 承诺 | 高 | 明确要求 `data.json` 保持完整,只拆 `data.js` |
| 用户未确认许可证类型 | 中 | 默认 MIT 并在交付说明标注"如需变更请告知" |
---
## 七 · 验收总纲
任一任务包完成,必须同时满足:
1. **给出验收命令的完整输出**(不是"我以为跑过了")
2. **跑八次回归**:`100% / 0 失败 / 0 超时`
3. **`CHANGELOG.md` 有对应条目**(`[Unreleased]` 下)
4. **本文件对应任务包下追加 `✅ 完成于 <commit-hash>`**
5. **若发现新问题**:写成新任务包追加到本文件,不在原任务里顺手修
---
## 附 · 执行状态总览
> **执行模型看这里**:找下一个可开工的任务。状态为「待开始」且依赖已满足的最优先任务就是你的目标。
| ID | 任务 | 阶段 | 优先级 | 预算 | 依赖 | 状态 |
|---|---|---|---|---|---|---|
| P1 | LICENSE | S1 | **P0** | 10 min | — | ✅ **已完成**(MIT) |
| P2 | npm 分发 | S1 | **P0** | 2 h | P1 ✅ | ✅ **已完成**(dist 构建 + npm pack 115.9KB) |
| P3 | CI 回归 | S1 | **P0** | 1.5 h | — | ✅ **已完成**(workflow + runner 重构 + exit code) |
| P4 | `data.js` 瘦身 | S1 | **P0** | 3 h | — | ✅ **已完成**(data.js 98KB/sources 395/data.json 完整/回归 1003/1003,见 c65a69c) |
| P5 | 暗色模式 | S2 | **P0** | 1 d | P4 ✅ | ✅ **已完成**(令牌组31/对比度10项≥4.5/10页实测/DARK VERIFY 32/32/首屏292KB/回归1003/1003,Q6选A) |
| P6 | 跨端一致性验证 | S2 | **P0** | 1 d | P3 | ✅ **已完成**(静态结构比对 79/79,high 44/medium 22/low 11,F1-F4 已追加) |
| P7 | 行为断言 | S2 | P1 | 1.5 d | — | ✅ **已完成**(8 动词引擎 + 6 试点全绿/回归 1009/1009) |
| P8 | RTL | S3 | P1 | 2 d | P5 | ✅ **已完成**(28 文件迁移/物理清零/14 处人工例外/三页实测零溢出) |
| P9 | FAQ 页 | S3 | P2 | 1 d | — | ✅ **已完成**(240 条/79 组件/搜索过滤/浏览器实测,details 懒加载版) |
| P10 | Figma 资源 | S4 | P2 | 2 d | P2 | ⚪ 待 P2 |
| P11 | 模板页库 | S4 | P2 | 2 d | — | 🟢 可开工(优先级低) |
| P12 | 版本发布流程 | S4 | P3 | 1 d | P2 | ✅ **已完成**(release.mjs 检查/bump + CONTRIBUTING 文档化,只做本地准备不自动 push/tag) |
### 推荐执行顺序
```
P3(CI,无依赖最快见效)
→ P4(瘦身,收益最大)
→ P2(分发,解除交付阻塞)
→ P5 + P6(可信度双支柱)
→ P7 → P8 → P9 → P10 → P11 → P12
```
**为什么 P3 排第一**:它是唯一能让后续所有改动**自动受保护**的任务 —— 有了 CI,其他任务的质量不再依赖人工记得跑回归。
**为什么 P4 第二**:实测净减 887 KB(991KB → ~110KB),收益/成本比最高,且依赖分析已完成。
**并行机会**:P2 与 P4 互不阻塞,可由两个模型同时做。P3 完成后应立即合并,让后续任务都在 CI 保护下。
---
## 四 · 2026-09-19 安全审计(衍生任务与已完成项)
> 起因:对仓库 + `192.168.5.7` 线上部署做全量安全与缺陷审计(报告与逐项证据见 `安全审计修复与待决事项.md`)。
> 已修复项在 CHANGELOG `[Unreleased] → Security` 有记录;下面只列**衍生任务包**与状态。
| ID | 任务 | 阶段 | 优先级 | 预算 | 状态 |
|---|---|---|---|---|---|
| S5-P13 | 部署可复现化 | S5 | **P0** | 2 h | ✅ **已完成**(`tools/pack-deploy.mjs` 以 `.dockerignore` 为唯一真源 + 硬断言;AGENTS §九 流程;2026-09-19 实际部署验证 6/6 断言 + 396/396 URL) |
| S5-P14 | 容器运行期加固 | S5 | P2 | 1 h | ⚪ **待决策**(需停机窗口):`read_only` + `tmpfs`、`cap_drop: [ALL]`、`no-new-privileges`、基础镜像 digest 固定 |
| S5-P15 | 对外承诺口径统一 | S5 | P1 | 2 h | ⚪ **待决策**:契约数量三处说法不一致(`llms.txt`「79 个」/`AGENTS.md`「79」/`index.json`「6 个核心」),线上实际只发布 6 份核心 + `index.json` |
| S5-P16 | 正式域名与 SEO | S5 | P2 | 1 h | ⚪ **待决策**:`sitemap.xml` 与 `package.json` 仍是 `YOUR-ACCOUNT.github.io` 占位;`build-site.ps1` 已支持 `SITE_URL_BASE`,但 `tools/verify-site-routing.mjs` 目前把占位 URL 写成了断言,换域名需同步改 |
| S5-P17 | 回归偶发失败的可追溯性 | S5 | P1 | 1 h | ⚪ **待开工**:2026-09-19 连跑 27 次中出现 2 次 `1016/1017`(78/79 页全通过),但 `tests/report.json` 的 `failedPages`/`timedOut` 为空、也未记录是哪条断言失败,导致无法定位。需让 runner 在非满分时落盘失败断言标识(页面 + `data-assert` + 期望/实际),并保留上一次报告不被覆盖 |
| S5-P18 | 组件库可 import(三端入口) | S5 | **P0** | 3 h | ✅ **已完成**(`dist/react|vue3|vue2/index.js` 各 79 组件 + `exports`/`peerDependencies`;顺带修掉 RangeQuickPicker 的 const 重赋值与 CodeInput 的 emit 遮蔽——两处都会让组件无法编译;`tools/verify-package-import.mjs` 20 checks;Vite + Vue3/React 真实工程 `file:` 安装后构建并浏览器实测通过) |
**已知但暂不处理**(用户 2026-09-19 决定):不对外公用 —— 线上保持 `127.0.0.1:3311` 回环,需 SSH 隧道访问;不加反代、不加域名、不加认证。
### S5-P15 补充说明
线上 `/.design_library/aurora-admin/components/` 只有 `button/card/input/modal/select/table.json` + `index.json`;本地是 79 份 + `index.json`。三处文档说法互相矛盾,需先定「对外到底承诺几份契约」,再统一 `llms.txt` / `AGENTS.md` / `index.json` 与线上发布内容。
### S5-P16 补充说明
`sitemap.xml` 的 396 条 URL 本身在线上全部 200(静态页无死链),问题只在文件本身的域名是占位值,且此前未 `COPY` 进镜像(已修)。换真域名时注意 `tools/verify-site-routing.mjs:48` 的断言。
---
## 五 · 2026-09-20 文档站导航(衍生任务与已完成项)
| ID | 任务 | 阶段 | 优先级 | 预算 | 状态 |
|---|---|---|---|---|---|
| S5-P19 | 导航语言选择改为下拉(美化) | S5 | P1 | 2 h | ✅ **已完成**(原「中/EN 双段」按钮换成令牌化下拉:地球图标 + 当前语言 + 箭头触发器,186px 卡片菜单含标题分隔线、ZH/EN 角标、对勾选中态;listbox ARIA + 方向键/Home/End/Esc/Tab/点击外部全路径;暗色令牌继承,选中项对比度 4.57、标题 6.50;≤1100px 收起语言名到 56px,实测 ≥860px 顶栏 0 溢出) |
| S5-P20 | 顶栏在 ≤820px 溢出(移动端导航无方案) | S5 | P2 | 2 h | ⚪ **待开工**:实测 820px 顶栏溢出 33px、768px 85px、600px 253px;≤900px 已无侧栏且**没有任何汉堡菜单**,等于移动端无法导航。这一层是既有缺口(移除语言控件后 820px 仍溢出 33px,可压缩仿真亦不变),与 S5-P19 无关。需要的是移动端导航方案(抽屉/汉堡 + 顶栏分段折叠),而非继续微调间距 |
| S5-P21 | 发布到私有 npm 源 | S5 | P1 | 1 h | ✅ **已完成**(`gitea.mymoyu.top` 的 npm registry,匿名可读;发布 3 个可互换包名 `@root/ui`(推荐,支持一行 `.npmrc`)/ `chunyu-ui` / `aurora-admin-design`;Vite+Vue3 真实工程实测安装→构建→浏览器渲染通过)。**待决**:是否也发布到公共 npm(本机无凭据,需用户 `npm login` 或 token;`chunyu-ui`/`aurora-admin-design` 在公共 npm 均未被占用) |
**S5-P20 实测数据**(2026-09-20,`http://127.0.0.1:3311/site/index.html#/component/button`):
| 视口宽 | 顶栏溢出 | 说明 |
|---|---|---|
| ≥1100 | 0 | 语言名 + 图标(115px) |
| 1024 / 900 / 860 | 0 | 语言名收起(56px),链接近距收到 8px |
| 820 | 33px | 移除语言控件仍溢出 33px → 与语言控件无关 |
| 768 | 85px | |
| 600 | 253px | |
---
## 附 · 规划修正记录
> 执行中发现规划与实际不符时,**以实测为准**,在此登记。
| 日期 | 任务 | 规划原写 | 实测 | 处理 |
|---|---|---|---|---|
| 2026-09-11 | P4 | `data.js` 目标 < 400 KB(推测 `sources` 是最大头) | `sources` 实测占 **89.6%**(888KB/991KB);拆出后可达 **~110KB** | 目标改为 < 150 KB,策略与体积数据全部替换为实测 |
| 2026-09-11 | P4 | 预计算 API 表估算 < 30 KB | 实测 **1.0 KB**(比估算乐观 30 倍) | 更新为实测值 |
| 2026-09-11 | P2 | 包名可用性未知 | registry 查询:`aurora-admin-design` **未被占用** | 补入「前置验证已完成」 |
| 2026-09-11 | P4 | 只说「改成 fetch」,未识别难点 | `app.js` 有 **10 处**消费 `sources`,其中 2 处是**渲染期同步解析** | 补入「依赖分析」与三阶段执行建议 |
| 2026-09-11 | P2/P4 | 验收命令有 3 处会误判(npm 不可用时误报 OK 等) | 实测触发 | 已改写为显式判断 exit code |
| 2026-09-19 | PLAN §7/§8 | 「不改 `site/dev-server.js`(已工作良好)」 | 单个 `GET /site/%00` 触发 `ERR_INVALID_ARG_VALUE` 未捕获异常,进程退出 | **以实测为准**:修复该文件(NUL 双重拦截 + `readFile` try/catch + `AA_PORT`),并新增 `tools/verify-dev-server.mjs`(20 checks / 3 条反例断言);PLAN 两处已标注 ⚠️ 规划修正 |
| 2026-09-19 | 部署方式 | 未规定(实际为手工拷贝到 `/opt/aurora-admin`) | 手工拷贝导致 ① `.dockerignore` 未随行 → 规范原文入镜像并对外 200;② 曾修好的 `absolute_redirect off` 被覆盖丢失 | 新增任务包 S5-P13:以 `.dockerignore` 为唯一真源的 `tools/pack-deploy.mjs` + AGENTS §九 标准流程;2026-09-19 已按该流程实际部署并验收 |
| 2026-09-19 | TESTING 基线 | 1009 通过 / 35 N/A / 共 1044 条断言 | 工作树实测 **1017 通过 / 0 失败 / 34 N/A / 共 1051**(连跑 10 次一致) | 更新 TESTING.md 与 AGENTS.md §八 的数字并标注口径来源 |
| 2026-09-20 | S1-P2 | 目标写「能拿到令牌 + 组件样式」,据此实现为 CSS/HTML 分发包 | 用户预期是**组件库**(`import { AaButton } from '.../vue3'`);实测 `dist/` 无任何可 import 组件,`main` 指向 CSS 文件 | **以用户预期为准**:补三端入口 + `exports` + `peerDependencies`,登记为 S5-P18 并已完成。原 S1-P2 验收命令全部仍通过,未破坏既有承诺 |
| 2026-09-20 | 5 端实现 | AGENTS 写「79 组件 × 5 端实现」 | 真编译时发现 `RangeQuickPicker`(React/Vue3)与 `CodeInput`(Vue3)**无法编译**——此前从未真编译过,结构断言测不出 | 已修;新增 `tools/verify-package-import.mjs` 的编译级检查(真编译 + 真渲染)防止复发 |