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,265 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Example: Testing baseline spawn behavior vs command-stream library
5
+ *
6
+ * Problem: When tests fail in CI, it's important to determine if the issue
7
+ * is with the library or with the underlying Node.js spawn behavior.
8
+ *
9
+ * Solution: Test both baseline (raw spawn) and library functionality to compare.
10
+ */
11
+
12
+ import { spawn } from 'child_process';
13
+ import { $ } from '../src/$.mjs';
14
+
15
+ console.log('Testing baseline vs library behavior');
16
+
17
+ // Example 1: Baseline spawn test (no library)
18
+ async function testBaselineSpawn() {
19
+ console.log('\nTEST 1: Baseline spawn (no command-stream)');
20
+
21
+ return new Promise((resolve, reject) => {
22
+ const child = spawn('echo', ['baseline test'], {
23
+ stdio: ['pipe', 'pipe', 'pipe'],
24
+ });
25
+
26
+ let stdout = '';
27
+ let stderr = '';
28
+
29
+ child.stdout.on('data', (data) => {
30
+ stdout += data.toString();
31
+ console.log('Baseline stdout:', data.toString().trim());
32
+ });
33
+
34
+ child.stderr.on('data', (data) => {
35
+ stderr += data.toString();
36
+ console.log('Baseline stderr:', data.toString().trim());
37
+ });
38
+
39
+ child.on('exit', (code, signal) => {
40
+ console.log(`Baseline exit: code=${code}, signal=${signal}`);
41
+ if (code === 0) {
42
+ resolve({ stdout, stderr, code });
43
+ } else {
44
+ reject(new Error(`Baseline failed: ${code}/${signal}`));
45
+ }
46
+ });
47
+
48
+ child.on('error', (error) => {
49
+ console.log('Baseline error:', error.message);
50
+ reject(error);
51
+ });
52
+ });
53
+ }
54
+
55
+ // Example 2: Library test (using command-stream)
56
+ async function testLibrary() {
57
+ console.log('\nTEST 2: Library test (using command-stream)');
58
+
59
+ try {
60
+ const result = await $`echo "library test"`;
61
+ console.log('Library stdout:', result.stdout.trim());
62
+ console.log(`Library exit: code=${result.code}`);
63
+ return result;
64
+ } catch (error) {
65
+ console.log('Library error:', error.message);
66
+ throw error;
67
+ }
68
+ }
69
+
70
+ // Example 3: Signal handling comparison
71
+ async function testSignalHandlingComparison() {
72
+ console.log('\nTEST 3: Signal handling comparison');
73
+
74
+ // Baseline signal handling
75
+ console.log('3a. Baseline signal handling:');
76
+ const baselineChild = spawn('sleep', ['30'], {
77
+ stdio: 'inherit',
78
+ });
79
+
80
+ setTimeout(() => {
81
+ console.log('Sending SIGTERM to baseline child...');
82
+ baselineChild.kill('SIGTERM');
83
+ }, 1000);
84
+
85
+ await new Promise((resolve) => {
86
+ baselineChild.on('exit', (code, signal) => {
87
+ console.log(`Baseline exited: code=${code}, signal=${signal}`);
88
+ resolve();
89
+ });
90
+ });
91
+
92
+ // Library signal handling
93
+ console.log('3b. Library signal handling:');
94
+ const runner = $`sleep 30`;
95
+ const promise = runner.start();
96
+
97
+ setTimeout(() => {
98
+ console.log('Sending kill to library runner...');
99
+ runner.kill();
100
+ }, 1000);
101
+
102
+ try {
103
+ await promise;
104
+ } catch (error) {
105
+ console.log(`Library exited: ${error.message}`);
106
+ }
107
+ console.log(`Library finished: ${runner.finished}`);
108
+ }
109
+
110
+ // Example 4: Streaming comparison
111
+ async function testStreamingComparison() {
112
+ console.log('\nTEST 4: Streaming output comparison');
113
+
114
+ // Baseline streaming
115
+ console.log('4a. Baseline streaming:');
116
+ await new Promise((resolve) => {
117
+ const child = spawn(
118
+ 'sh',
119
+ ['-c', 'for i in 1 2 3; do echo "baseline $i"; sleep 0.1; done'],
120
+ {
121
+ stdio: 'pipe',
122
+ }
123
+ );
124
+
125
+ child.stdout.on('data', (chunk) => {
126
+ process.stdout.write(`[Baseline chunk]: ${chunk}`);
127
+ });
128
+
129
+ child.on('exit', resolve);
130
+ });
131
+
132
+ // Library streaming
133
+ console.log('4b. Library streaming:');
134
+ const runner = $`sh -c 'for i in 1 2 3; do echo "library $i"; sleep 0.1; done'`;
135
+
136
+ for await (const chunk of runner.stream()) {
137
+ process.stdout.write(`[Library chunk]: ${chunk.data}`);
138
+ }
139
+ }
140
+
141
+ // Example 5: Error handling comparison
142
+ async function testErrorHandlingComparison() {
143
+ console.log('\nTEST 5: Error handling comparison');
144
+
145
+ // Baseline error handling
146
+ console.log('5a. Baseline error handling:');
147
+ try {
148
+ await new Promise((resolve, reject) => {
149
+ const child = spawn('false', [], { stdio: 'inherit' });
150
+ child.on('exit', (code) => {
151
+ if (code !== 0) {
152
+ reject(new Error(`Command failed with code ${code}`));
153
+ } else {
154
+ resolve();
155
+ }
156
+ });
157
+ });
158
+ } catch (error) {
159
+ console.log('Baseline error caught:', error.message);
160
+ }
161
+
162
+ // Library error handling
163
+ console.log('5b. Library error handling:');
164
+ try {
165
+ await $`false`;
166
+ } catch (error) {
167
+ console.log('Library error caught:', error.message);
168
+ }
169
+ }
170
+
171
+ // Example 6: CI-specific differences
172
+ async function testCISpecificDifferences() {
173
+ console.log('\nTEST 6: CI-specific behavior differences');
174
+
175
+ const isCI = process.env.CI === 'true';
176
+ const isTTY = process.stdout.isTTY;
177
+
178
+ console.log(`Environment: CI=${isCI}, TTY=${isTTY}`);
179
+
180
+ // Test that might behave differently in CI
181
+ const testScript = `
182
+ if [ -t 0 ]; then
183
+ echo "TTY detected"
184
+ else
185
+ echo "No TTY (typical in CI)"
186
+ fi
187
+ `;
188
+
189
+ // Baseline
190
+ console.log('6a. Baseline TTY detection:');
191
+ await new Promise((resolve) => {
192
+ const child = spawn('sh', ['-c', testScript], {
193
+ stdio: 'inherit',
194
+ });
195
+ child.on('exit', resolve);
196
+ });
197
+
198
+ // Library
199
+ console.log('6b. Library TTY detection:');
200
+ const result = await $`sh -c ${testScript}`;
201
+ console.log(result.stdout.trim());
202
+ }
203
+
204
+ // Example 7: Performance comparison
205
+ async function testPerformanceComparison() {
206
+ console.log('\nTEST 7: Performance comparison');
207
+
208
+ const iterations = 10;
209
+
210
+ // Baseline performance
211
+ console.log(`7a. Baseline performance (${iterations} iterations):`);
212
+ const baselineStart = Date.now();
213
+ for (let i = 0; i < iterations; i++) {
214
+ await new Promise((resolve) => {
215
+ const child = spawn('echo', [`test ${i}`], {
216
+ stdio: 'ignore',
217
+ });
218
+ child.on('exit', resolve);
219
+ });
220
+ }
221
+ const baselineTime = Date.now() - baselineStart;
222
+ console.log(`Baseline time: ${baselineTime}ms`);
223
+
224
+ // Library performance
225
+ console.log(`7b. Library performance (${iterations} iterations):`);
226
+ const libraryStart = Date.now();
227
+ for (let i = 0; i < iterations; i++) {
228
+ await $({ quiet: true })`echo "test ${i}"`;
229
+ }
230
+ const libraryTime = Date.now() - libraryStart;
231
+ console.log(`Library time: ${libraryTime}ms`);
232
+
233
+ console.log(`Overhead: ${libraryTime - baselineTime}ms`);
234
+ }
235
+
236
+ // Run all comparisons
237
+ async function main() {
238
+ console.log('Environment info:');
239
+ console.log(`- Node: ${process.version}`);
240
+ console.log(`- Platform: ${process.platform}`);
241
+ console.log(`- CI: ${process.env.CI || 'false'}`);
242
+ console.log(`- TTY: ${process.stdout.isTTY || false}`);
243
+
244
+ try {
245
+ await testBaselineSpawn();
246
+ await testLibrary();
247
+ await testSignalHandlingComparison();
248
+ await testStreamingComparison();
249
+ await testErrorHandlingComparison();
250
+ await testCISpecificDifferences();
251
+ await testPerformanceComparison();
252
+
253
+ console.log('\n✅ All comparison tests completed successfully');
254
+ console.log('Both baseline and library are working correctly');
255
+ } catch (error) {
256
+ console.error('\n❌ Test failed:', error);
257
+ console.error('This helps identify if the issue is with:');
258
+ console.error('- The library implementation');
259
+ console.error('- The underlying Node.js spawn behavior');
260
+ console.error('- CI environment configuration');
261
+ process.exit(1);
262
+ }
263
+ }
264
+
265
+ main();
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Example: Debugging ES module loading failures in CI
5
+ *
6
+ * Problem: In CI environments, child processes spawned with ES module imports
7
+ * sometimes fail immediately with SIGINT or other signals.
8
+ *
9
+ * Solution: Use different approaches for loading modules in child processes.
10
+ */
11
+
12
+ import { spawn } from 'child_process';
13
+ import { $ } from '../src/$.mjs';
14
+
15
+ console.log('Testing ES module loading in child processes');
16
+
17
+ // Example 1: Direct ES module import (may fail in CI)
18
+ async function testDirectESModule() {
19
+ console.log('\nTEST 1: Direct ES module import in child process');
20
+
21
+ const script = `
22
+ import { $ } from '../src/$.mjs';
23
+ console.log('Module loaded successfully');
24
+ const result = await $\`echo "ES module test"\`;
25
+ console.log('Result:', result.stdout);
26
+ `;
27
+
28
+ try {
29
+ // This might fail in CI with immediate SIGINT
30
+ const child = spawn('node', ['--input-type=module', '-e', script], {
31
+ stdio: 'inherit',
32
+ cwd: process.cwd(),
33
+ });
34
+
35
+ await new Promise((resolve, reject) => {
36
+ child.on('exit', (code, signal) => {
37
+ if (code === 0) {
38
+ console.log('✓ ES module loaded successfully');
39
+ resolve();
40
+ } else {
41
+ console.log(`✗ Failed with code ${code}, signal ${signal}`);
42
+ reject(new Error(`Process failed: ${code}/${signal}`));
43
+ }
44
+ });
45
+ });
46
+ } catch (error) {
47
+ console.log('Expected failure in CI:', error.message);
48
+ }
49
+ }
50
+
51
+ // Example 2: CommonJS fallback approach
52
+ async function testCommonJSFallback() {
53
+ console.log('\nTEST 2: CommonJS-style dynamic import');
54
+
55
+ const script = `
56
+ (async () => {
57
+ try {
58
+ const module = await import('../src/$.mjs');
59
+ const $ = module.$;
60
+ console.log('Module loaded via dynamic import');
61
+ const result = await $\`echo "Dynamic import test"\`;
62
+ console.log('Result:', result.stdout);
63
+ } catch (error) {
64
+ console.error('Import failed:', error.message);
65
+ process.exit(1);
66
+ }
67
+ })();
68
+ `;
69
+
70
+ const child = spawn('node', ['--input-type=module', '-e', script], {
71
+ stdio: 'inherit',
72
+ cwd: process.cwd(),
73
+ });
74
+
75
+ await new Promise((resolve) => {
76
+ child.on('exit', (code, signal) => {
77
+ console.log(`Process exited with code ${code}, signal ${signal}`);
78
+ resolve();
79
+ });
80
+ });
81
+ }
82
+
83
+ // Example 3: Simple inline script without imports (most reliable in CI)
84
+ async function testInlineScript() {
85
+ console.log('\nTEST 3: Inline script without ES module imports');
86
+
87
+ const child = spawn(
88
+ 'node',
89
+ [
90
+ '-e',
91
+ `
92
+ console.log('INLINE_START');
93
+ setTimeout(() => {
94
+ console.log('INLINE_END');
95
+ process.exit(0);
96
+ }, 100);
97
+ `,
98
+ ],
99
+ {
100
+ stdio: 'inherit',
101
+ }
102
+ );
103
+
104
+ await new Promise((resolve) => {
105
+ child.on('exit', (code) => {
106
+ console.log(`✓ Inline script completed with code ${code}`);
107
+ resolve();
108
+ });
109
+ });
110
+ }
111
+
112
+ // Example 4: Shell command fallback (most compatible)
113
+ async function testShellFallback() {
114
+ console.log('\nTEST 4: Shell command fallback');
115
+
116
+ // Use shell commands directly when ES modules fail
117
+ const child = spawn(
118
+ 'sh',
119
+ ['-c', 'echo "SHELL_START" && sleep 0.1 && echo "SHELL_END"'],
120
+ {
121
+ stdio: 'inherit',
122
+ }
123
+ );
124
+
125
+ await new Promise((resolve) => {
126
+ child.on('exit', (code) => {
127
+ console.log(`✓ Shell command completed with code ${code}`);
128
+ resolve();
129
+ });
130
+ });
131
+ }
132
+
133
+ // Example 5: Error handling with detailed diagnostics
134
+ async function testWithDiagnostics() {
135
+ console.log('\nTEST 5: Child process with detailed diagnostics');
136
+
137
+ const script = `
138
+ console.error('[DIAG] Node version:', process.version);
139
+ console.error('[DIAG] Platform:', process.platform);
140
+ console.error('[DIAG] CWD:', process.cwd());
141
+ console.error('[DIAG] Module paths:', module.paths);
142
+
143
+ import('../src/$.mjs').then(
144
+ (module) => {
145
+ console.log('SUCCESS: Module loaded');
146
+ process.exit(0);
147
+ },
148
+ (error) => {
149
+ console.error('FAILURE: Cannot load module');
150
+ console.error('Error:', error.message);
151
+ console.error('Stack:', error.stack);
152
+ process.exit(1);
153
+ }
154
+ );
155
+ `;
156
+
157
+ const child = spawn('node', ['--input-type=module', '-e', script], {
158
+ stdio: 'inherit',
159
+ cwd: process.cwd(),
160
+ });
161
+
162
+ await new Promise((resolve) => {
163
+ child.on('exit', resolve);
164
+ });
165
+ }
166
+
167
+ // Run all tests
168
+ async function main() {
169
+ console.log('Environment info:');
170
+ console.log('- Node version:', process.version);
171
+ console.log('- Platform:', process.platform);
172
+ console.log('- CI:', process.env.CI || 'false');
173
+ console.log('- GitHub Actions:', process.env.GITHUB_ACTIONS || 'false');
174
+
175
+ await testDirectESModule();
176
+ await testCommonJSFallback();
177
+ await testInlineScript();
178
+ await testShellFallback();
179
+ await testWithDiagnostics();
180
+
181
+ console.log('\nAll tests completed');
182
+ }
183
+
184
+ main().catch(console.error);
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Example: Debugging signal handling issues in CI
5
+ *
6
+ * Problem: SIGINT/SIGTERM signals behave differently in CI environments,
7
+ * especially with process groups and detached processes.
8
+ *
9
+ * Solution: Proper signal forwarding and cleanup strategies.
10
+ */
11
+
12
+ import { spawn } from 'child_process';
13
+ import { $ } from '../src/$.mjs';
14
+
15
+ console.log('Testing signal handling in CI environment');
16
+
17
+ // Example 1: Basic signal forwarding
18
+ async function testBasicSignalForwarding() {
19
+ console.log('\nTEST 1: Basic signal forwarding');
20
+
21
+ const child = spawn('sh', ['-c', 'echo "Starting sleep" && sleep 30'], {
22
+ stdio: 'inherit',
23
+ detached: false, // Not detached, stays in same process group
24
+ });
25
+
26
+ console.log(`Child PID: ${child.pid}`);
27
+
28
+ // Forward SIGINT to child
29
+ const signalHandler = () => {
30
+ console.log('Parent received SIGINT, forwarding to child...');
31
+ child.kill('SIGINT');
32
+ };
33
+ process.on('SIGINT', signalHandler);
34
+
35
+ // Simulate SIGINT after 1 second
36
+ setTimeout(() => {
37
+ console.log('Simulating SIGINT...');
38
+ process.kill(process.pid, 'SIGINT');
39
+ }, 1000);
40
+
41
+ await new Promise((resolve) => {
42
+ child.on('exit', (code, signal) => {
43
+ console.log(`Child exited with code ${code}, signal ${signal}`);
44
+ process.removeListener('SIGINT', signalHandler);
45
+ resolve();
46
+ });
47
+ });
48
+ }
49
+
50
+ // Example 2: Detached process group handling
51
+ async function testDetachedProcessGroup() {
52
+ console.log('\nTEST 2: Detached process group');
53
+
54
+ const child = spawn('sh', ['-c', 'echo "Detached start" && sleep 30'], {
55
+ stdio: 'inherit',
56
+ detached: true, // Creates new process group
57
+ });
58
+
59
+ const pgid = -child.pid; // Negative PID targets the process group
60
+ console.log(`Child PID: ${child.pid}, PGID: ${pgid}`);
61
+
62
+ // Kill entire process group
63
+ setTimeout(() => {
64
+ console.log('Killing process group...');
65
+ try {
66
+ process.kill(pgid, 'SIGTERM');
67
+ } catch (error) {
68
+ console.log('Error killing process group:', error.message);
69
+ // Fallback to killing just the child
70
+ child.kill('SIGTERM');
71
+ }
72
+ }, 1000);
73
+
74
+ await new Promise((resolve) => {
75
+ child.on('exit', (code, signal) => {
76
+ console.log(`Child exited with code ${code}, signal ${signal}`);
77
+ resolve();
78
+ });
79
+ });
80
+ }
81
+
82
+ // Example 3: Signal handling with command-stream
83
+ async function testCommandStreamSignals() {
84
+ console.log('\nTEST 3: Command-stream signal handling');
85
+
86
+ const runner = $`sleep 30`;
87
+ const promise = runner.start();
88
+
89
+ // Log when command starts
90
+ runner.on('start', () => {
91
+ console.log('Command started');
92
+ });
93
+
94
+ // Simulate interrupt after 1 second
95
+ setTimeout(() => {
96
+ console.log('Sending kill signal to runner...');
97
+ runner.kill();
98
+ }, 1000);
99
+
100
+ try {
101
+ await promise;
102
+ console.log('Command completed normally');
103
+ } catch (error) {
104
+ console.log('Command was interrupted:', error.message);
105
+ }
106
+
107
+ console.log('Runner finished:', runner.finished);
108
+ }
109
+
110
+ // Example 4: Cleanup on unexpected exit
111
+ async function testCleanupOnExit() {
112
+ console.log('\nTEST 4: Cleanup on unexpected exit');
113
+
114
+ const children = [];
115
+
116
+ // Cleanup function
117
+ const cleanup = () => {
118
+ console.log('Cleaning up child processes...');
119
+ children.forEach((child) => {
120
+ if (!child.killed) {
121
+ console.log(`Killing child ${child.pid}`);
122
+ child.kill('SIGTERM');
123
+ }
124
+ });
125
+ };
126
+
127
+ // Register cleanup handlers
128
+ process.on('exit', cleanup);
129
+ process.on('SIGINT', () => {
130
+ console.log('Received SIGINT');
131
+ cleanup();
132
+ process.exit(130); // Standard exit code for SIGINT
133
+ });
134
+ process.on('SIGTERM', () => {
135
+ console.log('Received SIGTERM');
136
+ cleanup();
137
+ process.exit(143); // Standard exit code for SIGTERM
138
+ });
139
+
140
+ // Start some child processes
141
+ for (let i = 0; i < 3; i++) {
142
+ const child = spawn('sleep', ['30'], {
143
+ stdio: 'ignore',
144
+ });
145
+ children.push(child);
146
+ console.log(`Started child ${i + 1} with PID ${child.pid}`);
147
+ }
148
+
149
+ // Simulate cleanup after 1 second
150
+ setTimeout(() => {
151
+ console.log('Triggering cleanup...');
152
+ cleanup();
153
+ }, 1000);
154
+
155
+ // Wait for all children to exit
156
+ await Promise.all(
157
+ children.map((child) => new Promise((resolve) => child.on('exit', resolve)))
158
+ );
159
+
160
+ console.log('All children cleaned up');
161
+ }
162
+
163
+ // Example 5: Signal handling in CI vs local environment
164
+ async function testEnvironmentDifferences() {
165
+ console.log('\nTEST 5: Environment-specific signal handling');
166
+
167
+ const isCI = process.env.CI === 'true';
168
+ const isGitHubActions = process.env.GITHUB_ACTIONS === 'true';
169
+ const isTTY = process.stdout.isTTY;
170
+
171
+ console.log('Environment:');
172
+ console.log(`- CI: ${isCI}`);
173
+ console.log(`- GitHub Actions: ${isGitHubActions}`);
174
+ console.log(`- TTY: ${isTTY}`);
175
+ console.log(`- Process group: ${process.pid}`);
176
+
177
+ // Different strategies based on environment
178
+ if (isCI) {
179
+ console.log('Using CI-optimized signal handling');
180
+ // In CI, we might need more aggressive cleanup
181
+ const child = spawn('sleep', ['30'], {
182
+ stdio: 'inherit',
183
+ detached: false, // Keep in same process group for CI
184
+ });
185
+
186
+ setTimeout(() => {
187
+ // Use SIGKILL as last resort in CI
188
+ child.kill('SIGKILL');
189
+ }, 1000);
190
+
191
+ await new Promise((resolve) => child.on('exit', resolve));
192
+ } else {
193
+ console.log('Using local development signal handling');
194
+ // In local dev, we can be more graceful
195
+ const child = spawn('sleep', ['30'], {
196
+ stdio: 'inherit',
197
+ detached: true, // Can detach in local environment
198
+ });
199
+
200
+ setTimeout(() => {
201
+ // Use SIGTERM for graceful shutdown
202
+ child.kill('SIGTERM');
203
+ }, 1000);
204
+
205
+ await new Promise((resolve) => child.on('exit', resolve));
206
+ }
207
+ }
208
+
209
+ // Run tests
210
+ async function main() {
211
+ try {
212
+ await testBasicSignalForwarding();
213
+ await testDetachedProcessGroup();
214
+ await testCommandStreamSignals();
215
+ await testCleanupOnExit();
216
+ await testEnvironmentDifferences();
217
+
218
+ console.log('\nAll signal handling tests completed');
219
+ } catch (error) {
220
+ console.error('Test failed:', error);
221
+ process.exit(1);
222
+ }
223
+ }
224
+
225
+ main();