Skip to content

Sync ghostty fork with upstream main#1484

Open
lawrencecchen wants to merge 30 commits intomainfrom
task-sync-ghostty-upstream-main
Open

Sync ghostty fork with upstream main#1484
lawrencecchen wants to merge 30 commits intomainfrom
task-sync-ghostty-upstream-main

Conversation

@lawrencecchen
Copy link
Copy Markdown
Contributor

@lawrencecchen lawrencecchen commented Mar 16, 2026

Summary

Testing

  • cd ghostty && zig build -Demit-xcframework=true -Demit-macos-app=false -Dxcframework-target=universal -Doptimize=ReleaseFast
  • GHOSTTY_SHA=51ba49a4bb74c2f3030b8a2878f4162d2624d4ca ./scripts/download-prebuilt-ghosttykit.sh
  • ./scripts/setup.sh
  • ./scripts/reload.sh --tag task-sync-ghostty-upstream

Summary by cubic

Syncs our ghostty fork with upstream main, pins the matching GhosttyKit xcframework checksum, and updates fork docs. Keeps the macOS 26 main titlebar opaque, hardens Find/search activation (pending-request tracking, safe fallback, ignore unsolicited opens), and refines chrome theme resolution (loaded-vs-runtime background, composited chrome opacity, background-blur).

  • Tests
    • Adds a UI test that boots a terminal surface and repeatedly verifies send_key_surface/list_surfaces; runs under allowAll and uses an in-app stress harness with diagnostics, socket health checks, retries, per-command timeouts, a background-thread loop, direct UNIX client with nc fallback, smarter cmux CLI discovery with env cmux fallback, forced CMUX_SOCKET_MODE, and now resolves the target workspace/surface via socket queries.
    • Adds unit tests for background-blur parsing, titlebar composited opacity, chrome config resolution (runtime-vs-loaded), and search activation decoding and fallbacks.

Written for commit ed9da3e. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • macOS background-blur options and runtime theme composition for improved titlebar/chrome rendering and opacity handling
    • More robust search activation with deferred/pending start-search and fallback behavior
  • Bug Fixes

    • Improved prompt redraw handling and reduced transient frames during resize
    • Display-link restart behavior on display changes
  • Tests

    • Expanded unit and UI tests covering blur parsing, titlebar opacity, theme resolution, and search activation flows
  • Documentation

    • Updated fork metadata and upstream notes
  • Chores

    • Submodule checksum mapping and CI test-run invocation refinement

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Mar 21, 2026 3:57am

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 16, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Updates docs and ghostty submodule; adds background-blur config parsing; implements a pending Ghostty search activation/resolution workflow; refactors runtime vs loaded chrome/theme composition and titlebar opacity; adds tests and a UI socket stress test; updates checksum mapping.

Changes

Cohort / File(s) Summary
Docs & Submodule
docs/ghostty-fork.md, ghostty
Refresh fork metadata and commit references to upstream main (a2b2b883e); advance ghostty submodule pointer to 51ba49a4b....
Ghostty config
Sources/GhosttyConfig.swift
Add BackgroundBlur enum, parser, and backgroundBlur field; parse background-blur config key.
Search activation workflow
Sources/AppDelegate.swift, Sources/GhosttyTerminalView.swift, Sources/TabManager.swift, Sources/...TerminalSurface
Introduce pending search request types and resolution helpers (CmuxPendingGhosttySearchRequest, CmuxGhosttyStartSearchResolution), decoding helper, resolver, fallback applier; add TerminalSurface request/consume/clear APIs; AppDelegate/TabManager updated to request/clear activations and defer search initialization.
Theme / titlebar & compositing
Sources/ContentView.swift, Sources/Panels/BrowserPanel.swift, Sources/Workspace.swift, Sources/WorkspaceContentView.swift
Add cmuxMainWindowTitlebarOpacity and cmuxResolveGhosttyChromeConfig; add compositedChromeOpacity/compositedChromeColor; change titlebar/theme state to use resolved runtime vs loaded config and include background-blur in refresh decision.
Tests
cmuxTests/GhosttyConfigTests.swift, cmuxTests/TerminalAndGhosttyTests.swift
Add unit tests for background-blur parsing, titlebar opacity/composited behavior, chrome config resolution, and five tests covering pending start-search resolution and fallback; adjust one workspace color alpha expectation.
UI automation & socket helpers
cmuxUITests/AutomationSocketUITests.swift
Add UI stress test testSurfaceListStillRespondsAfterRepeatedSendKey, socket I/O helpers, ControlSocketClient, and a wait helper.
BrowserPanel helpers
Sources/Panels/BrowserPanel.swift
Add GhosttyBackgroundTheme.compositedChromeOpacity(_:) and compositedChromeColor(backgroundColor:opacity:).
Checksum mapping
scripts/ghosttykit-checksums.txt
Add SHA-to-SHA256 mapping for ghostty commit 51ba49a4bb74c2f....
CI workflow
.github/workflows/test-e2e.yml
Construct xcodebuild invocation as an array and conditionally invoke it with display env prefix for streaming/conditional execution.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant AD as AppDelegate
    participant TS as TerminalSurface
    participant GTV as GhosttyTerminalView
    participant GA as GhosttyApp

    User->>AD: startOrFocusTerminalSearch()
    AD->>TS: requestGhosttySearchActivation(.startSearch)
    AD->>TS: performBindingAction("start_search")
    alt binding succeeds
        TS->>GA: binding succeeded / notify
        GA->>GTV: cmuxApplyPendingGhosttyStartSearchFallbackIfNeeded()
        GTV->>GTV: create/update searchState (maybe with needle)
        GTV->>AD: post focus / invoke notifier
    else binding fails
        TS->>TS: clearGhosttySearchActivationRequest()
        AD->>GTV: fallback initialize searchState
        GTV->>AD: post ghosttySearchFocus notification
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰
I hopped along the themed-up trail,
Held pending searches in my tail—
Chrome blurred soft, titlebars gleamed bright,
Submodule hopped to upstream light,
Tests and docs rejoiced tonight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Sync ghostty fork with upstream main' accurately summarizes the main change in the pull request, which syncs the ghostty submodule to upstream main.
Description check ✅ Passed The PR description covers the main changes (ghostty bump, docs update, checksum pinning) and includes testing steps, but lacks sections for manual verification details and demo video.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task-sync-ghostty-upstream-main

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

@lawrencecchen lawrencecchen force-pushed the task-sync-ghostty-upstream-main branch from 70c6fa2 to fcdeac5 Compare March 18, 2026 10:00
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 18, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/manaflow-ai/cmux/issues/comments/4064250722","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> <details>\n> <summary>⚙️ Run configuration</summary>\n> \n> **Configuration used**: defaults\n> \n> **Review profile**: CHILL\n> \n> **Plan**: Pro\n> \n> **Run ID**: `27761b8b-8e50-4fa3-b4aa-7ce1bbddd310`\n> \n> </details>\n> \n> <details>\n> <summary>📥 Commits</summary>\n> \n> Reviewing files that changed from the base of the PR and between 70c6fa23ee7355c66cd8707aadb61edea2eadaea and fcdeac56e3c466fb3fc77e6686c93c1fd3f02b8a.\n> \n> </details>\n> \n> <details>\n> <summary>📒 Files selected for processing (13)</summary>\n> \n> * `Sources/AppDelegate.swift`\n> * `Sources/ContentView.swift`\n> * `Sources/GhosttyConfig.swift`\n> * `Sources/GhosttyTerminalView.swift`\n> * `Sources/Panels/BrowserPanel.swift`\n> * `Sources/TabManager.swift`\n> * `Sources/Workspace.swift`\n> * `Sources/WorkspaceContentView.swift`\n> * `cmuxTests/GhosttyConfigTests.swift`\n> * `cmuxTests/TerminalAndGhosttyTests.swift`\n> * `docs/ghostty-fork.md`\n> * `ghostty`\n> * `scripts/ghosttykit-checksums.txt`\n> \n> </details>\n> \n> ```ascii\n>  _______________________________________________\n> < CodeRabbit: Because Jarvis was already taken. >\n>  -----------------------------------------------\n>   \\\n>    \\   (\\__/)\n>        (•ㅅ•)\n>        /   づ\n> ```\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nThis PR updates ghostty fork documentation and submodule pointer, adds a checksum entry, introduces a public helper to compute main window titlebar opacity and replaces inline calculations with it, and adds tests covering the new opacity helper.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Fork Documentation** <br> `docs/ghostty-fork.md`|Rebased fork metadata to upstream main (`a2b2b883e`), updated multiple commit hashes and section summaries (OSC99, macOS display link, keyboard copy mode, macOS resize, zsh Pure redraws, cmux theme picker).|\n|**Submodule & Checksums** <br> `ghostty` , `scripts/ghosttykit-checksums.txt`|Bumped ghostty submodule pointer to `51ba49a4b...` and added corresponding SHA256 checksum mapping line.|\n|**Titlebar Opacity Helper** <br> `Sources/ContentView.swift`|Added public `cmuxMainWindowTitlebarOpacity(backgroundOpacity:glassEffectAvailable:)` and replaced previous inline opacity calculation sites to use it.|\n|**Tests** <br> `cmuxTests/CmuxWebViewKeyEquivalentTests.swift`|Added MainWindowTitlebarOpacityTests with cases for glass effect available/unavailable validating the new opacity function.|\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly related PRs\n\n- manaflow-ai/cmux#667: Also modifies titlebar opacity/titlebar rendering in `Sources/ContentView.swift`.\n- manaflow-ai/cmux#1363: Updates ghostty submodule to include Pure prompt redraw fixes referenced in this PR's docs.\n- manaflow-ai/cmux#1405: Related changes to ghostty submodule pointer and checksum management.\n\n## Poem\n\n> 🐰 A hop through commits, bright and spry,  \n> Submodules nudged, checksums pile high,  \n> Titlebars steady, opacity true,  \n> Tests nod yes — the view is new.  \n> 🥕 Cheers from a rabbit, quick and wry!\n\n</details>\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n### ❌ Failed checks (1 warning)\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                           |\n| :---------------: | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|    Title check    | ✅ Passed | The title 'Sync ghostty fork with upstream main' accurately and concisely summarizes the main objective of the pull request: bumping the ghostty dependency and synchronizing the fork with upstream. |\n| Description check | ✅ Passed | The description covers all required template sections: summary explains what changed and why, testing provides specific commands for verification, and includes referenced external resources.        |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>📝 Generate docstrings</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> Create stacked PR\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> Commit on current branch\n\n</details>\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `task-sync-ghostty-upstream-main`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- pr_review_plan_action_start -->\n\n<details>\n<summary>📝 Coding Plan</summary>\n\n- [ ] <!-- {\"checkboxId\": \"6ad8a4e1-0b3a-4ea2-9b5b-d82c1f47d1f2\"} --> Generate coding plan for human review comments\n\n</details>\n\n<!-- pr_review_plan_action_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=manaflow-ai/cmux&utm_content=1484)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}}}

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
docs/ghostty-fork.md (1)

97-97: Avoid section-number coupling in HEAD note.

“section 6” is brittle if sections are reordered later. Prefer referencing the commit hash directly (or both section title + hash) to keep this line stable over time.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ghostty-fork.md` at line 97, The HEAD note currently says "section 6
theme-picker hardening commit," which couples the note to a mutable section
number; update that line to reference the commit hash (and optionally the
section title) instead of the section number so it remains stable — replace
"section 6 theme-picker hardening commit" with the commit SHA (e.g.,
<commit-hash>) or "theme-picker hardening commit (<commit-hash>)" in the HEAD
note.
Sources/WorkspaceContentView.swift (1)

209-218: Capture runtime opacity once per resolve pass.

defaultBackgroundOpacity() is invoked twice in this branch. Capturing it once makes the resolved/logged values deterministic within the same pass.

♻️ Suggested refactor
-            let runtimeBackground = defaultBackground()
+            let runtimeBackground = defaultBackground()
+            let runtimeBackgroundOpacity = defaultBackgroundOpacity()
             let resolved = cmuxResolveGhosttyChromeConfig(
                 loadedConfig: loadedConfig,
                 runtimeBackgroundColor: runtimeBackground,
-                runtimeBackgroundOpacity: defaultBackgroundOpacity()
+                runtimeBackgroundOpacity: runtimeBackgroundOpacity
             )
             next = resolved
             runtimeBackgroundHex = runtimeBackground.hexString()
-            runtimeOpacity = defaultBackgroundOpacity()
+            runtimeOpacity = runtimeBackgroundOpacity
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/WorkspaceContentView.swift` around lines 209 - 218, The code calls
defaultBackgroundOpacity() twice causing nondeterministic values; fix by calling
defaultBackgroundOpacity() once at the start of the pass (store it in a local
let, e.g. let runtimeOpacityValue = defaultBackgroundOpacity()), pass that
variable into cmuxResolveGhosttyChromeConfig (as runtimeBackgroundOpacity) and
use the same runtimeOpacityValue when assigning runtimeOpacity, keeping
runtimeBackground and runtimeBackgroundHex logic unchanged and removing the
duplicate defaultBackgroundOpacity() call.
Sources/ContentView.swift (1)

329-347: Use the clamped runtime opacity when writing back the resolved config.

Line 345 currently stores runtimeBackgroundOpacity (raw) even though Line 334 already computes a clamped value. Writing the clamped value keeps GhosttyConfig normalized and avoids invalid opacity values propagating.

♻️ Proposed patch
 func cmuxResolveGhosttyChromeConfig(
     loadedConfig: GhosttyConfig,
     runtimeBackgroundColor: NSColor,
     runtimeBackgroundOpacity: Double
 ) -> GhosttyConfig {
     let runtimeOpacity = GhosttyBackgroundTheme.clampedOpacity(runtimeBackgroundOpacity)
     let loadedOpacity = GhosttyBackgroundTheme.clampedOpacity(loadedConfig.backgroundOpacity)
@@
     var resolved = loadedConfig
     resolved.backgroundColor = runtimeBackgroundColor
-    resolved.backgroundOpacity = runtimeBackgroundOpacity
+    resolved.backgroundOpacity = runtimeOpacity
     return resolved
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/ContentView.swift` around lines 329 - 347, The function
cmuxResolveGhosttyChromeConfig computes a clamped runtimeOpacity but then writes
the raw runtimeBackgroundOpacity into resolved.backgroundOpacity; change the
assignment in cmuxResolveGhosttyChromeConfig to set resolved.backgroundOpacity =
runtimeOpacity (the clamped value) so GhosttyConfig remains normalized and
invalid opacity values are not propagated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ghostty`:
- Line 1: The ghostty submodule pointer in the superproject is out of sync:
superproject expects commit 51ba49a4bb74c2f3030b8a2878f4162d2624d4ca but the
submodule is at fcdeac56e3c466fb3fc77e6686c93c1fd3f02b8a; update the ghostty
submodule to the expected commit by checking out or merging the correct commit
in the ghostty repo, push that commit to the manaflow-ai/ghostty fork's main
branch, then in the superproject run git -C ghostty fetch && git -C ghostty
merge origin/main (or checkout the specific commit) and verify with git -C
ghostty merge-base --is-ancestor HEAD origin/main so the submodule HEAD matches
the superproject pointer before merging.

In `@Sources/AppDelegate.swift`:
- Around line 1743-1748: The call to
cmuxApplyPendingGhosttyStartSearchFallbackIfNeeded is being deferred with
DispatchQueue.main.async which creates a timing gap where the function can
return true while searchState is still nil; remove the async deferral and invoke
cmuxApplyPendingGhosttyStartSearchFallbackIfNeeded(terminalSurface,
searchFocusNotifier: searchFocusNotifier) synchronously on the current execution
context (or, if it must run on the main thread, perform a main-thread safe
synchronous invocation—i.e. call directly when already on main, otherwise
dispatch synchronously to DispatchQueue.main) so that searchState is initialized
deterministically before any immediate search-active checks or overlay
activation logic runs.

---

Nitpick comments:
In `@docs/ghostty-fork.md`:
- Line 97: The HEAD note currently says "section 6 theme-picker hardening
commit," which couples the note to a mutable section number; update that line to
reference the commit hash (and optionally the section title) instead of the
section number so it remains stable — replace "section 6 theme-picker hardening
commit" with the commit SHA (e.g., <commit-hash>) or "theme-picker hardening
commit (<commit-hash>)" in the HEAD note.

In `@Sources/ContentView.swift`:
- Around line 329-347: The function cmuxResolveGhosttyChromeConfig computes a
clamped runtimeOpacity but then writes the raw runtimeBackgroundOpacity into
resolved.backgroundOpacity; change the assignment in
cmuxResolveGhosttyChromeConfig to set resolved.backgroundOpacity =
runtimeOpacity (the clamped value) so GhosttyConfig remains normalized and
invalid opacity values are not propagated.

In `@Sources/WorkspaceContentView.swift`:
- Around line 209-218: The code calls defaultBackgroundOpacity() twice causing
nondeterministic values; fix by calling defaultBackgroundOpacity() once at the
start of the pass (store it in a local let, e.g. let runtimeOpacityValue =
defaultBackgroundOpacity()), pass that variable into
cmuxResolveGhosttyChromeConfig (as runtimeBackgroundOpacity) and use the same
runtimeOpacityValue when assigning runtimeOpacity, keeping runtimeBackground and
runtimeBackgroundHex logic unchanged and removing the duplicate
defaultBackgroundOpacity() call.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 27761b8b-8e50-4fa3-b4aa-7ce1bbddd310

📥 Commits

Reviewing files that changed from the base of the PR and between 70c6fa2 and fcdeac5.

📒 Files selected for processing (13)
  • Sources/AppDelegate.swift
  • Sources/ContentView.swift
  • Sources/GhosttyConfig.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/Panels/BrowserPanel.swift
  • Sources/TabManager.swift
  • Sources/Workspace.swift
  • Sources/WorkspaceContentView.swift
  • cmuxTests/GhosttyConfigTests.swift
  • cmuxTests/TerminalAndGhosttyTests.swift
  • docs/ghostty-fork.md
  • ghostty
  • scripts/ghosttykit-checksums.txt
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/ghosttykit-checksums.txt

@@ -1 +1 @@
Subproject commit bc9be90a21997a4e5f06bf15ae2ec0f937c2dc42
Subproject commit 51ba49a4bb74c2f3030b8a2878f4162d2624d4ca
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Read the submodule SHA recorded by the superproject
expected_sha="$(git ls-tree HEAD ghostty | awk '{print $3}')"
echo "Superproject pointer (ghostty): ${expected_sha}"

# 2) Ensure submodule checkout exists and matches the pointer
if [ ! -d ghostty ]; then
  echo "ghostty submodule directory not present. Initialize submodules first."
  exit 1
fi

actual_sha="$(git -C ghostty rev-parse HEAD)"
echo "Checked-out ghostty HEAD: ${actual_sha}"

if [ "${expected_sha}" != "${actual_sha}" ]; then
  echo "Mismatch: checked-out submodule HEAD does not match superproject pointer."
  exit 1
fi

# 3) Verify the commit is on remote main
git -C ghostty fetch origin main --quiet
if git -C ghostty merge-base --is-ancestor HEAD origin/main; then
  echo "OK: submodule commit is reachable from origin/main."
else
  echo "FAIL: submodule commit is NOT reachable from origin/main."
  exit 1
fi

Repository: manaflow-ai/cmux

Length of output: 273


Submodule pointer mismatch: superproject and ghostty checkout are out of sync.

The superproject points to commit 51ba49a4bb74c2f3030b8a2878f4162d2624d4ca, but the current ghostty submodule checkout is at fcdeac56e3c466fb3fc77e6686c93c1fd3f02b8a. This inconsistency must be resolved before merging. Ensure the ghostty submodule is updated to match the pointer, that the commit is pushed to the manaflow-ai/ghostty fork's main branch, and verify with git -C ghostty merge-base --is-ancestor HEAD origin/main.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghostty` at line 1, The ghostty submodule pointer in the superproject is out
of sync: superproject expects commit 51ba49a4bb74c2f3030b8a2878f4162d2624d4ca
but the submodule is at fcdeac56e3c466fb3fc77e6686c93c1fd3f02b8a; update the
ghostty submodule to the expected commit by checking out or merging the correct
commit in the ghostty repo, push that commit to the manaflow-ai/ghostty fork's
main branch, then in the superproject run git -C ghostty fetch && git -C ghostty
merge origin/main (or checkout the specific commit) and verify with git -C
ghostty merge-base --is-ancestor HEAD origin/main so the submodule HEAD matches
the superproject pointer before merging.

Comment on lines +1743 to 1748
DispatchQueue.main.async {
cmuxApplyPendingGhosttyStartSearchFallbackIfNeeded(
terminalSurface,
searchFocusNotifier: searchFocusNotifier
)
}
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

Avoid run-loop deferral for search fallback state initialization.

At Line 1743, forcing cmuxApplyPendingGhosttyStartSearchFallbackIfNeeded(...) onto DispatchQueue.main.async creates a timing gap where this function returns true while searchState can still be nil. That can desync immediate search-active checks and overlay activation paths.

Suggested fix
-    if terminalSurface.performBindingAction("start_search") {
-        DispatchQueue.main.async {
-            cmuxApplyPendingGhosttyStartSearchFallbackIfNeeded(
-                terminalSurface,
-                searchFocusNotifier: searchFocusNotifier
-            )
-        }
+    if terminalSurface.performBindingAction("start_search") {
+        if Thread.isMainThread {
+            cmuxApplyPendingGhosttyStartSearchFallbackIfNeeded(
+                terminalSurface,
+                searchFocusNotifier: searchFocusNotifier
+            )
+        } else {
+            DispatchQueue.main.async {
+                cmuxApplyPendingGhosttyStartSearchFallbackIfNeeded(
+                    terminalSurface,
+                    searchFocusNotifier: searchFocusNotifier
+                )
+            }
+        }
         return true
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/AppDelegate.swift` around lines 1743 - 1748, The call to
cmuxApplyPendingGhosttyStartSearchFallbackIfNeeded is being deferred with
DispatchQueue.main.async which creates a timing gap where the function can
return true while searchState is still nil; remove the async deferral and invoke
cmuxApplyPendingGhosttyStartSearchFallbackIfNeeded(terminalSurface,
searchFocusNotifier: searchFocusNotifier) synchronously on the current execution
context (or, if it must run on the main thread, perform a main-thread safe
synchronous invocation—i.e. call directly when already on main, otherwise
dispatch synchronously to DispatchQueue.main) so that searchState is initialized
deterministically before any immediate search-active checks or overlay
activation logic runs.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

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="cmuxUITests/AutomationSocketUITests.swift">

<violation number="1" location="cmuxUITests/AutomationSocketUITests.swift:194">
P2: Avoid unconditional netcat retry here: it can resend commands that were already written and duplicate stateful operations (e.g., `surface.send_key`).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d937c39bc8

ℹ️ 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".

Comment on lines +40 to +41
if Double(normalized) != nil {
return .enabled
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Parse zero-valued blur radii as disabled

BackgroundBlur.parse currently maps any numeric string to .enabled, so zero-form values like 00 or 0.0 are treated as blur-on instead of blur-off. This makes cmux’s parsed config diverge from Ghostty semantics for zero blur intensity and can trigger incorrect chrome/theme decisions (for example, blur-change refreshes and style checks) when config writers emit normalized numeric zero values.

Useful? React with 👍 / 👎.

Comment on lines +1007 to +1009
panel.surface.requestGhosttySearchActivation(.searchSelection)
if !panel.performBindingAction("search_selection") {
panel.surface.clearGhosttySearchActivationRequest()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clear stale pending state when search_selection callback is missing

searchSelection() sets pendingGhosttySearchActivation(.searchSelection) but only clears it when performBindingAction returns false; unlike the new start_search path, there is no fallback/cleanup when Ghostty acknowledges the binding but never emits GHOSTTY_ACTION_START_SEARCH. In that callback-loss case, Find Selection silently does nothing and the stale pending request can later cause unrelated start-search callbacks to be resolved with the wrong request type.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 605fe5c019

ℹ️ 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".

Comment on lines +1007 to 1010
panel.surface.requestGhosttySearchActivation(.searchSelection)
if !panel.performBindingAction("search_selection") {
panel.surface.clearGhosttySearchActivationRequest()
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add fallback when search_selection binding is unavailable

searchSelection() now only sets a pending request and calls performBindingAction("search_selection"); when that call returns false, it just clears pending state and exits. This regresses the previous fallback behavior where Find Selection still opened/focused the search UI, so on builds/configs where search_selection is not exposed (or temporarily fails), the command becomes a silent no-op for users.

Useful? React with 👍 / 👎.

Comment on lines +2199 to +2201
let pendingRequest = terminalSurface.consumeGhosttySearchActivationRequest()
let shouldDecodeNeedle =
terminalSurface.searchState != nil || pendingRequest != .startSearch
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Move pending search state consumption onto main thread

consumeGhosttySearchActivationRequest() is called before hopping to DispatchQueue.main, but the same pending field is written from main-thread UI paths (request.../clear...). Because this callback path is not guaranteed to be on main (the handler explicitly uses main hopping elsewhere), this introduces an unsynchronized cross-thread read/write race that can intermittently drop or misclassify pending search requests.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

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="cmuxUITests/AutomationSocketUITests.swift">

<violation number="1" location="cmuxUITests/AutomationSocketUITests.swift:38">
P2: Replace the fixed `RunLoop` sleep after `terminate()` with a deterministic wait on app state to reduce UI test flakiness.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


let cleanup = XCUIApplication()
cleanup.terminate()
RunLoop.current.run(until: Date().addingTimeInterval(0.5))
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 21, 2026

Choose a reason for hiding this comment

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

P2: Replace the fixed RunLoop sleep after terminate() with a deterministic wait on app state to reduce UI test flakiness.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At cmuxUITests/AutomationSocketUITests.swift, line 38:

<comment>Replace the fixed `RunLoop` sleep after `terminate()` with a deterministic wait on app state to reduce UI test flakiness.</comment>

<file context>
@@ -32,11 +32,15 @@ final class AutomationSocketUITests: XCTestCase {
+
+        let cleanup = XCUIApplication()
+        cleanup.terminate()
+        RunLoop.current.run(until: Date().addingTimeInterval(0.5))
     }
 
</file context>
Suggested change
RunLoop.current.run(until: Date().addingTimeInterval(0.5))
_ = cleanup.wait(for: .notRunning, timeout: 5.0)
Fix with Cubic

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

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="cmuxUITests/AutomationSocketUITests.swift">

<violation number="1" location="cmuxUITests/AutomationSocketUITests.swift:665">
P2: The new socket read loop returns at the first newline, which truncates multi-line command responses and breaks parsing of surface/workspace lists.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment on lines +665 to +668
accumulator.append(chunk)
if let newline = accumulator.firstIndex(of: "\n") {
return String(accumulator[..<newline])
}
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 21, 2026

Choose a reason for hiding this comment

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

P2: The new socket read loop returns at the first newline, which truncates multi-line command responses and breaks parsing of surface/workspace lists.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At cmuxUITests/AutomationSocketUITests.swift, line 665:

<comment>The new socket read loop returns at the first newline, which truncates multi-line command responses and breaks parsing of surface/workspace lists.</comment>

<file context>
@@ -568,39 +568,108 @@ final class AutomationSocketUITests: XCTestCase {
+                }
+                if count <= 0 { break }
+                if let chunk = String(bytes: buffer[0..<count], encoding: .utf8) {
+                    accumulator.append(chunk)
+                    if let newline = accumulator.firstIndex(of: "\n") {
+                        return String(accumulator[..<newline])
</file context>
Suggested change
accumulator.append(chunk)
if let newline = accumulator.firstIndex(of: "\n") {
return String(accumulator[..<newline])
}
accumulator.append(chunk)
Fix with Cubic

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

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="cmuxUITests/AutomationSocketUITests.swift">

<violation number="1" location="cmuxUITests/AutomationSocketUITests.swift:211">
P2: `waitForSocketReadyDiagnostics` returns diagnostics even when readiness times out, so callers can proceed without `socketReady == "1"`. Return `nil` on timeout so the guard correctly fails.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

}
return diagnostics["socketReady"] == "1"
}
return isReady ? lastDiagnostics : loadDiagnostics()
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 21, 2026

Choose a reason for hiding this comment

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

P2: waitForSocketReadyDiagnostics returns diagnostics even when readiness times out, so callers can proceed without socketReady == "1". Return nil on timeout so the guard correctly fails.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At cmuxUITests/AutomationSocketUITests.swift, line 211:

<comment>`waitForSocketReadyDiagnostics` returns diagnostics even when readiness times out, so callers can proceed without `socketReady == "1"`. Return `nil` on timeout so the guard correctly fails.</comment>

<file context>
@@ -178,16 +186,29 @@ final class AutomationSocketUITests: XCTestCase {
+            }
+            return diagnostics["socketReady"] == "1"
+        }
+        return isReady ? lastDiagnostics : loadDiagnostics()
     }
 
</file context>
Suggested change
return isReady ? lastDiagnostics : loadDiagnostics()
return isReady ? lastDiagnostics : nil
Fix with Cubic

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 06da3d91cf

ℹ️ 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".

Comment on lines +273 to +277
private func socketCommand(_ command: String, responseTimeout: TimeInterval = 2.0) -> String? {
if let response = ControlSocketClient(path: socketPath, responseTimeout: responseTimeout).sendLine(command) {
return response
}
return socketCommandViaNetcat(command, responseTimeout: responseTimeout)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid retrying by re-sending mutating socket commands

socketCommand falls back to socketCommandViaNetcat whenever ControlSocketClient.sendLine returns nil, but sendLine can return nil after it has already connected and written the command (for example, on read timeout). In that case, mutating commands such as new_workspace or send_key_surface are executed twice, which can create duplicate side effects and make this UI test flaky under slow CI timing. The fallback should only be used for pre-send failures (or retries should be made idempotent).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2bb008d3a1

ℹ️ 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".

Comment on lines +2906 to +2908
if let surfaceId = tabManager.focusedPanelId(for: workspaceId) {
return (workspaceId: workspaceId, surfaceId: surfaceId)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pick terminal panel before running socket send-key stress

resolvedAutomationSocketStressTarget returns tabManager.focusedPanelId immediately, but that ID can belong to a browser panel. The stress loop then calls send_key_surface <id> enter and expects OK, so any workspace focused on a non-terminal panel will deterministically fail this new UI-test harness even though terminal surfaces are available (the terminal-only fallbacks below are never reached once this early return runs). Restrict this first branch to focused terminal panels (or validate the ID is terminal) before using it as the send-key target.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

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="Sources/AppDelegate.swift">

<violation number="1" location="Sources/AppDelegate.swift:2906">
P2: Use a terminal panel ID when selecting the stress-test target; `focusedPanelId` can point to non-terminal panels and breaks `send_key_surface`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

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="Sources/AppDelegate.swift">

<violation number="1" location="Sources/AppDelegate.swift:2823">
P2: Moving the stress loop to a global queue introduces unsynchronized concurrent writes to the shared UI-test diagnostics file, which can drop `automationSocketStress*` fields and make stress-test completion/status flaky.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


let workspaceId = target.workspaceId.uuidString
let surfaceId = target.surfaceId.uuidString
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 21, 2026

Choose a reason for hiding this comment

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

P2: Moving the stress loop to a global queue introduces unsynchronized concurrent writes to the shared UI-test diagnostics file, which can drop automationSocketStress* fields and make stress-test completion/status flaky.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/AppDelegate.swift, line 2823:

<comment>Moving the stress loop to a global queue introduces unsynchronized concurrent writes to the shared UI-test diagnostics file, which can drop `automationSocketStress*` fields and make stress-test completion/status flaky.</comment>

<file context>
@@ -2820,51 +2820,13 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
-
-            trace.append(
-                "iteration\(iteration)=pingBefore:\(pingBefore ?? "<nil>"),send:\(sendResponse ?? "<nil>"),pingAfter:\(pingAfter ?? "<nil>"),list:\(listResponse ?? "<nil>")"
+        DispatchQueue.global(qos: .userInitiated).async { [weak self] in
+            self?.performAutomationSocketStressLoop(
+                socketPath: socketPath,
</file context>
Fix with Cubic

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ed9da3e24b

ℹ️ 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".

Comment on lines +2807 to +2811
let workspaceListResponse = TerminalController.probeSocketCommand(
"list_workspaces",
at: socketPath,
timeout: 1.0
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Run stress preflight socket probes off the main thread

runAutomationSocketStressUITestAttempt is scheduled on DispatchQueue.main, but it then synchronously probes list_workspaces/list_surfaces over the control socket. Those handlers resolve data via DispatchQueue.main.sync in TerminalController, so this path can block the handler waiting on main while main is blocked waiting for the socket reply (until timeout), causing the new stress harness to stay in waiting/failed despite a healthy listener. Execute these preflight probes from a background queue (or avoid commands that require main-sync) before parsing IDs.

Useful? React with 👍 / 👎.

Comment on lines +2470 to +2473
var payload = loadUITestDiagnostics(at: path)
for (key, value) in updates {
payload[key] = value
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Serialize diagnostics file updates across threads

updateUITestDiagnosticsIfNeeded performs a read-modify-write on the diagnostics JSON without synchronization, and this helper is invoked from the background stress loop while other diagnostics writers on main also rewrite the same file. These concurrent writes can overwrite each other and drop fields like automationSocketStressDone or trace data, making the UI test completion wait flaky. Use a single serial queue/lock for all diagnostics file writes.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant