Skip to content
Merged
Show file tree
Hide file tree
Changes from 57 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
00da345
CmuxControlSocket stage 3c-1: ControlCommandCoordinator + window domain
azooz2003-bit Jun 10, 2026
2383068
stage 3c: multi-protocol seam umbrella + shared param/ref helper port
azooz2003-bit Jun 10, 2026
b02c28d
stage 3c: extract App Focus + Feed + Notification domains
azooz2003-bit Jun 10, 2026
9bdae00
stage 3c: extract Mobile Host + Workspace Groups + Pane domains
azooz2003-bit Jun 10, 2026
4b8118f
stage 3c: fix int/double param helpers to match legacy NSNumber coercion
azooz2003-bit Jun 10, 2026
1905b38
stage 3c: integrate Workspace + Surface domains (full lifts)
azooz2003-bit Jun 10, 2026
8f7ac89
stage 3c: organize coordinator files into per-domain subfolders
azooz2003-bit Jun 10, 2026
487baaf
stage 3c: dedupe workspace.create onto the shared v2WorkspaceCreate body
azooz2003-bit Jun 10, 2026
6f2cba5
stage 3c: fix 8 divergences found by Workspace+Surface adversarial re…
azooz2003-bit Jun 11, 2026
fe419f0
Budget: entries for the two coordinator files grown by the divergence…
azooz2003-bit Jun 11, 2026
a94589d
Merge remote-tracking branch 'origin/main' into feat-ctl-coordinator-…
azooz2003-bit Jun 11, 2026
1e19188
CmuxTerminalCore: extract terminal core leaf (interop, key translatio…
azooz2003-bit Jun 11, 2026
edbdf67
CI: gate CmuxTerminalCore package tests (66 tests, 15 suites)
azooz2003-bit Jun 11, 2026
6b96072
Fix the two warnings that tripped the CI Swift warning budget
azooz2003-bit Jun 11, 2026
f731c27
Fix duplicate parameter name warning (sessionID sessionID) in workspa…
azooz2003-bit Jun 11, 2026
7d234dc
stage 3c: package side of System/Project/Debug/Sidebar/Browser domain…
azooz2003-bit Jun 11, 2026
494988f
CI: tolerate the cosmetic GhosttyKit binaryTarget diagnostic in the C…
azooz2003-bit Jun 11, 2026
39d111b
stage 3c: cut over System/Project/Debug/Sidebar/Browser domains to th…
azooz2003-bit Jun 11, 2026
ecd5148
stage 3c: dedupe file.open onto the shared v2FileOpen body
azooz2003-bit Jun 11, 2026
3178b68
stage 3c: fix browser.focus_mode.set/zoom.set error precedence; finis…
azooz2003-bit Jun 11, 2026
42f9332
Budget tsv: strip accidental leading whitespace
azooz2003-bit Jun 11, 2026
d47e003
Merge pull request #5909 from manaflow-ai/feat-ctl-3c-final-domains
azooz2003-bit Jun 11, 2026
29d8342
stage 3c: address review threads (handles observation, window.close t…
azooz2003-bit Jun 11, 2026
aadae54
CmuxTerminalCore: clipboard, render-demand, and surface-registry seams
azooz2003-bit Jun 12, 2026
0713b6d
CmuxTerminalServices: TerminalPasteboardService lifts GhosttyPasteboa…
azooz2003-bit Jun 12, 2026
0b6812d
CmuxTerminalEngine: surface registry, render-demand gating, Metal layer
azooz2003-bit Jun 12, 2026
0e5d265
App: rewire to CmuxTerminalEngine/CmuxTerminalServices, delete lifted…
azooz2003-bit Jun 12, 2026
ad70889
GhosttyMetalLayer: one critical section per vended drawable
azooz2003-bit Jun 12, 2026
2be538e
Merge origin/main: adopt PR 5778's socket-worker browser JS lane; rev…
azooz2003-bit Jun 12, 2026
5ebac5c
Engine tests: deterministic route-retire wait (fixes CI hang)
azooz2003-bit Jun 12, 2026
362ace9
Merge origin/feat-ctl-coordinator-3c-1 into feat-terminal-core
azooz2003-bit Jun 12, 2026
35eb145
Merge origin/feat-terminal-core into feat-terminal-engine
azooz2003-bit Jun 12, 2026
f54b421
CmuxTerminalCore: no namespace types; lint-enforce the rule repo-wide
azooz2003-bit Jun 12, 2026
57fd951
Merge remote-tracking branch 'origin/feat-terminal-core' into feat-te…
azooz2003-bit Jun 12, 2026
6996fc6
Merge origin/main into feat-terminal-core
azooz2003-bit Jun 12, 2026
8bbb21b
Merge origin/feat-terminal-core into feat-terminal-engine
azooz2003-bit Jun 12, 2026
ea8d799
Lift TerminalSurface model into CmuxTerminal package (stack D, tranch…
azooz2003-bit Jun 13, 2026
38b18b7
Hoist import CmuxTerminal into app-side tests naming the moved surfac…
azooz2003-bit Jun 13, 2026
f4c3689
Lift window-background policy + compositor blur into CmuxWorkspaceWin…
azooz2003-bit Jun 13, 2026
be6b65f
Lift Ghostty config-path namespace cluster into CmuxTerminalCore (sta…
azooz2003-bit Jun 13, 2026
c65e50d
Lift GhosttyBackgroundBlur config value into CmuxTerminalCore (stack …
azooz2003-bit Jun 13, 2026
0ce1595
Lift NSColor(hex:)/luminance/darken into CmuxTerminalCore (stack D, t…
azooz2003-bit Jun 13, 2026
5981d4a
Break GhosttyConfig <-> GhosttyApp config recursion by inverting owne…
azooz2003-bit Jun 13, 2026
3486bfe
Remove pbxproj references to the lifted CmuxApplicationSupportDirecto…
azooz2003-bit Jun 13, 2026
966c913
Relocate config-path namespace cluster to CmuxFoundation; the CLI sha…
azooz2003-bit Jun 13, 2026
3a89a1b
Wire CmuxTerminalCore into cmuxTests + fix test imports for lifted co…
azooz2003-bit Jun 13, 2026
8b5086c
Fix pre-existing Swift 6 isolation break in CmuxWorkspaceWindow blur …
azooz2003-bit Jun 13, 2026
b4b37ad
Consolidate config color/blur value types into CmuxFoundation; unwire…
azooz2003-bit Jun 13, 2026
959bd30
Remove stale WindowTransparencyDecisionTests referencing lifted free …
azooz2003-bit Jun 13, 2026
8c3de19
Lift SystemAppearance into CmuxTerminalCore as TerminalSystemAppearan…
azooz2003-bit Jun 13, 2026
fbd0e21
Lift ColorSchemePreference into CmuxTerminalCore as TerminalColorSche…
azooz2003-bit Jun 13, 2026
a160955
Move terminal color-scheme resolution into CmuxTerminalCore; GhosttyC…
azooz2003-bit Jun 13, 2026
2d3e968
Invert the DEBUG startup-preview reach out of GhosttyConfig (stack D,…
azooz2003-bit Jun 13, 2026
8e40b09
Lift NSColor.hexString() into CmuxFoundation (stack D, tranche A sub-6a)
azooz2003-bit Jun 13, 2026
943dc10
Move GhosttyConfig into CmuxTerminalCore (stack D, tranche A sub-6b)
azooz2003-bit Jun 13, 2026
8ca488b
Retarget the self-contained GhosttyConfig font-size suites into CmuxT…
azooz2003-bit Jun 13, 2026
3f8e336
Merge origin/main into feat-terminal-surface (re-sync onto merged 592…
azooz2003-bit Jun 14, 2026
cf80953
Fix post-re-sync CI: cmuxTests TerminalSurface import + 4 Swift-6 iso…
azooz2003-bit Jun 14, 2026
713016c
Ratchet GhosttyTerminalView file-length budget for the isolation-warn…
azooz2003-bit Jun 14, 2026
b67c530
Restore ghostty_surface_quicklook_font test stub in Engine/Services p…
azooz2003-bit Jun 14, 2026
00aca95
Merge origin/main again (5792 device-presence, 6057 Metal drawable, 6…
azooz2003-bit Jun 14, 2026
3b77c21
Add CmuxTerminal import to GhosttyDrawableSizeRetryTests (new 6057 te…
azooz2003-bit Jun 14, 2026
69abbe3
Merge origin/main again (5991 Workspace god-model split: CmuxWorkspac…
azooz2003-bit Jun 14, 2026
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
73 changes: 38 additions & 35 deletions .github/swift-file-length-budget.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,47 @@
# Format: max_lines<TAB>relative path
# Reduce counts as files shrink. CI fails if tracked files exceed this budget.
33285 CLI/cmux.swift
19213 Sources/ContentView.swift
17894 Sources/AppDelegate.swift
15182 Sources/GhosttyTerminalView.swift
14626 Sources/TerminalController.swift
13569 Sources/Panels/BrowserPanel.swift
12418 Sources/Workspace.swift
12045 cmuxTests/AppDelegateShortcutRoutingTests.swift
19197 Sources/ContentView.swift
17895 Sources/AppDelegate.swift
14627 Sources/TerminalController.swift
13572 Sources/Panels/BrowserPanel.swift
12419 Sources/Workspace.swift
12066 Sources/GhosttyTerminalView.swift
12046 cmuxTests/AppDelegateShortcutRoutingTests.swift
9345 cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
7737 Sources/Panels/BrowserPanelView.swift
7306 cmuxTests/WorkspaceUnitTests.swift
6943 cmuxTests/WorkspaceRemoteConnectionTests.swift
6555 cmuxTests/GhosttyConfigTests.swift
6315 cmuxTests/SessionPersistenceTests.swift
7309 cmuxTests/WorkspaceUnitTests.swift
6944 cmuxTests/WorkspaceRemoteConnectionTests.swift
6316 cmuxTests/SessionPersistenceTests.swift
6296 cmuxTests/GhosttyConfigTests.swift
6153 CLI/cmux_open.swift
6073 Sources/TextBoxInput.swift
6070 Sources/TabManager.swift
5967 cmuxTests/TerminalAndGhosttyTests.swift
6074 Sources/TextBoxInput.swift
6073 Sources/TabManager.swift
5969 cmuxTests/TerminalAndGhosttyTests.swift
5499 cmuxTests/BrowserConfigTests.swift
5468 Sources/cmuxApp.swift
5470 Sources/cmuxApp.swift
4706 Packages/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
4460 Sources/Panels/FilePreviewPanel.swift
4400 cmuxTests/BrowserPanelTests.swift
4227 Sources/BrowserWindowPortal.swift
3937 Sources/Feed/FeedPanelView.swift
3895 cmuxTests/WindowAndDragTests.swift
3762 cmuxTests/TabManagerUnitTests.swift
3763 cmuxTests/TabManagerUnitTests.swift
3699 cmuxTests/CLIGenericHookPersistenceTests.swift
3663 Packages/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift
3397 Sources/CmuxConfig.swift
3330 cmuxTests/TabManagerSessionSnapshotTests.swift
3331 cmuxTests/TabManagerSessionSnapshotTests.swift
3202 Sources/Update/UpdateTitlebarAccessory.swift
2877 Sources/SessionIndexView.swift
2871 cmuxTests/CMUXOpenCommandTests.swift
2565 Sources/Panels/CmuxWebView.swift
2545 cmuxTests/WorkspaceManualUnreadTests.swift
2544 cmuxTests/CommandPaletteSearchEngineTests.swift
2516 Sources/KeyboardShortcutSettings.swift
2327 cmuxTests/CJKIMEInputTests.swift
2328 cmuxTests/CJKIMEInputTests.swift
2322 Sources/Mobile/MobileHostService.swift
2314 Sources/FileExplorerView.swift
2260 Sources/TerminalWindowPortal.swift
2261 Sources/TerminalWindowPortal.swift
2235 Sources/TerminalNotificationStore.swift
2134 cmuxTests/ShortcutAndCommandPaletteTests.swift
2117 cmuxTests/CmuxConfigTests.swift
Expand All @@ -53,7 +53,7 @@
1794 Sources/SessionIndexStore.swift
1777 Sources/RestorableAgentSession.swift
1751 Sources/WindowDragHandleView.swift
1722 cmuxTests/TerminalControllerSocketSecurityTests.swift
1723 cmuxTests/TerminalControllerSocketSecurityTests.swift
1693 cmuxTests/WorkspacePullRequestSidebarTests.swift
1677 cmuxUITests/BrowserPaneNavigationKeybindUITests.swift
1652 cmuxTests/CMUXCLIErrorOutputRegressionTests.swift
Expand All @@ -66,9 +66,10 @@
1380 cmuxUITests/MenuKeyEquivalentRoutingUITests.swift
1376 cmuxTests/KeyboardShortcutSettingsFileStoreStartupTests.swift
1373 cmuxTests/AppDelegateIssue2907RoutingTests.swift
1365 Sources/Feed/FeedButtonStyleDebugWindowController.swift
1366 Sources/Feed/FeedButtonStyleDebugWindowController.swift
1362 Sources/CMUXInstalledExtensionSidebarHostView.swift
1312 cmuxTests/MobileHostAuthorizationTests.swift
1292 Packages/CmuxTerminalCore/Sources/CmuxTerminalCore/Config/GhosttyConfig.swift
1285 cmuxUITests/SidebarHelpMenuUITests.swift
1270 cmuxTests/RestorableAgentSessionIndexTests.swift
1256 Sources/Feed/FeedCoordinator.swift
Expand All @@ -78,9 +79,8 @@
1157 cmuxTests/SidebarOrderingTests.swift
1144 cmuxTests/PiVaultAgentPersistenceTests.swift
1126 cmuxTests/FileExplorerStoreTests.swift
1119 cmuxTests/AgentHibernationTests.swift
1120 cmuxTests/AgentHibernationTests.swift
1107 Sources/AppDelegate+CmuxSSHURL.swift
1096 Sources/GhosttyConfig.swift
1093 cmuxUITests/BonsplitTabDragUITests.swift
1021 cmuxUITests/TerminalCmdClickUITests.swift
1006 cmuxTests/CmuxSSHURLRequestTests.swift
Expand All @@ -89,14 +89,15 @@
945 Sources/SessionIndexRegisteredAgents.swift
941 Sources/App/TerminalDirectoryOpenSupport.swift
937 Sources/TextBoxMentionIndexStore.swift
929 Sources/App/ShortcutRoutingSupport.swift
925 Sources/DockPanelView.swift
934 Sources/App/ShortcutRoutingSupport.swift
926 Sources/DockPanelView.swift
919 Packages/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+RuntimeLifecycle.swift
917 cmuxTests/WorkspaceGroupTests.swift
905 Sources/CmuxSSHURLRequest.swift
903 Sources/CommandPalette/CommandPaletteSettingsToggle.swift
878 Sources/WorkspaceContentView.swift
880 Sources/WorkspaceContentView.swift
868 Sources/Panels/BrowserScreenshotSnapshotter.swift
865 Sources/Panels/TerminalPanel.swift
866 Sources/Panels/TerminalPanel.swift
856 Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/AppSection.swift
852 Packages/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator+Workspace.swift
847 cmuxTests/AgentSessionAutoResumeSettingsTests.swift
Expand All @@ -106,7 +107,7 @@
810 Packages/CmuxSwiftRender/Tests/CmuxSwiftRenderTests/SwiftViewInterpreterTests.swift
787 Sources/ClosedItemHistory.swift
774 cmuxUITests/BrowserFixtureInteractionUITests.swift
769 Sources/MainWindowFocusController.swift
770 Sources/MainWindowFocusController.swift
762 Packages/CmuxMobileTransport/Sources/CmuxMobileTransport/CmxNetworkByteTransport.swift
760 Packages/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swift
756 Sources/Panels/AgentSessionWebRendererCoordinator.swift
Expand All @@ -116,9 +117,10 @@
738 Packages/CMUXProjectModel/Sources/CMUXProjectModel/XcodeProjectAdapter.swift
738 Packages/CmuxAuthRuntime/Sources/CmuxAuthRuntime/Coordinator/AuthCoordinator.swift
716 Sources/TaskManagerSnapshot.swift
715 Packages/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+Input.swift
715 Sources/AppleScriptSupport.swift
710 Sources/TerminalSSHSessionDetector.swift
705 CLI/CMUXCLI+Config.swift
706 CLI/CMUXCLI+Config.swift
705 cmuxUITests/BrowserOmnibarSuggestionsUITests.swift
701 CLI/CMUXCLI+AgentHookDefinitions.swift
698 Sources/RightSidebarPanelView.swift
Expand All @@ -141,8 +143,8 @@
648 Packages/CmuxRemoteSession/Sources/CmuxRemoteSession/Session/RemoteSessionCoordinator.swift
640 cmuxTests/CommandPaletteNucleoFFITests.swift
630 Packages/CmuxSettings/Sources/CmuxSettings/Values/ShortcutWhenClause.swift
621 cmuxTests/FinderFileDropRegressionTests.swift
621 cmuxUITests/RightSidebarChromeHeightUITests.swift
620 cmuxTests/FinderFileDropRegressionTests.swift
620 cmuxTests/TerminalNotificationQueueTests.swift
614 Sources/PortScanner.swift
614 cmuxTests/SessionIndexViewTests.swift
Expand All @@ -164,15 +166,16 @@
568 Packages/CMUXMobileCore/Sources/CMUXMobileCore/MobileTerminalRenderGrid.swift
566 Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift
562 cmuxTests/AgentExecutableResolverTests.swift
560 cmuxTests/GhosttyConfigPathResolverTests.swift
561 cmuxTests/GhosttyConfigPathResolverTests.swift
558 Packages/CmuxGit/Sources/CmuxGit/Parsing/GitMetadataService+Config.swift
554 Sources/Panels/BrowserAutomation.swift
551 Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/BrowserSection.swift
547 Packages/CmuxSocketControl/Sources/CmuxSocketControl/SocketControlSettings.swift
546 Sources/Windowing/WindowGlassEffect.swift
547 Sources/Windowing/WindowGlassEffect.swift
540 Packages/CmuxWorkspaces/Sources/CmuxWorkspaces/Coordinators/WorkspaceReorderCoordinator.swift
539 CLI/CMUXCLI+Themes.swift
539 CLI/CodexTeamsApprovalBridge.swift
538 CLI/CMUXCLI+Themes.swift
539 Packages/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface.swift
538 Packages/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/PTYBridge/RemotePTYBridgeSession.swift
536 cmuxTests/CmuxConfigContextMenuTests.swift
533 Packages/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Pane/ControlCommandCoordinator+Pane.swift
Expand All @@ -192,11 +195,11 @@
516 Sources/CmuxConfigExecutor.swift
514 Packages/CmuxSwiftRender/Sources/CmuxSwiftRender/ExpressionEvaluator.swift
514 cmuxUITests/UpdatePillUITests.swift
510 Sources/TerminalImageTransfer.swift
509 Packages/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizerAdditionalPolicies.swift
509 Sources/TerminalImageTransfer.swift
507 Sources/TerminalControllerTopSupport.swift
506 Sources/App/MainWindowVisibilityController.swift
505 cmuxUITests/DisplayResolutionRegressionUITests.swift
504 cmuxTests/TerminalNotificationSocketActionTests.swift
503 Sources/Settings/ConfigSource.swift
502 Sources/CmuxEventPublishing.swift
502 Sources/Settings/ConfigSource.swift
1 change: 1 addition & 0 deletions CLI/CMUXCLI+Config.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import CmuxFoundation

extension CMUXCLI {
func runConfigCommand(
Expand Down
1 change: 1 addition & 0 deletions CLI/CMUXCLI+ThemeSupport.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import CmuxFoundation

extension CMUXCLI {
func availableThemeNames() -> [String] {
Expand Down
1 change: 1 addition & 0 deletions CLI/CMUXCLI+Themes.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import CmuxFoundation
import Darwin

extension CMUXCLI {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
public import AppKit

extension NSColor {
/// Creates a color from a 6-digit hex string (with or without a leading
/// `#`), or `nil` when the string is not a valid 6-digit hex color.
public convenience init?(hex: String) {
var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")

var rgb: UInt64 = 0
guard Scanner(string: hexSanitized).scanHexInt64(&rgb) else {
return nil
}

let r, g, b: CGFloat
if hexSanitized.count == 6 {
r = CGFloat((rgb & 0xFF0000) >> 16) / 255.0
g = CGFloat((rgb & 0x00FF00) >> 8) / 255.0
b = CGFloat(rgb & 0x0000FF) / 255.0
} else {
return nil
}
Comment on lines +7 to +22

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Swift Foundation, does Scanner.scanHexInt64(_:) succeed when only a prefix is valid hex (for example "12GG34")? Is checking scanner.isAtEnd required for strict full-string validation?

💡 Result:

In Swift Foundation, Scanner.scanHexInt64(:) does succeed when only a prefix is valid [1][2]. The method scans for a valid hexadecimal representation starting at the current position, and if found, it returns true and advances the scanner's position past the end of the scanned hexadecimal digits [1]. It does not require that the entire remainder of the string be consumed or that the scanner be at the end of the string [1]. For example, if you call scanHexInt64(:) on the string "12GG34", the scanner will successfully identify "12" as a valid hexadecimal number, store the value 0x12 (18) in the provided pointer, and move the scanner's current position to the character 'G'. Because it successfully scanned a valid prefix, it returns true [1]. Therefore, checking scanner.isAtEnd is required if you want to ensure the entire string is a valid hexadecimal number [1][3]. Without this check, the scanner will report success as long as it finds a valid numeric start, leaving the remaining invalid characters unparsed [1]. To perform strict full-string validation, you must ensure that after the scan completes, scanner.isAtEnd is true [1][4].

Citations:


🏁 Script executed:

find . -name "NSColor+Hex.swift" -type f

Repository: manaflow-ai/cmux

Length of output: 133


🏁 Script executed:

cat -n "./Packages/CmuxFoundation/Sources/CmuxFoundation/Color/NSColor+Hex.swift"

Repository: manaflow-ai/cmux

Length of output: 3537


Reject malformed hex input before conversion.

The hex parser accepts invalid input for two reasons:

  1. Line 8: replacingOccurrences(of: "#", with: "") removes all # characters globally, not just a leading prefix. Input like "1#23456" normalizes to "123456" and is accepted.

  2. Lines 10–13: Scanner.scanHexInt64(_:) succeeds on a valid hex prefix and does not consume the entire string. Input like "12ABXX" (6 chars) passes the length check, but Scanner consumes only "12AB", leaving "XX" unparsed. The resulting color is incorrect.

Replace with strict validation and parsing:

🔧 Suggested fix
-        var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
-        hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")
-
-        var rgb: UInt64 = 0
-        guard Scanner(string: hexSanitized).scanHexInt64(&rgb) else {
-            return nil
-        }
+        var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
+        if hexSanitized.hasPrefix("#") {
+            hexSanitized.removeFirst()
+        }
+        guard hexSanitized.count == 6,
+              hexSanitized.unicodeScalars.allSatisfy({ CharacterSet.hexDigits.contains($0) }),
+              let rgb = UInt64(hexSanitized, radix: 16) else {
+            return nil
+        }
🤖 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/CmuxFoundation/Sources/CmuxFoundation/Color/NSColor`+Hex.swift
around lines 7 - 22, The hex parser has two validation issues that accept
malformed input. First, the global replacingOccurrences(of:"#", with:"") call
removes all # characters instead of just a leading prefix, allowing input like
"1#23456" to be accepted. Second, Scanner.scanHexInt64(_:) only validates a
valid hex prefix and does not require consuming the entire string, so input like
"12ABXX" passes the length check but is parsed incorrectly. Replace the hex
string sanitization and validation logic by first removing only a leading # if
present, then validating that the remaining string is exactly 6 characters long
and contains only valid hexadecimal characters (0-9, A-F, a-f) before attempting
to parse it with the Scanner, rejecting any input that fails these strict
checks.


self.init(red: r, green: g, blue: b, alpha: 1.0)
}

/// Whether the color reads as light (relative luminance above 0.5).
public var isLightColor: Bool {
luminance > 0.5
}

/// The perceptual relative luminance of the color in sRGB, or `0` when the
/// color cannot be converted to sRGB.
public var luminance: Double {
var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
var a: CGFloat = 0

guard let rgb = usingColorSpace(.sRGB) else { return 0 }
rgb.getRed(&r, green: &g, blue: &b, alpha: &a)
return (0.299 * r) + (0.587 * g) + (0.114 * b)
}

/// Returns a darkened copy of the color, reducing brightness by `amount`
/// (0...1) in HSB space.
public func darken(by amount: CGFloat) -> NSColor {
var h: CGFloat = 0
var s: CGFloat = 0
var b: CGFloat = 0
var a: CGFloat = 0
getHue(&h, saturation: &s, brightness: &b, alpha: &a)
return NSColor(
hue: h,
saturation: s,
brightness: min(b * (1 - amount), 1),
alpha: a
)
}

/// The color as a `#`-prefixed, uppercased sRGB hex string. Returns a 6-digit
/// `#RRGGBB` string, or an 8-digit `#RRGGBBAA` string when `includeAlpha` is
/// `true`. The inverse of ``init(hex:)``.
public func hexString(includeAlpha: Bool = false) -> String {
let color = usingColorSpace(.sRGB) ?? self
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
let redByte = min(255, max(0, Int(red * 255)))
let greenByte = min(255, max(0, Int(green * 255)))
let blueByte = min(255, max(0, Int(blue * 255)))
if includeAlpha {
let alphaByte = min(255, max(0, Int(alpha * 255)))
return String(format: "#%02X%02X%02X%02X", redByte, greenByte, blueByte, alphaByte)
}
return String(format: "#%02X%02X%02X", redByte, greenByte, blueByte)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
public import Foundation

/// Resolves the Application Support base directories cmux scans for Ghostty
/// configuration, honoring `CFFIXED_USER_HOME` for test/sandbox overrides.
///
/// TRANSITIONAL: faithful lift of the app-target config-path namespace cluster
/// the engine and ``GhosttyConfig`` recurse through. These stateless directory
/// transforms have no natural receiver type; modernization into instantiated,
/// dependency-injected resolvers is deferred to the engine lift (Tranche C).
// lint:allow namespace-type — see TRANSITIONAL note above.
public enum CmuxApplicationSupportDirectories {
/// Returns the de-duplicated, standardized Application Support directories to
/// search, ordered from the most specific (`FileManager`-resolved) to the
/// `~/Library/Application Support` fallback.
public static func userDirectories(
environment: [String: String],
fileManager: FileManager = .default
) -> [URL] {
var urls: [URL] = []
var seen: Set<String> = []

func append(_ url: URL?) {
guard let url else { return }
let standardized = url.standardizedFileURL
if seen.insert(standardized.path).inserted {
urls.append(standardized)
}
}

append(fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first)

if let fixedHome = environment["CFFIXED_USER_HOME"]?.trimmingCharacters(in: .whitespacesAndNewlines),
!fixedHome.isEmpty {
append(
URL(fileURLWithPath: fixedHome, isDirectory: true)
.appendingPathComponent("Library/Application Support", isDirectory: true)
)
}

append(
URL(
fileURLWithPath: NSString(string: "~/Library/Application Support").expandingTildeInPath,
isDirectory: true
)
)

return urls
}
}
Loading
Loading