Clean build
This commit is contained in:
parent
3f335b489c
commit
316d8145f5
@ -1,5 +1,41 @@
|
||||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "defaults",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/sindresorhus/Defaults",
|
||||
"state" : {
|
||||
"revision" : "3efef5a28ebdbbe922d4a2049493733ed14475a6",
|
||||
"version" : "7.3.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "keyboardshortcuts",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/sindresorhus/KeyboardShortcuts",
|
||||
"state" : {
|
||||
"revision" : "045cf174010beb335fa1d2567d18c057b8787165",
|
||||
"version" : "2.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "launchatlogin",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/sindresorhus/LaunchAtLogin",
|
||||
"state" : {
|
||||
"revision" : "9a894d799269cb591037f9f9cb0961510d4dca81",
|
||||
"version" : "5.0.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "sparkle",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/sparkle-project/Sparkle.git",
|
||||
"state" : {
|
||||
"revision" : "0ca3004e98712ea2b39dd881d28448630cce1c99",
|
||||
"version" : "2.7.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-argument-parser",
|
||||
"kind" : "remoteSourceControl",
|
||||
@ -9,6 +45,15 @@
|
||||
"version" : "1.5.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-log",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-log.git",
|
||||
"state" : {
|
||||
"revision" : "3d8596ed08bd13520157f0355e35caed215ffbfa",
|
||||
"version" : "1.6.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-syntax",
|
||||
"kind" : "remoteSourceControl",
|
||||
@ -26,6 +71,15 @@
|
||||
"revision" : "399f76dcd91e4c688ca2301fa24a8cc6d9927211",
|
||||
"version" : "0.99.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swiftui-introspect",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
|
||||
"state" : {
|
||||
"revision" : "121c146fe591b1320238d054ae35c81ffa45f45a",
|
||||
"version" : "0.12.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
|
||||
@ -15,8 +15,10 @@ public class AXorcist {
|
||||
internal var recursiveCallDebugLogs: [String] = [] // Added for recursive logging
|
||||
|
||||
// Default values for collection and search if not provided by the command
|
||||
public static let defaultMaxDepthSearch = 10 // Example, adjust as needed
|
||||
public static let defaultMaxDepthCollectAll = 5
|
||||
public static let defaultMaxDepthSearch = 10 // Default for general locator-based searches
|
||||
public static let defaultMaxDepthCollectAll = 7 // Default for collectAll recursive operations
|
||||
public static let defaultMaxDepthPathResolution = 15 // Max depth for resolving path hints
|
||||
public static let defaultMaxDepthDescribe = 5 // ADDED: Default for description recursion
|
||||
public static let defaultTimeoutPerElementCollectAll = 0.5 // seconds
|
||||
|
||||
// Default attributes to fetch if none are specified by the command.
|
||||
@ -114,10 +116,14 @@ public class AXorcist {
|
||||
currentDebugLogs: inout [String]
|
||||
) -> Element? {
|
||||
let pathHintString = pathHint.joined(separator: ", ")
|
||||
// Log with the actual isDebugLoggingEnabled value
|
||||
currentDebugLogs.append(AXorcist.formatDebugLogMessage("navigateToElement: Entered. isDebugLoggingEnabled: \(isDebugLoggingEnabled). pathHint: [\(pathHintString)]", applicationName: nil, commandID: nil, file: #file, function: #function, line: #line))
|
||||
|
||||
func dLog(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
currentDebugLogs.append(AXorcist.formatDebugLogMessage(message, applicationName: nil, commandID: nil, file: file, function: function, line: line))
|
||||
// Use the passed-in isDebugLoggingEnabled
|
||||
if isDebugLoggingEnabled {
|
||||
currentDebugLogs.append(AXorcist.formatDebugLogMessage(message, applicationName: nil, commandID: nil, file: file, function: function, line: line))
|
||||
}
|
||||
}
|
||||
|
||||
var currentElement = startElement
|
||||
@ -143,7 +149,7 @@ public class AXorcist {
|
||||
for child in childrenFromElementDotChildren {
|
||||
let childBriefDescForLog = child.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs)
|
||||
if let actualValue = child.attribute(Attribute<String>(attributeName), isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs) {
|
||||
// dLog("Child (from Element.children) \(childBriefDescForLog) has '\(attributeName)': [\(actualValue)] (Expected: [\(expectedValue)])")
|
||||
dLog(" [Nav Child Check 1] Child: \(childBriefDescForLog), Attribute '\(attributeName)': [\(actualValue)] (Expected: [\(expectedValue)])")
|
||||
if actualValue == expectedValue {
|
||||
dLog("Matched child (from Element.children): \(childBriefDescForLog) for '\(attributeName):\(expectedValue)'")
|
||||
newElementForNextStep = child
|
||||
@ -175,8 +181,9 @@ public class AXorcist {
|
||||
currentDebugLogs.append(AXorcist.formatDebugLogMessage("navigateToElement: Direct kAXChildrenAttribute fallback found \(directAxElements.count) raw children for \(currentElementDescForFallbackLog).", applicationName: nil, commandID: nil, file: #file, function: #function, line: #line))
|
||||
for axChild in directAxElements {
|
||||
let childElement = Element(axChild)
|
||||
// let childBriefDescForLog = childElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs) // Avoid for now inside loop if too verbose or risky
|
||||
let childBriefDescForLogFallback = childElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs)
|
||||
if let actualValue = childElement.attribute(Attribute<String>(attributeName), isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs) {
|
||||
dLog(" [Nav Child Check 2-Fallback] Child: \(childBriefDescForLogFallback), Attribute '\(attributeName)': [\(actualValue)] (Expected: [\(expectedValue)])")
|
||||
if actualValue == expectedValue {
|
||||
currentDebugLogs.append(AXorcist.formatDebugLogMessage("navigateToElement: Matched child (from direct fallback) for '\(attributeName):\(expectedValue)' on \(currentElementDescForFallbackLog). Child: \(childElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))", applicationName: nil, commandID: nil, file: #file, function: #function, line: #line))
|
||||
newElementForNextStep = childElement
|
||||
|
||||
@ -120,6 +120,7 @@ public let kAXMenuItemRole = "AXMenuItem" // New
|
||||
public let kAXSplitGroupRole = "AXSplitGroup" // New
|
||||
public let kAXSplitterRole = "AXSplitter" // New
|
||||
public let kAXColorWellRole = "AXColorWell" // New
|
||||
public let kAXLinkRole = "AXLink" // New
|
||||
public let kAXUnknownRole = "AXUnknown" // New
|
||||
|
||||
// Attributes for web content and tables/lists
|
||||
|
||||
@ -77,11 +77,14 @@ public struct Element: Equatable, Hashable {
|
||||
}
|
||||
} else if T.self == Bool.self {
|
||||
if CFGetTypeID(unwrappedValue) == CFBooleanGetTypeID() {
|
||||
return CFBooleanGetValue(unwrappedValue as! CFBoolean) as? T
|
||||
// Reverted to as! based on new compiler note
|
||||
let swiftBool = CFBooleanGetValue(unwrappedValue as! CFBoolean)
|
||||
return swiftBool as? T
|
||||
}
|
||||
} else if T.self == Int.self {
|
||||
if CFGetTypeID(unwrappedValue) == CFNumberGetTypeID() {
|
||||
var intValue: Int = 0
|
||||
// Reverted to as! based on new compiler note
|
||||
if CFNumberGetValue(unwrappedValue as! CFNumber, .sInt64Type, &intValue) {
|
||||
return intValue as? T
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ public enum CommandType: String, Codable {
|
||||
}
|
||||
|
||||
// For encoding/decoding 'Any' type in JSON, especially for element attributes.
|
||||
public struct AnyCodable: Codable {
|
||||
public struct AnyCodable: Codable, @unchecked Sendable {
|
||||
public let value: Any
|
||||
|
||||
public init<T>(_ value: T?) {
|
||||
@ -162,7 +162,7 @@ public struct CommandEnvelope: Codable {
|
||||
}
|
||||
|
||||
// Locator for finding elements
|
||||
public struct Locator: Codable {
|
||||
public struct Locator: Codable, Sendable {
|
||||
public var match_all: Bool?
|
||||
public var criteria: [String: String]
|
||||
public var root_element_path_hint: [String]?
|
||||
@ -207,6 +207,18 @@ public struct QueryResponse: Codable {
|
||||
self.error = error
|
||||
self.debug_logs = debug_logs
|
||||
}
|
||||
|
||||
// Custom init for HandlerResponse integration
|
||||
public init(command_id: String, success: Bool, command: String, handlerResponse: HandlerResponse, debug_logs: [String]?) {
|
||||
self.command_id = command_id
|
||||
self.success = success
|
||||
self.command = command
|
||||
self.data = handlerResponse.data
|
||||
// If HandlerResponse has attributes, map them from its data field.
|
||||
self.attributes = handlerResponse.data?.attributes
|
||||
self.error = handlerResponse.error
|
||||
self.debug_logs = debug_logs
|
||||
}
|
||||
}
|
||||
|
||||
// Response for collect_all command (multiple elements)
|
||||
@ -302,7 +314,7 @@ public struct SimpleSuccessResponse: Codable, Equatable {
|
||||
|
||||
// Placeholder for any additional models if needed
|
||||
|
||||
public struct AXElement: Codable {
|
||||
public struct AXElement: Codable, Sendable {
|
||||
public var attributes: ElementAttributes?
|
||||
public var path: [String]?
|
||||
|
||||
@ -324,7 +336,7 @@ extension QueryResponse {
|
||||
|
||||
// MARK: - Handler Response Models
|
||||
|
||||
public struct HandlerResponse {
|
||||
public struct HandlerResponse: Codable, Sendable {
|
||||
public var data: AXElement?
|
||||
public var error: String?
|
||||
public var debug_logs: [String]?
|
||||
@ -345,3 +357,20 @@ internal struct CollectAllOutput: Encodable {
|
||||
let app_bundle_id: String?
|
||||
let debug_logs: [String]?
|
||||
}
|
||||
|
||||
// ADDED BatchResponse struct
|
||||
public struct BatchResponse: Codable {
|
||||
public var command_id: String
|
||||
public var success: Bool
|
||||
public var results: [HandlerResponse] // Array of HandlerResponses for each sub-command
|
||||
public var error: String? // For an overall batch error, if any
|
||||
public var debug_logs: [String]?
|
||||
|
||||
public init(command_id: String, success: Bool, results: [HandlerResponse], error: String? = nil, debug_logs: [String]? = nil) {
|
||||
self.command_id = command_id
|
||||
self.success = success
|
||||
self.results = results
|
||||
self.error = error
|
||||
self.debug_logs = debug_logs
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
import AppKit
|
||||
import ApplicationServices
|
||||
import Darwin
|
||||
import Foundation
|
||||
|
||||
// MARK: - Action & Data Handlers Extension
|
||||
@ -66,9 +67,26 @@ extension AXorcist {
|
||||
let targetElementForAction: Element
|
||||
if let actualLocator = locator {
|
||||
dLog("[AXorcist.handlePerformAction] Locator provided. Searching from current effectiveElement: \(effectiveElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs)) using locator criteria: \(actualLocator.criteria)")
|
||||
guard let foundElement = search(element: effectiveElement, locator: actualLocator, requireAction: actualLocator.requireAction, depth: 0, maxDepth: maxDepth ?? DEFAULT_MAX_DEPTH_SEARCH, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs) else {
|
||||
let error = "[AXorcist.handlePerformAction] Failed to find element with locator: \(actualLocator) starting from \(effectiveElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))"
|
||||
currentDebugLogs.append(error)
|
||||
|
||||
let searchResult = search(
|
||||
element: effectiveElement,
|
||||
locator: actualLocator,
|
||||
requireAction: actualLocator.requireAction,
|
||||
depth: 0,
|
||||
maxDepth: maxDepth ?? DEFAULT_MAX_DEPTH_SEARCH,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled
|
||||
)
|
||||
fputs("HANDLER_RAW_STDERR_BEFORE_LOG_APPEND handlePerformAction: searchResult.logs.count = \(searchResult.logs.count), currentDebugLogs count = \(currentDebugLogs.count)\n", stderr)
|
||||
currentDebugLogs.append("HANDLER_DEBUG: searchResult.logs.count = \(searchResult.logs.count) before append for performAction")
|
||||
currentDebugLogs.append(contentsOf: searchResult.logs)
|
||||
fputs("HANDLER_RAW_STDERR_AFTER_LOG_APPEND handlePerformAction: currentDebugLogs count = \(currentDebugLogs.count)\n", stderr)
|
||||
currentDebugLogs.append("POST_SEARCH_LOG_APPEND_MARKER_IN_HANDLER")
|
||||
|
||||
guard let foundElement = searchResult.foundElement else {
|
||||
let error = "[AXorcist.handlePerformAction] Search failed. Could not find element matching locator criteria \(actualLocator.criteria) starting from element \(effectiveElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))."
|
||||
if !currentDebugLogs.contains(error) {
|
||||
currentDebugLogs.append(error)
|
||||
}
|
||||
return HandlerResponse(data: nil, error: error, debug_logs: currentDebugLogs)
|
||||
}
|
||||
targetElementForAction = foundElement
|
||||
@ -236,17 +254,26 @@ extension AXorcist {
|
||||
let targetElementForExtract: Element
|
||||
if let actualLocator = locator {
|
||||
dLog("[handleExtractText] Locator provided. Searching from current effectiveElement: \(effectiveElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs)) using locator criteria: \(actualLocator.criteria)")
|
||||
guard let foundElement = search(
|
||||
|
||||
let searchResult = search(
|
||||
element: effectiveElement,
|
||||
locator: actualLocator,
|
||||
requireAction: nil,
|
||||
depth: 0,
|
||||
maxDepth: DEFAULT_MAX_DEPTH_SEARCH,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
) else {
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled
|
||||
)
|
||||
fputs("HANDLER_RAW_STDERR_BEFORE_LOG_APPEND handleExtractText: searchResult.logs.count = \(searchResult.logs.count), currentDebugLogs count = \(currentDebugLogs.count)\n", stderr)
|
||||
currentDebugLogs.append("HANDLER_DEBUG: searchResult.logs.count = \(searchResult.logs.count) before append for extractText")
|
||||
currentDebugLogs.append(contentsOf: searchResult.logs)
|
||||
fputs("HANDLER_RAW_STDERR_AFTER_LOG_APPEND handleExtractText: currentDebugLogs count = \(currentDebugLogs.count)\n", stderr)
|
||||
currentDebugLogs.append("POST_SEARCH_LOG_APPEND_MARKER_IN_EXTRACT_TEXT")
|
||||
|
||||
guard let foundElement = searchResult.foundElement else {
|
||||
let errorMessage = "[handleExtractText] Target element not found for locator: \(actualLocator) starting from \(effectiveElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))"
|
||||
currentDebugLogs.append(errorMessage)
|
||||
if !currentDebugLogs.contains(errorMessage) {
|
||||
currentDebugLogs.append(errorMessage)
|
||||
}
|
||||
return HandlerResponse(data: nil, error: errorMessage, debug_logs: currentDebugLogs)
|
||||
}
|
||||
targetElementForExtract = foundElement
|
||||
|
||||
@ -173,7 +173,7 @@ extension AXorcist {
|
||||
// This is distinct from commands axorc itself might handle outside of AXorcist library.
|
||||
// @unknown default: // This would be better if Swift enums allowed it easily here for non-frozen enums from other modules.
|
||||
// Since CommandType is in axorc, this default captures any CommandType case not explicitly handled above.
|
||||
default:
|
||||
@unknown default:
|
||||
let errorMsg =
|
||||
"Unknown or unhandled command type '\(subCommandEnvelope.command)' in batch processing within AXorcist (sub-command ID: \(subCmdID))"
|
||||
dLog(errorMsg, subCommandID: subCmdID)
|
||||
|
||||
@ -124,9 +124,20 @@ extension AXorcist {
|
||||
}
|
||||
|
||||
if let loc = locator {
|
||||
dLog("Locator provided. Searching for element from current startElement: \(startElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)) with locator criteria: \(String(describing: loc.criteria))")
|
||||
if let locatedStartElement = search(element: startElement, locator: loc, requireAction: loc.requireAction, depth: 0, maxDepth: Self.defaultMaxDepthSearch, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs) {
|
||||
dLog("Locator found element: \(locatedStartElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)). This will be the root for collectAll recursion.")
|
||||
dLog("Locator provided. Searching for element from current startElement: \(startElement.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)) with locator criteria: \(String(describing: loc.criteria))")
|
||||
|
||||
let searchResultCollectAll = search(element: startElement,
|
||||
locator: loc,
|
||||
requireAction: loc.requireAction,
|
||||
depth: 0,
|
||||
maxDepth: Self.defaultMaxDepthSearch,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled)
|
||||
self.recursiveCallDebugLogs.append("HANDLER_DEBUG: searchResultCollectAll.logs.count = \(searchResultCollectAll.logs.count) before append for collectAll")
|
||||
self.recursiveCallDebugLogs.append(contentsOf: searchResultCollectAll.logs)
|
||||
self.recursiveCallDebugLogs.append("POST_SEARCH_LOG_APPEND_MARKER_IN_COLLECT_ALL")
|
||||
|
||||
if let locatedStartElement = searchResultCollectAll.foundElement {
|
||||
dLog("Locator found element: \(locatedStartElement.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)). This will be the root for collectAll recursion.")
|
||||
startElement = locatedStartElement
|
||||
} else {
|
||||
let errorMsg = "Failed to find element with provided locator criteria: \(String(describing: loc.criteria)). Cannot start collectAll."
|
||||
@ -147,13 +158,13 @@ extension AXorcist {
|
||||
collectRecursively = { axUIElement, currentDepth in
|
||||
if currentDepth > recursionDepthLimit {
|
||||
dLog(
|
||||
"Reached recursionDepthLimit (\(recursionDepthLimit)) at element \(Element(axUIElement).briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)), stopping recursion for this branch."
|
||||
"Reached recursionDepthLimit (\(recursionDepthLimit)) at element \(Element(axUIElement).briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)), stopping recursion for this branch."
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
let currentElement = Element(axUIElement)
|
||||
dLog("Collecting element \(currentElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)) at depth \(currentDepth)")
|
||||
dLog("Collecting element \(currentElement.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)) at depth \(currentDepth)")
|
||||
|
||||
let fetchedAttrs = getElementAttributes(
|
||||
currentElement,
|
||||
@ -182,36 +193,40 @@ extension AXorcist {
|
||||
|
||||
if childrenResult == .success, let children = childrenRef as? [AXUIElement] {
|
||||
dLog(
|
||||
"Element \(currentElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)) has \(children.count) children at depth \(currentDepth). Recursing."
|
||||
"Element \(currentElement.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)) has \(children.count) children at depth \(currentDepth). Recursing."
|
||||
)
|
||||
for childElement in children {
|
||||
collectRecursively(childElement, currentDepth + 1)
|
||||
}
|
||||
} else if childrenResult != .success {
|
||||
dLog(
|
||||
"Failed to get children for element \(currentElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)): \(axErrorToString(childrenResult))"
|
||||
"Failed to get children for element \(currentElement.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)): \(axErrorToString(childrenResult))"
|
||||
)
|
||||
} else {
|
||||
dLog(
|
||||
"No children found for element \(currentElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)) at depth \(currentDepth)"
|
||||
"No children found for element \(currentElement.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs)) at depth \(currentDepth)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
dLog(
|
||||
"Starting recursive collection from start element: \(startElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs))"
|
||||
"Starting recursive collection from start element: \(startElement.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &self.recursiveCallDebugLogs))"
|
||||
)
|
||||
collectRecursively(startElement.underlyingElement, 0)
|
||||
|
||||
dLog("Collection complete. Found \(collectedAXElements.count) elements.")
|
||||
// Start recursion from the determined startElement
|
||||
if !self.recursiveCallDebugLogs.contains(where: { $0.contains("Failed to find element with provided locator criteria") && $0.contains("Cannot start collectAll") }) {
|
||||
// Only start if locator search (if any) didn't critically fail and try to return early.
|
||||
collectRecursively(startElement.underlyingElement, 0)
|
||||
}
|
||||
|
||||
return encode(CollectAllOutput(
|
||||
let output = CollectAllOutput(
|
||||
command_id: effectiveCommandId,
|
||||
success: true,
|
||||
success: true, // Assuming success if we reach here, errors would have returned earlier
|
||||
command: "collectAll",
|
||||
collected_elements: collectedAXElements,
|
||||
app_bundle_id: appIdentifier,
|
||||
debug_logs: self.recursiveCallDebugLogs
|
||||
))
|
||||
)
|
||||
return encode(output)
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,6 @@ extension AXorcist {
|
||||
let appIdentifier = appIdentifierOrNil ?? self.focusedAppKeyValue
|
||||
dLog("Handling query for app: \(appIdentifier)")
|
||||
|
||||
// Pass logging parameters to applicationElement
|
||||
guard let appElement = applicationElement(
|
||||
for: appIdentifier,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
@ -42,7 +41,6 @@ extension AXorcist {
|
||||
var effectiveElement = appElement
|
||||
if let pathHint = pathHint, !pathHint.isEmpty {
|
||||
dLog("Navigating with path_hint: \(pathHint.joined(separator: " -> "))")
|
||||
// Pass logging parameters to navigateToElement
|
||||
if let navigatedElement = self.navigateToElement(
|
||||
from: effectiveElement,
|
||||
pathHint: pathHint,
|
||||
@ -70,12 +68,11 @@ extension AXorcist {
|
||||
foundElement = effectiveElement
|
||||
} else {
|
||||
dLog("Locator contains element-specific criteria or is complex. Proceeding with search.")
|
||||
var searchStartElementForLocator = appElement
|
||||
var searchStartElementForLocator = effectiveElement
|
||||
if let rootPathHint = locator.root_element_path_hint, !rootPathHint.isEmpty {
|
||||
dLog(
|
||||
"Locator has root_element_path_hint: \(rootPathHint.joined(separator: " -> ")). Navigating from app element first."
|
||||
)
|
||||
// Pass logging parameters to navigateToElement
|
||||
guard let containerElement = self.navigateToElement(
|
||||
from: appElement,
|
||||
pathHint: rootPathHint,
|
||||
@ -90,31 +87,29 @@ extension AXorcist {
|
||||
}
|
||||
searchStartElementForLocator = containerElement
|
||||
dLog(
|
||||
"Searching with locator within container found by root_element_path_hint: \(searchStartElementForLocator.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))"
|
||||
"Searching with locator within container found by root_element_path_hint: \(searchStartElementForLocator.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))"
|
||||
)
|
||||
} else {
|
||||
searchStartElementForLocator = effectiveElement
|
||||
dLog(
|
||||
"Searching with locator from element (determined by main path_hint or app root): \(searchStartElementForLocator.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))"
|
||||
"Searching with locator from element (determined by main path_hint or app root): \(searchStartElementForLocator.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))"
|
||||
)
|
||||
}
|
||||
|
||||
let finalSearchTarget = (pathHint != nil && !pathHint!.isEmpty) ? effectiveElement :
|
||||
searchStartElementForLocator
|
||||
|
||||
// Pass logging parameters to search
|
||||
foundElement = search(
|
||||
element: finalSearchTarget,
|
||||
|
||||
let searchResult = search(
|
||||
element: searchStartElementForLocator,
|
||||
locator: locator,
|
||||
requireAction: locator.requireAction,
|
||||
depth: 0,
|
||||
maxDepth: maxDepth ?? AXorcist.defaultMaxDepthSearch,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled
|
||||
)
|
||||
currentDebugLogs.append("HANDLER_DEBUG: searchResult.logs.count = \(searchResult.logs.count) before append for query")
|
||||
currentDebugLogs.append(contentsOf: searchResult.logs)
|
||||
currentDebugLogs.append("POST_SEARCH_LOG_APPEND_MARKER_IN_QUERY")
|
||||
foundElement = searchResult.foundElement
|
||||
}
|
||||
|
||||
if let elementToQuery = foundElement {
|
||||
// Pass logging parameters to getElementAttributes
|
||||
var attributes = getElementAttributes(
|
||||
elementToQuery,
|
||||
requestedAttributes: requestedAttributes ?? [],
|
||||
@ -176,7 +171,6 @@ extension AXorcist {
|
||||
)
|
||||
}
|
||||
|
||||
// Find element to get attributes from
|
||||
var effectiveElement = appElement
|
||||
if let pathHint = pathHint, !pathHint.isEmpty {
|
||||
dLog("handleGetAttributes: Navigating with path_hint: \(pathHint.joined(separator: " -> "))")
|
||||
@ -199,20 +193,24 @@ extension AXorcist {
|
||||
}
|
||||
|
||||
dLog(
|
||||
"handleGetAttributes: Searching for element with locator: \(locator.criteria) from root: \(effectiveElement.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))"
|
||||
"handleGetAttributes: Searching for element with locator: \(locator.criteria) from root: \(effectiveElement.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))"
|
||||
)
|
||||
let foundElement = search(
|
||||
let searchResult = search(
|
||||
element: effectiveElement,
|
||||
locator: locator,
|
||||
requireAction: locator.requireAction,
|
||||
depth: 0,
|
||||
maxDepth: maxDepth ?? AXorcist.defaultMaxDepthSearch,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled
|
||||
)
|
||||
currentDebugLogs.append("HANDLER_DEBUG: searchResult.logs.count = \(searchResult.logs.count) before append for getAttributes")
|
||||
currentDebugLogs.append(contentsOf: searchResult.logs)
|
||||
currentDebugLogs.append("POST_SEARCH_LOG_APPEND_MARKER_IN_GET_ATTRIBUTES")
|
||||
let foundElement = searchResult.foundElement
|
||||
|
||||
if let elementToQuery = foundElement {
|
||||
dLog(
|
||||
"handleGetAttributes: Element found: \(elementToQuery.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs)). Fetching attributes: \(requestedAttributes ?? ["all"])..."
|
||||
"handleGetAttributes: Element found: \(elementToQuery.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs)). Fetching attributes: \(requestedAttributes ?? ["all"])..."
|
||||
)
|
||||
var attributes = getElementAttributes(
|
||||
elementToQuery,
|
||||
@ -227,7 +225,7 @@ extension AXorcist {
|
||||
attributes = encodeAttributesToJSONStringRepresentation(attributes)
|
||||
}
|
||||
dLog(
|
||||
"Successfully fetched attributes for element \(elementToQuery.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))."
|
||||
"Successfully fetched attributes for element \(elementToQuery.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))."
|
||||
)
|
||||
|
||||
let axElement = AXElement(attributes: attributes)
|
||||
@ -246,4 +244,102 @@ extension AXorcist {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
public func handleDescribeElement(
|
||||
for appIdentifierOrNil: String?,
|
||||
locator: Locator,
|
||||
pathHint: [String]?,
|
||||
maxDepth: Int?,
|
||||
requestedAttributes: [String]?,
|
||||
outputFormat: OutputFormat?,
|
||||
isDebugLoggingEnabled: Bool,
|
||||
currentDebugLogs: inout [String]
|
||||
) async -> HandlerResponse {
|
||||
|
||||
func dLog(_ message: String) { if isDebugLoggingEnabled { currentDebugLogs.append(message) } }
|
||||
|
||||
let appIdentifier = appIdentifierOrNil ?? self.focusedAppKeyValue
|
||||
dLog("Handling describe_element for app: \(appIdentifier)")
|
||||
|
||||
guard let appElement = applicationElement(
|
||||
for: appIdentifier,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
) else {
|
||||
return HandlerResponse(
|
||||
data: nil,
|
||||
error: "Application not found: \(appIdentifier)",
|
||||
debug_logs: isDebugLoggingEnabled ? currentDebugLogs : nil
|
||||
)
|
||||
}
|
||||
|
||||
var effectiveElement = appElement
|
||||
if let pathHint = pathHint, !pathHint.isEmpty {
|
||||
dLog("handleDescribeElement: Navigating with path_hint: \(pathHint.joined(separator: " -> "))")
|
||||
if let navigatedElement = self.navigateToElement(
|
||||
from: appElement,
|
||||
pathHint: pathHint,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
) {
|
||||
effectiveElement = navigatedElement
|
||||
} else {
|
||||
let errorMessage = "Element not found via path hint for describe: \(pathHint.joined(separator: " -> "))"
|
||||
dLog("handleDescribeElement: \(errorMessage)")
|
||||
return HandlerResponse(
|
||||
data: nil,
|
||||
error: errorMessage,
|
||||
debug_logs: isDebugLoggingEnabled ? currentDebugLogs : nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
dLog(
|
||||
"[AXorcist.handleDescribeElement] Searching for element to describe using locator: \(locator.criteria) from effective element: \(effectiveElement.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))"
|
||||
)
|
||||
|
||||
let searchMaxDepth = maxDepth ?? AXorcist.defaultMaxDepthSearch
|
||||
|
||||
let searchResult = search(
|
||||
element: effectiveElement,
|
||||
locator: locator,
|
||||
requireAction: locator.requireAction,
|
||||
depth: 0,
|
||||
maxDepth: searchMaxDepth,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled
|
||||
)
|
||||
currentDebugLogs.append("HANDLER_DEBUG: searchResult.logs.count = \(searchResult.logs.count) before append for describeElement")
|
||||
currentDebugLogs.append(contentsOf: searchResult.logs)
|
||||
currentDebugLogs.append("POST_SEARCH_LOG_APPEND_MARKER_IN_DESCRIBE")
|
||||
guard let elementToDescribe = searchResult.foundElement else {
|
||||
let error = "[AXorcist.handleDescribeElement] Element to describe not found for locator: \(locator.criteria)"
|
||||
currentDebugLogs.append(error)
|
||||
return HandlerResponse(data: nil, error: error, debug_logs: currentDebugLogs)
|
||||
}
|
||||
|
||||
dLog(
|
||||
"[AXorcist.handleDescribeElement] Element found: \(elementToDescribe.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs)). Now describing."
|
||||
)
|
||||
|
||||
var attributes = getElementAttributes(
|
||||
elementToDescribe,
|
||||
requestedAttributes: requestedAttributes ?? ["all"],
|
||||
forMultiDefault: true,
|
||||
targetRole: locator.criteria[kAXRoleAttribute],
|
||||
outputFormat: outputFormat ?? .verbose,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
)
|
||||
if outputFormat == .json_string {
|
||||
attributes = encodeAttributesToJSONStringRepresentation(attributes)
|
||||
}
|
||||
|
||||
let axElement = AXElement(
|
||||
attributes: attributes,
|
||||
path: elementToDescribe.generatePathArray(upTo: appElement, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs)
|
||||
)
|
||||
|
||||
return HandlerResponse(data: axElement, error: nil, debug_logs: currentDebugLogs)
|
||||
}
|
||||
}
|
||||
@ -82,14 +82,15 @@ extension AXorcist {
|
||||
dLog(
|
||||
"[AXorcist.handleGetAttributes] Not an AXApplication-only locator or value mismatch. Searching for element with locator: \(locator.criteria) from root: \(rootElementDescription)"
|
||||
)
|
||||
elementToQuery = search(
|
||||
let searchResultGetAttributes = search(
|
||||
element: effectiveElement,
|
||||
locator: locator,
|
||||
requireAction: locator.requireAction,
|
||||
maxDepth: maxDepth ?? DEFAULT_MAX_DEPTH_SEARCH,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled
|
||||
)
|
||||
currentDebugLogs.append(contentsOf: searchResultGetAttributes.logs)
|
||||
elementToQuery = searchResultGetAttributes.foundElement
|
||||
}
|
||||
|
||||
if let actualElementToQuery = elementToQuery {
|
||||
@ -243,14 +244,15 @@ extension AXorcist {
|
||||
let finalSearchTarget = (pathHint != nil && !pathHint!.isEmpty) ? effectiveElement :
|
||||
searchStartElementForLocator
|
||||
|
||||
foundElement = search(
|
||||
let searchResultQuery = search(
|
||||
element: finalSearchTarget,
|
||||
locator: locator,
|
||||
requireAction: locator.requireAction,
|
||||
maxDepth: maxDepth ?? DEFAULT_MAX_DEPTH_SEARCH,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled
|
||||
)
|
||||
currentDebugLogs.append(contentsOf: searchResultQuery.logs)
|
||||
foundElement = searchResultQuery.foundElement
|
||||
}
|
||||
|
||||
if let elementToQuery = foundElement {
|
||||
@ -350,18 +352,19 @@ extension AXorcist {
|
||||
dLog(
|
||||
"[AXorcist.handleDescribeElement] Searching for element with locator: \(locator.criteria) from root: \(rootElementDescription)"
|
||||
)
|
||||
let foundElement = search(
|
||||
let searchResultDescribe = search(
|
||||
element: effectiveElement,
|
||||
locator: locator,
|
||||
requireAction: locator.requireAction,
|
||||
maxDepth: maxDepth ?? DEFAULT_MAX_DEPTH_SEARCH,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled
|
||||
)
|
||||
currentDebugLogs.append(contentsOf: searchResultDescribe.logs)
|
||||
let foundElementForDescribe = searchResultDescribe.foundElement
|
||||
|
||||
if let elementToDescribe = foundElement {
|
||||
if let elementToDescribe = foundElementForDescribe {
|
||||
let elementDescription = elementToDescribe.briefDescription(
|
||||
option: .default,
|
||||
option: ValueFormatOption.default,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
)
|
||||
@ -374,9 +377,9 @@ extension AXorcist {
|
||||
var attributes = getElementAttributes(
|
||||
elementToDescribe,
|
||||
requestedAttributes: [], // Empty means 'all standard' or 'all known'
|
||||
forMultiDefault: false,
|
||||
forMultiDefault: true,
|
||||
targetRole: locator.criteria[kAXRoleAttribute],
|
||||
outputFormat: .verbose, // Describe implies verbose
|
||||
outputFormat: outputFormat ?? .smart,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
)
|
||||
@ -393,7 +396,7 @@ extension AXorcist {
|
||||
let axElement = AXElement(attributes: attributes, path: elementPathArray)
|
||||
|
||||
dLog(
|
||||
"[AXorcist.handleDescribeElement] Successfully described element \(elementToDescribe.briefDescription(option: .default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))."
|
||||
"[AXorcist.handleDescribeElement] Successfully described element \(elementToDescribe.briefDescription(option: ValueFormatOption.default, isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: ¤tDebugLogs))."
|
||||
)
|
||||
return HandlerResponse(data: axElement, error: nil, debug_logs: currentDebugLogs)
|
||||
} else {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// ElementSearch.swift - Contains search and element collection logic
|
||||
|
||||
import ApplicationServices
|
||||
import Darwin
|
||||
import Foundation
|
||||
|
||||
// Variable DEBUG_LOGGING_ENABLED is expected to be globally available from Logging.swift
|
||||
@ -97,14 +98,28 @@ public func search(element: Element,
|
||||
requireAction: String?,
|
||||
depth: Int = 0,
|
||||
maxDepth: Int = DEFAULT_MAX_DEPTH_SEARCH,
|
||||
isDebugLoggingEnabled: Bool,
|
||||
currentDebugLogs: inout [String]) -> Element? {
|
||||
func dLog(_ message: String) { if isDebugLoggingEnabled { currentDebugLogs.append(message) } }
|
||||
var tempLogs: [String] = [] // For calls to Element methods
|
||||
isDebugLoggingEnabled: Bool
|
||||
/* REMOVED: currentDebugLogs: inout [String] */) -> (foundElement: Element?, logs: [String]) { // CHANGED RETURN TYPE
|
||||
fputs("SEARCH_FUNCTION_RAW_PRINT_STDERR: Depth \(depth), isDebug: \(isDebugLoggingEnabled)\n", stderr)
|
||||
var internalSearchLogs: [String] = [] // NEW: Internal log storage
|
||||
|
||||
// DIRECT APPEND AND LOCAL LET FOR DEBUG FLAG
|
||||
internalSearchLogs.append("SEARCH_ENTRY_DIRECT_APPEND: Depth \(depth), isDebugLoggingEnabledParam: \(isDebugLoggingEnabled)")
|
||||
let localDebugEnabled = isDebugLoggingEnabled
|
||||
internalSearchLogs.append("SEARCH_ENTRY_LOCALDEBUG: localDebugEnabled is \(localDebugEnabled)")
|
||||
|
||||
func dLog(_ message: String) { if localDebugEnabled { internalSearchLogs.append(message) } } // Appends to internalSearchLogs
|
||||
|
||||
var tempLogsForElementMethods: [String] = [] // For calls to Element methods that require inout logs
|
||||
|
||||
let criteriaDesc = locator.criteria.map { "\($0.key)=\($0.value)" }.joined(separator: ", ")
|
||||
let roleStr = element.role(isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &tempLogs) ?? "nil"
|
||||
let titleStr = element.title(isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &tempLogs) ?? "N/A"
|
||||
// Calls to element.role, element.title etc. will use tempLogsForElementMethods
|
||||
// Their logs aren't the primary concern for *this* refactor's test, but they need a valid inout array.
|
||||
let roleStr = element.role(isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &tempLogsForElementMethods) ?? "nil"
|
||||
let titleStr = element.title(isDebugLoggingEnabled: isDebugLoggingEnabled, currentDebugLogs: &tempLogsForElementMethods) ?? "N/A"
|
||||
internalSearchLogs.append(contentsOf: tempLogsForElementMethods) // Append logs from element methods
|
||||
tempLogsForElementMethods.removeAll() // Clear for next use
|
||||
|
||||
dLog(
|
||||
"search [D\(depth)]: Visiting. Role: \(roleStr), Title: \(titleStr). Locator Criteria: [\(criteriaDesc)], Action: \(requireAction ?? "none")"
|
||||
)
|
||||
@ -113,36 +128,46 @@ public func search(element: Element,
|
||||
let briefDesc = element.briefDescription(
|
||||
option: .default,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: &tempLogs
|
||||
currentDebugLogs: &tempLogsForElementMethods
|
||||
)
|
||||
internalSearchLogs.append(contentsOf: tempLogsForElementMethods)
|
||||
tempLogsForElementMethods.removeAll()
|
||||
dLog("search [D\(depth)]: Max depth \(maxDepth) reached for element \(briefDesc).")
|
||||
return nil
|
||||
return (nil, internalSearchLogs) // RETURN TUPLE
|
||||
}
|
||||
|
||||
// evaluateElementAgainstCriteria still uses inout, its logs will be added to internalSearchLogs
|
||||
var logsFromEvaluate: [String] = []
|
||||
let matchStatus = evaluateElementAgainstCriteria(element: element,
|
||||
locator: locator,
|
||||
actionToVerify: requireAction,
|
||||
depth: depth,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs) // Pass through logs
|
||||
currentDebugLogs: &logsFromEvaluate)
|
||||
internalSearchLogs.append(contentsOf: logsFromEvaluate)
|
||||
|
||||
if matchStatus == .fullMatch {
|
||||
let briefDesc = element.briefDescription(
|
||||
option: .default,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: &tempLogs
|
||||
currentDebugLogs: &tempLogsForElementMethods
|
||||
)
|
||||
internalSearchLogs.append(contentsOf: tempLogsForElementMethods)
|
||||
tempLogsForElementMethods.removeAll()
|
||||
dLog(
|
||||
"search [D\(depth)]: evaluateElementAgainstCriteria returned .fullMatch for \(briefDesc). Returning element."
|
||||
)
|
||||
return element
|
||||
return (element, internalSearchLogs) // RETURN TUPLE
|
||||
}
|
||||
|
||||
let briefDesc = element.briefDescription(
|
||||
option: .default,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: &tempLogs
|
||||
currentDebugLogs: &tempLogsForElementMethods
|
||||
)
|
||||
internalSearchLogs.append(contentsOf: tempLogsForElementMethods)
|
||||
tempLogsForElementMethods.removeAll()
|
||||
|
||||
if matchStatus == .partialMatch_actionMissing {
|
||||
dLog(
|
||||
"search [D\(depth)]: Element \(briefDesc) matched criteria but missed action '\(requireAction ?? "")'. Continuing child search."
|
||||
@ -154,25 +179,31 @@ public func search(element: Element,
|
||||
|
||||
let childrenToSearch: [Element] = element.children(
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: &tempLogs
|
||||
currentDebugLogs: &tempLogsForElementMethods // Pass tempLogsForElementMethods here
|
||||
) ?? []
|
||||
internalSearchLogs.append(contentsOf: tempLogsForElementMethods)
|
||||
tempLogsForElementMethods.removeAll()
|
||||
|
||||
|
||||
if !childrenToSearch.isEmpty {
|
||||
for childElement in childrenToSearch {
|
||||
if let found = search(
|
||||
// RECURSIVE CALL
|
||||
let recursiveResult = search( // No longer passes currentDebugLogs
|
||||
element: childElement,
|
||||
locator: locator,
|
||||
requireAction: requireAction,
|
||||
depth: depth + 1,
|
||||
maxDepth: maxDepth,
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled,
|
||||
currentDebugLogs: ¤tDebugLogs
|
||||
) {
|
||||
return found
|
||||
isDebugLoggingEnabled: isDebugLoggingEnabled
|
||||
// Removed: currentDebugLogs: ¤tDebugLogs -> now &internalSearchLogs
|
||||
)
|
||||
internalSearchLogs.append(contentsOf: recursiveResult.logs) // Append logs from recursive call
|
||||
if let found = recursiveResult.foundElement {
|
||||
return (found, internalSearchLogs) // RETURN TUPLE
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return (nil, internalSearchLogs) // RETURN TUPLE
|
||||
}
|
||||
|
||||
@MainActor
|
||||
|
||||
@ -3,6 +3,12 @@
|
||||
import AXorcistLib
|
||||
import Foundation
|
||||
|
||||
// TEMPORARY TEST STRUCT - REMOVED
|
||||
// struct SimpleTestResponse: Codable {
|
||||
// var message: String
|
||||
// var logs: [String]?
|
||||
// }
|
||||
|
||||
struct CommandExecutor {
|
||||
|
||||
static func execute(
|
||||
@ -12,7 +18,10 @@ struct CommandExecutor {
|
||||
) async -> String {
|
||||
|
||||
var localDebugLogs: [String] = []
|
||||
if debug { localDebugLogs.append("Executing command: \(command.command) (ID: \(command.command_id))") }
|
||||
// Determine the effective debug logging state
|
||||
let effectiveDebugLogging = command.debug_logging ?? debug
|
||||
|
||||
if effectiveDebugLogging { localDebugLogs.append("Executing command: \(command.command) (ID: \(command.command_id)), effectiveDebug: \(effectiveDebugLogging), cliDebug: \(debug), jsonDebug: \(String(describing: command.debug_logging))") }
|
||||
|
||||
let ax = axorcist // Use the passed-in instance
|
||||
|
||||
@ -36,7 +45,7 @@ struct CommandExecutor {
|
||||
actionName: actionName,
|
||||
actionValue: command.action_value,
|
||||
maxDepth: command.max_elements,
|
||||
isDebugLoggingEnabled: debug,
|
||||
isDebugLoggingEnabled: effectiveDebugLogging,
|
||||
currentDebugLogs: &localDebugLogs
|
||||
)
|
||||
let queryResponse = QueryResponse(
|
||||
@ -44,7 +53,7 @@ struct CommandExecutor {
|
||||
success: handlerResponse.error == nil,
|
||||
command: command.command.rawValue,
|
||||
handlerResponse: handlerResponse,
|
||||
debug_logs: debug ? localDebugLogs : nil
|
||||
debug_logs: effectiveDebugLogging ? localDebugLogs : nil
|
||||
)
|
||||
return encodeToJson(queryResponse) ?? "{\"error\": \"Encoding performAction response failed\"}"
|
||||
|
||||
@ -52,7 +61,7 @@ struct CommandExecutor {
|
||||
let handlerResponse: HandlerResponse = await ax.handleGetFocusedElement(
|
||||
for: command.application,
|
||||
requestedAttributes: command.attributes,
|
||||
isDebugLoggingEnabled: debug,
|
||||
isDebugLoggingEnabled: effectiveDebugLogging,
|
||||
currentDebugLogs: &localDebugLogs
|
||||
)
|
||||
let queryResponse = QueryResponse(
|
||||
@ -60,7 +69,7 @@ struct CommandExecutor {
|
||||
success: handlerResponse.error == nil,
|
||||
command: command.command.rawValue,
|
||||
handlerResponse: handlerResponse,
|
||||
debug_logs: debug ? localDebugLogs : nil
|
||||
debug_logs: effectiveDebugLogging ? localDebugLogs : nil
|
||||
)
|
||||
return encodeToJson(queryResponse) ?? "{\"error\": \"Encoding getFocusedElement response failed\"}"
|
||||
|
||||
@ -83,7 +92,7 @@ struct CommandExecutor {
|
||||
pathHint: command.path_hint,
|
||||
maxDepth: command.max_elements,
|
||||
outputFormat: command.output_format,
|
||||
isDebugLoggingEnabled: debug,
|
||||
isDebugLoggingEnabled: effectiveDebugLogging,
|
||||
currentDebugLogs: &localDebugLogs
|
||||
)
|
||||
let queryResponse = QueryResponse(
|
||||
@ -91,7 +100,7 @@ struct CommandExecutor {
|
||||
success: handlerResponse.error == nil,
|
||||
command: command.command.rawValue,
|
||||
handlerResponse: handlerResponse,
|
||||
debug_logs: debug ? localDebugLogs : nil
|
||||
debug_logs: effectiveDebugLogging ? localDebugLogs : nil
|
||||
)
|
||||
return encodeToJson(queryResponse) ?? "{\"error\": \"Encoding getAttributes response failed\"}"
|
||||
|
||||
@ -114,7 +123,7 @@ struct CommandExecutor {
|
||||
maxDepth: command.max_elements,
|
||||
requestedAttributes: command.attributes,
|
||||
outputFormat: command.output_format,
|
||||
isDebugLoggingEnabled: debug,
|
||||
isDebugLoggingEnabled: effectiveDebugLogging,
|
||||
currentDebugLogs: &localDebugLogs
|
||||
)
|
||||
let queryResponse = QueryResponse(
|
||||
@ -122,7 +131,7 @@ struct CommandExecutor {
|
||||
success: handlerResponse.error == nil,
|
||||
command: command.command.rawValue,
|
||||
handlerResponse: handlerResponse,
|
||||
debug_logs: debug ? localDebugLogs : nil
|
||||
debug_logs: effectiveDebugLogging ? localDebugLogs : nil
|
||||
)
|
||||
return encodeToJson(queryResponse) ?? "{\"error\": \"Encoding query response failed\"}"
|
||||
|
||||
@ -144,7 +153,7 @@ struct CommandExecutor {
|
||||
pathHint: command.path_hint,
|
||||
maxDepth: command.max_elements,
|
||||
outputFormat: command.output_format,
|
||||
isDebugLoggingEnabled: debug,
|
||||
isDebugLoggingEnabled: effectiveDebugLogging,
|
||||
currentDebugLogs: &localDebugLogs
|
||||
)
|
||||
let queryResponse = QueryResponse(
|
||||
@ -152,7 +161,7 @@ struct CommandExecutor {
|
||||
success: handlerResponse.error == nil,
|
||||
command: command.command.rawValue,
|
||||
handlerResponse: handlerResponse,
|
||||
debug_logs: debug ? localDebugLogs : nil
|
||||
debug_logs: effectiveDebugLogging ? localDebugLogs : nil
|
||||
)
|
||||
return encodeToJson(queryResponse) ?? "{\"error\": \"Encoding describeElement response failed\"}"
|
||||
|
||||
@ -172,7 +181,7 @@ struct CommandExecutor {
|
||||
for: command.application,
|
||||
locator: locator,
|
||||
pathHint: command.path_hint,
|
||||
isDebugLoggingEnabled: debug,
|
||||
isDebugLoggingEnabled: effectiveDebugLogging,
|
||||
currentDebugLogs: &localDebugLogs
|
||||
)
|
||||
let queryResponse = QueryResponse(
|
||||
@ -180,14 +189,11 @@ struct CommandExecutor {
|
||||
success: handlerResponse.error == nil,
|
||||
command: command.command.rawValue,
|
||||
handlerResponse: handlerResponse,
|
||||
debug_logs: debug ? localDebugLogs : nil
|
||||
debug_logs: effectiveDebugLogging ? localDebugLogs : nil
|
||||
)
|
||||
return encodeToJson(queryResponse) ?? "{\"error\": \"Encoding extractText response failed\"}"
|
||||
|
||||
case .collectAll:
|
||||
// AXorcist.handleCollectAll returns a String (JSON) directly.
|
||||
// It manages its own debug logs internally via recursiveCallDebugLogs.
|
||||
// The `currentDebugLogs` passed to it is for initial logs only.
|
||||
let jsonStringResult = await ax.handleCollectAll(
|
||||
for: command.application,
|
||||
locator: command.locator,
|
||||
@ -196,64 +202,59 @@ struct CommandExecutor {
|
||||
requestedAttributes: command.attributes,
|
||||
outputFormat: command.output_format,
|
||||
commandId: command.command_id,
|
||||
isDebugLoggingEnabled: debug,
|
||||
isDebugLoggingEnabled: effectiveDebugLogging,
|
||||
currentDebugLogs: localDebugLogs
|
||||
)
|
||||
return jsonStringResult
|
||||
|
||||
case .batch:
|
||||
guard let subCommands = command.sub_commands else {
|
||||
let error = "Missing sub_commands for batch"
|
||||
let error = "Missing sub_commands for batch command"
|
||||
localDebugLogs.append(error)
|
||||
return encodeToJson(QueryResponse(
|
||||
return encodeToJson(BatchResponse(
|
||||
command_id: command.command_id,
|
||||
success: false,
|
||||
commandId: command.command_id,
|
||||
command: command.command.rawValue,
|
||||
results: [],
|
||||
error: error,
|
||||
debugLogs: debug ? localDebugLogs : nil
|
||||
)) ?? "{\"error\": \"Encoding error response failed\"}"
|
||||
debug_logs: effectiveDebugLogging ? localDebugLogs : nil
|
||||
)) ?? "{\"error\": \"Encoding batch error response failed\"}"
|
||||
}
|
||||
let batchHandlerResponses: [HandlerResponse] = await ax.handleBatchCommands(
|
||||
|
||||
var batchDebugLogs = localDebugLogs
|
||||
let batchResults: [HandlerResponse] = await ax.handleBatchCommands(
|
||||
batchCommandID: command.command_id,
|
||||
subCommands: subCommands,
|
||||
isDebugLoggingEnabled: debug,
|
||||
currentDebugLogs: &localDebugLogs
|
||||
isDebugLoggingEnabled: effectiveDebugLogging,
|
||||
currentDebugLogs: &batchDebugLogs
|
||||
)
|
||||
// Convert [HandlerResponse] to an array of QueryResponse objects
|
||||
let queryResponses = batchHandlerResponses.enumerated().map { index, hr -> QueryResponse in
|
||||
let subCommandId = index < subCommands.count ? subCommands[index].command_id : "batch_sub_\(index)"
|
||||
let subCommand = index < subCommands.count ? subCommands[index].command.rawValue : "unknown"
|
||||
return QueryResponse(
|
||||
command_id: subCommandId,
|
||||
success: hr.error == nil,
|
||||
command: subCommand,
|
||||
handlerResponse: hr,
|
||||
debug_logs: hr.debug_logs
|
||||
)
|
||||
}
|
||||
// Determine overall success of the batch
|
||||
let overallSuccess = batchHandlerResponses.allSatisfy { $0.error == nil }
|
||||
// Return BatchOperationResponse
|
||||
let batchResponse = BatchOperationResponse(
|
||||
|
||||
let overallSuccess = batchResults.allSatisfy { $0.error == nil }
|
||||
let batchResponse = BatchResponse(
|
||||
command_id: command.command_id,
|
||||
success: overallSuccess,
|
||||
results: queryResponses,
|
||||
debug_logs: debug ? localDebugLogs : nil
|
||||
results: batchResults,
|
||||
error: nil,
|
||||
debug_logs: effectiveDebugLogging ? batchDebugLogs : nil
|
||||
)
|
||||
return encodeToJson(batchResponse) ?? "{\"error\": \"Encoding batch response failed\"}"
|
||||
|
||||
case .ping:
|
||||
let appName = command.application ?? "N/A"
|
||||
let msg = "Ping received for \(appName). AXORC Version: \(AXORC_VERSION)"
|
||||
localDebugLogs.append(msg)
|
||||
return encodeToJson(SimpleSuccessResponse(
|
||||
if effectiveDebugLogging { localDebugLogs.append("Ping command received. Responding with pong.") }
|
||||
// Create an empty HandlerResponse for ping
|
||||
let pingHandlerResponse = HandlerResponse(
|
||||
data: nil,
|
||||
error: nil,
|
||||
debug_logs: nil // Ping-specific logs are already in localDebugLogs
|
||||
)
|
||||
// Construct QueryResponse using the HandlerResponse initializer
|
||||
let queryResponse = QueryResponse(
|
||||
command_id: command.command_id,
|
||||
success: true,
|
||||
status: "pong",
|
||||
message: msg,
|
||||
details: nil,
|
||||
debug_logs: debug ? localDebugLogs : nil
|
||||
)) ?? "{\"error\": \"Encoding ping response failed\"}"
|
||||
success: true, // Ping is always a success if reached
|
||||
command: command.command.rawValue,
|
||||
handlerResponse: pingHandlerResponse,
|
||||
debug_logs: effectiveDebugLogging ? localDebugLogs : nil
|
||||
)
|
||||
return encodeToJson(queryResponse) ?? "{\"error\": \"Encoding ping response failed\"}"
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,6 +266,9 @@ struct CommandExecutor {
|
||||
let data = try encoder.encode(object)
|
||||
return String(data: data, encoding: .utf8)
|
||||
} catch {
|
||||
// PRINT THE ERROR TO STDERR
|
||||
let errorDescription = "JSON ENCODING ERROR: \(error.localizedDescription). Details: \(error)"
|
||||
FileHandle.standardError.write(errorDescription.data(using: .utf8)!)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user