Skip to content

Commit 61e25a5

Browse files
committed
Merge remote-tracking branch 'origin/main' into issue-1983-newTabInsertIndex-crash
2 parents b431b66 + 7ffa447 commit 61e25a5

33 files changed

Lines changed: 804 additions & 148 deletions

.github/workflows/ci.yml

Lines changed: 187 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -478,38 +478,206 @@ jobs:
478478
sleep $((attempt * 5))
479479
done
480480
481-
- name: Run display resolution churn UI regression
481+
- name: Build for testing (display resolution)
482482
run: |
483483
set -euo pipefail
484484
SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages"
485+
xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug \
486+
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
487+
-disableAutomaticPackageResolution \
488+
-destination "platform=macOS" \
489+
build-for-testing
490+
491+
- name: Create persistent virtual display
492+
run: |
493+
set -euo pipefail
485494
HELPER_PATH="/tmp/create-virtual-display"
486-
MANIFEST_PATH="/tmp/cmux-ui-test-display-harness.json"
495+
clang -framework Foundation -framework CoreGraphics \
496+
-o "$HELPER_PATH" scripts/create-virtual-display.m
487497
488-
rm -f "$MANIFEST_PATH"
489-
trap 'rm -f "$MANIFEST_PATH"' EXIT
498+
VDISPLAY_READY="/tmp/cmux-vdisplay-persistent.ready"
499+
VDISPLAY_ID_PATH="/tmp/cmux-vdisplay-persistent.id"
500+
rm -f "$VDISPLAY_READY" "$VDISPLAY_ID_PATH"
501+
502+
"$HELPER_PATH" \
503+
--modes "1920x1080" \
504+
--ready-path "$VDISPLAY_READY" \
505+
--display-id-path "$VDISPLAY_ID_PATH" \
506+
> /tmp/cmux-vdisplay-persistent.log 2>&1 &
507+
echo "VDISPLAY_PERSISTENT_PID=$!" >> "$GITHUB_ENV"
508+
509+
echo "Waiting for persistent virtual display..."
510+
for i in $(seq 1 24); do
511+
if [ -f "$VDISPLAY_READY" ]; then break; fi
512+
sleep 0.5
513+
done
514+
if [ ! -f "$VDISPLAY_READY" ]; then
515+
echo "ERROR: Persistent virtual display not ready after 12s" >&2
516+
cat /tmp/cmux-vdisplay-persistent.log 2>/dev/null || true
517+
exit 1
518+
fi
519+
echo "Persistent virtual display ready: ID=$(cat "$VDISPLAY_ID_PATH")"
520+
521+
- name: Run display resolution churn UI regression
522+
run: |
523+
set -euo pipefail
524+
SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages"
525+
HELPER_PATH="/tmp/create-virtual-display"
526+
TOKEN="$(uuidgen)"
527+
DIAG_PATH="/tmp/cmux-ui-test-display-churn-${TOKEN}.json"
528+
DISPLAY_READY="/tmp/cmux-ui-test-display-${TOKEN}.ready"
529+
DISPLAY_ID_PATH="/tmp/cmux-ui-test-display-${TOKEN}.id"
530+
DISPLAY_START="/tmp/cmux-ui-test-display-${TOKEN}.start"
531+
DISPLAY_DONE="/tmp/cmux-ui-test-display-${TOKEN}.done"
532+
HELPER_LOG="/tmp/cmux-ui-test-display-${TOKEN}-helper.log"
533+
534+
cleanup() {
535+
pkill -x "cmux DEV" 2>/dev/null || true
536+
rm -f "$DIAG_PATH" "$DISPLAY_READY" "$DISPLAY_ID_PATH" "$DISPLAY_START" "$DISPLAY_DONE" "$HELPER_LOG"
537+
rm -f /tmp/cmux-ui-test-prelaunch.json /tmp/cmux-ui-test-display-harness.json
538+
}
539+
trap cleanup EXIT
490540
541+
# Build display helper
491542
clang -framework Foundation -framework CoreGraphics \
492543
-o "$HELPER_PATH" scripts/create-virtual-display.m
493544
494-
cat >"$MANIFEST_PATH" <<EOF
495-
{"helperBinaryPath":"$HELPER_PATH"}
496-
EOF
545+
# Find the app binary
546+
APP_BINARY=$(find ~/Library/Developer/Xcode/DerivedData -path "*/Build/Products/Debug/cmux DEV.app/Contents/MacOS/cmux DEV" -print -quit 2>/dev/null || true)
547+
if [ -z "$APP_BINARY" ]; then
548+
echo "ERROR: App binary not found in DerivedData" >&2
549+
exit 1
550+
fi
551+
echo "App binary: $APP_BINARY"
497552
498553
for attempt in 1 2; do
554+
cleanup 2>/dev/null || true
555+
556+
# Launch display helper from shell (non-sandboxed).
557+
# Use --start-delay-ms instead of --start-path because the XCTest
558+
# runner is sandboxed and can't write to /tmp/ for the start signal.
559+
# 10s delay gives the test time to capture baseline render stats.
560+
"$HELPER_PATH" \
561+
--modes "1920x1080,1728x1117,1600x900,1440x810" \
562+
--ready-path "$DISPLAY_READY" \
563+
--display-id-path "$DISPLAY_ID_PATH" \
564+
--done-path "$DISPLAY_DONE" \
565+
--iterations 40 \
566+
--interval-ms 40 \
567+
--start-delay-ms 10000 \
568+
> "$HELPER_LOG" 2>&1 &
569+
HELPER_PID=$!
570+
571+
# Wait for display ready
572+
echo "Waiting for virtual display..."
573+
for i in $(seq 1 24); do
574+
if [ -f "$DISPLAY_READY" ]; then break; fi
575+
sleep 0.5
576+
done
577+
if [ ! -f "$DISPLAY_READY" ]; then
578+
echo "ERROR: Virtual display not ready after 12s" >&2
579+
cat "$HELPER_LOG" 2>/dev/null || true
580+
continue
581+
fi
582+
DISPLAY_ID=$(cat "$DISPLAY_ID_PATH")
583+
echo "Virtual display ready: ID=$DISPLAY_ID"
584+
585+
# Launch app from shell (non-sandboxed, outside XCTest sandbox)
586+
CMUX_UI_TEST_MODE=1 \
587+
CMUX_UI_TEST_DIAGNOSTICS_PATH="$DIAG_PATH" \
588+
CMUX_UI_TEST_DISPLAY_RENDER_STATS=1 \
589+
CMUX_UI_TEST_TARGET_DISPLAY_ID="$DISPLAY_ID" \
590+
CMUX_TAG="ui-tests-display-resolution" \
591+
"$APP_BINARY" > /tmp/cmux-ui-test-app.log 2>&1 &
592+
APP_PID=$!
593+
echo "App launched: PID=$APP_PID"
594+
595+
# Wait for app diagnostics
596+
echo "Waiting for app diagnostics..."
597+
APP_READY=false
598+
for i in $(seq 1 30); do
599+
if [ -f "$DIAG_PATH" ]; then
600+
if python3 -c "import json; d=json.load(open('$DIAG_PATH')); assert d.get('pid')" 2>/dev/null; then
601+
APP_READY=true
602+
break
603+
fi
604+
fi
605+
if ! kill -0 "$APP_PID" 2>/dev/null; then
606+
echo "ERROR: App crashed during startup"
607+
cat /tmp/cmux-ui-test-app.log 2>/dev/null | tail -30 || true
608+
break
609+
fi
610+
sleep 0.5
611+
done
612+
613+
if [ "$APP_READY" != "true" ]; then
614+
echo "Attempt $attempt: App not ready after 15s"
615+
pkill -x "cmux DEV" 2>/dev/null || true
616+
kill "$HELPER_PID" 2>/dev/null || true
617+
if [ "$attempt" -eq 2 ]; then
618+
echo "Display resolution UI regression failed after 2 attempts" >&2
619+
echo "--- App log ---"
620+
cat /tmp/cmux-ui-test-app.log 2>/dev/null | tail -50 || true
621+
echo "--- Helper log ---"
622+
cat "$HELPER_LOG" 2>/dev/null | tail -20 || true
623+
echo "--- Diagnostics ---"
624+
cat "$DIAG_PATH" 2>/dev/null || echo "(not found)"
625+
exit 1
626+
fi
627+
sleep 3
628+
continue
629+
fi
630+
631+
echo "App started. Diagnostics:"
632+
cat "$DIAG_PATH"
633+
634+
# Wait for render stats (terminal surface initialization)
635+
echo "Waiting for render stats..."
636+
RENDER_READY=false
637+
for i in $(seq 1 40); do
638+
if python3 -c "import json; d=json.load(open('$DIAG_PATH')); assert d.get('renderStatsAvailable') == '1'" 2>/dev/null; then
639+
RENDER_READY=true
640+
echo "Render stats available after $((i / 2))s"
641+
break
642+
fi
643+
sleep 0.5
644+
done
645+
if [ "$RENDER_READY" != "true" ]; then
646+
echo "WARNING: Render stats not available after 20s. Diagnostics:"
647+
cat "$DIAG_PATH" 2>/dev/null || true
648+
echo "--- App log ---"
649+
cat /tmp/cmux-ui-test-app.log 2>/dev/null | tail -30 || true
650+
fi
651+
652+
# Write manifests so test can find the pre-launched state
653+
MANIFEST_PATH="/tmp/cmux-ui-test-display-harness.json"
654+
cat >"$MANIFEST_PATH" <<MANIFEST_EOF
655+
{"readyPath":"$DISPLAY_READY","displayIDPath":"$DISPLAY_ID_PATH","donePath":"$DISPLAY_DONE","logPath":"$HELPER_LOG"}
656+
MANIFEST_EOF
657+
658+
PRELAUNCH_PATH="/tmp/cmux-ui-test-prelaunch.json"
659+
cat >"$PRELAUNCH_PATH" <<PRELAUNCH_EOF
660+
{"diagnosticsPath":"$DIAG_PATH"}
661+
PRELAUNCH_EOF
662+
663+
# Run test — app is already launched from shell
499664
if xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug \
500665
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
501666
-disableAutomaticPackageResolution \
502667
-destination "platform=macOS" \
503668
-only-testing:cmuxUITests/DisplayResolutionRegressionUITests \
504-
test; then
669+
test-without-building; then
505670
exit 0
506671
fi
672+
673+
pkill -x "cmux DEV" 2>/dev/null || true
674+
kill "$HELPER_PID" 2>/dev/null || true
675+
507676
if [ "$attempt" -eq 2 ]; then
508677
echo "Display resolution UI regression failed after 2 attempts" >&2
509678
exit 1
510679
fi
511680
echo "Attempt $attempt failed, retrying..."
512-
pkill -x "cmux DEV" 2>/dev/null || true
513681
sleep 3
514682
done
515683
@@ -521,6 +689,14 @@ jobs:
521689
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
522690
-disableAutomaticPackageResolution \
523691
-destination "platform=macOS" \
524-
-maximum-test-execution-time-allowance 120 \
692+
-maximum-test-execution-time-allowance 180 \
525693
-only-testing:cmuxUITests/BrowserPaneNavigationKeybindUITests/testCmdFFocusesBrowserFindFieldAfterCmdDCmdLNavigation \
526-
test
694+
test-without-building
695+
696+
- name: Cleanup persistent virtual display
697+
if: always()
698+
run: |
699+
if [ -n "${VDISPLAY_PERSISTENT_PID:-}" ]; then
700+
kill "$VDISPLAY_PERSISTENT_PID" >/dev/null 2>&1 || true
701+
fi
702+
rm -f /tmp/cmux-vdisplay-persistent.ready /tmp/cmux-vdisplay-persistent.id /tmp/cmux-vdisplay-persistent.log

CONTRIBUTING.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,7 @@ See `docs/ghostty-fork.md` for details on fork changes and conflict notes.
9999

100100
## License
101101

102-
By contributing to this repository, you agree that your contributions are licensed under the project's GNU Affero General Public License v3.0 or later (`AGPL-3.0-or-later`).
102+
By contributing to this repository, you agree that:
103+
104+
1. Your contributions are licensed under the project's GNU Affero General Public License v3.0 or later (`AGPL-3.0-or-later`).
105+
2. You grant Manaflow, Inc. a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license to use, reproduce, modify, sublicense, and distribute your contributions under any license, including a commercial license offered to third parties.

LICENSE

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
Copyright (c) 2024-present Manaflow, Inc.
2+
3+
This software is dual-licensed:
4+
5+
1. Open source: GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later).
6+
See the full text below.
7+
8+
2. Commercial: For organizations that cannot comply with AGPL, a commercial license
9+
is available. Contact founders@manaflow.com for details.
10+
11+
--------------------------------------------------------------------------------
12+
113
GNU AFFERO GENERAL PUBLIC LICENSE
214
Version 3, 19 November 2007
315

README.ar.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,6 @@ cmux مجاني ومفتوح المصدر وسيظل كذلك دائمًا. إذ
268268

269269
## الرخصة
270270

271-
هذا المشروع مرخص بموجب رخصة GNU Affero العامة الإصدار 3.0 أو أحدث (`AGPL-3.0-or-later`).
271+
cmux مفتوح المصدر بموجب [AGPL-3.0-or-later](LICENSE).
272272

273-
راجع `LICENSE` للنص الكامل.
273+
إذا لم تستطع مؤسستك الامتثال لـ AGPL، فهناك ترخيص تجاري متاح. تواصل مع [founders@manaflow.com](mailto:founders@manaflow.com) للتفاصيل.

README.bs.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,6 @@ cmux je besplatan, otvorenog koda i uvijek će biti. Ako želite podržati razvo
268268

269269
## Licenca
270270

271-
Ovaj projekat je licenciran pod GNU Affero General Public License v3.0 ili novijom (`AGPL-3.0-or-later`).
271+
cmux je otvorenog koda pod [AGPL-3.0-or-later](LICENSE) licencom.
272272

273-
Pogledajte `LICENSE` za puni tekst.
273+
Ako vaša organizacija ne može ispuniti uslove AGPL-a, dostupna je komercijalna licenca. Kontaktirajte [founders@manaflow.com](mailto:founders@manaflow.com) za detalje.

README.da.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,6 @@ cmux er gratis, open source og vil altid være det. Hvis du gerne vil støtte ud
268268

269269
## Licens
270270

271-
Dette projekt er licenseret under GNU Affero General Public License v3.0 eller senere (`AGPL-3.0-or-later`).
271+
cmux er open source under [AGPL-3.0-or-later](LICENSE).
272272

273-
Se `LICENSE` for den fulde tekst.
273+
Hvis din organisation ikke kan overholde AGPL, er en kommerciel licens tilgængelig. Kontakt [founders@manaflow.com](mailto:founders@manaflow.com) for detaljer.

README.de.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,6 @@ cmux ist kostenlos, Open Source und wird es immer sein. Wenn Sie die Entwicklung
268268

269269
## Lizenz
270270

271-
Dieses Projekt ist unter der GNU Affero General Public License v3.0 oder neuer (`AGPL-3.0-or-later`) lizenziert.
271+
cmux ist Open Source unter [AGPL-3.0-or-later](LICENSE).
272272

273-
Den vollständigen Lizenztext finden Sie in der `LICENSE`-Datei.
273+
Wenn Ihre Organisation AGPL nicht einhalten kann, ist eine kommerzielle Lizenz verfügbar. Kontaktieren Sie [founders@manaflow.com](mailto:founders@manaflow.com) für Details.

README.es.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,6 @@ cmux es gratuito, de código abierto, y siempre lo será. Si deseas apoyar el de
268268

269269
## Licencia
270270

271-
Este proyecto está licenciado bajo la Licencia Pública General Affero de GNU v3.0 o posterior (`AGPL-3.0-or-later`).
271+
cmux es código abierto bajo [AGPL-3.0-or-later](LICENSE).
272272

273-
Consulta el archivo `LICENSE` para el texto completo.
273+
Si su organización no puede cumplir con AGPL, hay una licencia comercial disponible. Contacte a [founders@manaflow.com](mailto:founders@manaflow.com) para más detalles.

README.fr.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,6 @@ cmux est gratuit, open source, et le restera toujours. Si vous souhaitez souteni
268268

269269
## Licence
270270

271-
Ce projet est sous licence GNU Affero General Public License v3.0 ou ultérieure (`AGPL-3.0-or-later`).
271+
cmux est open source sous [AGPL-3.0-or-later](LICENSE).
272272

273-
Consultez le fichier `LICENSE` pour le texte complet.
273+
Si votre organisation ne peut pas se conformer à l'AGPL, une licence commerciale est disponible. Contactez [founders@manaflow.com](mailto:founders@manaflow.com) pour plus de détails.

README.it.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,6 @@ cmux è gratuito, open source, e lo sarà sempre. Se vuoi supportare lo sviluppo
268268

269269
## Licenza
270270

271-
Questo progetto è distribuito sotto la GNU Affero General Public License v3.0 o successiva (`AGPL-3.0-or-later`).
271+
cmux è open source sotto [AGPL-3.0-or-later](LICENSE).
272272

273-
Vedi `LICENSE` per il testo completo.
273+
Se la tua organizzazione non può conformarsi all'AGPL, è disponibile una licenza commerciale. Contatta [founders@manaflow.com](mailto:founders@manaflow.com) per i dettagli.

0 commit comments

Comments
 (0)