fix(ui): open help and menus without first-use suspension - #1079
Conversation
Keep lightweight help and menu chrome synchronously available so the first open does not wait on React’s Suspense fallback throttle. Preserve lazy loading for the other overlays. Add raw-PTY first-frame and idle-first latency coverage with screen-verified close/reopen, bounded process-group cleanup, and optional compiled-binary coverage.
Faster first-open rendering exposes tests that treat a short output-idle wait as proof a lone Escape has been parsed. Observe the closed menu before sending F8, hunk navigation, or an Escape-prefixed Alt binding instead of relying on the old suspension delay.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Greptile SummaryThis PR removes lazy Suspense boundaries from the lightweight help and menu overlays so their first visible commit is no longer throttled. It also adds a raw-PTY latency regression suite and makes existing PTY tests wait for menu closure before sending escape-prefixed input.
Confidence Score: 4/5The runtime change appears sound, but the repository’s explicit test-import requirement must be satisfied before merging. The static overlay imports are lightweight and the PTY synchronization changes follow established behavior; the only accepted issue is the new test’s prohibited dynamic import. Files Needing Attention: test/pty/dialog-first-open-integration.test.ts Important Files Changed
Prompt To Fix All With AI### Issue 1
test/pty/dialog-first-open-integration.test.ts:56-58
**Dynamic import violates test rule**
This test loads `PersistentTerminal` with `await import(...)` inside the test callback. The repository testing directive requires imports to be hoisted to the top level and explicitly forbids dynamic imports in tests. This requirement must be satisfied before merging while preserving the Unix-only platform handling.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "test(pty): verify menu closure before su..." | Re-trigger Greptile |
Follow-up to #1063. First of two first-interaction fixes; independent of #1078 (Shiki WASM decode).
Problem
The first
?(help) or F10 (menu) after launch takes ~310–360 ms to appear, on every host and in the compiled binary; reopening takes 5–25 ms. Waiting a few seconds before the first press doesn't help, and diff size doesn't matter.Cause:
HelpDialogandMenuDropdownwereReact.lazycomponents inside<Suspense fallback={null}>. The module import resolves in 3–6 ms, but React 19's reconciler throttles the commit after a fallback (FALLBACK_THROTTLE_MS = 300, present in both dev and production builds), so the real tree commits ~301 ms after the null fallback.act()bypasses that throttle, which is why no unit test orbench:interaction-latencyrun ever saw it. Full diagnosis with instrumented timelines in the linked issue thread.Approach
Import the two components statically. Their import graphs are small (command/key helpers and text helpers — no ThemeSelector, AgentSkill, Shiki or Pierre), so this doesn't move any heavy code onto the startup path: launch → first frame is unchanged and the npm bundle shrinks by 869 bytes.
ThemeSelectorandAgentSkillkeep their own lazy + Suspense wrappers and are not touched (see follow-ups).Second commit: two existing PTY tests pressed Escape to close the menu and immediately sent the next key. With the menu now closing quickly, that exposed a harness race (OpenTUI buffers a lone Escape until its parser timeout and may join the following escape-prefixed bytes). They now wait for the menu to disappear from the screen before sending more input. Production key routing is unchanged.
Measurements (median ms, n=5; before → after)
The remaining Linux first-frame cost is mostly the synchronous Shiki WASM decode that #1078 removes.
Tests / checks
test/pty/dialog-first-open-integration.test.ts: rawBun.Terminal, one-file git fixture, watch off, fixed theme, no extensions/update/broker. Sends the key in the first visible-frame callback (no warmup/press/waitIdle), then verifies close and reopen from the parsed screen. Four fresh processes: help/menu × immediate/2 s-idle. Gates: ≤200 ms immediate, ≤150 ms idle, first − reopen ≤150 ms. Fails 80/80 cases onmain, passes 80/80 here (macOS + Linux, source + binary). Raw bytes and final screen are kept on failure.bun run typecheck,deps:check,lint,format:check— pass.bun run test:integration— Linux 170 pass / 1 skip; macOS 5 failures reproduce onmain(TMPDIR trust-state cases, signal-lifecycle cases).bun run test:tty-smoke— Linux 10/10; plus a real-TTY keyboard/mouse smoke.bun run test— same pre-existing failures asmain.Follow-ups (not in this PR)
ThemeSelectorstill has the same first-use behaviour (measured ~306–361 ms).AgentSkillis lazy and unmeasured. Both need their own measurement before deciding static vs. preloaded.