Add App Bundle Integration

Nucleic-Session: 307EEE49-F1A9-4AF7-B2C1-72C8473CD6B4
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-08 05:03:13 -07:00
co-authored by nucleic
parent fb7d3f4b30
commit 8ea943a462
+34
View File
@@ -1720,6 +1720,40 @@ public final class AppStore: ConflictArbiter {
return await macVMManager.runningVMs()
}
/// Copy the currently-configured "Included apps" (``MacVMSettings/bundledAppPaths``) into every
/// running per-session macOS VM over vsock, so live clones get them without a base rebuild. Returns
/// a short, human-readable summary for the settings panel (how many VMs got the apps, and any
/// per-VM failures). Never throws a VM that fails is folded into the summary.
public func pushIncludedAppsToRunningMacVMs() async -> String {
guard let macVMManager else { return "The macOS VM service isn't available in this build." }
let apps = MacVMSettings.bundledAppPaths
guard !apps.isEmpty else { return "No included apps are configured to copy." }
let running = await macVMManager.runningVMs()
guard !running.isEmpty else { return "No macOS VMs are running to copy into." }
var succeeded = 0
var failures: [String] = []
for vm in running {
do {
let installed = try await macVMManager.installApps(name: vm.name, appPaths: apps)
if !installed.isEmpty { succeeded += 1 }
} catch {
failures.append("\(vm.name): \(error)")
}
}
let appWord = apps.count == 1 ? "app" : "apps"
let vmWord = running.count == 1 ? "VM" : "VMs"
if failures.isEmpty {
return "Copied \(apps.count) \(appWord) into \(succeeded) running \(vmWord)."
}
let failLine = failures.joined(separator: "; ")
if succeeded == 0 {
return "Couldn't copy into any running \(vmWord): \(failLine)"
}
return "Copied into \(succeeded) of \(running.count) \(vmWord); \(failures.count) failed: \(failLine)"
}
/// The current GUI screenshot (base64 JPEG) of a running per-session macOS VM, for the live monitor
/// panel. `nil` when the service isn't wired, the VM isn't running, or capture is unavailable.
public func captureMacVMScreen(name: String) async -> String? {