Skip to content

fix(cli): Move stdin processing to main process to resolve hang in child_process worker#878

Merged
yamadashy merged 1 commit intomainfrom
fix/stdin
Oct 2, 2025
Merged

fix(cli): Move stdin processing to main process to resolve hang in child_process worker#878
yamadashy merged 1 commit intomainfrom
fix/stdin

Conversation

@yamadashy
Copy link
Owner

This PR fixes the --stdin option hang issue reported in #867.

Summary

In v1.6.0, defaultAction was changed to run in a child_process worker for better resource isolation. However, child_process workers don't inherit stdin from the parent process by default, causing the worker to hang when trying to read from process.stdin.

Changes

  • Move stdin processing from worker to main process before worker creation
  • Change DefaultActionTask interface from isStdin to stdinFilePaths
  • Pass already-read file paths from stdin to the worker
  • Maintain resource isolation benefits of child_process while restoring stdin functionality

Technical Details

The root cause was that readFilePathsFromStdin() was called inside the child_process worker, but stdin was not inherited. The fix moves stdin reading to the main process and passes the file paths to the worker as a parameter.

This approach:

  • ✅ Preserves child_process resource isolation and stability
  • ✅ Minimal code changes
  • ✅ Returns to v1.5.0-like behavior for stdin processing
  • ✅ Lightweight stdin reading doesn't impact main process performance

Checklist

  • Run npm run test
  • Run npm run lint

Fixes #867

…ild_process worker

Issue #867で報告された--stdinオプションのハング問題を修正しました。

v1.6.0でdefaultActionがchild_processで実行されるようになりましたが、
child_processではデフォルトで親プロセスのstdinが継承されないため、
worker内でprocess.stdinを読み取ろうとするとハングしていました。

Changes:
- stdin処理をメインプロセスに移動し、読み取り結果をworkerに渡すように変更
- DefaultActionTask interfaceをisStdinからstdinFilePathsに変更
- child_processによるリソース分離と安定性を維持しながら、stdin機能を復元

Fixes #867
Copilot AI review requested due to automatic review settings October 2, 2025 15:02
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 2, 2025

Walkthrough

Moves --stdin file-path reading from the worker to the main defaultAction, validating no directories are passed with --stdin. The main action reads stdin file paths and passes them as stdinFilePaths to the worker. Worker logic now branches on stdinFilePaths presence. Tests updated to reflect the new task shape and flow.

Changes

Cohort / File(s) Summary of Changes
CLI main action: stdin handling moved to main
src/cli/actions/defaultAction.ts
Adds readFilePathsFromStdin and RepomixError usage. Validates directories not allowed with --stdin. Reads stdin file paths and passes stdinFilePaths into worker task. Keeps existing config/worker readiness flow; updates logging accordingly.
Worker: consume stdinFilePaths instead of reading stdin
src/cli/actions/workers/defaultActionWorker.ts
Replaces isStdin boolean with optional stdinFilePaths: string[]. Removes direct stdin reading and RepomixError usage. Branches on stdinFilePaths to process provided paths; otherwise continues directory-based flow.
Tests: main action
tests/cli/actions/defaultAction.test.ts
Mocks fileStdin.readFilePathsFromStdin. Updates expectations to use stdinFilePaths instead of isStdin.
Tests: worker
tests/cli/actions/workers/defaultActionWorker.test.ts
Supplies stdinFilePaths on task; removes mocks for stdin reading and related error cases. Updates assertions to pass stdinFilePaths to packager and adjusts control-flow expectations.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant CLI as defaultAction (main)
  participant Worker as defaultActionWorker
  participant Pack as pack()

  User->>CLI: repomix --stdin
  note over CLI: Read file paths from stdin
  CLI->>CLI: validate no directory args with --stdin
  CLI->>Worker: start task { stdinFilePaths }
  alt stdinFilePaths provided
    Worker->>Pack: pack({ explicitPaths: stdinFilePaths })
  else no stdinFilePaths
    Worker->>Pack: pack({ search in provided directories })
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and succinctly describes the primary change by stating that stdin processing has been moved to the main process to fix the hang in the child_process worker, matching the core purpose of the pull request.
Linked Issues Check ✅ Passed The code changes directly address the linked issue #867 by moving stdin reading to the main process, updating the DefaultActionTask interface, passing file paths into the worker, and preserving child_process isolation, thereby restoring --stdin functionality without regressions.
Out of Scope Changes Check ✅ Passed All modifications are scoped to stdin handling in the CLI actions, task interfaces, and corresponding tests, with no unrelated files or features touched outside the objectives defined by the linked issue.
Description Check ✅ Passed The pull request description follows the repository template by providing a clear summary of the changes and including a completed checklist for testing and linting, and it adds helpful context and technical details about the stdin hang issue.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/stdin

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

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

Copy link
Contributor

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 fixes a hang issue with the --stdin option by moving stdin processing from the child_process worker to the main process, resolving the problem where workers couldn't access stdin by default.

  • Move stdin file path reading from worker to main process before worker creation
  • Update DefaultActionTask interface to use stdinFilePaths array instead of isStdin boolean
  • Remove stdin validation and error handling from worker since it's now handled in main process

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/cli/actions/defaultAction.ts Added stdin processing in main process with validation and passes file paths to worker
src/cli/actions/workers/defaultActionWorker.ts Updated to receive pre-processed stdin file paths instead of handling stdin directly
tests/cli/actions/defaultAction.test.ts Updated test mocks and expectations for new stdin handling approach
tests/cli/actions/workers/defaultActionWorker.test.ts Removed stdin-related mocks and tests, updated task objects to use new interface

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @yamadashy, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug where the CLI's --stdin option would cause the application to hang. This occurred because the defaultAction was moved to a child process worker for performance, but child processes do not inherit standard input by default. The solution refactors the stdin handling to occur in the main process, passing the pre-read file paths to the worker, thereby resolving the hang while preserving the benefits of worker isolation.

Highlights

  • Fixes Stdin Hang Issue: This pull request resolves a critical issue where the --stdin option would cause the CLI to hang, as reported in The --stdin option does not seem to work #867.
  • Moved Stdin Processing to Main Process: The core fix involves moving the stdin file path reading from the child_process worker to the main process. This is necessary because child_process workers do not inherit standard input by default, leading to the hang.
  • Updated Worker Interface: The DefaultActionTask interface has been updated to pass the already-read stdinFilePaths directly to the worker, replacing the previous isStdin boolean flag.
  • Maintained Resource Isolation: This solution preserves the resource isolation benefits of using child_process workers while restoring the intended functionality of the --stdin option.
  • Added Stdin Argument Validation: New validation logic has been introduced to prevent users from specifying directory arguments when the --stdin option is active, ensuring correct usage.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@codecov
Copy link

codecov bot commented Oct 2, 2025

Codecov Report

❌ Patch coverage is 78.94737% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.81%. Comparing base (0071b64) to head (1bb752a).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
src/cli/actions/defaultAction.ts 73.33% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #878      +/-   ##
==========================================
- Coverage   88.85%   88.81%   -0.05%     
==========================================
  Files         109      109              
  Lines        7575     7580       +5     
  Branches     1423     1425       +2     
==========================================
+ Hits         6731     6732       +1     
- Misses        844      848       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively resolves the hanging issue with the --stdin option by moving the standard input processing from the child process worker to the main process. The approach of reading file paths in the main process and passing them to the worker is a clean solution that maintains the benefits of using a child process. The code changes are logical and the refactoring of tests is mostly correct. However, there's a gap in test coverage for the moved validation logic, which should be addressed.

@cloudflare-workers-and-pages
Copy link

Deploying repomix with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1bb752a
Status: ✅  Deploy successful!
Preview URL: https://ccb8c7f6.repomix.pages.dev
Branch Preview URL: https://fix-stdin.repomix.pages.dev

View logs

@claude
Copy link
Contributor

claude bot commented Oct 2, 2025

Code Review for PR #878

Thank you for this fix! The solution elegantly addresses the stdin hang issue by moving stdin processing to the main process before worker creation. Here's my detailed review:

✅ Strengths

  1. Root Cause Analysis: Excellent identification that child_process workers don't inherit stdin by default, causing the hang in v1.6.0
  2. Architecture Preservation: The fix maintains the resource isolation benefits of the child_process architecture while restoring functionality
  3. Clean Interface Change: Changing from isStdin boolean to stdinFilePaths array makes the worker interface more explicit and testable
  4. Proper Error Handling: Directory validation for stdin mode is preserved in the main process

🎯 Code Quality Observations

  1. Good separation of concerns: Moving stdin reading to the main process is the right architectural decision
  2. Test coverage maintained: Tests properly updated to reflect the new interface
  3. Minimal changes: The fix is focused and doesn't introduce unnecessary modifications

💡 Suggestions for Improvement

  1. Error Handling Enhancement: Consider adding error handling for the stdin reading in the main process:

    try {
      const stdinResult = await readFilePathsFromStdin(cwd);
      stdinFilePaths = stdinResult.filePaths;
    } catch (error) {
      throw new RepomixError(`Failed to read file paths from stdin: ${error.message}`);
    }
  2. Documentation: The comment explaining why stdin must be processed in the main process is helpful. Consider expanding it slightly:

    // Handle stdin processing in main process (before worker creation)
    // This is necessary because child_process workers don't inherit stdin
    // and would hang when trying to read from process.stdin
  3. Type Safety: The stdinFilePaths is optional but when cliOptions.stdin is true, it should always be defined. Consider making this relationship more explicit in the type system if feasible.

✅ Security & Performance

  • No security concerns identified
  • Performance impact is negligible as stdin reading is lightweight
  • Resource isolation benefits are properly maintained

✅ Testing

  • Test coverage looks comprehensive
  • Tests properly updated to reflect the new interface
  • Good removal of now-unnecessary error case tests from the worker

Conclusion

This is a well-crafted fix that addresses the issue without compromising the architecture. The code changes are minimal, focused, and maintain good separation of concerns. With the minor suggestions above (especially the error handling), this PR is ready to merge.

Great work on the diagnosis and fix! 🎉

Copy link
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: 0

🧹 Nitpick comments (1)
tests/cli/actions/workers/defaultActionWorker.test.ts (1)

224-238: Consider testing edge case: empty stdinFilePaths array.

The test handles empty directories array but passes a non-empty stdinFilePaths. Consider adding a test case that verifies behavior when stdinFilePaths is an empty array to ensure the worker handles this edge case gracefully.

Example test case:

it('should handle empty stdinFilePaths array', async () => {
  const task: DefaultActionTask = {
    directories: ['.'],
    cwd: '/test/project',
    config: mockConfig,
    cliOptions: mockCliOptions,
    stdinFilePaths: [],
  };

  mockPack.mockResolvedValueOnce(mockPackResult);

  await defaultActionWorker(task);

  expect(mockPack).toHaveBeenCalledWith(
    ['/test/project'],
    mockConfig,
    expect.any(Function),
    {},
    []
  );
});
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0071b64 and 1bb752a.

📒 Files selected for processing (4)
  • src/cli/actions/defaultAction.ts (3 hunks)
  • src/cli/actions/workers/defaultActionWorker.ts (4 hunks)
  • tests/cli/actions/defaultAction.test.ts (4 hunks)
  • tests/cli/actions/workers/defaultActionWorker.test.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/cli/actions/defaultAction.ts (3)
src/shared/errorHandle.ts (1)
  • RepomixError (6-11)
src/core/file/fileStdin.ts (1)
  • readFilePathsFromStdin (69-116)
src/cli/actions/workers/defaultActionWorker.ts (1)
  • DefaultActionTask (12-18)
tests/cli/actions/workers/defaultActionWorker.test.ts (1)
src/cli/actions/workers/defaultActionWorker.ts (1)
  • DefaultActionTask (12-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Build and run (windows-latest, 22.x)
  • GitHub Check: Build and run (windows-latest, 24.x)
  • GitHub Check: Build and run (windows-latest, 20.x)
  • GitHub Check: Test (windows-latest, 22.x)
  • GitHub Check: Test (windows-latest, 20.x)
  • GitHub Check: Build and run with Bun (windows-latest, latest)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (8)
tests/cli/actions/defaultAction.test.ts (2)

90-93: LGTM: Mock setup aligns with new stdin handling flow.

The mock correctly returns both filePaths and emptyDirPaths, matching the StdinFileResult type structure from readFilePathsFromStdin.


180-198: Verify directory validation for stdin mode.

The test verifies that stdinFilePaths is passed to the worker task, but it doesn't verify the directory validation logic introduced in the main action (lines 58-62 of src/cli/actions/defaultAction.ts). Consider adding a test case that verifies the error thrown when multiple directories or non-"." directories are provided with --stdin.

Example test case to add:

it('should throw error when stdin mode is used with invalid directory arguments', async () => {
  const options: CliOptions = {
    stdin: true,
  };

  await expect(runDefaultAction(['src', 'tests'], process.cwd(), options)).rejects.toThrow(
    'When using --stdin, do not specify directory arguments'
  );
});
src/cli/actions/defaultAction.ts (3)

57-62: LGTM: Directory validation prevents confusing behavior.

The validation correctly prevents users from specifying directory arguments when using --stdin, which would be ambiguous. The error message is clear and actionable.


80-87: LGTM: Task construction properly includes stdin file paths.

The optional stdinFilePaths field is correctly added to the worker task, allowing the worker to distinguish between stdin and directory modes.


52-67: Remove empty-stdin validation suggestion
readFilePathsFromStdin already throws RepomixError('No valid file paths found in stdin input.') on empty input.

src/cli/actions/workers/defaultActionWorker.ts (2)

58-72: LGTM: Worker correctly processes stdin file paths from main process.

The branching logic is clean and the worker now delegates stdin reading to the main process, resolving the child_process stdin inheritance issue. The pack() call correctly passes stdinFilePaths as the 5th argument.


73-80: LGTM: Directory processing path remains unchanged.

The else branch maintains the original directory processing logic, ensuring backward compatibility for non-stdin usage.

tests/cli/actions/workers/defaultActionWorker.test.ts (1)

201-222: LGTM: Test correctly verifies stdin file paths are passed to pack().

The test properly validates that stdinFilePaths from the task is forwarded to the pack() function as the 5th argument, matching the new worker implementation.

@yamadashy yamadashy merged commit 1fc859c into main Oct 2, 2025
52 checks passed
@yamadashy yamadashy deleted the fix/stdin branch October 2, 2025 15:10
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.

The --stdin option does not seem to work

2 participants