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,127 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
4
+ import {
5
+ beforeTestCleanup,
6
+ afterTestCleanup,
7
+ originalCwd,
8
+ } from './test-cleanup.mjs';
9
+ import { isWindows } from './test-helper.mjs';
10
+ import { $ } from '../src/$.mjs';
11
+ import { mkdtempSync, rmSync, realpathSync } from 'fs';
12
+ import { tmpdir } from 'os';
13
+ import { join } from 'path';
14
+
15
+ // Helper to normalize paths (handles macOS /var -> /private/var symlink)
16
+ const normalizePath = (p) => {
17
+ try {
18
+ return realpathSync(p);
19
+ } catch {
20
+ return p;
21
+ }
22
+ };
23
+
24
+ describe('Cleanup Verification', () => {
25
+ beforeEach(beforeTestCleanup);
26
+ afterEach(afterTestCleanup);
27
+
28
+ let testDirs = [];
29
+
30
+ afterEach(() => {
31
+ // Clean up test directories
32
+ for (const dir of testDirs) {
33
+ try {
34
+ rmSync(dir, { recursive: true, force: true });
35
+ } catch (e) {
36
+ // Ignore cleanup errors
37
+ }
38
+ }
39
+ testDirs = [];
40
+ });
41
+
42
+ test('should start in original directory', () => {
43
+ const currentCwd = process.cwd();
44
+ expect(currentCwd).toBe(originalCwd);
45
+ });
46
+
47
+ test('should restore cwd after simple cd command', async () => {
48
+ const tempDir = mkdtempSync(join(tmpdir(), 'cleanup-test-'));
49
+ testDirs.push(tempDir);
50
+
51
+ // Change directory
52
+ await $`cd ${tempDir}`;
53
+
54
+ // Verify we changed
55
+ const result = await $`pwd`;
56
+ expect(normalizePath(result.stdout.trim())).toBe(normalizePath(tempDir));
57
+
58
+ // Cwd should be changed within test
59
+ expect(normalizePath(process.cwd())).toBe(normalizePath(tempDir));
60
+ });
61
+
62
+ test('should be back in original directory after cd test', () => {
63
+ // This test verifies the previous test's cleanup worked
64
+ const currentCwd = process.cwd();
65
+ expect(currentCwd).toBe(originalCwd);
66
+ });
67
+
68
+ test('should restore cwd after cd with && operator', async () => {
69
+ const tempDir = mkdtempSync(join(tmpdir(), 'cleanup-test2-'));
70
+ testDirs.push(tempDir);
71
+
72
+ // Change directory with && operator
73
+ await $`cd ${tempDir} && echo "test"`;
74
+
75
+ // Should be in temp dir
76
+ expect(normalizePath(process.cwd())).toBe(normalizePath(tempDir));
77
+ });
78
+
79
+ test('should verify restoration after && cd test', () => {
80
+ const currentCwd = process.cwd();
81
+ expect(currentCwd).toBe(originalCwd);
82
+ });
83
+
84
+ // Skip on Windows - uses subshell syntax and pwd command
85
+ test.skipIf(isWindows)(
86
+ 'should not affect cwd when cd is in subshell',
87
+ async () => {
88
+ const tempDir = mkdtempSync(join(tmpdir(), 'cleanup-test3-'));
89
+ testDirs.push(tempDir);
90
+
91
+ // Change directory in subshell - should not affect parent
92
+ const result = await $`(cd ${tempDir} && pwd)`;
93
+ expect(normalizePath(result.stdout.trim())).toBe(normalizePath(tempDir));
94
+
95
+ // Should still be in original directory
96
+ const currentCwd = process.cwd();
97
+ expect(currentCwd).toBe(originalCwd);
98
+ }
99
+ );
100
+
101
+ test('should restore cwd after multiple cd commands', async () => {
102
+ const tempDir1 = mkdtempSync(join(tmpdir(), 'cleanup-test4-'));
103
+ const tempDir2 = mkdtempSync(join(tmpdir(), 'cleanup-test5-'));
104
+ testDirs.push(tempDir1, tempDir2);
105
+
106
+ // Multiple cd commands
107
+ await $`cd ${tempDir1}`;
108
+ expect(normalizePath(process.cwd())).toBe(normalizePath(tempDir1));
109
+
110
+ await $`cd ${tempDir2}`;
111
+ expect(normalizePath(process.cwd())).toBe(normalizePath(tempDir2));
112
+
113
+ await $`cd ${tempDir1}`;
114
+ expect(normalizePath(process.cwd())).toBe(normalizePath(tempDir1));
115
+ });
116
+
117
+ test('final verification - should still be in original directory', () => {
118
+ // Final check that all previous tests were properly cleaned up
119
+ const currentCwd = process.cwd();
120
+ expect(currentCwd).toBe(originalCwd);
121
+
122
+ // Also verify with pwd command
123
+ return $`pwd`.then((result) => {
124
+ expect(result.stdout.trim()).toBe(originalCwd);
125
+ });
126
+ });
127
+ });
@@ -0,0 +1,207 @@
1
+ import { describe, it, expect, afterEach } from 'bun:test';
2
+ import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
3
+ import { spawn } from 'child_process';
4
+ import { trace } from '../src/$.utils.mjs';
5
+
6
+ // Platform detection - Windows handles signals differently than Unix
7
+ const isWindows = process.platform === 'win32';
8
+
9
+ /**
10
+ * Baseline tests for CTRL+C signal handling using native spawn
11
+ * These tests verify that the CI environment can handle basic process spawning and signals
12
+ * without using our library, providing a comparison point for debugging
13
+ *
14
+ * Note: These tests are skipped on Windows because:
15
+ * 1. Windows doesn't have 'sh' shell by default
16
+ * 2. SIGINT/signal handling works fundamentally different on Windows
17
+ * 3. Exit codes 130 (128+SIGINT) are Unix-specific
18
+ */
19
+ describe.skipIf(isWindows)('CTRL+C Baseline Tests (Native Spawn)', () => {
20
+ let childProcesses = [];
21
+
22
+ afterEach(() => {
23
+ // Clean up any remaining child processes
24
+ childProcesses.forEach((child) => {
25
+ if (!child.killed) {
26
+ child.kill('SIGKILL');
27
+ }
28
+ });
29
+ childProcesses = [];
30
+ });
31
+
32
+ it('should handle SIGINT with simple shell command', async () => {
33
+ trace('BaselineTest', 'Testing simple shell command');
34
+
35
+ const child = spawn('sh', ['-c', 'echo "BASELINE_START" && sleep 30'], {
36
+ stdio: ['pipe', 'pipe', 'pipe'],
37
+ detached: true,
38
+ });
39
+
40
+ trace('BaselineTest', () => `Child spawned, PID: ${child.pid}`);
41
+ childProcesses.push(child);
42
+
43
+ let stdout = '';
44
+ let stderr = '';
45
+
46
+ child.stdout.on('data', (data) => {
47
+ stdout += data.toString();
48
+ trace(
49
+ 'BaselineTest',
50
+ () => `Received stdout: ${JSON.stringify(data.toString())}`
51
+ );
52
+ });
53
+
54
+ child.stderr.on('data', (data) => {
55
+ stderr += data.toString();
56
+ trace(
57
+ 'BaselineTest',
58
+ () => `Received stderr: ${JSON.stringify(data.toString())}`
59
+ );
60
+ });
61
+
62
+ // Wait for output
63
+ await new Promise((resolve) => setTimeout(resolve, 500));
64
+
65
+ trace('BaselineTest', 'Sending SIGINT');
66
+ child.kill('SIGINT');
67
+
68
+ // Wait for exit
69
+ const exitCode = await new Promise((resolve) => {
70
+ let resolved = false;
71
+ child.on('exit', (code, signal) => {
72
+ if (!resolved) {
73
+ resolved = true;
74
+ trace(
75
+ 'BaselineTest',
76
+ () => `Process exited with code: ${code} signal: ${signal}`
77
+ );
78
+ resolve(code !== null ? code : signal === 'SIGINT' ? 130 : 1);
79
+ }
80
+ });
81
+
82
+ // Timeout fallback
83
+ setTimeout(() => {
84
+ if (!resolved) {
85
+ resolved = true;
86
+ trace('BaselineTest', 'Timeout, force killing');
87
+ child.kill('SIGKILL');
88
+ resolve(137);
89
+ }
90
+ }, 3000);
91
+ });
92
+
93
+ trace('BaselineTest', () => `Final stdout: ${stdout}`);
94
+ trace('BaselineTest', () => `Final stderr: ${stderr}`);
95
+ trace('BaselineTest', () => `Exit code: ${exitCode}`);
96
+
97
+ expect(stdout).toContain('BASELINE_START');
98
+ // Accept both 130 (SIGINT) and 137 (SIGKILL) as valid
99
+ expect([130, 137].includes(exitCode)).toBe(true);
100
+ });
101
+
102
+ it('should handle Node.js inline script with SIGINT', async () => {
103
+ trace('BaselineTest', 'Testing Node.js inline script');
104
+
105
+ const nodeCode = `
106
+ console.log('NODE_START');
107
+ process.on('SIGINT', () => {
108
+ console.log('SIGINT_RECEIVED');
109
+ process.exit(130);
110
+ });
111
+ setTimeout(() => {
112
+ console.log('TIMEOUT');
113
+ process.exit(1);
114
+ }, 30000);
115
+ `;
116
+
117
+ const child = spawn('node', ['-e', nodeCode], {
118
+ stdio: ['pipe', 'pipe', 'pipe'],
119
+ detached: true,
120
+ });
121
+
122
+ trace('BaselineTest', () => `Node child spawned, PID: ${child.pid}`);
123
+ childProcesses.push(child);
124
+
125
+ let stdout = '';
126
+ child.stdout.on('data', (data) => {
127
+ stdout += data.toString();
128
+ trace(
129
+ 'BaselineTest',
130
+ () => `Node stdout: ${JSON.stringify(data.toString())}`
131
+ );
132
+ });
133
+
134
+ // Wait for startup
135
+ await new Promise((resolve) => setTimeout(resolve, 500));
136
+
137
+ trace('BaselineTest', 'Sending SIGINT to Node process');
138
+ child.kill('SIGINT');
139
+
140
+ const exitCode = await new Promise((resolve) => {
141
+ child.on('exit', (code) => {
142
+ trace('BaselineTest', () => `Node process exited with code: ${code}`);
143
+ resolve(code);
144
+ });
145
+ });
146
+
147
+ trace('BaselineTest', () => `Node final stdout: ${stdout}`);
148
+ trace('BaselineTest', () => `Node exit code: ${exitCode}`);
149
+
150
+ expect(stdout).toContain('NODE_START');
151
+ expect(stdout).toContain('SIGINT_RECEIVED');
152
+ expect(exitCode).toBe(130);
153
+ });
154
+
155
+ it('should handle Node.js script file', async () => {
156
+ trace('BaselineTest', 'Testing Node.js script file');
157
+
158
+ // Use the simple-test-sleep.js which doesn't have ES module dependencies
159
+ const child = spawn('node', ['js/examples/simple-test-sleep.js'], {
160
+ stdio: ['pipe', 'pipe', 'pipe'],
161
+ detached: true,
162
+ cwd: process.cwd(),
163
+ });
164
+
165
+ trace('BaselineTest', () => `Script child spawned, PID: ${child.pid}`);
166
+ childProcesses.push(child);
167
+
168
+ let stdout = '';
169
+ let stderr = '';
170
+
171
+ child.stdout.on('data', (data) => {
172
+ stdout += data.toString();
173
+ trace(
174
+ 'BaselineTest',
175
+ () => `Script stdout: ${JSON.stringify(data.toString())}`
176
+ );
177
+ });
178
+
179
+ child.stderr.on('data', (data) => {
180
+ stderr += data.toString();
181
+ trace('BaselineTest', () => `Script stderr: ${data.toString().trim()}`);
182
+ });
183
+
184
+ // Wait for startup
185
+ await new Promise((resolve) => setTimeout(resolve, 1000));
186
+
187
+ trace('BaselineTest', 'Sending SIGINT to script');
188
+ child.kill('SIGINT');
189
+
190
+ const exitCode = await new Promise((resolve) => {
191
+ child.on('exit', (code) => {
192
+ trace('BaselineTest', () => `Script exited with code: ${code}`);
193
+ resolve(code);
194
+ });
195
+ });
196
+
197
+ trace('BaselineTest', () => `Script final stdout: ${stdout}`);
198
+ trace(
199
+ 'BaselineTest',
200
+ () => `Script final stderr (first 200 chars): ${stderr.substring(0, 200)}`
201
+ );
202
+ trace('BaselineTest', () => `Script exit code: ${exitCode}`);
203
+
204
+ expect(stdout).toContain('STARTING_SLEEP');
205
+ expect(exitCode).toBe(130);
206
+ });
207
+ });
@@ -0,0 +1,220 @@
1
+ import { describe, it, expect } from 'bun:test';
2
+ import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
3
+ import { $ } from '../src/$.mjs';
4
+
5
+ // Platform detection - Windows handles signals differently than Unix
6
+ const isWindows = process.platform === 'win32';
7
+
8
+ // Skip signal tests on Windows - SIGTERM exit code 143 is Unix-specific
9
+ describe.skipIf(isWindows)('CTRL+C Basic Handling', () => {
10
+ it('should be able to kill a long-running process', async () => {
11
+ // Start a long-running process
12
+ const runner = $`sleep 10`;
13
+
14
+ // Start it without awaiting completion
15
+ const promise = runner.start();
16
+
17
+ // Give it time to start
18
+ await new Promise((resolve) => setTimeout(resolve, 100));
19
+
20
+ // Kill it manually (simulating what CTRL+C would do)
21
+ runner.kill();
22
+
23
+ // The process should complete with a non-zero exit code
24
+ const result = await promise;
25
+
26
+ // Should have a non-zero exit code (143 for SIGTERM)
27
+ expect(result.code).toBeGreaterThan(0);
28
+ expect(result.code).toBe(143); // 128 + 15 (SIGTERM)
29
+ });
30
+
31
+ it('should spawn processes with detached flag on Unix', async () => {
32
+ if (process.platform === 'win32') {
33
+ // Skip on Windows
34
+ return;
35
+ }
36
+
37
+ // Use /bin/sleep to get a real system process, not virtual command
38
+ const runner = $`/bin/sleep 1`;
39
+
40
+ // Start the process
41
+ const promise = runner.start();
42
+
43
+ // Give it a moment to spawn
44
+ await new Promise((resolve) => setTimeout(resolve, 50));
45
+
46
+ // Check that the child process exists and has a PID
47
+ expect(runner.child).toBeDefined();
48
+ expect(runner.child.pid).toBeGreaterThan(0);
49
+
50
+ // Kill and wait for completion
51
+ runner.kill();
52
+
53
+ try {
54
+ await promise;
55
+ } catch (error) {
56
+ // Expected to error
57
+ }
58
+ });
59
+
60
+ it('should handle CTRL+C character in raw mode', async () => {
61
+ // Test that the _forwardTTYStdin method properly handles CTRL+C
62
+ // This is a unit test of the specific functionality
63
+
64
+ const runner = $`cat`; // Use cat to read stdin
65
+
66
+ // Start the process
67
+ const promise = runner.start();
68
+
69
+ // Give it time to set up
70
+ await new Promise((resolve) => setTimeout(resolve, 100));
71
+
72
+ // Kill the process
73
+ runner.kill();
74
+
75
+ // Should complete with an error
76
+ let errorCode = null;
77
+ try {
78
+ await promise;
79
+ } catch (error) {
80
+ errorCode = error.code;
81
+ }
82
+
83
+ expect(errorCode).toBeDefined();
84
+ });
85
+ });
86
+
87
+ // Skip on Windows - SIGTERM exit code 143 is Unix-specific
88
+ describe.skipIf(isWindows)('CTRL+C Virtual Commands', () => {
89
+ it(
90
+ 'should cancel virtual command with AbortController',
91
+ async () => {
92
+ const runner = $`sleep 5`; // Virtual sleep command
93
+
94
+ const promise = runner.start();
95
+
96
+ // Give virtual command time to start
97
+ await new Promise((resolve) => setTimeout(resolve, 100));
98
+
99
+ // Kill the virtual command
100
+ runner.kill();
101
+
102
+ const result = await promise;
103
+
104
+ // Virtual commands return SIGTERM exit code when cancelled
105
+ expect(result.code).toBe(143);
106
+ },
107
+ { timeout: 5000 }
108
+ );
109
+
110
+ it(
111
+ 'should cancel virtual async generator',
112
+ async () => {
113
+ // Test cancelling a streaming virtual command
114
+ const runner = $`yes hello`;
115
+
116
+ // Start streaming
117
+ const streamPromise = (async () => {
118
+ let chunks = 0;
119
+ for await (const _chunk of runner.stream()) {
120
+ chunks++;
121
+ if (chunks >= 3) {
122
+ break; // Break should trigger cancellation
123
+ }
124
+ }
125
+ return chunks;
126
+ })();
127
+
128
+ const chunks = await streamPromise;
129
+ expect(chunks).toBe(3);
130
+ expect(runner.finished).toBe(true);
131
+ },
132
+ { timeout: 5000 }
133
+ );
134
+ });
135
+
136
+ // Skip on Windows - SIGTERM exit code 143 is Unix-specific
137
+ describe.skipIf(isWindows)('CTRL+C Different stdin Modes', () => {
138
+ it('should handle CTRL+C with string stdin', async () => {
139
+ // Use a long-running command that will actually be killed
140
+ const runner = $({ stdin: 'test input\n' })`sleep 10`;
141
+
142
+ const promise = runner.start();
143
+ await new Promise((resolve) => setTimeout(resolve, 200));
144
+
145
+ runner.kill();
146
+ const result = await promise;
147
+
148
+ expect(result.code).toBe(143);
149
+ });
150
+
151
+ it('should handle CTRL+C with Buffer stdin', async () => {
152
+ // Use a long-running command that will actually be killed
153
+ const runner = $({ stdin: Buffer.from('test input\n') })`sleep 10`;
154
+
155
+ const promise = runner.start();
156
+ await new Promise((resolve) => setTimeout(resolve, 200));
157
+
158
+ runner.kill();
159
+ const result = await promise;
160
+
161
+ expect(result.code).toBe(143);
162
+ });
163
+
164
+ it('should handle CTRL+C with ignore stdin', async () => {
165
+ const runner = $({ stdin: 'ignore' })`sleep 5`;
166
+
167
+ const promise = runner.start();
168
+ await new Promise((resolve) => setTimeout(resolve, 100));
169
+
170
+ runner.kill();
171
+ const result = await promise;
172
+
173
+ expect(result.code).toBe(143);
174
+ });
175
+ });
176
+
177
+ // Skip on Windows - SIGTERM exit code 143 is Unix-specific
178
+ describe.skipIf(isWindows)('CTRL+C Pipeline Interruption', () => {
179
+ it(
180
+ 'should interrupt simple pipeline',
181
+ async () => {
182
+ // Use a very simple approach that we know works
183
+ const runner = $`sleep 10`;
184
+
185
+ const promise = runner.start();
186
+ await new Promise((resolve) => setTimeout(resolve, 200));
187
+
188
+ runner.kill();
189
+ const result = await promise;
190
+
191
+ // Should be interrupted with SIGTERM code
192
+ expect(result.code).toBe(143);
193
+ },
194
+ { timeout: 3000 }
195
+ );
196
+ });
197
+
198
+ // Skip on Windows - uses 'sh' command and Unix-specific signals
199
+ describe.skipIf(isWindows)('CTRL+C Process Groups', () => {
200
+ it(
201
+ 'should handle process group termination on Unix',
202
+ async () => {
203
+ if (process.platform === 'win32') {
204
+ return;
205
+ } // Skip on Windows
206
+
207
+ // Use a command that spawns subprocesses
208
+ const runner = $`sh -c 'sleep 10 & sleep 10 & wait'`;
209
+
210
+ const promise = runner.start();
211
+ await new Promise((resolve) => setTimeout(resolve, 200));
212
+
213
+ runner.kill();
214
+ const result = await promise;
215
+
216
+ expect(result.code).toBe(143);
217
+ },
218
+ { timeout: 5000 }
219
+ );
220
+ });