import Foundation#if canImport(Darwin)import Darwin#elseif canImport(Glibc)import Glibc#elseif canImport(Musl)import Musl#endif#if os(macOS)import Security#endif #if os(Linux)@_silgen_name("pipe2")private func linuxPipe2(_ pipeDescriptors: UnsafeMutablePointer<Int32>, _ flags: Int32) -> Int32#endif public enum PathPurpose: Hashable, Sendable { case rpc case tty case nodeTooling} public struct PathDebugSnapshot: Equatable, Sendable { public let codexBinary: String? public let claudeBinary: String? public let geminiBinary: String? public let effectivePATH: String public let loginShellPATH: String? public static let empty = PathDebugSnapshot( codexBinary: nil, claudeBinary: nil, geminiBinary: nil, effectivePATH: "", loginShellPATH: nil) public init( codexBinary: String?, claudeBinary: String?, geminiBinary: String? = nil, effectivePATH: String, loginShellPATH: String?) { self.codexBinary = codexBinary self.claudeBinary = claudeBinary self.geminiBinary = geminiBinary self.effectivePATH = effectivePATH self.loginShellPATH = loginShellPATH }} public enum BinaryLocator { /// Test-only override so parallel Gemini suites can point at fake binaries /// without mutating process-wide `GEMINI_CLI_PATH`. @TaskLocal public static var geminiBinaryPathOverrideForTesting: String? public static func resolveClaudeBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "claude", overrideKey: "CLAUDE_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: self.claudeWellKnownPaths(home: home), fileManager: fileManager, home: home) } /// Well-known installation paths for the Claude CLI binary. /// Covers Anthropic's native installer (`~/.local/bin`), the `claude migrate-installer` /// self-updating location (`~/.claude/local`), the legacy per-user installer /// (`~/.claude/bin`), Homebrew, and the macOS Terminal installer (cmux.app). static func claudeWellKnownPaths(home: String) -> [String] { [ "\(home)/.local/bin/claude", "\(home)/.claude/local/claude", "\(home)/.claude/bin/claude", "/opt/homebrew/bin/claude", "/usr/local/bin/claude", "/Applications/cmux.app/Contents/Resources/bin/claude", ] } public static func resolveAntigravityBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "agy", overrideKey: "ANTIGRAVITY_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: [ "\(home)/.local/bin/agy", "/opt/homebrew/bin/agy", "/usr/local/bin/agy", ], fileManager: fileManager, home: home) } public static func resolveCodexBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, launchCandidateFilter: (String, FileManager) -> Bool = CodexLaunchPreflight.isLaunchCandidateAllowed, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "codex", overrideKey: "CODEX_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: self.codexWellKnownPaths(home: home), launchCandidateFilter: launchCandidateFilter, fileManager: fileManager, home: home) } /// Well-known installation paths for the signed Codex CLI bundled with current and legacy desktop apps. /// Keep these after PATH lookups, but use them as a safe fallback when a PATH shim is blocked. static func codexWellKnownPaths(home: String) -> [String] { #if os(macOS) [ "\(home)/Applications/ChatGPT.app/Contents/Resources/codex", "\(home)/Applications/Codex.app/Contents/Resources/codex", "/Applications/ChatGPT.app/Contents/Resources/codex", "/Applications/Codex.app/Contents/Resources/codex", ] #else [] #endif } public static func resolveGeminiBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { if let override = self.geminiBinaryPathOverrideForTesting, fileManager.isExecutableFile(atPath: override) { return override } return self.resolveBinary( name: "gemini", overrideKey: "GEMINI_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, fileManager: fileManager, home: home) } public static func resolveGrokBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "grok", overrideKey: "GROK_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: self.grokWellKnownPaths(home: home), fileManager: fileManager, home: home) } public static func resolveAmpBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "amp", overrideKey: "AMP_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: self.ampWellKnownPaths(home: home), fileManager: fileManager, home: home) } static func ampWellKnownPaths(home: String) -> [String] { [ "\(home)/.local/bin/amp", "\(home)/.amp/bin/amp", "/opt/homebrew/bin/amp", "/usr/local/bin/amp", ] } /// Well-known install locations for the Grok Build CLI binary. /// Covers the installer's default (`~/.grok/bin/grok`) and the symlinks it sometimes /// creates into `~/.local/bin` and `/usr/local/bin`. static func grokWellKnownPaths(home: String) -> [String] { [ "\(home)/.grok/bin/grok", "\(home)/.local/bin/grok", "/usr/local/bin/grok", "/opt/homebrew/bin/grok", ] } public static func resolveAWSBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "aws", overrideKey: "AWS_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: self.awsWellKnownPaths(home: home), fileManager: fileManager, home: home) } /// Well-known install locations for the AWS CLI v2 (`aws`). /// Covers Homebrew (Apple Silicon + Intel) and the per-user pip/uv install path. static func awsWellKnownPaths(home: String) -> [String] { [ "/opt/homebrew/bin/aws", "/usr/local/bin/aws", "\(home)/.local/bin/aws", ] } public static func resolveAuggieBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "auggie", overrideKey: "AUGGIE_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, fileManager: fileManager, home: home) } // swiftlint:disable function_parameter_count private static func resolveBinary( name: String, overrideKey: String, env: [String: String], loginPATH: [String]?, commandV: (String, String?, TimeInterval, FileManager) -> String?, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String?, wellKnownPaths: [String] = [], launchCandidateFilter: (String, FileManager) -> Bool = { _, _ in true }, fileManager: FileManager, home: String) -> String? { // swiftlint:enable function_parameter_count // 1) Explicit override if let override = env[overrideKey], fileManager.isExecutableFile(atPath: override) { return override } // 2) Login-shell PATH (captured once per launch) if let loginPATH, let pathHit = self.find( name, in: loginPATH, fileManager: fileManager, launchCandidateFilter: launchCandidateFilter) { return pathHit } // 3) Existing PATH if let existingPATH = env["PATH"], let pathHit = self.find( name, in: existingPATH.split(separator: ":").map(String.init), fileManager: fileManager, launchCandidateFilter: launchCandidateFilter) { return pathHit } // 4) Well-known installation paths (e.g. Homebrew, cmux.app bundle, ~/.claude/bin). // Prefer these before shell probing to avoid running interactive shell init for common installs. for candidate in wellKnownPaths where fileManager.isExecutableFile(atPath: candidate) && launchCandidateFilter(candidate, fileManager) { return candidate } // 5) Interactive login shell lookup (captures nvm/fnm/mise paths from .zshrc/.bashrc) if let shellHit = commandV(name, env["SHELL"], 2.0, fileManager), fileManager.isExecutableFile(atPath: shellHit), launchCandidateFilter(shellHit, fileManager) { return shellHit } // 5b) Alias fallback (login shell); only attempt after all standard lookups fail. if let aliasHit = aliasResolver(name, env["SHELL"], 2.0, fileManager, home), fileManager.isExecutableFile(atPath: aliasHit), launchCandidateFilter(aliasHit, fileManager) { return aliasHit } // 6) Minimal fallback let fallback = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"] if let pathHit = self.find( name, in: fallback, fileManager: fileManager, launchCandidateFilter: launchCandidateFilter) { return pathHit } return nil } private static func find( _ binary: String, in paths: [String], fileManager: FileManager, launchCandidateFilter: (String, FileManager) -> Bool = { _, _ in true }) -> String? { for path in paths where !path.isEmpty { let candidate = "\(path.hasSuffix("/") ? String(path.dropLast()) : path)/\(binary)" if fileManager.isExecutableFile(atPath: candidate), launchCandidateFilter(candidate, fileManager) { return candidate } } return nil }} public enum CodexLaunchPreflight { struct GatekeeperAssessment { let output: String let exitStatus: Int32 } public static func isLaunchCandidateAllowed(path: String, fileManager: FileManager = .default) -> Bool { #if os(macOS) self.isLaunchCandidateAllowed( path: path, fileManager: fileManager, hasExtendedAttribute: self.hasExtendedAttribute, spctlAssessment: { self.spctlAssessment(path: $0) }, appSignatureIsTrusted: self.isExpectedOpenAIAppSignature, isMachOExecutable: self.isMachOExecutable) #else _ = path _ = fileManager return true #endif } #if os(macOS) // Keep each security boundary injectable so preflight tests never inspect or launch host binaries. // swiftlint:disable:next function_parameter_count static func isLaunchCandidateAllowed( path: String, fileManager: FileManager, hasExtendedAttribute: (String, String) -> Bool, spctlAssessment: (String) -> GatekeeperAssessment?, appSignatureIsTrusted: (String) -> Bool, isMachOExecutable: (String) -> Bool) -> Bool { let realPath = URL(fileURLWithPath: path).resolvingSymlinksInPath().path let sourceAppBundlePath = self.containingAppBundlePath(for: path) let resolvedAppBundlePath = self.containingAppBundlePath(for: realPath) let appBundlePath: String? if let sourceAppBundlePath { let resolvedSourceBundle = URL(fileURLWithPath: sourceAppBundlePath).resolvingSymlinksInPath().path guard resolvedAppBundlePath == resolvedSourceBundle else { return false } appBundlePath = resolvedSourceBundle } else { appBundlePath = resolvedAppBundlePath } let appBundlePaths = [sourceAppBundlePath, appBundlePath].compactMap(\.self) let pathsToCheck = [path, realPath] + appBundlePaths + self .nativeCodexExecutableCandidates( for: realPath, fileManager: fileManager) for candidate in Set(pathsToCheck) where hasExtendedAttribute(candidate, "com.apple.malware") { return false } let hasQuarantine = Set(pathsToCheck).contains { hasExtendedAttribute($0, "com.apple.quarantine") } if let appBundlePath { guard appSignatureIsTrusted(appBundlePath), let assessment = spctlAssessment(appBundlePath), assessment.exitStatus == 0, self.isAcceptedAssessment(assessment.output, path: appBundlePath), !self.isExplicitlyBlockedAssessment(assessment.output, path: appBundlePath) else { return false } return true } guard let native = pathsToCheck.first(where: isMachOExecutable) else { return !hasQuarantine } guard let assessment = spctlAssessment(native) else { return !hasQuarantine } return !self.isExplicitlyBlockedAssessment(assessment.output, path: native) } private static func containingAppBundlePath(for path: String) -> String? { var candidate = URL(fileURLWithPath: path).standardizedFileURL while candidate.path != "/" { if candidate.pathExtension.caseInsensitiveCompare("app") == .orderedSame { return candidate.path } let parent = candidate.deletingLastPathComponent() guard parent.path != candidate.path else { return nil } candidate = parent } return nil } private static func nativeCodexExecutableCandidates(for path: String, fileManager: FileManager) -> [String] { let url = URL(fileURLWithPath: path) guard url.lastPathComponent == "codex.js" else { return [] } let packageRoot = url.deletingLastPathComponent().deletingLastPathComponent() return self.npmNativeCodexCandidates(packageRoot: packageRoot) .map(\.path) .filter { fileManager.isExecutableFile(atPath: $0) } } private static func npmNativeCodexCandidates(packageRoot: URL) -> [URL] { guard let target = self.darwinCodexTarget else { return [] } let optionalPackage = packageRoot .appendingPathComponent("node_modules") .appendingPathComponent("@openai") .appendingPathComponent(target.packageName) return [Lines 1–500 of 1256. Load more
import Foundation #if canImport(Darwin) import Darwin #elseif canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #endif #if os(macOS) import Security #endif #if os(Linux) @_silgen_name("pipe2") private func linuxPipe2(_ pipeDescriptors: UnsafeMutablePointer<Int32>, _ flags: Int32) -> Int32 #endif public enum PathPurpose: Hashable, Sendable { case rpc case tty case nodeTooling } public struct PathDebugSnapshot: Equatable, Sendable { public let codexBinary: String? public let claudeBinary: String? public let geminiBinary: String? public let effectivePATH: String public let loginShellPATH: String? public static let empty = PathDebugSnapshot( codexBinary: nil, claudeBinary: nil, geminiBinary: nil, effectivePATH: "", loginShellPATH: nil) public init( codexBinary: String?, claudeBinary: String?, geminiBinary: String? = nil, effectivePATH: String, loginShellPATH: String?) { self.codexBinary = codexBinary self.claudeBinary = claudeBinary self.geminiBinary = geminiBinary self.effectivePATH = effectivePATH self.loginShellPATH = loginShellPATH } } public enum BinaryLocator { /// Test-only override so parallel Gemini suites can point at fake binaries /// without mutating process-wide `GEMINI_CLI_PATH`. @TaskLocal public static var geminiBinaryPathOverrideForTesting: String? public static func resolveClaudeBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "claude", overrideKey: "CLAUDE_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: self.claudeWellKnownPaths(home: home), fileManager: fileManager, home: home) } /// Well-known installation paths for the Claude CLI binary. /// Covers Anthropic's native installer (`~/.local/bin`), the `claude migrate-installer` /// self-updating location (`~/.claude/local`), the legacy per-user installer /// (`~/.claude/bin`), Homebrew, and the macOS Terminal installer (cmux.app). static func claudeWellKnownPaths(home: String) -> [String] { [ "\(home)/.local/bin/claude", "\(home)/.claude/local/claude", "\(home)/.claude/bin/claude", "/opt/homebrew/bin/claude", "/usr/local/bin/claude", "/Applications/cmux.app/Contents/Resources/bin/claude", ] } public static func resolveAntigravityBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "agy", overrideKey: "ANTIGRAVITY_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: [ "\(home)/.local/bin/agy", "/opt/homebrew/bin/agy", "/usr/local/bin/agy", ], fileManager: fileManager, home: home) } public static func resolveCodexBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, launchCandidateFilter: (String, FileManager) -> Bool = CodexLaunchPreflight.isLaunchCandidateAllowed, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "codex", overrideKey: "CODEX_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: self.codexWellKnownPaths(home: home), launchCandidateFilter: launchCandidateFilter, fileManager: fileManager, home: home) } /// Well-known installation paths for the signed Codex CLI bundled with current and legacy desktop apps. /// Keep these after PATH lookups, but use them as a safe fallback when a PATH shim is blocked. static func codexWellKnownPaths(home: String) -> [String] { #if os(macOS) [ "\(home)/Applications/ChatGPT.app/Contents/Resources/codex", "\(home)/Applications/Codex.app/Contents/Resources/codex", "/Applications/ChatGPT.app/Contents/Resources/codex", "/Applications/Codex.app/Contents/Resources/codex", ] #else [] #endif } public static func resolveGeminiBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { if let override = self.geminiBinaryPathOverrideForTesting, fileManager.isExecutableFile(atPath: override) { return override } return self.resolveBinary( name: "gemini", overrideKey: "GEMINI_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, fileManager: fileManager, home: home) } public static func resolveGrokBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "grok", overrideKey: "GROK_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: self.grokWellKnownPaths(home: home), fileManager: fileManager, home: home) } public static func resolveAmpBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "amp", overrideKey: "AMP_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: self.ampWellKnownPaths(home: home), fileManager: fileManager, home: home) } static func ampWellKnownPaths(home: String) -> [String] { [ "\(home)/.local/bin/amp", "\(home)/.amp/bin/amp", "/opt/homebrew/bin/amp", "/usr/local/bin/amp", ] } /// Well-known install locations for the Grok Build CLI binary. /// Covers the installer's default (`~/.grok/bin/grok`) and the symlinks it sometimes /// creates into `~/.local/bin` and `/usr/local/bin`. static func grokWellKnownPaths(home: String) -> [String] { [ "\(home)/.grok/bin/grok", "\(home)/.local/bin/grok", "/usr/local/bin/grok", "/opt/homebrew/bin/grok", ] } public static func resolveAWSBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "aws", overrideKey: "AWS_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, wellKnownPaths: self.awsWellKnownPaths(home: home), fileManager: fileManager, home: home) } /// Well-known install locations for the AWS CLI v2 (`aws`). /// Covers Homebrew (Apple Silicon + Intel) and the per-user pip/uv install path. static func awsWellKnownPaths(home: String) -> [String] { [ "/opt/homebrew/bin/aws", "/usr/local/bin/aws", "\(home)/.local/bin/aws", ] } public static func resolveAuggieBinary( env: [String: String] = ProcessInfo.processInfo.environment, loginPATH: [String]? = LoginShellPathCache.shared.current, commandV: (String, String?, TimeInterval, FileManager) -> String? = ShellCommandLocator.commandV, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String? = ShellCommandLocator .resolveAlias, fileManager: FileManager = .default, home: String = NSHomeDirectory()) -> String? { self.resolveBinary( name: "auggie", overrideKey: "AUGGIE_CLI_PATH", env: env, loginPATH: loginPATH, commandV: commandV, aliasResolver: aliasResolver, fileManager: fileManager, home: home) } // swiftlint:disable function_parameter_count private static func resolveBinary( name: String, overrideKey: String, env: [String: String], loginPATH: [String]?, commandV: (String, String?, TimeInterval, FileManager) -> String?, aliasResolver: (String, String?, TimeInterval, FileManager, String) -> String?, wellKnownPaths: [String] = [], launchCandidateFilter: (String, FileManager) -> Bool = { _, _ in true }, fileManager: FileManager, home: String) -> String? { // swiftlint:enable function_parameter_count // 1) Explicit override if let override = env[overrideKey], fileManager.isExecutableFile(atPath: override) { return override } // 2) Login-shell PATH (captured once per launch) if let loginPATH, let pathHit = self.find( name, in: loginPATH, fileManager: fileManager, launchCandidateFilter: launchCandidateFilter) { return pathHit } // 3) Existing PATH if let existingPATH = env["PATH"], let pathHit = self.find( name, in: existingPATH.split(separator: ":").map(String.init), fileManager: fileManager, launchCandidateFilter: launchCandidateFilter) { return pathHit } // 4) Well-known installation paths (e.g. Homebrew, cmux.app bundle, ~/.claude/bin). // Prefer these before shell probing to avoid running interactive shell init for common installs. for candidate in wellKnownPaths where fileManager.isExecutableFile(atPath: candidate) && launchCandidateFilter(candidate, fileManager) { return candidate } // 5) Interactive login shell lookup (captures nvm/fnm/mise paths from .zshrc/.bashrc) if let shellHit = commandV(name, env["SHELL"], 2.0, fileManager), fileManager.isExecutableFile(atPath: shellHit), launchCandidateFilter(shellHit, fileManager) { return shellHit } // 5b) Alias fallback (login shell); only attempt after all standard lookups fail. if let aliasHit = aliasResolver(name, env["SHELL"], 2.0, fileManager, home), fileManager.isExecutableFile(atPath: aliasHit), launchCandidateFilter(aliasHit, fileManager) { return aliasHit } // 6) Minimal fallback let fallback = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"] if let pathHit = self.find( name, in: fallback, fileManager: fileManager, launchCandidateFilter: launchCandidateFilter) { return pathHit } return nil } private static func find( _ binary: String, in paths: [String], fileManager: FileManager, launchCandidateFilter: (String, FileManager) -> Bool = { _, _ in true }) -> String? { for path in paths where !path.isEmpty { let candidate = "\(path.hasSuffix("/") ? String(path.dropLast()) : path)/\(binary)" if fileManager.isExecutableFile(atPath: candidate), launchCandidateFilter(candidate, fileManager) { return candidate } } return nil } } public enum CodexLaunchPreflight { struct GatekeeperAssessment { let output: String let exitStatus: Int32 } public static func isLaunchCandidateAllowed(path: String, fileManager: FileManager = .default) -> Bool { #if os(macOS) self.isLaunchCandidateAllowed( path: path, fileManager: fileManager, hasExtendedAttribute: self.hasExtendedAttribute, spctlAssessment: { self.spctlAssessment(path: $0) }, appSignatureIsTrusted: self.isExpectedOpenAIAppSignature, isMachOExecutable: self.isMachOExecutable) #else _ = path _ = fileManager return true #endif } #if os(macOS) // Keep each security boundary injectable so preflight tests never inspect or launch host binaries. // swiftlint:disable:next function_parameter_count static func isLaunchCandidateAllowed( path: String, fileManager: FileManager, hasExtendedAttribute: (String, String) -> Bool, spctlAssessment: (String) -> GatekeeperAssessment?, appSignatureIsTrusted: (String) -> Bool, isMachOExecutable: (String) -> Bool) -> Bool { let realPath = URL(fileURLWithPath: path).resolvingSymlinksInPath().path let sourceAppBundlePath = self.containingAppBundlePath(for: path) let resolvedAppBundlePath = self.containingAppBundlePath(for: realPath) let appBundlePath: String? if let sourceAppBundlePath { let resolvedSourceBundle = URL(fileURLWithPath: sourceAppBundlePath).resolvingSymlinksInPath().path guard resolvedAppBundlePath == resolvedSourceBundle else { return false } appBundlePath = resolvedSourceBundle } else { appBundlePath = resolvedAppBundlePath } let appBundlePaths = [sourceAppBundlePath, appBundlePath].compactMap(\.self) let pathsToCheck = [path, realPath] + appBundlePaths + self .nativeCodexExecutableCandidates( for: realPath, fileManager: fileManager) for candidate in Set(pathsToCheck) where hasExtendedAttribute(candidate, "com.apple.malware") { return false } let hasQuarantine = Set(pathsToCheck).contains { hasExtendedAttribute($0, "com.apple.quarantine") } if let appBundlePath { guard appSignatureIsTrusted(appBundlePath), let assessment = spctlAssessment(appBundlePath), assessment.exitStatus == 0, self.isAcceptedAssessment(assessment.output, path: appBundlePath), !self.isExplicitlyBlockedAssessment(assessment.output, path: appBundlePath) else { return false } return true } guard let native = pathsToCheck.first(where: isMachOExecutable) else { return !hasQuarantine } guard let assessment = spctlAssessment(native) else { return !hasQuarantine } return !self.isExplicitlyBlockedAssessment(assessment.output, path: native) } private static func containingAppBundlePath(for path: String) -> String? { var candidate = URL(fileURLWithPath: path).standardizedFileURL while candidate.path != "/" { if candidate.pathExtension.caseInsensitiveCompare("app") == .orderedSame { return candidate.path } let parent = candidate.deletingLastPathComponent() guard parent.path != candidate.path else { return nil } candidate = parent } return nil } private static func nativeCodexExecutableCandidates(for path: String, fileManager: FileManager) -> [String] { let url = URL(fileURLWithPath: path) guard url.lastPathComponent == "codex.js" else { return [] } let packageRoot = url.deletingLastPathComponent().deletingLastPathComponent() return self.npmNativeCodexCandidates(packageRoot: packageRoot) .map(\.path) .filter { fileManager.isExecutableFile(atPath: $0) } } private static func npmNativeCodexCandidates(packageRoot: URL) -> [URL] { guard let target = self.darwinCodexTarget else { return [] } let optionalPackage = packageRoot .appendingPathComponent("node_modules") .appendingPathComponent("@openai") .appendingPathComponent(target.packageName) return [