iter(g297): 新增迭代循环诊断命令

This commit is contained in:
HIsheR
2026-10-26 23:38:43 +08:00
parent 308a7ee940
commit 2a7fce70aa
7 changed files with 61 additions and 7 deletions
+39 -1
View File
@@ -1750,6 +1750,41 @@ function cmdAuditSurface(args) {
process.exit(result.failures.length === 0 ? 0 : 1);
}
/*** 迭代循环诊断:锁心跳 / 上次留痕 / 待办数一眼看清,多实例接力时不必翻调度器库或靠猜(--json 给脚本用) ***/
function cmdLoop(args) {
const now = Math.floor(Date.now() / 1000);
const lockFile = path.join(INDEX_DIR, 'loop.lock');
let lock = null;
if (fs.existsSync(lockFile)) {
const raw = Number(fs.readFileSync(lockFile, 'utf8').trim()); // 锁内是点火时的 epoch 秒
const stamp = raw || Math.floor(fs.statSync(lockFile).mtimeMs / 1000); // 取不到数字就用 mtime 兜底
const age = now - stamp;
lock = { stamp, age, fresh: age < 900 }; // 15 分钟内的心跳算活着,与 ITERATION.md 的抢锁判据同口径
}
const logFile = path.join(INDEX_DIR, 'iterations.log');
const text = fs.existsSync(logFile) ? fs.readFileSync(logFile, 'utf8') : '';
const lines = text.split('\n').filter((l) => l.trim()); // 按行切即可:JSON.parse 容忍行尾 \r,不必额外归一化
let last = null;
try { last = lines.length ? JSON.parse(lines[lines.length - 1]) : null; } catch { last = null; } // 末行坏了不该让诊断命令崩,lint-iterations 会单独报
const data = JSON.parse(fs.readFileSync(path.join(INDEX_DIR, 'backlog.json'), 'utf8'));
const items = Array.isArray(data) ? data : data.items;
const open = items.filter((i) => i.status === 'open');
const pending = open.filter((i) => i.domain === 'visual');
if (args.includes('--json')) {
const out = { now, lock, entries: lines.length, last, total: items.length, open: open.length, openVisual: pending.length };
console.log(JSON.stringify(out, null, 2));
return;
}
console.log(`当前时间:${new Date(now * 1000).toLocaleString('zh-CN', { hour12: false })}`);
if (!lock) console.log('循环锁:无 → 可直接点火(写 .ua/loop.lock 后进连续迭代)');
else if (lock.fresh) console.log(`循环锁:心跳 ${lock.age} 秒前(< 15 分钟)→ 已有实例在跑,本轮不要抢锁`);
else console.log(`循环锁:心跳 ${lock.age} 秒前(≥ 15 分钟)→ 疑似中断,可删锁重新点火`);
console.log(last ? `上次留痕:${last.id} ${last.result} @ ${last.ts}(${last.commit})` : '上次留痕:无');
console.log(`累计留痕:${lines.length} 条|backlog:${items.length} 条,open ${open.length} 条(视觉欠账 ${pending.length} 条)`);
if (!open.length) console.log('选题:无 open 条目 → 本轮需按《选题规则》自补一条');
else console.log(`选题:下一条取 ${pending[0]?.id ?? open[0].id}(${pending[0] ? '视觉欠账优先' : '按数组顺序'})`);
}
/*** 迭代留痕校验:.ua/iterations.log 每行 JSON 字段与格式必须符合 ITERATION.md 规范 ***/
function cmdLintIterations() {
const file = path.join(INDEX_DIR, 'iterations.log');
@@ -1929,10 +1964,13 @@ switch (cmd) {
case 'audit:surface':
cmdAuditSurface(args);
break;
case 'loop':
cmdLoop(args);
break;
case 'mcp':
cmdMcp();
break;
default:
console.log('usage: ua <index|list|search <kw>|info <name> [--json|--md]|recipes [编号] [--json]|docs|tokens [--json|--unused]|style|sync-counts|verify|doctor|commit-lint|lint-iterations|audit:visual [--json|--baseline]|audit:contrast [--json|--list]|audit:motion [--json]|audit:surface [--json|--list]|changelog|mcp>');
console.log('usage: ua <index|list|search <kw>|info <name> [--json|--md]|recipes [编号] [--json]|docs|tokens [--json|--unused]|style|sync-counts|verify|doctor|commit-lint|lint-iterations|audit:visual [--json|--baseline]|audit:contrast [--json|--list]|audit:motion [--json]|audit:surface [--json|--list]|loop [--json]|changelog|mcp>');
process.exit(cmd ? 1 : 0);
}
+4 -2
View File
@@ -24,7 +24,9 @@
"ua audit:visual [--json|--baseline]:视觉漂移门禁,统计皮肤包里各类硬编码视觉字面量(字号/动效时长/阴影/圆角/焦点环/内距/控件高度/字重/行高/层级/边框色)并与 .ua/visual-baseline.json 棘轮比对,超基线退出码 1;--baseline 重写基线,--json 出机器可读计数与每类命中行号(line / prop / value / hint,Agent 可直接定位)",
"ua audit:contrast [--json|--list]:对比度门禁,把令牌里 18 组「前景色 × 底色」配对按 WCAG 公式算成对比度(求值支持 var() 与 color-mix,半透明底先压到页面底色),亮/暗 × 常规/高对比四套分算,低于阈值(正文 7 / 常规 4.5 / 禁用 2.6 / 非文本 3)退出码 1;--json 出逐对明细,--list 只列配对表",
"ua audit:motion [--json]:动效兜底门禁,两类必查——① 带 infinite 的动画逐个核对是否在 prefers-reduced-motion 块里 animation: none;② 悬停 / 按压的位移(translate)是否在减少动效下归零(认 ua- 类通配的全局规则)。缺兜底退出码 1(--json 出逐条明细)",
"ua mcp:零依赖 stdio MCP server,暴露 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe;get_component 支持 format: md 直接取可粘贴的 Markdown 片段"
"ua audit:surface [--json|--list]:表面阶梯门禁,逐档核对底色对底色的亮度比(页面底 → 表面 → 悬停底 → 按下底 ≥1.04、凹陷底 ≥1.02),亮/暗 × 常规/高对比四套主题各算一遍,不达标退出码 1;对比度只管文字读不读得清,管不到「悬停有没有反馈」(实测过 1.008 的悬停底)",
"ua mcp:零依赖 stdio MCP server,暴露 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe;get_component 支持 format: md 直接取可粘贴的 Markdown 片段",
"ua loop [--json]:迭代循环诊断,一眼看清锁心跳(是否 15 分钟内)、上次留痕、backlog 待办与视觉欠账数,并给出本轮该不该抢锁、下一条该选谁;多实例错位接力时不必翻调度器数据库"
],
"keyTypes": [
"ua.manifest.json 清单结构",
@@ -53,4 +55,4 @@
],
"components": []
}
}
}