mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 08:03:20 +00:00
Session snapshot/feed/activate/close/createBrowser/createTerminal, quick commands and agent options now run as Desktop mobileWeb.* adapters behind the generic host-request forwarder instead of shell translators. Voice, notification, terminal, browser, chat, About and diagnostics settings render as hosted page routes with native-*/web-* operation backends. Adds the hosted WebView e2e journeys used to validate them. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
59 lines
2.0 KiB
JavaScript
59 lines
2.0 KiB
JavaScript
import { WebSocket } from 'ws'
|
|
import {
|
|
evaluateHostedDocumentWithRetry,
|
|
readHostedWebViewState
|
|
} from './hosted-webview-cdp-session.mjs'
|
|
|
|
export async function readHostedWebViewControlPoint(
|
|
document,
|
|
label,
|
|
WebSocketCtor = WebSocket,
|
|
options = {}
|
|
) {
|
|
const expression = `(() => {
|
|
const element = ${options.matchText === true}
|
|
? Array.from(document.querySelectorAll('[role=button]')).find((candidate) => candidate.textContent.trim() === ${JSON.stringify(label)})
|
|
: Array.from(document.querySelectorAll('[aria-label]')).find((candidate) => candidate.getAttribute('aria-label') === ${JSON.stringify(label)});
|
|
if (!(element instanceof HTMLElement)) return '';
|
|
element.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
const rect = element.getBoundingClientRect();
|
|
const screenWidth = Number(screen.width);
|
|
const screenHeight = Number(screen.height);
|
|
const viewportTop = Math.max(0, screenHeight - Number(innerHeight));
|
|
return JSON.stringify({
|
|
x: (rect.left + rect.width / 2) / screenWidth,
|
|
y: (viewportTop + rect.top + rect.height / 2) / screenHeight
|
|
});
|
|
})()`
|
|
const value = await evaluateHostedDocumentWithRetry(document, expression, WebSocketCtor)
|
|
let point
|
|
try {
|
|
point = JSON.parse(value)
|
|
} catch {
|
|
const state = await readHostedWebViewState(document, WebSocketCtor).catch(() => null)
|
|
throw new Error(
|
|
`Hosted WebView control was not measurable: ${label}. State: ${JSON.stringify({
|
|
path: state ? new URL(state.href).pathname : null,
|
|
labels: state?.labels?.slice(0, 40),
|
|
text: state?.bodyText?.slice(0, 1000)
|
|
})}`
|
|
)
|
|
}
|
|
if (!isNormalizedPoint(point)) {
|
|
throw new Error(`Hosted WebView returned an invalid control point: ${label}`)
|
|
}
|
|
return point
|
|
}
|
|
|
|
function isNormalizedPoint(point) {
|
|
return (
|
|
point &&
|
|
Number.isFinite(point.x) &&
|
|
Number.isFinite(point.y) &&
|
|
point.x >= 0 &&
|
|
point.x <= 1 &&
|
|
point.y >= 0 &&
|
|
point.y <= 1
|
|
)
|
|
}
|