135 lines
4.6 KiB
Swift
135 lines
4.6 KiB
Swift
import Foundation
|
|
|
|
// MARK: - Result type (Codable so /system/validate can return JSON)
|
|
|
|
struct StartupCheckResult: Codable {
|
|
let name: String
|
|
let passed: Bool
|
|
let message: String
|
|
}
|
|
|
|
// MARK: - Validator
|
|
|
|
enum DaemonStartupValidator {
|
|
|
|
static func run() -> [StartupCheckResult] {
|
|
[
|
|
checkXcode(),
|
|
checkXcodebuild(),
|
|
checkDevicectl(),
|
|
checkSourcekitLSP(),
|
|
checkTeamID(),
|
|
checkSigningIdentity(),
|
|
checkXcodeGen(),
|
|
]
|
|
}
|
|
|
|
// MARK: - Checks
|
|
|
|
private static func checkXcode() -> StartupCheckResult {
|
|
let exists = FileManager.default.fileExists(atPath: "/Applications/Xcode.app")
|
|
return StartupCheckResult(
|
|
name: "Xcode Installation",
|
|
passed: exists,
|
|
message: exists
|
|
? "Xcode found at /Applications/Xcode.app"
|
|
: "Xcode not found — install from developer.apple.com or the App Store"
|
|
)
|
|
}
|
|
|
|
private static func checkXcodebuild() -> StartupCheckResult {
|
|
let result = shell("xcodebuild -version 2>/dev/null | head -1")
|
|
let passed = result.contains("Xcode")
|
|
return StartupCheckResult(
|
|
name: "xcodebuild",
|
|
passed: passed,
|
|
message: passed
|
|
? result.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
: "xcodebuild not functional — run: xcode-select --install"
|
|
)
|
|
}
|
|
|
|
private static func checkDevicectl() -> StartupCheckResult {
|
|
let result = shell("xcrun devicectl --version 2>/dev/null")
|
|
let passed = !result.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
|
return StartupCheckResult(
|
|
name: "devicectl",
|
|
passed: passed,
|
|
message: passed ? "devicectl available" : "devicectl not found — requires Xcode 15+"
|
|
)
|
|
}
|
|
|
|
private static func checkSourcekitLSP() -> StartupCheckResult {
|
|
let path = "/Applications/Xcode.app/Contents/Developer/Toolchains/" +
|
|
"XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp"
|
|
let exists = FileManager.default.fileExists(atPath: path)
|
|
return StartupCheckResult(
|
|
name: "sourcekit-lsp",
|
|
passed: exists,
|
|
message: exists ? "sourcekit-lsp found" : "sourcekit-lsp not found — completions unavailable"
|
|
)
|
|
}
|
|
|
|
private static func checkTeamID() -> StartupCheckResult {
|
|
let teamID = loadTeamID()
|
|
let valid = teamID.count == 10
|
|
&& teamID != "YOUR_10_CHAR_TEAM_ID"
|
|
&& teamID.allSatisfy({ $0.isLetter || $0.isNumber })
|
|
return StartupCheckResult(
|
|
name: "Team ID",
|
|
passed: valid,
|
|
message: valid
|
|
? "Team ID configured: \(teamID)"
|
|
: "Team ID not set — edit ~/.padxcode/config.json"
|
|
)
|
|
}
|
|
|
|
private static func checkSigningIdentity() -> StartupCheckResult {
|
|
let result = shell(
|
|
"security find-identity -v -p codesigning 2>/dev/null | grep 'Apple Development'"
|
|
)
|
|
let passed = !result.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
|
let certName = result
|
|
.components(separatedBy: "\"")
|
|
.dropFirst()
|
|
.first ?? "certificate present"
|
|
return StartupCheckResult(
|
|
name: "Apple Development Certificate",
|
|
passed: passed,
|
|
message: passed
|
|
? "Found: \(certName)"
|
|
: "No Apple Development certificate — Xcode → Settings → Accounts → Manage Certificates"
|
|
)
|
|
}
|
|
|
|
private static func checkXcodeGen() -> StartupCheckResult {
|
|
let result = shell("which xcodegen 2>/dev/null")
|
|
.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
let passed = !result.isEmpty
|
|
return StartupCheckResult(
|
|
name: "XcodeGen",
|
|
passed: passed,
|
|
message: passed
|
|
? "XcodeGen at \(result)"
|
|
: "XcodeGen not found — brew install xcodegen"
|
|
)
|
|
}
|
|
|
|
// MARK: - Shell helper
|
|
|
|
@discardableResult
|
|
private static func shell(_ command: String) -> String {
|
|
let p = Process()
|
|
p.executableURL = URL(fileURLWithPath: "/bin/zsh")
|
|
p.arguments = ["-lc", command]
|
|
let pipe = Pipe()
|
|
p.standardOutput = pipe
|
|
p.standardError = Pipe()
|
|
try? p.run()
|
|
p.waitUntilExit()
|
|
return String(
|
|
data: pipe.fileHandleForReading.readDataToEndOfFile(),
|
|
encoding: .utf8
|
|
) ?? ""
|
|
}
|
|
}
|