Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

Command output capture and preview

Run a finite test or build command to completion, retain all of its stdout and stderr in a private temporary file, display its first 120 lines, and return the command's exit code. The wrapper was tested on macOS. It is intended for Linux but has not been tested there. It requires a POSIX shell, mktemp and head.

Download or copy preview-run.sh into any convenient local directory. It does not need to be inside the project being tested.

For the script, tests and guide together, download the v0.1.0 source ZIP.

Run Vitest from your project

With Vitest already installed in your project, change to that project and put the wrapper before the exact command and arguments you would otherwise use:

cd /path/to/your-project
sh /path/to/preview-run.sh ./node_modules/.bin/vitest run src/example.test.ts

The script keeps that working directory and stdin. It invokes the command exactly once as the argument vector after preview-run.sh; it does not parse or evaluate a command string. Quote spaces and shell metacharacters at the calling shell, just as you would for a direct invocation:

sh /path/to/preview-run.sh node script.mjs '' 'two words' 'literal;value'

Before the command starts, stderr identifies the retained file:

Full output: /tmp/command-output.ABC123

Use the printed path to inspect late errors and the complete output, then remove the file when it is no longer needed:

less /tmp/command-output.ABC123
rm -- /tmp/command-output.ABC123

The preview goes to stdout. The log contains combined stdout and stderr in their captured order. A successful command returns 0; a normal nonzero command exit, including 127 when the command is not found, remains the wrapper's exit status. A preview error does not replace it. Calling the wrapper without a command returns 64. If the private log cannot be created, it returns 125 and does not run the command.

Scope and limits

This wrapper is for finite commands. Capture finishes before preview begins, so output is not live. It does not impose a timeout, supervise or kill processes, handle signals, or protect against SIGKILL and orphaned processes. It installs no dependencies, changes no persistent configuration, makes no network requests, uploads nothing, and does not delete the log automatically.

The retained file can grow to the command's complete output. The 120-line preview is neither a byte limit nor a storage limit. Because output is redirected to a file, programs may buffer or format it differently than they do in a terminal. Always inspect the log for messages after line 120.

This is an invocation workaround for the early pipe closure discussed in Vitest #11241. It avoids sending a live command directly through head; it does not repair Vitest's IPC handling or reproduce or fix the reported OOM race. The issue was closed on 18 September 2026 after a request for a working minimal reproduction. The maintainer could not reproduce the supplied case and rejected the proposed IPC fix. Do not treat that closure or the earlier linked proposal as a verified lifecycle fix. This wrapper remains useful only for its documented finite-command capture behavior.

Run checks

Node.js 20 or newer is required only for the tests. From the repository root:

node --test examples/command-output/preview-run.test.mjs
sh -n examples/command-output/preview-run.sh

The behavioral tests use a bounded local producer and real processes. They cover completion past the preview boundary, complete retained output, statuses 0, 7 and 127, exact argument, working-directory and stdin preservation, usage, log-creation failure, and preview failure. Direct integration with Vitest is outside this example's built-in test suite.

From the extracted ZIP's command-output directory, run node --test preview-run.test.mjs and sh -n preview-run.sh instead.

Separately checked on macOS with Node.js 24.19.0, Vitest 4.1.11 and 5.0.0, --pool=forks --maxWorkers=1 --reporter=verbose: both a passing and an intentionally failing finite test completed their afterAll hook. Their exit codes remained 0 and 1, respectively; all four runs displayed 120 lines while retaining late stderr and the final test summary in the log. This checks ordinary completion, not the reported dead-IPC/OOM race. Linux execution has not been checked here.

License

MIT. Use, modify and share the code, retaining the license notice.

Buy me a coffee, if this helped

This example is free. If it saves you some time and you feel like buying me a coffee, a small contribution is welcome and entirely optional. Useful feedback is appreciated too.

  • USDC / SOL · Solana: 9tY6D9mwcFaJwwzEHvw2v7nhSpdjqjNBYtuooyBN6rYy
  • USDC / ETH · Base: 0x568Ab98578d682FB0B0b45619BE73EbFfbf5a6eA
  • USDT · BNB Smart Chain (BEP20): 0x568Ab98578d682FB0B0b45619BE73EbFfbf5a6eA

Please use the asset and network shown above.