Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,10 @@ extension DragTool {
message: "Invalid \(parameterName) coordinates. Both x and y must be valid numbers")
}

// Coordinates outside the desktop are nearly always malformed tool input.
guard background || (x >= 0 && y >= 0) else {
// Displays left of or above the primary display have negative global coordinates.
guard background || ((-20000...20000).contains(x) && (-20000...20000).contains(y)) else {
throw CoordinateParseError(
message: "Invalid \(parameterName) coordinates. Both x and y must be non-negative")
}

guard background || (x <= 20000 && y <= 20000) else {
throw CoordinateParseError(
message: "Invalid \(parameterName) coordinates. Both x and y must be 20000 or less")
message: "Invalid \(parameterName) coordinates. Both x and y must be between -20000 and 20000")
}

return CGPoint(x: x, y: y)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@ extension MoveTool {
throw CoordinateParseError(message: "Invalid \(parameterName). Both x and y must be valid numbers")
}

guard x >= 0, y >= 0 else {
throw CoordinateParseError(message: "Invalid \(parameterName). Both x and y must be non-negative")
}

guard x <= 20000, y <= 20000 else {
throw CoordinateParseError(message: "Invalid \(parameterName). Both x and y must be 20000 or less")
guard (-20000...20000).contains(x), (-20000...20000).contains(y) else {
throw CoordinateParseError(
message: "Invalid \(parameterName). Both x and y must be between -20000 and 20000")
}

return CGPoint(x: x, y: y)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import CoreGraphics
import MCP
import PeekabooAutomationKit
import TachikomaMCP
import Testing
@testable import PeekabooAgentRuntime
@testable import PeekabooAutomation
@testable import PeekabooCore

@MainActor
struct MCPSecondaryDisplayPointerTests {
@Test(arguments: ["-100,200", "100,-200", "-100,-200"])
func `move accepts signed global coordinates for secondary displays`(_ coordinates: String) async throws {
let automation = MockAutomationService(accessibilityGranted: true)
let context = await MCPToolTestHelpers.makeLegacyContext(automation: automation)
let response = try await MoveTool(context: context).execute(arguments: ToolArguments(raw: [
"to": coordinates, "foreground": true,
]))
#expect(!response.isError)
#expect(automation.lastMoveTarget != nil)
print("MoveTool signed target=\(coordinates); isError=\(response.isError)")
}

@Test
func `foreground drag accepts endpoints left of and above the primary display`() async throws {
let automation = MockAutomationService(accessibilityGranted: true)
let context = await MCPToolTestHelpers.makeLegacyContext(automation: automation)
let response = try await DragTool(context: context).execute(arguments: ToolArguments(raw: [
"from_coords": "-100,200", "to_coords": "100,-200", "foreground": true,
]))
#expect(!response.isError)
print("DragTool signed endpoints=-100,200 to100,-200; isError=\(response.isError)")
}

@Test(arguments: ["-20001,1", "1,-20001", "20001,1", "nan,1", "inf,1"])
func `malformed or extreme foreground coordinates are refused`(_ coordinates: String) async throws {
let automation = MockAutomationService(accessibilityGranted: true)
let context = await MCPToolTestHelpers.makeLegacyContext(automation: automation)
let move = try await MoveTool(context: context).execute(arguments: ToolArguments(raw: [
"to": coordinates, "foreground": true,
]))
let drag = try await DragTool(context: context).execute(arguments: ToolArguments(raw: [
"from_coords": "0,0", "to_coords": coordinates, "foreground": true,
]))
#expect(move.isError)
#expect(drag.isError)
#expect(automation.lastMoveTarget == nil)
}
}
Loading