mcp-baepsae 5.1.0 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README-KR.md +98 -33
  2. package/README.md +101 -35
  3. package/bundled/baepsae-native +0 -0
  4. package/dist/backend.d.ts +26 -0
  5. package/dist/backend.d.ts.map +1 -0
  6. package/dist/backend.js +79 -0
  7. package/dist/backend.js.map +1 -0
  8. package/dist/index.js +3 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/tool-manifest.d.ts +12 -0
  11. package/dist/tool-manifest.d.ts.map +1 -0
  12. package/dist/tool-manifest.js +79 -0
  13. package/dist/tool-manifest.js.map +1 -0
  14. package/dist/tools/info.d.ts.map +1 -1
  15. package/dist/tools/info.js +104 -5
  16. package/dist/tools/info.js.map +1 -1
  17. package/dist/tools/input.js +7 -6
  18. package/dist/tools/input.js.map +1 -1
  19. package/dist/tools/media.d.ts.map +1 -1
  20. package/dist/tools/media.js +137 -11
  21. package/dist/tools/media.js.map +1 -1
  22. package/dist/tools/simulator.js +7 -7
  23. package/dist/tools/simulator.js.map +1 -1
  24. package/dist/tools/system.d.ts.map +1 -1
  25. package/dist/tools/system.js +2 -2
  26. package/dist/tools/system.js.map +1 -1
  27. package/dist/tools/ui.d.ts.map +1 -1
  28. package/dist/tools/ui.js +126 -8
  29. package/dist/tools/ui.js.map +1 -1
  30. package/dist/tools/workflow.d.ts +3 -0
  31. package/dist/tools/workflow.d.ts.map +1 -0
  32. package/dist/tools/workflow.js +434 -0
  33. package/dist/tools/workflow.js.map +1 -0
  34. package/dist/types.d.ts +15 -0
  35. package/dist/types.d.ts.map +1 -1
  36. package/dist/utils.d.ts +19 -3
  37. package/dist/utils.d.ts.map +1 -1
  38. package/dist/utils.js +110 -5
  39. package/dist/utils.js.map +1 -1
  40. package/dist/version.d.ts +1 -1
  41. package/dist/version.js +1 -1
  42. package/native/Sources/Commands/InputCommands.swift +53 -33
  43. package/native/Sources/Commands/SystemCommands.swift +86 -0
  44. package/native/Sources/Commands/UICommands.swift +254 -35
  45. package/native/Sources/Commands/WindowCommands.swift +11 -4
  46. package/native/Sources/IndigoHID/IndigoHIDClient.swift +222 -0
  47. package/native/Sources/IndigoHID/IndigoHIDCoordinates.swift +74 -0
  48. package/native/Sources/IndigoHID/IndigoHIDEvents.swift +63 -0
  49. package/native/Sources/IndigoHID/IndigoHIDLoader.swift +102 -0
  50. package/native/Sources/IndigoHID/IndigoHIDTypes.swift +41 -0
  51. package/native/Sources/Types.swift +26 -0
  52. package/native/Sources/Utils.swift +653 -13
  53. package/native/Sources/Version.swift +1 -1
  54. package/native/Sources/main.swift +55 -8
  55. package/native/Tests/BaepsaeNativeTests/BinaryInvocationTests.swift +54 -6
  56. package/package.json +12 -3
  57. package/scripts/dump-tabbar-actions.mjs +312 -0
  58. package/scripts/generate-tool-manifest.mjs +75 -0
  59. package/scripts/research-coordinate-calibration.mjs +276 -0
  60. package/scripts/research-input-channels.mjs +327 -0
  61. package/scripts/research-tap-tab-grid.mjs +271 -0
  62. package/scripts/verify-media-capture.mjs +99 -0
@@ -0,0 +1,74 @@
1
+ import CoreGraphics
2
+ import Foundation
3
+
4
+ // MARK: - Coordinate Normalization
5
+
6
+ /// Normalizes pixel coordinates to 0-1 ratio for IndigoHID.
7
+ /// IndigoHID expects coordinates as fractions of the screen dimensions.
8
+ struct IndigoHIDCoordinates {
9
+ let screenWidth: Double
10
+ let screenHeight: Double
11
+
12
+ init(screenWidth: Double, screenHeight: Double) {
13
+ self.screenWidth = max(1, screenWidth)
14
+ self.screenHeight = max(1, screenHeight)
15
+ }
16
+
17
+ /// Convert point coordinates (pixels) to normalized 0-1 ratio.
18
+ /// Origin is top-left.
19
+ func normalize(x: Double, y: Double) -> (x: Double, y: Double) {
20
+ return (x / screenWidth, y / screenHeight)
21
+ }
22
+
23
+ /// Create a touch point from pixel coordinates.
24
+ func touchPoint(x: Double, y: Double, phase: IndigoHIDTouchPhase, finger: UInt32 = 1) -> IndigoHIDTouchPoint {
25
+ let (nx, ny) = normalize(x: x, y: y)
26
+ return IndigoHIDTouchPoint(x: nx, y: ny, phase: phase, finger: finger)
27
+ }
28
+ }
29
+
30
+ /// Resolve screen dimensions for the given simulator UDID.
31
+ /// Falls back to common iPhone dimensions if detection fails.
32
+ func resolveSimulatorScreenSize(udid: String) -> (width: Double, height: Double) {
33
+ // Try to get screen size from simctl
34
+ let process = Process()
35
+ process.executableURL = URL(fileURLWithPath: "/usr/bin/xcrun")
36
+ process.arguments = ["simctl", "list", "devices", "-j"]
37
+
38
+ let pipe = Pipe()
39
+ process.standardOutput = pipe
40
+ process.standardError = FileHandle.nullDevice
41
+
42
+ do {
43
+ try process.run()
44
+ process.waitUntilExit()
45
+
46
+ let data = pipe.fileHandleForReading.readDataToEndOfFile()
47
+ if let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
48
+ let devices = json["devices"] as? [String: [[String: Any]]] {
49
+ for (_, deviceList) in devices {
50
+ for device in deviceList {
51
+ if let deviceUdid = device["udid"] as? String, deviceUdid == udid {
52
+ // Try to infer from device type
53
+ if let deviceType = device["deviceTypeIdentifier"] as? String {
54
+ if deviceType.contains("iPhone-16") || deviceType.contains("iPhone-15") {
55
+ return (393, 852)
56
+ }
57
+ if deviceType.contains("iPhone-SE") {
58
+ return (375, 667)
59
+ }
60
+ if deviceType.contains("iPad") {
61
+ return (1024, 1366)
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ } catch {
69
+ // Fall through to default
70
+ }
71
+
72
+ // Default: iPhone 15/16 logical resolution
73
+ return (393, 852)
74
+ }
@@ -0,0 +1,63 @@
1
+ @preconcurrency import Foundation
2
+
3
+ // bootstrap_look_up is in /usr/include/servers/bootstrap.h
4
+ @_silgen_name("bootstrap_look_up")
5
+ func _bootstrap_look_up(_ bp: mach_port_t, _ name: UnsafePointer<CChar>, _ sp: UnsafeMutablePointer<mach_port_t>) -> kern_return_t
6
+
7
+ // MARK: - Mach Port Communication
8
+
9
+ /// Resolves the IndigoHID Mach service port for a given simulator UDID.
10
+ func resolveIndigoHIDPort(udid: String) -> mach_port_t? {
11
+ let serviceName = "com.apple.CoreSimulator.IndigoHIDService.\(udid)"
12
+ var port: mach_port_t = mach_port_t(MACH_PORT_NULL)
13
+ let bp = mach_port_t(bootstrap_port)
14
+ let result = serviceName.withCString { cStr in
15
+ _bootstrap_look_up(bp, cStr, &port)
16
+ }
17
+ if result == KERN_SUCCESS && port != mach_port_t(MACH_PORT_NULL) {
18
+ return port
19
+ }
20
+ return nil
21
+ }
22
+
23
+ /// Sends an IndigoHID message to the simulator via Mach IPC.
24
+ func sendIndigoHIDMessage(_ data: CFData, to port: mach_port_t) -> Bool {
25
+ let bytes = CFDataGetBytePtr(data)
26
+ let length = CFDataGetLength(data)
27
+ guard let bytes, length > 0 else { return false }
28
+
29
+ // Construct mach message
30
+ let headerSize = MemoryLayout<mach_msg_header_t>.size
31
+ let totalSize = headerSize + length
32
+ let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: totalSize)
33
+ defer { buffer.deallocate() }
34
+
35
+ // Zero out buffer
36
+ buffer.initialize(repeating: 0, count: totalSize)
37
+
38
+ // Set up mach message header
39
+ buffer.withMemoryRebound(to: mach_msg_header_t.self, capacity: 1) { header in
40
+ header.pointee.msgh_bits = UInt32(MACH_MSG_TYPE_COPY_SEND)
41
+ header.pointee.msgh_size = mach_msg_size_t(totalSize)
42
+ header.pointee.msgh_remote_port = port
43
+ header.pointee.msgh_local_port = mach_port_t(MACH_PORT_NULL)
44
+ header.pointee.msgh_id = 0
45
+ }
46
+
47
+ // Copy payload after header
48
+ (buffer + headerSize).update(from: bytes, count: length)
49
+
50
+ let result = buffer.withMemoryRebound(to: mach_msg_header_t.self, capacity: 1) { header in
51
+ mach_msg(
52
+ header,
53
+ MACH_SEND_MSG,
54
+ mach_msg_size_t(totalSize),
55
+ 0,
56
+ mach_port_t(MACH_PORT_NULL),
57
+ MACH_MSG_TIMEOUT_NONE,
58
+ mach_port_t(MACH_PORT_NULL)
59
+ )
60
+ }
61
+
62
+ return result == KERN_SUCCESS
63
+ }
@@ -0,0 +1,102 @@
1
+ import Foundation
2
+
3
+ // MARK: - Symbol Types
4
+
5
+ // Function pointer types matching SimulatorKit's IndigoHID API
6
+ typealias IndigoHIDMessageForButtonFn = @convention(c) (
7
+ UInt32, // button type
8
+ UInt32, // state (1=down, 2=up)
9
+ UInt64 // timestamp
10
+ ) -> Unmanaged<CFData>?
11
+
12
+ typealias IndigoHIDMessageForKeyboardArbitraryFn = @convention(c) (
13
+ UInt32, // usage page
14
+ UInt32, // usage (key code)
15
+ UInt32, // key operation (1=down, 2=up)
16
+ UInt64 // timestamp
17
+ ) -> Unmanaged<CFData>?
18
+
19
+ typealias IndigoHIDMessageForMouseNSEventFn = @convention(c) (
20
+ UInt32, // touch phase
21
+ Double, // x (0-1 normalized)
22
+ Double, // y (0-1 normalized)
23
+ UInt32, // finger index
24
+ Double, // pressure
25
+ Double, // twist
26
+ Double, // major radius
27
+ Double, // minor radius
28
+ UInt64 // timestamp
29
+ ) -> Unmanaged<CFData>?
30
+
31
+ // MARK: - IndigoHID Loader
32
+
33
+ /// Loads IndigoHID symbols from SimulatorKit.framework via dlopen/dlsym.
34
+ /// This is a singleton — symbol loading happens once.
35
+ final class IndigoHIDLoader: @unchecked Sendable {
36
+ static let shared = IndigoHIDLoader()
37
+
38
+ let buttonFn: IndigoHIDMessageForButtonFn?
39
+ let keyboardFn: IndigoHIDMessageForKeyboardArbitraryFn?
40
+ let mouseFn: IndigoHIDMessageForMouseNSEventFn?
41
+
42
+ /// Whether all required symbols were loaded successfully.
43
+ var isAvailable: Bool {
44
+ return buttonFn != nil && keyboardFn != nil && mouseFn != nil
45
+ }
46
+
47
+ private init() {
48
+ let frameworkPath = "/Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/Frameworks/SimulatorKit.framework/SimulatorKit"
49
+ let alternativePath = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/SimulatorKit.framework/SimulatorKit"
50
+
51
+ var handle = dlopen(frameworkPath, RTLD_LAZY)
52
+ if handle == nil {
53
+ handle = dlopen(alternativePath, RTLD_LAZY)
54
+ }
55
+
56
+ guard let handle else {
57
+ self.buttonFn = nil
58
+ self.keyboardFn = nil
59
+ self.mouseFn = nil
60
+ return
61
+ }
62
+
63
+ if let sym = dlsym(handle, "IndigoHIDMessageForButton") {
64
+ self.buttonFn = unsafeBitCast(sym, to: IndigoHIDMessageForButtonFn.self)
65
+ } else {
66
+ self.buttonFn = nil
67
+ }
68
+
69
+ if let sym = dlsym(handle, "IndigoHIDMessageForKeyboardArbitrary") {
70
+ self.keyboardFn = unsafeBitCast(sym, to: IndigoHIDMessageForKeyboardArbitraryFn.self)
71
+ } else {
72
+ self.keyboardFn = nil
73
+ }
74
+
75
+ if let sym = dlsym(handle, "IndigoHIDMessageForMouseNSEvent") {
76
+ self.mouseFn = unsafeBitCast(sym, to: IndigoHIDMessageForMouseNSEventFn.self)
77
+ } else {
78
+ self.mouseFn = nil
79
+ }
80
+ }
81
+
82
+ /// Create a touch event message.
83
+ func createTouchMessage(phase: IndigoHIDTouchPhase, x: Double, y: Double, finger: UInt32 = 1) -> CFData? {
84
+ guard let fn = mouseFn else { return nil }
85
+ let timestamp = mach_absolute_time()
86
+ return fn(phase.rawValue, x, y, finger, 1.0, 0.0, 5.0, 5.0, timestamp)?.takeRetainedValue()
87
+ }
88
+
89
+ /// Create a button event message.
90
+ func createButtonMessage(button: IndigoHIDButtonEventType, state: UInt32) -> CFData? {
91
+ guard let fn = buttonFn else { return nil }
92
+ let timestamp = mach_absolute_time()
93
+ return fn(button.rawValue, state, timestamp)?.takeRetainedValue()
94
+ }
95
+
96
+ /// Create a keyboard event message.
97
+ func createKeyboardMessage(usagePage: UInt32, usage: UInt32, operation: IndigoHIDKeyOperation) -> CFData? {
98
+ guard let fn = keyboardFn else { return nil }
99
+ let timestamp = mach_absolute_time()
100
+ return fn(usagePage, usage, operation.rawValue, timestamp)?.takeRetainedValue()
101
+ }
102
+ }
@@ -0,0 +1,41 @@
1
+ import Foundation
2
+
3
+ // MARK: - Touch Phase
4
+
5
+ enum IndigoHIDTouchPhase: UInt32 {
6
+ case began = 1
7
+ case moved = 2
8
+ case ended = 4
9
+ }
10
+
11
+ // MARK: - Button Event Type
12
+
13
+ enum IndigoHIDButtonEventType: UInt32 {
14
+ case home = 1
15
+ case lock = 2
16
+ case siri = 3
17
+ case applePay = 4
18
+ }
19
+
20
+ // MARK: - Key Operation
21
+
22
+ enum IndigoHIDKeyOperation: UInt32 {
23
+ case keyDown = 1
24
+ case keyUp = 2
25
+ }
26
+
27
+ // MARK: - Touch Point
28
+
29
+ struct IndigoHIDTouchPoint {
30
+ let x: Double // 0.0 - 1.0 normalized
31
+ let y: Double // 0.0 - 1.0 normalized
32
+ let phase: IndigoHIDTouchPhase
33
+ let finger: UInt32
34
+
35
+ init(x: Double, y: Double, phase: IndigoHIDTouchPhase, finger: UInt32 = 1) {
36
+ self.x = max(0, min(1, x))
37
+ self.y = max(0, min(1, y))
38
+ self.phase = phase
39
+ self.finger = finger
40
+ }
41
+ }
@@ -26,6 +26,32 @@ enum NativeError: Error, CustomStringConvertible {
26
26
  }
27
27
  }
28
28
 
29
+ enum NativeErrorCode: String {
30
+ case invalidArguments = "invalid_arguments"
31
+ case unsupported = "unsupported"
32
+ case commandFailed = "command_failed"
33
+ }
34
+
35
+ enum NativeErrorCategory: String {
36
+ case validation
37
+ case execution
38
+ case environment
39
+ case permission
40
+ case unsupported
41
+ case availability
42
+ case timeout
43
+ case unknown
44
+ }
45
+
46
+ struct StructuredNativeError {
47
+ let code: String
48
+ let category: NativeErrorCategory
49
+ let retryable: Bool
50
+ let source: String
51
+ let message: String
52
+ let nativeCode: NativeErrorCode
53
+ }
54
+
29
55
  struct ParsedOptions {
30
56
  let command: String
31
57
  let options: [String: String]