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,225 @@
1
+ import { describe, test, expect } from 'bun:test';
2
+ import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
3
+ import { $, disableVirtualCommands } from '../src/$.mjs';
4
+
5
+ // Disable virtual commands to ensure we're testing system/built-in commands
6
+ disableVirtualCommands();
7
+
8
+ describe('.text() method for Bun.$ compatibility', () => {
9
+ test('sync execution should have .text() method', () => {
10
+ const result = $`echo "sync test"`.sync();
11
+
12
+ expect(typeof result.text).toBe('function');
13
+ expect(result.text).toBeInstanceOf(Function);
14
+ });
15
+
16
+ test('async execution should have .text() method', async () => {
17
+ const result = await $`echo "async test"`;
18
+
19
+ expect(typeof result.text).toBe('function');
20
+ expect(result.text).toBeInstanceOf(Function);
21
+ });
22
+
23
+ test('.text() should return stdout content (sync)', async () => {
24
+ const result = $`echo "hello world"`.sync();
25
+ const text = await result.text();
26
+
27
+ expect(text).toBe('hello world\n');
28
+ });
29
+
30
+ test('.text() should return stdout content (async)', async () => {
31
+ const result = await $`echo "hello async"`;
32
+ const text = await result.text();
33
+
34
+ expect(text).toBe('hello async\n');
35
+ });
36
+
37
+ test('.text() should handle empty output', async () => {
38
+ // Use a command that produces no output
39
+ const result = await $`true`;
40
+ const text = await result.text();
41
+
42
+ expect(text).toBe('');
43
+ });
44
+
45
+ test('.text() should handle multiline output', async () => {
46
+ // Use seq to generate multiline output
47
+ const result = await $`seq 1 3`;
48
+ const text = await result.text();
49
+
50
+ expect(text).toBe('1\n2\n3\n');
51
+ });
52
+
53
+ test('.text() should work with built-in commands', async () => {
54
+ const result = await $`seq 1 3`;
55
+ const text = await result.text();
56
+
57
+ expect(text).toBe('1\n2\n3\n');
58
+ });
59
+
60
+ test('.text() should work with cat built-in command', async () => {
61
+ // Create a test file first
62
+ await $`echo "test content" > temp-text-test.txt`;
63
+
64
+ const result = await $`cat temp-text-test.txt`;
65
+ const text = await result.text();
66
+
67
+ expect(text).toBe('test content\n');
68
+
69
+ // Clean up
70
+ await $`rm temp-text-test.txt`;
71
+ });
72
+
73
+ test('.text() should work with ls built-in command', async () => {
74
+ const result = await $`ls -1 js/tests/`;
75
+ const text = await result.text();
76
+
77
+ // Should contain at least this test file
78
+ expect(text).toContain('text-method.test.mjs');
79
+ });
80
+
81
+ test('.text() should work with pwd built-in command', async () => {
82
+ const result = await $`pwd`;
83
+ const text = await result.text();
84
+
85
+ // Should return a path ending with newline
86
+ expect(text.trim()).toBeTruthy();
87
+ expect(text.endsWith('\n')).toBe(true);
88
+ });
89
+
90
+ test('.text() should return empty string for commands with no stdout', async () => {
91
+ const result =
92
+ await $`mkdir -p temp-dir-for-text-test && rmdir temp-dir-for-text-test`;
93
+ const text = await result.text();
94
+
95
+ expect(text).toBe('');
96
+ });
97
+
98
+ test('.text() should work with piped commands (when supported)', async () => {
99
+ // Note: Pipeline with built-ins currently treats them as system commands
100
+ // This test checks the behavior - expecting an error about unsupported pipeline
101
+ try {
102
+ const result = await $`seq 1 3 | cat`;
103
+ // If this succeeds somehow, check the .text() method exists
104
+ if (result.text) {
105
+ const text = await result.text();
106
+ expect(typeof text).toBe('string');
107
+ }
108
+ } catch (error) {
109
+ // Expected for now - pipeline with system commands not supported
110
+ expect(error.message).toContain('not yet supported');
111
+ }
112
+ });
113
+
114
+ test('.text() should work with complex pipeline (when supported)', async () => {
115
+ // Create a temp file for sorting
116
+ await $`echo "3" > temp-sort-test.txt`;
117
+ await $`echo "1" >> temp-sort-test.txt`;
118
+ await $`echo "2" >> temp-sort-test.txt`;
119
+
120
+ try {
121
+ const result = await $`cat temp-sort-test.txt | sort`;
122
+ // If this succeeds somehow, check the .text() method exists
123
+ if (result.text) {
124
+ const text = await result.text();
125
+ expect(typeof text).toBe('string');
126
+ }
127
+ } catch (error) {
128
+ // Expected for now - pipeline with system commands not supported
129
+ expect(error.message).toContain('not yet supported');
130
+ }
131
+
132
+ // Clean up
133
+ await $`rm temp-sort-test.txt`;
134
+ });
135
+
136
+ test('.text() should handle commands with stderr but no stdout', async () => {
137
+ try {
138
+ const result = await $`cat nonexistent-file-text-test.txt`;
139
+ const text = await result.text();
140
+
141
+ expect(text).toBe('');
142
+ } catch (error) {
143
+ // Some shells might throw on error, that's fine
144
+ expect(error.result).toBeDefined();
145
+ if (error.result) {
146
+ const text = await error.result.text();
147
+ expect(text).toBe('');
148
+ }
149
+ }
150
+ });
151
+
152
+ test('.text() should be consistent with .stdout property', async () => {
153
+ const result = await $`echo "consistency test"`;
154
+ const text = await result.text();
155
+
156
+ expect(text).toBe(result.stdout);
157
+ });
158
+
159
+ test('.text() can be called multiple times', async () => {
160
+ const result = await $`echo "multiple calls"`;
161
+
162
+ const text1 = await result.text();
163
+ const text2 = await result.text();
164
+ const text3 = await result.text();
165
+
166
+ expect(text1).toBe('multiple calls\n');
167
+ expect(text2).toBe('multiple calls\n');
168
+ expect(text3).toBe('multiple calls\n');
169
+ expect(text1).toBe(text2);
170
+ expect(text2).toBe(text3);
171
+ });
172
+
173
+ test('.text() returns a Promise', () => {
174
+ const result = $`echo "promise test"`.sync();
175
+ const textPromise = result.text();
176
+
177
+ expect(textPromise).toBeInstanceOf(Promise);
178
+ });
179
+
180
+ test('.text() should work with binary-safe content', async () => {
181
+ const testContent = 'content with special chars: üñíçødé 🚀';
182
+ // Write content directly without shell quoting issues
183
+ await $`touch temp-unicode-test.txt`;
184
+ await $`echo ${testContent} > temp-unicode-test.txt`;
185
+
186
+ const result = await $`cat temp-unicode-test.txt`;
187
+ const text = await result.text();
188
+
189
+ expect(text).toContain('üñíçødé');
190
+ expect(text).toContain('🚀');
191
+
192
+ // Clean up
193
+ await $`rm temp-unicode-test.txt`;
194
+ });
195
+
196
+ test('.text() should work with .pipe() method results', async () => {
197
+ const result = await $`echo "pipe test"`.pipe($`cat`);
198
+ const text = await result.text();
199
+
200
+ expect(text).toBe('pipe test\n');
201
+ });
202
+
203
+ test('.text() method should be accessible', () => {
204
+ const result = $`echo "test"`.sync();
205
+ const keys = Object.keys(result);
206
+
207
+ // .text() method should be accessible
208
+ expect(result.text).toBeDefined();
209
+ expect(typeof result.text).toBe('function');
210
+
211
+ // Check if it's in the keys (implementation detail)
212
+ const hasTextKey = keys.includes('text');
213
+ expect(typeof hasTextKey).toBe('boolean'); // Just verify it's a boolean
214
+ });
215
+
216
+ test('.text() should handle very large output efficiently', async () => {
217
+ // Generate a reasonably large output
218
+ const result = await $`seq 1 1000`;
219
+ const text = await result.text();
220
+
221
+ expect(text).toContain('1\n');
222
+ expect(text).toContain('1000\n');
223
+ expect(text.split('\n')).toHaveLength(1001); // 1000 numbers + empty line at end
224
+ });
225
+ });
@@ -0,0 +1,364 @@
1
+ import { test, expect, describe, beforeEach, afterEach } from 'bun:test';
2
+ import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs';
3
+ import { isWindows } from './test-helper.mjs';
4
+ import {
5
+ $,
6
+ shell,
7
+ register,
8
+ unregister,
9
+ listCommands,
10
+ enableVirtualCommands,
11
+ } from '../src/$.mjs';
12
+
13
+ // Helper function to setup shell settings
14
+ function setupShellSettings() {
15
+ shell.errexit(false);
16
+ shell.verbose(false);
17
+ shell.xtrace(false);
18
+ shell.pipefail(false);
19
+ shell.nounset(false);
20
+ enableVirtualCommands();
21
+ }
22
+
23
+ describe('Virtual Commands System', () => {
24
+ beforeEach(async () => {
25
+ await beforeTestCleanup();
26
+ setupShellSettings();
27
+ });
28
+
29
+ afterEach(async () => {
30
+ await afterTestCleanup();
31
+ });
32
+
33
+ describe('Registration API', () => {
34
+ test('should register and execute custom virtual command', async () => {
35
+ register('greet', async ({ args }) => {
36
+ const name = args[0] || 'World';
37
+ return { stdout: `Hello, ${name}!\n`, code: 0 };
38
+ });
39
+
40
+ const result = await $`greet Alice`;
41
+
42
+ expect(result.stdout).toBe('Hello, Alice!\n');
43
+ expect(result.code).toBe(0);
44
+
45
+ // Cleanup
46
+ unregister('greet');
47
+ });
48
+
49
+ test('should unregister commands', async () => {
50
+ register('temp', async () => ({ stdout: 'temp', code: 0 }));
51
+
52
+ // Verify it exists
53
+ expect(listCommands()).toContain('temp');
54
+
55
+ // Unregister
56
+ const removed = unregister('temp');
57
+ expect(removed).toBe(true);
58
+ expect(listCommands()).not.toContain('temp');
59
+
60
+ // Verify it falls back to system command
61
+ try {
62
+ await $`temp`; // Should fail since 'temp' is not a system command
63
+ } catch (error) {
64
+ expect(error.code).not.toBe(0);
65
+ }
66
+ });
67
+
68
+ test('should list registered commands', () => {
69
+ const initialCommands = listCommands();
70
+
71
+ register('test1', async () => ({ stdout: '', code: 0 }));
72
+ register('test2', async () => ({ stdout: '', code: 0 }));
73
+
74
+ const commands = listCommands();
75
+ expect(commands).toContain('test1');
76
+ expect(commands).toContain('test2');
77
+ expect(commands.length).toBe(initialCommands.length + 2);
78
+
79
+ // Cleanup
80
+ unregister('test1');
81
+ unregister('test2');
82
+ });
83
+ });
84
+
85
+ describe('Built-in Commands', () => {
86
+ // Skip on Windows - uses Unix path /tmp
87
+ test.skipIf(isWindows)('should execute virtual cd command', async () => {
88
+ const originalCwd = process.cwd();
89
+
90
+ try {
91
+ const result = await $`cd /tmp`;
92
+ expect(result.code).toBe(0);
93
+ expect(process.cwd()).not.toBe(originalCwd);
94
+ expect(process.cwd()).toMatch(/tmp/);
95
+ } finally {
96
+ process.chdir(originalCwd);
97
+ }
98
+ });
99
+
100
+ test('should execute virtual pwd command', async () => {
101
+ const result = await $`pwd`;
102
+ expect(result.code).toBe(0);
103
+ expect(result.stdout.trim()).toBe(process.cwd());
104
+ });
105
+
106
+ test('should execute virtual echo command', async () => {
107
+ const result = await $`echo Hello World`;
108
+ expect(result.code).toBe(0);
109
+ expect(result.stdout).toBe('Hello World\n');
110
+ });
111
+
112
+ test('should execute echo with -n flag', async () => {
113
+ const result = await $`echo -n Hello`;
114
+ expect(result.code).toBe(0);
115
+ expect(result.stdout).toBe('Hello');
116
+ });
117
+
118
+ test('should execute virtual sleep command', async () => {
119
+ const start = Date.now();
120
+ const result = await $`sleep 0.1`;
121
+ const elapsed = Date.now() - start;
122
+
123
+ expect(result.code).toBe(0);
124
+ expect(elapsed).toBeGreaterThan(90); // At least 90ms
125
+ expect(elapsed).toBeLessThan(200); // But not too long
126
+ });
127
+
128
+ test('should execute virtual true command', async () => {
129
+ const result = await $`true`;
130
+ expect(result.code).toBe(0);
131
+ });
132
+
133
+ test('should execute virtual false command', async () => {
134
+ const result = await $`false`;
135
+ expect(result.code).toBe(1);
136
+ });
137
+
138
+ test('should execute virtual which command', async () => {
139
+ const result = await $`which echo`;
140
+ expect(result.code).toBe(0);
141
+ expect(result.stdout).toBe('echo: shell builtin\n');
142
+ });
143
+
144
+ test('should execute virtual exit command', async () => {
145
+ const result = await $`exit 0`;
146
+ expect(result.code).toBe(0);
147
+
148
+ const result2 = await $`exit 42`;
149
+ expect(result2.code).toBe(42);
150
+ });
151
+
152
+ test('should execute virtual env command', async () => {
153
+ const result = await $`env`;
154
+ expect(result.code).toBe(0);
155
+ expect(result.stdout).toContain('PATH=');
156
+ });
157
+
158
+ test('should execute virtual test command', async () => {
159
+ // Test directory
160
+ const result1 = await $`test -d .`;
161
+ expect(result1.code).toBe(0);
162
+
163
+ // Test file
164
+ const result2 = await $`test -f package.json`;
165
+ expect(result2.code).toBe(0);
166
+
167
+ // Test non-existent
168
+ const result3 = await $`test -f nonexistent-file-99999`;
169
+ expect(result3.code).toBe(1);
170
+ });
171
+ });
172
+
173
+ describe('Virtual vs System Commands', () => {
174
+ test('should prioritize virtual commands over system commands', async () => {
175
+ // Register a virtual 'ls' that overrides system ls
176
+ register('ls', async ({ args }) => ({
177
+ stdout: 'virtual ls output\n',
178
+ code: 0,
179
+ }));
180
+
181
+ const result = await $`ls`;
182
+ expect(result.stdout).toBe('virtual ls output\n');
183
+
184
+ // Cleanup - should fall back to system ls
185
+ unregister('ls');
186
+
187
+ const systemResult = await $`ls`;
188
+ expect(systemResult.stdout).not.toBe('virtual ls output\n');
189
+ expect(systemResult.code).toBe(0); // System ls should work
190
+ });
191
+
192
+ test('should fall back to system commands when virtual not found', async () => {
193
+ // This should use system echo (since we didn't override it... wait, we did!)
194
+ // Let's test with a command we definitely didn't override
195
+ const result = await $`date`;
196
+ expect(result.code).toBe(0);
197
+ expect(result.stdout).toContain('202'); // Should contain year
198
+ });
199
+ });
200
+
201
+ describe('Streaming Virtual Commands', () => {
202
+ test('should support async generator virtual commands', async () => {
203
+ register('count', async function* ({ args }) {
204
+ const max = parseInt(args[0] || 3);
205
+ for (let i = 1; i <= max; i++) {
206
+ yield `${i}\n`;
207
+ // Small delay to test streaming
208
+ await new Promise((r) => setTimeout(r, 10));
209
+ }
210
+ });
211
+
212
+ const chunks = [];
213
+ const cmd = $`count 3`;
214
+ for await (const chunk of cmd.stream()) {
215
+ chunks.push(chunk.data.toString());
216
+ }
217
+
218
+ expect(chunks.length).toBeGreaterThan(0);
219
+ const output = chunks.join('');
220
+
221
+ // Check if we got the numbers in order, regardless of newlines
222
+ expect(output).toContain('1');
223
+ expect(output).toContain('2');
224
+ expect(output).toContain('3');
225
+
226
+ // The output should be either "1\n2\n3\n" or "123" depending on buffering
227
+ const normalized = output.replace(/\n/g, '');
228
+ expect(normalized).toBe('123');
229
+
230
+ // Cleanup
231
+ unregister('count');
232
+ });
233
+
234
+ test('should handle events with streaming virtual commands', async () => {
235
+ register('stream-test', async function* ({ args }) {
236
+ yield 'chunk1\n';
237
+ yield 'chunk2\n';
238
+ });
239
+
240
+ const events = [];
241
+ const result = await new Promise((resolve) => {
242
+ const cmd = $`stream-test`;
243
+ cmd.on('stdout', () => events.push('stdout'));
244
+ cmd.on('data', (chunk) => events.push(`data-${chunk.type}`));
245
+ cmd.on('end', resolve);
246
+ cmd.then().catch(() => {}); // Start execution
247
+ });
248
+
249
+ expect(events.length).toBeGreaterThan(0);
250
+ expect(events).toContain('stdout');
251
+ expect(events).toContain('data-stdout');
252
+
253
+ // Cleanup
254
+ unregister('stream-test');
255
+ });
256
+ });
257
+
258
+ describe('Error Handling', () => {
259
+ test('should handle virtual command errors', async () => {
260
+ register('fail', async ({ args }) => {
261
+ throw new Error('Virtual command failed');
262
+ });
263
+
264
+ const result = await $`fail`;
265
+ expect(result.code).toBe(1);
266
+ expect(result.stderr).toContain('Virtual command failed');
267
+
268
+ // Cleanup
269
+ unregister('fail');
270
+ });
271
+
272
+ test('should respect errexit setting with virtual commands', async () => {
273
+ register('fail-code', async ({ args }) => ({
274
+ stdout: '',
275
+ stderr: 'Failed',
276
+ code: 42,
277
+ }));
278
+
279
+ shell.errexit(true);
280
+
281
+ try {
282
+ await $`fail-code`;
283
+ expect(true).toBe(false); // Should not reach here
284
+ } catch (error) {
285
+ expect(error.code).toBe(42);
286
+ }
287
+
288
+ shell.errexit(false);
289
+ const result = await $`fail-code`;
290
+ expect(result.code).toBe(42);
291
+
292
+ // Cleanup
293
+ unregister('fail-code');
294
+ });
295
+ });
296
+
297
+ describe('Command Arguments and Stdin', () => {
298
+ test('should pass arguments correctly to virtual commands', async () => {
299
+ register('args-test', async ({ args }) => ({
300
+ stdout: `Args: [${args.join(', ')}]\n`,
301
+ code: 0,
302
+ }));
303
+
304
+ const result = await $`args-test one "two three" four`;
305
+ expect(result.stdout).toBe('Args: [one, two three, four]\n');
306
+
307
+ // Cleanup
308
+ unregister('args-test');
309
+ });
310
+
311
+ test('should pass stdin to virtual commands', async () => {
312
+ register('stdin-test', async ({ args, stdin }) => ({
313
+ stdout: `Received: ${stdin}\n`,
314
+ code: 0,
315
+ }));
316
+
317
+ const result = await $`echo "test input" | stdin-test`;
318
+ expect(result.stdout).toBe('Received: test input\n\n');
319
+
320
+ // Cleanup
321
+ unregister('stdin-test');
322
+ });
323
+ });
324
+
325
+ describe('Shell Settings Integration', () => {
326
+ test('should respect verbose setting for virtual commands', async () => {
327
+ register('verbose-test', async () => ({ stdout: 'output', code: 0 }));
328
+
329
+ const originalLog = console.log;
330
+ const logs = [];
331
+ console.log = (...args) => logs.push(args.join(' '));
332
+
333
+ try {
334
+ shell.verbose(true);
335
+ await $`verbose-test arg1 arg2`;
336
+
337
+ expect(logs.some((log) => log.includes('verbose-test arg1 arg2'))).toBe(
338
+ true
339
+ );
340
+ } finally {
341
+ console.log = originalLog;
342
+ unregister('verbose-test');
343
+ }
344
+ });
345
+
346
+ test('should respect xtrace setting for virtual commands', async () => {
347
+ register('trace-test', async () => ({ stdout: 'output', code: 0 }));
348
+
349
+ const originalLog = console.log;
350
+ const logs = [];
351
+ console.log = (...args) => logs.push(args.join(' '));
352
+
353
+ try {
354
+ shell.xtrace(true);
355
+ await $`trace-test`;
356
+
357
+ expect(logs.some((log) => log.startsWith('+ trace-test'))).toBe(true);
358
+ } finally {
359
+ console.log = originalLog;
360
+ unregister('trace-test');
361
+ }
362
+ });
363
+ });
364
+ });