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

@@ -0,0 +1,47 @@
/** Own Electron fixture; no original runtime access. */
import fs from 'node:fs'
import path from 'node:path'
import assert from 'node:assert/strict'
import{createRequire}from'node:module'
import{spawn}from'node:child_process'
const require=createRequire(import.meta.url),module=require('electron'),electron=typeof module==='object'&&module.app?module:null
if(electron){electron.app.disableHardwareAcceleration();electron.app.commandLine.appendSwitch('use-angle','swiftshader');electron.app.commandLine.appendSwitch('disable-gpu-compositing')}
const root=path.resolve('.'),base=path.join(root,'.tmp')
if(!electron){const output=fs.mkdtempSync(path.join(base,'composer-add-menu-native-')),env={...process.env};delete env.ELECTRON_RUN_AS_NODE;delete env.ELECTRON_RENDERER_URL;const child=spawn(module,['--no-sandbox','--disable-gpu-sandbox',path.resolve('scripts/rea/test-composer-add-menu-native.mjs'),output],{env,windowsHide:true,stdio:'inherit'});process.exitCode=await new Promise(resolve=>child.on('exit',code=>resolve(code??1)))}
else void(async()=>{
const{app,BrowserWindow}=electron,output=path.resolve(process.argv.at(-1));assert.ok(path.relative(base,output).startsWith('composer-add-menu-native-')&&!path.relative(base,output).includes('..'));fs.mkdirSync(path.join(output,'data'));app.setPath('userData',path.join(output,'data'));await app.whenReady()
const location=file=>JSON.stringify(path.join(root,file).replaceAll('\\','/'))
fs.writeFileSync(path.join(output,'fixture.tsx'),`import React,{useState}from'react';import{createRoot}from'react-dom/client';import Add from ${location('src/renderer/src/workbuddy/composer/add-menu/SourceComposerAddMenu')};import{Menu,MenuItem}from ${location('src/renderer/src/workbuddy/composer/add-menu/source.mjs')};import ${location('src/renderer/src/styles/tokens.css')};import ${location('src/renderer/src/styles/app.css')};import ${location('src/renderer/src/workbuddy/conversation/source-styles.css')};
window.qa={actions:[],changes:[],opens:0,closes:0,slotCalls:0};const entries=[{id:'add-files',children:[{id:'local',label:'本地文件'},{id:'disabled-child',label:'Disabled',disabled:true}]},{id:'mode',children:[{id:'craft',label:'任务'}]},{id:'experts'},{id:'skills'},{id:'connectors',children:[{id:'configure',label:'配置连接器'}]},{id:'disabled-leaf',label:'Disabled leaf',disabled:true},{id:'leaf',label:'Direct action'}];function App(){const[disabled,setDisabled]=useState(false),[scope,setScope]=useState('A'),[custom,setCustom]=useState(false),[items,setItems]=useState(entries),[controlled,setControlled]=useState(false),[open,setOpen]=useState(false);Object.assign(window.qa,{setDisabled,setScope,setCustom,setItems,setControlled,setOpen});return<div className="chat-pane cr-theme" data-cr-theme="light" style={{height:'100vh'}}><button id="outside" style={{position:'absolute',left:10,top:10}}>Outside</button><div id="anchor" style={{position:'absolute',left:400,top:600}}><Add entries={items} scopeKey={scope} disabled={disabled} open={controlled?open:undefined} onOpenChange={value=>{window.qa.changes.push(value);if(controlled)setOpen(value)}} onOpen={()=>window.qa.opens++} onClose={()=>window.qa.closes++} onAction={id=>window.qa.actions.push(id)} renderTrigger={custom?({isOpen})=><button id="custom" aria-label="custom" data-host-open={isOpen}>Host</button>:undefined} slots={{experts:({closeMenu})=><Menu><MenuItem itemId="expert-item" onClick={()=>{window.qa.slotCalls++;closeMenu()}}>Real expert slot</MenuItem></Menu>,skills:({closeMenu})=><div role="menu"><input id="skill-query" aria-label="技能搜索"/><button id="skill-select" role="menuitem" onClick={()=>{window.qa.slotCalls++;closeMenu()}}>Real skill slot</button></div>}}/></div></div>}createRoot(document.getElementById('root')).render(<App/>);`)
await require('esbuild').build({entryPoints:[path.join(output,'fixture.tsx')],bundle:true,platform:'browser',format:'iife',jsx:'automatic',outfile:path.join(output,'fixture.js'),logLevel:'warning'})
fs.writeFileSync(path.join(output,'index.html'),'<html data-theme="light"><head><meta charset="utf-8"><link rel="stylesheet" href="fixture.css"><style>html,body,#root{margin:0;width:100%;height:100%}</style></head><body><div id="root"></div><script src="fixture.js"></script></body></html>')
const win=new BrowserWindow({width:1336,height:901,frame:false,useContentSize:true,show:false,webPreferences:{contextIsolation:true,nodeIntegration:false,backgroundThrottling:false}}),checks=[],errors=[],measurements={}
win.webContents.on('console-message',event=>{if(event.level==='error')errors.push(event.message)});await win.loadFile(path.join(output,'index.html'));win.webContents.debugger.attach('1.3');await win.webContents.debugger.sendCommand('Page.enable');win.showInactive()
const read=code=>win.webContents.executeJavaScript(code),cdp=(method,args)=>win.webContents.debugger.sendCommand(method,args),pause=ms=>new Promise(resolve=>setTimeout(resolve,ms)),check=(name,actual,expected)=>{assert.deepEqual(actual,expected,name);checks.push(name)}
const wait=async code=>{for(let i=0;i<100;i++){if(await read(code))return;await pause(30)}throw Error('Timeout '+code)}
const bounds=selector=>read(`(()=>{const r=document.querySelector(${JSON.stringify(selector)}).getBoundingClientRect();return[r.x,r.y,r.width,r.height]})()`)
const move=async selector=>{const r=await bounds(selector);await cdp('Input.dispatchMouseEvent',{type:'mouseMoved',x:r[0]+r[2]/2,y:r[1]+r[3]/2});await pause(170)}
const click=async selector=>{await move(selector);const r=await bounds(selector);for(const type of ['mousePressed','mouseReleased'])await cdp('Input.dispatchMouseEvent',{type,x:r[0]+r[2]/2,y:r[1]+r[3]/2,button:'left',clickCount:1});await pause(200)}
const key=async key=>{for(const type of ['keyDown','keyUp'])await cdp('Input.dispatchKeyEvent',{type,key,code:key,windowsVirtualKeyCode:({Enter:13,Escape:27,ArrowDown:40,ArrowUp:38,ArrowRight:39,ArrowLeft:37,Home:36,End:35})[key]??32,...type==='keyDown'&&key==='Enter'?{text:'\r'}:{}});await pause(200)}
const update=async code=>{await read(code);await pause(200)},capture=async name=>fs.writeFileSync(path.join(output,name+'.png'),Buffer.from((await cdp('Page.captureScreenshot',{format:'png',fromSurface:true})).data,'base64'))
const open=async()=>{await click('.wb-composer__add-button');await wait('!!document.querySelector(".cr-add-menu__popover")')}
try{
await wait('!!document.querySelector(".wb-composer__add-button")');measurements.trigger=await bounds('.wb-composer__add-button');check('source WB ghost medium circular trigger geometry',measurements.trigger.slice(2),[32,32]);check('compatible trigger aria label',await read('document.querySelector(".wb-composer__add-button").getAttribute("aria-label")'),'添加');check('closed initially',await read('!!document.querySelector(".cr-add-menu__popover")'),false)
await open();check('source trigger role/expanded retained',await read('[document.querySelector(".wb-composer__add-button").getAttribute("role"),document.querySelector(".wb-composer__add-button").getAttribute("aria-expanded")]'),['combobox','true']);measurements.parent=await bounds('.cr-add-menu__popover');check('source parent width200',measurements.parent[2],200);check('source top-start x400',measurements.parent[0],400);check('source top offset8',Math.round(measurements.parent[1]+measurements.parent[3]),592);check('six source standard/action entries',await read('document.querySelectorAll(".cr-add-menu__popover [data-add-menu-id]").length'),7);check('source entry row32',(await bounds('[data-add-menu-id=experts]'))[3],32);check('source file section divider',await read('document.querySelectorAll(".cr-add-menu__popover [role=separator]").length'),1);check('standard entry source SVGs',await read('[...document.querySelectorAll(".cr-add-menu__popover .cr-menu-item__icon svg")].length'),5);await capture('parent')
await move('[data-add-menu-id=experts]');await wait('!!document.querySelector(".cr-sub-menu__overlay [data-add-menu-id=expert-item]")');measurements.expert=await bounds('.cr-sub-menu__overlay');const expertRow=await bounds('[data-add-menu-id=experts]');check('source right-start submenu row offset4',measurements.expert[0],expertRow[0]+expertRow[2]+4);check('source selected parent open metadata',await read('document.querySelector("[data-add-menu-id=experts]").parentElement.dataset.submenuOpen'),'true');await move('[data-add-menu-id=expert-item]');check('pointer crossing retains parent and sub',await read('[!!document.querySelector(".cr-add-menu__popover"),!!document.querySelector(".cr-sub-menu__overlay")]'),[true,true]);await capture('expert-slot')
await click('[data-add-menu-id=expert-item]');await wait('!document.querySelector(".cr-add-menu__popover")');check('host slot action and close use real callback',await read('window.qa.slotCalls'),1);check('closing removes child portal',await read('!!document.querySelector(".cr-sub-menu__overlay")'),false)
await open();await move('[data-add-menu-id=skills]');await wait('!!document.querySelector("#skill-query")');await click('#skill-query');await cdp('Input.insertText',{text:'中文 skill'});check('embedded skill input remains usable',await read('document.querySelector("#skill-query").value'),'中文 skill');await click('#skill-select');await wait('!document.querySelector(".cr-add-menu__popover")');check('skill slot closes entire parent',await read('window.qa.slotCalls'),2)
await open();await move('[data-add-menu-id=add-files]');await wait('!!document.querySelector("[data-add-menu-id=local]")');await click('[data-add-menu-id=disabled-child]');check('disabled child does not dispatch',await read('window.qa.actions.length'),0);await click('[data-add-menu-id=local]');await wait('!document.querySelector(".cr-add-menu__popover")');check('generic submenu exact action',await read('window.qa.actions'),['local'])
await open();await click('[data-add-menu-id=disabled-leaf]');check('disabled leaf does not dispatch/close',await read('[window.qa.actions.length,!!document.querySelector(".cr-add-menu__popover")]'),[1,true]);await click('[data-add-menu-id=leaf]');await wait('!document.querySelector(".cr-add-menu__popover")');check('leaf action closes',await read('window.qa.actions'),['local','leaf'])
await open();await click('#outside');await wait('!document.querySelector(".cr-add-menu__popover")');check('outside closes source popover',await read('document.querySelector(".wb-composer__add-button").getAttribute("aria-expanded")'),'false')
await open();win.webContents.focus();await read('document.querySelector("[data-add-menu-id=experts]").focus()');await key('ArrowRight');await wait('!!document.querySelector("[data-add-menu-id=expert-item]")');check('source ArrowRight focuses submenu first',await read('document.activeElement.dataset.addMenuId'),'expert-item');await key('ArrowLeft');check('source ArrowLeft closes child only',await read('[!!document.querySelector(".cr-sub-menu__overlay"),!!document.querySelector(".cr-add-menu__popover"),document.activeElement.dataset.addMenuId]'),[false,true,'experts']);await key('Escape');await wait('!document.querySelector(".cr-add-menu__popover")');check('source Escape closes parent',await read('document.querySelector(".wb-composer__add-button").getAttribute("aria-expanded")'),'false')
await open();await move('[data-add-menu-id=experts]');await update('window.qa.setScope("B")');check('owner change destroys parent and submenu',await read('[!!document.querySelector(".cr-add-menu__popover"),!!document.querySelector(".cr-sub-menu__overlay")]'),[false,false]);await update('window.qa.setDisabled(true)');await click('.wb-composer__add-button');check('disabled trigger does not open',await read('!!document.querySelector(".cr-add-menu__popover")'),false)
await update('window.qa.setDisabled(false);window.qa.setControlled(true)');await open();check('controlled open callback connected',await read('window.qa.changes.at(-1)'),true);await update('window.qa.setOpen(false)');await wait('!document.querySelector(".cr-add-menu__popover")');check('controlled parent close clears floating children',await read('!!document.querySelector(".cr-sub-menu__overlay")'),false)
await update('window.qa.setControlled(false);window.qa.setCustom(true)');await click('#custom');await wait('!!document.querySelector(".cr-add-menu__popover")');check('custom trigger cloned by literal source events',await read('[document.querySelector("#custom").getAttribute("aria-expanded"),document.querySelector("#custom").dataset.hostOpen]'),['true','true']);await key('Escape');await wait('!document.querySelector(".cr-add-menu__popover")')
await update('window.qa.setCustom(false);window.qa.setItems([{id:"add-files",children:[{id:"local",label:"本地文件"}]},{id:"mode",children:[{id:"craft",label:"任务"}]},{id:"experts"},{id:"skills"},{id:"connectors",children:[{id:"configure",label:"配置连接器"}]}])');await open();measurements.sameState=await bounds('.cr-add-menu__popover .cr-menu');check('source actual five-entry menu geometry200x201',measurements.sameState.slice(2),[200,201]);check('source actual row width182',(await bounds('[data-add-menu-id=experts]'))[2],182)
const original=JSON.parse(fs.readFileSync('.tmp/rea-add-menu-open-settled-20261016/layout.json','utf8')).layout.documents.flatMap(document=>document.nodes)
for(const[selector,className,properties]of [['.cr-add-menu__popover .cr-menu','cr-menu',['border-radius','padding-left','padding-right','padding-top','padding-bottom','gap','background-color','box-shadow']],['[data-add-menu-id=experts]','cr-menu-item',['font-family','font-size','line-height','border-radius','padding-left','padding-right','color']]]){const node=original.find(item=>item.attributes?.class===className);assert(node,'Saved REA source node');const actual=await read(`(()=>{const style=getComputedStyle(document.querySelector(${JSON.stringify(selector)}));return Object.fromEntries(${JSON.stringify(properties)}.map(key=>[key,style.getPropertyValue(key)]))})()`);check('saved REA computed '+className,actual,Object.fromEntries(properties.map(key=>[key,node.styles[key]])))}await capture('source-same-state');await click('#outside');await wait('!document.querySelector(".cr-add-menu__popover")')
await update('window.qa.setItems([])');check('no available entries means no fake trigger',await read('!!document.querySelector(".wb-composer__add-button")'),false);check('no renderer exceptions',errors,[])
fs.writeFileSync(path.join(output,'report.json'),JSON.stringify({result:'PASS',checks,measurements,scope:'Own Electron execution of recovered fixed REA bodies and typed slots; no whole-app original pixel claim'},null,2));console.log(JSON.stringify({result:'PASS',checks:checks.length,output}));win.destroy();app.exit(0)
}catch(error){await capture('failure');fs.writeFileSync(path.join(output,'failure.json'),JSON.stringify({error:String(error),checks,errors,html:await read('document.body.innerHTML')},null,2));console.error(error);win.destroy();app.exit(1)}
})().catch(error=>{console.error(error);electron.app.exit(1)})