nvrsion: Add: Advanced Setting VM to Virtual Machines settings, including “Always open VM guest display” option, in Panels, Settings, and Project.
Nucleic-Promote: 1 Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
@@ -68,6 +68,9 @@ struct PaneledChatView: View {
|
||||
// selection when the chat changes so the Editor never shows another
|
||||
// worktree's file.
|
||||
.onChange(of: session?.id) { _, _ in fileSelection.clear() }
|
||||
// With "Always open VM guest display" on, surface the guest-screen monitor as soon as the
|
||||
// open chat has a booted macOS VM — regardless of how the VM was launched.
|
||||
.task(id: session?.id) { await watchGuestDisplay() }
|
||||
.alert("Save Layout", isPresented: $savingLayout) {
|
||||
TextField("Layout name", text: $layoutNameDraft)
|
||||
Button("Cancel", role: .cancel) {}
|
||||
@@ -176,6 +179,25 @@ struct PaneledChatView: View {
|
||||
onDrop: { panels.drop($0, into: slot) })
|
||||
}
|
||||
|
||||
// MARK: - Guest display
|
||||
|
||||
/// While a chat is open, watch its macOS VM and — when the user has enabled "Always open VM guest
|
||||
/// display" — reveal the VM monitor as soon as the guest boots, whatever launched it (`mac_vm_exec`,
|
||||
/// `mac_vm_computer`, or provisioning). `revealVMMonitor()` is idempotent (a no-op once a monitor is
|
||||
/// placed, and the panel re-roots onto the open chat), so polling and re-revealing is safe; the loop
|
||||
/// re-reads the setting each tick so flipping it on takes effect without reopening the chat.
|
||||
private func watchGuestDisplay() async {
|
||||
guard store.macVMSupported, let session else { return }
|
||||
let vmName = MacVMManager.vmName(for: session.id)
|
||||
while !Task.isCancelled {
|
||||
if MacVMSettings.alwaysOpenGuestDisplay,
|
||||
await store.runningMacVMs().contains(where: { $0.name == vmName }) {
|
||||
panels.revealVMMonitor()
|
||||
}
|
||||
try? await Task.sleep(for: .seconds(2))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Sizing
|
||||
|
||||
private func widthRange(_ container: CGSize) -> ClosedRange<CGFloat> {
|
||||
|
||||
@@ -460,6 +460,7 @@ private struct MacVMSettingsTab: View {
|
||||
@AppStorage(MacVMSettings.exposeByDefaultKey) private var exposeByDefault = true
|
||||
@AppStorage(MacVMSettings.computerUseByDefaultKey) private var computerUseByDefault = true
|
||||
@AppStorage(MacVMSettings.axAgentEnabledKey) private var axAgentEnabled = false
|
||||
@AppStorage(MacVMSettings.alwaysOpenGuestDisplayKey) private var alwaysOpenGuestDisplay = false
|
||||
@AppStorage(MacVMSettings.basePrebuiltPathKey) private var basePrebuiltPath = ""
|
||||
@AppStorage(MacVMSettings.restoreImagePathKey) private var restoreImagePath = ""
|
||||
@AppStorage(MacVMSettings.restoreImageURLKey) private var restoreImageURL = ""
|
||||
@@ -483,6 +484,8 @@ private struct MacVMSettingsTab: View {
|
||||
/// Whether the "Advanced" restore-source overrides are expanded. Driven open by picking the
|
||||
/// "Custom" base-version option (or by finding a manual override already stored on appearance).
|
||||
@State private var advancedExpanded = false
|
||||
/// Whether the "Advanced" power-user toggles under the service section are expanded.
|
||||
@State private var serviceAdvancedExpanded = false
|
||||
|
||||
private var supported: Bool { store.macVMSupported }
|
||||
|
||||
@@ -524,6 +527,16 @@ private struct MacVMSettingsTab: View {
|
||||
LearnMoreLink("Set up AX-based computer use", url: SupportURL.macVMAXAgent)
|
||||
}
|
||||
}
|
||||
|
||||
DisclosureGroup("Advanced", isExpanded: $serviceAdvancedExpanded) {
|
||||
Toggle("Always open VM guest display", isOn: $alwaysOpenGuestDisplay)
|
||||
.disabled(!serviceEnabled || !supported)
|
||||
Text("Automatically opens the live guest-screen monitor for every macOS VM the "
|
||||
+ "instant it boots — whatever launched it. Normally the monitor is opened on "
|
||||
+ "demand (the Control panel's \"Observe\"); this forces it always-on. Useful "
|
||||
+ "for Nucleic developers, or anyone diagnosing a VM that won't behave.")
|
||||
.settingsCaption()
|
||||
}
|
||||
}
|
||||
|
||||
Section("Base image") {
|
||||
|
||||
@@ -546,6 +546,13 @@ public enum MacVMSettings {
|
||||
/// virtual IO, which needs neither the agent nor those grants. Only meaningful while the service is on.
|
||||
public static let axAgentEnabledKey = "nucleic.macvm.axAgentEnabled"
|
||||
|
||||
/// Advanced/diagnostic: when on, the guest-screen **monitor** is opened automatically for every
|
||||
/// per-session macOS VM the instant it boots — no matter what launched it (`mac_vm_exec`,
|
||||
/// `mac_vm_computer`, or provisioning). Normally the monitor is opened on demand (the Control
|
||||
/// panel's "Observe"); this forces it always-on, which is handy for Nucleic developers or anyone
|
||||
/// diagnosing a VM that won't behave. OFF by default. Only meaningful while the service is on.
|
||||
public static let alwaysOpenGuestDisplayKey = "nucleic.macvm.alwaysOpenGuestDisplay"
|
||||
|
||||
/// Optional path to a **prebuilt** golden base VM bundle the user produced out-of-band. When set
|
||||
/// and present, the engine clones it directly and skips the install+provision path entirely. Empty
|
||||
/// → the engine builds its own golden base under the storage root (install from the restore image,
|
||||
@@ -613,6 +620,12 @@ public enum MacVMSettings {
|
||||
serviceEnabled && defaults.bool(forKey: axAgentEnabledKey)
|
||||
}
|
||||
|
||||
/// Whether the guest-screen monitor should auto-open for every session VM as it boots (see
|
||||
/// ``alwaysOpenGuestDisplayKey``). Only meaningful while the service is on.
|
||||
public static var alwaysOpenGuestDisplay: Bool {
|
||||
serviceEnabled && defaults.bool(forKey: alwaysOpenGuestDisplayKey)
|
||||
}
|
||||
|
||||
/// Configured prebuilt-base path, or `nil`/empty when unset.
|
||||
public static var basePrebuiltPath: String? {
|
||||
let v = (defaults.string(forKey: basePrebuiltPathKey) ?? "")
|
||||
|
||||
Reference in New Issue
Block a user