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,114 @@
|
|
|
1
|
+
import { $ } from '../src/$.mjs';
|
|
2
|
+
import { test, expect, describe, beforeEach, afterEach } from 'bun:test';
|
|
3
|
+
import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs';
|
|
4
|
+
|
|
5
|
+
describe('Interactive Option Tests', () => {
|
|
6
|
+
beforeEach(beforeTestCleanup);
|
|
7
|
+
afterEach(afterTestCleanup);
|
|
8
|
+
|
|
9
|
+
test('interactive option - default behavior', async () => {
|
|
10
|
+
// Test that interactive is false by default
|
|
11
|
+
const $custom = $({ capture: true, mirror: false });
|
|
12
|
+
const cmd = $custom`echo test`;
|
|
13
|
+
|
|
14
|
+
// Interactive should be false by default
|
|
15
|
+
expect(cmd.options.interactive).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('interactive option - explicit true', async () => {
|
|
19
|
+
// Test that interactive can be set to true
|
|
20
|
+
const $custom = $({ capture: true, mirror: false, interactive: true });
|
|
21
|
+
const cmd = $custom`echo test`;
|
|
22
|
+
|
|
23
|
+
// Interactive should be true when explicitly set
|
|
24
|
+
expect(cmd.options.interactive).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('interactive option - explicit false', async () => {
|
|
28
|
+
// Test that interactive can be explicitly set to false
|
|
29
|
+
const $custom = $({ capture: true, mirror: false, interactive: false });
|
|
30
|
+
const cmd = $custom`echo test`;
|
|
31
|
+
|
|
32
|
+
// Interactive should be false when explicitly set
|
|
33
|
+
expect(cmd.options.interactive).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('interactive option - passed through options merge', async () => {
|
|
37
|
+
// Test that interactive option is preserved when merging options
|
|
38
|
+
const $base = $({ capture: true, mirror: false });
|
|
39
|
+
const cmd = $base`echo test`;
|
|
40
|
+
|
|
41
|
+
// Start with different options to test merging
|
|
42
|
+
cmd.start({ interactive: true });
|
|
43
|
+
|
|
44
|
+
// Interactive should be true after options merge
|
|
45
|
+
expect(cmd.options.interactive).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('interactive option - does not affect command execution with pipes/capture', async () => {
|
|
49
|
+
// Test that setting interactive: true doesn't interfere with normal command execution
|
|
50
|
+
// when pipes are used (which prevents TTY forwarding anyway)
|
|
51
|
+
const $interactive = $({ capture: true, mirror: false, interactive: true });
|
|
52
|
+
const result = await $interactive`echo "interactive test"`;
|
|
53
|
+
|
|
54
|
+
expect(result.code).toBe(0);
|
|
55
|
+
expect(result.stdout.trim()).toBe('interactive test');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('interactive option - behavior with stdin inherit but no TTY', async () => {
|
|
59
|
+
// Test that interactive mode requires both interactive:true AND TTY conditions
|
|
60
|
+
// This test verifies the logic but won't actually use TTY in test environment
|
|
61
|
+
const $interactive = $({
|
|
62
|
+
capture: false,
|
|
63
|
+
mirror: false,
|
|
64
|
+
interactive: true,
|
|
65
|
+
stdin: 'inherit',
|
|
66
|
+
});
|
|
67
|
+
const cmd = $interactive`echo "tty test"`;
|
|
68
|
+
|
|
69
|
+
// Should still work even if TTY conditions aren't met
|
|
70
|
+
expect(cmd.options.interactive).toBe(true);
|
|
71
|
+
expect(cmd.options.stdin).toBe('inherit');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('interactive option - works with template literal syntax', async () => {
|
|
75
|
+
// Test interactive option with various template literal syntaxes
|
|
76
|
+
const name = 'world';
|
|
77
|
+
const $interactive = $({ capture: true, mirror: false, interactive: true });
|
|
78
|
+
const cmd = $interactive`echo "hello ${name}"`;
|
|
79
|
+
const result = await cmd;
|
|
80
|
+
|
|
81
|
+
expect(result.code).toBe(0);
|
|
82
|
+
expect(result.stdout.trim()).toBe('hello world'); // Safe string 'world' doesn't need quotes
|
|
83
|
+
expect(cmd.options.interactive).toBe(true); // Check the command object, not the result
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('interactive option - preserved in command chaining', async () => {
|
|
87
|
+
// Test that interactive option is preserved through command operations
|
|
88
|
+
const $interactive = $({ capture: true, mirror: false, interactive: true });
|
|
89
|
+
const cmd1 = $interactive`echo "first"`;
|
|
90
|
+
const cmd2 = cmd1.pipe($interactive`tr 'a-z' 'A-Z'`);
|
|
91
|
+
|
|
92
|
+
// Both commands should preserve the interactive setting
|
|
93
|
+
expect(cmd1.options.interactive).toBe(true);
|
|
94
|
+
// Note: cmd2 (piped command) might have different options, that's expected
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('interactive option - type checking', async () => {
|
|
98
|
+
// Test that interactive option accepts boolean values properly
|
|
99
|
+
const $true = $({ interactive: true, capture: true, mirror: false });
|
|
100
|
+
const $false = $({ interactive: false, capture: true, mirror: false });
|
|
101
|
+
const $default = $({ capture: true, mirror: false });
|
|
102
|
+
|
|
103
|
+
expect($true`echo test`.options.interactive).toBe(true);
|
|
104
|
+
expect($false`echo test`.options.interactive).toBe(false);
|
|
105
|
+
expect($default`echo test`.options.interactive).toBe(false);
|
|
106
|
+
|
|
107
|
+
// Test with non-boolean values (should still work, JavaScript is flexible)
|
|
108
|
+
const $truthy = $({ interactive: 1, capture: true, mirror: false });
|
|
109
|
+
const $falsy = $({ interactive: 0, capture: true, mirror: false });
|
|
110
|
+
|
|
111
|
+
expect(Boolean($truthy`echo test`.options.interactive)).toBe(true);
|
|
112
|
+
expect(Boolean($falsy`echo test`.options.interactive)).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { describe, it, expect } from 'bun:test';
|
|
4
|
+
import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
|
|
5
|
+
import { $ } from '../src/$.mjs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const calcPath = path.join(__dirname, '../examples/interactive-math-calc.mjs');
|
|
11
|
+
|
|
12
|
+
describe('Interactive Streaming', () => {
|
|
13
|
+
it('should support bidirectional streaming I/O while process is running', async () => {
|
|
14
|
+
// Start the interactive math calculator
|
|
15
|
+
const calc = $`node ${calcPath}`;
|
|
16
|
+
|
|
17
|
+
// Get the streams immediately (process auto-starts)
|
|
18
|
+
let stdin, stdout, stderr;
|
|
19
|
+
try {
|
|
20
|
+
stdin = await calc.streams.stdin;
|
|
21
|
+
stdout = await calc.streams.stdout;
|
|
22
|
+
stderr = await calc.streams.stderr;
|
|
23
|
+
} catch (e) {
|
|
24
|
+
console.error(`[interactive-streaming test] Error getting streams:`, e);
|
|
25
|
+
throw e;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Verify streams are available
|
|
29
|
+
expect(stdin).toBeTruthy();
|
|
30
|
+
expect(stdout).toBeTruthy();
|
|
31
|
+
expect(stderr).toBeTruthy();
|
|
32
|
+
|
|
33
|
+
// Set up stdout reader
|
|
34
|
+
const results = [];
|
|
35
|
+
let buffer = '';
|
|
36
|
+
|
|
37
|
+
stdout.on('data', (chunk) => {
|
|
38
|
+
buffer += chunk.toString();
|
|
39
|
+
const lines = buffer.split('\n');
|
|
40
|
+
buffer = lines.pop(); // Keep incomplete line in buffer
|
|
41
|
+
|
|
42
|
+
for (const line of lines) {
|
|
43
|
+
if (line.trim()) {
|
|
44
|
+
results.push(line.trim());
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Wait for calculator to be ready
|
|
50
|
+
await new Promise((resolve) => {
|
|
51
|
+
const checkReady = () => {
|
|
52
|
+
if (results.some((r) => r.includes('READY'))) {
|
|
53
|
+
resolve();
|
|
54
|
+
} else {
|
|
55
|
+
setTimeout(checkReady, 10);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
checkReady();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(results).toContain('READY');
|
|
62
|
+
|
|
63
|
+
// Test multiple math expressions
|
|
64
|
+
const testCases = [
|
|
65
|
+
{ input: '1+2', expected: 'RESULT: 3' },
|
|
66
|
+
{ input: '10*5', expected: 'RESULT: 50' },
|
|
67
|
+
{ input: '100/4', expected: 'RESULT: 25' },
|
|
68
|
+
{ input: '7-3', expected: 'RESULT: 4' },
|
|
69
|
+
{ input: '2**8', expected: 'RESULT: 256' },
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
for (const testCase of testCases) {
|
|
73
|
+
const beforeCount = results.length;
|
|
74
|
+
|
|
75
|
+
// Send expression
|
|
76
|
+
stdin.write(`${testCase.input}\n`);
|
|
77
|
+
|
|
78
|
+
// Wait for result
|
|
79
|
+
await new Promise((resolve) => {
|
|
80
|
+
const checkResult = () => {
|
|
81
|
+
if (results.length > beforeCount) {
|
|
82
|
+
resolve();
|
|
83
|
+
} else {
|
|
84
|
+
setTimeout(checkResult, 10);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
setTimeout(checkResult, 10);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Verify result
|
|
91
|
+
expect(results).toContain(testCase.expected);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Send exit command
|
|
95
|
+
stdin.write('exit\n');
|
|
96
|
+
|
|
97
|
+
// Wait for goodbye message
|
|
98
|
+
await new Promise((resolve) => {
|
|
99
|
+
const checkGoodbye = () => {
|
|
100
|
+
if (results.some((r) => r.includes('GOODBYE'))) {
|
|
101
|
+
resolve();
|
|
102
|
+
} else {
|
|
103
|
+
setTimeout(checkGoodbye, 10);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
setTimeout(checkGoodbye, 10);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(results).toContain('GOODBYE');
|
|
110
|
+
|
|
111
|
+
// Wait for process to complete
|
|
112
|
+
const result = await calc;
|
|
113
|
+
expect(result.code).toBe(0);
|
|
114
|
+
|
|
115
|
+
// Verify we received all expected results
|
|
116
|
+
const resultCount = results.filter((r) => r.includes('RESULT:')).length;
|
|
117
|
+
expect(resultCount).toBe(testCases.length);
|
|
118
|
+
}, 10000); // 10 second timeout
|
|
119
|
+
|
|
120
|
+
it('should handle errors in expressions', async () => {
|
|
121
|
+
const calc = $`node ${calcPath}`;
|
|
122
|
+
|
|
123
|
+
const stdin = await calc.streams.stdin;
|
|
124
|
+
const stdout = await calc.streams.stdout;
|
|
125
|
+
const stderr = await calc.streams.stderr;
|
|
126
|
+
|
|
127
|
+
expect(stdin).toBeTruthy();
|
|
128
|
+
expect(stdout).toBeTruthy();
|
|
129
|
+
expect(stderr).toBeTruthy();
|
|
130
|
+
|
|
131
|
+
const results = [];
|
|
132
|
+
const errors = [];
|
|
133
|
+
let stdoutBuffer = '';
|
|
134
|
+
let stderrBuffer = '';
|
|
135
|
+
|
|
136
|
+
stdout.on('data', (chunk) => {
|
|
137
|
+
stdoutBuffer += chunk.toString();
|
|
138
|
+
const lines = stdoutBuffer.split('\n');
|
|
139
|
+
stdoutBuffer = lines.pop();
|
|
140
|
+
for (const line of lines) {
|
|
141
|
+
if (line.trim()) {
|
|
142
|
+
results.push(line.trim());
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
stderr.on('data', (chunk) => {
|
|
148
|
+
stderrBuffer += chunk.toString();
|
|
149
|
+
const lines = stderrBuffer.split('\n');
|
|
150
|
+
stderrBuffer = lines.pop();
|
|
151
|
+
for (const line of lines) {
|
|
152
|
+
if (line.trim()) {
|
|
153
|
+
errors.push(line.trim());
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Wait for ready
|
|
159
|
+
await new Promise((resolve) => {
|
|
160
|
+
const check = () => {
|
|
161
|
+
if (results.some((r) => r.includes('READY'))) {
|
|
162
|
+
resolve();
|
|
163
|
+
} else {
|
|
164
|
+
setTimeout(check, 10);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
check();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Send invalid expression
|
|
171
|
+
stdin.write('invalid expression\n');
|
|
172
|
+
|
|
173
|
+
// Wait for error
|
|
174
|
+
await new Promise((resolve) => {
|
|
175
|
+
const check = () => {
|
|
176
|
+
if (errors.length > 0) {
|
|
177
|
+
resolve();
|
|
178
|
+
} else {
|
|
179
|
+
setTimeout(check, 10);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
setTimeout(check, 10);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
expect(errors[0]).toContain('ERROR: Invalid expression');
|
|
186
|
+
|
|
187
|
+
// Verify calculator still works after error
|
|
188
|
+
stdin.write('5+5\n');
|
|
189
|
+
|
|
190
|
+
const beforeCount = results.length;
|
|
191
|
+
await new Promise((resolve) => {
|
|
192
|
+
const check = () => {
|
|
193
|
+
if (results.length > beforeCount) {
|
|
194
|
+
resolve();
|
|
195
|
+
} else {
|
|
196
|
+
setTimeout(check, 10);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
setTimeout(check, 10);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
expect(results).toContain('RESULT: 10');
|
|
203
|
+
|
|
204
|
+
// Exit
|
|
205
|
+
stdin.write('exit\n');
|
|
206
|
+
const result = await calc;
|
|
207
|
+
expect(result.code).toBe(0);
|
|
208
|
+
}, 10000);
|
|
209
|
+
|
|
210
|
+
it('should auto-start process when accessing streams', async () => {
|
|
211
|
+
const calc = $`node ${calcPath}`;
|
|
212
|
+
|
|
213
|
+
// Process should not be started yet
|
|
214
|
+
expect(calc.started).toBe(false);
|
|
215
|
+
|
|
216
|
+
// Accessing streams should auto-start the process
|
|
217
|
+
const stdin = await calc.streams.stdin;
|
|
218
|
+
|
|
219
|
+
expect(calc.started).toBe(true);
|
|
220
|
+
expect(stdin).toBeTruthy();
|
|
221
|
+
|
|
222
|
+
// Clean up
|
|
223
|
+
stdin.write('exit\n');
|
|
224
|
+
await calc;
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('should return null for streams after process completes', async () => {
|
|
228
|
+
const calc = $`node ${calcPath}`;
|
|
229
|
+
|
|
230
|
+
const stdin = await calc.streams.stdin;
|
|
231
|
+
stdin.write('exit\n');
|
|
232
|
+
|
|
233
|
+
// Wait for process to complete
|
|
234
|
+
await calc;
|
|
235
|
+
|
|
236
|
+
// Streams should be null after completion
|
|
237
|
+
const stdinAfter = await calc.streams.stdin;
|
|
238
|
+
const stdoutAfter = await calc.streams.stdout;
|
|
239
|
+
const stderrAfter = await calc.streams.stderr;
|
|
240
|
+
|
|
241
|
+
expect(stdinAfter).toBeNull();
|
|
242
|
+
expect(stdoutAfter).toBeNull();
|
|
243
|
+
expect(stderrAfter).toBeNull();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('should handle multiple simultaneous calculations', async () => {
|
|
247
|
+
const calc = $`node ${calcPath}`;
|
|
248
|
+
|
|
249
|
+
const stdin = await calc.streams.stdin;
|
|
250
|
+
const stdout = await calc.streams.stdout;
|
|
251
|
+
|
|
252
|
+
const results = [];
|
|
253
|
+
let buffer = '';
|
|
254
|
+
|
|
255
|
+
stdout.on('data', (chunk) => {
|
|
256
|
+
buffer += chunk.toString();
|
|
257
|
+
const lines = buffer.split('\n');
|
|
258
|
+
buffer = lines.pop();
|
|
259
|
+
for (const line of lines) {
|
|
260
|
+
if (line.trim()) {
|
|
261
|
+
results.push(line.trim());
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Wait for ready
|
|
267
|
+
await new Promise((resolve) => {
|
|
268
|
+
const check = () => {
|
|
269
|
+
if (results.some((r) => r.includes('READY'))) {
|
|
270
|
+
resolve();
|
|
271
|
+
} else {
|
|
272
|
+
setTimeout(check, 10);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
check();
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Send multiple calculations rapidly
|
|
279
|
+
const expressions = ['1+1', '2+2', '3+3', '4+4', '5+5'];
|
|
280
|
+
for (const expr of expressions) {
|
|
281
|
+
stdin.write(`${expr}\n`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Wait for all results
|
|
285
|
+
await new Promise((resolve) => {
|
|
286
|
+
const check = () => {
|
|
287
|
+
const resultCount = results.filter((r) => r.includes('RESULT:')).length;
|
|
288
|
+
if (resultCount >= expressions.length) {
|
|
289
|
+
resolve();
|
|
290
|
+
} else {
|
|
291
|
+
setTimeout(check, 10);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
setTimeout(check, 10);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// Verify all results
|
|
298
|
+
expect(results).toContain('RESULT: 2');
|
|
299
|
+
expect(results).toContain('RESULT: 4');
|
|
300
|
+
expect(results).toContain('RESULT: 6');
|
|
301
|
+
expect(results).toContain('RESULT: 8');
|
|
302
|
+
expect(results).toContain('RESULT: 10');
|
|
303
|
+
|
|
304
|
+
stdin.write('exit\n');
|
|
305
|
+
await calc;
|
|
306
|
+
});
|
|
307
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Final test for issue #135: CI environment should not auto-enable trace
|
|
2
|
+
// This test verifies the main fix: CI=true should NOT cause trace logs
|
|
3
|
+
import { describe, it, beforeEach } from 'bun:test';
|
|
4
|
+
import assert from 'assert';
|
|
5
|
+
import { $ } from '../src/$.mjs';
|
|
6
|
+
|
|
7
|
+
describe('Issue #135: CI environment no longer auto-enables trace logs', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
// Clean up environment before each test
|
|
10
|
+
delete process.env.COMMAND_STREAM_VERBOSE;
|
|
11
|
+
delete process.env.COMMAND_STREAM_TRACE;
|
|
12
|
+
delete process.env.CI;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should NOT emit trace logs when CI=true (main fix)', async () => {
|
|
16
|
+
process.env.CI = 'true';
|
|
17
|
+
|
|
18
|
+
const $silent = $({ mirror: false, capture: true });
|
|
19
|
+
const result = await $silent`echo '{"status":"ok"}'`;
|
|
20
|
+
|
|
21
|
+
// Output should be clean JSON without trace logs
|
|
22
|
+
assert.strictEqual(result.stdout.trim(), '{"status":"ok"}');
|
|
23
|
+
|
|
24
|
+
// Should be parseable as JSON
|
|
25
|
+
const parsed = JSON.parse(result.stdout);
|
|
26
|
+
assert.deepStrictEqual(parsed, { status: 'ok' });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should allow JSON parsing in CI environment', async () => {
|
|
30
|
+
process.env.CI = 'true';
|
|
31
|
+
|
|
32
|
+
const $silent = $({ mirror: false, capture: true });
|
|
33
|
+
const result = await $silent`echo '{"count":42,"items":["a","b","c"]}'`;
|
|
34
|
+
|
|
35
|
+
// Should be able to parse complex JSON
|
|
36
|
+
const parsed = JSON.parse(result.stdout);
|
|
37
|
+
assert.strictEqual(parsed.count, 42);
|
|
38
|
+
assert.deepStrictEqual(parsed.items, ['a', 'b', 'c']);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should NOT produce trace logs by default (no env vars)', async () => {
|
|
42
|
+
const $silent = $({ mirror: false, capture: true });
|
|
43
|
+
const result = await $silent`echo test`;
|
|
44
|
+
|
|
45
|
+
// Simple text output should be clean
|
|
46
|
+
assert.strictEqual(result.stdout.trim(), 'test');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should work with mirror:false in CI environment', async () => {
|
|
50
|
+
process.env.CI = 'true';
|
|
51
|
+
|
|
52
|
+
const $silent = $({ mirror: false, capture: true });
|
|
53
|
+
const result = await $silent`echo hello`;
|
|
54
|
+
|
|
55
|
+
assert.strictEqual(result.stdout.trim(), 'hello');
|
|
56
|
+
assert.strictEqual(result.code, 0);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { $ } from '../src/$.mjs';
|
|
2
|
+
import { test, expect } from 'bun:test';
|
|
3
|
+
import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
|
|
4
|
+
|
|
5
|
+
const testJson =
|
|
6
|
+
'{"message": "hello", "number": 42, "active": true, "data": null}';
|
|
7
|
+
|
|
8
|
+
test('jq behavior - default mirror mode shows output automatically', async () => {
|
|
9
|
+
// Test that with default settings (mirror: true), jq output appears automatically
|
|
10
|
+
// User doesn't need to manually console.log the result
|
|
11
|
+
const result = await $`echo ${testJson} | jq .`;
|
|
12
|
+
|
|
13
|
+
expect(result.code).toBe(0);
|
|
14
|
+
expect(result.stdout).toContain('"message"');
|
|
15
|
+
expect(result.stdout).toContain('"hello"');
|
|
16
|
+
expect(result.stdout).toContain('42');
|
|
17
|
+
expect(result.stdout).toContain('true');
|
|
18
|
+
expect(result.stdout).toContain('null');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('jq behavior - explicit color output contains ANSI codes', async () => {
|
|
22
|
+
// Test that jq -C produces colored output with ANSI escape codes
|
|
23
|
+
const result = await $`echo ${testJson} | jq -C .`;
|
|
24
|
+
|
|
25
|
+
expect(result.code).toBe(0);
|
|
26
|
+
expect(result.stdout).toMatch(/\u001b\[\d+/); // Contains ANSI escape sequences
|
|
27
|
+
expect(result.stdout).toContain('"message"');
|
|
28
|
+
expect(result.stdout).toContain('"hello"');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('jq behavior - monochrome output has no ANSI codes', async () => {
|
|
32
|
+
// Test that jq -M produces clean output without colors
|
|
33
|
+
const result = await $`echo ${testJson} | jq -M .`;
|
|
34
|
+
|
|
35
|
+
expect(result.code).toBe(0);
|
|
36
|
+
expect(result.stdout).not.toMatch(/\u001b\[\d+/); // No ANSI escape sequences
|
|
37
|
+
expect(result.stdout).toContain('"message"');
|
|
38
|
+
expect(result.stdout).toContain('"hello"');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('jq behavior - field extraction works correctly', async () => {
|
|
42
|
+
// Test extracting specific fields with -r flag
|
|
43
|
+
const result = await $`echo ${testJson} | jq -r .message`;
|
|
44
|
+
|
|
45
|
+
expect(result.code).toBe(0);
|
|
46
|
+
expect(result.stdout.trim()).toBe('hello');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('jq behavior - complex JSON processing', async () => {
|
|
50
|
+
const complexJson =
|
|
51
|
+
'{"users": [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]}';
|
|
52
|
+
|
|
53
|
+
// Test extracting array elements
|
|
54
|
+
const result = await $`echo ${complexJson} | jq '.users[0].name'`;
|
|
55
|
+
|
|
56
|
+
expect(result.code).toBe(0);
|
|
57
|
+
expect(result.stdout.trim()).toBe('"Alice"');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('jq behavior - mirror mode vs capture mode', async () => {
|
|
61
|
+
// Test that mirror mode (default) automatically shows output
|
|
62
|
+
const $default = $({ capture: true, mirror: true });
|
|
63
|
+
const result1 = await $default`echo ${testJson} | jq .message`;
|
|
64
|
+
|
|
65
|
+
expect(result1.code).toBe(0);
|
|
66
|
+
expect(result1.stdout.trim()).toBe('"hello"');
|
|
67
|
+
|
|
68
|
+
// Test capture-only mode
|
|
69
|
+
const $captureOnly = $({ capture: true, mirror: false });
|
|
70
|
+
const result2 = await $captureOnly`echo ${testJson} | jq .message`;
|
|
71
|
+
|
|
72
|
+
expect(result2.code).toBe(0);
|
|
73
|
+
expect(result2.stdout.trim()).toBe('"hello"');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('jq behavior - TTY detection and automatic coloring', async () => {
|
|
77
|
+
// IMPORTANT: Understanding jq's color behavior
|
|
78
|
+
//
|
|
79
|
+
// When jq is used in a pipeline (echo ... | jq), it detects that its
|
|
80
|
+
// output is being piped and disables colors by default, EVEN if the
|
|
81
|
+
// parent process has a TTY (process.stdout.isTTY = true).
|
|
82
|
+
//
|
|
83
|
+
// This is smart behavior by jq:
|
|
84
|
+
// - Direct to terminal: jq enables colors (if TTY detected)
|
|
85
|
+
// - In a pipeline: jq disables colors (to avoid ANSI codes in pipes)
|
|
86
|
+
// - With -C flag: forces colors even in pipelines
|
|
87
|
+
// - With -M flag: disables colors even with TTY
|
|
88
|
+
//
|
|
89
|
+
// Since command-stream uses pipes internally, jq will typically NOT
|
|
90
|
+
// output colors by default, regardless of the TTY status.
|
|
91
|
+
|
|
92
|
+
const result = await $`echo ${testJson} | jq .`;
|
|
93
|
+
|
|
94
|
+
expect(result.code).toBe(0);
|
|
95
|
+
expect(result.stdout).toContain('"message"');
|
|
96
|
+
|
|
97
|
+
const hasColors = /\u001b\[\d+/.test(result.stdout);
|
|
98
|
+
|
|
99
|
+
// Log the actual behavior for debugging
|
|
100
|
+
if (process.env.DEBUG_JQ_TEST) {
|
|
101
|
+
console.log('jq default behavior:', {
|
|
102
|
+
hasColors,
|
|
103
|
+
isTTY: process.stdout.isTTY,
|
|
104
|
+
outputSample: result.stdout.substring(0, 50),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// In most cases, jq in a pipeline won't have colors
|
|
109
|
+
// But we accept both cases since it can vary by environment
|
|
110
|
+
expect(typeof hasColors).toBe('boolean');
|
|
111
|
+
|
|
112
|
+
// Verify we got valid JSON output regardless of colors
|
|
113
|
+
expect(result.stdout).toContain('"message"');
|
|
114
|
+
expect(result.stdout).toContain('"hello"');
|
|
115
|
+
expect(result.stdout).toContain('42');
|
|
116
|
+
expect(result.stdout).toContain('true');
|
|
117
|
+
expect(result.stdout).toContain('null');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('jq behavior - force colors work in any environment', async () => {
|
|
121
|
+
// Test that explicit -C flag produces colors even in non-TTY environments
|
|
122
|
+
const result = await $`echo ${testJson} | jq -C .`;
|
|
123
|
+
|
|
124
|
+
expect(result.code).toBe(0);
|
|
125
|
+
expect(result.stdout).toMatch(/\u001b\[\d+/); // Should have ANSI codes
|
|
126
|
+
expect(result.stdout).toContain('"message"');
|
|
127
|
+
|
|
128
|
+
// The color codes should make the output longer than the plain version
|
|
129
|
+
const plainResult = await $`echo ${testJson} | jq -M .`;
|
|
130
|
+
expect(result.stdout.length).toBeGreaterThan(plainResult.stdout.length);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('jq behavior - streaming with colors works', async () => {
|
|
134
|
+
// Test that jq colors work with streaming/piping
|
|
135
|
+
const result = await $`echo ${testJson} | jq -C . | cat`;
|
|
136
|
+
|
|
137
|
+
expect(result.code).toBe(0);
|
|
138
|
+
expect(result.stdout).toMatch(/\u001b\[\d+/); // Colors preserved through pipe
|
|
139
|
+
expect(result.stdout).toContain('"message"');
|
|
140
|
+
});
|