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,114 @@
1
+ import { $ } from '../src/$.mjs';
2
+ import { test, expect, describe, beforeEach, afterEach } from 'bun:test';
3
+ import { beforeTestCleanup, afterTestCleanup } from './test-cleanup.mjs';
4
+
5
+ describe('Interactive Option Tests', () => {
6
+ beforeEach(beforeTestCleanup);
7
+ afterEach(afterTestCleanup);
8
+
9
+ test('interactive option - default behavior', async () => {
10
+ // Test that interactive is false by default
11
+ const $custom = $({ capture: true, mirror: false });
12
+ const cmd = $custom`echo test`;
13
+
14
+ // Interactive should be false by default
15
+ expect(cmd.options.interactive).toBe(false);
16
+ });
17
+
18
+ test('interactive option - explicit true', async () => {
19
+ // Test that interactive can be set to true
20
+ const $custom = $({ capture: true, mirror: false, interactive: true });
21
+ const cmd = $custom`echo test`;
22
+
23
+ // Interactive should be true when explicitly set
24
+ expect(cmd.options.interactive).toBe(true);
25
+ });
26
+
27
+ test('interactive option - explicit false', async () => {
28
+ // Test that interactive can be explicitly set to false
29
+ const $custom = $({ capture: true, mirror: false, interactive: false });
30
+ const cmd = $custom`echo test`;
31
+
32
+ // Interactive should be false when explicitly set
33
+ expect(cmd.options.interactive).toBe(false);
34
+ });
35
+
36
+ test('interactive option - passed through options merge', async () => {
37
+ // Test that interactive option is preserved when merging options
38
+ const $base = $({ capture: true, mirror: false });
39
+ const cmd = $base`echo test`;
40
+
41
+ // Start with different options to test merging
42
+ cmd.start({ interactive: true });
43
+
44
+ // Interactive should be true after options merge
45
+ expect(cmd.options.interactive).toBe(true);
46
+ });
47
+
48
+ test('interactive option - does not affect command execution with pipes/capture', async () => {
49
+ // Test that setting interactive: true doesn't interfere with normal command execution
50
+ // when pipes are used (which prevents TTY forwarding anyway)
51
+ const $interactive = $({ capture: true, mirror: false, interactive: true });
52
+ const result = await $interactive`echo "interactive test"`;
53
+
54
+ expect(result.code).toBe(0);
55
+ expect(result.stdout.trim()).toBe('interactive test');
56
+ });
57
+
58
+ test('interactive option - behavior with stdin inherit but no TTY', async () => {
59
+ // Test that interactive mode requires both interactive:true AND TTY conditions
60
+ // This test verifies the logic but won't actually use TTY in test environment
61
+ const $interactive = $({
62
+ capture: false,
63
+ mirror: false,
64
+ interactive: true,
65
+ stdin: 'inherit',
66
+ });
67
+ const cmd = $interactive`echo "tty test"`;
68
+
69
+ // Should still work even if TTY conditions aren't met
70
+ expect(cmd.options.interactive).toBe(true);
71
+ expect(cmd.options.stdin).toBe('inherit');
72
+ });
73
+
74
+ test('interactive option - works with template literal syntax', async () => {
75
+ // Test interactive option with various template literal syntaxes
76
+ const name = 'world';
77
+ const $interactive = $({ capture: true, mirror: false, interactive: true });
78
+ const cmd = $interactive`echo "hello ${name}"`;
79
+ const result = await cmd;
80
+
81
+ expect(result.code).toBe(0);
82
+ expect(result.stdout.trim()).toBe('hello world'); // Safe string 'world' doesn't need quotes
83
+ expect(cmd.options.interactive).toBe(true); // Check the command object, not the result
84
+ });
85
+
86
+ test('interactive option - preserved in command chaining', async () => {
87
+ // Test that interactive option is preserved through command operations
88
+ const $interactive = $({ capture: true, mirror: false, interactive: true });
89
+ const cmd1 = $interactive`echo "first"`;
90
+ const cmd2 = cmd1.pipe($interactive`tr 'a-z' 'A-Z'`);
91
+
92
+ // Both commands should preserve the interactive setting
93
+ expect(cmd1.options.interactive).toBe(true);
94
+ // Note: cmd2 (piped command) might have different options, that's expected
95
+ });
96
+
97
+ test('interactive option - type checking', async () => {
98
+ // Test that interactive option accepts boolean values properly
99
+ const $true = $({ interactive: true, capture: true, mirror: false });
100
+ const $false = $({ interactive: false, capture: true, mirror: false });
101
+ const $default = $({ capture: true, mirror: false });
102
+
103
+ expect($true`echo test`.options.interactive).toBe(true);
104
+ expect($false`echo test`.options.interactive).toBe(false);
105
+ expect($default`echo test`.options.interactive).toBe(false);
106
+
107
+ // Test with non-boolean values (should still work, JavaScript is flexible)
108
+ const $truthy = $({ interactive: 1, capture: true, mirror: false });
109
+ const $falsy = $({ interactive: 0, capture: true, mirror: false });
110
+
111
+ expect(Boolean($truthy`echo test`.options.interactive)).toBe(true);
112
+ expect(Boolean($falsy`echo test`.options.interactive)).toBe(false);
113
+ });
114
+ });
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { describe, it, expect } from 'bun:test';
4
+ import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
5
+ import { $ } from '../src/$.mjs';
6
+ import path from 'path';
7
+ import { fileURLToPath } from 'url';
8
+
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+ const calcPath = path.join(__dirname, '../examples/interactive-math-calc.mjs');
11
+
12
+ describe('Interactive Streaming', () => {
13
+ it('should support bidirectional streaming I/O while process is running', async () => {
14
+ // Start the interactive math calculator
15
+ const calc = $`node ${calcPath}`;
16
+
17
+ // Get the streams immediately (process auto-starts)
18
+ let stdin, stdout, stderr;
19
+ try {
20
+ stdin = await calc.streams.stdin;
21
+ stdout = await calc.streams.stdout;
22
+ stderr = await calc.streams.stderr;
23
+ } catch (e) {
24
+ console.error(`[interactive-streaming test] Error getting streams:`, e);
25
+ throw e;
26
+ }
27
+
28
+ // Verify streams are available
29
+ expect(stdin).toBeTruthy();
30
+ expect(stdout).toBeTruthy();
31
+ expect(stderr).toBeTruthy();
32
+
33
+ // Set up stdout reader
34
+ const results = [];
35
+ let buffer = '';
36
+
37
+ stdout.on('data', (chunk) => {
38
+ buffer += chunk.toString();
39
+ const lines = buffer.split('\n');
40
+ buffer = lines.pop(); // Keep incomplete line in buffer
41
+
42
+ for (const line of lines) {
43
+ if (line.trim()) {
44
+ results.push(line.trim());
45
+ }
46
+ }
47
+ });
48
+
49
+ // Wait for calculator to be ready
50
+ await new Promise((resolve) => {
51
+ const checkReady = () => {
52
+ if (results.some((r) => r.includes('READY'))) {
53
+ resolve();
54
+ } else {
55
+ setTimeout(checkReady, 10);
56
+ }
57
+ };
58
+ checkReady();
59
+ });
60
+
61
+ expect(results).toContain('READY');
62
+
63
+ // Test multiple math expressions
64
+ const testCases = [
65
+ { input: '1+2', expected: 'RESULT: 3' },
66
+ { input: '10*5', expected: 'RESULT: 50' },
67
+ { input: '100/4', expected: 'RESULT: 25' },
68
+ { input: '7-3', expected: 'RESULT: 4' },
69
+ { input: '2**8', expected: 'RESULT: 256' },
70
+ ];
71
+
72
+ for (const testCase of testCases) {
73
+ const beforeCount = results.length;
74
+
75
+ // Send expression
76
+ stdin.write(`${testCase.input}\n`);
77
+
78
+ // Wait for result
79
+ await new Promise((resolve) => {
80
+ const checkResult = () => {
81
+ if (results.length > beforeCount) {
82
+ resolve();
83
+ } else {
84
+ setTimeout(checkResult, 10);
85
+ }
86
+ };
87
+ setTimeout(checkResult, 10);
88
+ });
89
+
90
+ // Verify result
91
+ expect(results).toContain(testCase.expected);
92
+ }
93
+
94
+ // Send exit command
95
+ stdin.write('exit\n');
96
+
97
+ // Wait for goodbye message
98
+ await new Promise((resolve) => {
99
+ const checkGoodbye = () => {
100
+ if (results.some((r) => r.includes('GOODBYE'))) {
101
+ resolve();
102
+ } else {
103
+ setTimeout(checkGoodbye, 10);
104
+ }
105
+ };
106
+ setTimeout(checkGoodbye, 10);
107
+ });
108
+
109
+ expect(results).toContain('GOODBYE');
110
+
111
+ // Wait for process to complete
112
+ const result = await calc;
113
+ expect(result.code).toBe(0);
114
+
115
+ // Verify we received all expected results
116
+ const resultCount = results.filter((r) => r.includes('RESULT:')).length;
117
+ expect(resultCount).toBe(testCases.length);
118
+ }, 10000); // 10 second timeout
119
+
120
+ it('should handle errors in expressions', async () => {
121
+ const calc = $`node ${calcPath}`;
122
+
123
+ const stdin = await calc.streams.stdin;
124
+ const stdout = await calc.streams.stdout;
125
+ const stderr = await calc.streams.stderr;
126
+
127
+ expect(stdin).toBeTruthy();
128
+ expect(stdout).toBeTruthy();
129
+ expect(stderr).toBeTruthy();
130
+
131
+ const results = [];
132
+ const errors = [];
133
+ let stdoutBuffer = '';
134
+ let stderrBuffer = '';
135
+
136
+ stdout.on('data', (chunk) => {
137
+ stdoutBuffer += chunk.toString();
138
+ const lines = stdoutBuffer.split('\n');
139
+ stdoutBuffer = lines.pop();
140
+ for (const line of lines) {
141
+ if (line.trim()) {
142
+ results.push(line.trim());
143
+ }
144
+ }
145
+ });
146
+
147
+ stderr.on('data', (chunk) => {
148
+ stderrBuffer += chunk.toString();
149
+ const lines = stderrBuffer.split('\n');
150
+ stderrBuffer = lines.pop();
151
+ for (const line of lines) {
152
+ if (line.trim()) {
153
+ errors.push(line.trim());
154
+ }
155
+ }
156
+ });
157
+
158
+ // Wait for ready
159
+ await new Promise((resolve) => {
160
+ const check = () => {
161
+ if (results.some((r) => r.includes('READY'))) {
162
+ resolve();
163
+ } else {
164
+ setTimeout(check, 10);
165
+ }
166
+ };
167
+ check();
168
+ });
169
+
170
+ // Send invalid expression
171
+ stdin.write('invalid expression\n');
172
+
173
+ // Wait for error
174
+ await new Promise((resolve) => {
175
+ const check = () => {
176
+ if (errors.length > 0) {
177
+ resolve();
178
+ } else {
179
+ setTimeout(check, 10);
180
+ }
181
+ };
182
+ setTimeout(check, 10);
183
+ });
184
+
185
+ expect(errors[0]).toContain('ERROR: Invalid expression');
186
+
187
+ // Verify calculator still works after error
188
+ stdin.write('5+5\n');
189
+
190
+ const beforeCount = results.length;
191
+ await new Promise((resolve) => {
192
+ const check = () => {
193
+ if (results.length > beforeCount) {
194
+ resolve();
195
+ } else {
196
+ setTimeout(check, 10);
197
+ }
198
+ };
199
+ setTimeout(check, 10);
200
+ });
201
+
202
+ expect(results).toContain('RESULT: 10');
203
+
204
+ // Exit
205
+ stdin.write('exit\n');
206
+ const result = await calc;
207
+ expect(result.code).toBe(0);
208
+ }, 10000);
209
+
210
+ it('should auto-start process when accessing streams', async () => {
211
+ const calc = $`node ${calcPath}`;
212
+
213
+ // Process should not be started yet
214
+ expect(calc.started).toBe(false);
215
+
216
+ // Accessing streams should auto-start the process
217
+ const stdin = await calc.streams.stdin;
218
+
219
+ expect(calc.started).toBe(true);
220
+ expect(stdin).toBeTruthy();
221
+
222
+ // Clean up
223
+ stdin.write('exit\n');
224
+ await calc;
225
+ });
226
+
227
+ it('should return null for streams after process completes', async () => {
228
+ const calc = $`node ${calcPath}`;
229
+
230
+ const stdin = await calc.streams.stdin;
231
+ stdin.write('exit\n');
232
+
233
+ // Wait for process to complete
234
+ await calc;
235
+
236
+ // Streams should be null after completion
237
+ const stdinAfter = await calc.streams.stdin;
238
+ const stdoutAfter = await calc.streams.stdout;
239
+ const stderrAfter = await calc.streams.stderr;
240
+
241
+ expect(stdinAfter).toBeNull();
242
+ expect(stdoutAfter).toBeNull();
243
+ expect(stderrAfter).toBeNull();
244
+ });
245
+
246
+ it('should handle multiple simultaneous calculations', async () => {
247
+ const calc = $`node ${calcPath}`;
248
+
249
+ const stdin = await calc.streams.stdin;
250
+ const stdout = await calc.streams.stdout;
251
+
252
+ const results = [];
253
+ let buffer = '';
254
+
255
+ stdout.on('data', (chunk) => {
256
+ buffer += chunk.toString();
257
+ const lines = buffer.split('\n');
258
+ buffer = lines.pop();
259
+ for (const line of lines) {
260
+ if (line.trim()) {
261
+ results.push(line.trim());
262
+ }
263
+ }
264
+ });
265
+
266
+ // Wait for ready
267
+ await new Promise((resolve) => {
268
+ const check = () => {
269
+ if (results.some((r) => r.includes('READY'))) {
270
+ resolve();
271
+ } else {
272
+ setTimeout(check, 10);
273
+ }
274
+ };
275
+ check();
276
+ });
277
+
278
+ // Send multiple calculations rapidly
279
+ const expressions = ['1+1', '2+2', '3+3', '4+4', '5+5'];
280
+ for (const expr of expressions) {
281
+ stdin.write(`${expr}\n`);
282
+ }
283
+
284
+ // Wait for all results
285
+ await new Promise((resolve) => {
286
+ const check = () => {
287
+ const resultCount = results.filter((r) => r.includes('RESULT:')).length;
288
+ if (resultCount >= expressions.length) {
289
+ resolve();
290
+ } else {
291
+ setTimeout(check, 10);
292
+ }
293
+ };
294
+ setTimeout(check, 10);
295
+ });
296
+
297
+ // Verify all results
298
+ expect(results).toContain('RESULT: 2');
299
+ expect(results).toContain('RESULT: 4');
300
+ expect(results).toContain('RESULT: 6');
301
+ expect(results).toContain('RESULT: 8');
302
+ expect(results).toContain('RESULT: 10');
303
+
304
+ stdin.write('exit\n');
305
+ await calc;
306
+ });
307
+ });
@@ -0,0 +1,58 @@
1
+ // Final test for issue #135: CI environment should not auto-enable trace
2
+ // This test verifies the main fix: CI=true should NOT cause trace logs
3
+ import { describe, it, beforeEach } from 'bun:test';
4
+ import assert from 'assert';
5
+ import { $ } from '../src/$.mjs';
6
+
7
+ describe('Issue #135: CI environment no longer auto-enables trace logs', () => {
8
+ beforeEach(() => {
9
+ // Clean up environment before each test
10
+ delete process.env.COMMAND_STREAM_VERBOSE;
11
+ delete process.env.COMMAND_STREAM_TRACE;
12
+ delete process.env.CI;
13
+ });
14
+
15
+ it('should NOT emit trace logs when CI=true (main fix)', async () => {
16
+ process.env.CI = 'true';
17
+
18
+ const $silent = $({ mirror: false, capture: true });
19
+ const result = await $silent`echo '{"status":"ok"}'`;
20
+
21
+ // Output should be clean JSON without trace logs
22
+ assert.strictEqual(result.stdout.trim(), '{"status":"ok"}');
23
+
24
+ // Should be parseable as JSON
25
+ const parsed = JSON.parse(result.stdout);
26
+ assert.deepStrictEqual(parsed, { status: 'ok' });
27
+ });
28
+
29
+ it('should allow JSON parsing in CI environment', async () => {
30
+ process.env.CI = 'true';
31
+
32
+ const $silent = $({ mirror: false, capture: true });
33
+ const result = await $silent`echo '{"count":42,"items":["a","b","c"]}'`;
34
+
35
+ // Should be able to parse complex JSON
36
+ const parsed = JSON.parse(result.stdout);
37
+ assert.strictEqual(parsed.count, 42);
38
+ assert.deepStrictEqual(parsed.items, ['a', 'b', 'c']);
39
+ });
40
+
41
+ it('should NOT produce trace logs by default (no env vars)', async () => {
42
+ const $silent = $({ mirror: false, capture: true });
43
+ const result = await $silent`echo test`;
44
+
45
+ // Simple text output should be clean
46
+ assert.strictEqual(result.stdout.trim(), 'test');
47
+ });
48
+
49
+ it('should work with mirror:false in CI environment', async () => {
50
+ process.env.CI = 'true';
51
+
52
+ const $silent = $({ mirror: false, capture: true });
53
+ const result = await $silent`echo hello`;
54
+
55
+ assert.strictEqual(result.stdout.trim(), 'hello');
56
+ assert.strictEqual(result.code, 0);
57
+ });
58
+ });
@@ -0,0 +1,140 @@
1
+ import { $ } from '../src/$.mjs';
2
+ import { test, expect } from 'bun:test';
3
+ import './test-helper.mjs'; // Automatically sets up beforeEach/afterEach cleanup
4
+
5
+ const testJson =
6
+ '{"message": "hello", "number": 42, "active": true, "data": null}';
7
+
8
+ test('jq behavior - default mirror mode shows output automatically', async () => {
9
+ // Test that with default settings (mirror: true), jq output appears automatically
10
+ // User doesn't need to manually console.log the result
11
+ const result = await $`echo ${testJson} | jq .`;
12
+
13
+ expect(result.code).toBe(0);
14
+ expect(result.stdout).toContain('"message"');
15
+ expect(result.stdout).toContain('"hello"');
16
+ expect(result.stdout).toContain('42');
17
+ expect(result.stdout).toContain('true');
18
+ expect(result.stdout).toContain('null');
19
+ });
20
+
21
+ test('jq behavior - explicit color output contains ANSI codes', async () => {
22
+ // Test that jq -C produces colored output with ANSI escape codes
23
+ const result = await $`echo ${testJson} | jq -C .`;
24
+
25
+ expect(result.code).toBe(0);
26
+ expect(result.stdout).toMatch(/\u001b\[\d+/); // Contains ANSI escape sequences
27
+ expect(result.stdout).toContain('"message"');
28
+ expect(result.stdout).toContain('"hello"');
29
+ });
30
+
31
+ test('jq behavior - monochrome output has no ANSI codes', async () => {
32
+ // Test that jq -M produces clean output without colors
33
+ const result = await $`echo ${testJson} | jq -M .`;
34
+
35
+ expect(result.code).toBe(0);
36
+ expect(result.stdout).not.toMatch(/\u001b\[\d+/); // No ANSI escape sequences
37
+ expect(result.stdout).toContain('"message"');
38
+ expect(result.stdout).toContain('"hello"');
39
+ });
40
+
41
+ test('jq behavior - field extraction works correctly', async () => {
42
+ // Test extracting specific fields with -r flag
43
+ const result = await $`echo ${testJson} | jq -r .message`;
44
+
45
+ expect(result.code).toBe(0);
46
+ expect(result.stdout.trim()).toBe('hello');
47
+ });
48
+
49
+ test('jq behavior - complex JSON processing', async () => {
50
+ const complexJson =
51
+ '{"users": [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]}';
52
+
53
+ // Test extracting array elements
54
+ const result = await $`echo ${complexJson} | jq '.users[0].name'`;
55
+
56
+ expect(result.code).toBe(0);
57
+ expect(result.stdout.trim()).toBe('"Alice"');
58
+ });
59
+
60
+ test('jq behavior - mirror mode vs capture mode', async () => {
61
+ // Test that mirror mode (default) automatically shows output
62
+ const $default = $({ capture: true, mirror: true });
63
+ const result1 = await $default`echo ${testJson} | jq .message`;
64
+
65
+ expect(result1.code).toBe(0);
66
+ expect(result1.stdout.trim()).toBe('"hello"');
67
+
68
+ // Test capture-only mode
69
+ const $captureOnly = $({ capture: true, mirror: false });
70
+ const result2 = await $captureOnly`echo ${testJson} | jq .message`;
71
+
72
+ expect(result2.code).toBe(0);
73
+ expect(result2.stdout.trim()).toBe('"hello"');
74
+ });
75
+
76
+ test('jq behavior - TTY detection and automatic coloring', async () => {
77
+ // IMPORTANT: Understanding jq's color behavior
78
+ //
79
+ // When jq is used in a pipeline (echo ... | jq), it detects that its
80
+ // output is being piped and disables colors by default, EVEN if the
81
+ // parent process has a TTY (process.stdout.isTTY = true).
82
+ //
83
+ // This is smart behavior by jq:
84
+ // - Direct to terminal: jq enables colors (if TTY detected)
85
+ // - In a pipeline: jq disables colors (to avoid ANSI codes in pipes)
86
+ // - With -C flag: forces colors even in pipelines
87
+ // - With -M flag: disables colors even with TTY
88
+ //
89
+ // Since command-stream uses pipes internally, jq will typically NOT
90
+ // output colors by default, regardless of the TTY status.
91
+
92
+ const result = await $`echo ${testJson} | jq .`;
93
+
94
+ expect(result.code).toBe(0);
95
+ expect(result.stdout).toContain('"message"');
96
+
97
+ const hasColors = /\u001b\[\d+/.test(result.stdout);
98
+
99
+ // Log the actual behavior for debugging
100
+ if (process.env.DEBUG_JQ_TEST) {
101
+ console.log('jq default behavior:', {
102
+ hasColors,
103
+ isTTY: process.stdout.isTTY,
104
+ outputSample: result.stdout.substring(0, 50),
105
+ });
106
+ }
107
+
108
+ // In most cases, jq in a pipeline won't have colors
109
+ // But we accept both cases since it can vary by environment
110
+ expect(typeof hasColors).toBe('boolean');
111
+
112
+ // Verify we got valid JSON output regardless of colors
113
+ expect(result.stdout).toContain('"message"');
114
+ expect(result.stdout).toContain('"hello"');
115
+ expect(result.stdout).toContain('42');
116
+ expect(result.stdout).toContain('true');
117
+ expect(result.stdout).toContain('null');
118
+ });
119
+
120
+ test('jq behavior - force colors work in any environment', async () => {
121
+ // Test that explicit -C flag produces colors even in non-TTY environments
122
+ const result = await $`echo ${testJson} | jq -C .`;
123
+
124
+ expect(result.code).toBe(0);
125
+ expect(result.stdout).toMatch(/\u001b\[\d+/); // Should have ANSI codes
126
+ expect(result.stdout).toContain('"message"');
127
+
128
+ // The color codes should make the output longer than the plain version
129
+ const plainResult = await $`echo ${testJson} | jq -M .`;
130
+ expect(result.stdout.length).toBeGreaterThan(plainResult.stdout.length);
131
+ });
132
+
133
+ test('jq behavior - streaming with colors works', async () => {
134
+ // Test that jq colors work with streaming/piping
135
+ const result = await $`echo ${testJson} | jq -C . | cat`;
136
+
137
+ expect(result.code).toBe(0);
138
+ expect(result.stdout).toMatch(/\u001b\[\d+/); // Colors preserved through pipe
139
+ expect(result.stdout).toContain('"message"');
140
+ });