iter(f03): 新增留痕格式门禁 lint-iterations
This commit is contained in:
+3
-2
@@ -12,9 +12,10 @@
|
||||
"style": "node packages/tools/cli/bin/ua.js style",
|
||||
"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",
|
||||
"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",
|
||||
"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": {
|
||||
"typescript": "^5.6.0"
|
||||
|
||||
@@ -693,6 +693,38 @@ function cmdCommitLint(args) {
|
||||
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);
|
||||
@@ -722,10 +754,13 @@ switch (cmd) {
|
||||
case 'commit-lint':
|
||||
cmdCommitLint(args);
|
||||
break;
|
||||
case 'lint-iterations':
|
||||
cmdLintIterations();
|
||||
break;
|
||||
case 'mcp':
|
||||
cmdMcp();
|
||||
break;
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user