130 lines
4.1 KiB
JavaScript
130 lines
4.1 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { existsSync } from 'node:fs'
|
|
import { homedir } from 'node:os'
|
|
import { resolve } from 'node:path'
|
|
import { spawnSync } from 'node:child_process'
|
|
|
|
const repoRoot = resolve(import.meta.dirname, '..', '..')
|
|
const cliPath = resolve(repoRoot, 'out', 'cli', 'index.js')
|
|
const args = new Set(process.argv.slice(2))
|
|
const requestedApps = valueFlag('--apps')
|
|
const includeScreenshot = args.has('--screenshot')
|
|
const session = valueFlag('--session') ?? `computer-smoke-${process.pid}`
|
|
const preferredApps = (requestedApps ?? process.env.ORCA_COMPUTER_SMOKE_APPS ?? 'Finder,TextEdit,Spotify,Slack,Microsoft Edge')
|
|
.split(',')
|
|
.map((app) => app.trim())
|
|
.filter(Boolean)
|
|
|
|
if (!existsSync(cliPath)) {
|
|
fail(`Missing built CLI at ${cliPath}. Run pnpm build:cli first.`)
|
|
}
|
|
|
|
const list = unwrapResult(runCli(['computer', 'list-apps', '--json']))
|
|
const apps = Array.isArray(list.apps) ? list.apps : []
|
|
const availableNames = new Set(apps.map((app) => String(app.name ?? '').toLowerCase()))
|
|
const availableBundles = new Set(apps.map((app) => String(app.bundleId ?? '').toLowerCase()).filter(Boolean))
|
|
const targets = preferredApps.filter((app) => availableNames.has(app.toLowerCase()) || availableBundles.has(app.toLowerCase()))
|
|
|
|
console.log(`computer-use smoke: ${apps.length} apps listed`)
|
|
if (targets.length === 0) {
|
|
console.log(`computer-use smoke: no preferred apps are running (${preferredApps.join(', ')})`)
|
|
process.exit(0)
|
|
}
|
|
|
|
let failures = 0
|
|
for (const app of targets) {
|
|
const result = runCli([
|
|
'computer',
|
|
'get-app-state',
|
|
'--session',
|
|
session,
|
|
'--app',
|
|
app,
|
|
...(includeScreenshot ? [] : ['--no-screenshot']),
|
|
'--json'
|
|
], { allowFailure: true })
|
|
|
|
if (!result.ok) {
|
|
failures += 1
|
|
console.log(`computer-use smoke: ${app}: failed: ${result.error}`)
|
|
continue
|
|
}
|
|
|
|
const state = unwrapResult(result.value)
|
|
const snapshot = state.snapshot
|
|
const treeText = String(snapshot.treeText ?? '')
|
|
const lineCount = treeText.split('\n').filter(Boolean).length
|
|
const secondaryActions = (treeText.match(/Secondary Actions:/g) ?? []).length
|
|
const settable = (treeText.match(/\bsettable\b/g) ?? []).length
|
|
const screenshotState = state.screenshot ? `${state.screenshot.width}x${state.screenshot.height}` : 'missing'
|
|
console.log([
|
|
`computer-use smoke: ${snapshot.app.name}`,
|
|
`${snapshot.elementCount} elements`,
|
|
`${lineCount} lines`,
|
|
`${secondaryActions} secondary-action lines`,
|
|
`${settable} settable elements`,
|
|
`screenshot=${screenshotState}`
|
|
].join(' | '))
|
|
}
|
|
|
|
if (failures > 0) {
|
|
fail(`${failures} app snapshot smoke check(s) failed`)
|
|
}
|
|
|
|
function valueFlag(name) {
|
|
const index = process.argv.indexOf(name)
|
|
if (index === -1) {
|
|
return null
|
|
}
|
|
return process.argv[index + 1] ?? null
|
|
}
|
|
|
|
function runCli(cliArgs, options = {}) {
|
|
const child = spawnSync(process.execPath, [cliPath, ...cliArgs], {
|
|
cwd: repoRoot,
|
|
encoding: 'utf8',
|
|
env: {
|
|
...process.env,
|
|
ORCA_USER_DATA_PATH: process.env.ORCA_COMPUTER_SMOKE_USER_DATA_PATH ?? defaultDevUserDataPath()
|
|
}
|
|
})
|
|
if (child.status !== 0) {
|
|
const error = (child.stderr || child.stdout || `exit ${child.status}`).trim()
|
|
if (options.allowFailure) {
|
|
return { ok: false, error }
|
|
}
|
|
fail(error)
|
|
}
|
|
try {
|
|
return options.allowFailure
|
|
? { ok: true, value: JSON.parse(child.stdout) }
|
|
: JSON.parse(child.stdout)
|
|
} catch (error) {
|
|
const detail = error instanceof Error ? error.message : String(error)
|
|
fail(`Could not parse CLI JSON for ${cliArgs.join(' ')}: ${detail}\n${child.stdout}`)
|
|
}
|
|
}
|
|
|
|
function defaultDevUserDataPath() {
|
|
if (process.platform === 'darwin') {
|
|
return resolve(homedir(), 'Library', 'Application Support', 'orca-dev')
|
|
}
|
|
if (process.platform === 'win32') {
|
|
return resolve(process.env.APPDATA ?? resolve(homedir(), 'AppData', 'Roaming'), 'orca-dev')
|
|
}
|
|
return resolve(process.env.XDG_CONFIG_HOME ?? resolve(homedir(), '.config'), 'orca-dev')
|
|
}
|
|
|
|
function unwrapResult(value) {
|
|
if (value && typeof value === 'object' && 'result' in value) {
|
|
return value.result
|
|
}
|
|
return value
|
|
}
|
|
|
|
function fail(message) {
|
|
console.error(`computer-use smoke: ${message}`)
|
|
process.exit(1)
|
|
}
|