chore: establish YCode replication baseline and TODO

This commit is contained in:
xiaohan.yuan committed 2026-10-17 02:43:49 +08:00
commit 6dc59f89ba
1118 files changed
+196002

No files matched your search

+151
View File
@@ -0,0 +1,151 @@
import './wb-legacy-disabled.mjs'
/**
* 完整采集对标外围结构:侧栏(品牌/导航/分组/账号)、搜索、通知、设置入口。
*
* 用法:node scripts/wb-shell.mjs <port> [outJson]
*/
import { writeFile } from 'node:fs/promises'
const port = Number(process.argv[2] ?? 9223)
const outJson = process.argv[3] ?? null
const PROPS = [
'display',
'flex-direction',
'align-items',
'justify-content',
'width',
'height',
'min-height',
'padding-top',
'padding-right',
'padding-bottom',
'padding-left',
'margin-top',
'margin-bottom',
'gap',
'background-color',
'color',
'border-top-width',
'border-top-color',
'border-radius',
'font-size',
'font-weight',
'line-height',
'opacity',
'position'
]
async function main() {
const list = await (await fetch(`http://127.0.0.1:${port}/json/list`)).json()
const page = list.filter((t) => t.type === 'page')[0]
if (!page) throw new Error('未找到页面')
const ws = new WebSocket(page.webSocketDebuggerUrl)
await new Promise((r, j) => {
const t = setTimeout(() => j(new Error('连接超时')), 8000)
ws.addEventListener('open', () => {
clearTimeout(t)
r()
})
ws.addEventListener('error', () => {
clearTimeout(t)
j(new Error('连接失败'))
})
})
const send = (method, params = {}) =>
new Promise((res, rej) => {
const id = Math.floor(Math.random() * 1e9)
const timer = setTimeout(() => rej(new Error(`超时 ${method}`)), 25000)
const h = (ev) => {
const m = JSON.parse(ev.data)
if (m.id === id) {
clearTimeout(timer)
ws.removeEventListener('message', h)
res(m.result)
}
}
ws.addEventListener('message', h)
ws.send(JSON.stringify({ id, method, params }))
})
const expr = `(() => {
const PROPS = ${JSON.stringify(PROPS)};
const clean = (v) => (v == null ? '' : String(v).replace(/\\s+/g, ' ').trim());
const picked = (el) => {
const cs = getComputedStyle(el);
const o = {};
for (const p of PROPS) {
const v = clean(cs.getPropertyValue(p));
if (v && v !== 'normal' && v !== 'auto' && v !== 'none' && v !== '0px' && v !== 'rgba(0, 0, 0, 0)') o[p] = v;
}
return o;
};
const rect = (el) => { const r = el.getBoundingClientRect(); return [Math.round(r.x), Math.round(r.y), Math.round(r.width), Math.round(r.height)]; };
// 1) 侧栏完整子树(含文字节点)
const side = document.querySelector('.conversation-sidebar') || document.querySelector('[class*="sidebar"]');
const sidebar = [];
if (side) {
const walk = (el, depth) => {
if (depth > 12) return;
const r = el.getBoundingClientRect();
if (r.width < 1 || r.height < 1) return;
const kids = [...el.children];
const ownText = kids.length === 0 ? clean(el.textContent).slice(0, 60) : '';
sidebar.push({ d: depth, tag: el.tagName.toLowerCase(), cls: clean(el.className).slice(0, 90), text: ownText, rect: rect(el), st: picked(el) });
kids.forEach((c) => walk(c, depth + 1));
};
walk(side, 0);
}
// 2) 全局搜外围相关元素(搜索/通知/账号/设置)
const keyword = /search|notif|account|avatar|user|profile|setting|login|inbox|message|bell/i;
const found = [];
document.querySelectorAll('[class]').forEach((el) => {
if (typeof el.className !== 'string') return;
if (!keyword.test(el.className)) return;
const r = el.getBoundingClientRect();
if (r.width < 8 || r.height < 8) return;
found.push({ cls: clean(el.className).slice(0, 100), rect: rect(el), text: clean(el.textContent).slice(0, 60), st: picked(el) });
});
return JSON.stringify({
viewport: { w: innerWidth, h: innerHeight },
sidebar,
found: found.slice(0, 60)
});
})()`
const r = await send('Runtime.evaluate', { expression: expr, returnByValue: true })
const data = JSON.parse(r.result.value)
console.log(`viewport ${data.viewport.w}x${data.viewport.h}`)
console.log(`\n===== 侧栏子树(${data.sidebar.length} 节点)=====`)
for (const n of data.sidebar) {
const cls = n.cls ? '.' + n.cls.split(/\s+/).slice(0, 2).join('.') : ''
const txt = n.text ? ` "${n.text}"` : ''
console.log(`${' '.repeat(n.d)}${n.tag}${cls} [${n.rect.join(',')}]${txt}`)
const keys = Object.keys(n.st)
if (keys.length) console.log(`${' '.repeat(n.d)} ${JSON.stringify(n.st)}`)
}
console.log(`\n===== 外围相关元素(${data.found.length})=====`)
for (const f of data.found) {
console.log(` .${f.cls.split(/\s+/).slice(0, 2).join('.')} [${f.rect.join(',')}] "${f.text}"`)
}
if (outJson) {
await writeFile(outJson, JSON.stringify(data, null, 2), 'utf8')
console.log(`\n已写出 ${outJson}`)
}
ws.close()
}
main().catch((e) => {
console.error('失败:', e.message)
process.exit(1)
})