command-stream 0.3.1 → 0.4.0

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
@@ -1,3 +1,6 @@
1
+ [![npm](https://img.shields.io/npm/v/command-stream.svg)](https://npmjs.com/command-stream)
2
+ [![License](https://img.shields.io/badge/license-Unlicense-blue.svg)](https://github.com/link-foundation/command-stream/blob/main/LICENSE)
3
+
1
4
  [![Open in Gitpod](https://img.shields.io/badge/Gitpod-ready--to--code-f29718?logo=gitpod)](https://gitpod.io/#https://github.com/link-foundation/command-stream)
2
5
  [![Open in GitHub Codespaces](https://img.shields.io/badge/GitHub%20Codespaces-Open-181717?logo=github)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=link-foundation/command-stream)
3
6
 
@@ -23,31 +26,39 @@ A modern $ shell utility library with streaming, async iteration, and EventEmitt
23
26
 
24
27
  ## Comparison with Other Libraries
25
28
 
26
- | Feature | [command-stream](https://github.com/link-foundation/command-stream) | [Bun.$](https://bun.sh/docs/runtime/shell) | [execa](https://github.com/sindresorhus/execa) | [zx](https://github.com/google/zx) |
27
- |---------|----------------|-------|-------|-----|
28
- | **Runtime Support** | ✅ Bun + Node.js | 🟡 Bun only | ✅ Node.js | ✅ Node.js |
29
- | **Template Literals** | ✅ `` $`cmd` `` | ✅ `` $`cmd` `` | ✅ `` $`cmd` `` | ✅ `` $`cmd` `` |
30
- | **Real-time Streaming** | ✅ Live output | ❌ Buffer only | 🟡 Limited | ❌ Buffer only |
31
- | **Synchronous Execution** | ✅ `.sync()` with events | ❌ No | ✅ `execaSync` | ❌ No |
32
- | **Async Iteration** | ✅ `for await (chunk of $.stream())` | ❌ No | ❌ No | ❌ No |
33
- | **EventEmitter Pattern** | ✅ `.on('data', ...)` | ❌ No | 🟡 Limited events | ❌ No |
34
- | **Mixed Patterns** | ✅ Events + await/sync | ❌ No | ❌ No | ❌ No |
35
- | **Bun.$ Compatibility** | ✅ `.text()` method support | ✅ Native API | ❌ No | ❌ No |
36
- | **Shell Injection Protection** | ✅ Auto-quoting | ✅ Built-in | ✅ Safe by default | ✅ Safe by default |
37
- | **Cross-platform** | ✅ macOS/Linux/Windows | ✅ Yes | ✅ Yes | ✅ Yes |
38
- | **Performance** | ⚡ Fast (Bun optimized) | ⚡ Very fast | 🐌 Moderate | 🐌 Slow |
39
- | **Memory Efficiency** | ✅ Streaming prevents buildup | 🟡 Buffers in memory | 🟡 Buffers in memory | 🟡 Buffers in memory |
40
- | **Error Handling** | ✅ Configurable (`set -e`/`set +e`, non-zero OK by default) | ✅ Throws on error | ✅ Throws on error | ✅ Throws on error |
41
- | **Shell Settings** | ✅ `set -e`/`set +e` equivalent | ❌ No | ❌ No | ❌ No |
42
- | **Stdout Support** | ✅ Real-time streaming + events | ✅ Shell redirection + buffered | ✅ Node.js streams + interleaved | ✅ Readable streams + `.pipe.stdout` |
43
- | **Stderr Support** | ✅ Real-time streaming + events | ✅ Redirection + `.quiet()` access | ✅ Streams + interleaved output | ✅ Readable streams + `.pipe.stderr` |
44
- | **Stdin Support** | ✅ string/Buffer/inherit/ignore | ✅ Pipe operations | ✅ Input/output streams | ✅ Basic stdin |
45
- | **Built-in Commands** | ✅ **18 commands**: cat, ls, mkdir, rm, mv, cp, touch, basename, dirname, seq, yes + all Bun.$ commands | ✅ echo, cd, etc. | ❌ Uses system | ❌ Uses system |
46
- | **Virtual Commands Engine** | ✅ **Revolutionary**: Register JavaScript functions as shell commands with full pipeline support | ❌ No extensibility | ❌ No custom commands | ❌ No custom commands |
47
- | **Pipeline/Piping Support** | ✅ **Advanced**: System + Built-ins + Virtual + Mixed + `.pipe()` method | ✅ Standard shell piping | ✅ Programmatic `.pipe()` + multi-destination | ✅ Shell piping + `.pipe()` method |
48
- | **Bundle Size** | 📦 ~15KB | 🎯 0KB (built-in) | 📦 ~25KB | 📦 ~50KB |
49
- | **TypeScript** | 🔄 Coming soon | Built-in | Full support | ✅ Full support |
50
- | **License** | ✅ **Unlicense (Public Domain)** | 🟡 MIT (+ LGPL dependencies) | 🟡 MIT | 🟡 Apache 2.0 |
29
+ | Feature | [command-stream](https://github.com/link-foundation/command-stream) | [Bun.$](https://bun.sh/docs/runtime/shell) | [execa](https://github.com/sindresorhus/execa) | [zx](https://github.com/google/zx) | [ShellJS](https://github.com/shelljs/shelljs) | [cross-spawn](https://github.com/moxystudio/node-cross-spawn) |
30
+ |---------|----------------|-------|-------|-----|-------|-------|
31
+ | **Runtime Support** | ✅ Bun + Node.js | 🟡 Bun only | ✅ Node.js | ✅ Node.js | ✅ Node.js | ✅ Node.js |
32
+ | **Template Literals** | ✅ `` $`cmd` `` | ✅ `` $`cmd` `` | ✅ `` $`cmd` `` | ✅ `` $`cmd` `` | ❌ Function calls | ❌ Function calls |
33
+ | **Real-time Streaming** | ✅ Live output | ❌ Buffer only | 🟡 Limited | ❌ Buffer only | ❌ Buffer only | ❌ Buffer only |
34
+ | **Synchronous Execution** | ✅ `.sync()` with events | ❌ No | ✅ `execaSync` | ❌ No | ✅ Sync by default | ✅ `spawnSync` |
35
+ | **Async Iteration** | ✅ `for await (chunk of $.stream())` | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No |
36
+ | **EventEmitter Pattern** | ✅ `.on('data', ...)` | ❌ No | 🟡 Limited events | ❌ No | ❌ No | 🟡 Child process events |
37
+ | **Mixed Patterns** | ✅ Events + await/sync | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No |
38
+ | **Bun.$ Compatibility** | ✅ `.text()` method support | ✅ Native API | ❌ No | ❌ No | ❌ No | ❌ No |
39
+ | **Shell Injection Protection** | ✅ Auto-quoting | ✅ Built-in | ✅ Safe by default | ✅ Safe by default | 🟡 Manual escaping | ✅ Safe by default |
40
+ | **Cross-platform** | ✅ macOS/Linux/Windows | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ **Specialized** cross-platform |
41
+ | **Performance** | ⚡ Fast (Bun optimized) | ⚡ Very fast | 🐌 Moderate | 🐌 Slow | 🐌 Moderate | ⚡ Fast |
42
+ | **Memory Efficiency** | ✅ Streaming prevents buildup | 🟡 Buffers in memory | 🟡 Buffers in memory | 🟡 Buffers in memory | 🟡 Buffers in memory | 🟡 Buffers in memory |
43
+ | **Error Handling** | ✅ Configurable (`set -e`/`set +e`, non-zero OK by default) | ✅ Throws on error | ✅ Throws on error | ✅ Throws on error | ✅ Configurable | ❌ Basic (exit codes) |
44
+ | **Shell Settings** | ✅ `set -e`/`set +e` equivalent | ❌ No | ❌ No | ❌ No | 🟡 Limited (`set()`) | ❌ No |
45
+ | **Stdout Support** | ✅ Real-time streaming + events | ✅ Shell redirection + buffered | ✅ Node.js streams + interleaved | ✅ Readable streams + `.pipe.stdout` | ✅ Direct output | ✅ Inherited/buffered |
46
+ | **Stderr Support** | ✅ Real-time streaming + events | ✅ Redirection + `.quiet()` access | ✅ Streams + interleaved output | ✅ Readable streams + `.pipe.stderr` | ✅ Error output | ✅ Inherited/buffered |
47
+ | **Stdin Support** | ✅ string/Buffer/inherit/ignore | ✅ Pipe operations | ✅ Input/output streams | ✅ Basic stdin | 🟡 Basic | ✅ Full stdio support |
48
+ | **Built-in Commands** | ✅ **18 commands**: cat, ls, mkdir, rm, mv, cp, touch, basename, dirname, seq, yes + all Bun.$ commands | ✅ echo, cd, etc. | ❌ Uses system | ❌ Uses system | ✅ **20+ commands**: cat, ls, mkdir, rm, mv, cp, etc. | ❌ Uses system |
49
+ | **Virtual Commands Engine** | ✅ **Revolutionary**: Register JavaScript functions as shell commands with full pipeline support | ❌ No extensibility | ❌ No custom commands | ❌ No custom commands | ❌ No custom commands | ❌ No custom commands |
50
+ | **Pipeline/Piping Support** | ✅ **Advanced**: System + Built-ins + Virtual + Mixed + `.pipe()` method | ✅ Standard shell piping | ✅ Programmatic `.pipe()` + multi-destination | ✅ Shell piping + `.pipe()` method | ✅ Shell piping + `.to()` method | ❌ No piping |
51
+ | **Bundle Size** | 📦 **~20KB gzipped** | 🎯 0KB (built-in) | 📦 ~400KB+ (packagephobia) | 📦 ~50KB+ (estimated) | 📦 ~15KB gzipped | 📦 ~2KB gzipped |
52
+ | **Signal Handling** | **Advanced SIGINT/SIGTERM forwarding** with cleanup | 🟡 Basic | 🟡 Basic | 🟡 Basic | 🟡 Basic | **Excellent** cross-platform |
53
+ | **Process Management** | ✅ **Robust child process lifecycle** with proper termination | Basic | Good | 🟡 Limited | 🟡 Limited | ✅ **Excellent** spawn wrapper |
54
+ | **Debug Tracing** | ✅ **Comprehensive VERBOSE logging** for CI/debugging | ❌ No | 🟡 Limited | ❌ No | 🟡 Basic | ❌ No |
55
+ | **Test Coverage** | ✅ **410 tests, 909 assertions** | 🟡 Good coverage | ✅ Excellent | 🟡 Good | ✅ Good | ✅ Good |
56
+ | **CI Reliability** | ✅ **Platform-specific handling** (macOS/Ubuntu) | 🟡 Basic | ✅ Good | 🟡 Basic | ✅ Good | ✅ **Excellent** |
57
+ | **Documentation** | ✅ **Comprehensive examples + guides** | ✅ Good | ✅ Excellent | 🟡 Limited | ✅ Good | 🟡 Basic |
58
+ | **TypeScript** | 🔄 Coming soon | ✅ Built-in | ✅ Full support | ✅ Full support | 🟡 Community types | ✅ Built-in |
59
+ | **License** | ✅ **Unlicense (Public Domain)** | 🟡 MIT (+ LGPL dependencies) | 🟡 MIT | 🟡 Apache 2.0 | 🟡 BSD-3-Clause | 🟡 MIT |
60
+
61
+ **📊 Popularity (Weekly Downloads 2024):** [cross-spawn](https://www.npmjs.com/package/cross-spawn): 102M+ • [execa](https://www.npmjs.com/package/execa): 98M+ • [ShellJS](https://www.npmjs.com/package/shelljs): 9M+ • [zx](https://www.npmjs.com/package/zx): Growing fast
51
62
 
52
63
  ### Why Choose command-stream?
53
64
 
@@ -60,7 +71,9 @@ A modern $ shell utility library with streaming, async iteration, and EventEmitt
60
71
  - **🐚 Shell Replacement**: Dynamic error handling with `set -e`/`set +e` equivalents for .sh file replacement
61
72
  - **⚡ Bun Optimized**: Designed for Bun with Node.js fallback compatibility
62
73
  - **💾 Memory Efficient**: Streaming prevents large buffer accumulation
63
- - **🛡️ Production Ready**: 266+ tests with comprehensive coverage
74
+ - **🛡️ Production Ready**: **410 tests, 909 assertions** with comprehensive coverage including CI reliability
75
+ - **🎯 Advanced Signal Handling**: Robust SIGINT/SIGTERM forwarding with proper child process cleanup
76
+ - **🔍 Debug-Friendly**: Comprehensive VERBOSE tracing for CI debugging and troubleshooting
64
77
 
65
78
  ## Built-in Commands (🚀 NEW!)
66
79
 
@@ -140,6 +153,42 @@ console.log(result.stdout);
140
153
  console.log(result.code); // exit code
141
154
  ```
142
155
 
156
+ ### Custom Options with $({ options }) Syntax (NEW!)
157
+
158
+ ```javascript
159
+ import { $ } from 'command-stream';
160
+
161
+ // Create a $ with custom options
162
+ const $silent = $({ mirror: false, capture: true });
163
+ const result = await $silent`echo "quiet operation"`;
164
+
165
+ // Options for stdin handling
166
+ const $withInput = $({ stdin: 'input data\n' });
167
+ await $withInput`cat`; // Pipes the input to cat
168
+
169
+ // Custom environment variables
170
+ const $withEnv = $({ env: { ...process.env, MY_VAR: 'value' } });
171
+ await $withEnv`printenv MY_VAR`; // Prints: value
172
+
173
+ // Custom working directory
174
+ const $inTmp = $({ cwd: '/tmp' });
175
+ await $inTmp`pwd`; // Prints: /tmp
176
+
177
+ // Combine multiple options
178
+ const $custom = $({
179
+ stdin: 'test data',
180
+ mirror: false,
181
+ capture: true,
182
+ cwd: '/tmp'
183
+ });
184
+ await $custom`cat > output.txt`; // Writes to /tmp/output.txt silently
185
+
186
+ // Reusable configurations
187
+ const $prod = $({ env: { NODE_ENV: 'production' }, capture: true });
188
+ await $prod`npm start`;
189
+ await $prod`npm test`;
190
+ ```
191
+
143
192
  ### Execution Control (NEW!)
144
193
 
145
194
  ```javascript
@@ -660,7 +709,8 @@ The enhanced `$` function returns a `ProcessRunner` instance that extends `Event
660
709
  - `env: object` - Environment variables
661
710
 
662
711
  **Override defaults:**
663
- - Use `sh(command, options)` for one-off overrides
712
+ - Use `$({ options })` syntax for one-off configurations with template literals
713
+ - Use `sh(command, options)` for one-off overrides with string commands
664
714
  - Use `create(defaultOptions)` to create custom `$` with different defaults
665
715
 
666
716
  ### Shell Settings API
@@ -676,6 +726,38 @@ Control shell behavior like bash `set`/`unset` commands:
676
726
  - `unset(option)`: Disable shell option
677
727
  - `shell.settings()`: Get current settings object
678
728
 
729
+ #### Error Handling Modes
730
+
731
+ ```javascript
732
+ import { $, shell } from 'command-stream';
733
+
734
+ // ✅ Default behavior: Commands don't throw on non-zero exit
735
+ const result = await $`ls nonexistent-file`; // Won't throw
736
+ console.log(result.code); // → 2 (non-zero, but no exception)
737
+
738
+ // ✅ Enable errexit: Commands throw on non-zero exit
739
+ shell.errexit(true);
740
+ try {
741
+ await $`ls nonexistent-file`; // Throws error
742
+ } catch (error) {
743
+ console.log('Command failed:', error.code); // → 2
744
+ }
745
+
746
+ // ✅ Disable errexit: Back to non-throwing behavior
747
+ shell.errexit(false);
748
+ await $`ls nonexistent-file`; // Won't throw, returns result with code 2
749
+
750
+ // ✅ One-time override without changing global settings
751
+ try {
752
+ const result = await $`ls nonexistent-file`;
753
+ if (result.code !== 0) {
754
+ throw new Error(`Command failed with code ${result.code}`);
755
+ }
756
+ } catch (error) {
757
+ console.log('Manual error handling');
758
+ }
759
+ ```
760
+
679
761
  ### Virtual Commands API
680
762
 
681
763
  Control and extend the command system with custom JavaScript functions:
@@ -690,6 +772,54 @@ Control and extend the command system with custom JavaScript functions:
690
772
  - `enableVirtualCommands()`: Enable virtual command processing
691
773
  - `disableVirtualCommands()`: Disable virtual commands (use system commands only)
692
774
 
775
+ #### Advanced Virtual Command Features
776
+
777
+ ```javascript
778
+ import { $, register } from 'command-stream';
779
+
780
+ // ✅ Cancellation support with AbortController
781
+ register('cancellable', async function* (args, stdin, options) {
782
+ for (let i = 0; i < 10; i++) {
783
+ if (options.signal?.aborted) {
784
+ break; // Proper cancellation handling
785
+ }
786
+ yield `Count: ${i}\n`;
787
+ await new Promise(resolve => setTimeout(resolve, 1000));
788
+ }
789
+ });
790
+
791
+ // ✅ Access to all process options
792
+ register('debug-info', async (args, stdin, options) => {
793
+ return {
794
+ stdout: JSON.stringify({
795
+ args,
796
+ cwd: options.cwd,
797
+ env: Object.keys(options.env || {}),
798
+ stdinLength: stdin.length,
799
+ mirror: options.mirror,
800
+ capture: options.capture
801
+ }, null, 2),
802
+ code: 0
803
+ };
804
+ });
805
+
806
+ // ✅ Error handling and non-zero exit codes
807
+ register('maybe-fail', async (args) => {
808
+ if (Math.random() > 0.5) {
809
+ return {
810
+ stdout: 'Success!\n',
811
+ code: 0
812
+ };
813
+ } else {
814
+ return {
815
+ stdout: '',
816
+ stderr: 'Random failure occurred\n',
817
+ code: 1
818
+ };
819
+ }
820
+ });
821
+ ```
822
+
693
823
  #### Handler Function Signature
694
824
 
695
825
  ```javascript
@@ -771,10 +901,172 @@ const result4 = await $`echo "pipe test"`.pipe($`cat`);
771
901
  const text4 = await result4.text(); // "pipe test\n"
772
902
  ```
773
903
 
904
+ ## Signal Handling (CTRL+C Support)
905
+
906
+ The library provides **advanced CTRL+C handling** that properly manages signals across different scenarios:
907
+
908
+ ### How It Works
909
+
910
+ 1. **Smart Signal Forwarding**: CTRL+C is forwarded **only when child processes are active**
911
+ 2. **User Handler Preservation**: When no children are running, your custom SIGINT handlers work normally
912
+ 3. **Process Groups**: Child processes use detached spawning for proper signal isolation
913
+ 4. **TTY Mode Support**: Raw TTY mode is properly managed and restored on interruption
914
+ 5. **Graceful Termination**: Uses SIGTERM → SIGKILL escalation for robust process cleanup
915
+ 6. **Exit Code Standards**: Proper signal exit codes (130 for SIGINT, 143 for SIGTERM)
916
+
917
+ ### Advanced Signal Behavior
918
+
919
+ ```javascript
920
+ // ✅ Smart signal handling - only interferes when necessary
921
+ import { $ } from 'command-stream';
922
+
923
+ // Case 1: No children active - your handlers work normally
924
+ process.on('SIGINT', () => {
925
+ console.log('My custom handler runs!');
926
+ process.exit(42); // Custom exit code
927
+ });
928
+ // Press CTRL+C → Your handler runs, exits with code 42
929
+
930
+ // Case 2: Children active - automatic forwarding
931
+ await $`ping 8.8.8.8`; // Press CTRL+C → Forwards to ping, exits with code 130
932
+
933
+ // Case 3: Multiple processes - all interrupted
934
+ await Promise.all([
935
+ $`sleep 100`,
936
+ $`ping google.com`
937
+ ]); // Press CTRL+C → All processes terminated, exits with code 130
938
+ ```
939
+
940
+ ### Examples
941
+
942
+ ```javascript
943
+ // Long-running command that can be interrupted with CTRL+C
944
+ try {
945
+ await $`ping 8.8.8.8`; // Press CTRL+C to stop
946
+ } catch (error) {
947
+ console.log('Command interrupted:', error.code); // Exit code 130 (SIGINT)
948
+ }
949
+
950
+ // Multiple concurrent processes - CTRL+C stops all
951
+ try {
952
+ await Promise.all([
953
+ $`sleep 100`,
954
+ $`ping google.com`,
955
+ $`tail -f /var/log/system.log`
956
+ ]);
957
+ } catch (error) {
958
+ // All processes are terminated when you press CTRL+C
959
+ }
960
+
961
+ // Works with streaming patterns too
962
+ try {
963
+ for await (const chunk of $`ping 8.8.8.8`.stream()) {
964
+ console.log(chunk);
965
+ // Press CTRL+C to break the loop and stop the process
966
+ }
967
+ } catch (error) {
968
+ console.log('Streaming interrupted');
969
+ }
970
+ ```
971
+
972
+ ### Signal Handling Behavior
973
+
974
+ - **🎯 Smart Detection**: Only forwards CTRL+C when child processes are active
975
+ - **🛡️ Non-Interference**: Preserves user SIGINT handlers when no children running
976
+ - **⚡ Interactive Commands**: Commands like `vim`, `less`, `top` work with their own signal handling
977
+ - **🔄 Process Groups**: Detached spawning ensures proper signal isolation
978
+ - **🧹 TTY Cleanup**: Raw terminal mode properly restored on interruption
979
+ - **📊 Standard Exit Codes**:
980
+ - `130` - SIGINT interruption (CTRL+C)
981
+ - `143` - SIGTERM termination (programmatic kill)
982
+ - `137` - SIGKILL force termination
983
+
984
+ ### Command Resolution Priority
985
+
986
+ ```javascript
987
+ // Understanding how commands are resolved:
988
+
989
+ // 1. Virtual Commands (highest priority)
990
+ register('echo', () => ({ stdout: 'virtual!\n', code: 0 }));
991
+ await $`echo test`; // → "virtual!"
992
+
993
+ // 2. Built-in Commands (if no virtual match)
994
+ unregister('echo');
995
+ await $`echo test`; // → Uses built-in echo
996
+
997
+ // 3. System Commands (if no built-in/virtual match)
998
+ await $`unknown-command`; // → Uses system PATH lookup
999
+
1000
+ // 4. Virtual Bypass (special case)
1001
+ await $({ stdin: 'data' })`sleep 1`; // Bypasses virtual sleep, uses system sleep
1002
+ ```
1003
+
1004
+ ## Execution Patterns Deep Dive
1005
+
1006
+ ### When to Use Different Patterns
1007
+
1008
+ ```javascript
1009
+ import { $ } from 'command-stream';
1010
+
1011
+ // ✅ Use await for simple command execution
1012
+ const result = await $`ls -la`;
1013
+
1014
+ // ✅ Use .sync() when you need blocking execution with events
1015
+ const syncCmd = $`build-script`
1016
+ .on('stdout', chunk => updateProgress(chunk))
1017
+ .sync(); // Events fire after completion
1018
+
1019
+ // ✅ Use .start() for non-blocking execution with real-time events
1020
+ const asyncCmd = $`long-running-server`
1021
+ .on('stdout', chunk => logOutput(chunk))
1022
+ .start(); // Events fire in real-time
1023
+
1024
+ // ✅ Use .stream() for processing large outputs efficiently
1025
+ for await (const chunk of $`generate-big-file`.stream()) {
1026
+ processChunkInRealTime(chunk);
1027
+ } // Memory efficient - processes chunks as they arrive
1028
+
1029
+ // ✅ Use EventEmitter pattern for complex workflows
1030
+ $`deployment-script`
1031
+ .on('stdout', chunk => {
1032
+ if (chunk.toString().includes('ERROR')) {
1033
+ handleError(chunk);
1034
+ }
1035
+ })
1036
+ .on('stderr', chunk => logError(chunk))
1037
+ .on('end', result => {
1038
+ if (result.code === 0) {
1039
+ notifySuccess();
1040
+ }
1041
+ })
1042
+ .start();
1043
+ ```
1044
+
1045
+ ### Performance Considerations
1046
+
1047
+ ```javascript
1048
+ // 🚀 Memory Efficient: For large outputs, use streaming
1049
+ for await (const chunk of $`cat huge-file.log`.stream()) {
1050
+ processChunk(chunk); // Processes incrementally
1051
+ }
1052
+
1053
+ // 🐌 Memory Inefficient: Buffers entire output in memory
1054
+ const result = await $`cat huge-file.log`;
1055
+ processFile(result.stdout); // Loads everything into memory
1056
+
1057
+ // ⚡ Fastest: Sync execution for small, quick commands
1058
+ const quickResult = $`pwd`.sync();
1059
+
1060
+ // 🔄 Best for UX: Async with events for long-running commands
1061
+ $`npm install`
1062
+ .on('stdout', showProgress)
1063
+ .start();
1064
+ ```
1065
+
774
1066
  ## Testing
775
1067
 
776
1068
  ```bash
777
- # Run comprehensive test suite (266 tests)
1069
+ # Run comprehensive test suite (270+ tests)
778
1070
  bun test
779
1071
 
780
1072
  # Run tests with coverage report
@@ -782,9 +1074,10 @@ bun test --coverage
782
1074
 
783
1075
  # Run specific test categories
784
1076
  npm run test:features # Feature comparison tests
785
- npm run test:builtin # Built-in commands tests
1077
+ npm run test:builtin # Built-in commands tests
786
1078
  npm run test:pipe # .pipe() method tests
787
1079
  npm run test:sync # Synchronous execution tests
1080
+ npm run test:signal # CTRL+C signal handling tests
788
1081
  ```
789
1082
 
790
1083
  ## Requirements
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "command-stream",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Modern $ shell utility library with streaming, async iteration, and EventEmitter support, optimized for Bun runtime",
5
5
  "type": "module",
6
- "main": "$.mjs",
6
+ "main": "src/$.mjs",
7
7
  "exports": {
8
- ".": "./$.mjs"
8
+ ".": "./src/$.mjs"
9
9
  },
10
10
  "repository": {
11
11
  "type": "git",
@@ -43,7 +43,7 @@
43
43
  "node": ">=20.0.0"
44
44
  },
45
45
  "files": [
46
- "$.mjs",
46
+ "src/",
47
47
  "README.md",
48
48
  "LICENSE"
49
49
  ]