iter(g297): 新增迭代循环诊断命令
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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": []
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user