npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bro-code/tasks

v2026.2.1

Published

A task runner with animated progress bars, step spinners, child-process log capture, interactive prompt handling, and full configurability via bro.config — powered by @bro-code/logger.

Readme

@bro-code/tasks

npm version license

A task runner with animated progress bars, step spinners, child-process log capture, interactive prompt handling, and full configurability via bro.config — powered by @bro-code/logger.

Installation

npm install @bro-code/tasks

Quick Start

TypeScript

import { Task } from '@bro-code/tasks';

const task = new Task({ message: 'Deploying app', type: 'rocket' });

await task.step('Compile', async (ctx) => {
  ctx.log('tsc completed');
});

await task.step('Upload', async (ctx) => {
  await uploadFiles();
  ctx.log('3 files uploaded');
});

task.end();

JavaScript (ESM)

import { Task } from '@bro-code/tasks';

const task = new Task({ message: 'Setup project', type: 'build' });

await task.step('Install deps', async (ctx) => {
  ctx.log('npm install completed');
});

task.end();

JavaScript (CommonJS)

const { Task } = require('@bro-code/tasks');

const task = new Task({ message: 'Setup project', type: 'build' });

async function main() {
  await task.step('Install deps', async (ctx) => {
    ctx.log('npm install completed');
  });
  task.end();
}

main();

Features

  • Progress bar — animated bar at the top showing overall completion
  • Step spinners — each step gets its own spinner animation while running
  • Log capturectx.log() captures output displayed after step completion
  • Interactive promptsctx.prompt() and ctx.select() pause the animation for user input, then restore the clean display
  • Child process runnerrun() executes commands and pipes output into step logs
  • Conditional stepstask.set() accepts shouldAdd flags to skip steps
  • Error persistence — optionally write error details to .logs/ directory
  • Configurable — reads bro.config.json for defaults (spinner, colors, progress bar width, etc.)

API

new Task(options)

Create a new task runner.

| Option | Type | Default | Description | |--------|------|---------|-------------| | message | string | — | Required. Display message for the task | | type | string | 'default' | Icon type (maps to symbol table) | | spinner | string | 'pulseDot' | Spinner animation name | | frameInterval | number | 80 | Animation speed in ms | | progressBarWidth | number | 20 | Width of the progress bar | | showDuration | boolean | true | Show elapsed time per step | | showProgressBar | boolean | true | Show the overall progress bar | | showStepLogs | boolean | true | Show captured logs inline | | maxLogLines | number | 5 | Max log lines displayed per step | | persistErrors | boolean | false | Write errors to log files | | logDir | string | '.logs' | Directory for error log files | | activeColor | string | 'cyan' | Color for in-progress text | | successColor | string | 'green' | Color for success text | | failColor | string | 'red' | Color for failure text | | parallel | boolean | false | Run steps in parallel instead of sequentially | | stopOnFail | boolean | false | Stop remaining steps when a step fails (sequential only) |

task.step(name, fn, options?)

Add and execute a step. The function receives a StepContext:

await task.step('My step', async (ctx) => {
  ctx.log('Captured log line');
  const answer = await ctx.prompt('Enter value');
  const choice = await ctx.select('Pick one', ['A', 'B', 'C']);
});

// With a per-step spinner override:
await task.step('Loading', async () => { ... }, { spinnerName: 'braille' });

task.set(steps)

Execute conditional steps (matches the legacy API pattern):

await task.set([
  { name: 'Create .env',    shouldAdd: !envExists,  method: async () => { ... } },
  { name: 'Create SSL',     shouldAdd: !sslExists,  method: async () => { ... } },
  { name: 'Create database', shouldAdd: !dbExists,   method: async () => { ... } },
]);

task.run(steps)

Execute an array of step definitions:

await task.run([
  { name: 'Lint',  fn: async () => { ... } },
  { name: 'Test',  fn: async () => { ... }, enabled: false },
  { name: 'Build', fn: async () => { ... }, spinnerName: 'build' },
]);

Parallel Execution

Run all steps simultaneously:

const task = new Task({ message: 'Parallel work', parallel: true });
await task.run([
  { name: 'Download A', fn: async () => { ... } },
  { name: 'Download B', fn: async () => { ... } },
  { name: 'Download C', fn: async () => { ... } },
]);

Priority Steps

When running in parallel, mark steps as priority to execute them sequentially first before the remaining steps run in parallel:

const task = new Task({ message: 'Install deps', parallel: true });
await task.set([
  { name: 'Root',   priority: true, method: async () => { ... } },  // runs first
  { name: 'Server', method: async () => { ... } },                  // then these
  { name: 'Client', method: async () => { ... } },                  // run in parallel
]);

Also works with task.run():

await task.run([
  { name: 'Prepare', priority: true, fn: async () => { ... } },
  { name: 'Build A', fn: async () => { ... } },
  { name: 'Build B', fn: async () => { ... } },
]);

task.end()

Finalize the display. Called automatically by set() and run().

Stop on Failure

Abort remaining steps when a step fails. Skipped steps show a log explaining why:

const task = new Task({ message: 'Deploy', stopOnFail: true });
await task.set([
  { name: 'Build',   method: async () => { ... } },  // if this fails...
  { name: 'Upload',  method: async () => { ... } },  // ...these are skipped
  { name: 'Notify',  method: async () => { ... } },  // with "Skipped — Build failed"
]);

Also works with task.run():

const task = new Task({ message: 'Pipeline', stopOnFail: true });
await task.run([
  { name: 'Lint',  fn: async () => { ... } },
  { name: 'Test',  fn: async () => { ... } },
  { name: 'Build', fn: async () => { ... } },
]);

task.skip()

Mark remaining steps as skipped and finalize.

run(cmd, args, ctx?, opts?)

Execute a child process with log capture:

import { Task, run } from '@bro-code/tasks';

const task = new Task({ message: 'Building' });
await task.step('Compile', async (ctx) => {
  await run('tsc', ['--project', 'tsconfig.json'], ctx, { cwd: './packages/app' });
});
task.end();

runInteractive(cmd, args, opts?)

Run a command with stdio: 'inherit' for full interactivity.

Available Spinners

pulseDot basic braille arrows dots circles corners blocks bars triangle pulseC line quads moon clock globe build rocket files test security sync hourglass start tree clean load theme weather colors squares

Configuration

Add a tasks section to your bro.config.json:

{
  "logger": { ... },
  "tasks": {
    "spinner": "braille",
    "type": "default",
    "frameInterval": 100,
    "progressBarWidth": 30,
    "showDuration": true,
    "showProgressBar": true,
    "showStepLogs": true,
    "maxLogLines": 10,
    "activeColor": "cyan",
    "successColor": "green",
    "failColor": "red",
    "persistErrors": true,
    "logDir": ".logs",
    "parallel": false,
    "stopOnFail": false
  }
}

License

MIT © Bro Code Technologies

Changelog

[2026.2.1] - 2026-04-23

Fixed

  • CJS build: tsconfig.cjs.json corrected to emit real CommonJS output. The previous module: Node16 setting combined with "type": "module" caused TypeScript to emit ESM syntax (export {) into dist/cjs/, which broke require() in Node.js environments.

[2026.2.0] - 2026-04-19

Added

  • stopOnFail option — when enabled, remaining sequential steps are skipped after a failure with a log message explaining which step caused the abort

Fixed

  • Multi-line error messages (e.g. from failed child processes) no longer break the animation by miscounting rendered lines — error messages are now split into individual lines for correct cursor tracking
  • Skipped steps now display their captured logs (previously only success/fail steps showed logs)

[2026.1.2] - 2026-04-19

Documentation

  • Added usage examples for all options in the README

[2026.1.1] - 2026-04-19

Changed

  • Replaced console.log in prompt UI with @bro-code/logger

[2026.1.0] - 2026-04-19

Added

  • priority field on StepDefinition and ConditionalStep — when parallel: true, priority steps run sequentially first, then remaining steps run in parallel

[2026.0.1] - 2026-04-19

Fixed

  • Avoid Node.js DEP0190 warning by refactoring spawn argument handling in shell mode

[2026.0.0] - 2026-04-18

Added

  • Task class with animated progress bar and step spinners
  • ctx.log() for capturing step output
  • ctx.prompt() and ctx.select() for interactive input with animation pause/resume
  • run() helper for child process execution with log capture
  • runInteractive() for interactive child processes
  • task.set() for conditional step batches (legacy API compatible)
  • task.run() for step definition arrays
  • task.skip() to skip remaining steps
  • Configurable via bro.config.json tasks section
  • 30+ built-in spinner animations
  • Error persistence to log files
  • Duration tracking per step
  • Parallel step execution
  • Per-step spinner overrides
  • Dual ESM/CJS output with full TypeScript types