command-stream 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. package/js/examples/01-basic-streaming.mjs +14 -0
  2. package/js/examples/02-async-iterator.mjs +9 -0
  3. package/js/examples/03-file-and-console.mjs +16 -0
  4. package/js/examples/04-claude-jq-pipe.mjs +16 -0
  5. package/js/examples/CI-DEBUG-README.md +138 -0
  6. package/js/examples/README-examples.mjs +111 -0
  7. package/js/examples/README.md +345 -0
  8. package/js/examples/STREAMING_INTERFACES_SUMMARY.md +116 -0
  9. package/js/examples/add-test-timeouts.js +107 -0
  10. package/js/examples/ansi-default-preserved.mjs +11 -0
  11. package/js/examples/ansi-global-config.mjs +12 -0
  12. package/js/examples/ansi-reset-default.mjs +12 -0
  13. package/js/examples/ansi-strip-utils.mjs +12 -0
  14. package/js/examples/baseline-child-process.mjs +23 -0
  15. package/js/examples/baseline-claude-test.mjs +47 -0
  16. package/js/examples/baseline-working.mjs +34 -0
  17. package/js/examples/capture-mirror-comparison.mjs +23 -0
  18. package/js/examples/capture-mirror-default.mjs +11 -0
  19. package/js/examples/capture-mirror-performance.mjs +16 -0
  20. package/js/examples/capture-mirror-show-only.mjs +16 -0
  21. package/js/examples/capture-mirror-silent-processing.mjs +16 -0
  22. package/js/examples/ci-debug-baseline-vs-library.mjs +265 -0
  23. package/js/examples/ci-debug-es-module-loading.mjs +184 -0
  24. package/js/examples/ci-debug-signal-handling.mjs +225 -0
  25. package/js/examples/ci-debug-stdout-buffering.mjs +94 -0
  26. package/js/examples/ci-debug-test-timeouts.mjs +259 -0
  27. package/js/examples/claude-exact-file-output.mjs +20 -0
  28. package/js/examples/claude-exact-jq.mjs +13 -0
  29. package/js/examples/claude-exact-streaming.mjs +13 -0
  30. package/js/examples/claude-jq-pipeline.mjs +13 -0
  31. package/js/examples/claude-json-stream.mjs +39 -0
  32. package/js/examples/claude-streaming-basic.mjs +99 -0
  33. package/js/examples/claude-streaming-demo.mjs +126 -0
  34. package/js/examples/claude-streaming-final.mjs +20 -0
  35. package/js/examples/cleanup-verification-test.mjs +115 -0
  36. package/js/examples/colors-buffer-processing.mjs +14 -0
  37. package/js/examples/colors-default-preserved.mjs +15 -0
  38. package/js/examples/colors-per-command-config.mjs +15 -0
  39. package/js/examples/colors-strip-ansi.mjs +13 -0
  40. package/js/examples/commandstream-jq.mjs +29 -0
  41. package/js/examples/commandstream-working.mjs +23 -0
  42. package/js/examples/comprehensive-streams-demo.mjs +121 -0
  43. package/js/examples/ctrl-c-concurrent-processes.mjs +20 -0
  44. package/js/examples/ctrl-c-long-running-command.mjs +20 -0
  45. package/js/examples/ctrl-c-real-system-command.mjs +17 -0
  46. package/js/examples/ctrl-c-sleep-command.mjs +17 -0
  47. package/js/examples/ctrl-c-stdin-forwarding.mjs +20 -0
  48. package/js/examples/ctrl-c-virtual-command.mjs +17 -0
  49. package/js/examples/debug-already-started.mjs +20 -0
  50. package/js/examples/debug-ansi-processing.mjs +42 -0
  51. package/js/examples/debug-basic-streaming.mjs +44 -0
  52. package/js/examples/debug-buildshellcommand.mjs +82 -0
  53. package/js/examples/debug-child-process.mjs +43 -0
  54. package/js/examples/debug-child-state.mjs +55 -0
  55. package/js/examples/debug-chunking.mjs +38 -0
  56. package/js/examples/debug-command-parsing.mjs +61 -0
  57. package/js/examples/debug-complete-consolidation.mjs +97 -0
  58. package/js/examples/debug-echo-args.mjs +22 -0
  59. package/js/examples/debug-emit-timing.mjs +28 -0
  60. package/js/examples/debug-end-event.mjs +56 -0
  61. package/js/examples/debug-errexit.mjs +16 -0
  62. package/js/examples/debug-event-emission.mjs +40 -0
  63. package/js/examples/debug-event-timing.mjs +67 -0
  64. package/js/examples/debug-event-vs-result.mjs +30 -0
  65. package/js/examples/debug-exact-command.mjs +28 -0
  66. package/js/examples/debug-exact-test-scenario.mjs +44 -0
  67. package/js/examples/debug-execution-path.mjs +27 -0
  68. package/js/examples/debug-exit-command.mjs +38 -0
  69. package/js/examples/debug-exit-virtual.mjs +54 -0
  70. package/js/examples/debug-finish-consolidation.mjs +44 -0
  71. package/js/examples/debug-force-cleanup.mjs +47 -0
  72. package/js/examples/debug-getter-basic.mjs +13 -0
  73. package/js/examples/debug-getter-direct.mjs +23 -0
  74. package/js/examples/debug-getter-internals.mjs +61 -0
  75. package/js/examples/debug-handler-detection.mjs +65 -0
  76. package/js/examples/debug-idempotent-finish.mjs +54 -0
  77. package/js/examples/debug-idempotent-kill.mjs +58 -0
  78. package/js/examples/debug-interpolation-individual.mjs +88 -0
  79. package/js/examples/debug-interpolation-issue.mjs +101 -0
  80. package/js/examples/debug-jq-streaming.mjs +57 -0
  81. package/js/examples/debug-jq-tty-colors.mjs +168 -0
  82. package/js/examples/debug-kill-cleanup.mjs +56 -0
  83. package/js/examples/debug-kill-method.mjs +33 -0
  84. package/js/examples/debug-listener-interference.mjs +38 -0
  85. package/js/examples/debug-listener-lifecycle.mjs +50 -0
  86. package/js/examples/debug-listener-timing.mjs +62 -0
  87. package/js/examples/debug-listeners-property.mjs +34 -0
  88. package/js/examples/debug-map-methods.mjs +39 -0
  89. package/js/examples/debug-not-awaited-cleanup.mjs +106 -0
  90. package/js/examples/debug-off-method.mjs +28 -0
  91. package/js/examples/debug-option-merging.mjs +17 -0
  92. package/js/examples/debug-options.mjs +36 -0
  93. package/js/examples/debug-output.mjs +25 -0
  94. package/js/examples/debug-pattern-matching.mjs +69 -0
  95. package/js/examples/debug-pipeline-cat.mjs +28 -0
  96. package/js/examples/debug-pipeline-cleanup.mjs +71 -0
  97. package/js/examples/debug-pipeline-error-detailed.mjs +78 -0
  98. package/js/examples/debug-pipeline-error.mjs +65 -0
  99. package/js/examples/debug-pipeline-issue.mjs +26 -0
  100. package/js/examples/debug-pipeline-method.mjs +22 -0
  101. package/js/examples/debug-pipeline-stream.mjs +66 -0
  102. package/js/examples/debug-pipeline.mjs +14 -0
  103. package/js/examples/debug-process-exit-trace.mjs +41 -0
  104. package/js/examples/debug-process-path.mjs +38 -0
  105. package/js/examples/debug-property-check.mjs +29 -0
  106. package/js/examples/debug-resource-cleanup.mjs +83 -0
  107. package/js/examples/debug-shell-args.mjs +103 -0
  108. package/js/examples/debug-sigint-child-handler.mjs +44 -0
  109. package/js/examples/debug-sigint-forwarding.mjs +61 -0
  110. package/js/examples/debug-sigint-handler-install.mjs +79 -0
  111. package/js/examples/debug-sigint-handler-order.mjs +85 -0
  112. package/js/examples/debug-sigint-listeners.mjs +48 -0
  113. package/js/examples/debug-sigint-start-pattern.mjs +62 -0
  114. package/js/examples/debug-sigint-timer.mjs +40 -0
  115. package/js/examples/debug-simple-command.mjs +49 -0
  116. package/js/examples/debug-simple-getter.mjs +30 -0
  117. package/js/examples/debug-simple.mjs +39 -0
  118. package/js/examples/debug-simplified-finished.mjs +102 -0
  119. package/js/examples/debug-stack-overflow.mjs +25 -0
  120. package/js/examples/debug-stdin-simple.mjs +28 -0
  121. package/js/examples/debug-stdin.mjs +28 -0
  122. package/js/examples/debug-stream-emitter-isolated.mjs +45 -0
  123. package/js/examples/debug-stream-emitter.mjs +25 -0
  124. package/js/examples/debug-stream-events.mjs +70 -0
  125. package/js/examples/debug-stream-generator.mjs +23 -0
  126. package/js/examples/debug-stream-getter-issue.mjs +37 -0
  127. package/js/examples/debug-stream-getter.mjs +19 -0
  128. package/js/examples/debug-stream-internals.mjs +64 -0
  129. package/js/examples/debug-stream-method.mjs +46 -0
  130. package/js/examples/debug-stream-object.mjs +58 -0
  131. package/js/examples/debug-stream-properties.mjs +37 -0
  132. package/js/examples/debug-stream-timing.mjs +28 -0
  133. package/js/examples/debug-streaming.mjs +24 -0
  134. package/js/examples/debug-test-isolation.mjs +54 -0
  135. package/js/examples/debug-test-state.mjs +27 -0
  136. package/js/examples/debug-user-sigint.mjs +19 -0
  137. package/js/examples/debug-virtual-disable.mjs +21 -0
  138. package/js/examples/debug-virtual-vs-real.mjs +68 -0
  139. package/js/examples/debug-with-trace.mjs +23 -0
  140. package/js/examples/debug_parent_stream.mjs +22 -0
  141. package/js/examples/emulate-claude-stream.mjs +30 -0
  142. package/js/examples/emulated-streaming-direct.mjs +22 -0
  143. package/js/examples/emulated-streaming-jq-pipe.mjs +22 -0
  144. package/js/examples/emulated-streaming-sh-pipe.mjs +23 -0
  145. package/js/examples/events-build-process.mjs +73 -0
  146. package/js/examples/events-concurrent-streams.mjs +51 -0
  147. package/js/examples/events-error-handling.mjs +59 -0
  148. package/js/examples/events-file-monitoring.mjs +66 -0
  149. package/js/examples/events-interactive-simulation.mjs +69 -0
  150. package/js/examples/events-log-processing.mjs +72 -0
  151. package/js/examples/events-network-monitoring.mjs +68 -0
  152. package/js/examples/events-ping-basic.mjs +37 -0
  153. package/js/examples/events-progress-tracking.mjs +55 -0
  154. package/js/examples/events-stdin-input.mjs +34 -0
  155. package/js/examples/example-ansi-ls.mjs +39 -0
  156. package/js/examples/example-top.mjs +27 -0
  157. package/js/examples/final-ping-stdin-proof.mjs +88 -0
  158. package/js/examples/final-test-shell-operators.mjs +123 -0
  159. package/js/examples/final-working-examples.mjs +162 -0
  160. package/js/examples/gh-auth-test.mjs +103 -0
  161. package/js/examples/gh-delete-hang-test.mjs +79 -0
  162. package/js/examples/gh-gist-creation-test.mjs +276 -0
  163. package/js/examples/gh-gist-minimal-test.mjs +89 -0
  164. package/js/examples/gh-hang-exact-original.mjs +83 -0
  165. package/js/examples/gh-hang-reproduction.mjs +151 -0
  166. package/js/examples/gh-hang-test-with-redirect.mjs +45 -0
  167. package/js/examples/gh-hang-test-without-redirect.mjs +43 -0
  168. package/js/examples/gh-minimal-hang-check.mjs +33 -0
  169. package/js/examples/gh-operations-with-cd.mjs +187 -0
  170. package/js/examples/gh-output-test.mjs +102 -0
  171. package/js/examples/gh-reproduce-hang.mjs +41 -0
  172. package/js/examples/git-operations-with-cd.mjs +186 -0
  173. package/js/examples/interactive-math-calc.mjs +45 -0
  174. package/js/examples/interactive-top-fixed.mjs +25 -0
  175. package/js/examples/interactive-top-improved.mjs +72 -0
  176. package/js/examples/interactive-top-pty-logging.mjs +69 -0
  177. package/js/examples/interactive-top-pty.mjs +27 -0
  178. package/js/examples/interactive-top-with-logging.mjs +56 -0
  179. package/js/examples/interactive-top.mjs +29 -0
  180. package/js/examples/jq-color-demo.mjs +53 -0
  181. package/js/examples/jq-colors-streaming.mjs +42 -0
  182. package/js/examples/manual-ctrl-c-test.mjs +50 -0
  183. package/js/examples/methods-multiple-options.mjs +25 -0
  184. package/js/examples/methods-run-basic.mjs +10 -0
  185. package/js/examples/methods-start-basic.mjs +10 -0
  186. package/js/examples/node-compat-data-events.mjs +36 -0
  187. package/js/examples/node-compat-readable-event.mjs +29 -0
  188. package/js/examples/node-compat-small-buffer.mjs +33 -0
  189. package/js/examples/options-capture-false.mjs +12 -0
  190. package/js/examples/options-combined-settings.mjs +13 -0
  191. package/js/examples/options-custom-input.mjs +16 -0
  192. package/js/examples/options-default-behavior.mjs +10 -0
  193. package/js/examples/options-maximum-performance.mjs +15 -0
  194. package/js/examples/options-mirror-false.mjs +10 -0
  195. package/js/examples/options-performance-mode.mjs +13 -0
  196. package/js/examples/options-performance-optimization.mjs +14 -0
  197. package/js/examples/options-run-alias-demo.mjs +15 -0
  198. package/js/examples/options-run-alias.mjs +10 -0
  199. package/js/examples/options-silent-execution.mjs +14 -0
  200. package/js/examples/options-streaming-capture.mjs +24 -0
  201. package/js/examples/options-streaming-multiple.mjs +35 -0
  202. package/js/examples/options-streaming-silent.mjs +21 -0
  203. package/js/examples/options-streaming-stdin.mjs +21 -0
  204. package/js/examples/ping-streaming-filtered.mjs +22 -0
  205. package/js/examples/ping-streaming-interruptible.mjs +47 -0
  206. package/js/examples/ping-streaming-silent.mjs +24 -0
  207. package/js/examples/ping-streaming-simple.mjs +13 -0
  208. package/js/examples/ping-streaming-statistics.mjs +49 -0
  209. package/js/examples/ping-streaming-timestamps.mjs +22 -0
  210. package/js/examples/ping-streaming.mjs +48 -0
  211. package/js/examples/prove-ping-stdin-limitation.mjs +94 -0
  212. package/js/examples/readme-example.mjs +39 -0
  213. package/js/examples/realtime-json-stream.mjs +143 -0
  214. package/js/examples/reliable-stdin-commands.mjs +135 -0
  215. package/js/examples/reproduce-issue-135-v2.mjs +15 -0
  216. package/js/examples/reproduce-issue-135.mjs +17 -0
  217. package/js/examples/shell-cd-behavior.mjs +88 -0
  218. package/js/examples/sigint-forwarding-test.mjs +60 -0
  219. package/js/examples/sigint-handler-test.mjs +72 -0
  220. package/js/examples/simple-async-test.mjs +49 -0
  221. package/js/examples/simple-claude-test.mjs +17 -0
  222. package/js/examples/simple-event-test.mjs +33 -0
  223. package/js/examples/simple-jq-streaming.mjs +48 -0
  224. package/js/examples/simple-stream-demo.mjs +35 -0
  225. package/js/examples/simple-test-sleep.js +30 -0
  226. package/js/examples/simple-working-stdin.mjs +30 -0
  227. package/js/examples/streaming-behavior-test.mjs +116 -0
  228. package/js/examples/streaming-direct-command.mjs +21 -0
  229. package/js/examples/streaming-filtered-output.mjs +33 -0
  230. package/js/examples/streaming-grep-pipeline.mjs +21 -0
  231. package/js/examples/streaming-interactive-stdin.mjs +24 -0
  232. package/js/examples/streaming-jq-pipeline.mjs +23 -0
  233. package/js/examples/streaming-multistage-pipeline.mjs +23 -0
  234. package/js/examples/streaming-pipes-event-pattern.mjs +27 -0
  235. package/js/examples/streaming-pipes-multistage.mjs +22 -0
  236. package/js/examples/streaming-pipes-realtime-jq.mjs +23 -0
  237. package/js/examples/streaming-progress-tracking.mjs +34 -0
  238. package/js/examples/streaming-reusable-configs.mjs +52 -0
  239. package/js/examples/streaming-silent-capture.mjs +20 -0
  240. package/js/examples/streaming-test-simple.mjs +70 -0
  241. package/js/examples/streaming-virtual-pipeline.mjs +18 -0
  242. package/js/examples/syntax-basic-comparison.mjs +31 -0
  243. package/js/examples/syntax-basic-options.mjs +12 -0
  244. package/js/examples/syntax-combined-options.mjs +19 -0
  245. package/js/examples/syntax-command-chaining.mjs +12 -0
  246. package/js/examples/syntax-custom-directory.mjs +10 -0
  247. package/js/examples/syntax-custom-environment.mjs +13 -0
  248. package/js/examples/syntax-custom-stdin.mjs +10 -0
  249. package/js/examples/syntax-mixed-regular.mjs +11 -0
  250. package/js/examples/syntax-mixed-usage.mjs +15 -0
  251. package/js/examples/syntax-multiple-listeners.mjs +87 -0
  252. package/js/examples/syntax-piping-comparison.mjs +32 -0
  253. package/js/examples/syntax-reusable-config.mjs +16 -0
  254. package/js/examples/syntax-reusable-configs.mjs +21 -0
  255. package/js/examples/syntax-silent-operations.mjs +10 -0
  256. package/js/examples/syntax-stdin-option.mjs +12 -0
  257. package/js/examples/temp-sigint-test.mjs +21 -0
  258. package/js/examples/test-actual-buildshell.mjs +44 -0
  259. package/js/examples/test-async-streams-working.mjs +102 -0
  260. package/js/examples/test-async-streams.mjs +90 -0
  261. package/js/examples/test-auth-parse.mjs +74 -0
  262. package/js/examples/test-auto-quoting.mjs +57 -0
  263. package/js/examples/test-auto-start-fix.mjs +95 -0
  264. package/js/examples/test-baseline-sigint.mjs +38 -0
  265. package/js/examples/test-buffer-behavior.mjs +39 -0
  266. package/js/examples/test-buffers-simple.mjs +35 -0
  267. package/js/examples/test-bun-specific-issue.mjs +106 -0
  268. package/js/examples/test-bun-streaming.mjs +81 -0
  269. package/js/examples/test-cat-direct.mjs +41 -0
  270. package/js/examples/test-cat-pipe.mjs +34 -0
  271. package/js/examples/test-cd-behavior.mjs +42 -0
  272. package/js/examples/test-child-process-timing.mjs +53 -0
  273. package/js/examples/test-child-sigint-handler.mjs +62 -0
  274. package/js/examples/test-cleanup-simple.mjs +21 -0
  275. package/js/examples/test-comprehensive-tracing.mjs +58 -0
  276. package/js/examples/test-correct-space-handling.mjs +46 -0
  277. package/js/examples/test-ctrl-c-debug.mjs +44 -0
  278. package/js/examples/test-ctrl-c-inherit.mjs +30 -0
  279. package/js/examples/test-ctrl-c-sleep.mjs +31 -0
  280. package/js/examples/test-ctrl-c.mjs +17 -0
  281. package/js/examples/test-debug-new-options.mjs +55 -0
  282. package/js/examples/test-debug-pty.mjs +49 -0
  283. package/js/examples/test-debug-tee.mjs +38 -0
  284. package/js/examples/test-debug.mjs +25 -0
  285. package/js/examples/test-direct-jq.mjs +47 -0
  286. package/js/examples/test-direct-pipe-reading.mjs +119 -0
  287. package/js/examples/test-direct-pipe.sh +28 -0
  288. package/js/examples/test-double-quoting-prevention.mjs +138 -0
  289. package/js/examples/test-edge-cases-quoting.mjs +89 -0
  290. package/js/examples/test-events.mjs +37 -0
  291. package/js/examples/test-explicit-stdio.mjs +51 -0
  292. package/js/examples/test-final-streaming.mjs +71 -0
  293. package/js/examples/test-fix.mjs +71 -0
  294. package/js/examples/test-incremental-streaming.mjs +46 -0
  295. package/js/examples/test-individual-spawn.mjs +35 -0
  296. package/js/examples/test-inherit-stdout-not-stdin.mjs +133 -0
  297. package/js/examples/test-injection-protection.mjs +77 -0
  298. package/js/examples/test-interactive-streaming.mjs +140 -0
  299. package/js/examples/test-interactive-top.md +24 -0
  300. package/js/examples/test-interactive.mjs +17 -0
  301. package/js/examples/test-interpolation.mjs +14 -0
  302. package/js/examples/test-interrupt.mjs +40 -0
  303. package/js/examples/test-issue-135-comprehensive.mjs +41 -0
  304. package/js/examples/test-issue12-detailed.mjs +89 -0
  305. package/js/examples/test-issue12-exact.mjs +33 -0
  306. package/js/examples/test-jq-color.mjs +57 -0
  307. package/js/examples/test-jq-colors.mjs +41 -0
  308. package/js/examples/test-jq-compact.mjs +33 -0
  309. package/js/examples/test-jq-native.sh +10 -0
  310. package/js/examples/test-jq-pipeline-behavior.mjs +80 -0
  311. package/js/examples/test-jq-realtime.mjs +40 -0
  312. package/js/examples/test-manual-start.mjs +54 -0
  313. package/js/examples/test-mixed-quoting.mjs +88 -0
  314. package/js/examples/test-multi-stream.mjs +50 -0
  315. package/js/examples/test-multistage-debug.mjs +44 -0
  316. package/js/examples/test-native-spawn-vs-command-stream.mjs +154 -0
  317. package/js/examples/test-no-parse-pipeline.mjs +33 -0
  318. package/js/examples/test-non-virtual.mjs +52 -0
  319. package/js/examples/test-operators.mjs +53 -0
  320. package/js/examples/test-parent-continues.mjs +44 -0
  321. package/js/examples/test-path-interpolation.mjs +86 -0
  322. package/js/examples/test-ping-kill-and-stdin.mjs +98 -0
  323. package/js/examples/test-ping.mjs +12 -0
  324. package/js/examples/test-pty-spawn.mjs +101 -0
  325. package/js/examples/test-pty.mjs +38 -0
  326. package/js/examples/test-quote-behavior-summary.mjs +110 -0
  327. package/js/examples/test-quote-edge-cases.mjs +69 -0
  328. package/js/examples/test-quote-parsing.mjs +23 -0
  329. package/js/examples/test-raw-function.mjs +153 -0
  330. package/js/examples/test-raw-streaming.mjs +47 -0
  331. package/js/examples/test-readme-examples.mjs +142 -0
  332. package/js/examples/test-real-cat.mjs +28 -0
  333. package/js/examples/test-real-commands.mjs +21 -0
  334. package/js/examples/test-real-shell.mjs +31 -0
  335. package/js/examples/test-real-stdin-commands.mjs +160 -0
  336. package/js/examples/test-runner-batched.mjs +98 -0
  337. package/js/examples/test-runner-simple.mjs +80 -0
  338. package/js/examples/test-runner.mjs +67 -0
  339. package/js/examples/test-scope-parse.mjs +31 -0
  340. package/js/examples/test-sh-pipeline.mjs +24 -0
  341. package/js/examples/test-shell-detection.mjs +71 -0
  342. package/js/examples/test-shell-parser.mjs +37 -0
  343. package/js/examples/test-sigint-behavior.mjs +241 -0
  344. package/js/examples/test-sigint-handling.sh +14 -0
  345. package/js/examples/test-simple-pipe.mjs +12 -0
  346. package/js/examples/test-simple-streaming.mjs +32 -0
  347. package/js/examples/test-sleep-stdin.js +27 -0
  348. package/js/examples/test-sleep.mjs +56 -0
  349. package/js/examples/test-smart-quoting.mjs +180 -0
  350. package/js/examples/test-spaces-in-path.mjs +48 -0
  351. package/js/examples/test-special-chars-quoting.mjs +54 -0
  352. package/js/examples/test-stdin-after-start.mjs +39 -0
  353. package/js/examples/test-stdin-simple.mjs +67 -0
  354. package/js/examples/test-stdin-timing.mjs +74 -0
  355. package/js/examples/test-stdio-combinations.mjs +124 -0
  356. package/js/examples/test-stream-access.mjs +84 -0
  357. package/js/examples/test-stream-cleanup.mjs +27 -0
  358. package/js/examples/test-stream-readers.mjs +152 -0
  359. package/js/examples/test-streaming-final.mjs +57 -0
  360. package/js/examples/test-streaming-interfaces.mjs +141 -0
  361. package/js/examples/test-streaming-timing.mjs +27 -0
  362. package/js/examples/test-streaming.mjs +32 -0
  363. package/js/examples/test-streams-stdin-comprehensive.mjs +134 -0
  364. package/js/examples/test-streams-stdin-ctrl-c.mjs +96 -0
  365. package/js/examples/test-template-literal.mjs +26 -0
  366. package/js/examples/test-template-vs-interpolation.mjs +49 -0
  367. package/js/examples/test-timing.mjs +41 -0
  368. package/js/examples/test-top-inherit-stdout-stdin-control.mjs +123 -0
  369. package/js/examples/test-top-quit-stdin.mjs +118 -0
  370. package/js/examples/test-trace-option.mjs +21 -0
  371. package/js/examples/test-user-double-quotes.mjs +36 -0
  372. package/js/examples/test-user-single-quotes.mjs +36 -0
  373. package/js/examples/test-verbose.mjs +18 -0
  374. package/js/examples/test-verbose2.mjs +32 -0
  375. package/js/examples/test-virtual-streaming.mjs +125 -0
  376. package/js/examples/test-waiting-command.mjs +52 -0
  377. package/js/examples/test-waiting-commands.mjs +83 -0
  378. package/js/examples/test-watch-mode.mjs +104 -0
  379. package/js/examples/test-yes-cancellation.mjs +26 -0
  380. package/js/examples/test-yes-detailed.mjs +58 -0
  381. package/js/examples/test-yes-trace.mjs +28 -0
  382. package/js/examples/trace-abort-controller.mjs +30 -0
  383. package/js/examples/trace-error-handling.mjs +22 -0
  384. package/js/examples/trace-pipeline-command.mjs +22 -0
  385. package/js/examples/trace-signal-handling.mjs +35 -0
  386. package/js/examples/trace-simple-command.mjs +18 -0
  387. package/js/examples/trace-stderr-output.mjs +22 -0
  388. package/js/examples/verify-fix-both-runtimes.mjs +73 -0
  389. package/js/examples/verify-issue12-fixed.mjs +78 -0
  390. package/js/examples/which-command-common-commands.mjs +19 -0
  391. package/js/examples/which-command-gh-test.mjs +23 -0
  392. package/js/examples/which-command-nonexistent.mjs +20 -0
  393. package/js/examples/which-command-system-comparison.mjs +28 -0
  394. package/js/examples/working-example.mjs +13 -0
  395. package/js/examples/working-stdin-examples.mjs +138 -0
  396. package/js/examples/working-streaming-demo.mjs +49 -0
  397. package/{src → js/src}/$.mjs +20 -4
  398. package/{src → js/src}/$.utils.mjs +14 -2
  399. package/js/tests/$.features.test.mjs +283 -0
  400. package/js/tests/$.test.mjs +935 -0
  401. package/js/tests/builtin-commands.test.mjs +387 -0
  402. package/js/tests/bun-shell-path-fix.test.mjs +115 -0
  403. package/js/tests/bun.features.test.mjs +189 -0
  404. package/js/tests/cd-virtual-command.test.mjs +622 -0
  405. package/js/tests/cleanup-verification.test.mjs +127 -0
  406. package/js/tests/ctrl-c-baseline.test.mjs +207 -0
  407. package/js/tests/ctrl-c-basic.test.mjs +220 -0
  408. package/js/tests/ctrl-c-library.test.mjs +197 -0
  409. package/js/tests/ctrl-c-signal.test.mjs +915 -0
  410. package/js/tests/examples.test.mjs +252 -0
  411. package/js/tests/execa.features.test.mjs +198 -0
  412. package/js/tests/gh-commands.test.mjs +164 -0
  413. package/js/tests/gh-gist-operations.test.mjs +221 -0
  414. package/js/tests/git-gh-cd.test.mjs +466 -0
  415. package/js/tests/interactive-option.test.mjs +114 -0
  416. package/js/tests/interactive-streaming.test.mjs +307 -0
  417. package/js/tests/issue-135-final.test.mjs +58 -0
  418. package/js/tests/jq-color-behavior.test.mjs +140 -0
  419. package/js/tests/jq.test.mjs +318 -0
  420. package/js/tests/options-examples.test.mjs +106 -0
  421. package/js/tests/options-syntax.test.mjs +112 -0
  422. package/js/tests/path-interpolation.test.mjs +412 -0
  423. package/js/tests/pipe.test.mjs +291 -0
  424. package/js/tests/raw-function.test.mjs +266 -0
  425. package/js/tests/readme-examples.test.mjs +427 -0
  426. package/js/tests/resource-cleanup-internals.test.mjs +669 -0
  427. package/js/tests/shell-settings.test.mjs +279 -0
  428. package/js/tests/sigint-cleanup-isolated.test.mjs +151 -0
  429. package/js/tests/sigint-cleanup.test.mjs +118 -0
  430. package/js/tests/start-run-edge-cases.test.mjs +152 -0
  431. package/js/tests/start-run-options.test.mjs +181 -0
  432. package/js/tests/stderr-output-handling.test.mjs +279 -0
  433. package/js/tests/streaming-interfaces.test.mjs +194 -0
  434. package/js/tests/sync.test.mjs +297 -0
  435. package/js/tests/system-pipe.test.mjs +226 -0
  436. package/js/tests/test-cleanup.mjs +200 -0
  437. package/js/tests/test-helper-fixed.mjs +148 -0
  438. package/js/tests/test-helper-v2.mjs +118 -0
  439. package/js/tests/test-helper.mjs +171 -0
  440. package/js/tests/test-sigint-child.js +15 -0
  441. package/js/tests/text-method.test.mjs +225 -0
  442. package/js/tests/virtual.test.mjs +364 -0
  443. package/js/tests/yes-command-cleanup.test.mjs +208 -0
  444. package/js/tests/zx.features.test.mjs +233 -0
  445. package/package.json +13 -12
  446. package/rust/Cargo.lock +947 -0
  447. package/rust/Cargo.toml +47 -0
  448. package/rust/src/commands/basename.rs +69 -0
  449. package/rust/src/commands/cat.rs +123 -0
  450. package/rust/src/commands/cd.rs +67 -0
  451. package/rust/src/commands/cp.rs +187 -0
  452. package/rust/src/commands/dirname.rs +57 -0
  453. package/rust/src/commands/echo.rs +73 -0
  454. package/rust/src/commands/env.rs +33 -0
  455. package/rust/src/commands/exit.rs +36 -0
  456. package/rust/src/commands/false.rs +24 -0
  457. package/rust/src/commands/ls.rs +182 -0
  458. package/rust/src/commands/mkdir.rs +98 -0
  459. package/rust/src/commands/mod.rs +200 -0
  460. package/rust/src/commands/mv.rs +180 -0
  461. package/rust/src/commands/pwd.rs +28 -0
  462. package/rust/src/commands/rm.rs +150 -0
  463. package/rust/src/commands/seq.rs +179 -0
  464. package/rust/src/commands/sleep.rs +97 -0
  465. package/rust/src/commands/test.rs +204 -0
  466. package/rust/src/commands/touch.rs +99 -0
  467. package/rust/src/commands/true.rs +24 -0
  468. package/rust/src/commands/which.rs +87 -0
  469. package/rust/src/commands/yes.rs +99 -0
  470. package/rust/src/lib.rs +492 -0
  471. package/rust/src/main.rs +37 -0
  472. package/rust/src/shell_parser.rs +565 -0
  473. package/rust/src/utils.rs +335 -0
  474. package/rust/tests/builtin_commands.rs +549 -0
  475. package/rust/tests/process_runner.rs +286 -0
  476. package/rust/tests/shell_parser.rs +296 -0
  477. package/rust/tests/utils.rs +282 -0
  478. package/rust/tests/virtual_commands.rs +199 -0
  479. /package/{src → js/src}/commands/$.basename.mjs +0 -0
  480. /package/{src → js/src}/commands/$.cat.mjs +0 -0
  481. /package/{src → js/src}/commands/$.cd.mjs +0 -0
  482. /package/{src → js/src}/commands/$.cp.mjs +0 -0
  483. /package/{src → js/src}/commands/$.dirname.mjs +0 -0
  484. /package/{src → js/src}/commands/$.echo.mjs +0 -0
  485. /package/{src → js/src}/commands/$.env.mjs +0 -0
  486. /package/{src → js/src}/commands/$.exit.mjs +0 -0
  487. /package/{src → js/src}/commands/$.false.mjs +0 -0
  488. /package/{src → js/src}/commands/$.ls.mjs +0 -0
  489. /package/{src → js/src}/commands/$.mkdir.mjs +0 -0
  490. /package/{src → js/src}/commands/$.mv.mjs +0 -0
  491. /package/{src → js/src}/commands/$.pwd.mjs +0 -0
  492. /package/{src → js/src}/commands/$.rm.mjs +0 -0
  493. /package/{src → js/src}/commands/$.seq.mjs +0 -0
  494. /package/{src → js/src}/commands/$.sleep.mjs +0 -0
  495. /package/{src → js/src}/commands/$.test.mjs +0 -0
  496. /package/{src → js/src}/commands/$.touch.mjs +0 -0
  497. /package/{src → js/src}/commands/$.true.mjs +0 -0
  498. /package/{src → js/src}/commands/$.which.mjs +0 -0
  499. /package/{src → js/src}/commands/$.yes.mjs +0 -0
  500. /package/{src → js/src}/shell-parser.mjs +0 -0
@@ -0,0 +1,492 @@
1
+ //! # command-stream
2
+ //!
3
+ //! Modern shell command execution library with streaming, async iteration, and event support.
4
+ //!
5
+ //! This library provides a Rust equivalent to the JavaScript command-stream library,
6
+ //! offering powerful shell command execution with streaming capabilities.
7
+ //!
8
+ //! ## Features
9
+ //!
10
+ //! - Async command execution with tokio
11
+ //! - Streaming output via async iterators
12
+ //! - Virtual commands for common operations (cat, ls, mkdir, etc.)
13
+ //! - Shell operator support (&&, ||, ;, |)
14
+ //! - Cross-platform support
15
+ //!
16
+ //! ## Quick Start
17
+ //!
18
+ //! ```rust,no_run
19
+ //! use command_stream::run;
20
+ //!
21
+ //! #[tokio::main]
22
+ //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
23
+ //! // Execute a simple command
24
+ //! let result = run("echo hello world").await?;
25
+ //! println!("{}", result.stdout);
26
+ //! Ok(())
27
+ //! }
28
+ //! ```
29
+
30
+ pub mod commands;
31
+ pub mod shell_parser;
32
+ pub mod utils;
33
+
34
+ use std::collections::HashMap;
35
+ use std::env;
36
+ use std::path::PathBuf;
37
+ use std::process::Stdio;
38
+ use std::sync::Arc;
39
+ use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
40
+ use tokio::process::{Child, Command};
41
+ use tokio::sync::{mpsc, Mutex};
42
+
43
+ pub use commands::{CommandContext, StreamChunk};
44
+ pub use shell_parser::{parse_shell_command, needs_real_shell, ParsedCommand};
45
+ pub use utils::{AnsiConfig, AnsiUtils, CommandResult, VirtualUtils, quote, trace};
46
+
47
+ /// Error type for command-stream operations
48
+ #[derive(Debug, thiserror::Error)]
49
+ pub enum Error {
50
+ #[error("IO error: {0}")]
51
+ Io(#[from] std::io::Error),
52
+
53
+ #[error("Command failed with exit code {code}: {message}")]
54
+ CommandFailed { code: i32, message: String },
55
+
56
+ #[error("Command not found: {0}")]
57
+ CommandNotFound(String),
58
+
59
+ #[error("Parse error: {0}")]
60
+ ParseError(String),
61
+
62
+ #[error("Cancelled")]
63
+ Cancelled,
64
+ }
65
+
66
+ /// Result type for command-stream operations
67
+ pub type Result<T> = std::result::Result<T, Error>;
68
+
69
+ /// Shell settings for controlling execution behavior
70
+ #[derive(Debug, Clone, Default)]
71
+ pub struct ShellSettings {
72
+ /// Exit immediately if a command exits with non-zero status (set -e)
73
+ pub errexit: bool,
74
+ /// Print commands as they are executed (set -v)
75
+ pub verbose: bool,
76
+ /// Print trace of commands (set -x)
77
+ pub xtrace: bool,
78
+ /// Return value of a pipeline is the status of the last command to exit with non-zero (set -o pipefail)
79
+ pub pipefail: bool,
80
+ /// Treat unset variables as an error (set -u)
81
+ pub nounset: bool,
82
+ }
83
+
84
+ /// Options for command execution
85
+ #[derive(Debug, Clone)]
86
+ pub struct RunOptions {
87
+ /// Mirror output to parent stdout/stderr
88
+ pub mirror: bool,
89
+ /// Capture output in result
90
+ pub capture: bool,
91
+ /// Standard input handling
92
+ pub stdin: StdinOption,
93
+ /// Working directory
94
+ pub cwd: Option<PathBuf>,
95
+ /// Environment variables
96
+ pub env: Option<HashMap<String, String>>,
97
+ /// Interactive mode (TTY forwarding)
98
+ pub interactive: bool,
99
+ /// Enable shell operator parsing
100
+ pub shell_operators: bool,
101
+ /// Enable tracing for this command
102
+ pub trace: bool,
103
+ }
104
+
105
+ impl Default for RunOptions {
106
+ fn default() -> Self {
107
+ RunOptions {
108
+ mirror: true,
109
+ capture: true,
110
+ stdin: StdinOption::Inherit,
111
+ cwd: None,
112
+ env: None,
113
+ interactive: false,
114
+ shell_operators: true,
115
+ trace: true,
116
+ }
117
+ }
118
+ }
119
+
120
+ /// Standard input options
121
+ #[derive(Debug, Clone)]
122
+ pub enum StdinOption {
123
+ /// Inherit from parent process
124
+ Inherit,
125
+ /// Pipe (allow writing to stdin)
126
+ Pipe,
127
+ /// Provide string content
128
+ Content(String),
129
+ /// Null device
130
+ Null,
131
+ }
132
+
133
+ /// A running or completed process
134
+ pub struct ProcessRunner {
135
+ command: String,
136
+ options: RunOptions,
137
+ child: Option<Child>,
138
+ result: Option<CommandResult>,
139
+ started: bool,
140
+ finished: bool,
141
+ cancelled: bool,
142
+ output_tx: Option<mpsc::Sender<StreamChunk>>,
143
+ output_rx: Option<mpsc::Receiver<StreamChunk>>,
144
+ }
145
+
146
+ impl ProcessRunner {
147
+ /// Create a new process runner
148
+ pub fn new(command: impl Into<String>, options: RunOptions) -> Self {
149
+ let (tx, rx) = mpsc::channel(1024);
150
+ ProcessRunner {
151
+ command: command.into(),
152
+ options,
153
+ child: None,
154
+ result: None,
155
+ started: false,
156
+ finished: false,
157
+ cancelled: false,
158
+ output_tx: Some(tx),
159
+ output_rx: Some(rx),
160
+ }
161
+ }
162
+
163
+ /// Start the process
164
+ pub async fn start(&mut self) -> Result<()> {
165
+ if self.started {
166
+ return Ok(());
167
+ }
168
+ self.started = true;
169
+
170
+ utils::trace_lazy("ProcessRunner", || {
171
+ format!("Starting command: {}", self.command)
172
+ });
173
+
174
+ // Check if this is a virtual command
175
+ let first_word = self.command.split_whitespace().next().unwrap_or("");
176
+ if let Some(result) = self.try_virtual_command(first_word).await {
177
+ self.result = Some(result);
178
+ self.finished = true;
179
+ return Ok(());
180
+ }
181
+
182
+ // Parse command for shell operators
183
+ let parsed = if self.options.shell_operators && !needs_real_shell(&self.command) {
184
+ parse_shell_command(&self.command)
185
+ } else {
186
+ None
187
+ };
188
+
189
+ // Execute via real shell if needed
190
+ let shell = find_available_shell();
191
+
192
+ let mut cmd = Command::new(&shell.cmd);
193
+ for arg in &shell.args {
194
+ cmd.arg(arg);
195
+ }
196
+ cmd.arg(&self.command);
197
+
198
+ // Configure stdin
199
+ match &self.options.stdin {
200
+ StdinOption::Inherit => { cmd.stdin(Stdio::inherit()); }
201
+ StdinOption::Pipe => { cmd.stdin(Stdio::piped()); }
202
+ StdinOption::Content(_) => { cmd.stdin(Stdio::piped()); }
203
+ StdinOption::Null => { cmd.stdin(Stdio::null()); }
204
+ }
205
+
206
+ // Configure stdout/stderr
207
+ if self.options.capture || self.options.mirror {
208
+ cmd.stdout(Stdio::piped());
209
+ cmd.stderr(Stdio::piped());
210
+ } else {
211
+ cmd.stdout(Stdio::inherit());
212
+ cmd.stderr(Stdio::inherit());
213
+ }
214
+
215
+ // Set working directory
216
+ if let Some(ref cwd) = self.options.cwd {
217
+ cmd.current_dir(cwd);
218
+ }
219
+
220
+ // Set environment
221
+ if let Some(ref env_vars) = self.options.env {
222
+ for (key, value) in env_vars {
223
+ cmd.env(key, value);
224
+ }
225
+ }
226
+
227
+ // Spawn the process
228
+ let child = cmd.spawn()?;
229
+ self.child = Some(child);
230
+
231
+ Ok(())
232
+ }
233
+
234
+ /// Run the process to completion
235
+ pub async fn run(&mut self) -> Result<CommandResult> {
236
+ self.start().await?;
237
+
238
+ if let Some(result) = &self.result {
239
+ return Ok(result.clone());
240
+ }
241
+
242
+ let mut child = self.child.take().ok_or_else(|| {
243
+ Error::Io(std::io::Error::new(
244
+ std::io::ErrorKind::Other,
245
+ "Process not started",
246
+ ))
247
+ })?;
248
+
249
+ // Handle stdin content if provided
250
+ if let StdinOption::Content(ref content) = self.options.stdin {
251
+ if let Some(mut stdin) = child.stdin.take() {
252
+ let content = content.clone();
253
+ tokio::spawn(async move {
254
+ let _ = stdin.write_all(content.as_bytes()).await;
255
+ let _ = stdin.shutdown().await;
256
+ });
257
+ }
258
+ }
259
+
260
+ // Collect output
261
+ let mut stdout_content = String::new();
262
+ let mut stderr_content = String::new();
263
+
264
+ if let Some(stdout) = child.stdout.take() {
265
+ let mut reader = BufReader::new(stdout).lines();
266
+ while let Ok(Some(line)) = reader.next_line().await {
267
+ if self.options.mirror {
268
+ println!("{}", line);
269
+ }
270
+ stdout_content.push_str(&line);
271
+ stdout_content.push('\n');
272
+ }
273
+ }
274
+
275
+ if let Some(stderr) = child.stderr.take() {
276
+ let mut reader = BufReader::new(stderr).lines();
277
+ while let Ok(Some(line)) = reader.next_line().await {
278
+ if self.options.mirror {
279
+ eprintln!("{}", line);
280
+ }
281
+ stderr_content.push_str(&line);
282
+ stderr_content.push('\n');
283
+ }
284
+ }
285
+
286
+ let status = child.wait().await?;
287
+ let code = status.code().unwrap_or(-1);
288
+
289
+ let result = CommandResult {
290
+ stdout: stdout_content,
291
+ stderr: stderr_content,
292
+ code,
293
+ };
294
+
295
+ self.result = Some(result.clone());
296
+ self.finished = true;
297
+
298
+ Ok(result)
299
+ }
300
+
301
+ /// Try to execute as a virtual command
302
+ async fn try_virtual_command(&self, cmd_name: &str) -> Option<CommandResult> {
303
+ if !commands::are_virtual_commands_enabled() {
304
+ return None;
305
+ }
306
+
307
+ // Parse args from command string
308
+ let parts: Vec<&str> = self.command.split_whitespace().collect();
309
+ let args: Vec<String> = parts.iter().skip(1).map(|s| s.to_string()).collect();
310
+
311
+ let ctx = CommandContext {
312
+ args,
313
+ stdin: match &self.options.stdin {
314
+ StdinOption::Content(s) => Some(s.clone()),
315
+ _ => None,
316
+ },
317
+ cwd: self.options.cwd.clone(),
318
+ env: self.options.env.clone(),
319
+ output_tx: self.output_tx.clone(),
320
+ is_cancelled: None,
321
+ };
322
+
323
+ match cmd_name {
324
+ "echo" => Some(commands::echo(ctx).await),
325
+ "pwd" => Some(commands::pwd(ctx).await),
326
+ "cd" => Some(commands::cd(ctx).await),
327
+ "true" => Some(commands::r#true(ctx).await),
328
+ "false" => Some(commands::r#false(ctx).await),
329
+ "sleep" => Some(commands::sleep(ctx).await),
330
+ "cat" => Some(commands::cat(ctx).await),
331
+ "ls" => Some(commands::ls(ctx).await),
332
+ "mkdir" => Some(commands::mkdir(ctx).await),
333
+ "rm" => Some(commands::rm(ctx).await),
334
+ "touch" => Some(commands::touch(ctx).await),
335
+ "cp" => Some(commands::cp(ctx).await),
336
+ "mv" => Some(commands::mv(ctx).await),
337
+ "basename" => Some(commands::basename(ctx).await),
338
+ "dirname" => Some(commands::dirname(ctx).await),
339
+ "env" => Some(commands::env(ctx).await),
340
+ "exit" => Some(commands::exit(ctx).await),
341
+ "which" => Some(commands::which(ctx).await),
342
+ "yes" => Some(commands::yes(ctx).await),
343
+ "seq" => Some(commands::seq(ctx).await),
344
+ "test" => Some(commands::test(ctx).await),
345
+ _ => None,
346
+ }
347
+ }
348
+
349
+ /// Kill the process
350
+ pub fn kill(&mut self) -> Result<()> {
351
+ self.cancelled = true;
352
+ if let Some(ref mut child) = self.child {
353
+ child.start_kill()?;
354
+ }
355
+ Ok(())
356
+ }
357
+
358
+ /// Check if the process is finished
359
+ pub fn is_finished(&self) -> bool {
360
+ self.finished
361
+ }
362
+
363
+ /// Get the result if available
364
+ pub fn result(&self) -> Option<&CommandResult> {
365
+ self.result.as_ref()
366
+ }
367
+ }
368
+
369
+ /// Shell configuration
370
+ #[derive(Debug, Clone)]
371
+ struct ShellConfig {
372
+ cmd: String,
373
+ args: Vec<String>,
374
+ }
375
+
376
+ /// Find an available shell
377
+ fn find_available_shell() -> ShellConfig {
378
+ let is_windows = cfg!(windows);
379
+
380
+ if is_windows {
381
+ // Windows shells
382
+ let shells = [
383
+ ("cmd.exe", vec!["/c"]),
384
+ ("powershell.exe", vec!["-Command"]),
385
+ ];
386
+
387
+ for (cmd, args) in shells {
388
+ if which::which(cmd).is_ok() {
389
+ return ShellConfig {
390
+ cmd: cmd.to_string(),
391
+ args: args.into_iter().map(String::from).collect(),
392
+ };
393
+ }
394
+ }
395
+
396
+ ShellConfig {
397
+ cmd: "cmd.exe".to_string(),
398
+ args: vec!["/c".to_string()],
399
+ }
400
+ } else {
401
+ // Unix shells
402
+ let shells = [
403
+ ("/bin/sh", vec!["-c"]),
404
+ ("/usr/bin/sh", vec!["-c"]),
405
+ ("/bin/bash", vec!["-c"]),
406
+ ("sh", vec!["-c"]),
407
+ ];
408
+
409
+ for (cmd, args) in shells {
410
+ if std::path::Path::new(cmd).exists() || which::which(cmd).is_ok() {
411
+ return ShellConfig {
412
+ cmd: cmd.to_string(),
413
+ args: args.into_iter().map(String::from).collect(),
414
+ };
415
+ }
416
+ }
417
+
418
+ ShellConfig {
419
+ cmd: "/bin/sh".to_string(),
420
+ args: vec!["-c".to_string()],
421
+ }
422
+ }
423
+ }
424
+
425
+ /// Execute a command and return the result
426
+ ///
427
+ /// This is the main entry point for simple command execution.
428
+ /// Named `run` instead of `$` since `$` is not a valid Rust identifier.
429
+ pub async fn run(command: impl Into<String>) -> Result<CommandResult> {
430
+ let mut runner = ProcessRunner::new(command, RunOptions::default());
431
+ runner.run().await
432
+ }
433
+
434
+ /// Alias for `run` function - for JavaScript-like API feel
435
+ /// Since `$` is not valid in Rust, this provides a similar short name
436
+ pub use run as execute;
437
+
438
+ /// Execute a command with custom options
439
+ pub async fn exec(command: impl Into<String>, options: RunOptions) -> Result<CommandResult> {
440
+ let mut runner = ProcessRunner::new(command, options);
441
+ runner.run().await
442
+ }
443
+
444
+ /// Create a new process runner without starting it
445
+ pub fn create(command: impl Into<String>, options: RunOptions) -> ProcessRunner {
446
+ ProcessRunner::new(command, options)
447
+ }
448
+
449
+ /// Execute a command synchronously (blocking)
450
+ pub fn run_sync(command: impl Into<String>) -> Result<CommandResult> {
451
+ let rt = tokio::runtime::Runtime::new()?;
452
+ rt.block_on(run(command))
453
+ }
454
+
455
+ #[cfg(test)]
456
+ mod tests {
457
+ use super::*;
458
+
459
+ #[tokio::test]
460
+ async fn test_simple_echo() {
461
+ let result = run("echo hello").await.unwrap();
462
+ assert!(result.is_success());
463
+ assert!(result.stdout.contains("hello"));
464
+ }
465
+
466
+ #[tokio::test]
467
+ async fn test_virtual_echo() {
468
+ let mut runner = ProcessRunner::new("echo test virtual", RunOptions::default());
469
+ let result = runner.run().await.unwrap();
470
+ assert!(result.is_success());
471
+ assert!(result.stdout.contains("test virtual"));
472
+ }
473
+
474
+ #[tokio::test]
475
+ async fn test_process_runner() {
476
+ let mut runner = ProcessRunner::new("echo hello world", RunOptions {
477
+ mirror: false,
478
+ ..Default::default()
479
+ });
480
+
481
+ let result = runner.run().await.unwrap();
482
+ assert!(result.is_success());
483
+ }
484
+
485
+ #[tokio::test]
486
+ async fn test_virtual_pwd() {
487
+ let mut runner = ProcessRunner::new("pwd", RunOptions::default());
488
+ let result = runner.run().await.unwrap();
489
+ assert!(result.is_success());
490
+ assert!(!result.stdout.is_empty());
491
+ }
492
+ }
@@ -0,0 +1,37 @@
1
+ //! command-stream CLI
2
+ //!
3
+ //! A simple CLI wrapper for the command-stream library.
4
+
5
+ use command_stream::{run, RunOptions, ProcessRunner};
6
+ use std::env;
7
+
8
+ #[tokio::main]
9
+ async fn main() -> Result<(), Box<dyn std::error::Error>> {
10
+ let args: Vec<String> = env::args().skip(1).collect();
11
+
12
+ if args.is_empty() {
13
+ eprintln!("Usage: command-stream <command> [args...]");
14
+ eprintln!();
15
+ eprintln!("Execute shell commands with streaming support.");
16
+ eprintln!();
17
+ eprintln!("Examples:");
18
+ eprintln!(" command-stream echo hello world");
19
+ eprintln!(" command-stream ls -la");
20
+ eprintln!(" command-stream 'echo hello && echo world'");
21
+ std::process::exit(1);
22
+ }
23
+
24
+ let command = args.join(" ");
25
+
26
+ let result = run(command).await?;
27
+
28
+ // Print any output that wasn't mirrored
29
+ if !result.stdout.is_empty() && !result.stdout.ends_with('\n') {
30
+ println!("{}", result.stdout);
31
+ }
32
+ if !result.stderr.is_empty() {
33
+ eprint!("{}", result.stderr);
34
+ }
35
+
36
+ std::process::exit(result.code);
37
+ }