iter(g228): 新增 ua doctor 环境自检命令
This commit is contained in:
@@ -1576,10 +1576,43 @@ function cmdLintIterations() {
|
||||
console.log(`lint-iterations OK (${lines.length} entries)`);
|
||||
}
|
||||
|
||||
/*** 环境自检:新 Agent 接手前一条命令确认 node / 依赖 / git 钩子 / .ua 元数据就绪,任一失败退出码 1 ***/
|
||||
function cmdDoctor() {
|
||||
const checks = []; // 逐项结果:名称 + 是否通过 + 可选失败详情
|
||||
const nodeMajor = Number(process.versions.node.split('.')[0]);
|
||||
checks.push({ name: `node >= 18(当前 ${process.versions.node})`, pass: nodeMajor >= 18 });
|
||||
checks.push({ name: 'pnpm-lock.yaml 存在', pass: fs.existsSync(path.join(ROOT, 'pnpm-lock.yaml')) });
|
||||
checks.push({ name: '依赖已安装(node_modules/)', pass: fs.existsSync(path.join(ROOT, 'node_modules')) });
|
||||
const hooksPath = spawnSync('git', ['config', 'core.hooksPath'], { cwd: ROOT }).stdout?.toString().trim(); // 显式 hooksPath 优先,默认取 .git/hooks
|
||||
const hookDir = hooksPath ? path.resolve(ROOT, hooksPath) : path.join(ROOT, '.git', 'hooks');
|
||||
checks.push({ name: 'commit-msg 钩子在位', pass: fs.existsSync(path.join(hookDir, 'commit-msg')) });
|
||||
const tryJson = (rel) => { // 存在且能 JSON.parse 才算过
|
||||
const p = path.join(ROOT, rel);
|
||||
if (!fs.existsSync(p)) return `文件不存在`;
|
||||
try { JSON.parse(fs.readFileSync(p, 'utf8')); return ''; } catch (e) { return `解析失败:${e.message}`; }
|
||||
};
|
||||
for (const rel of ['.ua/backlog.json', '.ua/index.json']) {
|
||||
const bad = tryJson(rel);
|
||||
checks.push({ name: `${rel} 可解析`, pass: !bad, detail: bad });
|
||||
}
|
||||
const logFile = path.join(INDEX_DIR, 'iterations.log');
|
||||
if (fs.existsSync(logFile)) {
|
||||
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' });
|
||||
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); }
|
||||
console.log(`doctor OK(${checks.length} 项全过)`);
|
||||
}
|
||||
|
||||
// ---- 入口 ----
|
||||
|
||||
const [cmd, ...args] = process.argv.slice(2);
|
||||
switch (cmd) {
|
||||
case 'doctor':
|
||||
cmdDoctor();
|
||||
break;
|
||||
case 'index':
|
||||
cmdIndex();
|
||||
break;
|
||||
@@ -1630,6 +1663,6 @@ switch (cmd) {
|
||||
cmdMcp();
|
||||
break;
|
||||
default:
|
||||
console.log('usage: ua <index|list|search <kw>|info <name>|docs|tokens [--json]|style|sync-counts|verify|commit-lint|lint-iterations|audit:visual [--json|--baseline]|changelog|mcp>');
|
||||
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]|changelog|mcp>');
|
||||
process.exit(cmd ? 1 : 0);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"MCP tool 入参 schema"
|
||||
]
|
||||
},
|
||||
"usage": "node packages/tools/cli/bin/ua.js <index|list|info <包名|组件id>|docs|tokens|style|verify|commit-lint|audit:visual|mcp>;仓库内等价于 npm run index / docs / style / verify / audit:visual",
|
||||
"usage": "node packages/tools/cli/bin/ua.js <index|list|info <包名|组件id>|docs|tokens|style|verify|commit-lint|audit:visual|doctor|mcp>;仓库内等价于 npm run index / docs / style / verify / audit:visual / doctor",
|
||||
"conventions": [
|
||||
"零依赖:只用 node 标准库,Node >= 18",
|
||||
"清单是单一来源:代码注释、文档站、llms-full.txt、MCP 全部从 ua.manifest.json 派生",
|
||||
@@ -36,7 +36,7 @@
|
||||
"docs": {
|
||||
"intro": "工程层工具包(private,不发布)。所有 Agent 与人都通过它读取组件库:清单驱动索引、文档、MCP 三件套,外加 style / verify 两道门禁。",
|
||||
"steps": [
|
||||
"装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual)",
|
||||
"接手先跑 ua doctor(node 版本 / 依赖 / git 钩子 / .ua 元数据一次检完,秒级),再跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify → lint-iterations → audit:visual)",
|
||||
"查组件:ua list 看全量,ua search <关键词> 按 id/标题/参数名/参数说明/步骤模糊找(「处理中」这类说明里的词也能搜到,命中非 id 标题时会标出命中字段;拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单)",
|
||||
"查配方:ua recipes 列全量(编号 / 标题 / 用到的组件),ua recipes <编号> 看骨架代码与要点(--json 给脚本用;MCP 里对应 list_recipes / get_recipe)",
|
||||
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码。令牌分十一组:颜色 / 圆角 / 间距 / 字号 / 字重行高 / 边框 / 阴影 / 动效 / 焦点环 / 控件高度 / 层级,弹层阴影用 --ua-shadow-1..4,过渡用 --ua-duration-* + --ua-ease,焦点环用 --ua-focus-ring(_inset)",
|
||||
|
||||
Reference in New Issue
Block a user