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

@tasteee/sheezy

v1.0.0

Published

A tiny, friendly shell runner with {{template}} interpolation, cwd tracking, and show / hide / intercept output. Every call returns a [result, error] tuple.

Readme

🐚 sheezy

A tiny, friendly shell runner for Node.

npm install @tasteee/sheezy

You want to run shell commands from a script. You want to drop variables into those commands without gluing strings together. You want cd to actually stick. And sometimes you want the output printed, sometimes hidden, sometimes handed to you.

Hi. I'm that library, it's me.

import { sheezy } from "@tasteee/sheezy";

const shell = sheezy.create();
await shell.run("npm run build");

shell.data.repoUrl = "https://github.com/tasteee/sheezy";
await shell.run("git clone {{repoUrl}}");

Just a run method that does the obvious thing.

Create a shell

A shell is a small object that remembers your working directory and your template data between calls.

const shell = sheezy.create();

You can hand it a starting directory, some data, and a few defaults:

const shell = sheezy.create({
  cwd: "/Users/you/projects",
  data: { branch: "main" },
  isSilent: false, // default is false
});

Everything is optional. With no arguments you get a shell with process.cwd() as the cwd and live output.

Run a command

const [result, runError] = await shell.run("ls -la");

run always returns a [result, error] tuple. No try/catch required. On success you get the result and a null error; on failure you get a null result and the error.

const [result, runError] = await shell.run("npm test");

if (runError) {
  console.error("tests failed", runError);
  return;
}

console.log(result.exitCode); // 0

The result is a plain object, the same shape every time:

type RunResultT = {
  command: string; // the command that ran (after interpolation)
  cwd: string; // the directory it ran in
  exitCode: number | undefined;
  stdout: string; // captured when hidden or intercepted
  stderr: string;
};

Interpolate from shell.data

Put {{placeholders}} in your command and sheezy fills them from shell.data before running. Set values however you like — up front, or as you go.

const shell = sheezy.create({ data: { folderName: "sheezy" } });

shell.data.repoUrl = "https://github.com/tasteee/sheezy";

await shell.run("git clone {{repoUrl}} {{folderName}}");
await shell.run("cd {{folderName}}");

Missing data quietly becomes an empty string. If you'd rather fail loudly when a placeholder has no value, just say so.

const shell = sheezy.create({ throwMissingData: true })
await shell.run("git clone {{repoUrl}}");
// throws: sheezy: missing template data for repoUrl

cd does the thing

cd is special. Instead of spawning a throwaway process that forgets where it went, sheezy updates shell.data.cwd and every later command runs from there.

const shell = sheezy.create();
await shell.run("cd packages/core");
await shell.run("npm install"); // runs inside packages/core

Chain it with && and the cd still applies to everything after it — the commands run one after another, left to right:

await shell.run("cd packages/core && npm install && npm run build");

Need an absolute path from the current directory? resolve tracks cwd too:

const buildDir = shell.resolve("dist"); // <cwd>/dist

Show it, hide it, or intercept it

By default, output streams straight to your terminal as it happens — exactly like you'd typed the command yourself.

await shell.run("npm run build"); // printed live

Pass isSilent to keep it quiet. Nothing prints, but it's still captured on the result so you can inspect it:

const [result] = await shell.run("npm run build", { isSilent: true });
console.log(result.stdout); // you have it, the terminal didn't

Or take the wheel completely with onOutput. You get every chunk of stdout and stderr as it arrives — log it, parse it, stream it to a UI, whatever:

await shell.run("npm run build", {
  onOutput: (output) => {
    progressBar.append(output);
  },
});

Run options, all together

await shell.run("deploy {{service}}", {
  isSilent: false, // hide output (default: false)
  onOutput: undefined, // intercept output chunk by chunk
  throwMissingData: false, // throw on missing {{placeholders}}
  shell: false, // hand the raw command to the system shell (see "Good to know")
  env: { NODE_ENV: "production" }, // extra environment variables
});

Any of these can also be set on sheezy.create(...) as defaults, and a per-run option always wins over the shell-level default.

Good to know

sheezy keeps command parsing simple and predictable. A command is split on spaces — quotes are not parsed. So this won't do what you might expect, the quotes are passed through as literal characters:

await shell.run('git commit -m "two words"'); // ⚠️ args: ["two, words]

When you need quotes, spaces inside an argument, pipes, globs, or redirects, turn on shell and let your system shell do the parsing:

await shell.run('git commit -m "two words"', { shell: true });

A few more things worth knowing:

  • && is a simple split. sheezy splits on && itself so cd can take effect between steps. It's textual, so avoid a literal && inside a quoted argument or an interpolated value.
  • & (parallel) isn't supported. Commands always run one at a time, left to right.
  • cd doesn't check the path. It updates data.cwd optimistically; a bad path surfaces as an error on the next command that runs there.

TypeScript

sheezy is written in TypeScript and ships its own types. The handy ones are exported if you want them:

import { sheezy } from "@tasteee/sheezy";
import type {
  ShellT,
  ShellDataT,
  ShellOptionsT,
  RunOptionsT,
  RunResultT,
  RunReturnT,
} from "@tasteee/sheezy";

Notes

  • ESM only. sheezy is published as an ES module. import, not require.
  • Node 18.19+ (it builds on execa 9).
  • && runs commands sequentially and stops at the first failure.

License

MIT © tasteee