iter(f03): 新增留痕格式门禁 lint-iterations

This commit is contained in:
HIsheR
2026-10-23 18:46:53 +08:00
parent 3fb3cd2395
commit f57da4c74e
2 changed files with 39 additions and 3 deletions
+3 -2
View File
@@ -12,9 +12,10 @@
"style": "node packages/tools/cli/bin/ua.js style", "style": "node packages/tools/cli/bin/ua.js style",
"index": "node packages/tools/cli/bin/ua.js index", "index": "node packages/tools/cli/bin/ua.js index",
"docs": "node packages/tools/cli/bin/ua.js index && node packages/tools/cli/bin/ua.js docs", "docs": "node packages/tools/cli/bin/ua.js index && node packages/tools/cli/bin/ua.js docs",
"check": "npm run build && npm run style && npm run typecheck && npm run smoke && npm run index && npm run verify", "check": "npm run build && npm run style && npm run typecheck && npm run smoke && npm run index && npm run verify && npm run lint-iterations",
"ua": "node packages/tools/cli/bin/ua.js", "ua": "node packages/tools/cli/bin/ua.js",
"verify": "node packages/tools/cli/bin/ua.js verify" "verify": "node packages/tools/cli/bin/ua.js verify",
"lint-iterations": "node packages/tools/cli/bin/ua.js lint-iterations"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^5.6.0" "typescript": "^5.6.0"
+36 -1
View File
@@ -693,6 +693,38 @@ function cmdCommitLint(args) {
console.log(`commit-lint OK (${type}${scope ? `(${scope})` : ''})`); console.log(`commit-lint OK (${type}${scope ? `(${scope})` : ''})`);
} }
/*** 迭代留痕校验:.ua/iterations.log 每行 JSON 字段与格式必须符合 ITERATION.md 规范 ***/
function cmdLintIterations() {
const file = path.join(INDEX_DIR, 'iterations.log');
if (!fs.existsSync(file)) return console.log('lint-iterations OK (no log)');
const lines = fs.readFileSync(file, 'utf8').split(/\r?\n/).filter((l) => l.trim());
const issues = [];
lines.forEach((line, i) => {
const tag = `iterations.log:${i + 1}`;
let o;
try { o = JSON.parse(line); } catch { issues.push(`${tag} 不是合法 JSON`); return; }
const keys = Object.keys(o);
if (keys.length !== 5 || !['ts', 'id', 'result', 'commit', 'summary'].every((k) => keys.includes(k))) {
issues.push(`${tag} 字段必须恰为 {ts,id,result,commit,summary}(当前 ${keys.join(',')})`);
}
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+08:00$/.test(String(o.ts ?? '')) || Number.isNaN(Date.parse(o.ts))) {
issues.push(`${tag} ts 须为可解析的本地 +08:00 ISO 时间`);
}
if (!/^[a-z]\d{2,}$/.test(String(o.id ?? ''))) issues.push(`${tag} id 须为 backlog 条目 id`);
if (o.result !== 'done' && o.result !== 'aborted') issues.push(`${tag} result 须为 done|aborted`);
const commit = String(o.commit ?? '');
if (o.result === 'done' && !/^[0-9a-f]{7,40}$/.test(commit)) issues.push(`${tag} done 条目 commit 须为 7-40 位哈希`);
if (o.result === 'aborted' && commit && !/^[0-9a-f]{7,40}$/.test(commit)) issues.push(`${tag} aborted 条目 commit 须为空或哈希`);
if (!String(o.summary ?? '').trim()) issues.push(`${tag} summary 不能为空`);
});
if (issues.length) {
for (const it of issues) console.error('lint-iterations: ' + it);
console.error(`${issues.length} violation(s)`);
process.exit(1);
}
console.log(`lint-iterations OK (${lines.length} entries)`);
}
// ---- 入口 ---- // ---- 入口 ----
const [cmd, ...args] = process.argv.slice(2); const [cmd, ...args] = process.argv.slice(2);
@@ -722,10 +754,13 @@ switch (cmd) {
case 'commit-lint': case 'commit-lint':
cmdCommitLint(args); cmdCommitLint(args);
break; break;
case 'lint-iterations':
cmdLintIterations();
break;
case 'mcp': case 'mcp':
cmdMcp(); cmdMcp();
break; break;
default: default:
console.log('usage: ua <index|list|info <name>|docs|style|verify|commit-lint|mcp>'); console.log('usage: ua <index|list|info <name>|docs|style|verify|commit-lint|lint-iterations|mcp>');
process.exit(cmd ? 1 : 0); process.exit(cmd ? 1 : 0);
} }