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,200 @@
1
+ /**
2
+ * Test cleanup utilities for command-stream tests
3
+ *
4
+ * Provides functions to be called in beforeEach/afterEach hooks
5
+ * within describe blocks.
6
+ *
7
+ * Usage:
8
+ * ```js
9
+ * import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs';
10
+ * import { describe, beforeEach, afterEach } from 'bun:test';
11
+ *
12
+ * describe('Your test suite', () => {
13
+ * beforeEach(beforeTestCleanup);
14
+ * afterEach(afterTestCleanup);
15
+ *
16
+ * // Your tests here
17
+ * });
18
+ * ```
19
+ */
20
+
21
+ import { resetGlobalState } from '../src/$.mjs';
22
+ import { existsSync } from 'fs';
23
+
24
+ // Save the original working directory when module loads
25
+ const originalCwd = process.cwd();
26
+
27
+ // Trace function for debugging
28
+ function trace(message) {
29
+ if (process.env.DEBUG || process.env.TRACE) {
30
+ const timestamp = new Date().toISOString();
31
+ console.error(`[TRACE ${timestamp}] [test-cleanup] ${message}`);
32
+ }
33
+ }
34
+
35
+ trace(`Module loaded - original working directory: ${originalCwd}`);
36
+
37
+ /**
38
+ * Cleanup function to call in beforeEach hook
39
+ */
40
+ export async function beforeTestCleanup() {
41
+ trace('beforeTestCleanup running');
42
+
43
+ // CRITICAL: Restore working directory first - MUST succeed for spawn to work
44
+ const currentDir = process.cwd();
45
+ if (currentDir !== originalCwd) {
46
+ trace(`Restoring cwd from ${currentDir} to ${originalCwd}`);
47
+ try {
48
+ // Force restoration regardless of current state
49
+ process.chdir(originalCwd);
50
+ } catch (_e) {
51
+ // Original directory might be gone, try fallbacks
52
+ try {
53
+ if (existsSync(originalCwd)) {
54
+ process.chdir(originalCwd);
55
+ } else if (existsSync('/workspace/command-stream')) {
56
+ process.chdir('/workspace/command-stream');
57
+ } else if (process.env.HOME && existsSync(process.env.HOME)) {
58
+ process.chdir(process.env.HOME);
59
+ } else {
60
+ process.chdir('/');
61
+ }
62
+ } catch (_e2) {
63
+ console.error(
64
+ '[test-cleanup] FATAL: Cannot set working directory in beforeTestCleanup'
65
+ );
66
+ trace('FATAL: Cannot set working directory');
67
+ }
68
+ }
69
+ }
70
+
71
+ // Call the comprehensive reset
72
+ resetGlobalState();
73
+
74
+ // Extra safety: ensure we're in a valid directory after reset
75
+ try {
76
+ process.cwd(); // This will throw if we're in a bad state
77
+ } catch (_e) {
78
+ // Force to a known good directory
79
+ process.chdir(originalCwd);
80
+ }
81
+
82
+ // VERIFY: Ensure we actually restored to the original directory
83
+ const finalCwd = process.cwd();
84
+ if (finalCwd !== originalCwd && existsSync(originalCwd)) {
85
+ console.error(
86
+ `[test-cleanup] WARNING: Failed to restore cwd! Expected: ${originalCwd}, Got: ${finalCwd}`
87
+ );
88
+ // Try one more time
89
+ try {
90
+ process.chdir(originalCwd);
91
+ const verifiedCwd = process.cwd();
92
+ if (verifiedCwd === originalCwd) {
93
+ trace('Successfully restored on second attempt');
94
+ } else {
95
+ throw new Error(
96
+ `[test-cleanup] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${verifiedCwd}`
97
+ );
98
+ }
99
+ } catch (_e) {
100
+ throw new Error(
101
+ `[test-cleanup] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${finalCwd}`
102
+ );
103
+ }
104
+ }
105
+
106
+ // Give a tiny bit of time for any async cleanup to complete
107
+ await new Promise((resolve) => setTimeout(resolve, 1));
108
+ trace('beforeTestCleanup completed');
109
+ }
110
+
111
+ /**
112
+ * Cleanup function to call in afterEach hook
113
+ */
114
+ export async function afterTestCleanup() {
115
+ trace('afterTestCleanup running');
116
+
117
+ // CRITICAL: Clean up and restore state after each test
118
+ const currentDir = process.cwd();
119
+ if (currentDir !== originalCwd) {
120
+ trace(`Restoring cwd from ${currentDir} to ${originalCwd}`);
121
+ try {
122
+ // Force restoration regardless of current state
123
+ process.chdir(originalCwd);
124
+ } catch (_e) {
125
+ // Original directory might be gone, try fallbacks
126
+ try {
127
+ if (existsSync(originalCwd)) {
128
+ process.chdir(originalCwd);
129
+ } else if (existsSync('/workspace/command-stream')) {
130
+ process.chdir('/workspace/command-stream');
131
+ } else if (process.env.HOME && existsSync(process.env.HOME)) {
132
+ process.chdir(process.env.HOME);
133
+ } else {
134
+ process.chdir('/');
135
+ }
136
+ } catch (_e2) {
137
+ console.error(
138
+ '[test-cleanup] FATAL: Cannot set working directory in afterTestCleanup'
139
+ );
140
+ trace('FATAL: Cannot set working directory');
141
+ }
142
+ }
143
+ }
144
+
145
+ // Call the comprehensive reset
146
+ resetGlobalState();
147
+
148
+ // Extra safety: ensure we're in a valid directory after reset
149
+ try {
150
+ process.cwd(); // This will throw if we're in a bad state
151
+ } catch (_e) {
152
+ // Force to a known good directory
153
+ process.chdir(originalCwd);
154
+ }
155
+
156
+ // VERIFY: Ensure we actually restored to the original directory
157
+ const finalCwd = process.cwd();
158
+ if (finalCwd !== originalCwd && existsSync(originalCwd)) {
159
+ console.error(
160
+ `[test-cleanup] WARNING: Failed to restore cwd in afterEach! Expected: ${originalCwd}, Got: ${finalCwd}`
161
+ );
162
+ // Try one more time
163
+ try {
164
+ process.chdir(originalCwd);
165
+ const verifiedCwd = process.cwd();
166
+ if (verifiedCwd === originalCwd) {
167
+ trace('Successfully restored on second attempt in afterEach');
168
+ } else {
169
+ throw new Error(
170
+ `[test-cleanup] CRITICAL: Cannot restore to original directory ${originalCwd} in afterEach, stuck in ${verifiedCwd}`
171
+ );
172
+ }
173
+ } catch (_e) {
174
+ throw new Error(
175
+ `[test-cleanup] CRITICAL: Cannot restore to original directory ${originalCwd} in afterEach, stuck in ${finalCwd}`
176
+ );
177
+ }
178
+ }
179
+
180
+ // Give a tiny bit of time for any async cleanup to complete
181
+ await new Promise((resolve) => setTimeout(resolve, 1));
182
+ trace('afterTestCleanup completed');
183
+ }
184
+
185
+ // Install a process exit handler to ensure cleanup even on crash
186
+ process.on('beforeExit', () => {
187
+ try {
188
+ if (process.cwd() !== originalCwd) {
189
+ process.chdir(originalCwd);
190
+ }
191
+ } catch (_e) {
192
+ // Ignore
193
+ }
194
+ });
195
+
196
+ // Export resetGlobalState for direct use if needed
197
+ export { resetGlobalState };
198
+
199
+ // Export original cwd for verification in tests
200
+ export { originalCwd };
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Test Helper for command-stream tests
3
+ *
4
+ * IMPORTANT: Due to Bun's test runner limitations, beforeEach/afterEach hooks
5
+ * MUST be within describe() blocks to work properly.
6
+ *
7
+ * Usage:
8
+ * ```js
9
+ * import { setupTestHooks } from './test-helper-fixed.mjs';
10
+ * import { describe } from 'bun:test';
11
+ *
12
+ * describe('Your test suite', () => {
13
+ * setupTestHooks();
14
+ *
15
+ * // Your tests here
16
+ * });
17
+ * ```
18
+ */
19
+
20
+ import { beforeEach, afterEach } from 'bun:test';
21
+ import { resetGlobalState } from '../src/$.mjs';
22
+ import { existsSync } from 'fs';
23
+
24
+ // Save the original working directory when tests start
25
+ const originalCwd = process.cwd();
26
+
27
+ // Trace function for debugging
28
+ function trace(message) {
29
+ if (process.env.DEBUG || process.env.TRACE) {
30
+ const timestamp = new Date().toISOString();
31
+ console.error(`[TRACE ${timestamp}] [test-helper] ${message}`);
32
+ }
33
+ }
34
+
35
+ trace(`Original working directory: ${originalCwd}`);
36
+
37
+ /**
38
+ * Sets up beforeEach and afterEach hooks to restore working directory
39
+ * and reset global state between tests.
40
+ *
41
+ * MUST be called inside a describe() block!
42
+ */
43
+ export function setupTestHooks() {
44
+ beforeEach(async () => {
45
+ trace('beforeEach hook running');
46
+ // CRITICAL: Restore working directory first - MUST succeed for spawn to work
47
+ const currentDir = process.cwd();
48
+ if (currentDir !== originalCwd) {
49
+ trace(`beforeEach: Restoring cwd from ${currentDir} to ${originalCwd}`);
50
+ try {
51
+ // Force restoration regardless of current state
52
+ process.chdir(originalCwd);
53
+ } catch (_e) {
54
+ // Original directory might be gone, try fallbacks
55
+ try {
56
+ if (existsSync(originalCwd)) {
57
+ process.chdir(originalCwd);
58
+ } else if (existsSync('/workspace/command-stream')) {
59
+ process.chdir('/workspace/command-stream');
60
+ } else if (process.env.HOME && existsSync(process.env.HOME)) {
61
+ process.chdir(process.env.HOME);
62
+ } else {
63
+ process.chdir('/');
64
+ }
65
+ } catch (_e2) {
66
+ console.error(
67
+ '[test-helper] FATAL: Cannot set working directory in beforeEach'
68
+ );
69
+ trace('FATAL: Cannot set working directory in beforeEach');
70
+ }
71
+ }
72
+ }
73
+
74
+ // Call the comprehensive reset
75
+ resetGlobalState();
76
+
77
+ // Extra safety: ensure we're in a valid directory after reset
78
+ try {
79
+ process.cwd(); // This will throw if we're in a bad state
80
+ } catch (_e) {
81
+ // Force to a known good directory
82
+ process.chdir(originalCwd);
83
+ }
84
+
85
+ // Give a tiny bit of time for any async cleanup to complete
86
+ await new Promise((resolve) => setTimeout(resolve, 1));
87
+ trace('beforeEach hook completed');
88
+ });
89
+
90
+ afterEach(async () => {
91
+ trace('afterEach hook running');
92
+ // CRITICAL: Clean up and restore state after each test
93
+ const currentDir = process.cwd();
94
+ if (currentDir !== originalCwd) {
95
+ trace(`afterEach: Restoring cwd from ${currentDir} to ${originalCwd}`);
96
+ try {
97
+ // Force restoration regardless of current state
98
+ process.chdir(originalCwd);
99
+ } catch (_e) {
100
+ // Original directory might be gone, try fallbacks
101
+ try {
102
+ if (existsSync(originalCwd)) {
103
+ process.chdir(originalCwd);
104
+ } else if (existsSync('/workspace/command-stream')) {
105
+ process.chdir('/workspace/command-stream');
106
+ } else if (process.env.HOME && existsSync(process.env.HOME)) {
107
+ process.chdir(process.env.HOME);
108
+ } else {
109
+ process.chdir('/');
110
+ }
111
+ } catch (_e2) {
112
+ console.error(
113
+ '[test-helper] FATAL: Cannot set working directory in afterEach'
114
+ );
115
+ trace('FATAL: Cannot set working directory in afterEach');
116
+ }
117
+ }
118
+ }
119
+
120
+ // Call the comprehensive reset
121
+ resetGlobalState();
122
+
123
+ // Extra safety: ensure we're in a valid directory after reset
124
+ try {
125
+ process.cwd(); // This will throw if we're in a bad state
126
+ } catch (_e) {
127
+ // Force to a known good directory
128
+ process.chdir(originalCwd);
129
+ }
130
+
131
+ // Give a tiny bit of time for any async cleanup to complete
132
+ await new Promise((resolve) => setTimeout(resolve, 1));
133
+ trace('afterEach hook completed');
134
+ });
135
+ }
136
+
137
+ // Install a process exit handler to ensure cleanup even on crash
138
+ process.on('beforeExit', () => {
139
+ try {
140
+ if (process.cwd() !== originalCwd) {
141
+ process.chdir(originalCwd);
142
+ }
143
+ } catch (_e) {
144
+ // Ignore
145
+ }
146
+ });
147
+
148
+ export { resetGlobalState };
@@ -0,0 +1,118 @@
1
+ import { beforeEach, afterEach } from 'bun:test';
2
+ import { resetGlobalState } from '../src/$.mjs';
3
+ import { existsSync } from 'fs';
4
+
5
+ // Save the original working directory when tests start
6
+ const originalCwd = process.cwd();
7
+
8
+ // Trace function for debugging
9
+ function trace(message) {
10
+ if (process.env.DEBUG || process.env.TRACE) {
11
+ const timestamp = new Date().toISOString();
12
+ console.error(`[TRACE ${timestamp}] [test-helper-v2] ${message}`);
13
+ }
14
+ }
15
+
16
+ trace(`Original working directory: ${originalCwd}`);
17
+
18
+ // Function to set up test hooks
19
+ export function setupTestHooks() {
20
+ trace('Setting up test hooks');
21
+
22
+ beforeEach(async () => {
23
+ trace('beforeEach hook running');
24
+ // CRITICAL: Restore working directory first - MUST succeed for spawn to work
25
+ const currentDir = process.cwd();
26
+ if (currentDir !== originalCwd) {
27
+ trace(`beforeEach: Restoring cwd from ${currentDir} to ${originalCwd}`);
28
+ try {
29
+ // Force restoration regardless of current state
30
+ process.chdir(originalCwd);
31
+ } catch (_e) {
32
+ // Original directory might be gone, try fallbacks
33
+ try {
34
+ if (existsSync(originalCwd)) {
35
+ process.chdir(originalCwd);
36
+ } else if (existsSync('/workspace/command-stream')) {
37
+ process.chdir('/workspace/command-stream');
38
+ } else if (process.env.HOME && existsSync(process.env.HOME)) {
39
+ process.chdir(process.env.HOME);
40
+ } else {
41
+ process.chdir('/');
42
+ }
43
+ } catch (_e2) {
44
+ console.error(
45
+ '[test-helper-v2] FATAL: Cannot set working directory in beforeEach'
46
+ );
47
+ trace('FATAL: Cannot set working directory in beforeEach');
48
+ }
49
+ }
50
+ }
51
+
52
+ // Call the comprehensive reset
53
+ resetGlobalState();
54
+
55
+ // Extra safety: ensure we're in a valid directory after reset
56
+ try {
57
+ process.cwd(); // This will throw if we're in a bad state
58
+ } catch (_e) {
59
+ // Force to a known good directory
60
+ process.chdir(originalCwd);
61
+ }
62
+
63
+ // Give a tiny bit of time for any async cleanup to complete
64
+ await new Promise((resolve) => setTimeout(resolve, 1));
65
+ trace('beforeEach hook completed');
66
+ });
67
+
68
+ afterEach(async () => {
69
+ trace('afterEach hook running');
70
+ // CRITICAL: Clean up and restore state after each test
71
+ const currentDir = process.cwd();
72
+ if (currentDir !== originalCwd) {
73
+ trace(`afterEach: Restoring cwd from ${currentDir} to ${originalCwd}`);
74
+ try {
75
+ // Force restoration regardless of current state
76
+ process.chdir(originalCwd);
77
+ } catch (_e) {
78
+ // Original directory might be gone, try fallbacks
79
+ try {
80
+ if (existsSync(originalCwd)) {
81
+ process.chdir(originalCwd);
82
+ } else if (existsSync('/workspace/command-stream')) {
83
+ process.chdir('/workspace/command-stream');
84
+ } else if (process.env.HOME && existsSync(process.env.HOME)) {
85
+ process.chdir(process.env.HOME);
86
+ } else {
87
+ process.chdir('/');
88
+ }
89
+ } catch (_e2) {
90
+ console.error(
91
+ '[test-helper-v2] FATAL: Cannot set working directory in afterEach'
92
+ );
93
+ trace('FATAL: Cannot set working directory in afterEach');
94
+ }
95
+ }
96
+ }
97
+
98
+ // Call the comprehensive reset
99
+ resetGlobalState();
100
+
101
+ // Extra safety: ensure we're in a valid directory after reset
102
+ try {
103
+ process.cwd(); // This will throw if we're in a bad state
104
+ } catch (_e) {
105
+ // Force to a known good directory
106
+ process.chdir(originalCwd);
107
+ }
108
+
109
+ // Give a tiny bit of time for any async cleanup to complete
110
+ await new Promise((resolve) => setTimeout(resolve, 1));
111
+ trace('afterEach hook completed');
112
+ });
113
+ }
114
+
115
+ // Auto-setup hooks when imported
116
+ setupTestHooks();
117
+
118
+ export { resetGlobalState };
@@ -0,0 +1,171 @@
1
+ import { beforeEach, afterEach } from 'bun:test';
2
+ import { resetGlobalState } from '../src/$.mjs';
3
+ import { existsSync } from 'fs';
4
+
5
+ // Platform detection helpers
6
+ export const isWindows = process.platform === 'win32';
7
+ export const isUnix = process.platform !== 'win32';
8
+
9
+ // Save the original working directory when tests start
10
+ const originalCwd = process.cwd();
11
+
12
+ // Trace function for debugging
13
+ function trace(message) {
14
+ if (process.env.DEBUG || process.env.TRACE) {
15
+ const timestamp = new Date().toISOString();
16
+ console.error(`[TRACE ${timestamp}] [test-helper] ${message}`);
17
+ }
18
+ }
19
+
20
+ trace(`Original working directory: ${originalCwd}`);
21
+
22
+ // Install a process exit handler to ensure cleanup even on crash
23
+ process.on('beforeExit', () => {
24
+ try {
25
+ if (process.cwd() !== originalCwd) {
26
+ process.chdir(originalCwd);
27
+ }
28
+ } catch (_e) {
29
+ // Ignore
30
+ }
31
+ });
32
+
33
+ // Reset global state before and after each test to prevent interference
34
+ // Use async to ensure cleanup completes
35
+ beforeEach(async () => {
36
+ // CRITICAL: Restore working directory first - MUST succeed for spawn to work
37
+ const currentDir = process.cwd();
38
+ if (currentDir !== originalCwd) {
39
+ trace(`beforeEach: Restoring cwd from ${currentDir} to ${originalCwd}`);
40
+ }
41
+ try {
42
+ // Force restoration regardless of current state
43
+ process.chdir(originalCwd);
44
+ } catch (_e) {
45
+ // Original directory might be gone, try fallbacks
46
+ try {
47
+ if (existsSync(originalCwd)) {
48
+ process.chdir(originalCwd);
49
+ } else if (existsSync('/workspace/command-stream')) {
50
+ process.chdir('/workspace/command-stream');
51
+ } else if (process.env.HOME && existsSync(process.env.HOME)) {
52
+ process.chdir(process.env.HOME);
53
+ } else {
54
+ process.chdir('/');
55
+ }
56
+ } catch (_e2) {
57
+ console.error(
58
+ '[test-helper] FATAL: Cannot set working directory in beforeEach'
59
+ );
60
+ trace('FATAL: Cannot set working directory in beforeEach');
61
+ }
62
+ }
63
+
64
+ // Call the comprehensive reset
65
+ resetGlobalState();
66
+
67
+ // Extra safety: ensure we're in a valid directory after reset
68
+ try {
69
+ process.cwd(); // This will throw if we're in a bad state
70
+ } catch (_e) {
71
+ // Force to a known good directory
72
+ process.chdir(originalCwd);
73
+ }
74
+
75
+ // VERIFY: Ensure we actually restored to the original directory
76
+ const finalCwd = process.cwd();
77
+ if (finalCwd !== originalCwd && existsSync(originalCwd)) {
78
+ console.error(
79
+ `[test-helper] WARNING: Failed to restore cwd! Expected: ${originalCwd}, Got: ${finalCwd}`
80
+ );
81
+ // Try one more time
82
+ try {
83
+ process.chdir(originalCwd);
84
+ const verifiedCwd = process.cwd();
85
+ if (verifiedCwd === originalCwd) {
86
+ trace('Successfully restored on second attempt');
87
+ } else {
88
+ throw new Error(
89
+ `[test-helper] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${verifiedCwd}`
90
+ );
91
+ }
92
+ } catch (_e) {
93
+ throw new Error(
94
+ `[test-helper] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${finalCwd}`
95
+ );
96
+ }
97
+ }
98
+
99
+ // Give a tiny bit of time for any async cleanup to complete
100
+ await new Promise((resolve) => setTimeout(resolve, 1));
101
+ });
102
+
103
+ afterEach(async () => {
104
+ // CRITICAL: Clean up and restore state after each test
105
+ const currentDir = process.cwd();
106
+ if (currentDir !== originalCwd) {
107
+ trace(`afterEach: Restoring cwd from ${currentDir} to ${originalCwd}`);
108
+ }
109
+ try {
110
+ // Force restoration regardless of current state
111
+ process.chdir(originalCwd);
112
+ } catch (_e) {
113
+ // Original directory might be gone, try fallbacks
114
+ try {
115
+ if (existsSync(originalCwd)) {
116
+ process.chdir(originalCwd);
117
+ } else if (existsSync('/workspace/command-stream')) {
118
+ process.chdir('/workspace/command-stream');
119
+ } else if (process.env.HOME && existsSync(process.env.HOME)) {
120
+ process.chdir(process.env.HOME);
121
+ } else {
122
+ process.chdir('/');
123
+ }
124
+ } catch (_e2) {
125
+ console.error(
126
+ '[test-helper] FATAL: Cannot set working directory in afterEach'
127
+ );
128
+ trace('FATAL: Cannot set working directory in afterEach');
129
+ }
130
+ }
131
+
132
+ // Call the comprehensive reset
133
+ resetGlobalState();
134
+
135
+ // Extra safety: ensure we're in a valid directory after reset
136
+ try {
137
+ process.cwd(); // This will throw if we're in a bad state
138
+ } catch (_e) {
139
+ // Force to a known good directory
140
+ process.chdir(originalCwd);
141
+ }
142
+
143
+ // VERIFY: Ensure we actually restored to the original directory
144
+ const finalCwd = process.cwd();
145
+ if (finalCwd !== originalCwd && existsSync(originalCwd)) {
146
+ console.error(
147
+ `[test-helper] WARNING: Failed to restore cwd! Expected: ${originalCwd}, Got: ${finalCwd}`
148
+ );
149
+ // Try one more time
150
+ try {
151
+ process.chdir(originalCwd);
152
+ const verifiedCwd = process.cwd();
153
+ if (verifiedCwd === originalCwd) {
154
+ trace('Successfully restored on second attempt');
155
+ } else {
156
+ throw new Error(
157
+ `[test-helper] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${verifiedCwd}`
158
+ );
159
+ }
160
+ } catch (_e) {
161
+ throw new Error(
162
+ `[test-helper] CRITICAL: Cannot restore to original directory ${originalCwd}, stuck in ${finalCwd}`
163
+ );
164
+ }
165
+ }
166
+
167
+ // Give a tiny bit of time for any async cleanup to complete
168
+ await new Promise((resolve) => setTimeout(resolve, 1));
169
+ });
170
+
171
+ export { resetGlobalState };
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ let sigintReceived = false;
3
+ process.on('SIGINT', () => {
4
+ console.log('CHILD_SIGINT_RECEIVED');
5
+ sigintReceived = true;
6
+ process.exit(130);
7
+ });
8
+
9
+ // Keep running until interrupted
10
+ console.log('CHILD_STARTED');
11
+ setInterval(() => {
12
+ if (!sigintReceived) {
13
+ console.log('CHILD_RUNNING');
14
+ }
15
+ }, 100);