Skip to content

fix: defer startup plugin checks until prompt idle#436

Open
vltansky wants to merge 3 commits intoGitlawb:mainfrom
vltansky:fix/defer-startup-checks-idle
Open

fix: defer startup plugin checks until prompt idle#436
vltansky wants to merge 3 commits intoGitlawb:mainfrom
vltansky:fix/defer-startup-checks-idle

Conversation

@vltansky
Copy link
Copy Markdown

@vltansky vltansky commented Apr 6, 2026

Summary

  • defer performStartupChecks() until the REPL is locally idle instead of firing it immediately on mount
  • keep startup plugin checks enabled by default, but move them out of the initial typing window
  • add a small gate helper test for the new startup-check condition

Why

Current builds already include the earlier keyboard-freeze fixes (#266, #285) and the startup dialog suppression fix (#423), but there are still reports in #363 where:

  • normal startup accepts a few characters and then becomes unusable
  • --bare works
  • a minimal settings file with plugins/hooks disabled also works

The strongest remaining code path is immediate plugin startup work from performStartupChecks(setAppState) landing during initial prompt interaction.

Test Plan

  • bun test src/screens/replStartupGates.test.ts
  • bun run build
  • bun run smoke

Note

Generated with Codex from a local reproduction, and the resulting fix did work for the reporter locally before opening this PR.

Closes #435

Copilot AI review requested due to automatic review settings April 6, 2026 15:35
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to prevent post-launch prompt input freezes by deferring performStartupChecks() (plugin startup work) until the REPL is locally idle, rather than running immediately on mount.

Changes:

  • Added a small gate helper (shouldRunStartupChecks) to centralize the startup-check conditions.
  • Updated REPL.tsx to delay startup checks with an idle window (via setTimeout) and re-check the gate before running.
  • Added a focused unit test for the new gate helper.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/screens/replStartupGates.ts Adds a helper predicate to decide if startup checks should run.
src/screens/replStartupGates.test.ts Adds unit tests validating the gate logic.
src/screens/REPL.tsx Defers performStartupChecks() until local prompt idle, with a delay + re-check.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Collaborator

@gnanam1990 gnanam1990 left a comment

Choose a reason for hiding this comment

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

Thanks for working on this. The approach makes sense, but I see one blocking issue in the current implementation:

  1. src/screens/REPL.tsx:823
    The new useEffect dependency array references promptTypingSuppressionActive, but that variable is declared later in the component. Since the dependency array is evaluated during render, this will throw a ReferenceError at runtime before the component finishes rendering.

Could you please move this effect below the promptTypingSuppressionActive declaration (or move that state/derived value earlier) and then re-run the checks?

There’s also a small follow-up cleanup opportunity to reuse PROMPT_SUPPRESSION_MS instead of another hardcoded 1500, but the runtime ordering issue is the blocking one.

Relocated the useEffect that gates startup checks so it sits after
both `promptTypingSuppressionActive` and `startupChecksStartedRef`
declarations, preventing a temporal dead-zone ReferenceError on the
dependency array.

Also replaced the magic `1500` with the existing `PROMPT_SUPPRESSION_MS`
constant to keep the idle-delay value in a single place.
@vltansky
Copy link
Copy Markdown
Author

vltansky commented Apr 7, 2026

done

Copy link
Copy Markdown
Collaborator

@Vasanthdev2004 Vasanthdev2004 left a comment

Choose a reason for hiding this comment

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

Rechecked the latest head 5e8487415a685134620d99ac5b29833c259df2d7 against current origin/main.

The earlier runtime ordering bug is fixed on this revision, but I still can't approve because the core startup-check gating regression is still present.

src/screens/REPL.tsx:1331-1366 now delays performStartupChecks() behind promptTypingSuppressionActive, and src/screens/replInputSuppression.ts:1-5 still defines that flag as:

isPromptInputActive || inputValue.trim().length > 0

So startup checks do not wait for the prompt to become idle; they wait for the prompt to become empty. If the session starts with a prefilled draft, or the user types part of a message and pauses without clearing it, shouldRunStartupChecks(...) stays false forever and performStartupChecks() never starts.

That is a behavioral regression from "run once the prompt is idle" to "run only when there is no draft text at all", and it can delay or completely skip startup plugin checks for the whole session.

The new focused test is also currently asserting that same regressed behavior:

  • src/screens/replStartupGates.test.ts:5-7 says startup checks should be blocked while the prompt is "actively typing or seeded"

That means the branch is not just missing coverage for the regression; it is codifying it as the expected outcome.

What I rechecked on this head:

  • direct code-path review of src/screens/REPL.tsx, src/screens/replStartupGates.ts, and src/screens/replInputSuppression.ts
  • bun test src/screens/replStartupGates.test.ts -> 4 pass
  • bun run build -> success
  • bun run smoke -> success

So the latest head is stable enough to build, but it still changes startup checks from an idle gate to an empty-input gate.

shouldRunStartupChecks now checks isPromptInputActive (clears after
PROMPT_SUPPRESSION_MS of idle) instead of promptTypingSuppressionActive
(stays true while any draft text exists). This prevents a regression
where startup checks would never fire if the prompt had a prefilled
draft or the user paused mid-message without clearing the input.
Copilot AI review requested due to automatic review settings April 7, 2026 17:29
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1339 to +1345
useEffect(() => {
if (
!shouldRunStartupChecks(
isRemoteSession,
startupChecksStartedRef.current,
isPromptInputActive,
)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

Startup-check gating only considers isPromptInputActive, but isPromptInputActive is not set when the prompt is seeded with buffered early input (consumeEarlyInput()), so startup checks can still run while inputValue already contains user text. This undermines the goal of deferring plugin startup work until the prompt is truly idle; consider gating on promptTypingSuppressionActive (or inputValue.trim().length === 0) instead of isPromptInputActive alone, and update shouldRunStartupChecks accordingly.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +6
): boolean {
return !isRemoteSession && !hasStarted && !isPromptInputActive
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

shouldRunStartupChecks only gates on isPromptInputActive, which does not capture the "seeded with buffered early input" case (where inputValue.trim().length > 0 but the typing flag is still false). If the intended condition is "prompt is idle and empty", consider changing the API to accept a broader suppression/idle flag (or include inputValue/hasBufferedInput) so the helper matches the actual startup-check eligibility rules.

Suggested change
): boolean {
return !isRemoteSession && !hasStarted && !isPromptInputActive
inputValue: string,
): boolean {
return (
!isRemoteSession &&
!hasStarted &&
!isPromptInputActive &&
inputValue.trim().length === 0
)

Copilot uses AI. Check for mistakes.
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.

Defer REPL startup plugin checks until prompt idle to avoid post-launch input freeze

4 participants