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 🙏

© 2025 – Pkg Stats / Ryan Hefner

mugo

v1.4.4

Published

Node.js scripting library

Readme

Mugo

Mugo makes scripting in node.js easy and intuitive. It provides a clear API for running commands locally as well as remotely over SSH, and includes helper functions to help with common situations. It keeps the simple cases simple, while still supporting more complex uses without a heavy syntactic burden.

Mugo makes use of the new async/await features of Javascript, and so requires at least Node 8.

Examples

Local

The standard run and sudo functions return promises, so for simple cases you can just do the following:

const { run } = require('mugo');

run('whoami').then(me => {
    console.log(`Hello, ${me}!`);
})

If you want to run a series of commands and do things with the results in between, you should use the async/await features.

const { run, sudo } = require('mugo');

async function main() {
    let me = await run('whoami');
    console.log(`Hello, local ${me}!`);

    let my_info = await sudo(`grep ${me} /etc/shadow`);
    console.log('My shadow entry:');
    console.log(my_info);
}

main();

In addition to using the run and sudo functions right from the module, you can make a new local instance to use.

const mugo = require('mugo');

let local = mugo.local({/* default options */});

local.run('whoami');

You can also change the options for the default functions, or for your local instance, using the defaults method.

const mugo = require('mugo');

mugo.defaults({/* new default options */});

let local = mugo.local({/* default options */});

local.defaults({/* new default options */});

Any option you provide can be overridden for a single run or sudo.

const { run } = require('mugo');

run('cat fstab', { cwd: '/etc' });

By default, using sudo will prompt for your password as it would on the command line. You can also provide a password for sudo to use. If you provide a password and the save_pass option, it will remember that password for subsequent sudo calls.

const { sudo } = require('mugo');

// only for this call
sudo('whoami', { sudo_pass: 'supersecret' });

// for this and all subsequent calls
sudo('ls -l /root', { sudo_pass: 'supersecret', save_pass: true });

If you pass a sudo password into the default options, it will be used for every sudo call. This can be done up front when creating a new local, or after the fact using the defaults method.

const mugo = require('mugo');

let local = mugo.local({ sudo_pass: 'supersecret' })
local.sudo('whoami') // won't prompt for password

let { sudo, defaults } = mugo;
defaults({ sudo_pass: 'supersecret' });
sudo('whoami'); // won't prompt for password

There are also local sync methods, which have the same interface but return the actual results of the commands, rather than a promise.

const {run_sync, sudo_sync} = require('mugo');

let me = run_sync('whoami');
console.log(`Hello, local ${me}!`);

let my_info = sudo_sync(`grep ${me} /etc/shadow`);
console.log('My shadow entry:');
console.log(my_info);

It also supports passing in streams for stdin, stdout, and/or stderr. You can also provide a string for stdin. You can read from the stdout and stderr streams and write to the stdin stream to have asynchronous communication with a running command.

const { run } = require('mugo');
let stdin = new Readable();
let stdout = new Writable();
let stderr = new Writable();

let out = run('something-interactive', {stdin, stdout, stderr});

stdout.on('data', output => {
    if(/*something about 'output' is true*/){
        stdin.write('some input');
    }
});

await out;

Remote

The remote api mostly mirrors the local api, although there are no sync functions, and to do remote calls, you need to create a remote instance first. The simplest case just requires a uri and a password.

let r = require('mugo').remote({
    uri: '[email protected]',
    pass: mugo.prompt_pass_sync(),
});

r.run('whoami').then(me => {
    console.log(`Hello, far-away ${me}!`);)

    r.end(); // must call end or node will hang forever
});

You can also use async/await.

let r = require('mugo').remote({
    uri: '[email protected]',
    pass: mugo.prompt_pass_sync(),
});

async function main() {
    let me = await r.run('whoami');
    console.log(`Hello, far-away ${me}!`);

    let my_info = await r.sudo(`grep ${me} /etc/shadow`);
    console.log('My far-away shadow entry:');
    console.log(my_info);

    r.end();
}

main();

Once you have a remote instance, you can change its default settings with the defaults method, but you can't change any of the SSL settings. You can also override settings on a per-call basis, just like with the local commands.

r.defaults({/* new default options */});

r.run('some-command', {/* different options */});

The remote interface also allows you to do FTP-style put and get. These methods only take individual files. Passing in a folder for either the local or remote side will result in an error. Also note that the files should be passed in as absolute paths. If a logger is available on the remote or provided to the functions, it will be used to log the file transfer.

let r = require('mugo').remote({
    uri: '[email protected]',
    pass: 'secret password',
});

await r.put('/local/file', '/remote/file', {/* options */});

await r.get('/remote/file', '/local/file', {/* options */});

Helper Functions

There are some helper functions available to make scripting easier.

Password Prompting

You can use the following functions to prompt for passwords

const mugo = require('mugo');

let password = mugo.prompt_pass_sync();

let r = mugo.remote({ uri: '[email protected]', pass: password });

async function main() {
    let new_password = await mugo.prompt_pass(); // async

    await r.sudo(`change_password ${new_password}`);
}

main();

Handling Uncaught Exceptions

There is a function you can run that will set up a default exception handler so that even if your script crashes for unexpected reasons, you are still able to see the stack trace and respond to the issue.

const mugo = require('mugo');

mugo.setup_uncaught_exception_handler();

// do more stuff

Options

A number of options are available, any of which can be passed to an individual function call, to the defaults function, or to the constructor.

Local

| Option | Used By | Description | Default Value | | ------------------- | ------------- | --------------------------------------------------------------------------- | ------------------- | | sudo_user | sudo | The user to run the command as (sudo -u user) | undefined | | sudo_prompt | sudo | A string to use for the sudo prompt (sudo -p prompt) | undefined | | sudo_pass | sudo | The password to provide to sudo over stdin (sudo -S) | undefined | | save_pass | sudo | Save the provided sudo password for later sudo commands | false | | cwd | run, sudo | The working directory from which to run commands | undefined | | encoding | run, sudo | The encoding to use when getting the output from the command | 'utf8' | | warn_only | run, sudo | Don't throw an exception if the command fails | false | | trim | run, sudo | Remove the trailing newline from the output | true | | flatten | run, sudo | Remove newlines and surrounding whitespace from cmd (for prettier printing) | false | | return_stderr_also| run, sudo | Return stderr along with stdout | false | | stdin | run, sudo | The stream or string to use for stdin. | undefined | | stdout | run, sudo | The stream to use for stdout. | undefined | | stderr | run, sudo | The stream to use for stderr. | undefined | | shell | run, sudo | Shell to use when running command | '/bin/bash' | | shell_wrap | run, sudo | Wrap cmd in shell explicitly | false | | logger | run, sudo | The logger object to use | new ConsoleLogger() |

Remote

For remote connections, you must provide at minimum a user, host, and password or private key. You can provide that information through the uri, the individual options, or any combination thereof.

If you provide an SSH password but not a sudo password, it will use the SSH password for sudo.

| Option | Used By | Description | Default Value | | ------------------- | --------------------------- | ---------------------------------------------------------------------------- | ------------------- | | uri | On construction only | URI to use for SSH connection (will be overridden by explicit options below) | undefined | | host | On construction only | Hostname to connect to | undefined | | port | On construction only | Port to connect on | 22 | | user | On construction only | Username to connect as | undefined | | pass | On construction only | Password to connect with | undefined | | private_key | On construction only | Private Key to connect using | undefined | | sudo_user | sudo | The user to run the command as (sudo -u user) | undefined | | sudo_prompt | sudo | A string to use for the sudo prompt (sudo -p prompt) | undefined | | sudo_pass | sudo | The password to provide to sudo over stdin (sudo -S) | undefined | | save_pass | sudo | Save the provided sudo password for later sudo commands | false | | encoding | run, sudo | The encoding to use when getting the output from the command | 'utf8' | | warn_only | run, sudo | Don't throw an exception if the command fails | false | | trim | run, sudo | Remove the trailing newline from the output | true | | flatten | run, sudo | Remove newlines and surrounding whitespace from cmd (for prettier printing) | false | | return_stderr_also| run, sudo | Return stderr along with stdout | false | | stdin | run, sudo | The stream or string to use for stdin. | undefined | | stdout | run, sudo | The stream to use for stdout. | undefined | | stderr | run, sudo | The stream to use for stderr. | undefined | | shell | run, sudo | Shell to use when running command | '/bin/bash' | | shell_wrap | run, sudo | Wrap cmd in shell explicitly | false | | logger | run, sudo, get, put | The logger object to use | new ConsoleLogger() | | mode | get, put | The mode to set on the destination file. Doesn't work if the file is empty. | undefined |

Errors

If any of the runner functions produces an error, it will have the following fields available:

| Field | Description | | ---------------------------- | ------------------------------------------------ | | err.exit_code | The exit code of the command itself | | err.stdout | The standard output text produced by the command | | err.stderr | The standard error text produced by the command | | err.message / err.toString() | Some kind of human readable error message |

Loggers

TODO flesh out logger documentation

class Logger {
    constructor() {

    }

    on_start(cmd, info) {

    }

    on_out(stdout, info) {

    }

    on_err(stderr, info) {

    }

    on_end(exit_code, info) {

    }
}

module.exports = {
    ConsoleLogger,
};