Files
ycode/scripts/verify-workbuddy-copy.mjs
T

68 lines
3.7 KiB
JavaScript

// Read-only verification of YCode's actual IPC and renderer after an offline import.
import fs from 'node:fs/promises'
import assert from 'node:assert/strict'
const endpoint = process.argv[2] || 'http://127.0.0.1:9237'
const copy = JSON.parse(await fs.readFile('.tmp/workbuddy-copy-report.json', 'utf8'))
assert.equal(copy.applied, true)
const pause = ms => new Promise(resolve => setTimeout(resolve, ms))
let targets
for (let attempt = 0; attempt < 80; attempt++) {
try { targets = await (await fetch(`${endpoint}/json/list`)).json(); break } catch { await pause(200) }
}
const target = targets?.find(value => value.type === 'page' && (value.title === 'YCode' || value.url.includes('/out/renderer/')))
assert.ok(target, 'YCode renderer must be running')
const socket = new WebSocket(target.webSocketDebuggerUrl)
await new Promise((resolve, reject) => { socket.onopen = resolve; socket.onerror = reject })
let sequence = 0
const pending = new Map()
const exceptions = []
socket.onmessage = event => {
const message = JSON.parse(event.data)
if (message.method === 'Runtime.exceptionThrown') exceptions.push(message.params.exceptionDetails.text)
const request = pending.get(message.id)
if (request) { pending.delete(message.id); message.error ? request.reject(new Error(message.error.message)) : request.resolve(message.result) }
}
const send = (method, params = {}) => new Promise((resolve, reject) => {
const id = ++sequence
pending.set(id, { resolve, reject })
socket.send(JSON.stringify({ id, method, params }))
})
await send('Runtime.enable')
let result
try {
for (let attempt = 0; attempt < 80; attempt++) {
result = await send('Runtime.evaluate', { expression: `(async()=>{
if(!window.ycode?.session)return null;
const list=await window.ycode.session.list();
const session=list.find(item=>item.id===${JSON.stringify(copy.sessionId)});
if(!session)return null;
const messages=await window.ycode.session.messages(session.id);
return {session,sessionCount:list.length,messageCount:messages.length,
tools:messages.flatMap(message=>message.tools??[]).length,
images:messages.flatMap(message=>message.attachments??[]).filter(item=>item.previewUrl?.startsWith('data:image/')).length,
userXmlWrappers:messages.filter(message=>message.role==='user'&&/<user_query>|<system-reminder/.test(message.content)).length,
streaming:messages.filter(message=>message.status==='streaming').length,
renderedUserMessages:document.querySelectorAll('.msg--user').length,
renderedAssistantMessages:document.querySelectorAll('.msg--assistant').length,
titleVisible:[...document.querySelectorAll('.sidebar__item-title')].some(item=>item.textContent===session.title)}
})()`, awaitPromise: true, returnByValue: true })
if (result.result?.value?.titleVisible && result.result.value.renderedUserMessages > 0) break
if (result.exceptionDetails) throw new Error(result.exceptionDetails.text)
await pause(250)
}
const actual = result.result.value
assert.equal(actual.messageCount, copy.stats.importedMessages)
assert.equal(actual.tools, copy.stats.toolCalls)
assert.equal(actual.images, copy.stats.copiedImages)
assert.equal(actual.sessionCount, copy.existingSessionCount + 1)
assert.equal(actual.titleVisible, true)
assert.equal(actual.userXmlWrappers, 0)
assert.equal(actual.streaming, 0)
assert.deepEqual(exceptions, [])
const image = await send('Page.captureScreenshot', { format: 'png', fromSurface: true })
await fs.writeFile('.tmp/ycode-workbuddy-copy.png', Buffer.from(image.data, 'base64'))
await fs.writeFile('.tmp/ycode-workbuddy-copy-ui-report.json', JSON.stringify({ ...actual, exceptions }, null, 2))
console.log(JSON.stringify({ ...actual, exceptions }))
} finally { socket.close() }