Repository navigation
Bug Fix - IntelliJIdea IDE freezes caused by a stdin/stdout pipe deadlock betwee… - #92
Open
Lycogrypho wants to merge 2 commits into
Open
Lycogrypho wants to merge 2 commits into
Lycogrypho wants to merge 2 commits into
Conversation
…n the plugin and the claude process. Restructure the agent documentation so its cross-references resolve. PROBLEM During long sessions IntelliJ IDEA froze, sometimes for over an hour, and only recovered when the claude process was restarted. idea.log records 41 UI freezes. All the long ones are blocked in ClaudeProcess.writeLine / FileOutputStream.writeBytes. ROOT CAUSE The stdout reader thread wrote auto-approved permission replies to claude's stdin synchronously, while processing claude's output. When the stdin pipe was full, that thread blocked and stopped draining stdout. claude then blocked on its own stdout and stopped reading stdin, so neither side could proceed. The UI thread, sending a periodic usage query, then blocked on the same write lock and froze the IDE. Teardown also closed stdin under that lock, so it could stall behind the stuck write. CHANGES - New controller/process/StdinWriter.kt: writes newline-terminated UTF-8 lines to stdin on a single dedicated thread, preserving order. Write failures are logged and do not stop later lines. - controller/process/ClaudeProcess.kt: writeLine queues the line on a bounded single-thread application pool executor and returns immediately; it still returns false when the process is dead. The write lock is removed. Teardown destroys the process before closing stdin, so a write stuck on a full pipe fails instead of stalling the shutdown. - New test controller/process/StdinWriterTest.kt: a pipe that stops draining does not block the caller; lines arrive whole and in order; a broken pipe does not stop later lines. - No security code was changed. The fix sits below PermissionBroker, which is untouched. - Documentation: CLAUDE.md gains the standard header. DIRECTIVES.md gains a "How the plugin is put together" architecture section. AGENTS.md points to DIRECTIVES.md for architecture and adds commands for a single test class, integration tests, a single frontend test file, and running builds and tests through the IDE's run server. CONTRIBUTING.md points to CLAUDE.md and DIRECTIVES.md and drops the link to the missing PROJECTMAP.md. BEHAVIOUR CHANGE writeLine now reports that a line was queued, not that it was written. A later pipe failure is logged and handled by the existing process-termination path. VERIFICATION Built with JBR 21.0.11 on Windows. StdinWriterTest (3), EdtProcessTeardownContractTest (4), and the NoComments, PackageDependency and FileSize contract tests pass. spotlessCheck and detekt pass. Full JVM suite: 4881 tests, 21 failed, 8 skipped. The same 21 fail on the original code: they depend on a POSIX environment (the bin/fake-claude script, Unix socket permissions and path length, symlinks, path separators). buildPlugin produced build/distributions/claude-code-native-6.0.1.zip, which contains StdinWriter and the updated ClaudeProcess. OPEN POINTS Not yet verified end to end in a running IDE. The integration tests that drive a real process cannot run on Windows. Manual check: install the zip and run a long task that previously froze.
…ry question card offers an Other answer with a free-text field. The model label could show a tagline from the catalog description instead of the model's name, because it took whatever came before " · ". It now uses only a segment that names the model with a version. Question cards had no way to give an answer outside the offered options; each question now ends with an Other choice that opens a text field, and the typed text is what gets sent. src/main/kotlin/dev/lain/claudejb/view/payload/composer/JcefModelLabels.kt - modelDisplayLabel picks the first description segment that starts with the model family and carries a version. Failing that, it uses the display name, then the name derived from the model id, but only if they carry a version. Failing that, it uses the bare name. A description segment without the family and a version is never used, because the catalog sometimes puts only a tagline there. The version pattern needs a word boundary after the digits, so a context size such as "1M" is not read as a version. src/main/ts/jcef/views/permissions/cards/question.ts - Every question ends with one fixed Other option. An Other supplied by the model (matched case-insensitively) is dropped rather than shown twice. Choosing Other reveals the text field and focuses it, and deselecting it hides the field. On submit, Other is replaced by the trimmed text typed into the field, so the model gets the answer and not the word Other. If the field is empty, Other is left out. On a multi-select the typed text is joined with the other chosen options. The click logic and option construction were moved into toggle, optionButton, otherInput and answerFor, keeping the builder readable and inside the file-size ceiling. src/main/resources/jcef/css/views/permissions/cards.css - Layout and hidden state of .q-other-input: full width, sitting under the options. src/main/resources/jcef/css/views/permissions/elicit.css - .q-other-input joins the existing input, focus and placeholder selectors, reusing the existing field style instead of defining a second one. src/test/kotlin/dev/lain/claudejb/view/payload/composer/JcefModelLabelTest.kt src/test/frontend/permissions/question-card.test.js Verification: npm test 46 files / 686 tests passed; eslint and prettier --check clean; gradlew test on JcefModelLabelTest and all *ContractTest passed; spotlessCheck passed. Not verified: detekt fails before analysing anything (Gradle appears to run on JDK 25 instead of JBR 21); the IDE's own analysis of the files had not finished; the keyboard pass on the new field has not been done.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PROBLEM
During long sessions IntelliJ IDEA froze, sometimes for over an hour, and only recovered when the claude process was restarted. idea.log records 41 UI freezes. All the long ones are blocked in ClaudeProcess.writeLine / FileOutputStream.writeBytes.
ROOT CAUSE
The stdout reader thread wrote auto-approved permission replies to claude's stdin synchronously, while processing claude's output. When the stdin pipe was full, that thread blocked and stopped draining stdout. claude then blocked on its own stdout and stopped reading stdin, so neither side could proceed. The UI thread, sending a periodic usage query, then blocked on the same write lock and froze the IDE. Teardown also closed stdin under that lock, so it could stall behind the stuck write.
CHANGES
BEHAVIOUR CHANGE
writeLine now reports that a line was queued, not that it was written. A later pipe failure is logged and handled by the existing process-termination path.
VERIFICATION
Built with JBR 21.0.11 on Windows. StdinWriterTest (3), EdtProcessTeardownContractTest (4), and the NoComments, PackageDependency and FileSize contract tests pass. spotlessCheck and detekt pass. Full JVM suite: 4881 tests, 21 failed, 8 skipped. The same 21 fail on the original code: they depend on a POSIX environment (the bin/fake-claude script, Unix socket permissions and path length, symlinks, path separators). buildPlugin produced build/distributions/claude-code-native-6.0.1.zip, which contains StdinWriter and the updated ClaudeProcess.
OPEN POINTS
Not yet verified end to end in a running IDE. The integration tests that drive a real process cannot run on Windows. Manual check: install the zip and run a long task that previously froze.