# dollar-shell

> A micro-library for running OS and shell commands from JavaScript/TypeScript using template tag functions. Works in Node, Deno, and Bun with the same API. Web streams, TypeScript typings, zero dependencies.

## Install

npm i --save dollar-shell

## Quick start

```js
import $ from 'dollar-shell';

const result = await $`echo hello`;
// result: {code: 0, signal: null, killed: false}
```

Run: `node my-script.js`

## API

- `$` — run a command, returns `Promise<{code, signal, killed}>`. Default export.
- `$$` — run a command, returns a `Subprocess` object (full control: kill, streams, exit code).
- `$sh` — run a shell command, returns `Promise<{code, signal, killed}>`.
- `shell` / `sh` — run a shell command, returns a `Subprocess` object.
- `spawn()` — low-level process spawning with full configuration.

Stream pipeline helpers (available on `$` and `$sh`):
- `.from` — stdout as a ReadableStream (source).
- `.to` — stdin as a WritableStream (sink).
- `.io` / `.through` — {readable, writable} duplex pair (transform step).

All tag functions accept an options object to return a new tag function with updated defaults.

Utilities: `raw()`, `winCmdEscape()`, `isWindows`, `cwd()`, `currentExecPath()`, `runFileArgs`, `shellEscape()`, `currentShellPath()`, `buildShellCommand()`.

## Common patterns

```js
import {$, $$, $sh, raw} from 'dollar-shell';

// Simple command
const result = await $`echo hello`;

// Shell command (pipes, aliases, globbing)
await $sh({stdout: 'inherit'})`ls -l . | grep LICENSE | wc`;

// Full Subprocess control
const sp = $$`sleep 5`;
sp.kill();
await sp.exited;

// Custom options (returns new tag function)
const $verbose = $({stdout: 'inherit', stderr: 'inherit'});
await $verbose`ls -l .`;

// Web stream pipeline
$.from`ls -l .`
  .pipeThrough($.io`grep LIC`)
  .pipeTo($.to({stdout: 'inherit'})`wc`);

// Bypass escaping with raw()
await $sh({stdout: 'inherit'})`echo ${raw('"hello"')}`;
```

## Forcing the Node backend

By default each runtime uses its native backend. Set the `DSH_FORCE_NODE` environment variable (e.g. `DSH_FORCE_NODE=1`) to make every runtime spawn through the Node backend (`node:child_process`; Bun and Deno run it on their Node compat). This swaps **only the spawn mechanism** — the runtime that runs your code and how dollar-shell re-launches it stay native, so a forced child of Bun/Deno is still `bun run …` / `deno run …`, never a bare `node`. Because dollar-shell's `env` option defaults to `process.env`, spawned children inherit the variable, so it forces the whole process tree; to force only the current process (no leak to children), set `globalThis.DSH_FORCE_NODE = true` before a dynamic `import()` instead (process-local). Useful to sidestep runtime-specific quirks. The backend is selected once, at import time. Treated as off: unset, `''`, `0`, `false`.

## Node streams (`dollar-shell/node`)

`import {$, $$, $sh, shell, spawn} from 'dollar-shell/node'` gives the identical API, but `stdin`/`stdout`/`stderr` are Node `Readable`/`Writable` (and `.io`/`.through`/`asDuplex` a Node `Duplex`) instead of Web streams — for direct Node-ecosystem piping with no adapter. Always spawns through the Node backend (`node:child_process`, run on Bun/Deno via their Node compat); only the spawn mechanism changes — the runtime launch stays native.

## Docs

- [$ (dollar)](https://github.com/uhop/dollar-shell/wiki/$): Spawn processes with simple return values, includes $.from, $.to, $.io/$.through
- [$$ (double dollar)](https://github.com/uhop/dollar-shell/wiki/$$): Spawn processes returning full Subprocess objects
- [$sh (dollar shell)](https://github.com/uhop/dollar-shell/wiki/$sh): Run shell commands with simple return values, includes $sh.from, $sh.to, $sh.io/$sh.through
- [shell / sh](https://github.com/uhop/dollar-shell/wiki/shell): Run shell commands returning full Subprocess objects
- [spawn()](https://github.com/uhop/dollar-shell/wiki/spawn): Low-level process spawning with full configuration
- [Utilities](https://github.com/uhop/dollar-shell/wiki/Utilities): Helper functions — raw(), winCmdEscape(), isWindows, cwd(), currentExecPath(), runFileArgs, shellEscape(), currentShellPath(), buildShellCommand()

## Links

- Docs: https://github.com/uhop/dollar-shell/wiki
- npm: https://www.npmjs.com/package/dollar-shell
- Full LLM reference: https://github.com/uhop/dollar-shell/blob/main/llms-full.txt
