From f41a83177856a011d409ebc1f2924458773a3e1c Mon Sep 17 00:00:00 2001 From: tiffanysun1 Date: Thu, 12 Mar 2026 02:26:52 -0700 Subject: [PATCH] Stop version lookup at root --- CLI/cmux.swift | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/CLI/cmux.swift b/CLI/cmux.swift index 6ddd7437..2ad2a8b9 100644 --- a/CLI/cmux.swift +++ b/CLI/cmux.swift @@ -8172,7 +8172,7 @@ struct CMUXCLI { } let fileManager = FileManager.default - var current = executableURL.deletingLastPathComponent() + var current = executableURL.deletingLastPathComponent().standardizedFileURL while true { let projectFile = current.appendingPathComponent("GhosttyTabs.xcodeproj/project.pbxproj") @@ -8193,8 +8193,7 @@ struct CMUXCLI { } } - let parent = current.deletingLastPathComponent() - if parent.path == current.path { + guard let parent = parentSearchURL(for: current) else { break } current = parent @@ -8263,6 +8262,22 @@ struct CMUXCLI { return String(normalized.prefix(12)) } + // Foundation can walk past "/" into "/.." when repeatedly deleting path + // components, so stop once the canonical root is reached. + private func parentSearchURL(for url: URL) -> URL? { + let standardized = url.standardizedFileURL + let path = standardized.path + guard !path.isEmpty, path != "/" else { + return nil + } + + let parent = standardized.deletingLastPathComponent().standardizedFileURL + guard parent.path != path else { + return nil + } + return parent + } + private func candidateInfoPlistURLs() -> [URL] { guard let executableURL = resolvedExecutableURL() else { return [] @@ -8280,7 +8295,7 @@ struct CMUXCLI { candidates.append(url) } - var current = executableURL.deletingLastPathComponent() + var current = executableURL.deletingLastPathComponent().standardizedFileURL while true { if current.pathExtension == "app" { appendIfExisting(current.appendingPathComponent("Contents/Info.plist")) @@ -8299,8 +8314,7 @@ struct CMUXCLI { break } - let parent = current.deletingLastPathComponent() - if parent.path == current.path { + guard let parent = parentSearchURL(for: current) else { break } current = parent