From 2e3f071657c064623f2f12a2b0f9aaa72a92396b Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 29 Dec 2025 09:43:14 +0100 Subject: [PATCH 1/9] Initial commit with task details Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/link-foundation/command-stream/issues/146 --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..56c995c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/link-foundation/command-stream/issues/146 +Your prepared branch: issue-146-f111406088b3 +Your prepared working directory: /tmp/gh-issue-solver-1766997793068 + +Proceed. From 6fc7817d434c24c45dd197d1fc00db762ad607a8 Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 29 Dec 2025 09:58:56 +0100 Subject: [PATCH 2/9] Reorganize JS to js/ folder and add Rust translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move JavaScript source files from src/ to js/src/ - Update all import paths in tests and examples - Update package.json exports to point to js/src/ - Add Rust translation in rust/ folder: - Complete shell parser with tokenizer - Utility functions (tracing, command results, ANSI handling) - All 21 virtual commands (echo, ls, cat, mkdir, etc.) - ProcessRunner for command execution - Unit tests for all modules - Add case study documentation in docs/case-studies/issue-146/ Note: ESLint warnings are pre-existing in the JS codebase, no new issues introduced. Fixes #146 ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- claude-profiles.mjs | 2 +- docs/case-studies/issue-146/README.md | 231 +++++++ examples/01-basic-streaming.mjs | 2 +- examples/02-async-iterator.mjs | 2 +- examples/03-file-and-console.mjs | 2 +- examples/04-claude-jq-pipe.mjs | 2 +- examples/README-examples.mjs | 2 +- examples/ansi-default-preserved.mjs | 2 +- examples/ansi-global-config.mjs | 2 +- examples/ansi-reset-default.mjs | 2 +- examples/ansi-strip-utils.mjs | 2 +- examples/capture-mirror-comparison.mjs | 2 +- examples/capture-mirror-default.mjs | 2 +- examples/capture-mirror-performance.mjs | 2 +- examples/capture-mirror-show-only.mjs | 2 +- examples/capture-mirror-silent-processing.mjs | 2 +- examples/ci-debug-baseline-vs-library.mjs | 2 +- examples/ci-debug-es-module-loading.mjs | 4 +- examples/ci-debug-signal-handling.mjs | 2 +- examples/ci-debug-stdout-buffering.mjs | 2 +- examples/ci-debug-test-timeouts.mjs | 2 +- examples/claude-exact-file-output.mjs | 2 +- examples/claude-exact-jq.mjs | 2 +- examples/claude-exact-streaming.mjs | 2 +- examples/claude-jq-pipeline.mjs | 2 +- examples/claude-streaming-basic.mjs | 2 +- examples/claude-streaming-demo.mjs | 2 +- examples/claude-streaming-final.mjs | 2 +- examples/cleanup-verification-test.mjs | 2 +- examples/colors-buffer-processing.mjs | 2 +- examples/colors-default-preserved.mjs | 2 +- examples/colors-per-command-config.mjs | 2 +- examples/colors-strip-ansi.mjs | 2 +- examples/commandstream-jq.mjs | 2 +- examples/commandstream-working.mjs | 2 +- examples/comprehensive-streams-demo.mjs | 2 +- examples/ctrl-c-concurrent-processes.mjs | 2 +- examples/ctrl-c-long-running-command.mjs | 2 +- examples/ctrl-c-real-system-command.mjs | 2 +- examples/ctrl-c-sleep-command.mjs | 2 +- examples/ctrl-c-stdin-forwarding.mjs | 2 +- examples/ctrl-c-virtual-command.mjs | 2 +- examples/debug-already-started.mjs | 2 +- examples/debug-ansi-processing.mjs | 2 +- examples/debug-basic-streaming.mjs | 2 +- examples/debug-child-process.mjs | 2 +- examples/debug-child-state.mjs | 2 +- examples/debug-chunking.mjs | 2 +- examples/debug-command-parsing.mjs | 2 +- examples/debug-complete-consolidation.mjs | 2 +- examples/debug-echo-args.mjs | 2 +- examples/debug-emit-timing.mjs | 2 +- examples/debug-end-event.mjs | 2 +- examples/debug-errexit.mjs | 2 +- examples/debug-event-emission.mjs | 2 +- examples/debug-event-timing.mjs | 2 +- examples/debug-event-vs-result.mjs | 2 +- examples/debug-exact-command.mjs | 2 +- examples/debug-exact-test-scenario.mjs | 2 +- examples/debug-execution-path.mjs | 2 +- examples/debug-exit-command.mjs | 2 +- examples/debug-exit-virtual.mjs | 2 +- examples/debug-finish-consolidation.mjs | 2 +- examples/debug-force-cleanup.mjs | 2 +- examples/debug-getter-basic.mjs | 2 +- examples/debug-getter-direct.mjs | 2 +- examples/debug-getter-internals.mjs | 2 +- examples/debug-handler-detection.mjs | 2 +- examples/debug-idempotent-finish.mjs | 2 +- examples/debug-idempotent-kill.mjs | 2 +- examples/debug-interpolation-individual.mjs | 2 +- examples/debug-interpolation-issue.mjs | 2 +- examples/debug-jq-streaming.mjs | 2 +- examples/debug-jq-tty-colors.mjs | 2 +- examples/debug-kill-cleanup.mjs | 2 +- examples/debug-kill-method.mjs | 2 +- examples/debug-listener-interference.mjs | 2 +- examples/debug-listener-lifecycle.mjs | 2 +- examples/debug-listener-timing.mjs | 2 +- examples/debug-listeners-property.mjs | 2 +- examples/debug-map-methods.mjs | 2 +- examples/debug-not-awaited-cleanup.mjs | 2 +- examples/debug-off-method.mjs | 2 +- examples/debug-option-merging.mjs | 2 +- examples/debug-options.mjs | 2 +- examples/debug-output.mjs | 2 +- examples/debug-pattern-matching.mjs | 2 +- examples/debug-pipeline-cat.mjs | 2 +- examples/debug-pipeline-cleanup.mjs | 2 +- examples/debug-pipeline-error-detailed.mjs | 2 +- examples/debug-pipeline-error.mjs | 2 +- examples/debug-pipeline-issue.mjs | 2 +- examples/debug-pipeline-method.mjs | 2 +- examples/debug-pipeline-stream.mjs | 2 +- examples/debug-pipeline.mjs | 2 +- examples/debug-process-exit-trace.mjs | 2 +- examples/debug-process-path.mjs | 2 +- examples/debug-property-check.mjs | 2 +- examples/debug-resource-cleanup.mjs | 2 +- examples/debug-sigint-child-handler.mjs | 2 +- examples/debug-sigint-forwarding.mjs | 2 +- examples/debug-sigint-handler-install.mjs | 2 +- examples/debug-sigint-handler-order.mjs | 2 +- examples/debug-sigint-listeners.mjs | 2 +- examples/debug-sigint-start-pattern.mjs | 2 +- examples/debug-sigint-timer.mjs | 2 +- examples/debug-simple-command.mjs | 2 +- examples/debug-simple-getter.mjs | 2 +- examples/debug-simple.mjs | 2 +- examples/debug-simplified-finished.mjs | 2 +- examples/debug-stack-overflow.mjs | 2 +- examples/debug-stdin-simple.mjs | 2 +- examples/debug-stdin.mjs | 2 +- examples/debug-stream-emitter-isolated.mjs | 2 +- examples/debug-stream-emitter.mjs | 2 +- examples/debug-stream-events.mjs | 2 +- examples/debug-stream-generator.mjs | 2 +- examples/debug-stream-getter-issue.mjs | 2 +- examples/debug-stream-getter.mjs | 2 +- examples/debug-stream-internals.mjs | 2 +- examples/debug-stream-method.mjs | 2 +- examples/debug-stream-object.mjs | 2 +- examples/debug-stream-properties.mjs | 2 +- examples/debug-stream-timing.mjs | 2 +- examples/debug-streaming.mjs | 2 +- examples/debug-test-state.mjs | 2 +- examples/debug-user-sigint.mjs | 2 +- examples/debug-virtual-disable.mjs | 2 +- examples/debug-virtual-vs-real.mjs | 2 +- examples/debug-with-trace.mjs | 2 +- examples/debug_parent_stream.mjs | 2 +- examples/emulated-streaming-direct.mjs | 2 +- examples/emulated-streaming-jq-pipe.mjs | 2 +- examples/emulated-streaming-sh-pipe.mjs | 2 +- examples/events-build-process.mjs | 2 +- examples/events-concurrent-streams.mjs | 2 +- examples/events-error-handling.mjs | 2 +- examples/events-file-monitoring.mjs | 2 +- examples/events-interactive-simulation.mjs | 2 +- examples/events-log-processing.mjs | 2 +- examples/events-network-monitoring.mjs | 2 +- examples/events-ping-basic.mjs | 2 +- examples/events-progress-tracking.mjs | 2 +- examples/events-stdin-input.mjs | 2 +- examples/example-ansi-ls.mjs | 2 +- examples/example-top.mjs | 2 +- examples/final-ping-stdin-proof.mjs | 2 +- examples/final-test-shell-operators.mjs | 2 +- examples/final-working-examples.mjs | 2 +- examples/gh-auth-test.mjs | 2 +- examples/gh-delete-hang-test.mjs | 2 +- examples/gh-gist-creation-test.mjs | 2 +- examples/gh-gist-minimal-test.mjs | 2 +- examples/gh-hang-exact-original.mjs | 2 +- examples/gh-hang-reproduction.mjs | 2 +- examples/gh-hang-test-with-redirect.mjs | 2 +- examples/gh-hang-test-without-redirect.mjs | 2 +- examples/gh-minimal-hang-check.mjs | 2 +- examples/gh-operations-with-cd.mjs | 2 +- examples/gh-output-test.mjs | 2 +- examples/gh-reproduce-hang.mjs | 2 +- examples/git-operations-with-cd.mjs | 2 +- examples/interactive-top-fixed.mjs | 2 +- examples/interactive-top-improved.mjs | 2 +- examples/interactive-top-pty-logging.mjs | 2 +- examples/interactive-top-with-logging.mjs | 2 +- examples/interactive-top.mjs | 2 +- examples/jq-color-demo.mjs | 2 +- examples/jq-colors-streaming.mjs | 2 +- examples/manual-ctrl-c-test.mjs | 2 +- examples/methods-multiple-options.mjs | 2 +- examples/methods-run-basic.mjs | 2 +- examples/methods-start-basic.mjs | 2 +- examples/options-capture-false.mjs | 2 +- examples/options-combined-settings.mjs | 2 +- examples/options-custom-input.mjs | 2 +- examples/options-default-behavior.mjs | 2 +- examples/options-maximum-performance.mjs | 2 +- examples/options-mirror-false.mjs | 2 +- examples/options-performance-mode.mjs | 2 +- examples/options-performance-optimization.mjs | 2 +- examples/options-run-alias-demo.mjs | 2 +- examples/options-run-alias.mjs | 2 +- examples/options-silent-execution.mjs | 2 +- examples/options-streaming-capture.mjs | 2 +- examples/options-streaming-multiple.mjs | 2 +- examples/options-streaming-silent.mjs | 2 +- examples/options-streaming-stdin.mjs | 2 +- examples/ping-streaming-filtered.mjs | 2 +- examples/ping-streaming-interruptible.mjs | 2 +- examples/ping-streaming-silent.mjs | 2 +- examples/ping-streaming-simple.mjs | 2 +- examples/ping-streaming-statistics.mjs | 2 +- examples/ping-streaming-timestamps.mjs | 2 +- examples/ping-streaming.mjs | 2 +- examples/prove-ping-stdin-limitation.mjs | 2 +- examples/readme-example.mjs | 2 +- examples/realtime-json-stream.mjs | 2 +- examples/reliable-stdin-commands.mjs | 2 +- examples/reproduce-issue-135-v2.mjs | 2 +- examples/reproduce-issue-135.mjs | 2 +- examples/shell-cd-behavior.mjs | 2 +- examples/sigint-forwarding-test.mjs | 2 +- examples/sigint-handler-test.mjs | 2 +- examples/simple-async-test.mjs | 2 +- examples/simple-claude-test.mjs | 2 +- examples/simple-event-test.mjs | 2 +- examples/simple-jq-streaming.mjs | 2 +- examples/simple-stream-demo.mjs | 2 +- examples/simple-working-stdin.mjs | 2 +- examples/streaming-behavior-test.mjs | 2 +- examples/streaming-direct-command.mjs | 2 +- examples/streaming-filtered-output.mjs | 2 +- examples/streaming-grep-pipeline.mjs | 2 +- examples/streaming-interactive-stdin.mjs | 2 +- examples/streaming-jq-pipeline.mjs | 2 +- examples/streaming-multistage-pipeline.mjs | 2 +- examples/streaming-pipes-event-pattern.mjs | 2 +- examples/streaming-pipes-multistage.mjs | 2 +- examples/streaming-pipes-realtime-jq.mjs | 2 +- examples/streaming-progress-tracking.mjs | 2 +- examples/streaming-reusable-configs.mjs | 2 +- examples/streaming-silent-capture.mjs | 2 +- examples/streaming-test-simple.mjs | 2 +- examples/streaming-virtual-pipeline.mjs | 2 +- examples/syntax-basic-comparison.mjs | 2 +- examples/syntax-basic-options.mjs | 2 +- examples/syntax-combined-options.mjs | 2 +- examples/syntax-command-chaining.mjs | 2 +- examples/syntax-custom-directory.mjs | 2 +- examples/syntax-custom-environment.mjs | 2 +- examples/syntax-custom-stdin.mjs | 2 +- examples/syntax-mixed-regular.mjs | 2 +- examples/syntax-mixed-usage.mjs | 2 +- examples/syntax-multiple-listeners.mjs | 2 +- examples/syntax-piping-comparison.mjs | 2 +- examples/syntax-reusable-config.mjs | 2 +- examples/syntax-reusable-configs.mjs | 2 +- examples/syntax-silent-operations.mjs | 2 +- examples/syntax-stdin-option.mjs | 2 +- examples/temp-sigint-test.mjs | 2 +- examples/test-actual-buildshell.mjs | 2 +- examples/test-async-streams-working.mjs | 2 +- examples/test-async-streams.mjs | 2 +- examples/test-auth-parse.mjs | 2 +- examples/test-auto-quoting.mjs | 2 +- examples/test-auto-start-fix.mjs | 2 +- examples/test-buffer-behavior.mjs | 2 +- examples/test-buffers-simple.mjs | 2 +- examples/test-bun-specific-issue.mjs | 2 +- examples/test-cd-behavior.mjs | 2 +- examples/test-child-process-timing.mjs | 2 +- examples/test-cleanup-simple.mjs | 2 +- examples/test-correct-space-handling.mjs | 2 +- examples/test-ctrl-c-debug.mjs | 2 +- examples/test-ctrl-c-inherit.mjs | 2 +- examples/test-ctrl-c-sleep.mjs | 2 +- examples/test-ctrl-c.mjs | 2 +- examples/test-debug-new-options.mjs | 2 +- examples/test-debug-pty.mjs | 2 +- examples/test-debug-tee.mjs | 2 +- examples/test-debug.mjs | 2 +- examples/test-double-quoting-prevention.mjs | 2 +- examples/test-edge-cases-quoting.mjs | 2 +- examples/test-events.mjs | 2 +- examples/test-explicit-stdio.mjs | 2 +- examples/test-final-streaming.mjs | 2 +- examples/test-fix.mjs | 2 +- examples/test-incremental-streaming.mjs | 2 +- examples/test-inherit-stdout-not-stdin.mjs | 2 +- examples/test-injection-protection.mjs | 2 +- examples/test-interactive-streaming.mjs | 2 +- examples/test-interactive.mjs | 2 +- examples/test-interpolation.mjs | 2 +- examples/test-interrupt.mjs | 2 +- examples/test-issue-135-comprehensive.mjs | 2 +- examples/test-issue12-detailed.mjs | 2 +- examples/test-issue12-exact.mjs | 2 +- examples/test-jq-color.mjs | 2 +- examples/test-jq-colors.mjs | 2 +- examples/test-jq-pipeline-behavior.mjs | 2 +- examples/test-jq-realtime.mjs | 2 +- examples/test-manual-start.mjs | 2 +- examples/test-mixed-quoting.mjs | 2 +- examples/test-multistage-debug.mjs | 2 +- .../test-native-spawn-vs-command-stream.mjs | 2 +- examples/test-no-parse-pipeline.mjs | 2 +- examples/test-non-virtual.mjs | 2 +- examples/test-operators.mjs | 2 +- examples/test-parent-continues.mjs | 2 +- examples/test-path-interpolation.mjs | 2 +- examples/test-ping-kill-and-stdin.mjs | 2 +- examples/test-ping.mjs | 2 +- examples/test-quote-behavior-summary.mjs | 2 +- examples/test-quote-edge-cases.mjs | 2 +- examples/test-quote-parsing.mjs | 2 +- examples/test-raw-function.mjs | 2 +- examples/test-raw-streaming.mjs | 2 +- examples/test-readme-examples.mjs | 2 +- examples/test-real-cat.mjs | 2 +- examples/test-real-commands.mjs | 2 +- examples/test-real-shell.mjs | 2 +- examples/test-real-stdin-commands.mjs | 2 +- examples/test-runner.mjs | 2 +- examples/test-sh-pipeline.mjs | 2 +- examples/test-shell-detection.mjs | 2 +- examples/test-shell-parser.mjs | 2 +- examples/test-sigint-behavior.mjs | 2 +- examples/test-simple-pipe.mjs | 2 +- examples/test-simple-streaming.mjs | 4 +- examples/test-smart-quoting.mjs | 2 +- examples/test-spaces-in-path.mjs | 2 +- examples/test-special-chars-quoting.mjs | 2 +- examples/test-stdin-after-start.mjs | 2 +- examples/test-stdin-simple.mjs | 2 +- examples/test-stdin-timing.mjs | 2 +- examples/test-stdio-combinations.mjs | 2 +- examples/test-stream-access.mjs | 2 +- examples/test-stream-cleanup.mjs | 2 +- examples/test-streaming-final.mjs | 2 +- examples/test-streaming-interfaces.mjs | 2 +- examples/test-streaming-timing.mjs | 2 +- examples/test-streaming.mjs | 2 +- examples/test-streams-stdin-comprehensive.mjs | 2 +- examples/test-streams-stdin-ctrl-c.mjs | 2 +- examples/test-template-literal.mjs | 2 +- examples/test-template-vs-interpolation.mjs | 2 +- examples/test-timing.mjs | 2 +- .../test-top-inherit-stdout-stdin-control.mjs | 2 +- examples/test-top-quit-stdin.mjs | 2 +- examples/test-trace-option.mjs | 2 +- examples/test-user-double-quotes.mjs | 2 +- examples/test-user-single-quotes.mjs | 2 +- examples/test-verbose.mjs | 2 +- examples/test-verbose2.mjs | 2 +- examples/test-virtual-streaming.mjs | 2 +- examples/test-waiting-command.mjs | 2 +- examples/test-waiting-commands.mjs | 2 +- examples/test-watch-mode.mjs | 2 +- examples/test-yes-cancellation.mjs | 2 +- examples/test-yes-detailed.mjs | 4 +- examples/test-yes-trace.mjs | 2 +- examples/trace-abort-controller.mjs | 2 +- examples/trace-error-handling.mjs | 2 +- examples/trace-pipeline-command.mjs | 2 +- examples/trace-signal-handling.mjs | 2 +- examples/trace-simple-command.mjs | 2 +- examples/trace-stderr-output.mjs | 2 +- examples/verify-fix-both-runtimes.mjs | 2 +- examples/verify-issue12-fixed.mjs | 2 +- examples/which-command-common-commands.mjs | 2 +- examples/which-command-gh-test.mjs | 2 +- examples/which-command-nonexistent.mjs | 2 +- examples/which-command-system-comparison.mjs | 2 +- examples/working-example.mjs | 2 +- examples/working-stdin-examples.mjs | 2 +- examples/working-streaming-demo.mjs | 2 +- {src => js/src}/$.mjs | 0 {src => js/src}/$.utils.mjs | 0 {src => js/src}/commands/$.basename.mjs | 0 {src => js/src}/commands/$.cat.mjs | 0 {src => js/src}/commands/$.cd.mjs | 0 {src => js/src}/commands/$.cp.mjs | 0 {src => js/src}/commands/$.dirname.mjs | 0 {src => js/src}/commands/$.echo.mjs | 0 {src => js/src}/commands/$.env.mjs | 0 {src => js/src}/commands/$.exit.mjs | 0 {src => js/src}/commands/$.false.mjs | 0 {src => js/src}/commands/$.ls.mjs | 0 {src => js/src}/commands/$.mkdir.mjs | 0 {src => js/src}/commands/$.mv.mjs | 0 {src => js/src}/commands/$.pwd.mjs | 0 {src => js/src}/commands/$.rm.mjs | 0 {src => js/src}/commands/$.seq.mjs | 0 {src => js/src}/commands/$.sleep.mjs | 0 {src => js/src}/commands/$.test.mjs | 0 {src => js/src}/commands/$.touch.mjs | 0 {src => js/src}/commands/$.true.mjs | 0 {src => js/src}/commands/$.which.mjs | 0 {src => js/src}/commands/$.yes.mjs | 0 {src => js/src}/shell-parser.mjs | 0 package.json | 7 +- rust/Cargo.toml | 47 ++ rust/src/commands/basename.rs | 69 +++ rust/src/commands/cat.rs | 123 ++++ rust/src/commands/cd.rs | 67 +++ rust/src/commands/cp.rs | 187 ++++++ rust/src/commands/dirname.rs | 57 ++ rust/src/commands/echo.rs | 33 + rust/src/commands/env.rs | 33 + rust/src/commands/exit.rs | 36 ++ rust/src/commands/false.rs | 24 + rust/src/commands/ls.rs | 182 ++++++ rust/src/commands/mkdir.rs | 98 +++ rust/src/commands/mod.rs | 188 ++++++ rust/src/commands/mv.rs | 180 ++++++ rust/src/commands/pwd.rs | 28 + rust/src/commands/rm.rs | 150 +++++ rust/src/commands/seq.rs | 179 ++++++ rust/src/commands/sleep.rs | 97 +++ rust/src/commands/test.rs | 204 +++++++ rust/src/commands/touch.rs | 99 +++ rust/src/commands/true.rs | 24 + rust/src/commands/which.rs | 68 +++ rust/src/commands/yes.rs | 99 +++ rust/src/lib.rs | 487 +++++++++++++++ rust/src/main.rs | 37 ++ rust/src/shell_parser.rs | 565 ++++++++++++++++++ rust/src/utils.rs | 335 +++++++++++ tests/$.features.test.mjs | 2 +- tests/$.test.mjs | 2 +- tests/builtin-commands.test.mjs | 4 +- tests/bun-shell-path-fix.test.mjs | 2 +- tests/cd-virtual-command.test.mjs | 2 +- tests/cleanup-verification.test.mjs | 2 +- tests/ctrl-c-baseline.test.mjs | 2 +- tests/ctrl-c-basic.test.mjs | 2 +- tests/ctrl-c-library.test.mjs | 4 +- tests/ctrl-c-signal.test.mjs | 10 +- tests/examples.test.mjs | 4 +- tests/gh-commands.test.mjs | 2 +- tests/gh-gist-operations.test.mjs | 2 +- tests/git-gh-cd.test.mjs | 2 +- tests/interactive-option.test.mjs | 2 +- tests/interactive-streaming.test.mjs | 2 +- tests/issue-135-final.test.mjs | 2 +- tests/jq-color-behavior.test.mjs | 2 +- tests/jq.test.mjs | 4 +- tests/options-examples.test.mjs | 2 +- tests/options-syntax.test.mjs | 2 +- tests/path-interpolation.test.mjs | 2 +- tests/pipe.test.mjs | 2 +- tests/raw-function.test.mjs | 2 +- tests/readme-examples.test.mjs | 2 +- tests/resource-cleanup-internals.test.mjs | 2 +- tests/shell-settings.test.mjs | 2 +- tests/sigint-cleanup-isolated.test.mjs | 2 +- tests/sigint-cleanup.test.mjs | 2 +- tests/start-run-edge-cases.test.mjs | 2 +- tests/start-run-options.test.mjs | 2 +- tests/stderr-output-handling.test.mjs | 2 +- tests/streaming-interfaces.test.mjs | 2 +- tests/sync.test.mjs | 2 +- tests/system-pipe.test.mjs | 2 +- tests/test-cleanup.mjs | 2 +- tests/test-helper-fixed.mjs | 2 +- tests/test-helper-v2.mjs | 2 +- tests/test-helper.mjs | 2 +- tests/text-method.test.mjs | 2 +- tests/virtual.test.mjs | 2 +- tests/yes-command-cleanup.test.mjs | 6 +- 451 files changed, 4342 insertions(+), 414 deletions(-) create mode 100644 docs/case-studies/issue-146/README.md rename {src => js/src}/$.mjs (100%) rename {src => js/src}/$.utils.mjs (100%) rename {src => js/src}/commands/$.basename.mjs (100%) rename {src => js/src}/commands/$.cat.mjs (100%) rename {src => js/src}/commands/$.cd.mjs (100%) rename {src => js/src}/commands/$.cp.mjs (100%) rename {src => js/src}/commands/$.dirname.mjs (100%) rename {src => js/src}/commands/$.echo.mjs (100%) rename {src => js/src}/commands/$.env.mjs (100%) rename {src => js/src}/commands/$.exit.mjs (100%) rename {src => js/src}/commands/$.false.mjs (100%) rename {src => js/src}/commands/$.ls.mjs (100%) rename {src => js/src}/commands/$.mkdir.mjs (100%) rename {src => js/src}/commands/$.mv.mjs (100%) rename {src => js/src}/commands/$.pwd.mjs (100%) rename {src => js/src}/commands/$.rm.mjs (100%) rename {src => js/src}/commands/$.seq.mjs (100%) rename {src => js/src}/commands/$.sleep.mjs (100%) rename {src => js/src}/commands/$.test.mjs (100%) rename {src => js/src}/commands/$.touch.mjs (100%) rename {src => js/src}/commands/$.true.mjs (100%) rename {src => js/src}/commands/$.which.mjs (100%) rename {src => js/src}/commands/$.yes.mjs (100%) rename {src => js/src}/shell-parser.mjs (100%) create mode 100644 rust/Cargo.toml create mode 100644 rust/src/commands/basename.rs create mode 100644 rust/src/commands/cat.rs create mode 100644 rust/src/commands/cd.rs create mode 100644 rust/src/commands/cp.rs create mode 100644 rust/src/commands/dirname.rs create mode 100644 rust/src/commands/echo.rs create mode 100644 rust/src/commands/env.rs create mode 100644 rust/src/commands/exit.rs create mode 100644 rust/src/commands/false.rs create mode 100644 rust/src/commands/ls.rs create mode 100644 rust/src/commands/mkdir.rs create mode 100644 rust/src/commands/mod.rs create mode 100644 rust/src/commands/mv.rs create mode 100644 rust/src/commands/pwd.rs create mode 100644 rust/src/commands/rm.rs create mode 100644 rust/src/commands/seq.rs create mode 100644 rust/src/commands/sleep.rs create mode 100644 rust/src/commands/test.rs create mode 100644 rust/src/commands/touch.rs create mode 100644 rust/src/commands/true.rs create mode 100644 rust/src/commands/which.rs create mode 100644 rust/src/commands/yes.rs create mode 100644 rust/src/lib.rs create mode 100644 rust/src/main.rs create mode 100644 rust/src/shell_parser.rs create mode 100644 rust/src/utils.rs diff --git a/claude-profiles.mjs b/claude-profiles.mjs index 95b89e0..b2fb02f 100755 --- a/claude-profiles.mjs +++ b/claude-profiles.mjs @@ -14,7 +14,7 @@ * - Verbose logging and file logging support */ -import { $ } from './src/$.mjs'; +import { $ } from './js/src/$.mjs'; import fs, { createWriteStream, promises as fsPromises } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/docs/case-studies/issue-146/README.md b/docs/case-studies/issue-146/README.md new file mode 100644 index 0000000..9b6c381 --- /dev/null +++ b/docs/case-studies/issue-146/README.md @@ -0,0 +1,231 @@ +# Case Study: JavaScript to Rust Translation (Issue #146) + +## Summary + +This document provides a comprehensive analysis of the process, challenges, and lessons learned from translating the command-stream JavaScript library to Rust. + +## Project Overview + +### Original JavaScript Codebase + +- **Main file**: `src/$.mjs` (~6,765 lines) +- **Shell parser**: `src/shell-parser.mjs` (~403 lines) +- **Utilities**: `src/$.utils.mjs` (~101 lines) +- **Virtual commands**: 21 command files in `src/commands/` +- **Total**: ~8,400 lines of JavaScript + +### Rust Translation + +- **Main library**: `rust/src/lib.rs` +- **Shell parser**: `rust/src/shell_parser.rs` +- **Utilities**: `rust/src/utils.rs` +- **Virtual commands**: 21 command modules in `rust/src/commands/` + +## Timeline of Development + +### Phase 1: Code Organization + +1. Created `js/` folder structure to house JavaScript code +2. Updated `package.json` to point to new `js/src/` location +3. Updated all import statements in tests and examples + +### Phase 2: Rust Project Setup + +1. Created `rust/` folder with Cargo.toml +2. Defined dependencies: + - `tokio` for async runtime + - `which` for command lookup + - `nix` for Unix signal handling + - `regex` for pattern matching + - `chrono` for timestamps + - `filetime` for file timestamp operations + +### Phase 3: Core Translation + +1. Translated shell parser (tokenizer, parser, AST types) +2. Translated utilities (tracing, command results, ANSI handling) +3. Translated main library (ProcessRunner, shell detection) +4. Translated all 21 virtual commands + +## Key Translation Patterns + +### 1. JavaScript Async to Rust Async + +**JavaScript:** +```javascript +async function sleep({ args, abortSignal }) { + const seconds = parseFloat(args[0] || 0); + await new Promise(resolve => setTimeout(resolve, seconds * 1000)); + return { stdout: '', code: 0 }; +} +``` + +**Rust:** +```rust +pub async fn sleep(ctx: CommandContext) -> CommandResult { + let seconds: f64 = ctx.args.first() + .and_then(|s| s.parse().ok()) + .unwrap_or(0.0); + + tokio::time::sleep(Duration::from_secs_f64(seconds)).await; + CommandResult::success_empty() +} +``` + +### 2. JavaScript Object Literals to Rust Structs + +**JavaScript:** +```javascript +const result = { + stdout: output, + stderr: '', + code: 0, + async text() { return this.stdout; } +}; +``` + +**Rust:** +```rust +#[derive(Debug, Clone)] +pub struct CommandResult { + pub stdout: String, + pub stderr: String, + pub code: i32, +} + +impl CommandResult { + pub fn success(stdout: impl Into) -> Self { + CommandResult { + stdout: stdout.into(), + stderr: String::new(), + code: 0, + } + } +} +``` + +### 3. JavaScript Closures to Rust Trait Objects + +**JavaScript:** +```javascript +function trace(category, messageOrFunc) { + const message = typeof messageOrFunc === 'function' + ? messageOrFunc() + : messageOrFunc; + console.error(`[TRACE] [${category}] ${message}`); +} +``` + +**Rust:** +```rust +pub fn trace_lazy(category: &str, message_fn: F) +where + F: FnOnce() -> String, +{ + if !is_trace_enabled() { + return; + } + trace(category, &message_fn()); +} +``` + +### 4. JavaScript Error Handling to Rust Result Types + +**JavaScript:** +```javascript +try { + const content = fs.readFileSync(path, 'utf8'); + return { stdout: content, code: 0 }; +} catch (error) { + if (error.code === 'ENOENT') { + return { stderr: `cat: ${file}: No such file or directory`, code: 1 }; + } + throw error; +} +``` + +**Rust:** +```rust +match fs::read_to_string(&path) { + Ok(content) => CommandResult::success(content), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + CommandResult::error(format!("cat: {}: No such file or directory\n", file)) + } + Err(e) => CommandResult::error(format!("cat: {}: {}\n", file, e)), +} +``` + +## Challenges Encountered + +### 1. Tagged Template Literals + +JavaScript's tagged template literal syntax `$\`echo hello\`` has no direct Rust equivalent. We implemented the `$()` function as a regular function call instead. + +### 2. Event Emitter Pattern + +JavaScript's EventEmitter pattern required translation to Rust's channel-based communication using `tokio::sync::mpsc`. + +### 3. Process Group Handling + +Unix process group management differs between Node.js and Rust. We used the `nix` crate for proper signal handling. + +### 4. Async Iterator Pattern + +JavaScript's `for await (const chunk of stream)` was translated to Rust's async stream patterns using channels. + +## Lessons Learned + +### 1. Type Safety Benefits + +Rust's type system caught several edge cases that existed in the JavaScript code: +- Null/undefined handling became explicit with `Option` +- Error handling became explicit with `Result` +- String encoding issues were caught at compile time + +### 2. Memory Management + +Rust's ownership model required explicit decisions about: +- When to clone vs borrow data +- Lifetime of process handles +- Cleanup of resources on cancellation + +### 3. Cross-Platform Considerations + +Both JavaScript and Rust require platform-specific code for: +- Shell detection (Windows vs Unix) +- Signal handling (SIGINT, SIGTERM) +- File permissions + +### 4. Testing Strategy + +Unit tests were essential for: +- Verifying parity with JavaScript behavior +- Catching edge cases early +- Documenting expected behavior + +## Architecture Comparison + +| Component | JavaScript | Rust | +|-----------|------------|------| +| Async Runtime | Node.js/Bun event loop | Tokio | +| Process Spawn | child_process.spawn | tokio::process::Command | +| Channels | EventEmitter | mpsc channels | +| Error Handling | try/catch | Result | +| String Handling | UTF-16 strings | UTF-8 String | +| File I/O | fs module | std::fs | +| Signal Handling | process.on('SIGINT') | tokio::signal | + +## Future Improvements + +1. **Streaming Improvements**: Implement async iterator traits for better streaming support +2. **Error Types**: Create more specific error types for different failure modes +3. **Performance**: Benchmark and optimize critical paths +4. **Platform Support**: Add more Windows-specific implementations +5. **CI/CD**: Add Rust builds to existing CI pipeline + +## References + +- Original Issue: https://github.com/link-foundation/command-stream/issues/146 +- Pull Request: https://github.com/link-foundation/command-stream/pull/147 +- Rust Book: https://doc.rust-lang.org/book/ +- Tokio Documentation: https://tokio.rs/ diff --git a/examples/01-basic-streaming.mjs b/examples/01-basic-streaming.mjs index 2b44c36..16a9f8d 100755 --- a/examples/01-basic-streaming.mjs +++ b/examples/01-basic-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Basic streaming example - shows real-time chunk processing -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; let chunkCount = 0; diff --git a/examples/02-async-iterator.mjs b/examples/02-async-iterator.mjs index ea855f5..323069b 100755 --- a/examples/02-async-iterator.mjs +++ b/examples/02-async-iterator.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Async iterator pattern - process chunks as they arrive -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Using async iteration:'); diff --git a/examples/03-file-and-console.mjs b/examples/03-file-and-console.mjs index af5c981..a0bd6b6 100755 --- a/examples/03-file-and-console.mjs +++ b/examples/03-file-and-console.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Stream to both console and file simultaneously -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { appendFileSync } from 'fs'; const logFile = 'stream-output.log'; diff --git a/examples/04-claude-jq-pipe.mjs b/examples/04-claude-jq-pipe.mjs index c3de8ef..12290f7 100755 --- a/examples/04-claude-jq-pipe.mjs +++ b/examples/04-claude-jq-pipe.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Claude output piped to jq for JSON processing -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Claude โ†’ jq pipeline:'); diff --git a/examples/README-examples.mjs b/examples/README-examples.mjs index 88b50fb..9fbf73a 100755 --- a/examples/README-examples.mjs +++ b/examples/README-examples.mjs @@ -4,7 +4,7 @@ * Examples for README - using manual timing approach until async streams are perfected */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('๐Ÿ“– README Examples - Streaming Interfaces'); console.log('='.repeat(50)); diff --git a/examples/ansi-default-preserved.mjs b/examples/ansi-default-preserved.mjs index 993a046..765a9c5 100755 --- a/examples/ansi-default-preserved.mjs +++ b/examples/ansi-default-preserved.mjs @@ -2,7 +2,7 @@ // Default behavior (ANSI preserved) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Default behavior (ANSI preserved):'); const colorCommand = diff --git a/examples/ansi-global-config.mjs b/examples/ansi-global-config.mjs index 15c223b..61dd615 100755 --- a/examples/ansi-global-config.mjs +++ b/examples/ansi-global-config.mjs @@ -2,7 +2,7 @@ // Global configuration to disable ANSI preservation -import { $, configureAnsi } from '../src/$.mjs'; +import { $, configureAnsi } from '../js/src/$.mjs'; console.log('Global configuration to disable ANSI preservation:'); configureAnsi({ preserveAnsi: false }); diff --git a/examples/ansi-reset-default.mjs b/examples/ansi-reset-default.mjs index 49cc6d0..1ebb020 100755 --- a/examples/ansi-reset-default.mjs +++ b/examples/ansi-reset-default.mjs @@ -2,7 +2,7 @@ // Reset to default (preserve ANSI) -import { $, configureAnsi } from '../src/$.mjs'; +import { $, configureAnsi } from '../js/src/$.mjs'; console.log('Reset to default (preserve ANSI):'); configureAnsi({ preserveAnsi: true }); diff --git a/examples/ansi-strip-utils.mjs b/examples/ansi-strip-utils.mjs index 1c97f4c..5715fda 100755 --- a/examples/ansi-strip-utils.mjs +++ b/examples/ansi-strip-utils.mjs @@ -2,7 +2,7 @@ // Using AnsiUtils to strip ANSI from result -import { $, AnsiUtils } from '../src/$.mjs'; +import { $, AnsiUtils } from '../js/src/$.mjs'; console.log('Using AnsiUtils to strip ANSI from result:'); const colorCommand = diff --git a/examples/capture-mirror-comparison.mjs b/examples/capture-mirror-comparison.mjs index a5f172b..9c01336 100755 --- a/examples/capture-mirror-comparison.mjs +++ b/examples/capture-mirror-comparison.mjs @@ -2,7 +2,7 @@ // Summary comparison of all capture/mirror combinations -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('๐Ÿ“Š Capture/Mirror Combinations Summary:'); console.log('โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”'); diff --git a/examples/capture-mirror-default.mjs b/examples/capture-mirror-default.mjs index 466785d..b09812f 100755 --- a/examples/capture-mirror-default.mjs +++ b/examples/capture-mirror-default.mjs @@ -2,7 +2,7 @@ // Default behavior (capture: true, mirror: true) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Default behavior (capture: true, mirror: true):'); console.log('await $`echo "Default: both enabled"`'); diff --git a/examples/capture-mirror-performance.mjs b/examples/capture-mirror-performance.mjs index f047bda..3c0f0e5 100755 --- a/examples/capture-mirror-performance.mjs +++ b/examples/capture-mirror-performance.mjs @@ -2,7 +2,7 @@ // capture: false, mirror: false (maximum performance) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('capture: false, mirror: false:'); console.log( diff --git a/examples/capture-mirror-show-only.mjs b/examples/capture-mirror-show-only.mjs index 6e85b78..eae1e02 100755 --- a/examples/capture-mirror-show-only.mjs +++ b/examples/capture-mirror-show-only.mjs @@ -2,7 +2,7 @@ // capture: false, mirror: true (just show output) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('capture: false, mirror: true:'); console.log( diff --git a/examples/capture-mirror-silent-processing.mjs b/examples/capture-mirror-silent-processing.mjs index 5d961ff..72daac4 100755 --- a/examples/capture-mirror-silent-processing.mjs +++ b/examples/capture-mirror-silent-processing.mjs @@ -2,7 +2,7 @@ // capture: true, mirror: false (silent data processing) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('capture: true, mirror: false:'); console.log( diff --git a/examples/ci-debug-baseline-vs-library.mjs b/examples/ci-debug-baseline-vs-library.mjs index 53d1213..7575967 100755 --- a/examples/ci-debug-baseline-vs-library.mjs +++ b/examples/ci-debug-baseline-vs-library.mjs @@ -10,7 +10,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing baseline vs library behavior'); diff --git a/examples/ci-debug-es-module-loading.mjs b/examples/ci-debug-es-module-loading.mjs index f97d86b..1bfcbba 100755 --- a/examples/ci-debug-es-module-loading.mjs +++ b/examples/ci-debug-es-module-loading.mjs @@ -10,7 +10,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing ES module loading in child processes'); @@ -19,7 +19,7 @@ async function testDirectESModule() { console.log('\nTEST 1: Direct ES module import in child process'); const script = ` - import { $ } from '../src/$.mjs'; + import { $ } from '../js/src/$.mjs'; console.log('Module loaded successfully'); const result = await $\`echo "ES module test"\`; console.log('Result:', result.stdout); diff --git a/examples/ci-debug-signal-handling.mjs b/examples/ci-debug-signal-handling.mjs index d8136f0..f47bd0d 100755 --- a/examples/ci-debug-signal-handling.mjs +++ b/examples/ci-debug-signal-handling.mjs @@ -10,7 +10,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing signal handling in CI environment'); diff --git a/examples/ci-debug-stdout-buffering.mjs b/examples/ci-debug-stdout-buffering.mjs index 2f6bbbc..18512ce 100755 --- a/examples/ci-debug-stdout-buffering.mjs +++ b/examples/ci-debug-stdout-buffering.mjs @@ -10,7 +10,7 @@ * Solution: Force stdout flush in non-TTY environments. */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing stdout buffering in CI environment'); console.log('Is TTY?', process.stdout.isTTY); diff --git a/examples/ci-debug-test-timeouts.mjs b/examples/ci-debug-test-timeouts.mjs index ccf10e7..1d75a4a 100755 --- a/examples/ci-debug-test-timeouts.mjs +++ b/examples/ci-debug-test-timeouts.mjs @@ -10,7 +10,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing timeout handling strategies'); diff --git a/examples/claude-exact-file-output.mjs b/examples/claude-exact-file-output.mjs index c13a7e2..20744aa 100755 --- a/examples/claude-exact-file-output.mjs +++ b/examples/claude-exact-file-output.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { appendFileSync } from 'fs'; const claude = 'claude'; diff --git a/examples/claude-exact-jq.mjs b/examples/claude-exact-jq.mjs index 5d5caa7..1bd832d 100755 --- a/examples/claude-exact-jq.mjs +++ b/examples/claude-exact-jq.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const claude = 'claude'; console.log('๐Ÿค– Claude โ†’ jq streaming pipeline'); diff --git a/examples/claude-exact-streaming.mjs b/examples/claude-exact-streaming.mjs index 1e4c29c..01dd473 100755 --- a/examples/claude-exact-streaming.mjs +++ b/examples/claude-exact-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const claude = 'claude'; console.log('๐Ÿค– Claude exact streaming example'); diff --git a/examples/claude-jq-pipeline.mjs b/examples/claude-jq-pipeline.mjs index 6d12f6c..537925a 100644 --- a/examples/claude-jq-pipeline.mjs +++ b/examples/claude-jq-pipeline.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('๐Ÿค– Claude โ†’ jq streaming pipeline'); diff --git a/examples/claude-streaming-basic.mjs b/examples/claude-streaming-basic.mjs index 1eec32c..2daf974 100755 --- a/examples/claude-streaming-basic.mjs +++ b/examples/claude-streaming-basic.mjs @@ -9,7 +9,7 @@ * 3. Both console display and file writing simultaneously */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { writeFileSync, appendFileSync, existsSync } from 'fs'; // Claude command - using a prompt that should generate multiple chunks diff --git a/examples/claude-streaming-demo.mjs b/examples/claude-streaming-demo.mjs index c085012..a706071 100755 --- a/examples/claude-streaming-demo.mjs +++ b/examples/claude-streaming-demo.mjs @@ -10,7 +10,7 @@ * 4. Handling of both stdout and stderr */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { writeFileSync, appendFileSync, existsSync } from 'fs'; // We'll use a command that produces output over time to simulate streaming diff --git a/examples/claude-streaming-final.mjs b/examples/claude-streaming-final.mjs index 3f6a776..41ab255 100644 --- a/examples/claude-streaming-final.mjs +++ b/examples/claude-streaming-final.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { appendFileSync } from 'fs'; console.log('๐Ÿค– Claude streaming example'); diff --git a/examples/cleanup-verification-test.mjs b/examples/cleanup-verification-test.mjs index da066f0..252a1d3 100755 --- a/examples/cleanup-verification-test.mjs +++ b/examples/cleanup-verification-test.mjs @@ -2,7 +2,7 @@ // Test comprehensive resource cleanup // This runs in a subprocess for isolation -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/colors-buffer-processing.mjs b/examples/colors-buffer-processing.mjs index 536368f..233c7be 100755 --- a/examples/colors-buffer-processing.mjs +++ b/examples/colors-buffer-processing.mjs @@ -2,7 +2,7 @@ // Using AnsiUtils.cleanForProcessing() for Buffer data -import { $, AnsiUtils } from '../src/$.mjs'; +import { $, AnsiUtils } from '../js/src/$.mjs'; console.log('Using AnsiUtils.cleanForProcessing() for Buffer data:'); const colorCommand = diff --git a/examples/colors-default-preserved.mjs b/examples/colors-default-preserved.mjs index 965340c..49da063 100755 --- a/examples/colors-default-preserved.mjs +++ b/examples/colors-default-preserved.mjs @@ -2,7 +2,7 @@ // Default behavior (ANSI colors preserved) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Default behavior (ANSI colors preserved):'); const colorCommand = diff --git a/examples/colors-per-command-config.mjs b/examples/colors-per-command-config.mjs index 65d5d2b..955c158 100755 --- a/examples/colors-per-command-config.mjs +++ b/examples/colors-per-command-config.mjs @@ -2,7 +2,7 @@ // Per-command ANSI configuration -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Per-command ANSI configuration:'); const colorCommand = diff --git a/examples/colors-strip-ansi.mjs b/examples/colors-strip-ansi.mjs index 3f5aadd..a21d3e4 100755 --- a/examples/colors-strip-ansi.mjs +++ b/examples/colors-strip-ansi.mjs @@ -2,7 +2,7 @@ // Using AnsiUtils.stripAnsi() for clean data processing -import { $, AnsiUtils } from '../src/$.mjs'; +import { $, AnsiUtils } from '../js/src/$.mjs'; console.log('Using AnsiUtils.stripAnsi() for clean data processing:'); const colorCommand = diff --git a/examples/commandstream-jq.mjs b/examples/commandstream-jq.mjs index 3bfda4b..d6f4ba7 100644 --- a/examples/commandstream-jq.mjs +++ b/examples/commandstream-jq.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { appendFileSync } from 'fs'; console.log('๐Ÿค– Command-stream: Claude โ†’ jq pipeline'); diff --git a/examples/commandstream-working.mjs b/examples/commandstream-working.mjs index b5d39f3..043dade 100644 --- a/examples/commandstream-working.mjs +++ b/examples/commandstream-working.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('๐Ÿค– Command-stream: Claude with stdin'); diff --git a/examples/comprehensive-streams-demo.mjs b/examples/comprehensive-streams-demo.mjs index 8de5e52..52dfd15 100755 --- a/examples/comprehensive-streams-demo.mjs +++ b/examples/comprehensive-streams-demo.mjs @@ -5,7 +5,7 @@ * Shows: streams.stdin, streams.stdout, streams.stderr, buffers, strings, kill() */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('๐Ÿš€ command-stream: Comprehensive Streaming Demo'); console.log('='.repeat(50)); diff --git a/examples/ctrl-c-concurrent-processes.mjs b/examples/ctrl-c-concurrent-processes.mjs index b20a50b..664dde5 100755 --- a/examples/ctrl-c-concurrent-processes.mjs +++ b/examples/ctrl-c-concurrent-processes.mjs @@ -2,7 +2,7 @@ // Multiple concurrent processes CTRL+C handling -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Multiple concurrent processes'); console.log('Starting 3 processes - press CTRL+C to interrupt all...\n'); diff --git a/examples/ctrl-c-long-running-command.mjs b/examples/ctrl-c-long-running-command.mjs index f368eec..91f4606 100755 --- a/examples/ctrl-c-long-running-command.mjs +++ b/examples/ctrl-c-long-running-command.mjs @@ -2,7 +2,7 @@ // Long-running command that can be interrupted with CTRL+C -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Long-running command (ping)'); console.log('Press CTRL+C to interrupt...\n'); diff --git a/examples/ctrl-c-real-system-command.mjs b/examples/ctrl-c-real-system-command.mjs index f9ddb0d..d8b8da0 100755 --- a/examples/ctrl-c-real-system-command.mjs +++ b/examples/ctrl-c-real-system-command.mjs @@ -2,7 +2,7 @@ // Real system command CTRL+C handling -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Real system command (ping)'); console.log('Starting ping command - press CTRL+C to interrupt...\n'); diff --git a/examples/ctrl-c-sleep-command.mjs b/examples/ctrl-c-sleep-command.mjs index 0b9c3f0..3cb8e2f 100755 --- a/examples/ctrl-c-sleep-command.mjs +++ b/examples/ctrl-c-sleep-command.mjs @@ -2,7 +2,7 @@ // Sleep command with signal handling -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Sleep command'); console.log('Press CTRL+C to interrupt the 10-second sleep...\n'); diff --git a/examples/ctrl-c-stdin-forwarding.mjs b/examples/ctrl-c-stdin-forwarding.mjs index ce9d213..d3e3199 100755 --- a/examples/ctrl-c-stdin-forwarding.mjs +++ b/examples/ctrl-c-stdin-forwarding.mjs @@ -2,7 +2,7 @@ // Command with stdin forwarding and CTRL+C handling -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Command with stdin forwarding'); console.log( diff --git a/examples/ctrl-c-virtual-command.mjs b/examples/ctrl-c-virtual-command.mjs index da9e474..0e1a845 100755 --- a/examples/ctrl-c-virtual-command.mjs +++ b/examples/ctrl-c-virtual-command.mjs @@ -2,7 +2,7 @@ // Virtual sleep command CTRL+C handling -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Virtual sleep command'); console.log('Sleeping for 30 seconds - press CTRL+C to interrupt...\n'); diff --git a/examples/debug-already-started.mjs b/examples/debug-already-started.mjs index 156d625..21702de 100755 --- a/examples/debug-already-started.mjs +++ b/examples/debug-already-started.mjs @@ -2,7 +2,7 @@ // Testing already started behavior -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing already started behavior:'); const runner = $`echo "already started"`; diff --git a/examples/debug-ansi-processing.mjs b/examples/debug-ansi-processing.mjs index b17573b..e0060ce 100755 --- a/examples/debug-ansi-processing.mjs +++ b/examples/debug-ansi-processing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, processOutput, getAnsiConfig } from '../src/$.mjs'; +import { $, processOutput, getAnsiConfig } from '../js/src/$.mjs'; console.log('=== Debug ANSI Processing ===\n'); diff --git a/examples/debug-basic-streaming.mjs b/examples/debug-basic-streaming.mjs index dde13d1..abdee1e 100755 --- a/examples/debug-basic-streaming.mjs +++ b/examples/debug-basic-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Basic Streaming Debug ==='); diff --git a/examples/debug-child-process.mjs b/examples/debug-child-process.mjs index 8638898..ae53157 100644 --- a/examples/debug-child-process.mjs +++ b/examples/debug-child-process.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function debugChildProcess() { console.log('๐Ÿ› Debugging child process creation'); diff --git a/examples/debug-child-state.mjs b/examples/debug-child-state.mjs index e3d4ebf..eb2c246 100755 --- a/examples/debug-child-state.mjs +++ b/examples/debug-child-state.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function debugChildState() { const cmd = $`cat`; diff --git a/examples/debug-chunking.mjs b/examples/debug-chunking.mjs index 82fe6b5..63ca960 100755 --- a/examples/debug-chunking.mjs +++ b/examples/debug-chunking.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const claude = 'claude'; console.log('๐Ÿ› Debug chunking test'); diff --git a/examples/debug-command-parsing.mjs b/examples/debug-command-parsing.mjs index 8f070a6..390c8d4 100644 --- a/examples/debug-command-parsing.mjs +++ b/examples/debug-command-parsing.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Debug command parsing -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-complete-consolidation.mjs b/examples/debug-complete-consolidation.mjs index 9fb88a2..7059d81 100755 --- a/examples/debug-complete-consolidation.mjs +++ b/examples/debug-complete-consolidation.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Complete Finish Method Consolidation Test ==='); diff --git a/examples/debug-echo-args.mjs b/examples/debug-echo-args.mjs index 41bd745..609d7e6 100644 --- a/examples/debug-echo-args.mjs +++ b/examples/debug-echo-args.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function debugEchoArgs() { console.log('=== Debug Echo Args ==='); diff --git a/examples/debug-emit-timing.mjs b/examples/debug-emit-timing.mjs index 58c1861..ed6c019 100755 --- a/examples/debug-emit-timing.mjs +++ b/examples/debug-emit-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Emit Timing Debug ==='); diff --git a/examples/debug-end-event.mjs b/examples/debug-end-event.mjs index 5a5c8aa..1787982 100755 --- a/examples/debug-end-event.mjs +++ b/examples/debug-end-event.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== End Event Debug ==='); diff --git a/examples/debug-errexit.mjs b/examples/debug-errexit.mjs index 0824541..77e29e6 100755 --- a/examples/debug-errexit.mjs +++ b/examples/debug-errexit.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, enableErrExit } from '../src/$.mjs'; +import { $, enableErrExit } from '../js/src/$.mjs'; console.log('=== Errexit Test ==='); diff --git a/examples/debug-event-emission.mjs b/examples/debug-event-emission.mjs index 14954d2..f7553b4 100755 --- a/examples/debug-event-emission.mjs +++ b/examples/debug-event-emission.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../src/$.mjs'; +import { $, disableVirtualCommands } from '../js/src/$.mjs'; console.log('=== Event Emission Debug ==='); diff --git a/examples/debug-event-timing.mjs b/examples/debug-event-timing.mjs index 66d14cb..60ee931 100755 --- a/examples/debug-event-timing.mjs +++ b/examples/debug-event-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../src/$.mjs'; +import { $, disableVirtualCommands } from '../js/src/$.mjs'; console.log('=== Event Timing Debug ==='); diff --git a/examples/debug-event-vs-result.mjs b/examples/debug-event-vs-result.mjs index 90a5ccb..f505b6b 100755 --- a/examples/debug-event-vs-result.mjs +++ b/examples/debug-event-vs-result.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Event vs Result Comparison ===\n'); diff --git a/examples/debug-exact-command.mjs b/examples/debug-exact-command.mjs index 93da65d..ee3a900 100755 --- a/examples/debug-exact-command.mjs +++ b/examples/debug-exact-command.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing Exact Command from jq-colors-streaming.mjs ===\n'); diff --git a/examples/debug-exact-test-scenario.mjs b/examples/debug-exact-test-scenario.mjs index 542cd50..f2d5f60 100755 --- a/examples/debug-exact-test-scenario.mjs +++ b/examples/debug-exact-test-scenario.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Exact replica of the failing test scenario -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-execution-path.mjs b/examples/debug-execution-path.mjs index 1dba77f..15d09cf 100755 --- a/examples/debug-execution-path.mjs +++ b/examples/debug-execution-path.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Debug execution path to see exactly what's happening -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode to see detailed tracing process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-exit-command.mjs b/examples/debug-exit-command.mjs index c7f69c9..75824ad 100755 --- a/examples/debug-exit-command.mjs +++ b/examples/debug-exit-command.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug the exit command specifically -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-exit-virtual.mjs b/examples/debug-exit-virtual.mjs index 3d96d10..42dfb61 100755 --- a/examples/debug-exit-virtual.mjs +++ b/examples/debug-exit-virtual.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug the virtual exit command directly -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-finish-consolidation.mjs b/examples/debug-finish-consolidation.mjs index df7e62e..5618b94 100755 --- a/examples/debug-finish-consolidation.mjs +++ b/examples/debug-finish-consolidation.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Finish Method Consolidation Test ==='); diff --git a/examples/debug-force-cleanup.mjs b/examples/debug-force-cleanup.mjs index 240d2a4..e1c7ad9 100755 --- a/examples/debug-force-cleanup.mjs +++ b/examples/debug-force-cleanup.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Test the forceCleanupAll function -import { $, forceCleanupAll } from '../src/$.mjs'; +import { $, forceCleanupAll } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-getter-basic.mjs b/examples/debug-getter-basic.mjs index 3669ec5..f4fa5b5 100755 --- a/examples/debug-getter-basic.mjs +++ b/examples/debug-getter-basic.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Basic Getter Debug ==='); diff --git a/examples/debug-getter-direct.mjs b/examples/debug-getter-direct.mjs index 042c9d7..b31d901 100755 --- a/examples/debug-getter-direct.mjs +++ b/examples/debug-getter-direct.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Direct Getter Debug ==='); diff --git a/examples/debug-getter-internals.mjs b/examples/debug-getter-internals.mjs index 6681e3a..5f1699f 100755 --- a/examples/debug-getter-internals.mjs +++ b/examples/debug-getter-internals.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../src/$.mjs'; +import { $, disableVirtualCommands } from '../js/src/$.mjs'; console.log('=== Getter Internals Debug ==='); diff --git a/examples/debug-handler-detection.mjs b/examples/debug-handler-detection.mjs index a50526d..2b90151 100755 --- a/examples/debug-handler-detection.mjs +++ b/examples/debug-handler-detection.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test the exact pattern matching used by the tests -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-idempotent-finish.mjs b/examples/debug-idempotent-finish.mjs index 7e8cc72..1fb2eaf 100755 --- a/examples/debug-idempotent-finish.mjs +++ b/examples/debug-idempotent-finish.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Idempotent Finish Method Test ==='); diff --git a/examples/debug-idempotent-kill.mjs b/examples/debug-idempotent-kill.mjs index 3a6c41f..3236b76 100755 --- a/examples/debug-idempotent-kill.mjs +++ b/examples/debug-idempotent-kill.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Idempotent Kill Test ==='); diff --git a/examples/debug-interpolation-individual.mjs b/examples/debug-interpolation-individual.mjs index b112c42..d814ef6 100644 --- a/examples/debug-interpolation-individual.mjs +++ b/examples/debug-interpolation-individual.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Individual Debugging for Quoting Issue ===\n'); diff --git a/examples/debug-interpolation-issue.mjs b/examples/debug-interpolation-issue.mjs index 7c59cf9..f10ad9e 100644 --- a/examples/debug-interpolation-issue.mjs +++ b/examples/debug-interpolation-issue.mjs @@ -5,7 +5,7 @@ // Issue: https://github.com/link-foundation/command-stream/issues/12 // Error: ENOENT: no such file or directory, posix_spawn ''/Users/konard/.claude/local/claude'' -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const claude = process.env.CLAUDE_PATH || '/Users/konard/.claude/local/claude'; diff --git a/examples/debug-jq-streaming.mjs b/examples/debug-jq-streaming.mjs index 0bad419..deccd8a 100755 --- a/examples/debug-jq-streaming.mjs +++ b/examples/debug-jq-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== JQ Streaming Debug ==='); diff --git a/examples/debug-jq-tty-colors.mjs b/examples/debug-jq-tty-colors.mjs index 018b6d7..28a882f 100644 --- a/examples/debug-jq-tty-colors.mjs +++ b/examples/debug-jq-tty-colors.mjs @@ -5,7 +5,7 @@ * This helps diagnose why the test behaves differently in different environments */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { spawn } from 'child_process'; const testJson = diff --git a/examples/debug-kill-cleanup.mjs b/examples/debug-kill-cleanup.mjs index 34f0234..3c97c8e 100755 --- a/examples/debug-kill-cleanup.mjs +++ b/examples/debug-kill-cleanup.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; function getSigintHandlerCount() { const sigintListeners = process.listeners('SIGINT'); diff --git a/examples/debug-kill-method.mjs b/examples/debug-kill-method.mjs index da7f7b1..3e51e46 100755 --- a/examples/debug-kill-method.mjs +++ b/examples/debug-kill-method.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing kill() method'); diff --git a/examples/debug-listener-interference.mjs b/examples/debug-listener-interference.mjs index 2037c20..f757a38 100755 --- a/examples/debug-listener-interference.mjs +++ b/examples/debug-listener-interference.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Listener Interference Debug ==='); diff --git a/examples/debug-listener-lifecycle.mjs b/examples/debug-listener-lifecycle.mjs index 2f689bf..a7e7c2f 100755 --- a/examples/debug-listener-lifecycle.mjs +++ b/examples/debug-listener-lifecycle.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Listener Lifecycle Debug ==='); diff --git a/examples/debug-listener-timing.mjs b/examples/debug-listener-timing.mjs index 6d006e4..4d190d0 100755 --- a/examples/debug-listener-timing.mjs +++ b/examples/debug-listener-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Listener Timing Debug ==='); diff --git a/examples/debug-listeners-property.mjs b/examples/debug-listeners-property.mjs index 0a92c88..d327020 100755 --- a/examples/debug-listeners-property.mjs +++ b/examples/debug-listeners-property.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Listeners Property Debug ==='); diff --git a/examples/debug-map-methods.mjs b/examples/debug-map-methods.mjs index 6280d97..7587468 100755 --- a/examples/debug-map-methods.mjs +++ b/examples/debug-map-methods.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Map Methods Debug ==='); diff --git a/examples/debug-not-awaited-cleanup.mjs b/examples/debug-not-awaited-cleanup.mjs index 32b0a40..9d72947 100755 --- a/examples/debug-not-awaited-cleanup.mjs +++ b/examples/debug-not-awaited-cleanup.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test the non-awaited command cleanup issue -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-off-method.mjs b/examples/debug-off-method.mjs index 4d62d21..b01eb61 100755 --- a/examples/debug-off-method.mjs +++ b/examples/debug-off-method.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Off Method Debug ==='); diff --git a/examples/debug-option-merging.mjs b/examples/debug-option-merging.mjs index e4ed533..3dcb414 100755 --- a/examples/debug-option-merging.mjs +++ b/examples/debug-option-merging.mjs @@ -2,7 +2,7 @@ // Testing option merging -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing option merging:'); const runner = $`echo "option merge test"`; diff --git a/examples/debug-options.mjs b/examples/debug-options.mjs index 729d766..4e1cccb 100644 --- a/examples/debug-options.mjs +++ b/examples/debug-options.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable trace to see what's happening process.env.COMMAND_STREAM_TRACE = 'ProcessRunner'; diff --git a/examples/debug-output.mjs b/examples/debug-output.mjs index 3ebc629..0396311 100644 --- a/examples/debug-output.mjs +++ b/examples/debug-output.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; enableVirtualCommands(); shell.verbose(false); diff --git a/examples/debug-pattern-matching.mjs b/examples/debug-pattern-matching.mjs index 882c2ea..e18f4f6 100755 --- a/examples/debug-pattern-matching.mjs +++ b/examples/debug-pattern-matching.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test pattern matching in signal handler detection -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-pipeline-cat.mjs b/examples/debug-pipeline-cat.mjs index 8c211ee..4f5c46d 100755 --- a/examples/debug-pipeline-cat.mjs +++ b/examples/debug-pipeline-cat.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Debug pipeline with cat -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-pipeline-cleanup.mjs b/examples/debug-pipeline-cleanup.mjs index 8aad787..41973df 100755 --- a/examples/debug-pipeline-cleanup.mjs +++ b/examples/debug-pipeline-cleanup.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test pipeline cleanup issues -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-pipeline-error-detailed.mjs b/examples/debug-pipeline-error-detailed.mjs index 34863c3..d63ac01 100755 --- a/examples/debug-pipeline-error-detailed.mjs +++ b/examples/debug-pipeline-error-detailed.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Detailed debug script for pipeline error cleanup -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode for tracing process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-pipeline-error.mjs b/examples/debug-pipeline-error.mjs index 00a5f26..7db74ec 100755 --- a/examples/debug-pipeline-error.mjs +++ b/examples/debug-pipeline-error.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test the specific pipeline error scenario -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-pipeline-issue.mjs b/examples/debug-pipeline-issue.mjs index 3a0bba3..8846ecc 100755 --- a/examples/debug-pipeline-issue.mjs +++ b/examples/debug-pipeline-issue.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Pipeline Debug ===\n'); diff --git a/examples/debug-pipeline-method.mjs b/examples/debug-pipeline-method.mjs index 7638e29..0ec05f3 100755 --- a/examples/debug-pipeline-method.mjs +++ b/examples/debug-pipeline-method.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Debug Which Pipeline Method is Used ===\n'); diff --git a/examples/debug-pipeline-stream.mjs b/examples/debug-pipeline-stream.mjs index 78925c0..4485ab8 100755 --- a/examples/debug-pipeline-stream.mjs +++ b/examples/debug-pipeline-stream.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Pipeline Stream Debug ==='); diff --git a/examples/debug-pipeline.mjs b/examples/debug-pipeline.mjs index 4c93986..12b39cc 100755 --- a/examples/debug-pipeline.mjs +++ b/examples/debug-pipeline.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Debug Pipeline Selection ===\n'); diff --git a/examples/debug-process-exit-trace.mjs b/examples/debug-process-exit-trace.mjs index 48c02ce..60e9baa 100755 --- a/examples/debug-process-exit-trace.mjs +++ b/examples/debug-process-exit-trace.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to trace process.exit calls -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-process-path.mjs b/examples/debug-process-path.mjs index 1b67ae2..09043b3 100755 --- a/examples/debug-process-path.mjs +++ b/examples/debug-process-path.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Process Path Debug ==='); diff --git a/examples/debug-property-check.mjs b/examples/debug-property-check.mjs index e95c3eb..8dca19f 100755 --- a/examples/debug-property-check.mjs +++ b/examples/debug-property-check.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Property Check Debug ==='); diff --git a/examples/debug-resource-cleanup.mjs b/examples/debug-resource-cleanup.mjs index b0b2561..f9547cb 100755 --- a/examples/debug-resource-cleanup.mjs +++ b/examples/debug-resource-cleanup.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test resource cleanup behavior -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-sigint-child-handler.mjs b/examples/debug-sigint-child-handler.mjs index b498dcf..cca7cb1 100755 --- a/examples/debug-sigint-child-handler.mjs +++ b/examples/debug-sigint-child-handler.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test SIGINT handler interaction -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-sigint-forwarding.mjs b/examples/debug-sigint-forwarding.mjs index d29aa3c..6d54f80 100755 --- a/examples/debug-sigint-forwarding.mjs +++ b/examples/debug-sigint-forwarding.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test SIGINT forwarding behavior -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-sigint-handler-install.mjs b/examples/debug-sigint-handler-install.mjs index 3e187d7..68116a5 100755 --- a/examples/debug-sigint-handler-install.mjs +++ b/examples/debug-sigint-handler-install.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to trace SIGINT handler installation and removal -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-sigint-handler-order.mjs b/examples/debug-sigint-handler-order.mjs index 9372280..c933d9f 100755 --- a/examples/debug-sigint-handler-order.mjs +++ b/examples/debug-sigint-handler-order.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test SIGINT handler order and execution -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-sigint-listeners.mjs b/examples/debug-sigint-listeners.mjs index 3ab05f5..6d022f4 100755 --- a/examples/debug-sigint-listeners.mjs +++ b/examples/debug-sigint-listeners.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== SIGINT Listeners Debug ==='); diff --git a/examples/debug-sigint-start-pattern.mjs b/examples/debug-sigint-start-pattern.mjs index a885b6e..66e13a8 100755 --- a/examples/debug-sigint-start-pattern.mjs +++ b/examples/debug-sigint-start-pattern.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== SIGINT Listeners Start Pattern Debug ==='); diff --git a/examples/debug-sigint-timer.mjs b/examples/debug-sigint-timer.mjs index a9f680b..734a498 100755 --- a/examples/debug-sigint-timer.mjs +++ b/examples/debug-sigint-timer.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to see if our timer fix is working -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/debug-simple-command.mjs b/examples/debug-simple-command.mjs index a40f952..ffab7ae 100644 --- a/examples/debug-simple-command.mjs +++ b/examples/debug-simple-command.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function debugSimpleCommand() { console.log('๐Ÿ› Testing with a simple non-builtin command'); diff --git a/examples/debug-simple-getter.mjs b/examples/debug-simple-getter.mjs index c07fdc6..4d4ce09 100755 --- a/examples/debug-simple-getter.mjs +++ b/examples/debug-simple-getter.mjs @@ -16,7 +16,7 @@ console.log('TestClass stdout:', test.stdout); console.log('Should be null:', test.stdout === null); // Now test with actual ProcessRunner -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const cmd = $`echo "test"`; console.log('ProcessRunner stdout:', cmd.stdout); diff --git a/examples/debug-simple.mjs b/examples/debug-simple.mjs index fd5f55f..ee0896e 100755 --- a/examples/debug-simple.mjs +++ b/examples/debug-simple.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, getAnsiConfig } from '../src/$.mjs'; +import { $, getAnsiConfig } from '../js/src/$.mjs'; console.log('=== Simple ANSI Debug ===\n'); diff --git a/examples/debug-simplified-finished.mjs b/examples/debug-simplified-finished.mjs index f1fd2b2..eef6dc3 100755 --- a/examples/debug-simplified-finished.mjs +++ b/examples/debug-simplified-finished.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Simplified Finished Field Test ==='); diff --git a/examples/debug-stack-overflow.mjs b/examples/debug-stack-overflow.mjs index 8154082..07cacb0 100644 --- a/examples/debug-stack-overflow.mjs +++ b/examples/debug-stack-overflow.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function debugStackOverflow() { console.log('Testing simple echo command...'); diff --git a/examples/debug-stdin-simple.mjs b/examples/debug-stdin-simple.mjs index 9c70305..b0c7309 100755 --- a/examples/debug-stdin-simple.mjs +++ b/examples/debug-stdin-simple.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Debug: Simple stdin test ==='); diff --git a/examples/debug-stdin.mjs b/examples/debug-stdin.mjs index cef39ea..21c4af9 100644 --- a/examples/debug-stdin.mjs +++ b/examples/debug-stdin.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function debugStdin() { console.log('๐Ÿ› Debugging stdin streams'); diff --git a/examples/debug-stream-emitter-isolated.mjs b/examples/debug-stream-emitter-isolated.mjs index f677c7e..4ea8ce3 100755 --- a/examples/debug-stream-emitter-isolated.mjs +++ b/examples/debug-stream-emitter-isolated.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Isolated StreamEmitter Debug ==='); diff --git a/examples/debug-stream-emitter.mjs b/examples/debug-stream-emitter.mjs index cbbd102..b960433 100755 --- a/examples/debug-stream-emitter.mjs +++ b/examples/debug-stream-emitter.mjs @@ -2,7 +2,7 @@ process.env.COMMAND_STREAM_VERBOSE = 'true'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== StreamEmitter Debug ==='); diff --git a/examples/debug-stream-events.mjs b/examples/debug-stream-events.mjs index 0936c68..8f9b05f 100755 --- a/examples/debug-stream-events.mjs +++ b/examples/debug-stream-events.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Stream Events Debug ==='); diff --git a/examples/debug-stream-generator.mjs b/examples/debug-stream-generator.mjs index 4abdde5..1bde6d7 100755 --- a/examples/debug-stream-generator.mjs +++ b/examples/debug-stream-generator.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Stream Generator Debug ==='); diff --git a/examples/debug-stream-getter-issue.mjs b/examples/debug-stream-getter-issue.mjs index 76df5fe..7cbbdd4 100755 --- a/examples/debug-stream-getter-issue.mjs +++ b/examples/debug-stream-getter-issue.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../src/$.mjs'; +import { $, disableVirtualCommands } from '../js/src/$.mjs'; console.log('=== Stream Getter Issue Debug ==='); diff --git a/examples/debug-stream-getter.mjs b/examples/debug-stream-getter.mjs index eae8e02..3fd0fce 100755 --- a/examples/debug-stream-getter.mjs +++ b/examples/debug-stream-getter.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../src/$.mjs'; +import { $, disableVirtualCommands } from '../js/src/$.mjs'; console.log('=== Stream Getter Debug ==='); diff --git a/examples/debug-stream-internals.mjs b/examples/debug-stream-internals.mjs index 8be210c..4852bb0 100755 --- a/examples/debug-stream-internals.mjs +++ b/examples/debug-stream-internals.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Stream Internals Debug ==='); diff --git a/examples/debug-stream-method.mjs b/examples/debug-stream-method.mjs index 226e454..7e8772b 100755 --- a/examples/debug-stream-method.mjs +++ b/examples/debug-stream-method.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Stream Method Debug ==='); diff --git a/examples/debug-stream-object.mjs b/examples/debug-stream-object.mjs index 1a6ac0d..6c44d83 100755 --- a/examples/debug-stream-object.mjs +++ b/examples/debug-stream-object.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function debugStreamObject() { console.log('=== Debug stream object details ==='); diff --git a/examples/debug-stream-properties.mjs b/examples/debug-stream-properties.mjs index 11a0f9f..dfd6dcf 100755 --- a/examples/debug-stream-properties.mjs +++ b/examples/debug-stream-properties.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../src/$.mjs'; +import { $, disableVirtualCommands } from '../js/src/$.mjs'; console.log('=== Stream Properties Debug ==='); diff --git a/examples/debug-stream-timing.mjs b/examples/debug-stream-timing.mjs index 131bf98..6ce16ce 100755 --- a/examples/debug-stream-timing.mjs +++ b/examples/debug-stream-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../src/$.mjs'; +import { $, disableVirtualCommands } from '../js/src/$.mjs'; console.log('=== Stream Timing Debug ==='); diff --git a/examples/debug-streaming.mjs b/examples/debug-streaming.mjs index 997201a..1b5b38d 100755 --- a/examples/debug-streaming.mjs +++ b/examples/debug-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Debug Streaming Test ===\n'); diff --git a/examples/debug-test-state.mjs b/examples/debug-test-state.mjs index 2d9897f..0c892a9 100644 --- a/examples/debug-test-state.mjs +++ b/examples/debug-test-state.mjs @@ -1,5 +1,5 @@ // Debug test to understand why virtual commands get bypassed in full test suite -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function debugTestState() { console.log('=== Debug Test State ==='); diff --git a/examples/debug-user-sigint.mjs b/examples/debug-user-sigint.mjs index 7c786ee..823eaa8 100755 --- a/examples/debug-user-sigint.mjs +++ b/examples/debug-user-sigint.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; let sigintReceived = false; diff --git a/examples/debug-virtual-disable.mjs b/examples/debug-virtual-disable.mjs index 70ffbcc..c1e2c7a 100755 --- a/examples/debug-virtual-disable.mjs +++ b/examples/debug-virtual-disable.mjs @@ -3,7 +3,7 @@ // Enable verbose tracing process.env.COMMAND_STREAM_VERBOSE = 'true'; -import { $, disableVirtualCommands } from '../src/$.mjs'; +import { $, disableVirtualCommands } from '../js/src/$.mjs'; console.log('=== Virtual Disable Debug ==='); diff --git a/examples/debug-virtual-vs-real.mjs b/examples/debug-virtual-vs-real.mjs index 6daf97f..845525f 100755 --- a/examples/debug-virtual-vs-real.mjs +++ b/examples/debug-virtual-vs-real.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../src/$.mjs'; +import { $, disableVirtualCommands } from '../js/src/$.mjs'; console.log('=== Virtual vs Real Commands Debug ==='); diff --git a/examples/debug-with-trace.mjs b/examples/debug-with-trace.mjs index 3e5cfbc..311067b 100644 --- a/examples/debug-with-trace.mjs +++ b/examples/debug-with-trace.mjs @@ -4,7 +4,7 @@ process.env.COMMAND_STREAM_TRACE = 'all'; process.env.COMMAND_STREAM_VERBOSE = 'true'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function debugWithTrace() { console.log('๐Ÿ› Testing with full tracing enabled'); diff --git a/examples/debug_parent_stream.mjs b/examples/debug_parent_stream.mjs index 1122a91..da903e9 100755 --- a/examples/debug_parent_stream.mjs +++ b/examples/debug_parent_stream.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== PARENT STREAM CLOSURE TEST ==='); diff --git a/examples/emulated-streaming-direct.mjs b/examples/emulated-streaming-direct.mjs index bd77c1a..4faf723 100755 --- a/examples/emulated-streaming-direct.mjs +++ b/examples/emulated-streaming-direct.mjs @@ -2,7 +2,7 @@ // Direct execution of emulator -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Direct execution of emulator:'); const start = Date.now(); diff --git a/examples/emulated-streaming-jq-pipe.mjs b/examples/emulated-streaming-jq-pipe.mjs index 27ee877..cb3ec03 100755 --- a/examples/emulated-streaming-jq-pipe.mjs +++ b/examples/emulated-streaming-jq-pipe.mjs @@ -2,7 +2,7 @@ // Emulator piped through jq -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Emulator piped through jq:'); const start = Date.now(); diff --git a/examples/emulated-streaming-sh-pipe.mjs b/examples/emulated-streaming-sh-pipe.mjs index 6f10dae..ad1d13e 100755 --- a/examples/emulated-streaming-sh-pipe.mjs +++ b/examples/emulated-streaming-sh-pipe.mjs @@ -2,7 +2,7 @@ // Using sh -c with pipe -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Using sh -c with pipe:'); const start = Date.now(); diff --git a/examples/events-build-process.mjs b/examples/events-build-process.mjs index 6dff4d1..19c7df8 100755 --- a/examples/events-build-process.mjs +++ b/examples/events-build-process.mjs @@ -2,7 +2,7 @@ // Build process simulation with events -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Build process simulation:'); const $buildProcess = $({ mirror: false }); diff --git a/examples/events-concurrent-streams.mjs b/examples/events-concurrent-streams.mjs index 9e93c40..fa2f74f 100755 --- a/examples/events-concurrent-streams.mjs +++ b/examples/events-concurrent-streams.mjs @@ -2,7 +2,7 @@ // Multiple concurrent event streams -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Multiple concurrent event streams:'); diff --git a/examples/events-error-handling.mjs b/examples/events-error-handling.mjs index ebb59ff..24c8be3 100755 --- a/examples/events-error-handling.mjs +++ b/examples/events-error-handling.mjs @@ -2,7 +2,7 @@ // Error handling and recovery with events -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Error handling and recovery:'); const $errorTest = $({ mirror: false }); diff --git a/examples/events-file-monitoring.mjs b/examples/events-file-monitoring.mjs index 52a6afe..899eba7 100755 --- a/examples/events-file-monitoring.mjs +++ b/examples/events-file-monitoring.mjs @@ -2,7 +2,7 @@ // File monitoring simulation with events -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('File monitoring simulation:'); const $fileMonitor = $({ mirror: false, capture: true }); diff --git a/examples/events-interactive-simulation.mjs b/examples/events-interactive-simulation.mjs index a604788..3718f6d 100755 --- a/examples/events-interactive-simulation.mjs +++ b/examples/events-interactive-simulation.mjs @@ -2,7 +2,7 @@ // Interactive command simulation with events -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Interactive command simulation:'); const $interactive = $({ stdin: 'John\n25\nDeveloper\ny\n', mirror: false }); diff --git a/examples/events-log-processing.mjs b/examples/events-log-processing.mjs index 7d1819d..bbfb44d 100755 --- a/examples/events-log-processing.mjs +++ b/examples/events-log-processing.mjs @@ -2,7 +2,7 @@ // Real-time log processing with events -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Real-time log processing:'); const $logProcessor = $({ mirror: false }); diff --git a/examples/events-network-monitoring.mjs b/examples/events-network-monitoring.mjs index 04b200d..8a90ec1 100755 --- a/examples/events-network-monitoring.mjs +++ b/examples/events-network-monitoring.mjs @@ -2,7 +2,7 @@ // Network monitoring with multiple hosts using events -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Network monitoring with multiple hosts:'); diff --git a/examples/events-ping-basic.mjs b/examples/events-ping-basic.mjs index edd849d..fe8ceb8 100755 --- a/examples/events-ping-basic.mjs +++ b/examples/events-ping-basic.mjs @@ -2,7 +2,7 @@ // Basic event-based ping with options -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Basic event-based ping (silent mode):'); const $silent = $({ mirror: false }); diff --git a/examples/events-progress-tracking.mjs b/examples/events-progress-tracking.mjs index 61d254e..68e8a16 100755 --- a/examples/events-progress-tracking.mjs +++ b/examples/events-progress-tracking.mjs @@ -2,7 +2,7 @@ // Long-running process with progress events -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Long-running process with progress tracking:'); const $progress = $({ mirror: false, capture: true }); diff --git a/examples/events-stdin-input.mjs b/examples/events-stdin-input.mjs index db67841..298dc25 100755 --- a/examples/events-stdin-input.mjs +++ b/examples/events-stdin-input.mjs @@ -2,7 +2,7 @@ // Event-based with custom stdin -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Event-based with custom stdin:'); const $withInput = $({ stdin: 'Hello\nWorld\nTest\n', mirror: false }); diff --git a/examples/example-ansi-ls.mjs b/examples/example-ansi-ls.mjs index 2ae75ac..924740e 100755 --- a/examples/example-ansi-ls.mjs +++ b/examples/example-ansi-ls.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, AnsiUtils } from '../src/$.mjs'; +import { $, AnsiUtils } from '../js/src/$.mjs'; console.log('=== ANSI Color Example with ls command ===\n'); diff --git a/examples/example-top.mjs b/examples/example-top.mjs index 1897d4e..930d5d4 100755 --- a/examples/example-top.mjs +++ b/examples/example-top.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log( '=== Running top command with ANSI colors preserved (default behavior) ===' diff --git a/examples/final-ping-stdin-proof.mjs b/examples/final-ping-stdin-proof.mjs index 44314b7..8d06a7e 100755 --- a/examples/final-ping-stdin-proof.mjs +++ b/examples/final-ping-stdin-proof.mjs @@ -5,7 +5,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== FINAL PROOF: ping stdin vs kill() ==='); diff --git a/examples/final-test-shell-operators.mjs b/examples/final-test-shell-operators.mjs index e1ed56d..b675155 100644 --- a/examples/final-test-shell-operators.mjs +++ b/examples/final-test-shell-operators.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; import { mkdtempSync, rmSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/examples/final-working-examples.mjs b/examples/final-working-examples.mjs index b5dcdcb..dd42797 100755 --- a/examples/final-working-examples.mjs +++ b/examples/final-working-examples.mjs @@ -4,7 +4,7 @@ * Final working examples of streaming interfaces for README */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('๐Ÿš€ Final Working Examples - Streaming Interfaces'); console.log('='.repeat(55)); diff --git a/examples/gh-auth-test.mjs b/examples/gh-auth-test.mjs index e9fd589..17761ea 100755 --- a/examples/gh-auth-test.mjs +++ b/examples/gh-auth-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing gh auth status with $.mjs\n'); diff --git a/examples/gh-delete-hang-test.mjs b/examples/gh-delete-hang-test.mjs index d6e9fce..95e9503 100755 --- a/examples/gh-delete-hang-test.mjs +++ b/examples/gh-delete-hang-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/examples/gh-gist-creation-test.mjs b/examples/gh-gist-creation-test.mjs index 284df7b..5b95188 100755 --- a/examples/gh-gist-creation-test.mjs +++ b/examples/gh-gist-creation-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/examples/gh-gist-minimal-test.mjs b/examples/gh-gist-minimal-test.mjs index b252097..e19d5f8 100755 --- a/examples/gh-gist-minimal-test.mjs +++ b/examples/gh-gist-minimal-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import fs from 'fs/promises'; console.log('=== Minimal gh gist create test ===\n'); diff --git a/examples/gh-hang-exact-original.mjs b/examples/gh-hang-exact-original.mjs index f3a5661..7c6fd5e 100755 --- a/examples/gh-hang-exact-original.mjs +++ b/examples/gh-hang-exact-original.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/examples/gh-hang-reproduction.mjs b/examples/gh-hang-reproduction.mjs index 964756e..5fea0e6 100644 --- a/examples/gh-hang-reproduction.mjs +++ b/examples/gh-hang-reproduction.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/examples/gh-hang-test-with-redirect.mjs b/examples/gh-hang-test-with-redirect.mjs index d59d5d9..1139675 100755 --- a/examples/gh-hang-test-with-redirect.mjs +++ b/examples/gh-hang-test-with-redirect.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { promises as fs } from 'fs'; console.log('Testing gh gist create WITH 2>&1 (should work)'); diff --git a/examples/gh-hang-test-without-redirect.mjs b/examples/gh-hang-test-without-redirect.mjs index d8ba2ba..0a1c3c3 100755 --- a/examples/gh-hang-test-without-redirect.mjs +++ b/examples/gh-hang-test-without-redirect.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { promises as fs } from 'fs'; console.log('Testing gh gist create WITHOUT 2>&1 (potential hang)'); diff --git a/examples/gh-minimal-hang-check.mjs b/examples/gh-minimal-hang-check.mjs index 9f46449..a09e350 100755 --- a/examples/gh-minimal-hang-check.mjs +++ b/examples/gh-minimal-hang-check.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Minimal test for hanging ===\n'); diff --git a/examples/gh-operations-with-cd.mjs b/examples/gh-operations-with-cd.mjs index e19ee8a..bbbc104 100644 --- a/examples/gh-operations-with-cd.mjs +++ b/examples/gh-operations-with-cd.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; import { mkdtempSync, rmSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/examples/gh-output-test.mjs b/examples/gh-output-test.mjs index 7d0afb0..e3a1f75 100755 --- a/examples/gh-output-test.mjs +++ b/examples/gh-output-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing where gh auth status outputs go ===\n'); diff --git a/examples/gh-reproduce-hang.mjs b/examples/gh-reproduce-hang.mjs index 34f9def..9d883de 100755 --- a/examples/gh-reproduce-hang.mjs +++ b/examples/gh-reproduce-hang.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/examples/git-operations-with-cd.mjs b/examples/git-operations-with-cd.mjs index 6950930..21aad24 100644 --- a/examples/git-operations-with-cd.mjs +++ b/examples/git-operations-with-cd.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; import { mkdtempSync, rmSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/examples/interactive-top-fixed.mjs b/examples/interactive-top-fixed.mjs index e2c84d4..6cb77f6 100755 --- a/examples/interactive-top-fixed.mjs +++ b/examples/interactive-top-fixed.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Fixed Interactive top command ==='); console.log('This version properly handles:'); diff --git a/examples/interactive-top-improved.mjs b/examples/interactive-top-improved.mjs index 81fae01..e7830f9 100755 --- a/examples/interactive-top-improved.mjs +++ b/examples/interactive-top-improved.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { ProcessRunner } from '../src/$.mjs'; +import { ProcessRunner } from '../js/src/$.mjs'; import { spawn } from 'child_process'; console.log('=== Improved Interactive top with command-stream ==='); diff --git a/examples/interactive-top-pty-logging.mjs b/examples/interactive-top-pty-logging.mjs index 43f0756..11cb569 100755 --- a/examples/interactive-top-pty-logging.mjs +++ b/examples/interactive-top-pty-logging.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/examples/interactive-top-with-logging.mjs b/examples/interactive-top-with-logging.mjs index 8ca396c..0d633ac 100755 --- a/examples/interactive-top-with-logging.mjs +++ b/examples/interactive-top-with-logging.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/examples/interactive-top.mjs b/examples/interactive-top.mjs index b3630bc..2b4607a 100755 --- a/examples/interactive-top.mjs +++ b/examples/interactive-top.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log( '=== Interactive top command (preserves ANSI colors and interactive controls) ===' diff --git a/examples/jq-color-demo.mjs b/examples/jq-color-demo.mjs index 130dc75..0cebfa9 100755 --- a/examples/jq-color-demo.mjs +++ b/examples/jq-color-demo.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== jq Color Output Demo ===\n'); diff --git a/examples/jq-colors-streaming.mjs b/examples/jq-colors-streaming.mjs index 05119c1..5400c4b 100755 --- a/examples/jq-colors-streaming.mjs +++ b/examples/jq-colors-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== jq Streaming with ANSI Colors ===\n'); diff --git a/examples/manual-ctrl-c-test.mjs b/examples/manual-ctrl-c-test.mjs index ad28057..d0a0faf 100755 --- a/examples/manual-ctrl-c-test.mjs +++ b/examples/manual-ctrl-c-test.mjs @@ -3,7 +3,7 @@ // Manual test for CTRL+C handling // Run this script and press CTRL+C to test signal propagation -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Manual CTRL+C Test ===\n'); console.log('This script will run ping continuously.'); diff --git a/examples/methods-multiple-options.mjs b/examples/methods-multiple-options.mjs index 388cd49..1c28d5b 100755 --- a/examples/methods-multiple-options.mjs +++ b/examples/methods-multiple-options.mjs @@ -2,7 +2,7 @@ // Both .start() and .run() support all the same options -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Both support all the same options:'); diff --git a/examples/methods-run-basic.mjs b/examples/methods-run-basic.mjs index 37a7c12..6996349 100755 --- a/examples/methods-run-basic.mjs +++ b/examples/methods-run-basic.mjs @@ -2,7 +2,7 @@ // Using .run() method (identical functionality to .start()) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Using .run() method (identical functionality):'); const result = await $`echo "Using .run() method"`.run({ mirror: false }); diff --git a/examples/methods-start-basic.mjs b/examples/methods-start-basic.mjs index 45c46d3..b314f51 100755 --- a/examples/methods-start-basic.mjs +++ b/examples/methods-start-basic.mjs @@ -2,7 +2,7 @@ // Using .start() method -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Using .start() method:'); const result = await $`echo "Using .start() method"`.start({ mirror: false }); diff --git a/examples/options-capture-false.mjs b/examples/options-capture-false.mjs index 64bab7a..92d2ebf 100755 --- a/examples/options-capture-false.mjs +++ b/examples/options-capture-false.mjs @@ -2,7 +2,7 @@ // Using .start() with capture: false -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing $`echo test`.start({ capture: false }):'); const result = await $`echo "test with capture false"`.start({ diff --git a/examples/options-combined-settings.mjs b/examples/options-combined-settings.mjs index 37b046a..110da4f 100755 --- a/examples/options-combined-settings.mjs +++ b/examples/options-combined-settings.mjs @@ -2,7 +2,7 @@ // Using .run() alias with both mirror and capture options -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing $`echo test`.run({ mirror: false, capture: true }):'); const result = await $`echo "test with both options"`.run({ diff --git a/examples/options-custom-input.mjs b/examples/options-custom-input.mjs index 6808280..be5b73c 100755 --- a/examples/options-custom-input.mjs +++ b/examples/options-custom-input.mjs @@ -2,7 +2,7 @@ // Custom input with options -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Custom input with options:'); console.log('await $`cat`.start({ stdin: "custom", mirror: false })'); diff --git a/examples/options-default-behavior.mjs b/examples/options-default-behavior.mjs index 06e344a..f0f2dd2 100755 --- a/examples/options-default-behavior.mjs +++ b/examples/options-default-behavior.mjs @@ -2,7 +2,7 @@ // Default behavior comparison (direct await) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing default await $`echo test` (for comparison):'); const result = await $`echo "test default behavior"`; diff --git a/examples/options-maximum-performance.mjs b/examples/options-maximum-performance.mjs index 9481d5e..6c501b0 100755 --- a/examples/options-maximum-performance.mjs +++ b/examples/options-maximum-performance.mjs @@ -2,7 +2,7 @@ // Maximum performance - no capture, no mirror -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Maximum performance - no capture, no mirror:'); console.log('await $`echo "blazing"`.start({ capture: false, mirror: false })'); diff --git a/examples/options-mirror-false.mjs b/examples/options-mirror-false.mjs index e986337..79a0497 100755 --- a/examples/options-mirror-false.mjs +++ b/examples/options-mirror-false.mjs @@ -2,7 +2,7 @@ // Using .start() with mirror: false -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing $`echo test`.start({ mirror: false }):'); const result = await $`echo "test with mirror false"`.start({ mirror: false }); diff --git a/examples/options-performance-mode.mjs b/examples/options-performance-mode.mjs index 51a1764..dbd303a 100755 --- a/examples/options-performance-mode.mjs +++ b/examples/options-performance-mode.mjs @@ -2,7 +2,7 @@ // capture: false and mirror: false together (maximum performance) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing $`echo test`.start({ capture: false, mirror: false }):'); const result = await $`echo "no capture, no mirror"`.start({ diff --git a/examples/options-performance-optimization.mjs b/examples/options-performance-optimization.mjs index f661c48..a1d4e1c 100755 --- a/examples/options-performance-optimization.mjs +++ b/examples/options-performance-optimization.mjs @@ -2,7 +2,7 @@ // Performance optimization - disable capture -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Performance optimization - disable capture:'); console.log('await $`echo "fast"`.start({ capture: false })'); diff --git a/examples/options-run-alias-demo.mjs b/examples/options-run-alias-demo.mjs index 9884105..aed3c93 100755 --- a/examples/options-run-alias-demo.mjs +++ b/examples/options-run-alias-demo.mjs @@ -2,7 +2,7 @@ // Using .run() alias -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Using .run() alias:'); console.log('await $`echo "alias"`.run({ capture: true, mirror: false })'); diff --git a/examples/options-run-alias.mjs b/examples/options-run-alias.mjs index ece0dae..0e7fd20 100755 --- a/examples/options-run-alias.mjs +++ b/examples/options-run-alias.mjs @@ -2,7 +2,7 @@ // Using .run() alias with capture: false -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing $`echo test`.run({ capture: false }):'); const result = await $`echo "test with run alias"`.run({ capture: false }); diff --git a/examples/options-silent-execution.mjs b/examples/options-silent-execution.mjs index 4218129..1294c0e 100755 --- a/examples/options-silent-execution.mjs +++ b/examples/options-silent-execution.mjs @@ -2,7 +2,7 @@ // Silent execution - disable mirroring -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Silent execution - disable mirroring:'); console.log('await $`echo "silent"`.start({ mirror: false })'); diff --git a/examples/options-streaming-capture.mjs b/examples/options-streaming-capture.mjs index 1869dfc..fe5b00c 100755 --- a/examples/options-streaming-capture.mjs +++ b/examples/options-streaming-capture.mjs @@ -2,7 +2,7 @@ // Capture enabled with streaming using $({ capture: true }) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Capture enabled with streaming:'); const $capture = $({ capture: true, mirror: false }); diff --git a/examples/options-streaming-multiple.mjs b/examples/options-streaming-multiple.mjs index 0027fad..786c754 100755 --- a/examples/options-streaming-multiple.mjs +++ b/examples/options-streaming-multiple.mjs @@ -2,7 +2,7 @@ // Multiple configured instances with different options -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Multiple configured instances:'); const $quiet = $({ mirror: false }); diff --git a/examples/options-streaming-silent.mjs b/examples/options-streaming-silent.mjs index fb4ab5e..8e96c3a 100755 --- a/examples/options-streaming-silent.mjs +++ b/examples/options-streaming-silent.mjs @@ -2,7 +2,7 @@ // Silent streaming using $({ mirror: false }) syntax -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Silent streaming (mirror: false):'); const $silent = $({ mirror: false }); diff --git a/examples/options-streaming-stdin.mjs b/examples/options-streaming-stdin.mjs index c8a8ef6..9a2ffe8 100755 --- a/examples/options-streaming-stdin.mjs +++ b/examples/options-streaming-stdin.mjs @@ -2,7 +2,7 @@ // Streaming with custom stdin using $({ stdin }) syntax -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Streaming with custom stdin:'); const $withStdin = $({ stdin: 'Hello\nWorld\n', mirror: false }); diff --git a/examples/ping-streaming-filtered.mjs b/examples/ping-streaming-filtered.mjs index ef14c1c..315bc7d 100755 --- a/examples/ping-streaming-filtered.mjs +++ b/examples/ping-streaming-filtered.mjs @@ -2,7 +2,7 @@ // Filtering only ping replies (no summary) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Filtering only ping replies (no summary):'); console.log('Running ping -c 3 1.1.1.1...\n'); diff --git a/examples/ping-streaming-interruptible.mjs b/examples/ping-streaming-interruptible.mjs index ff1e6d9..7df05c6 100755 --- a/examples/ping-streaming-interruptible.mjs +++ b/examples/ping-streaming-interruptible.mjs @@ -2,7 +2,7 @@ // Interruptible ping streaming - shows how to handle CTRL+C gracefully -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Interruptible Ping Streaming ==='); console.log('Streaming continuous ping - press CTRL+C to stop gracefully...\n'); diff --git a/examples/ping-streaming-silent.mjs b/examples/ping-streaming-silent.mjs index 5dd1673..38162d7 100755 --- a/examples/ping-streaming-silent.mjs +++ b/examples/ping-streaming-silent.mjs @@ -2,7 +2,7 @@ // Silent streaming (no mirror to terminal) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Silent streaming (no mirror to terminal):'); console.log('Running ping -c 3 127.0.0.1 with mirror: false...\n'); diff --git a/examples/ping-streaming-simple.mjs b/examples/ping-streaming-simple.mjs index 458384c..ee46c4f 100755 --- a/examples/ping-streaming-simple.mjs +++ b/examples/ping-streaming-simple.mjs @@ -2,7 +2,7 @@ // Simple ping streaming example - minimal code, maximum clarity -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Streaming ping output in real-time...\n'); diff --git a/examples/ping-streaming-statistics.mjs b/examples/ping-streaming-statistics.mjs index fac3a09..867ddee 100755 --- a/examples/ping-streaming-statistics.mjs +++ b/examples/ping-streaming-statistics.mjs @@ -2,7 +2,7 @@ // Counting responses with statistics -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Counting responses with statistics:'); console.log('Running ping -c 4 8.8.8.8...\n'); diff --git a/examples/ping-streaming-timestamps.mjs b/examples/ping-streaming-timestamps.mjs index ede697f..6101d26 100755 --- a/examples/ping-streaming-timestamps.mjs +++ b/examples/ping-streaming-timestamps.mjs @@ -2,7 +2,7 @@ // Basic ping streaming with timestamps -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Basic streaming with timestamps:'); console.log('Running ping -c 5 google.com...\n'); diff --git a/examples/ping-streaming.mjs b/examples/ping-streaming.mjs index 14c4b03..d0256c1 100755 --- a/examples/ping-streaming.mjs +++ b/examples/ping-streaming.mjs @@ -2,7 +2,7 @@ // Streaming ping example - shows real-time output as it arrives -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Real-time Ping Streaming Example ==='); console.log('Press CTRL+C to stop the ping...\n'); diff --git a/examples/prove-ping-stdin-limitation.mjs b/examples/prove-ping-stdin-limitation.mjs index c74a397..36e69bc 100755 --- a/examples/prove-ping-stdin-limitation.mjs +++ b/examples/prove-ping-stdin-limitation.mjs @@ -5,7 +5,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== PROOF: ping ignores stdin, needs kill() method ==='); console.log(''); diff --git a/examples/readme-example.mjs b/examples/readme-example.mjs index 40a2dfa..332596f 100755 --- a/examples/readme-example.mjs +++ b/examples/readme-example.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, register } from '../src/$.mjs'; +import { $, register } from '../js/src/$.mjs'; // Register a custom virtual command with the new object-based signature register('greet', async ({ stdin }) => ({ diff --git a/examples/realtime-json-stream.mjs b/examples/realtime-json-stream.mjs index 5b556ba..abef57f 100755 --- a/examples/realtime-json-stream.mjs +++ b/examples/realtime-json-stream.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Realtime JSON Streaming Demo ===\n'); console.log( diff --git a/examples/reliable-stdin-commands.mjs b/examples/reliable-stdin-commands.mjs index 81ac690..56f4bf1 100755 --- a/examples/reliable-stdin-commands.mjs +++ b/examples/reliable-stdin-commands.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Most reliable stdin commands ==='); diff --git a/examples/reproduce-issue-135-v2.mjs b/examples/reproduce-issue-135-v2.mjs index da619ca..8dadc74 100755 --- a/examples/reproduce-issue-135-v2.mjs +++ b/examples/reproduce-issue-135-v2.mjs @@ -4,7 +4,7 @@ process.env.CI = 'true'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test with CI=true set BEFORE import ==='); const $silent = $({ mirror: false, capture: true }); diff --git a/examples/reproduce-issue-135.mjs b/examples/reproduce-issue-135.mjs index 10bc1e5..97249d1 100755 --- a/examples/reproduce-issue-135.mjs +++ b/examples/reproduce-issue-135.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Reproducing issue #135: Trace logs interfere with output when CI=true -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const $silent = $({ mirror: false, capture: true }); diff --git a/examples/shell-cd-behavior.mjs b/examples/shell-cd-behavior.mjs index 0bcf8b5..8f01983 100644 --- a/examples/shell-cd-behavior.mjs +++ b/examples/shell-cd-behavior.mjs @@ -2,7 +2,7 @@ // This file documents how cd SHOULD behave to match shell behavior -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; enableVirtualCommands(); shell.verbose(false); diff --git a/examples/sigint-forwarding-test.mjs b/examples/sigint-forwarding-test.mjs index 945abfa..1a713e2 100755 --- a/examples/sigint-forwarding-test.mjs +++ b/examples/sigint-forwarding-test.mjs @@ -2,7 +2,7 @@ // Test SIGINT forwarding to child processes // This runs in a subprocess to avoid killing the test runner -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/sigint-handler-test.mjs b/examples/sigint-handler-test.mjs index 5045a9f..4324325 100755 --- a/examples/sigint-handler-test.mjs +++ b/examples/sigint-handler-test.mjs @@ -2,7 +2,7 @@ // Test script to verify SIGINT handler cleanup // This runs in a subprocess to avoid interfering with the test runner -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/simple-async-test.mjs b/examples/simple-async-test.mjs index 982205f..20e456b 100755 --- a/examples/simple-async-test.mjs +++ b/examples/simple-async-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Simple async streams test ==='); diff --git a/examples/simple-claude-test.mjs b/examples/simple-claude-test.mjs index 254f51b..a1bd1f8 100755 --- a/examples/simple-claude-test.mjs +++ b/examples/simple-claude-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Simple Claude test with command-stream -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Simple Claude test with command-stream ==='); diff --git a/examples/simple-event-test.mjs b/examples/simple-event-test.mjs index d852586..b500a81 100644 --- a/examples/simple-event-test.mjs +++ b/examples/simple-event-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('๐Ÿงช Simple event test'); diff --git a/examples/simple-jq-streaming.mjs b/examples/simple-jq-streaming.mjs index f90fc34..d8557f7 100755 --- a/examples/simple-jq-streaming.mjs +++ b/examples/simple-jq-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Simple jq Streaming Test ===\n'); diff --git a/examples/simple-stream-demo.mjs b/examples/simple-stream-demo.mjs index ec1c505..2ef5b56 100755 --- a/examples/simple-stream-demo.mjs +++ b/examples/simple-stream-demo.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing simple streaming without jq...\n'); diff --git a/examples/simple-working-stdin.mjs b/examples/simple-working-stdin.mjs index 0202b1a..0473212 100755 --- a/examples/simple-working-stdin.mjs +++ b/examples/simple-working-stdin.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function simpleWorkingStdin() { console.log('Simple working stdin test'); diff --git a/examples/streaming-behavior-test.mjs b/examples/streaming-behavior-test.mjs index fc6272d..280c610 100755 --- a/examples/streaming-behavior-test.mjs +++ b/examples/streaming-behavior-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $, register } from '../src/$.mjs'; +import { $, register } from '../js/src/$.mjs'; console.log('=== Comprehensive Streaming Behavior Test ===\n'); console.log( diff --git a/examples/streaming-direct-command.mjs b/examples/streaming-direct-command.mjs index e8c86bd..95294ec 100755 --- a/examples/streaming-direct-command.mjs +++ b/examples/streaming-direct-command.mjs @@ -2,7 +2,7 @@ // Basic streaming without pipes -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Direct command streaming test:'); diff --git a/examples/streaming-filtered-output.mjs b/examples/streaming-filtered-output.mjs index c456b6a..7d3195c 100755 --- a/examples/streaming-filtered-output.mjs +++ b/examples/streaming-filtered-output.mjs @@ -2,7 +2,7 @@ // Stream processing with filtering (only error-like output) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Filtered streaming (only error-like output):'); const $filtered = $({ mirror: false }); diff --git a/examples/streaming-grep-pipeline.mjs b/examples/streaming-grep-pipeline.mjs index bec8807..165b5f4 100755 --- a/examples/streaming-grep-pipeline.mjs +++ b/examples/streaming-grep-pipeline.mjs @@ -2,7 +2,7 @@ // grep pipeline streaming -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('grep pipeline streaming test:'); diff --git a/examples/streaming-interactive-stdin.mjs b/examples/streaming-interactive-stdin.mjs index b76468d..da1cc83 100755 --- a/examples/streaming-interactive-stdin.mjs +++ b/examples/streaming-interactive-stdin.mjs @@ -2,7 +2,7 @@ // Interactive-style streaming with custom stdin -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Interactive streaming with pre-filled input:'); const commands = 'ls -la\necho "Current directory listing"\nexit\n'; diff --git a/examples/streaming-jq-pipeline.mjs b/examples/streaming-jq-pipeline.mjs index 6a0207c..de36774 100755 --- a/examples/streaming-jq-pipeline.mjs +++ b/examples/streaming-jq-pipeline.mjs @@ -2,7 +2,7 @@ // jq pipeline streaming (critical test) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('jq pipeline streaming test:'); diff --git a/examples/streaming-multistage-pipeline.mjs b/examples/streaming-multistage-pipeline.mjs index 7294fdd..a944f4e 100755 --- a/examples/streaming-multistage-pipeline.mjs +++ b/examples/streaming-multistage-pipeline.mjs @@ -2,7 +2,7 @@ // Multi-stage pipeline streaming (cat | jq) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Multi-stage pipeline streaming test:'); diff --git a/examples/streaming-pipes-event-pattern.mjs b/examples/streaming-pipes-event-pattern.mjs index 4761a0a..021a73a 100755 --- a/examples/streaming-pipes-event-pattern.mjs +++ b/examples/streaming-pipes-event-pattern.mjs @@ -2,7 +2,7 @@ // EventEmitter pattern with pipes -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('EventEmitter pattern with pipes:'); const start = Date.now(); diff --git a/examples/streaming-pipes-multistage.mjs b/examples/streaming-pipes-multistage.mjs index c95a24a..fdc4bd4 100755 --- a/examples/streaming-pipes-multistage.mjs +++ b/examples/streaming-pipes-multistage.mjs @@ -2,7 +2,7 @@ // Multi-stage pipeline with streaming -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Multi-stage pipeline with streaming:'); const start = Date.now(); diff --git a/examples/streaming-pipes-realtime-jq.mjs b/examples/streaming-pipes-realtime-jq.mjs index 5e9703e..eaf2ec7 100755 --- a/examples/streaming-pipes-realtime-jq.mjs +++ b/examples/streaming-pipes-realtime-jq.mjs @@ -2,7 +2,7 @@ // Real-time streaming through jq pipe -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Real-time streaming with delays through jq:'); console.log('Each line should appear immediately, not all at once\n'); diff --git a/examples/streaming-progress-tracking.mjs b/examples/streaming-progress-tracking.mjs index 3521512..8846eca 100755 --- a/examples/streaming-progress-tracking.mjs +++ b/examples/streaming-progress-tracking.mjs @@ -2,7 +2,7 @@ // Streaming with progress tracking -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Progress tracking with streaming:'); const $progress = $({ mirror: false }); diff --git a/examples/streaming-reusable-configs.mjs b/examples/streaming-reusable-configs.mjs index 9c5d510..483d221 100755 --- a/examples/streaming-reusable-configs.mjs +++ b/examples/streaming-reusable-configs.mjs @@ -2,7 +2,7 @@ // Reusable streaming configurations -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Reusable streaming configurations:'); diff --git a/examples/streaming-silent-capture.mjs b/examples/streaming-silent-capture.mjs index 216a95e..a71039e 100755 --- a/examples/streaming-silent-capture.mjs +++ b/examples/streaming-silent-capture.mjs @@ -2,7 +2,7 @@ // Long-running command with silent capture -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Long-running with silent capture:'); const $longSilent = $({ mirror: false, capture: true }); diff --git a/examples/streaming-test-simple.mjs b/examples/streaming-test-simple.mjs index b23b34f..40c10cc 100755 --- a/examples/streaming-test-simple.mjs +++ b/examples/streaming-test-simple.mjs @@ -5,7 +5,7 @@ * Uses 'echo' and 'seq' commands that are guaranteed to exist */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { writeFileSync, appendFileSync, existsSync } from 'fs'; console.log('๐Ÿงช Testing streaming with simple commands...\n'); diff --git a/examples/streaming-virtual-pipeline.mjs b/examples/streaming-virtual-pipeline.mjs index 972456b..16dff18 100755 --- a/examples/streaming-virtual-pipeline.mjs +++ b/examples/streaming-virtual-pipeline.mjs @@ -2,7 +2,7 @@ // Virtual command with pipeline -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Virtual command with jq pipeline:'); diff --git a/examples/syntax-basic-comparison.mjs b/examples/syntax-basic-comparison.mjs index 27db032..b7fe19b 100755 --- a/examples/syntax-basic-comparison.mjs +++ b/examples/syntax-basic-comparison.mjs @@ -2,7 +2,7 @@ // Basic streaming comparison: regular $ vs $({ options }) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Basic streaming comparison:'); diff --git a/examples/syntax-basic-options.mjs b/examples/syntax-basic-options.mjs index fe3c92c..5efd793 100755 --- a/examples/syntax-basic-options.mjs +++ b/examples/syntax-basic-options.mjs @@ -2,7 +2,7 @@ // Basic options verification -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Verifying basic options...'); diff --git a/examples/syntax-combined-options.mjs b/examples/syntax-combined-options.mjs index 02b643a..9b662f6 100755 --- a/examples/syntax-combined-options.mjs +++ b/examples/syntax-combined-options.mjs @@ -2,7 +2,7 @@ // Combined multiple options using $({ options }) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Combined options:'); const $combined = $({ diff --git a/examples/syntax-command-chaining.mjs b/examples/syntax-command-chaining.mjs index 30f410c..80eaa9f 100755 --- a/examples/syntax-command-chaining.mjs +++ b/examples/syntax-command-chaining.mjs @@ -2,7 +2,7 @@ // Command chaining verification -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Verifying command chaining...'); diff --git a/examples/syntax-custom-directory.mjs b/examples/syntax-custom-directory.mjs index 82c9c76..cace4ce 100755 --- a/examples/syntax-custom-directory.mjs +++ b/examples/syntax-custom-directory.mjs @@ -2,7 +2,7 @@ // Custom working directory using $({ options }) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Custom working directory:'); const $inTmp = $({ cwd: '/tmp', mirror: false }); diff --git a/examples/syntax-custom-environment.mjs b/examples/syntax-custom-environment.mjs index c55eced..3dae7dc 100755 --- a/examples/syntax-custom-environment.mjs +++ b/examples/syntax-custom-environment.mjs @@ -2,7 +2,7 @@ // Custom environment using $({ options }) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Custom environment:'); const $withEnv = $({ diff --git a/examples/syntax-custom-stdin.mjs b/examples/syntax-custom-stdin.mjs index 28b4864..40d8f13 100755 --- a/examples/syntax-custom-stdin.mjs +++ b/examples/syntax-custom-stdin.mjs @@ -2,7 +2,7 @@ // Custom stdin using $({ options }) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Custom stdin:'); const $withInput = $({ stdin: 'Hello from stdin!\n' }); diff --git a/examples/syntax-mixed-regular.mjs b/examples/syntax-mixed-regular.mjs index 58bb937..665acc3 100755 --- a/examples/syntax-mixed-regular.mjs +++ b/examples/syntax-mixed-regular.mjs @@ -2,7 +2,7 @@ // Mixed with regular $ verification -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Verifying mixed with regular $...'); diff --git a/examples/syntax-mixed-usage.mjs b/examples/syntax-mixed-usage.mjs index 27eb443..757fd3c 100755 --- a/examples/syntax-mixed-usage.mjs +++ b/examples/syntax-mixed-usage.mjs @@ -2,7 +2,7 @@ // Mix with regular $ usage -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Mixed usage:'); console.log('Regular $ (with mirror):'); diff --git a/examples/syntax-multiple-listeners.mjs b/examples/syntax-multiple-listeners.mjs index 087c3ef..795fa2c 100755 --- a/examples/syntax-multiple-listeners.mjs +++ b/examples/syntax-multiple-listeners.mjs @@ -2,7 +2,7 @@ // Multiple event listeners comparison -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Multiple event listeners comparison:'); diff --git a/examples/syntax-piping-comparison.mjs b/examples/syntax-piping-comparison.mjs index 0c178a3..caac63a 100755 --- a/examples/syntax-piping-comparison.mjs +++ b/examples/syntax-piping-comparison.mjs @@ -2,7 +2,7 @@ // Command chaining with different options comparison -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Command chaining with different options:'); diff --git a/examples/syntax-reusable-config.mjs b/examples/syntax-reusable-config.mjs index 3269061..fb74afa 100755 --- a/examples/syntax-reusable-config.mjs +++ b/examples/syntax-reusable-config.mjs @@ -2,7 +2,7 @@ // Multiple uses of same configured $ verification -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Verifying reusable configurations...'); diff --git a/examples/syntax-reusable-configs.mjs b/examples/syntax-reusable-configs.mjs index 31f5a1c..80a526d 100755 --- a/examples/syntax-reusable-configs.mjs +++ b/examples/syntax-reusable-configs.mjs @@ -2,7 +2,7 @@ // Reusable configurations using $({ options }) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Reusable configurations:'); const $debug = $({ diff --git a/examples/syntax-silent-operations.mjs b/examples/syntax-silent-operations.mjs index 4b9dfdf..e6183e1 100755 --- a/examples/syntax-silent-operations.mjs +++ b/examples/syntax-silent-operations.mjs @@ -2,7 +2,7 @@ // Silent operations (no mirror to stdout) using $({ options }) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Silent operation:'); const $silent = $({ mirror: false }); diff --git a/examples/syntax-stdin-option.mjs b/examples/syntax-stdin-option.mjs index 2aca1e4..851c56e 100755 --- a/examples/syntax-stdin-option.mjs +++ b/examples/syntax-stdin-option.mjs @@ -2,7 +2,7 @@ // stdin option verification -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Verifying stdin option...'); diff --git a/examples/temp-sigint-test.mjs b/examples/temp-sigint-test.mjs index 0674145..ef9608b 100755 --- a/examples/temp-sigint-test.mjs +++ b/examples/temp-sigint-test.mjs @@ -2,7 +2,7 @@ // Temporary test file for SIGINT handling - can be used for debugging user signal handlers -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; let sigintReceived = false; diff --git a/examples/test-actual-buildshell.mjs b/examples/test-actual-buildshell.mjs index 7e03c25..3acc5da 100644 --- a/examples/test-actual-buildshell.mjs +++ b/examples/test-actual-buildshell.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test the actual buildShellCommand from command-stream -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose to see buildShellCommand traces process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/test-async-streams-working.mjs b/examples/test-async-streams-working.mjs index 3e911a8..c5cbb0e 100755 --- a/examples/test-async-streams-working.mjs +++ b/examples/test-async-streams-working.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test async streams with commands that wait ==='); diff --git a/examples/test-async-streams.mjs b/examples/test-async-streams.mjs index 51e4ef6..866a615 100755 --- a/examples/test-async-streams.mjs +++ b/examples/test-async-streams.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test async streams interface ==='); diff --git a/examples/test-auth-parse.mjs b/examples/test-auth-parse.mjs index e38a75c..812aa75 100644 --- a/examples/test-auth-parse.mjs +++ b/examples/test-auth-parse.mjs @@ -1,4 +1,4 @@ -import { $ } from './src/$.mjs'; +import { $ } from './js/src/$.mjs'; async function getDetailedAuthStatus() { try { diff --git a/examples/test-auto-quoting.mjs b/examples/test-auto-quoting.mjs index 4167902..ff945f6 100644 --- a/examples/test-auto-quoting.mjs +++ b/examples/test-auto-quoting.mjs @@ -3,7 +3,7 @@ // Test: Automatic quoting when user doesn't provide quotes // Expected: Smart auto-quoting based on content -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test: Automatic Smart Quoting ===\n'); diff --git a/examples/test-auto-start-fix.mjs b/examples/test-auto-start-fix.mjs index fb38c9e..88e8e9f 100755 --- a/examples/test-auto-start-fix.mjs +++ b/examples/test-auto-start-fix.mjs @@ -5,7 +5,7 @@ * not when accessing the parent objects (streams, buffers, strings). */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing Auto-Start Behavior Fix ==='); console.log(''); diff --git a/examples/test-buffer-behavior.mjs b/examples/test-buffer-behavior.mjs index b43a219..ca3ac34 100755 --- a/examples/test-buffer-behavior.mjs +++ b/examples/test-buffer-behavior.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing buffer behavior in stream()...'); diff --git a/examples/test-buffers-simple.mjs b/examples/test-buffers-simple.mjs index 0f1ac51..382bdbf 100755 --- a/examples/test-buffers-simple.mjs +++ b/examples/test-buffers-simple.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing buffer access...'); diff --git a/examples/test-bun-specific-issue.mjs b/examples/test-bun-specific-issue.mjs index 3006afb..c8c25cd 100755 --- a/examples/test-bun-specific-issue.mjs +++ b/examples/test-bun-specific-issue.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // More targeted test to find the real Bun shell path issue -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const isBun = typeof globalThis.Bun !== 'undefined'; console.log(`=== Bun Runtime Shell Path Test ===`); diff --git a/examples/test-cd-behavior.mjs b/examples/test-cd-behavior.mjs index 0cdf3c1..6ffa4ae 100644 --- a/examples/test-cd-behavior.mjs +++ b/examples/test-cd-behavior.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; enableVirtualCommands(); shell.verbose(false); diff --git a/examples/test-child-process-timing.mjs b/examples/test-child-process-timing.mjs index 1d07294..f8fc3d2 100755 --- a/examples/test-child-process-timing.mjs +++ b/examples/test-child-process-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Debug child process timing ==='); diff --git a/examples/test-cleanup-simple.mjs b/examples/test-cleanup-simple.mjs index 67d3c84..61a73ee 100755 --- a/examples/test-cleanup-simple.mjs +++ b/examples/test-cleanup-simple.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing stream cleanup...'); diff --git a/examples/test-correct-space-handling.mjs b/examples/test-correct-space-handling.mjs index bc1b3c0..4e6cf69 100644 --- a/examples/test-correct-space-handling.mjs +++ b/examples/test-correct-space-handling.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; import { mkdtempSync, rmSync, mkdirSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/examples/test-ctrl-c-debug.mjs b/examples/test-ctrl-c-debug.mjs index b22ecc7..f983630 100755 --- a/examples/test-ctrl-c-debug.mjs +++ b/examples/test-ctrl-c-debug.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing CTRL+C signal propagation'); console.log('Press CTRL+C to interrupt...'); diff --git a/examples/test-ctrl-c-inherit.mjs b/examples/test-ctrl-c-inherit.mjs index 90d43ec..be90118 100755 --- a/examples/test-ctrl-c-inherit.mjs +++ b/examples/test-ctrl-c-inherit.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing CTRL+C with explicit stdio inherit'); console.log('Press CTRL+C to interrupt the ping command...'); diff --git a/examples/test-ctrl-c-sleep.mjs b/examples/test-ctrl-c-sleep.mjs index fee4dc5..9283849 100755 --- a/examples/test-ctrl-c-sleep.mjs +++ b/examples/test-ctrl-c-sleep.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing CTRL+C with sleep command'); console.log('Press CTRL+C to interrupt the sleep...'); diff --git a/examples/test-ctrl-c.mjs b/examples/test-ctrl-c.mjs index bad7ac8..49db9e1 100755 --- a/examples/test-ctrl-c.mjs +++ b/examples/test-ctrl-c.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing CTRL+C handling with ping command'); console.log('Press CTRL+C to interrupt the ping command...'); diff --git a/examples/test-debug-new-options.mjs b/examples/test-debug-new-options.mjs index e4873d7..7c2d569 100755 --- a/examples/test-debug-new-options.mjs +++ b/examples/test-debug-new-options.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function debug() { console.log('=== Debugging how new options work ==='); diff --git a/examples/test-debug-pty.mjs b/examples/test-debug-pty.mjs index 4bd2b68..5bbac11 100755 --- a/examples/test-debug-pty.mjs +++ b/examples/test-debug-pty.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Add debug logging const original_runPipeline = $.prototype._runPipeline; diff --git a/examples/test-debug-tee.mjs b/examples/test-debug-tee.mjs index 5ab3af8..7fa4b7a 100755 --- a/examples/test-debug-tee.mjs +++ b/examples/test-debug-tee.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Debug Tee Streaming ===\n'); diff --git a/examples/test-debug.mjs b/examples/test-debug.mjs index ba25a70..7bc22b4 100755 --- a/examples/test-debug.mjs +++ b/examples/test-debug.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Starting test...'); diff --git a/examples/test-double-quoting-prevention.mjs b/examples/test-double-quoting-prevention.mjs index eb3049d..efa6ee8 100644 --- a/examples/test-double-quoting-prevention.mjs +++ b/examples/test-double-quoting-prevention.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test: Prevent double-quoting when user provides quotes on strings that need quoting -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Double-Quoting Prevention Test ===\n'); diff --git a/examples/test-edge-cases-quoting.mjs b/examples/test-edge-cases-quoting.mjs index 220681b..9fa9a91 100644 --- a/examples/test-edge-cases-quoting.mjs +++ b/examples/test-edge-cases-quoting.mjs @@ -3,7 +3,7 @@ // Test: Edge cases for quote handling // Expected: Proper handling of unusual quoting scenarios -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test: Quote Edge Cases ===\n'); diff --git a/examples/test-events.mjs b/examples/test-events.mjs index 508ec66..c84ecc9 100755 --- a/examples/test-events.mjs +++ b/examples/test-events.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test Event Emissions ===\n'); diff --git a/examples/test-explicit-stdio.mjs b/examples/test-explicit-stdio.mjs index 07c8cae..d74a03b 100755 --- a/examples/test-explicit-stdio.mjs +++ b/examples/test-explicit-stdio.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test with explicit stdio configuration ==='); diff --git a/examples/test-final-streaming.mjs b/examples/test-final-streaming.mjs index 6dbe956..a768f18 100755 --- a/examples/test-final-streaming.mjs +++ b/examples/test-final-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Final Streaming Test with PTY Workaround ===\n'); diff --git a/examples/test-fix.mjs b/examples/test-fix.mjs index 81333fc..2ff73ca 100644 --- a/examples/test-fix.mjs +++ b/examples/test-fix.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function testFix() { console.log('๐Ÿงช Testing the stdin pipe fix'); diff --git a/examples/test-incremental-streaming.mjs b/examples/test-incremental-streaming.mjs index e151355..74b70e1 100755 --- a/examples/test-incremental-streaming.mjs +++ b/examples/test-incremental-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing Incremental Streaming ===\n'); diff --git a/examples/test-inherit-stdout-not-stdin.mjs b/examples/test-inherit-stdout-not-stdin.mjs index 217e044..8a09683 100755 --- a/examples/test-inherit-stdout-not-stdin.mjs +++ b/examples/test-inherit-stdout-not-stdin.mjs @@ -5,7 +5,7 @@ * This allows parent process to see output, but child doesn't read from parent's stdin */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing inherit stdout but not stdin ==='); console.log(''); diff --git a/examples/test-injection-protection.mjs b/examples/test-injection-protection.mjs index b14fba9..3af6065 100644 --- a/examples/test-injection-protection.mjs +++ b/examples/test-injection-protection.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test shell injection protection with the smart quoting -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Shell Injection Protection Test ===\n'); diff --git a/examples/test-interactive-streaming.mjs b/examples/test-interactive-streaming.mjs index e9959f6..848ed01 100755 --- a/examples/test-interactive-streaming.mjs +++ b/examples/test-interactive-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function testInteractiveStreaming() { console.log('Testing Interactive Streaming I/O\n'); diff --git a/examples/test-interactive.mjs b/examples/test-interactive.mjs index 2ab3d80..90fe666 100755 --- a/examples/test-interactive.mjs +++ b/examples/test-interactive.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing interactive command detection...'); diff --git a/examples/test-interpolation.mjs b/examples/test-interpolation.mjs index 26bc76a..2462278 100644 --- a/examples/test-interpolation.mjs +++ b/examples/test-interpolation.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function testInterpolation() { const name = 'World'; diff --git a/examples/test-interrupt.mjs b/examples/test-interrupt.mjs index b1c59ac..761a07c 100755 --- a/examples/test-interrupt.mjs +++ b/examples/test-interrupt.mjs @@ -2,7 +2,7 @@ // Automated test for interruption handling -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function test() { console.log('Testing interruption of virtual sleep command...'); diff --git a/examples/test-issue-135-comprehensive.mjs b/examples/test-issue-135-comprehensive.mjs index 3f8d574..e02f097 100755 --- a/examples/test-issue-135-comprehensive.mjs +++ b/examples/test-issue-135-comprehensive.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Comprehensive test for issue #135: Trace logs interfere with output -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log( '=== Test 1: Default (no env vars, mirror:false, capture:true) ===' diff --git a/examples/test-issue12-detailed.mjs b/examples/test-issue12-detailed.mjs index 304bad9..69e3825 100644 --- a/examples/test-issue12-detailed.mjs +++ b/examples/test-issue12-detailed.mjs @@ -4,7 +4,7 @@ // Original issue: https://github.com/link-foundation/command-stream/issues/12 // Original error: ENOENT: no such file or directory, posix_spawn ''/Users/konard/.claude/local/claude'' -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const claude = process.env.CLAUDE_PATH || '/Users/konard/.claude/local/claude'; diff --git a/examples/test-issue12-exact.mjs b/examples/test-issue12-exact.mjs index b3054c2..5145708 100644 --- a/examples/test-issue12-exact.mjs +++ b/examples/test-issue12-exact.mjs @@ -4,7 +4,7 @@ // Original issue: https://github.com/link-foundation/command-stream/issues/12 // Original error: ENOENT: no such file or directory, posix_spawn ''/Users/konard/.claude/local/claude'' -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const claude = process.env.CLAUDE_PATH || '/Users/konard/.claude/local/claude'; diff --git a/examples/test-jq-color.mjs b/examples/test-jq-color.mjs index 23fed91..e49dc67 100644 --- a/examples/test-jq-color.mjs +++ b/examples/test-jq-color.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing jq Color Output ===\n'); diff --git a/examples/test-jq-colors.mjs b/examples/test-jq-colors.mjs index 8c5b733..c1fa9d3 100755 --- a/examples/test-jq-colors.mjs +++ b/examples/test-jq-colors.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing jq color output in pipelines ===\n'); diff --git a/examples/test-jq-pipeline-behavior.mjs b/examples/test-jq-pipeline-behavior.mjs index e9ade07..5188e6a 100644 --- a/examples/test-jq-pipeline-behavior.mjs +++ b/examples/test-jq-pipeline-behavior.mjs @@ -4,7 +4,7 @@ * Test to demonstrate jq's color behavior in different contexts */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { execSync } from 'child_process'; const testJson = '{"message": "hello", "number": 42}'; diff --git a/examples/test-jq-realtime.mjs b/examples/test-jq-realtime.mjs index cc06ab2..3ed67e0 100755 --- a/examples/test-jq-realtime.mjs +++ b/examples/test-jq-realtime.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing Real-Time jq Streaming ===\n'); diff --git a/examples/test-manual-start.mjs b/examples/test-manual-start.mjs index 8635cc4..5d523ef 100644 --- a/examples/test-manual-start.mjs +++ b/examples/test-manual-start.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function testManualStart() { console.log('๐Ÿงช Testing manual start with pipe stdin'); diff --git a/examples/test-mixed-quoting.mjs b/examples/test-mixed-quoting.mjs index 85a15f3..f53046a 100644 --- a/examples/test-mixed-quoting.mjs +++ b/examples/test-mixed-quoting.mjs @@ -3,7 +3,7 @@ // Test: Mixed quoted and unquoted arguments // Expected: Each argument properly handled based on its content -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test: Mixed Quoting Scenarios ===\n'); diff --git a/examples/test-multistage-debug.mjs b/examples/test-multistage-debug.mjs index ddba6d1..b0cc043 100755 --- a/examples/test-multistage-debug.mjs +++ b/examples/test-multistage-debug.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Debug Multi-Stage Pipeline ===\n'); diff --git a/examples/test-native-spawn-vs-command-stream.mjs b/examples/test-native-spawn-vs-command-stream.mjs index 09b6c71..acad1c0 100755 --- a/examples/test-native-spawn-vs-command-stream.mjs +++ b/examples/test-native-spawn-vs-command-stream.mjs @@ -6,7 +6,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing Native spawn vs command-stream kill capabilities ==='); console.log(''); diff --git a/examples/test-no-parse-pipeline.mjs b/examples/test-no-parse-pipeline.mjs index c54f1d0..176bd32 100755 --- a/examples/test-no-parse-pipeline.mjs +++ b/examples/test-no-parse-pipeline.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing: Disable pipeline parsing, let sh handle it\n'); diff --git a/examples/test-non-virtual.mjs b/examples/test-non-virtual.mjs index 7f0edeb..40b1a20 100644 --- a/examples/test-non-virtual.mjs +++ b/examples/test-non-virtual.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function testNonVirtual() { console.log('๐Ÿงช Testing with definitely non-virtual command'); diff --git a/examples/test-operators.mjs b/examples/test-operators.mjs index 5bf6e18..c3d4238 100644 --- a/examples/test-operators.mjs +++ b/examples/test-operators.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; enableVirtualCommands(); shell.verbose(true); diff --git a/examples/test-parent-continues.mjs b/examples/test-parent-continues.mjs index 2cf3e00..c77dd73 100755 --- a/examples/test-parent-continues.mjs +++ b/examples/test-parent-continues.mjs @@ -2,7 +2,7 @@ // Test that parent process continues after child is interrupted -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function test() { console.log('Testing that parent continues after child interruption...\n'); diff --git a/examples/test-path-interpolation.mjs b/examples/test-path-interpolation.mjs index a21fc8f..6dc6b09 100644 --- a/examples/test-path-interpolation.mjs +++ b/examples/test-path-interpolation.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing Path Interpolation Issues ===\n'); diff --git a/examples/test-ping-kill-and-stdin.mjs b/examples/test-ping-kill-and-stdin.mjs index 6a6faf1..cfcb966 100755 --- a/examples/test-ping-kill-and-stdin.mjs +++ b/examples/test-ping-kill-and-stdin.mjs @@ -6,7 +6,7 @@ * 2. kill() method works to interrupt ping commands */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing ping kill() and streams.stdin ==='); console.log(''); diff --git a/examples/test-ping.mjs b/examples/test-ping.mjs index 2f7d7cb..8dac6c3 100755 --- a/examples/test-ping.mjs +++ b/examples/test-ping.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test ping example similar to hive-mind/claude-pipe/test-ping.mjs -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('STARTING_PING'); try { diff --git a/examples/test-quote-behavior-summary.mjs b/examples/test-quote-behavior-summary.mjs index e48067e..170898d 100644 --- a/examples/test-quote-behavior-summary.mjs +++ b/examples/test-quote-behavior-summary.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Comprehensive test of the smart quoting behavior -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Smart Quoting Behavior Summary ===\n'); diff --git a/examples/test-quote-edge-cases.mjs b/examples/test-quote-edge-cases.mjs index 87906d3..4560ccd 100644 --- a/examples/test-quote-edge-cases.mjs +++ b/examples/test-quote-edge-cases.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test quoting edge cases for issue #12 -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing Quote Edge Cases for Issue #12 ===\n'); diff --git a/examples/test-quote-parsing.mjs b/examples/test-quote-parsing.mjs index cdb51a3..948962f 100644 --- a/examples/test-quote-parsing.mjs +++ b/examples/test-quote-parsing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { parseShellCommand } from '../src/shell-parser.mjs'; +import { parseShellCommand } from '../js/src/shell-parser.mjs'; const tests = [ 'cd "/tmp/my dir"', diff --git a/examples/test-raw-function.mjs b/examples/test-raw-function.mjs index 7d33104..143ef05 100755 --- a/examples/test-raw-function.mjs +++ b/examples/test-raw-function.mjs @@ -3,7 +3,7 @@ // Example: Using raw() to disable auto-escape for trusted command strings // This demonstrates the solution to issue #139 -import { $, raw } from '../src/$.mjs'; +import { $, raw } from '../js/src/$.mjs'; console.log('=== raw() Function Examples ===\n'); diff --git a/examples/test-raw-streaming.mjs b/examples/test-raw-streaming.mjs index 3503553..1f10fa7 100755 --- a/examples/test-raw-streaming.mjs +++ b/examples/test-raw-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing Raw Streaming (no jq) ===\n'); diff --git a/examples/test-readme-examples.mjs b/examples/test-readme-examples.mjs index 6a69723..8492d24 100644 --- a/examples/test-readme-examples.mjs +++ b/examples/test-readme-examples.mjs @@ -4,7 +4,7 @@ * Test the README examples to ensure they work correctly */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('๐Ÿงช Testing README Examples'); console.log('='.repeat(40)); diff --git a/examples/test-real-cat.mjs b/examples/test-real-cat.mjs index a20a6bc..c464679 100644 --- a/examples/test-real-cat.mjs +++ b/examples/test-real-cat.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function testRealCat() { console.log('Testing real cat (not virtual) with streams.stdin...'); diff --git a/examples/test-real-commands.mjs b/examples/test-real-commands.mjs index f24c40f..5172eef 100755 --- a/examples/test-real-commands.mjs +++ b/examples/test-real-commands.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Test with real commands only (no virtual echo):\n'); diff --git a/examples/test-real-shell.mjs b/examples/test-real-shell.mjs index e7594fb..8952fed 100755 --- a/examples/test-real-shell.mjs +++ b/examples/test-real-shell.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function testRealShellCommands() { console.log('Testing with real shell commands...'); diff --git a/examples/test-real-stdin-commands.mjs b/examples/test-real-stdin-commands.mjs index 846f356..0ebf036 100755 --- a/examples/test-real-stdin-commands.mjs +++ b/examples/test-real-stdin-commands.mjs @@ -4,7 +4,7 @@ * Test commands that actually read and respond to stdin */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing commands that ACTUALLY read stdin ==='); console.log(''); diff --git a/examples/test-runner.mjs b/examples/test-runner.mjs index 9a94ef9..8e956c3 100755 --- a/examples/test-runner.mjs +++ b/examples/test-runner.mjs @@ -5,7 +5,7 @@ * This helps identify test issues and ensures all tests pass in isolation */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { readdirSync } from 'fs'; import { join, basename } from 'path'; diff --git a/examples/test-sh-pipeline.mjs b/examples/test-sh-pipeline.mjs index 277be76..f236dba 100755 --- a/examples/test-sh-pipeline.mjs +++ b/examples/test-sh-pipeline.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing pipeline executed via sh -c:'); console.log('This should stream in real-time\n'); diff --git a/examples/test-shell-detection.mjs b/examples/test-shell-detection.mjs index f7b8c73..21f1bee 100755 --- a/examples/test-shell-detection.mjs +++ b/examples/test-shell-detection.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test script to reproduce Bun shell path detection issues -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Shell Detection Test ==='); console.log( diff --git a/examples/test-shell-parser.mjs b/examples/test-shell-parser.mjs index df46893..e55d369 100644 --- a/examples/test-shell-parser.mjs +++ b/examples/test-shell-parser.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { parseShellCommand, needsRealShell } from '../src/shell-parser.mjs'; +import { parseShellCommand, needsRealShell } from '../js/src/shell-parser.mjs'; const testCases = [ 'cd /tmp', diff --git a/examples/test-sigint-behavior.mjs b/examples/test-sigint-behavior.mjs index 3426d2d..57fb308 100755 --- a/examples/test-sigint-behavior.mjs +++ b/examples/test-sigint-behavior.mjs @@ -7,7 +7,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing SIGINT behavior'); diff --git a/examples/test-simple-pipe.mjs b/examples/test-simple-pipe.mjs index ca9880d..39059cb 100755 --- a/examples/test-simple-pipe.mjs +++ b/examples/test-simple-pipe.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Simple pipe test:'); diff --git a/examples/test-simple-streaming.mjs b/examples/test-simple-streaming.mjs index 2e2a2e4..237fc83 100644 --- a/examples/test-simple-streaming.mjs +++ b/examples/test-simple-streaming.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; -import { trace } from '../src/$.utils.mjs'; +import { $ } from '../js/src/$.mjs'; +import { trace } from '../js/src/$.utils.mjs'; async function testSimpleStreaming() { trace('TestExample', '๐Ÿงช Testing simple streaming after fix'); diff --git a/examples/test-smart-quoting.mjs b/examples/test-smart-quoting.mjs index 226e0c7..bec1459 100644 --- a/examples/test-smart-quoting.mjs +++ b/examples/test-smart-quoting.mjs @@ -3,7 +3,7 @@ // Test smart quoting behavior for interpolated strings // We need to preserve user-provided quotes while still auto-quoting when necessary -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Smart Quoting Tests ===\n'); diff --git a/examples/test-spaces-in-path.mjs b/examples/test-spaces-in-path.mjs index 9589429..fa86e60 100644 --- a/examples/test-spaces-in-path.mjs +++ b/examples/test-spaces-in-path.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; import { mkdtempSync, rmSync, mkdirSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/examples/test-special-chars-quoting.mjs b/examples/test-special-chars-quoting.mjs index b578836..95a2b26 100644 --- a/examples/test-special-chars-quoting.mjs +++ b/examples/test-special-chars-quoting.mjs @@ -3,7 +3,7 @@ // Test: Quoting strings with special characters // Expected: Proper escaping and quoting for shell safety -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test: Special Characters Quoting ===\n'); diff --git a/examples/test-stdin-after-start.mjs b/examples/test-stdin-after-start.mjs index 7aa8eb9..2467b0f 100755 --- a/examples/test-stdin-after-start.mjs +++ b/examples/test-stdin-after-start.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test stdin access after process starts ==='); diff --git a/examples/test-stdin-simple.mjs b/examples/test-stdin-simple.mjs index eae4b52..550ee2e 100755 --- a/examples/test-stdin-simple.mjs +++ b/examples/test-stdin-simple.mjs @@ -4,7 +4,7 @@ * Simple focused test for streams.stdin functionality */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing streams.stdin simple functionality ==='); diff --git a/examples/test-stdin-timing.mjs b/examples/test-stdin-timing.mjs index 4051ac0..dc4d2fa 100755 --- a/examples/test-stdin-timing.mjs +++ b/examples/test-stdin-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test stdin timing with proper flow ==='); diff --git a/examples/test-stdio-combinations.mjs b/examples/test-stdio-combinations.mjs index 210aae1..4538bc1 100755 --- a/examples/test-stdio-combinations.mjs +++ b/examples/test-stdio-combinations.mjs @@ -4,7 +4,7 @@ * Test different stdio combinations with streams interface */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing stdio combinations with streams interface ==='); console.log(''); diff --git a/examples/test-stream-access.mjs b/examples/test-stream-access.mjs index d07978d..8c6b450 100644 --- a/examples/test-stream-access.mjs +++ b/examples/test-stream-access.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function testStreamAccess() { console.log('Testing event-driven stream access (no setTimeout)...\n'); diff --git a/examples/test-stream-cleanup.mjs b/examples/test-stream-cleanup.mjs index aaa8460..5b9ad61 100755 --- a/examples/test-stream-cleanup.mjs +++ b/examples/test-stream-cleanup.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing stream cleanup...'); diff --git a/examples/test-streaming-final.mjs b/examples/test-streaming-final.mjs index cf2f89e..7a2c319 100755 --- a/examples/test-streaming-final.mjs +++ b/examples/test-streaming-final.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Final Real-Time Streaming Test ===\n'); diff --git a/examples/test-streaming-interfaces.mjs b/examples/test-streaming-interfaces.mjs index a2565ed..89ff3a0 100755 --- a/examples/test-streaming-interfaces.mjs +++ b/examples/test-streaming-interfaces.mjs @@ -12,7 +12,7 @@ * node examples/test-streaming-interfaces.mjs */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('='.repeat(60)); console.log('TESTING NEW STREAMING INTERFACES (Issue #33)'); diff --git a/examples/test-streaming-timing.mjs b/examples/test-streaming-timing.mjs index c7cae52..4c7747d 100644 --- a/examples/test-streaming-timing.mjs +++ b/examples/test-streaming-timing.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function test() { console.log('Starting test...'); diff --git a/examples/test-streaming.mjs b/examples/test-streaming.mjs index c4205c9..8f63214 100644 --- a/examples/test-streaming.mjs +++ b/examples/test-streaming.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function testStreaming() { console.log('Testing basic cat with streams.stdin...'); diff --git a/examples/test-streams-stdin-comprehensive.mjs b/examples/test-streams-stdin-comprehensive.mjs index 9ff15b5..ae1a685 100755 --- a/examples/test-streams-stdin-comprehensive.mjs +++ b/examples/test-streams-stdin-comprehensive.mjs @@ -7,7 +7,7 @@ * - Testing with commands that actually read stdin */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing streams.stdin comprehensive functionality ==='); console.log(''); diff --git a/examples/test-streams-stdin-ctrl-c.mjs b/examples/test-streams-stdin-ctrl-c.mjs index 7ac2dd4..eaeef29 100755 --- a/examples/test-streams-stdin-ctrl-c.mjs +++ b/examples/test-streams-stdin-ctrl-c.mjs @@ -4,7 +4,7 @@ * Test to verify that streams.stdin can be used to send CTRL+C to interrupt commands */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing streams.stdin CTRL+C functionality ==='); console.log(''); diff --git a/examples/test-template-literal.mjs b/examples/test-template-literal.mjs index dd92a40..7a9b95a 100644 --- a/examples/test-template-literal.mjs +++ b/examples/test-template-literal.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; enableVirtualCommands(); shell.verbose(true); diff --git a/examples/test-template-vs-interpolation.mjs b/examples/test-template-vs-interpolation.mjs index dacd28d..577d029 100644 --- a/examples/test-template-vs-interpolation.mjs +++ b/examples/test-template-vs-interpolation.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test the difference between template literals and string interpolation -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/examples/test-timing.mjs b/examples/test-timing.mjs index afa073c..bd81b99 100755 --- a/examples/test-timing.mjs +++ b/examples/test-timing.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing exact timing of cancellation...'); diff --git a/examples/test-top-inherit-stdout-stdin-control.mjs b/examples/test-top-inherit-stdout-stdin-control.mjs index 30a065d..cba2b51 100755 --- a/examples/test-top-inherit-stdout-stdin-control.mjs +++ b/examples/test-top-inherit-stdout-stdin-control.mjs @@ -5,7 +5,7 @@ * This demonstrates the key requirement: inherit stdout but control stdin independently */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing top with inherit stdout + streams.stdin control ==='); console.log(''); diff --git a/examples/test-top-quit-stdin.mjs b/examples/test-top-quit-stdin.mjs index 94cb973..1553e8b 100755 --- a/examples/test-top-quit-stdin.mjs +++ b/examples/test-top-quit-stdin.mjs @@ -5,7 +5,7 @@ * This demonstrates stdin control for interactive commands that actually read stdin */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Testing top command quit via streams.stdin ==='); console.log(''); diff --git a/examples/test-trace-option.mjs b/examples/test-trace-option.mjs index e66aa50..58588b7 100755 --- a/examples/test-trace-option.mjs +++ b/examples/test-trace-option.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test the trace option in $ config -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Test: mirror:false with trace:false in CI environment ==='); process.env.CI = 'true'; diff --git a/examples/test-user-double-quotes.mjs b/examples/test-user-double-quotes.mjs index 104a3dd..d00f516 100644 --- a/examples/test-user-double-quotes.mjs +++ b/examples/test-user-double-quotes.mjs @@ -3,7 +3,7 @@ // Test: User provides double quotes around interpolated value // Expected: Preserve double quotes (wrapped in single quotes for shell) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const claude = '/Users/konard/.claude/local/claude'; diff --git a/examples/test-user-single-quotes.mjs b/examples/test-user-single-quotes.mjs index f147456..f6bffdc 100644 --- a/examples/test-user-single-quotes.mjs +++ b/examples/test-user-single-quotes.mjs @@ -3,7 +3,7 @@ // Test: User provides single quotes around interpolated value // Expected: Preserve single quotes without double-escaping -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const claude = '/Users/konard/.claude/local/claude'; diff --git a/examples/test-verbose.mjs b/examples/test-verbose.mjs index c57b06f..b55729f 100755 --- a/examples/test-verbose.mjs +++ b/examples/test-verbose.mjs @@ -1,4 +1,4 @@ -import { $, shell } from '../src/$.mjs'; +import { $, shell } from '../js/src/$.mjs'; const originalLog = console.log; const capturedLogs = []; diff --git a/examples/test-verbose2.mjs b/examples/test-verbose2.mjs index 70f389f..5e2eec2 100755 --- a/examples/test-verbose2.mjs +++ b/examples/test-verbose2.mjs @@ -1,4 +1,4 @@ -import { $, shell } from '../src/$.mjs'; +import { $, shell } from '../js/src/$.mjs'; const originalLog = console.log; const capturedLogs = []; diff --git a/examples/test-virtual-streaming.mjs b/examples/test-virtual-streaming.mjs index e251392..8999a28 100755 --- a/examples/test-virtual-streaming.mjs +++ b/examples/test-virtual-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $, register } from '../src/$.mjs'; +import { $, register } from '../js/src/$.mjs'; console.log('=== Testing Virtual Command Streaming ===\n'); diff --git a/examples/test-waiting-command.mjs b/examples/test-waiting-command.mjs index 3772bdd..d5570d6 100644 --- a/examples/test-waiting-command.mjs +++ b/examples/test-waiting-command.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; async function testWaitingCommand() { console.log('๐Ÿงช Testing with command that truly waits'); diff --git a/examples/test-waiting-commands.mjs b/examples/test-waiting-commands.mjs index ffc92fe..36989d8 100755 --- a/examples/test-waiting-commands.mjs +++ b/examples/test-waiting-commands.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Commands that definitely wait for stdin ==='); diff --git a/examples/test-watch-mode.mjs b/examples/test-watch-mode.mjs index 64238ca..56e03eb 100755 --- a/examples/test-watch-mode.mjs +++ b/examples/test-watch-mode.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { promises as fs } from 'fs'; import { spawn } from 'child_process'; import os from 'os'; diff --git a/examples/test-yes-cancellation.mjs b/examples/test-yes-cancellation.mjs index b51efea..9882b76 100755 --- a/examples/test-yes-cancellation.mjs +++ b/examples/test-yes-cancellation.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing yes command cancellation...'); diff --git a/examples/test-yes-detailed.mjs b/examples/test-yes-detailed.mjs index e7e903b..26b267e 100755 --- a/examples/test-yes-detailed.mjs +++ b/examples/test-yes-detailed.mjs @@ -1,10 +1,10 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing yes command cancellation in detail...'); // Test 1: Direct generator usage console.log('\n=== Test 1: Direct generator test ==='); -import yesCommand from '../src/commands/$.yes.mjs'; +import yesCommand from '../js/src/commands/$.yes.mjs'; let cancelled = false; const abortController = new AbortController(); diff --git a/examples/test-yes-trace.mjs b/examples/test-yes-trace.mjs index 8cf0316..b2cd04c 100755 --- a/examples/test-yes-trace.mjs +++ b/examples/test-yes-trace.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing yes command stopping...'); diff --git a/examples/trace-abort-controller.mjs b/examples/trace-abort-controller.mjs index f56ac74..9802c05 100755 --- a/examples/trace-abort-controller.mjs +++ b/examples/trace-abort-controller.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-abort-controller.mjs */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing AbortController with tracing...'); diff --git a/examples/trace-error-handling.mjs b/examples/trace-error-handling.mjs index a1060dc..68bfe01 100755 --- a/examples/trace-error-handling.mjs +++ b/examples/trace-error-handling.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-error-handling.mjs */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing error handling with tracing...'); diff --git a/examples/trace-pipeline-command.mjs b/examples/trace-pipeline-command.mjs index b1e144c..0dd7860 100755 --- a/examples/trace-pipeline-command.mjs +++ b/examples/trace-pipeline-command.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-pipeline-command.mjs */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing pipeline command with tracing...'); diff --git a/examples/trace-signal-handling.mjs b/examples/trace-signal-handling.mjs index 4370cb3..0dfe593 100755 --- a/examples/trace-signal-handling.mjs +++ b/examples/trace-signal-handling.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-signal-handling.mjs */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing signal handling with tracing...'); diff --git a/examples/trace-simple-command.mjs b/examples/trace-simple-command.mjs index 4d8cca4..5ef6e5e 100755 --- a/examples/trace-simple-command.mjs +++ b/examples/trace-simple-command.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-simple-command.mjs */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing simple command execution with tracing...'); diff --git a/examples/trace-stderr-output.mjs b/examples/trace-stderr-output.mjs index 182c97e..7e823a7 100755 --- a/examples/trace-stderr-output.mjs +++ b/examples/trace-stderr-output.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-stderr-output.mjs */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing stderr output with tracing...'); diff --git a/examples/verify-fix-both-runtimes.mjs b/examples/verify-fix-both-runtimes.mjs index cf158b9..ea47534 100644 --- a/examples/verify-fix-both-runtimes.mjs +++ b/examples/verify-fix-both-runtimes.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Verification script that works in both Bun and Node.js -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; const runtime = typeof globalThis.Bun !== 'undefined' ? 'Bun' : 'Node.js'; console.log(`=== Fix Verification for ${runtime} ===`); diff --git a/examples/verify-issue12-fixed.mjs b/examples/verify-issue12-fixed.mjs index a16ad74..4a9beef 100644 --- a/examples/verify-issue12-fixed.mjs +++ b/examples/verify-issue12-fixed.mjs @@ -4,7 +4,7 @@ // Issue: https://github.com/link-foundation/command-stream/issues/12 // Original error had double quotes: posix_spawn ''/Users/konard/.claude/local/claude'' -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { spawn } from 'child_process'; console.log('=== Issue #12 Fix Verification ===\n'); diff --git a/examples/which-command-common-commands.mjs b/examples/which-command-common-commands.mjs index de52604..c19632c 100755 --- a/examples/which-command-common-commands.mjs +++ b/examples/which-command-common-commands.mjs @@ -2,7 +2,7 @@ // Testing with other common commands -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing with other common commands:'); const commands = ['sh', 'ls', 'cat', 'grep']; diff --git a/examples/which-command-gh-test.mjs b/examples/which-command-gh-test.mjs index d79bb9b..27e3fbc 100755 --- a/examples/which-command-gh-test.mjs +++ b/examples/which-command-gh-test.mjs @@ -2,7 +2,7 @@ // Testing which gh (the command from GitHub issue #7) -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing which gh (the command from the GitHub issue):'); try { diff --git a/examples/which-command-nonexistent.mjs b/examples/which-command-nonexistent.mjs index 0ebab35..27a4895 100755 --- a/examples/which-command-nonexistent.mjs +++ b/examples/which-command-nonexistent.mjs @@ -2,7 +2,7 @@ // Testing non-existent command -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Testing non-existent command:'); try { diff --git a/examples/which-command-system-comparison.mjs b/examples/which-command-system-comparison.mjs index b2ecbbc..04c4fc8 100755 --- a/examples/which-command-system-comparison.mjs +++ b/examples/which-command-system-comparison.mjs @@ -2,7 +2,7 @@ // Comparing with system /usr/bin/which -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('Comparing with system /usr/bin/which:'); try { diff --git a/examples/working-example.mjs b/examples/working-example.mjs index 00b3fd7..68dc3e9 100755 --- a/examples/working-example.mjs +++ b/examples/working-example.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Simple working example - generate numbers with delay to see real streaming console.log('๐Ÿš€ Real streaming example'); diff --git a/examples/working-stdin-examples.mjs b/examples/working-stdin-examples.mjs index 342d814..d899cbc 100755 --- a/examples/working-stdin-examples.mjs +++ b/examples/working-stdin-examples.mjs @@ -4,7 +4,7 @@ * Working examples of stdin control that account for async process spawning */ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Working stdin control examples ==='); diff --git a/examples/working-streaming-demo.mjs b/examples/working-streaming-demo.mjs index 41ea4b6..04ecc42 100755 --- a/examples/working-streaming-demo.mjs +++ b/examples/working-streaming-demo.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; console.log('=== Working Streaming Examples (without pipes) ===\n'); diff --git a/src/$.mjs b/js/src/$.mjs similarity index 100% rename from src/$.mjs rename to js/src/$.mjs diff --git a/src/$.utils.mjs b/js/src/$.utils.mjs similarity index 100% rename from src/$.utils.mjs rename to js/src/$.utils.mjs diff --git a/src/commands/$.basename.mjs b/js/src/commands/$.basename.mjs similarity index 100% rename from src/commands/$.basename.mjs rename to js/src/commands/$.basename.mjs diff --git a/src/commands/$.cat.mjs b/js/src/commands/$.cat.mjs similarity index 100% rename from src/commands/$.cat.mjs rename to js/src/commands/$.cat.mjs diff --git a/src/commands/$.cd.mjs b/js/src/commands/$.cd.mjs similarity index 100% rename from src/commands/$.cd.mjs rename to js/src/commands/$.cd.mjs diff --git a/src/commands/$.cp.mjs b/js/src/commands/$.cp.mjs similarity index 100% rename from src/commands/$.cp.mjs rename to js/src/commands/$.cp.mjs diff --git a/src/commands/$.dirname.mjs b/js/src/commands/$.dirname.mjs similarity index 100% rename from src/commands/$.dirname.mjs rename to js/src/commands/$.dirname.mjs diff --git a/src/commands/$.echo.mjs b/js/src/commands/$.echo.mjs similarity index 100% rename from src/commands/$.echo.mjs rename to js/src/commands/$.echo.mjs diff --git a/src/commands/$.env.mjs b/js/src/commands/$.env.mjs similarity index 100% rename from src/commands/$.env.mjs rename to js/src/commands/$.env.mjs diff --git a/src/commands/$.exit.mjs b/js/src/commands/$.exit.mjs similarity index 100% rename from src/commands/$.exit.mjs rename to js/src/commands/$.exit.mjs diff --git a/src/commands/$.false.mjs b/js/src/commands/$.false.mjs similarity index 100% rename from src/commands/$.false.mjs rename to js/src/commands/$.false.mjs diff --git a/src/commands/$.ls.mjs b/js/src/commands/$.ls.mjs similarity index 100% rename from src/commands/$.ls.mjs rename to js/src/commands/$.ls.mjs diff --git a/src/commands/$.mkdir.mjs b/js/src/commands/$.mkdir.mjs similarity index 100% rename from src/commands/$.mkdir.mjs rename to js/src/commands/$.mkdir.mjs diff --git a/src/commands/$.mv.mjs b/js/src/commands/$.mv.mjs similarity index 100% rename from src/commands/$.mv.mjs rename to js/src/commands/$.mv.mjs diff --git a/src/commands/$.pwd.mjs b/js/src/commands/$.pwd.mjs similarity index 100% rename from src/commands/$.pwd.mjs rename to js/src/commands/$.pwd.mjs diff --git a/src/commands/$.rm.mjs b/js/src/commands/$.rm.mjs similarity index 100% rename from src/commands/$.rm.mjs rename to js/src/commands/$.rm.mjs diff --git a/src/commands/$.seq.mjs b/js/src/commands/$.seq.mjs similarity index 100% rename from src/commands/$.seq.mjs rename to js/src/commands/$.seq.mjs diff --git a/src/commands/$.sleep.mjs b/js/src/commands/$.sleep.mjs similarity index 100% rename from src/commands/$.sleep.mjs rename to js/src/commands/$.sleep.mjs diff --git a/src/commands/$.test.mjs b/js/src/commands/$.test.mjs similarity index 100% rename from src/commands/$.test.mjs rename to js/src/commands/$.test.mjs diff --git a/src/commands/$.touch.mjs b/js/src/commands/$.touch.mjs similarity index 100% rename from src/commands/$.touch.mjs rename to js/src/commands/$.touch.mjs diff --git a/src/commands/$.true.mjs b/js/src/commands/$.true.mjs similarity index 100% rename from src/commands/$.true.mjs rename to js/src/commands/$.true.mjs diff --git a/src/commands/$.which.mjs b/js/src/commands/$.which.mjs similarity index 100% rename from src/commands/$.which.mjs rename to js/src/commands/$.which.mjs diff --git a/src/commands/$.yes.mjs b/js/src/commands/$.yes.mjs similarity index 100% rename from src/commands/$.yes.mjs rename to js/src/commands/$.yes.mjs diff --git a/src/shell-parser.mjs b/js/src/shell-parser.mjs similarity index 100% rename from src/shell-parser.mjs rename to js/src/shell-parser.mjs diff --git a/package.json b/package.json index 63c0274..2f95963 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "version": "0.8.3", "description": "Modern $ shell utility library with streaming, async iteration, and EventEmitter support, optimized for Bun runtime", "type": "module", - "main": "src/$.mjs", + "main": "js/src/$.mjs", "exports": { - ".": "./src/$.mjs" + ".": "./js/src/$.mjs" }, "repository": { "type": "git", @@ -54,7 +54,8 @@ "node": ">=20.0.0" }, "files": [ - "src/", + "js/", + "rust/", "README.md", "LICENSE" ], diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 0000000..e283685 --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "command-stream" +version = "0.8.3" +edition = "2021" +authors = ["link-foundation"] +description = "Modern shell command execution library with streaming, async iteration, and event support" +license = "Unlicense" +repository = "https://github.com/link-foundation/command-stream" +keywords = ["shell", "command", "streaming", "async", "process"] +categories = ["command-line-utilities", "asynchronous"] +readme = "../README.md" + +[lib] +name = "command_stream" +path = "src/lib.rs" + +[[bin]] +name = "command-stream" +path = "src/main.rs" + +[dependencies] +tokio = { version = "1.43", features = ["full", "process", "signal"] } +async-trait = "0.1" +thiserror = "2.0" +once_cell = "1.20" +regex = "1.11" +serde = { version = "1.0", features = ["derive"], optional = true } +serde_json = { version = "1.0", optional = true } +nix = { version = "0.29", features = ["signal", "process"] } +libc = "0.2" +which = "7.0" +glob = "0.3" +chrono = "0.4" +filetime = "0.2" + +[dev-dependencies] +tokio-test = "0.4" +tempfile = "3.14" +assert_cmd = "2.0" + +[features] +default = [] +json = ["serde", "serde_json"] + +[profile.release] +opt-level = 3 +lto = true diff --git a/rust/src/commands/basename.rs b/rust/src/commands/basename.rs new file mode 100644 index 0000000..704d7d9 --- /dev/null +++ b/rust/src/commands/basename.rs @@ -0,0 +1,69 @@ +//! Virtual `basename` command implementation + +use crate::commands::CommandContext; +use crate::utils::{CommandResult, VirtualUtils}; +use std::path::Path; + +/// Execute the basename command +/// +/// Strips directory and suffix from filenames. +pub async fn basename(ctx: CommandContext) -> CommandResult { + if ctx.args.is_empty() { + return VirtualUtils::missing_operand_error("basename"); + } + + let path = &ctx.args[0]; + let suffix = ctx.args.get(1); + + let base = Path::new(path) + .file_name() + .map(|n| n.to_string_lossy().to_string()) + .unwrap_or_default(); + + let result = if let Some(suf) = suffix { + if base.ends_with(suf.as_str()) { + base[..base.len() - suf.len()].to_string() + } else { + base + } + } else { + base + }; + + CommandResult::success(format!("{}\n", result)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_basename_simple() { + let ctx = CommandContext::new(vec!["/path/to/file.txt".to_string()]); + let result = basename(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "file.txt\n"); + } + + #[tokio::test] + async fn test_basename_with_suffix() { + let ctx = CommandContext::new(vec![ + "/path/to/file.txt".to_string(), + ".txt".to_string(), + ]); + let result = basename(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "file\n"); + } + + #[tokio::test] + async fn test_basename_no_path() { + let ctx = CommandContext::new(vec!["file.txt".to_string()]); + let result = basename(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "file.txt\n"); + } +} diff --git a/rust/src/commands/cat.rs b/rust/src/commands/cat.rs new file mode 100644 index 0000000..70447c8 --- /dev/null +++ b/rust/src/commands/cat.rs @@ -0,0 +1,123 @@ +//! Virtual `cat` command implementation + +use crate::commands::CommandContext; +use crate::utils::{trace_lazy, CommandResult, VirtualUtils}; +use std::fs; + +/// Execute the cat command +/// +/// Concatenates and displays file contents. +pub async fn cat(ctx: CommandContext) -> CommandResult { + if ctx.args.is_empty() { + // Read from stdin if no files specified + if let Some(ref stdin) = ctx.stdin { + if !stdin.is_empty() { + return CommandResult::success(stdin.clone()); + } + } + return CommandResult::success_empty(); + } + + let cwd = ctx.get_cwd(); + let mut outputs = Vec::new(); + + for file in &ctx.args { + // Check for cancellation before processing each file + if ctx.is_cancelled() { + trace_lazy("VirtualCommand", || { + "cat: cancelled while processing files".to_string() + }); + return CommandResult::error_with_code("", 130); // SIGINT exit code + } + + trace_lazy("VirtualCommand", || { + format!("cat: reading file {:?}", file) + }); + + let resolved_path = VirtualUtils::resolve_path(file, Some(&cwd)); + + match fs::read_to_string(&resolved_path) { + Ok(content) => { + outputs.push(content); + } + Err(e) => { + let error_msg = if e.kind() == std::io::ErrorKind::NotFound { + format!("cat: {}: No such file or directory\n", file) + } else if e.kind() == std::io::ErrorKind::IsADirectory + || (e.kind() == std::io::ErrorKind::Other && e.to_string().contains("directory")) + { + format!("cat: {}: Is a directory\n", file) + } else { + format!("cat: {}: {}\n", file, e) + }; + return CommandResult::error(error_msg); + } + } + } + + let output = outputs.join(""); + trace_lazy("VirtualCommand", || { + format!("cat: success, bytes read: {}", output.len()) + }); + + CommandResult::success(output) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Write; + use tempfile::NamedTempFile; + + #[tokio::test] + async fn test_cat_file() { + let mut temp = NamedTempFile::new().unwrap(); + writeln!(temp, "Hello, World!").unwrap(); + + let ctx = CommandContext::new(vec![ + temp.path().to_string_lossy().to_string() + ]); + let result = cat(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "Hello, World!\n"); + } + + #[tokio::test] + async fn test_cat_stdin() { + let mut ctx = CommandContext::new(vec![]); + ctx.stdin = Some("stdin content".to_string()); + + let result = cat(ctx).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "stdin content"); + } + + #[tokio::test] + async fn test_cat_nonexistent() { + let ctx = CommandContext::new(vec![ + "/nonexistent/file/12345".to_string() + ]); + let result = cat(ctx).await; + + assert!(!result.is_success()); + assert!(result.stderr.contains("No such file or directory")); + } + + #[tokio::test] + async fn test_cat_multiple_files() { + let mut temp1 = NamedTempFile::new().unwrap(); + let mut temp2 = NamedTempFile::new().unwrap(); + write!(temp1, "file1").unwrap(); + write!(temp2, "file2").unwrap(); + + let ctx = CommandContext::new(vec![ + temp1.path().to_string_lossy().to_string(), + temp2.path().to_string_lossy().to_string(), + ]); + let result = cat(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "file1file2"); + } +} diff --git a/rust/src/commands/cd.rs b/rust/src/commands/cd.rs new file mode 100644 index 0000000..a0e9f88 --- /dev/null +++ b/rust/src/commands/cd.rs @@ -0,0 +1,67 @@ +//! Virtual `cd` command implementation + +use crate::commands::CommandContext; +use crate::utils::{trace, CommandResult}; +use std::env; +use std::path::PathBuf; + +/// Execute the cd command +/// +/// Changes the current working directory. +pub async fn cd(ctx: CommandContext) -> CommandResult { + let target = if ctx.args.is_empty() { + // No argument - go to home directory + env::var("HOME") + .or_else(|_| env::var("USERPROFILE")) + .unwrap_or_else(|_| "/".to_string()) + } else { + ctx.args[0].clone() + }; + + trace("VirtualCommand", &format!("cd: changing directory to {:?}", target)); + + let path = PathBuf::from(&target); + + match env::set_current_dir(&path) { + Ok(()) => { + let new_dir = env::current_dir() + .map(|p| p.display().to_string()) + .unwrap_or_default(); + trace("VirtualCommand", &format!("cd: success, new dir: {}", new_dir)); + // cd command should not output anything on success + CommandResult::success_empty() + } + Err(e) => { + trace("VirtualCommand", &format!("cd: failed: {}", e)); + CommandResult::error(format!("cd: {}\n", e)) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::tempdir; + + #[tokio::test] + async fn test_cd_to_temp() { + let temp = tempdir().unwrap(); + let temp_path = temp.path().to_string_lossy().to_string(); + let original_dir = env::current_dir().unwrap(); + + let ctx = CommandContext::new(vec![temp_path.clone()]); + let result = cd(ctx).await; + assert!(result.is_success()); + assert_eq!(result.stdout, ""); + + // Restore original directory + env::set_current_dir(original_dir).unwrap(); + } + + #[tokio::test] + async fn test_cd_to_nonexistent() { + let ctx = CommandContext::new(vec!["/nonexistent/path/12345".to_string()]); + let result = cd(ctx).await; + assert!(!result.is_success()); + } +} diff --git a/rust/src/commands/cp.rs b/rust/src/commands/cp.rs new file mode 100644 index 0000000..adee339 --- /dev/null +++ b/rust/src/commands/cp.rs @@ -0,0 +1,187 @@ +//! Virtual `cp` command implementation + +use crate::commands::CommandContext; +use crate::utils::{trace_lazy, CommandResult, VirtualUtils}; +use std::fs; +use std::path::Path; + +/// Execute the cp command +/// +/// Copies files and directories. +pub async fn cp(ctx: CommandContext) -> CommandResult { + if ctx.args.len() < 2 { + return VirtualUtils::invalid_argument_error("cp", "missing file operand"); + } + + // Parse flags + let mut recursive = false; + let mut paths = Vec::new(); + + for arg in &ctx.args { + if arg == "-r" || arg == "-R" || arg == "--recursive" { + recursive = true; + } else if arg.starts_with('-') { + if arg.contains('r') || arg.contains('R') { + recursive = true; + } + } else { + paths.push(arg.clone()); + } + } + + if paths.len() < 2 { + return VirtualUtils::invalid_argument_error("cp", "missing destination file operand"); + } + + let cwd = ctx.get_cwd(); + let dest = paths.pop().unwrap(); + let dest_path = VirtualUtils::resolve_path(&dest, Some(&cwd)); + + // If multiple sources or dest is a directory, copy into the directory + let dest_is_dir = dest_path.is_dir(); + let multiple_sources = paths.len() > 1; + + if multiple_sources && !dest_is_dir { + return CommandResult::error(format!( + "cp: target '{}' is not a directory\n", + dest + )); + } + + for source in paths { + let source_path = VirtualUtils::resolve_path(&source, Some(&cwd)); + + trace_lazy("VirtualCommand", || { + format!("cp: copying {:?} to {:?}", source_path, dest_path) + }); + + if !source_path.exists() { + return CommandResult::error(format!( + "cp: cannot stat '{}': No such file or directory\n", + source + )); + } + + let final_dest = if dest_is_dir { + dest_path.join(source_path.file_name().unwrap_or_default()) + } else { + dest_path.clone() + }; + + if source_path.is_dir() { + if !recursive { + return CommandResult::error(format!( + "cp: -r not specified; omitting directory '{}'\n", + source + )); + } + + if let Err(e) = copy_dir_recursive(&source_path, &final_dest) { + return CommandResult::error(format!( + "cp: cannot copy '{}': {}\n", + source, e + )); + } + } else { + if let Some(parent) = final_dest.parent() { + if !parent.exists() { + if let Err(e) = fs::create_dir_all(parent) { + return CommandResult::error(format!( + "cp: cannot create directory '{}': {}\n", + parent.display(), e + )); + } + } + } + + if let Err(e) = fs::copy(&source_path, &final_dest) { + return CommandResult::error(format!( + "cp: cannot copy '{}': {}\n", + source, e + )); + } + } + } + + CommandResult::success_empty() +} + +fn copy_dir_recursive(src: &Path, dst: &Path) -> std::io::Result<()> { + fs::create_dir_all(dst)?; + + for entry in fs::read_dir(src)? { + let entry = entry?; + let entry_path = entry.path(); + let dest_path = dst.join(entry.file_name()); + + if entry_path.is_dir() { + copy_dir_recursive(&entry_path, &dest_path)?; + } else { + fs::copy(&entry_path, &dest_path)?; + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::tempdir; + + #[tokio::test] + async fn test_cp_file() { + let temp = tempdir().unwrap(); + let src = temp.path().join("source.txt"); + let dst = temp.path().join("dest.txt"); + fs::write(&src, "test content").unwrap(); + + let ctx = CommandContext::new(vec![ + src.to_string_lossy().to_string(), + dst.to_string_lossy().to_string(), + ]); + let result = cp(ctx).await; + + assert!(result.is_success()); + assert!(dst.exists()); + assert_eq!(fs::read_to_string(&dst).unwrap(), "test content"); + } + + #[tokio::test] + async fn test_cp_directory_recursive() { + let temp = tempdir().unwrap(); + let src_dir = temp.path().join("src_dir"); + let dst_dir = temp.path().join("dst_dir"); + + fs::create_dir(&src_dir).unwrap(); + fs::write(src_dir.join("file.txt"), "test").unwrap(); + + let ctx = CommandContext::new(vec![ + "-r".to_string(), + src_dir.to_string_lossy().to_string(), + dst_dir.to_string_lossy().to_string(), + ]); + let result = cp(ctx).await; + + assert!(result.is_success()); + assert!(dst_dir.join("file.txt").exists()); + } + + #[tokio::test] + async fn test_cp_directory_without_recursive() { + let temp = tempdir().unwrap(); + let src_dir = temp.path().join("src_dir"); + let dst_dir = temp.path().join("dst_dir"); + + fs::create_dir(&src_dir).unwrap(); + + let ctx = CommandContext::new(vec![ + src_dir.to_string_lossy().to_string(), + dst_dir.to_string_lossy().to_string(), + ]); + let result = cp(ctx).await; + + assert!(!result.is_success()); + assert!(result.stderr.contains("-r not specified")); + } +} diff --git a/rust/src/commands/dirname.rs b/rust/src/commands/dirname.rs new file mode 100644 index 0000000..b8668b5 --- /dev/null +++ b/rust/src/commands/dirname.rs @@ -0,0 +1,57 @@ +//! Virtual `dirname` command implementation + +use crate::commands::CommandContext; +use crate::utils::{CommandResult, VirtualUtils}; +use std::path::Path; + +/// Execute the dirname command +/// +/// Strips the last component from filenames. +pub async fn dirname(ctx: CommandContext) -> CommandResult { + if ctx.args.is_empty() { + return VirtualUtils::missing_operand_error("dirname"); + } + + let path = &ctx.args[0]; + let parent = Path::new(path) + .parent() + .map(|p| p.to_string_lossy().to_string()) + .unwrap_or_else(|| ".".to_string()); + + // Handle empty parent (file in current directory) + let result = if parent.is_empty() { "." } else { &parent }; + + CommandResult::success(format!("{}\n", result)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_dirname_simple() { + let ctx = CommandContext::new(vec!["/path/to/file.txt".to_string()]); + let result = dirname(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "/path/to\n"); + } + + #[tokio::test] + async fn test_dirname_just_file() { + let ctx = CommandContext::new(vec!["file.txt".to_string()]); + let result = dirname(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, ".\n"); + } + + #[tokio::test] + async fn test_dirname_root() { + let ctx = CommandContext::new(vec!["/file.txt".to_string()]); + let result = dirname(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "/\n"); + } +} diff --git a/rust/src/commands/echo.rs b/rust/src/commands/echo.rs new file mode 100644 index 0000000..0383493 --- /dev/null +++ b/rust/src/commands/echo.rs @@ -0,0 +1,33 @@ +//! Virtual `echo` command implementation + +use crate::commands::CommandContext; +use crate::utils::CommandResult; + +/// Execute the echo command +/// +/// Outputs the arguments separated by spaces, followed by a newline. +pub async fn echo(ctx: CommandContext) -> CommandResult { + let output = ctx.args.join(" "); + CommandResult::success(format!("{}\n", output)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_echo_simple() { + let ctx = CommandContext::new(vec!["hello".to_string(), "world".to_string()]); + let result = echo(ctx).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "hello world\n"); + } + + #[tokio::test] + async fn test_echo_empty() { + let ctx = CommandContext::new(vec![]); + let result = echo(ctx).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "\n"); + } +} diff --git a/rust/src/commands/env.rs b/rust/src/commands/env.rs new file mode 100644 index 0000000..6491fe3 --- /dev/null +++ b/rust/src/commands/env.rs @@ -0,0 +1,33 @@ +//! Virtual `env` command implementation + +use crate::commands::CommandContext; +use crate::utils::CommandResult; +use std::env; + +/// Execute the env command +/// +/// Displays environment variables. +pub async fn env(_ctx: CommandContext) -> CommandResult { + let mut output = String::new(); + + for (key, value) in env::vars() { + output.push_str(&format!("{}={}\n", key, value)); + } + + CommandResult::success(output) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_env() { + let ctx = CommandContext::new(vec![]); + let result = env(ctx).await; + + assert!(result.is_success()); + // Should contain at least PATH or HOME + assert!(result.stdout.contains("PATH=") || result.stdout.contains("HOME=")); + } +} diff --git a/rust/src/commands/exit.rs b/rust/src/commands/exit.rs new file mode 100644 index 0000000..857186c --- /dev/null +++ b/rust/src/commands/exit.rs @@ -0,0 +1,36 @@ +//! Virtual `exit` command implementation + +use crate::commands::CommandContext; +use crate::utils::CommandResult; + +/// Execute the exit command +/// +/// Exits with the specified code (default 0). +/// Note: This doesn't actually exit the process, it returns the exit code. +pub async fn exit(ctx: CommandContext) -> CommandResult { + let code: i32 = ctx.args + .first() + .and_then(|s| s.parse().ok()) + .unwrap_or(0); + + CommandResult::error_with_code("", code) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_exit_default() { + let ctx = CommandContext::new(vec![]); + let result = exit(ctx).await; + assert_eq!(result.code, 0); + } + + #[tokio::test] + async fn test_exit_with_code() { + let ctx = CommandContext::new(vec!["42".to_string()]); + let result = exit(ctx).await; + assert_eq!(result.code, 42); + } +} diff --git a/rust/src/commands/false.rs b/rust/src/commands/false.rs new file mode 100644 index 0000000..046cbeb --- /dev/null +++ b/rust/src/commands/false.rs @@ -0,0 +1,24 @@ +//! Virtual `false` command implementation + +use crate::commands::CommandContext; +use crate::utils::CommandResult; + +/// Execute the false command +/// +/// Always returns failure (exit code 1). +pub async fn r#false(_ctx: CommandContext) -> CommandResult { + CommandResult::error_with_code("", 1) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_false() { + let ctx = CommandContext::new(vec![]); + let result = r#false(ctx).await; + assert!(!result.is_success()); + assert_eq!(result.code, 1); + } +} diff --git a/rust/src/commands/ls.rs b/rust/src/commands/ls.rs new file mode 100644 index 0000000..9faec6e --- /dev/null +++ b/rust/src/commands/ls.rs @@ -0,0 +1,182 @@ +//! Virtual `ls` command implementation + +use crate::commands::CommandContext; +use crate::utils::{trace_lazy, CommandResult}; +use std::fs; +use std::path::Path; + +/// Execute the ls command +/// +/// Lists directory contents. +pub async fn ls(ctx: CommandContext) -> CommandResult { + // Parse flags + let mut show_all = false; + let mut long_format = false; + let mut paths = Vec::new(); + + for arg in &ctx.args { + if arg == "-a" || arg == "--all" { + show_all = true; + } else if arg == "-l" { + long_format = true; + } else if arg == "-la" || arg == "-al" { + show_all = true; + long_format = true; + } else if arg.starts_with('-') { + if arg.contains('a') { + show_all = true; + } + if arg.contains('l') { + long_format = true; + } + } else { + paths.push(arg.clone()); + } + } + + // Default to current directory + if paths.is_empty() { + paths.push(".".to_string()); + } + + let cwd = ctx.get_cwd(); + let mut outputs = Vec::new(); + + for path_str in paths { + let resolved_path = if Path::new(&path_str).is_absolute() { + Path::new(&path_str).to_path_buf() + } else { + cwd.join(&path_str) + }; + + trace_lazy("VirtualCommand", || { + format!("ls: listing {:?}", resolved_path) + }); + + if !resolved_path.exists() { + return CommandResult::error(format!( + "ls: cannot access '{}': No such file or directory\n", + path_str + )); + } + + if resolved_path.is_file() { + outputs.push(format_entry(&resolved_path, long_format)); + } else { + match fs::read_dir(&resolved_path) { + Ok(entries) => { + let mut entry_strs = Vec::new(); + + for entry in entries { + if let Ok(entry) = entry { + let name = entry.file_name().to_string_lossy().to_string(); + + // Skip hidden files unless -a is specified + if !show_all && name.starts_with('.') { + continue; + } + + if long_format { + entry_strs.push(format_entry(&entry.path(), true)); + } else { + entry_strs.push(name); + } + } + } + + entry_strs.sort(); + outputs.push(entry_strs.join("\n")); + } + Err(e) => { + return CommandResult::error(format!("ls: cannot open '{}': {}\n", path_str, e)); + } + } + } + } + + let output = outputs.join("\n"); + if output.is_empty() { + CommandResult::success_empty() + } else { + CommandResult::success(format!("{}\n", output)) + } +} + +fn format_entry(path: &Path, long_format: bool) -> String { + let name = path.file_name() + .map(|n| n.to_string_lossy().to_string()) + .unwrap_or_else(|| path.display().to_string()); + + if !long_format { + return name; + } + + // Long format: permissions, links, owner, group, size, date, name + let metadata = match fs::metadata(path) { + Ok(m) => m, + Err(_) => return name, + }; + + let file_type = if metadata.is_dir() { "d" } else { "-" }; + let size = metadata.len(); + + // Simplified permissions + let perms = if metadata.is_dir() { + "drwxr-xr-x" + } else { + "-rw-r--r--" + }; + + format!("{} {:>8} {}", perms, size, name) +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::tempdir; + + #[tokio::test] + async fn test_ls_current_dir() { + let ctx = CommandContext::new(vec![]); + let result = ls(ctx).await; + assert!(result.is_success()); + } + + #[tokio::test] + async fn test_ls_with_path() { + let temp = tempdir().unwrap(); + fs::write(temp.path().join("file.txt"), "test").unwrap(); + + let ctx = CommandContext::new(vec![ + temp.path().to_string_lossy().to_string() + ]); + let result = ls(ctx).await; + + assert!(result.is_success()); + assert!(result.stdout.contains("file.txt")); + } + + #[tokio::test] + async fn test_ls_hidden_files() { + let temp = tempdir().unwrap(); + fs::write(temp.path().join(".hidden"), "test").unwrap(); + fs::write(temp.path().join("visible"), "test").unwrap(); + + // Without -a + let ctx = CommandContext::new(vec![ + temp.path().to_string_lossy().to_string() + ]); + let result = ls(ctx).await; + assert!(!result.stdout.contains(".hidden")); + assert!(result.stdout.contains("visible")); + + // With -a + let ctx = CommandContext::new(vec![ + "-a".to_string(), + temp.path().to_string_lossy().to_string(), + ]); + let result = ls(ctx).await; + assert!(result.stdout.contains(".hidden")); + assert!(result.stdout.contains("visible")); + } +} diff --git a/rust/src/commands/mkdir.rs b/rust/src/commands/mkdir.rs new file mode 100644 index 0000000..4605222 --- /dev/null +++ b/rust/src/commands/mkdir.rs @@ -0,0 +1,98 @@ +//! Virtual `mkdir` command implementation + +use crate::commands::CommandContext; +use crate::utils::{trace_lazy, CommandResult, VirtualUtils}; +use std::fs; + +/// Execute the mkdir command +/// +/// Creates directories. +pub async fn mkdir(ctx: CommandContext) -> CommandResult { + if ctx.args.is_empty() { + return VirtualUtils::missing_operand_error("mkdir"); + } + + // Check for -p flag + let mut create_parents = false; + let mut dirs = Vec::new(); + + for arg in &ctx.args { + if arg == "-p" { + create_parents = true; + } else if arg.starts_with('-') { + // Skip other flags + } else { + dirs.push(arg.clone()); + } + } + + if dirs.is_empty() { + return VirtualUtils::missing_operand_error("mkdir"); + } + + let cwd = ctx.get_cwd(); + + for dir in dirs { + let resolved_path = VirtualUtils::resolve_path(&dir, Some(&cwd)); + + trace_lazy("VirtualCommand", || { + format!("mkdir: creating directory {:?}, parents: {}", resolved_path, create_parents) + }); + + let result = if create_parents { + fs::create_dir_all(&resolved_path) + } else { + fs::create_dir(&resolved_path) + }; + + if let Err(e) = result { + return CommandResult::error(format!("mkdir: cannot create directory '{}': {}\n", dir, e)); + } + } + + CommandResult::success_empty() +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::tempdir; + + #[tokio::test] + async fn test_mkdir_simple() { + let temp = tempdir().unwrap(); + let new_dir = temp.path().join("new_directory"); + + let ctx = CommandContext::new(vec![ + new_dir.to_string_lossy().to_string() + ]); + let result = mkdir(ctx).await; + + assert!(result.is_success()); + assert!(new_dir.exists()); + } + + #[tokio::test] + async fn test_mkdir_with_parents() { + let temp = tempdir().unwrap(); + let nested_dir = temp.path().join("a/b/c/d"); + + let ctx = CommandContext::new(vec![ + "-p".to_string(), + nested_dir.to_string_lossy().to_string(), + ]); + let result = mkdir(ctx).await; + + assert!(result.is_success()); + assert!(nested_dir.exists()); + } + + #[tokio::test] + async fn test_mkdir_missing_operand() { + let ctx = CommandContext::new(vec![]); + let result = mkdir(ctx).await; + + assert!(!result.is_success()); + assert!(result.stderr.contains("missing operand")); + } +} diff --git a/rust/src/commands/mod.rs b/rust/src/commands/mod.rs new file mode 100644 index 0000000..0d4cf1b --- /dev/null +++ b/rust/src/commands/mod.rs @@ -0,0 +1,188 @@ +//! Virtual command implementations +//! +//! This module contains implementations of shell commands that run in-process +//! without spawning external processes. These provide faster execution and +//! consistent behavior across platforms. + +mod cat; +mod cd; +mod echo; +mod pwd; +mod sleep; +mod r#true; +mod r#false; +mod mkdir; +mod rm; +mod touch; +mod ls; +mod cp; +mod mv; +mod basename; +mod dirname; +mod env; +mod exit; +mod which; +mod yes; +mod seq; +mod test; + +pub use cat::cat; +pub use cd::cd; +pub use echo::echo; +pub use pwd::pwd; +pub use sleep::sleep; +pub use r#true::r#true; +pub use r#false::r#false; +pub use mkdir::mkdir; +pub use rm::rm; +pub use touch::touch; +pub use ls::ls; +pub use cp::cp; +pub use mv::mv; +pub use basename::basename; +pub use dirname::dirname; +pub use env::env; +pub use exit::exit; +pub use which::which; +pub use yes::yes; +pub use seq::seq; +pub use test::test; + +use crate::utils::CommandResult; +use std::collections::HashMap; +use std::path::Path; +use tokio::sync::mpsc; + +/// Context for virtual command execution +#[derive(Debug)] +pub struct CommandContext { + /// Command arguments (excluding the command name) + pub args: Vec, + /// Standard input content + pub stdin: Option, + /// Current working directory + pub cwd: Option, + /// Environment variables + pub env: Option>, + /// Channel to send streaming output + pub output_tx: Option>, + /// Cancellation check function + pub is_cancelled: Option bool + Send + Sync>>, +} + +/// A chunk of streaming output +#[derive(Debug, Clone)] +pub enum StreamChunk { + Stdout(String), + Stderr(String), +} + +impl CommandContext { + /// Create a new command context with arguments + pub fn new(args: Vec) -> Self { + CommandContext { + args, + stdin: None, + cwd: None, + env: None, + output_tx: None, + is_cancelled: None, + } + } + + /// Check if the command has been cancelled + pub fn is_cancelled(&self) -> bool { + self.is_cancelled + .as_ref() + .map(|f| f()) + .unwrap_or(false) + } + + /// Get the current working directory + pub fn get_cwd(&self) -> std::path::PathBuf { + self.cwd.clone().unwrap_or_else(|| { + std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("/")) + }) + } +} + +/// Type for virtual command handler functions +pub type VirtualCommandHandler = fn(CommandContext) -> std::pin::Pin + Send>>; + +/// Registry of virtual commands +pub struct VirtualCommandRegistry { + commands: HashMap, +} + +impl Default for VirtualCommandRegistry { + fn default() -> Self { + Self::new() + } +} + +impl VirtualCommandRegistry { + /// Create a new empty registry + pub fn new() -> Self { + VirtualCommandRegistry { + commands: HashMap::new(), + } + } + + /// Create a registry with all built-in commands registered + pub fn with_builtins() -> Self { + let mut registry = Self::new(); + registry.register_builtins(); + registry + } + + /// Register a virtual command + pub fn register(&mut self, name: &str, handler: VirtualCommandHandler) { + self.commands.insert(name.to_string(), handler); + } + + /// Unregister a virtual command + pub fn unregister(&mut self, name: &str) -> bool { + self.commands.remove(name).is_some() + } + + /// Get a virtual command handler + pub fn get(&self, name: &str) -> Option<&VirtualCommandHandler> { + self.commands.get(name) + } + + /// Check if a command is registered + pub fn contains(&self, name: &str) -> bool { + self.commands.contains_key(name) + } + + /// List all registered command names + pub fn list(&self) -> Vec<&str> { + self.commands.keys().map(|s| s.as_str()).collect() + } + + /// Register all built-in commands + pub fn register_builtins(&mut self) { + // Note: These are placeholder registrations - actual async handlers + // would need proper wrapper functions + // The actual commands are available as standalone functions + } +} + +/// Global virtual commands enabled flag +static VIRTUAL_COMMANDS_ENABLED: std::sync::atomic::AtomicBool = + std::sync::atomic::AtomicBool::new(true); + +/// Enable virtual commands +pub fn enable_virtual_commands() { + VIRTUAL_COMMANDS_ENABLED.store(true, std::sync::atomic::Ordering::SeqCst); +} + +/// Disable virtual commands +pub fn disable_virtual_commands() { + VIRTUAL_COMMANDS_ENABLED.store(false, std::sync::atomic::Ordering::SeqCst); +} + +/// Check if virtual commands are enabled +pub fn are_virtual_commands_enabled() -> bool { + VIRTUAL_COMMANDS_ENABLED.load(std::sync::atomic::Ordering::SeqCst) +} diff --git a/rust/src/commands/mv.rs b/rust/src/commands/mv.rs new file mode 100644 index 0000000..8485f6c --- /dev/null +++ b/rust/src/commands/mv.rs @@ -0,0 +1,180 @@ +//! Virtual `mv` command implementation + +use crate::commands::CommandContext; +use crate::utils::{trace_lazy, CommandResult, VirtualUtils}; +use std::fs; + +/// Execute the mv command +/// +/// Moves (renames) files and directories. +pub async fn mv(ctx: CommandContext) -> CommandResult { + if ctx.args.len() < 2 { + return VirtualUtils::invalid_argument_error("mv", "missing file operand"); + } + + // Parse flags (currently just skip them) + let mut paths = Vec::new(); + + for arg in &ctx.args { + if !arg.starts_with('-') { + paths.push(arg.clone()); + } + } + + if paths.len() < 2 { + return VirtualUtils::invalid_argument_error("mv", "missing destination file operand"); + } + + let cwd = ctx.get_cwd(); + let dest = paths.pop().unwrap(); + let dest_path = VirtualUtils::resolve_path(&dest, Some(&cwd)); + + // If multiple sources or dest is a directory, move into the directory + let dest_is_dir = dest_path.is_dir(); + let multiple_sources = paths.len() > 1; + + if multiple_sources && !dest_is_dir { + return CommandResult::error(format!( + "mv: target '{}' is not a directory\n", + dest + )); + } + + for source in paths { + let source_path = VirtualUtils::resolve_path(&source, Some(&cwd)); + + trace_lazy("VirtualCommand", || { + format!("mv: moving {:?} to {:?}", source_path, dest_path) + }); + + if !source_path.exists() { + return CommandResult::error(format!( + "mv: cannot stat '{}': No such file or directory\n", + source + )); + } + + let final_dest = if dest_is_dir { + dest_path.join(source_path.file_name().unwrap_or_default()) + } else { + dest_path.clone() + }; + + // Try rename first (fastest if on same filesystem) + match fs::rename(&source_path, &final_dest) { + Ok(()) => continue, + Err(e) => { + // If rename fails (e.g., cross-filesystem), try copy + delete + if e.kind() == std::io::ErrorKind::CrossesDevices + || e.kind() == std::io::ErrorKind::Other + { + if source_path.is_dir() { + if let Err(e) = copy_and_remove_dir(&source_path, &final_dest) { + return CommandResult::error(format!( + "mv: cannot move '{}': {}\n", + source, e + )); + } + } else { + if let Err(e) = fs::copy(&source_path, &final_dest) { + return CommandResult::error(format!( + "mv: cannot move '{}': {}\n", + source, e + )); + } + if let Err(e) = fs::remove_file(&source_path) { + return CommandResult::error(format!( + "mv: cannot remove '{}': {}\n", + source, e + )); + } + } + } else { + return CommandResult::error(format!( + "mv: cannot move '{}': {}\n", + source, e + )); + } + } + } + } + + CommandResult::success_empty() +} + +fn copy_and_remove_dir(src: &std::path::Path, dst: &std::path::Path) -> std::io::Result<()> { + fs::create_dir_all(dst)?; + + for entry in fs::read_dir(src)? { + let entry = entry?; + let entry_path = entry.path(); + let dest_path = dst.join(entry.file_name()); + + if entry_path.is_dir() { + copy_and_remove_dir(&entry_path, &dest_path)?; + } else { + fs::copy(&entry_path, &dest_path)?; + } + } + + fs::remove_dir_all(src)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::tempdir; + + #[tokio::test] + async fn test_mv_file() { + let temp = tempdir().unwrap(); + let src = temp.path().join("source.txt"); + let dst = temp.path().join("dest.txt"); + fs::write(&src, "test content").unwrap(); + + let ctx = CommandContext::new(vec![ + src.to_string_lossy().to_string(), + dst.to_string_lossy().to_string(), + ]); + let result = mv(ctx).await; + + assert!(result.is_success()); + assert!(!src.exists()); + assert!(dst.exists()); + assert_eq!(fs::read_to_string(&dst).unwrap(), "test content"); + } + + #[tokio::test] + async fn test_mv_directory() { + let temp = tempdir().unwrap(); + let src_dir = temp.path().join("src_dir"); + let dst_dir = temp.path().join("dst_dir"); + + fs::create_dir(&src_dir).unwrap(); + fs::write(src_dir.join("file.txt"), "test").unwrap(); + + let ctx = CommandContext::new(vec![ + src_dir.to_string_lossy().to_string(), + dst_dir.to_string_lossy().to_string(), + ]); + let result = mv(ctx).await; + + assert!(result.is_success()); + assert!(!src_dir.exists()); + assert!(dst_dir.join("file.txt").exists()); + } + + #[tokio::test] + async fn test_mv_nonexistent() { + let temp = tempdir().unwrap(); + + let ctx = CommandContext::new(vec![ + "/nonexistent/file".to_string(), + temp.path().join("dest").to_string_lossy().to_string(), + ]); + let result = mv(ctx).await; + + assert!(!result.is_success()); + } +} diff --git a/rust/src/commands/pwd.rs b/rust/src/commands/pwd.rs new file mode 100644 index 0000000..acf0fee --- /dev/null +++ b/rust/src/commands/pwd.rs @@ -0,0 +1,28 @@ +//! Virtual `pwd` command implementation + +use crate::commands::CommandContext; +use crate::utils::CommandResult; +use std::env; + +/// Execute the pwd command +/// +/// Prints the current working directory. +pub async fn pwd(_ctx: CommandContext) -> CommandResult { + match env::current_dir() { + Ok(path) => CommandResult::success(format!("{}\n", path.display())), + Err(e) => CommandResult::error(format!("pwd: {}\n", e)), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_pwd() { + let ctx = CommandContext::new(vec![]); + let result = pwd(ctx).await; + assert!(result.is_success()); + assert!(!result.stdout.is_empty()); + } +} diff --git a/rust/src/commands/rm.rs b/rust/src/commands/rm.rs new file mode 100644 index 0000000..42b10ff --- /dev/null +++ b/rust/src/commands/rm.rs @@ -0,0 +1,150 @@ +//! Virtual `rm` command implementation + +use crate::commands::CommandContext; +use crate::utils::{trace_lazy, CommandResult, VirtualUtils}; +use std::fs; + +/// Execute the rm command +/// +/// Removes files and directories. +pub async fn rm(ctx: CommandContext) -> CommandResult { + if ctx.args.is_empty() { + return VirtualUtils::missing_operand_error("rm"); + } + + // Parse flags + let mut recursive = false; + let mut force = false; + let mut paths = Vec::new(); + + for arg in &ctx.args { + if arg == "-r" || arg == "-R" || arg == "--recursive" { + recursive = true; + } else if arg == "-f" || arg == "--force" { + force = true; + } else if arg == "-rf" || arg == "-fr" { + recursive = true; + force = true; + } else if arg.starts_with('-') { + // Check for combined flags like -rf + if arg.contains('r') || arg.contains('R') { + recursive = true; + } + if arg.contains('f') { + force = true; + } + } else { + paths.push(arg.clone()); + } + } + + if paths.is_empty() { + return VirtualUtils::missing_operand_error("rm"); + } + + let cwd = ctx.get_cwd(); + + for path_str in paths { + let resolved_path = VirtualUtils::resolve_path(&path_str, Some(&cwd)); + + trace_lazy("VirtualCommand", || { + format!("rm: removing {:?}, recursive: {}, force: {}", resolved_path, recursive, force) + }); + + if !resolved_path.exists() { + if !force { + return CommandResult::error(format!( + "rm: cannot remove '{}': No such file or directory\n", + path_str + )); + } + continue; + } + + let result = if resolved_path.is_dir() { + if recursive { + fs::remove_dir_all(&resolved_path) + } else { + return CommandResult::error(format!( + "rm: cannot remove '{}': Is a directory\n", + path_str + )); + } + } else { + fs::remove_file(&resolved_path) + }; + + if let Err(e) = result { + if !force { + return CommandResult::error(format!("rm: cannot remove '{}': {}\n", path_str, e)); + } + } + } + + CommandResult::success_empty() +} + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Write; + use tempfile::{tempdir, NamedTempFile}; + + #[tokio::test] + async fn test_rm_file() { + let mut temp = NamedTempFile::new().unwrap(); + writeln!(temp, "test").unwrap(); + let path = temp.path().to_path_buf(); + + // Keep the file but get the path + let path_str = path.to_string_lossy().to_string(); + drop(temp); + + // Create file again + fs::write(&path, "test").unwrap(); + + let ctx = CommandContext::new(vec![path_str.clone()]); + let result = rm(ctx).await; + + assert!(result.is_success()); + assert!(!path.exists()); + } + + #[tokio::test] + async fn test_rm_directory_recursive() { + let temp = tempdir().unwrap(); + let dir = temp.path().join("subdir"); + fs::create_dir(&dir).unwrap(); + fs::write(dir.join("file.txt"), "test").unwrap(); + + let ctx = CommandContext::new(vec![ + "-r".to_string(), + dir.to_string_lossy().to_string(), + ]); + let result = rm(ctx).await; + + assert!(result.is_success()); + assert!(!dir.exists()); + } + + #[tokio::test] + async fn test_rm_nonexistent_force() { + let ctx = CommandContext::new(vec![ + "-f".to_string(), + "/nonexistent/file/12345".to_string(), + ]); + let result = rm(ctx).await; + + assert!(result.is_success()); + } + + #[tokio::test] + async fn test_rm_nonexistent_no_force() { + let ctx = CommandContext::new(vec![ + "/nonexistent/file/12345".to_string() + ]); + let result = rm(ctx).await; + + assert!(!result.is_success()); + } +} diff --git a/rust/src/commands/seq.rs b/rust/src/commands/seq.rs new file mode 100644 index 0000000..a88af7c --- /dev/null +++ b/rust/src/commands/seq.rs @@ -0,0 +1,179 @@ +//! Virtual `seq` command implementation + +use crate::commands::CommandContext; +use crate::utils::{CommandResult, VirtualUtils}; + +/// Execute the seq command +/// +/// Prints a sequence of numbers. +pub async fn seq(ctx: CommandContext) -> CommandResult { + if ctx.args.is_empty() { + return VirtualUtils::missing_operand_error("seq"); + } + + let (first, increment, last) = match ctx.args.len() { + 1 => { + let last: f64 = match ctx.args[0].parse() { + Ok(n) => n, + Err(_) => { + return CommandResult::error(format!( + "seq: invalid floating point argument: '{}'\n", + ctx.args[0] + )); + } + }; + (1.0, 1.0, last) + } + 2 => { + let first: f64 = match ctx.args[0].parse() { + Ok(n) => n, + Err(_) => { + return CommandResult::error(format!( + "seq: invalid floating point argument: '{}'\n", + ctx.args[0] + )); + } + }; + let last: f64 = match ctx.args[1].parse() { + Ok(n) => n, + Err(_) => { + return CommandResult::error(format!( + "seq: invalid floating point argument: '{}'\n", + ctx.args[1] + )); + } + }; + (first, 1.0, last) + } + _ => { + let first: f64 = match ctx.args[0].parse() { + Ok(n) => n, + Err(_) => { + return CommandResult::error(format!( + "seq: invalid floating point argument: '{}'\n", + ctx.args[0] + )); + } + }; + let increment: f64 = match ctx.args[1].parse() { + Ok(n) => n, + Err(_) => { + return CommandResult::error(format!( + "seq: invalid floating point argument: '{}'\n", + ctx.args[1] + )); + } + }; + let last: f64 = match ctx.args[2].parse() { + Ok(n) => n, + Err(_) => { + return CommandResult::error(format!( + "seq: invalid floating point argument: '{}'\n", + ctx.args[2] + )); + } + }; + (first, increment, last) + } + }; + + if increment == 0.0 { + return CommandResult::error("seq: zero increment\n"); + } + + let mut output = String::new(); + let mut current = first; + + if increment > 0.0 { + while current <= last { + if ctx.is_cancelled() { + return CommandResult::error_with_code("", 130); + } + + // Format as integer if possible + if current.fract() == 0.0 { + output.push_str(&format!("{}\n", current as i64)); + } else { + output.push_str(&format!("{}\n", current)); + } + current += increment; + } + } else { + while current >= last { + if ctx.is_cancelled() { + return CommandResult::error_with_code("", 130); + } + + if current.fract() == 0.0 { + output.push_str(&format!("{}\n", current as i64)); + } else { + output.push_str(&format!("{}\n", current)); + } + current += increment; + } + } + + CommandResult::success(output) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_seq_single_arg() { + let ctx = CommandContext::new(vec!["5".to_string()]); + let result = seq(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "1\n2\n3\n4\n5\n"); + } + + #[tokio::test] + async fn test_seq_two_args() { + let ctx = CommandContext::new(vec!["3".to_string(), "7".to_string()]); + let result = seq(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "3\n4\n5\n6\n7\n"); + } + + #[tokio::test] + async fn test_seq_three_args() { + let ctx = CommandContext::new(vec![ + "2".to_string(), + "2".to_string(), + "8".to_string(), + ]); + let result = seq(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "2\n4\n6\n8\n"); + } + + #[tokio::test] + async fn test_seq_descending() { + let ctx = CommandContext::new(vec![ + "5".to_string(), + "-1".to_string(), + "1".to_string(), + ]); + let result = seq(ctx).await; + + assert!(result.is_success()); + assert_eq!(result.stdout, "5\n4\n3\n2\n1\n"); + } + + #[tokio::test] + async fn test_seq_zero_increment() { + let ctx = CommandContext::new(vec![ + "1".to_string(), + "0".to_string(), + "5".to_string(), + ]); + let result = seq(ctx).await; + + assert!(!result.is_success()); + assert!(result.stderr.contains("zero increment")); + } +} diff --git a/rust/src/commands/sleep.rs b/rust/src/commands/sleep.rs new file mode 100644 index 0000000..60adfd6 --- /dev/null +++ b/rust/src/commands/sleep.rs @@ -0,0 +1,97 @@ +//! Virtual `sleep` command implementation + +use crate::commands::CommandContext; +use crate::utils::{trace_lazy, CommandResult}; +use tokio::time::{sleep as tokio_sleep, Duration}; + +/// Execute the sleep command +/// +/// Pauses for the specified number of seconds. +pub async fn sleep(ctx: CommandContext) -> CommandResult { + let seconds_str = ctx.args.first().map(|s| s.as_str()).unwrap_or("0"); + + let seconds: f64 = match seconds_str.parse() { + Ok(s) => s, + Err(_) => { + return CommandResult::error(format!( + "sleep: invalid time interval '{}'\n", + seconds_str + )); + } + }; + + if seconds < 0.0 { + return CommandResult::error(format!( + "sleep: invalid time interval '{}'\n", + seconds_str + )); + } + + trace_lazy("VirtualCommand", || { + format!("sleep: starting {} seconds", seconds) + }); + + let duration = Duration::from_secs_f64(seconds); + + // Check for cancellation during sleep + tokio::select! { + _ = tokio_sleep(duration) => { + trace_lazy("VirtualCommand", || { + format!("sleep: completed naturally after {} seconds", seconds) + }); + CommandResult::success_empty() + } + _ = async { + loop { + tokio::time::sleep(Duration::from_millis(100)).await; + if ctx.is_cancelled() { + break; + } + } + } => { + trace_lazy("VirtualCommand", || { + format!("sleep: cancelled after partial sleep") + }); + CommandResult::error_with_code("", 130) // SIGINT exit code + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::time::Instant; + + #[tokio::test] + async fn test_sleep_short() { + let ctx = CommandContext::new(vec!["0.1".to_string()]); + let start = Instant::now(); + let result = sleep(ctx).await; + let elapsed = start.elapsed(); + + assert!(result.is_success()); + assert!(elapsed >= Duration::from_millis(100)); + assert!(elapsed < Duration::from_millis(200)); + } + + #[tokio::test] + async fn test_sleep_zero() { + let ctx = CommandContext::new(vec!["0".to_string()]); + let result = sleep(ctx).await; + assert!(result.is_success()); + } + + #[tokio::test] + async fn test_sleep_invalid() { + let ctx = CommandContext::new(vec!["invalid".to_string()]); + let result = sleep(ctx).await; + assert!(!result.is_success()); + } + + #[tokio::test] + async fn test_sleep_negative() { + let ctx = CommandContext::new(vec!["-1".to_string()]); + let result = sleep(ctx).await; + assert!(!result.is_success()); + } +} diff --git a/rust/src/commands/test.rs b/rust/src/commands/test.rs new file mode 100644 index 0000000..b6c273c --- /dev/null +++ b/rust/src/commands/test.rs @@ -0,0 +1,204 @@ +//! Virtual `test` command implementation + +use crate::commands::CommandContext; +use crate::utils::CommandResult; +use std::fs; +use std::path::Path; + +/// Execute the test command +/// +/// Evaluates conditional expressions. +pub async fn test(ctx: CommandContext) -> CommandResult { + if ctx.args.is_empty() { + return CommandResult::error_with_code("", 1); + } + + let result = evaluate_expression(&ctx.args); + + if result { + CommandResult::success_empty() + } else { + CommandResult::error_with_code("", 1) + } +} + +fn evaluate_expression(args: &[String]) -> bool { + if args.is_empty() { + return false; + } + + // Handle unary operators + if args.len() == 2 { + let op = &args[0]; + let arg = &args[1]; + + return match op.as_str() { + "-e" => Path::new(arg).exists(), + "-f" => Path::new(arg).is_file(), + "-d" => Path::new(arg).is_dir(), + "-r" => { + // Check if readable (simplified) + fs::metadata(arg).is_ok() + } + "-w" => { + // Check if writable (simplified) + fs::metadata(arg).map(|m| !m.permissions().readonly()).unwrap_or(false) + } + "-x" => { + // Check if executable (simplified - Unix only) + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + fs::metadata(arg) + .map(|m| m.permissions().mode() & 0o111 != 0) + .unwrap_or(false) + } + #[cfg(not(unix))] + { + Path::new(arg).exists() + } + } + "-s" => { + // Check if file has size > 0 + fs::metadata(arg).map(|m| m.len() > 0).unwrap_or(false) + } + "-z" => arg.is_empty(), + "-n" => !arg.is_empty(), + "!" => !evaluate_expression(&args[1..]), + _ => false, + }; + } + + // Handle binary operators + if args.len() == 3 { + let left = &args[0]; + let op = &args[1]; + let right = &args[2]; + + return match op.as_str() { + "=" | "==" => left == right, + "!=" => left != right, + "-eq" => { + let l: i64 = left.parse().unwrap_or(0); + let r: i64 = right.parse().unwrap_or(0); + l == r + } + "-ne" => { + let l: i64 = left.parse().unwrap_or(0); + let r: i64 = right.parse().unwrap_or(0); + l != r + } + "-lt" => { + let l: i64 = left.parse().unwrap_or(0); + let r: i64 = right.parse().unwrap_or(0); + l < r + } + "-le" => { + let l: i64 = left.parse().unwrap_or(0); + let r: i64 = right.parse().unwrap_or(0); + l <= r + } + "-gt" => { + let l: i64 = left.parse().unwrap_or(0); + let r: i64 = right.parse().unwrap_or(0); + l > r + } + "-ge" => { + let l: i64 = left.parse().unwrap_or(0); + let r: i64 = right.parse().unwrap_or(0); + l >= r + } + _ => false, + }; + } + + // Single argument: true if non-empty + if args.len() == 1 { + return !args[0].is_empty(); + } + + false +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::tempdir; + + #[tokio::test] + async fn test_file_exists() { + let temp = tempdir().unwrap(); + let file = temp.path().join("test.txt"); + fs::write(&file, "test").unwrap(); + + let ctx = CommandContext::new(vec![ + "-e".to_string(), + file.to_string_lossy().to_string(), + ]); + let result = test(ctx).await; + assert!(result.is_success()); + } + + #[tokio::test] + async fn test_file_not_exists() { + let ctx = CommandContext::new(vec![ + "-e".to_string(), + "/nonexistent/file/12345".to_string(), + ]); + let result = test(ctx).await; + assert!(!result.is_success()); + } + + #[tokio::test] + async fn test_string_equality() { + let ctx = CommandContext::new(vec![ + "hello".to_string(), + "=".to_string(), + "hello".to_string(), + ]); + let result = test(ctx).await; + assert!(result.is_success()); + } + + #[tokio::test] + async fn test_string_inequality() { + let ctx = CommandContext::new(vec![ + "hello".to_string(), + "!=".to_string(), + "world".to_string(), + ]); + let result = test(ctx).await; + assert!(result.is_success()); + } + + #[tokio::test] + async fn test_numeric_comparison() { + let ctx = CommandContext::new(vec![ + "5".to_string(), + "-gt".to_string(), + "3".to_string(), + ]); + let result = test(ctx).await; + assert!(result.is_success()); + } + + #[tokio::test] + async fn test_empty_string() { + let ctx = CommandContext::new(vec![ + "-z".to_string(), + "".to_string(), + ]); + let result = test(ctx).await; + assert!(result.is_success()); + } + + #[tokio::test] + async fn test_non_empty_string() { + let ctx = CommandContext::new(vec![ + "-n".to_string(), + "hello".to_string(), + ]); + let result = test(ctx).await; + assert!(result.is_success()); + } +} diff --git a/rust/src/commands/touch.rs b/rust/src/commands/touch.rs new file mode 100644 index 0000000..5f15bf5 --- /dev/null +++ b/rust/src/commands/touch.rs @@ -0,0 +1,99 @@ +//! Virtual `touch` command implementation + +use crate::commands::CommandContext; +use crate::utils::{trace_lazy, CommandResult, VirtualUtils}; +use std::fs::{self, OpenOptions}; +use std::time::SystemTime; + +/// Execute the touch command +/// +/// Updates file timestamps or creates empty files. +pub async fn touch(ctx: CommandContext) -> CommandResult { + if ctx.args.is_empty() { + return VirtualUtils::missing_operand_error("touch"); + } + + let cwd = ctx.get_cwd(); + + for file in &ctx.args { + if file.starts_with('-') { + // Skip flags for now + continue; + } + + let resolved_path = VirtualUtils::resolve_path(file, Some(&cwd)); + + trace_lazy("VirtualCommand", || { + format!("touch: touching {:?}", resolved_path) + }); + + if resolved_path.exists() { + // Update modification time + let now = SystemTime::now(); + if let Err(e) = filetime::set_file_mtime(&resolved_path, filetime::FileTime::from_system_time(now)) { + // Fallback: try to just open and close the file + if let Err(e2) = OpenOptions::new().write(true).open(&resolved_path) { + return CommandResult::error(format!("touch: cannot touch '{}': {}\n", file, e2)); + } + } + } else { + // Create the file + if let Some(parent) = resolved_path.parent() { + if !parent.exists() { + if let Err(e) = fs::create_dir_all(parent) { + return CommandResult::error(format!("touch: cannot touch '{}': {}\n", file, e)); + } + } + } + + if let Err(e) = fs::File::create(&resolved_path) { + return CommandResult::error(format!("touch: cannot touch '{}': {}\n", file, e)); + } + } + } + + CommandResult::success_empty() +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::tempdir; + + #[tokio::test] + async fn test_touch_new_file() { + let temp = tempdir().unwrap(); + let new_file = temp.path().join("new_file.txt"); + + let ctx = CommandContext::new(vec![ + new_file.to_string_lossy().to_string() + ]); + let result = touch(ctx).await; + + assert!(result.is_success()); + assert!(new_file.exists()); + } + + #[tokio::test] + async fn test_touch_existing_file() { + let temp = tempdir().unwrap(); + let file = temp.path().join("existing.txt"); + fs::write(&file, "test").unwrap(); + + let ctx = CommandContext::new(vec![ + file.to_string_lossy().to_string() + ]); + let result = touch(ctx).await; + + assert!(result.is_success()); + } + + #[tokio::test] + async fn test_touch_missing_operand() { + let ctx = CommandContext::new(vec![]); + let result = touch(ctx).await; + + assert!(!result.is_success()); + assert!(result.stderr.contains("missing operand")); + } +} diff --git a/rust/src/commands/true.rs b/rust/src/commands/true.rs new file mode 100644 index 0000000..5441029 --- /dev/null +++ b/rust/src/commands/true.rs @@ -0,0 +1,24 @@ +//! Virtual `true` command implementation + +use crate::commands::CommandContext; +use crate::utils::CommandResult; + +/// Execute the true command +/// +/// Always returns success (exit code 0). +pub async fn r#true(_ctx: CommandContext) -> CommandResult { + CommandResult::success_empty() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_true() { + let ctx = CommandContext::new(vec![]); + let result = r#true(ctx).await; + assert!(result.is_success()); + assert_eq!(result.code, 0); + } +} diff --git a/rust/src/commands/which.rs b/rust/src/commands/which.rs new file mode 100644 index 0000000..3853b81 --- /dev/null +++ b/rust/src/commands/which.rs @@ -0,0 +1,68 @@ +//! Virtual `which` command implementation + +use crate::commands::CommandContext; +use crate::utils::{CommandResult, VirtualUtils}; + +/// Execute the which command +/// +/// Locates commands in the PATH. +pub async fn which(ctx: CommandContext) -> CommandResult { + if ctx.args.is_empty() { + return VirtualUtils::missing_operand_error("which"); + } + + let mut output = String::new(); + let mut found_all = true; + + for cmd in &ctx.args { + if cmd.starts_with('-') { + continue; + } + + match which::which(cmd) { + Ok(path) => { + output.push_str(&format!("{}\n", path.display())); + } + Err(_) => { + found_all = false; + } + } + } + + if output.is_empty() { + CommandResult::error_with_code("", 1) + } else if !found_all { + // Some commands found, some not + CommandResult { + stdout: output, + stderr: String::new(), + code: 1, + } + } else { + CommandResult::success(output) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_which_existing_command() { + // 'sh' should exist on most Unix systems + let ctx = CommandContext::new(vec!["sh".to_string()]); + let result = which(ctx).await; + + // May or may not find sh depending on PATH + // Just check it doesn't panic + assert!(result.code == 0 || result.code == 1); + } + + #[tokio::test] + async fn test_which_nonexistent_command() { + let ctx = CommandContext::new(vec!["nonexistent_command_12345".to_string()]); + let result = which(ctx).await; + + assert_eq!(result.code, 1); + } +} diff --git a/rust/src/commands/yes.rs b/rust/src/commands/yes.rs new file mode 100644 index 0000000..9e53f87 --- /dev/null +++ b/rust/src/commands/yes.rs @@ -0,0 +1,99 @@ +//! Virtual `yes` command implementation + +use crate::commands::{CommandContext, StreamChunk}; +use crate::utils::{trace_lazy, CommandResult}; +use tokio::time::Duration; + +/// Execute the yes command +/// +/// Outputs a string repeatedly until cancelled. +pub async fn yes(ctx: CommandContext) -> CommandResult { + let output_str = if ctx.args.is_empty() { + "y".to_string() + } else { + ctx.args.join(" ") + }; + + let line = format!("{}\n", output_str); + + trace_lazy("VirtualCommand", || { + format!("yes: starting with output '{}'", output_str) + }); + + // If we have a streaming output channel, use it + if let Some(ref tx) = ctx.output_tx { + loop { + if ctx.is_cancelled() { + trace_lazy("VirtualCommand", || "yes: cancelled".to_string()); + return CommandResult::error_with_code("", 130); + } + + if tx.send(StreamChunk::Stdout(line.clone())).await.is_err() { + // Channel closed + break; + } + + // Small delay to prevent overwhelming + tokio::time::sleep(Duration::from_micros(100)).await; + } + } else { + // Without streaming, just output a few lines and return + // This is a safety measure to prevent infinite output + let mut output = String::new(); + let max_iterations = 1000; + + for _ in 0..max_iterations { + if ctx.is_cancelled() { + trace_lazy("VirtualCommand", || "yes: cancelled".to_string()); + return CommandResult::error_with_code("", 130); + } + output.push_str(&line); + } + + return CommandResult::success(output); + } + + CommandResult::error_with_code("", 130) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::atomic::{AtomicBool, Ordering}; + use std::sync::Arc; + + #[tokio::test] + async fn test_yes_with_cancellation() { + let cancelled = Arc::new(AtomicBool::new(false)); + let cancelled_clone = cancelled.clone(); + + let mut ctx = CommandContext::new(vec![]); + ctx.is_cancelled = Some(Box::new(move || cancelled_clone.load(Ordering::SeqCst))); + + // Cancel after a short delay + tokio::spawn(async move { + tokio::time::sleep(Duration::from_millis(10)).await; + cancelled.store(true, Ordering::SeqCst); + }); + + let result = yes(ctx).await; + + // Should have produced some output before being cancelled + assert!(!result.stdout.is_empty() || result.code == 130); + } + + #[tokio::test] + async fn test_yes_custom_string() { + let cancelled = Arc::new(AtomicBool::new(false)); + let cancelled_clone = cancelled.clone(); + + let mut ctx = CommandContext::new(vec!["hello".to_string()]); + ctx.is_cancelled = Some(Box::new(move || cancelled_clone.load(Ordering::SeqCst))); + + // Cancel immediately + cancelled.store(true, Ordering::SeqCst); + + let result = yes(ctx).await; + assert_eq!(result.code, 130); + } +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs new file mode 100644 index 0000000..0cc5850 --- /dev/null +++ b/rust/src/lib.rs @@ -0,0 +1,487 @@ +//! # command-stream +//! +//! Modern shell command execution library with streaming, async iteration, and event support. +//! +//! This library provides a Rust equivalent to the JavaScript command-stream library, +//! offering powerful shell command execution with streaming capabilities. +//! +//! ## Features +//! +//! - Async command execution with tokio +//! - Streaming output via async iterators +//! - Virtual commands for common operations (cat, ls, mkdir, etc.) +//! - Shell operator support (&&, ||, ;, |) +//! - Cross-platform support +//! +//! ## Quick Start +//! +//! ```rust,no_run +//! use command_stream::$; +//! +//! #[tokio::main] +//! async fn main() -> Result<(), Box> { +//! // Execute a simple command +//! let result = $("echo hello world").await?; +//! println!("{}", result.stdout); +//! Ok(()) +//! } +//! ``` + +pub mod commands; +pub mod shell_parser; +pub mod utils; + +use std::collections::HashMap; +use std::env; +use std::path::PathBuf; +use std::process::Stdio; +use std::sync::Arc; +use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; +use tokio::process::{Child, Command}; +use tokio::sync::{mpsc, Mutex}; + +pub use commands::{CommandContext, StreamChunk}; +pub use shell_parser::{parse_shell_command, needs_real_shell, ParsedCommand}; +pub use utils::{AnsiConfig, AnsiUtils, CommandResult, VirtualUtils, quote, trace}; + +/// Error type for command-stream operations +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + + #[error("Command failed with exit code {code}: {message}")] + CommandFailed { code: i32, message: String }, + + #[error("Command not found: {0}")] + CommandNotFound(String), + + #[error("Parse error: {0}")] + ParseError(String), + + #[error("Cancelled")] + Cancelled, +} + +/// Result type for command-stream operations +pub type Result = std::result::Result; + +/// Shell settings for controlling execution behavior +#[derive(Debug, Clone, Default)] +pub struct ShellSettings { + /// Exit immediately if a command exits with non-zero status (set -e) + pub errexit: bool, + /// Print commands as they are executed (set -v) + pub verbose: bool, + /// Print trace of commands (set -x) + pub xtrace: bool, + /// Return value of a pipeline is the status of the last command to exit with non-zero (set -o pipefail) + pub pipefail: bool, + /// Treat unset variables as an error (set -u) + pub nounset: bool, +} + +/// Options for command execution +#[derive(Debug, Clone)] +pub struct RunOptions { + /// Mirror output to parent stdout/stderr + pub mirror: bool, + /// Capture output in result + pub capture: bool, + /// Standard input handling + pub stdin: StdinOption, + /// Working directory + pub cwd: Option, + /// Environment variables + pub env: Option>, + /// Interactive mode (TTY forwarding) + pub interactive: bool, + /// Enable shell operator parsing + pub shell_operators: bool, + /// Enable tracing for this command + pub trace: bool, +} + +impl Default for RunOptions { + fn default() -> Self { + RunOptions { + mirror: true, + capture: true, + stdin: StdinOption::Inherit, + cwd: None, + env: None, + interactive: false, + shell_operators: true, + trace: true, + } + } +} + +/// Standard input options +#[derive(Debug, Clone)] +pub enum StdinOption { + /// Inherit from parent process + Inherit, + /// Pipe (allow writing to stdin) + Pipe, + /// Provide string content + Content(String), + /// Null device + Null, +} + +/// A running or completed process +pub struct ProcessRunner { + command: String, + options: RunOptions, + child: Option, + result: Option, + started: bool, + finished: bool, + cancelled: bool, + output_tx: Option>, + output_rx: Option>, +} + +impl ProcessRunner { + /// Create a new process runner + pub fn new(command: impl Into, options: RunOptions) -> Self { + let (tx, rx) = mpsc::channel(1024); + ProcessRunner { + command: command.into(), + options, + child: None, + result: None, + started: false, + finished: false, + cancelled: false, + output_tx: Some(tx), + output_rx: Some(rx), + } + } + + /// Start the process + pub async fn start(&mut self) -> Result<()> { + if self.started { + return Ok(()); + } + self.started = true; + + utils::trace_lazy("ProcessRunner", || { + format!("Starting command: {}", self.command) + }); + + // Check if this is a virtual command + let first_word = self.command.split_whitespace().next().unwrap_or(""); + if let Some(result) = self.try_virtual_command(first_word).await { + self.result = Some(result); + self.finished = true; + return Ok(()); + } + + // Parse command for shell operators + let parsed = if self.options.shell_operators && !needs_real_shell(&self.command) { + parse_shell_command(&self.command) + } else { + None + }; + + // Execute via real shell if needed + let shell = find_available_shell(); + + let mut cmd = Command::new(&shell.cmd); + for arg in &shell.args { + cmd.arg(arg); + } + cmd.arg(&self.command); + + // Configure stdin + match &self.options.stdin { + StdinOption::Inherit => { cmd.stdin(Stdio::inherit()); } + StdinOption::Pipe => { cmd.stdin(Stdio::piped()); } + StdinOption::Content(_) => { cmd.stdin(Stdio::piped()); } + StdinOption::Null => { cmd.stdin(Stdio::null()); } + } + + // Configure stdout/stderr + if self.options.capture || self.options.mirror { + cmd.stdout(Stdio::piped()); + cmd.stderr(Stdio::piped()); + } else { + cmd.stdout(Stdio::inherit()); + cmd.stderr(Stdio::inherit()); + } + + // Set working directory + if let Some(ref cwd) = self.options.cwd { + cmd.current_dir(cwd); + } + + // Set environment + if let Some(ref env_vars) = self.options.env { + for (key, value) in env_vars { + cmd.env(key, value); + } + } + + // Spawn the process + let child = cmd.spawn()?; + self.child = Some(child); + + Ok(()) + } + + /// Run the process to completion + pub async fn run(&mut self) -> Result { + self.start().await?; + + if let Some(result) = &self.result { + return Ok(result.clone()); + } + + let child = self.child.take().ok_or_else(|| { + Error::Io(std::io::Error::new( + std::io::ErrorKind::Other, + "Process not started", + )) + })?; + + // Handle stdin content if provided + if let StdinOption::Content(ref content) = self.options.stdin { + if let Some(mut stdin) = child.stdin { + let content = content.clone(); + tokio::spawn(async move { + let _ = stdin.write_all(content.as_bytes()).await; + let _ = stdin.shutdown().await; + }); + } + } + + // Collect output + let mut stdout_content = String::new(); + let mut stderr_content = String::new(); + + if let Some(stdout) = child.stdout { + let mut reader = BufReader::new(stdout).lines(); + while let Ok(Some(line)) = reader.next_line().await { + if self.options.mirror { + println!("{}", line); + } + stdout_content.push_str(&line); + stdout_content.push('\n'); + } + } + + if let Some(stderr) = child.stderr { + let mut reader = BufReader::new(stderr).lines(); + while let Ok(Some(line)) = reader.next_line().await { + if self.options.mirror { + eprintln!("{}", line); + } + stderr_content.push_str(&line); + stderr_content.push('\n'); + } + } + + let status = child.wait().await?; + let code = status.code().unwrap_or(-1); + + let result = CommandResult { + stdout: stdout_content, + stderr: stderr_content, + code, + }; + + self.result = Some(result.clone()); + self.finished = true; + + Ok(result) + } + + /// Try to execute as a virtual command + async fn try_virtual_command(&self, cmd_name: &str) -> Option { + if !commands::are_virtual_commands_enabled() { + return None; + } + + // Parse args from command string + let parts: Vec<&str> = self.command.split_whitespace().collect(); + let args: Vec = parts.iter().skip(1).map(|s| s.to_string()).collect(); + + let ctx = CommandContext { + args, + stdin: match &self.options.stdin { + StdinOption::Content(s) => Some(s.clone()), + _ => None, + }, + cwd: self.options.cwd.clone(), + env: self.options.env.clone(), + output_tx: self.output_tx.clone(), + is_cancelled: None, + }; + + match cmd_name { + "echo" => Some(commands::echo(ctx).await), + "pwd" => Some(commands::pwd(ctx).await), + "cd" => Some(commands::cd(ctx).await), + "true" => Some(commands::r#true(ctx).await), + "false" => Some(commands::r#false(ctx).await), + "sleep" => Some(commands::sleep(ctx).await), + "cat" => Some(commands::cat(ctx).await), + "ls" => Some(commands::ls(ctx).await), + "mkdir" => Some(commands::mkdir(ctx).await), + "rm" => Some(commands::rm(ctx).await), + "touch" => Some(commands::touch(ctx).await), + "cp" => Some(commands::cp(ctx).await), + "mv" => Some(commands::mv(ctx).await), + "basename" => Some(commands::basename(ctx).await), + "dirname" => Some(commands::dirname(ctx).await), + "env" => Some(commands::env(ctx).await), + "exit" => Some(commands::exit(ctx).await), + "which" => Some(commands::which(ctx).await), + "yes" => Some(commands::yes(ctx).await), + "seq" => Some(commands::seq(ctx).await), + "test" => Some(commands::test(ctx).await), + _ => None, + } + } + + /// Kill the process + pub fn kill(&mut self) -> Result<()> { + self.cancelled = true; + if let Some(ref mut child) = self.child { + child.start_kill()?; + } + Ok(()) + } + + /// Check if the process is finished + pub fn is_finished(&self) -> bool { + self.finished + } + + /// Get the result if available + pub fn result(&self) -> Option<&CommandResult> { + self.result.as_ref() + } +} + +/// Shell configuration +#[derive(Debug, Clone)] +struct ShellConfig { + cmd: String, + args: Vec, +} + +/// Find an available shell +fn find_available_shell() -> ShellConfig { + let is_windows = cfg!(windows); + + if is_windows { + // Windows shells + let shells = [ + ("cmd.exe", vec!["/c"]), + ("powershell.exe", vec!["-Command"]), + ]; + + for (cmd, args) in shells { + if which::which(cmd).is_ok() { + return ShellConfig { + cmd: cmd.to_string(), + args: args.into_iter().map(String::from).collect(), + }; + } + } + + ShellConfig { + cmd: "cmd.exe".to_string(), + args: vec!["/c".to_string()], + } + } else { + // Unix shells + let shells = [ + ("/bin/sh", vec!["-c"]), + ("/usr/bin/sh", vec!["-c"]), + ("/bin/bash", vec!["-c"]), + ("sh", vec!["-c"]), + ]; + + for (cmd, args) in shells { + if std::path::Path::new(cmd).exists() || which::which(cmd).is_ok() { + return ShellConfig { + cmd: cmd.to_string(), + args: args.into_iter().map(String::from).collect(), + }; + } + } + + ShellConfig { + cmd: "/bin/sh".to_string(), + args: vec!["-c".to_string()], + } + } +} + +/// Execute a command and return the result +/// +/// This is the main entry point for simple command execution. +pub async fn $(command: impl Into) -> Result { + let mut runner = ProcessRunner::new(command, RunOptions::default()); + runner.run().await +} + +/// Execute a command with custom options +pub async fn exec(command: impl Into, options: RunOptions) -> Result { + let mut runner = ProcessRunner::new(command, options); + runner.run().await +} + +/// Create a new process runner without starting it +pub fn create(command: impl Into, options: RunOptions) -> ProcessRunner { + ProcessRunner::new(command, options) +} + +/// Execute a command synchronously (blocking) +pub fn run_sync(command: impl Into) -> Result { + let rt = tokio::runtime::Runtime::new()?; + rt.block_on($(command)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_simple_echo() { + let result = $("echo hello").await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("hello")); + } + + #[tokio::test] + async fn test_virtual_echo() { + let mut runner = ProcessRunner::new("echo test virtual", RunOptions::default()); + let result = runner.run().await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("test virtual")); + } + + #[tokio::test] + async fn test_process_runner() { + let mut runner = ProcessRunner::new("echo hello world", RunOptions { + mirror: false, + ..Default::default() + }); + + let result = runner.run().await.unwrap(); + assert!(result.is_success()); + } + + #[tokio::test] + async fn test_virtual_pwd() { + let mut runner = ProcessRunner::new("pwd", RunOptions::default()); + let result = runner.run().await.unwrap(); + assert!(result.is_success()); + assert!(!result.stdout.is_empty()); + } +} diff --git a/rust/src/main.rs b/rust/src/main.rs new file mode 100644 index 0000000..1578578 --- /dev/null +++ b/rust/src/main.rs @@ -0,0 +1,37 @@ +//! command-stream CLI +//! +//! A simple CLI wrapper for the command-stream library. + +use command_stream::{$, RunOptions, ProcessRunner}; +use std::env; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let args: Vec = env::args().skip(1).collect(); + + if args.is_empty() { + eprintln!("Usage: command-stream [args...]"); + eprintln!(); + eprintln!("Execute shell commands with streaming support."); + eprintln!(); + eprintln!("Examples:"); + eprintln!(" command-stream echo hello world"); + eprintln!(" command-stream ls -la"); + eprintln!(" command-stream 'echo hello && echo world'"); + std::process::exit(1); + } + + let command = args.join(" "); + + let result = $(command).await?; + + // Print any output that wasn't mirrored + if !result.stdout.is_empty() && !result.stdout.ends_with('\n') { + println!("{}", result.stdout); + } + if !result.stderr.is_empty() { + eprint!("{}", result.stderr); + } + + std::process::exit(result.code); +} diff --git a/rust/src/shell_parser.rs b/rust/src/shell_parser.rs new file mode 100644 index 0000000..c82e01a --- /dev/null +++ b/rust/src/shell_parser.rs @@ -0,0 +1,565 @@ +//! Enhanced shell command parser that handles &&, ||, ;, and () operators +//! This allows virtual commands to work properly with shell operators + +use std::fmt; + +/// Token types for the parser +#[derive(Debug, Clone, PartialEq)] +pub enum TokenType { + Word(String), + And, // && + Or, // || + Semicolon, // ; + Pipe, // | + LParen, // ( + RParen, // ) + RedirectOut, // > + RedirectAppend, // >> + RedirectIn, // < + Eof, +} + +impl fmt::Display for TokenType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TokenType::Word(s) => write!(f, "Word({})", s), + TokenType::And => write!(f, "&&"), + TokenType::Or => write!(f, "||"), + TokenType::Semicolon => write!(f, ";"), + TokenType::Pipe => write!(f, "|"), + TokenType::LParen => write!(f, "("), + TokenType::RParen => write!(f, ")"), + TokenType::RedirectOut => write!(f, ">"), + TokenType::RedirectAppend => write!(f, ">>"), + TokenType::RedirectIn => write!(f, "<"), + TokenType::Eof => write!(f, "EOF"), + } + } +} + +/// A token with its type and original value +#[derive(Debug, Clone)] +pub struct Token { + pub token_type: TokenType, + pub value: String, +} + +/// Redirect information +#[derive(Debug, Clone)] +pub struct Redirect { + pub redirect_type: TokenType, + pub target: String, +} + +/// Parsed argument with quote information +#[derive(Debug, Clone)] +pub struct ParsedArg { + pub value: String, + pub quoted: bool, + pub quote_char: Option, +} + +/// Types of parsed commands +#[derive(Debug, Clone)] +pub enum ParsedCommand { + /// A simple command with command name, arguments, and optional redirects + Simple { + cmd: String, + args: Vec, + redirects: Vec, + }, + /// A sequence of commands connected by &&, ||, or ; + Sequence { + commands: Vec, + operators: Vec, + }, + /// A pipeline of commands connected by | + Pipeline { + commands: Vec, + }, + /// A subshell (commands in parentheses) + Subshell { + command: Box, + }, +} + +/// Tokenize a shell command string +pub fn tokenize(command: &str) -> Vec { + let mut tokens = Vec::new(); + let chars: Vec = command.chars().collect(); + let mut i = 0; + + while i < chars.len() { + // Skip whitespace + while i < chars.len() && chars[i].is_whitespace() { + i += 1; + } + + if i >= chars.len() { + break; + } + + // Check for operators + if chars[i] == '&' && i + 1 < chars.len() && chars[i + 1] == '&' { + tokens.push(Token { + token_type: TokenType::And, + value: "&&".to_string(), + }); + i += 2; + } else if chars[i] == '|' && i + 1 < chars.len() && chars[i + 1] == '|' { + tokens.push(Token { + token_type: TokenType::Or, + value: "||".to_string(), + }); + i += 2; + } else if chars[i] == '|' { + tokens.push(Token { + token_type: TokenType::Pipe, + value: "|".to_string(), + }); + i += 1; + } else if chars[i] == ';' { + tokens.push(Token { + token_type: TokenType::Semicolon, + value: ";".to_string(), + }); + i += 1; + } else if chars[i] == '(' { + tokens.push(Token { + token_type: TokenType::LParen, + value: "(".to_string(), + }); + i += 1; + } else if chars[i] == ')' { + tokens.push(Token { + token_type: TokenType::RParen, + value: ")".to_string(), + }); + i += 1; + } else if chars[i] == '>' && i + 1 < chars.len() && chars[i + 1] == '>' { + tokens.push(Token { + token_type: TokenType::RedirectAppend, + value: ">>".to_string(), + }); + i += 2; + } else if chars[i] == '>' { + tokens.push(Token { + token_type: TokenType::RedirectOut, + value: ">".to_string(), + }); + i += 1; + } else if chars[i] == '<' { + tokens.push(Token { + token_type: TokenType::RedirectIn, + value: "<".to_string(), + }); + i += 1; + } else { + // Parse word (respecting quotes) + let mut word = String::new(); + let mut in_quote = false; + let mut quote_char = ' '; + + while i < chars.len() { + let c = chars[i]; + + if !in_quote { + if c == '"' || c == '\'' { + in_quote = true; + quote_char = c; + word.push(c); + i += 1; + } else if c.is_whitespace() || "&|;()<>".contains(c) { + break; + } else if c == '\\' && i + 1 < chars.len() { + // Handle escape sequences + word.push(c); + i += 1; + if i < chars.len() { + word.push(chars[i]); + i += 1; + } + } else { + word.push(c); + i += 1; + } + } else { + let prev_char = if i > 0 { Some(chars[i - 1]) } else { None }; + if c == quote_char && prev_char != Some('\\') { + in_quote = false; + word.push(c); + i += 1; + } else if c == '\\' && i + 1 < chars.len() { + let next_char = chars[i + 1]; + if next_char == quote_char || next_char == '\\' { + // Handle escaped quotes and backslashes inside quotes + word.push(c); + i += 1; + if i < chars.len() { + word.push(chars[i]); + i += 1; + } + } else { + word.push(c); + i += 1; + } + } else { + word.push(c); + i += 1; + } + } + } + + if !word.is_empty() { + tokens.push(Token { + token_type: TokenType::Word(word.clone()), + value: word, + }); + } + } + } + + tokens.push(Token { + token_type: TokenType::Eof, + value: String::new(), + }); + + tokens +} + +/// Shell command parser +pub struct ShellParser { + tokens: Vec, + pos: usize, +} + +impl ShellParser { + /// Create a new parser for the given command + pub fn new(command: &str) -> Self { + ShellParser { + tokens: tokenize(command), + pos: 0, + } + } + + fn current(&self) -> &Token { + self.tokens.get(self.pos).unwrap_or(&Token { + token_type: TokenType::Eof, + value: String::new(), + }) + } + + fn consume(&mut self) -> Token { + let token = self.current().clone(); + self.pos += 1; + token + } + + /// Parse the main command sequence + pub fn parse(&mut self) -> Option { + self.parse_sequence() + } + + /// Parse a sequence of commands connected by &&, ||, ; + fn parse_sequence(&mut self) -> Option { + let mut commands = Vec::new(); + let mut operators = Vec::new(); + + // Parse first command + if let Some(cmd) = self.parse_pipeline() { + commands.push(cmd); + } + + // Parse additional commands with operators + loop { + match &self.current().token_type { + TokenType::Eof | TokenType::RParen => break, + TokenType::And | TokenType::Or | TokenType::Semicolon => { + let op = self.consume().token_type; + operators.push(op); + + if let Some(cmd) = self.parse_pipeline() { + commands.push(cmd); + } + } + _ => break, + } + } + + if commands.len() == 1 && operators.is_empty() { + return commands.into_iter().next(); + } + + if commands.is_empty() { + return None; + } + + Some(ParsedCommand::Sequence { + commands, + operators, + }) + } + + /// Parse a pipeline (commands connected by |) + fn parse_pipeline(&mut self) -> Option { + let mut commands = Vec::new(); + + if let Some(cmd) = self.parse_command() { + commands.push(cmd); + } + + while matches!(self.current().token_type, TokenType::Pipe) { + self.consume(); + if let Some(cmd) = self.parse_command() { + commands.push(cmd); + } + } + + if commands.len() == 1 { + return commands.into_iter().next(); + } + + if commands.is_empty() { + return None; + } + + Some(ParsedCommand::Pipeline { commands }) + } + + /// Parse a single command or subshell + fn parse_command(&mut self) -> Option { + // Check for subshell + if matches!(self.current().token_type, TokenType::LParen) { + self.consume(); // consume ( + let subshell = self.parse_sequence(); + + if matches!(self.current().token_type, TokenType::RParen) { + self.consume(); // consume ) + } + + return subshell.map(|cmd| ParsedCommand::Subshell { + command: Box::new(cmd), + }); + } + + // Parse simple command + self.parse_simple_command() + } + + /// Parse a simple command (command + args + redirections) + fn parse_simple_command(&mut self) -> Option { + let mut words = Vec::new(); + let mut redirects = Vec::new(); + + loop { + match &self.current().token_type { + TokenType::Eof => break, + TokenType::Word(w) => { + words.push(w.clone()); + self.consume(); + } + TokenType::RedirectOut | TokenType::RedirectAppend | TokenType::RedirectIn => { + let redirect_type = self.consume().token_type; + if let TokenType::Word(target) = &self.current().token_type { + redirects.push(Redirect { + redirect_type, + target: target.clone(), + }); + self.consume(); + } + } + _ => break, + } + } + + if words.is_empty() { + return None; + } + + let cmd = words.remove(0); + let args: Vec = words + .into_iter() + .map(|word| { + // Remove quotes if present + if (word.starts_with('"') && word.ends_with('"')) + || (word.starts_with('\'') && word.ends_with('\'')) + { + ParsedArg { + value: word[1..word.len() - 1].to_string(), + quoted: true, + quote_char: Some(word.chars().next().unwrap()), + } + } else { + ParsedArg { + value: word, + quoted: false, + quote_char: None, + } + } + }) + .collect(); + + Some(ParsedCommand::Simple { + cmd, + args, + redirects, + }) + } +} + +/// Parse a shell command with support for &&, ||, ;, and () +pub fn parse_shell_command(command: &str) -> Option { + let mut parser = ShellParser::new(command); + parser.parse() +} + +/// Check if a command needs shell features we don't handle +pub fn needs_real_shell(command: &str) -> bool { + // Check for features we don't handle yet + let unsupported = [ + "`", // Command substitution + "$(", // Command substitution + "${", // Variable expansion + "~", // Home expansion (at start of word) + "*", // Glob patterns + "?", // Glob patterns + "[", // Glob patterns + "2>", // stderr redirection + "&>", // Combined redirection + ">&", // File descriptor duplication + "<<", // Here documents + "<<<", // Here strings + ]; + + for feature in &unsupported { + if command.contains(feature) { + return true; + } + } + + false +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_tokenize_simple_command() { + let tokens = tokenize("echo hello world"); + assert_eq!(tokens.len(), 4); // 3 words + EOF + assert!(matches!(tokens[0].token_type, TokenType::Word(_))); + assert!(matches!(tokens[3].token_type, TokenType::Eof)); + } + + #[test] + fn test_tokenize_with_operators() { + let tokens = tokenize("cmd1 && cmd2 || cmd3"); + assert_eq!(tokens.len(), 6); // 3 words + 2 operators + EOF + assert!(matches!(tokens[1].token_type, TokenType::And)); + assert!(matches!(tokens[3].token_type, TokenType::Or)); + } + + #[test] + fn test_tokenize_with_pipe() { + let tokens = tokenize("ls | grep foo"); + assert_eq!(tokens.len(), 5); // 3 words + 1 pipe + EOF + assert!(matches!(tokens[1].token_type, TokenType::Pipe)); + } + + #[test] + fn test_tokenize_with_quotes() { + let tokens = tokenize("echo 'hello world'"); + assert_eq!(tokens.len(), 3); // echo + quoted string + EOF + if let TokenType::Word(w) = &tokens[1].token_type { + assert_eq!(w, "'hello world'"); + } else { + panic!("Expected Word token"); + } + } + + #[test] + fn test_parse_simple_command() { + let cmd = parse_shell_command("echo hello world").unwrap(); + match cmd { + ParsedCommand::Simple { cmd, args, .. } => { + assert_eq!(cmd, "echo"); + assert_eq!(args.len(), 2); + assert_eq!(args[0].value, "hello"); + assert_eq!(args[1].value, "world"); + } + _ => panic!("Expected Simple command"), + } + } + + #[test] + fn test_parse_pipeline() { + let cmd = parse_shell_command("ls | grep foo | wc -l").unwrap(); + match cmd { + ParsedCommand::Pipeline { commands } => { + assert_eq!(commands.len(), 3); + } + _ => panic!("Expected Pipeline"), + } + } + + #[test] + fn test_parse_sequence() { + let cmd = parse_shell_command("cmd1 && cmd2 || cmd3").unwrap(); + match cmd { + ParsedCommand::Sequence { + commands, + operators, + } => { + assert_eq!(commands.len(), 3); + assert_eq!(operators.len(), 2); + assert!(matches!(operators[0], TokenType::And)); + assert!(matches!(operators[1], TokenType::Or)); + } + _ => panic!("Expected Sequence"), + } + } + + #[test] + fn test_needs_real_shell() { + assert!(needs_real_shell("echo $(date)")); + assert!(needs_real_shell("ls *.txt")); + assert!(needs_real_shell("echo ${HOME}")); + assert!(!needs_real_shell("echo hello")); + assert!(!needs_real_shell("ls | grep foo")); + } + + #[test] + fn test_parse_with_redirect() { + let cmd = parse_shell_command("echo hello > output.txt").unwrap(); + match cmd { + ParsedCommand::Simple { + cmd, + args, + redirects, + } => { + assert_eq!(cmd, "echo"); + assert_eq!(args.len(), 1); + assert_eq!(redirects.len(), 1); + assert!(matches!( + redirects[0].redirect_type, + TokenType::RedirectOut + )); + assert_eq!(redirects[0].target, "output.txt"); + } + _ => panic!("Expected Simple command with redirect"), + } + } + + #[test] + fn test_parse_subshell() { + let cmd = parse_shell_command("(echo hello) && echo world").unwrap(); + match cmd { + ParsedCommand::Sequence { commands, .. } => { + assert_eq!(commands.len(), 2); + assert!(matches!(commands[0], ParsedCommand::Subshell { .. })); + } + _ => panic!("Expected Sequence with Subshell"), + } + } +} diff --git a/rust/src/utils.rs b/rust/src/utils.rs new file mode 100644 index 0000000..080f1a8 --- /dev/null +++ b/rust/src/utils.rs @@ -0,0 +1,335 @@ +//! Utility functions and types for command-stream +//! +//! This module provides helper functions for tracing, error handling, +//! and common file system operations used by virtual commands. + +use std::env; +use std::path::{Path, PathBuf}; + +/// Check if tracing is enabled via environment variables +/// +/// Tracing can be controlled via: +/// - COMMAND_STREAM_TRACE=true/false (explicit control) +/// - COMMAND_STREAM_VERBOSE=true (enables tracing unless TRACE=false) +pub fn is_trace_enabled() -> bool { + let trace_env = env::var("COMMAND_STREAM_TRACE").ok(); + let verbose_env = env::var("COMMAND_STREAM_VERBOSE") + .map(|v| v == "true") + .unwrap_or(false); + + match trace_env.as_deref() { + Some("false") => false, + Some("true") => true, + _ => verbose_env, + } +} + +/// Trace function for verbose logging +/// +/// Outputs trace messages to stderr when tracing is enabled. +/// Messages are prefixed with timestamp and category. +pub fn trace(category: &str, message: &str) { + if !is_trace_enabled() { + return; + } + + let timestamp = chrono::Utc::now().to_rfc3339(); + eprintln!("[TRACE {}] [{}] {}", timestamp, category, message); +} + +/// Trace function with lazy message evaluation +/// +/// Only evaluates the message function if tracing is enabled. +pub fn trace_lazy(category: &str, message_fn: F) +where + F: FnOnce() -> String, +{ + if !is_trace_enabled() { + return; + } + + trace(category, &message_fn()); +} + +/// Result type for virtual command operations +#[derive(Debug, Clone)] +pub struct CommandResult { + pub stdout: String, + pub stderr: String, + pub code: i32, +} + +impl CommandResult { + /// Create a success result with stdout output + pub fn success(stdout: impl Into) -> Self { + CommandResult { + stdout: stdout.into(), + stderr: String::new(), + code: 0, + } + } + + /// Create an empty success result + pub fn success_empty() -> Self { + CommandResult { + stdout: String::new(), + stderr: String::new(), + code: 0, + } + } + + /// Create an error result with stderr output + pub fn error(stderr: impl Into) -> Self { + CommandResult { + stdout: String::new(), + stderr: stderr.into(), + code: 1, + } + } + + /// Create an error result with custom exit code + pub fn error_with_code(stderr: impl Into, code: i32) -> Self { + CommandResult { + stdout: String::new(), + stderr: stderr.into(), + code, + } + } + + /// Check if the command was successful + pub fn is_success(&self) -> bool { + self.code == 0 + } +} + +/// Utility functions for virtual commands +pub struct VirtualUtils; + +impl VirtualUtils { + /// Create standardized error response for missing operands + pub fn missing_operand_error(command_name: &str) -> CommandResult { + CommandResult::error(format!("{}: missing operand", command_name)) + } + + /// Create standardized error response for missing operands with custom message + pub fn missing_operand_error_with_message( + command_name: &str, + message: &str, + ) -> CommandResult { + CommandResult::error(format!("{}: {}", command_name, message)) + } + + /// Create standardized error response for invalid arguments + pub fn invalid_argument_error(command_name: &str, message: &str) -> CommandResult { + CommandResult::error(format!("{}: {}", command_name, message)) + } + + /// Create standardized success response + pub fn success(stdout: impl Into) -> CommandResult { + CommandResult::success(stdout) + } + + /// Create standardized error response + pub fn error(stderr: impl Into) -> CommandResult { + CommandResult::error(stderr) + } + + /// Validate that command has required number of arguments + pub fn validate_args( + args: &[String], + min_count: usize, + command_name: &str, + ) -> Option { + if args.len() < min_count { + if min_count == 1 { + return Some(Self::missing_operand_error(command_name)); + } else { + return Some(Self::invalid_argument_error( + command_name, + &format!("requires at least {} arguments", min_count), + )); + } + } + None // No error + } + + /// Resolve file path with optional cwd parameter + pub fn resolve_path(file_path: &str, cwd: Option<&Path>) -> PathBuf { + let path = Path::new(file_path); + if path.is_absolute() { + path.to_path_buf() + } else { + let base_path = cwd.map(|p| p.to_path_buf()).unwrap_or_else(|| { + env::current_dir().unwrap_or_else(|_| PathBuf::from("/")) + }); + base_path.join(path) + } + } +} + +/// ANSI control character utilities +pub struct AnsiUtils; + +impl AnsiUtils { + /// Strip ANSI escape sequences from text + pub fn strip_ansi(text: &str) -> String { + let re = regex::Regex::new(r"\x1b\[[0-9;]*[mGKHFJ]").unwrap(); + re.replace_all(text, "").to_string() + } + + /// Strip control characters from text, preserving newlines, carriage returns, and tabs + pub fn strip_control_chars(text: &str) -> String { + text.chars() + .filter(|c| { + // Preserve newlines (\n = \x0A), carriage returns (\r = \x0D), and tabs (\t = \x09) + !matches!(*c as u32, + 0x00..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F | 0x7F + ) + }) + .collect() + } + + /// Strip both ANSI sequences and control characters + pub fn strip_all(text: &str) -> String { + Self::strip_control_chars(&Self::strip_ansi(text)) + } + + /// Clean data for processing (strips ANSI and control chars) + pub fn clean_for_processing(data: &str) -> String { + Self::strip_all(data) + } +} + +/// Configuration for ANSI handling +#[derive(Debug, Clone)] +pub struct AnsiConfig { + pub preserve_ansi: bool, + pub preserve_control_chars: bool, +} + +impl Default for AnsiConfig { + fn default() -> Self { + AnsiConfig { + preserve_ansi: true, + preserve_control_chars: true, + } + } +} + +impl AnsiConfig { + /// Process output according to config settings + pub fn process_output(&self, data: &str) -> String { + if !self.preserve_ansi && !self.preserve_control_chars { + AnsiUtils::clean_for_processing(data) + } else if !self.preserve_ansi { + AnsiUtils::strip_ansi(data) + } else if !self.preserve_control_chars { + AnsiUtils::strip_control_chars(data) + } else { + data.to_string() + } + } +} + +/// Quote a value for safe shell usage +pub fn quote(value: &str) -> String { + if value.is_empty() { + return "''".to_string(); + } + + // If already properly quoted, check if we can use as-is + if value.starts_with('\'') && value.ends_with('\'') && value.len() >= 2 { + let inner = &value[1..value.len() - 1]; + if !inner.contains('\'') { + return value.to_string(); + } + } + + if value.starts_with('"') && value.ends_with('"') && value.len() > 2 { + // If already double-quoted, wrap in single quotes + return format!("'{}'", value); + } + + // Check if the string needs quoting at all + // Safe characters: alphanumeric, dash, underscore, dot, slash, colon, equals, comma, plus + let safe_pattern = regex::Regex::new(r"^[a-zA-Z0-9_\-./=,+@:]+$").unwrap(); + + if safe_pattern.is_match(value) { + return value.to_string(); + } + + // Default behavior: wrap in single quotes and escape any internal single quotes + format!("'{}'", value.replace('\'', "'\\''")) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_command_result_success() { + let result = CommandResult::success("hello"); + assert!(result.is_success()); + assert_eq!(result.stdout, "hello"); + assert_eq!(result.stderr, ""); + assert_eq!(result.code, 0); + } + + #[test] + fn test_command_result_error() { + let result = CommandResult::error("something went wrong"); + assert!(!result.is_success()); + assert_eq!(result.stdout, ""); + assert_eq!(result.stderr, "something went wrong"); + assert_eq!(result.code, 1); + } + + #[test] + fn test_resolve_path_absolute() { + let path = VirtualUtils::resolve_path("/absolute/path", None); + assert_eq!(path, PathBuf::from("/absolute/path")); + } + + #[test] + fn test_resolve_path_relative() { + let cwd = PathBuf::from("/home/user"); + let path = VirtualUtils::resolve_path("relative/path", Some(&cwd)); + assert_eq!(path, PathBuf::from("/home/user/relative/path")); + } + + #[test] + fn test_strip_ansi() { + let text = "\x1b[31mRed text\x1b[0m"; + assert_eq!(AnsiUtils::strip_ansi(text), "Red text"); + } + + #[test] + fn test_strip_control_chars() { + let text = "Hello\x00World\nNew line\tTab"; + assert_eq!(AnsiUtils::strip_control_chars(text), "HelloWorld\nNew line\tTab"); + } + + #[test] + fn test_quote_empty() { + assert_eq!(quote(""), "''"); + } + + #[test] + fn test_quote_safe_chars() { + assert_eq!(quote("hello"), "hello"); + assert_eq!(quote("/path/to/file"), "/path/to/file"); + } + + #[test] + fn test_quote_special_chars() { + assert_eq!(quote("hello world"), "'hello world'"); + assert_eq!(quote("it's"), "'it'\\''s'"); + } + + #[test] + fn test_validate_args() { + let args = vec!["arg1".to_string()]; + assert!(VirtualUtils::validate_args(&args, 1, "cmd").is_none()); + assert!(VirtualUtils::validate_args(&args, 2, "cmd").is_some()); + } +} diff --git a/tests/$.features.test.mjs b/tests/$.features.test.mjs index 9eb0f60..d44c6e4 100644 --- a/tests/$.features.test.mjs +++ b/tests/$.features.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, shell, disableVirtualCommands } from '../src/$.mjs'; +import { $, shell, disableVirtualCommands } from '../js/src/$.mjs'; // Reset shell settings before each test to prevent interference beforeEach(() => { diff --git a/tests/$.test.mjs b/tests/$.test.mjs index 6552298..1c1253c 100644 --- a/tests/$.test.mjs +++ b/tests/$.test.mjs @@ -12,7 +12,7 @@ import { shell, disableVirtualCommands, enableVirtualCommands, -} from '../src/$.mjs'; +} from '../js/src/$.mjs'; // Reset shell settings before each test to prevent interference beforeEach(() => { diff --git a/tests/builtin-commands.test.mjs b/tests/builtin-commands.test.mjs index 4e837a9..db1c1f3 100644 --- a/tests/builtin-commands.test.mjs +++ b/tests/builtin-commands.test.mjs @@ -1,7 +1,7 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, register, unregister, enableVirtualCommands } from '../src/$.mjs'; -import { trace } from '../src/$.utils.mjs'; +import { $, register, unregister, enableVirtualCommands } from '../js/src/$.mjs'; +import { trace } from '../js/src/$.utils.mjs'; import { rmSync, existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs'; import { join } from 'path'; diff --git a/tests/bun-shell-path-fix.test.mjs b/tests/bun-shell-path-fix.test.mjs index fab5aab..9e2965f 100644 --- a/tests/bun-shell-path-fix.test.mjs +++ b/tests/bun-shell-path-fix.test.mjs @@ -7,7 +7,7 @@ */ import { test, expect, describe } from 'bun:test'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Test both Bun and Node.js runtimes const isBun = typeof globalThis.Bun !== 'undefined'; diff --git a/tests/cd-virtual-command.test.mjs b/tests/cd-virtual-command.test.mjs index 18d3038..aabcbf6 100644 --- a/tests/cd-virtual-command.test.mjs +++ b/tests/cd-virtual-command.test.mjs @@ -4,7 +4,7 @@ import { afterTestCleanup, originalCwd, } from './test-cleanup.mjs'; -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; import { mkdtempSync, rmSync, diff --git a/tests/cleanup-verification.test.mjs b/tests/cleanup-verification.test.mjs index 5855203..3747d0e 100644 --- a/tests/cleanup-verification.test.mjs +++ b/tests/cleanup-verification.test.mjs @@ -7,7 +7,7 @@ import { originalCwd, } from './test-cleanup.mjs'; import { isWindows } from './test-helper.mjs'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { mkdtempSync, rmSync, realpathSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/tests/ctrl-c-baseline.test.mjs b/tests/ctrl-c-baseline.test.mjs index a5cabe0..b1c48df 100644 --- a/tests/ctrl-c-baseline.test.mjs +++ b/tests/ctrl-c-baseline.test.mjs @@ -1,7 +1,7 @@ import { describe, it, expect, afterEach } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup import { spawn } from 'child_process'; -import { trace } from '../src/$.utils.mjs'; +import { trace } from '../js/src/$.utils.mjs'; // Platform detection - Windows handles signals differently than Unix const isWindows = process.platform === 'win32'; diff --git a/tests/ctrl-c-basic.test.mjs b/tests/ctrl-c-basic.test.mjs index 1606a21..7e68a6a 100644 --- a/tests/ctrl-c-basic.test.mjs +++ b/tests/ctrl-c-basic.test.mjs @@ -1,6 +1,6 @@ import { describe, it, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Platform detection - Windows handles signals differently than Unix const isWindows = process.platform === 'win32'; diff --git a/tests/ctrl-c-library.test.mjs b/tests/ctrl-c-library.test.mjs index 4149caa..0b33d28 100644 --- a/tests/ctrl-c-library.test.mjs +++ b/tests/ctrl-c-library.test.mjs @@ -1,8 +1,8 @@ import { describe, it, expect, afterEach } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup import { spawn } from 'child_process'; -import { $ } from '../src/$.mjs'; -import { trace } from '../src/$.utils.mjs'; +import { $ } from '../js/src/$.mjs'; +import { trace } from '../js/src/$.utils.mjs'; // Platform detection - Windows handles signals differently than Unix const isWindows = process.platform === 'win32'; diff --git a/tests/ctrl-c-signal.test.mjs b/tests/ctrl-c-signal.test.mjs index 26a2d90..449edaf 100644 --- a/tests/ctrl-c-signal.test.mjs +++ b/tests/ctrl-c-signal.test.mjs @@ -1,7 +1,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; import { spawn } from 'child_process'; -import { trace } from '../src/$.utils.mjs'; +import { trace } from '../js/src/$.utils.mjs'; // Platform detection - Windows handles signals differently than Unix const isWindows = process.platform === 'win32'; @@ -664,7 +664,7 @@ describe.skipIf(isWindows)('CTRL+C with Different stdin Modes', () => { [ '-e', ` - import { $ } from './src/$.mjs'; + import { $ } from './js/src/$.mjs'; // Start a long-running command const runner = $\`sleep 5\`; @@ -720,7 +720,7 @@ describe.skipIf(isWindows)('CTRL+C with Different stdin Modes', () => { [ '-e', ` - import { $ } from './src/$.mjs'; + import { $ } from './js/src/$.mjs'; console.log('STARTING_SLEEP_WITH_CUSTOM_STDIN'); @@ -772,7 +772,7 @@ describe.skipIf(isWindows)('CTRL+C with Different stdin Modes', () => { [ '-e', ` - import { $ } from './src/$.mjs'; + import { $ } from './js/src/$.mjs'; const isBun = typeof globalThis.Bun !== 'undefined'; console.log('RUNTIME: ' + (isBun ? 'BUN' : 'NODE')); @@ -857,7 +857,7 @@ describe.skipIf(isWindows)('CTRL+C with Different stdin Modes', () => { [ '-e', ` - import { $ } from './src/$.mjs'; + import { $ } from './js/src/$.mjs'; // Set up user's SIGINT handler AFTER importing our library process.on('SIGINT', () => { diff --git a/tests/examples.test.mjs b/tests/examples.test.mjs index 9c7cd42..2be2b13 100644 --- a/tests/examples.test.mjs +++ b/tests/examples.test.mjs @@ -1,7 +1,7 @@ import { test, expect, describe } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../src/$.mjs'; -import { trace } from '../src/$.utils.mjs'; +import { $ } from '../js/src/$.mjs'; +import { trace } from '../js/src/$.utils.mjs'; import { readdirSync, statSync, readFileSync } from 'fs'; import { join } from 'path'; diff --git a/tests/gh-commands.test.mjs b/tests/gh-commands.test.mjs index c7cd4b6..2729f3b 100644 --- a/tests/gh-commands.test.mjs +++ b/tests/gh-commands.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Platform detection - tests use Unix shell redirection 2>&1 and sh -c const isWindows = process.platform === 'win32'; diff --git a/tests/gh-gist-operations.test.mjs b/tests/gh-gist-operations.test.mjs index 2cf9edb..9f4eaae 100644 --- a/tests/gh-gist-operations.test.mjs +++ b/tests/gh-gist-operations.test.mjs @@ -8,7 +8,7 @@ import { afterEach, } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/tests/git-gh-cd.test.mjs b/tests/git-gh-cd.test.mjs index 356e0e3..e7f399c 100644 --- a/tests/git-gh-cd.test.mjs +++ b/tests/git-gh-cd.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; -import { $, shell, enableVirtualCommands } from '../src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; import { mkdtempSync, rmSync, existsSync, realpathSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/tests/interactive-option.test.mjs b/tests/interactive-option.test.mjs index af6b24e..44a3b41 100644 --- a/tests/interactive-option.test.mjs +++ b/tests/interactive-option.test.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; diff --git a/tests/interactive-streaming.test.mjs b/tests/interactive-streaming.test.mjs index 6ae67cc..d98bb5a 100644 --- a/tests/interactive-streaming.test.mjs +++ b/tests/interactive-streaming.test.mjs @@ -2,7 +2,7 @@ import { describe, it, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/tests/issue-135-final.test.mjs b/tests/issue-135-final.test.mjs index f7edc02..e31a2e9 100755 --- a/tests/issue-135-final.test.mjs +++ b/tests/issue-135-final.test.mjs @@ -2,7 +2,7 @@ // This test verifies the main fix: CI=true should NOT cause trace logs import { describe, it, beforeEach } from 'bun:test'; import assert from 'assert'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; describe('Issue #135: CI environment no longer auto-enables trace logs', () => { beforeEach(() => { diff --git a/tests/jq-color-behavior.test.mjs b/tests/jq-color-behavior.test.mjs index dcb32f9..a8134e9 100644 --- a/tests/jq-color-behavior.test.mjs +++ b/tests/jq-color-behavior.test.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { test, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup diff --git a/tests/jq.test.mjs b/tests/jq.test.mjs index fb3839d..deb7193 100644 --- a/tests/jq.test.mjs +++ b/tests/jq.test.mjs @@ -1,5 +1,5 @@ -import { $ } from '../src/$.mjs'; -import { trace } from '../src/$.utils.mjs'; +import { $ } from '../js/src/$.mjs'; +import { trace } from '../js/src/$.utils.mjs'; import { describe, test, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup diff --git a/tests/options-examples.test.mjs b/tests/options-examples.test.mjs index a9526f9..e9cc975 100644 --- a/tests/options-examples.test.mjs +++ b/tests/options-examples.test.mjs @@ -2,7 +2,7 @@ import { test, expect, describe } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; describe('Options Examples (Feature Demo)', () => { test('example: disable capture for performance', async () => { diff --git a/tests/options-syntax.test.mjs b/tests/options-syntax.test.mjs index e0f4db4..c68a132 100644 --- a/tests/options-syntax.test.mjs +++ b/tests/options-syntax.test.mjs @@ -1,6 +1,6 @@ import { describe, it, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; describe('$({ options }) syntax', () => { it('should support $({ options }) syntax for custom options', async () => { diff --git a/tests/path-interpolation.test.mjs b/tests/path-interpolation.test.mjs index c5b3e0c..8a6dbf9 100644 --- a/tests/path-interpolation.test.mjs +++ b/tests/path-interpolation.test.mjs @@ -1,4 +1,4 @@ -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { test, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup diff --git a/tests/pipe.test.mjs b/tests/pipe.test.mjs index c185b70..5ba999f 100644 --- a/tests/pipe.test.mjs +++ b/tests/pipe.test.mjs @@ -6,7 +6,7 @@ import { unregister, enableVirtualCommands, disableVirtualCommands, -} from '../src/$.mjs'; +} from '../js/src/$.mjs'; import { rmSync, existsSync, mkdirSync, writeFileSync } from 'fs'; import { join } from 'path'; diff --git a/tests/raw-function.test.mjs b/tests/raw-function.test.mjs index 82d6f83..aab827a 100644 --- a/tests/raw-function.test.mjs +++ b/tests/raw-function.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach } from 'bun:test'; import './test-helper.mjs'; -import { $, raw, shell, disableVirtualCommands } from '../src/$.mjs'; +import { $, raw, shell, disableVirtualCommands } from '../js/src/$.mjs'; // Disable virtual commands for consistent system command behavior beforeEach(() => { diff --git a/tests/readme-examples.test.mjs b/tests/readme-examples.test.mjs index 76ad339..3fe27c2 100644 --- a/tests/readme-examples.test.mjs +++ b/tests/readme-examples.test.mjs @@ -8,7 +8,7 @@ import { set, unset, disableVirtualCommands, -} from '../src/$.mjs'; +} from '../js/src/$.mjs'; // Helper function to setup shell settings for README tests function setupShellForReadme() { diff --git a/tests/resource-cleanup-internals.test.mjs b/tests/resource-cleanup-internals.test.mjs index 455feaa..df862a7 100644 --- a/tests/resource-cleanup-internals.test.mjs +++ b/tests/resource-cleanup-internals.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, forceCleanupAll } from '../src/$.mjs'; +import { $, forceCleanupAll } from '../js/src/$.mjs'; import { EventEmitter } from 'events'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/tests/shell-settings.test.mjs b/tests/shell-settings.test.mjs index 5ebe47b..729de8f 100644 --- a/tests/shell-settings.test.mjs +++ b/tests/shell-settings.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, shell, set, unset } from '../src/$.mjs'; +import { $, shell, set, unset } from '../js/src/$.mjs'; describe('Shell Settings (set -e / set +e equivalent)', () => { beforeEach(() => { diff --git a/tests/sigint-cleanup-isolated.test.mjs b/tests/sigint-cleanup-isolated.test.mjs index 74a9090..cd9616d 100644 --- a/tests/sigint-cleanup-isolated.test.mjs +++ b/tests/sigint-cleanup-isolated.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; diff --git a/tests/sigint-cleanup.test.mjs b/tests/sigint-cleanup.test.mjs index 0c16ba9..3299bd4 100644 --- a/tests/sigint-cleanup.test.mjs +++ b/tests/sigint-cleanup.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Platform detection - Windows handles signals differently than Unix const isWindows = process.platform === 'win32'; diff --git a/tests/start-run-edge-cases.test.mjs b/tests/start-run-edge-cases.test.mjs index 35fd2f9..625e624 100644 --- a/tests/start-run-edge-cases.test.mjs +++ b/tests/start-run-edge-cases.test.mjs @@ -2,7 +2,7 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, shell } from '../src/$.mjs'; +import { $, shell } from '../js/src/$.mjs'; describe('Start/Run Edge Cases and Advanced Usage', () => { beforeEach(() => { diff --git a/tests/start-run-options.test.mjs b/tests/start-run-options.test.mjs index da45bcc..b079fae 100644 --- a/tests/start-run-options.test.mjs +++ b/tests/start-run-options.test.mjs @@ -2,7 +2,7 @@ import { test, expect, describe } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; describe('Start/Run Options Passing', () => { describe('.start() method with options', () => { diff --git a/tests/stderr-output-handling.test.mjs b/tests/stderr-output-handling.test.mjs index f673508..d70914a 100644 --- a/tests/stderr-output-handling.test.mjs +++ b/tests/stderr-output-handling.test.mjs @@ -1,7 +1,7 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; import { isWindows } from './test-helper.mjs'; -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/tests/streaming-interfaces.test.mjs b/tests/streaming-interfaces.test.mjs index b04bb0b..f0610c5 100644 --- a/tests/streaming-interfaces.test.mjs +++ b/tests/streaming-interfaces.test.mjs @@ -1,6 +1,6 @@ import { test, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../src/$.mjs'; +import { $ } from '../js/src/$.mjs'; // Platform detection - Some tests use Unix utilities (cat, grep, sort, sh) const isWindows = process.platform === 'win32'; diff --git a/tests/sync.test.mjs b/tests/sync.test.mjs index 09b0a6f..8e4a1c3 100644 --- a/tests/sync.test.mjs +++ b/tests/sync.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, shell } from '../src/$.mjs'; +import { $, shell } from '../js/src/$.mjs'; // Reset shell settings before each test beforeEach(() => { diff --git a/tests/system-pipe.test.mjs b/tests/system-pipe.test.mjs index 77b6865..59b1058 100644 --- a/tests/system-pipe.test.mjs +++ b/tests/system-pipe.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, shell, disableVirtualCommands } from '../src/$.mjs'; +import { $, shell, disableVirtualCommands } from '../js/src/$.mjs'; import { execSync } from 'child_process'; // Platform detection - These tests use Unix utilities (printf, grep, sed, awk, etc.) diff --git a/tests/test-cleanup.mjs b/tests/test-cleanup.mjs index 6bfe6b6..39cb024 100644 --- a/tests/test-cleanup.mjs +++ b/tests/test-cleanup.mjs @@ -18,7 +18,7 @@ * ``` */ -import { resetGlobalState } from '../src/$.mjs'; +import { resetGlobalState } from '../js/src/$.mjs'; import { existsSync } from 'fs'; // Save the original working directory when module loads diff --git a/tests/test-helper-fixed.mjs b/tests/test-helper-fixed.mjs index 6bf9b0b..7b00610 100644 --- a/tests/test-helper-fixed.mjs +++ b/tests/test-helper-fixed.mjs @@ -18,7 +18,7 @@ */ import { beforeEach, afterEach } from 'bun:test'; -import { resetGlobalState } from '../src/$.mjs'; +import { resetGlobalState } from '../js/src/$.mjs'; import { existsSync } from 'fs'; // Save the original working directory when tests start diff --git a/tests/test-helper-v2.mjs b/tests/test-helper-v2.mjs index c2aa4cb..4e45ae0 100644 --- a/tests/test-helper-v2.mjs +++ b/tests/test-helper-v2.mjs @@ -1,5 +1,5 @@ import { beforeEach, afterEach } from 'bun:test'; -import { resetGlobalState } from '../src/$.mjs'; +import { resetGlobalState } from '../js/src/$.mjs'; import { existsSync } from 'fs'; // Save the original working directory when tests start diff --git a/tests/test-helper.mjs b/tests/test-helper.mjs index 9320a2f..d3dea5d 100644 --- a/tests/test-helper.mjs +++ b/tests/test-helper.mjs @@ -1,5 +1,5 @@ import { beforeEach, afterEach } from 'bun:test'; -import { resetGlobalState } from '../src/$.mjs'; +import { resetGlobalState } from '../js/src/$.mjs'; import { existsSync } from 'fs'; // Platform detection helpers diff --git a/tests/text-method.test.mjs b/tests/text-method.test.mjs index ab0b70b..bc48b13 100644 --- a/tests/text-method.test.mjs +++ b/tests/text-method.test.mjs @@ -1,6 +1,6 @@ import { describe, test, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, disableVirtualCommands } from '../src/$.mjs'; +import { $, disableVirtualCommands } from '../js/src/$.mjs'; // Disable virtual commands to ensure we're testing system/built-in commands disableVirtualCommands(); diff --git a/tests/virtual.test.mjs b/tests/virtual.test.mjs index 0c3b38a..ce4b550 100644 --- a/tests/virtual.test.mjs +++ b/tests/virtual.test.mjs @@ -8,7 +8,7 @@ import { unregister, listCommands, enableVirtualCommands, -} from '../src/$.mjs'; +} from '../js/src/$.mjs'; // Helper function to setup shell settings function setupShellSettings() { diff --git a/tests/yes-command-cleanup.test.mjs b/tests/yes-command-cleanup.test.mjs index 34ac9ea..fb80186 100644 --- a/tests/yes-command-cleanup.test.mjs +++ b/tests/yes-command-cleanup.test.mjs @@ -1,7 +1,7 @@ import { test, expect, describe } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../src/$.mjs'; -import { trace } from '../src/$.utils.mjs'; +import { $ } from '../js/src/$.mjs'; +import { trace } from '../js/src/$.utils.mjs'; describe('Yes Command Cleanup Tests', () => { test('should stop yes command when breaking from async iteration', async () => { @@ -152,7 +152,7 @@ describe('Yes Command Cleanup Tests', () => { test('should cleanup yes command in subprocess', async () => { // Create a test script that runs yes and should exit cleanly const script = ` - import { $ } from './src/$.mjs'; + import { $ } from './js/src/$.mjs'; const runner = $({ mirror: false })\`yes "subprocess test"\`; let count = 0; From 405b5261ee0d73b3a970483703a70b8d1bdbcb0d Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 29 Dec 2025 09:59:59 +0100 Subject: [PATCH 3/9] Revert "Initial commit with task details" This reverts commit 2e3f071657c064623f2f12a2b0f9aaa72a92396b. --- CLAUDE.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 56c995c..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/link-foundation/command-stream/issues/146 -Your prepared branch: issue-146-f111406088b3 -Your prepared working directory: /tmp/gh-issue-solver-1766997793068 - -Proceed. From 60e2a36f1f503472b22a254ff228c74590033915 Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 29 Dec 2025 14:22:34 +0100 Subject: [PATCH 4/9] Move tests to js/tests, add Rust tests, fix Rust compilation errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move root ./tests folder to ./js/tests as per feedback - Update all import paths from ../js/src/ to ../src/ - Update package.json and bunfig.toml to use js/tests path - Add comprehensive Rust test suite in rust/tests/ mirroring JS tests - Fix Rust compilation errors: - Rename $ function to run ($ is not valid Rust identifier) - Fix shell parser current() method to avoid borrowing issues - Fix ProcessRunner child handle borrowing - Add manual Debug impl for CommandContext - Improve echo command to support -n, -e, -E flags - Improve which command to recognize virtual/builtin commands - Fix eslint warnings (unused catch variables) ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .changeset/rust-translation.md | 14 + .gitignore | 2 +- bunfig.toml | 4 +- {tests => js/tests}/$.features.test.mjs | 2 +- {tests => js/tests}/$.test.mjs | 2 +- {tests => js/tests}/builtin-commands.test.mjs | 4 +- .../tests}/bun-shell-path-fix.test.mjs | 2 +- {tests => js/tests}/bun.features.test.mjs | 0 .../tests}/cd-virtual-command.test.mjs | 2 +- .../tests}/cleanup-verification.test.mjs | 2 +- {tests => js/tests}/ctrl-c-baseline.test.mjs | 2 +- {tests => js/tests}/ctrl-c-basic.test.mjs | 2 +- {tests => js/tests}/ctrl-c-library.test.mjs | 4 +- {tests => js/tests}/ctrl-c-signal.test.mjs | 2 +- {tests => js/tests}/examples.test.mjs | 4 +- {tests => js/tests}/execa.features.test.mjs | 0 {tests => js/tests}/gh-commands.test.mjs | 2 +- .../tests}/gh-gist-operations.test.mjs | 2 +- {tests => js/tests}/git-gh-cd.test.mjs | 2 +- .../tests}/interactive-option.test.mjs | 2 +- .../tests}/interactive-streaming.test.mjs | 2 +- {tests => js/tests}/issue-135-final.test.mjs | 2 +- .../tests}/jq-color-behavior.test.mjs | 2 +- {tests => js/tests}/jq.test.mjs | 4 +- {tests => js/tests}/options-examples.test.mjs | 2 +- {tests => js/tests}/options-syntax.test.mjs | 2 +- .../tests}/path-interpolation.test.mjs | 2 +- {tests => js/tests}/pipe.test.mjs | 2 +- {tests => js/tests}/raw-function.test.mjs | 2 +- {tests => js/tests}/readme-examples.test.mjs | 2 +- .../resource-cleanup-internals.test.mjs | 2 +- {tests => js/tests}/shell-settings.test.mjs | 2 +- .../tests}/sigint-cleanup-isolated.test.mjs | 2 +- {tests => js/tests}/sigint-cleanup.test.mjs | 2 +- .../tests}/start-run-edge-cases.test.mjs | 2 +- .../tests}/start-run-options.test.mjs | 2 +- .../tests}/stderr-output-handling.test.mjs | 2 +- .../tests}/streaming-interfaces.test.mjs | 2 +- {tests => js/tests}/sync.test.mjs | 2 +- {tests => js/tests}/system-pipe.test.mjs | 2 +- {tests => js/tests}/test-cleanup.mjs | 20 +- {tests => js/tests}/test-helper-fixed.mjs | 16 +- {tests => js/tests}/test-helper-v2.mjs | 14 +- {tests => js/tests}/test-helper.mjs | 20 +- {tests => js/tests}/test-sigint-child.js | 0 {tests => js/tests}/text-method.test.mjs | 2 +- {tests => js/tests}/virtual.test.mjs | 2 +- .../tests}/yes-command-cleanup.test.mjs | 4 +- {tests => js/tests}/zx.features.test.mjs | 0 package.json | 16 +- rust/Cargo.lock | 947 ++++++++++++++++++ rust/src/commands/echo.rs | 44 +- rust/src/commands/mod.rs | 14 +- rust/src/commands/which.rs | 37 +- rust/src/lib.rs | 23 +- rust/src/main.rs | 4 +- rust/src/shell_parser.rs | 4 +- rust/tests/builtin_commands.rs | 549 ++++++++++ rust/tests/process_runner.rs | 286 ++++++ rust/tests/shell_parser.rs | 296 ++++++ rust/tests/utils.rs | 282 ++++++ rust/tests/virtual_commands.rs | 199 ++++ 62 files changed, 2763 insertions(+), 114 deletions(-) create mode 100644 .changeset/rust-translation.md rename {tests => js/tests}/$.features.test.mjs (99%) rename {tests => js/tests}/$.test.mjs (99%) rename {tests => js/tests}/builtin-commands.test.mjs (99%) rename {tests => js/tests}/bun-shell-path-fix.test.mjs (99%) rename {tests => js/tests}/bun.features.test.mjs (100%) rename {tests => js/tests}/cd-virtual-command.test.mjs (99%) rename {tests => js/tests}/cleanup-verification.test.mjs (99%) rename {tests => js/tests}/ctrl-c-baseline.test.mjs (99%) rename {tests => js/tests}/ctrl-c-basic.test.mjs (99%) rename {tests => js/tests}/ctrl-c-library.test.mjs (98%) rename {tests => js/tests}/ctrl-c-signal.test.mjs (99%) rename {tests => js/tests}/examples.test.mjs (99%) rename {tests => js/tests}/execa.features.test.mjs (100%) rename {tests => js/tests}/gh-commands.test.mjs (99%) rename {tests => js/tests}/gh-gist-operations.test.mjs (99%) rename {tests => js/tests}/git-gh-cd.test.mjs (99%) rename {tests => js/tests}/interactive-option.test.mjs (99%) rename {tests => js/tests}/interactive-streaming.test.mjs (99%) rename {tests => js/tests}/issue-135-final.test.mjs (98%) rename {tests => js/tests}/jq-color-behavior.test.mjs (99%) rename {tests => js/tests}/jq.test.mjs (99%) rename {tests => js/tests}/options-examples.test.mjs (98%) rename {tests => js/tests}/options-syntax.test.mjs (99%) rename {tests => js/tests}/path-interpolation.test.mjs (99%) rename {tests => js/tests}/pipe.test.mjs (99%) rename {tests => js/tests}/raw-function.test.mjs (99%) rename {tests => js/tests}/readme-examples.test.mjs (99%) rename {tests => js/tests}/resource-cleanup-internals.test.mjs (99%) rename {tests => js/tests}/shell-settings.test.mjs (99%) rename {tests => js/tests}/sigint-cleanup-isolated.test.mjs (99%) rename {tests => js/tests}/sigint-cleanup.test.mjs (99%) rename {tests => js/tests}/start-run-edge-cases.test.mjs (99%) rename {tests => js/tests}/start-run-options.test.mjs (99%) rename {tests => js/tests}/stderr-output-handling.test.mjs (99%) rename {tests => js/tests}/streaming-interfaces.test.mjs (99%) rename {tests => js/tests}/sync.test.mjs (99%) rename {tests => js/tests}/system-pipe.test.mjs (99%) rename {tests => js/tests}/test-cleanup.mjs (96%) rename {tests => js/tests}/test-helper-fixed.mjs (95%) rename {tests => js/tests}/test-helper-v2.mjs (95%) rename {tests => js/tests}/test-helper.mjs (96%) rename {tests => js/tests}/test-sigint-child.js (100%) rename {tests => js/tests}/text-method.test.mjs (99%) rename {tests => js/tests}/virtual.test.mjs (99%) rename {tests => js/tests}/yes-command-cleanup.test.mjs (98%) rename {tests => js/tests}/zx.features.test.mjs (100%) create mode 100644 rust/Cargo.lock create mode 100644 rust/tests/builtin_commands.rs create mode 100644 rust/tests/process_runner.rs create mode 100644 rust/tests/shell_parser.rs create mode 100644 rust/tests/utils.rs create mode 100644 rust/tests/virtual_commands.rs diff --git a/.changeset/rust-translation.md b/.changeset/rust-translation.md new file mode 100644 index 0000000..3452d91 --- /dev/null +++ b/.changeset/rust-translation.md @@ -0,0 +1,14 @@ +--- +'command-stream': minor +--- + +Add Rust translation and reorganize codebase + +- Reorganize JavaScript source files into `js/` folder structure +- Move tests from root `tests/` to `js/tests/` +- Add complete Rust translation in `rust/` folder with: + - Shell parser supporting &&, ||, ;, |, (), and redirections + - All 21 virtual commands (cat, cp, mv, rm, touch, mkdir, ls, cd, pwd, echo, yes, seq, sleep, env, which, test, exit, basename, dirname, true, false) + - ProcessRunner for async command execution with tokio + - Comprehensive test suite mirroring JavaScript tests + - Case study documentation in docs/case-studies/issue-146/ diff --git a/.gitignore b/.gitignore index a6d35d7..9c6fcd2 100644 --- a/.gitignore +++ b/.gitignore @@ -142,4 +142,4 @@ vite.config.ts.timestamp-* .persisted-configs # jscpd reports -reports/ \ No newline at end of file +reports/rust/target/ diff --git a/bunfig.toml b/bunfig.toml index b8ab7a8..5ba5351 100644 --- a/bunfig.toml +++ b/bunfig.toml @@ -1,8 +1,8 @@ # Bun configuration file [test] -# Only run tests from the tests/ directory -root = "./tests" +# Only run tests from the js/tests/ directory +root = "./js/tests" # Increase timeout from default 5000ms to 10000ms (2x) for CI stability timeout = 10000 diff --git a/tests/$.features.test.mjs b/js/tests/$.features.test.mjs similarity index 99% rename from tests/$.features.test.mjs rename to js/tests/$.features.test.mjs index d44c6e4..9eb0f60 100644 --- a/tests/$.features.test.mjs +++ b/js/tests/$.features.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, shell, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, disableVirtualCommands } from '../src/$.mjs'; // Reset shell settings before each test to prevent interference beforeEach(() => { diff --git a/tests/$.test.mjs b/js/tests/$.test.mjs similarity index 99% rename from tests/$.test.mjs rename to js/tests/$.test.mjs index 1c1253c..6552298 100644 --- a/tests/$.test.mjs +++ b/js/tests/$.test.mjs @@ -12,7 +12,7 @@ import { shell, disableVirtualCommands, enableVirtualCommands, -} from '../js/src/$.mjs'; +} from '../src/$.mjs'; // Reset shell settings before each test to prevent interference beforeEach(() => { diff --git a/tests/builtin-commands.test.mjs b/js/tests/builtin-commands.test.mjs similarity index 99% rename from tests/builtin-commands.test.mjs rename to js/tests/builtin-commands.test.mjs index db1c1f3..4e837a9 100644 --- a/tests/builtin-commands.test.mjs +++ b/js/tests/builtin-commands.test.mjs @@ -1,7 +1,7 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, register, unregister, enableVirtualCommands } from '../js/src/$.mjs'; -import { trace } from '../js/src/$.utils.mjs'; +import { $, register, unregister, enableVirtualCommands } from '../src/$.mjs'; +import { trace } from '../src/$.utils.mjs'; import { rmSync, existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs'; import { join } from 'path'; diff --git a/tests/bun-shell-path-fix.test.mjs b/js/tests/bun-shell-path-fix.test.mjs similarity index 99% rename from tests/bun-shell-path-fix.test.mjs rename to js/tests/bun-shell-path-fix.test.mjs index 9e2965f..fab5aab 100644 --- a/tests/bun-shell-path-fix.test.mjs +++ b/js/tests/bun-shell-path-fix.test.mjs @@ -7,7 +7,7 @@ */ import { test, expect, describe } from 'bun:test'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Test both Bun and Node.js runtimes const isBun = typeof globalThis.Bun !== 'undefined'; diff --git a/tests/bun.features.test.mjs b/js/tests/bun.features.test.mjs similarity index 100% rename from tests/bun.features.test.mjs rename to js/tests/bun.features.test.mjs diff --git a/tests/cd-virtual-command.test.mjs b/js/tests/cd-virtual-command.test.mjs similarity index 99% rename from tests/cd-virtual-command.test.mjs rename to js/tests/cd-virtual-command.test.mjs index aabcbf6..18d3038 100644 --- a/tests/cd-virtual-command.test.mjs +++ b/js/tests/cd-virtual-command.test.mjs @@ -4,7 +4,7 @@ import { afterTestCleanup, originalCwd, } from './test-cleanup.mjs'; -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; import { mkdtempSync, rmSync, diff --git a/tests/cleanup-verification.test.mjs b/js/tests/cleanup-verification.test.mjs similarity index 99% rename from tests/cleanup-verification.test.mjs rename to js/tests/cleanup-verification.test.mjs index 3747d0e..5855203 100644 --- a/tests/cleanup-verification.test.mjs +++ b/js/tests/cleanup-verification.test.mjs @@ -7,7 +7,7 @@ import { originalCwd, } from './test-cleanup.mjs'; import { isWindows } from './test-helper.mjs'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { mkdtempSync, rmSync, realpathSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/tests/ctrl-c-baseline.test.mjs b/js/tests/ctrl-c-baseline.test.mjs similarity index 99% rename from tests/ctrl-c-baseline.test.mjs rename to js/tests/ctrl-c-baseline.test.mjs index b1c48df..a5cabe0 100644 --- a/tests/ctrl-c-baseline.test.mjs +++ b/js/tests/ctrl-c-baseline.test.mjs @@ -1,7 +1,7 @@ import { describe, it, expect, afterEach } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup import { spawn } from 'child_process'; -import { trace } from '../js/src/$.utils.mjs'; +import { trace } from '../src/$.utils.mjs'; // Platform detection - Windows handles signals differently than Unix const isWindows = process.platform === 'win32'; diff --git a/tests/ctrl-c-basic.test.mjs b/js/tests/ctrl-c-basic.test.mjs similarity index 99% rename from tests/ctrl-c-basic.test.mjs rename to js/tests/ctrl-c-basic.test.mjs index 7e68a6a..1606a21 100644 --- a/tests/ctrl-c-basic.test.mjs +++ b/js/tests/ctrl-c-basic.test.mjs @@ -1,6 +1,6 @@ import { describe, it, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Platform detection - Windows handles signals differently than Unix const isWindows = process.platform === 'win32'; diff --git a/tests/ctrl-c-library.test.mjs b/js/tests/ctrl-c-library.test.mjs similarity index 98% rename from tests/ctrl-c-library.test.mjs rename to js/tests/ctrl-c-library.test.mjs index 0b33d28..4149caa 100644 --- a/tests/ctrl-c-library.test.mjs +++ b/js/tests/ctrl-c-library.test.mjs @@ -1,8 +1,8 @@ import { describe, it, expect, afterEach } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup import { spawn } from 'child_process'; -import { $ } from '../js/src/$.mjs'; -import { trace } from '../js/src/$.utils.mjs'; +import { $ } from '../src/$.mjs'; +import { trace } from '../src/$.utils.mjs'; // Platform detection - Windows handles signals differently than Unix const isWindows = process.platform === 'win32'; diff --git a/tests/ctrl-c-signal.test.mjs b/js/tests/ctrl-c-signal.test.mjs similarity index 99% rename from tests/ctrl-c-signal.test.mjs rename to js/tests/ctrl-c-signal.test.mjs index 449edaf..7b71768 100644 --- a/tests/ctrl-c-signal.test.mjs +++ b/js/tests/ctrl-c-signal.test.mjs @@ -1,7 +1,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; import { spawn } from 'child_process'; -import { trace } from '../js/src/$.utils.mjs'; +import { trace } from '../src/$.utils.mjs'; // Platform detection - Windows handles signals differently than Unix const isWindows = process.platform === 'win32'; diff --git a/tests/examples.test.mjs b/js/tests/examples.test.mjs similarity index 99% rename from tests/examples.test.mjs rename to js/tests/examples.test.mjs index 2be2b13..9c7cd42 100644 --- a/tests/examples.test.mjs +++ b/js/tests/examples.test.mjs @@ -1,7 +1,7 @@ import { test, expect, describe } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../js/src/$.mjs'; -import { trace } from '../js/src/$.utils.mjs'; +import { $ } from '../src/$.mjs'; +import { trace } from '../src/$.utils.mjs'; import { readdirSync, statSync, readFileSync } from 'fs'; import { join } from 'path'; diff --git a/tests/execa.features.test.mjs b/js/tests/execa.features.test.mjs similarity index 100% rename from tests/execa.features.test.mjs rename to js/tests/execa.features.test.mjs diff --git a/tests/gh-commands.test.mjs b/js/tests/gh-commands.test.mjs similarity index 99% rename from tests/gh-commands.test.mjs rename to js/tests/gh-commands.test.mjs index 2729f3b..c7cd4b6 100644 --- a/tests/gh-commands.test.mjs +++ b/js/tests/gh-commands.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Platform detection - tests use Unix shell redirection 2>&1 and sh -c const isWindows = process.platform === 'win32'; diff --git a/tests/gh-gist-operations.test.mjs b/js/tests/gh-gist-operations.test.mjs similarity index 99% rename from tests/gh-gist-operations.test.mjs rename to js/tests/gh-gist-operations.test.mjs index 9f4eaae..2cf9edb 100644 --- a/tests/gh-gist-operations.test.mjs +++ b/js/tests/gh-gist-operations.test.mjs @@ -8,7 +8,7 @@ import { afterEach, } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/tests/git-gh-cd.test.mjs b/js/tests/git-gh-cd.test.mjs similarity index 99% rename from tests/git-gh-cd.test.mjs rename to js/tests/git-gh-cd.test.mjs index e7f399c..356e0e3 100644 --- a/tests/git-gh-cd.test.mjs +++ b/js/tests/git-gh-cd.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; import { mkdtempSync, rmSync, existsSync, realpathSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/tests/interactive-option.test.mjs b/js/tests/interactive-option.test.mjs similarity index 99% rename from tests/interactive-option.test.mjs rename to js/tests/interactive-option.test.mjs index 44a3b41..af6b24e 100644 --- a/tests/interactive-option.test.mjs +++ b/js/tests/interactive-option.test.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; diff --git a/tests/interactive-streaming.test.mjs b/js/tests/interactive-streaming.test.mjs similarity index 99% rename from tests/interactive-streaming.test.mjs rename to js/tests/interactive-streaming.test.mjs index d98bb5a..6ae67cc 100644 --- a/tests/interactive-streaming.test.mjs +++ b/js/tests/interactive-streaming.test.mjs @@ -2,7 +2,7 @@ import { describe, it, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/tests/issue-135-final.test.mjs b/js/tests/issue-135-final.test.mjs similarity index 98% rename from tests/issue-135-final.test.mjs rename to js/tests/issue-135-final.test.mjs index e31a2e9..f7edc02 100755 --- a/tests/issue-135-final.test.mjs +++ b/js/tests/issue-135-final.test.mjs @@ -2,7 +2,7 @@ // This test verifies the main fix: CI=true should NOT cause trace logs import { describe, it, beforeEach } from 'bun:test'; import assert from 'assert'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; describe('Issue #135: CI environment no longer auto-enables trace logs', () => { beforeEach(() => { diff --git a/tests/jq-color-behavior.test.mjs b/js/tests/jq-color-behavior.test.mjs similarity index 99% rename from tests/jq-color-behavior.test.mjs rename to js/tests/jq-color-behavior.test.mjs index a8134e9..dcb32f9 100644 --- a/tests/jq-color-behavior.test.mjs +++ b/js/tests/jq-color-behavior.test.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { test, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup diff --git a/tests/jq.test.mjs b/js/tests/jq.test.mjs similarity index 99% rename from tests/jq.test.mjs rename to js/tests/jq.test.mjs index deb7193..fb3839d 100644 --- a/tests/jq.test.mjs +++ b/js/tests/jq.test.mjs @@ -1,5 +1,5 @@ -import { $ } from '../js/src/$.mjs'; -import { trace } from '../js/src/$.utils.mjs'; +import { $ } from '../src/$.mjs'; +import { trace } from '../src/$.utils.mjs'; import { describe, test, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup diff --git a/tests/options-examples.test.mjs b/js/tests/options-examples.test.mjs similarity index 98% rename from tests/options-examples.test.mjs rename to js/tests/options-examples.test.mjs index e9cc975..a9526f9 100644 --- a/tests/options-examples.test.mjs +++ b/js/tests/options-examples.test.mjs @@ -2,7 +2,7 @@ import { test, expect, describe } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; describe('Options Examples (Feature Demo)', () => { test('example: disable capture for performance', async () => { diff --git a/tests/options-syntax.test.mjs b/js/tests/options-syntax.test.mjs similarity index 99% rename from tests/options-syntax.test.mjs rename to js/tests/options-syntax.test.mjs index c68a132..e0f4db4 100644 --- a/tests/options-syntax.test.mjs +++ b/js/tests/options-syntax.test.mjs @@ -1,6 +1,6 @@ import { describe, it, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; describe('$({ options }) syntax', () => { it('should support $({ options }) syntax for custom options', async () => { diff --git a/tests/path-interpolation.test.mjs b/js/tests/path-interpolation.test.mjs similarity index 99% rename from tests/path-interpolation.test.mjs rename to js/tests/path-interpolation.test.mjs index 8a6dbf9..c5b3e0c 100644 --- a/tests/path-interpolation.test.mjs +++ b/js/tests/path-interpolation.test.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { test, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup diff --git a/tests/pipe.test.mjs b/js/tests/pipe.test.mjs similarity index 99% rename from tests/pipe.test.mjs rename to js/tests/pipe.test.mjs index 5ba999f..c185b70 100644 --- a/tests/pipe.test.mjs +++ b/js/tests/pipe.test.mjs @@ -6,7 +6,7 @@ import { unregister, enableVirtualCommands, disableVirtualCommands, -} from '../js/src/$.mjs'; +} from '../src/$.mjs'; import { rmSync, existsSync, mkdirSync, writeFileSync } from 'fs'; import { join } from 'path'; diff --git a/tests/raw-function.test.mjs b/js/tests/raw-function.test.mjs similarity index 99% rename from tests/raw-function.test.mjs rename to js/tests/raw-function.test.mjs index aab827a..82d6f83 100644 --- a/tests/raw-function.test.mjs +++ b/js/tests/raw-function.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach } from 'bun:test'; import './test-helper.mjs'; -import { $, raw, shell, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, raw, shell, disableVirtualCommands } from '../src/$.mjs'; // Disable virtual commands for consistent system command behavior beforeEach(() => { diff --git a/tests/readme-examples.test.mjs b/js/tests/readme-examples.test.mjs similarity index 99% rename from tests/readme-examples.test.mjs rename to js/tests/readme-examples.test.mjs index 3fe27c2..76ad339 100644 --- a/tests/readme-examples.test.mjs +++ b/js/tests/readme-examples.test.mjs @@ -8,7 +8,7 @@ import { set, unset, disableVirtualCommands, -} from '../js/src/$.mjs'; +} from '../src/$.mjs'; // Helper function to setup shell settings for README tests function setupShellForReadme() { diff --git a/tests/resource-cleanup-internals.test.mjs b/js/tests/resource-cleanup-internals.test.mjs similarity index 99% rename from tests/resource-cleanup-internals.test.mjs rename to js/tests/resource-cleanup-internals.test.mjs index df862a7..455feaa 100644 --- a/tests/resource-cleanup-internals.test.mjs +++ b/js/tests/resource-cleanup-internals.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, forceCleanupAll } from '../js/src/$.mjs'; +import { $, forceCleanupAll } from '../src/$.mjs'; import { EventEmitter } from 'events'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/tests/shell-settings.test.mjs b/js/tests/shell-settings.test.mjs similarity index 99% rename from tests/shell-settings.test.mjs rename to js/tests/shell-settings.test.mjs index 729de8f..5ebe47b 100644 --- a/tests/shell-settings.test.mjs +++ b/js/tests/shell-settings.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, shell, set, unset } from '../js/src/$.mjs'; +import { $, shell, set, unset } from '../src/$.mjs'; describe('Shell Settings (set -e / set +e equivalent)', () => { beforeEach(() => { diff --git a/tests/sigint-cleanup-isolated.test.mjs b/js/tests/sigint-cleanup-isolated.test.mjs similarity index 99% rename from tests/sigint-cleanup-isolated.test.mjs rename to js/tests/sigint-cleanup-isolated.test.mjs index cd9616d..74a9090 100644 --- a/tests/sigint-cleanup-isolated.test.mjs +++ b/js/tests/sigint-cleanup-isolated.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; diff --git a/tests/sigint-cleanup.test.mjs b/js/tests/sigint-cleanup.test.mjs similarity index 99% rename from tests/sigint-cleanup.test.mjs rename to js/tests/sigint-cleanup.test.mjs index 3299bd4..0c16ba9 100644 --- a/tests/sigint-cleanup.test.mjs +++ b/js/tests/sigint-cleanup.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Platform detection - Windows handles signals differently than Unix const isWindows = process.platform === 'win32'; diff --git a/tests/start-run-edge-cases.test.mjs b/js/tests/start-run-edge-cases.test.mjs similarity index 99% rename from tests/start-run-edge-cases.test.mjs rename to js/tests/start-run-edge-cases.test.mjs index 625e624..35fd2f9 100644 --- a/tests/start-run-edge-cases.test.mjs +++ b/js/tests/start-run-edge-cases.test.mjs @@ -2,7 +2,7 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, shell } from '../js/src/$.mjs'; +import { $, shell } from '../src/$.mjs'; describe('Start/Run Edge Cases and Advanced Usage', () => { beforeEach(() => { diff --git a/tests/start-run-options.test.mjs b/js/tests/start-run-options.test.mjs similarity index 99% rename from tests/start-run-options.test.mjs rename to js/tests/start-run-options.test.mjs index b079fae..da45bcc 100644 --- a/tests/start-run-options.test.mjs +++ b/js/tests/start-run-options.test.mjs @@ -2,7 +2,7 @@ import { test, expect, describe } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; describe('Start/Run Options Passing', () => { describe('.start() method with options', () => { diff --git a/tests/stderr-output-handling.test.mjs b/js/tests/stderr-output-handling.test.mjs similarity index 99% rename from tests/stderr-output-handling.test.mjs rename to js/tests/stderr-output-handling.test.mjs index d70914a..f673508 100644 --- a/tests/stderr-output-handling.test.mjs +++ b/js/tests/stderr-output-handling.test.mjs @@ -1,7 +1,7 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs'; import { isWindows } from './test-helper.mjs'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/tests/streaming-interfaces.test.mjs b/js/tests/streaming-interfaces.test.mjs similarity index 99% rename from tests/streaming-interfaces.test.mjs rename to js/tests/streaming-interfaces.test.mjs index f0610c5..b04bb0b 100644 --- a/tests/streaming-interfaces.test.mjs +++ b/js/tests/streaming-interfaces.test.mjs @@ -1,6 +1,6 @@ import { test, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Platform detection - Some tests use Unix utilities (cat, grep, sort, sh) const isWindows = process.platform === 'win32'; diff --git a/tests/sync.test.mjs b/js/tests/sync.test.mjs similarity index 99% rename from tests/sync.test.mjs rename to js/tests/sync.test.mjs index 8e4a1c3..09b0a6f 100644 --- a/tests/sync.test.mjs +++ b/js/tests/sync.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import { isWindows } from './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, shell } from '../js/src/$.mjs'; +import { $, shell } from '../src/$.mjs'; // Reset shell settings before each test beforeEach(() => { diff --git a/tests/system-pipe.test.mjs b/js/tests/system-pipe.test.mjs similarity index 99% rename from tests/system-pipe.test.mjs rename to js/tests/system-pipe.test.mjs index 59b1058..77b6865 100644 --- a/tests/system-pipe.test.mjs +++ b/js/tests/system-pipe.test.mjs @@ -1,6 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, shell, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, disableVirtualCommands } from '../src/$.mjs'; import { execSync } from 'child_process'; // Platform detection - These tests use Unix utilities (printf, grep, sed, awk, etc.) diff --git a/tests/test-cleanup.mjs b/js/tests/test-cleanup.mjs similarity index 96% rename from tests/test-cleanup.mjs rename to js/tests/test-cleanup.mjs index 39cb024..2e0eca4 100644 --- a/tests/test-cleanup.mjs +++ b/js/tests/test-cleanup.mjs @@ -18,7 +18,7 @@ * ``` */ -import { resetGlobalState } from '../js/src/$.mjs'; +import { resetGlobalState } from '../src/$.mjs'; import { existsSync } from 'fs'; // Save the original working directory when module loads @@ -47,7 +47,7 @@ export async function beforeTestCleanup() { try { // Force restoration regardless of current state process.chdir(originalCwd); - } catch (e) { + } catch (_e) { // Original directory might be gone, try fallbacks try { if (existsSync(originalCwd)) { @@ -59,7 +59,7 @@ export async function beforeTestCleanup() { } else { process.chdir('/'); } - } catch (e2) { + } catch (_e2) { console.error( '[test-cleanup] FATAL: Cannot set working directory in beforeTestCleanup' ); @@ -74,7 +74,7 @@ export async function beforeTestCleanup() { // Extra safety: ensure we're in a valid directory after reset try { process.cwd(); // This will throw if we're in a bad state - } catch (e) { + } catch (_e) { // Force to a known good directory process.chdir(originalCwd); } @@ -96,7 +96,7 @@ export async function beforeTestCleanup() { `[test-cleanup] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${verifiedCwd}` ); } - } catch (e) { + } catch (_e) { throw new Error( `[test-cleanup] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${finalCwd}` ); @@ -121,7 +121,7 @@ export async function afterTestCleanup() { try { // Force restoration regardless of current state process.chdir(originalCwd); - } catch (e) { + } catch (_e) { // Original directory might be gone, try fallbacks try { if (existsSync(originalCwd)) { @@ -133,7 +133,7 @@ export async function afterTestCleanup() { } else { process.chdir('/'); } - } catch (e2) { + } catch (_e2) { console.error( '[test-cleanup] FATAL: Cannot set working directory in afterTestCleanup' ); @@ -148,7 +148,7 @@ export async function afterTestCleanup() { // Extra safety: ensure we're in a valid directory after reset try { process.cwd(); // This will throw if we're in a bad state - } catch (e) { + } catch (_e) { // Force to a known good directory process.chdir(originalCwd); } @@ -170,7 +170,7 @@ export async function afterTestCleanup() { `[test-cleanup] CRITICAL: Cannot restore to original directory ${originalCwd} in afterEach, stuck in ${verifiedCwd}` ); } - } catch (e) { + } catch (_e) { throw new Error( `[test-cleanup] CRITICAL: Cannot restore to original directory ${originalCwd} in afterEach, stuck in ${finalCwd}` ); @@ -188,7 +188,7 @@ process.on('beforeExit', () => { if (process.cwd() !== originalCwd) { process.chdir(originalCwd); } - } catch (e) { + } catch (_e) { // Ignore } }); diff --git a/tests/test-helper-fixed.mjs b/js/tests/test-helper-fixed.mjs similarity index 95% rename from tests/test-helper-fixed.mjs rename to js/tests/test-helper-fixed.mjs index 7b00610..f82f8ca 100644 --- a/tests/test-helper-fixed.mjs +++ b/js/tests/test-helper-fixed.mjs @@ -18,7 +18,7 @@ */ import { beforeEach, afterEach } from 'bun:test'; -import { resetGlobalState } from '../js/src/$.mjs'; +import { resetGlobalState } from '../src/$.mjs'; import { existsSync } from 'fs'; // Save the original working directory when tests start @@ -50,7 +50,7 @@ export function setupTestHooks() { try { // Force restoration regardless of current state process.chdir(originalCwd); - } catch (e) { + } catch (_e) { // Original directory might be gone, try fallbacks try { if (existsSync(originalCwd)) { @@ -62,7 +62,7 @@ export function setupTestHooks() { } else { process.chdir('/'); } - } catch (e2) { + } catch (_e2) { console.error( '[test-helper] FATAL: Cannot set working directory in beforeEach' ); @@ -77,7 +77,7 @@ export function setupTestHooks() { // Extra safety: ensure we're in a valid directory after reset try { process.cwd(); // This will throw if we're in a bad state - } catch (e) { + } catch (_e) { // Force to a known good directory process.chdir(originalCwd); } @@ -96,7 +96,7 @@ export function setupTestHooks() { try { // Force restoration regardless of current state process.chdir(originalCwd); - } catch (e) { + } catch (_e) { // Original directory might be gone, try fallbacks try { if (existsSync(originalCwd)) { @@ -108,7 +108,7 @@ export function setupTestHooks() { } else { process.chdir('/'); } - } catch (e2) { + } catch (_e2) { console.error( '[test-helper] FATAL: Cannot set working directory in afterEach' ); @@ -123,7 +123,7 @@ export function setupTestHooks() { // Extra safety: ensure we're in a valid directory after reset try { process.cwd(); // This will throw if we're in a bad state - } catch (e) { + } catch (_e) { // Force to a known good directory process.chdir(originalCwd); } @@ -140,7 +140,7 @@ process.on('beforeExit', () => { if (process.cwd() !== originalCwd) { process.chdir(originalCwd); } - } catch (e) { + } catch (_e) { // Ignore } }); diff --git a/tests/test-helper-v2.mjs b/js/tests/test-helper-v2.mjs similarity index 95% rename from tests/test-helper-v2.mjs rename to js/tests/test-helper-v2.mjs index 4e45ae0..3a42e80 100644 --- a/tests/test-helper-v2.mjs +++ b/js/tests/test-helper-v2.mjs @@ -1,5 +1,5 @@ import { beforeEach, afterEach } from 'bun:test'; -import { resetGlobalState } from '../js/src/$.mjs'; +import { resetGlobalState } from '../src/$.mjs'; import { existsSync } from 'fs'; // Save the original working directory when tests start @@ -28,7 +28,7 @@ export function setupTestHooks() { try { // Force restoration regardless of current state process.chdir(originalCwd); - } catch (e) { + } catch (_e) { // Original directory might be gone, try fallbacks try { if (existsSync(originalCwd)) { @@ -40,7 +40,7 @@ export function setupTestHooks() { } else { process.chdir('/'); } - } catch (e2) { + } catch (_e2) { console.error( '[test-helper-v2] FATAL: Cannot set working directory in beforeEach' ); @@ -55,7 +55,7 @@ export function setupTestHooks() { // Extra safety: ensure we're in a valid directory after reset try { process.cwd(); // This will throw if we're in a bad state - } catch (e) { + } catch (_e) { // Force to a known good directory process.chdir(originalCwd); } @@ -74,7 +74,7 @@ export function setupTestHooks() { try { // Force restoration regardless of current state process.chdir(originalCwd); - } catch (e) { + } catch (_e) { // Original directory might be gone, try fallbacks try { if (existsSync(originalCwd)) { @@ -86,7 +86,7 @@ export function setupTestHooks() { } else { process.chdir('/'); } - } catch (e2) { + } catch (_e2) { console.error( '[test-helper-v2] FATAL: Cannot set working directory in afterEach' ); @@ -101,7 +101,7 @@ export function setupTestHooks() { // Extra safety: ensure we're in a valid directory after reset try { process.cwd(); // This will throw if we're in a bad state - } catch (e) { + } catch (_e) { // Force to a known good directory process.chdir(originalCwd); } diff --git a/tests/test-helper.mjs b/js/tests/test-helper.mjs similarity index 96% rename from tests/test-helper.mjs rename to js/tests/test-helper.mjs index d3dea5d..3ddb896 100644 --- a/tests/test-helper.mjs +++ b/js/tests/test-helper.mjs @@ -1,5 +1,5 @@ import { beforeEach, afterEach } from 'bun:test'; -import { resetGlobalState } from '../js/src/$.mjs'; +import { resetGlobalState } from '../src/$.mjs'; import { existsSync } from 'fs'; // Platform detection helpers @@ -25,7 +25,7 @@ process.on('beforeExit', () => { if (process.cwd() !== originalCwd) { process.chdir(originalCwd); } - } catch (e) { + } catch (_e) { // Ignore } }); @@ -41,7 +41,7 @@ beforeEach(async () => { try { // Force restoration regardless of current state process.chdir(originalCwd); - } catch (e) { + } catch (_e) { // Original directory might be gone, try fallbacks try { if (existsSync(originalCwd)) { @@ -53,7 +53,7 @@ beforeEach(async () => { } else { process.chdir('/'); } - } catch (e2) { + } catch (_e2) { console.error( '[test-helper] FATAL: Cannot set working directory in beforeEach' ); @@ -67,7 +67,7 @@ beforeEach(async () => { // Extra safety: ensure we're in a valid directory after reset try { process.cwd(); // This will throw if we're in a bad state - } catch (e) { + } catch (_e) { // Force to a known good directory process.chdir(originalCwd); } @@ -89,7 +89,7 @@ beforeEach(async () => { `[test-helper] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${verifiedCwd}` ); } - } catch (e) { + } catch (_e) { throw new Error( `[test-helper] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${finalCwd}` ); @@ -109,7 +109,7 @@ afterEach(async () => { try { // Force restoration regardless of current state process.chdir(originalCwd); - } catch (e) { + } catch (_e) { // Original directory might be gone, try fallbacks try { if (existsSync(originalCwd)) { @@ -121,7 +121,7 @@ afterEach(async () => { } else { process.chdir('/'); } - } catch (e2) { + } catch (_e2) { console.error( '[test-helper] FATAL: Cannot set working directory in afterEach' ); @@ -135,7 +135,7 @@ afterEach(async () => { // Extra safety: ensure we're in a valid directory after reset try { process.cwd(); // This will throw if we're in a bad state - } catch (e) { + } catch (_e) { // Force to a known good directory process.chdir(originalCwd); } @@ -157,7 +157,7 @@ afterEach(async () => { `[test-helper] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${verifiedCwd}` ); } - } catch (e) { + } catch (_e) { throw new Error( `[test-helper] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${finalCwd}` ); diff --git a/tests/test-sigint-child.js b/js/tests/test-sigint-child.js similarity index 100% rename from tests/test-sigint-child.js rename to js/tests/test-sigint-child.js diff --git a/tests/text-method.test.mjs b/js/tests/text-method.test.mjs similarity index 99% rename from tests/text-method.test.mjs rename to js/tests/text-method.test.mjs index bc48b13..ab0b70b 100644 --- a/tests/text-method.test.mjs +++ b/js/tests/text-method.test.mjs @@ -1,6 +1,6 @@ import { describe, test, expect } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, disableVirtualCommands } from '../src/$.mjs'; // Disable virtual commands to ensure we're testing system/built-in commands disableVirtualCommands(); diff --git a/tests/virtual.test.mjs b/js/tests/virtual.test.mjs similarity index 99% rename from tests/virtual.test.mjs rename to js/tests/virtual.test.mjs index ce4b550..0c3b38a 100644 --- a/tests/virtual.test.mjs +++ b/js/tests/virtual.test.mjs @@ -8,7 +8,7 @@ import { unregister, listCommands, enableVirtualCommands, -} from '../js/src/$.mjs'; +} from '../src/$.mjs'; // Helper function to setup shell settings function setupShellSettings() { diff --git a/tests/yes-command-cleanup.test.mjs b/js/tests/yes-command-cleanup.test.mjs similarity index 98% rename from tests/yes-command-cleanup.test.mjs rename to js/tests/yes-command-cleanup.test.mjs index fb80186..f0ff5dd 100644 --- a/tests/yes-command-cleanup.test.mjs +++ b/js/tests/yes-command-cleanup.test.mjs @@ -1,7 +1,7 @@ import { test, expect, describe } from 'bun:test'; import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup -import { $ } from '../js/src/$.mjs'; -import { trace } from '../js/src/$.utils.mjs'; +import { $ } from '../src/$.mjs'; +import { trace } from '../src/$.utils.mjs'; describe('Yes Command Cleanup Tests', () => { test('should stop yes command when breaking from async iteration', async () => { diff --git a/tests/zx.features.test.mjs b/js/tests/zx.features.test.mjs similarity index 100% rename from tests/zx.features.test.mjs rename to js/tests/zx.features.test.mjs diff --git a/package.json b/package.json index 2f95963..c47aed9 100644 --- a/package.json +++ b/package.json @@ -16,14 +16,14 @@ "url": "https://github.com/link-foundation/command-stream/issues" }, "scripts": { - "test": "bun test tests/", - "test:coverage": "bun test tests/ --coverage", - "test:features": "bun test tests/*.features.test.mjs", - "test:comparison": "bun test tests/*.features.test.mjs --reporter=verbose", - "test:readme": "bun test tests/readme-examples.test.mjs", - "test:sync": "bun test tests/sync.test.mjs", - "test:builtin": "bun test tests/builtin-commands.test.mjs", - "test:pipe": "bun test tests/pipe.test.mjs", + "test": "bun test js/tests/", + "test:coverage": "bun test js/tests/ --coverage", + "test:features": "bun test js/tests/*.features.test.mjs", + "test:comparison": "bun test js/tests/*.features.test.mjs --reporter=verbose", + "test:readme": "bun test js/tests/readme-examples.test.mjs", + "test:sync": "bun test js/tests/sync.test.mjs", + "test:builtin": "bun test js/tests/builtin-commands.test.mjs", + "test:pipe": "bun test js/tests/pipe.test.mjs", "lint": "eslint .", "lint:fix": "eslint . --fix", "format": "prettier --write .", diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 0000000..a2b4183 --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,947 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "assert_cmd" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcbb6924530aa9e0432442af08bbcafdad182db80d2e560da42a6d442535bf85" +dependencies = [ + "anstyle", + "bstr", + "libc", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "cc" +version = "1.2.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "command-stream" +version = "0.8.3" +dependencies = [ + "assert_cmd", + "async-trait", + "chrono", + "filetime", + "glob", + "libc", + "nix", + "once_cell", + "regex", + "serde", + "serde_json", + "tempfile", + "thiserror", + "tokio", + "tokio-test", + "which", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "filetime" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.178" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" + +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags", + "libc", + "redox_syscall 0.7.0", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "predicates" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +dependencies = [ + "anstyle", + "difflib", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" + +[[package]] +name = "predicates-tree" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "proc-macro2" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "syn" +version = "2.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "which" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" +dependencies = [ + "either", + "env_home", + "rustix", + "winsafe", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "zmij" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4a4e8e9dc5c62d159f04fcdbe07f4c3fb710415aab4754bf11505501e3251d" diff --git a/rust/src/commands/echo.rs b/rust/src/commands/echo.rs index 0383493..7c3e74c 100644 --- a/rust/src/commands/echo.rs +++ b/rust/src/commands/echo.rs @@ -6,9 +6,49 @@ use crate::utils::CommandResult; /// Execute the echo command /// /// Outputs the arguments separated by spaces, followed by a newline. +/// Supports -n (no newline), -e (interpret escape sequences), and -E (no escape sequences) pub async fn echo(ctx: CommandContext) -> CommandResult { - let output = ctx.args.join(" "); - CommandResult::success(format!("{}\n", output)) + let mut no_newline = false; + let mut interpret_escapes = false; + let mut args = ctx.args.iter().peekable(); + + // Parse flags + while let Some(arg) = args.peek() { + if arg.starts_with('-') && arg.len() > 1 && arg.chars().skip(1).all(|c| c == 'n' || c == 'e' || c == 'E') { + let arg = args.next().unwrap(); + for c in arg.chars().skip(1) { + match c { + 'n' => no_newline = true, + 'e' => interpret_escapes = true, + 'E' => interpret_escapes = false, + _ => {} + } + } + } else { + break; + } + } + + // Collect remaining args + let remaining: Vec<_> = args.collect(); + let output = remaining.iter().map(|s| s.as_str()).collect::>().join(" "); + + // Process escape sequences if -e flag is set + let output = if interpret_escapes { + output + .replace("\\n", "\n") + .replace("\\t", "\t") + .replace("\\r", "\r") + .replace("\\\\", "\\") + } else { + output + }; + + if no_newline { + CommandResult::success(output) + } else { + CommandResult::success(format!("{}\n", output)) + } } #[cfg(test)] diff --git a/rust/src/commands/mod.rs b/rust/src/commands/mod.rs index 0d4cf1b..5f2ba42 100644 --- a/rust/src/commands/mod.rs +++ b/rust/src/commands/mod.rs @@ -54,7 +54,6 @@ use std::path::Path; use tokio::sync::mpsc; /// Context for virtual command execution -#[derive(Debug)] pub struct CommandContext { /// Command arguments (excluding the command name) pub args: Vec, @@ -70,6 +69,19 @@ pub struct CommandContext { pub is_cancelled: Option bool + Send + Sync>>, } +impl std::fmt::Debug for CommandContext { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CommandContext") + .field("args", &self.args) + .field("stdin", &self.stdin) + .field("cwd", &self.cwd) + .field("env", &self.env) + .field("output_tx", &self.output_tx.is_some()) + .field("is_cancelled", &self.is_cancelled.is_some()) + .finish() + } +} + /// A chunk of streaming output #[derive(Debug, Clone)] pub enum StreamChunk { diff --git a/rust/src/commands/which.rs b/rust/src/commands/which.rs index 3853b81..2cbc0ff 100644 --- a/rust/src/commands/which.rs +++ b/rust/src/commands/which.rs @@ -3,15 +3,23 @@ use crate::commands::CommandContext; use crate::utils::{CommandResult, VirtualUtils}; +/// List of virtual (shell builtin) commands +const VIRTUAL_COMMANDS: &[&str] = &[ + "echo", "pwd", "cd", "true", "false", "sleep", "cat", "ls", "mkdir", "rm", + "touch", "cp", "mv", "basename", "dirname", "env", "exit", "which", "yes", + "seq", "test", +]; + /// Execute the which command /// -/// Locates commands in the PATH. +/// Locates commands in the PATH or identifies shell builtins. pub async fn which(ctx: CommandContext) -> CommandResult { if ctx.args.is_empty() { return VirtualUtils::missing_operand_error("which"); } let mut output = String::new(); + let mut errors = String::new(); let mut found_all = true; for cmd in &ctx.args { @@ -19,23 +27,34 @@ pub async fn which(ctx: CommandContext) -> CommandResult { continue; } - match which::which(cmd) { - Ok(path) => { - output.push_str(&format!("{}\n", path.display())); - } - Err(_) => { - found_all = false; + // Check if it's a virtual/builtin command + if VIRTUAL_COMMANDS.contains(&cmd.as_str()) { + output.push_str(&format!("{}: shell builtin\n", cmd)); + } else { + // Try to find in PATH + match which::which(cmd) { + Ok(path) => { + output.push_str(&format!("{}\n", path.display())); + } + Err(_) => { + found_all = false; + errors.push_str(&format!("which: no {} in PATH\n", cmd)); + } } } } if output.is_empty() { - CommandResult::error_with_code("", 1) + CommandResult { + stdout: String::new(), + stderr: errors, + code: 1, + } } else if !found_all { // Some commands found, some not CommandResult { stdout: output, - stderr: String::new(), + stderr: errors, code: 1, } } else { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 0cc5850..311230f 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -16,12 +16,12 @@ //! ## Quick Start //! //! ```rust,no_run -//! use command_stream::$; +//! use command_stream::run; //! //! #[tokio::main] //! async fn main() -> Result<(), Box> { //! // Execute a simple command -//! let result = $("echo hello world").await?; +//! let result = run("echo hello world").await?; //! println!("{}", result.stdout); //! Ok(()) //! } @@ -239,7 +239,7 @@ impl ProcessRunner { return Ok(result.clone()); } - let child = self.child.take().ok_or_else(|| { + let mut child = self.child.take().ok_or_else(|| { Error::Io(std::io::Error::new( std::io::ErrorKind::Other, "Process not started", @@ -248,7 +248,7 @@ impl ProcessRunner { // Handle stdin content if provided if let StdinOption::Content(ref content) = self.options.stdin { - if let Some(mut stdin) = child.stdin { + if let Some(mut stdin) = child.stdin.take() { let content = content.clone(); tokio::spawn(async move { let _ = stdin.write_all(content.as_bytes()).await; @@ -261,7 +261,7 @@ impl ProcessRunner { let mut stdout_content = String::new(); let mut stderr_content = String::new(); - if let Some(stdout) = child.stdout { + if let Some(stdout) = child.stdout.take() { let mut reader = BufReader::new(stdout).lines(); while let Ok(Some(line)) = reader.next_line().await { if self.options.mirror { @@ -272,7 +272,7 @@ impl ProcessRunner { } } - if let Some(stderr) = child.stderr { + if let Some(stderr) = child.stderr.take() { let mut reader = BufReader::new(stderr).lines(); while let Ok(Some(line)) = reader.next_line().await { if self.options.mirror { @@ -425,11 +425,16 @@ fn find_available_shell() -> ShellConfig { /// Execute a command and return the result /// /// This is the main entry point for simple command execution. -pub async fn $(command: impl Into) -> Result { +/// Named `run` instead of `$` since `$` is not a valid Rust identifier. +pub async fn run(command: impl Into) -> Result { let mut runner = ProcessRunner::new(command, RunOptions::default()); runner.run().await } +/// Alias for `run` function - for JavaScript-like API feel +/// Since `$` is not valid in Rust, this provides a similar short name +pub use run as execute; + /// Execute a command with custom options pub async fn exec(command: impl Into, options: RunOptions) -> Result { let mut runner = ProcessRunner::new(command, options); @@ -444,7 +449,7 @@ pub fn create(command: impl Into, options: RunOptions) -> ProcessRunner /// Execute a command synchronously (blocking) pub fn run_sync(command: impl Into) -> Result { let rt = tokio::runtime::Runtime::new()?; - rt.block_on($(command)) + rt.block_on(run(command)) } #[cfg(test)] @@ -453,7 +458,7 @@ mod tests { #[tokio::test] async fn test_simple_echo() { - let result = $("echo hello").await.unwrap(); + let result = run("echo hello").await.unwrap(); assert!(result.is_success()); assert!(result.stdout.contains("hello")); } diff --git a/rust/src/main.rs b/rust/src/main.rs index 1578578..b6e8edd 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -2,7 +2,7 @@ //! //! A simple CLI wrapper for the command-stream library. -use command_stream::{$, RunOptions, ProcessRunner}; +use command_stream::{run, RunOptions, ProcessRunner}; use std::env; #[tokio::main] @@ -23,7 +23,7 @@ async fn main() -> Result<(), Box> { let command = args.join(" "); - let result = $(command).await?; + let result = run(command).await?; // Print any output that wasn't mirrored if !result.stdout.is_empty() && !result.stdout.ends_with('\n') { diff --git a/rust/src/shell_parser.rs b/rust/src/shell_parser.rs index c82e01a..6d65454 100644 --- a/rust/src/shell_parser.rs +++ b/rust/src/shell_parser.rs @@ -242,8 +242,8 @@ impl ShellParser { } } - fn current(&self) -> &Token { - self.tokens.get(self.pos).unwrap_or(&Token { + fn current(&self) -> Token { + self.tokens.get(self.pos).cloned().unwrap_or(Token { token_type: TokenType::Eof, value: String::new(), }) diff --git a/rust/tests/builtin_commands.rs b/rust/tests/builtin_commands.rs new file mode 100644 index 0000000..f86dd0d --- /dev/null +++ b/rust/tests/builtin_commands.rs @@ -0,0 +1,549 @@ +//! Integration tests for built-in virtual commands +//! +//! These tests mirror the JavaScript tests in js/tests/builtin-commands.test.mjs + +use command_stream::commands::{ + basename, cat, cd, cp, dirname, echo, env, exit, ls, mkdir, mv, pwd, rm, seq, sleep, test, + touch, which, yes, CommandContext, +}; +use command_stream::utils::CommandResult; +use std::fs; +use std::path::PathBuf; +use tempfile::TempDir; + +/// Helper to create a command context with args +fn ctx(args: Vec<&str>) -> CommandContext { + CommandContext { + args: args.into_iter().map(String::from).collect(), + stdin: None, + cwd: None, + env: None, + output_tx: None, + is_cancelled: None, + } +} + +/// Helper to create a command context with args and cwd +fn ctx_with_cwd(args: Vec<&str>, cwd: PathBuf) -> CommandContext { + CommandContext { + args: args.into_iter().map(String::from).collect(), + stdin: None, + cwd: Some(cwd), + env: None, + output_tx: None, + is_cancelled: None, + } +} + +/// Helper to create a command context with stdin +fn ctx_with_stdin(args: Vec<&str>, stdin: &str) -> CommandContext { + CommandContext { + args: args.into_iter().map(String::from).collect(), + stdin: Some(stdin.to_string()), + cwd: None, + env: None, + output_tx: None, + is_cancelled: None, + } +} + +// ============================================================================ +// Echo Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_echo_basic() { + let result = echo(ctx(vec!["Hello", "World"])).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "Hello World\n"); +} + +#[tokio::test] +async fn test_echo_with_n_flag() { + let result = echo(ctx(vec!["-n", "Hello"])).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "Hello"); +} + +#[tokio::test] +async fn test_echo_empty() { + let result = echo(ctx(vec![])).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "\n"); +} + +#[tokio::test] +async fn test_echo_with_e_flag() { + let result = echo(ctx(vec!["-e", "Hello\\nWorld"])).await; + assert!(result.is_success()); + assert!(result.stdout.contains("\n")); +} + +// ============================================================================ +// Pwd Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_pwd_returns_current_directory() { + let result = pwd(ctx(vec![])).await; + assert!(result.is_success()); + assert!(!result.stdout.is_empty()); +} + +// ============================================================================ +// True/False Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_true_command() { + let result = command_stream::commands::r#true(ctx(vec![])).await; + assert!(result.is_success()); + assert_eq!(result.code, 0); +} + +#[tokio::test] +async fn test_false_command() { + let result = command_stream::commands::r#false(ctx(vec![])).await; + assert!(!result.is_success()); + assert_eq!(result.code, 1); +} + +// ============================================================================ +// Cat Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_cat_read_file() { + let dir = TempDir::new().unwrap(); + let file_path = dir.path().join("test.txt"); + fs::write(&file_path, "Hello World\nLine 2\n").unwrap(); + + let result = cat(ctx(vec![file_path.to_str().unwrap()])).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "Hello World\nLine 2\n"); +} + +#[tokio::test] +async fn test_cat_from_stdin() { + let result = cat(ctx_with_stdin(vec![], "stdin input")).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "stdin input"); +} + +#[tokio::test] +async fn test_cat_nonexistent_file() { + let result = cat(ctx(vec!["nonexistent.txt"])).await; + assert!(!result.is_success()); + assert!(result.stderr.contains("No such file or directory")); +} + +// ============================================================================ +// Ls Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_ls_list_directory() { + let dir = TempDir::new().unwrap(); + fs::write(dir.path().join("file1.txt"), "content").unwrap(); + fs::write(dir.path().join("file2.txt"), "content").unwrap(); + fs::create_dir(dir.path().join("subdir")).unwrap(); + + let result = ls(ctx(vec![dir.path().to_str().unwrap()])).await; + assert!(result.is_success()); + assert!(result.stdout.contains("file1.txt")); + assert!(result.stdout.contains("file2.txt")); + assert!(result.stdout.contains("subdir")); +} + +#[tokio::test] +async fn test_ls_with_a_flag() { + let dir = TempDir::new().unwrap(); + fs::write(dir.path().join(".hidden"), "content").unwrap(); + fs::write(dir.path().join("visible.txt"), "content").unwrap(); + + let result = ls(ctx(vec!["-a", dir.path().to_str().unwrap()])).await; + assert!(result.is_success()); + assert!(result.stdout.contains(".hidden")); + assert!(result.stdout.contains("visible.txt")); +} + +#[tokio::test] +async fn test_ls_with_l_flag() { + let dir = TempDir::new().unwrap(); + fs::write(dir.path().join("test.txt"), "content").unwrap(); + + let result = ls(ctx(vec!["-l", dir.path().to_str().unwrap()])).await; + assert!(result.is_success()); + // Long format should include permissions + assert!(result.stdout.contains("-") || result.stdout.contains("r")); + assert!(result.stdout.contains("test.txt")); +} + +// ============================================================================ +// Mkdir Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_mkdir_create_directory() { + let dir = TempDir::new().unwrap(); + let new_dir = dir.path().join("newdir"); + + let result = mkdir(ctx(vec![new_dir.to_str().unwrap()])).await; + assert!(result.is_success()); + assert!(new_dir.exists()); +} + +#[tokio::test] +async fn test_mkdir_with_p_flag() { + let dir = TempDir::new().unwrap(); + let nested_dir = dir.path().join("parent").join("child"); + + let result = mkdir(ctx(vec!["-p", nested_dir.to_str().unwrap()])).await; + assert!(result.is_success()); + assert!(nested_dir.exists()); +} + +// ============================================================================ +// Touch Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_touch_create_file() { + let dir = TempDir::new().unwrap(); + let file_path = dir.path().join("touched.txt"); + + let result = touch(ctx(vec![file_path.to_str().unwrap()])).await; + assert!(result.is_success()); + assert!(file_path.exists()); +} + +#[tokio::test] +async fn test_touch_update_timestamp() { + let dir = TempDir::new().unwrap(); + let file_path = dir.path().join("existing.txt"); + fs::write(&file_path, "content").unwrap(); + let old_mtime = fs::metadata(&file_path).unwrap().modified().unwrap(); + + // Wait a bit to ensure timestamp difference + std::thread::sleep(std::time::Duration::from_millis(10)); + + let result = touch(ctx(vec![file_path.to_str().unwrap()])).await; + assert!(result.is_success()); + + let new_mtime = fs::metadata(&file_path).unwrap().modified().unwrap(); + assert!(new_mtime > old_mtime); +} + +// ============================================================================ +// Rm Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_rm_remove_file() { + let dir = TempDir::new().unwrap(); + let file_path = dir.path().join("to-remove.txt"); + fs::write(&file_path, "content").unwrap(); + + let result = rm(ctx(vec![file_path.to_str().unwrap()])).await; + assert!(result.is_success()); + assert!(!file_path.exists()); +} + +#[tokio::test] +async fn test_rm_fail_on_directory() { + let dir = TempDir::new().unwrap(); + let sub_dir = dir.path().join("to-remove-dir"); + fs::create_dir(&sub_dir).unwrap(); + + let result = rm(ctx(vec![sub_dir.to_str().unwrap()])).await; + assert!(!result.is_success()); + assert!(result.stderr.contains("Is a directory")); + assert!(sub_dir.exists()); +} + +#[tokio::test] +async fn test_rm_recursive() { + let dir = TempDir::new().unwrap(); + let sub_dir = dir.path().join("to-remove-recursive"); + fs::create_dir(&sub_dir).unwrap(); + fs::write(sub_dir.join("file.txt"), "content").unwrap(); + + let result = rm(ctx(vec!["-r", sub_dir.to_str().unwrap()])).await; + assert!(result.is_success()); + assert!(!sub_dir.exists()); +} + +#[tokio::test] +async fn test_rm_force() { + let result = rm(ctx(vec!["-f", "nonexistent.txt"])).await; + assert!(result.is_success()); +} + +// ============================================================================ +// Cp Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_cp_copy_file() { + let dir = TempDir::new().unwrap(); + let source = dir.path().join("source.txt"); + let dest = dir.path().join("dest.txt"); + fs::write(&source, "test content").unwrap(); + + let result = cp(ctx(vec![source.to_str().unwrap(), dest.to_str().unwrap()])).await; + assert!(result.is_success()); + assert!(dest.exists()); + assert_eq!(fs::read_to_string(&dest).unwrap(), "test content"); +} + +#[tokio::test] +async fn test_cp_recursive() { + let dir = TempDir::new().unwrap(); + let source_dir = dir.path().join("source-dir"); + let dest_dir = dir.path().join("dest-dir"); + fs::create_dir(&source_dir).unwrap(); + fs::write(source_dir.join("file.txt"), "content").unwrap(); + + let result = cp(ctx(vec![ + "-r", + source_dir.to_str().unwrap(), + dest_dir.to_str().unwrap(), + ])) + .await; + assert!(result.is_success()); + assert!(dest_dir.exists()); + assert!(dest_dir.join("file.txt").exists()); +} + +// ============================================================================ +// Mv Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_mv_rename_file() { + let dir = TempDir::new().unwrap(); + let source = dir.path().join("source.txt"); + let dest = dir.path().join("dest.txt"); + fs::write(&source, "test content").unwrap(); + + let result = mv(ctx(vec![source.to_str().unwrap(), dest.to_str().unwrap()])).await; + assert!(result.is_success()); + assert!(!source.exists()); + assert!(dest.exists()); + assert_eq!(fs::read_to_string(&dest).unwrap(), "test content"); +} + +#[tokio::test] +async fn test_mv_to_directory() { + let dir = TempDir::new().unwrap(); + let source = dir.path().join("source.txt"); + let dest_dir = dir.path().join("dest-dir"); + fs::write(&source, "test content").unwrap(); + fs::create_dir(&dest_dir).unwrap(); + + let result = mv(ctx(vec![source.to_str().unwrap(), dest_dir.to_str().unwrap()])).await; + assert!(result.is_success()); + assert!(!source.exists()); + assert!(dest_dir.join("source.txt").exists()); +} + +// ============================================================================ +// Basename/Dirname Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_basename() { + let result = basename(ctx(vec!["/path/to/file.txt"])).await; + assert!(result.is_success()); + assert_eq!(result.stdout.trim(), "file.txt"); +} + +#[tokio::test] +async fn test_basename_with_suffix() { + let result = basename(ctx(vec!["/path/to/file.txt", ".txt"])).await; + assert!(result.is_success()); + assert_eq!(result.stdout.trim(), "file"); +} + +#[tokio::test] +async fn test_dirname() { + let result = dirname(ctx(vec!["/path/to/file.txt"])).await; + assert!(result.is_success()); + assert_eq!(result.stdout.trim(), "/path/to"); +} + +// ============================================================================ +// Which Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_which_builtin() { + let result = which(ctx(vec!["echo"])).await; + assert!(result.is_success()); + assert!(result.stdout.contains("shell builtin")); +} + +// ============================================================================ +// Exit Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_exit_default() { + let result = exit(ctx(vec![])).await; + assert!(result.is_success()); + assert_eq!(result.code, 0); +} + +#[tokio::test] +async fn test_exit_with_code() { + let result = exit(ctx(vec!["42"])).await; + assert!(!result.is_success()); + assert_eq!(result.code, 42); +} + +// ============================================================================ +// Sleep Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_sleep() { + let start = std::time::Instant::now(); + let result = sleep(ctx(vec!["0.1"])).await; + let elapsed = start.elapsed(); + + assert!(result.is_success()); + assert!(elapsed.as_millis() >= 90); + assert!(elapsed.as_millis() < 200); +} + +// ============================================================================ +// Seq Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_seq_simple() { + let result = seq(ctx(vec!["5"])).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "1\n2\n3\n4\n5\n"); +} + +#[tokio::test] +async fn test_seq_range() { + let result = seq(ctx(vec!["2", "5"])).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "2\n3\n4\n5\n"); +} + +#[tokio::test] +async fn test_seq_with_increment() { + let result = seq(ctx(vec!["1", "2", "5"])).await; + assert!(result.is_success()); + assert_eq!(result.stdout, "1\n3\n5\n"); +} + +// ============================================================================ +// Yes Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_yes_with_cancel() { + use std::sync::atomic::{AtomicBool, Ordering}; + use std::sync::Arc; + + // Create a cancellation flag + let cancelled = Arc::new(AtomicBool::new(false)); + let cancelled_clone = cancelled.clone(); + + // Cancel after a short delay + tokio::spawn(async move { + tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + cancelled_clone.store(true, Ordering::SeqCst); + }); + + let ctx = CommandContext { + args: vec![], + stdin: None, + cwd: None, + env: None, + output_tx: None, + is_cancelled: Some(Box::new(move || cancelled.load(Ordering::SeqCst))), + }; + + let result = yes(ctx).await; + // Yes command should have produced some output before being cancelled + assert!(result.stdout.contains("y") || result.is_success()); +} + +// ============================================================================ +// Test Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_test_file_exists() { + let dir = TempDir::new().unwrap(); + let file_path = dir.path().join("test.txt"); + fs::write(&file_path, "content").unwrap(); + + let result = test(ctx(vec!["-e", file_path.to_str().unwrap()])).await; + assert!(result.is_success()); +} + +#[tokio::test] +async fn test_test_file_not_exists() { + let result = test(ctx(vec!["-e", "nonexistent.txt"])).await; + assert!(!result.is_success()); +} + +#[tokio::test] +async fn test_test_is_file() { + let dir = TempDir::new().unwrap(); + let file_path = dir.path().join("test.txt"); + fs::write(&file_path, "content").unwrap(); + + let result = test(ctx(vec!["-f", file_path.to_str().unwrap()])).await; + assert!(result.is_success()); +} + +#[tokio::test] +async fn test_test_is_directory() { + let dir = TempDir::new().unwrap(); + + let result = test(ctx(vec!["-d", dir.path().to_str().unwrap()])).await; + assert!(result.is_success()); +} + +#[tokio::test] +async fn test_test_string_not_empty() { + let result = test(ctx(vec!["-n", "hello"])).await; + assert!(result.is_success()); +} + +#[tokio::test] +async fn test_test_string_empty() { + let result = test(ctx(vec!["-z", ""])).await; + assert!(result.is_success()); +} + +#[tokio::test] +async fn test_test_string_equals() { + let result = test(ctx(vec!["hello", "=", "hello"])).await; + assert!(result.is_success()); +} + +#[tokio::test] +async fn test_test_string_not_equals() { + let result = test(ctx(vec!["hello", "!=", "world"])).await; + assert!(result.is_success()); +} + +// ============================================================================ +// Env Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_env_list() { + let result = env(ctx(vec![])).await; + assert!(result.is_success()); + // Should contain some environment variables + assert!(!result.stdout.is_empty()); +} diff --git a/rust/tests/process_runner.rs b/rust/tests/process_runner.rs new file mode 100644 index 0000000..93c1c19 --- /dev/null +++ b/rust/tests/process_runner.rs @@ -0,0 +1,286 @@ +//! Integration tests for ProcessRunner +//! +//! These tests mirror the JavaScript $.test.mjs tests + +use command_stream::{run, create, exec, ProcessRunner, RunOptions, StdinOption}; +use std::collections::HashMap; +use std::path::PathBuf; +use tempfile::TempDir; + +// ============================================================================ +// Basic Command Execution Tests +// ============================================================================ + +#[tokio::test] +async fn test_simple_echo() { + let result = run("echo hello").await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("hello")); +} + +#[tokio::test] +async fn test_echo_with_multiple_words() { + let result = run("echo hello world").await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("hello world")); +} + +#[tokio::test] +async fn test_command_with_arguments() { + let result = run("echo -n test").await.unwrap(); + assert!(result.is_success()); +} + +#[tokio::test] +async fn test_false_command_returns_nonzero() { + let result = run("false").await.unwrap(); + assert!(!result.is_success()); + assert_eq!(result.code, 1); +} + +#[tokio::test] +async fn test_true_command_returns_zero() { + let result = run("true").await.unwrap(); + assert!(result.is_success()); + assert_eq!(result.code, 0); +} + +// ============================================================================ +// ProcessRunner Tests +// ============================================================================ + +#[tokio::test] +async fn test_process_runner_basic() { + let mut runner = ProcessRunner::new( + "echo hello", + RunOptions { + mirror: false, + ..Default::default() + }, + ); + + let result = runner.run().await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("hello")); +} + +#[tokio::test] +async fn test_process_runner_with_capture() { + let mut runner = ProcessRunner::new( + "echo captured", + RunOptions { + mirror: false, + capture: true, + ..Default::default() + }, + ); + + let result = runner.run().await.unwrap(); + assert!(result.stdout.contains("captured")); +} + +#[tokio::test] +async fn test_process_runner_is_finished() { + let mut runner = ProcessRunner::new("true", RunOptions::default()); + + assert!(!runner.is_finished()); + let _ = runner.run().await; + assert!(runner.is_finished()); +} + +#[tokio::test] +async fn test_process_runner_result() { + let mut runner = ProcessRunner::new("echo test", RunOptions::default()); + let _ = runner.run().await; + + let result = runner.result(); + assert!(result.is_some()); + assert!(result.unwrap().is_success()); +} + +// ============================================================================ +// Working Directory Tests +// ============================================================================ + +#[tokio::test] +async fn test_custom_working_directory() { + let dir = TempDir::new().unwrap(); + std::fs::write(dir.path().join("test.txt"), "content").unwrap(); + + let mut runner = ProcessRunner::new( + "ls", + RunOptions { + mirror: false, + cwd: Some(dir.path().to_path_buf()), + ..Default::default() + }, + ); + + let result = runner.run().await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("test.txt")); +} + +// ============================================================================ +// Environment Variables Tests +// ============================================================================ + +#[tokio::test] +async fn test_custom_environment_variable() { + let mut env_vars = HashMap::new(); + env_vars.insert("MY_TEST_VAR".to_string(), "test_value".to_string()); + + let mut runner = ProcessRunner::new( + "printenv MY_TEST_VAR", + RunOptions { + mirror: false, + env: Some(env_vars), + ..Default::default() + }, + ); + + let result = runner.run().await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("test_value")); +} + +// ============================================================================ +// Stdin Tests +// ============================================================================ + +#[tokio::test] +async fn test_stdin_content() { + let mut runner = ProcessRunner::new( + "cat", + RunOptions { + mirror: false, + stdin: StdinOption::Content("hello from stdin".to_string()), + ..Default::default() + }, + ); + + let result = runner.run().await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("hello from stdin")); +} + +// ============================================================================ +// exec Function Tests +// ============================================================================ + +#[tokio::test] +async fn test_exec_with_options() { + let result = exec( + "echo test", + RunOptions { + mirror: false, + ..Default::default() + }, + ) + .await + .unwrap(); + + assert!(result.is_success()); + assert!(result.stdout.contains("test")); +} + +// ============================================================================ +// create Function Tests +// ============================================================================ + +#[tokio::test] +async fn test_create_and_run() { + let mut runner = create("echo created", RunOptions::default()); + let result = runner.run().await.unwrap(); + + assert!(result.is_success()); + assert!(result.stdout.contains("created")); +} + +// ============================================================================ +// Virtual Command Tests +// ============================================================================ + +#[tokio::test] +async fn test_virtual_echo() { + let result = run("echo virtual echo").await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("virtual echo")); +} + +#[tokio::test] +async fn test_virtual_pwd() { + let result = run("pwd").await.unwrap(); + assert!(result.is_success()); + assert!(!result.stdout.is_empty()); +} + +#[tokio::test] +async fn test_virtual_true() { + let result = run("true").await.unwrap(); + assert!(result.is_success()); + assert_eq!(result.code, 0); +} + +#[tokio::test] +async fn test_virtual_false() { + let result = run("false").await.unwrap(); + assert!(!result.is_success()); + assert_eq!(result.code, 1); +} + +#[tokio::test] +async fn test_virtual_sleep() { + let start = std::time::Instant::now(); + let result = run("sleep 0.05").await.unwrap(); + let elapsed = start.elapsed(); + + assert!(result.is_success()); + assert!(elapsed.as_millis() >= 40); +} + +// ============================================================================ +// Stderr Tests +// ============================================================================ + +#[tokio::test] +async fn test_stderr_capture() { + let result = run("cat nonexistent_file_12345").await.unwrap(); + assert!(!result.is_success()); + assert!(!result.stderr.is_empty()); +} + +// ============================================================================ +// Exit Code Tests +// ============================================================================ + +#[tokio::test] +async fn test_exit_code_zero() { + let result = run("exit 0").await.unwrap(); + assert_eq!(result.code, 0); +} + +#[tokio::test] +async fn test_exit_code_nonzero() { + let result = run("exit 42").await.unwrap(); + assert_eq!(result.code, 42); +} + +// ============================================================================ +// Kill/Cancel Tests +// ============================================================================ + +#[tokio::test] +async fn test_kill_process() { + let mut runner = ProcessRunner::new( + "sleep 10", + RunOptions { + mirror: false, + ..Default::default() + }, + ); + + runner.start().await.unwrap(); + let kill_result = runner.kill(); + assert!(kill_result.is_ok()); +} diff --git a/rust/tests/shell_parser.rs b/rust/tests/shell_parser.rs new file mode 100644 index 0000000..240666b --- /dev/null +++ b/rust/tests/shell_parser.rs @@ -0,0 +1,296 @@ +//! Integration tests for shell parser +//! +//! These tests mirror the JavaScript shell parser tests + +use command_stream::shell_parser::{needs_real_shell, parse_shell_command, tokenize, ParsedCommand, TokenType}; + +// ============================================================================ +// Tokenizer Tests +// ============================================================================ + +#[test] +fn test_tokenize_simple_command() { + let tokens = tokenize("echo hello world"); + assert_eq!(tokens.len(), 4); // 3 words + EOF + assert!(matches!(tokens[0].token_type, TokenType::Word(_))); + assert!(matches!(tokens[1].token_type, TokenType::Word(_))); + assert!(matches!(tokens[2].token_type, TokenType::Word(_))); + assert!(matches!(tokens[3].token_type, TokenType::Eof)); +} + +#[test] +fn test_tokenize_with_and_operator() { + let tokens = tokenize("cmd1 && cmd2"); + assert!(tokens.iter().any(|t| matches!(t.token_type, TokenType::And))); +} + +#[test] +fn test_tokenize_with_or_operator() { + let tokens = tokenize("cmd1 || cmd2"); + assert!(tokens.iter().any(|t| matches!(t.token_type, TokenType::Or))); +} + +#[test] +fn test_tokenize_with_pipe() { + let tokens = tokenize("ls | grep foo"); + assert!(tokens.iter().any(|t| matches!(t.token_type, TokenType::Pipe))); +} + +#[test] +fn test_tokenize_with_semicolon() { + let tokens = tokenize("cmd1 ; cmd2"); + assert!(tokens.iter().any(|t| matches!(t.token_type, TokenType::Semicolon))); +} + +#[test] +fn test_tokenize_with_parentheses() { + let tokens = tokenize("(echo hello)"); + assert!(tokens.iter().any(|t| matches!(t.token_type, TokenType::LParen))); + assert!(tokens.iter().any(|t| matches!(t.token_type, TokenType::RParen))); +} + +#[test] +fn test_tokenize_with_redirect() { + let tokens = tokenize("echo hello > file.txt"); + assert!(tokens.iter().any(|t| matches!(t.token_type, TokenType::RedirectOut))); +} + +#[test] +fn test_tokenize_with_append_redirect() { + let tokens = tokenize("echo hello >> file.txt"); + assert!(tokens.iter().any(|t| matches!(t.token_type, TokenType::RedirectAppend))); +} + +#[test] +fn test_tokenize_with_input_redirect() { + let tokens = tokenize("cat < file.txt"); + assert!(tokens.iter().any(|t| matches!(t.token_type, TokenType::RedirectIn))); +} + +#[test] +fn test_tokenize_single_quoted_string() { + let tokens = tokenize("echo 'hello world'"); + assert_eq!(tokens.len(), 3); // echo + quoted string + EOF + if let TokenType::Word(w) = &tokens[1].token_type { + assert_eq!(w, "'hello world'"); + } else { + panic!("Expected Word token"); + } +} + +#[test] +fn test_tokenize_double_quoted_string() { + let tokens = tokenize("echo \"hello world\""); + assert_eq!(tokens.len(), 3); // echo + quoted string + EOF + if let TokenType::Word(w) = &tokens[1].token_type { + assert_eq!(w, "\"hello world\""); + } else { + panic!("Expected Word token"); + } +} + +#[test] +fn test_tokenize_mixed_operators() { + let tokens = tokenize("cmd1 && cmd2 || cmd3 ; cmd4"); + let ops: Vec<_> = tokens + .iter() + .filter(|t| matches!(t.token_type, TokenType::And | TokenType::Or | TokenType::Semicolon)) + .collect(); + assert_eq!(ops.len(), 3); +} + +// ============================================================================ +// Parser Tests +// ============================================================================ + +#[test] +fn test_parse_simple_command() { + let cmd = parse_shell_command("echo hello world").unwrap(); + match cmd { + ParsedCommand::Simple { cmd, args, .. } => { + assert_eq!(cmd, "echo"); + assert_eq!(args.len(), 2); + assert_eq!(args[0].value, "hello"); + assert_eq!(args[1].value, "world"); + } + _ => panic!("Expected Simple command"), + } +} + +#[test] +fn test_parse_command_with_quoted_args() { + let cmd = parse_shell_command("echo 'hello world'").unwrap(); + match cmd { + ParsedCommand::Simple { cmd, args, .. } => { + assert_eq!(cmd, "echo"); + assert_eq!(args.len(), 1); + assert_eq!(args[0].value, "hello world"); + assert!(args[0].quoted); + } + _ => panic!("Expected Simple command"), + } +} + +#[test] +fn test_parse_pipeline() { + let cmd = parse_shell_command("ls | grep foo | wc -l").unwrap(); + match cmd { + ParsedCommand::Pipeline { commands } => { + assert_eq!(commands.len(), 3); + } + _ => panic!("Expected Pipeline"), + } +} + +#[test] +fn test_parse_sequence_with_and() { + let cmd = parse_shell_command("cmd1 && cmd2").unwrap(); + match cmd { + ParsedCommand::Sequence { commands, operators } => { + assert_eq!(commands.len(), 2); + assert_eq!(operators.len(), 1); + assert!(matches!(operators[0], TokenType::And)); + } + _ => panic!("Expected Sequence"), + } +} + +#[test] +fn test_parse_sequence_with_or() { + let cmd = parse_shell_command("cmd1 || cmd2").unwrap(); + match cmd { + ParsedCommand::Sequence { commands, operators } => { + assert_eq!(commands.len(), 2); + assert_eq!(operators.len(), 1); + assert!(matches!(operators[0], TokenType::Or)); + } + _ => panic!("Expected Sequence"), + } +} + +#[test] +fn test_parse_sequence_mixed() { + let cmd = parse_shell_command("cmd1 && cmd2 || cmd3").unwrap(); + match cmd { + ParsedCommand::Sequence { commands, operators } => { + assert_eq!(commands.len(), 3); + assert_eq!(operators.len(), 2); + assert!(matches!(operators[0], TokenType::And)); + assert!(matches!(operators[1], TokenType::Or)); + } + _ => panic!("Expected Sequence"), + } +} + +#[test] +fn test_parse_with_redirect_out() { + let cmd = parse_shell_command("echo hello > output.txt").unwrap(); + match cmd { + ParsedCommand::Simple { cmd, args, redirects } => { + assert_eq!(cmd, "echo"); + assert_eq!(args.len(), 1); + assert_eq!(redirects.len(), 1); + assert!(matches!(redirects[0].redirect_type, TokenType::RedirectOut)); + assert_eq!(redirects[0].target, "output.txt"); + } + _ => panic!("Expected Simple command with redirect"), + } +} + +#[test] +fn test_parse_with_redirect_append() { + let cmd = parse_shell_command("echo hello >> output.txt").unwrap(); + match cmd { + ParsedCommand::Simple { redirects, .. } => { + assert_eq!(redirects.len(), 1); + assert!(matches!(redirects[0].redirect_type, TokenType::RedirectAppend)); + } + _ => panic!("Expected Simple command with redirect"), + } +} + +#[test] +fn test_parse_subshell() { + let cmd = parse_shell_command("(echo hello)").unwrap(); + match cmd { + ParsedCommand::Subshell { command } => { + match *command { + ParsedCommand::Simple { cmd, .. } => { + assert_eq!(cmd, "echo"); + } + _ => panic!("Expected Simple command inside subshell"), + } + } + _ => panic!("Expected Subshell"), + } +} + +#[test] +fn test_parse_subshell_with_sequence() { + let cmd = parse_shell_command("(echo hello) && echo world").unwrap(); + match cmd { + ParsedCommand::Sequence { commands, .. } => { + assert_eq!(commands.len(), 2); + assert!(matches!(commands[0], ParsedCommand::Subshell { .. })); + } + _ => panic!("Expected Sequence with Subshell"), + } +} + +#[test] +fn test_parse_complex_pipeline_and_sequence() { + let cmd = parse_shell_command("ls | grep foo && cat file | wc").unwrap(); + // This should be: (ls | grep foo) && (cat file | wc) + match cmd { + ParsedCommand::Sequence { commands, operators } => { + assert_eq!(commands.len(), 2); + assert_eq!(operators.len(), 1); + // Both commands should be pipelines + } + _ => panic!("Expected Sequence"), + } +} + +// ============================================================================ +// needs_real_shell Tests +// ============================================================================ + +#[test] +fn test_needs_real_shell_command_substitution() { + assert!(needs_real_shell("echo $(date)")); + assert!(needs_real_shell("echo `date`")); +} + +#[test] +fn test_needs_real_shell_variable_expansion() { + assert!(needs_real_shell("echo ${HOME}")); +} + +#[test] +fn test_needs_real_shell_glob_patterns() { + assert!(needs_real_shell("ls *.txt")); + assert!(needs_real_shell("ls file?.txt")); + assert!(needs_real_shell("ls [abc].txt")); +} + +#[test] +fn test_needs_real_shell_stderr_redirect() { + assert!(needs_real_shell("cmd 2>/dev/null")); +} + +#[test] +fn test_needs_real_shell_combined_redirect() { + assert!(needs_real_shell("cmd &>/dev/null")); +} + +#[test] +fn test_needs_real_shell_here_document() { + assert!(needs_real_shell("cat << EOF")); +} + +#[test] +fn test_needs_real_shell_simple_commands() { + assert!(!needs_real_shell("echo hello")); + assert!(!needs_real_shell("ls | grep foo")); + assert!(!needs_real_shell("cmd1 && cmd2")); +} diff --git a/rust/tests/utils.rs b/rust/tests/utils.rs new file mode 100644 index 0000000..97693d7 --- /dev/null +++ b/rust/tests/utils.rs @@ -0,0 +1,282 @@ +//! Integration tests for utility functions +//! +//! These tests mirror the JavaScript utility tests + +use command_stream::utils::{AnsiConfig, AnsiUtils, CommandResult, VirtualUtils, quote}; +use std::path::PathBuf; + +// ============================================================================ +// CommandResult Tests +// ============================================================================ + +#[test] +fn test_command_result_success() { + let result = CommandResult::success("hello"); + assert!(result.is_success()); + assert_eq!(result.stdout, "hello"); + assert_eq!(result.stderr, ""); + assert_eq!(result.code, 0); +} + +#[test] +fn test_command_result_success_empty() { + let result = CommandResult::success_empty(); + assert!(result.is_success()); + assert_eq!(result.stdout, ""); + assert_eq!(result.stderr, ""); + assert_eq!(result.code, 0); +} + +#[test] +fn test_command_result_error() { + let result = CommandResult::error("something went wrong"); + assert!(!result.is_success()); + assert_eq!(result.stdout, ""); + assert_eq!(result.stderr, "something went wrong"); + assert_eq!(result.code, 1); +} + +#[test] +fn test_command_result_error_with_code() { + let result = CommandResult::error_with_code("not found", 127); + assert!(!result.is_success()); + assert_eq!(result.code, 127); +} + +// ============================================================================ +// VirtualUtils Tests +// ============================================================================ + +#[test] +fn test_missing_operand_error() { + let result = VirtualUtils::missing_operand_error("cat"); + assert!(!result.is_success()); + assert!(result.stderr.contains("cat")); + assert!(result.stderr.contains("missing operand")); +} + +#[test] +fn test_invalid_argument_error() { + let result = VirtualUtils::invalid_argument_error("test", "invalid option"); + assert!(!result.is_success()); + assert!(result.stderr.contains("test")); + assert!(result.stderr.contains("invalid option")); +} + +#[test] +fn test_validate_args_sufficient() { + let args = vec!["arg1".to_string()]; + let error = VirtualUtils::validate_args(&args, 1, "cmd"); + assert!(error.is_none()); +} + +#[test] +fn test_validate_args_insufficient() { + let args = vec![]; + let error = VirtualUtils::validate_args(&args, 1, "cmd"); + assert!(error.is_some()); +} + +#[test] +fn test_resolve_path_absolute() { + let path = VirtualUtils::resolve_path("/absolute/path", None); + assert_eq!(path, PathBuf::from("/absolute/path")); +} + +#[test] +fn test_resolve_path_relative_with_cwd() { + let cwd = PathBuf::from("/home/user"); + let path = VirtualUtils::resolve_path("relative/path", Some(&cwd)); + assert_eq!(path, PathBuf::from("/home/user/relative/path")); +} + +#[test] +fn test_resolve_path_relative_without_cwd() { + let path = VirtualUtils::resolve_path("relative/path", None); + // Should resolve relative to current directory + assert!(path.ends_with("relative/path")); +} + +// ============================================================================ +// AnsiUtils Tests +// ============================================================================ + +#[test] +fn test_strip_ansi_basic() { + let text = "\x1b[31mRed text\x1b[0m"; + assert_eq!(AnsiUtils::strip_ansi(text), "Red text"); +} + +#[test] +fn test_strip_ansi_multiple() { + let text = "\x1b[1m\x1b[31mBold Red\x1b[0m normal"; + let result = AnsiUtils::strip_ansi(text); + assert_eq!(result, "Bold Red normal"); +} + +#[test] +fn test_strip_ansi_no_sequences() { + let text = "plain text"; + assert_eq!(AnsiUtils::strip_ansi(text), "plain text"); +} + +#[test] +fn test_strip_ansi_color_codes() { + let text = "\x1b[32mGreen\x1b[0m and \x1b[34mBlue\x1b[0m"; + assert_eq!(AnsiUtils::strip_ansi(text), "Green and Blue"); +} + +#[test] +fn test_strip_control_chars_basic() { + let text = "Hello\x00World"; + assert_eq!(AnsiUtils::strip_control_chars(text), "HelloWorld"); +} + +#[test] +fn test_strip_control_chars_preserve_newline() { + let text = "Line1\nLine2"; + assert_eq!(AnsiUtils::strip_control_chars(text), "Line1\nLine2"); +} + +#[test] +fn test_strip_control_chars_preserve_tab() { + let text = "Col1\tCol2"; + assert_eq!(AnsiUtils::strip_control_chars(text), "Col1\tCol2"); +} + +#[test] +fn test_strip_control_chars_preserve_carriage_return() { + let text = "Line1\r\nLine2"; + assert_eq!(AnsiUtils::strip_control_chars(text), "Line1\r\nLine2"); +} + +#[test] +fn test_strip_all() { + let text = "\x1b[31mRed\x00text\x1b[0m\nNewline"; + let result = AnsiUtils::strip_all(text); + assert_eq!(result, "Redtext\nNewline"); +} + +// ============================================================================ +// AnsiConfig Tests +// ============================================================================ + +#[test] +fn test_ansi_config_default() { + let config = AnsiConfig::default(); + assert!(config.preserve_ansi); + assert!(config.preserve_control_chars); +} + +#[test] +fn test_ansi_config_process_preserve_all() { + let config = AnsiConfig { + preserve_ansi: true, + preserve_control_chars: true, + }; + let text = "\x1b[31mRed\x00text\x1b[0m"; + let result = config.process_output(text); + assert_eq!(result, text); +} + +#[test] +fn test_ansi_config_process_strip_ansi_only() { + let config = AnsiConfig { + preserve_ansi: false, + preserve_control_chars: true, + }; + let text = "\x1b[31mRed text\x1b[0m"; + let result = config.process_output(text); + assert_eq!(result, "Red text"); +} + +#[test] +fn test_ansi_config_process_strip_control_only() { + let config = AnsiConfig { + preserve_ansi: true, + preserve_control_chars: false, + }; + let text = "Hello\x00World\nNewline"; + let result = config.process_output(text); + assert_eq!(result, "HelloWorld\nNewline"); +} + +#[test] +fn test_ansi_config_process_strip_all() { + let config = AnsiConfig { + preserve_ansi: false, + preserve_control_chars: false, + }; + let text = "\x1b[31mRed\x00text\x1b[0m"; + let result = config.process_output(text); + assert_eq!(result, "Redtext"); +} + +// ============================================================================ +// Quote Function Tests +// ============================================================================ + +#[test] +fn test_quote_empty_string() { + assert_eq!(quote(""), "''"); +} + +#[test] +fn test_quote_simple_string() { + assert_eq!(quote("hello"), "hello"); +} + +#[test] +fn test_quote_path() { + assert_eq!(quote("/path/to/file"), "/path/to/file"); +} + +#[test] +fn test_quote_with_spaces() { + assert_eq!(quote("hello world"), "'hello world'"); +} + +#[test] +fn test_quote_with_single_quote() { + assert_eq!(quote("it's"), "'it'\\''s'"); +} + +#[test] +fn test_quote_already_single_quoted() { + assert_eq!(quote("'hello'"), "'hello'"); +} + +#[test] +fn test_quote_already_double_quoted() { + let result = quote("\"hello\""); + assert!(result.contains("hello")); +} + +#[test] +fn test_quote_safe_characters() { + // These should not need quoting + assert_eq!(quote("file.txt"), "file.txt"); + assert_eq!(quote("path/to/file"), "path/to/file"); + assert_eq!(quote("key=value"), "key=value"); + assert_eq!(quote("user@host"), "user@host"); +} + +#[test] +fn test_quote_special_characters() { + // These need quoting + let result = quote("hello$world"); + assert!(result.starts_with("'") && result.ends_with("'")); + + let result = quote("hello;world"); + assert!(result.starts_with("'") && result.ends_with("'")); + + let result = quote("hello|world"); + assert!(result.starts_with("'") && result.ends_with("'")); +} + +#[test] +fn test_quote_newline() { + let result = quote("hello\nworld"); + assert!(result.contains("hello")); + assert!(result.contains("world")); +} diff --git a/rust/tests/virtual_commands.rs b/rust/tests/virtual_commands.rs new file mode 100644 index 0000000..0c9bbe8 --- /dev/null +++ b/rust/tests/virtual_commands.rs @@ -0,0 +1,199 @@ +//! Integration tests for virtual command system +//! +//! These tests mirror the JavaScript tests in js/tests/virtual.test.mjs + +use command_stream::commands::{ + are_virtual_commands_enabled, disable_virtual_commands, enable_virtual_commands, + CommandContext, VirtualCommandRegistry, +}; +use command_stream::{run, ProcessRunner, RunOptions}; + +// ============================================================================ +// Virtual Commands Enable/Disable Tests +// ============================================================================ + +#[test] +fn test_virtual_commands_default_enabled() { + assert!(are_virtual_commands_enabled()); +} + +#[test] +fn test_disable_virtual_commands() { + enable_virtual_commands(); // Ensure enabled first + disable_virtual_commands(); + assert!(!are_virtual_commands_enabled()); + enable_virtual_commands(); // Restore +} + +#[test] +fn test_enable_virtual_commands() { + disable_virtual_commands(); + enable_virtual_commands(); + assert!(are_virtual_commands_enabled()); +} + +// ============================================================================ +// Virtual Command Registry Tests +// ============================================================================ + +#[test] +fn test_registry_new() { + let registry = VirtualCommandRegistry::new(); + assert!(registry.list().is_empty()); +} + +#[test] +fn test_registry_contains() { + let registry = VirtualCommandRegistry::new(); + assert!(!registry.contains("nonexistent")); +} + +// ============================================================================ +// CommandContext Tests +// ============================================================================ + +#[test] +fn test_command_context_new() { + let ctx = CommandContext::new(vec!["arg1".to_string(), "arg2".to_string()]); + assert_eq!(ctx.args.len(), 2); + assert_eq!(ctx.args[0], "arg1"); + assert_eq!(ctx.args[1], "arg2"); +} + +#[test] +fn test_command_context_get_cwd() { + let ctx = CommandContext::new(vec![]); + let cwd = ctx.get_cwd(); + assert!(cwd.exists()); +} + +#[test] +fn test_command_context_with_cwd() { + let ctx = CommandContext { + args: vec![], + stdin: None, + cwd: Some(std::path::PathBuf::from("/tmp")), + env: None, + output_tx: None, + is_cancelled: None, + }; + assert_eq!(ctx.get_cwd(), std::path::PathBuf::from("/tmp")); +} + +#[test] +fn test_command_context_is_cancelled_default() { + let ctx = CommandContext::new(vec![]); + assert!(!ctx.is_cancelled()); +} + +#[test] +fn test_command_context_is_cancelled_with_fn() { + let ctx = CommandContext { + args: vec![], + stdin: None, + cwd: None, + env: None, + output_tx: None, + is_cancelled: Some(Box::new(|| true)), + }; + assert!(ctx.is_cancelled()); +} + +// ============================================================================ +// Built-in Command Execution Tests +// ============================================================================ + +#[tokio::test] +async fn test_execute_virtual_echo() { + enable_virtual_commands(); + let result = run("echo Hello World").await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("Hello World")); +} + +#[tokio::test] +async fn test_execute_virtual_pwd() { + enable_virtual_commands(); + let result = run("pwd").await.unwrap(); + assert!(result.is_success()); + assert!(!result.stdout.is_empty()); +} + +#[tokio::test] +async fn test_execute_virtual_true() { + enable_virtual_commands(); + let result = run("true").await.unwrap(); + assert!(result.is_success()); + assert_eq!(result.code, 0); +} + +#[tokio::test] +async fn test_execute_virtual_false() { + enable_virtual_commands(); + let result = run("false").await.unwrap(); + assert!(!result.is_success()); + assert_eq!(result.code, 1); +} + +#[tokio::test] +async fn test_execute_virtual_exit() { + enable_virtual_commands(); + + let result = run("exit 0").await.unwrap(); + assert_eq!(result.code, 0); + + let result = run("exit 42").await.unwrap(); + assert_eq!(result.code, 42); +} + +#[tokio::test] +async fn test_execute_virtual_which() { + enable_virtual_commands(); + let result = run("which echo").await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("shell builtin")); +} + +#[tokio::test] +async fn test_execute_virtual_sleep() { + enable_virtual_commands(); + let start = std::time::Instant::now(); + let result = run("sleep 0.1").await.unwrap(); + let elapsed = start.elapsed(); + + assert!(result.is_success()); + assert!(elapsed.as_millis() >= 90); + assert!(elapsed.as_millis() < 300); +} + +#[tokio::test] +async fn test_execute_echo_with_n_flag() { + enable_virtual_commands(); + let result = run("echo -n Hello").await.unwrap(); + assert!(result.is_success()); + assert_eq!(result.stdout.trim(), "Hello"); + // -n flag should not add newline + assert!(!result.stdout.ends_with("\n\n")); +} + +// ============================================================================ +// Process Runner with Virtual Commands Tests +// ============================================================================ + +#[tokio::test] +async fn test_process_runner_virtual_echo() { + enable_virtual_commands(); + let mut runner = ProcessRunner::new("echo test virtual", RunOptions::default()); + let result = runner.run().await.unwrap(); + assert!(result.is_success()); + assert!(result.stdout.contains("test virtual")); +} + +#[tokio::test] +async fn test_process_runner_virtual_pwd() { + enable_virtual_commands(); + let mut runner = ProcessRunner::new("pwd", RunOptions::default()); + let result = runner.run().await.unwrap(); + assert!(result.is_success()); + assert!(!result.stdout.is_empty()); +} From 0a9a8a67d33003b5a385c9fc7e8a0592a466399d Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 29 Dec 2025 14:26:20 +0100 Subject: [PATCH 5/9] Fix CI workflow paths for reorganized codebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update bun test path from tests/ to js/tests/ - Update Node.js compatibility test path from ./src/ to ./js/src/ ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 585e6f6..916f824 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -151,7 +151,7 @@ jobs: - name: Run tests (Bun) if: matrix.runtime == 'bun' - run: bun test tests/ + run: bun test js/tests/ env: COMMAND_STREAM_VERBOSE: true @@ -166,7 +166,7 @@ jobs: run: | node -e " try { - const { $ } = require('./src/\$.mjs'); + const { $ } = require('./js/src/\$.mjs'); console.log('โœ… Module loads successfully in Node.js ${{ matrix.node-version }}'); } catch (error) { console.error('โŒ Module failed to load:', error.message); From b7475f93032608edcbc00dc7a00e1081bfc09748 Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 29 Dec 2025 14:30:05 +0100 Subject: [PATCH 6/9] Fix gitignore and format docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add rust/target/ to .gitignore to exclude Rust build artifacts - Format docs/case-studies/issue-146/README.md ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .gitignore | 5 +++- docs/case-studies/issue-146/README.md | 43 +++++++++++++++++---------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 9c6fcd2..9042777 100644 --- a/.gitignore +++ b/.gitignore @@ -142,4 +142,7 @@ vite.config.ts.timestamp-* .persisted-configs # jscpd reports -reports/rust/target/ +reports/ + +# Rust build artifacts +rust/target/ diff --git a/docs/case-studies/issue-146/README.md b/docs/case-studies/issue-146/README.md index 9b6c381..3b32008 100644 --- a/docs/case-studies/issue-146/README.md +++ b/docs/case-studies/issue-146/README.md @@ -52,15 +52,17 @@ This document provides a comprehensive analysis of the process, challenges, and ### 1. JavaScript Async to Rust Async **JavaScript:** + ```javascript async function sleep({ args, abortSignal }) { const seconds = parseFloat(args[0] || 0); - await new Promise(resolve => setTimeout(resolve, seconds * 1000)); + await new Promise((resolve) => setTimeout(resolve, seconds * 1000)); return { stdout: '', code: 0 }; } ``` **Rust:** + ```rust pub async fn sleep(ctx: CommandContext) -> CommandResult { let seconds: f64 = ctx.args.first() @@ -75,16 +77,20 @@ pub async fn sleep(ctx: CommandContext) -> CommandResult { ### 2. JavaScript Object Literals to Rust Structs **JavaScript:** + ```javascript const result = { stdout: output, stderr: '', code: 0, - async text() { return this.stdout; } + async text() { + return this.stdout; + }, }; ``` **Rust:** + ```rust #[derive(Debug, Clone)] pub struct CommandResult { @@ -107,16 +113,17 @@ impl CommandResult { ### 3. JavaScript Closures to Rust Trait Objects **JavaScript:** + ```javascript function trace(category, messageOrFunc) { - const message = typeof messageOrFunc === 'function' - ? messageOrFunc() - : messageOrFunc; + const message = + typeof messageOrFunc === 'function' ? messageOrFunc() : messageOrFunc; console.error(`[TRACE] [${category}] ${message}`); } ``` **Rust:** + ```rust pub fn trace_lazy(category: &str, message_fn: F) where @@ -132,6 +139,7 @@ where ### 4. JavaScript Error Handling to Rust Result Types **JavaScript:** + ```javascript try { const content = fs.readFileSync(path, 'utf8'); @@ -145,6 +153,7 @@ try { ``` **Rust:** + ```rust match fs::read_to_string(&path) { Ok(content) => CommandResult::success(content), @@ -159,7 +168,7 @@ match fs::read_to_string(&path) { ### 1. Tagged Template Literals -JavaScript's tagged template literal syntax `$\`echo hello\`` has no direct Rust equivalent. We implemented the `$()` function as a regular function call instead. +JavaScript's tagged template literal syntax `$\`echo hello\``has no direct Rust equivalent. We implemented the`$()` function as a regular function call instead. ### 2. Event Emitter Pattern @@ -178,6 +187,7 @@ JavaScript's `for await (const chunk of stream)` was translated to Rust's async ### 1. Type Safety Benefits Rust's type system caught several edge cases that existed in the JavaScript code: + - Null/undefined handling became explicit with `Option` - Error handling became explicit with `Result` - String encoding issues were caught at compile time @@ -185,6 +195,7 @@ Rust's type system caught several edge cases that existed in the JavaScript code ### 2. Memory Management Rust's ownership model required explicit decisions about: + - When to clone vs borrow data - Lifetime of process handles - Cleanup of resources on cancellation @@ -192,6 +203,7 @@ Rust's ownership model required explicit decisions about: ### 3. Cross-Platform Considerations Both JavaScript and Rust require platform-specific code for: + - Shell detection (Windows vs Unix) - Signal handling (SIGINT, SIGTERM) - File permissions @@ -199,21 +211,22 @@ Both JavaScript and Rust require platform-specific code for: ### 4. Testing Strategy Unit tests were essential for: + - Verifying parity with JavaScript behavior - Catching edge cases early - Documenting expected behavior ## Architecture Comparison -| Component | JavaScript | Rust | -|-----------|------------|------| -| Async Runtime | Node.js/Bun event loop | Tokio | -| Process Spawn | child_process.spawn | tokio::process::Command | -| Channels | EventEmitter | mpsc channels | -| Error Handling | try/catch | Result | -| String Handling | UTF-16 strings | UTF-8 String | -| File I/O | fs module | std::fs | -| Signal Handling | process.on('SIGINT') | tokio::signal | +| Component | JavaScript | Rust | +| --------------- | ---------------------- | ----------------------- | +| Async Runtime | Node.js/Bun event loop | Tokio | +| Process Spawn | child_process.spawn | tokio::process::Command | +| Channels | EventEmitter | mpsc channels | +| Error Handling | try/catch | Result | +| String Handling | UTF-16 strings | UTF-8 String | +| File I/O | fs module | std::fs | +| Signal Handling | process.on('SIGINT') | tokio::signal | ## Future Improvements From e491e525aeeec8239507567ad7fe74879ef3a227 Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 29 Dec 2025 14:42:21 +0100 Subject: [PATCH 7/9] Move examples to js/examples and fix test paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move examples folder to js/examples for consistency with js/ structure - Update test files to reference js/examples and js/tests paths - Update internal references in examples to use new paths - Fix ls -1 tests/ to ls -1 js/tests/ in text-method.test.mjs - Update eslint config to include js/tests and js/examples patterns ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- eslint.config.js | 19 ++++++++++++++++--- .../examples}/01-basic-streaming.mjs | 0 .../examples}/02-async-iterator.mjs | 0 .../examples}/03-file-and-console.mjs | 0 .../examples}/04-claude-jq-pipe.mjs | 0 {examples => js/examples}/CI-DEBUG-README.md | 12 ++++++------ {examples => js/examples}/README-examples.mjs | 0 {examples => js/examples}/README.md | 10 +++++----- .../examples}/STREAMING_INTERFACES_SUMMARY.md | 0 .../examples}/add-test-timeouts.js | 0 .../examples}/ansi-default-preserved.mjs | 0 .../examples}/ansi-global-config.mjs | 0 .../examples}/ansi-reset-default.mjs | 0 .../examples}/ansi-strip-utils.mjs | 0 .../examples}/baseline-child-process.mjs | 0 .../examples}/baseline-claude-test.mjs | 0 .../examples}/baseline-working.mjs | 0 .../examples}/capture-mirror-comparison.mjs | 0 .../examples}/capture-mirror-default.mjs | 0 .../examples}/capture-mirror-performance.mjs | 0 .../examples}/capture-mirror-show-only.mjs | 0 .../capture-mirror-silent-processing.mjs | 0 .../ci-debug-baseline-vs-library.mjs | 0 .../examples}/ci-debug-es-module-loading.mjs | 0 .../examples}/ci-debug-signal-handling.mjs | 0 .../examples}/ci-debug-stdout-buffering.mjs | 0 .../examples}/ci-debug-test-timeouts.mjs | 0 .../examples}/claude-exact-file-output.mjs | 0 {examples => js/examples}/claude-exact-jq.mjs | 0 .../examples}/claude-exact-streaming.mjs | 0 .../examples}/claude-jq-pipeline.mjs | 0 .../examples}/claude-json-stream.mjs | 0 .../examples}/claude-streaming-basic.mjs | 0 .../examples}/claude-streaming-demo.mjs | 0 .../examples}/claude-streaming-final.mjs | 0 .../examples}/cleanup-verification-test.mjs | 0 .../examples}/colors-buffer-processing.mjs | 0 .../examples}/colors-default-preserved.mjs | 0 .../examples}/colors-per-command-config.mjs | 0 .../examples}/colors-strip-ansi.mjs | 0 .../examples}/commandstream-jq.mjs | 0 .../examples}/commandstream-working.mjs | 0 .../examples}/comprehensive-streams-demo.mjs | 0 .../examples}/ctrl-c-concurrent-processes.mjs | 0 .../examples}/ctrl-c-long-running-command.mjs | 0 .../examples}/ctrl-c-real-system-command.mjs | 0 .../examples}/ctrl-c-sleep-command.mjs | 0 .../examples}/ctrl-c-stdin-forwarding.mjs | 0 .../examples}/ctrl-c-virtual-command.mjs | 0 .../examples}/debug-already-started.mjs | 0 .../examples}/debug-ansi-processing.mjs | 0 .../examples}/debug-basic-streaming.mjs | 0 .../examples}/debug-buildshellcommand.mjs | 0 .../examples}/debug-child-process.mjs | 0 .../examples}/debug-child-state.mjs | 0 {examples => js/examples}/debug-chunking.mjs | 0 .../examples}/debug-command-parsing.mjs | 0 .../debug-complete-consolidation.mjs | 0 {examples => js/examples}/debug-echo-args.mjs | 0 .../examples}/debug-emit-timing.mjs | 0 {examples => js/examples}/debug-end-event.mjs | 0 {examples => js/examples}/debug-errexit.mjs | 0 .../examples}/debug-event-emission.mjs | 0 .../examples}/debug-event-timing.mjs | 0 .../examples}/debug-event-vs-result.mjs | 0 .../examples}/debug-exact-command.mjs | 0 .../examples}/debug-exact-test-scenario.mjs | 0 .../examples}/debug-execution-path.mjs | 0 .../examples}/debug-exit-command.mjs | 0 .../examples}/debug-exit-virtual.mjs | 0 .../examples}/debug-finish-consolidation.mjs | 0 .../examples}/debug-force-cleanup.mjs | 0 .../examples}/debug-getter-basic.mjs | 0 .../examples}/debug-getter-direct.mjs | 0 .../examples}/debug-getter-internals.mjs | 0 .../examples}/debug-handler-detection.mjs | 0 .../examples}/debug-idempotent-finish.mjs | 0 .../examples}/debug-idempotent-kill.mjs | 0 .../debug-interpolation-individual.mjs | 0 .../examples}/debug-interpolation-issue.mjs | 0 .../examples}/debug-jq-streaming.mjs | 0 .../examples}/debug-jq-tty-colors.mjs | 0 .../examples}/debug-kill-cleanup.mjs | 0 .../examples}/debug-kill-method.mjs | 0 .../examples}/debug-listener-interference.mjs | 0 .../examples}/debug-listener-lifecycle.mjs | 0 .../examples}/debug-listener-timing.mjs | 0 .../examples}/debug-listeners-property.mjs | 0 .../examples}/debug-map-methods.mjs | 0 .../examples}/debug-not-awaited-cleanup.mjs | 0 .../examples}/debug-off-method.mjs | 0 .../examples}/debug-option-merging.mjs | 0 {examples => js/examples}/debug-options.mjs | 0 {examples => js/examples}/debug-output.mjs | 0 .../examples}/debug-pattern-matching.mjs | 0 .../examples}/debug-pipeline-cat.mjs | 0 .../examples}/debug-pipeline-cleanup.mjs | 0 .../debug-pipeline-error-detailed.mjs | 0 .../examples}/debug-pipeline-error.mjs | 0 .../examples}/debug-pipeline-issue.mjs | 0 .../examples}/debug-pipeline-method.mjs | 0 .../examples}/debug-pipeline-stream.mjs | 0 {examples => js/examples}/debug-pipeline.mjs | 0 .../examples}/debug-process-exit-trace.mjs | 0 .../examples}/debug-process-path.mjs | 0 .../examples}/debug-property-check.mjs | 0 .../examples}/debug-resource-cleanup.mjs | 0 .../examples}/debug-shell-args.mjs | 0 .../examples}/debug-sigint-child-handler.mjs | 0 .../examples}/debug-sigint-forwarding.mjs | 0 .../debug-sigint-handler-install.mjs | 0 .../examples}/debug-sigint-handler-order.mjs | 0 .../examples}/debug-sigint-listeners.mjs | 0 .../examples}/debug-sigint-start-pattern.mjs | 0 .../examples}/debug-sigint-timer.mjs | 0 .../examples}/debug-simple-command.mjs | 0 .../examples}/debug-simple-getter.mjs | 0 {examples => js/examples}/debug-simple.mjs | 0 .../examples}/debug-simplified-finished.mjs | 0 .../examples}/debug-stack-overflow.mjs | 0 .../examples}/debug-stdin-simple.mjs | 0 {examples => js/examples}/debug-stdin.mjs | 0 .../debug-stream-emitter-isolated.mjs | 0 .../examples}/debug-stream-emitter.mjs | 0 .../examples}/debug-stream-events.mjs | 0 .../examples}/debug-stream-generator.mjs | 0 .../examples}/debug-stream-getter-issue.mjs | 0 .../examples}/debug-stream-getter.mjs | 0 .../examples}/debug-stream-internals.mjs | 0 .../examples}/debug-stream-method.mjs | 0 .../examples}/debug-stream-object.mjs | 0 .../examples}/debug-stream-properties.mjs | 0 .../examples}/debug-stream-timing.mjs | 0 {examples => js/examples}/debug-streaming.mjs | 0 .../examples}/debug-test-isolation.mjs | 0 .../examples}/debug-test-state.mjs | 0 .../examples}/debug-user-sigint.mjs | 0 .../examples}/debug-virtual-disable.mjs | 0 .../examples}/debug-virtual-vs-real.mjs | 0 .../examples}/debug-with-trace.mjs | 0 .../examples}/debug_parent_stream.mjs | 0 .../examples}/emulate-claude-stream.mjs | 0 .../examples}/emulated-streaming-direct.mjs | 2 +- .../examples}/emulated-streaming-jq-pipe.mjs | 2 +- .../examples}/emulated-streaming-sh-pipe.mjs | 2 +- .../examples}/events-build-process.mjs | 0 .../examples}/events-concurrent-streams.mjs | 0 .../examples}/events-error-handling.mjs | 0 .../examples}/events-file-monitoring.mjs | 0 .../events-interactive-simulation.mjs | 0 .../examples}/events-log-processing.mjs | 0 .../examples}/events-network-monitoring.mjs | 0 .../examples}/events-ping-basic.mjs | 0 .../examples}/events-progress-tracking.mjs | 0 .../examples}/events-stdin-input.mjs | 0 {examples => js/examples}/example-ansi-ls.mjs | 0 {examples => js/examples}/example-top.mjs | 0 .../examples}/final-ping-stdin-proof.mjs | 0 .../examples}/final-test-shell-operators.mjs | 0 .../examples}/final-working-examples.mjs | 0 {examples => js/examples}/gh-auth-test.mjs | 0 .../examples}/gh-delete-hang-test.mjs | 0 .../examples}/gh-gist-creation-test.mjs | 0 .../examples}/gh-gist-minimal-test.mjs | 0 .../examples}/gh-hang-exact-original.mjs | 0 .../examples}/gh-hang-reproduction.mjs | 0 .../examples}/gh-hang-test-with-redirect.mjs | 0 .../gh-hang-test-without-redirect.mjs | 0 .../examples}/gh-minimal-hang-check.mjs | 0 .../examples}/gh-operations-with-cd.mjs | 0 {examples => js/examples}/gh-output-test.mjs | 0 .../examples}/gh-reproduce-hang.mjs | 0 .../examples}/git-operations-with-cd.mjs | 0 .../examples}/interactive-math-calc.mjs | 0 .../examples}/interactive-top-fixed.mjs | 0 .../examples}/interactive-top-improved.mjs | 0 .../examples}/interactive-top-pty-logging.mjs | 0 .../examples}/interactive-top-pty.mjs | 0 .../interactive-top-with-logging.mjs | 0 {examples => js/examples}/interactive-top.mjs | 0 {examples => js/examples}/jq-color-demo.mjs | 0 .../examples}/jq-colors-streaming.mjs | 0 .../examples}/manual-ctrl-c-test.mjs | 0 .../examples}/methods-multiple-options.mjs | 0 .../examples}/methods-run-basic.mjs | 0 .../examples}/methods-start-basic.mjs | 0 .../examples}/node-compat-data-events.mjs | 2 +- .../examples}/node-compat-readable-event.mjs | 2 +- .../examples}/node-compat-small-buffer.mjs | 2 +- .../examples}/options-capture-false.mjs | 0 .../examples}/options-combined-settings.mjs | 0 .../examples}/options-custom-input.mjs | 0 .../examples}/options-default-behavior.mjs | 0 .../examples}/options-maximum-performance.mjs | 0 .../examples}/options-mirror-false.mjs | 0 .../examples}/options-performance-mode.mjs | 0 .../options-performance-optimization.mjs | 0 .../examples}/options-run-alias-demo.mjs | 0 .../examples}/options-run-alias.mjs | 0 .../examples}/options-silent-execution.mjs | 0 .../examples}/options-streaming-capture.mjs | 0 .../examples}/options-streaming-multiple.mjs | 0 .../examples}/options-streaming-silent.mjs | 0 .../examples}/options-streaming-stdin.mjs | 0 .../examples}/ping-streaming-filtered.mjs | 0 .../ping-streaming-interruptible.mjs | 0 .../examples}/ping-streaming-silent.mjs | 0 .../examples}/ping-streaming-simple.mjs | 0 .../examples}/ping-streaming-statistics.mjs | 0 .../examples}/ping-streaming-timestamps.mjs | 0 {examples => js/examples}/ping-streaming.mjs | 0 .../examples}/prove-ping-stdin-limitation.mjs | 0 {examples => js/examples}/readme-example.mjs | 0 .../examples}/realtime-json-stream.mjs | 0 .../examples}/reliable-stdin-commands.mjs | 0 .../examples}/reproduce-issue-135-v2.mjs | 0 .../examples}/reproduce-issue-135.mjs | 0 .../examples}/shell-cd-behavior.mjs | 0 .../examples}/sigint-forwarding-test.mjs | 0 .../examples}/sigint-handler-test.mjs | 0 .../examples}/simple-async-test.mjs | 0 .../examples}/simple-claude-test.mjs | 0 .../examples}/simple-event-test.mjs | 0 .../examples}/simple-jq-streaming.mjs | 0 .../examples}/simple-stream-demo.mjs | 0 .../examples}/simple-test-sleep.js | 0 .../examples}/simple-working-stdin.mjs | 0 .../examples}/streaming-behavior-test.mjs | 0 .../examples}/streaming-direct-command.mjs | 2 +- .../examples}/streaming-filtered-output.mjs | 0 .../examples}/streaming-grep-pipeline.mjs | 2 +- .../examples}/streaming-interactive-stdin.mjs | 0 .../examples}/streaming-jq-pipeline.mjs | 2 +- .../streaming-multistage-pipeline.mjs | 2 +- .../streaming-pipes-event-pattern.mjs | 0 .../examples}/streaming-pipes-multistage.mjs | 0 .../examples}/streaming-pipes-realtime-jq.mjs | 0 .../examples}/streaming-progress-tracking.mjs | 0 .../examples}/streaming-reusable-configs.mjs | 0 .../examples}/streaming-silent-capture.mjs | 0 .../examples}/streaming-test-simple.mjs | 0 .../examples}/streaming-virtual-pipeline.mjs | 0 .../examples}/syntax-basic-comparison.mjs | 0 .../examples}/syntax-basic-options.mjs | 0 .../examples}/syntax-combined-options.mjs | 0 .../examples}/syntax-command-chaining.mjs | 0 .../examples}/syntax-custom-directory.mjs | 0 .../examples}/syntax-custom-environment.mjs | 0 .../examples}/syntax-custom-stdin.mjs | 0 .../examples}/syntax-mixed-regular.mjs | 0 .../examples}/syntax-mixed-usage.mjs | 0 .../examples}/syntax-multiple-listeners.mjs | 0 .../examples}/syntax-piping-comparison.mjs | 0 .../examples}/syntax-reusable-config.mjs | 0 .../examples}/syntax-reusable-configs.mjs | 0 .../examples}/syntax-silent-operations.mjs | 0 .../examples}/syntax-stdin-option.mjs | 0 .../examples}/temp-sigint-test.mjs | 0 .../examples}/test-actual-buildshell.mjs | 0 .../examples}/test-async-streams-working.mjs | 0 .../examples}/test-async-streams.mjs | 0 {examples => js/examples}/test-auth-parse.mjs | 0 .../examples}/test-auto-quoting.mjs | 0 .../examples}/test-auto-start-fix.mjs | 0 .../examples}/test-baseline-sigint.mjs | 0 .../examples}/test-buffer-behavior.mjs | 0 .../examples}/test-buffers-simple.mjs | 0 .../examples}/test-bun-specific-issue.mjs | 0 .../examples}/test-bun-streaming.mjs | 4 ++-- {examples => js/examples}/test-cat-direct.mjs | 11 +++++++---- {examples => js/examples}/test-cat-pipe.mjs | 2 +- .../examples}/test-cd-behavior.mjs | 0 .../examples}/test-child-process-timing.mjs | 0 .../examples}/test-child-sigint-handler.mjs | 0 .../examples}/test-cleanup-simple.mjs | 0 .../examples}/test-comprehensive-tracing.mjs | 14 +++++++------- .../examples}/test-correct-space-handling.mjs | 0 .../examples}/test-ctrl-c-debug.mjs | 0 .../examples}/test-ctrl-c-inherit.mjs | 0 .../examples}/test-ctrl-c-sleep.mjs | 0 {examples => js/examples}/test-ctrl-c.mjs | 0 .../examples}/test-debug-new-options.mjs | 0 {examples => js/examples}/test-debug-pty.mjs | 4 ++-- {examples => js/examples}/test-debug-tee.mjs | 2 +- {examples => js/examples}/test-debug.mjs | 0 {examples => js/examples}/test-direct-jq.mjs | 2 +- .../examples}/test-direct-pipe-reading.mjs | 8 ++++---- {examples => js/examples}/test-direct-pipe.sh | 0 .../test-double-quoting-prevention.mjs | 0 .../examples}/test-edge-cases-quoting.mjs | 0 {examples => js/examples}/test-events.mjs | 2 +- .../examples}/test-explicit-stdio.mjs | 0 .../examples}/test-final-streaming.mjs | 6 +++--- {examples => js/examples}/test-fix.mjs | 0 .../examples}/test-incremental-streaming.mjs | 0 .../examples}/test-individual-spawn.mjs | 11 +++++++---- .../test-inherit-stdout-not-stdin.mjs | 0 .../examples}/test-injection-protection.mjs | 0 .../examples}/test-interactive-streaming.mjs | 0 .../examples}/test-interactive-top.md | 2 +- .../examples}/test-interactive.mjs | 0 .../examples}/test-interpolation.mjs | 0 {examples => js/examples}/test-interrupt.mjs | 0 .../test-issue-135-comprehensive.mjs | 0 .../examples}/test-issue12-detailed.mjs | 0 .../examples}/test-issue12-exact.mjs | 0 {examples => js/examples}/test-jq-color.mjs | 0 {examples => js/examples}/test-jq-colors.mjs | 0 {examples => js/examples}/test-jq-compact.mjs | 2 +- {examples => js/examples}/test-jq-native.sh | 0 .../examples}/test-jq-pipeline-behavior.mjs | 0 .../examples}/test-jq-realtime.mjs | 2 +- .../examples}/test-manual-start.mjs | 0 .../examples}/test-mixed-quoting.mjs | 0 .../examples}/test-multi-stream.mjs | 11 +++++++---- .../examples}/test-multistage-debug.mjs | 2 +- .../test-native-spawn-vs-command-stream.mjs | 0 .../examples}/test-no-parse-pipeline.mjs | 2 +- .../examples}/test-non-virtual.mjs | 0 {examples => js/examples}/test-operators.mjs | 0 .../examples}/test-parent-continues.mjs | 0 .../examples}/test-path-interpolation.mjs | 0 .../examples}/test-ping-kill-and-stdin.mjs | 0 {examples => js/examples}/test-ping.mjs | 0 {examples => js/examples}/test-pty-spawn.mjs | 4 ++-- {examples => js/examples}/test-pty.mjs | 2 +- .../examples}/test-quote-behavior-summary.mjs | 0 .../examples}/test-quote-edge-cases.mjs | 0 .../examples}/test-quote-parsing.mjs | 0 .../examples}/test-raw-function.mjs | 0 .../examples}/test-raw-streaming.mjs | 0 .../examples}/test-readme-examples.mjs | 0 {examples => js/examples}/test-real-cat.mjs | 0 .../examples}/test-real-commands.mjs | 2 +- {examples => js/examples}/test-real-shell.mjs | 0 .../examples}/test-real-stdin-commands.mjs | 0 .../examples}/test-runner-batched.mjs | 0 .../examples}/test-runner-simple.mjs | 0 {examples => js/examples}/test-runner.mjs | 0 .../examples}/test-scope-parse.mjs | 0 .../examples}/test-sh-pipeline.mjs | 2 +- .../examples}/test-shell-detection.mjs | 0 .../examples}/test-shell-parser.mjs | 0 .../examples}/test-sigint-behavior.mjs | 0 .../examples}/test-sigint-handling.sh | 0 .../examples}/test-simple-pipe.mjs | 0 .../examples}/test-simple-streaming.mjs | 0 {examples => js/examples}/test-sleep-stdin.js | 0 {examples => js/examples}/test-sleep.mjs | 0 .../examples}/test-smart-quoting.mjs | 0 .../examples}/test-spaces-in-path.mjs | 0 .../examples}/test-special-chars-quoting.mjs | 0 .../examples}/test-stdin-after-start.mjs | 0 .../examples}/test-stdin-simple.mjs | 0 .../examples}/test-stdin-timing.mjs | 0 .../examples}/test-stdio-combinations.mjs | 0 .../examples}/test-stream-access.mjs | 0 .../examples}/test-stream-cleanup.mjs | 0 .../examples}/test-stream-readers.mjs | 6 +++--- .../examples}/test-streaming-final.mjs | 4 ++-- .../examples}/test-streaming-interfaces.mjs | 2 +- .../examples}/test-streaming-timing.mjs | 0 {examples => js/examples}/test-streaming.mjs | 0 .../test-streams-stdin-comprehensive.mjs | 0 .../examples}/test-streams-stdin-ctrl-c.mjs | 0 .../examples}/test-template-literal.mjs | 0 .../test-template-vs-interpolation.mjs | 0 {examples => js/examples}/test-timing.mjs | 0 .../test-top-inherit-stdout-stdin-control.mjs | 0 .../examples}/test-top-quit-stdin.mjs | 0 .../examples}/test-trace-option.mjs | 0 .../examples}/test-user-double-quotes.mjs | 0 .../examples}/test-user-single-quotes.mjs | 0 {examples => js/examples}/test-verbose.mjs | 0 {examples => js/examples}/test-verbose2.mjs | 0 .../examples}/test-virtual-streaming.mjs | 0 .../examples}/test-waiting-command.mjs | 0 .../examples}/test-waiting-commands.mjs | 0 {examples => js/examples}/test-watch-mode.mjs | 0 .../examples}/test-yes-cancellation.mjs | 0 .../examples}/test-yes-detailed.mjs | 0 {examples => js/examples}/test-yes-trace.mjs | 0 .../examples}/trace-abort-controller.mjs | 2 +- .../examples}/trace-error-handling.mjs | 2 +- .../examples}/trace-pipeline-command.mjs | 2 +- .../examples}/trace-signal-handling.mjs | 2 +- .../examples}/trace-simple-command.mjs | 2 +- .../examples}/trace-stderr-output.mjs | 2 +- .../examples}/verify-fix-both-runtimes.mjs | 0 .../examples}/verify-issue12-fixed.mjs | 0 .../which-command-common-commands.mjs | 0 .../examples}/which-command-gh-test.mjs | 0 .../examples}/which-command-nonexistent.mjs | 0 .../which-command-system-comparison.mjs | 0 {examples => js/examples}/working-example.mjs | 0 .../examples}/working-stdin-examples.mjs | 0 .../examples}/working-streaming-demo.mjs | 0 js/tests/ctrl-c-baseline.test.mjs | 2 +- js/tests/ctrl-c-library.test.mjs | 2 +- js/tests/ctrl-c-signal.test.mjs | 2 +- js/tests/examples.test.mjs | 10 +++++----- js/tests/text-method.test.mjs | 2 +- temp-unicode-test.txt | 0 403 files changed, 111 insertions(+), 89 deletions(-) rename {examples => js/examples}/01-basic-streaming.mjs (100%) rename {examples => js/examples}/02-async-iterator.mjs (100%) rename {examples => js/examples}/03-file-and-console.mjs (100%) rename {examples => js/examples}/04-claude-jq-pipe.mjs (100%) rename {examples => js/examples}/CI-DEBUG-README.md (92%) rename {examples => js/examples}/README-examples.mjs (100%) rename {examples => js/examples}/README.md (98%) rename {examples => js/examples}/STREAMING_INTERFACES_SUMMARY.md (100%) rename {examples => js/examples}/add-test-timeouts.js (100%) rename {examples => js/examples}/ansi-default-preserved.mjs (100%) rename {examples => js/examples}/ansi-global-config.mjs (100%) rename {examples => js/examples}/ansi-reset-default.mjs (100%) rename {examples => js/examples}/ansi-strip-utils.mjs (100%) rename {examples => js/examples}/baseline-child-process.mjs (100%) rename {examples => js/examples}/baseline-claude-test.mjs (100%) rename {examples => js/examples}/baseline-working.mjs (100%) rename {examples => js/examples}/capture-mirror-comparison.mjs (100%) rename {examples => js/examples}/capture-mirror-default.mjs (100%) rename {examples => js/examples}/capture-mirror-performance.mjs (100%) rename {examples => js/examples}/capture-mirror-show-only.mjs (100%) rename {examples => js/examples}/capture-mirror-silent-processing.mjs (100%) rename {examples => js/examples}/ci-debug-baseline-vs-library.mjs (100%) rename {examples => js/examples}/ci-debug-es-module-loading.mjs (100%) rename {examples => js/examples}/ci-debug-signal-handling.mjs (100%) rename {examples => js/examples}/ci-debug-stdout-buffering.mjs (100%) rename {examples => js/examples}/ci-debug-test-timeouts.mjs (100%) rename {examples => js/examples}/claude-exact-file-output.mjs (100%) rename {examples => js/examples}/claude-exact-jq.mjs (100%) rename {examples => js/examples}/claude-exact-streaming.mjs (100%) rename {examples => js/examples}/claude-jq-pipeline.mjs (100%) rename {examples => js/examples}/claude-json-stream.mjs (100%) rename {examples => js/examples}/claude-streaming-basic.mjs (100%) rename {examples => js/examples}/claude-streaming-demo.mjs (100%) rename {examples => js/examples}/claude-streaming-final.mjs (100%) rename {examples => js/examples}/cleanup-verification-test.mjs (100%) rename {examples => js/examples}/colors-buffer-processing.mjs (100%) rename {examples => js/examples}/colors-default-preserved.mjs (100%) rename {examples => js/examples}/colors-per-command-config.mjs (100%) rename {examples => js/examples}/colors-strip-ansi.mjs (100%) rename {examples => js/examples}/commandstream-jq.mjs (100%) rename {examples => js/examples}/commandstream-working.mjs (100%) rename {examples => js/examples}/comprehensive-streams-demo.mjs (100%) rename {examples => js/examples}/ctrl-c-concurrent-processes.mjs (100%) rename {examples => js/examples}/ctrl-c-long-running-command.mjs (100%) rename {examples => js/examples}/ctrl-c-real-system-command.mjs (100%) rename {examples => js/examples}/ctrl-c-sleep-command.mjs (100%) rename {examples => js/examples}/ctrl-c-stdin-forwarding.mjs (100%) rename {examples => js/examples}/ctrl-c-virtual-command.mjs (100%) rename {examples => js/examples}/debug-already-started.mjs (100%) rename {examples => js/examples}/debug-ansi-processing.mjs (100%) rename {examples => js/examples}/debug-basic-streaming.mjs (100%) rename {examples => js/examples}/debug-buildshellcommand.mjs (100%) rename {examples => js/examples}/debug-child-process.mjs (100%) rename {examples => js/examples}/debug-child-state.mjs (100%) rename {examples => js/examples}/debug-chunking.mjs (100%) rename {examples => js/examples}/debug-command-parsing.mjs (100%) rename {examples => js/examples}/debug-complete-consolidation.mjs (100%) rename {examples => js/examples}/debug-echo-args.mjs (100%) rename {examples => js/examples}/debug-emit-timing.mjs (100%) rename {examples => js/examples}/debug-end-event.mjs (100%) rename {examples => js/examples}/debug-errexit.mjs (100%) rename {examples => js/examples}/debug-event-emission.mjs (100%) rename {examples => js/examples}/debug-event-timing.mjs (100%) rename {examples => js/examples}/debug-event-vs-result.mjs (100%) rename {examples => js/examples}/debug-exact-command.mjs (100%) rename {examples => js/examples}/debug-exact-test-scenario.mjs (100%) rename {examples => js/examples}/debug-execution-path.mjs (100%) rename {examples => js/examples}/debug-exit-command.mjs (100%) rename {examples => js/examples}/debug-exit-virtual.mjs (100%) rename {examples => js/examples}/debug-finish-consolidation.mjs (100%) rename {examples => js/examples}/debug-force-cleanup.mjs (100%) rename {examples => js/examples}/debug-getter-basic.mjs (100%) rename {examples => js/examples}/debug-getter-direct.mjs (100%) rename {examples => js/examples}/debug-getter-internals.mjs (100%) rename {examples => js/examples}/debug-handler-detection.mjs (100%) rename {examples => js/examples}/debug-idempotent-finish.mjs (100%) rename {examples => js/examples}/debug-idempotent-kill.mjs (100%) rename {examples => js/examples}/debug-interpolation-individual.mjs (100%) rename {examples => js/examples}/debug-interpolation-issue.mjs (100%) rename {examples => js/examples}/debug-jq-streaming.mjs (100%) rename {examples => js/examples}/debug-jq-tty-colors.mjs (100%) rename {examples => js/examples}/debug-kill-cleanup.mjs (100%) rename {examples => js/examples}/debug-kill-method.mjs (100%) rename {examples => js/examples}/debug-listener-interference.mjs (100%) rename {examples => js/examples}/debug-listener-lifecycle.mjs (100%) rename {examples => js/examples}/debug-listener-timing.mjs (100%) rename {examples => js/examples}/debug-listeners-property.mjs (100%) rename {examples => js/examples}/debug-map-methods.mjs (100%) rename {examples => js/examples}/debug-not-awaited-cleanup.mjs (100%) rename {examples => js/examples}/debug-off-method.mjs (100%) rename {examples => js/examples}/debug-option-merging.mjs (100%) rename {examples => js/examples}/debug-options.mjs (100%) rename {examples => js/examples}/debug-output.mjs (100%) rename {examples => js/examples}/debug-pattern-matching.mjs (100%) rename {examples => js/examples}/debug-pipeline-cat.mjs (100%) rename {examples => js/examples}/debug-pipeline-cleanup.mjs (100%) rename {examples => js/examples}/debug-pipeline-error-detailed.mjs (100%) rename {examples => js/examples}/debug-pipeline-error.mjs (100%) rename {examples => js/examples}/debug-pipeline-issue.mjs (100%) rename {examples => js/examples}/debug-pipeline-method.mjs (100%) rename {examples => js/examples}/debug-pipeline-stream.mjs (100%) rename {examples => js/examples}/debug-pipeline.mjs (100%) rename {examples => js/examples}/debug-process-exit-trace.mjs (100%) rename {examples => js/examples}/debug-process-path.mjs (100%) rename {examples => js/examples}/debug-property-check.mjs (100%) rename {examples => js/examples}/debug-resource-cleanup.mjs (100%) rename {examples => js/examples}/debug-shell-args.mjs (100%) rename {examples => js/examples}/debug-sigint-child-handler.mjs (100%) rename {examples => js/examples}/debug-sigint-forwarding.mjs (100%) rename {examples => js/examples}/debug-sigint-handler-install.mjs (100%) rename {examples => js/examples}/debug-sigint-handler-order.mjs (100%) rename {examples => js/examples}/debug-sigint-listeners.mjs (100%) rename {examples => js/examples}/debug-sigint-start-pattern.mjs (100%) rename {examples => js/examples}/debug-sigint-timer.mjs (100%) rename {examples => js/examples}/debug-simple-command.mjs (100%) rename {examples => js/examples}/debug-simple-getter.mjs (100%) rename {examples => js/examples}/debug-simple.mjs (100%) rename {examples => js/examples}/debug-simplified-finished.mjs (100%) rename {examples => js/examples}/debug-stack-overflow.mjs (100%) rename {examples => js/examples}/debug-stdin-simple.mjs (100%) rename {examples => js/examples}/debug-stdin.mjs (100%) rename {examples => js/examples}/debug-stream-emitter-isolated.mjs (100%) rename {examples => js/examples}/debug-stream-emitter.mjs (100%) rename {examples => js/examples}/debug-stream-events.mjs (100%) rename {examples => js/examples}/debug-stream-generator.mjs (100%) rename {examples => js/examples}/debug-stream-getter-issue.mjs (100%) rename {examples => js/examples}/debug-stream-getter.mjs (100%) rename {examples => js/examples}/debug-stream-internals.mjs (100%) rename {examples => js/examples}/debug-stream-method.mjs (100%) rename {examples => js/examples}/debug-stream-object.mjs (100%) rename {examples => js/examples}/debug-stream-properties.mjs (100%) rename {examples => js/examples}/debug-stream-timing.mjs (100%) rename {examples => js/examples}/debug-streaming.mjs (100%) rename {examples => js/examples}/debug-test-isolation.mjs (100%) rename {examples => js/examples}/debug-test-state.mjs (100%) rename {examples => js/examples}/debug-user-sigint.mjs (100%) rename {examples => js/examples}/debug-virtual-disable.mjs (100%) rename {examples => js/examples}/debug-virtual-vs-real.mjs (100%) rename {examples => js/examples}/debug-with-trace.mjs (100%) rename {examples => js/examples}/debug_parent_stream.mjs (100%) rename {examples => js/examples}/emulate-claude-stream.mjs (100%) rename {examples => js/examples}/emulated-streaming-direct.mjs (83%) rename {examples => js/examples}/emulated-streaming-jq-pipe.mjs (81%) rename {examples => js/examples}/emulated-streaming-sh-pipe.mjs (85%) rename {examples => js/examples}/events-build-process.mjs (100%) rename {examples => js/examples}/events-concurrent-streams.mjs (100%) rename {examples => js/examples}/events-error-handling.mjs (100%) rename {examples => js/examples}/events-file-monitoring.mjs (100%) rename {examples => js/examples}/events-interactive-simulation.mjs (100%) rename {examples => js/examples}/events-log-processing.mjs (100%) rename {examples => js/examples}/events-network-monitoring.mjs (100%) rename {examples => js/examples}/events-ping-basic.mjs (100%) rename {examples => js/examples}/events-progress-tracking.mjs (100%) rename {examples => js/examples}/events-stdin-input.mjs (100%) rename {examples => js/examples}/example-ansi-ls.mjs (100%) rename {examples => js/examples}/example-top.mjs (100%) rename {examples => js/examples}/final-ping-stdin-proof.mjs (100%) rename {examples => js/examples}/final-test-shell-operators.mjs (100%) rename {examples => js/examples}/final-working-examples.mjs (100%) rename {examples => js/examples}/gh-auth-test.mjs (100%) rename {examples => js/examples}/gh-delete-hang-test.mjs (100%) rename {examples => js/examples}/gh-gist-creation-test.mjs (100%) rename {examples => js/examples}/gh-gist-minimal-test.mjs (100%) rename {examples => js/examples}/gh-hang-exact-original.mjs (100%) rename {examples => js/examples}/gh-hang-reproduction.mjs (100%) rename {examples => js/examples}/gh-hang-test-with-redirect.mjs (100%) rename {examples => js/examples}/gh-hang-test-without-redirect.mjs (100%) rename {examples => js/examples}/gh-minimal-hang-check.mjs (100%) rename {examples => js/examples}/gh-operations-with-cd.mjs (100%) rename {examples => js/examples}/gh-output-test.mjs (100%) rename {examples => js/examples}/gh-reproduce-hang.mjs (100%) rename {examples => js/examples}/git-operations-with-cd.mjs (100%) rename {examples => js/examples}/interactive-math-calc.mjs (100%) rename {examples => js/examples}/interactive-top-fixed.mjs (100%) rename {examples => js/examples}/interactive-top-improved.mjs (100%) rename {examples => js/examples}/interactive-top-pty-logging.mjs (100%) rename {examples => js/examples}/interactive-top-pty.mjs (100%) rename {examples => js/examples}/interactive-top-with-logging.mjs (100%) rename {examples => js/examples}/interactive-top.mjs (100%) rename {examples => js/examples}/jq-color-demo.mjs (100%) rename {examples => js/examples}/jq-colors-streaming.mjs (100%) rename {examples => js/examples}/manual-ctrl-c-test.mjs (100%) rename {examples => js/examples}/methods-multiple-options.mjs (100%) rename {examples => js/examples}/methods-run-basic.mjs (100%) rename {examples => js/examples}/methods-start-basic.mjs (100%) rename {examples => js/examples}/node-compat-data-events.mjs (90%) rename {examples => js/examples}/node-compat-readable-event.mjs (88%) rename {examples => js/examples}/node-compat-small-buffer.mjs (90%) rename {examples => js/examples}/options-capture-false.mjs (100%) rename {examples => js/examples}/options-combined-settings.mjs (100%) rename {examples => js/examples}/options-custom-input.mjs (100%) rename {examples => js/examples}/options-default-behavior.mjs (100%) rename {examples => js/examples}/options-maximum-performance.mjs (100%) rename {examples => js/examples}/options-mirror-false.mjs (100%) rename {examples => js/examples}/options-performance-mode.mjs (100%) rename {examples => js/examples}/options-performance-optimization.mjs (100%) rename {examples => js/examples}/options-run-alias-demo.mjs (100%) rename {examples => js/examples}/options-run-alias.mjs (100%) rename {examples => js/examples}/options-silent-execution.mjs (100%) rename {examples => js/examples}/options-streaming-capture.mjs (100%) rename {examples => js/examples}/options-streaming-multiple.mjs (100%) rename {examples => js/examples}/options-streaming-silent.mjs (100%) rename {examples => js/examples}/options-streaming-stdin.mjs (100%) rename {examples => js/examples}/ping-streaming-filtered.mjs (100%) rename {examples => js/examples}/ping-streaming-interruptible.mjs (100%) rename {examples => js/examples}/ping-streaming-silent.mjs (100%) rename {examples => js/examples}/ping-streaming-simple.mjs (100%) rename {examples => js/examples}/ping-streaming-statistics.mjs (100%) rename {examples => js/examples}/ping-streaming-timestamps.mjs (100%) rename {examples => js/examples}/ping-streaming.mjs (100%) rename {examples => js/examples}/prove-ping-stdin-limitation.mjs (100%) rename {examples => js/examples}/readme-example.mjs (100%) rename {examples => js/examples}/realtime-json-stream.mjs (100%) rename {examples => js/examples}/reliable-stdin-commands.mjs (100%) rename {examples => js/examples}/reproduce-issue-135-v2.mjs (100%) rename {examples => js/examples}/reproduce-issue-135.mjs (100%) rename {examples => js/examples}/shell-cd-behavior.mjs (100%) rename {examples => js/examples}/sigint-forwarding-test.mjs (100%) rename {examples => js/examples}/sigint-handler-test.mjs (100%) rename {examples => js/examples}/simple-async-test.mjs (100%) rename {examples => js/examples}/simple-claude-test.mjs (100%) rename {examples => js/examples}/simple-event-test.mjs (100%) rename {examples => js/examples}/simple-jq-streaming.mjs (100%) rename {examples => js/examples}/simple-stream-demo.mjs (100%) rename {examples => js/examples}/simple-test-sleep.js (100%) rename {examples => js/examples}/simple-working-stdin.mjs (100%) rename {examples => js/examples}/streaming-behavior-test.mjs (100%) rename {examples => js/examples}/streaming-direct-command.mjs (85%) rename {examples => js/examples}/streaming-filtered-output.mjs (100%) rename {examples => js/examples}/streaming-grep-pipeline.mjs (82%) rename {examples => js/examples}/streaming-interactive-stdin.mjs (100%) rename {examples => js/examples}/streaming-jq-pipeline.mjs (84%) rename {examples => js/examples}/streaming-multistage-pipeline.mjs (84%) rename {examples => js/examples}/streaming-pipes-event-pattern.mjs (100%) rename {examples => js/examples}/streaming-pipes-multistage.mjs (100%) rename {examples => js/examples}/streaming-pipes-realtime-jq.mjs (100%) rename {examples => js/examples}/streaming-progress-tracking.mjs (100%) rename {examples => js/examples}/streaming-reusable-configs.mjs (100%) rename {examples => js/examples}/streaming-silent-capture.mjs (100%) rename {examples => js/examples}/streaming-test-simple.mjs (100%) rename {examples => js/examples}/streaming-virtual-pipeline.mjs (100%) rename {examples => js/examples}/syntax-basic-comparison.mjs (100%) rename {examples => js/examples}/syntax-basic-options.mjs (100%) rename {examples => js/examples}/syntax-combined-options.mjs (100%) rename {examples => js/examples}/syntax-command-chaining.mjs (100%) rename {examples => js/examples}/syntax-custom-directory.mjs (100%) rename {examples => js/examples}/syntax-custom-environment.mjs (100%) rename {examples => js/examples}/syntax-custom-stdin.mjs (100%) rename {examples => js/examples}/syntax-mixed-regular.mjs (100%) rename {examples => js/examples}/syntax-mixed-usage.mjs (100%) rename {examples => js/examples}/syntax-multiple-listeners.mjs (100%) rename {examples => js/examples}/syntax-piping-comparison.mjs (100%) rename {examples => js/examples}/syntax-reusable-config.mjs (100%) rename {examples => js/examples}/syntax-reusable-configs.mjs (100%) rename {examples => js/examples}/syntax-silent-operations.mjs (100%) rename {examples => js/examples}/syntax-stdin-option.mjs (100%) rename {examples => js/examples}/temp-sigint-test.mjs (100%) rename {examples => js/examples}/test-actual-buildshell.mjs (100%) rename {examples => js/examples}/test-async-streams-working.mjs (100%) rename {examples => js/examples}/test-async-streams.mjs (100%) rename {examples => js/examples}/test-auth-parse.mjs (100%) rename {examples => js/examples}/test-auto-quoting.mjs (100%) rename {examples => js/examples}/test-auto-start-fix.mjs (100%) rename {examples => js/examples}/test-baseline-sigint.mjs (100%) rename {examples => js/examples}/test-buffer-behavior.mjs (100%) rename {examples => js/examples}/test-buffers-simple.mjs (100%) rename {examples => js/examples}/test-bun-specific-issue.mjs (100%) rename {examples => js/examples}/test-bun-streaming.mjs (92%) rename {examples => js/examples}/test-cat-direct.mjs (84%) rename {examples => js/examples}/test-cat-pipe.mjs (90%) rename {examples => js/examples}/test-cd-behavior.mjs (100%) rename {examples => js/examples}/test-child-process-timing.mjs (100%) rename {examples => js/examples}/test-child-sigint-handler.mjs (100%) rename {examples => js/examples}/test-cleanup-simple.mjs (100%) rename {examples => js/examples}/test-comprehensive-tracing.mjs (74%) rename {examples => js/examples}/test-correct-space-handling.mjs (100%) rename {examples => js/examples}/test-ctrl-c-debug.mjs (100%) rename {examples => js/examples}/test-ctrl-c-inherit.mjs (100%) rename {examples => js/examples}/test-ctrl-c-sleep.mjs (100%) rename {examples => js/examples}/test-ctrl-c.mjs (100%) rename {examples => js/examples}/test-debug-new-options.mjs (100%) rename {examples => js/examples}/test-debug-pty.mjs (89%) rename {examples => js/examples}/test-debug-tee.mjs (93%) rename {examples => js/examples}/test-debug.mjs (100%) rename {examples => js/examples}/test-direct-jq.mjs (93%) rename {examples => js/examples}/test-direct-pipe-reading.mjs (90%) rename {examples => js/examples}/test-direct-pipe.sh (100%) rename {examples => js/examples}/test-double-quoting-prevention.mjs (100%) rename {examples => js/examples}/test-edge-cases-quoting.mjs (100%) rename {examples => js/examples}/test-events.mjs (92%) rename {examples => js/examples}/test-explicit-stdio.mjs (100%) rename {examples => js/examples}/test-final-streaming.mjs (85%) rename {examples => js/examples}/test-fix.mjs (100%) rename {examples => js/examples}/test-incremental-streaming.mjs (100%) rename {examples => js/examples}/test-individual-spawn.mjs (82%) rename {examples => js/examples}/test-inherit-stdout-not-stdin.mjs (100%) rename {examples => js/examples}/test-injection-protection.mjs (100%) rename {examples => js/examples}/test-interactive-streaming.mjs (100%) rename {examples => js/examples}/test-interactive-top.md (95%) rename {examples => js/examples}/test-interactive.mjs (100%) rename {examples => js/examples}/test-interpolation.mjs (100%) rename {examples => js/examples}/test-interrupt.mjs (100%) rename {examples => js/examples}/test-issue-135-comprehensive.mjs (100%) rename {examples => js/examples}/test-issue12-detailed.mjs (100%) rename {examples => js/examples}/test-issue12-exact.mjs (100%) rename {examples => js/examples}/test-jq-color.mjs (100%) rename {examples => js/examples}/test-jq-colors.mjs (100%) rename {examples => js/examples}/test-jq-compact.mjs (90%) rename {examples => js/examples}/test-jq-native.sh (100%) rename {examples => js/examples}/test-jq-pipeline-behavior.mjs (100%) rename {examples => js/examples}/test-jq-realtime.mjs (91%) rename {examples => js/examples}/test-manual-start.mjs (100%) rename {examples => js/examples}/test-mixed-quoting.mjs (100%) rename {examples => js/examples}/test-multi-stream.mjs (89%) rename {examples => js/examples}/test-multistage-debug.mjs (92%) rename {examples => js/examples}/test-native-spawn-vs-command-stream.mjs (100%) rename {examples => js/examples}/test-no-parse-pipeline.mjs (91%) rename {examples => js/examples}/test-non-virtual.mjs (100%) rename {examples => js/examples}/test-operators.mjs (100%) rename {examples => js/examples}/test-parent-continues.mjs (100%) rename {examples => js/examples}/test-path-interpolation.mjs (100%) rename {examples => js/examples}/test-ping-kill-and-stdin.mjs (100%) rename {examples => js/examples}/test-ping.mjs (100%) rename {examples => js/examples}/test-pty-spawn.mjs (94%) rename {examples => js/examples}/test-pty.mjs (92%) rename {examples => js/examples}/test-quote-behavior-summary.mjs (100%) rename {examples => js/examples}/test-quote-edge-cases.mjs (100%) rename {examples => js/examples}/test-quote-parsing.mjs (100%) rename {examples => js/examples}/test-raw-function.mjs (100%) rename {examples => js/examples}/test-raw-streaming.mjs (100%) rename {examples => js/examples}/test-readme-examples.mjs (100%) rename {examples => js/examples}/test-real-cat.mjs (100%) rename {examples => js/examples}/test-real-commands.mjs (85%) rename {examples => js/examples}/test-real-shell.mjs (100%) rename {examples => js/examples}/test-real-stdin-commands.mjs (100%) rename {examples => js/examples}/test-runner-batched.mjs (100%) rename {examples => js/examples}/test-runner-simple.mjs (100%) rename {examples => js/examples}/test-runner.mjs (100%) rename {examples => js/examples}/test-scope-parse.mjs (100%) rename {examples => js/examples}/test-sh-pipeline.mjs (87%) rename {examples => js/examples}/test-shell-detection.mjs (100%) rename {examples => js/examples}/test-shell-parser.mjs (100%) rename {examples => js/examples}/test-sigint-behavior.mjs (100%) rename {examples => js/examples}/test-sigint-handling.sh (100%) rename {examples => js/examples}/test-simple-pipe.mjs (100%) rename {examples => js/examples}/test-simple-streaming.mjs (100%) rename {examples => js/examples}/test-sleep-stdin.js (100%) rename {examples => js/examples}/test-sleep.mjs (100%) rename {examples => js/examples}/test-smart-quoting.mjs (100%) rename {examples => js/examples}/test-spaces-in-path.mjs (100%) rename {examples => js/examples}/test-special-chars-quoting.mjs (100%) rename {examples => js/examples}/test-stdin-after-start.mjs (100%) rename {examples => js/examples}/test-stdin-simple.mjs (100%) rename {examples => js/examples}/test-stdin-timing.mjs (100%) rename {examples => js/examples}/test-stdio-combinations.mjs (100%) rename {examples => js/examples}/test-stream-access.mjs (100%) rename {examples => js/examples}/test-stream-cleanup.mjs (100%) rename {examples => js/examples}/test-stream-readers.mjs (93%) rename {examples => js/examples}/test-streaming-final.mjs (89%) rename {examples => js/examples}/test-streaming-interfaces.mjs (98%) rename {examples => js/examples}/test-streaming-timing.mjs (100%) rename {examples => js/examples}/test-streaming.mjs (100%) rename {examples => js/examples}/test-streams-stdin-comprehensive.mjs (100%) rename {examples => js/examples}/test-streams-stdin-ctrl-c.mjs (100%) rename {examples => js/examples}/test-template-literal.mjs (100%) rename {examples => js/examples}/test-template-vs-interpolation.mjs (100%) rename {examples => js/examples}/test-timing.mjs (100%) rename {examples => js/examples}/test-top-inherit-stdout-stdin-control.mjs (100%) rename {examples => js/examples}/test-top-quit-stdin.mjs (100%) rename {examples => js/examples}/test-trace-option.mjs (100%) rename {examples => js/examples}/test-user-double-quotes.mjs (100%) rename {examples => js/examples}/test-user-single-quotes.mjs (100%) rename {examples => js/examples}/test-verbose.mjs (100%) rename {examples => js/examples}/test-verbose2.mjs (100%) rename {examples => js/examples}/test-virtual-streaming.mjs (100%) rename {examples => js/examples}/test-waiting-command.mjs (100%) rename {examples => js/examples}/test-waiting-commands.mjs (100%) rename {examples => js/examples}/test-watch-mode.mjs (100%) rename {examples => js/examples}/test-yes-cancellation.mjs (100%) rename {examples => js/examples}/test-yes-detailed.mjs (100%) rename {examples => js/examples}/test-yes-trace.mjs (100%) rename {examples => js/examples}/trace-abort-controller.mjs (89%) rename {examples => js/examples}/trace-error-handling.mjs (84%) rename {examples => js/examples}/trace-pipeline-command.mjs (84%) rename {examples => js/examples}/trace-signal-handling.mjs (89%) rename {examples => js/examples}/trace-simple-command.mjs (83%) rename {examples => js/examples}/trace-stderr-output.mjs (86%) rename {examples => js/examples}/verify-fix-both-runtimes.mjs (100%) rename {examples => js/examples}/verify-issue12-fixed.mjs (100%) rename {examples => js/examples}/which-command-common-commands.mjs (100%) rename {examples => js/examples}/which-command-gh-test.mjs (100%) rename {examples => js/examples}/which-command-nonexistent.mjs (100%) rename {examples => js/examples}/which-command-system-comparison.mjs (100%) rename {examples => js/examples}/working-example.mjs (100%) rename {examples => js/examples}/working-stdin-examples.mjs (100%) rename {examples => js/examples}/working-streaming-demo.mjs (100%) create mode 100644 temp-unicode-test.txt diff --git a/eslint.config.js b/eslint.config.js index 970e9f9..45be7aa 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -120,7 +120,14 @@ export default [ }, { // Test files have different requirements - files: ['tests/**/*.js', 'tests/**/*.mjs', '**/*.test.js', '**/*.test.mjs'], + files: [ + 'tests/**/*.js', + 'tests/**/*.mjs', + 'js/tests/**/*.js', + 'js/tests/**/*.mjs', + '**/*.test.js', + '**/*.test.mjs', + ], rules: { 'no-unused-vars': 'off', // Tests often have unused vars for demonstration or intentional non-use 'require-await': 'off', // Async functions without await are common in tests @@ -138,7 +145,13 @@ export default [ }, { // Example and debug files are more lenient - files: ['examples/**/*.js', 'examples/**/*.mjs', 'claude-profiles.mjs'], + files: [ + 'examples/**/*.js', + 'examples/**/*.mjs', + 'js/examples/**/*.js', + 'js/examples/**/*.mjs', + 'claude-profiles.mjs', + ], rules: { 'no-unused-vars': 'off', // Examples often have unused vars for demonstration 'require-await': 'off', // Async functions without await are common in examples @@ -160,7 +173,7 @@ export default [ }, { // Virtual command implementations have specific interface requirements - files: ['src/commands/**/*.mjs'], + files: ['src/commands/**/*.mjs', 'js/src/commands/**/*.mjs'], rules: { 'require-await': 'off', // Commands must be async to match interface even if they don't await complexity: 'off', // Commands can be complex due to argument parsing and validation diff --git a/examples/01-basic-streaming.mjs b/js/examples/01-basic-streaming.mjs similarity index 100% rename from examples/01-basic-streaming.mjs rename to js/examples/01-basic-streaming.mjs diff --git a/examples/02-async-iterator.mjs b/js/examples/02-async-iterator.mjs similarity index 100% rename from examples/02-async-iterator.mjs rename to js/examples/02-async-iterator.mjs diff --git a/examples/03-file-and-console.mjs b/js/examples/03-file-and-console.mjs similarity index 100% rename from examples/03-file-and-console.mjs rename to js/examples/03-file-and-console.mjs diff --git a/examples/04-claude-jq-pipe.mjs b/js/examples/04-claude-jq-pipe.mjs similarity index 100% rename from examples/04-claude-jq-pipe.mjs rename to js/examples/04-claude-jq-pipe.mjs diff --git a/examples/CI-DEBUG-README.md b/js/examples/CI-DEBUG-README.md similarity index 92% rename from examples/CI-DEBUG-README.md rename to js/examples/CI-DEBUG-README.md index 7020afa..86cdc84 100644 --- a/examples/CI-DEBUG-README.md +++ b/js/examples/CI-DEBUG-README.md @@ -11,7 +11,7 @@ This directory contains examples for debugging common issues that occur in CI en **Solution**: Force stdout flush when not in TTY mode. ```bash -node examples/ci-debug-stdout-buffering.mjs +node js/examples/ci-debug-stdout-buffering.mjs ``` ### 2. ES Module Loading Failures (`ci-debug-es-module-loading.mjs`) @@ -21,7 +21,7 @@ node examples/ci-debug-stdout-buffering.mjs **Solution**: Use different module loading strategies or fallback to shell commands. ```bash -node examples/ci-debug-es-module-loading.mjs +node js/examples/ci-debug-es-module-loading.mjs ``` ### 3. Signal Handling (`ci-debug-signal-handling.mjs`) @@ -31,7 +31,7 @@ node examples/ci-debug-es-module-loading.mjs **Solution**: Proper signal forwarding and environment-aware cleanup strategies. ```bash -node examples/ci-debug-signal-handling.mjs +node js/examples/ci-debug-signal-handling.mjs ``` ### 4. Test Timeouts (`ci-debug-test-timeouts.mjs`) @@ -41,7 +41,7 @@ node examples/ci-debug-signal-handling.mjs **Solution**: Add explicit timeouts to all tests and implement timeout strategies. ```bash -node examples/ci-debug-test-timeouts.mjs +node js/examples/ci-debug-test-timeouts.mjs ``` ### 5. Baseline vs Library Testing (`ci-debug-baseline-vs-library.mjs`) @@ -51,7 +51,7 @@ node examples/ci-debug-test-timeouts.mjs **Solution**: Test both raw spawn and library functionality for comparison. ```bash -node examples/ci-debug-baseline-vs-library.mjs +node js/examples/ci-debug-baseline-vs-library.mjs ``` ## Quick Debugging Checklist @@ -113,7 +113,7 @@ process.on('exit', cleanup); ```bash # Run all CI debugging examples -for f in examples/ci-debug-*.mjs; do +for f in js/examples/ci-debug-*.mjs; do echo "Running $f..." node "$f" echo "" diff --git a/examples/README-examples.mjs b/js/examples/README-examples.mjs similarity index 100% rename from examples/README-examples.mjs rename to js/examples/README-examples.mjs diff --git a/examples/README.md b/js/examples/README.md similarity index 98% rename from examples/README.md rename to js/examples/README.md index 9a0df93..07bbf25 100644 --- a/examples/README.md +++ b/js/examples/README.md @@ -318,19 +318,19 @@ The simplest examples to get started: ```bash # Run a basic example -bun examples/ping-streaming-simple.mjs +bun js/examples/ping-streaming-simple.mjs # Test ANSI color handling -node examples/colors-default-preserved.mjs +node js/examples/colors-default-preserved.mjs # Try CTRL+C signal handling -node examples/ctrl-c-long-running-command.mjs +node js/examples/ctrl-c-long-running-command.mjs # Test streaming with options -node examples/options-streaming-silent.mjs +node js/examples/options-streaming-silent.mjs # Event-based processing -node examples/events-log-processing.mjs +node js/examples/events-log-processing.mjs ``` ## File Naming Convention diff --git a/examples/STREAMING_INTERFACES_SUMMARY.md b/js/examples/STREAMING_INTERFACES_SUMMARY.md similarity index 100% rename from examples/STREAMING_INTERFACES_SUMMARY.md rename to js/examples/STREAMING_INTERFACES_SUMMARY.md diff --git a/examples/add-test-timeouts.js b/js/examples/add-test-timeouts.js similarity index 100% rename from examples/add-test-timeouts.js rename to js/examples/add-test-timeouts.js diff --git a/examples/ansi-default-preserved.mjs b/js/examples/ansi-default-preserved.mjs similarity index 100% rename from examples/ansi-default-preserved.mjs rename to js/examples/ansi-default-preserved.mjs diff --git a/examples/ansi-global-config.mjs b/js/examples/ansi-global-config.mjs similarity index 100% rename from examples/ansi-global-config.mjs rename to js/examples/ansi-global-config.mjs diff --git a/examples/ansi-reset-default.mjs b/js/examples/ansi-reset-default.mjs similarity index 100% rename from examples/ansi-reset-default.mjs rename to js/examples/ansi-reset-default.mjs diff --git a/examples/ansi-strip-utils.mjs b/js/examples/ansi-strip-utils.mjs similarity index 100% rename from examples/ansi-strip-utils.mjs rename to js/examples/ansi-strip-utils.mjs diff --git a/examples/baseline-child-process.mjs b/js/examples/baseline-child-process.mjs similarity index 100% rename from examples/baseline-child-process.mjs rename to js/examples/baseline-child-process.mjs diff --git a/examples/baseline-claude-test.mjs b/js/examples/baseline-claude-test.mjs similarity index 100% rename from examples/baseline-claude-test.mjs rename to js/examples/baseline-claude-test.mjs diff --git a/examples/baseline-working.mjs b/js/examples/baseline-working.mjs similarity index 100% rename from examples/baseline-working.mjs rename to js/examples/baseline-working.mjs diff --git a/examples/capture-mirror-comparison.mjs b/js/examples/capture-mirror-comparison.mjs similarity index 100% rename from examples/capture-mirror-comparison.mjs rename to js/examples/capture-mirror-comparison.mjs diff --git a/examples/capture-mirror-default.mjs b/js/examples/capture-mirror-default.mjs similarity index 100% rename from examples/capture-mirror-default.mjs rename to js/examples/capture-mirror-default.mjs diff --git a/examples/capture-mirror-performance.mjs b/js/examples/capture-mirror-performance.mjs similarity index 100% rename from examples/capture-mirror-performance.mjs rename to js/examples/capture-mirror-performance.mjs diff --git a/examples/capture-mirror-show-only.mjs b/js/examples/capture-mirror-show-only.mjs similarity index 100% rename from examples/capture-mirror-show-only.mjs rename to js/examples/capture-mirror-show-only.mjs diff --git a/examples/capture-mirror-silent-processing.mjs b/js/examples/capture-mirror-silent-processing.mjs similarity index 100% rename from examples/capture-mirror-silent-processing.mjs rename to js/examples/capture-mirror-silent-processing.mjs diff --git a/examples/ci-debug-baseline-vs-library.mjs b/js/examples/ci-debug-baseline-vs-library.mjs similarity index 100% rename from examples/ci-debug-baseline-vs-library.mjs rename to js/examples/ci-debug-baseline-vs-library.mjs diff --git a/examples/ci-debug-es-module-loading.mjs b/js/examples/ci-debug-es-module-loading.mjs similarity index 100% rename from examples/ci-debug-es-module-loading.mjs rename to js/examples/ci-debug-es-module-loading.mjs diff --git a/examples/ci-debug-signal-handling.mjs b/js/examples/ci-debug-signal-handling.mjs similarity index 100% rename from examples/ci-debug-signal-handling.mjs rename to js/examples/ci-debug-signal-handling.mjs diff --git a/examples/ci-debug-stdout-buffering.mjs b/js/examples/ci-debug-stdout-buffering.mjs similarity index 100% rename from examples/ci-debug-stdout-buffering.mjs rename to js/examples/ci-debug-stdout-buffering.mjs diff --git a/examples/ci-debug-test-timeouts.mjs b/js/examples/ci-debug-test-timeouts.mjs similarity index 100% rename from examples/ci-debug-test-timeouts.mjs rename to js/examples/ci-debug-test-timeouts.mjs diff --git a/examples/claude-exact-file-output.mjs b/js/examples/claude-exact-file-output.mjs similarity index 100% rename from examples/claude-exact-file-output.mjs rename to js/examples/claude-exact-file-output.mjs diff --git a/examples/claude-exact-jq.mjs b/js/examples/claude-exact-jq.mjs similarity index 100% rename from examples/claude-exact-jq.mjs rename to js/examples/claude-exact-jq.mjs diff --git a/examples/claude-exact-streaming.mjs b/js/examples/claude-exact-streaming.mjs similarity index 100% rename from examples/claude-exact-streaming.mjs rename to js/examples/claude-exact-streaming.mjs diff --git a/examples/claude-jq-pipeline.mjs b/js/examples/claude-jq-pipeline.mjs similarity index 100% rename from examples/claude-jq-pipeline.mjs rename to js/examples/claude-jq-pipeline.mjs diff --git a/examples/claude-json-stream.mjs b/js/examples/claude-json-stream.mjs similarity index 100% rename from examples/claude-json-stream.mjs rename to js/examples/claude-json-stream.mjs diff --git a/examples/claude-streaming-basic.mjs b/js/examples/claude-streaming-basic.mjs similarity index 100% rename from examples/claude-streaming-basic.mjs rename to js/examples/claude-streaming-basic.mjs diff --git a/examples/claude-streaming-demo.mjs b/js/examples/claude-streaming-demo.mjs similarity index 100% rename from examples/claude-streaming-demo.mjs rename to js/examples/claude-streaming-demo.mjs diff --git a/examples/claude-streaming-final.mjs b/js/examples/claude-streaming-final.mjs similarity index 100% rename from examples/claude-streaming-final.mjs rename to js/examples/claude-streaming-final.mjs diff --git a/examples/cleanup-verification-test.mjs b/js/examples/cleanup-verification-test.mjs similarity index 100% rename from examples/cleanup-verification-test.mjs rename to js/examples/cleanup-verification-test.mjs diff --git a/examples/colors-buffer-processing.mjs b/js/examples/colors-buffer-processing.mjs similarity index 100% rename from examples/colors-buffer-processing.mjs rename to js/examples/colors-buffer-processing.mjs diff --git a/examples/colors-default-preserved.mjs b/js/examples/colors-default-preserved.mjs similarity index 100% rename from examples/colors-default-preserved.mjs rename to js/examples/colors-default-preserved.mjs diff --git a/examples/colors-per-command-config.mjs b/js/examples/colors-per-command-config.mjs similarity index 100% rename from examples/colors-per-command-config.mjs rename to js/examples/colors-per-command-config.mjs diff --git a/examples/colors-strip-ansi.mjs b/js/examples/colors-strip-ansi.mjs similarity index 100% rename from examples/colors-strip-ansi.mjs rename to js/examples/colors-strip-ansi.mjs diff --git a/examples/commandstream-jq.mjs b/js/examples/commandstream-jq.mjs similarity index 100% rename from examples/commandstream-jq.mjs rename to js/examples/commandstream-jq.mjs diff --git a/examples/commandstream-working.mjs b/js/examples/commandstream-working.mjs similarity index 100% rename from examples/commandstream-working.mjs rename to js/examples/commandstream-working.mjs diff --git a/examples/comprehensive-streams-demo.mjs b/js/examples/comprehensive-streams-demo.mjs similarity index 100% rename from examples/comprehensive-streams-demo.mjs rename to js/examples/comprehensive-streams-demo.mjs diff --git a/examples/ctrl-c-concurrent-processes.mjs b/js/examples/ctrl-c-concurrent-processes.mjs similarity index 100% rename from examples/ctrl-c-concurrent-processes.mjs rename to js/examples/ctrl-c-concurrent-processes.mjs diff --git a/examples/ctrl-c-long-running-command.mjs b/js/examples/ctrl-c-long-running-command.mjs similarity index 100% rename from examples/ctrl-c-long-running-command.mjs rename to js/examples/ctrl-c-long-running-command.mjs diff --git a/examples/ctrl-c-real-system-command.mjs b/js/examples/ctrl-c-real-system-command.mjs similarity index 100% rename from examples/ctrl-c-real-system-command.mjs rename to js/examples/ctrl-c-real-system-command.mjs diff --git a/examples/ctrl-c-sleep-command.mjs b/js/examples/ctrl-c-sleep-command.mjs similarity index 100% rename from examples/ctrl-c-sleep-command.mjs rename to js/examples/ctrl-c-sleep-command.mjs diff --git a/examples/ctrl-c-stdin-forwarding.mjs b/js/examples/ctrl-c-stdin-forwarding.mjs similarity index 100% rename from examples/ctrl-c-stdin-forwarding.mjs rename to js/examples/ctrl-c-stdin-forwarding.mjs diff --git a/examples/ctrl-c-virtual-command.mjs b/js/examples/ctrl-c-virtual-command.mjs similarity index 100% rename from examples/ctrl-c-virtual-command.mjs rename to js/examples/ctrl-c-virtual-command.mjs diff --git a/examples/debug-already-started.mjs b/js/examples/debug-already-started.mjs similarity index 100% rename from examples/debug-already-started.mjs rename to js/examples/debug-already-started.mjs diff --git a/examples/debug-ansi-processing.mjs b/js/examples/debug-ansi-processing.mjs similarity index 100% rename from examples/debug-ansi-processing.mjs rename to js/examples/debug-ansi-processing.mjs diff --git a/examples/debug-basic-streaming.mjs b/js/examples/debug-basic-streaming.mjs similarity index 100% rename from examples/debug-basic-streaming.mjs rename to js/examples/debug-basic-streaming.mjs diff --git a/examples/debug-buildshellcommand.mjs b/js/examples/debug-buildshellcommand.mjs similarity index 100% rename from examples/debug-buildshellcommand.mjs rename to js/examples/debug-buildshellcommand.mjs diff --git a/examples/debug-child-process.mjs b/js/examples/debug-child-process.mjs similarity index 100% rename from examples/debug-child-process.mjs rename to js/examples/debug-child-process.mjs diff --git a/examples/debug-child-state.mjs b/js/examples/debug-child-state.mjs similarity index 100% rename from examples/debug-child-state.mjs rename to js/examples/debug-child-state.mjs diff --git a/examples/debug-chunking.mjs b/js/examples/debug-chunking.mjs similarity index 100% rename from examples/debug-chunking.mjs rename to js/examples/debug-chunking.mjs diff --git a/examples/debug-command-parsing.mjs b/js/examples/debug-command-parsing.mjs similarity index 100% rename from examples/debug-command-parsing.mjs rename to js/examples/debug-command-parsing.mjs diff --git a/examples/debug-complete-consolidation.mjs b/js/examples/debug-complete-consolidation.mjs similarity index 100% rename from examples/debug-complete-consolidation.mjs rename to js/examples/debug-complete-consolidation.mjs diff --git a/examples/debug-echo-args.mjs b/js/examples/debug-echo-args.mjs similarity index 100% rename from examples/debug-echo-args.mjs rename to js/examples/debug-echo-args.mjs diff --git a/examples/debug-emit-timing.mjs b/js/examples/debug-emit-timing.mjs similarity index 100% rename from examples/debug-emit-timing.mjs rename to js/examples/debug-emit-timing.mjs diff --git a/examples/debug-end-event.mjs b/js/examples/debug-end-event.mjs similarity index 100% rename from examples/debug-end-event.mjs rename to js/examples/debug-end-event.mjs diff --git a/examples/debug-errexit.mjs b/js/examples/debug-errexit.mjs similarity index 100% rename from examples/debug-errexit.mjs rename to js/examples/debug-errexit.mjs diff --git a/examples/debug-event-emission.mjs b/js/examples/debug-event-emission.mjs similarity index 100% rename from examples/debug-event-emission.mjs rename to js/examples/debug-event-emission.mjs diff --git a/examples/debug-event-timing.mjs b/js/examples/debug-event-timing.mjs similarity index 100% rename from examples/debug-event-timing.mjs rename to js/examples/debug-event-timing.mjs diff --git a/examples/debug-event-vs-result.mjs b/js/examples/debug-event-vs-result.mjs similarity index 100% rename from examples/debug-event-vs-result.mjs rename to js/examples/debug-event-vs-result.mjs diff --git a/examples/debug-exact-command.mjs b/js/examples/debug-exact-command.mjs similarity index 100% rename from examples/debug-exact-command.mjs rename to js/examples/debug-exact-command.mjs diff --git a/examples/debug-exact-test-scenario.mjs b/js/examples/debug-exact-test-scenario.mjs similarity index 100% rename from examples/debug-exact-test-scenario.mjs rename to js/examples/debug-exact-test-scenario.mjs diff --git a/examples/debug-execution-path.mjs b/js/examples/debug-execution-path.mjs similarity index 100% rename from examples/debug-execution-path.mjs rename to js/examples/debug-execution-path.mjs diff --git a/examples/debug-exit-command.mjs b/js/examples/debug-exit-command.mjs similarity index 100% rename from examples/debug-exit-command.mjs rename to js/examples/debug-exit-command.mjs diff --git a/examples/debug-exit-virtual.mjs b/js/examples/debug-exit-virtual.mjs similarity index 100% rename from examples/debug-exit-virtual.mjs rename to js/examples/debug-exit-virtual.mjs diff --git a/examples/debug-finish-consolidation.mjs b/js/examples/debug-finish-consolidation.mjs similarity index 100% rename from examples/debug-finish-consolidation.mjs rename to js/examples/debug-finish-consolidation.mjs diff --git a/examples/debug-force-cleanup.mjs b/js/examples/debug-force-cleanup.mjs similarity index 100% rename from examples/debug-force-cleanup.mjs rename to js/examples/debug-force-cleanup.mjs diff --git a/examples/debug-getter-basic.mjs b/js/examples/debug-getter-basic.mjs similarity index 100% rename from examples/debug-getter-basic.mjs rename to js/examples/debug-getter-basic.mjs diff --git a/examples/debug-getter-direct.mjs b/js/examples/debug-getter-direct.mjs similarity index 100% rename from examples/debug-getter-direct.mjs rename to js/examples/debug-getter-direct.mjs diff --git a/examples/debug-getter-internals.mjs b/js/examples/debug-getter-internals.mjs similarity index 100% rename from examples/debug-getter-internals.mjs rename to js/examples/debug-getter-internals.mjs diff --git a/examples/debug-handler-detection.mjs b/js/examples/debug-handler-detection.mjs similarity index 100% rename from examples/debug-handler-detection.mjs rename to js/examples/debug-handler-detection.mjs diff --git a/examples/debug-idempotent-finish.mjs b/js/examples/debug-idempotent-finish.mjs similarity index 100% rename from examples/debug-idempotent-finish.mjs rename to js/examples/debug-idempotent-finish.mjs diff --git a/examples/debug-idempotent-kill.mjs b/js/examples/debug-idempotent-kill.mjs similarity index 100% rename from examples/debug-idempotent-kill.mjs rename to js/examples/debug-idempotent-kill.mjs diff --git a/examples/debug-interpolation-individual.mjs b/js/examples/debug-interpolation-individual.mjs similarity index 100% rename from examples/debug-interpolation-individual.mjs rename to js/examples/debug-interpolation-individual.mjs diff --git a/examples/debug-interpolation-issue.mjs b/js/examples/debug-interpolation-issue.mjs similarity index 100% rename from examples/debug-interpolation-issue.mjs rename to js/examples/debug-interpolation-issue.mjs diff --git a/examples/debug-jq-streaming.mjs b/js/examples/debug-jq-streaming.mjs similarity index 100% rename from examples/debug-jq-streaming.mjs rename to js/examples/debug-jq-streaming.mjs diff --git a/examples/debug-jq-tty-colors.mjs b/js/examples/debug-jq-tty-colors.mjs similarity index 100% rename from examples/debug-jq-tty-colors.mjs rename to js/examples/debug-jq-tty-colors.mjs diff --git a/examples/debug-kill-cleanup.mjs b/js/examples/debug-kill-cleanup.mjs similarity index 100% rename from examples/debug-kill-cleanup.mjs rename to js/examples/debug-kill-cleanup.mjs diff --git a/examples/debug-kill-method.mjs b/js/examples/debug-kill-method.mjs similarity index 100% rename from examples/debug-kill-method.mjs rename to js/examples/debug-kill-method.mjs diff --git a/examples/debug-listener-interference.mjs b/js/examples/debug-listener-interference.mjs similarity index 100% rename from examples/debug-listener-interference.mjs rename to js/examples/debug-listener-interference.mjs diff --git a/examples/debug-listener-lifecycle.mjs b/js/examples/debug-listener-lifecycle.mjs similarity index 100% rename from examples/debug-listener-lifecycle.mjs rename to js/examples/debug-listener-lifecycle.mjs diff --git a/examples/debug-listener-timing.mjs b/js/examples/debug-listener-timing.mjs similarity index 100% rename from examples/debug-listener-timing.mjs rename to js/examples/debug-listener-timing.mjs diff --git a/examples/debug-listeners-property.mjs b/js/examples/debug-listeners-property.mjs similarity index 100% rename from examples/debug-listeners-property.mjs rename to js/examples/debug-listeners-property.mjs diff --git a/examples/debug-map-methods.mjs b/js/examples/debug-map-methods.mjs similarity index 100% rename from examples/debug-map-methods.mjs rename to js/examples/debug-map-methods.mjs diff --git a/examples/debug-not-awaited-cleanup.mjs b/js/examples/debug-not-awaited-cleanup.mjs similarity index 100% rename from examples/debug-not-awaited-cleanup.mjs rename to js/examples/debug-not-awaited-cleanup.mjs diff --git a/examples/debug-off-method.mjs b/js/examples/debug-off-method.mjs similarity index 100% rename from examples/debug-off-method.mjs rename to js/examples/debug-off-method.mjs diff --git a/examples/debug-option-merging.mjs b/js/examples/debug-option-merging.mjs similarity index 100% rename from examples/debug-option-merging.mjs rename to js/examples/debug-option-merging.mjs diff --git a/examples/debug-options.mjs b/js/examples/debug-options.mjs similarity index 100% rename from examples/debug-options.mjs rename to js/examples/debug-options.mjs diff --git a/examples/debug-output.mjs b/js/examples/debug-output.mjs similarity index 100% rename from examples/debug-output.mjs rename to js/examples/debug-output.mjs diff --git a/examples/debug-pattern-matching.mjs b/js/examples/debug-pattern-matching.mjs similarity index 100% rename from examples/debug-pattern-matching.mjs rename to js/examples/debug-pattern-matching.mjs diff --git a/examples/debug-pipeline-cat.mjs b/js/examples/debug-pipeline-cat.mjs similarity index 100% rename from examples/debug-pipeline-cat.mjs rename to js/examples/debug-pipeline-cat.mjs diff --git a/examples/debug-pipeline-cleanup.mjs b/js/examples/debug-pipeline-cleanup.mjs similarity index 100% rename from examples/debug-pipeline-cleanup.mjs rename to js/examples/debug-pipeline-cleanup.mjs diff --git a/examples/debug-pipeline-error-detailed.mjs b/js/examples/debug-pipeline-error-detailed.mjs similarity index 100% rename from examples/debug-pipeline-error-detailed.mjs rename to js/examples/debug-pipeline-error-detailed.mjs diff --git a/examples/debug-pipeline-error.mjs b/js/examples/debug-pipeline-error.mjs similarity index 100% rename from examples/debug-pipeline-error.mjs rename to js/examples/debug-pipeline-error.mjs diff --git a/examples/debug-pipeline-issue.mjs b/js/examples/debug-pipeline-issue.mjs similarity index 100% rename from examples/debug-pipeline-issue.mjs rename to js/examples/debug-pipeline-issue.mjs diff --git a/examples/debug-pipeline-method.mjs b/js/examples/debug-pipeline-method.mjs similarity index 100% rename from examples/debug-pipeline-method.mjs rename to js/examples/debug-pipeline-method.mjs diff --git a/examples/debug-pipeline-stream.mjs b/js/examples/debug-pipeline-stream.mjs similarity index 100% rename from examples/debug-pipeline-stream.mjs rename to js/examples/debug-pipeline-stream.mjs diff --git a/examples/debug-pipeline.mjs b/js/examples/debug-pipeline.mjs similarity index 100% rename from examples/debug-pipeline.mjs rename to js/examples/debug-pipeline.mjs diff --git a/examples/debug-process-exit-trace.mjs b/js/examples/debug-process-exit-trace.mjs similarity index 100% rename from examples/debug-process-exit-trace.mjs rename to js/examples/debug-process-exit-trace.mjs diff --git a/examples/debug-process-path.mjs b/js/examples/debug-process-path.mjs similarity index 100% rename from examples/debug-process-path.mjs rename to js/examples/debug-process-path.mjs diff --git a/examples/debug-property-check.mjs b/js/examples/debug-property-check.mjs similarity index 100% rename from examples/debug-property-check.mjs rename to js/examples/debug-property-check.mjs diff --git a/examples/debug-resource-cleanup.mjs b/js/examples/debug-resource-cleanup.mjs similarity index 100% rename from examples/debug-resource-cleanup.mjs rename to js/examples/debug-resource-cleanup.mjs diff --git a/examples/debug-shell-args.mjs b/js/examples/debug-shell-args.mjs similarity index 100% rename from examples/debug-shell-args.mjs rename to js/examples/debug-shell-args.mjs diff --git a/examples/debug-sigint-child-handler.mjs b/js/examples/debug-sigint-child-handler.mjs similarity index 100% rename from examples/debug-sigint-child-handler.mjs rename to js/examples/debug-sigint-child-handler.mjs diff --git a/examples/debug-sigint-forwarding.mjs b/js/examples/debug-sigint-forwarding.mjs similarity index 100% rename from examples/debug-sigint-forwarding.mjs rename to js/examples/debug-sigint-forwarding.mjs diff --git a/examples/debug-sigint-handler-install.mjs b/js/examples/debug-sigint-handler-install.mjs similarity index 100% rename from examples/debug-sigint-handler-install.mjs rename to js/examples/debug-sigint-handler-install.mjs diff --git a/examples/debug-sigint-handler-order.mjs b/js/examples/debug-sigint-handler-order.mjs similarity index 100% rename from examples/debug-sigint-handler-order.mjs rename to js/examples/debug-sigint-handler-order.mjs diff --git a/examples/debug-sigint-listeners.mjs b/js/examples/debug-sigint-listeners.mjs similarity index 100% rename from examples/debug-sigint-listeners.mjs rename to js/examples/debug-sigint-listeners.mjs diff --git a/examples/debug-sigint-start-pattern.mjs b/js/examples/debug-sigint-start-pattern.mjs similarity index 100% rename from examples/debug-sigint-start-pattern.mjs rename to js/examples/debug-sigint-start-pattern.mjs diff --git a/examples/debug-sigint-timer.mjs b/js/examples/debug-sigint-timer.mjs similarity index 100% rename from examples/debug-sigint-timer.mjs rename to js/examples/debug-sigint-timer.mjs diff --git a/examples/debug-simple-command.mjs b/js/examples/debug-simple-command.mjs similarity index 100% rename from examples/debug-simple-command.mjs rename to js/examples/debug-simple-command.mjs diff --git a/examples/debug-simple-getter.mjs b/js/examples/debug-simple-getter.mjs similarity index 100% rename from examples/debug-simple-getter.mjs rename to js/examples/debug-simple-getter.mjs diff --git a/examples/debug-simple.mjs b/js/examples/debug-simple.mjs similarity index 100% rename from examples/debug-simple.mjs rename to js/examples/debug-simple.mjs diff --git a/examples/debug-simplified-finished.mjs b/js/examples/debug-simplified-finished.mjs similarity index 100% rename from examples/debug-simplified-finished.mjs rename to js/examples/debug-simplified-finished.mjs diff --git a/examples/debug-stack-overflow.mjs b/js/examples/debug-stack-overflow.mjs similarity index 100% rename from examples/debug-stack-overflow.mjs rename to js/examples/debug-stack-overflow.mjs diff --git a/examples/debug-stdin-simple.mjs b/js/examples/debug-stdin-simple.mjs similarity index 100% rename from examples/debug-stdin-simple.mjs rename to js/examples/debug-stdin-simple.mjs diff --git a/examples/debug-stdin.mjs b/js/examples/debug-stdin.mjs similarity index 100% rename from examples/debug-stdin.mjs rename to js/examples/debug-stdin.mjs diff --git a/examples/debug-stream-emitter-isolated.mjs b/js/examples/debug-stream-emitter-isolated.mjs similarity index 100% rename from examples/debug-stream-emitter-isolated.mjs rename to js/examples/debug-stream-emitter-isolated.mjs diff --git a/examples/debug-stream-emitter.mjs b/js/examples/debug-stream-emitter.mjs similarity index 100% rename from examples/debug-stream-emitter.mjs rename to js/examples/debug-stream-emitter.mjs diff --git a/examples/debug-stream-events.mjs b/js/examples/debug-stream-events.mjs similarity index 100% rename from examples/debug-stream-events.mjs rename to js/examples/debug-stream-events.mjs diff --git a/examples/debug-stream-generator.mjs b/js/examples/debug-stream-generator.mjs similarity index 100% rename from examples/debug-stream-generator.mjs rename to js/examples/debug-stream-generator.mjs diff --git a/examples/debug-stream-getter-issue.mjs b/js/examples/debug-stream-getter-issue.mjs similarity index 100% rename from examples/debug-stream-getter-issue.mjs rename to js/examples/debug-stream-getter-issue.mjs diff --git a/examples/debug-stream-getter.mjs b/js/examples/debug-stream-getter.mjs similarity index 100% rename from examples/debug-stream-getter.mjs rename to js/examples/debug-stream-getter.mjs diff --git a/examples/debug-stream-internals.mjs b/js/examples/debug-stream-internals.mjs similarity index 100% rename from examples/debug-stream-internals.mjs rename to js/examples/debug-stream-internals.mjs diff --git a/examples/debug-stream-method.mjs b/js/examples/debug-stream-method.mjs similarity index 100% rename from examples/debug-stream-method.mjs rename to js/examples/debug-stream-method.mjs diff --git a/examples/debug-stream-object.mjs b/js/examples/debug-stream-object.mjs similarity index 100% rename from examples/debug-stream-object.mjs rename to js/examples/debug-stream-object.mjs diff --git a/examples/debug-stream-properties.mjs b/js/examples/debug-stream-properties.mjs similarity index 100% rename from examples/debug-stream-properties.mjs rename to js/examples/debug-stream-properties.mjs diff --git a/examples/debug-stream-timing.mjs b/js/examples/debug-stream-timing.mjs similarity index 100% rename from examples/debug-stream-timing.mjs rename to js/examples/debug-stream-timing.mjs diff --git a/examples/debug-streaming.mjs b/js/examples/debug-streaming.mjs similarity index 100% rename from examples/debug-streaming.mjs rename to js/examples/debug-streaming.mjs diff --git a/examples/debug-test-isolation.mjs b/js/examples/debug-test-isolation.mjs similarity index 100% rename from examples/debug-test-isolation.mjs rename to js/examples/debug-test-isolation.mjs diff --git a/examples/debug-test-state.mjs b/js/examples/debug-test-state.mjs similarity index 100% rename from examples/debug-test-state.mjs rename to js/examples/debug-test-state.mjs diff --git a/examples/debug-user-sigint.mjs b/js/examples/debug-user-sigint.mjs similarity index 100% rename from examples/debug-user-sigint.mjs rename to js/examples/debug-user-sigint.mjs diff --git a/examples/debug-virtual-disable.mjs b/js/examples/debug-virtual-disable.mjs similarity index 100% rename from examples/debug-virtual-disable.mjs rename to js/examples/debug-virtual-disable.mjs diff --git a/examples/debug-virtual-vs-real.mjs b/js/examples/debug-virtual-vs-real.mjs similarity index 100% rename from examples/debug-virtual-vs-real.mjs rename to js/examples/debug-virtual-vs-real.mjs diff --git a/examples/debug-with-trace.mjs b/js/examples/debug-with-trace.mjs similarity index 100% rename from examples/debug-with-trace.mjs rename to js/examples/debug-with-trace.mjs diff --git a/examples/debug_parent_stream.mjs b/js/examples/debug_parent_stream.mjs similarity index 100% rename from examples/debug_parent_stream.mjs rename to js/examples/debug_parent_stream.mjs diff --git a/examples/emulate-claude-stream.mjs b/js/examples/emulate-claude-stream.mjs similarity index 100% rename from examples/emulate-claude-stream.mjs rename to js/examples/emulate-claude-stream.mjs diff --git a/examples/emulated-streaming-direct.mjs b/js/examples/emulated-streaming-direct.mjs similarity index 83% rename from examples/emulated-streaming-direct.mjs rename to js/examples/emulated-streaming-direct.mjs index 4faf723..7dee008 100755 --- a/examples/emulated-streaming-direct.mjs +++ b/js/examples/emulated-streaming-direct.mjs @@ -7,7 +7,7 @@ import { $ } from '../js/src/$.mjs'; console.log('Direct execution of emulator:'); const start = Date.now(); -for await (const chunk of $`bun run examples/emulate-claude-stream.mjs`.stream()) { +for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs`.stream()) { if (chunk.type === 'stdout') { const elapsed = Date.now() - start; const lines = chunk.data diff --git a/examples/emulated-streaming-jq-pipe.mjs b/js/examples/emulated-streaming-jq-pipe.mjs similarity index 81% rename from examples/emulated-streaming-jq-pipe.mjs rename to js/examples/emulated-streaming-jq-pipe.mjs index cb3ec03..9e17051 100755 --- a/examples/emulated-streaming-jq-pipe.mjs +++ b/js/examples/emulated-streaming-jq-pipe.mjs @@ -7,7 +7,7 @@ import { $ } from '../js/src/$.mjs'; console.log('Emulator piped through jq:'); const start = Date.now(); -for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | jq .`.stream()) { +for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | jq .`.stream()) { if (chunk.type === 'stdout') { const elapsed = Date.now() - start; const lines = chunk.data diff --git a/examples/emulated-streaming-sh-pipe.mjs b/js/examples/emulated-streaming-sh-pipe.mjs similarity index 85% rename from examples/emulated-streaming-sh-pipe.mjs rename to js/examples/emulated-streaming-sh-pipe.mjs index ad1d13e..cb47b23 100755 --- a/examples/emulated-streaming-sh-pipe.mjs +++ b/js/examples/emulated-streaming-sh-pipe.mjs @@ -7,7 +7,7 @@ import { $ } from '../js/src/$.mjs'; console.log('Using sh -c with pipe:'); const start = Date.now(); -const cmd = $`sh -c 'bun run examples/emulate-claude-stream.mjs | jq .'`; +const cmd = $`sh -c 'bun run js/examples/emulate-claude-stream.mjs | jq .'`; for await (const chunk of cmd.stream()) { if (chunk.type === 'stdout') { const elapsed = Date.now() - start; diff --git a/examples/events-build-process.mjs b/js/examples/events-build-process.mjs similarity index 100% rename from examples/events-build-process.mjs rename to js/examples/events-build-process.mjs diff --git a/examples/events-concurrent-streams.mjs b/js/examples/events-concurrent-streams.mjs similarity index 100% rename from examples/events-concurrent-streams.mjs rename to js/examples/events-concurrent-streams.mjs diff --git a/examples/events-error-handling.mjs b/js/examples/events-error-handling.mjs similarity index 100% rename from examples/events-error-handling.mjs rename to js/examples/events-error-handling.mjs diff --git a/examples/events-file-monitoring.mjs b/js/examples/events-file-monitoring.mjs similarity index 100% rename from examples/events-file-monitoring.mjs rename to js/examples/events-file-monitoring.mjs diff --git a/examples/events-interactive-simulation.mjs b/js/examples/events-interactive-simulation.mjs similarity index 100% rename from examples/events-interactive-simulation.mjs rename to js/examples/events-interactive-simulation.mjs diff --git a/examples/events-log-processing.mjs b/js/examples/events-log-processing.mjs similarity index 100% rename from examples/events-log-processing.mjs rename to js/examples/events-log-processing.mjs diff --git a/examples/events-network-monitoring.mjs b/js/examples/events-network-monitoring.mjs similarity index 100% rename from examples/events-network-monitoring.mjs rename to js/examples/events-network-monitoring.mjs diff --git a/examples/events-ping-basic.mjs b/js/examples/events-ping-basic.mjs similarity index 100% rename from examples/events-ping-basic.mjs rename to js/examples/events-ping-basic.mjs diff --git a/examples/events-progress-tracking.mjs b/js/examples/events-progress-tracking.mjs similarity index 100% rename from examples/events-progress-tracking.mjs rename to js/examples/events-progress-tracking.mjs diff --git a/examples/events-stdin-input.mjs b/js/examples/events-stdin-input.mjs similarity index 100% rename from examples/events-stdin-input.mjs rename to js/examples/events-stdin-input.mjs diff --git a/examples/example-ansi-ls.mjs b/js/examples/example-ansi-ls.mjs similarity index 100% rename from examples/example-ansi-ls.mjs rename to js/examples/example-ansi-ls.mjs diff --git a/examples/example-top.mjs b/js/examples/example-top.mjs similarity index 100% rename from examples/example-top.mjs rename to js/examples/example-top.mjs diff --git a/examples/final-ping-stdin-proof.mjs b/js/examples/final-ping-stdin-proof.mjs similarity index 100% rename from examples/final-ping-stdin-proof.mjs rename to js/examples/final-ping-stdin-proof.mjs diff --git a/examples/final-test-shell-operators.mjs b/js/examples/final-test-shell-operators.mjs similarity index 100% rename from examples/final-test-shell-operators.mjs rename to js/examples/final-test-shell-operators.mjs diff --git a/examples/final-working-examples.mjs b/js/examples/final-working-examples.mjs similarity index 100% rename from examples/final-working-examples.mjs rename to js/examples/final-working-examples.mjs diff --git a/examples/gh-auth-test.mjs b/js/examples/gh-auth-test.mjs similarity index 100% rename from examples/gh-auth-test.mjs rename to js/examples/gh-auth-test.mjs diff --git a/examples/gh-delete-hang-test.mjs b/js/examples/gh-delete-hang-test.mjs similarity index 100% rename from examples/gh-delete-hang-test.mjs rename to js/examples/gh-delete-hang-test.mjs diff --git a/examples/gh-gist-creation-test.mjs b/js/examples/gh-gist-creation-test.mjs similarity index 100% rename from examples/gh-gist-creation-test.mjs rename to js/examples/gh-gist-creation-test.mjs diff --git a/examples/gh-gist-minimal-test.mjs b/js/examples/gh-gist-minimal-test.mjs similarity index 100% rename from examples/gh-gist-minimal-test.mjs rename to js/examples/gh-gist-minimal-test.mjs diff --git a/examples/gh-hang-exact-original.mjs b/js/examples/gh-hang-exact-original.mjs similarity index 100% rename from examples/gh-hang-exact-original.mjs rename to js/examples/gh-hang-exact-original.mjs diff --git a/examples/gh-hang-reproduction.mjs b/js/examples/gh-hang-reproduction.mjs similarity index 100% rename from examples/gh-hang-reproduction.mjs rename to js/examples/gh-hang-reproduction.mjs diff --git a/examples/gh-hang-test-with-redirect.mjs b/js/examples/gh-hang-test-with-redirect.mjs similarity index 100% rename from examples/gh-hang-test-with-redirect.mjs rename to js/examples/gh-hang-test-with-redirect.mjs diff --git a/examples/gh-hang-test-without-redirect.mjs b/js/examples/gh-hang-test-without-redirect.mjs similarity index 100% rename from examples/gh-hang-test-without-redirect.mjs rename to js/examples/gh-hang-test-without-redirect.mjs diff --git a/examples/gh-minimal-hang-check.mjs b/js/examples/gh-minimal-hang-check.mjs similarity index 100% rename from examples/gh-minimal-hang-check.mjs rename to js/examples/gh-minimal-hang-check.mjs diff --git a/examples/gh-operations-with-cd.mjs b/js/examples/gh-operations-with-cd.mjs similarity index 100% rename from examples/gh-operations-with-cd.mjs rename to js/examples/gh-operations-with-cd.mjs diff --git a/examples/gh-output-test.mjs b/js/examples/gh-output-test.mjs similarity index 100% rename from examples/gh-output-test.mjs rename to js/examples/gh-output-test.mjs diff --git a/examples/gh-reproduce-hang.mjs b/js/examples/gh-reproduce-hang.mjs similarity index 100% rename from examples/gh-reproduce-hang.mjs rename to js/examples/gh-reproduce-hang.mjs diff --git a/examples/git-operations-with-cd.mjs b/js/examples/git-operations-with-cd.mjs similarity index 100% rename from examples/git-operations-with-cd.mjs rename to js/examples/git-operations-with-cd.mjs diff --git a/examples/interactive-math-calc.mjs b/js/examples/interactive-math-calc.mjs similarity index 100% rename from examples/interactive-math-calc.mjs rename to js/examples/interactive-math-calc.mjs diff --git a/examples/interactive-top-fixed.mjs b/js/examples/interactive-top-fixed.mjs similarity index 100% rename from examples/interactive-top-fixed.mjs rename to js/examples/interactive-top-fixed.mjs diff --git a/examples/interactive-top-improved.mjs b/js/examples/interactive-top-improved.mjs similarity index 100% rename from examples/interactive-top-improved.mjs rename to js/examples/interactive-top-improved.mjs diff --git a/examples/interactive-top-pty-logging.mjs b/js/examples/interactive-top-pty-logging.mjs similarity index 100% rename from examples/interactive-top-pty-logging.mjs rename to js/examples/interactive-top-pty-logging.mjs diff --git a/examples/interactive-top-pty.mjs b/js/examples/interactive-top-pty.mjs similarity index 100% rename from examples/interactive-top-pty.mjs rename to js/examples/interactive-top-pty.mjs diff --git a/examples/interactive-top-with-logging.mjs b/js/examples/interactive-top-with-logging.mjs similarity index 100% rename from examples/interactive-top-with-logging.mjs rename to js/examples/interactive-top-with-logging.mjs diff --git a/examples/interactive-top.mjs b/js/examples/interactive-top.mjs similarity index 100% rename from examples/interactive-top.mjs rename to js/examples/interactive-top.mjs diff --git a/examples/jq-color-demo.mjs b/js/examples/jq-color-demo.mjs similarity index 100% rename from examples/jq-color-demo.mjs rename to js/examples/jq-color-demo.mjs diff --git a/examples/jq-colors-streaming.mjs b/js/examples/jq-colors-streaming.mjs similarity index 100% rename from examples/jq-colors-streaming.mjs rename to js/examples/jq-colors-streaming.mjs diff --git a/examples/manual-ctrl-c-test.mjs b/js/examples/manual-ctrl-c-test.mjs similarity index 100% rename from examples/manual-ctrl-c-test.mjs rename to js/examples/manual-ctrl-c-test.mjs diff --git a/examples/methods-multiple-options.mjs b/js/examples/methods-multiple-options.mjs similarity index 100% rename from examples/methods-multiple-options.mjs rename to js/examples/methods-multiple-options.mjs diff --git a/examples/methods-run-basic.mjs b/js/examples/methods-run-basic.mjs similarity index 100% rename from examples/methods-run-basic.mjs rename to js/examples/methods-run-basic.mjs diff --git a/examples/methods-start-basic.mjs b/js/examples/methods-start-basic.mjs similarity index 100% rename from examples/methods-start-basic.mjs rename to js/examples/methods-start-basic.mjs diff --git a/examples/node-compat-data-events.mjs b/js/examples/node-compat-data-events.mjs similarity index 90% rename from examples/node-compat-data-events.mjs rename to js/examples/node-compat-data-events.mjs index 1458eea..b3f17a9 100755 --- a/examples/node-compat-data-events.mjs +++ b/js/examples/node-compat-data-events.mjs @@ -9,7 +9,7 @@ console.log('Node.js spawn with on("data") events:'); const start = Date.now(); let chunkCount = 0; -const proc1 = spawn('bun', ['run', 'examples/emulate-claude-stream.mjs']); +const proc1 = spawn('bun', ['run', 'js/examples/emulate-claude-stream.mjs']); const proc2 = spawn('jq', ['.'], { stdio: ['pipe', 'pipe', 'pipe'], }); diff --git a/examples/node-compat-readable-event.mjs b/js/examples/node-compat-readable-event.mjs similarity index 88% rename from examples/node-compat-readable-event.mjs rename to js/examples/node-compat-readable-event.mjs index 075bedf..747999a 100755 --- a/examples/node-compat-readable-event.mjs +++ b/js/examples/node-compat-readable-event.mjs @@ -9,7 +9,7 @@ console.log('Using readable event:'); const start = Date.now(); let chunkCount = 0; -const proc1 = spawn('bun', ['run', 'examples/emulate-claude-stream.mjs']); +const proc1 = spawn('bun', ['run', 'js/examples/emulate-claude-stream.mjs']); const proc2 = spawn('jq', ['.'], { stdio: ['pipe', 'pipe', 'pipe'], }); diff --git a/examples/node-compat-small-buffer.mjs b/js/examples/node-compat-small-buffer.mjs similarity index 90% rename from examples/node-compat-small-buffer.mjs rename to js/examples/node-compat-small-buffer.mjs index 204ad5d..53fb931 100755 --- a/examples/node-compat-small-buffer.mjs +++ b/js/examples/node-compat-small-buffer.mjs @@ -9,7 +9,7 @@ console.log('Reading with small buffer size:'); const start = Date.now(); let chunkCount = 0; -const proc1 = spawn('bun', ['run', 'examples/emulate-claude-stream.mjs']); +const proc1 = spawn('bun', ['run', 'js/examples/emulate-claude-stream.mjs']); const proc2 = spawn('jq', ['.'], { stdio: ['pipe', 'pipe', 'pipe'], }); diff --git a/examples/options-capture-false.mjs b/js/examples/options-capture-false.mjs similarity index 100% rename from examples/options-capture-false.mjs rename to js/examples/options-capture-false.mjs diff --git a/examples/options-combined-settings.mjs b/js/examples/options-combined-settings.mjs similarity index 100% rename from examples/options-combined-settings.mjs rename to js/examples/options-combined-settings.mjs diff --git a/examples/options-custom-input.mjs b/js/examples/options-custom-input.mjs similarity index 100% rename from examples/options-custom-input.mjs rename to js/examples/options-custom-input.mjs diff --git a/examples/options-default-behavior.mjs b/js/examples/options-default-behavior.mjs similarity index 100% rename from examples/options-default-behavior.mjs rename to js/examples/options-default-behavior.mjs diff --git a/examples/options-maximum-performance.mjs b/js/examples/options-maximum-performance.mjs similarity index 100% rename from examples/options-maximum-performance.mjs rename to js/examples/options-maximum-performance.mjs diff --git a/examples/options-mirror-false.mjs b/js/examples/options-mirror-false.mjs similarity index 100% rename from examples/options-mirror-false.mjs rename to js/examples/options-mirror-false.mjs diff --git a/examples/options-performance-mode.mjs b/js/examples/options-performance-mode.mjs similarity index 100% rename from examples/options-performance-mode.mjs rename to js/examples/options-performance-mode.mjs diff --git a/examples/options-performance-optimization.mjs b/js/examples/options-performance-optimization.mjs similarity index 100% rename from examples/options-performance-optimization.mjs rename to js/examples/options-performance-optimization.mjs diff --git a/examples/options-run-alias-demo.mjs b/js/examples/options-run-alias-demo.mjs similarity index 100% rename from examples/options-run-alias-demo.mjs rename to js/examples/options-run-alias-demo.mjs diff --git a/examples/options-run-alias.mjs b/js/examples/options-run-alias.mjs similarity index 100% rename from examples/options-run-alias.mjs rename to js/examples/options-run-alias.mjs diff --git a/examples/options-silent-execution.mjs b/js/examples/options-silent-execution.mjs similarity index 100% rename from examples/options-silent-execution.mjs rename to js/examples/options-silent-execution.mjs diff --git a/examples/options-streaming-capture.mjs b/js/examples/options-streaming-capture.mjs similarity index 100% rename from examples/options-streaming-capture.mjs rename to js/examples/options-streaming-capture.mjs diff --git a/examples/options-streaming-multiple.mjs b/js/examples/options-streaming-multiple.mjs similarity index 100% rename from examples/options-streaming-multiple.mjs rename to js/examples/options-streaming-multiple.mjs diff --git a/examples/options-streaming-silent.mjs b/js/examples/options-streaming-silent.mjs similarity index 100% rename from examples/options-streaming-silent.mjs rename to js/examples/options-streaming-silent.mjs diff --git a/examples/options-streaming-stdin.mjs b/js/examples/options-streaming-stdin.mjs similarity index 100% rename from examples/options-streaming-stdin.mjs rename to js/examples/options-streaming-stdin.mjs diff --git a/examples/ping-streaming-filtered.mjs b/js/examples/ping-streaming-filtered.mjs similarity index 100% rename from examples/ping-streaming-filtered.mjs rename to js/examples/ping-streaming-filtered.mjs diff --git a/examples/ping-streaming-interruptible.mjs b/js/examples/ping-streaming-interruptible.mjs similarity index 100% rename from examples/ping-streaming-interruptible.mjs rename to js/examples/ping-streaming-interruptible.mjs diff --git a/examples/ping-streaming-silent.mjs b/js/examples/ping-streaming-silent.mjs similarity index 100% rename from examples/ping-streaming-silent.mjs rename to js/examples/ping-streaming-silent.mjs diff --git a/examples/ping-streaming-simple.mjs b/js/examples/ping-streaming-simple.mjs similarity index 100% rename from examples/ping-streaming-simple.mjs rename to js/examples/ping-streaming-simple.mjs diff --git a/examples/ping-streaming-statistics.mjs b/js/examples/ping-streaming-statistics.mjs similarity index 100% rename from examples/ping-streaming-statistics.mjs rename to js/examples/ping-streaming-statistics.mjs diff --git a/examples/ping-streaming-timestamps.mjs b/js/examples/ping-streaming-timestamps.mjs similarity index 100% rename from examples/ping-streaming-timestamps.mjs rename to js/examples/ping-streaming-timestamps.mjs diff --git a/examples/ping-streaming.mjs b/js/examples/ping-streaming.mjs similarity index 100% rename from examples/ping-streaming.mjs rename to js/examples/ping-streaming.mjs diff --git a/examples/prove-ping-stdin-limitation.mjs b/js/examples/prove-ping-stdin-limitation.mjs similarity index 100% rename from examples/prove-ping-stdin-limitation.mjs rename to js/examples/prove-ping-stdin-limitation.mjs diff --git a/examples/readme-example.mjs b/js/examples/readme-example.mjs similarity index 100% rename from examples/readme-example.mjs rename to js/examples/readme-example.mjs diff --git a/examples/realtime-json-stream.mjs b/js/examples/realtime-json-stream.mjs similarity index 100% rename from examples/realtime-json-stream.mjs rename to js/examples/realtime-json-stream.mjs diff --git a/examples/reliable-stdin-commands.mjs b/js/examples/reliable-stdin-commands.mjs similarity index 100% rename from examples/reliable-stdin-commands.mjs rename to js/examples/reliable-stdin-commands.mjs diff --git a/examples/reproduce-issue-135-v2.mjs b/js/examples/reproduce-issue-135-v2.mjs similarity index 100% rename from examples/reproduce-issue-135-v2.mjs rename to js/examples/reproduce-issue-135-v2.mjs diff --git a/examples/reproduce-issue-135.mjs b/js/examples/reproduce-issue-135.mjs similarity index 100% rename from examples/reproduce-issue-135.mjs rename to js/examples/reproduce-issue-135.mjs diff --git a/examples/shell-cd-behavior.mjs b/js/examples/shell-cd-behavior.mjs similarity index 100% rename from examples/shell-cd-behavior.mjs rename to js/examples/shell-cd-behavior.mjs diff --git a/examples/sigint-forwarding-test.mjs b/js/examples/sigint-forwarding-test.mjs similarity index 100% rename from examples/sigint-forwarding-test.mjs rename to js/examples/sigint-forwarding-test.mjs diff --git a/examples/sigint-handler-test.mjs b/js/examples/sigint-handler-test.mjs similarity index 100% rename from examples/sigint-handler-test.mjs rename to js/examples/sigint-handler-test.mjs diff --git a/examples/simple-async-test.mjs b/js/examples/simple-async-test.mjs similarity index 100% rename from examples/simple-async-test.mjs rename to js/examples/simple-async-test.mjs diff --git a/examples/simple-claude-test.mjs b/js/examples/simple-claude-test.mjs similarity index 100% rename from examples/simple-claude-test.mjs rename to js/examples/simple-claude-test.mjs diff --git a/examples/simple-event-test.mjs b/js/examples/simple-event-test.mjs similarity index 100% rename from examples/simple-event-test.mjs rename to js/examples/simple-event-test.mjs diff --git a/examples/simple-jq-streaming.mjs b/js/examples/simple-jq-streaming.mjs similarity index 100% rename from examples/simple-jq-streaming.mjs rename to js/examples/simple-jq-streaming.mjs diff --git a/examples/simple-stream-demo.mjs b/js/examples/simple-stream-demo.mjs similarity index 100% rename from examples/simple-stream-demo.mjs rename to js/examples/simple-stream-demo.mjs diff --git a/examples/simple-test-sleep.js b/js/examples/simple-test-sleep.js similarity index 100% rename from examples/simple-test-sleep.js rename to js/examples/simple-test-sleep.js diff --git a/examples/simple-working-stdin.mjs b/js/examples/simple-working-stdin.mjs similarity index 100% rename from examples/simple-working-stdin.mjs rename to js/examples/simple-working-stdin.mjs diff --git a/examples/streaming-behavior-test.mjs b/js/examples/streaming-behavior-test.mjs similarity index 100% rename from examples/streaming-behavior-test.mjs rename to js/examples/streaming-behavior-test.mjs diff --git a/examples/streaming-direct-command.mjs b/js/examples/streaming-direct-command.mjs similarity index 85% rename from examples/streaming-direct-command.mjs rename to js/examples/streaming-direct-command.mjs index 95294ec..cb29011 100755 --- a/examples/streaming-direct-command.mjs +++ b/js/examples/streaming-direct-command.mjs @@ -8,7 +8,7 @@ console.log('Direct command streaming test:'); const start = Date.now(); let chunkCount = 0; -for await (const chunk of $`bun run examples/emulate-claude-stream.mjs`.stream()) { +for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs`.stream()) { if (chunk.type === 'stdout') { chunkCount++; const elapsed = Date.now() - start; diff --git a/examples/streaming-filtered-output.mjs b/js/examples/streaming-filtered-output.mjs similarity index 100% rename from examples/streaming-filtered-output.mjs rename to js/examples/streaming-filtered-output.mjs diff --git a/examples/streaming-grep-pipeline.mjs b/js/examples/streaming-grep-pipeline.mjs similarity index 82% rename from examples/streaming-grep-pipeline.mjs rename to js/examples/streaming-grep-pipeline.mjs index 165b5f4..a62bb67 100755 --- a/examples/streaming-grep-pipeline.mjs +++ b/js/examples/streaming-grep-pipeline.mjs @@ -8,7 +8,7 @@ console.log('grep pipeline streaming test:'); const start = Date.now(); let chunkCount = 0; -for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | grep -E '"type"'`.stream()) { +for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | grep -E '"type"'`.stream()) { if (chunk.type === 'stdout') { chunkCount++; const elapsed = Date.now() - start; diff --git a/examples/streaming-interactive-stdin.mjs b/js/examples/streaming-interactive-stdin.mjs similarity index 100% rename from examples/streaming-interactive-stdin.mjs rename to js/examples/streaming-interactive-stdin.mjs diff --git a/examples/streaming-jq-pipeline.mjs b/js/examples/streaming-jq-pipeline.mjs similarity index 84% rename from examples/streaming-jq-pipeline.mjs rename to js/examples/streaming-jq-pipeline.mjs index de36774..7982575 100755 --- a/examples/streaming-jq-pipeline.mjs +++ b/js/examples/streaming-jq-pipeline.mjs @@ -8,7 +8,7 @@ console.log('jq pipeline streaming test:'); const start = Date.now(); let chunkCount = 0; -for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | jq .`.stream()) { +for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | jq .`.stream()) { if (chunk.type === 'stdout') { chunkCount++; const elapsed = Date.now() - start; diff --git a/examples/streaming-multistage-pipeline.mjs b/js/examples/streaming-multistage-pipeline.mjs similarity index 84% rename from examples/streaming-multistage-pipeline.mjs rename to js/examples/streaming-multistage-pipeline.mjs index a944f4e..2a90b88 100755 --- a/examples/streaming-multistage-pipeline.mjs +++ b/js/examples/streaming-multistage-pipeline.mjs @@ -8,7 +8,7 @@ console.log('Multi-stage pipeline streaming test:'); const start = Date.now(); let chunkCount = 0; -for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | cat | jq .`.stream()) { +for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | cat | jq .`.stream()) { if (chunk.type === 'stdout') { chunkCount++; const elapsed = Date.now() - start; diff --git a/examples/streaming-pipes-event-pattern.mjs b/js/examples/streaming-pipes-event-pattern.mjs similarity index 100% rename from examples/streaming-pipes-event-pattern.mjs rename to js/examples/streaming-pipes-event-pattern.mjs diff --git a/examples/streaming-pipes-multistage.mjs b/js/examples/streaming-pipes-multistage.mjs similarity index 100% rename from examples/streaming-pipes-multistage.mjs rename to js/examples/streaming-pipes-multistage.mjs diff --git a/examples/streaming-pipes-realtime-jq.mjs b/js/examples/streaming-pipes-realtime-jq.mjs similarity index 100% rename from examples/streaming-pipes-realtime-jq.mjs rename to js/examples/streaming-pipes-realtime-jq.mjs diff --git a/examples/streaming-progress-tracking.mjs b/js/examples/streaming-progress-tracking.mjs similarity index 100% rename from examples/streaming-progress-tracking.mjs rename to js/examples/streaming-progress-tracking.mjs diff --git a/examples/streaming-reusable-configs.mjs b/js/examples/streaming-reusable-configs.mjs similarity index 100% rename from examples/streaming-reusable-configs.mjs rename to js/examples/streaming-reusable-configs.mjs diff --git a/examples/streaming-silent-capture.mjs b/js/examples/streaming-silent-capture.mjs similarity index 100% rename from examples/streaming-silent-capture.mjs rename to js/examples/streaming-silent-capture.mjs diff --git a/examples/streaming-test-simple.mjs b/js/examples/streaming-test-simple.mjs similarity index 100% rename from examples/streaming-test-simple.mjs rename to js/examples/streaming-test-simple.mjs diff --git a/examples/streaming-virtual-pipeline.mjs b/js/examples/streaming-virtual-pipeline.mjs similarity index 100% rename from examples/streaming-virtual-pipeline.mjs rename to js/examples/streaming-virtual-pipeline.mjs diff --git a/examples/syntax-basic-comparison.mjs b/js/examples/syntax-basic-comparison.mjs similarity index 100% rename from examples/syntax-basic-comparison.mjs rename to js/examples/syntax-basic-comparison.mjs diff --git a/examples/syntax-basic-options.mjs b/js/examples/syntax-basic-options.mjs similarity index 100% rename from examples/syntax-basic-options.mjs rename to js/examples/syntax-basic-options.mjs diff --git a/examples/syntax-combined-options.mjs b/js/examples/syntax-combined-options.mjs similarity index 100% rename from examples/syntax-combined-options.mjs rename to js/examples/syntax-combined-options.mjs diff --git a/examples/syntax-command-chaining.mjs b/js/examples/syntax-command-chaining.mjs similarity index 100% rename from examples/syntax-command-chaining.mjs rename to js/examples/syntax-command-chaining.mjs diff --git a/examples/syntax-custom-directory.mjs b/js/examples/syntax-custom-directory.mjs similarity index 100% rename from examples/syntax-custom-directory.mjs rename to js/examples/syntax-custom-directory.mjs diff --git a/examples/syntax-custom-environment.mjs b/js/examples/syntax-custom-environment.mjs similarity index 100% rename from examples/syntax-custom-environment.mjs rename to js/examples/syntax-custom-environment.mjs diff --git a/examples/syntax-custom-stdin.mjs b/js/examples/syntax-custom-stdin.mjs similarity index 100% rename from examples/syntax-custom-stdin.mjs rename to js/examples/syntax-custom-stdin.mjs diff --git a/examples/syntax-mixed-regular.mjs b/js/examples/syntax-mixed-regular.mjs similarity index 100% rename from examples/syntax-mixed-regular.mjs rename to js/examples/syntax-mixed-regular.mjs diff --git a/examples/syntax-mixed-usage.mjs b/js/examples/syntax-mixed-usage.mjs similarity index 100% rename from examples/syntax-mixed-usage.mjs rename to js/examples/syntax-mixed-usage.mjs diff --git a/examples/syntax-multiple-listeners.mjs b/js/examples/syntax-multiple-listeners.mjs similarity index 100% rename from examples/syntax-multiple-listeners.mjs rename to js/examples/syntax-multiple-listeners.mjs diff --git a/examples/syntax-piping-comparison.mjs b/js/examples/syntax-piping-comparison.mjs similarity index 100% rename from examples/syntax-piping-comparison.mjs rename to js/examples/syntax-piping-comparison.mjs diff --git a/examples/syntax-reusable-config.mjs b/js/examples/syntax-reusable-config.mjs similarity index 100% rename from examples/syntax-reusable-config.mjs rename to js/examples/syntax-reusable-config.mjs diff --git a/examples/syntax-reusable-configs.mjs b/js/examples/syntax-reusable-configs.mjs similarity index 100% rename from examples/syntax-reusable-configs.mjs rename to js/examples/syntax-reusable-configs.mjs diff --git a/examples/syntax-silent-operations.mjs b/js/examples/syntax-silent-operations.mjs similarity index 100% rename from examples/syntax-silent-operations.mjs rename to js/examples/syntax-silent-operations.mjs diff --git a/examples/syntax-stdin-option.mjs b/js/examples/syntax-stdin-option.mjs similarity index 100% rename from examples/syntax-stdin-option.mjs rename to js/examples/syntax-stdin-option.mjs diff --git a/examples/temp-sigint-test.mjs b/js/examples/temp-sigint-test.mjs similarity index 100% rename from examples/temp-sigint-test.mjs rename to js/examples/temp-sigint-test.mjs diff --git a/examples/test-actual-buildshell.mjs b/js/examples/test-actual-buildshell.mjs similarity index 100% rename from examples/test-actual-buildshell.mjs rename to js/examples/test-actual-buildshell.mjs diff --git a/examples/test-async-streams-working.mjs b/js/examples/test-async-streams-working.mjs similarity index 100% rename from examples/test-async-streams-working.mjs rename to js/examples/test-async-streams-working.mjs diff --git a/examples/test-async-streams.mjs b/js/examples/test-async-streams.mjs similarity index 100% rename from examples/test-async-streams.mjs rename to js/examples/test-async-streams.mjs diff --git a/examples/test-auth-parse.mjs b/js/examples/test-auth-parse.mjs similarity index 100% rename from examples/test-auth-parse.mjs rename to js/examples/test-auth-parse.mjs diff --git a/examples/test-auto-quoting.mjs b/js/examples/test-auto-quoting.mjs similarity index 100% rename from examples/test-auto-quoting.mjs rename to js/examples/test-auto-quoting.mjs diff --git a/examples/test-auto-start-fix.mjs b/js/examples/test-auto-start-fix.mjs similarity index 100% rename from examples/test-auto-start-fix.mjs rename to js/examples/test-auto-start-fix.mjs diff --git a/examples/test-baseline-sigint.mjs b/js/examples/test-baseline-sigint.mjs similarity index 100% rename from examples/test-baseline-sigint.mjs rename to js/examples/test-baseline-sigint.mjs diff --git a/examples/test-buffer-behavior.mjs b/js/examples/test-buffer-behavior.mjs similarity index 100% rename from examples/test-buffer-behavior.mjs rename to js/examples/test-buffer-behavior.mjs diff --git a/examples/test-buffers-simple.mjs b/js/examples/test-buffers-simple.mjs similarity index 100% rename from examples/test-buffers-simple.mjs rename to js/examples/test-buffers-simple.mjs diff --git a/examples/test-bun-specific-issue.mjs b/js/examples/test-bun-specific-issue.mjs similarity index 100% rename from examples/test-bun-specific-issue.mjs rename to js/examples/test-bun-specific-issue.mjs diff --git a/examples/test-bun-streaming.mjs b/js/examples/test-bun-streaming.mjs similarity index 92% rename from examples/test-bun-streaming.mjs rename to js/examples/test-bun-streaming.mjs index c095cfd..c5db5f7 100755 --- a/examples/test-bun-streaming.mjs +++ b/js/examples/test-bun-streaming.mjs @@ -22,7 +22,7 @@ for await (const chunk of proc1.stdout) { console.log('\nTest 2: Command with jq pipeline'); const proc2 = Bun.spawn( - ['sh', '-c', './examples/emulate-claude-stream.mjs | jq .'], + ['sh', '-c', './js/examples/emulate-claude-stream.mjs | jq .'], { stdout: 'pipe', stderr: 'pipe', @@ -47,7 +47,7 @@ for await (const chunk of proc2.stdout) { console.log('\nTest 3: Read stdout using different method'); const proc3 = Bun.spawn( - ['sh', '-c', './examples/emulate-claude-stream.mjs | jq .'], + ['sh', '-c', './js/examples/emulate-claude-stream.mjs | jq .'], { stdout: 'pipe', stderr: 'pipe', diff --git a/examples/test-cat-direct.mjs b/js/examples/test-cat-direct.mjs similarity index 84% rename from examples/test-cat-direct.mjs rename to js/examples/test-cat-direct.mjs index aed2787..d92e345 100755 --- a/examples/test-cat-direct.mjs +++ b/js/examples/test-cat-direct.mjs @@ -3,10 +3,13 @@ console.log('=== Test cat | jq directly ===\n'); // Direct Bun test -const proc1 = Bun.spawn(['bun', 'run', 'examples/emulate-claude-stream.mjs'], { - stdout: 'pipe', - stderr: 'pipe', -}); +const proc1 = Bun.spawn( + ['bun', 'run', 'js/examples/emulate-claude-stream.mjs'], + { + stdout: 'pipe', + stderr: 'pipe', + } +); const proc2 = Bun.spawn(['cat'], { stdin: proc1.stdout, diff --git a/examples/test-cat-pipe.mjs b/js/examples/test-cat-pipe.mjs similarity index 90% rename from examples/test-cat-pipe.mjs rename to js/examples/test-cat-pipe.mjs index e0ea6fe..14af4ba 100755 --- a/examples/test-cat-pipe.mjs +++ b/js/examples/test-cat-pipe.mjs @@ -5,7 +5,7 @@ console.log('Test: Piping through cat (should not buffer)\n'); // First process: emulator -const proc1 = Bun.spawn(['./examples/emulate-claude-stream.mjs'], { +const proc1 = Bun.spawn(['./js/examples/emulate-claude-stream.mjs'], { stdout: 'pipe', stderr: 'pipe', }); diff --git a/examples/test-cd-behavior.mjs b/js/examples/test-cd-behavior.mjs similarity index 100% rename from examples/test-cd-behavior.mjs rename to js/examples/test-cd-behavior.mjs diff --git a/examples/test-child-process-timing.mjs b/js/examples/test-child-process-timing.mjs similarity index 100% rename from examples/test-child-process-timing.mjs rename to js/examples/test-child-process-timing.mjs diff --git a/examples/test-child-sigint-handler.mjs b/js/examples/test-child-sigint-handler.mjs similarity index 100% rename from examples/test-child-sigint-handler.mjs rename to js/examples/test-child-sigint-handler.mjs diff --git a/examples/test-cleanup-simple.mjs b/js/examples/test-cleanup-simple.mjs similarity index 100% rename from examples/test-cleanup-simple.mjs rename to js/examples/test-cleanup-simple.mjs diff --git a/examples/test-comprehensive-tracing.mjs b/js/examples/test-comprehensive-tracing.mjs similarity index 74% rename from examples/test-comprehensive-tracing.mjs rename to js/examples/test-comprehensive-tracing.mjs index 64fa046..74cb6ef 100755 --- a/examples/test-comprehensive-tracing.mjs +++ b/js/examples/test-comprehensive-tracing.mjs @@ -15,7 +15,7 @@ * - trace-error-handling.mjs - Error conditions and cleanup * * Usage for any example: - * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-[example-name].mjs + * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-[example-name].mjs * * For CI debugging, enable tracing in your test runs: * COMMAND_STREAM_TRACE=ProcessRunner bun test @@ -36,22 +36,22 @@ console.log(''); console.log('Run individual examples to test specific areas:'); console.log(''); console.log( - 'COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-simple-command.mjs' + 'COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-simple-command.mjs' ); console.log( - 'COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-signal-handling.mjs' + 'COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-signal-handling.mjs' ); console.log( - 'COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-abort-controller.mjs' + 'COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-abort-controller.mjs' ); console.log( - 'COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-stderr-output.mjs' + 'COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-stderr-output.mjs' ); console.log( - 'COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-pipeline-command.mjs' + 'COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-pipeline-command.mjs' ); console.log( - 'COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-error-handling.mjs' + 'COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-error-handling.mjs' ); console.log(''); console.log('๐Ÿ’ก Use COMMAND_STREAM_TRACE=* to see all tracing categories'); diff --git a/examples/test-correct-space-handling.mjs b/js/examples/test-correct-space-handling.mjs similarity index 100% rename from examples/test-correct-space-handling.mjs rename to js/examples/test-correct-space-handling.mjs diff --git a/examples/test-ctrl-c-debug.mjs b/js/examples/test-ctrl-c-debug.mjs similarity index 100% rename from examples/test-ctrl-c-debug.mjs rename to js/examples/test-ctrl-c-debug.mjs diff --git a/examples/test-ctrl-c-inherit.mjs b/js/examples/test-ctrl-c-inherit.mjs similarity index 100% rename from examples/test-ctrl-c-inherit.mjs rename to js/examples/test-ctrl-c-inherit.mjs diff --git a/examples/test-ctrl-c-sleep.mjs b/js/examples/test-ctrl-c-sleep.mjs similarity index 100% rename from examples/test-ctrl-c-sleep.mjs rename to js/examples/test-ctrl-c-sleep.mjs diff --git a/examples/test-ctrl-c.mjs b/js/examples/test-ctrl-c.mjs similarity index 100% rename from examples/test-ctrl-c.mjs rename to js/examples/test-ctrl-c.mjs diff --git a/examples/test-debug-new-options.mjs b/js/examples/test-debug-new-options.mjs similarity index 100% rename from examples/test-debug-new-options.mjs rename to js/examples/test-debug-new-options.mjs diff --git a/examples/test-debug-pty.mjs b/js/examples/test-debug-pty.mjs similarity index 89% rename from examples/test-debug-pty.mjs rename to js/examples/test-debug-pty.mjs index 5bbac11..3227996 100755 --- a/examples/test-debug-pty.mjs +++ b/js/examples/test-debug-pty.mjs @@ -30,7 +30,7 @@ console.log('Testing pipeline routing:\n'); // Test with actual file to avoid shell wrapper console.log('Test 1: Using actual file command:'); const start = Date.now(); -for await (const chunk of $`./examples/emulate-claude-stream.mjs | jq .`.stream()) { +for await (const chunk of $`./js/examples/emulate-claude-stream.mjs | jq .`.stream()) { if (chunk.type === 'stdout') { const elapsed = Date.now() - start; const lines = chunk.data.toString().trim().split('\n').slice(0, 2); @@ -40,7 +40,7 @@ for await (const chunk of $`./examples/emulate-claude-stream.mjs | jq .`.stream( console.log('\nTest 2: Using bun run:'); const start2 = Date.now(); -for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | jq .`.stream()) { +for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | jq .`.stream()) { if (chunk.type === 'stdout') { const elapsed = Date.now() - start2; const lines = chunk.data.toString().trim().split('\n').slice(0, 2); diff --git a/examples/test-debug-tee.mjs b/js/examples/test-debug-tee.mjs similarity index 93% rename from examples/test-debug-tee.mjs rename to js/examples/test-debug-tee.mjs index 7fa4b7a..1d99a01 100755 --- a/examples/test-debug-tee.mjs +++ b/js/examples/test-debug-tee.mjs @@ -5,7 +5,7 @@ import { $ } from '../js/src/$.mjs'; console.log('=== Debug Tee Streaming ===\n'); // Patch the emit function to trace calls -const cmd = $`bun run examples/emulate-claude-stream.mjs | cat | jq .`; +const cmd = $`bun run js/examples/emulate-claude-stream.mjs | cat | jq .`; const originalEmit = cmd.emit.bind(cmd); let emitCount = 0; diff --git a/examples/test-debug.mjs b/js/examples/test-debug.mjs similarity index 100% rename from examples/test-debug.mjs rename to js/examples/test-debug.mjs diff --git a/examples/test-direct-jq.mjs b/js/examples/test-direct-jq.mjs similarity index 93% rename from examples/test-direct-jq.mjs rename to js/examples/test-direct-jq.mjs index ac28cf0..0ba41e4 100755 --- a/examples/test-direct-jq.mjs +++ b/js/examples/test-direct-jq.mjs @@ -5,7 +5,7 @@ console.log('Test: Spawn processes directly and pipe them\n'); // First process: emulator -const proc1 = Bun.spawn(['./examples/emulate-claude-stream.mjs'], { +const proc1 = Bun.spawn(['./js/examples/emulate-claude-stream.mjs'], { stdout: 'pipe', stderr: 'pipe', }); diff --git a/examples/test-direct-pipe-reading.mjs b/js/examples/test-direct-pipe-reading.mjs similarity index 90% rename from examples/test-direct-pipe-reading.mjs rename to js/examples/test-direct-pipe-reading.mjs index 2db1964..61fea00 100755 --- a/examples/test-direct-pipe-reading.mjs +++ b/js/examples/test-direct-pipe-reading.mjs @@ -8,7 +8,7 @@ console.log('=== Testing Direct Pipe Reading Methods ===\n'); console.log('Method 1: Manual pipe connection with for await:'); { const proc1 = Bun.spawn( - ['bun', 'run', 'examples/emulate-claude-stream.mjs'], + ['bun', 'run', 'js/examples/emulate-claude-stream.mjs'], { stdout: 'pipe', stderr: 'pipe', @@ -39,7 +39,7 @@ console.log('Method 1: Manual pipe connection with for await:'); console.log('\nMethod 2: Read from first process while piped:'); { const proc1 = Bun.spawn( - ['bun', 'run', 'examples/emulate-claude-stream.mjs'], + ['bun', 'run', 'js/examples/emulate-claude-stream.mjs'], { stdout: 'pipe', stderr: 'pipe', @@ -64,7 +64,7 @@ console.log('\nMethod 2: Read from first process while piped:'); console.log('\nMethod 3: Using tee() to split stream:'); { const proc1 = Bun.spawn( - ['bun', 'run', 'examples/emulate-claude-stream.mjs'], + ['bun', 'run', 'js/examples/emulate-claude-stream.mjs'], { stdout: 'pipe', stderr: 'pipe', @@ -99,7 +99,7 @@ console.log('\nMethod 3: Using tee() to split stream:'); console.log('\nMethod 4: Full pipeline as single command:'); { const proc = Bun.spawn( - ['sh', '-c', 'bun run examples/emulate-claude-stream.mjs | jq .'], + ['sh', '-c', 'bun run js/examples/emulate-claude-stream.mjs | jq .'], { stdout: 'pipe', stderr: 'pipe', diff --git a/examples/test-direct-pipe.sh b/js/examples/test-direct-pipe.sh similarity index 100% rename from examples/test-direct-pipe.sh rename to js/examples/test-direct-pipe.sh diff --git a/examples/test-double-quoting-prevention.mjs b/js/examples/test-double-quoting-prevention.mjs similarity index 100% rename from examples/test-double-quoting-prevention.mjs rename to js/examples/test-double-quoting-prevention.mjs diff --git a/examples/test-edge-cases-quoting.mjs b/js/examples/test-edge-cases-quoting.mjs similarity index 100% rename from examples/test-edge-cases-quoting.mjs rename to js/examples/test-edge-cases-quoting.mjs diff --git a/examples/test-events.mjs b/js/examples/test-events.mjs similarity index 92% rename from examples/test-events.mjs rename to js/examples/test-events.mjs index c84ecc9..365fc1e 100755 --- a/examples/test-events.mjs +++ b/js/examples/test-events.mjs @@ -5,7 +5,7 @@ import { $ } from '../js/src/$.mjs'; console.log('=== Test Event Emissions ===\n'); console.log('Test: emulate | cat | jq with event listeners'); -const cmd = $`bun run examples/emulate-claude-stream.mjs | cat | jq .`; +const cmd = $`bun run js/examples/emulate-claude-stream.mjs | cat | jq .`; const start = Date.now(); let eventCount = 0; diff --git a/examples/test-explicit-stdio.mjs b/js/examples/test-explicit-stdio.mjs similarity index 100% rename from examples/test-explicit-stdio.mjs rename to js/examples/test-explicit-stdio.mjs diff --git a/examples/test-final-streaming.mjs b/js/examples/test-final-streaming.mjs similarity index 85% rename from examples/test-final-streaming.mjs rename to js/examples/test-final-streaming.mjs index a768f18..8001a40 100755 --- a/examples/test-final-streaming.mjs +++ b/js/examples/test-final-streaming.mjs @@ -7,7 +7,7 @@ console.log('=== Final Streaming Test with PTY Workaround ===\n'); console.log('Test 1: Direct emulator execution (baseline):'); { const start = Date.now(); - for await (const chunk of $`bun run examples/emulate-claude-stream.mjs`.stream()) { + for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs`.stream()) { if (chunk.type === 'stdout') { const elapsed = Date.now() - start; const lines = chunk.data @@ -29,7 +29,7 @@ console.log( const start = Date.now(); let chunkCount = 0; - for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | jq .`.stream()) { + for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | jq .`.stream()) { if (chunk.type === 'stdout') { chunkCount++; const elapsed = Date.now() - start; @@ -53,7 +53,7 @@ console.log('\nTest 3: Complex pipeline with jq -c:'); { const start = Date.now(); - for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | jq -c .`.stream()) { + for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | jq -c .`.stream()) { if (chunk.type === 'stdout') { const elapsed = Date.now() - start; const lines = chunk.data.toString().trim().split('\n'); diff --git a/examples/test-fix.mjs b/js/examples/test-fix.mjs similarity index 100% rename from examples/test-fix.mjs rename to js/examples/test-fix.mjs diff --git a/examples/test-incremental-streaming.mjs b/js/examples/test-incremental-streaming.mjs similarity index 100% rename from examples/test-incremental-streaming.mjs rename to js/examples/test-incremental-streaming.mjs diff --git a/examples/test-individual-spawn.mjs b/js/examples/test-individual-spawn.mjs similarity index 82% rename from examples/test-individual-spawn.mjs rename to js/examples/test-individual-spawn.mjs index e497f67..bc38dce 100755 --- a/examples/test-individual-spawn.mjs +++ b/js/examples/test-individual-spawn.mjs @@ -2,10 +2,13 @@ // Test spawning processes individually and connecting them -const proc1 = Bun.spawn(['bun', 'run', 'examples/emulate-claude-stream.mjs'], { - stdout: 'pipe', - stderr: 'pipe', -}); +const proc1 = Bun.spawn( + ['bun', 'run', 'js/examples/emulate-claude-stream.mjs'], + { + stdout: 'pipe', + stderr: 'pipe', + } +); const proc2 = Bun.spawn(['jq', '.'], { stdin: proc1.stdout, diff --git a/examples/test-inherit-stdout-not-stdin.mjs b/js/examples/test-inherit-stdout-not-stdin.mjs similarity index 100% rename from examples/test-inherit-stdout-not-stdin.mjs rename to js/examples/test-inherit-stdout-not-stdin.mjs diff --git a/examples/test-injection-protection.mjs b/js/examples/test-injection-protection.mjs similarity index 100% rename from examples/test-injection-protection.mjs rename to js/examples/test-injection-protection.mjs diff --git a/examples/test-interactive-streaming.mjs b/js/examples/test-interactive-streaming.mjs similarity index 100% rename from examples/test-interactive-streaming.mjs rename to js/examples/test-interactive-streaming.mjs diff --git a/examples/test-interactive-top.md b/js/examples/test-interactive-top.md similarity index 95% rename from examples/test-interactive-top.md rename to js/examples/test-interactive-top.md index 3a4f145..eb84b03 100644 --- a/examples/test-interactive-top.md +++ b/js/examples/test-interactive-top.md @@ -3,7 +3,7 @@ To test the interactive top example: ```bash -node examples/interactive-top.mjs +node js/examples/interactive-top.mjs ``` **Expected behavior:** diff --git a/examples/test-interactive.mjs b/js/examples/test-interactive.mjs similarity index 100% rename from examples/test-interactive.mjs rename to js/examples/test-interactive.mjs diff --git a/examples/test-interpolation.mjs b/js/examples/test-interpolation.mjs similarity index 100% rename from examples/test-interpolation.mjs rename to js/examples/test-interpolation.mjs diff --git a/examples/test-interrupt.mjs b/js/examples/test-interrupt.mjs similarity index 100% rename from examples/test-interrupt.mjs rename to js/examples/test-interrupt.mjs diff --git a/examples/test-issue-135-comprehensive.mjs b/js/examples/test-issue-135-comprehensive.mjs similarity index 100% rename from examples/test-issue-135-comprehensive.mjs rename to js/examples/test-issue-135-comprehensive.mjs diff --git a/examples/test-issue12-detailed.mjs b/js/examples/test-issue12-detailed.mjs similarity index 100% rename from examples/test-issue12-detailed.mjs rename to js/examples/test-issue12-detailed.mjs diff --git a/examples/test-issue12-exact.mjs b/js/examples/test-issue12-exact.mjs similarity index 100% rename from examples/test-issue12-exact.mjs rename to js/examples/test-issue12-exact.mjs diff --git a/examples/test-jq-color.mjs b/js/examples/test-jq-color.mjs similarity index 100% rename from examples/test-jq-color.mjs rename to js/examples/test-jq-color.mjs diff --git a/examples/test-jq-colors.mjs b/js/examples/test-jq-colors.mjs similarity index 100% rename from examples/test-jq-colors.mjs rename to js/examples/test-jq-colors.mjs diff --git a/examples/test-jq-compact.mjs b/js/examples/test-jq-compact.mjs similarity index 90% rename from examples/test-jq-compact.mjs rename to js/examples/test-jq-compact.mjs index 7ea3afb..c975254 100755 --- a/examples/test-jq-compact.mjs +++ b/js/examples/test-jq-compact.mjs @@ -4,7 +4,7 @@ console.log('Test: jq with -c (compact) flag\n'); -const proc1 = Bun.spawn(['./examples/emulate-claude-stream.mjs'], { +const proc1 = Bun.spawn(['./js/examples/emulate-claude-stream.mjs'], { stdout: 'pipe', stderr: 'pipe', }); diff --git a/examples/test-jq-native.sh b/js/examples/test-jq-native.sh similarity index 100% rename from examples/test-jq-native.sh rename to js/examples/test-jq-native.sh diff --git a/examples/test-jq-pipeline-behavior.mjs b/js/examples/test-jq-pipeline-behavior.mjs similarity index 100% rename from examples/test-jq-pipeline-behavior.mjs rename to js/examples/test-jq-pipeline-behavior.mjs diff --git a/examples/test-jq-realtime.mjs b/js/examples/test-jq-realtime.mjs similarity index 91% rename from examples/test-jq-realtime.mjs rename to js/examples/test-jq-realtime.mjs index 3ed67e0..b2b9577 100755 --- a/examples/test-jq-realtime.mjs +++ b/js/examples/test-jq-realtime.mjs @@ -9,7 +9,7 @@ const start = Date.now(); let lastTime = start; let chunkCount = 0; -for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | jq .`.stream()) { +for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | jq .`.stream()) { if (chunk.type === 'stdout') { chunkCount++; const now = Date.now(); diff --git a/examples/test-manual-start.mjs b/js/examples/test-manual-start.mjs similarity index 100% rename from examples/test-manual-start.mjs rename to js/examples/test-manual-start.mjs diff --git a/examples/test-mixed-quoting.mjs b/js/examples/test-mixed-quoting.mjs similarity index 100% rename from examples/test-mixed-quoting.mjs rename to js/examples/test-mixed-quoting.mjs diff --git a/examples/test-multi-stream.mjs b/js/examples/test-multi-stream.mjs similarity index 89% rename from examples/test-multi-stream.mjs rename to js/examples/test-multi-stream.mjs index 19f7cdf..5d9b8bf 100755 --- a/examples/test-multi-stream.mjs +++ b/js/examples/test-multi-stream.mjs @@ -4,10 +4,13 @@ console.log('=== Testing Multi-Stream Pipeline Reading ===\n'); -const proc1 = Bun.spawn(['bun', 'run', 'examples/emulate-claude-stream.mjs'], { - stdout: 'pipe', - stderr: 'pipe', -}); +const proc1 = Bun.spawn( + ['bun', 'run', 'js/examples/emulate-claude-stream.mjs'], + { + stdout: 'pipe', + stderr: 'pipe', + } +); // Use tee to split the stream so we can both pipe it and read it const [readStream, pipeStream] = proc1.stdout.tee(); diff --git a/examples/test-multistage-debug.mjs b/js/examples/test-multistage-debug.mjs similarity index 92% rename from examples/test-multistage-debug.mjs rename to js/examples/test-multistage-debug.mjs index b0cc043..5d87787 100755 --- a/examples/test-multistage-debug.mjs +++ b/js/examples/test-multistage-debug.mjs @@ -10,7 +10,7 @@ let chunkCount = 0; let firstChunkTime = null; let lastChunkTime = null; -for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | cat | jq .`.stream()) { +for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | cat | jq .`.stream()) { if (chunk.type === 'stdout') { chunkCount++; const elapsed = Date.now() - start; diff --git a/examples/test-native-spawn-vs-command-stream.mjs b/js/examples/test-native-spawn-vs-command-stream.mjs similarity index 100% rename from examples/test-native-spawn-vs-command-stream.mjs rename to js/examples/test-native-spawn-vs-command-stream.mjs diff --git a/examples/test-no-parse-pipeline.mjs b/js/examples/test-no-parse-pipeline.mjs similarity index 91% rename from examples/test-no-parse-pipeline.mjs rename to js/examples/test-no-parse-pipeline.mjs index 176bd32..066b645 100755 --- a/examples/test-no-parse-pipeline.mjs +++ b/js/examples/test-no-parse-pipeline.mjs @@ -14,7 +14,7 @@ $.prototype._parseCommand = function (command) { const start = Date.now(); // This will now be executed as a single sh command -const cmd = $`bun run examples/emulate-claude-stream.mjs | jq .`; +const cmd = $`bun run js/examples/emulate-claude-stream.mjs | jq .`; for await (const chunk of cmd.stream()) { if (chunk.type === 'stdout') { diff --git a/examples/test-non-virtual.mjs b/js/examples/test-non-virtual.mjs similarity index 100% rename from examples/test-non-virtual.mjs rename to js/examples/test-non-virtual.mjs diff --git a/examples/test-operators.mjs b/js/examples/test-operators.mjs similarity index 100% rename from examples/test-operators.mjs rename to js/examples/test-operators.mjs diff --git a/examples/test-parent-continues.mjs b/js/examples/test-parent-continues.mjs similarity index 100% rename from examples/test-parent-continues.mjs rename to js/examples/test-parent-continues.mjs diff --git a/examples/test-path-interpolation.mjs b/js/examples/test-path-interpolation.mjs similarity index 100% rename from examples/test-path-interpolation.mjs rename to js/examples/test-path-interpolation.mjs diff --git a/examples/test-ping-kill-and-stdin.mjs b/js/examples/test-ping-kill-and-stdin.mjs similarity index 100% rename from examples/test-ping-kill-and-stdin.mjs rename to js/examples/test-ping-kill-and-stdin.mjs diff --git a/examples/test-ping.mjs b/js/examples/test-ping.mjs similarity index 100% rename from examples/test-ping.mjs rename to js/examples/test-ping.mjs diff --git a/examples/test-pty-spawn.mjs b/js/examples/test-pty-spawn.mjs similarity index 94% rename from examples/test-pty-spawn.mjs rename to js/examples/test-pty-spawn.mjs index 83eaf42..5552bcc 100755 --- a/examples/test-pty-spawn.mjs +++ b/js/examples/test-pty-spawn.mjs @@ -27,7 +27,7 @@ console.log('\nUsing script command as PTY wrapper:'); '/dev/null', 'sh', '-c', - 'bun run examples/emulate-claude-stream.mjs | jq .', + 'bun run js/examples/emulate-claude-stream.mjs | jq .', ], { stdout: 'pipe', @@ -70,7 +70,7 @@ console.log('\nTrying with TTY environment variables:'); let chunkCount = 0; const proc = Bun.spawn( - ['sh', '-c', 'bun run examples/emulate-claude-stream.mjs | jq .'], + ['sh', '-c', 'bun run js/examples/emulate-claude-stream.mjs | jq .'], { stdout: 'pipe', stderr: 'pipe', diff --git a/examples/test-pty.mjs b/js/examples/test-pty.mjs similarity index 92% rename from examples/test-pty.mjs rename to js/examples/test-pty.mjs index ffaa99e..59af499 100755 --- a/examples/test-pty.mjs +++ b/js/examples/test-pty.mjs @@ -4,7 +4,7 @@ console.log('Test: Using unbuffer to force line buffering\n'); -const proc1 = Bun.spawn(['./examples/emulate-claude-stream.mjs'], { +const proc1 = Bun.spawn(['./js/examples/emulate-claude-stream.mjs'], { stdout: 'pipe', stderr: 'pipe', }); diff --git a/examples/test-quote-behavior-summary.mjs b/js/examples/test-quote-behavior-summary.mjs similarity index 100% rename from examples/test-quote-behavior-summary.mjs rename to js/examples/test-quote-behavior-summary.mjs diff --git a/examples/test-quote-edge-cases.mjs b/js/examples/test-quote-edge-cases.mjs similarity index 100% rename from examples/test-quote-edge-cases.mjs rename to js/examples/test-quote-edge-cases.mjs diff --git a/examples/test-quote-parsing.mjs b/js/examples/test-quote-parsing.mjs similarity index 100% rename from examples/test-quote-parsing.mjs rename to js/examples/test-quote-parsing.mjs diff --git a/examples/test-raw-function.mjs b/js/examples/test-raw-function.mjs similarity index 100% rename from examples/test-raw-function.mjs rename to js/examples/test-raw-function.mjs diff --git a/examples/test-raw-streaming.mjs b/js/examples/test-raw-streaming.mjs similarity index 100% rename from examples/test-raw-streaming.mjs rename to js/examples/test-raw-streaming.mjs diff --git a/examples/test-readme-examples.mjs b/js/examples/test-readme-examples.mjs similarity index 100% rename from examples/test-readme-examples.mjs rename to js/examples/test-readme-examples.mjs diff --git a/examples/test-real-cat.mjs b/js/examples/test-real-cat.mjs similarity index 100% rename from examples/test-real-cat.mjs rename to js/examples/test-real-cat.mjs diff --git a/examples/test-real-commands.mjs b/js/examples/test-real-commands.mjs similarity index 85% rename from examples/test-real-commands.mjs rename to js/examples/test-real-commands.mjs index 5172eef..5a17edb 100755 --- a/examples/test-real-commands.mjs +++ b/js/examples/test-real-commands.mjs @@ -10,7 +10,7 @@ console.log('Result:', result.stdout); console.log('\nTest streaming:'); const start = Date.now(); -for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | jq .`.stream()) { +for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | jq .`.stream()) { if (chunk.type === 'stdout') { const elapsed = Date.now() - start; const lines = chunk.data.toString().trim().split('\n').slice(0, 2); diff --git a/examples/test-real-shell.mjs b/js/examples/test-real-shell.mjs similarity index 100% rename from examples/test-real-shell.mjs rename to js/examples/test-real-shell.mjs diff --git a/examples/test-real-stdin-commands.mjs b/js/examples/test-real-stdin-commands.mjs similarity index 100% rename from examples/test-real-stdin-commands.mjs rename to js/examples/test-real-stdin-commands.mjs diff --git a/examples/test-runner-batched.mjs b/js/examples/test-runner-batched.mjs similarity index 100% rename from examples/test-runner-batched.mjs rename to js/examples/test-runner-batched.mjs diff --git a/examples/test-runner-simple.mjs b/js/examples/test-runner-simple.mjs similarity index 100% rename from examples/test-runner-simple.mjs rename to js/examples/test-runner-simple.mjs diff --git a/examples/test-runner.mjs b/js/examples/test-runner.mjs similarity index 100% rename from examples/test-runner.mjs rename to js/examples/test-runner.mjs diff --git a/examples/test-scope-parse.mjs b/js/examples/test-scope-parse.mjs similarity index 100% rename from examples/test-scope-parse.mjs rename to js/examples/test-scope-parse.mjs diff --git a/examples/test-sh-pipeline.mjs b/js/examples/test-sh-pipeline.mjs similarity index 87% rename from examples/test-sh-pipeline.mjs rename to js/examples/test-sh-pipeline.mjs index f236dba..2b7efe5 100755 --- a/examples/test-sh-pipeline.mjs +++ b/js/examples/test-sh-pipeline.mjs @@ -8,7 +8,7 @@ console.log('This should stream in real-time\n'); const start = Date.now(); // Execute the entire pipeline as a single shell command -const cmd = $`sh -c 'bun run examples/emulate-claude-stream.mjs | jq .'`; +const cmd = $`sh -c 'bun run js/examples/emulate-claude-stream.mjs | jq .'`; for await (const chunk of cmd.stream()) { if (chunk.type === 'stdout') { diff --git a/examples/test-shell-detection.mjs b/js/examples/test-shell-detection.mjs similarity index 100% rename from examples/test-shell-detection.mjs rename to js/examples/test-shell-detection.mjs diff --git a/examples/test-shell-parser.mjs b/js/examples/test-shell-parser.mjs similarity index 100% rename from examples/test-shell-parser.mjs rename to js/examples/test-shell-parser.mjs diff --git a/examples/test-sigint-behavior.mjs b/js/examples/test-sigint-behavior.mjs similarity index 100% rename from examples/test-sigint-behavior.mjs rename to js/examples/test-sigint-behavior.mjs diff --git a/examples/test-sigint-handling.sh b/js/examples/test-sigint-handling.sh similarity index 100% rename from examples/test-sigint-handling.sh rename to js/examples/test-sigint-handling.sh diff --git a/examples/test-simple-pipe.mjs b/js/examples/test-simple-pipe.mjs similarity index 100% rename from examples/test-simple-pipe.mjs rename to js/examples/test-simple-pipe.mjs diff --git a/examples/test-simple-streaming.mjs b/js/examples/test-simple-streaming.mjs similarity index 100% rename from examples/test-simple-streaming.mjs rename to js/examples/test-simple-streaming.mjs diff --git a/examples/test-sleep-stdin.js b/js/examples/test-sleep-stdin.js similarity index 100% rename from examples/test-sleep-stdin.js rename to js/examples/test-sleep-stdin.js diff --git a/examples/test-sleep.mjs b/js/examples/test-sleep.mjs similarity index 100% rename from examples/test-sleep.mjs rename to js/examples/test-sleep.mjs diff --git a/examples/test-smart-quoting.mjs b/js/examples/test-smart-quoting.mjs similarity index 100% rename from examples/test-smart-quoting.mjs rename to js/examples/test-smart-quoting.mjs diff --git a/examples/test-spaces-in-path.mjs b/js/examples/test-spaces-in-path.mjs similarity index 100% rename from examples/test-spaces-in-path.mjs rename to js/examples/test-spaces-in-path.mjs diff --git a/examples/test-special-chars-quoting.mjs b/js/examples/test-special-chars-quoting.mjs similarity index 100% rename from examples/test-special-chars-quoting.mjs rename to js/examples/test-special-chars-quoting.mjs diff --git a/examples/test-stdin-after-start.mjs b/js/examples/test-stdin-after-start.mjs similarity index 100% rename from examples/test-stdin-after-start.mjs rename to js/examples/test-stdin-after-start.mjs diff --git a/examples/test-stdin-simple.mjs b/js/examples/test-stdin-simple.mjs similarity index 100% rename from examples/test-stdin-simple.mjs rename to js/examples/test-stdin-simple.mjs diff --git a/examples/test-stdin-timing.mjs b/js/examples/test-stdin-timing.mjs similarity index 100% rename from examples/test-stdin-timing.mjs rename to js/examples/test-stdin-timing.mjs diff --git a/examples/test-stdio-combinations.mjs b/js/examples/test-stdio-combinations.mjs similarity index 100% rename from examples/test-stdio-combinations.mjs rename to js/examples/test-stdio-combinations.mjs diff --git a/examples/test-stream-access.mjs b/js/examples/test-stream-access.mjs similarity index 100% rename from examples/test-stream-access.mjs rename to js/examples/test-stream-access.mjs diff --git a/examples/test-stream-cleanup.mjs b/js/examples/test-stream-cleanup.mjs similarity index 100% rename from examples/test-stream-cleanup.mjs rename to js/examples/test-stream-cleanup.mjs diff --git a/examples/test-stream-readers.mjs b/js/examples/test-stream-readers.mjs similarity index 93% rename from examples/test-stream-readers.mjs rename to js/examples/test-stream-readers.mjs index ae78ef0..c9acdb2 100755 --- a/examples/test-stream-readers.mjs +++ b/js/examples/test-stream-readers.mjs @@ -8,7 +8,7 @@ console.log('=== Testing Different Stream Reading Methods ===\n'); console.log('Method 1: ReadableStream getReader():'); { const proc = Bun.spawn( - ['sh', '-c', 'bun run examples/emulate-claude-stream.mjs | jq .'], + ['sh', '-c', 'bun run js/examples/emulate-claude-stream.mjs | jq .'], { stdout: 'pipe', stderr: 'pipe', @@ -55,7 +55,7 @@ console.log('\nMethod 2: Check if readable() method exists:'); console.log('\nMethod 3: Using Response API:'); { const proc = Bun.spawn( - ['sh', '-c', 'bun run examples/emulate-claude-stream.mjs | jq .'], + ['sh', '-c', 'bun run js/examples/emulate-claude-stream.mjs | jq .'], { stdout: 'pipe', stderr: 'pipe', @@ -91,7 +91,7 @@ console.log('\nMethod 3: Using Response API:'); console.log('\nMethod 4: Polling with small timeout:'); { const proc = Bun.spawn( - ['sh', '-c', 'bun run examples/emulate-claude-stream.mjs | jq .'], + ['sh', '-c', 'bun run js/examples/emulate-claude-stream.mjs | jq .'], { stdout: 'pipe', stderr: 'pipe', diff --git a/examples/test-streaming-final.mjs b/js/examples/test-streaming-final.mjs similarity index 89% rename from examples/test-streaming-final.mjs rename to js/examples/test-streaming-final.mjs index 7a2c319..b5a406a 100755 --- a/examples/test-streaming-final.mjs +++ b/js/examples/test-streaming-final.mjs @@ -7,7 +7,7 @@ console.log('=== Final Real-Time Streaming Test ===\n'); console.log('Test 1: Simple command streaming (baseline):'); { const start = Date.now(); - for await (const chunk of $`bun run examples/emulate-claude-stream.mjs`.stream()) { + for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs`.stream()) { if (chunk.type === 'stdout') { const elapsed = Date.now() - start; const lines = chunk.data.toString().trim().split('\n'); @@ -26,7 +26,7 @@ console.log('\nTest 2: With jq pipeline (using PTY for real-time streaming):'); let chunkCount = 0; // Use a real command instead of virtual echo - for await (const chunk of $`bun run examples/emulate-claude-stream.mjs | jq .`.stream()) { + for await (const chunk of $`bun run js/examples/emulate-claude-stream.mjs | jq .`.stream()) { if (chunk.type === 'stdout') { chunkCount++; const elapsed = Date.now() - start; diff --git a/examples/test-streaming-interfaces.mjs b/js/examples/test-streaming-interfaces.mjs similarity index 98% rename from examples/test-streaming-interfaces.mjs rename to js/examples/test-streaming-interfaces.mjs index 89ff3a0..24316cf 100755 --- a/examples/test-streaming-interfaces.mjs +++ b/js/examples/test-streaming-interfaces.mjs @@ -9,7 +9,7 @@ * - command.strings.stdin/stdout/stderr (text data) * * Usage: - * node examples/test-streaming-interfaces.mjs + * node js/examples/test-streaming-interfaces.mjs */ import { $ } from '../js/src/$.mjs'; diff --git a/examples/test-streaming-timing.mjs b/js/examples/test-streaming-timing.mjs similarity index 100% rename from examples/test-streaming-timing.mjs rename to js/examples/test-streaming-timing.mjs diff --git a/examples/test-streaming.mjs b/js/examples/test-streaming.mjs similarity index 100% rename from examples/test-streaming.mjs rename to js/examples/test-streaming.mjs diff --git a/examples/test-streams-stdin-comprehensive.mjs b/js/examples/test-streams-stdin-comprehensive.mjs similarity index 100% rename from examples/test-streams-stdin-comprehensive.mjs rename to js/examples/test-streams-stdin-comprehensive.mjs diff --git a/examples/test-streams-stdin-ctrl-c.mjs b/js/examples/test-streams-stdin-ctrl-c.mjs similarity index 100% rename from examples/test-streams-stdin-ctrl-c.mjs rename to js/examples/test-streams-stdin-ctrl-c.mjs diff --git a/examples/test-template-literal.mjs b/js/examples/test-template-literal.mjs similarity index 100% rename from examples/test-template-literal.mjs rename to js/examples/test-template-literal.mjs diff --git a/examples/test-template-vs-interpolation.mjs b/js/examples/test-template-vs-interpolation.mjs similarity index 100% rename from examples/test-template-vs-interpolation.mjs rename to js/examples/test-template-vs-interpolation.mjs diff --git a/examples/test-timing.mjs b/js/examples/test-timing.mjs similarity index 100% rename from examples/test-timing.mjs rename to js/examples/test-timing.mjs diff --git a/examples/test-top-inherit-stdout-stdin-control.mjs b/js/examples/test-top-inherit-stdout-stdin-control.mjs similarity index 100% rename from examples/test-top-inherit-stdout-stdin-control.mjs rename to js/examples/test-top-inherit-stdout-stdin-control.mjs diff --git a/examples/test-top-quit-stdin.mjs b/js/examples/test-top-quit-stdin.mjs similarity index 100% rename from examples/test-top-quit-stdin.mjs rename to js/examples/test-top-quit-stdin.mjs diff --git a/examples/test-trace-option.mjs b/js/examples/test-trace-option.mjs similarity index 100% rename from examples/test-trace-option.mjs rename to js/examples/test-trace-option.mjs diff --git a/examples/test-user-double-quotes.mjs b/js/examples/test-user-double-quotes.mjs similarity index 100% rename from examples/test-user-double-quotes.mjs rename to js/examples/test-user-double-quotes.mjs diff --git a/examples/test-user-single-quotes.mjs b/js/examples/test-user-single-quotes.mjs similarity index 100% rename from examples/test-user-single-quotes.mjs rename to js/examples/test-user-single-quotes.mjs diff --git a/examples/test-verbose.mjs b/js/examples/test-verbose.mjs similarity index 100% rename from examples/test-verbose.mjs rename to js/examples/test-verbose.mjs diff --git a/examples/test-verbose2.mjs b/js/examples/test-verbose2.mjs similarity index 100% rename from examples/test-verbose2.mjs rename to js/examples/test-verbose2.mjs diff --git a/examples/test-virtual-streaming.mjs b/js/examples/test-virtual-streaming.mjs similarity index 100% rename from examples/test-virtual-streaming.mjs rename to js/examples/test-virtual-streaming.mjs diff --git a/examples/test-waiting-command.mjs b/js/examples/test-waiting-command.mjs similarity index 100% rename from examples/test-waiting-command.mjs rename to js/examples/test-waiting-command.mjs diff --git a/examples/test-waiting-commands.mjs b/js/examples/test-waiting-commands.mjs similarity index 100% rename from examples/test-waiting-commands.mjs rename to js/examples/test-waiting-commands.mjs diff --git a/examples/test-watch-mode.mjs b/js/examples/test-watch-mode.mjs similarity index 100% rename from examples/test-watch-mode.mjs rename to js/examples/test-watch-mode.mjs diff --git a/examples/test-yes-cancellation.mjs b/js/examples/test-yes-cancellation.mjs similarity index 100% rename from examples/test-yes-cancellation.mjs rename to js/examples/test-yes-cancellation.mjs diff --git a/examples/test-yes-detailed.mjs b/js/examples/test-yes-detailed.mjs similarity index 100% rename from examples/test-yes-detailed.mjs rename to js/examples/test-yes-detailed.mjs diff --git a/examples/test-yes-trace.mjs b/js/examples/test-yes-trace.mjs similarity index 100% rename from examples/test-yes-trace.mjs rename to js/examples/test-yes-trace.mjs diff --git a/examples/trace-abort-controller.mjs b/js/examples/trace-abort-controller.mjs similarity index 89% rename from examples/trace-abort-controller.mjs rename to js/examples/trace-abort-controller.mjs index 9802c05..02082c6 100755 --- a/examples/trace-abort-controller.mjs +++ b/js/examples/trace-abort-controller.mjs @@ -7,7 +7,7 @@ * signal handling and virtual command cancellation. * * Usage: - * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-abort-controller.mjs + * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-abort-controller.mjs */ import { $ } from '../js/src/$.mjs'; diff --git a/examples/trace-error-handling.mjs b/js/examples/trace-error-handling.mjs similarity index 84% rename from examples/trace-error-handling.mjs rename to js/examples/trace-error-handling.mjs index 68bfe01..185f044 100755 --- a/examples/trace-error-handling.mjs +++ b/js/examples/trace-error-handling.mjs @@ -7,7 +7,7 @@ * cleanup on failure, and exception handling. * * Usage: - * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-error-handling.mjs + * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-error-handling.mjs */ import { $ } from '../js/src/$.mjs'; diff --git a/examples/trace-pipeline-command.mjs b/js/examples/trace-pipeline-command.mjs similarity index 84% rename from examples/trace-pipeline-command.mjs rename to js/examples/trace-pipeline-command.mjs index 0dd7860..93223f6 100755 --- a/examples/trace-pipeline-command.mjs +++ b/js/examples/trace-pipeline-command.mjs @@ -7,7 +7,7 @@ * parsing, pipeline creation, and multi-process coordination. * * Usage: - * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-pipeline-command.mjs + * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-pipeline-command.mjs */ import { $ } from '../js/src/$.mjs'; diff --git a/examples/trace-signal-handling.mjs b/js/examples/trace-signal-handling.mjs similarity index 89% rename from examples/trace-signal-handling.mjs rename to js/examples/trace-signal-handling.mjs index 0dfe593..63e8773 100755 --- a/examples/trace-signal-handling.mjs +++ b/js/examples/trace-signal-handling.mjs @@ -7,7 +7,7 @@ * SIGINT forwarding and cleanup operations. * * Usage: - * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-signal-handling.mjs + * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-signal-handling.mjs */ import { $ } from '../js/src/$.mjs'; diff --git a/examples/trace-simple-command.mjs b/js/examples/trace-simple-command.mjs similarity index 83% rename from examples/trace-simple-command.mjs rename to js/examples/trace-simple-command.mjs index 5ef6e5e..24191a4 100755 --- a/examples/trace-simple-command.mjs +++ b/js/examples/trace-simple-command.mjs @@ -7,7 +7,7 @@ * stdout/stderr handling, and completion. * * Usage: - * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-simple-command.mjs + * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-simple-command.mjs */ import { $ } from '../js/src/$.mjs'; diff --git a/examples/trace-stderr-output.mjs b/js/examples/trace-stderr-output.mjs similarity index 86% rename from examples/trace-stderr-output.mjs rename to js/examples/trace-stderr-output.mjs index 7e823a7..b44547a 100755 --- a/examples/trace-stderr-output.mjs +++ b/js/examples/trace-stderr-output.mjs @@ -7,7 +7,7 @@ * data capture, and I/O operations. * * Usage: - * COMMAND_STREAM_TRACE=ProcessRunner node examples/trace-stderr-output.mjs + * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-stderr-output.mjs */ import { $ } from '../js/src/$.mjs'; diff --git a/examples/verify-fix-both-runtimes.mjs b/js/examples/verify-fix-both-runtimes.mjs similarity index 100% rename from examples/verify-fix-both-runtimes.mjs rename to js/examples/verify-fix-both-runtimes.mjs diff --git a/examples/verify-issue12-fixed.mjs b/js/examples/verify-issue12-fixed.mjs similarity index 100% rename from examples/verify-issue12-fixed.mjs rename to js/examples/verify-issue12-fixed.mjs diff --git a/examples/which-command-common-commands.mjs b/js/examples/which-command-common-commands.mjs similarity index 100% rename from examples/which-command-common-commands.mjs rename to js/examples/which-command-common-commands.mjs diff --git a/examples/which-command-gh-test.mjs b/js/examples/which-command-gh-test.mjs similarity index 100% rename from examples/which-command-gh-test.mjs rename to js/examples/which-command-gh-test.mjs diff --git a/examples/which-command-nonexistent.mjs b/js/examples/which-command-nonexistent.mjs similarity index 100% rename from examples/which-command-nonexistent.mjs rename to js/examples/which-command-nonexistent.mjs diff --git a/examples/which-command-system-comparison.mjs b/js/examples/which-command-system-comparison.mjs similarity index 100% rename from examples/which-command-system-comparison.mjs rename to js/examples/which-command-system-comparison.mjs diff --git a/examples/working-example.mjs b/js/examples/working-example.mjs similarity index 100% rename from examples/working-example.mjs rename to js/examples/working-example.mjs diff --git a/examples/working-stdin-examples.mjs b/js/examples/working-stdin-examples.mjs similarity index 100% rename from examples/working-stdin-examples.mjs rename to js/examples/working-stdin-examples.mjs diff --git a/examples/working-streaming-demo.mjs b/js/examples/working-streaming-demo.mjs similarity index 100% rename from examples/working-streaming-demo.mjs rename to js/examples/working-streaming-demo.mjs diff --git a/js/tests/ctrl-c-baseline.test.mjs b/js/tests/ctrl-c-baseline.test.mjs index a5cabe0..8bc4cc8 100644 --- a/js/tests/ctrl-c-baseline.test.mjs +++ b/js/tests/ctrl-c-baseline.test.mjs @@ -156,7 +156,7 @@ describe.skipIf(isWindows)('CTRL+C Baseline Tests (Native Spawn)', () => { trace('BaselineTest', 'Testing Node.js script file'); // Use the simple-test-sleep.js which doesn't have ES module dependencies - const child = spawn('node', ['examples/simple-test-sleep.js'], { + const child = spawn('node', ['js/examples/simple-test-sleep.js'], { stdio: ['pipe', 'pipe', 'pipe'], detached: true, cwd: process.cwd(), diff --git a/js/tests/ctrl-c-library.test.mjs b/js/tests/ctrl-c-library.test.mjs index 4149caa..a6da297 100644 --- a/js/tests/ctrl-c-library.test.mjs +++ b/js/tests/ctrl-c-library.test.mjs @@ -58,7 +58,7 @@ describe.skipIf(isWindows)('CTRL+C Library Tests (command-stream)', () => { trace('LibraryTest', 'Testing library via external script'); // Use test-sleep.mjs which imports our library - const child = spawn('node', ['examples/test-sleep.mjs'], { + const child = spawn('node', ['js/examples/test-sleep.mjs'], { stdio: ['pipe', 'pipe', 'pipe'], detached: true, cwd: process.cwd(), diff --git a/js/tests/ctrl-c-signal.test.mjs b/js/tests/ctrl-c-signal.test.mjs index 7b71768..7347787 100644 --- a/js/tests/ctrl-c-signal.test.mjs +++ b/js/tests/ctrl-c-signal.test.mjs @@ -826,7 +826,7 @@ describe.skipIf(isWindows)('CTRL+C with Different stdin Modes', () => { // Test 1: Virtual command cancellation with proper exit codes trace('SignalTest', 'Testing virtual command SIGINT cancellation...'); - const child1 = spawn('node', ['examples/test-sleep.mjs'], { + const child1 = spawn('node', ['js/examples/test-sleep.mjs'], { stdio: ['pipe', 'pipe', 'pipe'], detached: true, }); diff --git a/js/tests/examples.test.mjs b/js/tests/examples.test.mjs index 9c7cd42..12d648d 100644 --- a/js/tests/examples.test.mjs +++ b/js/tests/examples.test.mjs @@ -6,7 +6,7 @@ import { readdirSync, statSync, readFileSync } from 'fs'; import { join } from 'path'; // Get all .mjs examples -const examplesDir = join(process.cwd(), 'examples'); +const examplesDir = join(process.cwd(), 'js/examples'); const allExamples = readdirSync(examplesDir) .filter( (file) => @@ -24,7 +24,7 @@ describe('Examples Execution Tests', () => { // Core functionality test - our main example should work // SKIP: May hang when run with full suite test.skip('readme-example.mjs should execute and demonstrate new API signature', async () => { - const result = await $`node examples/readme-example.mjs`; + const result = await $`node js/examples/readme-example.mjs`; expect(result.code).toBe(0); expect(result.stdout).toContain('Hello, World!'); expect(result.stdout).toContain('Hello, Mr. Smith!'); @@ -36,7 +36,7 @@ describe('Examples Execution Tests', () => { // JSON streaming test - key feature // SKIP: This test hangs when run with full test suite due to sleep commands test.skip('simple-jq-streaming.mjs should complete successfully', async () => { - const result = await $`node examples/simple-jq-streaming.mjs`; + const result = await $`node js/examples/simple-jq-streaming.mjs`; expect(result.code).toBe(0); expect(result.stdout).toContain('โœ… Streaming completed successfully!'); expect(result.stdout).toContain('๐ŸŽ‰ All tests passed!'); @@ -67,7 +67,7 @@ describe('Examples Execution Tests', () => { if (manualTestExamples.length > 0) { trace('ExampleTest', 'Recommended for manual testing:'); manualTestExamples.forEach((ex) => - trace('ExampleTest', () => `node examples/${ex}`) + trace('ExampleTest', () => `node js/examples/${ex}`) ); } @@ -168,7 +168,7 @@ describe('Examples Execution Tests', () => { const { spawn } = await import('child_process'); // Start our debug script that imports $ but doesn't run commands - const child = spawn('node', ['examples/debug-user-sigint.mjs'], { + const child = spawn('node', ['js/examples/debug-user-sigint.mjs'], { stdio: ['pipe', 'pipe', 'pipe'], detached: true, }); diff --git a/js/tests/text-method.test.mjs b/js/tests/text-method.test.mjs index ab0b70b..ce7227e 100644 --- a/js/tests/text-method.test.mjs +++ b/js/tests/text-method.test.mjs @@ -71,7 +71,7 @@ describe('.text() method for Bun.$ compatibility', () => { }); test('.text() should work with ls built-in command', async () => { - const result = await $`ls -1 tests/`; + const result = await $`ls -1 js/tests/`; const text = await result.text(); // Should contain at least this test file diff --git a/temp-unicode-test.txt b/temp-unicode-test.txt new file mode 100644 index 0000000..e69de29 From dc548ba113aea7ef088b14b0c3a3b5e273b3a765 Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 29 Dec 2025 14:47:19 +0100 Subject: [PATCH 8/9] Fix import paths in examples after move to js/examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Change ../js/src/ to ../src/ since examples are now at js/examples/ - Fix corrupted quote in test-auth-parse.mjs ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- js/examples/01-basic-streaming.mjs | 2 +- js/examples/02-async-iterator.mjs | 2 +- js/examples/03-file-and-console.mjs | 2 +- js/examples/04-claude-jq-pipe.mjs | 2 +- js/examples/README-examples.mjs | 2 +- js/examples/ansi-default-preserved.mjs | 2 +- js/examples/ansi-global-config.mjs | 2 +- js/examples/ansi-reset-default.mjs | 2 +- js/examples/ansi-strip-utils.mjs | 2 +- js/examples/capture-mirror-comparison.mjs | 2 +- js/examples/capture-mirror-default.mjs | 2 +- js/examples/capture-mirror-performance.mjs | 2 +- js/examples/capture-mirror-show-only.mjs | 2 +- js/examples/capture-mirror-silent-processing.mjs | 2 +- js/examples/ci-debug-baseline-vs-library.mjs | 2 +- js/examples/ci-debug-es-module-loading.mjs | 4 ++-- js/examples/ci-debug-signal-handling.mjs | 2 +- js/examples/ci-debug-stdout-buffering.mjs | 2 +- js/examples/ci-debug-test-timeouts.mjs | 2 +- js/examples/claude-exact-file-output.mjs | 2 +- js/examples/claude-exact-jq.mjs | 2 +- js/examples/claude-exact-streaming.mjs | 2 +- js/examples/claude-jq-pipeline.mjs | 2 +- js/examples/claude-streaming-basic.mjs | 2 +- js/examples/claude-streaming-demo.mjs | 2 +- js/examples/claude-streaming-final.mjs | 2 +- js/examples/cleanup-verification-test.mjs | 2 +- js/examples/colors-buffer-processing.mjs | 2 +- js/examples/colors-default-preserved.mjs | 2 +- js/examples/colors-per-command-config.mjs | 2 +- js/examples/colors-strip-ansi.mjs | 2 +- js/examples/commandstream-jq.mjs | 2 +- js/examples/commandstream-working.mjs | 2 +- js/examples/comprehensive-streams-demo.mjs | 2 +- js/examples/ctrl-c-concurrent-processes.mjs | 2 +- js/examples/ctrl-c-long-running-command.mjs | 2 +- js/examples/ctrl-c-real-system-command.mjs | 2 +- js/examples/ctrl-c-sleep-command.mjs | 2 +- js/examples/ctrl-c-stdin-forwarding.mjs | 2 +- js/examples/ctrl-c-virtual-command.mjs | 2 +- js/examples/debug-already-started.mjs | 2 +- js/examples/debug-ansi-processing.mjs | 2 +- js/examples/debug-basic-streaming.mjs | 2 +- js/examples/debug-child-process.mjs | 2 +- js/examples/debug-child-state.mjs | 2 +- js/examples/debug-chunking.mjs | 2 +- js/examples/debug-command-parsing.mjs | 2 +- js/examples/debug-complete-consolidation.mjs | 2 +- js/examples/debug-echo-args.mjs | 2 +- js/examples/debug-emit-timing.mjs | 2 +- js/examples/debug-end-event.mjs | 2 +- js/examples/debug-errexit.mjs | 2 +- js/examples/debug-event-emission.mjs | 2 +- js/examples/debug-event-timing.mjs | 2 +- js/examples/debug-event-vs-result.mjs | 2 +- js/examples/debug-exact-command.mjs | 2 +- js/examples/debug-exact-test-scenario.mjs | 2 +- js/examples/debug-execution-path.mjs | 2 +- js/examples/debug-exit-command.mjs | 2 +- js/examples/debug-exit-virtual.mjs | 2 +- js/examples/debug-finish-consolidation.mjs | 2 +- js/examples/debug-force-cleanup.mjs | 2 +- js/examples/debug-getter-basic.mjs | 2 +- js/examples/debug-getter-direct.mjs | 2 +- js/examples/debug-getter-internals.mjs | 2 +- js/examples/debug-handler-detection.mjs | 2 +- js/examples/debug-idempotent-finish.mjs | 2 +- js/examples/debug-idempotent-kill.mjs | 2 +- js/examples/debug-interpolation-individual.mjs | 2 +- js/examples/debug-interpolation-issue.mjs | 2 +- js/examples/debug-jq-streaming.mjs | 2 +- js/examples/debug-jq-tty-colors.mjs | 2 +- js/examples/debug-kill-cleanup.mjs | 2 +- js/examples/debug-kill-method.mjs | 2 +- js/examples/debug-listener-interference.mjs | 2 +- js/examples/debug-listener-lifecycle.mjs | 2 +- js/examples/debug-listener-timing.mjs | 2 +- js/examples/debug-listeners-property.mjs | 2 +- js/examples/debug-map-methods.mjs | 2 +- js/examples/debug-not-awaited-cleanup.mjs | 2 +- js/examples/debug-off-method.mjs | 2 +- js/examples/debug-option-merging.mjs | 2 +- js/examples/debug-options.mjs | 2 +- js/examples/debug-output.mjs | 2 +- js/examples/debug-pattern-matching.mjs | 2 +- js/examples/debug-pipeline-cat.mjs | 2 +- js/examples/debug-pipeline-cleanup.mjs | 2 +- js/examples/debug-pipeline-error-detailed.mjs | 2 +- js/examples/debug-pipeline-error.mjs | 2 +- js/examples/debug-pipeline-issue.mjs | 2 +- js/examples/debug-pipeline-method.mjs | 2 +- js/examples/debug-pipeline-stream.mjs | 2 +- js/examples/debug-pipeline.mjs | 2 +- js/examples/debug-process-exit-trace.mjs | 2 +- js/examples/debug-process-path.mjs | 2 +- js/examples/debug-property-check.mjs | 2 +- js/examples/debug-resource-cleanup.mjs | 2 +- js/examples/debug-sigint-child-handler.mjs | 2 +- js/examples/debug-sigint-forwarding.mjs | 2 +- js/examples/debug-sigint-handler-install.mjs | 2 +- js/examples/debug-sigint-handler-order.mjs | 2 +- js/examples/debug-sigint-listeners.mjs | 2 +- js/examples/debug-sigint-start-pattern.mjs | 2 +- js/examples/debug-sigint-timer.mjs | 2 +- js/examples/debug-simple-command.mjs | 2 +- js/examples/debug-simple-getter.mjs | 2 +- js/examples/debug-simple.mjs | 2 +- js/examples/debug-simplified-finished.mjs | 2 +- js/examples/debug-stack-overflow.mjs | 2 +- js/examples/debug-stdin-simple.mjs | 2 +- js/examples/debug-stdin.mjs | 2 +- js/examples/debug-stream-emitter-isolated.mjs | 2 +- js/examples/debug-stream-emitter.mjs | 2 +- js/examples/debug-stream-events.mjs | 2 +- js/examples/debug-stream-generator.mjs | 2 +- js/examples/debug-stream-getter-issue.mjs | 2 +- js/examples/debug-stream-getter.mjs | 2 +- js/examples/debug-stream-internals.mjs | 2 +- js/examples/debug-stream-method.mjs | 2 +- js/examples/debug-stream-object.mjs | 2 +- js/examples/debug-stream-properties.mjs | 2 +- js/examples/debug-stream-timing.mjs | 2 +- js/examples/debug-streaming.mjs | 2 +- js/examples/debug-test-state.mjs | 2 +- js/examples/debug-user-sigint.mjs | 2 +- js/examples/debug-virtual-disable.mjs | 2 +- js/examples/debug-virtual-vs-real.mjs | 2 +- js/examples/debug-with-trace.mjs | 2 +- js/examples/debug_parent_stream.mjs | 2 +- js/examples/emulated-streaming-direct.mjs | 2 +- js/examples/emulated-streaming-jq-pipe.mjs | 2 +- js/examples/emulated-streaming-sh-pipe.mjs | 2 +- js/examples/events-build-process.mjs | 2 +- js/examples/events-concurrent-streams.mjs | 2 +- js/examples/events-error-handling.mjs | 2 +- js/examples/events-file-monitoring.mjs | 2 +- js/examples/events-interactive-simulation.mjs | 2 +- js/examples/events-log-processing.mjs | 2 +- js/examples/events-network-monitoring.mjs | 2 +- js/examples/events-ping-basic.mjs | 2 +- js/examples/events-progress-tracking.mjs | 2 +- js/examples/events-stdin-input.mjs | 2 +- js/examples/example-ansi-ls.mjs | 2 +- js/examples/example-top.mjs | 2 +- js/examples/final-ping-stdin-proof.mjs | 2 +- js/examples/final-test-shell-operators.mjs | 2 +- js/examples/final-working-examples.mjs | 2 +- js/examples/gh-auth-test.mjs | 2 +- js/examples/gh-delete-hang-test.mjs | 2 +- js/examples/gh-gist-creation-test.mjs | 2 +- js/examples/gh-gist-minimal-test.mjs | 2 +- js/examples/gh-hang-exact-original.mjs | 2 +- js/examples/gh-hang-reproduction.mjs | 2 +- js/examples/gh-hang-test-with-redirect.mjs | 2 +- js/examples/gh-hang-test-without-redirect.mjs | 2 +- js/examples/gh-minimal-hang-check.mjs | 2 +- js/examples/gh-operations-with-cd.mjs | 2 +- js/examples/gh-output-test.mjs | 2 +- js/examples/gh-reproduce-hang.mjs | 2 +- js/examples/git-operations-with-cd.mjs | 2 +- js/examples/interactive-top-fixed.mjs | 2 +- js/examples/interactive-top-improved.mjs | 2 +- js/examples/interactive-top-pty-logging.mjs | 2 +- js/examples/interactive-top-with-logging.mjs | 2 +- js/examples/interactive-top.mjs | 2 +- js/examples/jq-color-demo.mjs | 2 +- js/examples/jq-colors-streaming.mjs | 2 +- js/examples/manual-ctrl-c-test.mjs | 2 +- js/examples/methods-multiple-options.mjs | 2 +- js/examples/methods-run-basic.mjs | 2 +- js/examples/methods-start-basic.mjs | 2 +- js/examples/options-capture-false.mjs | 2 +- js/examples/options-combined-settings.mjs | 2 +- js/examples/options-custom-input.mjs | 2 +- js/examples/options-default-behavior.mjs | 2 +- js/examples/options-maximum-performance.mjs | 2 +- js/examples/options-mirror-false.mjs | 2 +- js/examples/options-performance-mode.mjs | 2 +- js/examples/options-performance-optimization.mjs | 2 +- js/examples/options-run-alias-demo.mjs | 2 +- js/examples/options-run-alias.mjs | 2 +- js/examples/options-silent-execution.mjs | 2 +- js/examples/options-streaming-capture.mjs | 2 +- js/examples/options-streaming-multiple.mjs | 2 +- js/examples/options-streaming-silent.mjs | 2 +- js/examples/options-streaming-stdin.mjs | 2 +- js/examples/ping-streaming-filtered.mjs | 2 +- js/examples/ping-streaming-interruptible.mjs | 2 +- js/examples/ping-streaming-silent.mjs | 2 +- js/examples/ping-streaming-simple.mjs | 2 +- js/examples/ping-streaming-statistics.mjs | 2 +- js/examples/ping-streaming-timestamps.mjs | 2 +- js/examples/ping-streaming.mjs | 2 +- js/examples/prove-ping-stdin-limitation.mjs | 2 +- js/examples/readme-example.mjs | 2 +- js/examples/realtime-json-stream.mjs | 2 +- js/examples/reliable-stdin-commands.mjs | 2 +- js/examples/reproduce-issue-135-v2.mjs | 2 +- js/examples/reproduce-issue-135.mjs | 2 +- js/examples/shell-cd-behavior.mjs | 2 +- js/examples/sigint-forwarding-test.mjs | 2 +- js/examples/sigint-handler-test.mjs | 2 +- js/examples/simple-async-test.mjs | 2 +- js/examples/simple-claude-test.mjs | 2 +- js/examples/simple-event-test.mjs | 2 +- js/examples/simple-jq-streaming.mjs | 2 +- js/examples/simple-stream-demo.mjs | 2 +- js/examples/simple-working-stdin.mjs | 2 +- js/examples/streaming-behavior-test.mjs | 2 +- js/examples/streaming-direct-command.mjs | 2 +- js/examples/streaming-filtered-output.mjs | 2 +- js/examples/streaming-grep-pipeline.mjs | 2 +- js/examples/streaming-interactive-stdin.mjs | 2 +- js/examples/streaming-jq-pipeline.mjs | 2 +- js/examples/streaming-multistage-pipeline.mjs | 2 +- js/examples/streaming-pipes-event-pattern.mjs | 2 +- js/examples/streaming-pipes-multistage.mjs | 2 +- js/examples/streaming-pipes-realtime-jq.mjs | 2 +- js/examples/streaming-progress-tracking.mjs | 2 +- js/examples/streaming-reusable-configs.mjs | 2 +- js/examples/streaming-silent-capture.mjs | 2 +- js/examples/streaming-test-simple.mjs | 2 +- js/examples/streaming-virtual-pipeline.mjs | 2 +- js/examples/syntax-basic-comparison.mjs | 2 +- js/examples/syntax-basic-options.mjs | 2 +- js/examples/syntax-combined-options.mjs | 2 +- js/examples/syntax-command-chaining.mjs | 2 +- js/examples/syntax-custom-directory.mjs | 2 +- js/examples/syntax-custom-environment.mjs | 2 +- js/examples/syntax-custom-stdin.mjs | 2 +- js/examples/syntax-mixed-regular.mjs | 2 +- js/examples/syntax-mixed-usage.mjs | 2 +- js/examples/syntax-multiple-listeners.mjs | 2 +- js/examples/syntax-piping-comparison.mjs | 2 +- js/examples/syntax-reusable-config.mjs | 2 +- js/examples/syntax-reusable-configs.mjs | 2 +- js/examples/syntax-silent-operations.mjs | 2 +- js/examples/syntax-stdin-option.mjs | 2 +- js/examples/temp-sigint-test.mjs | 2 +- js/examples/test-actual-buildshell.mjs | 2 +- js/examples/test-async-streams-working.mjs | 2 +- js/examples/test-async-streams.mjs | 2 +- js/examples/test-auth-parse.mjs | 2 +- js/examples/test-auto-quoting.mjs | 2 +- js/examples/test-auto-start-fix.mjs | 2 +- js/examples/test-buffer-behavior.mjs | 2 +- js/examples/test-buffers-simple.mjs | 2 +- js/examples/test-bun-specific-issue.mjs | 2 +- js/examples/test-cd-behavior.mjs | 2 +- js/examples/test-child-process-timing.mjs | 2 +- js/examples/test-cleanup-simple.mjs | 2 +- js/examples/test-correct-space-handling.mjs | 2 +- js/examples/test-ctrl-c-debug.mjs | 2 +- js/examples/test-ctrl-c-inherit.mjs | 2 +- js/examples/test-ctrl-c-sleep.mjs | 2 +- js/examples/test-ctrl-c.mjs | 2 +- js/examples/test-debug-new-options.mjs | 2 +- js/examples/test-debug-pty.mjs | 2 +- js/examples/test-debug-tee.mjs | 2 +- js/examples/test-debug.mjs | 2 +- js/examples/test-double-quoting-prevention.mjs | 2 +- js/examples/test-edge-cases-quoting.mjs | 2 +- js/examples/test-events.mjs | 2 +- js/examples/test-explicit-stdio.mjs | 2 +- js/examples/test-final-streaming.mjs | 2 +- js/examples/test-fix.mjs | 2 +- js/examples/test-incremental-streaming.mjs | 2 +- js/examples/test-inherit-stdout-not-stdin.mjs | 2 +- js/examples/test-injection-protection.mjs | 2 +- js/examples/test-interactive-streaming.mjs | 2 +- js/examples/test-interactive.mjs | 2 +- js/examples/test-interpolation.mjs | 2 +- js/examples/test-interrupt.mjs | 2 +- js/examples/test-issue-135-comprehensive.mjs | 2 +- js/examples/test-issue12-detailed.mjs | 2 +- js/examples/test-issue12-exact.mjs | 2 +- js/examples/test-jq-color.mjs | 2 +- js/examples/test-jq-colors.mjs | 2 +- js/examples/test-jq-pipeline-behavior.mjs | 2 +- js/examples/test-jq-realtime.mjs | 2 +- js/examples/test-manual-start.mjs | 2 +- js/examples/test-mixed-quoting.mjs | 2 +- js/examples/test-multistage-debug.mjs | 2 +- js/examples/test-native-spawn-vs-command-stream.mjs | 2 +- js/examples/test-no-parse-pipeline.mjs | 2 +- js/examples/test-non-virtual.mjs | 2 +- js/examples/test-operators.mjs | 2 +- js/examples/test-parent-continues.mjs | 2 +- js/examples/test-path-interpolation.mjs | 2 +- js/examples/test-ping-kill-and-stdin.mjs | 2 +- js/examples/test-ping.mjs | 2 +- js/examples/test-quote-behavior-summary.mjs | 2 +- js/examples/test-quote-edge-cases.mjs | 2 +- js/examples/test-quote-parsing.mjs | 2 +- js/examples/test-raw-function.mjs | 2 +- js/examples/test-raw-streaming.mjs | 2 +- js/examples/test-readme-examples.mjs | 2 +- js/examples/test-real-cat.mjs | 2 +- js/examples/test-real-commands.mjs | 2 +- js/examples/test-real-shell.mjs | 2 +- js/examples/test-real-stdin-commands.mjs | 2 +- js/examples/test-runner.mjs | 2 +- js/examples/test-sh-pipeline.mjs | 2 +- js/examples/test-shell-detection.mjs | 2 +- js/examples/test-shell-parser.mjs | 2 +- js/examples/test-sigint-behavior.mjs | 2 +- js/examples/test-simple-pipe.mjs | 2 +- js/examples/test-simple-streaming.mjs | 4 ++-- js/examples/test-smart-quoting.mjs | 2 +- js/examples/test-spaces-in-path.mjs | 2 +- js/examples/test-special-chars-quoting.mjs | 2 +- js/examples/test-stdin-after-start.mjs | 2 +- js/examples/test-stdin-simple.mjs | 2 +- js/examples/test-stdin-timing.mjs | 2 +- js/examples/test-stdio-combinations.mjs | 2 +- js/examples/test-stream-access.mjs | 2 +- js/examples/test-stream-cleanup.mjs | 2 +- js/examples/test-streaming-final.mjs | 2 +- js/examples/test-streaming-interfaces.mjs | 2 +- js/examples/test-streaming-timing.mjs | 2 +- js/examples/test-streaming.mjs | 2 +- js/examples/test-streams-stdin-comprehensive.mjs | 2 +- js/examples/test-streams-stdin-ctrl-c.mjs | 2 +- js/examples/test-template-literal.mjs | 2 +- js/examples/test-template-vs-interpolation.mjs | 2 +- js/examples/test-timing.mjs | 2 +- js/examples/test-top-inherit-stdout-stdin-control.mjs | 2 +- js/examples/test-top-quit-stdin.mjs | 2 +- js/examples/test-trace-option.mjs | 2 +- js/examples/test-user-double-quotes.mjs | 2 +- js/examples/test-user-single-quotes.mjs | 2 +- js/examples/test-verbose.mjs | 2 +- js/examples/test-verbose2.mjs | 2 +- js/examples/test-virtual-streaming.mjs | 2 +- js/examples/test-waiting-command.mjs | 2 +- js/examples/test-waiting-commands.mjs | 2 +- js/examples/test-watch-mode.mjs | 2 +- js/examples/test-yes-cancellation.mjs | 2 +- js/examples/test-yes-detailed.mjs | 4 ++-- js/examples/test-yes-trace.mjs | 2 +- js/examples/trace-abort-controller.mjs | 2 +- js/examples/trace-error-handling.mjs | 2 +- js/examples/trace-pipeline-command.mjs | 2 +- js/examples/trace-signal-handling.mjs | 2 +- js/examples/trace-simple-command.mjs | 2 +- js/examples/trace-stderr-output.mjs | 2 +- js/examples/verify-fix-both-runtimes.mjs | 2 +- js/examples/verify-issue12-fixed.mjs | 2 +- js/examples/which-command-common-commands.mjs | 2 +- js/examples/which-command-gh-test.mjs | 2 +- js/examples/which-command-nonexistent.mjs | 2 +- js/examples/which-command-system-comparison.mjs | 2 +- js/examples/working-example.mjs | 2 +- js/examples/working-stdin-examples.mjs | 2 +- js/examples/working-streaming-demo.mjs | 2 +- 355 files changed, 358 insertions(+), 358 deletions(-) diff --git a/js/examples/01-basic-streaming.mjs b/js/examples/01-basic-streaming.mjs index 16a9f8d..2b44c36 100755 --- a/js/examples/01-basic-streaming.mjs +++ b/js/examples/01-basic-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Basic streaming example - shows real-time chunk processing -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; let chunkCount = 0; diff --git a/js/examples/02-async-iterator.mjs b/js/examples/02-async-iterator.mjs index 323069b..ea855f5 100755 --- a/js/examples/02-async-iterator.mjs +++ b/js/examples/02-async-iterator.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Async iterator pattern - process chunks as they arrive -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Using async iteration:'); diff --git a/js/examples/03-file-and-console.mjs b/js/examples/03-file-and-console.mjs index a0bd6b6..af5c981 100755 --- a/js/examples/03-file-and-console.mjs +++ b/js/examples/03-file-and-console.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Stream to both console and file simultaneously -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { appendFileSync } from 'fs'; const logFile = 'stream-output.log'; diff --git a/js/examples/04-claude-jq-pipe.mjs b/js/examples/04-claude-jq-pipe.mjs index 12290f7..c3de8ef 100755 --- a/js/examples/04-claude-jq-pipe.mjs +++ b/js/examples/04-claude-jq-pipe.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Claude output piped to jq for JSON processing -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Claude โ†’ jq pipeline:'); diff --git a/js/examples/README-examples.mjs b/js/examples/README-examples.mjs index 9fbf73a..88b50fb 100755 --- a/js/examples/README-examples.mjs +++ b/js/examples/README-examples.mjs @@ -4,7 +4,7 @@ * Examples for README - using manual timing approach until async streams are perfected */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('๐Ÿ“– README Examples - Streaming Interfaces'); console.log('='.repeat(50)); diff --git a/js/examples/ansi-default-preserved.mjs b/js/examples/ansi-default-preserved.mjs index 765a9c5..993a046 100755 --- a/js/examples/ansi-default-preserved.mjs +++ b/js/examples/ansi-default-preserved.mjs @@ -2,7 +2,7 @@ // Default behavior (ANSI preserved) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Default behavior (ANSI preserved):'); const colorCommand = diff --git a/js/examples/ansi-global-config.mjs b/js/examples/ansi-global-config.mjs index 61dd615..15c223b 100755 --- a/js/examples/ansi-global-config.mjs +++ b/js/examples/ansi-global-config.mjs @@ -2,7 +2,7 @@ // Global configuration to disable ANSI preservation -import { $, configureAnsi } from '../js/src/$.mjs'; +import { $, configureAnsi } from '../src/$.mjs'; console.log('Global configuration to disable ANSI preservation:'); configureAnsi({ preserveAnsi: false }); diff --git a/js/examples/ansi-reset-default.mjs b/js/examples/ansi-reset-default.mjs index 1ebb020..49cc6d0 100755 --- a/js/examples/ansi-reset-default.mjs +++ b/js/examples/ansi-reset-default.mjs @@ -2,7 +2,7 @@ // Reset to default (preserve ANSI) -import { $, configureAnsi } from '../js/src/$.mjs'; +import { $, configureAnsi } from '../src/$.mjs'; console.log('Reset to default (preserve ANSI):'); configureAnsi({ preserveAnsi: true }); diff --git a/js/examples/ansi-strip-utils.mjs b/js/examples/ansi-strip-utils.mjs index 5715fda..1c97f4c 100755 --- a/js/examples/ansi-strip-utils.mjs +++ b/js/examples/ansi-strip-utils.mjs @@ -2,7 +2,7 @@ // Using AnsiUtils to strip ANSI from result -import { $, AnsiUtils } from '../js/src/$.mjs'; +import { $, AnsiUtils } from '../src/$.mjs'; console.log('Using AnsiUtils to strip ANSI from result:'); const colorCommand = diff --git a/js/examples/capture-mirror-comparison.mjs b/js/examples/capture-mirror-comparison.mjs index 9c01336..a5f172b 100755 --- a/js/examples/capture-mirror-comparison.mjs +++ b/js/examples/capture-mirror-comparison.mjs @@ -2,7 +2,7 @@ // Summary comparison of all capture/mirror combinations -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('๐Ÿ“Š Capture/Mirror Combinations Summary:'); console.log('โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”'); diff --git a/js/examples/capture-mirror-default.mjs b/js/examples/capture-mirror-default.mjs index b09812f..466785d 100755 --- a/js/examples/capture-mirror-default.mjs +++ b/js/examples/capture-mirror-default.mjs @@ -2,7 +2,7 @@ // Default behavior (capture: true, mirror: true) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Default behavior (capture: true, mirror: true):'); console.log('await $`echo "Default: both enabled"`'); diff --git a/js/examples/capture-mirror-performance.mjs b/js/examples/capture-mirror-performance.mjs index 3c0f0e5..f047bda 100755 --- a/js/examples/capture-mirror-performance.mjs +++ b/js/examples/capture-mirror-performance.mjs @@ -2,7 +2,7 @@ // capture: false, mirror: false (maximum performance) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('capture: false, mirror: false:'); console.log( diff --git a/js/examples/capture-mirror-show-only.mjs b/js/examples/capture-mirror-show-only.mjs index eae1e02..6e85b78 100755 --- a/js/examples/capture-mirror-show-only.mjs +++ b/js/examples/capture-mirror-show-only.mjs @@ -2,7 +2,7 @@ // capture: false, mirror: true (just show output) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('capture: false, mirror: true:'); console.log( diff --git a/js/examples/capture-mirror-silent-processing.mjs b/js/examples/capture-mirror-silent-processing.mjs index 72daac4..5d961ff 100755 --- a/js/examples/capture-mirror-silent-processing.mjs +++ b/js/examples/capture-mirror-silent-processing.mjs @@ -2,7 +2,7 @@ // capture: true, mirror: false (silent data processing) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('capture: true, mirror: false:'); console.log( diff --git a/js/examples/ci-debug-baseline-vs-library.mjs b/js/examples/ci-debug-baseline-vs-library.mjs index 7575967..53d1213 100755 --- a/js/examples/ci-debug-baseline-vs-library.mjs +++ b/js/examples/ci-debug-baseline-vs-library.mjs @@ -10,7 +10,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing baseline vs library behavior'); diff --git a/js/examples/ci-debug-es-module-loading.mjs b/js/examples/ci-debug-es-module-loading.mjs index 1bfcbba..f97d86b 100755 --- a/js/examples/ci-debug-es-module-loading.mjs +++ b/js/examples/ci-debug-es-module-loading.mjs @@ -10,7 +10,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing ES module loading in child processes'); @@ -19,7 +19,7 @@ async function testDirectESModule() { console.log('\nTEST 1: Direct ES module import in child process'); const script = ` - import { $ } from '../js/src/$.mjs'; + import { $ } from '../src/$.mjs'; console.log('Module loaded successfully'); const result = await $\`echo "ES module test"\`; console.log('Result:', result.stdout); diff --git a/js/examples/ci-debug-signal-handling.mjs b/js/examples/ci-debug-signal-handling.mjs index f47bd0d..d8136f0 100755 --- a/js/examples/ci-debug-signal-handling.mjs +++ b/js/examples/ci-debug-signal-handling.mjs @@ -10,7 +10,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing signal handling in CI environment'); diff --git a/js/examples/ci-debug-stdout-buffering.mjs b/js/examples/ci-debug-stdout-buffering.mjs index 18512ce..2f6bbbc 100755 --- a/js/examples/ci-debug-stdout-buffering.mjs +++ b/js/examples/ci-debug-stdout-buffering.mjs @@ -10,7 +10,7 @@ * Solution: Force stdout flush in non-TTY environments. */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing stdout buffering in CI environment'); console.log('Is TTY?', process.stdout.isTTY); diff --git a/js/examples/ci-debug-test-timeouts.mjs b/js/examples/ci-debug-test-timeouts.mjs index 1d75a4a..ccf10e7 100755 --- a/js/examples/ci-debug-test-timeouts.mjs +++ b/js/examples/ci-debug-test-timeouts.mjs @@ -10,7 +10,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing timeout handling strategies'); diff --git a/js/examples/claude-exact-file-output.mjs b/js/examples/claude-exact-file-output.mjs index 20744aa..c13a7e2 100755 --- a/js/examples/claude-exact-file-output.mjs +++ b/js/examples/claude-exact-file-output.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { appendFileSync } from 'fs'; const claude = 'claude'; diff --git a/js/examples/claude-exact-jq.mjs b/js/examples/claude-exact-jq.mjs index 1bd832d..5d5caa7 100755 --- a/js/examples/claude-exact-jq.mjs +++ b/js/examples/claude-exact-jq.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const claude = 'claude'; console.log('๐Ÿค– Claude โ†’ jq streaming pipeline'); diff --git a/js/examples/claude-exact-streaming.mjs b/js/examples/claude-exact-streaming.mjs index 01dd473..1e4c29c 100755 --- a/js/examples/claude-exact-streaming.mjs +++ b/js/examples/claude-exact-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const claude = 'claude'; console.log('๐Ÿค– Claude exact streaming example'); diff --git a/js/examples/claude-jq-pipeline.mjs b/js/examples/claude-jq-pipeline.mjs index 537925a..6d12f6c 100644 --- a/js/examples/claude-jq-pipeline.mjs +++ b/js/examples/claude-jq-pipeline.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('๐Ÿค– Claude โ†’ jq streaming pipeline'); diff --git a/js/examples/claude-streaming-basic.mjs b/js/examples/claude-streaming-basic.mjs index 2daf974..1eec32c 100755 --- a/js/examples/claude-streaming-basic.mjs +++ b/js/examples/claude-streaming-basic.mjs @@ -9,7 +9,7 @@ * 3. Both console display and file writing simultaneously */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { writeFileSync, appendFileSync, existsSync } from 'fs'; // Claude command - using a prompt that should generate multiple chunks diff --git a/js/examples/claude-streaming-demo.mjs b/js/examples/claude-streaming-demo.mjs index a706071..c085012 100755 --- a/js/examples/claude-streaming-demo.mjs +++ b/js/examples/claude-streaming-demo.mjs @@ -10,7 +10,7 @@ * 4. Handling of both stdout and stderr */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { writeFileSync, appendFileSync, existsSync } from 'fs'; // We'll use a command that produces output over time to simulate streaming diff --git a/js/examples/claude-streaming-final.mjs b/js/examples/claude-streaming-final.mjs index 41ab255..3f6a776 100644 --- a/js/examples/claude-streaming-final.mjs +++ b/js/examples/claude-streaming-final.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { appendFileSync } from 'fs'; console.log('๐Ÿค– Claude streaming example'); diff --git a/js/examples/cleanup-verification-test.mjs b/js/examples/cleanup-verification-test.mjs index 252a1d3..da066f0 100755 --- a/js/examples/cleanup-verification-test.mjs +++ b/js/examples/cleanup-verification-test.mjs @@ -2,7 +2,7 @@ // Test comprehensive resource cleanup // This runs in a subprocess for isolation -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/colors-buffer-processing.mjs b/js/examples/colors-buffer-processing.mjs index 233c7be..536368f 100755 --- a/js/examples/colors-buffer-processing.mjs +++ b/js/examples/colors-buffer-processing.mjs @@ -2,7 +2,7 @@ // Using AnsiUtils.cleanForProcessing() for Buffer data -import { $, AnsiUtils } from '../js/src/$.mjs'; +import { $, AnsiUtils } from '../src/$.mjs'; console.log('Using AnsiUtils.cleanForProcessing() for Buffer data:'); const colorCommand = diff --git a/js/examples/colors-default-preserved.mjs b/js/examples/colors-default-preserved.mjs index 49da063..965340c 100755 --- a/js/examples/colors-default-preserved.mjs +++ b/js/examples/colors-default-preserved.mjs @@ -2,7 +2,7 @@ // Default behavior (ANSI colors preserved) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Default behavior (ANSI colors preserved):'); const colorCommand = diff --git a/js/examples/colors-per-command-config.mjs b/js/examples/colors-per-command-config.mjs index 955c158..65d5d2b 100755 --- a/js/examples/colors-per-command-config.mjs +++ b/js/examples/colors-per-command-config.mjs @@ -2,7 +2,7 @@ // Per-command ANSI configuration -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Per-command ANSI configuration:'); const colorCommand = diff --git a/js/examples/colors-strip-ansi.mjs b/js/examples/colors-strip-ansi.mjs index a21d3e4..3f5aadd 100755 --- a/js/examples/colors-strip-ansi.mjs +++ b/js/examples/colors-strip-ansi.mjs @@ -2,7 +2,7 @@ // Using AnsiUtils.stripAnsi() for clean data processing -import { $, AnsiUtils } from '../js/src/$.mjs'; +import { $, AnsiUtils } from '../src/$.mjs'; console.log('Using AnsiUtils.stripAnsi() for clean data processing:'); const colorCommand = diff --git a/js/examples/commandstream-jq.mjs b/js/examples/commandstream-jq.mjs index d6f4ba7..3bfda4b 100644 --- a/js/examples/commandstream-jq.mjs +++ b/js/examples/commandstream-jq.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { appendFileSync } from 'fs'; console.log('๐Ÿค– Command-stream: Claude โ†’ jq pipeline'); diff --git a/js/examples/commandstream-working.mjs b/js/examples/commandstream-working.mjs index 043dade..b5d39f3 100644 --- a/js/examples/commandstream-working.mjs +++ b/js/examples/commandstream-working.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('๐Ÿค– Command-stream: Claude with stdin'); diff --git a/js/examples/comprehensive-streams-demo.mjs b/js/examples/comprehensive-streams-demo.mjs index 52dfd15..8de5e52 100755 --- a/js/examples/comprehensive-streams-demo.mjs +++ b/js/examples/comprehensive-streams-demo.mjs @@ -5,7 +5,7 @@ * Shows: streams.stdin, streams.stdout, streams.stderr, buffers, strings, kill() */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('๐Ÿš€ command-stream: Comprehensive Streaming Demo'); console.log('='.repeat(50)); diff --git a/js/examples/ctrl-c-concurrent-processes.mjs b/js/examples/ctrl-c-concurrent-processes.mjs index 664dde5..b20a50b 100755 --- a/js/examples/ctrl-c-concurrent-processes.mjs +++ b/js/examples/ctrl-c-concurrent-processes.mjs @@ -2,7 +2,7 @@ // Multiple concurrent processes CTRL+C handling -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Multiple concurrent processes'); console.log('Starting 3 processes - press CTRL+C to interrupt all...\n'); diff --git a/js/examples/ctrl-c-long-running-command.mjs b/js/examples/ctrl-c-long-running-command.mjs index 91f4606..f368eec 100755 --- a/js/examples/ctrl-c-long-running-command.mjs +++ b/js/examples/ctrl-c-long-running-command.mjs @@ -2,7 +2,7 @@ // Long-running command that can be interrupted with CTRL+C -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Long-running command (ping)'); console.log('Press CTRL+C to interrupt...\n'); diff --git a/js/examples/ctrl-c-real-system-command.mjs b/js/examples/ctrl-c-real-system-command.mjs index d8b8da0..f9ddb0d 100755 --- a/js/examples/ctrl-c-real-system-command.mjs +++ b/js/examples/ctrl-c-real-system-command.mjs @@ -2,7 +2,7 @@ // Real system command CTRL+C handling -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Real system command (ping)'); console.log('Starting ping command - press CTRL+C to interrupt...\n'); diff --git a/js/examples/ctrl-c-sleep-command.mjs b/js/examples/ctrl-c-sleep-command.mjs index 3cb8e2f..0b9c3f0 100755 --- a/js/examples/ctrl-c-sleep-command.mjs +++ b/js/examples/ctrl-c-sleep-command.mjs @@ -2,7 +2,7 @@ // Sleep command with signal handling -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Sleep command'); console.log('Press CTRL+C to interrupt the 10-second sleep...\n'); diff --git a/js/examples/ctrl-c-stdin-forwarding.mjs b/js/examples/ctrl-c-stdin-forwarding.mjs index d3e3199..ce9d213 100755 --- a/js/examples/ctrl-c-stdin-forwarding.mjs +++ b/js/examples/ctrl-c-stdin-forwarding.mjs @@ -2,7 +2,7 @@ // Command with stdin forwarding and CTRL+C handling -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Command with stdin forwarding'); console.log( diff --git a/js/examples/ctrl-c-virtual-command.mjs b/js/examples/ctrl-c-virtual-command.mjs index 0e1a845..da9e474 100755 --- a/js/examples/ctrl-c-virtual-command.mjs +++ b/js/examples/ctrl-c-virtual-command.mjs @@ -2,7 +2,7 @@ // Virtual sleep command CTRL+C handling -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Virtual sleep command'); console.log('Sleeping for 30 seconds - press CTRL+C to interrupt...\n'); diff --git a/js/examples/debug-already-started.mjs b/js/examples/debug-already-started.mjs index 21702de..156d625 100755 --- a/js/examples/debug-already-started.mjs +++ b/js/examples/debug-already-started.mjs @@ -2,7 +2,7 @@ // Testing already started behavior -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing already started behavior:'); const runner = $`echo "already started"`; diff --git a/js/examples/debug-ansi-processing.mjs b/js/examples/debug-ansi-processing.mjs index e0060ce..b17573b 100755 --- a/js/examples/debug-ansi-processing.mjs +++ b/js/examples/debug-ansi-processing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, processOutput, getAnsiConfig } from '../js/src/$.mjs'; +import { $, processOutput, getAnsiConfig } from '../src/$.mjs'; console.log('=== Debug ANSI Processing ===\n'); diff --git a/js/examples/debug-basic-streaming.mjs b/js/examples/debug-basic-streaming.mjs index abdee1e..dde13d1 100755 --- a/js/examples/debug-basic-streaming.mjs +++ b/js/examples/debug-basic-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Basic Streaming Debug ==='); diff --git a/js/examples/debug-child-process.mjs b/js/examples/debug-child-process.mjs index ae53157..8638898 100644 --- a/js/examples/debug-child-process.mjs +++ b/js/examples/debug-child-process.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function debugChildProcess() { console.log('๐Ÿ› Debugging child process creation'); diff --git a/js/examples/debug-child-state.mjs b/js/examples/debug-child-state.mjs index eb2c246..e3d4ebf 100755 --- a/js/examples/debug-child-state.mjs +++ b/js/examples/debug-child-state.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function debugChildState() { const cmd = $`cat`; diff --git a/js/examples/debug-chunking.mjs b/js/examples/debug-chunking.mjs index 63ca960..82fe6b5 100755 --- a/js/examples/debug-chunking.mjs +++ b/js/examples/debug-chunking.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const claude = 'claude'; console.log('๐Ÿ› Debug chunking test'); diff --git a/js/examples/debug-command-parsing.mjs b/js/examples/debug-command-parsing.mjs index 390c8d4..8f070a6 100644 --- a/js/examples/debug-command-parsing.mjs +++ b/js/examples/debug-command-parsing.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Debug command parsing -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-complete-consolidation.mjs b/js/examples/debug-complete-consolidation.mjs index 7059d81..9fb88a2 100755 --- a/js/examples/debug-complete-consolidation.mjs +++ b/js/examples/debug-complete-consolidation.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Complete Finish Method Consolidation Test ==='); diff --git a/js/examples/debug-echo-args.mjs b/js/examples/debug-echo-args.mjs index 609d7e6..41bd745 100644 --- a/js/examples/debug-echo-args.mjs +++ b/js/examples/debug-echo-args.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function debugEchoArgs() { console.log('=== Debug Echo Args ==='); diff --git a/js/examples/debug-emit-timing.mjs b/js/examples/debug-emit-timing.mjs index ed6c019..58c1861 100755 --- a/js/examples/debug-emit-timing.mjs +++ b/js/examples/debug-emit-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Emit Timing Debug ==='); diff --git a/js/examples/debug-end-event.mjs b/js/examples/debug-end-event.mjs index 1787982..5a5c8aa 100755 --- a/js/examples/debug-end-event.mjs +++ b/js/examples/debug-end-event.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== End Event Debug ==='); diff --git a/js/examples/debug-errexit.mjs b/js/examples/debug-errexit.mjs index 77e29e6..0824541 100755 --- a/js/examples/debug-errexit.mjs +++ b/js/examples/debug-errexit.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, enableErrExit } from '../js/src/$.mjs'; +import { $, enableErrExit } from '../src/$.mjs'; console.log('=== Errexit Test ==='); diff --git a/js/examples/debug-event-emission.mjs b/js/examples/debug-event-emission.mjs index f7553b4..14954d2 100755 --- a/js/examples/debug-event-emission.mjs +++ b/js/examples/debug-event-emission.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, disableVirtualCommands } from '../src/$.mjs'; console.log('=== Event Emission Debug ==='); diff --git a/js/examples/debug-event-timing.mjs b/js/examples/debug-event-timing.mjs index 60ee931..66d14cb 100755 --- a/js/examples/debug-event-timing.mjs +++ b/js/examples/debug-event-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, disableVirtualCommands } from '../src/$.mjs'; console.log('=== Event Timing Debug ==='); diff --git a/js/examples/debug-event-vs-result.mjs b/js/examples/debug-event-vs-result.mjs index f505b6b..90a5ccb 100755 --- a/js/examples/debug-event-vs-result.mjs +++ b/js/examples/debug-event-vs-result.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Event vs Result Comparison ===\n'); diff --git a/js/examples/debug-exact-command.mjs b/js/examples/debug-exact-command.mjs index ee3a900..93da65d 100755 --- a/js/examples/debug-exact-command.mjs +++ b/js/examples/debug-exact-command.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing Exact Command from jq-colors-streaming.mjs ===\n'); diff --git a/js/examples/debug-exact-test-scenario.mjs b/js/examples/debug-exact-test-scenario.mjs index f2d5f60..542cd50 100755 --- a/js/examples/debug-exact-test-scenario.mjs +++ b/js/examples/debug-exact-test-scenario.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Exact replica of the failing test scenario -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-execution-path.mjs b/js/examples/debug-execution-path.mjs index 15d09cf..1dba77f 100755 --- a/js/examples/debug-execution-path.mjs +++ b/js/examples/debug-execution-path.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Debug execution path to see exactly what's happening -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode to see detailed tracing process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-exit-command.mjs b/js/examples/debug-exit-command.mjs index 75824ad..c7f69c9 100755 --- a/js/examples/debug-exit-command.mjs +++ b/js/examples/debug-exit-command.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug the exit command specifically -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-exit-virtual.mjs b/js/examples/debug-exit-virtual.mjs index 42dfb61..3d96d10 100755 --- a/js/examples/debug-exit-virtual.mjs +++ b/js/examples/debug-exit-virtual.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug the virtual exit command directly -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-finish-consolidation.mjs b/js/examples/debug-finish-consolidation.mjs index 5618b94..df7e62e 100755 --- a/js/examples/debug-finish-consolidation.mjs +++ b/js/examples/debug-finish-consolidation.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Finish Method Consolidation Test ==='); diff --git a/js/examples/debug-force-cleanup.mjs b/js/examples/debug-force-cleanup.mjs index e1c7ad9..240d2a4 100755 --- a/js/examples/debug-force-cleanup.mjs +++ b/js/examples/debug-force-cleanup.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Test the forceCleanupAll function -import { $, forceCleanupAll } from '../js/src/$.mjs'; +import { $, forceCleanupAll } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-getter-basic.mjs b/js/examples/debug-getter-basic.mjs index f4fa5b5..3669ec5 100755 --- a/js/examples/debug-getter-basic.mjs +++ b/js/examples/debug-getter-basic.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Basic Getter Debug ==='); diff --git a/js/examples/debug-getter-direct.mjs b/js/examples/debug-getter-direct.mjs index b31d901..042c9d7 100755 --- a/js/examples/debug-getter-direct.mjs +++ b/js/examples/debug-getter-direct.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Direct Getter Debug ==='); diff --git a/js/examples/debug-getter-internals.mjs b/js/examples/debug-getter-internals.mjs index 5f1699f..6681e3a 100755 --- a/js/examples/debug-getter-internals.mjs +++ b/js/examples/debug-getter-internals.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, disableVirtualCommands } from '../src/$.mjs'; console.log('=== Getter Internals Debug ==='); diff --git a/js/examples/debug-handler-detection.mjs b/js/examples/debug-handler-detection.mjs index 2b90151..a50526d 100755 --- a/js/examples/debug-handler-detection.mjs +++ b/js/examples/debug-handler-detection.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test the exact pattern matching used by the tests -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-idempotent-finish.mjs b/js/examples/debug-idempotent-finish.mjs index 1fb2eaf..7e8cc72 100755 --- a/js/examples/debug-idempotent-finish.mjs +++ b/js/examples/debug-idempotent-finish.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Idempotent Finish Method Test ==='); diff --git a/js/examples/debug-idempotent-kill.mjs b/js/examples/debug-idempotent-kill.mjs index 3236b76..3a6c41f 100755 --- a/js/examples/debug-idempotent-kill.mjs +++ b/js/examples/debug-idempotent-kill.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Idempotent Kill Test ==='); diff --git a/js/examples/debug-interpolation-individual.mjs b/js/examples/debug-interpolation-individual.mjs index d814ef6..b112c42 100644 --- a/js/examples/debug-interpolation-individual.mjs +++ b/js/examples/debug-interpolation-individual.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Individual Debugging for Quoting Issue ===\n'); diff --git a/js/examples/debug-interpolation-issue.mjs b/js/examples/debug-interpolation-issue.mjs index f10ad9e..7c59cf9 100644 --- a/js/examples/debug-interpolation-issue.mjs +++ b/js/examples/debug-interpolation-issue.mjs @@ -5,7 +5,7 @@ // Issue: https://github.com/link-foundation/command-stream/issues/12 // Error: ENOENT: no such file or directory, posix_spawn ''/Users/konard/.claude/local/claude'' -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const claude = process.env.CLAUDE_PATH || '/Users/konard/.claude/local/claude'; diff --git a/js/examples/debug-jq-streaming.mjs b/js/examples/debug-jq-streaming.mjs index deccd8a..0bad419 100755 --- a/js/examples/debug-jq-streaming.mjs +++ b/js/examples/debug-jq-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== JQ Streaming Debug ==='); diff --git a/js/examples/debug-jq-tty-colors.mjs b/js/examples/debug-jq-tty-colors.mjs index 28a882f..018b6d7 100644 --- a/js/examples/debug-jq-tty-colors.mjs +++ b/js/examples/debug-jq-tty-colors.mjs @@ -5,7 +5,7 @@ * This helps diagnose why the test behaves differently in different environments */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { spawn } from 'child_process'; const testJson = diff --git a/js/examples/debug-kill-cleanup.mjs b/js/examples/debug-kill-cleanup.mjs index 3c97c8e..34f0234 100755 --- a/js/examples/debug-kill-cleanup.mjs +++ b/js/examples/debug-kill-cleanup.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; function getSigintHandlerCount() { const sigintListeners = process.listeners('SIGINT'); diff --git a/js/examples/debug-kill-method.mjs b/js/examples/debug-kill-method.mjs index 3e51e46..da7f7b1 100755 --- a/js/examples/debug-kill-method.mjs +++ b/js/examples/debug-kill-method.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing kill() method'); diff --git a/js/examples/debug-listener-interference.mjs b/js/examples/debug-listener-interference.mjs index f757a38..2037c20 100755 --- a/js/examples/debug-listener-interference.mjs +++ b/js/examples/debug-listener-interference.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Listener Interference Debug ==='); diff --git a/js/examples/debug-listener-lifecycle.mjs b/js/examples/debug-listener-lifecycle.mjs index a7e7c2f..2f689bf 100755 --- a/js/examples/debug-listener-lifecycle.mjs +++ b/js/examples/debug-listener-lifecycle.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Listener Lifecycle Debug ==='); diff --git a/js/examples/debug-listener-timing.mjs b/js/examples/debug-listener-timing.mjs index 4d190d0..6d006e4 100755 --- a/js/examples/debug-listener-timing.mjs +++ b/js/examples/debug-listener-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Listener Timing Debug ==='); diff --git a/js/examples/debug-listeners-property.mjs b/js/examples/debug-listeners-property.mjs index d327020..0a92c88 100755 --- a/js/examples/debug-listeners-property.mjs +++ b/js/examples/debug-listeners-property.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Listeners Property Debug ==='); diff --git a/js/examples/debug-map-methods.mjs b/js/examples/debug-map-methods.mjs index 7587468..6280d97 100755 --- a/js/examples/debug-map-methods.mjs +++ b/js/examples/debug-map-methods.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Map Methods Debug ==='); diff --git a/js/examples/debug-not-awaited-cleanup.mjs b/js/examples/debug-not-awaited-cleanup.mjs index 9d72947..32b0a40 100755 --- a/js/examples/debug-not-awaited-cleanup.mjs +++ b/js/examples/debug-not-awaited-cleanup.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test the non-awaited command cleanup issue -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-off-method.mjs b/js/examples/debug-off-method.mjs index b01eb61..4d62d21 100755 --- a/js/examples/debug-off-method.mjs +++ b/js/examples/debug-off-method.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Off Method Debug ==='); diff --git a/js/examples/debug-option-merging.mjs b/js/examples/debug-option-merging.mjs index 3dcb414..e4ed533 100755 --- a/js/examples/debug-option-merging.mjs +++ b/js/examples/debug-option-merging.mjs @@ -2,7 +2,7 @@ // Testing option merging -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing option merging:'); const runner = $`echo "option merge test"`; diff --git a/js/examples/debug-options.mjs b/js/examples/debug-options.mjs index 4e1cccb..729d766 100644 --- a/js/examples/debug-options.mjs +++ b/js/examples/debug-options.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable trace to see what's happening process.env.COMMAND_STREAM_TRACE = 'ProcessRunner'; diff --git a/js/examples/debug-output.mjs b/js/examples/debug-output.mjs index 0396311..3ebc629 100644 --- a/js/examples/debug-output.mjs +++ b/js/examples/debug-output.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; enableVirtualCommands(); shell.verbose(false); diff --git a/js/examples/debug-pattern-matching.mjs b/js/examples/debug-pattern-matching.mjs index e18f4f6..882c2ea 100755 --- a/js/examples/debug-pattern-matching.mjs +++ b/js/examples/debug-pattern-matching.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test pattern matching in signal handler detection -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-pipeline-cat.mjs b/js/examples/debug-pipeline-cat.mjs index 4f5c46d..8c211ee 100755 --- a/js/examples/debug-pipeline-cat.mjs +++ b/js/examples/debug-pipeline-cat.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Debug pipeline with cat -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-pipeline-cleanup.mjs b/js/examples/debug-pipeline-cleanup.mjs index 41973df..8aad787 100755 --- a/js/examples/debug-pipeline-cleanup.mjs +++ b/js/examples/debug-pipeline-cleanup.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test pipeline cleanup issues -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-pipeline-error-detailed.mjs b/js/examples/debug-pipeline-error-detailed.mjs index d63ac01..34863c3 100755 --- a/js/examples/debug-pipeline-error-detailed.mjs +++ b/js/examples/debug-pipeline-error-detailed.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Detailed debug script for pipeline error cleanup -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode for tracing process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-pipeline-error.mjs b/js/examples/debug-pipeline-error.mjs index 7db74ec..00a5f26 100755 --- a/js/examples/debug-pipeline-error.mjs +++ b/js/examples/debug-pipeline-error.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test the specific pipeline error scenario -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-pipeline-issue.mjs b/js/examples/debug-pipeline-issue.mjs index 8846ecc..3a0bba3 100755 --- a/js/examples/debug-pipeline-issue.mjs +++ b/js/examples/debug-pipeline-issue.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Pipeline Debug ===\n'); diff --git a/js/examples/debug-pipeline-method.mjs b/js/examples/debug-pipeline-method.mjs index 0ec05f3..7638e29 100755 --- a/js/examples/debug-pipeline-method.mjs +++ b/js/examples/debug-pipeline-method.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Debug Which Pipeline Method is Used ===\n'); diff --git a/js/examples/debug-pipeline-stream.mjs b/js/examples/debug-pipeline-stream.mjs index 4485ab8..78925c0 100755 --- a/js/examples/debug-pipeline-stream.mjs +++ b/js/examples/debug-pipeline-stream.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Pipeline Stream Debug ==='); diff --git a/js/examples/debug-pipeline.mjs b/js/examples/debug-pipeline.mjs index 12b39cc..4c93986 100755 --- a/js/examples/debug-pipeline.mjs +++ b/js/examples/debug-pipeline.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Debug Pipeline Selection ===\n'); diff --git a/js/examples/debug-process-exit-trace.mjs b/js/examples/debug-process-exit-trace.mjs index 60e9baa..48c02ce 100755 --- a/js/examples/debug-process-exit-trace.mjs +++ b/js/examples/debug-process-exit-trace.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to trace process.exit calls -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-process-path.mjs b/js/examples/debug-process-path.mjs index 09043b3..1b67ae2 100755 --- a/js/examples/debug-process-path.mjs +++ b/js/examples/debug-process-path.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Process Path Debug ==='); diff --git a/js/examples/debug-property-check.mjs b/js/examples/debug-property-check.mjs index 8dca19f..e95c3eb 100755 --- a/js/examples/debug-property-check.mjs +++ b/js/examples/debug-property-check.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Property Check Debug ==='); diff --git a/js/examples/debug-resource-cleanup.mjs b/js/examples/debug-resource-cleanup.mjs index f9547cb..b0b2561 100755 --- a/js/examples/debug-resource-cleanup.mjs +++ b/js/examples/debug-resource-cleanup.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test resource cleanup behavior -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-sigint-child-handler.mjs b/js/examples/debug-sigint-child-handler.mjs index cca7cb1..b498dcf 100755 --- a/js/examples/debug-sigint-child-handler.mjs +++ b/js/examples/debug-sigint-child-handler.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test SIGINT handler interaction -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-sigint-forwarding.mjs b/js/examples/debug-sigint-forwarding.mjs index 6d54f80..d29aa3c 100755 --- a/js/examples/debug-sigint-forwarding.mjs +++ b/js/examples/debug-sigint-forwarding.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test SIGINT forwarding behavior -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-sigint-handler-install.mjs b/js/examples/debug-sigint-handler-install.mjs index 68116a5..3e187d7 100755 --- a/js/examples/debug-sigint-handler-install.mjs +++ b/js/examples/debug-sigint-handler-install.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to trace SIGINT handler installation and removal -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-sigint-handler-order.mjs b/js/examples/debug-sigint-handler-order.mjs index c933d9f..9372280 100755 --- a/js/examples/debug-sigint-handler-order.mjs +++ b/js/examples/debug-sigint-handler-order.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to test SIGINT handler order and execution -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-sigint-listeners.mjs b/js/examples/debug-sigint-listeners.mjs index 6d022f4..3ab05f5 100755 --- a/js/examples/debug-sigint-listeners.mjs +++ b/js/examples/debug-sigint-listeners.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== SIGINT Listeners Debug ==='); diff --git a/js/examples/debug-sigint-start-pattern.mjs b/js/examples/debug-sigint-start-pattern.mjs index 66e13a8..a885b6e 100755 --- a/js/examples/debug-sigint-start-pattern.mjs +++ b/js/examples/debug-sigint-start-pattern.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== SIGINT Listeners Start Pattern Debug ==='); diff --git a/js/examples/debug-sigint-timer.mjs b/js/examples/debug-sigint-timer.mjs index 734a498..a9f680b 100755 --- a/js/examples/debug-sigint-timer.mjs +++ b/js/examples/debug-sigint-timer.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env bun // Debug script to see if our timer fix is working -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/debug-simple-command.mjs b/js/examples/debug-simple-command.mjs index ffab7ae..a40f952 100644 --- a/js/examples/debug-simple-command.mjs +++ b/js/examples/debug-simple-command.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function debugSimpleCommand() { console.log('๐Ÿ› Testing with a simple non-builtin command'); diff --git a/js/examples/debug-simple-getter.mjs b/js/examples/debug-simple-getter.mjs index 4d4ce09..c07fdc6 100755 --- a/js/examples/debug-simple-getter.mjs +++ b/js/examples/debug-simple-getter.mjs @@ -16,7 +16,7 @@ console.log('TestClass stdout:', test.stdout); console.log('Should be null:', test.stdout === null); // Now test with actual ProcessRunner -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const cmd = $`echo "test"`; console.log('ProcessRunner stdout:', cmd.stdout); diff --git a/js/examples/debug-simple.mjs b/js/examples/debug-simple.mjs index ee0896e..fd5f55f 100755 --- a/js/examples/debug-simple.mjs +++ b/js/examples/debug-simple.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, getAnsiConfig } from '../js/src/$.mjs'; +import { $, getAnsiConfig } from '../src/$.mjs'; console.log('=== Simple ANSI Debug ===\n'); diff --git a/js/examples/debug-simplified-finished.mjs b/js/examples/debug-simplified-finished.mjs index eef6dc3..f1fd2b2 100755 --- a/js/examples/debug-simplified-finished.mjs +++ b/js/examples/debug-simplified-finished.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Simplified Finished Field Test ==='); diff --git a/js/examples/debug-stack-overflow.mjs b/js/examples/debug-stack-overflow.mjs index 07cacb0..8154082 100644 --- a/js/examples/debug-stack-overflow.mjs +++ b/js/examples/debug-stack-overflow.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function debugStackOverflow() { console.log('Testing simple echo command...'); diff --git a/js/examples/debug-stdin-simple.mjs b/js/examples/debug-stdin-simple.mjs index b0c7309..9c70305 100755 --- a/js/examples/debug-stdin-simple.mjs +++ b/js/examples/debug-stdin-simple.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Debug: Simple stdin test ==='); diff --git a/js/examples/debug-stdin.mjs b/js/examples/debug-stdin.mjs index 21c4af9..cef39ea 100644 --- a/js/examples/debug-stdin.mjs +++ b/js/examples/debug-stdin.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function debugStdin() { console.log('๐Ÿ› Debugging stdin streams'); diff --git a/js/examples/debug-stream-emitter-isolated.mjs b/js/examples/debug-stream-emitter-isolated.mjs index 4ea8ce3..f677c7e 100755 --- a/js/examples/debug-stream-emitter-isolated.mjs +++ b/js/examples/debug-stream-emitter-isolated.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Isolated StreamEmitter Debug ==='); diff --git a/js/examples/debug-stream-emitter.mjs b/js/examples/debug-stream-emitter.mjs index b960433..cbbd102 100755 --- a/js/examples/debug-stream-emitter.mjs +++ b/js/examples/debug-stream-emitter.mjs @@ -2,7 +2,7 @@ process.env.COMMAND_STREAM_VERBOSE = 'true'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== StreamEmitter Debug ==='); diff --git a/js/examples/debug-stream-events.mjs b/js/examples/debug-stream-events.mjs index 8f9b05f..0936c68 100755 --- a/js/examples/debug-stream-events.mjs +++ b/js/examples/debug-stream-events.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Stream Events Debug ==='); diff --git a/js/examples/debug-stream-generator.mjs b/js/examples/debug-stream-generator.mjs index 1bde6d7..4abdde5 100755 --- a/js/examples/debug-stream-generator.mjs +++ b/js/examples/debug-stream-generator.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Stream Generator Debug ==='); diff --git a/js/examples/debug-stream-getter-issue.mjs b/js/examples/debug-stream-getter-issue.mjs index 7cbbdd4..76df5fe 100755 --- a/js/examples/debug-stream-getter-issue.mjs +++ b/js/examples/debug-stream-getter-issue.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, disableVirtualCommands } from '../src/$.mjs'; console.log('=== Stream Getter Issue Debug ==='); diff --git a/js/examples/debug-stream-getter.mjs b/js/examples/debug-stream-getter.mjs index 3fd0fce..eae8e02 100755 --- a/js/examples/debug-stream-getter.mjs +++ b/js/examples/debug-stream-getter.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, disableVirtualCommands } from '../src/$.mjs'; console.log('=== Stream Getter Debug ==='); diff --git a/js/examples/debug-stream-internals.mjs b/js/examples/debug-stream-internals.mjs index 4852bb0..8be210c 100755 --- a/js/examples/debug-stream-internals.mjs +++ b/js/examples/debug-stream-internals.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Stream Internals Debug ==='); diff --git a/js/examples/debug-stream-method.mjs b/js/examples/debug-stream-method.mjs index 7e8772b..226e454 100755 --- a/js/examples/debug-stream-method.mjs +++ b/js/examples/debug-stream-method.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Stream Method Debug ==='); diff --git a/js/examples/debug-stream-object.mjs b/js/examples/debug-stream-object.mjs index 6c44d83..1a6ac0d 100755 --- a/js/examples/debug-stream-object.mjs +++ b/js/examples/debug-stream-object.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function debugStreamObject() { console.log('=== Debug stream object details ==='); diff --git a/js/examples/debug-stream-properties.mjs b/js/examples/debug-stream-properties.mjs index dfd6dcf..11a0f9f 100755 --- a/js/examples/debug-stream-properties.mjs +++ b/js/examples/debug-stream-properties.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, disableVirtualCommands } from '../src/$.mjs'; console.log('=== Stream Properties Debug ==='); diff --git a/js/examples/debug-stream-timing.mjs b/js/examples/debug-stream-timing.mjs index 6ce16ce..131bf98 100755 --- a/js/examples/debug-stream-timing.mjs +++ b/js/examples/debug-stream-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, disableVirtualCommands } from '../src/$.mjs'; console.log('=== Stream Timing Debug ==='); diff --git a/js/examples/debug-streaming.mjs b/js/examples/debug-streaming.mjs index 1b5b38d..997201a 100755 --- a/js/examples/debug-streaming.mjs +++ b/js/examples/debug-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Debug Streaming Test ===\n'); diff --git a/js/examples/debug-test-state.mjs b/js/examples/debug-test-state.mjs index 0c892a9..2d9897f 100644 --- a/js/examples/debug-test-state.mjs +++ b/js/examples/debug-test-state.mjs @@ -1,5 +1,5 @@ // Debug test to understand why virtual commands get bypassed in full test suite -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function debugTestState() { console.log('=== Debug Test State ==='); diff --git a/js/examples/debug-user-sigint.mjs b/js/examples/debug-user-sigint.mjs index 823eaa8..7c786ee 100755 --- a/js/examples/debug-user-sigint.mjs +++ b/js/examples/debug-user-sigint.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; let sigintReceived = false; diff --git a/js/examples/debug-virtual-disable.mjs b/js/examples/debug-virtual-disable.mjs index c1e2c7a..70ffbcc 100755 --- a/js/examples/debug-virtual-disable.mjs +++ b/js/examples/debug-virtual-disable.mjs @@ -3,7 +3,7 @@ // Enable verbose tracing process.env.COMMAND_STREAM_VERBOSE = 'true'; -import { $, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, disableVirtualCommands } from '../src/$.mjs'; console.log('=== Virtual Disable Debug ==='); diff --git a/js/examples/debug-virtual-vs-real.mjs b/js/examples/debug-virtual-vs-real.mjs index 845525f..6daf97f 100755 --- a/js/examples/debug-virtual-vs-real.mjs +++ b/js/examples/debug-virtual-vs-real.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, disableVirtualCommands } from '../js/src/$.mjs'; +import { $, disableVirtualCommands } from '../src/$.mjs'; console.log('=== Virtual vs Real Commands Debug ==='); diff --git a/js/examples/debug-with-trace.mjs b/js/examples/debug-with-trace.mjs index 311067b..3e5cfbc 100644 --- a/js/examples/debug-with-trace.mjs +++ b/js/examples/debug-with-trace.mjs @@ -4,7 +4,7 @@ process.env.COMMAND_STREAM_TRACE = 'all'; process.env.COMMAND_STREAM_VERBOSE = 'true'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function debugWithTrace() { console.log('๐Ÿ› Testing with full tracing enabled'); diff --git a/js/examples/debug_parent_stream.mjs b/js/examples/debug_parent_stream.mjs index da903e9..1122a91 100755 --- a/js/examples/debug_parent_stream.mjs +++ b/js/examples/debug_parent_stream.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== PARENT STREAM CLOSURE TEST ==='); diff --git a/js/examples/emulated-streaming-direct.mjs b/js/examples/emulated-streaming-direct.mjs index 7dee008..ee15ce9 100755 --- a/js/examples/emulated-streaming-direct.mjs +++ b/js/examples/emulated-streaming-direct.mjs @@ -2,7 +2,7 @@ // Direct execution of emulator -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Direct execution of emulator:'); const start = Date.now(); diff --git a/js/examples/emulated-streaming-jq-pipe.mjs b/js/examples/emulated-streaming-jq-pipe.mjs index 9e17051..8beb849 100755 --- a/js/examples/emulated-streaming-jq-pipe.mjs +++ b/js/examples/emulated-streaming-jq-pipe.mjs @@ -2,7 +2,7 @@ // Emulator piped through jq -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Emulator piped through jq:'); const start = Date.now(); diff --git a/js/examples/emulated-streaming-sh-pipe.mjs b/js/examples/emulated-streaming-sh-pipe.mjs index cb47b23..ee64b6a 100755 --- a/js/examples/emulated-streaming-sh-pipe.mjs +++ b/js/examples/emulated-streaming-sh-pipe.mjs @@ -2,7 +2,7 @@ // Using sh -c with pipe -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Using sh -c with pipe:'); const start = Date.now(); diff --git a/js/examples/events-build-process.mjs b/js/examples/events-build-process.mjs index 19c7df8..6dff4d1 100755 --- a/js/examples/events-build-process.mjs +++ b/js/examples/events-build-process.mjs @@ -2,7 +2,7 @@ // Build process simulation with events -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Build process simulation:'); const $buildProcess = $({ mirror: false }); diff --git a/js/examples/events-concurrent-streams.mjs b/js/examples/events-concurrent-streams.mjs index fa2f74f..9e93c40 100755 --- a/js/examples/events-concurrent-streams.mjs +++ b/js/examples/events-concurrent-streams.mjs @@ -2,7 +2,7 @@ // Multiple concurrent event streams -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Multiple concurrent event streams:'); diff --git a/js/examples/events-error-handling.mjs b/js/examples/events-error-handling.mjs index 24c8be3..ebb59ff 100755 --- a/js/examples/events-error-handling.mjs +++ b/js/examples/events-error-handling.mjs @@ -2,7 +2,7 @@ // Error handling and recovery with events -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Error handling and recovery:'); const $errorTest = $({ mirror: false }); diff --git a/js/examples/events-file-monitoring.mjs b/js/examples/events-file-monitoring.mjs index 899eba7..52a6afe 100755 --- a/js/examples/events-file-monitoring.mjs +++ b/js/examples/events-file-monitoring.mjs @@ -2,7 +2,7 @@ // File monitoring simulation with events -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('File monitoring simulation:'); const $fileMonitor = $({ mirror: false, capture: true }); diff --git a/js/examples/events-interactive-simulation.mjs b/js/examples/events-interactive-simulation.mjs index 3718f6d..a604788 100755 --- a/js/examples/events-interactive-simulation.mjs +++ b/js/examples/events-interactive-simulation.mjs @@ -2,7 +2,7 @@ // Interactive command simulation with events -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Interactive command simulation:'); const $interactive = $({ stdin: 'John\n25\nDeveloper\ny\n', mirror: false }); diff --git a/js/examples/events-log-processing.mjs b/js/examples/events-log-processing.mjs index bbfb44d..7d1819d 100755 --- a/js/examples/events-log-processing.mjs +++ b/js/examples/events-log-processing.mjs @@ -2,7 +2,7 @@ // Real-time log processing with events -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Real-time log processing:'); const $logProcessor = $({ mirror: false }); diff --git a/js/examples/events-network-monitoring.mjs b/js/examples/events-network-monitoring.mjs index 8a90ec1..04b200d 100755 --- a/js/examples/events-network-monitoring.mjs +++ b/js/examples/events-network-monitoring.mjs @@ -2,7 +2,7 @@ // Network monitoring with multiple hosts using events -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Network monitoring with multiple hosts:'); diff --git a/js/examples/events-ping-basic.mjs b/js/examples/events-ping-basic.mjs index fe8ceb8..edd849d 100755 --- a/js/examples/events-ping-basic.mjs +++ b/js/examples/events-ping-basic.mjs @@ -2,7 +2,7 @@ // Basic event-based ping with options -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Basic event-based ping (silent mode):'); const $silent = $({ mirror: false }); diff --git a/js/examples/events-progress-tracking.mjs b/js/examples/events-progress-tracking.mjs index 68e8a16..61d254e 100755 --- a/js/examples/events-progress-tracking.mjs +++ b/js/examples/events-progress-tracking.mjs @@ -2,7 +2,7 @@ // Long-running process with progress events -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Long-running process with progress tracking:'); const $progress = $({ mirror: false, capture: true }); diff --git a/js/examples/events-stdin-input.mjs b/js/examples/events-stdin-input.mjs index 298dc25..db67841 100755 --- a/js/examples/events-stdin-input.mjs +++ b/js/examples/events-stdin-input.mjs @@ -2,7 +2,7 @@ // Event-based with custom stdin -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Event-based with custom stdin:'); const $withInput = $({ stdin: 'Hello\nWorld\nTest\n', mirror: false }); diff --git a/js/examples/example-ansi-ls.mjs b/js/examples/example-ansi-ls.mjs index 924740e..2ae75ac 100755 --- a/js/examples/example-ansi-ls.mjs +++ b/js/examples/example-ansi-ls.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, AnsiUtils } from '../js/src/$.mjs'; +import { $, AnsiUtils } from '../src/$.mjs'; console.log('=== ANSI Color Example with ls command ===\n'); diff --git a/js/examples/example-top.mjs b/js/examples/example-top.mjs index 930d5d4..1897d4e 100755 --- a/js/examples/example-top.mjs +++ b/js/examples/example-top.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log( '=== Running top command with ANSI colors preserved (default behavior) ===' diff --git a/js/examples/final-ping-stdin-proof.mjs b/js/examples/final-ping-stdin-proof.mjs index 8d06a7e..44314b7 100755 --- a/js/examples/final-ping-stdin-proof.mjs +++ b/js/examples/final-ping-stdin-proof.mjs @@ -5,7 +5,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== FINAL PROOF: ping stdin vs kill() ==='); diff --git a/js/examples/final-test-shell-operators.mjs b/js/examples/final-test-shell-operators.mjs index b675155..e1ed56d 100644 --- a/js/examples/final-test-shell-operators.mjs +++ b/js/examples/final-test-shell-operators.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; import { mkdtempSync, rmSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/js/examples/final-working-examples.mjs b/js/examples/final-working-examples.mjs index dd42797..b5dcdcb 100755 --- a/js/examples/final-working-examples.mjs +++ b/js/examples/final-working-examples.mjs @@ -4,7 +4,7 @@ * Final working examples of streaming interfaces for README */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('๐Ÿš€ Final Working Examples - Streaming Interfaces'); console.log('='.repeat(55)); diff --git a/js/examples/gh-auth-test.mjs b/js/examples/gh-auth-test.mjs index 17761ea..e9fd589 100755 --- a/js/examples/gh-auth-test.mjs +++ b/js/examples/gh-auth-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing gh auth status with $.mjs\n'); diff --git a/js/examples/gh-delete-hang-test.mjs b/js/examples/gh-delete-hang-test.mjs index 95e9503..d6e9fce 100755 --- a/js/examples/gh-delete-hang-test.mjs +++ b/js/examples/gh-delete-hang-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/js/examples/gh-gist-creation-test.mjs b/js/examples/gh-gist-creation-test.mjs index 5b95188..284df7b 100755 --- a/js/examples/gh-gist-creation-test.mjs +++ b/js/examples/gh-gist-creation-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/js/examples/gh-gist-minimal-test.mjs b/js/examples/gh-gist-minimal-test.mjs index e19d5f8..b252097 100755 --- a/js/examples/gh-gist-minimal-test.mjs +++ b/js/examples/gh-gist-minimal-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import fs from 'fs/promises'; console.log('=== Minimal gh gist create test ===\n'); diff --git a/js/examples/gh-hang-exact-original.mjs b/js/examples/gh-hang-exact-original.mjs index 7c6fd5e..f3a5661 100755 --- a/js/examples/gh-hang-exact-original.mjs +++ b/js/examples/gh-hang-exact-original.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/js/examples/gh-hang-reproduction.mjs b/js/examples/gh-hang-reproduction.mjs index 5fea0e6..964756e 100644 --- a/js/examples/gh-hang-reproduction.mjs +++ b/js/examples/gh-hang-reproduction.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/js/examples/gh-hang-test-with-redirect.mjs b/js/examples/gh-hang-test-with-redirect.mjs index 1139675..d59d5d9 100755 --- a/js/examples/gh-hang-test-with-redirect.mjs +++ b/js/examples/gh-hang-test-with-redirect.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { promises as fs } from 'fs'; console.log('Testing gh gist create WITH 2>&1 (should work)'); diff --git a/js/examples/gh-hang-test-without-redirect.mjs b/js/examples/gh-hang-test-without-redirect.mjs index 0a1c3c3..d8ba2ba 100755 --- a/js/examples/gh-hang-test-without-redirect.mjs +++ b/js/examples/gh-hang-test-without-redirect.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { promises as fs } from 'fs'; console.log('Testing gh gist create WITHOUT 2>&1 (potential hang)'); diff --git a/js/examples/gh-minimal-hang-check.mjs b/js/examples/gh-minimal-hang-check.mjs index a09e350..9f46449 100755 --- a/js/examples/gh-minimal-hang-check.mjs +++ b/js/examples/gh-minimal-hang-check.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Minimal test for hanging ===\n'); diff --git a/js/examples/gh-operations-with-cd.mjs b/js/examples/gh-operations-with-cd.mjs index bbbc104..e19ee8a 100644 --- a/js/examples/gh-operations-with-cd.mjs +++ b/js/examples/gh-operations-with-cd.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; import { mkdtempSync, rmSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/js/examples/gh-output-test.mjs b/js/examples/gh-output-test.mjs index e3a1f75..7d0afb0 100755 --- a/js/examples/gh-output-test.mjs +++ b/js/examples/gh-output-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing where gh auth status outputs go ===\n'); diff --git a/js/examples/gh-reproduce-hang.mjs b/js/examples/gh-reproduce-hang.mjs index 9d883de..34f9def 100755 --- a/js/examples/gh-reproduce-hang.mjs +++ b/js/examples/gh-reproduce-hang.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; diff --git a/js/examples/git-operations-with-cd.mjs b/js/examples/git-operations-with-cd.mjs index 21aad24..6950930 100644 --- a/js/examples/git-operations-with-cd.mjs +++ b/js/examples/git-operations-with-cd.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; import { mkdtempSync, rmSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/js/examples/interactive-top-fixed.mjs b/js/examples/interactive-top-fixed.mjs index 6cb77f6..e2c84d4 100755 --- a/js/examples/interactive-top-fixed.mjs +++ b/js/examples/interactive-top-fixed.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Fixed Interactive top command ==='); console.log('This version properly handles:'); diff --git a/js/examples/interactive-top-improved.mjs b/js/examples/interactive-top-improved.mjs index e7830f9..81fae01 100755 --- a/js/examples/interactive-top-improved.mjs +++ b/js/examples/interactive-top-improved.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { ProcessRunner } from '../js/src/$.mjs'; +import { ProcessRunner } from '../src/$.mjs'; import { spawn } from 'child_process'; console.log('=== Improved Interactive top with command-stream ==='); diff --git a/js/examples/interactive-top-pty-logging.mjs b/js/examples/interactive-top-pty-logging.mjs index 11cb569..43f0756 100755 --- a/js/examples/interactive-top-pty-logging.mjs +++ b/js/examples/interactive-top-pty-logging.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/js/examples/interactive-top-with-logging.mjs b/js/examples/interactive-top-with-logging.mjs index 0d633ac..8ca396c 100755 --- a/js/examples/interactive-top-with-logging.mjs +++ b/js/examples/interactive-top-with-logging.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/js/examples/interactive-top.mjs b/js/examples/interactive-top.mjs index 2b4607a..b3630bc 100755 --- a/js/examples/interactive-top.mjs +++ b/js/examples/interactive-top.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log( '=== Interactive top command (preserves ANSI colors and interactive controls) ===' diff --git a/js/examples/jq-color-demo.mjs b/js/examples/jq-color-demo.mjs index 0cebfa9..130dc75 100755 --- a/js/examples/jq-color-demo.mjs +++ b/js/examples/jq-color-demo.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== jq Color Output Demo ===\n'); diff --git a/js/examples/jq-colors-streaming.mjs b/js/examples/jq-colors-streaming.mjs index 5400c4b..05119c1 100755 --- a/js/examples/jq-colors-streaming.mjs +++ b/js/examples/jq-colors-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== jq Streaming with ANSI Colors ===\n'); diff --git a/js/examples/manual-ctrl-c-test.mjs b/js/examples/manual-ctrl-c-test.mjs index d0a0faf..ad28057 100755 --- a/js/examples/manual-ctrl-c-test.mjs +++ b/js/examples/manual-ctrl-c-test.mjs @@ -3,7 +3,7 @@ // Manual test for CTRL+C handling // Run this script and press CTRL+C to test signal propagation -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Manual CTRL+C Test ===\n'); console.log('This script will run ping continuously.'); diff --git a/js/examples/methods-multiple-options.mjs b/js/examples/methods-multiple-options.mjs index 1c28d5b..388cd49 100755 --- a/js/examples/methods-multiple-options.mjs +++ b/js/examples/methods-multiple-options.mjs @@ -2,7 +2,7 @@ // Both .start() and .run() support all the same options -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Both support all the same options:'); diff --git a/js/examples/methods-run-basic.mjs b/js/examples/methods-run-basic.mjs index 6996349..37a7c12 100755 --- a/js/examples/methods-run-basic.mjs +++ b/js/examples/methods-run-basic.mjs @@ -2,7 +2,7 @@ // Using .run() method (identical functionality to .start()) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Using .run() method (identical functionality):'); const result = await $`echo "Using .run() method"`.run({ mirror: false }); diff --git a/js/examples/methods-start-basic.mjs b/js/examples/methods-start-basic.mjs index b314f51..45c46d3 100755 --- a/js/examples/methods-start-basic.mjs +++ b/js/examples/methods-start-basic.mjs @@ -2,7 +2,7 @@ // Using .start() method -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Using .start() method:'); const result = await $`echo "Using .start() method"`.start({ mirror: false }); diff --git a/js/examples/options-capture-false.mjs b/js/examples/options-capture-false.mjs index 92d2ebf..64bab7a 100755 --- a/js/examples/options-capture-false.mjs +++ b/js/examples/options-capture-false.mjs @@ -2,7 +2,7 @@ // Using .start() with capture: false -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing $`echo test`.start({ capture: false }):'); const result = await $`echo "test with capture false"`.start({ diff --git a/js/examples/options-combined-settings.mjs b/js/examples/options-combined-settings.mjs index 110da4f..37b046a 100755 --- a/js/examples/options-combined-settings.mjs +++ b/js/examples/options-combined-settings.mjs @@ -2,7 +2,7 @@ // Using .run() alias with both mirror and capture options -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing $`echo test`.run({ mirror: false, capture: true }):'); const result = await $`echo "test with both options"`.run({ diff --git a/js/examples/options-custom-input.mjs b/js/examples/options-custom-input.mjs index be5b73c..6808280 100755 --- a/js/examples/options-custom-input.mjs +++ b/js/examples/options-custom-input.mjs @@ -2,7 +2,7 @@ // Custom input with options -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Custom input with options:'); console.log('await $`cat`.start({ stdin: "custom", mirror: false })'); diff --git a/js/examples/options-default-behavior.mjs b/js/examples/options-default-behavior.mjs index f0f2dd2..06e344a 100755 --- a/js/examples/options-default-behavior.mjs +++ b/js/examples/options-default-behavior.mjs @@ -2,7 +2,7 @@ // Default behavior comparison (direct await) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing default await $`echo test` (for comparison):'); const result = await $`echo "test default behavior"`; diff --git a/js/examples/options-maximum-performance.mjs b/js/examples/options-maximum-performance.mjs index 6c501b0..9481d5e 100755 --- a/js/examples/options-maximum-performance.mjs +++ b/js/examples/options-maximum-performance.mjs @@ -2,7 +2,7 @@ // Maximum performance - no capture, no mirror -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Maximum performance - no capture, no mirror:'); console.log('await $`echo "blazing"`.start({ capture: false, mirror: false })'); diff --git a/js/examples/options-mirror-false.mjs b/js/examples/options-mirror-false.mjs index 79a0497..e986337 100755 --- a/js/examples/options-mirror-false.mjs +++ b/js/examples/options-mirror-false.mjs @@ -2,7 +2,7 @@ // Using .start() with mirror: false -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing $`echo test`.start({ mirror: false }):'); const result = await $`echo "test with mirror false"`.start({ mirror: false }); diff --git a/js/examples/options-performance-mode.mjs b/js/examples/options-performance-mode.mjs index dbd303a..51a1764 100755 --- a/js/examples/options-performance-mode.mjs +++ b/js/examples/options-performance-mode.mjs @@ -2,7 +2,7 @@ // capture: false and mirror: false together (maximum performance) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing $`echo test`.start({ capture: false, mirror: false }):'); const result = await $`echo "no capture, no mirror"`.start({ diff --git a/js/examples/options-performance-optimization.mjs b/js/examples/options-performance-optimization.mjs index a1d4e1c..f661c48 100755 --- a/js/examples/options-performance-optimization.mjs +++ b/js/examples/options-performance-optimization.mjs @@ -2,7 +2,7 @@ // Performance optimization - disable capture -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Performance optimization - disable capture:'); console.log('await $`echo "fast"`.start({ capture: false })'); diff --git a/js/examples/options-run-alias-demo.mjs b/js/examples/options-run-alias-demo.mjs index aed3c93..9884105 100755 --- a/js/examples/options-run-alias-demo.mjs +++ b/js/examples/options-run-alias-demo.mjs @@ -2,7 +2,7 @@ // Using .run() alias -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Using .run() alias:'); console.log('await $`echo "alias"`.run({ capture: true, mirror: false })'); diff --git a/js/examples/options-run-alias.mjs b/js/examples/options-run-alias.mjs index 0e7fd20..ece0dae 100755 --- a/js/examples/options-run-alias.mjs +++ b/js/examples/options-run-alias.mjs @@ -2,7 +2,7 @@ // Using .run() alias with capture: false -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing $`echo test`.run({ capture: false }):'); const result = await $`echo "test with run alias"`.run({ capture: false }); diff --git a/js/examples/options-silent-execution.mjs b/js/examples/options-silent-execution.mjs index 1294c0e..4218129 100755 --- a/js/examples/options-silent-execution.mjs +++ b/js/examples/options-silent-execution.mjs @@ -2,7 +2,7 @@ // Silent execution - disable mirroring -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Silent execution - disable mirroring:'); console.log('await $`echo "silent"`.start({ mirror: false })'); diff --git a/js/examples/options-streaming-capture.mjs b/js/examples/options-streaming-capture.mjs index fe5b00c..1869dfc 100755 --- a/js/examples/options-streaming-capture.mjs +++ b/js/examples/options-streaming-capture.mjs @@ -2,7 +2,7 @@ // Capture enabled with streaming using $({ capture: true }) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Capture enabled with streaming:'); const $capture = $({ capture: true, mirror: false }); diff --git a/js/examples/options-streaming-multiple.mjs b/js/examples/options-streaming-multiple.mjs index 786c754..0027fad 100755 --- a/js/examples/options-streaming-multiple.mjs +++ b/js/examples/options-streaming-multiple.mjs @@ -2,7 +2,7 @@ // Multiple configured instances with different options -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Multiple configured instances:'); const $quiet = $({ mirror: false }); diff --git a/js/examples/options-streaming-silent.mjs b/js/examples/options-streaming-silent.mjs index 8e96c3a..fb4ab5e 100755 --- a/js/examples/options-streaming-silent.mjs +++ b/js/examples/options-streaming-silent.mjs @@ -2,7 +2,7 @@ // Silent streaming using $({ mirror: false }) syntax -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Silent streaming (mirror: false):'); const $silent = $({ mirror: false }); diff --git a/js/examples/options-streaming-stdin.mjs b/js/examples/options-streaming-stdin.mjs index 9a2ffe8..c8a8ef6 100755 --- a/js/examples/options-streaming-stdin.mjs +++ b/js/examples/options-streaming-stdin.mjs @@ -2,7 +2,7 @@ // Streaming with custom stdin using $({ stdin }) syntax -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Streaming with custom stdin:'); const $withStdin = $({ stdin: 'Hello\nWorld\n', mirror: false }); diff --git a/js/examples/ping-streaming-filtered.mjs b/js/examples/ping-streaming-filtered.mjs index 315bc7d..ef14c1c 100755 --- a/js/examples/ping-streaming-filtered.mjs +++ b/js/examples/ping-streaming-filtered.mjs @@ -2,7 +2,7 @@ // Filtering only ping replies (no summary) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Filtering only ping replies (no summary):'); console.log('Running ping -c 3 1.1.1.1...\n'); diff --git a/js/examples/ping-streaming-interruptible.mjs b/js/examples/ping-streaming-interruptible.mjs index 7df05c6..ff1e6d9 100755 --- a/js/examples/ping-streaming-interruptible.mjs +++ b/js/examples/ping-streaming-interruptible.mjs @@ -2,7 +2,7 @@ // Interruptible ping streaming - shows how to handle CTRL+C gracefully -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Interruptible Ping Streaming ==='); console.log('Streaming continuous ping - press CTRL+C to stop gracefully...\n'); diff --git a/js/examples/ping-streaming-silent.mjs b/js/examples/ping-streaming-silent.mjs index 38162d7..5dd1673 100755 --- a/js/examples/ping-streaming-silent.mjs +++ b/js/examples/ping-streaming-silent.mjs @@ -2,7 +2,7 @@ // Silent streaming (no mirror to terminal) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Silent streaming (no mirror to terminal):'); console.log('Running ping -c 3 127.0.0.1 with mirror: false...\n'); diff --git a/js/examples/ping-streaming-simple.mjs b/js/examples/ping-streaming-simple.mjs index ee46c4f..458384c 100755 --- a/js/examples/ping-streaming-simple.mjs +++ b/js/examples/ping-streaming-simple.mjs @@ -2,7 +2,7 @@ // Simple ping streaming example - minimal code, maximum clarity -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Streaming ping output in real-time...\n'); diff --git a/js/examples/ping-streaming-statistics.mjs b/js/examples/ping-streaming-statistics.mjs index 867ddee..fac3a09 100755 --- a/js/examples/ping-streaming-statistics.mjs +++ b/js/examples/ping-streaming-statistics.mjs @@ -2,7 +2,7 @@ // Counting responses with statistics -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Counting responses with statistics:'); console.log('Running ping -c 4 8.8.8.8...\n'); diff --git a/js/examples/ping-streaming-timestamps.mjs b/js/examples/ping-streaming-timestamps.mjs index 6101d26..ede697f 100755 --- a/js/examples/ping-streaming-timestamps.mjs +++ b/js/examples/ping-streaming-timestamps.mjs @@ -2,7 +2,7 @@ // Basic ping streaming with timestamps -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Basic streaming with timestamps:'); console.log('Running ping -c 5 google.com...\n'); diff --git a/js/examples/ping-streaming.mjs b/js/examples/ping-streaming.mjs index d0256c1..14c4b03 100755 --- a/js/examples/ping-streaming.mjs +++ b/js/examples/ping-streaming.mjs @@ -2,7 +2,7 @@ // Streaming ping example - shows real-time output as it arrives -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Real-time Ping Streaming Example ==='); console.log('Press CTRL+C to stop the ping...\n'); diff --git a/js/examples/prove-ping-stdin-limitation.mjs b/js/examples/prove-ping-stdin-limitation.mjs index 36e69bc..c74a397 100755 --- a/js/examples/prove-ping-stdin-limitation.mjs +++ b/js/examples/prove-ping-stdin-limitation.mjs @@ -5,7 +5,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== PROOF: ping ignores stdin, needs kill() method ==='); console.log(''); diff --git a/js/examples/readme-example.mjs b/js/examples/readme-example.mjs index 332596f..40a2dfa 100755 --- a/js/examples/readme-example.mjs +++ b/js/examples/readme-example.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, register } from '../js/src/$.mjs'; +import { $, register } from '../src/$.mjs'; // Register a custom virtual command with the new object-based signature register('greet', async ({ stdin }) => ({ diff --git a/js/examples/realtime-json-stream.mjs b/js/examples/realtime-json-stream.mjs index abef57f..5b556ba 100755 --- a/js/examples/realtime-json-stream.mjs +++ b/js/examples/realtime-json-stream.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Realtime JSON Streaming Demo ===\n'); console.log( diff --git a/js/examples/reliable-stdin-commands.mjs b/js/examples/reliable-stdin-commands.mjs index 56f4bf1..81ac690 100755 --- a/js/examples/reliable-stdin-commands.mjs +++ b/js/examples/reliable-stdin-commands.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Most reliable stdin commands ==='); diff --git a/js/examples/reproduce-issue-135-v2.mjs b/js/examples/reproduce-issue-135-v2.mjs index 8dadc74..da619ca 100755 --- a/js/examples/reproduce-issue-135-v2.mjs +++ b/js/examples/reproduce-issue-135-v2.mjs @@ -4,7 +4,7 @@ process.env.CI = 'true'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test with CI=true set BEFORE import ==='); const $silent = $({ mirror: false, capture: true }); diff --git a/js/examples/reproduce-issue-135.mjs b/js/examples/reproduce-issue-135.mjs index 97249d1..10bc1e5 100755 --- a/js/examples/reproduce-issue-135.mjs +++ b/js/examples/reproduce-issue-135.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Reproducing issue #135: Trace logs interfere with output when CI=true -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const $silent = $({ mirror: false, capture: true }); diff --git a/js/examples/shell-cd-behavior.mjs b/js/examples/shell-cd-behavior.mjs index 8f01983..0bcf8b5 100644 --- a/js/examples/shell-cd-behavior.mjs +++ b/js/examples/shell-cd-behavior.mjs @@ -2,7 +2,7 @@ // This file documents how cd SHOULD behave to match shell behavior -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; enableVirtualCommands(); shell.verbose(false); diff --git a/js/examples/sigint-forwarding-test.mjs b/js/examples/sigint-forwarding-test.mjs index 1a713e2..945abfa 100755 --- a/js/examples/sigint-forwarding-test.mjs +++ b/js/examples/sigint-forwarding-test.mjs @@ -2,7 +2,7 @@ // Test SIGINT forwarding to child processes // This runs in a subprocess to avoid killing the test runner -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/sigint-handler-test.mjs b/js/examples/sigint-handler-test.mjs index 4324325..5045a9f 100755 --- a/js/examples/sigint-handler-test.mjs +++ b/js/examples/sigint-handler-test.mjs @@ -2,7 +2,7 @@ // Test script to verify SIGINT handler cleanup // This runs in a subprocess to avoid interfering with the test runner -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/simple-async-test.mjs b/js/examples/simple-async-test.mjs index 20e456b..982205f 100755 --- a/js/examples/simple-async-test.mjs +++ b/js/examples/simple-async-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Simple async streams test ==='); diff --git a/js/examples/simple-claude-test.mjs b/js/examples/simple-claude-test.mjs index a1bd1f8..254f51b 100755 --- a/js/examples/simple-claude-test.mjs +++ b/js/examples/simple-claude-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Simple Claude test with command-stream -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Simple Claude test with command-stream ==='); diff --git a/js/examples/simple-event-test.mjs b/js/examples/simple-event-test.mjs index b500a81..d852586 100644 --- a/js/examples/simple-event-test.mjs +++ b/js/examples/simple-event-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('๐Ÿงช Simple event test'); diff --git a/js/examples/simple-jq-streaming.mjs b/js/examples/simple-jq-streaming.mjs index d8557f7..f90fc34 100755 --- a/js/examples/simple-jq-streaming.mjs +++ b/js/examples/simple-jq-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Simple jq Streaming Test ===\n'); diff --git a/js/examples/simple-stream-demo.mjs b/js/examples/simple-stream-demo.mjs index 2ef5b56..ec1c505 100755 --- a/js/examples/simple-stream-demo.mjs +++ b/js/examples/simple-stream-demo.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing simple streaming without jq...\n'); diff --git a/js/examples/simple-working-stdin.mjs b/js/examples/simple-working-stdin.mjs index 0473212..0202b1a 100755 --- a/js/examples/simple-working-stdin.mjs +++ b/js/examples/simple-working-stdin.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function simpleWorkingStdin() { console.log('Simple working stdin test'); diff --git a/js/examples/streaming-behavior-test.mjs b/js/examples/streaming-behavior-test.mjs index 280c610..fc6272d 100755 --- a/js/examples/streaming-behavior-test.mjs +++ b/js/examples/streaming-behavior-test.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $, register } from '../js/src/$.mjs'; +import { $, register } from '../src/$.mjs'; console.log('=== Comprehensive Streaming Behavior Test ===\n'); console.log( diff --git a/js/examples/streaming-direct-command.mjs b/js/examples/streaming-direct-command.mjs index cb29011..bbac30d 100755 --- a/js/examples/streaming-direct-command.mjs +++ b/js/examples/streaming-direct-command.mjs @@ -2,7 +2,7 @@ // Basic streaming without pipes -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Direct command streaming test:'); diff --git a/js/examples/streaming-filtered-output.mjs b/js/examples/streaming-filtered-output.mjs index 7d3195c..c456b6a 100755 --- a/js/examples/streaming-filtered-output.mjs +++ b/js/examples/streaming-filtered-output.mjs @@ -2,7 +2,7 @@ // Stream processing with filtering (only error-like output) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Filtered streaming (only error-like output):'); const $filtered = $({ mirror: false }); diff --git a/js/examples/streaming-grep-pipeline.mjs b/js/examples/streaming-grep-pipeline.mjs index a62bb67..9a9fe01 100755 --- a/js/examples/streaming-grep-pipeline.mjs +++ b/js/examples/streaming-grep-pipeline.mjs @@ -2,7 +2,7 @@ // grep pipeline streaming -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('grep pipeline streaming test:'); diff --git a/js/examples/streaming-interactive-stdin.mjs b/js/examples/streaming-interactive-stdin.mjs index da1cc83..b76468d 100755 --- a/js/examples/streaming-interactive-stdin.mjs +++ b/js/examples/streaming-interactive-stdin.mjs @@ -2,7 +2,7 @@ // Interactive-style streaming with custom stdin -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Interactive streaming with pre-filled input:'); const commands = 'ls -la\necho "Current directory listing"\nexit\n'; diff --git a/js/examples/streaming-jq-pipeline.mjs b/js/examples/streaming-jq-pipeline.mjs index 7982575..d52a494 100755 --- a/js/examples/streaming-jq-pipeline.mjs +++ b/js/examples/streaming-jq-pipeline.mjs @@ -2,7 +2,7 @@ // jq pipeline streaming (critical test) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('jq pipeline streaming test:'); diff --git a/js/examples/streaming-multistage-pipeline.mjs b/js/examples/streaming-multistage-pipeline.mjs index 2a90b88..52490ab 100755 --- a/js/examples/streaming-multistage-pipeline.mjs +++ b/js/examples/streaming-multistage-pipeline.mjs @@ -2,7 +2,7 @@ // Multi-stage pipeline streaming (cat | jq) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Multi-stage pipeline streaming test:'); diff --git a/js/examples/streaming-pipes-event-pattern.mjs b/js/examples/streaming-pipes-event-pattern.mjs index 021a73a..4761a0a 100755 --- a/js/examples/streaming-pipes-event-pattern.mjs +++ b/js/examples/streaming-pipes-event-pattern.mjs @@ -2,7 +2,7 @@ // EventEmitter pattern with pipes -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('EventEmitter pattern with pipes:'); const start = Date.now(); diff --git a/js/examples/streaming-pipes-multistage.mjs b/js/examples/streaming-pipes-multistage.mjs index fdc4bd4..c95a24a 100755 --- a/js/examples/streaming-pipes-multistage.mjs +++ b/js/examples/streaming-pipes-multistage.mjs @@ -2,7 +2,7 @@ // Multi-stage pipeline with streaming -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Multi-stage pipeline with streaming:'); const start = Date.now(); diff --git a/js/examples/streaming-pipes-realtime-jq.mjs b/js/examples/streaming-pipes-realtime-jq.mjs index eaf2ec7..5e9703e 100755 --- a/js/examples/streaming-pipes-realtime-jq.mjs +++ b/js/examples/streaming-pipes-realtime-jq.mjs @@ -2,7 +2,7 @@ // Real-time streaming through jq pipe -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Real-time streaming with delays through jq:'); console.log('Each line should appear immediately, not all at once\n'); diff --git a/js/examples/streaming-progress-tracking.mjs b/js/examples/streaming-progress-tracking.mjs index 8846eca..3521512 100755 --- a/js/examples/streaming-progress-tracking.mjs +++ b/js/examples/streaming-progress-tracking.mjs @@ -2,7 +2,7 @@ // Streaming with progress tracking -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Progress tracking with streaming:'); const $progress = $({ mirror: false }); diff --git a/js/examples/streaming-reusable-configs.mjs b/js/examples/streaming-reusable-configs.mjs index 483d221..9c5d510 100755 --- a/js/examples/streaming-reusable-configs.mjs +++ b/js/examples/streaming-reusable-configs.mjs @@ -2,7 +2,7 @@ // Reusable streaming configurations -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Reusable streaming configurations:'); diff --git a/js/examples/streaming-silent-capture.mjs b/js/examples/streaming-silent-capture.mjs index a71039e..216a95e 100755 --- a/js/examples/streaming-silent-capture.mjs +++ b/js/examples/streaming-silent-capture.mjs @@ -2,7 +2,7 @@ // Long-running command with silent capture -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Long-running with silent capture:'); const $longSilent = $({ mirror: false, capture: true }); diff --git a/js/examples/streaming-test-simple.mjs b/js/examples/streaming-test-simple.mjs index 40c10cc..b23b34f 100755 --- a/js/examples/streaming-test-simple.mjs +++ b/js/examples/streaming-test-simple.mjs @@ -5,7 +5,7 @@ * Uses 'echo' and 'seq' commands that are guaranteed to exist */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { writeFileSync, appendFileSync, existsSync } from 'fs'; console.log('๐Ÿงช Testing streaming with simple commands...\n'); diff --git a/js/examples/streaming-virtual-pipeline.mjs b/js/examples/streaming-virtual-pipeline.mjs index 16dff18..972456b 100755 --- a/js/examples/streaming-virtual-pipeline.mjs +++ b/js/examples/streaming-virtual-pipeline.mjs @@ -2,7 +2,7 @@ // Virtual command with pipeline -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Virtual command with jq pipeline:'); diff --git a/js/examples/syntax-basic-comparison.mjs b/js/examples/syntax-basic-comparison.mjs index b7fe19b..27db032 100755 --- a/js/examples/syntax-basic-comparison.mjs +++ b/js/examples/syntax-basic-comparison.mjs @@ -2,7 +2,7 @@ // Basic streaming comparison: regular $ vs $({ options }) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Basic streaming comparison:'); diff --git a/js/examples/syntax-basic-options.mjs b/js/examples/syntax-basic-options.mjs index 5efd793..fe3c92c 100755 --- a/js/examples/syntax-basic-options.mjs +++ b/js/examples/syntax-basic-options.mjs @@ -2,7 +2,7 @@ // Basic options verification -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Verifying basic options...'); diff --git a/js/examples/syntax-combined-options.mjs b/js/examples/syntax-combined-options.mjs index 9b662f6..02b643a 100755 --- a/js/examples/syntax-combined-options.mjs +++ b/js/examples/syntax-combined-options.mjs @@ -2,7 +2,7 @@ // Combined multiple options using $({ options }) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Combined options:'); const $combined = $({ diff --git a/js/examples/syntax-command-chaining.mjs b/js/examples/syntax-command-chaining.mjs index 80eaa9f..30f410c 100755 --- a/js/examples/syntax-command-chaining.mjs +++ b/js/examples/syntax-command-chaining.mjs @@ -2,7 +2,7 @@ // Command chaining verification -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Verifying command chaining...'); diff --git a/js/examples/syntax-custom-directory.mjs b/js/examples/syntax-custom-directory.mjs index cace4ce..82c9c76 100755 --- a/js/examples/syntax-custom-directory.mjs +++ b/js/examples/syntax-custom-directory.mjs @@ -2,7 +2,7 @@ // Custom working directory using $({ options }) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Custom working directory:'); const $inTmp = $({ cwd: '/tmp', mirror: false }); diff --git a/js/examples/syntax-custom-environment.mjs b/js/examples/syntax-custom-environment.mjs index 3dae7dc..c55eced 100755 --- a/js/examples/syntax-custom-environment.mjs +++ b/js/examples/syntax-custom-environment.mjs @@ -2,7 +2,7 @@ // Custom environment using $({ options }) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Custom environment:'); const $withEnv = $({ diff --git a/js/examples/syntax-custom-stdin.mjs b/js/examples/syntax-custom-stdin.mjs index 40d8f13..28b4864 100755 --- a/js/examples/syntax-custom-stdin.mjs +++ b/js/examples/syntax-custom-stdin.mjs @@ -2,7 +2,7 @@ // Custom stdin using $({ options }) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Custom stdin:'); const $withInput = $({ stdin: 'Hello from stdin!\n' }); diff --git a/js/examples/syntax-mixed-regular.mjs b/js/examples/syntax-mixed-regular.mjs index 665acc3..58bb937 100755 --- a/js/examples/syntax-mixed-regular.mjs +++ b/js/examples/syntax-mixed-regular.mjs @@ -2,7 +2,7 @@ // Mixed with regular $ verification -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Verifying mixed with regular $...'); diff --git a/js/examples/syntax-mixed-usage.mjs b/js/examples/syntax-mixed-usage.mjs index 757fd3c..27eb443 100755 --- a/js/examples/syntax-mixed-usage.mjs +++ b/js/examples/syntax-mixed-usage.mjs @@ -2,7 +2,7 @@ // Mix with regular $ usage -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Mixed usage:'); console.log('Regular $ (with mirror):'); diff --git a/js/examples/syntax-multiple-listeners.mjs b/js/examples/syntax-multiple-listeners.mjs index 795fa2c..087c3ef 100755 --- a/js/examples/syntax-multiple-listeners.mjs +++ b/js/examples/syntax-multiple-listeners.mjs @@ -2,7 +2,7 @@ // Multiple event listeners comparison -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Multiple event listeners comparison:'); diff --git a/js/examples/syntax-piping-comparison.mjs b/js/examples/syntax-piping-comparison.mjs index caac63a..0c178a3 100755 --- a/js/examples/syntax-piping-comparison.mjs +++ b/js/examples/syntax-piping-comparison.mjs @@ -2,7 +2,7 @@ // Command chaining with different options comparison -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Command chaining with different options:'); diff --git a/js/examples/syntax-reusable-config.mjs b/js/examples/syntax-reusable-config.mjs index fb74afa..3269061 100755 --- a/js/examples/syntax-reusable-config.mjs +++ b/js/examples/syntax-reusable-config.mjs @@ -2,7 +2,7 @@ // Multiple uses of same configured $ verification -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Verifying reusable configurations...'); diff --git a/js/examples/syntax-reusable-configs.mjs b/js/examples/syntax-reusable-configs.mjs index 80a526d..31f5a1c 100755 --- a/js/examples/syntax-reusable-configs.mjs +++ b/js/examples/syntax-reusable-configs.mjs @@ -2,7 +2,7 @@ // Reusable configurations using $({ options }) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Reusable configurations:'); const $debug = $({ diff --git a/js/examples/syntax-silent-operations.mjs b/js/examples/syntax-silent-operations.mjs index e6183e1..4b9dfdf 100755 --- a/js/examples/syntax-silent-operations.mjs +++ b/js/examples/syntax-silent-operations.mjs @@ -2,7 +2,7 @@ // Silent operations (no mirror to stdout) using $({ options }) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Silent operation:'); const $silent = $({ mirror: false }); diff --git a/js/examples/syntax-stdin-option.mjs b/js/examples/syntax-stdin-option.mjs index 851c56e..2aca1e4 100755 --- a/js/examples/syntax-stdin-option.mjs +++ b/js/examples/syntax-stdin-option.mjs @@ -2,7 +2,7 @@ // stdin option verification -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Verifying stdin option...'); diff --git a/js/examples/temp-sigint-test.mjs b/js/examples/temp-sigint-test.mjs index ef9608b..0674145 100755 --- a/js/examples/temp-sigint-test.mjs +++ b/js/examples/temp-sigint-test.mjs @@ -2,7 +2,7 @@ // Temporary test file for SIGINT handling - can be used for debugging user signal handlers -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; let sigintReceived = false; diff --git a/js/examples/test-actual-buildshell.mjs b/js/examples/test-actual-buildshell.mjs index 3acc5da..7e03c25 100644 --- a/js/examples/test-actual-buildshell.mjs +++ b/js/examples/test-actual-buildshell.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test the actual buildShellCommand from command-stream -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose to see buildShellCommand traces process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/test-async-streams-working.mjs b/js/examples/test-async-streams-working.mjs index c5cbb0e..3e911a8 100755 --- a/js/examples/test-async-streams-working.mjs +++ b/js/examples/test-async-streams-working.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test async streams with commands that wait ==='); diff --git a/js/examples/test-async-streams.mjs b/js/examples/test-async-streams.mjs index 866a615..51e4ef6 100755 --- a/js/examples/test-async-streams.mjs +++ b/js/examples/test-async-streams.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test async streams interface ==='); diff --git a/js/examples/test-auth-parse.mjs b/js/examples/test-auth-parse.mjs index 812aa75..6311309 100644 --- a/js/examples/test-auth-parse.mjs +++ b/js/examples/test-auth-parse.mjs @@ -1,4 +1,4 @@ -import { $ } from './js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function getDetailedAuthStatus() { try { diff --git a/js/examples/test-auto-quoting.mjs b/js/examples/test-auto-quoting.mjs index ff945f6..4167902 100644 --- a/js/examples/test-auto-quoting.mjs +++ b/js/examples/test-auto-quoting.mjs @@ -3,7 +3,7 @@ // Test: Automatic quoting when user doesn't provide quotes // Expected: Smart auto-quoting based on content -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test: Automatic Smart Quoting ===\n'); diff --git a/js/examples/test-auto-start-fix.mjs b/js/examples/test-auto-start-fix.mjs index 88e8e9f..fb38c9e 100755 --- a/js/examples/test-auto-start-fix.mjs +++ b/js/examples/test-auto-start-fix.mjs @@ -5,7 +5,7 @@ * not when accessing the parent objects (streams, buffers, strings). */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing Auto-Start Behavior Fix ==='); console.log(''); diff --git a/js/examples/test-buffer-behavior.mjs b/js/examples/test-buffer-behavior.mjs index ca3ac34..b43a219 100755 --- a/js/examples/test-buffer-behavior.mjs +++ b/js/examples/test-buffer-behavior.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing buffer behavior in stream()...'); diff --git a/js/examples/test-buffers-simple.mjs b/js/examples/test-buffers-simple.mjs index 382bdbf..0f1ac51 100755 --- a/js/examples/test-buffers-simple.mjs +++ b/js/examples/test-buffers-simple.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing buffer access...'); diff --git a/js/examples/test-bun-specific-issue.mjs b/js/examples/test-bun-specific-issue.mjs index c8c25cd..3006afb 100755 --- a/js/examples/test-bun-specific-issue.mjs +++ b/js/examples/test-bun-specific-issue.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // More targeted test to find the real Bun shell path issue -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const isBun = typeof globalThis.Bun !== 'undefined'; console.log(`=== Bun Runtime Shell Path Test ===`); diff --git a/js/examples/test-cd-behavior.mjs b/js/examples/test-cd-behavior.mjs index 6ffa4ae..0cdf3c1 100644 --- a/js/examples/test-cd-behavior.mjs +++ b/js/examples/test-cd-behavior.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; enableVirtualCommands(); shell.verbose(false); diff --git a/js/examples/test-child-process-timing.mjs b/js/examples/test-child-process-timing.mjs index f8fc3d2..1d07294 100755 --- a/js/examples/test-child-process-timing.mjs +++ b/js/examples/test-child-process-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Debug child process timing ==='); diff --git a/js/examples/test-cleanup-simple.mjs b/js/examples/test-cleanup-simple.mjs index 61a73ee..67d3c84 100755 --- a/js/examples/test-cleanup-simple.mjs +++ b/js/examples/test-cleanup-simple.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing stream cleanup...'); diff --git a/js/examples/test-correct-space-handling.mjs b/js/examples/test-correct-space-handling.mjs index 4e6cf69..bc1b3c0 100644 --- a/js/examples/test-correct-space-handling.mjs +++ b/js/examples/test-correct-space-handling.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; import { mkdtempSync, rmSync, mkdirSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/js/examples/test-ctrl-c-debug.mjs b/js/examples/test-ctrl-c-debug.mjs index f983630..b22ecc7 100755 --- a/js/examples/test-ctrl-c-debug.mjs +++ b/js/examples/test-ctrl-c-debug.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing CTRL+C signal propagation'); console.log('Press CTRL+C to interrupt...'); diff --git a/js/examples/test-ctrl-c-inherit.mjs b/js/examples/test-ctrl-c-inherit.mjs index be90118..90d43ec 100755 --- a/js/examples/test-ctrl-c-inherit.mjs +++ b/js/examples/test-ctrl-c-inherit.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing CTRL+C with explicit stdio inherit'); console.log('Press CTRL+C to interrupt the ping command...'); diff --git a/js/examples/test-ctrl-c-sleep.mjs b/js/examples/test-ctrl-c-sleep.mjs index 9283849..fee4dc5 100755 --- a/js/examples/test-ctrl-c-sleep.mjs +++ b/js/examples/test-ctrl-c-sleep.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing CTRL+C with sleep command'); console.log('Press CTRL+C to interrupt the sleep...'); diff --git a/js/examples/test-ctrl-c.mjs b/js/examples/test-ctrl-c.mjs index 49db9e1..bad7ac8 100755 --- a/js/examples/test-ctrl-c.mjs +++ b/js/examples/test-ctrl-c.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing CTRL+C handling with ping command'); console.log('Press CTRL+C to interrupt the ping command...'); diff --git a/js/examples/test-debug-new-options.mjs b/js/examples/test-debug-new-options.mjs index 7c2d569..e4873d7 100755 --- a/js/examples/test-debug-new-options.mjs +++ b/js/examples/test-debug-new-options.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function debug() { console.log('=== Debugging how new options work ==='); diff --git a/js/examples/test-debug-pty.mjs b/js/examples/test-debug-pty.mjs index 3227996..be90eea 100755 --- a/js/examples/test-debug-pty.mjs +++ b/js/examples/test-debug-pty.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Add debug logging const original_runPipeline = $.prototype._runPipeline; diff --git a/js/examples/test-debug-tee.mjs b/js/examples/test-debug-tee.mjs index 1d99a01..713ff33 100755 --- a/js/examples/test-debug-tee.mjs +++ b/js/examples/test-debug-tee.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Debug Tee Streaming ===\n'); diff --git a/js/examples/test-debug.mjs b/js/examples/test-debug.mjs index 7bc22b4..ba25a70 100755 --- a/js/examples/test-debug.mjs +++ b/js/examples/test-debug.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Starting test...'); diff --git a/js/examples/test-double-quoting-prevention.mjs b/js/examples/test-double-quoting-prevention.mjs index efa6ee8..eb3049d 100644 --- a/js/examples/test-double-quoting-prevention.mjs +++ b/js/examples/test-double-quoting-prevention.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test: Prevent double-quoting when user provides quotes on strings that need quoting -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Double-Quoting Prevention Test ===\n'); diff --git a/js/examples/test-edge-cases-quoting.mjs b/js/examples/test-edge-cases-quoting.mjs index 9fa9a91..220681b 100644 --- a/js/examples/test-edge-cases-quoting.mjs +++ b/js/examples/test-edge-cases-quoting.mjs @@ -3,7 +3,7 @@ // Test: Edge cases for quote handling // Expected: Proper handling of unusual quoting scenarios -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test: Quote Edge Cases ===\n'); diff --git a/js/examples/test-events.mjs b/js/examples/test-events.mjs index 365fc1e..fbb8452 100755 --- a/js/examples/test-events.mjs +++ b/js/examples/test-events.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test Event Emissions ===\n'); diff --git a/js/examples/test-explicit-stdio.mjs b/js/examples/test-explicit-stdio.mjs index d74a03b..07c8cae 100755 --- a/js/examples/test-explicit-stdio.mjs +++ b/js/examples/test-explicit-stdio.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test with explicit stdio configuration ==='); diff --git a/js/examples/test-final-streaming.mjs b/js/examples/test-final-streaming.mjs index 8001a40..88c36b1 100755 --- a/js/examples/test-final-streaming.mjs +++ b/js/examples/test-final-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Final Streaming Test with PTY Workaround ===\n'); diff --git a/js/examples/test-fix.mjs b/js/examples/test-fix.mjs index 2ff73ca..81333fc 100644 --- a/js/examples/test-fix.mjs +++ b/js/examples/test-fix.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function testFix() { console.log('๐Ÿงช Testing the stdin pipe fix'); diff --git a/js/examples/test-incremental-streaming.mjs b/js/examples/test-incremental-streaming.mjs index 74b70e1..e151355 100755 --- a/js/examples/test-incremental-streaming.mjs +++ b/js/examples/test-incremental-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing Incremental Streaming ===\n'); diff --git a/js/examples/test-inherit-stdout-not-stdin.mjs b/js/examples/test-inherit-stdout-not-stdin.mjs index 8a09683..217e044 100755 --- a/js/examples/test-inherit-stdout-not-stdin.mjs +++ b/js/examples/test-inherit-stdout-not-stdin.mjs @@ -5,7 +5,7 @@ * This allows parent process to see output, but child doesn't read from parent's stdin */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing inherit stdout but not stdin ==='); console.log(''); diff --git a/js/examples/test-injection-protection.mjs b/js/examples/test-injection-protection.mjs index 3af6065..b14fba9 100644 --- a/js/examples/test-injection-protection.mjs +++ b/js/examples/test-injection-protection.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test shell injection protection with the smart quoting -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Shell Injection Protection Test ===\n'); diff --git a/js/examples/test-interactive-streaming.mjs b/js/examples/test-interactive-streaming.mjs index 848ed01..e9959f6 100755 --- a/js/examples/test-interactive-streaming.mjs +++ b/js/examples/test-interactive-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function testInteractiveStreaming() { console.log('Testing Interactive Streaming I/O\n'); diff --git a/js/examples/test-interactive.mjs b/js/examples/test-interactive.mjs index 90fe666..2ab3d80 100755 --- a/js/examples/test-interactive.mjs +++ b/js/examples/test-interactive.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing interactive command detection...'); diff --git a/js/examples/test-interpolation.mjs b/js/examples/test-interpolation.mjs index 2462278..26bc76a 100644 --- a/js/examples/test-interpolation.mjs +++ b/js/examples/test-interpolation.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function testInterpolation() { const name = 'World'; diff --git a/js/examples/test-interrupt.mjs b/js/examples/test-interrupt.mjs index 761a07c..b1c59ac 100755 --- a/js/examples/test-interrupt.mjs +++ b/js/examples/test-interrupt.mjs @@ -2,7 +2,7 @@ // Automated test for interruption handling -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function test() { console.log('Testing interruption of virtual sleep command...'); diff --git a/js/examples/test-issue-135-comprehensive.mjs b/js/examples/test-issue-135-comprehensive.mjs index e02f097..3f8d574 100755 --- a/js/examples/test-issue-135-comprehensive.mjs +++ b/js/examples/test-issue-135-comprehensive.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Comprehensive test for issue #135: Trace logs interfere with output -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log( '=== Test 1: Default (no env vars, mirror:false, capture:true) ===' diff --git a/js/examples/test-issue12-detailed.mjs b/js/examples/test-issue12-detailed.mjs index 69e3825..304bad9 100644 --- a/js/examples/test-issue12-detailed.mjs +++ b/js/examples/test-issue12-detailed.mjs @@ -4,7 +4,7 @@ // Original issue: https://github.com/link-foundation/command-stream/issues/12 // Original error: ENOENT: no such file or directory, posix_spawn ''/Users/konard/.claude/local/claude'' -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const claude = process.env.CLAUDE_PATH || '/Users/konard/.claude/local/claude'; diff --git a/js/examples/test-issue12-exact.mjs b/js/examples/test-issue12-exact.mjs index 5145708..b3054c2 100644 --- a/js/examples/test-issue12-exact.mjs +++ b/js/examples/test-issue12-exact.mjs @@ -4,7 +4,7 @@ // Original issue: https://github.com/link-foundation/command-stream/issues/12 // Original error: ENOENT: no such file or directory, posix_spawn ''/Users/konard/.claude/local/claude'' -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const claude = process.env.CLAUDE_PATH || '/Users/konard/.claude/local/claude'; diff --git a/js/examples/test-jq-color.mjs b/js/examples/test-jq-color.mjs index e49dc67..23fed91 100644 --- a/js/examples/test-jq-color.mjs +++ b/js/examples/test-jq-color.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing jq Color Output ===\n'); diff --git a/js/examples/test-jq-colors.mjs b/js/examples/test-jq-colors.mjs index c1fa9d3..8c5b733 100755 --- a/js/examples/test-jq-colors.mjs +++ b/js/examples/test-jq-colors.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing jq color output in pipelines ===\n'); diff --git a/js/examples/test-jq-pipeline-behavior.mjs b/js/examples/test-jq-pipeline-behavior.mjs index 5188e6a..e9ade07 100644 --- a/js/examples/test-jq-pipeline-behavior.mjs +++ b/js/examples/test-jq-pipeline-behavior.mjs @@ -4,7 +4,7 @@ * Test to demonstrate jq's color behavior in different contexts */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { execSync } from 'child_process'; const testJson = '{"message": "hello", "number": 42}'; diff --git a/js/examples/test-jq-realtime.mjs b/js/examples/test-jq-realtime.mjs index b2b9577..67e4ee8 100755 --- a/js/examples/test-jq-realtime.mjs +++ b/js/examples/test-jq-realtime.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing Real-Time jq Streaming ===\n'); diff --git a/js/examples/test-manual-start.mjs b/js/examples/test-manual-start.mjs index 5d523ef..8635cc4 100644 --- a/js/examples/test-manual-start.mjs +++ b/js/examples/test-manual-start.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function testManualStart() { console.log('๐Ÿงช Testing manual start with pipe stdin'); diff --git a/js/examples/test-mixed-quoting.mjs b/js/examples/test-mixed-quoting.mjs index f53046a..85a15f3 100644 --- a/js/examples/test-mixed-quoting.mjs +++ b/js/examples/test-mixed-quoting.mjs @@ -3,7 +3,7 @@ // Test: Mixed quoted and unquoted arguments // Expected: Each argument properly handled based on its content -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test: Mixed Quoting Scenarios ===\n'); diff --git a/js/examples/test-multistage-debug.mjs b/js/examples/test-multistage-debug.mjs index 5d87787..cb0d10c 100755 --- a/js/examples/test-multistage-debug.mjs +++ b/js/examples/test-multistage-debug.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Debug Multi-Stage Pipeline ===\n'); diff --git a/js/examples/test-native-spawn-vs-command-stream.mjs b/js/examples/test-native-spawn-vs-command-stream.mjs index acad1c0..09b6c71 100755 --- a/js/examples/test-native-spawn-vs-command-stream.mjs +++ b/js/examples/test-native-spawn-vs-command-stream.mjs @@ -6,7 +6,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing Native spawn vs command-stream kill capabilities ==='); console.log(''); diff --git a/js/examples/test-no-parse-pipeline.mjs b/js/examples/test-no-parse-pipeline.mjs index 066b645..69978af 100755 --- a/js/examples/test-no-parse-pipeline.mjs +++ b/js/examples/test-no-parse-pipeline.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing: Disable pipeline parsing, let sh handle it\n'); diff --git a/js/examples/test-non-virtual.mjs b/js/examples/test-non-virtual.mjs index 40b1a20..7f0edeb 100644 --- a/js/examples/test-non-virtual.mjs +++ b/js/examples/test-non-virtual.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function testNonVirtual() { console.log('๐Ÿงช Testing with definitely non-virtual command'); diff --git a/js/examples/test-operators.mjs b/js/examples/test-operators.mjs index c3d4238..5bf6e18 100644 --- a/js/examples/test-operators.mjs +++ b/js/examples/test-operators.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; enableVirtualCommands(); shell.verbose(true); diff --git a/js/examples/test-parent-continues.mjs b/js/examples/test-parent-continues.mjs index c77dd73..2cf3e00 100755 --- a/js/examples/test-parent-continues.mjs +++ b/js/examples/test-parent-continues.mjs @@ -2,7 +2,7 @@ // Test that parent process continues after child is interrupted -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function test() { console.log('Testing that parent continues after child interruption...\n'); diff --git a/js/examples/test-path-interpolation.mjs b/js/examples/test-path-interpolation.mjs index 6dc6b09..a21fc8f 100644 --- a/js/examples/test-path-interpolation.mjs +++ b/js/examples/test-path-interpolation.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing Path Interpolation Issues ===\n'); diff --git a/js/examples/test-ping-kill-and-stdin.mjs b/js/examples/test-ping-kill-and-stdin.mjs index cfcb966..6a6faf1 100755 --- a/js/examples/test-ping-kill-and-stdin.mjs +++ b/js/examples/test-ping-kill-and-stdin.mjs @@ -6,7 +6,7 @@ * 2. kill() method works to interrupt ping commands */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing ping kill() and streams.stdin ==='); console.log(''); diff --git a/js/examples/test-ping.mjs b/js/examples/test-ping.mjs index 8dac6c3..2f7d7cb 100755 --- a/js/examples/test-ping.mjs +++ b/js/examples/test-ping.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test ping example similar to hive-mind/claude-pipe/test-ping.mjs -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('STARTING_PING'); try { diff --git a/js/examples/test-quote-behavior-summary.mjs b/js/examples/test-quote-behavior-summary.mjs index 170898d..e48067e 100644 --- a/js/examples/test-quote-behavior-summary.mjs +++ b/js/examples/test-quote-behavior-summary.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Comprehensive test of the smart quoting behavior -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Smart Quoting Behavior Summary ===\n'); diff --git a/js/examples/test-quote-edge-cases.mjs b/js/examples/test-quote-edge-cases.mjs index 4560ccd..87906d3 100644 --- a/js/examples/test-quote-edge-cases.mjs +++ b/js/examples/test-quote-edge-cases.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test quoting edge cases for issue #12 -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing Quote Edge Cases for Issue #12 ===\n'); diff --git a/js/examples/test-quote-parsing.mjs b/js/examples/test-quote-parsing.mjs index 948962f..cdb51a3 100644 --- a/js/examples/test-quote-parsing.mjs +++ b/js/examples/test-quote-parsing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { parseShellCommand } from '../js/src/shell-parser.mjs'; +import { parseShellCommand } from '../src/shell-parser.mjs'; const tests = [ 'cd "/tmp/my dir"', diff --git a/js/examples/test-raw-function.mjs b/js/examples/test-raw-function.mjs index 143ef05..7d33104 100755 --- a/js/examples/test-raw-function.mjs +++ b/js/examples/test-raw-function.mjs @@ -3,7 +3,7 @@ // Example: Using raw() to disable auto-escape for trusted command strings // This demonstrates the solution to issue #139 -import { $, raw } from '../js/src/$.mjs'; +import { $, raw } from '../src/$.mjs'; console.log('=== raw() Function Examples ===\n'); diff --git a/js/examples/test-raw-streaming.mjs b/js/examples/test-raw-streaming.mjs index 1f10fa7..3503553 100755 --- a/js/examples/test-raw-streaming.mjs +++ b/js/examples/test-raw-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing Raw Streaming (no jq) ===\n'); diff --git a/js/examples/test-readme-examples.mjs b/js/examples/test-readme-examples.mjs index 8492d24..6a69723 100644 --- a/js/examples/test-readme-examples.mjs +++ b/js/examples/test-readme-examples.mjs @@ -4,7 +4,7 @@ * Test the README examples to ensure they work correctly */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('๐Ÿงช Testing README Examples'); console.log('='.repeat(40)); diff --git a/js/examples/test-real-cat.mjs b/js/examples/test-real-cat.mjs index c464679..a20a6bc 100644 --- a/js/examples/test-real-cat.mjs +++ b/js/examples/test-real-cat.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function testRealCat() { console.log('Testing real cat (not virtual) with streams.stdin...'); diff --git a/js/examples/test-real-commands.mjs b/js/examples/test-real-commands.mjs index 5a17edb..6cab5d0 100755 --- a/js/examples/test-real-commands.mjs +++ b/js/examples/test-real-commands.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Test with real commands only (no virtual echo):\n'); diff --git a/js/examples/test-real-shell.mjs b/js/examples/test-real-shell.mjs index 8952fed..e7594fb 100755 --- a/js/examples/test-real-shell.mjs +++ b/js/examples/test-real-shell.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function testRealShellCommands() { console.log('Testing with real shell commands...'); diff --git a/js/examples/test-real-stdin-commands.mjs b/js/examples/test-real-stdin-commands.mjs index 0ebf036..846f356 100755 --- a/js/examples/test-real-stdin-commands.mjs +++ b/js/examples/test-real-stdin-commands.mjs @@ -4,7 +4,7 @@ * Test commands that actually read and respond to stdin */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing commands that ACTUALLY read stdin ==='); console.log(''); diff --git a/js/examples/test-runner.mjs b/js/examples/test-runner.mjs index 8e956c3..9a94ef9 100755 --- a/js/examples/test-runner.mjs +++ b/js/examples/test-runner.mjs @@ -5,7 +5,7 @@ * This helps identify test issues and ensures all tests pass in isolation */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { readdirSync } from 'fs'; import { join, basename } from 'path'; diff --git a/js/examples/test-sh-pipeline.mjs b/js/examples/test-sh-pipeline.mjs index 2b7efe5..220132e 100755 --- a/js/examples/test-sh-pipeline.mjs +++ b/js/examples/test-sh-pipeline.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing pipeline executed via sh -c:'); console.log('This should stream in real-time\n'); diff --git a/js/examples/test-shell-detection.mjs b/js/examples/test-shell-detection.mjs index 21f1bee..f7b8c73 100755 --- a/js/examples/test-shell-detection.mjs +++ b/js/examples/test-shell-detection.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test script to reproduce Bun shell path detection issues -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Shell Detection Test ==='); console.log( diff --git a/js/examples/test-shell-parser.mjs b/js/examples/test-shell-parser.mjs index e55d369..df46893 100644 --- a/js/examples/test-shell-parser.mjs +++ b/js/examples/test-shell-parser.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { parseShellCommand, needsRealShell } from '../js/src/shell-parser.mjs'; +import { parseShellCommand, needsRealShell } from '../src/shell-parser.mjs'; const testCases = [ 'cd /tmp', diff --git a/js/examples/test-sigint-behavior.mjs b/js/examples/test-sigint-behavior.mjs index 57fb308..3426d2d 100755 --- a/js/examples/test-sigint-behavior.mjs +++ b/js/examples/test-sigint-behavior.mjs @@ -7,7 +7,7 @@ */ import { spawn } from 'child_process'; -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing SIGINT behavior'); diff --git a/js/examples/test-simple-pipe.mjs b/js/examples/test-simple-pipe.mjs index 39059cb..ca9880d 100755 --- a/js/examples/test-simple-pipe.mjs +++ b/js/examples/test-simple-pipe.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Simple pipe test:'); diff --git a/js/examples/test-simple-streaming.mjs b/js/examples/test-simple-streaming.mjs index 237fc83..2e2a2e4 100644 --- a/js/examples/test-simple-streaming.mjs +++ b/js/examples/test-simple-streaming.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; -import { trace } from '../js/src/$.utils.mjs'; +import { $ } from '../src/$.mjs'; +import { trace } from '../src/$.utils.mjs'; async function testSimpleStreaming() { trace('TestExample', '๐Ÿงช Testing simple streaming after fix'); diff --git a/js/examples/test-smart-quoting.mjs b/js/examples/test-smart-quoting.mjs index bec1459..226e0c7 100644 --- a/js/examples/test-smart-quoting.mjs +++ b/js/examples/test-smart-quoting.mjs @@ -3,7 +3,7 @@ // Test smart quoting behavior for interpolated strings // We need to preserve user-provided quotes while still auto-quoting when necessary -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Smart Quoting Tests ===\n'); diff --git a/js/examples/test-spaces-in-path.mjs b/js/examples/test-spaces-in-path.mjs index fa86e60..9589429 100644 --- a/js/examples/test-spaces-in-path.mjs +++ b/js/examples/test-spaces-in-path.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; import { mkdtempSync, rmSync, mkdirSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; diff --git a/js/examples/test-special-chars-quoting.mjs b/js/examples/test-special-chars-quoting.mjs index 95a2b26..b578836 100644 --- a/js/examples/test-special-chars-quoting.mjs +++ b/js/examples/test-special-chars-quoting.mjs @@ -3,7 +3,7 @@ // Test: Quoting strings with special characters // Expected: Proper escaping and quoting for shell safety -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test: Special Characters Quoting ===\n'); diff --git a/js/examples/test-stdin-after-start.mjs b/js/examples/test-stdin-after-start.mjs index 2467b0f..7aa8eb9 100755 --- a/js/examples/test-stdin-after-start.mjs +++ b/js/examples/test-stdin-after-start.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test stdin access after process starts ==='); diff --git a/js/examples/test-stdin-simple.mjs b/js/examples/test-stdin-simple.mjs index 550ee2e..eae4b52 100755 --- a/js/examples/test-stdin-simple.mjs +++ b/js/examples/test-stdin-simple.mjs @@ -4,7 +4,7 @@ * Simple focused test for streams.stdin functionality */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing streams.stdin simple functionality ==='); diff --git a/js/examples/test-stdin-timing.mjs b/js/examples/test-stdin-timing.mjs index dc4d2fa..4051ac0 100755 --- a/js/examples/test-stdin-timing.mjs +++ b/js/examples/test-stdin-timing.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test stdin timing with proper flow ==='); diff --git a/js/examples/test-stdio-combinations.mjs b/js/examples/test-stdio-combinations.mjs index 4538bc1..210aae1 100755 --- a/js/examples/test-stdio-combinations.mjs +++ b/js/examples/test-stdio-combinations.mjs @@ -4,7 +4,7 @@ * Test different stdio combinations with streams interface */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing stdio combinations with streams interface ==='); console.log(''); diff --git a/js/examples/test-stream-access.mjs b/js/examples/test-stream-access.mjs index 8c6b450..d07978d 100644 --- a/js/examples/test-stream-access.mjs +++ b/js/examples/test-stream-access.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function testStreamAccess() { console.log('Testing event-driven stream access (no setTimeout)...\n'); diff --git a/js/examples/test-stream-cleanup.mjs b/js/examples/test-stream-cleanup.mjs index 5b9ad61..aaa8460 100755 --- a/js/examples/test-stream-cleanup.mjs +++ b/js/examples/test-stream-cleanup.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing stream cleanup...'); diff --git a/js/examples/test-streaming-final.mjs b/js/examples/test-streaming-final.mjs index b5a406a..e6a8947 100755 --- a/js/examples/test-streaming-final.mjs +++ b/js/examples/test-streaming-final.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Final Real-Time Streaming Test ===\n'); diff --git a/js/examples/test-streaming-interfaces.mjs b/js/examples/test-streaming-interfaces.mjs index 24316cf..906e73e 100755 --- a/js/examples/test-streaming-interfaces.mjs +++ b/js/examples/test-streaming-interfaces.mjs @@ -12,7 +12,7 @@ * node js/examples/test-streaming-interfaces.mjs */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('='.repeat(60)); console.log('TESTING NEW STREAMING INTERFACES (Issue #33)'); diff --git a/js/examples/test-streaming-timing.mjs b/js/examples/test-streaming-timing.mjs index 4c7747d..c7cae52 100644 --- a/js/examples/test-streaming-timing.mjs +++ b/js/examples/test-streaming-timing.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function test() { console.log('Starting test...'); diff --git a/js/examples/test-streaming.mjs b/js/examples/test-streaming.mjs index 8f63214..c4205c9 100644 --- a/js/examples/test-streaming.mjs +++ b/js/examples/test-streaming.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function testStreaming() { console.log('Testing basic cat with streams.stdin...'); diff --git a/js/examples/test-streams-stdin-comprehensive.mjs b/js/examples/test-streams-stdin-comprehensive.mjs index ae1a685..9ff15b5 100755 --- a/js/examples/test-streams-stdin-comprehensive.mjs +++ b/js/examples/test-streams-stdin-comprehensive.mjs @@ -7,7 +7,7 @@ * - Testing with commands that actually read stdin */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing streams.stdin comprehensive functionality ==='); console.log(''); diff --git a/js/examples/test-streams-stdin-ctrl-c.mjs b/js/examples/test-streams-stdin-ctrl-c.mjs index eaeef29..7ac2dd4 100755 --- a/js/examples/test-streams-stdin-ctrl-c.mjs +++ b/js/examples/test-streams-stdin-ctrl-c.mjs @@ -4,7 +4,7 @@ * Test to verify that streams.stdin can be used to send CTRL+C to interrupt commands */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing streams.stdin CTRL+C functionality ==='); console.log(''); diff --git a/js/examples/test-template-literal.mjs b/js/examples/test-template-literal.mjs index 7a9b95a..dd92a40 100644 --- a/js/examples/test-template-literal.mjs +++ b/js/examples/test-template-literal.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $, shell, enableVirtualCommands } from '../js/src/$.mjs'; +import { $, shell, enableVirtualCommands } from '../src/$.mjs'; enableVirtualCommands(); shell.verbose(true); diff --git a/js/examples/test-template-vs-interpolation.mjs b/js/examples/test-template-vs-interpolation.mjs index 577d029..dacd28d 100644 --- a/js/examples/test-template-vs-interpolation.mjs +++ b/js/examples/test-template-vs-interpolation.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test the difference between template literals and string interpolation -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Enable verbose mode process.env.COMMAND_STREAM_VERBOSE = 'true'; diff --git a/js/examples/test-timing.mjs b/js/examples/test-timing.mjs index bd81b99..afa073c 100755 --- a/js/examples/test-timing.mjs +++ b/js/examples/test-timing.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing exact timing of cancellation...'); diff --git a/js/examples/test-top-inherit-stdout-stdin-control.mjs b/js/examples/test-top-inherit-stdout-stdin-control.mjs index cba2b51..30a065d 100755 --- a/js/examples/test-top-inherit-stdout-stdin-control.mjs +++ b/js/examples/test-top-inherit-stdout-stdin-control.mjs @@ -5,7 +5,7 @@ * This demonstrates the key requirement: inherit stdout but control stdin independently */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing top with inherit stdout + streams.stdin control ==='); console.log(''); diff --git a/js/examples/test-top-quit-stdin.mjs b/js/examples/test-top-quit-stdin.mjs index 1553e8b..94cb973 100755 --- a/js/examples/test-top-quit-stdin.mjs +++ b/js/examples/test-top-quit-stdin.mjs @@ -5,7 +5,7 @@ * This demonstrates stdin control for interactive commands that actually read stdin */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Testing top command quit via streams.stdin ==='); console.log(''); diff --git a/js/examples/test-trace-option.mjs b/js/examples/test-trace-option.mjs index 58588b7..e66aa50 100755 --- a/js/examples/test-trace-option.mjs +++ b/js/examples/test-trace-option.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Test the trace option in $ config -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Test: mirror:false with trace:false in CI environment ==='); process.env.CI = 'true'; diff --git a/js/examples/test-user-double-quotes.mjs b/js/examples/test-user-double-quotes.mjs index d00f516..104a3dd 100644 --- a/js/examples/test-user-double-quotes.mjs +++ b/js/examples/test-user-double-quotes.mjs @@ -3,7 +3,7 @@ // Test: User provides double quotes around interpolated value // Expected: Preserve double quotes (wrapped in single quotes for shell) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const claude = '/Users/konard/.claude/local/claude'; diff --git a/js/examples/test-user-single-quotes.mjs b/js/examples/test-user-single-quotes.mjs index f6bffdc..f147456 100644 --- a/js/examples/test-user-single-quotes.mjs +++ b/js/examples/test-user-single-quotes.mjs @@ -3,7 +3,7 @@ // Test: User provides single quotes around interpolated value // Expected: Preserve single quotes without double-escaping -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const claude = '/Users/konard/.claude/local/claude'; diff --git a/js/examples/test-verbose.mjs b/js/examples/test-verbose.mjs index b55729f..c57b06f 100755 --- a/js/examples/test-verbose.mjs +++ b/js/examples/test-verbose.mjs @@ -1,4 +1,4 @@ -import { $, shell } from '../js/src/$.mjs'; +import { $, shell } from '../src/$.mjs'; const originalLog = console.log; const capturedLogs = []; diff --git a/js/examples/test-verbose2.mjs b/js/examples/test-verbose2.mjs index 5e2eec2..70f389f 100755 --- a/js/examples/test-verbose2.mjs +++ b/js/examples/test-verbose2.mjs @@ -1,4 +1,4 @@ -import { $, shell } from '../js/src/$.mjs'; +import { $, shell } from '../src/$.mjs'; const originalLog = console.log; const capturedLogs = []; diff --git a/js/examples/test-virtual-streaming.mjs b/js/examples/test-virtual-streaming.mjs index 8999a28..e251392 100755 --- a/js/examples/test-virtual-streaming.mjs +++ b/js/examples/test-virtual-streaming.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { $, register } from '../js/src/$.mjs'; +import { $, register } from '../src/$.mjs'; console.log('=== Testing Virtual Command Streaming ===\n'); diff --git a/js/examples/test-waiting-command.mjs b/js/examples/test-waiting-command.mjs index d5570d6..3772bdd 100644 --- a/js/examples/test-waiting-command.mjs +++ b/js/examples/test-waiting-command.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; async function testWaitingCommand() { console.log('๐Ÿงช Testing with command that truly waits'); diff --git a/js/examples/test-waiting-commands.mjs b/js/examples/test-waiting-commands.mjs index 36989d8..ffc92fe 100755 --- a/js/examples/test-waiting-commands.mjs +++ b/js/examples/test-waiting-commands.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Commands that definitely wait for stdin ==='); diff --git a/js/examples/test-watch-mode.mjs b/js/examples/test-watch-mode.mjs index 56e03eb..64238ca 100755 --- a/js/examples/test-watch-mode.mjs +++ b/js/examples/test-watch-mode.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { promises as fs } from 'fs'; import { spawn } from 'child_process'; import os from 'os'; diff --git a/js/examples/test-yes-cancellation.mjs b/js/examples/test-yes-cancellation.mjs index 9882b76..b51efea 100755 --- a/js/examples/test-yes-cancellation.mjs +++ b/js/examples/test-yes-cancellation.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing yes command cancellation...'); diff --git a/js/examples/test-yes-detailed.mjs b/js/examples/test-yes-detailed.mjs index 26b267e..e7e903b 100755 --- a/js/examples/test-yes-detailed.mjs +++ b/js/examples/test-yes-detailed.mjs @@ -1,10 +1,10 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing yes command cancellation in detail...'); // Test 1: Direct generator usage console.log('\n=== Test 1: Direct generator test ==='); -import yesCommand from '../js/src/commands/$.yes.mjs'; +import yesCommand from '../src/commands/$.yes.mjs'; let cancelled = false; const abortController = new AbortController(); diff --git a/js/examples/test-yes-trace.mjs b/js/examples/test-yes-trace.mjs index b2cd04c..8cf0316 100755 --- a/js/examples/test-yes-trace.mjs +++ b/js/examples/test-yes-trace.mjs @@ -1,4 +1,4 @@ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing yes command stopping...'); diff --git a/js/examples/trace-abort-controller.mjs b/js/examples/trace-abort-controller.mjs index 02082c6..3e17a0d 100755 --- a/js/examples/trace-abort-controller.mjs +++ b/js/examples/trace-abort-controller.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-abort-controller.mjs */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing AbortController with tracing...'); diff --git a/js/examples/trace-error-handling.mjs b/js/examples/trace-error-handling.mjs index 185f044..abc1752 100755 --- a/js/examples/trace-error-handling.mjs +++ b/js/examples/trace-error-handling.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-error-handling.mjs */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing error handling with tracing...'); diff --git a/js/examples/trace-pipeline-command.mjs b/js/examples/trace-pipeline-command.mjs index 93223f6..b56c8ea 100755 --- a/js/examples/trace-pipeline-command.mjs +++ b/js/examples/trace-pipeline-command.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-pipeline-command.mjs */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing pipeline command with tracing...'); diff --git a/js/examples/trace-signal-handling.mjs b/js/examples/trace-signal-handling.mjs index 63e8773..a633333 100755 --- a/js/examples/trace-signal-handling.mjs +++ b/js/examples/trace-signal-handling.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-signal-handling.mjs */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing signal handling with tracing...'); diff --git a/js/examples/trace-simple-command.mjs b/js/examples/trace-simple-command.mjs index 24191a4..c303f5e 100755 --- a/js/examples/trace-simple-command.mjs +++ b/js/examples/trace-simple-command.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-simple-command.mjs */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing simple command execution with tracing...'); diff --git a/js/examples/trace-stderr-output.mjs b/js/examples/trace-stderr-output.mjs index b44547a..1678a89 100755 --- a/js/examples/trace-stderr-output.mjs +++ b/js/examples/trace-stderr-output.mjs @@ -10,7 +10,7 @@ * COMMAND_STREAM_TRACE=ProcessRunner node js/examples/trace-stderr-output.mjs */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing stderr output with tracing...'); diff --git a/js/examples/verify-fix-both-runtimes.mjs b/js/examples/verify-fix-both-runtimes.mjs index ea47534..cf158b9 100644 --- a/js/examples/verify-fix-both-runtimes.mjs +++ b/js/examples/verify-fix-both-runtimes.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Verification script that works in both Bun and Node.js -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; const runtime = typeof globalThis.Bun !== 'undefined' ? 'Bun' : 'Node.js'; console.log(`=== Fix Verification for ${runtime} ===`); diff --git a/js/examples/verify-issue12-fixed.mjs b/js/examples/verify-issue12-fixed.mjs index 4a9beef..a16ad74 100644 --- a/js/examples/verify-issue12-fixed.mjs +++ b/js/examples/verify-issue12-fixed.mjs @@ -4,7 +4,7 @@ // Issue: https://github.com/link-foundation/command-stream/issues/12 // Original error had double quotes: posix_spawn ''/Users/konard/.claude/local/claude'' -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; import { spawn } from 'child_process'; console.log('=== Issue #12 Fix Verification ===\n'); diff --git a/js/examples/which-command-common-commands.mjs b/js/examples/which-command-common-commands.mjs index c19632c..de52604 100755 --- a/js/examples/which-command-common-commands.mjs +++ b/js/examples/which-command-common-commands.mjs @@ -2,7 +2,7 @@ // Testing with other common commands -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing with other common commands:'); const commands = ['sh', 'ls', 'cat', 'grep']; diff --git a/js/examples/which-command-gh-test.mjs b/js/examples/which-command-gh-test.mjs index 27e3fbc..d79bb9b 100755 --- a/js/examples/which-command-gh-test.mjs +++ b/js/examples/which-command-gh-test.mjs @@ -2,7 +2,7 @@ // Testing which gh (the command from GitHub issue #7) -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing which gh (the command from the GitHub issue):'); try { diff --git a/js/examples/which-command-nonexistent.mjs b/js/examples/which-command-nonexistent.mjs index 27a4895..0ebab35 100755 --- a/js/examples/which-command-nonexistent.mjs +++ b/js/examples/which-command-nonexistent.mjs @@ -2,7 +2,7 @@ // Testing non-existent command -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Testing non-existent command:'); try { diff --git a/js/examples/which-command-system-comparison.mjs b/js/examples/which-command-system-comparison.mjs index 04c4fc8..b2ecbbc 100755 --- a/js/examples/which-command-system-comparison.mjs +++ b/js/examples/which-command-system-comparison.mjs @@ -2,7 +2,7 @@ // Comparing with system /usr/bin/which -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('Comparing with system /usr/bin/which:'); try { diff --git a/js/examples/working-example.mjs b/js/examples/working-example.mjs index 68dc3e9..00b3fd7 100755 --- a/js/examples/working-example.mjs +++ b/js/examples/working-example.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; // Simple working example - generate numbers with delay to see real streaming console.log('๐Ÿš€ Real streaming example'); diff --git a/js/examples/working-stdin-examples.mjs b/js/examples/working-stdin-examples.mjs index d899cbc..342d814 100755 --- a/js/examples/working-stdin-examples.mjs +++ b/js/examples/working-stdin-examples.mjs @@ -4,7 +4,7 @@ * Working examples of stdin control that account for async process spawning */ -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Working stdin control examples ==='); diff --git a/js/examples/working-streaming-demo.mjs b/js/examples/working-streaming-demo.mjs index 04ecc42..41ea4b6 100755 --- a/js/examples/working-streaming-demo.mjs +++ b/js/examples/working-streaming-demo.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { $ } from '../js/src/$.mjs'; +import { $ } from '../src/$.mjs'; console.log('=== Working Streaming Examples (without pipes) ===\n'); From 93b3c10f42dda2730aa3d60afa44b6d6d006b4b6 Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 29 Dec 2025 14:50:41 +0100 Subject: [PATCH 9/9] Fix path to test-sleep.mjs in ctrl-c-signal test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update path from examples/ to js/examples/ in script path ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- js/tests/ctrl-c-signal.test.mjs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/tests/ctrl-c-signal.test.mjs b/js/tests/ctrl-c-signal.test.mjs index 7347787..0293492 100644 --- a/js/tests/ctrl-c-signal.test.mjs +++ b/js/tests/ctrl-c-signal.test.mjs @@ -116,7 +116,11 @@ describe.skipIf(isWindows)('CTRL+C Signal Handling', () => { // Check if file exists first const fs = await import('fs'); const path = await import('path'); - const scriptPath = path.join(process.cwd(), 'examples', 'test-sleep.mjs'); + const scriptPath = path.join( + process.cwd(), + 'js/examples', + 'test-sleep.mjs' + ); trace('SignalTest', () => `Script path: ${scriptPath}`); trace('SignalTest', () => `Script exists: ${fs.existsSync(scriptPath)}`);