mirror of
https://github.com/samsonjs/Peekaboo.git
synced 2026-04-27 15:07:41 +00:00
- Add AsyncAdapter.swift to bridge async/sync execution - Change AsyncParsableCommand back to ParsableCommand - Implement AsyncRunnable protocol for async execution - Use DispatchSemaphore pattern for synchronous blocking - Make ErrorBox thread-safe with @unchecked Sendable This fixes the CLI execution issue where commands were showing help instead of executing, by properly bridging the async/sync worlds as required by ArgumentParser. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
140 lines
No EOL
3.1 KiB
Swift
140 lines
No EOL
3.1 KiB
Swift
import Foundation
|
|
import ArgumentParser
|
|
|
|
// MARK: - Adapter for AsyncParsableCommand to ParsableCommand bridge
|
|
|
|
protocol AsyncRunnable {
|
|
func runAsync() async throws
|
|
}
|
|
|
|
extension PeekabooCommand {
|
|
func run() throws {
|
|
let box = ErrorBox()
|
|
let sem = DispatchSemaphore(value: 0)
|
|
Task {
|
|
defer { sem.signal() }
|
|
do {
|
|
try await (self as AsyncRunnable).runAsync()
|
|
} catch {
|
|
box.error = error
|
|
}
|
|
}
|
|
sem.wait()
|
|
if let error = box.error {
|
|
throw error
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ImageCommand {
|
|
func run() throws {
|
|
let box = ErrorBox()
|
|
let sem = DispatchSemaphore(value: 0)
|
|
Task {
|
|
defer { sem.signal() }
|
|
do {
|
|
try await (self as AsyncRunnable).runAsync()
|
|
} catch {
|
|
box.error = error
|
|
}
|
|
}
|
|
sem.wait()
|
|
if let error = box.error {
|
|
throw error
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ListCommand {
|
|
func run() throws {
|
|
let box = ErrorBox()
|
|
let sem = DispatchSemaphore(value: 0)
|
|
Task {
|
|
defer { sem.signal() }
|
|
do {
|
|
try await (self as AsyncRunnable).runAsync()
|
|
} catch {
|
|
box.error = error
|
|
}
|
|
}
|
|
sem.wait()
|
|
if let error = box.error {
|
|
throw error
|
|
}
|
|
}
|
|
}
|
|
|
|
extension AppsSubcommand {
|
|
func run() throws {
|
|
let box = ErrorBox()
|
|
let sem = DispatchSemaphore(value: 0)
|
|
Task {
|
|
defer { sem.signal() }
|
|
do {
|
|
try await (self as AsyncRunnable).runAsync()
|
|
} catch {
|
|
box.error = error
|
|
}
|
|
}
|
|
sem.wait()
|
|
if let error = box.error {
|
|
throw error
|
|
}
|
|
}
|
|
}
|
|
|
|
extension WindowsSubcommand {
|
|
func run() throws {
|
|
let box = ErrorBox()
|
|
let sem = DispatchSemaphore(value: 0)
|
|
Task {
|
|
defer { sem.signal() }
|
|
do {
|
|
try await (self as AsyncRunnable).runAsync()
|
|
} catch {
|
|
box.error = error
|
|
}
|
|
}
|
|
sem.wait()
|
|
if let error = box.error {
|
|
throw error
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ServerStatusSubcommand {
|
|
func run() throws {
|
|
let box = ErrorBox()
|
|
let sem = DispatchSemaphore(value: 0)
|
|
Task {
|
|
defer { sem.signal() }
|
|
do {
|
|
try await (self as AsyncRunnable).runAsync()
|
|
} catch {
|
|
box.error = error
|
|
}
|
|
}
|
|
sem.wait()
|
|
if let error = box.error {
|
|
throw error
|
|
}
|
|
}
|
|
}
|
|
|
|
private final class ErrorBox: @unchecked Sendable {
|
|
private var _error: Error? = nil
|
|
private let lock = NSLock()
|
|
|
|
var error: Error? {
|
|
get {
|
|
lock.lock()
|
|
defer { lock.unlock() }
|
|
return _error
|
|
}
|
|
set {
|
|
lock.lock()
|
|
defer { lock.unlock() }
|
|
_error = newValue
|
|
}
|
|
}
|
|
} |