cueward-adapter-macos 0.5.0

macOS adapter for Cueward with Safari, Notes, Messages, Reminders, Calendar, Screenshot, Clipboard, and OCR integrations.
func optionalElement(_ element: AXUIElement, _ key: String) -> AXUIElement? {
    guard let raw = attribute(element, key) else { return nil }
    guard CFGetTypeID(raw) == AXUIElementGetTypeID() else { fail("invalid AX root value") }
    return (raw as! AXUIElement)
}

struct AppRoots {
    let windows: [AXUIElement]
    let menu: AXUIElement?
    let context: String

    init() {
        var found = elements(application, kAXWindowsAttribute)
        let main = optionalElement(application, kAXMainWindowAttribute)
        let focused = optionalElement(application, kAXFocusedWindowAttribute)
        for element in [main, focused].compactMap({ $0 }) {
            if !found.contains(where: { CFEqual($0, element) }) { found.append(element) }
        }
        guard found.count <= 64 else { fail("app has too many AX roots to bind safely") }
        windows = found
        menu = optionalElement(application, kAXMenuBarAttribute)
        context = fingerprint([
            "app": instance,
            "windows": found.map { rootFingerprint($0) },
            "main": main.map { rootFingerprint($0) } as Any? ?? NSNull(),
            "focused": focused.map { rootFingerprint($0) } as Any? ?? NSNull(),
        ], parent: "")
    }

    func root(_ ref: String) -> AXUIElement {
        if ref == "menu", let menu { return menu }
        guard ref.hasPrefix("w"), let index = Int(ref.dropFirst()), windows.indices.contains(index) else {
            fail("app AX root disappeared; inspect the app again")
        }
        let element = windows[index]
        let identity = rootFingerprint(element)
        guard windows.filter({ rootFingerprint($0) == identity }).count == 1 else {
            fail("app AX root identity is ambiguous")
        }
        return element
    }
}

func rootFingerprint(_ element: AXUIElement) -> String {
    fingerprint(appNode(element), parent: "")
}

func resolve(_ reference: String, _ roots: AppRoots) -> (AXUIElement, String, String) {
    let parts = reference.split(separator: ".", omittingEmptySubsequences: false).map(String.init)
    guard let first = parts.first, parts.count <= 13 else { fail("invalid app element ref") }
    var element = roots.root(first)
    let rootID = rootFingerprint(element)
    var parent = roots.context
    for part in parts.dropFirst() {
        guard let index = Int(part), index >= 0 else { fail("invalid app element ref") }
        let children = elements(element, kAXChildrenAttribute)
        guard index < children.count else { fail("app element disappeared; inspect again") }
        parent = fingerprint(appNode(element), parent: parent)
        element = children[index]
    }
    return (element, parent, rootID)
}

func validateObservation(_ context: String) {
    ensureUnlocked()
    guard fingerprint(processIdentity(pid), parent: "") == fingerprint(instance, parent: ""),
          AppRoots().context == context else { fail("app context changed; inspect again") }
}