iter(g249): doctor 增加命令面与门禁链自洽自检

This commit is contained in:
HIsheR
2026-10-26 22:05:39 +08:00
parent 38731955dc
commit 2c348704a0
6 changed files with 46 additions and 7 deletions
+3 -2
View File
@@ -1,6 +1,6 @@
{
"$schema": "ui-arch-registry-index/0.1",
"generatedAt": "2026-10-26T14:02:07.910Z",
"generatedAt": "2026-10-26T14:05:23.913Z",
"repoRoot": ".",
"packages": [
{
@@ -4112,6 +4112,7 @@
"api": {
"entry": "bin/ua.js",
"exports": [
"ua doctor:11 项环境与自洽预检(node / 依赖 / git 钩子与身份 / .ua 元数据可解析 / usage 串 ↔ dispatch 一致 / check 链覆盖全部门禁步骤 / CLI 清单声明的命令都有实现),任一失败退出码 1",
"ua index:扫描 packages/ 两层目录的 ua.manifest.json,生成 .ua/index.json 与 llms.txt",
"ua list:列出注册表内所有包与组件数;--json 输出「包 + 组件 id」结构化数组,--components 逐组件展开",
"ua info <包名|组件id>:包名返回摘要,组件 id 返回 props 表 + 步骤 + 示例;--json 输出原始清单,--md 直接给可粘贴的 Markdown 片段(标题 + 参数表 + 用法 + 示例)",
@@ -4137,7 +4138,7 @@
"docs": {
"intro": "工程层工具包(private,不发布)。所有 Agent 与人都通过它读取组件库:清单驱动索引、文档、MCP 三件套,外加 style / verify 两道门禁。",
"steps": [
"接手先跑 ua doctor(node 版本 / 依赖 / git 钩子 / .ua 元数据一次检完,秒级),再跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual → audit:contrast)",
"接手先跑 ua doctor(11 项:node / 依赖 / git 钩子与身份 / 元数据 / 命令面三方一致 / 门禁链完整,秒级),再跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual → audit:contrast)",
"查组件:ua list 看全量,ua search <关键词> 按 id/标题/参数名/参数说明/步骤五层 + 配方三层(标题/配方组件/要点)模糊找(命中非 id 标题会标出命中字段,配方命中行直接给 ua recipes <编号> 指路;拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单);要给文档 / issue / 回复贴组件说明时加 --md,直接拿到标题 + 参数表 + 用法 + 示例的 Markdown 片段",
"查配方:ua recipes 列全量(编号 / 标题 / 用到的组件),ua recipes <编号> 看骨架代码与要点(--json 给脚本用;MCP 里对应 list_recipes / get_recipe)",
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码。令牌分十三组:颜色 / 混色浓度 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 位移 / 焦点环 / 控件高度 / 层级,color-mix 混入浓度用 --ua-alpha-soft/tint/line/mid/strong/heavy,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,transform 位移用 --ua-translate-*(负号 calc(-1 * var(...))),焦点环用 --ua-focus-ring(_inset)",
+1 -1
View File
@@ -7,7 +7,7 @@
1. **包管理器必须用 pnpm**:包间依赖用 `workspace:*` 协议,npm 不支持。安装依赖:`pnpm install`。
2. **构建工具**:TypeScript 5(`tsc`)。若环境未全局安装,可使用托管工作区的副本:`C:/Users/shawn/.workbuddy/binaries/node/workspace/node_modules/typescript`(本仓库历史即如此构建)。
3. **Node**:>= 18,ESM(`"type": "module"`)。
4. **环境自检 + 验证基线**:先跑 `node packages/tools/cli/bin/ua.js doctor`(秒级检查 node 版本 / 依赖安装 / git 钩子 / .ua 元数据可解析,任一失败退出码 1),通过后再跑 `npm run check`(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual → audit:contrast)确认基线全绿,再开始改代码。
4. **环境自检 + 验证基线**:先跑 `node packages/tools/cli/bin/ua.js doctor`(秒级 11 项检查:node 版本 / 依赖安装 / git 钩子 / git 身份 / .ua 元数据可解析 / usage 串 ↔ dispatch 一致 / check 链覆盖全部门禁步骤 / CLI 清单声明的命令都有实现,任一失败退出码 1),通过后再跑 `npm run check`(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual → audit:contrast)确认基线全绿,再开始改代码。
## 编码规范(强制)
+3 -2
View File
@@ -1,6 +1,6 @@
# @ui-arch 组件库 Agent 文档(无图形版)
> 自动生成于 2026-10-26T14:02:07.910Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
> 自动生成于 2026-10-26T14:05:23.913Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
## 快速上手
@@ -40,7 +40,7 @@
### @ui-arch/cli
1. 接手先跑 ua doctor(node 版本 / 依赖 / git 钩子 / .ua 元数据一次检完,秒级),再跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual → audit:contrast)
1. 接手先跑 ua doctor(11 项:node / 依赖 / git 钩子与身份 / 元数据 / 命令面三方一致 / 门禁链完整,秒级),再跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual → audit:contrast)
2. 查组件:ua list 看全量,ua search <关键词> 按 id/标题/参数名/参数说明/步骤五层 + 配方三层(标题/配方组件/要点)模糊找(命中非 id 标题会标出命中字段,配方命中行直接给 ua recipes <编号> 指路;拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单);要给文档 / issue / 回复贴组件说明时加 --md,直接拿到标题 + 参数表 + 用法 + 示例的 Markdown 片段
3. 查配方:ua recipes 列全量(编号 / 标题 / 用到的组件),ua recipes <编号> 看骨架代码与要点(--json 给脚本用;MCP 里对应 list_recipes / get_recipe)
4. 查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码。令牌分十三组:颜色 / 混色浓度 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 位移 / 焦点环 / 控件高度 / 层级,color-mix 混入浓度用 --ua-alpha-soft/tint/line/mid/strong/heavy,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,transform 位移用 --ua-translate-*(负号 calc(-1 * var(...))),焦点环用 --ua-focus-ring(_inset)
@@ -2342,6 +2342,7 @@ import '@ui-arch/tokens/tokens.css'; then use var(--ua-color-accent) etc. in any
API 速览:
- ua doctor:11 项环境与自洽预检(node / 依赖 / git 钩子与身份 / .ua 元数据可解析 / usage 串 ↔ dispatch 一致 / check 链覆盖全部门禁步骤 / CLI 清单声明的命令都有实现),任一失败退出码 1
- ua index:扫描 packages/ 两层目录的 ua.manifest.json,生成 .ua/index.json 与 llms.txt
- ua list:列出注册表内所有包与组件数;--json 输出「包 + 组件 id」结构化数组,--components 逐组件展开
- ua info <包名|组件id>:包名返回摘要,组件 id 返回 props 表 + 步骤 + 示例;--json 输出原始清单,--md 直接给可粘贴的 Markdown 片段(标题 + 参数表 + 用法 + 示例)
+1
View File
@@ -136,6 +136,7 @@
- 类型: tooling · 目录: packages/tools/cli
- 描述: ua 命令行与 MCP 注册表服务:把各包 ua.manifest.json 汇总成机器可读索引(.ua/index.json)、Agent 全量文档(llms-full.txt)与人类文档站,并提供清单一致性门禁。
- API:
- ua doctor:11 项环境与自洽预检(node / 依赖 / git 钩子与身份 / .ua 元数据可解析 / usage 串 ↔ dispatch 一致 / check 链覆盖全部门禁步骤 / CLI 清单声明的命令都有实现),任一失败退出码 1
- ua index:扫描 packages/ 两层目录的 ua.manifest.json,生成 .ua/index.json 与 llms.txt
- ua list:列出注册表内所有包与组件数;--json 输出「包 + 组件 id」结构化数组,--components 逐组件展开
- ua info <包名|组件id>:包名返回摘要,组件 id 返回 props 表 + 步骤 + 示例;--json 输出原始清单,--md 直接给可粘贴的 Markdown 片段(标题 + 参数表 + 用法 + 示例)
+36 -1
View File
@@ -1675,6 +1675,17 @@ function cmdLintIterations() {
}
/*** 环境自检:新 Agent 接手前一条命令确认 node / 依赖 / git 钩子 / .ua 元数据就绪,任一失败退出码 1 ***/
/*** 作用:解析本文件的命令面——dispatch 的 case 集合 vs usage 串里列的命令,两者必须相互覆盖
* 新增命令时只加 case 不改 usage(或反之)会让 Agent 查不到入口:usage 是 Agent 唯一能看到的命令清单。 ***/
function commandSurface() {
const self = fs.readFileSync(fileURLToPath(import.meta.url), 'utf8');
const cases = new Set([...self.matchAll(/^ {2}case '([^']+)':/gm)].map((m) => m[1]));
const usage = /console\.log\('usage: ua <(.+)>'\)/.exec(self); // 贪婪到行尾括号:usage 里本身含 <kw> 这类尖括号
// 先剔掉 [--json|--baseline] 这类选项组再按 | 切:否则选项里的竖线会被当成命令分隔符
const listed = usage ? usage[1].replace(/\[[^\]]*\]/g, '').split('|').map((part) => part.trim().split(/\s+/)[0]).filter(Boolean) : [];
return { cases, listed };
}
function cmdDoctor() {
const checks = []; // 逐项结果:名称 + 是否通过 + 可选失败详情
const nodeMajor = Number(process.versions.node.split('.')[0]);
@@ -1701,6 +1712,30 @@ function cmdDoctor() {
const badLines = fs.readFileSync(logFile, 'utf8').split(/\r?\n/).filter((l) => l.trim()).filter((l) => { try { JSON.parse(l); return false; } catch { return true; } });
checks.push({ name: '.ua/iterations.log 每行合法 JSON', pass: !badLines.length, detail: badLines.length ? `${badLines.length} 行非法(首行:${badLines[0].slice(0, 40)}…)` : '' });
} else checks.push({ name: '.ua/iterations.log 存在', pass: false, detail: '尚未生成,跑一轮迭代或 ua index' });
// 命令面自检:usage ↔ dispatch ↔ CLI 清单三方一致,防止新命令只落一处
const { cases, listed } = commandSurface();
const missingInUsage = [...cases].filter((c) => !listed.includes(c));
const missingInCode = listed.filter((c) => !cases.has(c));
checks.push({
name: 'usage 串 ↔ dispatch 一致',
pass: !missingInUsage.length && !missingInCode.length,
detail: [missingInUsage.length ? `usage 缺 ${missingInUsage.join('/')}` : '', missingInCode.length ? `实现缺 ${missingInCode.join('/')}` : ''].filter(Boolean).join(';'),
});
// 门禁链自检:package.json 的 check 必须跑齐所有门禁步骤(新增门禁忘了接进链等于没加)
const needSteps = ['build', 'demo', 'style', 'typecheck', 'smoke', 'index', 'verify', 'lint-iterations', 'audit:visual', 'audit:contrast'];
const chain = String(JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).scripts?.check ?? '');
const lacking = needSteps.filter((step) => !chain.includes(`npm run ${step}`));
checks.push({ name: 'check 链覆盖全部门禁步骤', pass: !lacking.length, detail: lacking.length ? `缺 ${lacking.join(' / ')}` : '' });
// 清单自检:ua.manifest.json 里写进 api.exports 的命令必须真的存在(文档承诺 ≠ 实现)
const cliManifestPath = path.join(ROOT, 'packages', 'tools', 'cli', 'ua.manifest.json');
const declared = fs.existsSync(cliManifestPath)
? (JSON.parse(fs.readFileSync(cliManifestPath, 'utf8')).api?.exports ?? [])
.filter((line) => /^ua \S/.test(line))
.map((line) => line.replace(/^ua\s+/, '').split(/[\s:]/)[0]) // 说明用全角冒号接在后面,按空白与冒号一起切
: [];
const ghost = declared.filter((name) => !cases.has(name));
checks.push({ name: 'CLI 清单声明的命令都有实现', pass: !ghost.length, detail: ghost.length ? `清单有实现无:${ghost.join('/')}` : '' });
for (const c of checks) console.log(`${c.pass ? 'pass' : 'FAIL'} ${c.name}${c.detail ? ':' + c.detail : ''}`);
const fails = checks.filter((c) => !c.pass).length;
if (fails) { console.error(`doctor: ${fails} 项未通过,先修复再跑 npm run check`); process.exit(1); }
@@ -1767,6 +1802,6 @@ switch (cmd) {
cmdMcp();
break;
default:
console.log('usage: ua <index|list|search <kw>|info <name>|docs|tokens [--json]|style|sync-counts|verify|doctor|commit-lint|lint-iterations|audit:visual [--json|--baseline]|audit:contrast [--json|--list]|changelog|mcp>');
console.log('usage: ua <index|list|search <kw>|info <name> [--json|--md]|recipes [编号] [--json]|docs|tokens [--json]|style|sync-counts|verify|doctor|commit-lint|lint-iterations|audit:visual [--json|--baseline]|audit:contrast [--json|--list]|changelog|mcp>');
process.exit(cmd ? 1 : 0);
}
+2 -1
View File
@@ -12,6 +12,7 @@
"api": {
"entry": "bin/ua.js",
"exports": [
"ua doctor:11 项环境与自洽预检(node / 依赖 / git 钩子与身份 / .ua 元数据可解析 / usage 串 ↔ dispatch 一致 / check 链覆盖全部门禁步骤 / CLI 清单声明的命令都有实现),任一失败退出码 1",
"ua index:扫描 packages/ 两层目录的 ua.manifest.json,生成 .ua/index.json 与 llms.txt",
"ua list:列出注册表内所有包与组件数;--json 输出「包 + 组件 id」结构化数组,--components 逐组件展开",
"ua info <包名|组件id>:包名返回摘要,组件 id 返回 props 表 + 步骤 + 示例;--json 输出原始清单,--md 直接给可粘贴的 Markdown 片段(标题 + 参数表 + 用法 + 示例)",
@@ -37,7 +38,7 @@
"docs": {
"intro": "工程层工具包(private,不发布)。所有 Agent 与人都通过它读取组件库:清单驱动索引、文档、MCP 三件套,外加 style / verify 两道门禁。",
"steps": [
"接手先跑 ua doctor(node 版本 / 依赖 / git 钩子 / .ua 元数据一次检完,秒级),再跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual → audit:contrast)",
"接手先跑 ua doctor(11 项:node / 依赖 / git 钩子与身份 / 元数据 / 命令面三方一致 / 门禁链完整,秒级),再跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual → audit:contrast)",
"查组件:ua list 看全量,ua search <关键词> 按 id/标题/参数名/参数说明/步骤五层 + 配方三层(标题/配方组件/要点)模糊找(命中非 id 标题会标出命中字段,配方命中行直接给 ua recipes <编号> 指路;拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单);要给文档 / issue / 回复贴组件说明时加 --md,直接拿到标题 + 参数表 + 用法 + 示例的 Markdown 片段",
"查配方:ua recipes 列全量(编号 / 标题 / 用到的组件),ua recipes <编号> 看骨架代码与要点(--json 给脚本用;MCP 里对应 list_recipes / get_recipe)",
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码。令牌分十三组:颜色 / 混色浓度 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 位移 / 焦点环 / 控件高度 / 层级,color-mix 混入浓度用 --ua-alpha-soft/tint/line/mid/strong/heavy,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,transform 位移用 --ua-translate-*(负号 calc(-1 * var(...))),焦点环用 --ua-focus-ring(_inset)",