Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -263,16 +263,6 @@ public final class GhosttyRuntime {
return true
}

if action.tag == GHOSTTY_ACTION_RENDER {
guard target.tag == GHOSTTY_TARGET_SURFACE,
let surface = target.target.surface,
let bridge = GhosttySurfaceBridge.fromOpaque(ghostty_surface_userdata(surface)) else { return false }
Task { @MainActor [bridge] in
bridge.surfaceView?.drawForWakeup()
}
return true
}

if action.tag == GHOSTTY_ACTION_SET_TITLE {
guard target.tag == GHOSTTY_TARGET_SURFACE,
let surface = target.target.surface,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ import UIKit
final class GhosttySurfaceBridge: @unchecked Sendable {
// lint:allow lock — sanctioned carve-out: serial low-level primitive hidden behind the type, guarding a single weak ref on the libghostty-callback / typing-latency path; actor rewrite tracked as the GhosttySurfaceView split follow-up.
private let lock = NSLock()
// Deliberately STRONG: libghostty holds the raw view pointer
// (`ghostty_platform_ios_s.uiview`, passUnretained in `makeSurface`), so
// the view must outlive queued surface operations. Surface creation gives
// libghostty an owned bridge retain; dismantle detaches this reference to
// break the view<->bridge cycle, and final C-surface destruction releases
// the bridge only after internal callbacks and app-action leases stop.
// Deliberately STRONG despite forming a view<->bridge cycle: libghostty
// holds the raw view pointer (`ghostty_platform_ios_s.uiview`,
// passUnretained in `makeSurface`), so the view must outlive every queued
// surface operation. A weak back-reference would let the view deallocate
// while queued renderer work still dereferences that pointer
// (use-after-free). The cycle means a closed terminal's view/bridge/
// surface are reclaimed only by the render-pipeline recovery rebuild, not
// by dismantle; fixing the leak needs retained-uiview / free-on-dismantle
// choreography, tracked in
// https://github.com/manaflow-ai/cmux/issues/7199.
private var _surfaceView: GhosttySurfaceView?

var surfaceView: GhosttySurfaceView? {
Expand Down Expand Up @@ -68,11 +72,6 @@ final class GhosttySurfaceBridge: @unchecked Sendable {
guard let userdata else { return nil }
return Unmanaged<GhosttySurfaceBridge>.fromOpaque(userdata).takeUnretainedValue()
}

static func releaseRetainedOpaque(_ userdata: UnsafeMutableRawPointer?) {
guard let userdata else { return }
Unmanaged<GhosttySurfaceBridge>.fromOpaque(userdata).release()
}
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ extension GhosttySurfaceView {
pendingSurfaceFreeCount += 1
enqueueSurfaceFree(
oldSurface,
bridge: oldBridge,
generation: surfaceGeneration,
on: oldQueue
) { [weak self] in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2495,18 +2495,22 @@ public final class GhosttySurfaceView: UIView, TerminalSurfaceHosting {
// never use-after-free against the free, and no two of them ever touch
// the surface concurrently. `processOutput`'s main-actor guard stops new
// work from being enqueued once `surface` is nil, so only the bounded
// backlog drains before the free. libghostty owns bridge userdata through final destruction and every app-action lease.
enqueueSurfaceFree(surface, generation: surfaceGeneration, on: currentQueue)
// backlog drains before the free. (Retain the bridge across the hop; it
// owns the userdata libghostty still references until the free.)
enqueueSurfaceFree(surface, bridge: currentBridge, generation: surfaceGeneration, on: currentQueue)
Comment on lines +2498 to +2500

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n 'disposeSurface|enqueueSurfaceFree|ghostty_platform_ios_s|uiview|detach\(\)' \
  Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal ghostty

Repository: manaflow-ai/cmux

Length of output: 1866


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- GhosttySurfaceBridge.swift ---\n'
cat -n Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceBridge.swift

printf '\n--- GhosttySurfaceView.swift relevant sections ---\n'
sed -n '2460,2525p' Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift | cat -n
sed -n '1850,1892p' Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift | cat -n
sed -n '3448,3482p' Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift | cat -n

printf '\n--- RenderRecovery relevant section ---\n'
sed -n '180,225p' Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView+RenderRecovery.swift | cat -n

Repository: manaflow-ai/cmux

Length of output: 245


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- GhosttySurfaceBridge.swift ---'
cat -n Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceBridge.swift

echo
echo '--- GhosttySurfaceView.swift relevant sections ---'
sed -n '2460,2525p' Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift | cat -n
sed -n '1850,1892p' Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift | cat -n
sed -n '3448,3482p' Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift | cat -n

echo
echo '--- RenderRecovery relevant section ---'
sed -n '180,225p' Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView+RenderRecovery.swift | cat -n

Repository: manaflow-ai/cmux

Length of output: 13650


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- Locate Ghostty source files ---'
git ls-files | rg '(^ghostty/|^P|\.h$|ghostty_surface\.c|ghostty\.h|ghostty_platform)' | head -200

echo
echo '--- Search IOS platform code for uiview/uiview callbacks ---'
rg -n 'uiview|ghostty_platform_ios|GHOSTTY_PLATFORM_IOS' ghostty Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal 2>/dev/null | head -300

echo
echo '--- Search surface free implementation/usages in Ghostty source ---'
rg -n 'ghostty_surface_free|surface_free|free.*surface|ghostty_surface_new|surface_new' ghostty Packages/iOS/CmuxMobileTerminal 2>/dev/null | head -400

echo
echo '--- Search userdata ownership comments in Ghostty source ---'
rg -n 'userdata|platform|iOS|UIKit|UIView|ios\\.uiview' ghostty/Packages ghostty || true

Repository: manaflow-ai/cmux

Length of output: 17635


🌐 Web query:

Ghostty ghostty_surface_free userdata iOS uiview platform ownership

💡 Result:

In the Ghostty architecture, these components relate to how the terminal emulator interfaces with the host platform's UI and memory management: ghostty_surface_free This is a C API function provided by libghostty [1][2]. It is used to deallocate a terminal surface and its associated resources, such as Metal rendering structures and terminal grid state [3][4]. When called, it initiates the teardown of the renderer and associated platform-specific layers (like IOSurface or Metal layers on Apple platforms) [5]. userdata The userdata pointer is an arbitrary void* provided in the ghostty_surface_config_s configuration struct during the initialization of a surface [1][3]. It allows the embedding application to associate its own context (e.g., a Controller, ViewModel, or View object) with the Ghostty surface [2]. This pointer can be retrieved at any time using the ghostty_surface_userdata C API function [1][2]. iOS UIView and Platform Ownership On iOS, Ghostty uses a platform-native approach where the embedding application provides a UIView into which Ghostty renders using Metal [3][4]. - Platform Data: The platform-specific configuration for iOS is defined in the ghostty_platform_ios_s struct, which contains a void* member named uiview to hold a reference to the host application's view [1][3]. - Ownership: Ghostty's core (libghostty) manages the terminal emulation, grid state, and Metal rendering pipeline [6][4]. However, the embedding application typically retains ownership of the native UI objects (like the UIView). Because Ghostty's renderer may perform asynchronous operations (e.g., presenting frames via Metal or Core Animation), issues such as use-after-free can occur if the host application frees its UI resources before Ghostty has finished its internal cleanup, necessitating careful synchronization during surface teardown [5]. The "lazy/pull" architecture often employed by Ghostty-based apps means the Zig core owns the terminal state, while the Swift/native wrapper queries it as needed [7].

Citations:


🌐 Web query:

github ghostty-src ghostty_platform_ios.c ghostty_surface_free uiview

💡 Result:

In the Ghostty terminal emulator codebase, ghostty_surface_free is a C API function used to deallocate a surface and its associated resources [1][2][3]. When operating on iOS, the surface uses platform-specific configuration defined by ghostty_platform_ios_s, which contains a void* pointer to a UIView [4][2][3]. Technical details regarding this implementation include: 1. Function Purpose: ghostty_surface_free serves as the primary cleanup mechanism for a terminal surface [1][2]. Internally, it triggers the application to close the surface, subsequently calling deinitialization routines [5][6]. 2. iOS Platform Data: The ghostty_platform_ios_s structure is defined in include/ghostty.h as a wrapper for a UIView pointer, allowing the terminal to render its output into that native iOS view, typically utilizing Metal for GPU acceleration [2][3]. 3. Implementation Context: The underlying logic is handled in Zig [5][6]. When ghostty_surface_free is called, it typically involves tearing down the renderer (such as Metal-based swap chains), stopping terminal threads, and releasing GPU-related resources like IOSurfaces and textures [7]. 4. Potential Issues: Developers should be aware of lifecycle management complexities, such as potential use-after-free scenarios if Metal completion handlers or Core Animation transactions attempt to reference resources (like an IOSurface) after they have been freed during the surface teardown process [7]. The C API and related structures are found within the include/ghostty.h header, and the platform-specific logic is managed in files such as src/apprt/embedded.zig [4][5][3].

Citations:


🌐 Web query:

ghostty src embedded.zig uiview ghostty_platform_ios_s

💡 Result:

In the Ghostty terminal emulator codebase, ghostty_platform_ios_s is a C structure used within the embedded runtime API to provide platform-specific configuration for iOS [1][2]. It is defined in the public header file include/ghostty.h as follows: typedef struct { void* uiview; } ghostty_platform_ios_s; This structure contains a single member, uiview, which is a pointer to the UIView (cast to void*) where the terminal is intended to render [3][2]. The file src/apprt/embedded.zig acts as the Zig-side implementation of this embedded runtime [4][5]. Within this file, the Platform union (and its associated C compatibility union) handles the initialization and abstraction of these platform-specific views [6][7]. The init function in embedded.zig ensures that when the library is initialized, the uiview provided via the C ABI is properly cast and stored for use by Ghostty's rendering engine, which uses Metal to render to the specified view [6][3]. In practical usage, such as in the Swift-based surface view implementation, the host application passes a reference to its UIView—via an opaque pointer—to the libghostty configuration [8]. This allows Ghostty to function as an embedded component within a larger iOS application, rather than managing the entire application lifecycle itself [4][5].

Citations:


Keep the unretained platform view alive through teardown.

disposeSurface() detaches currentBridge before this asynchronous free, so retaining the bridge no longer keeps GhosttySurfaceView alive. Since makeSurface() stores self as an unretained ghostty_platform_ios_s.uiview, the pinned Ghostty teardown/cleanup path could still reference a released view. Retain the view on teardown until free completion, or replace the unretained platform userdata with a retained/pinned ownership object.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift`
around lines 2498 - 2500, Update disposeSurface() and the enqueueSurfaceFree
teardown path so GhosttySurfaceView remains strongly retained until asynchronous
surface free and cleanup complete, rather than relying on currentBridge after it
is detached. Preserve the existing generation and queue coordination, and
release the view only from the free-completion path; alternatively, replace the
unretained uiview userdata created by makeSurface() with an ownership object
that remains pinned through teardown.

}

func enqueueSurfaceFree(
_ surface: ghostty_surface_t,
bridge: GhosttySurfaceBridge,
generation: UInt64, on queue: GhosttySurfaceWorkQueue,
completion: (@MainActor @Sendable () -> Void)? = nil
) {
let retainedBridge = Unmanaged.passRetained(bridge)
surfaceFreeDrainWatchdog.start(generation: generation) { [weak self] in self?.pendingSurfaceFreeCount ?? 0 }
queue.async { [weak self] in
ghostty_surface_free(surface)
retainedBridge.release()
Task { @MainActor in self?.surfaceFreeDrainWatchdog.cancel(generation: generation); completion?() }
}
}
Expand Down Expand Up @@ -3461,8 +3465,7 @@ public final class GhosttySurfaceView: UIView, TerminalSurfaceHosting {

private func makeSurface(app: ghostty_app_t) -> ghostty_surface_t? {
var surfaceConfig = ghostty_surface_config_new()
let retainedBridge = Unmanaged.passRetained(bridge)
let bridgePointer = retainedBridge.toOpaque()
let bridgePointer = Unmanaged.passUnretained(bridge).toOpaque()
surfaceConfig.userdata = bridgePointer
surfaceConfig.platform_tag = GHOSTTY_PLATFORM_IOS
surfaceConfig.platform = ghostty_platform_u(
Expand All @@ -3481,10 +3484,7 @@ public final class GhosttySurfaceView: UIView, TerminalSurfaceHosting {
}
}
surfaceConfig.io_write_userdata = bridgePointer
guard let createdSurface = ghostty_surface_new_with_owned_userdata(
app, &surfaceConfig, GhosttySurfaceBridge.releaseRetainedOpaque
) else {
retainedBridge.release()
guard let createdSurface = ghostty_surface_new(app, &surfaceConfig) else {
return nil
}
guard ghostty_surface_set_render_presented_callback(
Expand Down

This file was deleted.

47 changes: 0 additions & 47 deletions Sources/App/ShortcutBareStartRouting.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,43 +69,6 @@ func bareShortcutFastPathKey(for event: NSEvent) -> String? {
}

extension AppDelegate {
#if DEBUG
/// Process environment is fixed at launch; snapshot this DEBUG-only trace
/// opt-in instead of rebuilding the environment on every keystroke.
static let shortcutMonitorTraceEnvironmentEnabled =
ProcessInfo.processInfo.environment["CMUX_SHORTCUT_MONITOR_TRACE"] == "1"
#endif

/// Returns the already-resolved tab manager when plain terminal text can
/// bypass browser, palette, and workspace shortcut-context resolution.
func terminalTextShortcutBypassTabManagerBeforeContextResolution(
event: NSEvent,
normalizedFlags: NSEvent.ModifierFlags
) -> TabManager? {
guard normalizedFlags.isEmpty,
activeConfiguredShortcutChordPrefixForCurrentEvent == nil,
event.cmuxIsPrintableTextInput,
let window = event.window ?? shortcutRoutingKeyWindow,
window.firstResponder is GhosttyNSView,
NSApp.modalWindow == nil,
window.attachedSheet == nil,
let windowId = mainWindowId(from: window),
let tabManager = tabManagerFor(windowId: windowId),
!commandPaletteWindowStore.isVisible(windowId),
!commandPaletteWindowStore.isPendingOpenRaw(windowId),
!NotificationsPopoverVisibilityState.shared.isShown(in: window.windowNumber) else {
return nil
}

guard shouldBypassPlainKeyShortcutRouting(
event: event,
normalizedFlags: normalizedFlags
) else {
return nil
}
return tabManager
}

func shouldBypassPlainKeyShortcutRouting(
event: NSEvent,
normalizedFlags: NSEvent.ModifierFlags
Expand All @@ -129,13 +92,3 @@ extension AppDelegate {
}
}
}

private extension NSEvent {
var cmuxIsPrintableTextInput: Bool {
guard let characters, !characters.isEmpty else { return false }
return characters.unicodeScalars.allSatisfy { scalar in
!CharacterSet.controlCharacters.contains(scalar)
&& (scalar.value < 0xF700 || scalar.value > 0xF8FF)
}
}
}
28 changes: 10 additions & 18 deletions Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12552,7 +12552,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
var shortcutMs: Double = 0
CmuxTypingTiming.logEventDelay(path: "appMonitor", event: event)
let shortcutMonitorTraceEnabled =
Self.shortcutMonitorTraceEnvironmentEnabled
ProcessInfo.processInfo.environment["CMUX_SHORTCUT_MONITOR_TRACE"] == "1"
|| UserDefaults.standard.bool(forKey: "cmuxShortcutMonitorTrace")
if shortcutMonitorTraceEnabled {
let frType = shortcutRoutingKeyWindow?.firstResponder.map { String(describing: type(of: $0)) } ?? "nil"
Expand Down Expand Up @@ -12932,31 +12932,23 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
// charactersIgnoringModifiers returns non-ASCII characters that never match
// Latin shortcut keys. Normalize via KeyboardLayout so downstream comparisons
// (Cmd+1-9, Ctrl+1-9, omnibar N/P, command palette, etc.) work correctly.
let chars = KeyboardLayout.normalizedCharacters(for: event)
let flags = event.modifierFlags.intersection(.deviceIndependentFlagsMask)
let hasControl = flags.contains(.control)
let hasCommand = flags.contains(.command)
let hasOption = flags.contains(.option)
let isControlOnly = hasControl && !hasCommand && !hasOption
let controlDChar = chars == "d" || event.characters == "\u{04}"
let isControlD = isControlOnly && (controlDChar || event.keyCode == 2)
let configuredShortcutEventWindowNumber = configuredShortcutChordWindowNumber(for: event)
if let pendingConfiguredShortcutChord,
pendingConfiguredShortcutChord.windowNumber == configuredShortcutChordWindowNumber(for: event) {
pendingConfiguredShortcutChord.windowNumber == configuredShortcutEventWindowNumber {
activeConfiguredShortcutChordPrefixForCurrentEvent = pendingConfiguredShortcutChord.firstStroke
} else {
activeConfiguredShortcutChordPrefixForCurrentEvent = nil
}
pendingConfiguredShortcutChord = nil
defer { activeConfiguredShortcutChordPrefixForCurrentEvent = nil; clearShortcutEventFocusContextCache(for: event) }

if let textBoxShortcutTabManager = terminalTextShortcutBypassTabManagerBeforeContextResolution(
event: event,
normalizedFlags: flags.subtracting([.numericPad, .function, .capsLock])
) {
textBoxShortcutTabManager.clearFocusedTerminalTextBoxHideEscapeArm()
return false
}

let chars = KeyboardLayout.normalizedCharacters(for: event)
let hasControl = flags.contains(.control)
let hasCommand = flags.contains(.command)
let hasOption = flags.contains(.option)
let isControlOnly = hasControl && !hasCommand && !hasOption
let controlDChar = chars == "d" || event.characters == "\u{04}"
let isControlD = isControlOnly && (controlDChar || event.keyCode == 2)
#if DEBUG
if isControlD {
writeChildExitKeyboardProbe(
Expand Down
11 changes: 4 additions & 7 deletions Sources/ControlSurfaceResumeTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -278,13 +278,10 @@ extension TerminalController {
)
content.apply(to: alert, presentingWindow: nil)

switch alert.runModal() {
case .alertFirstButtonReturn:
return .auto
case .alertSecondButtonReturn:
return .prompt
default:
return .manual
return switch alert.runModal() {
case .alertFirstButtonReturn: .auto
case .alertSecondButtonReturn: .prompt
default: .manual
}
}

Expand Down
4 changes: 0 additions & 4 deletions cmux.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ C0DE71B10000000000000001 /* AppDelegate+AgentChatNotifications.swift in Sources
F6000000A1B2C3D4E5F60718 /* AppDelegateShortcutRoutingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6000001A1B2C3D4E5F60718 /* AppDelegateShortcutRoutingTests.swift */; };
C6711A030000000000000001 /* AppDelegateSurfaceResumeTerminalIdTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6711B030000000000000001 /* AppDelegateSurfaceResumeTerminalIdTests.swift */; };
4E6A6F5C1D2B4980A1234568 /* AppDelegateSurfaceShortcutRoutingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E6A6F5C1D2B4980A1234567 /* AppDelegateSurfaceShortcutRoutingTests.swift */; };
F8808A000000000000000001 /* AppDelegateTerminalTypingShortcutFastPathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8808A000000000000000002 /* AppDelegateTerminalTypingShortcutFastPathTests.swift */; };
F47126CFDAE244988A92E2D0 /* AppDelegateWindowFrameReconcileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD21AD844E5D4D50A6DFC442 /* AppDelegateWindowFrameReconcileTests.swift */; };
A11EAB000000000000000000 /* AppearanceSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11EAB000000000000000001 /* AppearanceSettings.swift */; };
A11EAA000000000000000000 /* AppearanceSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11EAA000000000000000001 /* AppearanceSettingsTests.swift */; };
Expand Down Expand Up @@ -2501,7 +2500,6 @@ C0DE71B10000000000000002 /* AppDelegate+AgentChatNotifications.swift */ = {isa =
F6000001A1B2C3D4E5F60718 /* AppDelegateShortcutRoutingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegateShortcutRoutingTests.swift; sourceTree = "<group>"; };
C6711B030000000000000001 /* AppDelegateSurfaceResumeTerminalIdTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegateSurfaceResumeTerminalIdTests.swift; sourceTree = "<group>"; };
4E6A6F5C1D2B4980A1234567 /* AppDelegateSurfaceShortcutRoutingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegateSurfaceShortcutRoutingTests.swift; sourceTree = "<group>"; };
F8808A000000000000000002 /* AppDelegateTerminalTypingShortcutFastPathTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegateTerminalTypingShortcutFastPathTests.swift; sourceTree = "<group>"; };
FD21AD844E5D4D50A6DFC442 /* AppDelegateWindowFrameReconcileTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegateWindowFrameReconcileTests.swift; sourceTree = "<group>"; };
A11EAB000000000000000001 /* AppearanceSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettings.swift; sourceTree = "<group>"; };
A11EAA000000000000000001 /* AppearanceSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6363,7 +6361,6 @@ C0DE71B10000000000000002 /* AppDelegate+AgentChatNotifications.swift */ = {isa =
FA100001A1B2C3D4E5F60718 /* BrowserImportMappingTests.swift */,
F6000001A1B2C3D4E5F60718 /* AppDelegateShortcutRoutingTests.swift */,
F5588001A1B2C3D4E5F60718 /* AppDelegateOptionDigitShortcutRoutingTests.swift */,
F8808A000000000000000002 /* AppDelegateTerminalTypingShortcutFastPathTests.swift */,
6419B0026419B0026419B002 /* AppDelegateShortcutRoutingRepairProbe.swift */,
4E6A6F5C1D2B4980A1234567 /* AppDelegateSurfaceShortcutRoutingTests.swift */,
6512F0C06512F0C06512F001 /* MainWindowFocusRestoreTests.swift */,
Expand Down Expand Up @@ -8938,7 +8935,6 @@ C0DE71B10000000000000002 /* AppDelegate+AgentChatNotifications.swift */ = {isa =
F6000000A1B2C3D4E5F60718 /* AppDelegateShortcutRoutingTests.swift in Sources */,
C6711A030000000000000001 /* AppDelegateSurfaceResumeTerminalIdTests.swift in Sources */,
4E6A6F5C1D2B4980A1234568 /* AppDelegateSurfaceShortcutRoutingTests.swift in Sources */,
F8808A000000000000000001 /* AppDelegateTerminalTypingShortcutFastPathTests.swift in Sources */,
F47126CFDAE244988A92E2D0 /* AppDelegateWindowFrameReconcileTests.swift in Sources */,
A11EAA000000000000000000 /* AppearanceSettingsTests.swift in Sources */,
A7206E010000000000000001 /* AppIconAppearanceObserverTests.swift in Sources */,
Expand Down
Loading