fix(cua): preserve window metadata and support Apple CLI test runtimes
This commit is contained in:
1 parent
d994a3326b
commit
bf508eaa2f
6 files changed
+34
-8
No files matched your search
@@ -30,7 +30,7 @@ Element clicks prefer advertised AX actions and otherwise use pointer delivery.
|
||||
|
||||
The responsible host/helper needs macOS Accessibility permission for AX state and input, and Screen Recording permission for screenshots. Capability preflight and permission errors do not grant permissions. Capture refuses a window that moves or resizes while the image is being read. Unassociated system panels and accessory-only applications are not selectable.
|
||||
|
||||
Use `swift test --package-path packages/experimental/cua/native` for offline unit checks and `python3 packages/experimental/cua/native/tests/protocol_e2e.py` for JSONL admission, ordered replies and EOF shutdown without desktop operations. All Python native checks accept `--helper` to select a separately built comparison binary.
|
||||
Use `python3 packages/experimental/cua/native/tests/test_swift.py` for offline unit checks with the selected Apple toolchain’s Swift Testing framework/runtime paths and `python3 packages/experimental/cua/native/tests/protocol_e2e.py` for JSONL admission, ordered replies and EOF shutdown without desktop operations. All Python native checks accept `--helper` to select a separately built comparison binary.
|
||||
|
||||
Run `python3 packages/experimental/cua/native/tests/axless_e2e.py` after building and unlocking the Mac to verify an owned window whose application removes and later restores its AX roots. The check requires existing Accessibility/Screen Recording grants, rejects stale element indices, captures the AXless window, verifies a coordinate click in the fixture state file, and checks restoration. It never changes system permission settings.
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ final class AXAccess {
|
||||
}
|
||||
func elementValue(_ value: CFTypeRef, _ name: String) throws -> AXUIElement {
|
||||
guard CFGetTypeID(value) == AXUIElementGetTypeID() else { throw NativeFailure(code: "NATIVE_ERROR", message: "Accessibility \(name) is not an element") }
|
||||
return unsafeBitCast(value, to: AXUIElement.self)
|
||||
return unsafeDowncast(value, to: AXUIElement.self)
|
||||
}
|
||||
func element(_ element: AXUIElement, _ name: String) throws -> AXUIElement? {
|
||||
guard let value = try attribute(element, name) else { return nil }
|
||||
@@ -123,8 +123,8 @@ final class AXAccess {
|
||||
func bounds(_ element: AXUIElement) throws -> WindowBounds? {
|
||||
guard let position = try attribute(element, "AXPosition"), let size = try attribute(element, "AXSize") else { return nil }
|
||||
guard CFGetTypeID(position) == AXValueGetTypeID(), CFGetTypeID(size) == AXValueGetTypeID() else { return nil }
|
||||
let positionValue = unsafeBitCast(position, to: AXValue.self)
|
||||
let sizeValue = unsafeBitCast(size, to: AXValue.self)
|
||||
let positionValue = unsafeDowncast(position, to: AXValue.self)
|
||||
let sizeValue = unsafeDowncast(size, to: AXValue.self)
|
||||
var point = CGPoint.zero
|
||||
var dimensions = CGSize.zero
|
||||
guard AXValueGetValue(positionValue, .cgPoint, &point), AXValueGetValue(sizeValue, .cgSize, &dimensions),
|
||||
|
||||
@@ -183,9 +183,7 @@ actor AXWorker {
|
||||
try NativePlatform.requireAccessibility()
|
||||
if let window { _ = try NativePlatform.ownedWindow(identity.pid, window) }
|
||||
try cancellation.check()
|
||||
let observedWindows: [WindowInfo]
|
||||
if let window { observedWindows = [try NativePlatform.ownedWindow(identity.pid, window)] }
|
||||
else { observedWindows = NativePlatform.windows().filter { $0.pid == identity.pid } }
|
||||
let observedWindows = NativePlatform.windows().filter { $0.pid == identity.pid }
|
||||
let id = try identifier("snapshot")
|
||||
let scope = SnapshotScope(appHandle: handle, windowID: window)
|
||||
snapshots[scope] = NativeSnapshot(id: id, scope: scope, elements: projection.indexed)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
"""Run Swift Testing with the selected Apple toolchain's runtime search paths."""
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main():
|
||||
compiler = Path(subprocess.check_output(["xcrun", "--find", "swift"], text=True).strip())
|
||||
package = Path(__file__).resolve().parents[1]
|
||||
command = [str(compiler), "test", "--package-path", str(package),
|
||||
"--disable-xctest", "--enable-swift-testing"]
|
||||
# Command Line Tools ships these libraries outside SwiftPM's default search
|
||||
# paths. Full Xcode and other selected toolchains keep their normal lookup.
|
||||
framework_root = compiler.parents[2] / "Library/Developer/Frameworks"
|
||||
if (framework_root / "Testing.framework").is_dir():
|
||||
command += ["-Xswiftc", "-F", "-Xswiftc", str(framework_root),
|
||||
"-Xlinker", "-F", "-Xlinker", str(framework_root),
|
||||
"-Xlinker", "-rpath", "-Xlinker", str(framework_root)]
|
||||
runtime = framework_root.parent / "usr/lib"
|
||||
if (runtime / "lib_TestingInterop.dylib").is_file():
|
||||
command += ["-Xlinker", "-rpath", "-Xlinker", str(runtime)]
|
||||
command += sys.argv[1:]
|
||||
raise SystemExit(subprocess.call(command))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -36,6 +36,7 @@
|
||||
"native/Package.swift",
|
||||
"native/Sources",
|
||||
"native/tests/swift",
|
||||
"native/tests/test_swift.py",
|
||||
"native/LICENSE.cua-driver",
|
||||
"native/upstream.json",
|
||||
"native/README.txt",
|
||||
|
||||
@@ -175,7 +175,7 @@ export function readWorkspaceManifests(repositoryRoot: string): WorkspaceManifes
|
||||
|
||||
const packageFileExtras: Readonly<Record<string, readonly string[]>> = {
|
||||
// CUA publishes its client API and attributed native source for local macOS builds.
|
||||
'@deepseek-ai/dsh-experimental-cua': ['lib/api.js', 'lib/bridge.js', 'native/Package.swift', 'native/Sources', 'native/tests/swift', 'native/LICENSE.cua-driver', 'native/upstream.json', 'native/README.txt', 'native/protocol.schema.json'],
|
||||
'@deepseek-ai/dsh-experimental-cua': ['lib/api.js', 'lib/bridge.js', 'native/Package.swift', 'native/Sources', 'native/tests/swift', 'native/tests/test_swift.py', 'native/LICENSE.cua-driver', 'native/upstream.json', 'native/README.txt', 'native/protocol.schema.json'],
|
||||
// Owned Worker bundles import this public bootstrap before their business entry.
|
||||
'@deepseek-ai/dsh-app-boot': ['lib/worker/profile-resolution-bootstrap.js'],
|
||||
// Statically linked client libraries keep their stylesheets next to the emitted
|
||||
|
||||
Reference in new issue
Block a user