Files

66 lines
2.2 KiB
Swift

/// Computer Use: semantic AX and background-safe macOS computer use.
///
/// Four modes:
/// mcp — run the MCP server over stdio
/// --check — print permission status as JSON to stdout and exit
/// --list-apps — print running regular apps as JSON to stdout and exit
/// (default) — open the permission setup GUI
import AppKit
import Foundation
setbuf(stdout, nil)
let args = CommandLine.arguments
let subcommand = args.count >= 2 ? args[1] : ""
switch subcommand {
case "mcp":
if ProcessInfo.processInfo.environment["OPENWORK_COMPUTER_USE_CURSOR_OVERLAY"] == "0" {
let server = MCPServer()
await server.run()
} else {
await runMCPServerWithOverlay()
}
case "--check":
// Fresh process → fresh TCC read → always accurate.
let status = ComputerUsePermissions.status()
let json = "{\"ok\":\(status.ok),\"accessibility\":\(status.accessibility),\"screenRecording\":\(status.screenRecording)}"
print(json)
exit(0)
case "--list-apps":
// Running regular apps (Dock-visible). Needs no TCC permissions, so this
// is safe to call from the composer at any time.
let apps = NSWorkspace.shared.runningApplications
.filter { $0.activationPolicy == .regular }
.compactMap(\.localizedName)
.sorted { $0.localizedCaseInsensitiveCompare($1) == .orderedAscending }
let payload: [String: Any] = ["ok": true, "apps": apps]
let data = (try? JSONSerialization.data(withJSONObject: payload)) ?? Data("{\"ok\":false,\"apps\":[]}".utf8)
print(String(decoding: data, as: UTF8.self))
exit(0)
default:
await runPermissionSetupApp()
}
@MainActor
func runMCPServerWithOverlay() async {
NSApplication.shared.setActivationPolicy(.accessory)
let server = MCPServer()
Task.detached {
await server.run()
await MainActor.run {
NSApplication.shared.terminate(nil)
}
}
NSApplication.shared.run()
}
@MainActor
func runPermissionSetupApp() async {
NSApplication.shared.setActivationPolicy(.regular)
let appDelegate = PermissionSetupAppDelegate()
NSApplication.shared.delegate = appDelegate
NSApplication.shared.run()
}