mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 16:02:24 +00:00
* fix(terminal): converge post-spawn PTY size reconcile to fix split-mount column desync Follow-up to #6644/#6649. Those added a post-spawn PTY reconcile but capped it at a FIXED 12 requestAnimationFrames whose counter advanced even on frames where the pane was unmeasurable or the split layout had not yet equalized. When a tab MOUNTS with a split layout already present (a new worktree opened with the side split panel on), the real narrow split width settles AFTER frame 12, so the reconcile gave up while xterm had reflowed narrow and the PTY stayed pinned at the wide spawn width. The corrective xterm onResize is dropped during the hidden mount window (isRendererPtyResizeAuthoritative() is false), so process.stdout.columns stayed wide and interactive TUIs (Claude Code) rendered garbled until a manual resize. Extract the reconcile into pty-size-reconcile.ts with an authoritative-gated convergence loop instead of a fixed frame budget: - While the pane is hidden (onResize dropped), the reconcile is the SOLE corrector: it keeps polling and forwarding every grid change (its transport.resize bypasses the visibility gate). Hidden frames never advance the settle counter. - Once visible AND stable for SETTLE_FRAMES, it hands off to the live onResize/ResizeObserver path, which reliably catches any later reflow. - Hard cap (MAX_FRAMES) guarantees termination; mobile-fit/locked frames are skipped; the reconcile handle is cancelled on dispose. Harness: pty-size-reconcile.test.ts (14 tests) drives the loop with a deterministic frame scheduler; the desync-repro tests fail against the old 12-frame logic and pass on the fix. Adds an e2e "MOUNTS with a split layout present" test. Caveat: headless Electron does not reproduce this layout-settle-after-rAF race (the existing golden e2e passes even against the old buggy logic), which is why #6644/#6649 merged with green e2e yet the bug persisted. The unit test is the real regression harness; the e2e tests are integration smoke. Made with [Orca](https://github.com/stablyai/orca) Co-authored-by: Orca <help@stably.ai> * fix(terminal): re-assert PTY size on visibility resume to heal stubborn column desync Follow-up within the same fix: the user reported "sometimes even resizing doesn't fix it." Root cause beyond the mount-timing race — the renderer forwards resizes fire-and-forget and dedupes on the size it THINKS it sent, but never learns the PTY's actual size. A resize dropped main-side (the pane was hidden, a mobile take-back resize-suppression window, or a provider no-op) leaves xterm and the PTY silently diverged; a later same-cols layout fires no onResize, so it never self-corrects. Expose the PTY's last-APPLIED size to the renderer and re-assert on show: - New read-only IPC pty:getSize -> ptySizes.get(id) (the size written only when a resize actually lands or at spawn — the authoritative "what the PTY believes it is"). Wired through preload (window.api.pty.getSize) + api-types. - On visibility resume (noteVisibilityResume), the pane re-fits, reads the PTY's real size, and re-asserts via forwardPtyResize ONLY on genuine drift — so no spurious SIGWINCH on an already-synced resume (which would jar alt-screen TUIs). Routed through forwardPtyResize so the authoritative/mobile gates are re-checked at send time; remote-runtime PTYs (separate viewport channel) are skipped; overlapping resumes coalesce to one query. Also register pty:getSize in the registerPtyHandlers removeHandler cleanup block so re-registration (macOS re-activate / new window) doesn't throw on a duplicate ipcMain.handle, and make the pty IPC test mock throw on duplicate channels like real Electron so this class of omission is caught going forward. Tests: 7 resume-reassert cases (drift / match / null / remote-skip / mobile-fit-skip / hide-during-hop / overlap-coalesce), all non-vacuous. Full terminal-pane + pty IPC suites green (1494 tests); typecheck (web+node) + oxlint clean; e2e desync specs pass against a fresh build. Made with [Orca](https://github.com/stablyai/orca) Co-authored-by: Orca <help@stably.ai> * Stub PTY getSize API and skip redundant Wayland GPU sandbox tests - Implement PTY `getSize` stub in `web-preload-api.ts` to satisfy API requirements for the web-preload environment. - Skip the unfixed Wayland GPU sandbox negative control test if the target base branch already contains the sandbox workaround. --------- Co-authored-by: Orca <help@stably.ai> Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
139 lines
5.5 KiB
YAML
139 lines
5.5 KiB
YAML
name: Linux Wayland GPU Sandbox
|
|
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- .github/workflows/linux-wayland-gpu-sandbox.yml
|
|
- config/scripts/linux-wayland-renderer-diagnostics.mjs
|
|
- config/scripts/linux-wayland-terminal-exercise.mjs
|
|
- config/scripts/linux-wayland-validation-watchdog.mjs
|
|
- config/scripts/verify-linux-wayland-gpu-sandbox.mjs
|
|
- src/main/startup/configure-process.ts
|
|
- src/main/startup/configure-process.test.ts
|
|
- src/preload/api-types.ts
|
|
- src/preload/index.ts
|
|
- src/renderer/src/components/terminal-pane/pty-connection.ts
|
|
- src/renderer/src/lib/pane-manager/terminal-webgl-auto-policy.ts
|
|
- src/renderer/src/web/web-preload-api.ts
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
verify:
|
|
name: wayland terminal input
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Install native build tools and Wayland compositor
|
|
run: sudo apt-get update && sudo apt-get install -y build-essential python3 zsh weston
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version-file: package.json
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v6
|
|
with:
|
|
run_install: false
|
|
|
|
# Why: mirrors pr.yml so native module rebuilds do not use pnpm's
|
|
# non-executable bundled gyp_main.py on Linux runners.
|
|
- name: Use external node-gyp to avoid pnpm's bundled copy
|
|
run: |
|
|
npm install -g node-gyp@11.5.0
|
|
echo "npm_config_node_gyp=$(npm root -g)/node-gyp/bin/node-gyp.js" >> "$GITHUB_ENV"
|
|
|
|
- name: Prepare dependency install
|
|
run: |
|
|
if [ -e node_modules ]; then
|
|
ls -ld node_modules
|
|
rm -rf node_modules
|
|
fi
|
|
|
|
- name: Install dependencies
|
|
# Why: pnpm 10.24's frozen headless fast path can fail on fresh Ubuntu
|
|
# runners while creating the root node_modules. Use the normal resolver
|
|
# path, then verify package metadata stayed unchanged.
|
|
run: |
|
|
pnpm install --no-frozen-lockfile --prefer-frozen-lockfile=false
|
|
git diff --exit-code package.json pnpm-lock.yaml
|
|
|
|
- name: Start Weston
|
|
run: |
|
|
set -euo pipefail
|
|
export XDG_RUNTIME_DIR="$RUNNER_TEMP/xdg-runtime"
|
|
mkdir -p "$XDG_RUNTIME_DIR"
|
|
chmod 700 "$XDG_RUNTIME_DIR"
|
|
unset DISPLAY
|
|
weston --backend=headless-backend.so --socket=wayland-1 --idle-time=0 --log="$RUNNER_TEMP/weston.log" &
|
|
echo "XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR" >> "$GITHUB_ENV"
|
|
echo "WAYLAND_DISPLAY=wayland-1" >> "$GITHUB_ENV"
|
|
echo "XDG_SESSION_TYPE=wayland" >> "$GITHUB_ENV"
|
|
echo "ELECTRON_OZONE_PLATFORM_HINT=wayland" >> "$GITHUB_ENV"
|
|
echo "ORCA_WAYLAND_GPU_VERBOSE=1" >> "$GITHUB_ENV"
|
|
for _ in $(seq 1 50); do
|
|
if [ -S "$XDG_RUNTIME_DIR/wayland-1" ]; then
|
|
break
|
|
fi
|
|
sleep 0.2
|
|
done
|
|
test -S "$XDG_RUNTIME_DIR/wayland-1"
|
|
|
|
- name: Reproduce terminal input freeze without the workaround
|
|
id: reproduce_base
|
|
if: github.event_name == 'pull_request'
|
|
# Why: still collect fixed-path Wayland evidence when the base repro
|
|
# stops reproducing; the final gate below fails the job in that case.
|
|
continue-on-error: true
|
|
timeout-minutes: 10
|
|
run: |
|
|
set -euo pipefail
|
|
git fetch --no-tags --depth=1 origin "${{ github.event.pull_request.base.sha }}"
|
|
# Why: once the PR base includes this workaround, the partial
|
|
# checkout cannot reconstruct an unfixed Wayland negative control.
|
|
if git show "${{ github.event.pull_request.base.sha }}:src/main/startup/configure-process.ts" | grep -Eq "appendSwitch\\(['\"]disable-gpu-sandbox['\"]\\)"; then
|
|
echo "The base build already contains the Linux Wayland GPU sandbox workaround; skipping unfixed-path reproduction."
|
|
exit 0
|
|
fi
|
|
# Why: keep the new verifier scripts, but run them against the
|
|
# unfixed production terminal/GPU path instead of a hybrid checkout.
|
|
git checkout "${{ github.event.pull_request.base.sha }}" -- \
|
|
src/main/startup/configure-process.ts \
|
|
src/preload/api-types.ts \
|
|
src/preload/index.ts \
|
|
src/renderer/src/components/terminal-pane/pty-connection.ts \
|
|
src/renderer/src/lib/pane-manager/terminal-webgl-auto-policy.ts \
|
|
src/renderer/src/web/web-preload-api.ts
|
|
rm -rf out
|
|
node config/scripts/verify-linux-wayland-gpu-sandbox.mjs --mode=expect-repro
|
|
|
|
- name: Verify terminal input under Wayland GPU sandbox workaround
|
|
if: ${{ !cancelled() }}
|
|
timeout-minutes: 10
|
|
run: |
|
|
set -euo pipefail
|
|
git checkout --force "$GITHUB_SHA"
|
|
rm -rf out
|
|
node config/scripts/verify-linux-wayland-gpu-sandbox.mjs
|
|
|
|
- name: Require base reproduction
|
|
if: ${{ github.event_name == 'pull_request' && steps.reproduce_base.outcome != 'success' }}
|
|
run: |
|
|
echo "The unfixed base build did not reproduce the Wayland terminal input failure."
|
|
exit 1
|
|
|
|
- name: Upload Weston log
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: weston-log
|
|
path: ${{ runner.temp }}/weston.log
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|