Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6dd0e68
Fix sidebar drag terminal resize lag
lawrencecchen Mar 17, 2026
dc46e4e
Add display resolution churn regression
lawrencecchen Mar 17, 2026
2c2e156
Prelaunch display churn helper in e2e workflow
lawrencecchen Mar 17, 2026
092026e
Use manifest handoff for display churn UI test
lawrencecchen Mar 17, 2026
612408a
Fix e2e display churn harness startup
lawrencecchen Mar 17, 2026
216a4c5
Resolve display churn UI test socket path
lawrencecchen Mar 17, 2026
49c4aed
Use marker-based socket discovery in display UI test
lawrencecchen Mar 17, 2026
968292e
Add failing sidebar drag portal regression tests
lawrencecchen Mar 17, 2026
5d06d70
Fix sidebar drag terminal portal resize lag
lawrencecchen Mar 17, 2026
6051c3d
Add failing scoped resize regression tests
lawrencecchen Mar 17, 2026
876b6dd
Fix terminal portal resize scheduling lag
lawrencecchen Mar 17, 2026
26d1a16
Add failing zsh resize prompt regression test
lawrencecchen Mar 17, 2026
2cf087e
Fix zsh resize prompt duplication
lawrencecchen Mar 17, 2026
8dc2f32
Fix Sequoia sidebar resize regression
lawrencecchen Mar 18, 2026
b364416
Guard display-resolution CI runner
lawrencecchen Mar 18, 2026
ef1e598
Run display-resolution CI on WarpBuild
lawrencecchen Mar 18, 2026
62eda8d
Allow backgrounded display regression app launch
lawrencecchen Mar 18, 2026
c0c62cc
Launch display regression app directly
lawrencecchen Mar 18, 2026
95c0b2c
Launch display regression app via NSWorkspace
lawrencecchen Mar 18, 2026
255edf3
Load display regression launch env from manifest
lawrencecchen Mar 18, 2026
f1a6d0e
Write display regression manifest in runner temp dir
lawrencecchen Mar 18, 2026
1819091
Write display regression manifest in shared tmp
lawrencecchen Mar 18, 2026
0af68b2
Write display regression manifest in repo scratch dir
lawrencecchen Mar 18, 2026
98588e0
Launch display regression app with explicit env
lawrencecchen Mar 18, 2026
a8734cd
Avoid xcodebuild broken pipe in compat CI
lawrencecchen Mar 18, 2026
9f27e50
Launch display regression via XCUIApplication
lawrencecchen Mar 18, 2026
35af973
Harden display regression socket readiness
lawrencecchen Mar 18, 2026
08b5cf3
Trust display socket diagnostics path
lawrencecchen Mar 18, 2026
d2db98b
Replace display socket probe with render diagnostics
lawrencecchen Mar 18, 2026
f25628c
Write display churn start marker atomically
lawrencecchen Mar 18, 2026
cf9d03f
Move display churn harness out of /tmp
lawrencecchen Mar 18, 2026
895124f
Merge origin/main into task-cyber-resize-lag
lawrencecchen Mar 18, 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
5 changes: 3 additions & 2 deletions .github/workflows/ci-macos-compat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ jobs:
echo "Selected: $XCODE_APP"
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
XCODE_VER="$(xcodebuild -version | head -1)"
XCODE_VERSION_OUTPUT="$(xcodebuild -version)"
XCODE_VER="${XCODE_VERSION_OUTPUT%%$'\n'*}"
echo "XCODE_VER=$XCODE_VER" >> "$GITHUB_ENV"
echo "$XCODE_VER"
echo "$XCODE_VERSION_OUTPUT"
xcrun --sdk macosx --show-sdk-path
sw_vers

Expand Down
134 changes: 134 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,137 @@ jobs:
CMUX_LAG_MAX_CHURN_P95_MS=35 \
CMUX_LAG_KEY_EVENTS=180 \
python3 tests/test_workspace_churn_up_arrow_lag.py

ui-display-resolution-regression:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
runs-on: warp-macos-15-arm64-6x
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: recursive

- name: Select Xcode
run: |
set -euo pipefail
if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then
XCODE_DIR="/Applications/Xcode.app/Contents/Developer"
else
XCODE_APP="$(ls -d /Applications/Xcode*.app 2>/dev/null | sort | tail -n 1 || true)"
if [ -n "$XCODE_APP" ]; then
XCODE_DIR="$XCODE_APP/Contents/Developer"
else
echo "No Xcode.app found under /Applications" >&2
exit 1
fi
fi
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
xcodebuild -version
xcrun --sdk macosx --show-sdk-path

- name: Download pre-built GhosttyKit.xcframework
run: ./scripts/download-prebuilt-ghosttykit.sh

- name: Install zig
run: |
ZIG_REQUIRED="0.15.2"
if command -v zig >/dev/null 2>&1 && zig version 2>/dev/null | grep -q "^${ZIG_REQUIRED}"; then

@cubic-dev-ai cubic-dev-ai Bot Mar 17, 2026 •

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: Use an exact Zig version comparison; the current regex prefix check can incorrectly accept non-required versions.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci.yml, line 424:

<comment>Use an exact Zig version comparison; the current regex prefix check can incorrectly accept non-required versions.</comment>

<file context>
@@ -385,3 +385,128 @@ jobs:
+      - name: Install zig
+        run: |
+          ZIG_REQUIRED="0.15.2"
+          if command -v zig >/dev/null 2>&1 && zig version 2>/dev/null | grep -q "^${ZIG_REQUIRED}"; then
+            echo "zig ${ZIG_REQUIRED} already installed"
+          else
</file context>
Suggested change
if command -v zig >/dev/null 2>&1 && zig version 2>/dev/null | grep -q "^${ZIG_REQUIRED}"; then
if command -v zig >/dev/null 2>&1 && [ "$(zig version 2>/dev/null)" = "${ZIG_REQUIRED}" ]; then
Fix with Cubic

echo "zig ${ZIG_REQUIRED} already installed"
else
echo "Installing zig ${ZIG_REQUIRED} from tarball"
curl -fSL "https://ziglang.org/download/${ZIG_REQUIRED}/zig-aarch64-macos-${ZIG_REQUIRED}.tar.xz" -o /tmp/zig.tar.xz
tar xf /tmp/zig.tar.xz -C /tmp
sudo mkdir -p /usr/local/bin /usr/local/lib
sudo cp -f /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/zig /usr/local/bin/zig
sudo cp -rf /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/lib /usr/local/lib/zig

@cubic-dev-ai cubic-dev-ai Bot Mar 17, 2026 •

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: Replace the Zig lib directory before copying; otherwise an existing install can produce nested /usr/local/lib/zig/lib and a broken Zig runtime layout.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci.yml, line 432:

<comment>Replace the Zig lib directory before copying; otherwise an existing install can produce nested `/usr/local/lib/zig/lib` and a broken Zig runtime layout.</comment>

<file context>
@@ -385,3 +385,128 @@ jobs:
+            tar xf /tmp/zig.tar.xz -C /tmp
+            sudo mkdir -p /usr/local/bin /usr/local/lib
+            sudo cp -f /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/zig /usr/local/bin/zig
+            sudo cp -rf /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/lib /usr/local/lib/zig
+            export PATH="/usr/local/bin:$PATH"
+            zig version
</file context>
Suggested change
sudo cp -rf /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/lib /usr/local/lib/zig
sudo rm -rf /usr/local/lib/zig
sudo cp -rf /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/lib /usr/local/lib/zig
Fix with Cubic

export PATH="/usr/local/bin:$PATH"
zig version
fi

- name: Cache Swift packages
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: .ci-source-packages
key: spm-ui-display-resolution-${{ hashFiles('GhosttyTabs.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}
restore-keys: spm-ui-display-resolution-

- name: Resolve Swift packages
run: |
set -euo pipefail
SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages"
mkdir -p "$SOURCE_PACKAGES_DIR"

for attempt in 1 2 3; do
if xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
-resolvePackageDependencies; then
exit 0
fi
if [ "$attempt" -eq 3 ]; then
echo "Failed to resolve Swift packages after 3 attempts" >&2
exit 1
fi
echo "Package resolution failed on attempt $attempt, retrying..."
sleep $((attempt * 5))
done

- name: Run display resolution churn UI regression
run: |
set -euo pipefail
SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages"
HARNESS_DIR="${RUNNER_TEMP}/cmux-display-churn-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
mkdir -p "$HARNESS_DIR"
PREFIX="${HARNESS_DIR}/cmux-display-churn"
READY_PATH="${PREFIX}.ready"
DISPLAY_ID_PATH="${PREFIX}.id"
START_PATH="${PREFIX}.start"
DONE_PATH="${PREFIX}.done"
LOG_PATH="${PREFIX}.log"
MANIFEST_PATH="${HARNESS_DIR}/cmux-ui-test-display-harness.json"

rm -f "$READY_PATH" "$DISPLAY_ID_PATH" "$START_PATH" "$DONE_PATH" "$LOG_PATH" "$MANIFEST_PATH"

clang -framework Foundation -framework CoreGraphics \
-o /tmp/create-virtual-display scripts/create-virtual-display.m

/tmp/create-virtual-display \
--modes 1920x1080,1728x1117,1600x900,1440x810 \
--ready-path "$READY_PATH" \
--display-id-path "$DISPLAY_ID_PATH" \
--start-path "$START_PATH" \
--done-path "$DONE_PATH" \
--iterations 40 \
--interval-ms 40 \
>"$LOG_PATH" 2>&1 &
VDISPLAY_PID=$!
trap 'kill "$VDISPLAY_PID" >/dev/null 2>&1 || true; rm -f "$MANIFEST_PATH"' EXIT

for _ in {1..120}; do
[ -f "$READY_PATH" ] && break
sleep 0.25
done
[ -f "$READY_PATH" ] || {
echo "Display harness failed to start" >&2
cat "$LOG_PATH" >&2 || true
exit 1
}

cat >"$MANIFEST_PATH" <<EOF
{"readyPath":"$READY_PATH","displayIDPath":"$DISPLAY_ID_PATH","startPath":"$START_PATH","donePath":"$DONE_PATH","logPath":"$LOG_PATH"}
EOF
echo "Display harness manifest: $MANIFEST_PATH"
cat "$MANIFEST_PATH"

CMUX_UI_TEST_DISPLAY_READY_PATH="$READY_PATH" \
CMUX_UI_TEST_DISPLAY_ID_PATH="$DISPLAY_ID_PATH" \
CMUX_UI_TEST_DISPLAY_START_PATH="$START_PATH" \
CMUX_UI_TEST_DISPLAY_DONE_PATH="$DONE_PATH" \
CMUX_UI_TEST_DISPLAY_LOG_PATH="$LOG_PATH" \
xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
-disableAutomaticPackageResolution \
-destination "platform=macOS" \
-only-testing:cmuxUITests/DisplayResolutionRegressionUITests \
test
61 changes: 59 additions & 2 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ jobs:
fi

- name: Create virtual display
if: ${{ inputs.test_filter != 'DisplayResolutionRegressionUITests' }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
run: |
set -euo pipefail
echo "=== Display before ==="
Expand Down Expand Up @@ -204,8 +205,64 @@ jobs:
set -euo pipefail
SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages"
ONLY_TESTING="-only-testing:cmuxUITests/$TEST_FILTER"
DISPLAY_ENV_PREFIX=()

if [ "$TEST_FILTER" = "DisplayResolutionRegressionUITests" ]; then
HARNESS_DIR="${RUNNER_TEMP}/cmux-display-churn-${{ github.run_id }}-${{ github.run_attempt }}"
mkdir -p "$HARNESS_DIR"
PREFIX="${HARNESS_DIR}/cmux-display-churn"
READY_PATH="${PREFIX}.ready"
DISPLAY_ID_PATH="${PREFIX}.id"
START_PATH="${PREFIX}.start"
DONE_PATH="${PREFIX}.done"
LOG_PATH="${PREFIX}.log"
MANIFEST_PATH="${HARNESS_DIR}/cmux-ui-test-display-harness.json"

rm -f "$READY_PATH" "$DISPLAY_ID_PATH" "$START_PATH" "$DONE_PATH" "$LOG_PATH" "$MANIFEST_PATH"

clang -framework Foundation -framework CoreGraphics \
-o /tmp/create-virtual-display scripts/create-virtual-display.m

/tmp/create-virtual-display \
--modes 1920x1080,1728x1117,1600x900,1440x810 \
--ready-path "$READY_PATH" \
--display-id-path "$DISPLAY_ID_PATH" \
--start-path "$START_PATH" \
--done-path "$DONE_PATH" \
--iterations 40 \
--interval-ms 40 \
>"$LOG_PATH" 2>&1 &
DISPLAY_VDISPLAY_PID=$!
trap 'kill "${DISPLAY_VDISPLAY_PID:-}" >/dev/null 2>&1 || true; rm -f "$MANIFEST_PATH"' EXIT

for _ in {1..120}; do
[ -f "$READY_PATH" ] && break
sleep 0.25
done
[ -f "$READY_PATH" ] || {
echo "Display harness failed to start" >&2
cat "$LOG_PATH" >&2 || true
exit 1
}

cat >"$MANIFEST_PATH" <<EOF
{"readyPath":"$READY_PATH","displayIDPath":"$DISPLAY_ID_PATH","startPath":"$START_PATH","donePath":"$DONE_PATH","logPath":"$LOG_PATH"}
EOF
echo "Display harness manifest: $MANIFEST_PATH"
cat "$MANIFEST_PATH"

DISPLAY_ENV_PREFIX=(
CMUX_UI_TEST_DISPLAY_READY_PATH="$READY_PATH"
CMUX_UI_TEST_DISPLAY_ID_PATH="$DISPLAY_ID_PATH"
CMUX_UI_TEST_DISPLAY_START_PATH="$START_PATH"
CMUX_UI_TEST_DISPLAY_DONE_PATH="$DONE_PATH"
CMUX_UI_TEST_DISPLAY_LOG_PATH="$LOG_PATH"
)
fi

Comment thread
coderabbitai[bot] marked this conversation as resolved.
# Start recording right before the test (after build/resolve)
# Start recording right before the test (after build/resolve).
# The display churn regression creates its own virtual display above,
# so recording must start after that harness is ready.
if [ "$RECORD_VIDEO" = "true" ]; then
DEVLIST=$( ffmpeg -f avfoundation -list_devices true -i "" 2>&1 || true )
echo "Available devices:"
Expand Down Expand Up @@ -233,7 +290,7 @@ jobs:
fi

set +e
OUTPUT=$(xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug \
OUTPUT=$(env "${DISPLAY_ENV_PREFIX[@]}" xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
-disableAutomaticPackageResolution \
-destination "platform=macOS" \
Expand Down
4 changes: 4 additions & 0 deletions GhosttyTabs.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
B9000012A1B2C3D4E5F60719 /* AutomationSocketUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9000011A1B2C3D4E5F60719 /* AutomationSocketUITests.swift */; };
B8F266236A1A3D9A45BD840F /* SidebarResizeUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818DBCD4AB69EB72573E8138 /* SidebarResizeUITests.swift */; };
B8F266246A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F266256A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift */; };
B8F266266A1A3D9A45BD840F /* DisplayResolutionRegressionUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F266276A1A3D9A45BD840F /* DisplayResolutionRegressionUITests.swift */; };
C0B4D9B0A1B2C3D4E5F60718 /* UpdatePillUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B4D9B1A1B2C3D4E5F60718 /* UpdatePillUITests.swift */; };
B9000014A1B2C3D4E5F60719 /* JumpToUnreadUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9000013A1B2C3D4E5F60719 /* JumpToUnreadUITests.swift */; };
B9000015A1B2C3D4E5F60719 /* MultiWindowNotificationsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9000016A1B2C3D4E5F60719 /* MultiWindowNotificationsUITests.swift */; };
Expand Down Expand Up @@ -231,6 +232,7 @@
A5001611 /* SessionPersistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionPersistence.swift; sourceTree = "<group>"; };
818DBCD4AB69EB72573E8138 /* SidebarResizeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarResizeUITests.swift; sourceTree = "<group>"; };
B8F266256A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarHelpMenuUITests.swift; sourceTree = "<group>"; };
B8F266276A1A3D9A45BD840F /* DisplayResolutionRegressionUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayResolutionRegressionUITests.swift; sourceTree = "<group>"; };
C0B4D9B1A1B2C3D4E5F60718 /* UpdatePillUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdatePillUITests.swift; sourceTree = "<group>"; };
A5001101 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
IC000002 /* AppIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder; path = AppIcon.icon; sourceTree = "<group>"; };
Expand Down Expand Up @@ -491,6 +493,7 @@
B9000016A1B2C3D4E5F60719 /* MultiWindowNotificationsUITests.swift */,
818DBCD4AB69EB72573E8138 /* SidebarResizeUITests.swift */,
B8F266256A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift */,
B8F266276A1A3D9A45BD840F /* DisplayResolutionRegressionUITests.swift */,
D0E0F0B1A1B2C3D4E5F60718 /* BrowserPaneNavigationKeybindUITests.swift */,
D0E0F0B3A1B2C3D4E5F60718 /* BrowserOmnibarSuggestionsUITests.swift */,
FB100001A1B2C3D4E5F60718 /* BrowserImportProfilesUITests.swift */,
Expand Down Expand Up @@ -749,6 +752,7 @@
B9000015A1B2C3D4E5F60719 /* MultiWindowNotificationsUITests.swift in Sources */,
B8F266236A1A3D9A45BD840F /* SidebarResizeUITests.swift in Sources */,
B8F266246A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift in Sources */,
B8F266266A1A3D9A45BD840F /* DisplayResolutionRegressionUITests.swift in Sources */,
D0E0F0B0A1B2C3D4E5F60718 /* BrowserPaneNavigationKeybindUITests.swift in Sources */,
D0E0F0B2A1B2C3D4E5F60718 /* BrowserOmnibarSuggestionsUITests.swift in Sources */,
FB100000A1B2C3D4E5F60718 /* BrowserImportProfilesUITests.swift in Sources */,
Expand Down
5 changes: 2 additions & 3 deletions Resources/shell-integration/cmux-zsh-integration.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,8 @@ _cmux_install_winch_guard() {
[[ -n "$CMUX_TAB_ID" ]] || return 0
[[ -n "$CMUX_PANEL_ID" ]] || return 0

# Keep a spacer line so prompt redraw during resize cannot clobber the
# tail of command output that was rendered immediately above the prompt.
builtin print -r -- ""
# Ghostty already marks prompt redraws on SIGWINCH. Writing to the PTY
# here grows the screen and makes resize look like a fresh prompt.
return 0
}

Expand Down
Loading
Loading