import { env, exit, stdin, stdout } from 'node:process' import { createInterface } from 'node:readline' // TODO(@nekomeowww): try now to directly embed binary / base64, even tests. `xz` warned us. const tinyPngBase64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Wn8vO0AAAAASUVORK5CYII=' const state = { sessionTag: env.FAKE_RUNNER_SESSION_TAG || 'vm-local-1', displayId: env.FAKE_RUNNER_DISPLAY_ID || ':99', hostName: env.FAKE_RUNNER_HOST_NAME || 'fake-remote', remoteUser: env.FAKE_RUNNER_REMOTE_USER || 'airi', width: Number.parseInt(env.FAKE_RUNNER_WIDTH || '1280', 10), height: Number.parseInt(env.FAKE_RUNNER_HEIGHT || '720', 10), observationBaseUrl: env.FAKE_RUNNER_OBSERVATION_BASE_URL || '', } function executionTarget() { return { mode: 'remote', transport: 'ssh-stdio', hostName: state.hostName, remoteUser: state.remoteUser, displayId: state.displayId, sessionTag: state.sessionTag, isolated: true, tainted: false, } } function permissionInfo() { return { screenRecording: { status: 'granted', target: `${state.displayId} via scrot`, checkedBy: 'scrot', }, accessibility: { status: 'unsupported', target: `${state.displayId} linux-x11 session`, note: 'linux-x11 runner does not rely on accessibility APIs', }, automationToSystemEvents: { status: 'unsupported', target: `${state.displayId} linux-x11 session`, note: 'linux-x11 runner does not use System Events', }, } } function displayInfo() { return { available: true, platform: 'linux', logicalWidth: state.width, logicalHeight: state.height, pixelWidth: state.width, pixelHeight: state.height, scaleFactor: 1, isRetina: false, note: `managed virtual X session ${state.displayId}`, } } function writeResponse(response) { stdout.write(`${JSON.stringify(response)}\n`) } const rl = createInterface({ input: stdin, crlfDelay: Infinity, }) rl.on('line', (line) => { const trimmed = line.trim() if (!trimmed) { return } const request = JSON.parse(trimmed) if (env.FAKE_RUNNER_CLOSE_ON_MUTATION === '1' && ['click', 'typeText', 'pressKeys', 'scroll'].includes(request.method)) { exit(1) } switch (request.method) { case 'initialize': writeResponse({ id: request.id, ok: true, result: { executionTarget: executionTarget(), displayInfo: displayInfo(), permissionInfo: permissionInfo(), }, }) return case 'getExecutionTarget': writeResponse({ id: request.id, ok: true, result: executionTarget(), }) return case 'getDisplayInfo': writeResponse({ id: request.id, ok: true, result: displayInfo(), }) return case 'getForegroundContext': writeResponse({ id: request.id, ok: true, result: { available: true, appName: 'mousepad', windowTitle: 'Mousepad', platform: 'linux', }, }) return case 'getPermissionInfo': writeResponse({ id: request.id, ok: true, result: permissionInfo(), }) return case 'takeScreenshot': writeResponse({ id: request.id, ok: true, result: { dataBase64: tinyPngBase64, mimeType: 'image/png', ...(state.observationBaseUrl ? { publicUrl: `${state.observationBaseUrl.replace(/\/$/, '')}/fake-screenshot.png`, } : {}), width: state.width, height: state.height, executionTarget: executionTarget(), }, }) return case 'click': case 'typeText': case 'pressKeys': case 'scroll': case 'wait': writeResponse({ id: request.id, ok: true, result: { performed: true, backend: 'linux-x11', notes: [`${request.method} executed`], executionTarget: executionTarget(), }, }) return case 'openTestTarget': writeResponse({ id: request.id, ok: true, result: { launched: true, appName: 'mousepad', windowTitle: 'Mousepad', recommendedClickPoint: { x: 180, y: 150, }, executionTarget: executionTarget(), }, }) return case 'shutdown': writeResponse({ id: request.id, ok: true, result: { ok: true, }, }) exit(0) } })