1. 目录 mcn-work-shop -> mcn-workshop(空间分组名取会话 cwd 的目录名,只改字符串无效,必须真改名) 2. 全仓替换 mcn-work-shop -> mcn-workshop:37 文件 121 处;历史日志按沿革句规矩保留当时目录名 3. 任务进度可见:/api/run/status 产出 已运行时长/工具调用/最近动作/停滞判定(读会话日志尾部),前端新增右下角常驻面板,四处任务入口接入 4. 会话归属目录配置化:新增 config.sessionCwd(留空=工作台自身目录),现指向 D://AI技能//mcn-workshop,使任务显示为命名分组而非「未分组任务」 5. 修前端轮询静默缺陷:连续 3 次查询失败即提示服务断开(原逻辑静默空转到 15 分钟超时,用户零感知)
59 lines
3.8 KiB
JavaScript
59 lines
3.8 KiB
JavaScript
// 验证周榜数值列「窄 + 右对齐」:功能页 #/ranking + 首页预览表,只读测量
|
|
const list = await fetch('http://localhost:9223/json').then((r) => r.json());
|
|
let page = list.find((t) => t.type === 'page' && t.url.includes('localhost:8899'));
|
|
if (!page) { console.log('ERR: no workbuddy page open'); process.exit(1); }
|
|
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
|
let id = 0; const pending = new Map();
|
|
const send = (method, params = {}) => new Promise((res, rej) => { const i = ++id; pending.set(i, { res, rej }); ws.send(JSON.stringify({ id: i, method, params })); });
|
|
ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.id && pending.has(m.id)) { const p = pending.get(m.id); pending.delete(m.id); m.error ? p.rej(new Error(m.error.message)) : p.res(m.result); } };
|
|
await new Promise((r) => (ws.onopen = r));
|
|
const ev = async (expr) => { const r = await send('Runtime.evaluate', { expression: expr, returnByValue: true, awaitPromise: true }); if (r.exceptionDetails) return { __err: (r.exceptionDetails.exception?.description || r.exceptionDetails.text).slice(0, 300) }; return r.result.value; };
|
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
await send('Page.enable'); await send('Runtime.enable');
|
|
const goto = async (hash) => { await send('Page.navigate', { url: 'http://localhost:8899/' + hash }); await sleep(1500); await send('Page.reload', { ignoreCache: true }); await sleep(3000); };
|
|
|
|
// ===== 1) 功能页 #/ranking =====
|
|
await goto('#/ranking');
|
|
const rankPage = await ev(`(() => {
|
|
const ths = [...document.querySelectorAll('.table th')];
|
|
const wideKeys = ['comprehensiveScore','followers','newFans','newLikes','newComments','newShares'];
|
|
const colInfo = ths.map((th) => {
|
|
const rect = th.getBoundingClientRect();
|
|
return { key: th.dataset.sort || '', label: th.textContent.trim().slice(0,8), wide: th.classList.contains('th-wide'), w: Math.round(rect.width), thAlign: getComputedStyle(th).textAlign };
|
|
});
|
|
// td 对齐抽查:第一个数据行
|
|
const row = document.querySelector('.table tbody tr');
|
|
const tds = row ? [...row.children] : [];
|
|
const tdAligns = tds.map((td) => td.className + ':' + getComputedStyle(td).textAlign);
|
|
return { colInfo, tdAligns, rowCount: document.querySelectorAll('.table tbody tr').length };
|
|
})()`);
|
|
console.log('【功能页 #/ranking】');
|
|
for (const c of rankPage.colInfo) {
|
|
if (c.wide) console.log(` ${(c.key||c.label).padEnd(20)} w=${String(c.w).padStart(4)} thAlign=${c.thAlign}`);
|
|
}
|
|
console.log(' td 对齐:', rankPage.tdAligns.join(' | '));
|
|
const wideCols = rankPage.colInfo.filter((c) => c.wide);
|
|
const rankOk = wideCols.length === 6 && wideCols.every((c) => c.w <= 100 && c.thAlign === 'right') && rankPage.tdAligns.every((t) => !t.startsWith('num') || t.endsWith('right'));
|
|
|
|
// ===== 2) 首页预览表 =====
|
|
await goto('#/');
|
|
const home = await ev(`(() => {
|
|
const row = document.querySelector('#rankPreviewList .rank-row:not(.rank-head)');
|
|
if (!row) return { err: 'no row' };
|
|
const W = (sel) => Math.round(row.querySelector(sel).getBoundingClientRect().width);
|
|
const A = (sel) => getComputedStyle(row.querySelector(sel)).textAlign;
|
|
return {
|
|
score: { w: W('.rk-score'), align: A('.rk-score') },
|
|
fans: { w: W('.rk-num:nth-child(5)'), align: A('.rk-num:nth-child(5)') },
|
|
likes: { w: W('.rk-num:nth-child(6)'), align: A('.rk-num:nth-child(6)') },
|
|
comments: { w: W('.rk-num:nth-child(7)'), align: A('.rk-num:nth-child(7)') },
|
|
shares: { w: W('.rk-num:nth-child(8)'), align: A('.rk-num:nth-child(8)') },
|
|
};
|
|
})()`);
|
|
console.log('【首页预览表】');
|
|
console.log(' ', JSON.stringify(home));
|
|
const homeOk = ['score','fans','likes','comments','shares'].every((k) => home[k] && home[k].w <= 85 && home[k].align === 'right');
|
|
|
|
console.log(rankOk && homeOk ? 'PASS' : 'CHECK: 功能页=' + rankOk + ' 首页=' + homeOk);
|
|
ws.close();
|