#!/usr/bin/env ruby require 'xcodeproj' # Create project project_path = 'MarkBaseInstaller.xcodeproj' project = Xcodeproj::Project.new(project_path) # Create target (use macOS 14.0 as base platform, will update deployment target later) target = project.new_target(:application, 'MarkBaseInstaller', :macos, '14.0') # Create group for source files main_group = project.main_group sources_group = main_group.new_group('Sources') # Create AppDelegate.swift file reference app_delegate_file = sources_group.new_file('AppDelegate.swift') # Add file to target target.source_build_phase.add_file_reference(app_delegate_file) # Configure build settings target.build_configurations.each do |config| config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'com.momentry.markbase.installer' config.build_settings['DEVELOPMENT_TEAM'] = 'K3TDMD9Y6B' config.build_settings['CODE_SIGN_IDENTITY'] = 'Developer ID Application' config.build_settings['SWIFT_VERSION'] = '6.0' config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '26.0' config.build_settings['PRODUCT_NAME'] = 'MarkBaseInstaller' config.build_settings['INFOPLIST_FILE'] = 'Info.plist' config.build_settings['CODE_SIGN_ENTITLEMENTS'] = 'MarkBaseInstaller.entitlements' # Disable automatic signing (use manual Developer ID) config.build_settings['CODE_SIGN_STYLE'] = 'Manual' end # Create Info.plist info_plist_path = 'Info.plist' File.write(info_plist_path, <<-PLIST) CFBundleIdentifier com.momentry.markbase.installer CFBundleName MarkBase Installer CFBundleVersion 1.0.0 CFBundleShortVersionString 1.0.0 CFBundleExecutable MarkBaseInstaller CFBundlePackageType APPL LSMinimumSystemVersion 26.0 NSHighResolutionCapable NSPrincipalClass NSApplication PLIST # Create entitlements entitlements_path = 'MarkBaseInstaller.entitlements' File.write(entitlements_path, <<-ENTITLEMENTS) com.apple.developer.system-extension.install ENTITLEMENTS # Create AppDelegate.swift app_delegate_path = 'Sources/AppDelegate.swift' File.write(app_delegate_path, <<-SWIFT) import Cocoa import SystemExtensions import OSLog class AppDelegate: NSObject, NSApplicationDelegate { let logger = Logger(subsystem: "com.momentry.markbase.installer", category: "AppDelegate") var window: NSWindow! var statusLabel: NSTextField! var installButton: NSButton! var extensionDelegate: ExtensionDelegate? func applicationDidFinishLaunching(_ aNotification: Notification) { logger.info("MarkBase Installer started") createWindow() setupUI() window.makeKeyAndOrderFront(nil) } func createWindow() { window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 500, height: 400), styleMask: [.titled, .closable, .miniaturizable], backing: .buffered, defer: false ) window.title = "MarkBase Installer" window.center() window.isReleasedWhenClosed = false } func setupUI() { let contentView = window.contentView! // Title let titleLabel = NSTextField(labelWithString: "MarkBase System Extension Installer") titleLabel.font = NSFont.systemFont(ofSize: 18, weight: .bold) titleLabel.alignment = .center contentView.addSubview(titleLabel) // Status Label statusLabel = NSTextField(wrappingLabelWithString: "Ready to install MarkBaseFS System Extension") statusLabel.font = NSFont.systemFont(ofSize: 14) statusLabel.alignment = .center contentView.addSubview(statusLabel) // Install Button installButton = NSButton(title: "Install System Extension", target: self, action: #selector(installExtension)) installButton.bezelStyle = .rounded installButton.font = NSFont.systemFont(ofSize: 13, weight: .medium) contentView.addSubview(installButton) // Layout titleLabel.translatesAutoresizingMaskIntoConstraints = false statusLabel.translatesAutoresizingMaskIntoConstraints = false installButton.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ titleLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 50), statusLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), statusLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 40), statusLabel.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.8), installButton.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), installButton.topAnchor.constraint(equalTo: statusLabel.bottomAnchor, constant: 40), installButton.widthAnchor.constraint(equalToConstant: 200), installButton.heightAnchor.constraint(equalToConstant: 30), ]) } @objc func installExtension() { logger.info("Install button clicked") let extensionID = "com.momentry.markbase.fskit" logger.info("Requesting activation for extension: \(extensionID)") updateStatus("Requesting installation...") installButton.isEnabled = false let request = OSSystemExtensionRequest.activationRequest( forExtensionWithIdentifier: extensionID, queue: .main ) // Create delegate and store as strong reference extensionDelegate = ExtensionDelegate( onSuccess: { self.logger.info("Extension activated successfully") self.updateStatus("✅ Installation successful!") self.installButton.isEnabled = true self.extensionDelegate = nil }, onError: { error in self.logger.error("Extension activation failed: \(error.localizedDescription)") self.updateStatus("❌ Installation failed: \(error.localizedDescription)") self.installButton.isEnabled = true self.extensionDelegate = nil }, onNeedsApproval: { self.logger.info("Extension needs user approval") self.updateStatus("⏳ Waiting for approval in System Settings") } ) request.delegate = extensionDelegate OSSystemExtensionManager.shared.submitRequest(request) } func updateStatus(_ message: String) { DispatchQueue.main.async { self.statusLabel.stringValue = message } } } class ExtensionDelegate: NSObject, OSSystemExtensionRequestDelegate { let onSuccess: () -> Void let onError: (Error) -> Void let onNeedsApproval: () -> Void init(onSuccess: @escaping () -> Void, onError: @escaping (Error) -> Void, onNeedsApproval: @escaping () -> Void) { self.onSuccess = onSuccess self.onError = onError self.onNeedsApproval = onNeedsApproval super.init() } func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) { Logger(subsystem: "com.momentry.markbase.installer", category: "ExtensionDelegate") .info("Request finished with result") onSuccess() } func request(_ request: OSSystemExtensionRequest, didFailWithError error: Error) { Logger(subsystem: "com.momentry.markbase.installer", category: "ExtensionDelegate") .error("Request failed with error: \(error.localizedDescription)") onError(error) } func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) { Logger(subsystem: "com.momentry.markbase.installer", category: "ExtensionDelegate") .info("Request needs user approval") onNeedsApproval() } func request(_ request: OSSystemExtensionRequest, actionForReplacingExtension existing: OSSystemExtensionProperties, withExtension ext: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction { Logger(subsystem: "com.momentry.markbase.installer", category: "ExtensionDelegate") .info("Replacing extension") return .replace } } SWIFT # Save project project.save puts "Project created successfully at #{project_path}" puts "Files created:" puts " - Info.plist" puts " - MarkBaseInstaller.entitlements" puts " - Sources/AppDelegate.swift" puts "" puts "Next step: Build the project with:" puts " xcodebuild -project #{project_path} -scheme MarkBaseInstaller -configuration Release build"