chopup
v1.1.2
Published
A tool to wrap long-running processes and chop their logs based on file changes.
Readme
chopup
A CLI tool to wrap long-running processes, chop output into segments, and send input to the wrapped process via IPC.
Installation (Recommended: Global)
Install globally with pnpm:
pnpm add -g chopupOr, to use directly with npx:
npx chopup run -- <command-to-wrap> [args...]Features
- Wraps and runs any user-specified command using the
runsubcommand (default). - Captures stdout and stderr from the wrapped process.
- Segments/chops logs into new files in a specified log directory on IPC request.
- Allows sending input strings to the stdin of the wrapped process via IPC.
- Graceful shutdown and bulletproof process tree cleanup.
- IPC server for on-demand log chopping and input sending.
- (EXPERIMENTAL) File/dir watching to trigger log chopping.
- (EXPERIMENTAL) Send initial input to the wrapped process on startup.
Usage (Global CLI)
chopup uses explicit subcommands: run (default), request-logs, and send-input.
1. Wrap a Process (using the run command)
This is the default command if no other subcommand is specified.
chopup run [--log-dir <log-dir>] [--socket-path <path>] [--initial-chop] [--watch-file <file-or-dir>] [--send <input>] [--verbose] -- <command-to-wrap> [args...]
# OR (since run is default):
chopup [--log-dir <log-dir>] [--socket-path <path>] [--initial-chop] [--watch-file <file-or-dir>] [--send <input>] [--verbose] -- <command-to-wrap> [args...]Example:
chopup run -- node my-interactive-app.js
# Or simply:
chopup -- node my-interactive-app.js--log-dir <path>: Directory to store chopped log files (optional, defaults to$CHOPUP_LOG_DIRor<system_temp_dir>/chopup/logs).--socket-path <path>: Path for the IPC socket file (optional, defaults to<log-dir>/chopup-<pid>.sock).--initial-chop: Perform an initial log chop immediately on startup (optional).--watch-file <file-or-dir>: (EXPERIMENTAL) Watch a file or directory for changes to trigger log chopping (optional).--send <input>: (EXPERIMENTAL) Send an initial input string to the wrapped process after startup (optional).--verbose: Enable verbose logging (optional).--: Separator before the command to wrap.<command-to-wrap> [args...]: The command and arguments to run (e.g.,node my-app.js).
What happens:
- The wrapped process runs.
- All stdout/stderr is captured by
chopup. - On startup,
chopupprints the IPC socket path to stdout:
(Note: The actual socket path is shown in this output. Use it for IPC commands.)CHOPUP_SOCKET_PATH=<path-to-socket> CHOPUP_PROCESS_READY - Log chopping and input sending only occur when requested via IPC using other
chopupcommands (see below).
2. Trigger Log Chopping via IPC (from another shell)
Use the request-logs command:
chopup request-logs --socket <socket-path>Example:
chopup request-logs --socket /tmp/chopup/logs/chopup-12345.sock--socket <socket-path>: The IPC socket path of the runningchopup runinstance (from its startup log output).
What happens:
- The tool connects to the running
chopup runinstance via its IPC socket. - It requests an immediate log chop.
- The string
LOGS_CHOPPEDis printed if logs were chopped, or a message if no new logs. - On error, prints
CHOPUP_REQUEST_LOGS_ERROR_NO_SERVERorCHOPUP_REQUEST_LOGS_ERROR_UNKNOWNto stderr.
3. Sending Input to the Wrapped Process via IPC (from another shell)
Use the send-input command:
chopup send-input --socket <socket-path> --input "<string-to-send>"Log Suppression Note:
- When running
send-input, only the following will be printed to stdout:CHOPUP_INPUT_SENT(on success)CHOPUP_INPUT_SEND_ERROR,CHOPUP_INPUT_SEND_ERROR_NO_CHILD, orCHOPUP_INPUT_SEND_ERROR_BACKPRESSURE(on failure)
- All other debug/info logs are suppressed for this command to ensure clean output for integration tests and scripting.
- Connection errors (e.g., invalid socket, exited process) are printed to stderr as
CHOPUP_INPUT_SEND_ERROR_NO_SERVERorCHOPUP_SEND_INPUT_ERROR_CONNECTION_FAILED.
Example:
Suppose my-interactive-app.js prompts "Are you sure? (y/n): ".
chopup send-input --socket /tmp/chopup/logs/chopup-12345.sock --input "y\n"--socket <socket-path>: The IPC socket path of the runningchopup runinstance.--input "<string-to-send>": The string to send to the wrapped process's stdin.- Important: If your wrapped process expects a newline to process the input (common for CLI prompts), make sure to include
\nin your input string, e.g.,"y\n"or"some text then enter\n".
- Important: If your wrapped process expects a newline to process the input (common for CLI prompts), make sure to include
What happens:
- Connects to the
chopup runinstance via IPC. - Sends the specified string to the stdin of the process
chopupis wrapping. - The
send-inputcommand will print a confirmation (e.g.,CHOPUP_INPUT_SENT) or an error message. No other logs will be printed.
Exhaustive Example Workflows
Basic Interactive Example
Start
chopup runin one shell with an interactive script:chopup -- node examples/interactive-script.js- Note the
CHOPUP_SOCKET_PATH=...printed on startup.
- Note the
From another shell, send input to the script:
chopup send-input --socket <socket-path> --input "Alice\n"Observe
interactive-script.jsin the first shell receiving the input and printing it.From another shell, trigger a log chop:
chopup request-logs --socket <socket-path>Check the log directory for segmented log files.
Run with Custom Log Directory
chopup --log-dir ./my-logs -- node examples/interactive-script.jsRun with Initial Input (EXPERIMENTAL)
chopup --send "hello world\n" -- node examples/interactive-script.jsRun with File Watching (EXPERIMENTAL)
chopup --watch-file ./trigger.txt -- node examples/long-running-script.js
# Touch or modify trigger.txt in another shell to trigger a log chopRun with Specific Socket Path
chopup --socket-path /tmp/my-custom.sock -- node examples/interactive-script.js
# Use /tmp/my-custom.sock for send-input and request-logsRun with Verbose Logging
chopup --verbose -- node examples/interactive-script.js
# See extra [DEBUG] and [DEBUG_SOCKET] logsRun with Initial Log Chop
chopup --initial-chop -- node examples/long-running-script.jsLocal Development Usage (Alternative)
If you have chopup cloned locally:
Run/Wrap a process:
pnpm start -- run [--log-dir <log-dir>] [--socket-path <path>] [--initial-chop] [--watch-file <file-or-dir>] [--send <input>] [--verbose] -- <command-to-wrap> [args...]
# Or (since run is default):
pnpm start -- [--log-dir <log-dir>] [--socket-path <path>] [--initial-chop] [--watch-file <file-or-dir>] [--send <input>] [--verbose] -- <command-to-wrap> [args...]Request Logs via IPC:
pnpm start -- request-logs --socket <socket-path>Send Input via IPC:
pnpm start -- send-input --socket <socket-path> --input "<string-to-send>"Troubleshooting
- No logs are chopped: You must use the
chopup request-logs --socket <path>command. - Input not sent / IPC not working:
- Ensure you are using the correct IPC socket path from the running
chopup runinstance's output (CHOPUP_SOCKET_PATH=...). - Verify the
chopup runinstance is still running. - Ensure the wrapped application is actually waiting for stdin if you are using
send-input. - For
send-input, onlyCHOPUP_INPUT_SENT,CHOPUP_INPUT_SEND_ERROR,CHOPUP_INPUT_SEND_ERROR_NO_CHILD, orCHOPUP_INPUT_SEND_ERROR_BACKPRESSUREwill be printed to stdout. Connection errors will be printed to stderr asCHOPUP_INPUT_SEND_ERROR_NO_SERVERorCHOPUP_SEND_INPUT_ERROR_CONNECTION_FAILED. All other logs are suppressed for this command.
- Ensure you are using the correct IPC socket path from the running
- Log files not appearing: Check permissions on the log directory and that the
chopup runprocess has not exited before logs could be written. - Process cleanup: All child processes are killed on exit. If not, use
tree-killor manually clean up. - Error Codes:
CHOPUP_INPUT_SEND_ERROR_NO_SERVER: Could not connect to the IPC socket (wrong path or process exited).CHOPUP_INPUT_SEND_ERROR: Failed to send input to the child process.CHOPUP_INPUT_SEND_ERROR_NO_CHILD: No child process available to send input.CHOPUP_INPUT_SEND_ERROR_BACKPRESSURE: Child process stdin buffer is full.CHOPUP_REQUEST_LOGS_ERROR_NO_SERVER: Could not connect to the IPC socket for log chopping.CHOPUP_REQUEST_LOGS_ERROR_UNKNOWN: Unknown error during log chopping request.CHOPUP_SEND_INPUT_ERROR_CONNECTION_FAILED: General connection failure for send-input.CHOPUP_SEND_INPUT_ERROR_UNEXPECTED_RESPONSE: Unexpected response from server.CHOPUP_SEND_INPUT_ERROR_SERVER_PARSE: Server could not parse the IPC message.CHOPUP_SEND_INPUT_ERROR_UNEXPECTED_CLOSE: IPC connection closed unexpectedly.
Development
- Format:
pnpm format - Lint:
pnpm lint - Test:
pnpm test - Build:
pnpm build(createsdist/index.js)
Verifying Examples
All example scripts referenced above are in the examples/ directory:
examples/interactive-script.js: Simple script that prints input it receives.examples/long-running-script.js: Script that logs periodically.
To verify the CLI and README examples:
- Open two or more terminals in the project root.
- In one terminal, run a
chopupexample (see above). - In another terminal, use
chopup send-inputorchopup request-logsas shown. - Check the output and log files in the specified log directory.
A helper script examples/verify-examples.sh is provided to automate these checks for CI or local verification.
License
ISC
CI/CD & Release
- All PRs and pushes run CI (build, test, cross-platform smoke test).
- Merges to
maintrigger semantic-release:- Version bump, changelog, and npm publish (public).
- Requires
NPM_TOKENsecret in repo settings. - Uses Conventional Commits for changelog and versioning.
- Excessive logging is enabled in CI and release for observability.
Local Release Test
pnpm run release --dry-runNPM Publish
- Set
NPM_TOKENin GitHub repo secrets for publish to work. publishConfig.accessis set topublicin package.json.
