askeroo
Version:
A modern CLI prompt library with flow control, history navigation, and conditional prompts
91 lines • 3.36 kB
JavaScript
import { spawn } from "child_process";
import { EventEmitter } from "events";
/**
* Spawn a command with automatic color preservation
*
* This function automatically enables ANSI colors in command output by:
* 1. Using node-pty if available (creates real pseudo-TTY)
* 2. Falling back to environment variables (FORCE_COLOR, etc.)
*
* @param command - Command to run
* @param args - Command arguments
* @param options - Additional spawn options
* @returns EventEmitter with stdout, stderr streams and events
*
* @example
* ```typescript
* const git = spawnWithColors("git", ["status"]);
* git.stdout.on("data", (data) => output.write(data.toString()));
* git.on("close", (code) => console.log("Exit code:", code));
* ```
*/
export function spawnWithColors(command, args = [], options = {}) {
// Try to use node-pty if available (best solution - real pseudo-TTY)
try {
const pty = require("node-pty");
// Combine command and args for pty
const fullCommand = [command, ...args].join(" ");
const ptyProcess = pty.spawn(command, args, {
name: "xterm-color",
cols: process.stdout.columns || 80,
rows: process.stdout.rows || 24,
cwd: options.cwd || process.cwd(),
env: { ...process.env, ...options.env },
});
// Create an EventEmitter to match spawn interface
const emitter = new EventEmitter();
// Create readable streams for stdout (pty combines stdout/stderr)
const { Readable } = require("stream");
const stdoutStream = new Readable({
read() { },
});
const stderrStream = new Readable({
read() { },
});
// Forward pty data to stdout stream
ptyProcess.onData((data) => {
stdoutStream.push(data);
});
// Handle exit
ptyProcess.onExit(({ exitCode, signal }) => {
stdoutStream.push(null); // End stream
stderrStream.push(null);
emitter.emit("close", exitCode, signal);
});
emitter.stdout = stdoutStream;
emitter.stderr = stderrStream;
emitter.pid = ptyProcess.pid;
return emitter;
}
catch (error) {
// node-pty not available or failed, fall back to regular spawn with color env vars
}
// Fallback: Use regular spawn with color-forcing environment variables
const colorEnv = {
...process.env,
...options.env,
// Force colors for various tools
FORCE_COLOR: "1",
CLICOLOR_FORCE: "1",
// npm/yarn specific
npm_config_color: "always",
// Git specific
GIT_CONFIG_PARAMETERS: "'color.ui=always'",
};
const proc = spawn(command, args, {
...options,
env: colorEnv,
});
// Create an EventEmitter to wrap the spawn result
const emitter = new EventEmitter();
// Forward all events from the child process
proc.on("close", (code, signal) => emitter.emit("close", code, signal));
proc.on("error", (err) => emitter.emit("error", err));
proc.on("exit", (code, signal) => emitter.emit("exit", code, signal));
// Attach streams
emitter.stdout = proc.stdout;
emitter.stderr = proc.stderr;
emitter.pid = proc.pid;
return emitter;
}
//# sourceMappingURL=spawn-with-colors.js.map