command-stream 0.8.2 → 0.9.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/js/examples/01-basic-streaming.mjs +14 -0
- package/js/examples/02-async-iterator.mjs +9 -0
- package/js/examples/03-file-and-console.mjs +16 -0
- package/js/examples/04-claude-jq-pipe.mjs +16 -0
- package/js/examples/CI-DEBUG-README.md +138 -0
- package/js/examples/README-examples.mjs +111 -0
- package/js/examples/README.md +345 -0
- package/js/examples/STREAMING_INTERFACES_SUMMARY.md +116 -0
- package/js/examples/add-test-timeouts.js +107 -0
- package/js/examples/ansi-default-preserved.mjs +11 -0
- package/js/examples/ansi-global-config.mjs +12 -0
- package/js/examples/ansi-reset-default.mjs +12 -0
- package/js/examples/ansi-strip-utils.mjs +12 -0
- package/js/examples/baseline-child-process.mjs +23 -0
- package/js/examples/baseline-claude-test.mjs +47 -0
- package/js/examples/baseline-working.mjs +34 -0
- package/js/examples/capture-mirror-comparison.mjs +23 -0
- package/js/examples/capture-mirror-default.mjs +11 -0
- package/js/examples/capture-mirror-performance.mjs +16 -0
- package/js/examples/capture-mirror-show-only.mjs +16 -0
- package/js/examples/capture-mirror-silent-processing.mjs +16 -0
- package/js/examples/ci-debug-baseline-vs-library.mjs +265 -0
- package/js/examples/ci-debug-es-module-loading.mjs +184 -0
- package/js/examples/ci-debug-signal-handling.mjs +225 -0
- package/js/examples/ci-debug-stdout-buffering.mjs +94 -0
- package/js/examples/ci-debug-test-timeouts.mjs +259 -0
- package/js/examples/claude-exact-file-output.mjs +20 -0
- package/js/examples/claude-exact-jq.mjs +13 -0
- package/js/examples/claude-exact-streaming.mjs +13 -0
- package/js/examples/claude-jq-pipeline.mjs +13 -0
- package/js/examples/claude-json-stream.mjs +39 -0
- package/js/examples/claude-streaming-basic.mjs +99 -0
- package/js/examples/claude-streaming-demo.mjs +126 -0
- package/js/examples/claude-streaming-final.mjs +20 -0
- package/js/examples/cleanup-verification-test.mjs +115 -0
- package/js/examples/colors-buffer-processing.mjs +14 -0
- package/js/examples/colors-default-preserved.mjs +15 -0
- package/js/examples/colors-per-command-config.mjs +15 -0
- package/js/examples/colors-strip-ansi.mjs +13 -0
- package/js/examples/commandstream-jq.mjs +29 -0
- package/js/examples/commandstream-working.mjs +23 -0
- package/js/examples/comprehensive-streams-demo.mjs +121 -0
- package/js/examples/ctrl-c-concurrent-processes.mjs +20 -0
- package/js/examples/ctrl-c-long-running-command.mjs +20 -0
- package/js/examples/ctrl-c-real-system-command.mjs +17 -0
- package/js/examples/ctrl-c-sleep-command.mjs +17 -0
- package/js/examples/ctrl-c-stdin-forwarding.mjs +20 -0
- package/js/examples/ctrl-c-virtual-command.mjs +17 -0
- package/js/examples/debug-already-started.mjs +20 -0
- package/js/examples/debug-ansi-processing.mjs +42 -0
- package/js/examples/debug-basic-streaming.mjs +44 -0
- package/js/examples/debug-buildshellcommand.mjs +82 -0
- package/js/examples/debug-child-process.mjs +43 -0
- package/js/examples/debug-child-state.mjs +55 -0
- package/js/examples/debug-chunking.mjs +38 -0
- package/js/examples/debug-command-parsing.mjs +61 -0
- package/js/examples/debug-complete-consolidation.mjs +97 -0
- package/js/examples/debug-echo-args.mjs +22 -0
- package/js/examples/debug-emit-timing.mjs +28 -0
- package/js/examples/debug-end-event.mjs +56 -0
- package/js/examples/debug-errexit.mjs +16 -0
- package/js/examples/debug-event-emission.mjs +40 -0
- package/js/examples/debug-event-timing.mjs +67 -0
- package/js/examples/debug-event-vs-result.mjs +30 -0
- package/js/examples/debug-exact-command.mjs +28 -0
- package/js/examples/debug-exact-test-scenario.mjs +44 -0
- package/js/examples/debug-execution-path.mjs +27 -0
- package/js/examples/debug-exit-command.mjs +38 -0
- package/js/examples/debug-exit-virtual.mjs +54 -0
- package/js/examples/debug-finish-consolidation.mjs +44 -0
- package/js/examples/debug-force-cleanup.mjs +47 -0
- package/js/examples/debug-getter-basic.mjs +13 -0
- package/js/examples/debug-getter-direct.mjs +23 -0
- package/js/examples/debug-getter-internals.mjs +61 -0
- package/js/examples/debug-handler-detection.mjs +65 -0
- package/js/examples/debug-idempotent-finish.mjs +54 -0
- package/js/examples/debug-idempotent-kill.mjs +58 -0
- package/js/examples/debug-interpolation-individual.mjs +88 -0
- package/js/examples/debug-interpolation-issue.mjs +101 -0
- package/js/examples/debug-jq-streaming.mjs +57 -0
- package/js/examples/debug-jq-tty-colors.mjs +168 -0
- package/js/examples/debug-kill-cleanup.mjs +56 -0
- package/js/examples/debug-kill-method.mjs +33 -0
- package/js/examples/debug-listener-interference.mjs +38 -0
- package/js/examples/debug-listener-lifecycle.mjs +50 -0
- package/js/examples/debug-listener-timing.mjs +62 -0
- package/js/examples/debug-listeners-property.mjs +34 -0
- package/js/examples/debug-map-methods.mjs +39 -0
- package/js/examples/debug-not-awaited-cleanup.mjs +106 -0
- package/js/examples/debug-off-method.mjs +28 -0
- package/js/examples/debug-option-merging.mjs +17 -0
- package/js/examples/debug-options.mjs +36 -0
- package/js/examples/debug-output.mjs +25 -0
- package/js/examples/debug-pattern-matching.mjs +69 -0
- package/js/examples/debug-pipeline-cat.mjs +28 -0
- package/js/examples/debug-pipeline-cleanup.mjs +71 -0
- package/js/examples/debug-pipeline-error-detailed.mjs +78 -0
- package/js/examples/debug-pipeline-error.mjs +65 -0
- package/js/examples/debug-pipeline-issue.mjs +26 -0
- package/js/examples/debug-pipeline-method.mjs +22 -0
- package/js/examples/debug-pipeline-stream.mjs +66 -0
- package/js/examples/debug-pipeline.mjs +14 -0
- package/js/examples/debug-process-exit-trace.mjs +41 -0
- package/js/examples/debug-process-path.mjs +38 -0
- package/js/examples/debug-property-check.mjs +29 -0
- package/js/examples/debug-resource-cleanup.mjs +83 -0
- package/js/examples/debug-shell-args.mjs +103 -0
- package/js/examples/debug-sigint-child-handler.mjs +44 -0
- package/js/examples/debug-sigint-forwarding.mjs +61 -0
- package/js/examples/debug-sigint-handler-install.mjs +79 -0
- package/js/examples/debug-sigint-handler-order.mjs +85 -0
- package/js/examples/debug-sigint-listeners.mjs +48 -0
- package/js/examples/debug-sigint-start-pattern.mjs +62 -0
- package/js/examples/debug-sigint-timer.mjs +40 -0
- package/js/examples/debug-simple-command.mjs +49 -0
- package/js/examples/debug-simple-getter.mjs +30 -0
- package/js/examples/debug-simple.mjs +39 -0
- package/js/examples/debug-simplified-finished.mjs +102 -0
- package/js/examples/debug-stack-overflow.mjs +25 -0
- package/js/examples/debug-stdin-simple.mjs +28 -0
- package/js/examples/debug-stdin.mjs +28 -0
- package/js/examples/debug-stream-emitter-isolated.mjs +45 -0
- package/js/examples/debug-stream-emitter.mjs +25 -0
- package/js/examples/debug-stream-events.mjs +70 -0
- package/js/examples/debug-stream-generator.mjs +23 -0
- package/js/examples/debug-stream-getter-issue.mjs +37 -0
- package/js/examples/debug-stream-getter.mjs +19 -0
- package/js/examples/debug-stream-internals.mjs +64 -0
- package/js/examples/debug-stream-method.mjs +46 -0
- package/js/examples/debug-stream-object.mjs +58 -0
- package/js/examples/debug-stream-properties.mjs +37 -0
- package/js/examples/debug-stream-timing.mjs +28 -0
- package/js/examples/debug-streaming.mjs +24 -0
- package/js/examples/debug-test-isolation.mjs +54 -0
- package/js/examples/debug-test-state.mjs +27 -0
- package/js/examples/debug-user-sigint.mjs +19 -0
- package/js/examples/debug-virtual-disable.mjs +21 -0
- package/js/examples/debug-virtual-vs-real.mjs +68 -0
- package/js/examples/debug-with-trace.mjs +23 -0
- package/js/examples/debug_parent_stream.mjs +22 -0
- package/js/examples/emulate-claude-stream.mjs +30 -0
- package/js/examples/emulated-streaming-direct.mjs +22 -0
- package/js/examples/emulated-streaming-jq-pipe.mjs +22 -0
- package/js/examples/emulated-streaming-sh-pipe.mjs +23 -0
- package/js/examples/events-build-process.mjs +73 -0
- package/js/examples/events-concurrent-streams.mjs +51 -0
- package/js/examples/events-error-handling.mjs +59 -0
- package/js/examples/events-file-monitoring.mjs +66 -0
- package/js/examples/events-interactive-simulation.mjs +69 -0
- package/js/examples/events-log-processing.mjs +72 -0
- package/js/examples/events-network-monitoring.mjs +68 -0
- package/js/examples/events-ping-basic.mjs +37 -0
- package/js/examples/events-progress-tracking.mjs +55 -0
- package/js/examples/events-stdin-input.mjs +34 -0
- package/js/examples/example-ansi-ls.mjs +39 -0
- package/js/examples/example-top.mjs +27 -0
- package/js/examples/final-ping-stdin-proof.mjs +88 -0
- package/js/examples/final-test-shell-operators.mjs +123 -0
- package/js/examples/final-working-examples.mjs +162 -0
- package/js/examples/gh-auth-test.mjs +103 -0
- package/js/examples/gh-delete-hang-test.mjs +79 -0
- package/js/examples/gh-gist-creation-test.mjs +276 -0
- package/js/examples/gh-gist-minimal-test.mjs +89 -0
- package/js/examples/gh-hang-exact-original.mjs +83 -0
- package/js/examples/gh-hang-reproduction.mjs +151 -0
- package/js/examples/gh-hang-test-with-redirect.mjs +45 -0
- package/js/examples/gh-hang-test-without-redirect.mjs +43 -0
- package/js/examples/gh-minimal-hang-check.mjs +33 -0
- package/js/examples/gh-operations-with-cd.mjs +187 -0
- package/js/examples/gh-output-test.mjs +102 -0
- package/js/examples/gh-reproduce-hang.mjs +41 -0
- package/js/examples/git-operations-with-cd.mjs +186 -0
- package/js/examples/interactive-math-calc.mjs +45 -0
- package/js/examples/interactive-top-fixed.mjs +25 -0
- package/js/examples/interactive-top-improved.mjs +72 -0
- package/js/examples/interactive-top-pty-logging.mjs +69 -0
- package/js/examples/interactive-top-pty.mjs +27 -0
- package/js/examples/interactive-top-with-logging.mjs +56 -0
- package/js/examples/interactive-top.mjs +29 -0
- package/js/examples/jq-color-demo.mjs +53 -0
- package/js/examples/jq-colors-streaming.mjs +42 -0
- package/js/examples/manual-ctrl-c-test.mjs +50 -0
- package/js/examples/methods-multiple-options.mjs +25 -0
- package/js/examples/methods-run-basic.mjs +10 -0
- package/js/examples/methods-start-basic.mjs +10 -0
- package/js/examples/node-compat-data-events.mjs +36 -0
- package/js/examples/node-compat-readable-event.mjs +29 -0
- package/js/examples/node-compat-small-buffer.mjs +33 -0
- package/js/examples/options-capture-false.mjs +12 -0
- package/js/examples/options-combined-settings.mjs +13 -0
- package/js/examples/options-custom-input.mjs +16 -0
- package/js/examples/options-default-behavior.mjs +10 -0
- package/js/examples/options-maximum-performance.mjs +15 -0
- package/js/examples/options-mirror-false.mjs +10 -0
- package/js/examples/options-performance-mode.mjs +13 -0
- package/js/examples/options-performance-optimization.mjs +14 -0
- package/js/examples/options-run-alias-demo.mjs +15 -0
- package/js/examples/options-run-alias.mjs +10 -0
- package/js/examples/options-silent-execution.mjs +14 -0
- package/js/examples/options-streaming-capture.mjs +24 -0
- package/js/examples/options-streaming-multiple.mjs +35 -0
- package/js/examples/options-streaming-silent.mjs +21 -0
- package/js/examples/options-streaming-stdin.mjs +21 -0
- package/js/examples/ping-streaming-filtered.mjs +22 -0
- package/js/examples/ping-streaming-interruptible.mjs +47 -0
- package/js/examples/ping-streaming-silent.mjs +24 -0
- package/js/examples/ping-streaming-simple.mjs +13 -0
- package/js/examples/ping-streaming-statistics.mjs +49 -0
- package/js/examples/ping-streaming-timestamps.mjs +22 -0
- package/js/examples/ping-streaming.mjs +48 -0
- package/js/examples/prove-ping-stdin-limitation.mjs +94 -0
- package/js/examples/readme-example.mjs +39 -0
- package/js/examples/realtime-json-stream.mjs +143 -0
- package/js/examples/reliable-stdin-commands.mjs +135 -0
- package/js/examples/reproduce-issue-135-v2.mjs +15 -0
- package/js/examples/reproduce-issue-135.mjs +17 -0
- package/js/examples/shell-cd-behavior.mjs +88 -0
- package/js/examples/sigint-forwarding-test.mjs +60 -0
- package/js/examples/sigint-handler-test.mjs +72 -0
- package/js/examples/simple-async-test.mjs +49 -0
- package/js/examples/simple-claude-test.mjs +17 -0
- package/js/examples/simple-event-test.mjs +33 -0
- package/js/examples/simple-jq-streaming.mjs +48 -0
- package/js/examples/simple-stream-demo.mjs +35 -0
- package/js/examples/simple-test-sleep.js +30 -0
- package/js/examples/simple-working-stdin.mjs +30 -0
- package/js/examples/streaming-behavior-test.mjs +116 -0
- package/js/examples/streaming-direct-command.mjs +21 -0
- package/js/examples/streaming-filtered-output.mjs +33 -0
- package/js/examples/streaming-grep-pipeline.mjs +21 -0
- package/js/examples/streaming-interactive-stdin.mjs +24 -0
- package/js/examples/streaming-jq-pipeline.mjs +23 -0
- package/js/examples/streaming-multistage-pipeline.mjs +23 -0
- package/js/examples/streaming-pipes-event-pattern.mjs +27 -0
- package/js/examples/streaming-pipes-multistage.mjs +22 -0
- package/js/examples/streaming-pipes-realtime-jq.mjs +23 -0
- package/js/examples/streaming-progress-tracking.mjs +34 -0
- package/js/examples/streaming-reusable-configs.mjs +52 -0
- package/js/examples/streaming-silent-capture.mjs +20 -0
- package/js/examples/streaming-test-simple.mjs +70 -0
- package/js/examples/streaming-virtual-pipeline.mjs +18 -0
- package/js/examples/syntax-basic-comparison.mjs +31 -0
- package/js/examples/syntax-basic-options.mjs +12 -0
- package/js/examples/syntax-combined-options.mjs +19 -0
- package/js/examples/syntax-command-chaining.mjs +12 -0
- package/js/examples/syntax-custom-directory.mjs +10 -0
- package/js/examples/syntax-custom-environment.mjs +13 -0
- package/js/examples/syntax-custom-stdin.mjs +10 -0
- package/js/examples/syntax-mixed-regular.mjs +11 -0
- package/js/examples/syntax-mixed-usage.mjs +15 -0
- package/js/examples/syntax-multiple-listeners.mjs +87 -0
- package/js/examples/syntax-piping-comparison.mjs +32 -0
- package/js/examples/syntax-reusable-config.mjs +16 -0
- package/js/examples/syntax-reusable-configs.mjs +21 -0
- package/js/examples/syntax-silent-operations.mjs +10 -0
- package/js/examples/syntax-stdin-option.mjs +12 -0
- package/js/examples/temp-sigint-test.mjs +21 -0
- package/js/examples/test-actual-buildshell.mjs +44 -0
- package/js/examples/test-async-streams-working.mjs +102 -0
- package/js/examples/test-async-streams.mjs +90 -0
- package/js/examples/test-auth-parse.mjs +74 -0
- package/js/examples/test-auto-quoting.mjs +57 -0
- package/js/examples/test-auto-start-fix.mjs +95 -0
- package/js/examples/test-baseline-sigint.mjs +38 -0
- package/js/examples/test-buffer-behavior.mjs +39 -0
- package/js/examples/test-buffers-simple.mjs +35 -0
- package/js/examples/test-bun-specific-issue.mjs +106 -0
- package/js/examples/test-bun-streaming.mjs +81 -0
- package/js/examples/test-cat-direct.mjs +41 -0
- package/js/examples/test-cat-pipe.mjs +34 -0
- package/js/examples/test-cd-behavior.mjs +42 -0
- package/js/examples/test-child-process-timing.mjs +53 -0
- package/js/examples/test-child-sigint-handler.mjs +62 -0
- package/js/examples/test-cleanup-simple.mjs +21 -0
- package/js/examples/test-comprehensive-tracing.mjs +58 -0
- package/js/examples/test-correct-space-handling.mjs +46 -0
- package/js/examples/test-ctrl-c-debug.mjs +44 -0
- package/js/examples/test-ctrl-c-inherit.mjs +30 -0
- package/js/examples/test-ctrl-c-sleep.mjs +31 -0
- package/js/examples/test-ctrl-c.mjs +17 -0
- package/js/examples/test-debug-new-options.mjs +55 -0
- package/js/examples/test-debug-pty.mjs +49 -0
- package/js/examples/test-debug-tee.mjs +38 -0
- package/js/examples/test-debug.mjs +25 -0
- package/js/examples/test-direct-jq.mjs +47 -0
- package/js/examples/test-direct-pipe-reading.mjs +119 -0
- package/js/examples/test-direct-pipe.sh +28 -0
- package/js/examples/test-double-quoting-prevention.mjs +138 -0
- package/js/examples/test-edge-cases-quoting.mjs +89 -0
- package/js/examples/test-events.mjs +37 -0
- package/js/examples/test-explicit-stdio.mjs +51 -0
- package/js/examples/test-final-streaming.mjs +71 -0
- package/js/examples/test-fix.mjs +71 -0
- package/js/examples/test-incremental-streaming.mjs +46 -0
- package/js/examples/test-individual-spawn.mjs +35 -0
- package/js/examples/test-inherit-stdout-not-stdin.mjs +133 -0
- package/js/examples/test-injection-protection.mjs +77 -0
- package/js/examples/test-interactive-streaming.mjs +140 -0
- package/js/examples/test-interactive-top.md +24 -0
- package/js/examples/test-interactive.mjs +17 -0
- package/js/examples/test-interpolation.mjs +14 -0
- package/js/examples/test-interrupt.mjs +40 -0
- package/js/examples/test-issue-135-comprehensive.mjs +41 -0
- package/js/examples/test-issue12-detailed.mjs +89 -0
- package/js/examples/test-issue12-exact.mjs +33 -0
- package/js/examples/test-jq-color.mjs +57 -0
- package/js/examples/test-jq-colors.mjs +41 -0
- package/js/examples/test-jq-compact.mjs +33 -0
- package/js/examples/test-jq-native.sh +10 -0
- package/js/examples/test-jq-pipeline-behavior.mjs +80 -0
- package/js/examples/test-jq-realtime.mjs +40 -0
- package/js/examples/test-manual-start.mjs +54 -0
- package/js/examples/test-mixed-quoting.mjs +88 -0
- package/js/examples/test-multi-stream.mjs +50 -0
- package/js/examples/test-multistage-debug.mjs +44 -0
- package/js/examples/test-native-spawn-vs-command-stream.mjs +154 -0
- package/js/examples/test-no-parse-pipeline.mjs +33 -0
- package/js/examples/test-non-virtual.mjs +52 -0
- package/js/examples/test-operators.mjs +53 -0
- package/js/examples/test-parent-continues.mjs +44 -0
- package/js/examples/test-path-interpolation.mjs +86 -0
- package/js/examples/test-ping-kill-and-stdin.mjs +98 -0
- package/js/examples/test-ping.mjs +12 -0
- package/js/examples/test-pty-spawn.mjs +101 -0
- package/js/examples/test-pty.mjs +38 -0
- package/js/examples/test-quote-behavior-summary.mjs +110 -0
- package/js/examples/test-quote-edge-cases.mjs +69 -0
- package/js/examples/test-quote-parsing.mjs +23 -0
- package/js/examples/test-raw-function.mjs +153 -0
- package/js/examples/test-raw-streaming.mjs +47 -0
- package/js/examples/test-readme-examples.mjs +142 -0
- package/js/examples/test-real-cat.mjs +28 -0
- package/js/examples/test-real-commands.mjs +21 -0
- package/js/examples/test-real-shell.mjs +31 -0
- package/js/examples/test-real-stdin-commands.mjs +160 -0
- package/js/examples/test-runner-batched.mjs +98 -0
- package/js/examples/test-runner-simple.mjs +80 -0
- package/js/examples/test-runner.mjs +67 -0
- package/js/examples/test-scope-parse.mjs +31 -0
- package/js/examples/test-sh-pipeline.mjs +24 -0
- package/js/examples/test-shell-detection.mjs +71 -0
- package/js/examples/test-shell-parser.mjs +37 -0
- package/js/examples/test-sigint-behavior.mjs +241 -0
- package/js/examples/test-sigint-handling.sh +14 -0
- package/js/examples/test-simple-pipe.mjs +12 -0
- package/js/examples/test-simple-streaming.mjs +32 -0
- package/js/examples/test-sleep-stdin.js +27 -0
- package/js/examples/test-sleep.mjs +56 -0
- package/js/examples/test-smart-quoting.mjs +180 -0
- package/js/examples/test-spaces-in-path.mjs +48 -0
- package/js/examples/test-special-chars-quoting.mjs +54 -0
- package/js/examples/test-stdin-after-start.mjs +39 -0
- package/js/examples/test-stdin-simple.mjs +67 -0
- package/js/examples/test-stdin-timing.mjs +74 -0
- package/js/examples/test-stdio-combinations.mjs +124 -0
- package/js/examples/test-stream-access.mjs +84 -0
- package/js/examples/test-stream-cleanup.mjs +27 -0
- package/js/examples/test-stream-readers.mjs +152 -0
- package/js/examples/test-streaming-final.mjs +57 -0
- package/js/examples/test-streaming-interfaces.mjs +141 -0
- package/js/examples/test-streaming-timing.mjs +27 -0
- package/js/examples/test-streaming.mjs +32 -0
- package/js/examples/test-streams-stdin-comprehensive.mjs +134 -0
- package/js/examples/test-streams-stdin-ctrl-c.mjs +96 -0
- package/js/examples/test-template-literal.mjs +26 -0
- package/js/examples/test-template-vs-interpolation.mjs +49 -0
- package/js/examples/test-timing.mjs +41 -0
- package/js/examples/test-top-inherit-stdout-stdin-control.mjs +123 -0
- package/js/examples/test-top-quit-stdin.mjs +118 -0
- package/js/examples/test-trace-option.mjs +21 -0
- package/js/examples/test-user-double-quotes.mjs +36 -0
- package/js/examples/test-user-single-quotes.mjs +36 -0
- package/js/examples/test-verbose.mjs +18 -0
- package/js/examples/test-verbose2.mjs +32 -0
- package/js/examples/test-virtual-streaming.mjs +125 -0
- package/js/examples/test-waiting-command.mjs +52 -0
- package/js/examples/test-waiting-commands.mjs +83 -0
- package/js/examples/test-watch-mode.mjs +104 -0
- package/js/examples/test-yes-cancellation.mjs +26 -0
- package/js/examples/test-yes-detailed.mjs +58 -0
- package/js/examples/test-yes-trace.mjs +28 -0
- package/js/examples/trace-abort-controller.mjs +30 -0
- package/js/examples/trace-error-handling.mjs +22 -0
- package/js/examples/trace-pipeline-command.mjs +22 -0
- package/js/examples/trace-signal-handling.mjs +35 -0
- package/js/examples/trace-simple-command.mjs +18 -0
- package/js/examples/trace-stderr-output.mjs +22 -0
- package/js/examples/verify-fix-both-runtimes.mjs +73 -0
- package/js/examples/verify-issue12-fixed.mjs +78 -0
- package/js/examples/which-command-common-commands.mjs +19 -0
- package/js/examples/which-command-gh-test.mjs +23 -0
- package/js/examples/which-command-nonexistent.mjs +20 -0
- package/js/examples/which-command-system-comparison.mjs +28 -0
- package/js/examples/working-example.mjs +13 -0
- package/js/examples/working-stdin-examples.mjs +138 -0
- package/js/examples/working-streaming-demo.mjs +49 -0
- package/{src → js/src}/$.mjs +20 -4
- package/{src → js/src}/$.utils.mjs +14 -2
- package/js/tests/$.features.test.mjs +283 -0
- package/js/tests/$.test.mjs +935 -0
- package/js/tests/builtin-commands.test.mjs +387 -0
- package/js/tests/bun-shell-path-fix.test.mjs +115 -0
- package/js/tests/bun.features.test.mjs +189 -0
- package/js/tests/cd-virtual-command.test.mjs +622 -0
- package/js/tests/cleanup-verification.test.mjs +127 -0
- package/js/tests/ctrl-c-baseline.test.mjs +207 -0
- package/js/tests/ctrl-c-basic.test.mjs +220 -0
- package/js/tests/ctrl-c-library.test.mjs +197 -0
- package/js/tests/ctrl-c-signal.test.mjs +915 -0
- package/js/tests/examples.test.mjs +252 -0
- package/js/tests/execa.features.test.mjs +198 -0
- package/js/tests/gh-commands.test.mjs +164 -0
- package/js/tests/gh-gist-operations.test.mjs +221 -0
- package/js/tests/git-gh-cd.test.mjs +466 -0
- package/js/tests/interactive-option.test.mjs +114 -0
- package/js/tests/interactive-streaming.test.mjs +307 -0
- package/js/tests/issue-135-final.test.mjs +58 -0
- package/js/tests/jq-color-behavior.test.mjs +140 -0
- package/js/tests/jq.test.mjs +318 -0
- package/js/tests/options-examples.test.mjs +106 -0
- package/js/tests/options-syntax.test.mjs +112 -0
- package/js/tests/path-interpolation.test.mjs +412 -0
- package/js/tests/pipe.test.mjs +291 -0
- package/js/tests/raw-function.test.mjs +266 -0
- package/js/tests/readme-examples.test.mjs +427 -0
- package/js/tests/resource-cleanup-internals.test.mjs +669 -0
- package/js/tests/shell-settings.test.mjs +279 -0
- package/js/tests/sigint-cleanup-isolated.test.mjs +151 -0
- package/js/tests/sigint-cleanup.test.mjs +118 -0
- package/js/tests/start-run-edge-cases.test.mjs +152 -0
- package/js/tests/start-run-options.test.mjs +181 -0
- package/js/tests/stderr-output-handling.test.mjs +279 -0
- package/js/tests/streaming-interfaces.test.mjs +194 -0
- package/js/tests/sync.test.mjs +297 -0
- package/js/tests/system-pipe.test.mjs +226 -0
- package/js/tests/test-cleanup.mjs +200 -0
- package/js/tests/test-helper-fixed.mjs +148 -0
- package/js/tests/test-helper-v2.mjs +118 -0
- package/js/tests/test-helper.mjs +171 -0
- package/js/tests/test-sigint-child.js +15 -0
- package/js/tests/text-method.test.mjs +225 -0
- package/js/tests/virtual.test.mjs +364 -0
- package/js/tests/yes-command-cleanup.test.mjs +208 -0
- package/js/tests/zx.features.test.mjs +233 -0
- package/package.json +13 -12
- package/rust/Cargo.lock +947 -0
- package/rust/Cargo.toml +47 -0
- package/rust/src/commands/basename.rs +69 -0
- package/rust/src/commands/cat.rs +123 -0
- package/rust/src/commands/cd.rs +67 -0
- package/rust/src/commands/cp.rs +187 -0
- package/rust/src/commands/dirname.rs +57 -0
- package/rust/src/commands/echo.rs +73 -0
- package/rust/src/commands/env.rs +33 -0
- package/rust/src/commands/exit.rs +36 -0
- package/rust/src/commands/false.rs +24 -0
- package/rust/src/commands/ls.rs +182 -0
- package/rust/src/commands/mkdir.rs +98 -0
- package/rust/src/commands/mod.rs +200 -0
- package/rust/src/commands/mv.rs +180 -0
- package/rust/src/commands/pwd.rs +28 -0
- package/rust/src/commands/rm.rs +150 -0
- package/rust/src/commands/seq.rs +179 -0
- package/rust/src/commands/sleep.rs +97 -0
- package/rust/src/commands/test.rs +204 -0
- package/rust/src/commands/touch.rs +99 -0
- package/rust/src/commands/true.rs +24 -0
- package/rust/src/commands/which.rs +87 -0
- package/rust/src/commands/yes.rs +99 -0
- package/rust/src/lib.rs +492 -0
- package/rust/src/main.rs +37 -0
- package/rust/src/shell_parser.rs +565 -0
- package/rust/src/utils.rs +335 -0
- package/rust/tests/builtin_commands.rs +549 -0
- package/rust/tests/process_runner.rs +286 -0
- package/rust/tests/shell_parser.rs +296 -0
- package/rust/tests/utils.rs +282 -0
- package/rust/tests/virtual_commands.rs +199 -0
- /package/{src → js/src}/commands/$.basename.mjs +0 -0
- /package/{src → js/src}/commands/$.cat.mjs +0 -0
- /package/{src → js/src}/commands/$.cd.mjs +0 -0
- /package/{src → js/src}/commands/$.cp.mjs +0 -0
- /package/{src → js/src}/commands/$.dirname.mjs +0 -0
- /package/{src → js/src}/commands/$.echo.mjs +0 -0
- /package/{src → js/src}/commands/$.env.mjs +0 -0
- /package/{src → js/src}/commands/$.exit.mjs +0 -0
- /package/{src → js/src}/commands/$.false.mjs +0 -0
- /package/{src → js/src}/commands/$.ls.mjs +0 -0
- /package/{src → js/src}/commands/$.mkdir.mjs +0 -0
- /package/{src → js/src}/commands/$.mv.mjs +0 -0
- /package/{src → js/src}/commands/$.pwd.mjs +0 -0
- /package/{src → js/src}/commands/$.rm.mjs +0 -0
- /package/{src → js/src}/commands/$.seq.mjs +0 -0
- /package/{src → js/src}/commands/$.sleep.mjs +0 -0
- /package/{src → js/src}/commands/$.test.mjs +0 -0
- /package/{src → js/src}/commands/$.touch.mjs +0 -0
- /package/{src → js/src}/commands/$.true.mjs +0 -0
- /package/{src → js/src}/commands/$.which.mjs +0 -0
- /package/{src → js/src}/commands/$.yes.mjs +0 -0
- /package/{src → js/src}/shell-parser.mjs +0 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { test, expect, describe } from 'bun:test';
|
|
4
|
+
import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
|
|
5
|
+
import { $ } from '../src/$.mjs';
|
|
6
|
+
|
|
7
|
+
describe('Start/Run Options Passing', () => {
|
|
8
|
+
describe('.start() method with options', () => {
|
|
9
|
+
test('should pass capture: false option correctly', async () => {
|
|
10
|
+
const result = await $`echo "test with capture false"`.start({
|
|
11
|
+
capture: false,
|
|
12
|
+
});
|
|
13
|
+
expect(result.stdout).toBeUndefined();
|
|
14
|
+
expect(result.code).toBe(0);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('should pass capture: true option correctly', async () => {
|
|
18
|
+
const result = await $`echo "test with capture true"`.start({
|
|
19
|
+
capture: true,
|
|
20
|
+
});
|
|
21
|
+
expect(result.stdout).toBe('test with capture true\n');
|
|
22
|
+
expect(result.code).toBe(0);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('should pass mirror: false option correctly', async () => {
|
|
26
|
+
// mirror: false should still capture but not show output to console
|
|
27
|
+
const result = await $`echo "test with mirror false"`.start({
|
|
28
|
+
mirror: false,
|
|
29
|
+
});
|
|
30
|
+
expect(result.stdout).toBe('test with mirror false\n');
|
|
31
|
+
expect(result.code).toBe(0);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should pass both capture and mirror options', async () => {
|
|
35
|
+
const result = await $`echo "test both options"`.start({
|
|
36
|
+
capture: false,
|
|
37
|
+
mirror: false,
|
|
38
|
+
});
|
|
39
|
+
expect(result.stdout).toBeUndefined();
|
|
40
|
+
expect(result.code).toBe(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('should pass stdin option correctly', async () => {
|
|
44
|
+
const result = await $`cat`.start({
|
|
45
|
+
stdin: 'custom input data',
|
|
46
|
+
capture: true,
|
|
47
|
+
});
|
|
48
|
+
expect(result.stdout).toBe('custom input data');
|
|
49
|
+
expect(result.code).toBe(0);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Skip on Windows - uses 'ls /tmp' which is Unix-specific
|
|
53
|
+
test.skipIf(isWindows)('should work with real shell commands', async () => {
|
|
54
|
+
const result = await $`ls /tmp`.start({ capture: false });
|
|
55
|
+
expect(result.stdout).toBeUndefined();
|
|
56
|
+
expect(result.code).toBe(0);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('should ignore options if process already started', async () => {
|
|
60
|
+
const runner = $`echo "already started test"`;
|
|
61
|
+
|
|
62
|
+
// Start the process
|
|
63
|
+
const firstResult = await runner.start();
|
|
64
|
+
expect(firstResult.stdout).toBe('already started test\n');
|
|
65
|
+
|
|
66
|
+
// Try to start again with different options - should be ignored
|
|
67
|
+
const secondResult = await runner.start({ capture: false });
|
|
68
|
+
expect(secondResult.stdout).toBe('already started test\n'); // Should still have stdout
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('.run() method (alias for .start())', () => {
|
|
73
|
+
test('should work identically to .start() with capture: false', async () => {
|
|
74
|
+
const result = await $`echo "test with run alias"`.run({
|
|
75
|
+
capture: false,
|
|
76
|
+
});
|
|
77
|
+
expect(result.stdout).toBeUndefined();
|
|
78
|
+
expect(result.code).toBe(0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('should work identically to .start() with capture: true', async () => {
|
|
82
|
+
const result = await $`echo "test with run alias"`.run({ capture: true });
|
|
83
|
+
expect(result.stdout).toBe('test with run alias\n');
|
|
84
|
+
expect(result.code).toBe(0);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('should work with multiple options', async () => {
|
|
88
|
+
const result = await $`echo "run with multiple options"`.run({
|
|
89
|
+
mirror: false,
|
|
90
|
+
capture: true,
|
|
91
|
+
});
|
|
92
|
+
expect(result.stdout).toBe('run with multiple options\n');
|
|
93
|
+
expect(result.code).toBe(0);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('should work with stdin option', async () => {
|
|
97
|
+
const result = await $`cat`.run({
|
|
98
|
+
stdin: 'run method input',
|
|
99
|
+
capture: true,
|
|
100
|
+
});
|
|
101
|
+
expect(result.stdout).toBe('run method input');
|
|
102
|
+
expect(result.code).toBe(0);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('Backward compatibility', () => {
|
|
107
|
+
test('direct await should still work with default options', async () => {
|
|
108
|
+
const result = await $`echo "default behavior"`;
|
|
109
|
+
expect(result.stdout).toBe('default behavior\n');
|
|
110
|
+
expect(result.code).toBe(0);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('.start() without options should work identically to direct await', async () => {
|
|
114
|
+
const directResult = await $`echo "no options test"`;
|
|
115
|
+
const startResult = await $`echo "no options test"`.start();
|
|
116
|
+
|
|
117
|
+
expect(directResult.stdout).toBe(startResult.stdout);
|
|
118
|
+
expect(directResult.code).toBe(startResult.code);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('.run() without options should work identically to direct await', async () => {
|
|
122
|
+
const directResult = await $`echo "run no options"`;
|
|
123
|
+
const runResult = await $`echo "run no options"`.run();
|
|
124
|
+
|
|
125
|
+
expect(directResult.stdout).toBe(runResult.stdout);
|
|
126
|
+
expect(directResult.code).toBe(runResult.code);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('Virtual commands support', () => {
|
|
131
|
+
test('should work with virtual echo command', async () => {
|
|
132
|
+
const result = await $`echo "virtual command test"`.start({
|
|
133
|
+
capture: false,
|
|
134
|
+
});
|
|
135
|
+
expect(result.stdout).toBeUndefined();
|
|
136
|
+
expect(result.code).toBe(0);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('should work with virtual commands using .run()', async () => {
|
|
140
|
+
const result = await $`echo "virtual run test"`.run({
|
|
141
|
+
capture: true,
|
|
142
|
+
mirror: false,
|
|
143
|
+
});
|
|
144
|
+
expect(result.stdout).toBe('virtual run test\n');
|
|
145
|
+
expect(result.code).toBe(0);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('Edge cases', () => {
|
|
150
|
+
test('should handle empty options object', async () => {
|
|
151
|
+
const result = await $`echo "empty options"`.start({});
|
|
152
|
+
expect(result.stdout).toBe('empty options\n');
|
|
153
|
+
expect(result.code).toBe(0);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('should handle mode option alongside other options', async () => {
|
|
157
|
+
const result = await $`echo "with mode option"`.start({
|
|
158
|
+
mode: 'async',
|
|
159
|
+
capture: false,
|
|
160
|
+
});
|
|
161
|
+
expect(result.stdout).toBeUndefined();
|
|
162
|
+
expect(result.code).toBe(0);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test('should reinitialize chunks when capture option changes', async () => {
|
|
166
|
+
const runner = $`echo "chunk reinit test"`;
|
|
167
|
+
|
|
168
|
+
// Verify initial state
|
|
169
|
+
expect(runner.options.capture).toBe(true);
|
|
170
|
+
expect(runner.outChunks).toEqual([]);
|
|
171
|
+
|
|
172
|
+
// Change capture to false
|
|
173
|
+
const result = await runner.start({ capture: false });
|
|
174
|
+
|
|
175
|
+
// Verify chunks were reinitialized
|
|
176
|
+
expect(runner.options.capture).toBe(false);
|
|
177
|
+
expect(runner.outChunks).toBe(null);
|
|
178
|
+
expect(result.stdout).toBeUndefined();
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
});
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { test, expect, describe, beforeEach, afterEach } from 'bun:test';
|
|
2
|
+
import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs';
|
|
3
|
+
import { isWindows } from './test-helper.mjs';
|
|
4
|
+
import { $ } from '../src/$.mjs';
|
|
5
|
+
import { promises as fs } from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import os from 'os';
|
|
8
|
+
|
|
9
|
+
describe('Stderr output handling in $.mjs', () => {
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
await beforeTestCleanup();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(async () => {
|
|
15
|
+
await afterTestCleanup();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Skip on Windows - uses sh -c with shell redirection
|
|
19
|
+
test.skipIf(isWindows)(
|
|
20
|
+
'commands that output to stderr should not hang when captured',
|
|
21
|
+
async () => {
|
|
22
|
+
// Test with a command that writes to stderr
|
|
23
|
+
const result =
|
|
24
|
+
await $`sh -c 'echo "stdout message" && echo "stderr message" >&2'`.run(
|
|
25
|
+
{
|
|
26
|
+
capture: true,
|
|
27
|
+
mirror: false,
|
|
28
|
+
timeout: 5000, // Safety timeout
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
expect(result.code).toBe(0);
|
|
33
|
+
expect(result.stdout).toContain('stdout message');
|
|
34
|
+
expect(result.stderr).toContain('stderr message');
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Skip on Windows - uses 'which' command which is Unix-specific
|
|
39
|
+
test.skipIf(isWindows)(
|
|
40
|
+
'gh commands with progress output to stderr should complete',
|
|
41
|
+
async () => {
|
|
42
|
+
// Check if gh is available
|
|
43
|
+
try {
|
|
44
|
+
await $`which gh`.run({ capture: true, mirror: false });
|
|
45
|
+
} catch {
|
|
46
|
+
console.log('Skipping: gh not available');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// gh version outputs to stderr for progress
|
|
51
|
+
const result = await $`gh version`.run({
|
|
52
|
+
capture: true,
|
|
53
|
+
mirror: false,
|
|
54
|
+
timeout: 5000,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(result.code).toBe(0);
|
|
58
|
+
expect(result.stdout).toBeDefined();
|
|
59
|
+
// Version info should be in stdout
|
|
60
|
+
expect(result.stdout).toContain('gh version');
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Skip on Windows - uses sh -c and 2>&1 shell redirection
|
|
65
|
+
test.skipIf(isWindows)(
|
|
66
|
+
'capturing with 2>&1 should combine stderr into stdout',
|
|
67
|
+
async () => {
|
|
68
|
+
const result =
|
|
69
|
+
await $`sh -c 'echo "stdout" && echo "stderr" >&2' 2>&1`.run({
|
|
70
|
+
capture: true,
|
|
71
|
+
mirror: false,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(result.code).toBe(0);
|
|
75
|
+
expect(result.stdout).toContain('stdout');
|
|
76
|
+
expect(result.stdout).toContain('stderr');
|
|
77
|
+
expect(result.stderr).toBe(''); // stderr should be empty since redirected
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// Skip on Windows - uses sh scripts and chmod
|
|
82
|
+
test.skipIf(isWindows)(
|
|
83
|
+
'long-running commands with stderr output should not hang',
|
|
84
|
+
async () => {
|
|
85
|
+
// Create a script that outputs to both stdout and stderr over time
|
|
86
|
+
const scriptPath = path.join(os.tmpdir(), 'test-script.sh');
|
|
87
|
+
const scriptContent = `#!/bin/sh
|
|
88
|
+
for i in 1 2 3; do
|
|
89
|
+
echo "stdout: iteration $i"
|
|
90
|
+
echo "stderr: iteration $i" >&2
|
|
91
|
+
sleep 0.1
|
|
92
|
+
done
|
|
93
|
+
`;
|
|
94
|
+
await fs.writeFile(scriptPath, scriptContent);
|
|
95
|
+
await $`chmod +x ${scriptPath}`.run({ capture: true, mirror: false });
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const startTime = Date.now();
|
|
99
|
+
const result = await $`${scriptPath}`.run({
|
|
100
|
+
capture: true,
|
|
101
|
+
mirror: false,
|
|
102
|
+
timeout: 5000,
|
|
103
|
+
});
|
|
104
|
+
const duration = Date.now() - startTime;
|
|
105
|
+
|
|
106
|
+
expect(result.code).toBe(0);
|
|
107
|
+
expect(result.stdout).toContain('stdout: iteration 3');
|
|
108
|
+
expect(result.stderr).toContain('stderr: iteration 3');
|
|
109
|
+
expect(duration).toBeLessThan(2000); // Should complete quickly, not hang
|
|
110
|
+
} finally {
|
|
111
|
+
await fs.unlink(scriptPath).catch(() => {});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
// Skip on Windows - uses 2>&1 shell redirection which doesn't work the same way on Windows
|
|
117
|
+
test.skipIf(isWindows)(
|
|
118
|
+
'gh gist create with stderr progress should work correctly',
|
|
119
|
+
async () => {
|
|
120
|
+
// Check authentication first
|
|
121
|
+
const authCheck = await $`gh auth status 2>&1`.run({
|
|
122
|
+
capture: true,
|
|
123
|
+
mirror: false,
|
|
124
|
+
});
|
|
125
|
+
if (authCheck.code !== 0) {
|
|
126
|
+
console.log(
|
|
127
|
+
'Skipping gh gist test - not authenticated (this is OK - we are testing $.mjs, not gh auth)'
|
|
128
|
+
);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Check if we can actually create gists (not just authenticated)
|
|
133
|
+
const testAccess = await $`gh api user/gists --method HEAD 2>&1`.run({
|
|
134
|
+
capture: true,
|
|
135
|
+
mirror: false,
|
|
136
|
+
});
|
|
137
|
+
if (testAccess.code !== 0) {
|
|
138
|
+
// In CI with GitHub Actions token, we might get 404 or 403 errors
|
|
139
|
+
if (
|
|
140
|
+
testAccess.stdout.includes(
|
|
141
|
+
'Resource not accessible by integration'
|
|
142
|
+
) ||
|
|
143
|
+
testAccess.stdout.includes('HTTP 404') ||
|
|
144
|
+
testAccess.stdout.includes('HTTP 403')
|
|
145
|
+
) {
|
|
146
|
+
console.log(
|
|
147
|
+
'Skipping gh gist test - limited GitHub Actions token or API access (this is OK - we are testing $.mjs, not gh permissions)'
|
|
148
|
+
);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Create test file
|
|
154
|
+
const testFile = path.join(os.tmpdir(), 'stderr-test.txt');
|
|
155
|
+
await fs.writeFile(testFile, 'Testing stderr handling\n');
|
|
156
|
+
|
|
157
|
+
let gistId = null;
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
// Without 2>&1 redirection - capture both streams separately
|
|
161
|
+
const result1 =
|
|
162
|
+
await $`gh gist create ${testFile} --desc "stderr-test-1" --public=false`.run(
|
|
163
|
+
{
|
|
164
|
+
capture: true,
|
|
165
|
+
mirror: false,
|
|
166
|
+
timeout: 10000,
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
expect(result1.code).toBe(0);
|
|
171
|
+
expect(result1.stdout).toBeDefined();
|
|
172
|
+
|
|
173
|
+
// The URL should be in stdout
|
|
174
|
+
const url1 = result1.stdout.trim();
|
|
175
|
+
expect(url1).toContain('gist.github.com');
|
|
176
|
+
gistId = url1.split('/').pop();
|
|
177
|
+
|
|
178
|
+
// Clean up first gist
|
|
179
|
+
await $`gh gist delete ${gistId} --yes`.run({
|
|
180
|
+
capture: true,
|
|
181
|
+
mirror: false,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// With 2>&1 redirection - all output in stdout
|
|
185
|
+
const result2 =
|
|
186
|
+
await $`gh gist create ${testFile} --desc "stderr-test-2" --public=false 2>&1`.run(
|
|
187
|
+
{
|
|
188
|
+
capture: true,
|
|
189
|
+
mirror: false,
|
|
190
|
+
timeout: 10000,
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
expect(result2.code).toBe(0);
|
|
195
|
+
expect(result2.stdout).toBeDefined();
|
|
196
|
+
|
|
197
|
+
// Should contain both progress messages and URL
|
|
198
|
+
expect(result2.stdout).toContain('Creating gist');
|
|
199
|
+
expect(result2.stdout).toContain('gist.github.com');
|
|
200
|
+
|
|
201
|
+
// Extract and clean up second gist
|
|
202
|
+
const lines = result2.stdout.trim().split('\n');
|
|
203
|
+
const url2 = lines.find((line) => line.includes('gist.github.com'));
|
|
204
|
+
if (url2) {
|
|
205
|
+
gistId = url2.split('/').pop();
|
|
206
|
+
await $`gh gist delete ${gistId} --yes`.run({
|
|
207
|
+
capture: true,
|
|
208
|
+
mirror: false,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
} finally {
|
|
212
|
+
// Clean up
|
|
213
|
+
await fs.unlink(testFile).catch(() => {});
|
|
214
|
+
if (gistId) {
|
|
215
|
+
await $`gh gist delete ${gistId} --yes`
|
|
216
|
+
.run({ capture: true, mirror: false })
|
|
217
|
+
.catch(() => {});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
// Skip on Windows - uses sh -c with shell redirection
|
|
224
|
+
test.skipIf(isWindows)(
|
|
225
|
+
'streaming mode should handle stderr correctly',
|
|
226
|
+
async () => {
|
|
227
|
+
const cmd = $`sh -c 'echo "line1" && echo "err1" >&2 && sleep 0.1 && echo "line2" && echo "err2" >&2'`;
|
|
228
|
+
|
|
229
|
+
const collected = {
|
|
230
|
+
stdout: [],
|
|
231
|
+
stderr: [],
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
for await (const chunk of cmd.stream()) {
|
|
235
|
+
if (chunk.type === 'stdout') {
|
|
236
|
+
collected.stdout.push(chunk.data.toString());
|
|
237
|
+
} else if (chunk.type === 'stderr') {
|
|
238
|
+
collected.stderr.push(chunk.data.toString());
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const result = await cmd;
|
|
243
|
+
|
|
244
|
+
expect(result.code).toBe(0);
|
|
245
|
+
expect(collected.stdout.join('')).toContain('line1');
|
|
246
|
+
expect(collected.stdout.join('')).toContain('line2');
|
|
247
|
+
expect(collected.stderr.join('')).toContain('err1');
|
|
248
|
+
expect(collected.stderr.join('')).toContain('err2');
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
// Skip on Windows - uses sh -c with shell redirection; also already skipped
|
|
253
|
+
test.skip('timeout should work even with pending stderr', async () => {
|
|
254
|
+
// Command that continuously outputs to stderr
|
|
255
|
+
const startTime = Date.now();
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
await $`sh -c 'while true; do echo "stderr output" >&2; sleep 0.1; done'`.run(
|
|
259
|
+
{
|
|
260
|
+
capture: true,
|
|
261
|
+
mirror: false,
|
|
262
|
+
timeout: 1000, // 1 second timeout
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
// Should not reach here
|
|
267
|
+
expect(true).toBe(false);
|
|
268
|
+
} catch (error) {
|
|
269
|
+
const duration = Date.now() - startTime;
|
|
270
|
+
|
|
271
|
+
// Should have timed out
|
|
272
|
+
expect(duration).toBeGreaterThanOrEqual(900);
|
|
273
|
+
expect(duration).toBeLessThan(1500);
|
|
274
|
+
|
|
275
|
+
// Error should indicate timeout/killed
|
|
276
|
+
expect(error).toBeDefined();
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
});
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { test, expect } from 'bun:test';
|
|
2
|
+
import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
|
|
3
|
+
import { $ } from '../src/$.mjs';
|
|
4
|
+
|
|
5
|
+
// Platform detection - Some tests use Unix utilities (cat, grep, sort, sh)
|
|
6
|
+
const isWindows = process.platform === 'win32';
|
|
7
|
+
|
|
8
|
+
// Skip on Windows - uses 'cat' command
|
|
9
|
+
test.skipIf(isWindows)(
|
|
10
|
+
'streaming interfaces - basic functionality',
|
|
11
|
+
async () => {
|
|
12
|
+
// Test streams.stdin with cat
|
|
13
|
+
const catCmd = $`cat`;
|
|
14
|
+
const stdin = await catCmd.streams.stdin;
|
|
15
|
+
|
|
16
|
+
if (stdin) {
|
|
17
|
+
stdin.write('Hello from streams.stdin!\n');
|
|
18
|
+
stdin.write('Multiple lines work\n');
|
|
19
|
+
stdin.end();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const result = await catCmd;
|
|
23
|
+
expect(result.code).toBe(0);
|
|
24
|
+
expect(result.stdout).toContain('Hello from streams.stdin!');
|
|
25
|
+
expect(result.stdout).toContain('Multiple lines work');
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
test('streaming interfaces - auto-start behavior', async () => {
|
|
30
|
+
const cmd = $`echo "test"`;
|
|
31
|
+
|
|
32
|
+
// Accessing parent objects should not auto-start
|
|
33
|
+
const streams = cmd.streams;
|
|
34
|
+
const buffers = cmd.buffers;
|
|
35
|
+
const strings = cmd.strings;
|
|
36
|
+
expect(cmd.started).toBe(false);
|
|
37
|
+
|
|
38
|
+
// Accessing actual properties should auto-start
|
|
39
|
+
const stdout = cmd.streams.stdout;
|
|
40
|
+
expect(cmd.started).toBe(true);
|
|
41
|
+
|
|
42
|
+
await cmd;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Skip on Windows - uses 'printf' command
|
|
46
|
+
test.skipIf(isWindows)('streaming interfaces - buffers interface', async () => {
|
|
47
|
+
const cmd = $`printf "Binary test"`;
|
|
48
|
+
const buffer = await cmd.buffers.stdout;
|
|
49
|
+
|
|
50
|
+
expect(Buffer.isBuffer(buffer)).toBe(true);
|
|
51
|
+
expect(buffer.toString()).toBe('Binary test');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('streaming interfaces - strings interface', async () => {
|
|
55
|
+
const cmd = $`echo "String test"`;
|
|
56
|
+
const str = await cmd.strings.stdout;
|
|
57
|
+
|
|
58
|
+
expect(typeof str).toBe('string');
|
|
59
|
+
expect(str.trim()).toBe('String test');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Skip on Windows - uses 'sh -c' command
|
|
63
|
+
test.skipIf(isWindows)(
|
|
64
|
+
'streaming interfaces - mixed stdout/stderr',
|
|
65
|
+
async () => {
|
|
66
|
+
const cmd = $`sh -c 'echo "stdout" && echo "stderr" >&2'`;
|
|
67
|
+
|
|
68
|
+
const [stdout, stderr] = await Promise.all([
|
|
69
|
+
cmd.strings.stdout,
|
|
70
|
+
cmd.strings.stderr,
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
expect(stdout.trim()).toBe('stdout');
|
|
74
|
+
expect(stderr.trim()).toBe('stderr');
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Skip on Windows - uses Unix signal exit codes (130, 143)
|
|
79
|
+
test.skipIf(isWindows)(
|
|
80
|
+
'streaming interfaces - kill method works',
|
|
81
|
+
async () => {
|
|
82
|
+
const cmd = $`sleep 10`;
|
|
83
|
+
|
|
84
|
+
// Start the process
|
|
85
|
+
await cmd.streams.stdout;
|
|
86
|
+
expect(cmd.started).toBe(true);
|
|
87
|
+
|
|
88
|
+
// Kill after short delay
|
|
89
|
+
setTimeout(() => cmd.kill(), 100);
|
|
90
|
+
|
|
91
|
+
const result = await cmd;
|
|
92
|
+
expect([130, 143, null]).toContain(result.code); // SIGTERM/SIGINT codes
|
|
93
|
+
},
|
|
94
|
+
5000
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// Skip on Windows - uses 'cat' command (not available on Windows)
|
|
98
|
+
test.skipIf(isWindows)(
|
|
99
|
+
'streaming interfaces - stdin control with cross-platform command',
|
|
100
|
+
async () => {
|
|
101
|
+
// Use 'cat' which works identically on all platforms and waits for input
|
|
102
|
+
const catCmd = $`cat`;
|
|
103
|
+
const stdin = await catCmd.streams.stdin;
|
|
104
|
+
|
|
105
|
+
// Send some data and close stdin
|
|
106
|
+
setTimeout(() => {
|
|
107
|
+
if (stdin && !stdin.destroyed) {
|
|
108
|
+
stdin.write('Hello from stdin!\n');
|
|
109
|
+
stdin.write('Multiple lines work\n');
|
|
110
|
+
setTimeout(() => stdin.end(), 100);
|
|
111
|
+
}
|
|
112
|
+
}, 100);
|
|
113
|
+
|
|
114
|
+
// Backup kill (shouldn't be needed since we close stdin)
|
|
115
|
+
setTimeout(() => {
|
|
116
|
+
if (!catCmd.finished) {
|
|
117
|
+
catCmd.kill();
|
|
118
|
+
}
|
|
119
|
+
}, 2000);
|
|
120
|
+
|
|
121
|
+
const result = await catCmd;
|
|
122
|
+
expect(typeof result.code).toBe('number');
|
|
123
|
+
expect(result.code).toBe(0); // Should exit cleanly when stdin is closed
|
|
124
|
+
expect(result.stdout.length).toBeGreaterThan(0);
|
|
125
|
+
expect(result.stdout).toContain('Hello from stdin!');
|
|
126
|
+
expect(result.stdout).toContain('Multiple lines work');
|
|
127
|
+
},
|
|
128
|
+
5000
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
test('streaming interfaces - immediate access after completion', async () => {
|
|
132
|
+
const cmd = $`echo "immediate test"`;
|
|
133
|
+
const result = await cmd;
|
|
134
|
+
|
|
135
|
+
// After completion, should return immediate results
|
|
136
|
+
const buffer = cmd.buffers.stdout;
|
|
137
|
+
const string = cmd.strings.stdout;
|
|
138
|
+
|
|
139
|
+
expect(Buffer.isBuffer(buffer)).toBe(true);
|
|
140
|
+
expect(typeof string).toBe('string');
|
|
141
|
+
expect(buffer.toString().trim()).toBe('immediate test');
|
|
142
|
+
expect(string.trim()).toBe('immediate test');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('streaming interfaces - backward compatibility', async () => {
|
|
146
|
+
// Traditional await syntax should still work
|
|
147
|
+
const result = await $`echo "backward compatible"`;
|
|
148
|
+
expect(result.code).toBe(0);
|
|
149
|
+
expect(result.stdout.trim()).toBe('backward compatible');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Skip on Windows - uses 'sort' command with different behavior
|
|
153
|
+
test.skipIf(isWindows)(
|
|
154
|
+
'streaming interfaces - stdin pipe mode works',
|
|
155
|
+
async () => {
|
|
156
|
+
// Test that stdin: 'pipe' is properly handled vs string data
|
|
157
|
+
const sortCmd = $`sort`;
|
|
158
|
+
const stdin = await sortCmd.streams.stdin;
|
|
159
|
+
|
|
160
|
+
expect(stdin).not.toBe(null);
|
|
161
|
+
expect(typeof stdin.write).toBe('function');
|
|
162
|
+
|
|
163
|
+
stdin.write('zebra\n');
|
|
164
|
+
stdin.write('apple\n');
|
|
165
|
+
stdin.write('banana\n');
|
|
166
|
+
stdin.end();
|
|
167
|
+
|
|
168
|
+
const result = await sortCmd;
|
|
169
|
+
expect(result.code).toBe(0);
|
|
170
|
+
expect(result.stdout).toBe('apple\nbanana\nzebra\n');
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
// Skip on Windows - uses 'grep' command
|
|
175
|
+
test.skipIf(isWindows)(
|
|
176
|
+
'streaming interfaces - grep filtering via stdin',
|
|
177
|
+
async () => {
|
|
178
|
+
const grepCmd = $`grep "important"`;
|
|
179
|
+
const stdin = await grepCmd.streams.stdin;
|
|
180
|
+
|
|
181
|
+
stdin.write('ignore this line\n');
|
|
182
|
+
stdin.write('important message 1\n');
|
|
183
|
+
stdin.write('skip this too\n');
|
|
184
|
+
stdin.write('another important note\n');
|
|
185
|
+
stdin.end();
|
|
186
|
+
|
|
187
|
+
const result = await grepCmd;
|
|
188
|
+
expect(result.code).toBe(0);
|
|
189
|
+
expect(result.stdout).toContain('important message 1');
|
|
190
|
+
expect(result.stdout).toContain('another important note');
|
|
191
|
+
expect(result.stdout).not.toContain('ignore this');
|
|
192
|
+
expect(result.stdout).not.toContain('skip this');
|
|
193
|
+
}
|
|
194
|
+
);
|