Skip to content

fix(inquirerer): dispatch every key in a stdin chunk; arm idle timeout only for non-TTY input - #104

Merged
pyramation merged 1 commit into
mainfrom
devin/1785803980-inquirerer-keypress-timeout
Aug 4, 2026
Merged

fix(inquirerer): dispatch every key in a stdin chunk; arm idle timeout only for non-TTY input#104
pyramation merged 1 commit into
mainfrom
devin/1785803980-inquirerer-keypress-timeout

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

Two upstream fixes for defects that consumers are currently working around downstream (constructive agentic/cli carries a local patch for both; see constructive#1642).

1. A stdin chunk is not one key. TerminalKeypress looked the whole data chunk up as one exact key:

this.dataHandler = (key) => { this.listeners[key]?.forEach(h => h()); ... }

Text prompts register a listener per printable character (keypress.on(char, …)), so any chunk carrying more than one keypress — a paste, fast typing, a terminal batching bytes — matched nothing and was silently discarded. Downstream symptom: pasted passwords arrive truncated and sign-in fails with a misleading MFA error. Ctrl-C was likewise ignored when it shared a chunk.

The handler now segments the chunk and dispatches key by key, via a new exported segmentKeys(chunk). Escape sequences stay whole (CSI ESC [ … final, SS3 ESC O x, meta ESC x) and the rest splits per code point, so astral characters survive. An exact chunk match still wins first, since consumers may register sequences the segmenter doesn't model. Dispatch bails mid-chunk when a handler calls pause() (ENTER handlers do), so keys typed after a submit don't leak into the next prompt.

2. The default inactivity timeout was armed backwards.

-} else if (!noTty) {
+} else if (!noTty && !isInteractiveInput(input)) {
   this.timeout = DEFAULT_NON_TTY_TIMEOUT;   // 15s
 }

DEFAULT_NON_TTY_TIMEOUT was applied whenever noTty was false — i.e. to real interactive terminals, killing anyone who paused 15s at a prompt — while the non-interactive case it is named and written for (formatTimeoutError tells you to "pass the required arguments as CLI flags" / "pass --no-tty") got no timeout at all. It now arms on the actual condition it guards: the prompter is waiting for input on a stream that is not a TTY, e.g. a CI run invoking an interactive CLI. Explicit timeout is still honored everywhere, and noTty: true (which answers from defaults without waiting) stays unarmed.

Once this publishes, agentic/cli/src/keypress-chunks.ts (which reaches into the private prompter.keypress.dataHandler) and its timeout: 0x7fffffff workaround can both be deleted.

New tests: __tests__/keypress-chunks.test.ts, __tests__/inactivity-timeout.test.ts. Full package suite green (166 tests, snapshots unchanged).

Link to Devin session: https://app.devin.ai/sessions/783ae9ff63b445879450d5051d9d3d83
Requested by: @pyramation

@pyramation pyramation self-assigned this Aug 4, 2026
@devin-ai-integration

Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@pyramation
pyramation merged commit fe97801 into main Aug 4, 2026
55 checks passed
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.

1 participant