diff --git a/.ua/index.json b/.ua/index.json index 94c4522..1f6c472 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -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)", diff --git a/AGENTS.md b/AGENTS.md index b65a2a0..c0e585d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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)确认基线全绿,再开始改代码。 ## 编码规范(强制) diff --git a/llms-full.txt b/llms-full.txt index 7cb6ce5..07d9551 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -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 片段(标题 + 参数表 + 用法 + 示例) diff --git a/llms.txt b/llms.txt index 832d089..2785bde 100644 --- a/llms.txt +++ b/llms.txt @@ -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 片段(标题 + 参数表 + 用法 + 示例) diff --git a/packages/tools/cli/bin/ua.js b/packages/tools/cli/bin/ua.js index 796c58f..fc3c84f 100644 --- a/packages/tools/cli/bin/ua.js +++ b/packages/tools/cli/bin/ua.js @@ -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 里本身含 这类尖括号 + // 先剔掉 [--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 |info |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 |info [--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); } diff --git a/packages/tools/cli/ua.manifest.json b/packages/tools/cli/ua.manifest.json index 62ad4dc..35d6d0e 100644 --- a/packages/tools/cli/ua.manifest.json +++ b/packages/tools/cli/ua.manifest.json @@ -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)",