command-stream 0.7.0 โ†’ 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,43 +27,44 @@ A modern $ shell utility library with streaming, async iteration, and EventEmitt
27
27
 
28
28
  ## Comparison with Other Libraries
29
29
 
30
- | Feature | [**command-stream**](https://github.com/link-foundation/command-stream) | [**execa**](https://github.com/sindresorhus/execa) | [**cross-spawn**](https://github.com/moxystudio/node-cross-spawn) | [**Bun.$**](https://github.com/oven-sh/bun) | [**ShellJS**](https://github.com/shelljs/shelljs) | [**zx**](https://github.com/google/zx) |
31
- |---------|----------------|-------|-------|-----|-------|-------|
32
- | **๐Ÿ“ฆ NPM Package** | [![npm](https://img.shields.io/npm/v/command-stream.svg)](https://www.npmjs.com/package/command-stream) | [![npm](https://img.shields.io/npm/v/execa.svg)](https://www.npmjs.com/package/execa) | [![npm](https://img.shields.io/npm/v/cross-spawn.svg)](https://www.npmjs.com/package/cross-spawn) | N/A (Built-in) | [![npm](https://img.shields.io/npm/v/shelljs.svg)](https://www.npmjs.com/package/shelljs) | [![npm](https://img.shields.io/npm/v/zx.svg)](https://www.npmjs.com/package/zx) |
33
- | **โญ GitHub Stars** | [**โญ 2** (Please โญ us!)](https://github.com/link-foundation/command-stream) | [โญ 7,264](https://github.com/sindresorhus/execa) | [โญ 1,149](https://github.com/moxystudio/node-cross-spawn) | [โญ 80,169](https://github.com/oven-sh/bun) (Full Runtime) | [โญ 14,375](https://github.com/shelljs/shelljs) | [โญ 44,569](https://github.com/google/zx) |
34
- | **๐Ÿ“Š Monthly Downloads** | **893** (New project!) | **381M** | **409M** | N/A (Built-in) | **35M** | **4.2M** |
35
- | **๐Ÿ“ˆ Total Downloads** | **Growing** | **6B+** | **5.4B** | N/A (Built-in) | **596M** | **37M** |
36
- | **Runtime Support** | โœ… Bun + Node.js | โœ… Node.js | โœ… Node.js | ๐ŸŸก Bun only | โœ… Node.js | โœ… Node.js |
37
- | **Template Literals** | โœ… `` $`cmd` `` | โœ… `` $`cmd` `` | โŒ Function calls | โœ… `` $`cmd` `` | โŒ Function calls | โœ… `` $`cmd` `` |
38
- | **Real-time Streaming** | โœ… Live output | ๐ŸŸก Limited | โŒ Buffer only | โŒ Buffer only | โŒ Buffer only | โŒ Buffer only |
39
- | **Synchronous Execution** | โœ… `.sync()` with events | โœ… `execaSync` | โœ… `spawnSync` | โŒ No | โœ… Sync by default | โŒ No |
40
- | **Async Iteration** | โœ… `for await (chunk of $.stream())` | โŒ No | โŒ No | โŒ No | โŒ No | โŒ No |
41
- | **EventEmitter Pattern** | โœ… `.on('data', ...)` | ๐ŸŸก Limited events | ๐ŸŸก Child process events | โŒ No | โŒ No | โŒ No |
42
- | **Mixed Patterns** | โœ… Events + await/sync | โŒ No | โŒ No | โŒ No | โŒ No | โŒ No |
43
- | **Bun.$ Compatibility** | โœ… `.text()` method support | โŒ No | โŒ No | โœ… Native API | โŒ No | โŒ No |
44
- | **Shell Injection Protection** | โœ… Smart auto-quoting | โœ… Safe by default | โœ… Safe by default | โœ… Built-in | ๐ŸŸก Manual escaping | โœ… Safe by default |
45
- | **Cross-platform** | โœ… macOS/Linux/Windows | โœ… Yes | โœ… **Specialized** cross-platform | โœ… Yes | โœ… Yes | โœ… Yes |
46
- | **Performance** | โšก Fast (Bun optimized) | ๐ŸŒ Moderate | โšก Fast | โšก Very fast | ๐ŸŒ Moderate | ๐ŸŒ Slow |
47
- | **Memory Efficiency** | โœ… Streaming prevents buildup | ๐ŸŸก Buffers in memory | ๐ŸŸก Buffers in memory | ๐ŸŸก Buffers in memory | ๐ŸŸก Buffers in memory | ๐ŸŸก Buffers in memory |
48
- | **Error Handling** | โœ… Configurable (`set -e`/`set +e`, non-zero OK by default) | โœ… Throws on error | โŒ Basic (exit codes) | โœ… Throws on error | โœ… Configurable | โœ… Throws on error |
49
- | **Shell Settings** | โœ… `set -e`/`set +e` equivalent | โŒ No | โŒ No | โŒ No | ๐ŸŸก Limited (`set()`) | โŒ No |
50
- | **Stdout Support** | โœ… Real-time streaming + events | โœ… Node.js streams + interleaved | โœ… Inherited/buffered | โœ… Shell redirection + buffered | โœ… Direct output | โœ… Readable streams + `.pipe.stdout` |
51
- | **Stderr Support** | โœ… Real-time streaming + events | โœ… Streams + interleaved output | โœ… Inherited/buffered | โœ… Redirection + `.quiet()` access | โœ… Error output | โœ… Readable streams + `.pipe.stderr` |
52
- | **Stdin Support** | โœ… string/Buffer/inherit/ignore | โœ… Input/output streams | โœ… Full stdio support | โœ… Pipe operations | ๐ŸŸก Basic | โœ… Basic stdin |
53
- | **Built-in Commands** | โœ… **18 commands**: cat, ls, mkdir, rm, mv, cp, touch, basename, dirname, seq, yes + all Bun.$ commands | โŒ Uses system | โŒ Uses system | โœ… echo, cd, etc. | โœ… **20+ commands**: cat, ls, mkdir, rm, mv, cp, etc. | โŒ Uses system |
54
- | **Virtual Commands Engine** | โœ… **Revolutionary**: Register JavaScript functions as shell commands with full pipeline support | โŒ No custom commands | โŒ No custom commands | โŒ No extensibility | โŒ No custom commands | โŒ No custom commands |
55
- | **Pipeline/Piping Support** | โœ… **Advanced**: System + Built-ins + Virtual + Mixed + `.pipe()` method | โœ… Programmatic `.pipe()` + multi-destination | โŒ No piping | โœ… Standard shell piping | โœ… Shell piping + `.to()` method | โœ… Shell piping + `.pipe()` method |
56
- | **Bundle Size** | ๐Ÿ“ฆ **~20KB gzipped** | ๐Ÿ“ฆ ~400KB+ (packagephobia) | ๐Ÿ“ฆ ~2KB gzipped | ๐ŸŽฏ 0KB (built-in) | ๐Ÿ“ฆ ~15KB gzipped | ๐Ÿ“ฆ ~50KB+ (estimated) |
57
- | **Signal Handling** | โœ… **Advanced SIGINT/SIGTERM forwarding** with cleanup | ๐ŸŸก Basic | โœ… **Excellent** cross-platform | ๐ŸŸก Basic | ๐ŸŸก Basic | ๐ŸŸก Basic |
58
- | **Process Management** | โœ… **Robust child process lifecycle** with proper termination | โœ… Good | โœ… **Excellent** spawn wrapper | โŒ Basic | ๐ŸŸก Limited | ๐ŸŸก Limited |
59
- | **Debug Tracing** | โœ… **Comprehensive VERBOSE logging** for CI/debugging | ๐ŸŸก Limited | โŒ No | โŒ No | ๐ŸŸก Basic | โŒ No |
60
- | **Test Coverage** | โœ… **518+ tests, 1165+ assertions** | โœ… Excellent | โœ… Good | ๐ŸŸก Good coverage | โœ… Good | ๐ŸŸก Good |
61
- | **CI Reliability** | โœ… **Platform-specific handling** (macOS/Ubuntu) | โœ… Good | โœ… **Excellent** | ๐ŸŸก Basic | โœ… Good | ๐ŸŸก Basic |
62
- | **Documentation** | โœ… **Comprehensive examples + guides** | โœ… Excellent | ๐ŸŸก Basic | โœ… Good | โœ… Good | ๐ŸŸก Limited |
63
- | **TypeScript** | ๐Ÿ”„ Coming soon | โœ… Full support | โœ… Built-in | โœ… Built-in | ๐ŸŸก Community types | โœ… Full support |
64
- | **License** | โœ… **Unlicense (Public Domain)** | ๐ŸŸก MIT | ๐ŸŸก MIT | ๐ŸŸก MIT (+ LGPL dependencies) | ๐ŸŸก BSD-3-Clause | ๐ŸŸก Apache 2.0 |
65
-
66
- **๐Ÿ“Š Popularity & Adoption:**
30
+ | Feature | [**command-stream**](https://github.com/link-foundation/command-stream) | [**execa**](https://github.com/sindresorhus/execa) | [**cross-spawn**](https://github.com/moxystudio/node-cross-spawn) | [**Bun.$**](https://github.com/oven-sh/bun) | [**ShellJS**](https://github.com/shelljs/shelljs) | [**zx**](https://github.com/google/zx) |
31
+ | ------------------------------ | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
32
+ | **๐Ÿ“ฆ NPM Package** | [![npm](https://img.shields.io/npm/v/command-stream.svg)](https://www.npmjs.com/package/command-stream) | [![npm](https://img.shields.io/npm/v/execa.svg)](https://www.npmjs.com/package/execa) | [![npm](https://img.shields.io/npm/v/cross-spawn.svg)](https://www.npmjs.com/package/cross-spawn) | N/A (Built-in) | [![npm](https://img.shields.io/npm/v/shelljs.svg)](https://www.npmjs.com/package/shelljs) | [![npm](https://img.shields.io/npm/v/zx.svg)](https://www.npmjs.com/package/zx) |
33
+ | **โญ GitHub Stars** | [**โญ 2** (Please โญ us!)](https://github.com/link-foundation/command-stream) | [โญ 7,264](https://github.com/sindresorhus/execa) | [โญ 1,149](https://github.com/moxystudio/node-cross-spawn) | [โญ 80,169](https://github.com/oven-sh/bun) (Full Runtime) | [โญ 14,375](https://github.com/shelljs/shelljs) | [โญ 44,569](https://github.com/google/zx) |
34
+ | **๐Ÿ“Š Monthly Downloads** | **893** (New project!) | **381M** | **409M** | N/A (Built-in) | **35M** | **4.2M** |
35
+ | **๐Ÿ“ˆ Total Downloads** | **Growing** | **6B+** | **5.4B** | N/A (Built-in) | **596M** | **37M** |
36
+ | **Runtime Support** | โœ… Bun + Node.js | โœ… Node.js | โœ… Node.js | ๐ŸŸก Bun only | โœ… Node.js | โœ… Node.js |
37
+ | **Template Literals** | โœ… `` $`cmd` `` | โœ… `` $`cmd` `` | โŒ Function calls | โœ… `` $`cmd` `` | โŒ Function calls | โœ… `` $`cmd` `` |
38
+ | **Real-time Streaming** | โœ… Live output | ๐ŸŸก Limited | โŒ Buffer only | โŒ Buffer only | โŒ Buffer only | โŒ Buffer only |
39
+ | **Synchronous Execution** | โœ… `.sync()` with events | โœ… `execaSync` | โœ… `spawnSync` | โŒ No | โœ… Sync by default | โŒ No |
40
+ | **Async Iteration** | โœ… `for await (chunk of $.stream())` | โŒ No | โŒ No | โŒ No | โŒ No | โŒ No |
41
+ | **EventEmitter Pattern** | โœ… `.on('data', ...)` | ๐ŸŸก Limited events | ๐ŸŸก Child process events | โŒ No | โŒ No | โŒ No |
42
+ | **Mixed Patterns** | โœ… Events + await/sync | โŒ No | โŒ No | โŒ No | โŒ No | โŒ No |
43
+ | **Bun.$ Compatibility** | โœ… `.text()` method support | โŒ No | โŒ No | โœ… Native API | โŒ No | โŒ No |
44
+ | **Shell Injection Protection** | โœ… Smart auto-quoting | โœ… Safe by default | โœ… Safe by default | โœ… Built-in | ๐ŸŸก Manual escaping | โœ… Safe by default |
45
+ | **Cross-platform** | โœ… macOS/Linux/Windows | โœ… Yes | โœ… **Specialized** cross-platform | โœ… Yes | โœ… Yes | โœ… Yes |
46
+ | **Performance** | โšก Fast (Bun optimized) | ๐ŸŒ Moderate | โšก Fast | โšก Very fast | ๐ŸŒ Moderate | ๐ŸŒ Slow |
47
+ | **Memory Efficiency** | โœ… Streaming prevents buildup | ๐ŸŸก Buffers in memory | ๐ŸŸก Buffers in memory | ๐ŸŸก Buffers in memory | ๐ŸŸก Buffers in memory | ๐ŸŸก Buffers in memory |
48
+ | **Error Handling** | โœ… Configurable (`set -e`/`set +e`, non-zero OK by default) | โœ… Throws on error | โŒ Basic (exit codes) | โœ… Throws on error | โœ… Configurable | โœ… Throws on error |
49
+ | **Shell Settings** | โœ… `set -e`/`set +e` equivalent | โŒ No | โŒ No | โŒ No | ๐ŸŸก Limited (`set()`) | โŒ No |
50
+ | **Stdout Support** | โœ… Real-time streaming + events | โœ… Node.js streams + interleaved | โœ… Inherited/buffered | โœ… Shell redirection + buffered | โœ… Direct output | โœ… Readable streams + `.pipe.stdout` |
51
+ | **Stderr Support** | โœ… Real-time streaming + events | โœ… Streams + interleaved output | โœ… Inherited/buffered | โœ… Redirection + `.quiet()` access | โœ… Error output | โœ… Readable streams + `.pipe.stderr` |
52
+ | **Stdin Support** | โœ… string/Buffer/inherit/ignore | โœ… Input/output streams | โœ… Full stdio support | โœ… Pipe operations | ๐ŸŸก Basic | โœ… Basic stdin |
53
+ | **Built-in Commands** | โœ… **18 commands**: cat, ls, mkdir, rm, mv, cp, touch, basename, dirname, seq, yes + all Bun.$ commands | โŒ Uses system | โŒ Uses system | โœ… echo, cd, etc. | โœ… **20+ commands**: cat, ls, mkdir, rm, mv, cp, etc. | โŒ Uses system |
54
+ | **Virtual Commands Engine** | โœ… **Revolutionary**: Register JavaScript functions as shell commands with full pipeline support | โŒ No custom commands | โŒ No custom commands | โŒ No extensibility | โŒ No custom commands | โŒ No custom commands |
55
+ | **Pipeline/Piping Support** | โœ… **Advanced**: System + Built-ins + Virtual + Mixed + `.pipe()` method | โœ… Programmatic `.pipe()` + multi-destination | โŒ No piping | โœ… Standard shell piping | โœ… Shell piping + `.to()` method | โœ… Shell piping + `.pipe()` method |
56
+ | **Bundle Size** | ๐Ÿ“ฆ **~20KB gzipped** | ๐Ÿ“ฆ ~400KB+ (packagephobia) | ๐Ÿ“ฆ ~2KB gzipped | ๐ŸŽฏ 0KB (built-in) | ๐Ÿ“ฆ ~15KB gzipped | ๐Ÿ“ฆ ~50KB+ (estimated) |
57
+ | **Signal Handling** | โœ… **Advanced SIGINT/SIGTERM forwarding** with cleanup | ๐ŸŸก Basic | โœ… **Excellent** cross-platform | ๐ŸŸก Basic | ๐ŸŸก Basic | ๐ŸŸก Basic |
58
+ | **Process Management** | โœ… **Robust child process lifecycle** with proper termination | โœ… Good | โœ… **Excellent** spawn wrapper | โŒ Basic | ๐ŸŸก Limited | ๐ŸŸก Limited |
59
+ | **Debug Tracing** | โœ… **Comprehensive VERBOSE logging** for CI/debugging | ๐ŸŸก Limited | โŒ No | โŒ No | ๐ŸŸก Basic | โŒ No |
60
+ | **Test Coverage** | โœ… **518+ tests, 1165+ assertions** | โœ… Excellent | โœ… Good | ๐ŸŸก Good coverage | โœ… Good | ๐ŸŸก Good |
61
+ | **CI Reliability** | โœ… **Platform-specific handling** (macOS/Ubuntu) | โœ… Good | โœ… **Excellent** | ๐ŸŸก Basic | โœ… Good | ๐ŸŸก Basic |
62
+ | **Documentation** | โœ… **Comprehensive examples + guides** | โœ… Excellent | ๐ŸŸก Basic | โœ… Good | โœ… Good | ๐ŸŸก Limited |
63
+ | **TypeScript** | ๐Ÿ”„ Coming soon | โœ… Full support | โœ… Built-in | โœ… Built-in | ๐ŸŸก Community types | โœ… Full support |
64
+ | **License** | โœ… **Unlicense (Public Domain)** | ๐ŸŸก MIT | ๐ŸŸก MIT | ๐ŸŸก MIT (+ LGPL dependencies) | ๐ŸŸก BSD-3-Clause | ๐ŸŸก Apache 2.0 |
65
+
66
+ **๐Ÿ“Š Popularity & Adoption:**
67
+
67
68
  - **โญ GitHub Stars:** [Bun: 80,169](https://github.com/oven-sh/bun) โ€ข [zx: 44,569](https://github.com/google/zx) โ€ข [ShellJS: 14,375](https://github.com/shelljs/shelljs) โ€ข [execa: 7,264](https://github.com/sindresorhus/execa) โ€ข [cross-spawn: 1,149](https://github.com/moxystudio/node-cross-spawn) โ€ข [**command-stream: 2 โญ us!**](https://github.com/link-foundation/command-stream)
68
69
  - **๐Ÿ“ˆ Total Downloads:** [execa: 6B+](https://www.npmjs.com/package/execa) โ€ข [cross-spawn: 5.4B](https://www.npmjs.com/package/cross-spawn) โ€ข [ShellJS: 596M](https://www.npmjs.com/package/shelljs) โ€ข [zx: 37M](https://www.npmjs.com/package/zx) โ€ข [command-stream: Growing](https://www.npmjs.com/package/command-stream)
69
70
  - **๐Ÿ“Š Monthly Downloads:** [cross-spawn: 409M](https://www.npmjs.com/package/cross-spawn) โ€ข [execa: 381M](https://www.npmjs.com/package/execa) โ€ข [ShellJS: 35M](https://www.npmjs.com/package/shelljs) โ€ข [zx: 4.2M](https://www.npmjs.com/package/zx) โ€ข [command-stream: 893 (growing!)](https://www.npmjs.com/package/command-stream)
@@ -79,7 +80,7 @@ A modern $ shell utility library with streaming, async iteration, and EventEmitt
79
80
  - **๐Ÿ“ก Real-time Processing**: Only library with true streaming and async iteration
80
81
  - **๐Ÿ”„ Flexible Patterns**: Multiple usage patterns (await, events, iteration, mixed)
81
82
  - **๐Ÿš Shell Replacement**: Dynamic error handling with `set -e`/`set +e` equivalents for .sh file replacement
82
- - **โšก Bun Optimized**: Designed for Bun with Node.js fallback compatibility
83
+ - **โšก Bun Optimized**: Designed for Bun with Node.js fallback compatibility
83
84
  - **๐Ÿ’พ Memory Efficient**: Streaming prevents large buffer accumulation
84
85
  - **๐Ÿ›ก๏ธ Production Ready**: **518+ tests, 1165+ assertions** with comprehensive coverage including CI reliability
85
86
  - **๐ŸŽฏ Advanced Signal Handling**: Robust SIGINT/SIGTERM forwarding with proper child process cleanup
@@ -90,21 +91,24 @@ A modern $ shell utility library with streaming, async iteration, and EventEmitt
90
91
  command-stream now includes **18 built-in commands** that work identically to their bash/sh counterparts, providing true cross-platform shell scripting without system dependencies:
91
92
 
92
93
  ### ๐Ÿ“ **File System Commands**
94
+
93
95
  - `cat` - Read and display file contents
94
96
  - `ls` - List directory contents (supports `-l`, `-a`, `-A`)
95
97
  - `mkdir` - Create directories (supports `-p` recursive)
96
- - `rm` - Remove files/directories (supports `-r`, `-f`)
98
+ - `rm` - Remove files/directories (supports `-r`, `-f`)
97
99
  - `mv` - Move/rename files and directories
98
100
  - `cp` - Copy files/directories (supports `-r` recursive)
99
101
  - `touch` - Create files or update timestamps
100
102
 
101
- ### ๐Ÿ”ง **Utility Commands**
103
+ ### ๐Ÿ”ง **Utility Commands**
104
+
102
105
  - `basename` - Extract filename from path
103
106
  - `dirname` - Extract directory from path
104
107
  - `seq` - Generate number sequences
105
108
  - `yes` - Output string repeatedly (streaming)
106
109
 
107
110
  ### โšก **System Commands**
111
+
108
112
  - `cd` - Change directory
109
113
  - `pwd` - Print working directory
110
114
  - `echo` - Print arguments (supports `-n`)
@@ -161,11 +165,11 @@ Command-stream provides intelligent auto-quoting to protect against shell inject
161
165
  import { $ } from 'command-stream';
162
166
 
163
167
  // Safe strings are NOT quoted (performance optimization)
164
- await $`echo ${name}`; // name = "hello" โ†’ echo hello
165
- await $`${cmd} --version`; // cmd = "/usr/bin/node" โ†’ /usr/bin/node --version
168
+ await $`echo ${name}`; // name = "hello" โ†’ echo hello
169
+ await $`${cmd} --version`; // cmd = "/usr/bin/node" โ†’ /usr/bin/node --version
166
170
 
167
171
  // Dangerous strings are automatically quoted for safety
168
- await $`echo ${userInput}`; // userInput = "test; rm -rf /" โ†’ echo 'test; rm -rf /'
172
+ await $`echo ${userInput}`; // userInput = "test; rm -rf /" โ†’ echo 'test; rm -rf /'
169
173
  await $`echo ${pathWithSpaces}`; // pathWithSpaces = "/my path/file" โ†’ echo '/my path/file'
170
174
 
171
175
  // Special characters that trigger auto-quoting:
@@ -173,10 +177,10 @@ await $`echo ${pathWithSpaces}`; // pathWithSpaces = "/my path/file" โ†’ echo '/
173
177
 
174
178
  // User-provided quotes are preserved
175
179
  const quotedPath = "'/path with spaces/file'";
176
- await $`cat ${quotedPath}`; // โ†’ cat '/path with spaces/file' (no double-quoting!)
180
+ await $`cat ${quotedPath}`; // โ†’ cat '/path with spaces/file' (no double-quoting!)
177
181
 
178
182
  const doubleQuoted = '"/path with spaces/file"';
179
- await $`cat ${doubleQuoted}`; // โ†’ cat '"/path with spaces/file"' (preserves intent)
183
+ await $`cat ${doubleQuoted}`; // โ†’ cat '"/path with spaces/file"' (preserves intent)
180
184
  ```
181
185
 
182
186
  ### Shell Injection Protection
@@ -186,19 +190,70 @@ All interpolated values are automatically secured:
186
190
  ```javascript
187
191
  // โœ… SAFE - All these injection attempts are neutralized
188
192
  const dangerous = "'; rm -rf /; echo '";
189
- await $`echo ${dangerous}`; // โ†’ echo ''\'' rm -rf /; echo '\'''
193
+ await $`echo ${dangerous}`; // โ†’ echo ''\'' rm -rf /; echo '\'''
190
194
 
191
- const cmdSubstitution = "$(whoami)";
195
+ const cmdSubstitution = '$(whoami)';
192
196
  await $`echo ${cmdSubstitution}`; // โ†’ echo '$(whoami)' (literal text, not executed)
193
197
 
194
- const varExpansion = "$HOME";
195
- await $`echo ${varExpansion}`; // โ†’ echo '$HOME' (literal text, not expanded)
198
+ const varExpansion = '$HOME';
199
+ await $`echo ${varExpansion}`; // โ†’ echo '$HOME' (literal text, not expanded)
196
200
 
197
201
  // โœ… SAFE - Even complex injection attempts
198
- const complex = "`cat /etc/passwd`";
199
- await $`echo ${complex}`; // โ†’ echo '`cat /etc/passwd`' (literal text)
202
+ const complex = '`cat /etc/passwd`';
203
+ await $`echo ${complex}`; // โ†’ echo '`cat /etc/passwd`' (literal text)
200
204
  ```
201
205
 
206
+ ### Disabling Auto-Escape (Advanced)
207
+
208
+ **โš ๏ธ WARNING: Use with extreme caution! Only use `raw()` with trusted input to prevent shell injection attacks.**
209
+
210
+ For advanced use cases where you need to use command strings directly without auto-escaping, use the `raw()` function:
211
+
212
+ ```javascript
213
+ import { $, raw } from 'command-stream';
214
+
215
+ // โš ๏ธ DANGEROUS - Bypasses all safety checks
216
+ const userCommand = 'echo "hello" && ls -la';
217
+ await $`${raw(userCommand)}`; // โ†’ Executes: echo "hello" && ls -la
218
+
219
+ // โœ… Safe use case: Trusted command templates
220
+ const trustedCommand = 'git log --oneline --graph --all';
221
+ await $`${raw(trustedCommand)}`;
222
+
223
+ // โœ… Combining raw with safe interpolation
224
+ const branch = 'main'; // User input - will be auto-quoted
225
+ await $`${raw('git log --oneline')} ${branch}`;
226
+ // โ†’ git log --oneline 'main' (raw part unescaped, branch safely quoted)
227
+
228
+ // ๐ŸŽฏ Use case: Pre-built command strings from configuration
229
+ const config = {
230
+ backupCommand: 'tar -czf backup.tar.gz --exclude="*.log" .',
231
+ cleanCommand: 'find . -name "*.tmp" -delete',
232
+ };
233
+ await $`${raw(config.backupCommand)}`;
234
+
235
+ // โš ๏ธ NEVER use raw() with user input
236
+ const userInput = req.body.command; // โŒ DANGEROUS!
237
+ await $`${raw(userInput)}`; // โŒ Shell injection vulnerability!
238
+
239
+ // โœ… Instead, use normal interpolation for user input
240
+ await $`echo ${userInput}`; // โœ… Safe - auto-escaped
241
+ ```
242
+
243
+ **When to use `raw()`:**
244
+
245
+ - โœ… Trusted command templates from your codebase
246
+ - โœ… Configuration files you control
247
+ - โœ… Hardcoded command strings
248
+ - โœ… Complex shell operators that need to be preserved
249
+
250
+ **When NOT to use `raw()`:**
251
+
252
+ - โŒ User input (form fields, API parameters, CLI arguments)
253
+ - โŒ External data (database, API responses, files)
254
+ - โŒ Any untrusted source
255
+ - โŒ When you're unsure - use normal interpolation instead
256
+
202
257
  ## Usage Patterns
203
258
 
204
259
  ### Classic Await (Backward Compatible)
@@ -242,7 +297,7 @@ const $custom = $({
242
297
  stdin: 'test data',
243
298
  mirror: false,
244
299
  capture: true,
245
- cwd: '/tmp'
300
+ cwd: '/tmp',
246
301
  });
247
302
  await $custom`cat > output.txt`; // Writes to /tmp/output.txt silently
248
303
 
@@ -263,21 +318,21 @@ const cmd = $`echo "hello"`;
263
318
  // Three ways to start execution:
264
319
 
265
320
  // 1. Explicit start with options
266
- cmd.start(); // Default async mode
267
- cmd.start({ mode: 'async' }); // Explicitly async
268
- cmd.start({ mode: 'sync' }); // Synchronous execution
321
+ cmd.start(); // Default async mode
322
+ cmd.start({ mode: 'async' }); // Explicitly async
323
+ cmd.start({ mode: 'sync' }); // Synchronous execution
269
324
 
270
325
  // 2. Convenience methods
271
- cmd.async(); // Same as start({ mode: 'async' })
272
- cmd.sync(); // Same as start({ mode: 'sync' })
326
+ cmd.async(); // Same as start({ mode: 'async' })
327
+ cmd.sync(); // Same as start({ mode: 'sync' })
273
328
 
274
329
  // 3. Auto-start by awaiting (always async)
275
- await cmd; // Auto-starts in async mode
330
+ await cmd; // Auto-starts in async mode
276
331
 
277
332
  // Event handlers can be attached before starting
278
333
  const process = $`long-command`
279
- .on('data', chunk => console.log('Received:', chunk))
280
- .on('end', result => console.log('Done!'));
334
+ .on('data', (chunk) => console.log('Received:', chunk))
335
+ .on('end', (result) => console.log('Done!'));
281
336
 
282
337
  // Start whenever you're ready
283
338
  process.start();
@@ -293,9 +348,7 @@ const result = $`echo "hello"`.sync();
293
348
  console.log(result.stdout); // "hello\n"
294
349
 
295
350
  // Events still work but are batched after completion
296
- $`echo "world"`
297
- .on('end', result => console.log('Done:', result))
298
- .sync();
351
+ $`echo "world"`.on('end', (result) => console.log('Done:', result)).sync();
299
352
  ```
300
353
 
301
354
  ### Async Iteration (Real-time Streaming)
@@ -317,19 +370,18 @@ import { $ } from 'command-stream';
317
370
 
318
371
  // Attach event handlers then start execution
319
372
  $`command`
320
- .on('data', chunk => {
373
+ .on('data', (chunk) => {
321
374
  if (chunk.type === 'stdout') {
322
375
  console.log('Stdout:', chunk.data.toString());
323
376
  }
324
377
  })
325
- .on('stderr', chunk => console.log('Stderr:', chunk))
326
- .on('end', result => console.log('Done:', result))
327
- .on('exit', code => console.log('Exit code:', code))
378
+ .on('stderr', (chunk) => console.log('Stderr:', chunk))
379
+ .on('end', (result) => console.log('Done:', result))
380
+ .on('exit', (code) => console.log('Exit code:', code))
328
381
  .start(); // Explicitly start the command
329
382
 
330
383
  // Or auto-start by awaiting
331
- const cmd = $`another-command`
332
- .on('data', chunk => console.log(chunk));
384
+ const cmd = $`another-command`.on('data', (chunk) => console.log(chunk));
333
385
  await cmd; // Auto-starts in async mode
334
386
  ```
335
387
 
@@ -340,7 +392,7 @@ import { $ } from 'command-stream';
340
392
 
341
393
  // Async mode - events fire in real-time
342
394
  const process = $`streaming-command`;
343
- process.on('data', chunk => {
395
+ process.on('data', (chunk) => {
344
396
  processRealTimeData(chunk);
345
397
  });
346
398
  const result = await process;
@@ -348,7 +400,7 @@ console.log('Final output:', result.stdout);
348
400
 
349
401
  // Sync mode - events fire after completion (batched)
350
402
  const syncCmd = $`another-command`;
351
- syncCmd.on('end', result => {
403
+ syncCmd.on('end', (result) => {
352
404
  console.log('Completed with:', result.stdout);
353
405
  });
354
406
  const syncResult = syncCmd.sync();
@@ -401,9 +453,9 @@ console.log('Ping stopped with code:', pingResult.code); // 143 (SIGTERM)
401
453
  const mixedCmd = $`sh -c 'echo "out" && echo "err" >&2'`;
402
454
  const [stdout, stderr] = await Promise.all([
403
455
  mixedCmd.strings.stdout, // Available after finish
404
- mixedCmd.strings.stderr // Available after finish
456
+ mixedCmd.strings.stderr, // Available after finish
405
457
  ]);
406
- console.log('Out:', stdout.trim()); // "out"
458
+ console.log('Out:', stdout.trim()); // "out"
407
459
  console.log('Err:', stderr.trim()); // "err"
408
460
 
409
461
  // ๐Ÿƒโ€โ™‚๏ธ AUTO-START: Streams auto-start processes when accessed
@@ -419,7 +471,8 @@ console.log(traditional.stdout); // "still works\n"
419
471
  ```
420
472
 
421
473
  **Key Features:**
422
- - `command.streams.stdin/stdout/stderr` - Direct access to Node.js streams
474
+
475
+ - `command.streams.stdin/stdout/stderr` - Direct access to Node.js streams
423
476
  - `command.buffers.stdin/stdout/stderr` - Binary data as Buffer objects
424
477
  - `command.strings.stdin/stdout/stderr` - Text data as strings
425
478
  - `command.kill()` - Forceful process termination
@@ -428,6 +481,7 @@ console.log(traditional.stdout); // "still works\n"
428
481
  - **Network commands (ping, wget) ignore stdin** โ†’ Use `kill()` method instead
429
482
 
430
483
  **๐Ÿš€ Streams vs Buffers/Strings:**
484
+
431
485
  - **`streams.*`** - Available **immediately** when command starts, for real-time interaction
432
486
  - **`buffers.*` & `strings.*`** - Complete **snapshots** available only **after** command finishes
433
487
 
@@ -448,18 +502,18 @@ await $`npm run build`;
448
502
  shell.errexit(false);
449
503
  const cleanup = await $`rm -rf temp`; // Won't throw if fails
450
504
 
451
- // set -e again for critical operations
505
+ // set -e again for critical operations
452
506
  shell.errexit(true);
453
507
  await $`cp -r build/* deploy/`;
454
508
 
455
509
  // Other bash-like settings
456
- shell.verbose(true); // set -v: print commands
457
- shell.xtrace(true); // set -x: trace execution
510
+ shell.verbose(true); // set -v: print commands
511
+ shell.xtrace(true); // set -x: trace execution
458
512
 
459
513
  // Or use the bash-style API
460
- set('e'); // set -e
461
- unset('e'); // set +e
462
- set('x'); // set -x
514
+ set('e'); // set -e
515
+ unset('e'); // set +e
516
+ set('x'); // set -x
463
517
  set('verbose'); // Long form also supported
464
518
  ```
465
519
 
@@ -489,7 +543,7 @@ console.log(content.stdout);
489
543
 
490
544
  // Path operations
491
545
  const filename = await $`basename project/src/index.js .js`; // โ†’ "index"
492
- const directory = await $`dirname project/src/index.js`; // โ†’ "project/src"
546
+ const directory = await $`dirname project/src/index.js`; // โ†’ "project/src"
493
547
 
494
548
  // Generate sequences and process them
495
549
  await $`seq 1 10 | cat > numbers.txt`;
@@ -513,15 +567,15 @@ register('greet', async ({ args, stdin }) => {
513
567
  });
514
568
 
515
569
  // Use it like any other command
516
- await $`greet Alice`; // โ†’ "Hello, Alice!"
517
- await $`echo "Bob" | greet`; // โ†’ "Hello, Bob!"
570
+ await $`greet Alice`; // โ†’ "Hello, Alice!"
571
+ await $`echo "Bob" | greet`; // โ†’ "Hello, Bob!"
518
572
 
519
573
  // Streaming virtual commands with async generators
520
574
  register('countdown', async function* ({ args }) {
521
575
  const start = parseInt(args[0] || 5);
522
576
  for (let i = start; i >= 0; i--) {
523
577
  yield `${i}\n`;
524
- await new Promise(r => setTimeout(r, 1000));
578
+ await new Promise((r) => setTimeout(r, 1000));
525
579
  }
526
580
  });
527
581
 
@@ -534,8 +588,8 @@ for await (const chunk of $`countdown 3`.stream()) {
534
588
  }
535
589
 
536
590
  // Management functions
537
- console.log(listCommands()); // List all registered commands
538
- unregister('greet'); // Remove custom commands
591
+ console.log(listCommands()); // List all registered commands
592
+ unregister('greet'); // Remove custom commands
539
593
  ```
540
594
 
541
595
  #### ๐Ÿ”ฅ **Why Virtual Commands Are Revolutionary**
@@ -543,28 +597,29 @@ unregister('greet'); // Remove custom commands
543
597
  **No other shell library offers this level of extensibility:**
544
598
 
545
599
  - **๐Ÿšซ Bun.$**: Fixed set of built-in commands, no extensibility API
546
- - **๐Ÿšซ execa**: Transform/pipeline system, but no custom commands
600
+ - **๐Ÿšซ execa**: Transform/pipeline system, but no custom commands
547
601
  - **๐Ÿšซ zx**: JavaScript functions only, no shell command integration
548
602
 
549
603
  **command-stream breaks the barrier** between JavaScript functions and shell commands:
550
604
 
551
605
  ```javascript
552
606
  // โŒ Other libraries: Choose JavaScript OR shell
553
- await execa('node', ['script.js']); // execa: separate processes
554
- await $`node script.js`; // zx: shell commands only
607
+ await execa('node', ['script.js']); // execa: separate processes
608
+ await $`node script.js`; // zx: shell commands only
555
609
 
556
- // โœ… command-stream: JavaScript functions AS shell commands
610
+ // โœ… command-stream: JavaScript functions AS shell commands
557
611
  register('deploy', async ({ args }) => {
558
612
  const env = args[0] || 'staging';
559
613
  await deployToEnvironment(env);
560
614
  return { stdout: `Deployed to ${env}!\n`, code: 0 };
561
615
  });
562
616
 
563
- await $`deploy production`; // JavaScript function as shell command!
617
+ await $`deploy production`; // JavaScript function as shell command!
564
618
  await $`deploy staging | tee log.txt`; // Works in pipelines!
565
619
  ```
566
620
 
567
621
  **Unique capabilities:**
622
+
568
623
  - **Seamless Integration**: Virtual commands work exactly like built-ins
569
624
  - **Pipeline Support**: Full stdin/stdout passing between virtual and system commands
570
625
  - **Streaming**: Async generators for real-time output
@@ -581,9 +636,9 @@ await $`deploy staging | tee log.txt`; // Works in pipelines!
581
636
  import { $, register } from 'command-stream';
582
637
 
583
638
  // โœ… Standard shell piping (like all libraries)
584
- await $`echo "hello world" | wc -w`; // โ†’ "2"
639
+ await $`echo "hello world" | wc -w`; // โ†’ "2"
585
640
 
586
- // โœ… Built-in to built-in piping
641
+ // โœ… Built-in to built-in piping
587
642
  await $`seq 1 5 | cat > numbers.txt`;
588
643
 
589
644
  // โœ… System to built-in piping
@@ -599,10 +654,10 @@ register('reverse', async ({ args, stdin }) => {
599
654
  });
600
655
 
601
656
  // โœ… Built-in to virtual piping
602
- await $`echo "hello" | uppercase`; // โ†’ "HELLO"
657
+ await $`echo "hello" | uppercase`; // โ†’ "HELLO"
603
658
 
604
- // โœ… Virtual to virtual piping
605
- await $`echo "hello" | uppercase | reverse`; // โ†’ "OLLEH"
659
+ // โœ… Virtual to virtual piping
660
+ await $`echo "hello" | uppercase | reverse`; // โ†’ "OLLEH"
606
661
 
607
662
  // โœ… Mixed pipelines (system + built-in + virtual)
608
663
  await $`git log --oneline | head -n 3 | uppercase | cat > LOG.txt`;
@@ -687,17 +742,18 @@ unregister('extract-field');
687
742
 
688
743
  #### **๐Ÿ†š How We Compare**
689
744
 
690
- | Library | Pipeline Types | Custom Commands in Pipes | `.pipe()` Method | Real-time Streaming |
691
- |---------|----------------|---------------------------|------------------|---------------------|
692
- | **command-stream** | โœ… System + Built-ins + Virtual + Mixed | โœ… **Full support** | โœ… **Full virtual command support** | โœ… **Yes** |
693
- | **Bun.$** | โœ… System + Built-ins | โŒ No custom commands | โŒ No `.pipe()` method | โŒ No |
694
- | **execa** | โœ… Programmatic `.pipe()` | โŒ No shell integration | โœ… Basic process piping | ๐ŸŸก Limited |
695
- | **zx** | โœ… Shell piping + `.pipe()` | โŒ No custom commands | โœ… Stream piping only | โŒ No |
745
+ | Library | Pipeline Types | Custom Commands in Pipes | `.pipe()` Method | Real-time Streaming |
746
+ | ------------------ | --------------------------------------- | ------------------------ | ----------------------------------- | ------------------- |
747
+ | **command-stream** | โœ… System + Built-ins + Virtual + Mixed | โœ… **Full support** | โœ… **Full virtual command support** | โœ… **Yes** |
748
+ | **Bun.$** | โœ… System + Built-ins | โŒ No custom commands | โŒ No `.pipe()` method | โŒ No |
749
+ | **execa** | โœ… Programmatic `.pipe()` | โŒ No shell integration | โœ… Basic process piping | ๐ŸŸก Limited |
750
+ | **zx** | โœ… Shell piping + `.pipe()` | โŒ No custom commands | โœ… Stream piping only | โŒ No |
696
751
 
697
752
  **๐ŸŽฏ Unique Advantages:**
753
+
698
754
  - **Virtual commands work seamlessly in both shell pipes AND `.pipe()` method** - no other library can do this
699
755
  - **Mixed pipeline types** - combine system, built-in, and virtual commands freely in both syntaxes
700
- - **Real-time streaming** through virtual command pipelines
756
+ - **Real-time streaming** through virtual command pipelines
701
757
  - **Full stdin/stdout passing** between all command types
702
758
  - **Dual piping syntax** - use shell `|` OR programmatic `.pipe()` interchangeably
703
759
 
@@ -710,29 +766,31 @@ import { $ } from 'command-stream';
710
766
 
711
767
  // This command will:
712
768
  // 1. Print "Hello" to your terminal (stdoutโ†’stdout)
713
- // 2. Print "Error!" to your terminal (stderrโ†’stderr)
769
+ // 2. Print "Error!" to your terminal (stderrโ†’stderr)
714
770
  // 3. Capture both outputs for programmatic access
715
771
  const result = await $`sh -c "echo 'Hello'; echo 'Error!' >&2"`;
716
772
 
717
773
  console.log('Captured stdout:', result.stdout); // "Hello\n"
718
774
  console.log('Captured stderr:', result.stderr); // "Error!\n"
719
- console.log('Exit code:', result.code); // 0
775
+ console.log('Exit code:', result.code); // 0
720
776
  ```
721
777
 
722
778
  **Key Default Options:**
779
+
723
780
  - `mirror: true` - Live output to terminal (like shell)
724
781
  - `capture: true` - Capture output for later use (unlike shell)
725
782
  - `stdin: 'inherit'` - Inherit stdin from parent process
726
783
 
727
784
  **Fully Controllable:**
785
+
728
786
  ```javascript
729
787
  import { $, create, sh } from 'command-stream';
730
788
 
731
789
  // Disable terminal output but still capture
732
790
  const result = await sh('echo "silent"', { mirror: false });
733
791
 
734
- // Custom stdin input
735
- const custom = await sh('cat', { stdin: "custom input" });
792
+ // Custom stdin input
793
+ const custom = await sh('cat', { stdin: 'custom input' });
736
794
 
737
795
  // Create custom $ with different defaults
738
796
  const quiet$ = create({ mirror: false });
@@ -758,7 +816,7 @@ let logFile = null;
758
816
  for await (const chunk of $`your-streaming-command`.stream()) {
759
817
  if (chunk.type === 'stdout') {
760
818
  const data = chunk.data.toString();
761
-
819
+
762
820
  // Extract session ID from output
763
821
  if (!sessionId && data.includes('session_id')) {
764
822
  try {
@@ -770,7 +828,7 @@ for await (const chunk of $`your-streaming-command`.stream()) {
770
828
  // Handle JSON parse errors
771
829
  }
772
830
  }
773
-
831
+
774
832
  // Write to log file in real-time
775
833
  if (logFile) {
776
834
  appendFileSync(logFile, data);
@@ -826,7 +884,7 @@ The enhanced `$` function returns a `ProcessRunner` instance that extends `Event
826
884
  #### Properties
827
885
 
828
886
  - `stdout`: Direct access to child process stdout stream
829
- - `stderr`: Direct access to child process stderr stream
887
+ - `stderr`: Direct access to child process stderr stream
830
888
  - `stdin`: Direct access to child process stdin stream
831
889
 
832
890
  ### Default Options
@@ -843,6 +901,7 @@ The enhanced `$` function returns a `ProcessRunner` instance that extends `Event
843
901
  ```
844
902
 
845
903
  **Option Details:**
904
+
846
905
  - `mirror: boolean` - Whether to pipe output to terminal in real-time
847
906
  - `capture: boolean` - Whether to capture output in result object
848
907
  - `stdin: 'inherit' | 'ignore' | string | Buffer` - How to handle stdin
@@ -851,6 +910,7 @@ The enhanced `$` function returns a `ProcessRunner` instance that extends `Event
851
910
  - `env: object` - Environment variables
852
911
 
853
912
  **Override defaults:**
913
+
854
914
  - Use `$({ options })` syntax for one-off configurations with template literals
855
915
  - Use `sh(command, options)` for one-off overrides with string commands
856
916
  - Use `create(defaultOptions)` to create custom `$` with different defaults
@@ -910,7 +970,7 @@ Control and extend the command system with custom JavaScript functions:
910
970
  - `name`: Command name (string)
911
971
  - `handler`: Function or async generator `(args, stdin, options) => result`
912
972
  - `unregister(name)`: Remove a virtual command
913
- - `listCommands()`: Get array of all registered command names
973
+ - `listCommands()`: Get array of all registered command names
914
974
  - `enableVirtualCommands()`: Enable virtual command processing
915
975
  - `disableVirtualCommands()`: Disable virtual commands (use system commands only)
916
976
 
@@ -926,7 +986,7 @@ register('cancellable', async function* ({ args, stdin, abortSignal }) {
926
986
  break; // Proper cancellation handling
927
987
  }
928
988
  yield `Count: ${i}\n`;
929
- await new Promise(resolve => setTimeout(resolve, 1000));
989
+ await new Promise((resolve) => setTimeout(resolve, 1000));
930
990
  }
931
991
  });
932
992
 
@@ -934,35 +994,42 @@ register('cancellable', async function* ({ args, stdin, abortSignal }) {
934
994
  // All original options (built-in + custom) are available in the 'options' object
935
995
  // Common options like cwd, env are also available at top level for convenience
936
996
  // Runtime additions: isCancelled function, abortSignal
937
- register('debug-info', async ({ args, stdin, cwd, env, options, isCancelled }) => {
938
- return {
939
- stdout: JSON.stringify({
940
- args,
941
- cwd, // Available at top level for convenience
942
- env: Object.keys(env || {}), // Available at top level for convenience
943
- stdinLength: stdin?.length || 0,
944
- allOptions: options, // All original options (built-in + custom)
945
- mirror: options.mirror, // Built-in option from options object
946
- capture: options.capture, // Built-in option from options object
947
- customOption: options.customOption || 'not provided', // Custom option
948
- isCancelledAvailable: typeof isCancelled === 'function'
949
- }, null, 2),
950
- code: 0
951
- };
952
- });
997
+ register(
998
+ 'debug-info',
999
+ async ({ args, stdin, cwd, env, options, isCancelled }) => {
1000
+ return {
1001
+ stdout: JSON.stringify(
1002
+ {
1003
+ args,
1004
+ cwd, // Available at top level for convenience
1005
+ env: Object.keys(env || {}), // Available at top level for convenience
1006
+ stdinLength: stdin?.length || 0,
1007
+ allOptions: options, // All original options (built-in + custom)
1008
+ mirror: options.mirror, // Built-in option from options object
1009
+ capture: options.capture, // Built-in option from options object
1010
+ customOption: options.customOption || 'not provided', // Custom option
1011
+ isCancelledAvailable: typeof isCancelled === 'function',
1012
+ },
1013
+ null,
1014
+ 2
1015
+ ),
1016
+ code: 0,
1017
+ };
1018
+ }
1019
+ );
953
1020
 
954
1021
  // โœ… Error handling and non-zero exit codes
955
1022
  register('maybe-fail', async ({ args }) => {
956
1023
  if (Math.random() > 0.5) {
957
1024
  return {
958
1025
  stdout: 'Success!\n',
959
- code: 0
1026
+ code: 0,
960
1027
  };
961
1028
  } else {
962
1029
  return {
963
1030
  stdout: '',
964
1031
  stderr: 'Random failure occurred\n',
965
- code: 1
1032
+ code: 1,
966
1033
  };
967
1034
  }
968
1035
  });
@@ -971,12 +1038,15 @@ register('maybe-fail', async ({ args }) => {
971
1038
  register('show-options', async ({ args, stdin, options, cwd }) => {
972
1039
  return {
973
1040
  stdout: `Custom: ${options.customValue || 'none'}, CWD: ${cwd || options.cwd || 'default'}\n`,
974
- code: 0
1041
+ code: 0,
975
1042
  };
976
1043
  });
977
1044
 
978
1045
  // Usage example showing options passed to virtual command:
979
- const result = await $({ customValue: 'hello world', cwd: '/tmp' })`show-options`;
1046
+ const result = await $({
1047
+ customValue: 'hello world',
1048
+ cwd: '/tmp',
1049
+ })`show-options`;
980
1050
  console.log(result.stdout); // Output: Custom: hello world, CWD: /tmp
981
1051
  ```
982
1052
 
@@ -1005,6 +1075,46 @@ async function streamingHandler({ args, stdin, abortSignal, cwd, env, options, i
1005
1075
  }
1006
1076
  ```
1007
1077
 
1078
+ ### Utility Functions API
1079
+
1080
+ Control how values are interpolated into commands:
1081
+
1082
+ #### Functions
1083
+
1084
+ - `quote(value)`: Manually quote a value using the same smart quoting logic as auto-interpolation
1085
+ - `raw(value)`: **โš ๏ธ Dangerous!** Bypass auto-escaping to use command strings directly (see [Disabling Auto-Escape](#disabling-auto-escape-advanced))
1086
+
1087
+ #### quote() - Manual Quoting
1088
+
1089
+ Apply the same smart quoting logic manually:
1090
+
1091
+ ```javascript
1092
+ import { $, quote } from 'command-stream';
1093
+
1094
+ const path = '/path with spaces/file.txt';
1095
+ const quoted = quote(path);
1096
+ console.log(quoted); // โ†’ '/path with spaces/file.txt'
1097
+
1098
+ // Use case: Pre-process values before interpolation
1099
+ const args = ['hello world', 'test'].map(quote);
1100
+ // โ†’ ["'hello world'", 'test']
1101
+ ```
1102
+
1103
+ #### raw() - Disable Auto-Escape
1104
+
1105
+ **โš ๏ธ WARNING: Only use with trusted input!** See [Disabling Auto-Escape](#disabling-auto-escape-advanced) section for detailed documentation and security considerations.
1106
+
1107
+ ```javascript
1108
+ import { $, raw } from 'command-stream';
1109
+
1110
+ // Bypass auto-escaping for trusted command strings
1111
+ const trustedCommand = 'echo "hello" && ls -la';
1112
+ await $`${raw(trustedCommand)}`;
1113
+ // โ†’ Executes: echo "hello" && ls -la (without escaping)
1114
+
1115
+ // โš ๏ธ NEVER use with untrusted input - shell injection risk!
1116
+ ```
1117
+
1008
1118
  ### Built-in Commands
1009
1119
 
1010
1120
  18 cross-platform commands that work identically everywhere:
@@ -1014,6 +1124,7 @@ async function streamingHandler({ args, stdin, abortSignal, cwd, env, options, i
1014
1124
  **System**: `cd`, `pwd`, `echo`, `sleep`, `true`, `false`, `which`, `exit`, `env`, `test`
1015
1125
 
1016
1126
  All built-in commands support:
1127
+
1017
1128
  - Standard flags (e.g., `ls -la`, `mkdir -p`, `rm -rf`)
1018
1129
  - Pipeline operations
1019
1130
  - Option awareness (`cwd`, `env`, etc.)
@@ -1051,7 +1162,7 @@ import { $ } from 'command-stream';
1051
1162
  const result1 = await $`echo "hello world"`;
1052
1163
  const text1 = await result1.text(); // "hello world\n"
1053
1164
 
1054
- const result2 = $`echo "sync example"`.sync();
1165
+ const result2 = $`echo "sync example"`.sync();
1055
1166
  const text2 = await result2.text(); // "sync example\n"
1056
1167
 
1057
1168
  // .text() is equivalent to accessing .stdout
@@ -1085,7 +1196,7 @@ The library provides **advanced CTRL+C handling** that properly manages signals
1085
1196
  // โœ… Smart signal handling - only interferes when necessary
1086
1197
  import { $ } from 'command-stream';
1087
1198
 
1088
- // Case 1: No children active - your handlers work normally
1199
+ // Case 1: No children active - your handlers work normally
1089
1200
  process.on('SIGINT', () => {
1090
1201
  console.log('My custom handler runs!');
1091
1202
  process.exit(42); // Custom exit code
@@ -1096,10 +1207,7 @@ process.on('SIGINT', () => {
1096
1207
  await $`ping 8.8.8.8`; // Press CTRL+C โ†’ Forwards to ping, exits with code 130
1097
1208
 
1098
1209
  // Case 3: Multiple processes - all interrupted
1099
- await Promise.all([
1100
- $`sleep 100`,
1101
- $`ping google.com`
1102
- ]); // Press CTRL+C โ†’ All processes terminated, exits with code 130
1210
+ await Promise.all([$`sleep 100`, $`ping google.com`]); // Press CTRL+C โ†’ All processes terminated, exits with code 130
1103
1211
  ```
1104
1212
 
1105
1213
  ### Examples
@@ -1107,7 +1215,7 @@ await Promise.all([
1107
1215
  ```javascript
1108
1216
  // Long-running command that can be interrupted with CTRL+C
1109
1217
  try {
1110
- await $`ping 8.8.8.8`; // Press CTRL+C to stop
1218
+ await $`ping 8.8.8.8`; // Press CTRL+C to stop
1111
1219
  } catch (error) {
1112
1220
  console.log('Command interrupted:', error.code); // Exit code 130 (SIGINT)
1113
1221
  }
@@ -1117,7 +1225,7 @@ try {
1117
1225
  await Promise.all([
1118
1226
  $`sleep 100`,
1119
1227
  $`ping google.com`,
1120
- $`tail -f /var/log/system.log`
1228
+ $`tail -f /var/log/system.log`,
1121
1229
  ]);
1122
1230
  } catch (error) {
1123
1231
  // All processes are terminated when you press CTRL+C
@@ -1137,11 +1245,11 @@ try {
1137
1245
  ### Signal Handling Behavior
1138
1246
 
1139
1247
  - **๐ŸŽฏ Smart Detection**: Only forwards CTRL+C when child processes are active
1140
- - **๐Ÿ›ก๏ธ Non-Interference**: Preserves user SIGINT handlers when no children running
1248
+ - **๐Ÿ›ก๏ธ Non-Interference**: Preserves user SIGINT handlers when no children running
1141
1249
  - **โšก Interactive Commands**: Use `interactive: true` option for commands like `vim`, `less`, `top` to enable proper TTY forwarding and signal handling
1142
1250
  - **๐Ÿ”„ Process Groups**: Detached spawning ensures proper signal isolation
1143
1251
  - **๐Ÿงน TTY Cleanup**: Raw terminal mode properly restored on interruption
1144
- - **๐Ÿ“Š Standard Exit Codes**:
1252
+ - **๐Ÿ“Š Standard Exit Codes**:
1145
1253
  - `130` - SIGINT interruption (CTRL+C)
1146
1254
  - `143` - SIGTERM termination (programmatic kill)
1147
1255
  - `137` - SIGKILL force termination
@@ -1155,7 +1263,7 @@ try {
1155
1263
  register('echo', () => ({ stdout: 'virtual!\n', code: 0 }));
1156
1264
  await $`echo test`; // โ†’ "virtual!"
1157
1265
 
1158
- // 2. Built-in Commands (if no virtual match)
1266
+ // 2. Built-in Commands (if no virtual match)
1159
1267
  unregister('echo');
1160
1268
  await $`echo test`; // โ†’ Uses built-in echo
1161
1269
 
@@ -1178,12 +1286,12 @@ const result = await $`ls -la`;
1178
1286
 
1179
1287
  // โœ… Use .sync() when you need blocking execution with events
1180
1288
  const syncCmd = $`build-script`
1181
- .on('stdout', chunk => updateProgress(chunk))
1289
+ .on('stdout', (chunk) => updateProgress(chunk))
1182
1290
  .sync(); // Events fire after completion
1183
1291
 
1184
- // โœ… Use .start() for non-blocking execution with real-time events
1292
+ // โœ… Use .start() for non-blocking execution with real-time events
1185
1293
  const asyncCmd = $`long-running-server`
1186
- .on('stdout', chunk => logOutput(chunk))
1294
+ .on('stdout', (chunk) => logOutput(chunk))
1187
1295
  .start(); // Events fire in real-time
1188
1296
 
1189
1297
  // โœ… Use .stream() for processing large outputs efficiently
@@ -1193,13 +1301,13 @@ for await (const chunk of $`generate-big-file`.stream()) {
1193
1301
 
1194
1302
  // โœ… Use EventEmitter pattern for complex workflows
1195
1303
  $`deployment-script`
1196
- .on('stdout', chunk => {
1304
+ .on('stdout', (chunk) => {
1197
1305
  if (chunk.toString().includes('ERROR')) {
1198
1306
  handleError(chunk);
1199
1307
  }
1200
1308
  })
1201
- .on('stderr', chunk => logError(chunk))
1202
- .on('end', result => {
1309
+ .on('stderr', (chunk) => logError(chunk))
1310
+ .on('end', (result) => {
1203
1311
  if (result.code === 0) {
1204
1312
  notifySuccess();
1205
1313
  }
@@ -1223,9 +1331,7 @@ processFile(result.stdout); // Loads everything into memory
1223
1331
  const quickResult = $`pwd`.sync();
1224
1332
 
1225
1333
  // ๐Ÿ”„ Best for UX: Async with events for long-running commands
1226
- $`npm install`
1227
- .on('stdout', showProgress)
1228
- .start();
1334
+ $`npm install`.on('stdout', showProgress).start();
1229
1335
  ```
1230
1336
 
1231
1337
  ## Testing
@@ -1239,7 +1345,7 @@ bun test --coverage
1239
1345
 
1240
1346
  # Run specific test categories
1241
1347
  npm run test:features # Feature comparison tests
1242
- npm run test:builtin # Built-in commands tests
1348
+ npm run test:builtin # Built-in commands tests
1243
1349
  npm run test:pipe # .pipe() method tests
1244
1350
  npm run test:sync # Synchronous execution tests
1245
1351
  npm run test:signal # CTRL+C signal handling tests
@@ -1253,11 +1359,13 @@ npm run test:signal # CTRL+C signal handling tests
1253
1359
  ## Roadmap
1254
1360
 
1255
1361
  ### ๐Ÿ”„ **Coming Soon**
1362
+
1256
1363
  - **TypeScript Support**: Full .d.ts definitions and type safety
1257
1364
  - **Enhanced Shell Options**: `set -u` (nounset) and `set -o pipefail` support
1258
1365
  - **More Built-in Commands**: Additional cross-platform utilities
1259
1366
 
1260
1367
  ### ๐Ÿ’ก **Planned Features**
1368
+
1261
1369
  - **Performance Optimizations**: Further Bun runtime optimizations
1262
1370
  - **Advanced Error Handling**: Enhanced error context and debugging
1263
1371
  - **Plugin System**: Extensible architecture for custom integrations
@@ -1267,6 +1375,7 @@ npm run test:signal # CTRL+C signal handling tests
1267
1375
  We welcome contributions! Since command-stream is **public domain software**, your contributions will also be released into the public domain.
1268
1376
 
1269
1377
  ### ๐Ÿš€ **Getting Started**
1378
+
1270
1379
  ```bash
1271
1380
  git clone https://github.com/link-foundation/command-stream.git
1272
1381
  cd command-stream
@@ -1275,12 +1384,14 @@ bun test # Run the full test suite
1275
1384
  ```
1276
1385
 
1277
1386
  ### ๐Ÿ“‹ **Development Guidelines**
1387
+
1278
1388
  - All features must have comprehensive tests
1279
1389
  - Built-in commands should match bash/sh behavior exactly
1280
1390
  - Maintain cross-platform compatibility (Windows, macOS, Linux)
1281
1391
  - Follow the existing code style and patterns
1282
1392
 
1283
1393
  ### ๐Ÿงช **Running Tests**
1394
+
1284
1395
  ```bash
1285
1396
  bun test # All 518+ tests
1286
1397
  bun test tests/pipe.test.mjs # Specific test file
@@ -1300,6 +1411,7 @@ Unlike other shell utilities that require attribution (MIT, Apache 2.0), command
1300
1411
  - โœ… **Corporate friendly** - No license compliance overhead
1301
1412
 
1302
1413
  This makes command-stream ideal for:
1414
+
1303
1415
  - **Commercial products** where license attribution is inconvenient
1304
1416
  - **Embedded systems** where every byte counts
1305
1417
  - **Educational materials** that can be freely shared