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

@lewishowles/cli-style

v0.8.0

Published

Shared terminal output styles for Lewis Howles tools, diagnostics, and package CLIs.

Readme

CLI style

Shared terminal output styles for local tools, diagnostics, agent-facing reports, and package CLIs.

Use it directly from JavaScript, or call the same renderers from Bash, Python, and Swift through the cli-style binary.

Requirements

  • Bun and Node.js 20 or newer for JavaScript projects and local binary builds
  • The standalone cli-style binary for Bash, Python, or Swift projects that should not install Bun

Install

JavaScript projects can install the package directly:

bun add @lewishowles/cli-style

Bash, Python, and Swift projects call the cli-style binary through thin adapters. If the project already has Node or Bun tooling, add this package as a dev dependency and use the package binary. Otherwise, install or vendor the standalone binary and put it on PATH:

export PATH="/path/to/cli-style/bin:$PATH"

Build a standalone binary when a repo should not need Bun at runtime:

bun run build:binary
bun run smoke:binary

Create a binary install tarball:

bun run package:binary
tar -tzf dist/release/cli-style-*.tar.gz

The package contains bin/cli-style and adapters/.

Choose an integration

All renderers return text. JavaScript imports functions directly. CLI, Bash, Python, and Swift integrations pass JSON-compatible data to a named renderer.

JavaScript

Create the ui instance at the CLI entrypoint, then pass ui.options to renderers. That keeps flag, environment, stream, colour, Unicode, and width detection in one place.

import { createCliStyle, status } from "@lewishowles/cli-style";

const ui = createCliStyle({
	argv: process.argv.slice(2),
	env: process.env,
	stdout: process.stdout,
});

const output = status("success", "184 tests", {
	...ui.options,
	label: "Build passed",
});

ui.print(output);

Renderer methods return strings. ui.print(), ui.write(), and CLI commands handle stdout and stderr.

CLI render

Use cli-style render <renderer> when a script needs rendered text from JSON input:

cli-style render status --profile diagnostic <<'JSON'
{
  "type": "success",
  "label": "Build passed",
  "detail": "184 tests"
}
JSON

Use renderer names from the tables below, for example status, row, diagnostic-report, or task-summary.

Bash

Source the Bash adapter, then use convenience helpers for common primitive and per-script pattern renderers:

source "$(cli-style adapter-path bash)"

label='Build "passed"'
detail="/path/to/project"

cli_style_status success "$label" "$detail" --profile diagnostic
cli_style_row "Workspace" "$detail" --plain
cli_style_row "Bundle" "is 22.3 KB, above the 12.0 KB budget" failed --plain
command="$(cli_style_span "npm run docs:readme" info --plain)"
cli_style_hint "Run $command before release" --plain
cli_style_divider "Project setup" --plain

cli_style_command_result success "Build passed" "bun run test:unit" 0 "1.2s" "184 tests" --plain
cli_style_task_summary partial "Adopt cli-style" "Bash wrappers added" "Updated adapter" "Update scripts" --plain
cli_style_confirmation_result confirmed "Publish release" "v0.6.0" "Tag push starts npm publish" --plain
cli_style_next_step_block "Update helpers scripts" "Wrappers are now available" "scripts/setup.sh --check" "" --plain

The convenience functions build JSON internally, so callers do not need to escape quotes, backslashes, or paths by hand.

Set CLI_STYLE_BIN when cli-style is not on PATH:

CLI_STYLE_BIN="/path/to/cli-style" cli_style_status success "Build passed" "" --plain

Use cli_style_render for literal or prebuilt JSON, especially for aggregate patterns or multi-item pattern fields:

cli_style_render diagnostic-report --profile diagnostic <<'JSON'
{
  "title": "Release checks",
  "checks": [
    {
      "name": "README",
      "result": "success"
    }
  ]
}
JSON

Python

Add the adapter directory to PYTHONPATH, then import the generic render() helper or convenience functions:

export PYTHONPATH="$(cli-style adapter-path python):$PYTHONPATH"
from cli_style import status, row, span, hint, divider

kwargs = {"binary": "./bin/cli-style.js", "plain": True}

print(status("success", "Build passed", "184 tests", **kwargs))
print(row("Workspace", "/path/to/project", **kwargs))
print(row("Bundle", "over budget", "failed", **kwargs))
command = span("npm run docs:readme", "info", **kwargs)
print(hint(f"Run {command} before release", **kwargs))
print(divider("Project setup", **kwargs))

Convenience functions build the renderer payload internally, so callers pass plain Python strings without hand-building JSON.

Pass binary= when cli-style is not on PATH. The generic render() helper remains for aggregate patterns or multi-item fields:

from cli_style import render

output = render(
	"diagnostic-report",
	{
		"title": "Release checks",
		"checks": [{"name": "README", "result": "success"}],
	},
	profile="diagnostic",
)

print(output)

Swift

Add the adapter file to your Swift project, then use the CliStyle enum for convenience functions or the generic render method:

cli-style adapter-path swift
# Returns the path to CliStyle.swift for inclusion in your project
let options = CliStyleOptions(binary: "./bin/cli-style.js", isPlain: true)

print(try CliStyle.status(type: "success", label: "Build passed", detail: "184 tests", options: options))
print(try CliStyle.row(label: "Workspace", value: "/path/to/project", options: options))
print(try CliStyle.row(label: "Bundle", value: "over budget", result: "failed", options: options))
let command = try CliStyle.span(value: "npm run docs:readme", tone: "info", options: options)
print(try CliStyle.hint(message: "Run " + command + " before release", options: options))
print(try CliStyle.divider(label: "Project setup", options: options))

print(try CliStyle.commandResult(result: "success", summary: "Build passed", command: "bun run test:unit", exitCode: 0, duration: "1.2s", detail: "184 tests", options: options))
print(try CliStyle.taskSummary(result: "partial", task: "Adopt cli-style", summary: "Wrappers added", completed: "Updated adapter", remaining: "Update scripts", options: options))
print(try CliStyle.confirmationResult(state: "confirmed", action: "Publish release", item: "v0.6.0", detail: "Tag push starts npm publish", options: options))
print(try CliStyle.nextStepBlock(nextStep: "Update helpers scripts", reason: "Wrappers are now available", command: "scripts/setup.sh --check", alternative: "", options: options))

Convenience functions build the renderer payload internally, so callers pass plain Swift strings without hand-building JSON.

Pass binary: in CliStyleOptions when cli-style is not on PATH. The generic CliStyle.render(_:data:options:) method remains for aggregate patterns or multi-item fields:

let output = try CliStyle.render(
    "diagnostic-report",
    data: [
        "title": "Release checks",
        "checks": [["name": "README", "result": "success"]],
    ],
    options: CliStyleOptions(profile: "diagnostic")
)

print(output)

Available renderers

Renderer names are stable for cli-style render, cli_style_render, and Python render(). JavaScript uses camel-case function names.

| Renderer | JavaScript | Bash helper | Python helper | Swift helper | Purpose | | --------------------- | ------------------------------------- | ------------------------------------ | ---------------------------------- | -------------------------------------- | --------------------------------------------------------------- | | status | status(resultType, detail, options) | cli_style_status type label detail | status(type, label, detail) | CliStyle.status(type, label, detail) | Result line with symbol, label, and detail. | | row | row(label, value, options) | cli_style_row label value [result] | row(label, value, result) | CliStyle.row(label, value, result) | Aligned label/value row, optionally marked with a result state. | | span | span(value, tone, options) | cli_style_span value [tone] | span(value, tone) | CliStyle.span(value, tone) | Inline colour or weight for a word, command, file, or value. | | hint | hint(message, options) | cli_style_hint message | hint(message) | CliStyle.hint(message) | Informational hint line. | | divider | divider(options) | cli_style_divider label | divider(label) | CliStyle.divider(label) | Section divider with an optional label. | | command-result | commandResult(options) | cli_style_command_result ... | command_result(...) | CliStyle.commandResult(...) | Command execution outcome with exit code and duration. | | audit-finding | auditFinding(options) | cli_style_audit_finding ... | audit_finding(...) | CliStyle.auditFinding(...) | Structured audit finding with evidence and recommendation. | | task-summary | taskSummary(options) | cli_style_task_summary ... | task_summary(...) | CliStyle.taskSummary(...) | Task progress with completed and remaining items. | | confirmation-result | confirmationResult(options) | cli_style_confirmation_result ... | confirmation_result(...) | CliStyle.confirmationResult(...) | Confirmation outcome with action and item. | | next-step-block | nextStepBlock(options) | cli_style_next_step_block ... | next_step_block(...) | CliStyle.nextStepBlock(...) | Next-step guidance with command and alternative. | | chip | chip(label, tone, options) | Use cli_style_render | Use render("chip", ...) | Use CliStyle.render | Compact labelled state. | | panel | panel(options) | Use cli_style_render | Use render("panel", ...) | Use CliStyle.render | Framed content block for grouped output. | | table | table(options) | Use cli_style_render | Use render("table", ...) | Use CliStyle.render | Tabular records with narrow-width fallback. | | progress-bar | progressBar(options) | Use cli_style_render | Use render("progress-bar", ...) | Use CliStyle.render | Single progress value with numeric text. | | bar-chart | barChart(options) | Use cli_style_render | Use render("bar-chart", ...) | Use CliStyle.render | Multi-row bar chart. | | step | step(label, state, options) | Use cli_style_render | Use render("step", ...) | Use CliStyle.render | One workflow step. | | step-progress | stepProgress(options) | Use cli_style_render | Use render("step-progress", ...) | Use CliStyle.render | Numbered workflow steps. | | empty-state | emptyState(title, detail, options) | Use cli_style_render | Use render("empty-state", ...) | Use CliStyle.render | Empty result message. | | error-block | errorBlock(title, lines, options) | Use cli_style_render | Use render("error-block", ...) | Use CliStyle.render | Structured error block. |

Use render("<renderer>", data, ...) (Python) or CliStyle.render(_:data:options:) (Swift) for aggregate patterns (diagnostic-report, agent-transcript, compact-data-table) or any renderer with multi-item fields.

Primitive data shapes

Use these shapes with cli-style render, cli_style_render, or Python render(). JavaScript callers pass the listed function arguments directly.

status

{
	"type": "success",
	"label": "Build passed",
	"detail": "184 tests"
}
  • type: one of the result types listed below
  • label: optional label override
  • detail: optional text after the label

row

{
	"label": "Bundle",
	"value": "is 22.3 KB, above the 12.0 KB budget",
	"result": "failed",
	"labelWidth": 8
}
  • label: left-hand label
  • value: right-hand value
  • result: optional result type for a symbol and tone
  • labelWidth: optional minimum label width
  • labelColour, valueColour, separator: optional presentation overrides

span

{
	"value": "npm run docs:readme",
	"tone": "info"
}
  • value: inline text to emphasise
  • tone: optional tone, defaulting to info
  • weight: optional ANSI style, defaulting to bold

hint

{
	"message": "Run npm run docs:readme before release"
}

Pre-render a span when only part of the hint needs emphasis.

Structured primitives

| Renderer | Main fields | | --------------- | -------------------------------------- | | divider | label, dividerWidth, character | | chip | label, tone | | panel | title, lines, tone, panelWidth | | table | columns, rows, width | | progress-bar | value, max, barWidth, tone | | bar-chart | rows, barWidth | | step | label, state | | step-progress | steps, current | | empty-state | title, detail | | error-block | title, lines |

For visual examples, run cli-style gallery --section primitives.

Patterns

Patterns are built-in composite renderers for common report shapes. They use the same lower-level primitives internally, but accept structured objects so callers do not need to assemble panels, statuses, tables, and rows by hand.

| Renderer | JavaScript | Purpose | Main fields | | --------------------- | ------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------ | | diagnostic-report | diagnosticReport(report, options) | Aggregate check report. | title, checks, findings, skippedChecks, nextActions | | command-result | commandResult(result, options) | Single command outcome with metadata. | title, result, summary, command, exitCode, duration, details | | audit-finding | auditFinding(finding, options) | Single audit finding. | title, result, finding, location, evidence, recommendation, references | | task-summary | taskSummary(summary, options) | Completed and remaining task summary. | title, task, result, summary, completed, remaining | | agent-transcript | agentTranscript(transcript, options) | User, agent, and tool transcript. | title, entries | | confirmation-result | confirmationResult(confirmation, options) | Confirmation outcome with detail. | title, state, action, item, detail | | next-step-block | nextStepBlock(nextStep, options) | Next-step guidance. | title, next, reason, commands, alternatives | | compact-data-table | compactDataTable(data, options) | Titled compact data table. | title, summary, columns, rows |

For visual examples, run cli-style gallery --section patterns.

The Bash adapter also exposes scalar convenience wrappers for per-script usage:

| Bash helper | Renderer | Arguments before render flags | | ------------------------------- | --------------------- | -------------------------------------------------------------------------- | | cli_style_command_result | command-result | result, summary, command, exit_code, duration, detail | | cli_style_audit_finding | audit-finding | result, finding, location, recommendation, evidence, reference | | cli_style_task_summary | task-summary | result, task, summary, completed, remaining | | cli_style_confirmation_result | confirmation-result | state, action, item, detail | | cli_style_next_step_block | next-step-block | next, reason, command, alternative |

Pass an empty string for optional positional fields you want to skip. Use cli_style_render or cli_style_render_json for aggregate reports, tables, transcripts, and multi-item arrays.

Swift equivalents are available as CliStyle.commandResult(...), CliStyle.auditFinding(...), CliStyle.taskSummary(...), CliStyle.confirmationResult(...), and CliStyle.nextStepBlock(...). Use CliStyle.render for aggregate reports, tables, transcripts, and multi-item arrays.

Pattern example

JavaScript:

import { createCliStyle, diagnosticReport } from "@lewishowles/cli-style";

const ui = createCliStyle({
	argv: process.argv.slice(2),
	env: process.env,
	stdout: process.stdout,
});

const output = diagnosticReport(
	{
		title: "Release checks",
		checks: [
			{
				name: "README",
				result: "success",
			},
			{
				detail: "object-BmsQavd_.js over budget",
				name: "Package size",
				result: "failed",
			},
		],
		findings: [
			{
				message: "dist/object-BmsQavd_.js is 22.3 KB, above the 12.0 KB budget",
				result: "failed",
			},
		],
		nextActions: ["Reduce package size, or raise the budget with a release-note-worthy reason."],
	},
	ui.options,
);

ui.print(output);

CLI:

cli-style render diagnostic-report --profile diagnostic <<'JSON'
{
  "title": "Release checks",
  "checks": [
    {
      "name": "README",
      "result": "success"
    },
    {
      "name": "Package size",
      "result": "failed",
      "detail": "object-BmsQavd_.js over budget"
    }
  ],
  "findings": [
    {
      "result": "failed",
      "message": "dist/object-BmsQavd_.js is 22.3 KB, above the 12.0 KB budget"
    }
  ],
  "nextActions": [
    "Reduce package size, or raise the budget with a release-note-worthy reason."
  ]
}
JSON

Python:

from cli_style import render

output = render(
	"diagnostic-report",
	{
		"title": "Release checks",
		"checks": [
			{
				"name": "README",
				"result": "success",
			},
			{
				"name": "Package size",
				"result": "failed",
				"detail": "object-BmsQavd_.js over budget",
			},
		],
		"findings": [
			{
				"result": "failed",
				"message": "dist/object-BmsQavd_.js is 22.3 KB, above the 12.0 KB budget",
			},
		],
		"nextActions": [
			"Reduce package size, or raise the budget with a release-note-worthy reason.",
		],
	},
	profile="diagnostic",
)

Reporter

Use a reporter when a JavaScript script needs grouped output built over time.

import { createReporter } from "@lewishowles/cli-style";

const reporter = createReporter({
	colour: false,
});

reporter.divider("Project setup", "Claude + Codex");
reporter.group(
	"Agent scripts",
	[
		{
			label: "project-diagnostics.py",
			result: "unchanged",
		},
		{
			label: "repo-context.py",
			result: "unchanged",
		},
	],
	{
		summary: "2 already linked",
	},
);
reporter.status("success", "Done.");

console.log(reporter.render());

Use reporter.divider() for major phases. Use reporter.section() for a normal info status row inside a phase. Panels are for framed content blocks, not headings.

Groups can include verbose detail rows when a caller opts in:

const reporter = createReporter({
	verbose: process.env.AGENTS_VERBOSE === "1",
});

Options and flags

JavaScript options

Most renderers accept the same output options:

| Option | Purpose | | --------- | ------------------------------------------------------------------------- | | profile | Output profile: human, agent, diagnostic, ci, plain, or json. | | colour | Whether ANSI colour should be applied. | | unicode | Whether Unicode symbols should be used. | | width | Available output width for renderers that adapt layout. |

Use createCliStyle() to resolve these options from argv, env, stdout, CI, TTY, NO_COLOR, and terminal capability.

CLI and Bash flags

| Flag | Purpose | | ---------------------------- | -------------------------------------- | | --profile <name> | Render with a named profile. | | --plain | Disable colour and Unicode decoration. | | --no-colour / --no-color | Disable ANSI colour. | | --no-unicode | Use ASCII symbols. | | --width <columns> | Override detected output width. |

cli-style render rejects --json. JSON profile behaviour is for library calls and machine-readable commands.

Python options

| Argument | Purpose | | ------------ | ------------------------------------------------ | | profile | Render with a named profile. | | width | Override detected output width. | | plain | Disable colour and Unicode decoration. | | no_colour | Disable ANSI colour. | | no_unicode | Use ASCII symbols. | | binary | Path or command name for the cli-style binary. | | extra_args | Extra CLI arguments to pass through. |

Swift options

Swift options are passed via the CliStyleOptions struct:

| Property | Purpose | | ------------- | ------------------------------------------------ | | binary | Path or command name for the cli-style binary. | | profile | Render with a named profile. | | width | Override detected output width. | | isPlain | Disable colour and Unicode decoration. | | isNoColour | Disable ANSI colour. | | isNoUnicode | Use ASCII symbols. | | extraArgs | Extra CLI arguments to pass through. |

Profiles

| Profile | Behaviour | | ------------ | --------------------------------------------------------------------------------- | | human | Colour and Unicode when supported; compact but visually pleasant. | | agent | Markdown-like, structured, easy to quote or parse. | | diagnostic | Optimised for check summaries, findings, skipped checks, and next actions. | | ci | Stable, grep-friendly, no decorative panels; colour off unless explicitly forced. | | plain | No ANSI, no Unicode dependency, simple text layout. | | json | Machine-readable only; library calls return structured data unchanged. |

Result types and tones

Result types drive symbols, labels, priority, and semantic colour:

| Result | Label | Unicode | ASCII | Tone | | ----------- | --------- | ------- | ----- | --------- | | success | Success | | OK | success | | info | Info | | > | info | | warning | Warning | | ! | warning | | partial | Partial | | ! | warning | | unchanged | Unchanged | | - | muted | | skipped | Skipped | | - | muted | | unknown | Unknown | ? | ? | muted | | failed | Failed | × | x | danger |

Tone values used by public APIs include info, success, warning, danger, and muted.

Gallery

Use the gallery to review current renderer output:

cli-style gallery
cli-style gallery no-colour
cli-style gallery --section primitives
cli-style gallery --section patterns
cli-style gallery --fixture audit-finding
cli-style gallery --profile agent
cli-style gallery --width 64
cli-style gallery --variants

Use --interactive to select a section or fixture with fzf when it is installed.