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,221 @@
|
|
|
1
|
+
import {
|
|
2
|
+
test,
|
|
3
|
+
expect,
|
|
4
|
+
describe,
|
|
5
|
+
beforeAll,
|
|
6
|
+
afterAll,
|
|
7
|
+
beforeEach,
|
|
8
|
+
afterEach,
|
|
9
|
+
} from 'bun:test';
|
|
10
|
+
import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs';
|
|
11
|
+
import { $ } from '../src/$.mjs';
|
|
12
|
+
import { promises as fs } from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import os from 'os';
|
|
15
|
+
|
|
16
|
+
describe('GitHub Gist Operations with $.mjs', () => {
|
|
17
|
+
let isAuthenticated = false;
|
|
18
|
+
let testGistId = null;
|
|
19
|
+
const TEST_DESC = 'test-command-stream-gist';
|
|
20
|
+
const CI_ENVIRONMENT =
|
|
21
|
+
process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
|
|
22
|
+
|
|
23
|
+
beforeEach(async () => {
|
|
24
|
+
await beforeTestCleanup();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(async () => {
|
|
28
|
+
await afterTestCleanup();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
beforeAll(async () => {
|
|
32
|
+
// Skip write operations in CI environment
|
|
33
|
+
if (CI_ENVIRONMENT) {
|
|
34
|
+
console.log('Skipping gist write tests in CI environment');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check if authenticated
|
|
39
|
+
const authResult = await $`gh auth status 2>&1`.run({
|
|
40
|
+
capture: true,
|
|
41
|
+
mirror: false,
|
|
42
|
+
});
|
|
43
|
+
isAuthenticated = authResult.code === 0;
|
|
44
|
+
|
|
45
|
+
if (!isAuthenticated) {
|
|
46
|
+
console.log('Skipping gist tests - GitHub CLI not authenticated');
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
afterAll(async () => {
|
|
51
|
+
// Clean up any test gists
|
|
52
|
+
if (isAuthenticated && testGistId) {
|
|
53
|
+
try {
|
|
54
|
+
await $`gh gist delete ${testGistId} --yes`.run({
|
|
55
|
+
capture: true,
|
|
56
|
+
mirror: false,
|
|
57
|
+
});
|
|
58
|
+
} catch (error) {
|
|
59
|
+
// Ignore cleanup errors
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('gh gist create should work with $.mjs and not hang', async () => {
|
|
65
|
+
if (CI_ENVIRONMENT || !isAuthenticated) {
|
|
66
|
+
console.log('Skipped: CI environment or not authenticated');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Create a temporary file
|
|
71
|
+
const tempFile = path.join(os.tmpdir(), 'test-gist-file.txt');
|
|
72
|
+
await fs.writeFile(tempFile, 'Test content for gist\n');
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
// Create gist with timeout to prevent hanging
|
|
76
|
+
const result =
|
|
77
|
+
await $`gh gist create ${tempFile} --desc "${TEST_DESC}" --public=false 2>&1`.run(
|
|
78
|
+
{
|
|
79
|
+
capture: true,
|
|
80
|
+
mirror: false,
|
|
81
|
+
timeout: 10000, // 10 second timeout
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Should complete successfully
|
|
86
|
+
expect(result.code).toBe(0);
|
|
87
|
+
expect(result.stdout).toBeDefined();
|
|
88
|
+
expect(result.stdout).toContain('gist.github.com');
|
|
89
|
+
|
|
90
|
+
// Extract gist ID for cleanup
|
|
91
|
+
const lines = result.stdout.trim().split('\n');
|
|
92
|
+
const gistUrl = lines.find((line) => line.includes('gist.github.com'));
|
|
93
|
+
if (gistUrl) {
|
|
94
|
+
testGistId = gistUrl.split('/').pop();
|
|
95
|
+
expect(testGistId).toBeTruthy();
|
|
96
|
+
expect(testGistId.length).toBeGreaterThan(0);
|
|
97
|
+
}
|
|
98
|
+
} finally {
|
|
99
|
+
// Clean up temp file
|
|
100
|
+
await fs.unlink(tempFile).catch(() => {});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('gh gist view should retrieve gist details', async () => {
|
|
105
|
+
if (CI_ENVIRONMENT || !isAuthenticated || !testGistId) {
|
|
106
|
+
console.log('Skipped: CI environment or no test gist available');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const result = await $`gh gist view ${testGistId} --files`.run({
|
|
111
|
+
capture: true,
|
|
112
|
+
mirror: false,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(result.code).toBe(0);
|
|
116
|
+
expect(result.stdout).toBeDefined();
|
|
117
|
+
expect(result.stdout).toContain('test-gist-file.txt');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('gh api should work for gist operations', async () => {
|
|
121
|
+
if (CI_ENVIRONMENT || !isAuthenticated || !testGistId) {
|
|
122
|
+
console.log('Skipped: CI environment or no test gist available');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const result = await $`gh api /gists/${testGistId} --jq '.description'`.run(
|
|
127
|
+
{
|
|
128
|
+
capture: true,
|
|
129
|
+
mirror: false,
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
expect(result.code).toBe(0);
|
|
134
|
+
expect(result.stdout.trim()).toBe(TEST_DESC);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test.skip('gh gist edit should add files to existing gist', async () => {
|
|
138
|
+
if (CI_ENVIRONMENT || !isAuthenticated || !testGistId) {
|
|
139
|
+
console.log('Skipped: CI environment or no test gist available');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Create another file to add
|
|
144
|
+
const tempFile2 = path.join(os.tmpdir(), 'additional-file.txt');
|
|
145
|
+
await fs.writeFile(tempFile2, 'Additional content\n');
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const result =
|
|
149
|
+
await $`gh gist edit ${testGistId} ${tempFile2} --filename "added.txt" 2>&1`.run(
|
|
150
|
+
{
|
|
151
|
+
capture: true,
|
|
152
|
+
mirror: false,
|
|
153
|
+
timeout: 10000,
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// gh gist edit may not return 0 but should complete
|
|
158
|
+
expect(result).toBeDefined();
|
|
159
|
+
|
|
160
|
+
// Verify file was added
|
|
161
|
+
const verifyResult = await $`gh gist view ${testGistId} --files`.run({
|
|
162
|
+
capture: true,
|
|
163
|
+
mirror: false,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
expect(verifyResult.code).toBe(0);
|
|
167
|
+
expect(verifyResult.stdout).toContain('added.txt');
|
|
168
|
+
} finally {
|
|
169
|
+
await fs.unlink(tempFile2).catch(() => {});
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('gh gist delete should remove gist', async () => {
|
|
174
|
+
if (CI_ENVIRONMENT || !isAuthenticated || !testGistId) {
|
|
175
|
+
console.log('Skipped: CI environment or no test gist available');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const result = await $`gh gist delete ${testGistId} --yes`.run({
|
|
180
|
+
capture: true,
|
|
181
|
+
mirror: false,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
expect(result.code).toBe(0);
|
|
185
|
+
|
|
186
|
+
// Verify deletion - should fail to view
|
|
187
|
+
try {
|
|
188
|
+
await $`gh gist view ${testGistId}`.run({
|
|
189
|
+
capture: true,
|
|
190
|
+
mirror: false,
|
|
191
|
+
});
|
|
192
|
+
// Should not reach here
|
|
193
|
+
expect(true).toBe(false);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
// Expected to fail
|
|
196
|
+
expect(error).toBeDefined();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Clear the ID since it's deleted
|
|
200
|
+
testGistId = null;
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test('complex gh command with pipes should work', async () => {
|
|
204
|
+
if (CI_ENVIRONMENT || !isAuthenticated) {
|
|
205
|
+
console.log('Skipped: CI environment or not authenticated');
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Test piping gh output through other commands
|
|
210
|
+
const result = await $`gh api /gists --jq '.[0].id' | head -1`.run({
|
|
211
|
+
capture: true,
|
|
212
|
+
mirror: false,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
expect(result.code).toBe(0);
|
|
216
|
+
expect(result.stdout).toBeDefined();
|
|
217
|
+
// Should be a single line (gist ID)
|
|
218
|
+
const lines = result.stdout.trim().split('\n');
|
|
219
|
+
expect(lines.length).toBe(1);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import { test, expect, describe, beforeEach, afterEach } from 'bun:test';
|
|
2
|
+
import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs';
|
|
3
|
+
import { $, shell, enableVirtualCommands } from '../src/$.mjs';
|
|
4
|
+
import { mkdtempSync, rmSync, existsSync, realpathSync } from 'fs';
|
|
5
|
+
import { tmpdir } from 'os';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
|
|
8
|
+
// Platform detection - Tests use bash and Unix shell commands
|
|
9
|
+
const isWindows = process.platform === 'win32';
|
|
10
|
+
|
|
11
|
+
// Helper to normalize paths (handles macOS /var -> /private/var symlink)
|
|
12
|
+
const normalizePath = (p) => {
|
|
13
|
+
try {
|
|
14
|
+
return realpathSync(p);
|
|
15
|
+
} catch {
|
|
16
|
+
return p;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
// IMPORTANT: Call cleanup first to restore cwd
|
|
22
|
+
await beforeTestCleanup();
|
|
23
|
+
|
|
24
|
+
shell.errexit(false);
|
|
25
|
+
shell.verbose(false);
|
|
26
|
+
shell.xtrace(false);
|
|
27
|
+
shell.pipefail(false);
|
|
28
|
+
shell.nounset(false);
|
|
29
|
+
enableVirtualCommands();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
afterEach(async () => {
|
|
33
|
+
// IMPORTANT: Call cleanup to restore cwd
|
|
34
|
+
await afterTestCleanup();
|
|
35
|
+
|
|
36
|
+
shell.errexit(false);
|
|
37
|
+
shell.verbose(false);
|
|
38
|
+
shell.xtrace(false);
|
|
39
|
+
shell.pipefail(false);
|
|
40
|
+
shell.nounset(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Skip on Windows - uses bash -c, pwd, subshells, and Unix redirection
|
|
44
|
+
describe.skipIf(isWindows)(
|
|
45
|
+
'Git and GH commands with cd virtual command',
|
|
46
|
+
() => {
|
|
47
|
+
// The test-cleanup functions handle cwd restoration globally
|
|
48
|
+
|
|
49
|
+
describe('Git operations in temp directories', () => {
|
|
50
|
+
let tempDir;
|
|
51
|
+
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
tempDir = mkdtempSync(join(tmpdir(), 'git-test-'));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
afterEach(() => {
|
|
57
|
+
// Clean up the temp directory
|
|
58
|
+
try {
|
|
59
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
60
|
+
} catch (e) {
|
|
61
|
+
// Ignore cleanup errors
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('should initialize git repo after cd to temp directory', async () => {
|
|
66
|
+
const originalCwd = process.cwd();
|
|
67
|
+
|
|
68
|
+
const cdResult = await $`cd ${tempDir}`;
|
|
69
|
+
expect(cdResult.code).toBe(0);
|
|
70
|
+
|
|
71
|
+
const initResult = await $`git init`;
|
|
72
|
+
expect(initResult.code).toBe(0);
|
|
73
|
+
// Git init outputs to stderr
|
|
74
|
+
const output = initResult.stdout + initResult.stderr;
|
|
75
|
+
expect(output).toContain('Initialized empty Git repository');
|
|
76
|
+
|
|
77
|
+
const statusResult = await $`git status`;
|
|
78
|
+
expect(statusResult.code).toBe(0);
|
|
79
|
+
expect(statusResult.stdout).toContain('On branch');
|
|
80
|
+
|
|
81
|
+
await $`cd ${originalCwd}`;
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('should handle git commands in temp directory with cd chain', async () => {
|
|
85
|
+
const originalCwd = process.cwd();
|
|
86
|
+
|
|
87
|
+
// Git init and check status
|
|
88
|
+
const result =
|
|
89
|
+
await $`cd ${tempDir} && git init && git status --porcelain`;
|
|
90
|
+
expect(result.code).toBe(0);
|
|
91
|
+
// Git init outputs to stderr, check both
|
|
92
|
+
const output = result.stdout + result.stderr;
|
|
93
|
+
expect(output).toContain('Initialized empty Git repository');
|
|
94
|
+
|
|
95
|
+
await $`cd ${originalCwd}`;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('should create and commit files in temp git repo', async () => {
|
|
99
|
+
const originalCwd = process.cwd();
|
|
100
|
+
|
|
101
|
+
await $`cd ${tempDir}`;
|
|
102
|
+
await $`git init`;
|
|
103
|
+
await $`git config user.email "test@example.com"`;
|
|
104
|
+
await $`git config user.name "Test User"`;
|
|
105
|
+
|
|
106
|
+
// Use bash -c to properly handle redirection
|
|
107
|
+
await $`bash -c 'echo "test content" > test.txt'`;
|
|
108
|
+
await $`git add test.txt`;
|
|
109
|
+
|
|
110
|
+
const commitResult = await $`git commit -m "Initial commit"`;
|
|
111
|
+
expect(commitResult.code).toBe(0);
|
|
112
|
+
expect(commitResult.stdout).toContain('1 file changed');
|
|
113
|
+
|
|
114
|
+
const logResult = await $`git log --oneline`;
|
|
115
|
+
expect(logResult.code).toBe(0);
|
|
116
|
+
expect(logResult.stdout).toContain('Initial commit');
|
|
117
|
+
|
|
118
|
+
await $`cd ${originalCwd}`;
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('should handle git branch operations with cd', async () => {
|
|
122
|
+
const originalCwd = process.cwd();
|
|
123
|
+
|
|
124
|
+
await $`cd ${tempDir} && git init`;
|
|
125
|
+
await $`cd ${tempDir} && git config user.email "test@example.com"`;
|
|
126
|
+
await $`cd ${tempDir} && git config user.name "Test User"`;
|
|
127
|
+
await $`cd ${tempDir} && bash -c 'echo "content" > file.txt' && git add . && git commit -m "init"`;
|
|
128
|
+
|
|
129
|
+
const branchResult =
|
|
130
|
+
await $`cd ${tempDir} && git branch --show-current`;
|
|
131
|
+
expect(branchResult.code).toBe(0);
|
|
132
|
+
const defaultBranch = branchResult.stdout.trim();
|
|
133
|
+
expect(['main', 'master']).toContain(defaultBranch);
|
|
134
|
+
|
|
135
|
+
await $`cd ${tempDir} && git checkout -b feature-branch`;
|
|
136
|
+
|
|
137
|
+
const newBranchResult =
|
|
138
|
+
await $`cd ${tempDir} && git branch --show-current`;
|
|
139
|
+
expect(newBranchResult.code).toBe(0);
|
|
140
|
+
expect(newBranchResult.stdout.trim()).toBe('feature-branch');
|
|
141
|
+
|
|
142
|
+
await $`cd ${originalCwd}`;
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('should handle multiple temp directories with cd', async () => {
|
|
146
|
+
const tempDir2 = mkdtempSync(join(tmpdir(), 'git-test2-'));
|
|
147
|
+
const originalCwd = process.cwd();
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
await $`cd ${tempDir} && git init && bash -c 'echo "repo1" > file.txt'`;
|
|
151
|
+
await $`cd ${tempDir2} && git init && bash -c 'echo "repo2" > file.txt'`;
|
|
152
|
+
|
|
153
|
+
const repo1Content = await $`cd ${tempDir} && cat file.txt`;
|
|
154
|
+
expect(repo1Content.stdout.trim()).toBe('repo1');
|
|
155
|
+
|
|
156
|
+
const repo2Content = await $`cd ${tempDir2} && cat file.txt`;
|
|
157
|
+
expect(repo2Content.stdout.trim()).toBe('repo2');
|
|
158
|
+
|
|
159
|
+
const repo1Status = await $`cd ${tempDir} && git status --porcelain`;
|
|
160
|
+
expect(repo1Status.stdout).toContain('file.txt');
|
|
161
|
+
|
|
162
|
+
const repo2Status = await $`cd ${tempDir2} && git status --porcelain`;
|
|
163
|
+
expect(repo2Status.stdout).toContain('file.txt');
|
|
164
|
+
} finally {
|
|
165
|
+
rmSync(tempDir2, { recursive: true, force: true });
|
|
166
|
+
await $`cd ${originalCwd}`;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test('should handle git diff operations after cd', async () => {
|
|
171
|
+
const originalCwd = process.cwd();
|
|
172
|
+
|
|
173
|
+
await $`cd ${tempDir} && git init`;
|
|
174
|
+
await $`cd ${tempDir} && git config user.email "test@example.com"`;
|
|
175
|
+
await $`cd ${tempDir} && git config user.name "Test User"`;
|
|
176
|
+
await $`cd ${tempDir} && bash -c 'echo "line1" > file.txt' && git add . && git commit -m "first"`;
|
|
177
|
+
await $`cd ${tempDir} && bash -c 'echo "line2" >> file.txt'`;
|
|
178
|
+
|
|
179
|
+
const diffResult = await $`cd ${tempDir} && git diff`;
|
|
180
|
+
expect(diffResult.code).toBe(0);
|
|
181
|
+
expect(diffResult.stdout).toContain('+line2');
|
|
182
|
+
|
|
183
|
+
const statusResult = await $`cd ${tempDir} && git status --porcelain`;
|
|
184
|
+
expect(statusResult.stdout).toContain(' M file.txt');
|
|
185
|
+
|
|
186
|
+
await $`cd ${originalCwd}`;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('should work with git in subshells', async () => {
|
|
190
|
+
const originalCwd = process.cwd();
|
|
191
|
+
|
|
192
|
+
// Initialize repo in subshell - should not affect parent
|
|
193
|
+
await $`(cd ${tempDir} && git init && git config user.email "test@example.com")`;
|
|
194
|
+
|
|
195
|
+
// Verify we're still in original directory
|
|
196
|
+
const pwd = await $`pwd`;
|
|
197
|
+
expect(pwd.stdout.trim()).toBe(originalCwd);
|
|
198
|
+
|
|
199
|
+
// But the repo should exist
|
|
200
|
+
const checkResult = await $`cd ${tempDir} && git status`;
|
|
201
|
+
expect(checkResult.code).toBe(0);
|
|
202
|
+
|
|
203
|
+
await $`cd ${originalCwd}`;
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
describe('GH CLI operations with cd', () => {
|
|
208
|
+
test('should check gh auth status', async () => {
|
|
209
|
+
const result = await $`gh auth status`;
|
|
210
|
+
// This might fail if not authenticated, but we're testing the command execution
|
|
211
|
+
expect([0, 1]).toContain(result.code);
|
|
212
|
+
|
|
213
|
+
if (result.code === 0) {
|
|
214
|
+
expect(result.stdout.toLowerCase()).toMatch(
|
|
215
|
+
/logged in|authenticated/i
|
|
216
|
+
);
|
|
217
|
+
} else {
|
|
218
|
+
expect(result.stderr.toLowerCase()).toMatch(
|
|
219
|
+
/not.*authenticated|not.*logged/i
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test('should handle gh api calls with cd to temp directory', async () => {
|
|
225
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'gh-test-'));
|
|
226
|
+
const originalCwd = process.cwd();
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
await $`cd ${tempDir}`;
|
|
230
|
+
|
|
231
|
+
const result =
|
|
232
|
+
await $`gh api user --jq .login 2>/dev/null || echo "not-authenticated"`;
|
|
233
|
+
expect(result.code).toBe(0);
|
|
234
|
+
// Result will be either a username or "not-authenticated"
|
|
235
|
+
expect(result.stdout.trim().length).toBeGreaterThan(0);
|
|
236
|
+
|
|
237
|
+
await $`cd ${originalCwd}`;
|
|
238
|
+
} finally {
|
|
239
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test('should simulate gh repo clone pattern', async () => {
|
|
244
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'gh-clone-'));
|
|
245
|
+
const originalCwd = process.cwd();
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
// Simulate the pattern from solve.mjs without actually cloning
|
|
249
|
+
const owner = 'octocat';
|
|
250
|
+
const repo = 'Hello-World';
|
|
251
|
+
|
|
252
|
+
await $`cd ${tempDir}`;
|
|
253
|
+
|
|
254
|
+
// Test the command structure (use -- to separate git flags as per gh documentation)
|
|
255
|
+
const cloneCmd = `gh repo clone ${owner}/${repo} . -- --depth 1 2>&1 || echo "Clone would execute here"`;
|
|
256
|
+
const result = await $`bash -c ${cloneCmd}`;
|
|
257
|
+
expect(result.code).toBe(0);
|
|
258
|
+
|
|
259
|
+
// Test that we're in the right directory
|
|
260
|
+
const pwdResult = await $`pwd`;
|
|
261
|
+
expect(normalizePath(pwdResult.stdout.trim())).toBe(
|
|
262
|
+
normalizePath(tempDir)
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
await $`cd ${originalCwd}`;
|
|
266
|
+
} finally {
|
|
267
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test('should handle gh commands with directory context', async () => {
|
|
272
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'gh-context-'));
|
|
273
|
+
const originalCwd = process.cwd();
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
// Create a mock git repo structure
|
|
277
|
+
await $`cd ${tempDir} && git init`;
|
|
278
|
+
await $`cd ${tempDir} && git config user.email "test@example.com"`;
|
|
279
|
+
await $`cd ${tempDir} && git config user.name "Test User"`;
|
|
280
|
+
await $`cd ${tempDir} && bash -c 'echo "# Test Repo" > README.md'`;
|
|
281
|
+
await $`cd ${tempDir} && git add . && git commit -m "Initial commit"`;
|
|
282
|
+
|
|
283
|
+
// Test gh command patterns that would work in a repo context
|
|
284
|
+
const statusResult = await $`cd ${tempDir} && git status --porcelain`;
|
|
285
|
+
expect(statusResult.code).toBe(0);
|
|
286
|
+
expect(statusResult.stdout).toBe('');
|
|
287
|
+
|
|
288
|
+
// Simulate checking for existing PRs (would fail without actual remote)
|
|
289
|
+
const prListCmd =
|
|
290
|
+
await $`cd ${tempDir} && gh pr list --limit 1 2>&1 || echo "No remote configured"`;
|
|
291
|
+
expect(prListCmd.code).toBe(0);
|
|
292
|
+
|
|
293
|
+
await $`cd ${originalCwd}`;
|
|
294
|
+
} finally {
|
|
295
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
describe('Combined git and gh workflows', () => {
|
|
301
|
+
test('should simulate solve.mjs workflow pattern', async () => {
|
|
302
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'workflow-'));
|
|
303
|
+
const originalCwd = process.cwd();
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
// Step 1: Navigate to temp directory
|
|
307
|
+
await $`cd ${tempDir}`;
|
|
308
|
+
|
|
309
|
+
// Step 2: Initialize git repo (simulating clone)
|
|
310
|
+
await $`git init`;
|
|
311
|
+
await $`git config user.email "bot@example.com"`;
|
|
312
|
+
await $`git config user.name "Bot User"`;
|
|
313
|
+
|
|
314
|
+
// Step 3: Check current branch
|
|
315
|
+
const branchResult = await $`git branch --show-current`;
|
|
316
|
+
const currentBranch = branchResult.stdout.trim() || 'master';
|
|
317
|
+
|
|
318
|
+
// Step 4: Create new feature branch
|
|
319
|
+
const branchName = `feature-${Date.now()}`;
|
|
320
|
+
await $`git checkout -b ${branchName}`;
|
|
321
|
+
|
|
322
|
+
// Step 5: Verify branch switch
|
|
323
|
+
const newBranchResult = await $`git branch --show-current`;
|
|
324
|
+
expect(newBranchResult.stdout.trim()).toBe(branchName);
|
|
325
|
+
|
|
326
|
+
// Step 6: Make changes
|
|
327
|
+
await $`bash -c 'echo "feature implementation" > feature.js'`;
|
|
328
|
+
await $`git add .`;
|
|
329
|
+
|
|
330
|
+
// Step 7: Check status
|
|
331
|
+
const statusResult = await $`git status --porcelain`;
|
|
332
|
+
expect(statusResult.stdout.trim()).toMatch(/A.*feature\.js/);
|
|
333
|
+
|
|
334
|
+
// Step 8: Commit changes
|
|
335
|
+
await $`git commit -m "Add feature implementation"`;
|
|
336
|
+
|
|
337
|
+
// Step 9: Verify commit
|
|
338
|
+
const logResult = await $`git log --oneline -1`;
|
|
339
|
+
expect(logResult.stdout).toContain('Add feature implementation');
|
|
340
|
+
|
|
341
|
+
await $`cd ${originalCwd}`;
|
|
342
|
+
} finally {
|
|
343
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test('should handle error scenarios with cd and git', async () => {
|
|
348
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'error-test-'));
|
|
349
|
+
const originalCwd = process.cwd();
|
|
350
|
+
|
|
351
|
+
try {
|
|
352
|
+
// Test invalid git command in temp directory
|
|
353
|
+
await $`cd ${tempDir}`;
|
|
354
|
+
// Git status will fail in non-git directory
|
|
355
|
+
const result = await $`git status 2>&1 || echo "not a git repo"`;
|
|
356
|
+
const output = result.stdout + result.stderr;
|
|
357
|
+
expect(output.toLowerCase()).toMatch(
|
|
358
|
+
/not a git repo|fatal.*not a git repository/
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
// Test recovery after error
|
|
362
|
+
await $`git init`;
|
|
363
|
+
const retryResult = await $`git status`;
|
|
364
|
+
expect(retryResult.code).toBe(0);
|
|
365
|
+
|
|
366
|
+
await $`cd ${originalCwd}`;
|
|
367
|
+
} finally {
|
|
368
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test('should preserve cwd after command chains', async () => {
|
|
373
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'cwd-test-'));
|
|
374
|
+
const originalCwd = process.cwd();
|
|
375
|
+
|
|
376
|
+
try {
|
|
377
|
+
// Run commands with cd in subshell
|
|
378
|
+
await $`(cd ${tempDir} && git init && echo 'test' > file.txt)`;
|
|
379
|
+
|
|
380
|
+
// Verify we're still in original directory
|
|
381
|
+
const currentDir = await $`pwd`;
|
|
382
|
+
expect(currentDir.stdout.trim()).toBe(originalCwd);
|
|
383
|
+
|
|
384
|
+
// Verify the commands actually ran in temp directory
|
|
385
|
+
const checkResult =
|
|
386
|
+
await $`cd ${tempDir} && test -f file.txt && echo "exists"`;
|
|
387
|
+
expect(checkResult.stdout.trim()).toBe('exists');
|
|
388
|
+
} finally {
|
|
389
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
test('should work with complex git workflows using operators', async () => {
|
|
394
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'complex-'));
|
|
395
|
+
const originalCwd = process.cwd();
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
// Complex workflow with &&, ||, and ;
|
|
399
|
+
const result =
|
|
400
|
+
await $`cd ${tempDir} && git init && git config user.email "test@test.com" && git config user.name "Test" ; echo "setup done"`;
|
|
401
|
+
expect(result.stdout).toContain('setup done');
|
|
402
|
+
|
|
403
|
+
// Use || for error handling - git remote add returns 0 even for non-existent URLs
|
|
404
|
+
const errorHandling =
|
|
405
|
+
await $`cd ${tempDir} && git remote get-url nonexistent 2>/dev/null || echo "remote failed as expected"`;
|
|
406
|
+
expect(errorHandling.stdout).toContain('remote failed as expected');
|
|
407
|
+
|
|
408
|
+
// Complex chain with file operations
|
|
409
|
+
await $`cd ${tempDir} && echo "test" > file1.txt && git add . && git commit -m "test" && echo "committed"`;
|
|
410
|
+
|
|
411
|
+
const logCheck = await $`cd ${tempDir} && git log --oneline`;
|
|
412
|
+
expect(logCheck.stdout).toContain('test');
|
|
413
|
+
|
|
414
|
+
await $`cd ${originalCwd}`;
|
|
415
|
+
} finally {
|
|
416
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
describe('Path resolution and quoting with cd', () => {
|
|
422
|
+
// Global cleanup handles cwd restoration
|
|
423
|
+
|
|
424
|
+
test('should handle paths with spaces in git operations', async () => {
|
|
425
|
+
const baseTempDir = mkdtempSync(join(tmpdir(), 'space-test-'));
|
|
426
|
+
const tempDirWithSpace = join(baseTempDir, 'my test dir');
|
|
427
|
+
|
|
428
|
+
try {
|
|
429
|
+
await $`mkdir -p ${tempDirWithSpace}`;
|
|
430
|
+
await $`cd ${tempDirWithSpace} && git init`;
|
|
431
|
+
|
|
432
|
+
const pwdResult = await $`cd ${tempDirWithSpace} && pwd`;
|
|
433
|
+
expect(normalizePath(pwdResult.stdout.trim())).toBe(
|
|
434
|
+
normalizePath(tempDirWithSpace)
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
// Test git operations in directory with spaces
|
|
438
|
+
await $`cd ${tempDirWithSpace} && git config user.email "test@test.com"`;
|
|
439
|
+
await $`cd ${tempDirWithSpace} && git config user.name "Test User"`;
|
|
440
|
+
await $`cd ${tempDirWithSpace} && bash -c 'echo "test" > file.txt' && git add . && git commit -m "test"`;
|
|
441
|
+
|
|
442
|
+
const logResult =
|
|
443
|
+
await $`cd ${tempDirWithSpace} && git log --oneline`;
|
|
444
|
+
expect(logResult.stdout).toContain('test');
|
|
445
|
+
} finally {
|
|
446
|
+
rmSync(baseTempDir, { recursive: true, force: true });
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
test('should handle special characters in paths', async () => {
|
|
451
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'special-chars-'));
|
|
452
|
+
const specialDir = join(tempDir, "test-'dir'-$1");
|
|
453
|
+
|
|
454
|
+
try {
|
|
455
|
+
await $`mkdir -p ${specialDir}`;
|
|
456
|
+
await $`cd ${specialDir} && git init`;
|
|
457
|
+
|
|
458
|
+
const statusResult = await $`cd ${specialDir} && git status`;
|
|
459
|
+
expect(statusResult.code).toBe(0);
|
|
460
|
+
} finally {
|
|
461
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
);
|