Skip to content

fix: flush process output before completion#455

Open
Showiix wants to merge 3 commits into
wonderwhy-er:mainfrom
Showiix:fix/process-output-close
Open

fix: flush process output before completion#455
Showiix wants to merge 3 commits into
wonderwhy-er:mainfrom
Showiix:fix/process-output-close

Conversation

@Showiix
Copy link
Copy Markdown

@Showiix Showiix commented Apr 29, 2026

User description

Summary

  • finalize completed process sessions on close instead of exit so stdout/stderr have drained
  • preserve fast-exiting process stderr in completed session output
  • add a regression test for a fast-failing process that writes stderr before exit

Fixes #395

Test

  • npm run build
  • node test/test-process-output-close.js

CodeAnt-AI Description

Keep fast-exiting process output until stdio finishes

What Changed

  • Completed processes are now saved only after their output streams close, so short-lived commands keep late stdout/stderr in the finished result.
  • Fast-failing processes still show the correct exit code in completed output.
  • Added a regression test for a process that writes a large amount to stderr and exits immediately.

Impact

✅ Fewer missing error messages
✅ More complete process output
✅ Clearer fast-failure results

🔄 Retrigger CodeAnt AI Review

Details

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

  • Bug Fixes

    • Improved process output handling so all stdout/stderr (including late-arriving data) is captured; completed sessions are persisted only after streams fully close to prevent lost output and ensure correct exit status.
  • Tests

    • Added an executable test that simulates a fast-exiting process to verify output is retained, exit codes are preserved, and sessions are not left in a blocked state.

@codeant-ai
Copy link
Copy Markdown
Contributor

codeant-ai Bot commented Apr 29, 2026

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 935b4866-62e3-4a1f-863e-899637b8600a

📥 Commits

Reviewing files that changed from the base of the PR and between c4c8550 and e07dbfe.

📒 Files selected for processing (1)
  • test/test-process-output-close.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/test-process-output-close.js

📝 Walkthrough

Walkthrough

Switches terminal-manager's lifecycle listener from the child process exit event to close, persisting completed sessions and removing the active session only after stdio streams close. Adds a test that verifies stderr is captured for fast-exiting processes.

Changes

Cohort / File(s) Summary
Process lifecycle & session persistence
src/terminal-manager.ts
Replaced exit handler with close to delay cleanup until stdio streams close; persist completed sessions and remove active-session entry after streams close. File now ends with a trailing newline.
Fast-exit stderr test
test/test-process-output-close.js
New test that spawns a helper ESM script producing large stderr then exiting quickly; runs via terminalManager.executeCommand with timeout, asserts session unblocked, reads paginated output to confirm preserved stderr and exit code, and cleans up temp files.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant TerminalManager
    participant ChildProcess
    participant Storage

    Client->>TerminalManager: executeCommand(cmd, ...)
    TerminalManager->>ChildProcess: spawn process
    ChildProcess-->>TerminalManager: stdout/stderr (stream chunks)
    ChildProcess-->>TerminalManager: exit (process exits)
    note right of TerminalManager: do not finalize session yet
    ChildProcess-->>TerminalManager: close (stdio streams closed)
    TerminalManager->>Storage: persist completed session (output, exitCode)
    TerminalManager->>Client: mark session complete / isBlocked = false
    Client->>TerminalManager: readOutputPaginated(...) -> returns persisted output
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped where streams were quick to flee,
I waited till they sighed "I'm free".
No crumb of stderr left behind,
I gather each and keep in mind.
Hooray — no lost output for me!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: flush process output before completion' accurately describes the main change: using the 'close' event instead of 'exit' to ensure stdout/stderr streams are fully drained before session completion.
Linked Issues check ✅ Passed The pull request directly addresses issue #395 by changing the process lifecycle listener from 'exit' to 'close' events, ensuring stderr is captured even for fast-exiting processes, and adds a regression test validating this behavior.
Out of Scope Changes check ✅ Passed All changes are in-scope: the terminal manager fix targets the core issue, the test validates the fix for fast-exiting processes, and the trailing newline is a minor formatting consistency improvement.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 3/8 reviews remaining, refill in 31 minutes and 53 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai codeant-ai Bot added the size:M This PR changes 30-99 lines, ignoring generated files label Apr 29, 2026
Comment thread test/test-process-output-close.js Outdated
await fs.writeFile(
SCRIPT_PATH,
[
"import fs from 'fs';",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion: The temporary script is written with ESM syntax but saved as .js in a temp directory that is outside this package scope, so Node will treat it as CommonJS and fail with a syntax error before running the stderr writes. This makes the regression test fail for the wrong reason. Save it as .mjs or use CommonJS syntax in the generated script. [possible bug]

Severity Level: Major ⚠️
-`test-process-output-close.js` fails due to child SyntaxError.
- ⚠️ Stderr flush regression for fast-exiting processes not validated.
- ⚠️ `npm test` / CI pipeline will report failing test suite.
Steps of Reproduction ✅
1. Run the test suite (e.g. `npm test` which calls `node test/run-all-tests.js` per
`package.json:24,43` and `test/run-all-tests.js:90-99`). The runner discovers
`test-process-output-close.js` via its `files.filter(file => file.startsWith('test') &&
file.endsWith('.js'))` logic at `test/run-all-tests.js:104-108` and spawns it with `node
./test-process-output-close.js` from `test/run-all-tests.js:57-63`.

2. Inside `test/test-process-output-close.js`, the default export `runTests()` at lines
50-62 is executed (because the file is treated as an ES module due to the project
`package.json` having `"type": "module"` at line 10). `runTests()` calls `setup()` at
lines 15-27, which writes `fast-stderr.js` into the OS temp directory (`TEST_DIR` at line
8, `SCRIPT_PATH` at line 9) with the first line of the file being `import fs from 'fs';`
per the string array at lines 20-25.

3. `testFastExitStderrIsFlushed()` at lines 33-48 constructs `command =
\`${quoteForShell(process.execPath)} ${quoteForShell(SCRIPT_PATH)}\`` at line 34 and
passes it to `terminalManager.executeCommand(command, 2000)` at line 35, causing a child
Node process to run `/tmp/.../fast-stderr.js` directly (outside the project tree, so there
is no nearby `package.json` with `"type": "module"`).

4. The child Node process treats `/tmp/.../fast-stderr.js` as a CommonJS `.js` file
(because there is no `package.json` in its ancestor directories declaring `"type":
"module"`), encounters the first line `import fs from 'fs';` (originating from
`test/test-process-output-close.js:20`) as invalid syntax, and exits with a SyntaxError
before executing any of the `fs.writeSync` calls at lines 21-23. As a result, when
`testFastExitStderrIsFlushed()` reads output via
`terminalManager.readOutputPaginated(result.pid, 0, 100)` at line 39 and then asserts that
`text` includes `FAST_STDERR_START` and `FAST_STDERR_END` at lines 44-45, those markers
are missing (only Node's syntax error is present), so the test fails for the wrong reason
and the intended stderr-flush regression is not actually exercised. This behavior is
deterministic whenever the test is run.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** test/test-process-output-close.js
**Line:** 20:20
**Comment:**
	*Possible Bug: The temporary script is written with ESM syntax but saved as `.js` in a temp directory that is outside this package scope, so Node will treat it as CommonJS and fail with a syntax error before running the stderr writes. This makes the regression test fail for the wrong reason. Save it as `.mjs` or use CommonJS syntax in the generated script.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai
Copy link
Copy Markdown
Contributor

codeant-ai Bot commented Apr 29, 2026

CodeAnt AI finished reviewing your PR.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/test-process-output-close.js`:
- Around line 14-31: The setup() function can leak the temporary directory if
fs.writeFile throws; modify setup() so that after creating testDir (via
fs.mkdtemp(TEST_DIR_PREFIX)) you guard the subsequent file operations with a
try/catch or try/finally that calls fs.rm(testDir, { recursive: true, force:
true }) on error, or alternatively make setup() return a disposer/teardown
callback that always removes testDir on failure; ensure you reference the
created scriptPath and call fs.rm in the error path so partially created
fixtures are cleaned up (leave teardown(testDir) as the successful teardown
path).
- Around line 69-73: The entrypoint check using import.meta.url ===
`file://${process.argv[1]}` can fail for relative process.argv[1]; update the
check to normalize process.argv[1] with pathToFileURL before comparison (like in
test-widget-state-runtime.js and test-markdown-preview.js). Locate the
conditional that wraps runTests() (the import.meta.url comparison) and replace
the raw file://${process.argv[1]} comparison with
pathToFileURL(process.argv[1]).toString() so import.meta.url reliably matches
whether argv[1] is relative or absolute, leaving the runTests() invocation
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 67690712-27e5-4fb5-bc4d-2be149702379

📥 Commits

Reviewing files that changed from the base of the PR and between dac9a1c and c4c8550.

📒 Files selected for processing (1)
  • test/test-process-output-close.js

Comment thread test/test-process-output-close.js
Comment thread test/test-process-output-close.js Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

read_process_output loses stderr when process exits quickly (exit code 1, zero output)

1 participant