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,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
|
|
4
|
+
import {
|
|
5
|
+
beforeTestCleanup,
|
|
6
|
+
afterTestCleanup,
|
|
7
|
+
originalCwd,
|
|
8
|
+
} from './test-cleanup.mjs';
|
|
9
|
+
import { isWindows } from './test-helper.mjs';
|
|
10
|
+
import { $ } from '../src/$.mjs';
|
|
11
|
+
import { mkdtempSync, rmSync, realpathSync } from 'fs';
|
|
12
|
+
import { tmpdir } from 'os';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
|
|
15
|
+
// Helper to normalize paths (handles macOS /var -> /private/var symlink)
|
|
16
|
+
const normalizePath = (p) => {
|
|
17
|
+
try {
|
|
18
|
+
return realpathSync(p);
|
|
19
|
+
} catch {
|
|
20
|
+
return p;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
describe('Cleanup Verification', () => {
|
|
25
|
+
beforeEach(beforeTestCleanup);
|
|
26
|
+
afterEach(afterTestCleanup);
|
|
27
|
+
|
|
28
|
+
let testDirs = [];
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
// Clean up test directories
|
|
32
|
+
for (const dir of testDirs) {
|
|
33
|
+
try {
|
|
34
|
+
rmSync(dir, { recursive: true, force: true });
|
|
35
|
+
} catch (e) {
|
|
36
|
+
// Ignore cleanup errors
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
testDirs = [];
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('should start in original directory', () => {
|
|
43
|
+
const currentCwd = process.cwd();
|
|
44
|
+
expect(currentCwd).toBe(originalCwd);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('should restore cwd after simple cd command', async () => {
|
|
48
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'cleanup-test-'));
|
|
49
|
+
testDirs.push(tempDir);
|
|
50
|
+
|
|
51
|
+
// Change directory
|
|
52
|
+
await $`cd ${tempDir}`;
|
|
53
|
+
|
|
54
|
+
// Verify we changed
|
|
55
|
+
const result = await $`pwd`;
|
|
56
|
+
expect(normalizePath(result.stdout.trim())).toBe(normalizePath(tempDir));
|
|
57
|
+
|
|
58
|
+
// Cwd should be changed within test
|
|
59
|
+
expect(normalizePath(process.cwd())).toBe(normalizePath(tempDir));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('should be back in original directory after cd test', () => {
|
|
63
|
+
// This test verifies the previous test's cleanup worked
|
|
64
|
+
const currentCwd = process.cwd();
|
|
65
|
+
expect(currentCwd).toBe(originalCwd);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('should restore cwd after cd with && operator', async () => {
|
|
69
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'cleanup-test2-'));
|
|
70
|
+
testDirs.push(tempDir);
|
|
71
|
+
|
|
72
|
+
// Change directory with && operator
|
|
73
|
+
await $`cd ${tempDir} && echo "test"`;
|
|
74
|
+
|
|
75
|
+
// Should be in temp dir
|
|
76
|
+
expect(normalizePath(process.cwd())).toBe(normalizePath(tempDir));
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('should verify restoration after && cd test', () => {
|
|
80
|
+
const currentCwd = process.cwd();
|
|
81
|
+
expect(currentCwd).toBe(originalCwd);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Skip on Windows - uses subshell syntax and pwd command
|
|
85
|
+
test.skipIf(isWindows)(
|
|
86
|
+
'should not affect cwd when cd is in subshell',
|
|
87
|
+
async () => {
|
|
88
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'cleanup-test3-'));
|
|
89
|
+
testDirs.push(tempDir);
|
|
90
|
+
|
|
91
|
+
// Change directory in subshell - should not affect parent
|
|
92
|
+
const result = await $`(cd ${tempDir} && pwd)`;
|
|
93
|
+
expect(normalizePath(result.stdout.trim())).toBe(normalizePath(tempDir));
|
|
94
|
+
|
|
95
|
+
// Should still be in original directory
|
|
96
|
+
const currentCwd = process.cwd();
|
|
97
|
+
expect(currentCwd).toBe(originalCwd);
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
test('should restore cwd after multiple cd commands', async () => {
|
|
102
|
+
const tempDir1 = mkdtempSync(join(tmpdir(), 'cleanup-test4-'));
|
|
103
|
+
const tempDir2 = mkdtempSync(join(tmpdir(), 'cleanup-test5-'));
|
|
104
|
+
testDirs.push(tempDir1, tempDir2);
|
|
105
|
+
|
|
106
|
+
// Multiple cd commands
|
|
107
|
+
await $`cd ${tempDir1}`;
|
|
108
|
+
expect(normalizePath(process.cwd())).toBe(normalizePath(tempDir1));
|
|
109
|
+
|
|
110
|
+
await $`cd ${tempDir2}`;
|
|
111
|
+
expect(normalizePath(process.cwd())).toBe(normalizePath(tempDir2));
|
|
112
|
+
|
|
113
|
+
await $`cd ${tempDir1}`;
|
|
114
|
+
expect(normalizePath(process.cwd())).toBe(normalizePath(tempDir1));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('final verification - should still be in original directory', () => {
|
|
118
|
+
// Final check that all previous tests were properly cleaned up
|
|
119
|
+
const currentCwd = process.cwd();
|
|
120
|
+
expect(currentCwd).toBe(originalCwd);
|
|
121
|
+
|
|
122
|
+
// Also verify with pwd command
|
|
123
|
+
return $`pwd`.then((result) => {
|
|
124
|
+
expect(result.stdout.trim()).toBe(originalCwd);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach } from 'bun:test';
|
|
2
|
+
import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import { trace } from '../src/$.utils.mjs';
|
|
5
|
+
|
|
6
|
+
// Platform detection - Windows handles signals differently than Unix
|
|
7
|
+
const isWindows = process.platform === 'win32';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Baseline tests for CTRL+C signal handling using native spawn
|
|
11
|
+
* These tests verify that the CI environment can handle basic process spawning and signals
|
|
12
|
+
* without using our library, providing a comparison point for debugging
|
|
13
|
+
*
|
|
14
|
+
* Note: These tests are skipped on Windows because:
|
|
15
|
+
* 1. Windows doesn't have 'sh' shell by default
|
|
16
|
+
* 2. SIGINT/signal handling works fundamentally different on Windows
|
|
17
|
+
* 3. Exit codes 130 (128+SIGINT) are Unix-specific
|
|
18
|
+
*/
|
|
19
|
+
describe.skipIf(isWindows)('CTRL+C Baseline Tests (Native Spawn)', () => {
|
|
20
|
+
let childProcesses = [];
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
// Clean up any remaining child processes
|
|
24
|
+
childProcesses.forEach((child) => {
|
|
25
|
+
if (!child.killed) {
|
|
26
|
+
child.kill('SIGKILL');
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
childProcesses = [];
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should handle SIGINT with simple shell command', async () => {
|
|
33
|
+
trace('BaselineTest', 'Testing simple shell command');
|
|
34
|
+
|
|
35
|
+
const child = spawn('sh', ['-c', 'echo "BASELINE_START" && sleep 30'], {
|
|
36
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
37
|
+
detached: true,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
trace('BaselineTest', () => `Child spawned, PID: ${child.pid}`);
|
|
41
|
+
childProcesses.push(child);
|
|
42
|
+
|
|
43
|
+
let stdout = '';
|
|
44
|
+
let stderr = '';
|
|
45
|
+
|
|
46
|
+
child.stdout.on('data', (data) => {
|
|
47
|
+
stdout += data.toString();
|
|
48
|
+
trace(
|
|
49
|
+
'BaselineTest',
|
|
50
|
+
() => `Received stdout: ${JSON.stringify(data.toString())}`
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
child.stderr.on('data', (data) => {
|
|
55
|
+
stderr += data.toString();
|
|
56
|
+
trace(
|
|
57
|
+
'BaselineTest',
|
|
58
|
+
() => `Received stderr: ${JSON.stringify(data.toString())}`
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Wait for output
|
|
63
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
64
|
+
|
|
65
|
+
trace('BaselineTest', 'Sending SIGINT');
|
|
66
|
+
child.kill('SIGINT');
|
|
67
|
+
|
|
68
|
+
// Wait for exit
|
|
69
|
+
const exitCode = await new Promise((resolve) => {
|
|
70
|
+
let resolved = false;
|
|
71
|
+
child.on('exit', (code, signal) => {
|
|
72
|
+
if (!resolved) {
|
|
73
|
+
resolved = true;
|
|
74
|
+
trace(
|
|
75
|
+
'BaselineTest',
|
|
76
|
+
() => `Process exited with code: ${code} signal: ${signal}`
|
|
77
|
+
);
|
|
78
|
+
resolve(code !== null ? code : signal === 'SIGINT' ? 130 : 1);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Timeout fallback
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
if (!resolved) {
|
|
85
|
+
resolved = true;
|
|
86
|
+
trace('BaselineTest', 'Timeout, force killing');
|
|
87
|
+
child.kill('SIGKILL');
|
|
88
|
+
resolve(137);
|
|
89
|
+
}
|
|
90
|
+
}, 3000);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
trace('BaselineTest', () => `Final stdout: ${stdout}`);
|
|
94
|
+
trace('BaselineTest', () => `Final stderr: ${stderr}`);
|
|
95
|
+
trace('BaselineTest', () => `Exit code: ${exitCode}`);
|
|
96
|
+
|
|
97
|
+
expect(stdout).toContain('BASELINE_START');
|
|
98
|
+
// Accept both 130 (SIGINT) and 137 (SIGKILL) as valid
|
|
99
|
+
expect([130, 137].includes(exitCode)).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should handle Node.js inline script with SIGINT', async () => {
|
|
103
|
+
trace('BaselineTest', 'Testing Node.js inline script');
|
|
104
|
+
|
|
105
|
+
const nodeCode = `
|
|
106
|
+
console.log('NODE_START');
|
|
107
|
+
process.on('SIGINT', () => {
|
|
108
|
+
console.log('SIGINT_RECEIVED');
|
|
109
|
+
process.exit(130);
|
|
110
|
+
});
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
console.log('TIMEOUT');
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}, 30000);
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
const child = spawn('node', ['-e', nodeCode], {
|
|
118
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
119
|
+
detached: true,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
trace('BaselineTest', () => `Node child spawned, PID: ${child.pid}`);
|
|
123
|
+
childProcesses.push(child);
|
|
124
|
+
|
|
125
|
+
let stdout = '';
|
|
126
|
+
child.stdout.on('data', (data) => {
|
|
127
|
+
stdout += data.toString();
|
|
128
|
+
trace(
|
|
129
|
+
'BaselineTest',
|
|
130
|
+
() => `Node stdout: ${JSON.stringify(data.toString())}`
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Wait for startup
|
|
135
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
136
|
+
|
|
137
|
+
trace('BaselineTest', 'Sending SIGINT to Node process');
|
|
138
|
+
child.kill('SIGINT');
|
|
139
|
+
|
|
140
|
+
const exitCode = await new Promise((resolve) => {
|
|
141
|
+
child.on('exit', (code) => {
|
|
142
|
+
trace('BaselineTest', () => `Node process exited with code: ${code}`);
|
|
143
|
+
resolve(code);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
trace('BaselineTest', () => `Node final stdout: ${stdout}`);
|
|
148
|
+
trace('BaselineTest', () => `Node exit code: ${exitCode}`);
|
|
149
|
+
|
|
150
|
+
expect(stdout).toContain('NODE_START');
|
|
151
|
+
expect(stdout).toContain('SIGINT_RECEIVED');
|
|
152
|
+
expect(exitCode).toBe(130);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should handle Node.js script file', async () => {
|
|
156
|
+
trace('BaselineTest', 'Testing Node.js script file');
|
|
157
|
+
|
|
158
|
+
// Use the simple-test-sleep.js which doesn't have ES module dependencies
|
|
159
|
+
const child = spawn('node', ['js/examples/simple-test-sleep.js'], {
|
|
160
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
161
|
+
detached: true,
|
|
162
|
+
cwd: process.cwd(),
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
trace('BaselineTest', () => `Script child spawned, PID: ${child.pid}`);
|
|
166
|
+
childProcesses.push(child);
|
|
167
|
+
|
|
168
|
+
let stdout = '';
|
|
169
|
+
let stderr = '';
|
|
170
|
+
|
|
171
|
+
child.stdout.on('data', (data) => {
|
|
172
|
+
stdout += data.toString();
|
|
173
|
+
trace(
|
|
174
|
+
'BaselineTest',
|
|
175
|
+
() => `Script stdout: ${JSON.stringify(data.toString())}`
|
|
176
|
+
);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
child.stderr.on('data', (data) => {
|
|
180
|
+
stderr += data.toString();
|
|
181
|
+
trace('BaselineTest', () => `Script stderr: ${data.toString().trim()}`);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Wait for startup
|
|
185
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
186
|
+
|
|
187
|
+
trace('BaselineTest', 'Sending SIGINT to script');
|
|
188
|
+
child.kill('SIGINT');
|
|
189
|
+
|
|
190
|
+
const exitCode = await new Promise((resolve) => {
|
|
191
|
+
child.on('exit', (code) => {
|
|
192
|
+
trace('BaselineTest', () => `Script exited with code: ${code}`);
|
|
193
|
+
resolve(code);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
trace('BaselineTest', () => `Script final stdout: ${stdout}`);
|
|
198
|
+
trace(
|
|
199
|
+
'BaselineTest',
|
|
200
|
+
() => `Script final stderr (first 200 chars): ${stderr.substring(0, 200)}`
|
|
201
|
+
);
|
|
202
|
+
trace('BaselineTest', () => `Script exit code: ${exitCode}`);
|
|
203
|
+
|
|
204
|
+
expect(stdout).toContain('STARTING_SLEEP');
|
|
205
|
+
expect(exitCode).toBe(130);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { describe, it, expect } from 'bun:test';
|
|
2
|
+
import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
|
|
3
|
+
import { $ } from '../src/$.mjs';
|
|
4
|
+
|
|
5
|
+
// Platform detection - Windows handles signals differently than Unix
|
|
6
|
+
const isWindows = process.platform === 'win32';
|
|
7
|
+
|
|
8
|
+
// Skip signal tests on Windows - SIGTERM exit code 143 is Unix-specific
|
|
9
|
+
describe.skipIf(isWindows)('CTRL+C Basic Handling', () => {
|
|
10
|
+
it('should be able to kill a long-running process', async () => {
|
|
11
|
+
// Start a long-running process
|
|
12
|
+
const runner = $`sleep 10`;
|
|
13
|
+
|
|
14
|
+
// Start it without awaiting completion
|
|
15
|
+
const promise = runner.start();
|
|
16
|
+
|
|
17
|
+
// Give it time to start
|
|
18
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
19
|
+
|
|
20
|
+
// Kill it manually (simulating what CTRL+C would do)
|
|
21
|
+
runner.kill();
|
|
22
|
+
|
|
23
|
+
// The process should complete with a non-zero exit code
|
|
24
|
+
const result = await promise;
|
|
25
|
+
|
|
26
|
+
// Should have a non-zero exit code (143 for SIGTERM)
|
|
27
|
+
expect(result.code).toBeGreaterThan(0);
|
|
28
|
+
expect(result.code).toBe(143); // 128 + 15 (SIGTERM)
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should spawn processes with detached flag on Unix', async () => {
|
|
32
|
+
if (process.platform === 'win32') {
|
|
33
|
+
// Skip on Windows
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Use /bin/sleep to get a real system process, not virtual command
|
|
38
|
+
const runner = $`/bin/sleep 1`;
|
|
39
|
+
|
|
40
|
+
// Start the process
|
|
41
|
+
const promise = runner.start();
|
|
42
|
+
|
|
43
|
+
// Give it a moment to spawn
|
|
44
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
45
|
+
|
|
46
|
+
// Check that the child process exists and has a PID
|
|
47
|
+
expect(runner.child).toBeDefined();
|
|
48
|
+
expect(runner.child.pid).toBeGreaterThan(0);
|
|
49
|
+
|
|
50
|
+
// Kill and wait for completion
|
|
51
|
+
runner.kill();
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
await promise;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
// Expected to error
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should handle CTRL+C character in raw mode', async () => {
|
|
61
|
+
// Test that the _forwardTTYStdin method properly handles CTRL+C
|
|
62
|
+
// This is a unit test of the specific functionality
|
|
63
|
+
|
|
64
|
+
const runner = $`cat`; // Use cat to read stdin
|
|
65
|
+
|
|
66
|
+
// Start the process
|
|
67
|
+
const promise = runner.start();
|
|
68
|
+
|
|
69
|
+
// Give it time to set up
|
|
70
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
71
|
+
|
|
72
|
+
// Kill the process
|
|
73
|
+
runner.kill();
|
|
74
|
+
|
|
75
|
+
// Should complete with an error
|
|
76
|
+
let errorCode = null;
|
|
77
|
+
try {
|
|
78
|
+
await promise;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
errorCode = error.code;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
expect(errorCode).toBeDefined();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Skip on Windows - SIGTERM exit code 143 is Unix-specific
|
|
88
|
+
describe.skipIf(isWindows)('CTRL+C Virtual Commands', () => {
|
|
89
|
+
it(
|
|
90
|
+
'should cancel virtual command with AbortController',
|
|
91
|
+
async () => {
|
|
92
|
+
const runner = $`sleep 5`; // Virtual sleep command
|
|
93
|
+
|
|
94
|
+
const promise = runner.start();
|
|
95
|
+
|
|
96
|
+
// Give virtual command time to start
|
|
97
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
98
|
+
|
|
99
|
+
// Kill the virtual command
|
|
100
|
+
runner.kill();
|
|
101
|
+
|
|
102
|
+
const result = await promise;
|
|
103
|
+
|
|
104
|
+
// Virtual commands return SIGTERM exit code when cancelled
|
|
105
|
+
expect(result.code).toBe(143);
|
|
106
|
+
},
|
|
107
|
+
{ timeout: 5000 }
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
it(
|
|
111
|
+
'should cancel virtual async generator',
|
|
112
|
+
async () => {
|
|
113
|
+
// Test cancelling a streaming virtual command
|
|
114
|
+
const runner = $`yes hello`;
|
|
115
|
+
|
|
116
|
+
// Start streaming
|
|
117
|
+
const streamPromise = (async () => {
|
|
118
|
+
let chunks = 0;
|
|
119
|
+
for await (const _chunk of runner.stream()) {
|
|
120
|
+
chunks++;
|
|
121
|
+
if (chunks >= 3) {
|
|
122
|
+
break; // Break should trigger cancellation
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return chunks;
|
|
126
|
+
})();
|
|
127
|
+
|
|
128
|
+
const chunks = await streamPromise;
|
|
129
|
+
expect(chunks).toBe(3);
|
|
130
|
+
expect(runner.finished).toBe(true);
|
|
131
|
+
},
|
|
132
|
+
{ timeout: 5000 }
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Skip on Windows - SIGTERM exit code 143 is Unix-specific
|
|
137
|
+
describe.skipIf(isWindows)('CTRL+C Different stdin Modes', () => {
|
|
138
|
+
it('should handle CTRL+C with string stdin', async () => {
|
|
139
|
+
// Use a long-running command that will actually be killed
|
|
140
|
+
const runner = $({ stdin: 'test input\n' })`sleep 10`;
|
|
141
|
+
|
|
142
|
+
const promise = runner.start();
|
|
143
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
144
|
+
|
|
145
|
+
runner.kill();
|
|
146
|
+
const result = await promise;
|
|
147
|
+
|
|
148
|
+
expect(result.code).toBe(143);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should handle CTRL+C with Buffer stdin', async () => {
|
|
152
|
+
// Use a long-running command that will actually be killed
|
|
153
|
+
const runner = $({ stdin: Buffer.from('test input\n') })`sleep 10`;
|
|
154
|
+
|
|
155
|
+
const promise = runner.start();
|
|
156
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
157
|
+
|
|
158
|
+
runner.kill();
|
|
159
|
+
const result = await promise;
|
|
160
|
+
|
|
161
|
+
expect(result.code).toBe(143);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should handle CTRL+C with ignore stdin', async () => {
|
|
165
|
+
const runner = $({ stdin: 'ignore' })`sleep 5`;
|
|
166
|
+
|
|
167
|
+
const promise = runner.start();
|
|
168
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
169
|
+
|
|
170
|
+
runner.kill();
|
|
171
|
+
const result = await promise;
|
|
172
|
+
|
|
173
|
+
expect(result.code).toBe(143);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Skip on Windows - SIGTERM exit code 143 is Unix-specific
|
|
178
|
+
describe.skipIf(isWindows)('CTRL+C Pipeline Interruption', () => {
|
|
179
|
+
it(
|
|
180
|
+
'should interrupt simple pipeline',
|
|
181
|
+
async () => {
|
|
182
|
+
// Use a very simple approach that we know works
|
|
183
|
+
const runner = $`sleep 10`;
|
|
184
|
+
|
|
185
|
+
const promise = runner.start();
|
|
186
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
187
|
+
|
|
188
|
+
runner.kill();
|
|
189
|
+
const result = await promise;
|
|
190
|
+
|
|
191
|
+
// Should be interrupted with SIGTERM code
|
|
192
|
+
expect(result.code).toBe(143);
|
|
193
|
+
},
|
|
194
|
+
{ timeout: 3000 }
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Skip on Windows - uses 'sh' command and Unix-specific signals
|
|
199
|
+
describe.skipIf(isWindows)('CTRL+C Process Groups', () => {
|
|
200
|
+
it(
|
|
201
|
+
'should handle process group termination on Unix',
|
|
202
|
+
async () => {
|
|
203
|
+
if (process.platform === 'win32') {
|
|
204
|
+
return;
|
|
205
|
+
} // Skip on Windows
|
|
206
|
+
|
|
207
|
+
// Use a command that spawns subprocesses
|
|
208
|
+
const runner = $`sh -c 'sleep 10 & sleep 10 & wait'`;
|
|
209
|
+
|
|
210
|
+
const promise = runner.start();
|
|
211
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
212
|
+
|
|
213
|
+
runner.kill();
|
|
214
|
+
const result = await promise;
|
|
215
|
+
|
|
216
|
+
expect(result.code).toBe(143);
|
|
217
|
+
},
|
|
218
|
+
{ timeout: 5000 }
|
|
219
|
+
);
|
|
220
|
+
});
|