
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Beautiful CLI spinners for long-running async tasks with nested subtask support. Built with Ink and React.
# bun
bun add livelines
# npm
npm install livelines
# pnpm
pnpm add livelines
# yarn
yarn add livelines
import LiveLine from 'livelines';
const ll = new LiveLine();
async function main() {
const task = ll.task('Installing dependencies...');
await install();
task.success('143 packages installed');
}
main();
Create subtasks by calling .task() on any task handle:
import LiveLine from 'livelines';
const ll = new LiveLine();
async function build() {
const build = ll.task('Building project...', { color: 'cyan' });
const compile = build.task('Compiling TypeScript...');
await compileTS();
compile.success('42 files compiled');
const bundle = build.task('Bundling for production...');
await bundleCode();
bundle.success('Bundle: 248kb');
build.success('Build completed');
}
Output:
✔ Building project... [3s]
✔ Compiling TypeScript... [1s]
42 files compiled
✔ Bundling for production... [2s]
Bundle: 248kb
Build completed
Update a task's message while it's running:
const upload = ll.task('Uploading files...');
for (const file of files) {
upload.update(`Uploading ${file}...`);
await uploadFile(file);
}
upload.success(`${files.length} files uploaded`);
Show recent messages for tasks with frequent updates using logLines:
const deploy = ll.task('Deploying...', { logLines: 3 });
deploy.update('Uploading index.html...');
deploy.update('Uploading app.js...');
deploy.update('Uploading styles.css...');
deploy.update('Uploading assets...');
// Shows the last 3 messages above the current one
new LiveLine()Creates a new LiveLine instance and begins rendering to the terminal.
liveline.task(name, options?)Creates a new top-level task.
Parameters:
name (string) — The task name/labeloptions (TaskOptions) — Optional configurationReturns: TaskHandle
| Option | Type | Default | Description |
|---|---|---|---|
spinner | SpinnerName | SpinnerObject | 'dots' | Spinner style from cli-spinners or custom object |
color | string | 'green' | Task name color (any Ink/Chalk color) |
logLines | number | 0 | Number of previous messages to display |
showElapsed | boolean | true | Show elapsed time |
The object returned by .task() with the following methods:
.update(message)Update the task's current message.
task.update('Processing item 5 of 10...');
.success(message)Mark the task as successfully completed with a final message.
task.success('Completed successfully');
.error(message)Mark the task as failed with an error message.
task.error('Failed to connect to server');
.task(name, options?)Create a nested subtask.
const subtask = task.task('Subtask name...', { color: 'blue' });
Use any spinner from cli-spinners:
ll.task('Loading...', { spinner: 'aesthetic' });
ll.task('Downloading...', { spinner: 'arrow3' });
ll.task('Processing...', { spinner: 'bouncingBar' });
Or define your own:
ll.task('Custom spinner...', {
spinner: {
interval: 100,
frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
},
});
Use any color supported by Ink / Chalk:
ll.task('Info', { color: 'blue' });
ll.task('Warning', { color: 'yellow' });
ll.task('Processing', { color: 'cyan' });
ll.task('Deploy', { color: 'magenta' });
import LiveLine from 'livelines';
const ll = new LiveLine();
async function main() {
// Build phase
const build = ll.task('Building project...', { color: 'cyan' });
const install = build.task('Installing dependencies...', { color: 'blue' });
await sleep(1200);
install.success('143 packages installed');
const compile = build.task('Compiling source...');
const typescript = compile.task('TypeScript files...');
await sleep(800);
typescript.success('42 files compiled');
const styles = compile.task('Stylesheets...');
await sleep(400);
styles.success('12 files processed');
compile.success('Compilation complete');
build.success('Build completed in 3.7s');
// Deploy phase
const deploy = ll.task('Deploying to production...', { color: 'magenta' });
const upload = deploy.task('Uploading files...', { logLines: 3 });
for (const file of ['index.html', 'app.js', 'app.css']) {
upload.update(`Uploading ${file}...`);
await sleep(300);
}
upload.success('3 files uploaded');
deploy.success('Deployed to https://app.example.com');
}
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
main();
Please see CONTRIBUTING.md for contribution guidelines.
MIT
FAQs
CLI spinners for long running async proccesses
We found that livelines demonstrated a healthy version release cadence and project activity because the last version was released less than 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
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.