more logging
This commit is contained in:
@@ -1069,12 +1069,19 @@ async function getLabelBoxesForRefs({
|
|||||||
logger?: { info?: (...args: unknown[]) => void; error?: (...args: unknown[]) => void }
|
logger?: { info?: (...args: unknown[]) => void; error?: (...args: unknown[]) => void }
|
||||||
cdp?: ICDPSession
|
cdp?: ICDPSession
|
||||||
}): Promise<AriaLabel[]> {
|
}): Promise<AriaLabel[]> {
|
||||||
|
const log = logger?.info ?? logger?.error ?? console.error
|
||||||
const session = cdp || await getCDPSessionForPage({ page, wsUrl })
|
const session = cdp || await getCDPSessionForPage({ page, wsUrl })
|
||||||
const sema = new Sema(maxConcurrency)
|
const sema = new Sema(maxConcurrency)
|
||||||
const labelRefs = refs.filter((ref) => {
|
const labelRefs = refs.filter((ref) => {
|
||||||
return Boolean(ref.backendNodeId) && INTERACTIVE_ROLES.has(ref.role)
|
return Boolean(ref.backendNodeId) && INTERACTIVE_ROLES.has(ref.role)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
log(`[getLabelBoxesForRefs] processing ${labelRefs.length} interactive refs (concurrency: ${maxConcurrency})`)
|
||||||
|
const startTime = Date.now()
|
||||||
|
let completed = 0
|
||||||
|
let timedOut = 0
|
||||||
|
let failed = 0
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const labels = await Promise.all(
|
const labels = await Promise.all(
|
||||||
labelRefs.map(async (ref) => {
|
labelRefs.map(async (ref) => {
|
||||||
@@ -1089,8 +1096,12 @@ async function getLabelBoxesForRefs({
|
|||||||
setTimeout(() => { resolve(null) }, BOX_MODEL_TIMEOUT_MS)
|
setTimeout(() => { resolve(null) }, BOX_MODEL_TIMEOUT_MS)
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
completed++
|
||||||
|
if (completed % 50 === 0 || completed === labelRefs.length) {
|
||||||
|
log(`[getLabelBoxesForRefs] progress: ${completed}/${labelRefs.length} (${timedOut} timeouts, ${failed} errors) - ${Date.now() - startTime}ms`)
|
||||||
|
}
|
||||||
if (!response) {
|
if (!response) {
|
||||||
logger?.error?.('[playwriter] getBoxModel timed out for', ref.ref)
|
timedOut++
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const box = buildBoxFromQuad(response.model.border)
|
const box = buildBoxFromQuad(response.model.border)
|
||||||
@@ -1099,13 +1110,15 @@ async function getLabelBoxesForRefs({
|
|||||||
}
|
}
|
||||||
return { ref: ref.ref, role: ref.role, box }
|
return { ref: ref.ref, role: ref.role, box }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger?.error?.('[playwriter] getBoxModel failed for', ref.ref, error)
|
completed++
|
||||||
|
failed++
|
||||||
return null
|
return null
|
||||||
} finally {
|
} finally {
|
||||||
sema.release()
|
sema.release()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
log(`[getLabelBoxesForRefs] done: ${completed} completed, ${timedOut} timeouts, ${failed} errors - ${Date.now() - startTime}ms`)
|
||||||
return labels.filter(isTruthy)
|
return labels.filter(isTruthy)
|
||||||
} finally {
|
} finally {
|
||||||
if (!cdp) {
|
if (!cdp) {
|
||||||
@@ -1145,24 +1158,24 @@ export async function showAriaRefLabels({ page, locator, interactiveOnly = true,
|
|||||||
labelCount: number
|
labelCount: number
|
||||||
}> {
|
}> {
|
||||||
const startTime = Date.now()
|
const startTime = Date.now()
|
||||||
|
const log = logger?.info ?? logger?.error ?? console.error
|
||||||
|
|
||||||
|
log(`[showAriaRefLabels] starting...`)
|
||||||
await ensureA11yClient(page)
|
await ensureA11yClient(page)
|
||||||
|
log(`[showAriaRefLabels] ensureA11yClient: ${Date.now() - startTime}ms`)
|
||||||
|
|
||||||
const log = logger?.info ?? logger?.error
|
const cdpStart = Date.now()
|
||||||
if (log) {
|
|
||||||
log(`ensureA11yClient: ${Date.now() - startTime}ms`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const snapshotStart = Date.now()
|
|
||||||
const cdp = await getCDPSessionForPage({ page, wsUrl })
|
const cdp = await getCDPSessionForPage({ page, wsUrl })
|
||||||
|
log(`[showAriaRefLabels] getCDPSessionForPage: ${Date.now() - cdpStart}ms`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const snapshotStart = Date.now()
|
||||||
const { snapshot, refs } = await getAriaSnapshot({ page, locator, interactiveOnly, wsUrl, cdp })
|
const { snapshot, refs } = await getAriaSnapshot({ page, locator, interactiveOnly, wsUrl, cdp })
|
||||||
const shortRefMap = new Map(refs.map((entry) => {
|
const shortRefMap = new Map(refs.map((entry) => {
|
||||||
return [entry.ref, entry.shortRef]
|
return [entry.ref, entry.shortRef]
|
||||||
}))
|
}))
|
||||||
if (log) {
|
const interactiveRefs = refs.filter((ref) => Boolean(ref.backendNodeId) && INTERACTIVE_ROLES.has(ref.role))
|
||||||
log(`getAriaSnapshot: ${Date.now() - snapshotStart}ms`)
|
log(`[showAriaRefLabels] getAriaSnapshot: ${Date.now() - snapshotStart}ms (${refs.length} refs, ${interactiveRefs.length} interactive)`)
|
||||||
}
|
|
||||||
|
|
||||||
const rootHandle = locator ? await locator.elementHandle() : null
|
const rootHandle = locator ? await locator.elementHandle() : null
|
||||||
|
|
||||||
@@ -1174,9 +1187,7 @@ export async function showAriaRefLabels({ page, locator, interactiveOnly = true,
|
|||||||
ref: shortRefMap.get(label.ref) ?? label.ref,
|
ref: shortRefMap.get(label.ref) ?? label.ref,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (log) {
|
log(`[showAriaRefLabels] getLabelBoxesForRefs: ${Date.now() - labelsStart}ms (${labels.length} boxes)`)
|
||||||
log(`getLabelBoxesForRefs: ${Date.now() - labelsStart}ms (${labels.length} boxes)`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderStart = Date.now()
|
const renderStart = Date.now()
|
||||||
const labelCount = await page.evaluate(({ entries, root, interactiveOnly: intOnly }) => {
|
const labelCount = await page.evaluate(({ entries, root, interactiveOnly: intOnly }) => {
|
||||||
@@ -1196,9 +1207,8 @@ export async function showAriaRefLabels({ page, locator, interactiveOnly = true,
|
|||||||
throw new Error('a11y client not loaded')
|
throw new Error('a11y client not loaded')
|
||||||
}, { entries: shortLabels, root: rootHandle, interactiveOnly })
|
}, { entries: shortLabels, root: rootHandle, interactiveOnly })
|
||||||
|
|
||||||
if (log) {
|
log(`[showAriaRefLabels] renderA11yLabels: ${Date.now() - renderStart}ms (${labelCount} labels)`)
|
||||||
log(`renderA11yLabels: ${Date.now() - renderStart}ms (${labelCount} labels)`)
|
log(`[showAriaRefLabels] total: ${Date.now() - startTime}ms`)
|
||||||
}
|
|
||||||
|
|
||||||
return { snapshot, labelCount }
|
return { snapshot, labelCount }
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
+20
-20
@@ -1116,61 +1116,61 @@ export async function startPlayWriterCDPRelayServer({
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
// CLI Execute Endpoints - For stateful code execution via CLI
|
// CLI Execute Endpoints - For stateful code execution via CLI
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// Session counter for suggesting next session number
|
// Session counter for suggesting next session number
|
||||||
let nextSessionNumber = 1
|
let nextSessionNumber = 1
|
||||||
|
|
||||||
// Lazy-load ExecutorManager to avoid circular imports and only when needed
|
// Lazy-load ExecutorManager to avoid circular imports and only when needed
|
||||||
let executorManager: import('./executor.js').ExecutorManager | null = null
|
let executorManager: import('./executor.js').ExecutorManager | null = null
|
||||||
|
|
||||||
const getExecutorManager = async () => {
|
const getExecutorManager = async () => {
|
||||||
if (!executorManager) {
|
if (!executorManager) {
|
||||||
const { ExecutorManager } = await import('./executor.js')
|
const { ExecutorManager } = await import('./executor.js')
|
||||||
// Pass config instead of URL so executor can generate unique client IDs for each connection
|
// Pass config instead of URL so executor can generate unique client IDs for each connection
|
||||||
executorManager = new ExecutorManager({
|
executorManager = new ExecutorManager({
|
||||||
cdpConfig: { host: '127.0.0.1', port },
|
cdpConfig: { host: '127.0.0.1', port },
|
||||||
logger: logger || { log: console.log, error: console.error },
|
logger: logger || { log: console.error, error: console.error },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return executorManager
|
return executorManager
|
||||||
}
|
}
|
||||||
|
|
||||||
app.post('/cli/execute', async (c) => {
|
app.post('/cli/execute', async (c) => {
|
||||||
try {
|
try {
|
||||||
const body = await c.req.json() as { sessionId: string; code: string; timeout?: number; cwd?: string }
|
const body = await c.req.json() as { sessionId: string; code: string; timeout?: number; cwd?: string }
|
||||||
const { sessionId, code, timeout = 10000, cwd } = body
|
const { sessionId, code, timeout = 10000, cwd } = body
|
||||||
|
|
||||||
if (!sessionId || !code) {
|
if (!sessionId || !code) {
|
||||||
return c.json({ error: 'sessionId and code are required' }, 400)
|
return c.json({ error: 'sessionId and code are required' }, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
const manager = await getExecutorManager()
|
const manager = await getExecutorManager()
|
||||||
const executor = manager.getExecutor(sessionId, cwd)
|
const executor = manager.getExecutor(sessionId, cwd)
|
||||||
const result = await executor.execute(code, timeout)
|
const result = await executor.execute(code, timeout)
|
||||||
|
|
||||||
// Increment session counter after each execution to avoid conflicts
|
// Increment session counter after each execution to avoid conflicts
|
||||||
nextSessionNumber++
|
nextSessionNumber++
|
||||||
|
|
||||||
return c.json(result)
|
return c.json(result)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
logger?.error('Execute endpoint error:', error)
|
logger?.error('Execute endpoint error:', error)
|
||||||
return c.json({ text: `Server error: ${error.message}`, images: [], isError: true }, 500)
|
return c.json({ text: `Server error: ${error.message}`, images: [], isError: true }, 500)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
app.post('/cli/reset', async (c) => {
|
app.post('/cli/reset', async (c) => {
|
||||||
try {
|
try {
|
||||||
const body = await c.req.json() as { sessionId: string; cwd?: string }
|
const body = await c.req.json() as { sessionId: string; cwd?: string }
|
||||||
const { sessionId, cwd } = body
|
const { sessionId, cwd } = body
|
||||||
|
|
||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
return c.json({ error: 'sessionId is required' }, 400)
|
return c.json({ error: 'sessionId is required' }, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
const manager = await getExecutorManager()
|
const manager = await getExecutorManager()
|
||||||
const executor = manager.getExecutor(sessionId, cwd)
|
const executor = manager.getExecutor(sessionId, cwd)
|
||||||
const { page, context } = await executor.reset()
|
const { page, context } = await executor.reset()
|
||||||
|
|
||||||
return c.json({
|
return c.json({
|
||||||
success: true,
|
success: true,
|
||||||
pageUrl: page.url(),
|
pageUrl: page.url(),
|
||||||
@@ -1181,32 +1181,32 @@ export async function startPlayWriterCDPRelayServer({
|
|||||||
return c.json({ error: error.message }, 500)
|
return c.json({ error: error.message }, 500)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/cli/sessions', async (c) => {
|
app.get('/cli/sessions', async (c) => {
|
||||||
const manager = await getExecutorManager()
|
const manager = await getExecutorManager()
|
||||||
return c.json({ sessions: manager.listSessions() })
|
return c.json({ sessions: manager.listSessions() })
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/cli/session/suggest', (c) => {
|
app.get('/cli/session/suggest', (c) => {
|
||||||
return c.json({ next: nextSessionNumber })
|
return c.json({ next: nextSessionNumber })
|
||||||
})
|
})
|
||||||
|
|
||||||
app.post('/cli/session/delete', async (c) => {
|
app.post('/cli/session/delete', async (c) => {
|
||||||
try {
|
try {
|
||||||
const body = await c.req.json() as { sessionId: string }
|
const body = await c.req.json() as { sessionId: string }
|
||||||
const { sessionId } = body
|
const { sessionId } = body
|
||||||
|
|
||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
return c.json({ error: 'sessionId is required' }, 400)
|
return c.json({ error: 'sessionId is required' }, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
const manager = await getExecutorManager()
|
const manager = await getExecutorManager()
|
||||||
const deleted = manager.deleteExecutor(sessionId)
|
const deleted = manager.deleteExecutor(sessionId)
|
||||||
|
|
||||||
if (!deleted) {
|
if (!deleted) {
|
||||||
return c.json({ error: `Session ${sessionId} not found` }, 404)
|
return c.json({ error: `Session ${sessionId} not found` }, 404)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.json({ success: true })
|
return c.json({ success: true })
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
logger?.error('Delete session endpoint error:', error)
|
logger?.error('Delete session endpoint error:', error)
|
||||||
|
|||||||
Reference in New Issue
Block a user