工作台:目录改名 mcn-workshop + 任务进度可见 + 会话归属配置化

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 分钟超时,用户零感知)
This commit is contained in:
maogeigei committed 2026-10-08 13:09:06 +08:00
1 parent d07049ecf1
commit f77735b206
115 files changed
+1103 -1514

No files matched your search

@@ -0,0 +1,70 @@
// 验证「账号设定」内容区左右 20px 间隔(persona-wrap padding 0 20px)
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 (url) => {
await send('Page.navigate', { url });
await sleep(2500);
await send('Page.reload', { ignoreCache: true });
await sleep(3000);
};
console.log('=== 旧梦留声机 1629(有卡片)===');
await goto('http://localhost:8899/#/account/1629');
const tabClick = await ev(`(() => {
const b = document.querySelector('[data-tab="persona"]');
if (!b) return { err: 'no persona tab' };
b.click();
return 'clicked persona tab';
})()`);
console.log('切tab:', JSON.stringify(tabClick));
await sleep(1800);
const s1 = await ev(`(() => {
const wrap = document.querySelector('.persona-wrap');
const card = document.querySelector('.card-view');
const img = card && card.querySelector('img');
if (!wrap) return { err: 'no .persona-wrap' };
const cs = getComputedStyle(wrap);
const dbody = document.querySelector('.detail-body');
const dw = dbody ? dbody.getBoundingClientRect().width : null;
const ww = wrap.getBoundingClientRect().width;
const iw = img ? img.getBoundingClientRect().width : null;
return {
paddingLeft: cs.paddingLeft,
paddingRight: cs.paddingRight,
detailBodyW: dw,
wrapW: ww,
imgW: iw,
imgInset: iw !== null && dw !== null ? (dw - iw).toFixed(1) : null, // 卡片比内容区窄多少(两侧总和)
};
})()`);
console.log('persona padding 检查:', JSON.stringify(s1, null, 2));
// 切文字版后再看文字容器
const s2 = await ev(`(() => {
const btn = document.querySelector('.persona-vs-icons [data-vs="text"]');
if (btn) btn.click();
return 'switched to text';
})()`);
await sleep(600);
const s3 = await ev(`(() => {
const md = document.querySelector('.persona-text');
if (!md) return { err: 'no .persona-text' };
const dbody = document.querySelector('.detail-body');
const dw = dbody ? dbody.getBoundingClientRect().width : null;
const mw = md.getBoundingClientRect().width;
return { mdW: mw, inset: dw !== null ? (dw - mw).toFixed(1) : null };
})()`);
console.log('文字版检查:', JSON.stringify(s3, null, 2));
ws.close();
console.log('DONE');