native macOS codings agent orchestrator prowl.onev.cat
Something went wrong. Try again.
Swift
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169// ProwlCLI/Commands/LifecycleSelectorOptions.swift// Typed target selectors for action-first lifecycle commands.
import ArgumentParserimport Foundationimport ProwlCLIShared
struct LifecycleSelectorOptions: ParsableArguments { @Option(name: .long, help: "Target worktree by id, name, or path.") var worktree: String?
@Option(name: .long, help: "Target tab by UUID or short handle (for example, t4).") var tab: String?
@Option(name: .long, help: "Target pane by UUID or short handle (for example, p3).") var pane: String?
func resolveWorktree(positionalTarget: String?) throws -> TargetSelector { try resolve(positionalTarget: positionalTarget, acceptedSelector: .worktree) }
func resolvePane(positionalTarget: String?) throws -> TargetSelector { let provided = [worktree, tab, pane].compactMap { $0 } guard provided.count <= 1 else { throw ExitError( code: CLIErrorCode.invalidArgument, message: "At most one target selector (--worktree, --tab, --pane) is allowed." ) }
if let positionalTarget { guard provided.isEmpty else { throw ExitError( code: CLIErrorCode.invalidArgument, message: "Use either a positional pane or --pane." ) } guard isPaneReference(positionalTarget) else { throw ExitError( code: CLIErrorCode.invalidArgument, message: "create pane requires a pane UUID or prefixed handle (pN)." ) } return .pane(positionalTarget) }
if worktree != nil || tab != nil { throw ExitError( code: CLIErrorCode.invalidArgument, message: "create pane accepts only --pane, not --worktree or --tab." ) } guard let pane else { throw ExitError( code: CLIErrorCode.invalidArgument, message: "create pane requires an explicit pane anchor." ) } guard isPaneReference(pane) else { throw ExitError( code: CLIErrorCode.invalidArgument, message: "create pane requires a pane UUID or prefixed handle (pN)." ) } return .pane(pane) }
func resolveTerminalTarget(positionalTarget: String?) throws -> TargetSelector { let provided = [worktree, tab, pane].compactMap { $0 } guard provided.count <= 1 else { throw ExitError( code: CLIErrorCode.invalidArgument, message: "At most one target selector (--worktree, --tab, --pane) is allowed." ) }
if let positionalTarget { guard provided.isEmpty else { throw ExitError( code: CLIErrorCode.invalidArgument, message: "Use either a positional target or one selector flag (--tab, --pane)." ) } guard isTerminalReference(positionalTarget) else { throw ExitError( code: CLIErrorCode.invalidArgument, message: "close requires a pane/tab UUID or prefixed handle (pN or tN)." ) } return .auto(positionalTarget) }
if worktree != nil { throw ExitError( code: CLIErrorCode.invalidArgument, message: "close accepts only --tab or --pane, not --worktree." ) } if let tab { return .tab(tab) } if let pane { return .pane(pane) } throw ExitError( code: CLIErrorCode.invalidArgument, message: "close requires an explicit pane or tab target." ) }
private enum AcceptedSelector { case worktree }
private func resolve(positionalTarget: String?, acceptedSelector: AcceptedSelector) throws -> TargetSelector { let provided = [worktree, tab, pane].compactMap { $0 } guard provided.count <= 1 else { throw ExitError( code: CLIErrorCode.invalidArgument, message: "At most one target selector (--worktree, --tab, --pane) is allowed." ) }
if let positionalTarget { guard provided.isEmpty else { throw ExitError( code: CLIErrorCode.invalidArgument, message: "Use either a positional target or one selector flag (--worktree)." ) } return .worktree(positionalTarget) }
switch acceptedSelector { case .worktree: if let worktree { return .worktree(worktree) } if tab != nil || pane != nil { throw ExitError( code: CLIErrorCode.invalidArgument, message: "create tab accepts only a worktree target." ) } throw ExitError( code: CLIErrorCode.invalidArgument, message: "create tab requires an explicit worktree target." ) } }
private func isTerminalReference(_ value: String) -> Bool { isPaneReference(value) || isPrefixedHandle(value, prefix: "t") }
private func isPaneReference(_ value: String) -> Bool { UUID(uuidString: value) != nil || isPrefixedHandle(value, prefix: "p") }
private func isPrefixedHandle(_ value: String, prefix: Character) -> Bool { let normalized = value.lowercased() guard normalized.first == prefix else { return false } let digits = normalized.dropFirst() guard !digits.isEmpty, digits.allSatisfy({ $0.isASCII && $0.isNumber }), let handle = Int(digits), handle > 0 else { return false } return true }}