Conversation
|
@phongndo is attempting to deploy a commit to the Manaflow Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughCentralizes config discovery in GhosttyConfig, adds URL-backed resolution with canonicalization and non-empty filtering, exposes editorConfigURLs and cmuxAppSupportConfigURLs, updates GhosttyTerminalView to open all discovered configs (creating a fallback file when needed), and expands symlink/precedence tests. Changes
Sequence DiagramsequenceDiagram
participant User
participant Terminal as GhosttyTerminalView
participant Config as GhosttyConfig
participant FM as FileManager
participant Workspace as NSWorkspace
User->>Terminal: Click "Ghostty Settings"
activate Terminal
Terminal->>Config: editorConfigURLs(fileManager:, currentBundleIdentifier:, environment:, ...)
activate Config
Config->>FM: enumerate candidate URLs (XDG, HOME, AppSupport)
FM-->>Config: existence/type/size info
Config->>FM: resolve symlinks / canonicalize paths
FM-->>Config: canonical path results
Config-->>Terminal: prioritized non-empty URL list (or first-default fallback)
deactivate Config
alt URLs found
Terminal->>Workspace: open(listOfURLs)
else No URLs found
Terminal->>FM: create parent dirs & empty fallback file
FM-->>Terminal: success/failure
Terminal->>Workspace: open(fallbackURL)
end
deactivate Terminal
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip CodeRabbit can use your project's `swiftlint` configuration to improve the quality of Swift code reviews.Add a configuration file to your project to customize how CodeRabbit runs |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
Sources/GhosttyConfig.swift (1)
215-223: Inconsistent symlink handling withcmuxAppSupportConfigURLs.The
existingNonEmptyFileURLhelper (used for XDG and mitchellh paths) handles both regular files and symlinks, butGhosttyApp.cmuxAppSupportConfigURLs(context snippet atSources/GhosttyTerminalView.swift:1414-1448) only checks fortype == .typeRegular, excluding symlinks.If a user symlinks their cmux app support config (e.g.,
~/Library/Application Support/com.cmuxterm.app/config→ dotfiles location), it won't be discovered and opened, while symlinked XDG configs will work correctly.Consider aligning the symlink handling in
cmuxAppSupportConfigURLsto match the behavior here.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/GhosttyConfig.swift` around lines 215 - 223, The cmuxAppSupportConfigURLs path discovery excludes symlinks while existingNonEmptyFileURL accepts them; update GhosttyApp.cmuxAppSupportConfigURLs to treat symbolic links as valid config files the same way by checking for symlink file attributes (e.g., URLResourceValues.isSymbolicLink or FileAttributeKey.type == .typeSymbolicLink) in addition to regular files, and if a symlink is found resolve or validate its destination is a non-empty file before returning it so symlinked cmux config locations are discovered like XDG/mitchellh paths handled by existingNonEmptyFileURL.Sources/GhosttyTerminalView.swift (1)
1645-1649: Handle fallback file-creation failures explicitly before opening TextEdit.Line 1645–Line 1649 currently ignore directory/file creation failures, but Line 1655 still attempts to open the URL list. If the fallback path is not writable, the settings action can silently fail.
Proposed hardening
if let fallbackURL = fileURLs.first { let fallbackPath = fallbackURL.path if fileURLs.count == 1, !fileManager.fileExists(atPath: fallbackPath) { - try? fileManager.createDirectory( - at: fallbackURL.deletingLastPathComponent(), - withIntermediateDirectories: true - ) - fileManager.createFile(atPath: fallbackPath, contents: Data()) + do { + try fileManager.createDirectory( + at: fallbackURL.deletingLastPathComponent(), + withIntermediateDirectories: true + ) + let created = fileManager.createFile(atPath: fallbackPath, contents: Data()) + guard created || fileManager.fileExists(atPath: fallbackPath) else { +#if DEBUG + dlog("settings.open failed to create fallback config at \(fallbackPath)") +#endif + return + } + } catch { +#if DEBUG + dlog("settings.open failed to prepare fallback config path error=\(error.localizedDescription)") +#endif + return + } } }As per coding guidelines, "All debug events must be logged using the
dlog()function, which is only available in DEBUG builds. All call sites must be wrapped in#if DEBUG/#endifpreprocessor directives."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/GhosttyTerminalView.swift` around lines 1645 - 1649, Replace the silent failures by explicitly checking the results of creating the parent directory and the fallback file: use do/catch around fileManager.createDirectory(at: fallbackURL.deletingLastPathComponent(), withIntermediateDirectories: true) and check the Bool result of fileManager.createFile(atPath: fallbackPath, contents: Data()); if either operation fails, log the error/details using dlog(...) wrapped in `#if` DEBUG / `#endif` and avoid proceeding to open the URL list / launch TextEdit (return or throw early). Ensure you reference the existing symbols fallbackURL, fallbackPath, fileManager.createDirectory(...), and fileManager.createFile(...) so the failure is detected and handled before the code that opens the URL list executes.cmuxTests/GhosttyConfigTests.swift (1)
527-536: Consider removing redundant negative assertion.The positive assertion on lines 517-526 already verified that the result equals
[injectedConfig]. This negative assertion adds no additional coverage since ifresult == [injectedConfig], it logically follows thatresult != [otherConfig].♻️ Proposed simplification
XCTAssertEqual( GhosttyConfig.editorConfigURLs( fileManager: fileManager, currentBundleIdentifier: "com.cmuxterm.app.debug.issue-1476", appSupportDirectory: appSupportDirectory, homeDirectory: injectedHomeDirectory, environment: [:] ), [injectedConfig] ) - XCTAssertNotEqual( - GhosttyConfig.editorConfigURLs( - fileManager: fileManager, - currentBundleIdentifier: "com.cmuxterm.app.debug.issue-1476", - appSupportDirectory: appSupportDirectory, - homeDirectory: injectedHomeDirectory, - environment: [:] - ), - [otherConfig] - ) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cmuxTests/GhosttyConfigTests.swift` around lines 527 - 536, Remove the redundant negative assertion that compares GhosttyConfig.editorConfigURLs(...) to [otherConfig]; the preceding positive assertion already confirms the result equals [injectedConfig]. Locate the XCTAssertNotEqual block that calls GhosttyConfig.editorConfigURLs with fileManager/currentBundleIdentifier/appSupportDirectory/homeDirectory/environment and referencing otherConfig, and delete that entire XCTAssertNotEqual assertion to simplify the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@cmuxTests/GhosttyConfigTests.swift`:
- Around line 527-536: Remove the redundant negative assertion that compares
GhosttyConfig.editorConfigURLs(...) to [otherConfig]; the preceding positive
assertion already confirms the result equals [injectedConfig]. Locate the
XCTAssertNotEqual block that calls GhosttyConfig.editorConfigURLs with
fileManager/currentBundleIdentifier/appSupportDirectory/homeDirectory/environment
and referencing otherConfig, and delete that entire XCTAssertNotEqual assertion
to simplify the test.
In `@Sources/GhosttyConfig.swift`:
- Around line 215-223: The cmuxAppSupportConfigURLs path discovery excludes
symlinks while existingNonEmptyFileURL accepts them; update
GhosttyApp.cmuxAppSupportConfigURLs to treat symbolic links as valid config
files the same way by checking for symlink file attributes (e.g.,
URLResourceValues.isSymbolicLink or FileAttributeKey.type == .typeSymbolicLink)
in addition to regular files, and if a symlink is found resolve or validate its
destination is a non-empty file before returning it so symlinked cmux config
locations are discovered like XDG/mitchellh paths handled by
existingNonEmptyFileURL.
In `@Sources/GhosttyTerminalView.swift`:
- Around line 1645-1649: Replace the silent failures by explicitly checking the
results of creating the parent directory and the fallback file: use do/catch
around fileManager.createDirectory(at: fallbackURL.deletingLastPathComponent(),
withIntermediateDirectories: true) and check the Bool result of
fileManager.createFile(atPath: fallbackPath, contents: Data()); if either
operation fails, log the error/details using dlog(...) wrapped in `#if` DEBUG /
`#endif` and avoid proceeding to open the URL list / launch TextEdit (return or
throw early). Ensure you reference the existing symbols fallbackURL,
fallbackPath, fileManager.createDirectory(...), and fileManager.createFile(...)
so the failure is detected and handled before the code that opens the URL list
executes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a438183a-0eff-48df-8490-faef93e30353
📒 Files selected for processing (3)
Sources/GhosttyConfig.swiftSources/GhosttyTerminalView.swiftcmuxTests/GhosttyConfigTests.swift
There was a problem hiding this comment.
Pull request overview
This PR updates the “Open Configuration in TextEdit” behavior to locate and open the relevant Ghostty/cmux config files (in load order), with a fallback path when no existing configs are found.
Changes:
- Added
GhosttyConfig.editorConfigURLs(...)to resolve config file URLs (including XDG, legacy paths, and cmux app-support config). - Updated
openConfigurationInTextEdit()to open all resolved config URLs and create the fallback config file/directory when none exist. - Added unit tests covering URL ordering, fallbacks, empty-file handling, XDG override, injected home dir, and symlink handling.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| Sources/GhosttyTerminalView.swift | Uses new resolver to open multiple config files in TextEdit; creates fallback config path if needed. |
| Sources/GhosttyConfig.swift | Introduces editorConfigURLs to compute candidate config locations and return existing non-empty configs (or a fallback). |
| cmuxTests/GhosttyConfigTests.swift | Adds test coverage for the new URL resolution behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
1 issue found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="cmuxTests/GhosttyConfigTests.swift">
<violation number="1" location="cmuxTests/GhosttyConfigTests.swift:423">
P2: `testEditorConfigURLsIgnoresEmptyFiles` is ineffective: it expects the same XDG path that was just created as an empty file, so it cannot catch regressions where empty files are mistakenly treated as valid config files.</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Add one-off context when rerunning by tagging
@cubic-dev-aiwith guidance or docs links (includingllms.txt) - Ask questions if you need clarification on any suggestion
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e336ec2e3f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
Sources/GhosttyConfig.swift (1)
322-375: Finish threading the injectedfileManagerthrough reads.
loadFromDiskForTests(fileManager:)uses the injected manager for discovery, butreadConfigFilefalls back toFileManager.defaultfor the actual read path. That makes the new injection point only half-effective.♻️ Proposed refactor
- for path in configPaths { - if let contents = readConfigFile(at: path) { + for path in configPaths { + if let contents = readConfigFile(at: path, fileManager: fileManager) { config.parse(contents) } } @@ - private static func readConfigFile(at path: String) -> String? { - let fileManager = FileManager.default + private static func readConfigFile( + at path: String, + fileManager: FileManager = .default + ) -> String? { guard let url = existingNonEmptyConfigURL( for: URL(fileURLWithPath: path), fileManager: fileManager ) else { return nil }Also applies to: 679-684
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/GhosttyConfig.swift` around lines 322 - 375, loadFromDiskForTests currently uses the injected FileManager to build configPaths but still calls readConfigFile(at:) which uses FileManager.default; update readConfigFile to accept a FileManager parameter (e.g., readConfigFile(at:using:)) and change all call sites—specifically the loop inside loadFromDiskForTests and the other places referenced (around the other call site at the 679-684 region)—to pass the injected fileManager; also update any helper functions that compute paths (defaultConfigURLs, cmuxAppSupportConfigURLs) call sites to ensure they use the same injected FileManager so all file reads and path resolutions are consistently using the injected FileManager.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Sources/GhosttyConfig.swift`:
- Around line 185-193: The current xdgConfigRoot closure uses
NSString.expandingTildeInPath which expands ~ against the process user instead
of the injected homeDirectory and also allows non-absolute XDG_CONFIG_HOME
values; update logic in the xdgConfigRoot closure to: 1) detect a value starting
with "~" or "~/" and replace that leading component with the provided
homeDirectory path (do not call expandingTildeInPath), 2) if the value is not
absolute after this normalization, treat it as invalid and fall back to
homeDirectory.appendingPathComponent(".config", isDirectory: true), and 3) if
the value is absolute after normalization, return URL(fileURLWithPath:
normalized, isDirectory: true); also add a unit test for
editorConfigURLs/homeDirectory with environment["XDG_CONFIG_HOME"] set to a
tilde path to verify expansion uses the injected homeDirectory.
---
Nitpick comments:
In `@Sources/GhosttyConfig.swift`:
- Around line 322-375: loadFromDiskForTests currently uses the injected
FileManager to build configPaths but still calls readConfigFile(at:) which uses
FileManager.default; update readConfigFile to accept a FileManager parameter
(e.g., readConfigFile(at:using:)) and change all call sites—specifically the
loop inside loadFromDiskForTests and the other places referenced (around the
other call site at the 679-684 region)—to pass the injected fileManager; also
update any helper functions that compute paths (defaultConfigURLs,
cmuxAppSupportConfigURLs) call sites to ensure they use the same injected
FileManager so all file reads and path resolutions are consistently using the
injected FileManager.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b18fde29-2a41-4297-a48c-550da3b6317b
📒 Files selected for processing (3)
Sources/GhosttyConfig.swiftSources/GhosttyTerminalView.swiftcmuxTests/GhosttyConfigTests.swift
🚧 Files skipped from review as they are similar to previous changes (1)
- Sources/GhosttyTerminalView.swift
There was a problem hiding this comment.
🧹 Nitpick comments (2)
Sources/GhosttyConfig.swift (1)
145-162: Optional: avoid duplicate stat calls for regular files.
existingNonEmptyConfigURLfetches file attributes and then immediately re-fetches them viahasNonEmptyRegularFileAttributes(at:)for regular files. You can reuse the first attributes payload to reduce I/O.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/GhosttyConfig.swift` around lines 145 - 162, The code performs two stats for the same path: the outer attributes lookup and then a second call inside hasNonEmptyRegularFileAttributes(at:); modify existingNonEmptyConfigURL to reuse the attributes already obtained for url.path instead of calling hasNonEmptyRegularFileAttributes(at:), by extracting the size from the earlier attributes dictionary (attributes[.size] as? NSNumber) and returning url only if type == .typeRegular and size.intValue > 0; you can keep hasNonEmptyRegularFileAttributes(at:) for other callers or remove it if unused.cmuxTests/GhosttyConfigTests.swift (1)
712-751: Optional: rename this test for intent clarity.
testEditorConfigURLsDeduplicatesCanonicalPathWhenCmuxConfigSymlinksToDefaultGhosttyConfigcurrently asserts both URLs are preserved and only canonicalized-set count is one. A name reflecting “preserves both entrypoints with shared canonical target” would reduce ambiguity.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cmuxTests/GhosttyConfigTests.swift` around lines 712 - 751, Rename the test function testEditorConfigURLsDeduplicatesCanonicalPathWhenCmuxConfigSymlinksToDefaultGhosttyConfig to a clearer name such as testEditorConfigURLsPreservesBothEntrypointsWhenSymlinkedToSameCanonicalTarget; update the function declaration and any references to it so that the intent (that both entrypoint URLs are preserved even though their canonical/resolved path is the same) is explicit, leaving the body intact which exercises GhosttyConfig.editorConfigURLs and its resulting assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@cmuxTests/GhosttyConfigTests.swift`:
- Around line 712-751: Rename the test function
testEditorConfigURLsDeduplicatesCanonicalPathWhenCmuxConfigSymlinksToDefaultGhosttyConfig
to a clearer name such as
testEditorConfigURLsPreservesBothEntrypointsWhenSymlinkedToSameCanonicalTarget;
update the function declaration and any references to it so that the intent
(that both entrypoint URLs are preserved even though their canonical/resolved
path is the same) is explicit, leaving the body intact which exercises
GhosttyConfig.editorConfigURLs and its resulting assertions.
In `@Sources/GhosttyConfig.swift`:
- Around line 145-162: The code performs two stats for the same path: the outer
attributes lookup and then a second call inside
hasNonEmptyRegularFileAttributes(at:); modify existingNonEmptyConfigURL to reuse
the attributes already obtained for url.path instead of calling
hasNonEmptyRegularFileAttributes(at:), by extracting the size from the earlier
attributes dictionary (attributes[.size] as? NSNumber) and returning url only if
type == .typeRegular and size.intValue > 0; you can keep
hasNonEmptyRegularFileAttributes(at:) for other callers or remove it if unused.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 99e2d023-df1e-4204-ac05-041af0085512
📒 Files selected for processing (2)
Sources/GhosttyConfig.swiftcmuxTests/GhosttyConfigTests.swift
|
@codex review |
@phongndo I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
|
🧠 Learnings used✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
|
Codex Review: Didn't find any major issues. You're on a roll. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Continuation of 59e2281 TURN 1: Checked for open PRs implementing a cmux-level keybindings config file; found none actively working on issue manaflow-ai#1486, with only PR manaflow-ai#1513 existing as an unrelated Ghostty config fix. OVERALL: Investigated open PR status for keybindings config feature and confirmed issue manaflow-ai#1486 is requested but not currently being implemented. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
ghostty_config_open_path()behavior behindGhostty Settings…with cmux-side resolution that walks the expected top-level Ghostty config load order and opens allexisting non-empty config files in TextEdit.
XDG_CONFIG_HOMEso the settings action follows the same XDG root users expect when their Ghostty config is not under~/.config.Why:
Ghostty Settings…was opening the wrong file for users whose real config lived in XDG locations such as~/.config/ghostty/config.Closes #1476
Testing
./scripts/reload.sh --tag issue-1476XDG_CONFIG_HOMEManual verification:
Note:
successfully.
Demo Video
Review Trigger (Copy/Paste as PR comment)
Checklist
Summary by CodeRabbit
New Features
Tests