
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
cli-inspector
Advanced tools
A library to help test CLI. Originally intended to test inquirer.js driven CLIs.
npm install cli-inspector
const inspector = require('cli-inspector');
inspector.run(
cmd_line, // command-line to spawn child process
interactions, // array of Interactions (see below)
options // extends child_process.spawnOptions
);
The gif below shows a build of cli-inspector, including tests, which use cli-inspector to test an example inquirer.js pizza-ordering application.

cli-inspector exposes a single method - run(). The idea is to provide it an
array of in-sequence CLI interaction.
An example interactions array: src/test/fixtures/inquirer/interactions.js.
/**
* run an cli-test.
* 1. spawn a child process with the cmd_line specified.
* 2. Provide an array of individual interactions. See [tests](test/fixtures/inquirer/interactions.ts)
* for a working example. `npm run build` to see it in action.
* interactions.forEach( (interaction) => {
* - wait for the prompt on interaction.stdout (string/regexp)
* - pipe interaction.input to stdin
* - wait for interaction.stdout/interaction.stderr if specified.
* rinse and repeat
* 3. Options provide control over the inspector and the child_process.
* The most important control provided by `cli-inspector` are
* - `delta`, the polling interval. Defaults to 1000
* - `timeout`, the time to wait in ms till
* @export
* @param {string} cmd_line
* @param {Interaction[]} interactions
* @param {Options} [options]
*/
export async function run(
cmd_line: string,
interactions: Interaction[],
options?: Options
);
export interface Interaction {
/**
* await prompt before processing this element
*
* @type {(string | RegExp)}
*/
prompt: string | RegExp;
/**
* when prompt found, input is piped into stdin of child process.
* If an array, each element is sent with the delta timeout
*
* @type {((string | RegExp)[] | (string | RegExp))}
*/
input: (string | RegExp)[] | (string | RegExp);
/**
* (Optional) message to await on stdout of child process, after input
*
* @type {(string | RegExp)}
*/
stdout?: string | RegExp;
/**
* (Optional) message to await on stderr of child process, after input
*
* @type {(string | RegExp)}
*/
stderr?: string | RegExp;
/**
* optional timeout for this step.
*
* @type {(number | null)}
* @default (value of options.timeout)
*/
timeout?: number | null;
/**
* debug this step only. useful to find problems deep in an interaction chain.
*
* @type {boolean}
* @default false
*/
debugStep?: boolean;
}
export interface Options extends SpawnOptions {
/**
* prints all child_process stdin/stdout/stderr to process stdout/stderr
*
* @type {boolean}
* @default false
*/
debug?: boolean;
/**
* Total timeout for each prompt-input-response sequence.
* Specified in milliseconds
* Can also be customized per interaction, but this sets the default value
* for all interactions when not specified.
*
* @type {number}
* @default 5000
*/
timeout?: number;
/**
* delta time between polling intervals and between keyboard sequences.
* Specified in milliseconds
*
* @type {number}
* @default 1000
*/
delta?: number;
/**
* Normally, the child process is killed on exit. This allows control.
* Generally, this is not very useful except for interactive debugging.
*
* @type {boolean}
* @default false
*/
killOnExit?: boolean;
}
CLIs have control sequences that make exact matching very cumbersome to create and maintain. It's much more convenient to use RegExps with wildcards and keywords.
This works well, but a few cautions:
[\s\S]* to .* with regular expressions that match multi-line strings with terminal control characters.^?[]()-{}!,*.\n at column 80. The spawn operation however does not expose the underying TTY or control over it. Until we find a way around, the simplest thing is to add the [\n]? as an optional character in the match sequence.cli-inspector adds a details object to erros thrown. Specifically, details.transcript, which records a step-by-step pattern match, making it easier to see what is actually being seen. A sample is shown below:// Using err.details to get inspector state and debugging insight.
try {
inspector.run(cmd_line, interactions, options);
} catch (err) {
console.log(JSON.stringify(err.details, null, 2));
throw err;
}
git clone https://github.com/tufan-io/cli-inspector
cd cli-inspector
npm i
npm run build
+---------------+
| cli-inspector | +---------------+
| | stdin | child process |
| +----------------------> |
| | stdout | |
| <----------------------+ |
| | stderr | |
| <----------------------+ |
+---------------+ +---------------+
There are multiple debug controls provided, please look at the code or ask questions!
Apache 2.0
Bugs, PRs, comments, suggestions welcomed!
FAQs
Automate CLI testing with style
The npm package cli-inspector receives a total of 3 weekly downloads. As such, cli-inspector popularity was classified as not popular.
We found that cli-inspector demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.