From 40c13d5f636f5c6beec7509ceeada6f38067cb15 Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 8 Jun 2026 12:49:30 +0000 Subject: [PATCH 1/6] Initial commit with task details Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: https://github.com/link-foundation/command-stream/issues/160 --- .gitkeep | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitkeep diff --git a/.gitkeep b/.gitkeep new file mode 100644 index 0000000..866cee6 --- /dev/null +++ b/.gitkeep @@ -0,0 +1 @@ +# .gitkeep file auto-generated at 2026-06-08T12:49:30.050Z for PR creation at branch issue-160-a2a2313cf693 for issue https://github.com/link-foundation/command-stream/issues/160 \ No newline at end of file From 49864778be0dc248b4b720ee93f413964312e864 Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 8 Jun 2026 13:25:54 +0000 Subject: [PATCH 2/6] chore: separate JavaScript and Rust package roots --- .github/DEPLOYMENT.md | 118 +- .github/workflows/{release.yml => js.yml} | 221 +- .github/workflows/rust.yml | 303 + .husky/pre-commit | 2 +- README.md | 1503 +--- docs/case-studies/issue-160/README.md | 132 + .../issue-160/data/bun-install-refresh.log | 14 + ...en-development-pipeline-template.repo.json | 1 + .../issue-160/data/csharp-template-head.txt | 1 + .../data/current-file-tree-after.txt | 749 ++ .../data/current-file-tree-before.txt | 671 ++ .../issue-160/data/download-jq.log | 5 + .../issue-160/data/issue-160-comments.json | 1 + .../issue-160/data/issue-160.json | 1 + ...en-development-pipeline-template.repo.json | 1 + .../issue-160/data/js-duplication.log | 2 + .../issue-160/data/js-format-check.log | 3 + docs/case-studies/issue-160/data/js-lint.log | 1 + .../issue-160/data/js-template-head.txt | 1 + docs/case-studies/issue-160/data/js-test.log | 6779 +++++++++++++++++ .../data/npm-package-lock-refresh.log | 12 + docs/case-studies/issue-160/data/pr-161.json | 1 + ...en-development-pipeline-template.repo.json | 1 + .../issue-160/data/python-template-head.txt | 1 + .../data/repository-layout-after.log | 12 + .../data/repository-layout-before.log | 64 + ...en-development-pipeline-template.repo.json | 1 + .../issue-160/data/rust-clippy.log | 317 + .../issue-160/data/rust-doc-test.log | 120 + docs/case-studies/issue-160/data/rust-fmt.log | 0 .../issue-160/data/rust-package.log | 54 + .../data/rust-script-publish-crate-test.log | 51 + .../rust-script-version-and-commit-test.log | 197 + .../data/rust-template-created-issue.txt | 1 + .../data/rust-template-existing-issues.json | 1 + .../issue-160/data/rust-template-head.txt | 1 + .../case-studies/issue-160/data/rust-test.log | 631 ++ .../data/shared-markdown-format-check.log | 2 + .../data/shared-markdown-format-write.log | 2 + .../issue-160/data/workflow-yaml-parse.log | 2 + ...evelopment-pipeline-template.file-tree.txt | 42 + .../.github/workflows/docs.yml | 96 + .../.github/workflows/release.yml | 566 ++ .../scripts/bump-version.mjs | 102 + .../scripts/check-file-size.mjs | 97 + .../scripts/check-release-needed.mjs | 338 + .../scripts/check-release-needed.test.mjs | 362 + .../scripts/create-github-release.mjs | 599 ++ .../scripts/create-github-release.test.mjs | 285 + .../scripts/detect-code-changes.mjs | 204 + .../scripts/merge-changesets.mjs | 264 + .../scripts/release-workflow-policy.test.mjs | 91 + .../scripts/validate-changeset.mjs | 268 + .../scripts/version-and-commit.mjs | 412 + .../scripts/version-and-commit.test.mjs | 155 + .../scripts/wait-for-nuget.mjs | 249 + .../scripts/wait-for-nuget.test.mjs | 357 + ...evelopment-pipeline-template.file-tree.txt | 305 + .../actions/publish-dockerhub/action.yml | 58 + .../.github/workflows/example-app.yml | 296 + .../.github/workflows/links.yml | 84 + .../.github/workflows/release.yml | 600 ++ .../scripts/changeset-version.mjs | 75 + .../scripts/check-changesets.mjs | 67 + .../scripts/check-docker-publish.mjs | 143 + .../scripts/check-file-line-limits.sh | 90 + .../scripts/check-mjs-syntax.sh | 29 + .../scripts/check-release-needed.mjs | 123 + .../scripts/check-version.mjs | 129 + .../scripts/check-web-archive.mjs | 263 + .../scripts/create-github-release.mjs | 296 + .../scripts/create-manual-changeset.mjs | 100 + .../scripts/detect-code-changes.mjs | 155 + .../scripts/format-github-release.mjs | 90 + .../scripts/format-release-notes-helpers.mjs | 26 + .../scripts/format-release-notes.mjs | 230 + .../scripts/instant-version-bump.mjs | 172 + .../scripts/js-paths.mjs | 177 + .../scripts/merge-changesets.mjs | 274 + .../scripts/package-info.mjs | 97 + .../scripts/publish-to-npm.mjs | 325 + .../scripts/setup-npm.mjs | 265 + .../scripts/simulate-fresh-merge.sh | 61 + .../scripts/update-preview-images.mjs | 343 + .../scripts/validate-changeset.mjs | 276 + .../scripts/version-and-commit.mjs | 284 + .../scripts/wait-for-npm.mjs | 191 + .../issue-160/templates/js-ci-files.txt | 28 + ...evelopment-pipeline-template.file-tree.txt | 39 + .../.github/workflows/docs.yml | 89 + .../.github/workflows/release.yml | 361 + .../scripts/bump_version.py | 171 + .../scripts/check_file_size.py | 109 + .../scripts/create_github_release.py | 260 + .../scripts/create_manual_changeset.py | 249 + .../scripts/detect_code_changes.py | 193 + .../scripts/format_release_notes.py | 254 + .../scripts/publish_to_pypi.py | 157 + .../scripts/validate_changeset.py | 161 + .../scripts/version_and_commit.py | 237 + ...evelopment-pipeline-template.file-tree.txt | 135 + .../.github/workflows/release.yml | 710 ++ .../scripts/bump-version.rs | 165 + .../scripts/check-changelog-fragment.rs | 164 + .../scripts/check-crate-size.rs | 262 + .../scripts/check-file-size.rs | 293 + .../scripts/check-release-needed.rs | 395 + .../scripts/check-version-modification.rs | 163 + .../scripts/collect-changelog.rs | 234 + .../scripts/create-changelog-fragment.rs | 119 + .../scripts/create-github-release.rs | 535 ++ .../scripts/detect-code-changes.rs | 186 + .../scripts/get-bump-type.rs | 174 + .../scripts/get-version.rs | 72 + .../scripts/git-config.rs | 62 + .../scripts/publish-crate.rs | 338 + .../scripts/rust-paths.rs | 273 + .../scripts/version-and-commit.rs | 736 ++ .../scripts/wait-for-crate.rs | 178 + .../issue-160/templates/rust-ci-files.txt | 18 + {.changeset => js/.changeset}/README.md | 0 {.changeset => js/.changeset}/config.json | 0 js/.changeset/separate-language-releases.md | 6 + .jscpd.json => js/.jscpd.json | 0 .npmignore => js/.npmignore | 0 .prettierignore => js/.prettierignore | 0 .prettierrc => js/.prettierrc | 0 CHANGELOG.md => js/CHANGELOG.md | 0 js/README.md | 1484 ++++ bun.lock => js/bun.lock | 0 bunfig.toml => js/bunfig.toml | 6 +- deno.json => js/deno.json | 0 eslint.config.js => js/eslint.config.js | 0 package-lock.json => js/package-lock.json | 0 package.json => js/package.json | 38 +- {scripts => js/scripts}/changeset-version.mjs | 7 +- .../scripts}/create-github-release.mjs | 19 +- .../scripts}/create-manual-changeset.mjs | 0 .../scripts}/format-github-release.mjs | 17 +- .../scripts}/format-release-notes.mjs | 2 +- .../scripts}/instant-version-bump.mjs | 3 - {scripts => js/scripts}/merge-changesets.mjs | 0 {scripts => js/scripts}/publish-to-npm.mjs | 0 {scripts => js/scripts}/setup-npm.mjs | 0 .../scripts}/validate-changeset.mjs | 12 +- .../scripts}/version-and-commit.mjs | 4 +- js/tests/publish-to-crates.test.mjs | 72 - js/tests/repository-layout.test.mjs | 67 + js/tests/sync-rust-version.test.mjs | 86 - js/tests/virtual.test.mjs | 2 +- rust/CHANGELOG.md | 142 + rust/Cargo.toml | 2 +- rust/README.md | 62 + ...08_issue_160_separate_language_releases.md | 8 + rust/changelog.d/README.md | 135 + rust/scripts/bump-version.rs | 165 + rust/scripts/check-changelog-fragment.rs | 164 + rust/scripts/check-crate-size.rs | 262 + rust/scripts/check-file-size.rs | 293 + rust/scripts/check-release-needed.rs | 395 + rust/scripts/check-version-modification.rs | 163 + rust/scripts/collect-changelog.rs | 234 + rust/scripts/create-changelog-fragment.rs | 119 + rust/scripts/create-github-release.rs | 535 ++ rust/scripts/detect-code-changes.rs | 186 + rust/scripts/get-bump-type.rs | 174 + rust/scripts/get-version.rs | 72 + rust/scripts/git-config.rs | 62 + rust/scripts/publish-crate.rs | 333 + rust/scripts/rust-paths.rs | 273 + rust/scripts/version-and-commit.rs | 747 ++ rust/scripts/wait-for-crate.rs | 178 + scripts/publish-to-crates.mjs | 259 - scripts/sync-rust-version.mjs | 206 - 174 files changed, 34251 insertions(+), 2354 deletions(-) rename .github/workflows/{release.yml => js.yml} (56%) create mode 100644 .github/workflows/rust.yml create mode 100644 docs/case-studies/issue-160/README.md create mode 100644 docs/case-studies/issue-160/data/bun-install-refresh.log create mode 100644 docs/case-studies/issue-160/data/csharp-ai-driven-development-pipeline-template.repo.json create mode 100644 docs/case-studies/issue-160/data/csharp-template-head.txt create mode 100644 docs/case-studies/issue-160/data/current-file-tree-after.txt create mode 100644 docs/case-studies/issue-160/data/current-file-tree-before.txt create mode 100644 docs/case-studies/issue-160/data/download-jq.log create mode 100644 docs/case-studies/issue-160/data/issue-160-comments.json create mode 100644 docs/case-studies/issue-160/data/issue-160.json create mode 100644 docs/case-studies/issue-160/data/js-ai-driven-development-pipeline-template.repo.json create mode 100644 docs/case-studies/issue-160/data/js-duplication.log create mode 100644 docs/case-studies/issue-160/data/js-format-check.log create mode 100644 docs/case-studies/issue-160/data/js-lint.log create mode 100644 docs/case-studies/issue-160/data/js-template-head.txt create mode 100644 docs/case-studies/issue-160/data/js-test.log create mode 100644 docs/case-studies/issue-160/data/npm-package-lock-refresh.log create mode 100644 docs/case-studies/issue-160/data/pr-161.json create mode 100644 docs/case-studies/issue-160/data/python-ai-driven-development-pipeline-template.repo.json create mode 100644 docs/case-studies/issue-160/data/python-template-head.txt create mode 100644 docs/case-studies/issue-160/data/repository-layout-after.log create mode 100644 docs/case-studies/issue-160/data/repository-layout-before.log create mode 100644 docs/case-studies/issue-160/data/rust-ai-driven-development-pipeline-template.repo.json create mode 100644 docs/case-studies/issue-160/data/rust-clippy.log create mode 100644 docs/case-studies/issue-160/data/rust-doc-test.log create mode 100644 docs/case-studies/issue-160/data/rust-fmt.log create mode 100644 docs/case-studies/issue-160/data/rust-package.log create mode 100644 docs/case-studies/issue-160/data/rust-script-publish-crate-test.log create mode 100644 docs/case-studies/issue-160/data/rust-script-version-and-commit-test.log create mode 100644 docs/case-studies/issue-160/data/rust-template-created-issue.txt create mode 100644 docs/case-studies/issue-160/data/rust-template-existing-issues.json create mode 100644 docs/case-studies/issue-160/data/rust-template-head.txt create mode 100644 docs/case-studies/issue-160/data/rust-test.log create mode 100644 docs/case-studies/issue-160/data/shared-markdown-format-check.log create mode 100644 docs/case-studies/issue-160/data/shared-markdown-format-write.log create mode 100644 docs/case-studies/issue-160/data/workflow-yaml-parse.log create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template.file-tree.txt create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/.github/workflows/docs.yml create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/.github/workflows/release.yml create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/bump-version.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/check-file-size.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/check-release-needed.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/check-release-needed.test.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/create-github-release.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/create-github-release.test.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/detect-code-changes.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/merge-changesets.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/release-workflow-policy.test.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/validate-changeset.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/version-and-commit.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/version-and-commit.test.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/wait-for-nuget.mjs create mode 100644 docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/wait-for-nuget.test.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template.file-tree.txt create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/.github/actions/publish-dockerhub/action.yml create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/.github/workflows/example-app.yml create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/.github/workflows/links.yml create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/.github/workflows/release.yml create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/changeset-version.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-changesets.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-docker-publish.mjs create mode 100755 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-file-line-limits.sh create mode 100755 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-mjs-syntax.sh create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-release-needed.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-version.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-web-archive.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/create-github-release.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/create-manual-changeset.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/detect-code-changes.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/format-github-release.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/format-release-notes-helpers.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/format-release-notes.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/instant-version-bump.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/js-paths.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/merge-changesets.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/package-info.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/publish-to-npm.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/setup-npm.mjs create mode 100755 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/simulate-fresh-merge.sh create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/update-preview-images.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/validate-changeset.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/version-and-commit.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/wait-for-npm.mjs create mode 100644 docs/case-studies/issue-160/templates/js-ci-files.txt create mode 100644 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template.file-tree.txt create mode 100644 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/.github/workflows/docs.yml create mode 100644 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/.github/workflows/release.yml create mode 100755 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/bump_version.py create mode 100755 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/check_file_size.py create mode 100755 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/create_github_release.py create mode 100644 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/create_manual_changeset.py create mode 100755 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/detect_code_changes.py create mode 100644 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/format_release_notes.py create mode 100755 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/publish_to_pypi.py create mode 100644 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/validate_changeset.py create mode 100755 docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/version_and_commit.py create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template.file-tree.txt create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/.github/workflows/release.yml create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/bump-version.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/check-changelog-fragment.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/check-crate-size.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/check-file-size.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/check-release-needed.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/check-version-modification.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/collect-changelog.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/create-changelog-fragment.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/create-github-release.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/detect-code-changes.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/get-bump-type.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/get-version.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/git-config.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/publish-crate.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/rust-paths.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/version-and-commit.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/wait-for-crate.rs create mode 100644 docs/case-studies/issue-160/templates/rust-ci-files.txt rename {.changeset => js/.changeset}/README.md (100%) rename {.changeset => js/.changeset}/config.json (100%) create mode 100644 js/.changeset/separate-language-releases.md rename .jscpd.json => js/.jscpd.json (100%) rename .npmignore => js/.npmignore (100%) rename .prettierignore => js/.prettierignore (100%) rename .prettierrc => js/.prettierrc (100%) rename CHANGELOG.md => js/CHANGELOG.md (100%) create mode 100644 js/README.md rename bun.lock => js/bun.lock (100%) rename bunfig.toml => js/bunfig.toml (69%) rename deno.json => js/deno.json (100%) rename eslint.config.js => js/eslint.config.js (100%) rename package-lock.json => js/package-lock.json (100%) rename package.json => js/package.json (64%) rename {scripts => js/scripts}/changeset-version.mjs (87%) rename {scripts => js/scripts}/create-github-release.mjs (82%) rename {scripts => js/scripts}/create-manual-changeset.mjs (100%) rename {scripts => js/scripts}/format-github-release.mjs (81%) rename {scripts => js/scripts}/format-release-notes.mjs (99%) rename {scripts => js/scripts}/instant-version-bump.mjs (97%) rename {scripts => js/scripts}/merge-changesets.mjs (100%) rename {scripts => js/scripts}/publish-to-npm.mjs (100%) rename {scripts => js/scripts}/setup-npm.mjs (100%) rename {scripts => js/scripts}/validate-changeset.mjs (95%) rename {scripts => js/scripts}/version-and-commit.mjs (98%) delete mode 100644 js/tests/publish-to-crates.test.mjs create mode 100644 js/tests/repository-layout.test.mjs delete mode 100644 js/tests/sync-rust-version.test.mjs create mode 100644 rust/CHANGELOG.md create mode 100644 rust/README.md create mode 100644 rust/changelog.d/20260608_issue_160_separate_language_releases.md create mode 100644 rust/changelog.d/README.md create mode 100644 rust/scripts/bump-version.rs create mode 100644 rust/scripts/check-changelog-fragment.rs create mode 100644 rust/scripts/check-crate-size.rs create mode 100644 rust/scripts/check-file-size.rs create mode 100644 rust/scripts/check-release-needed.rs create mode 100644 rust/scripts/check-version-modification.rs create mode 100644 rust/scripts/collect-changelog.rs create mode 100644 rust/scripts/create-changelog-fragment.rs create mode 100644 rust/scripts/create-github-release.rs create mode 100644 rust/scripts/detect-code-changes.rs create mode 100644 rust/scripts/get-bump-type.rs create mode 100644 rust/scripts/get-version.rs create mode 100644 rust/scripts/git-config.rs create mode 100644 rust/scripts/publish-crate.rs create mode 100644 rust/scripts/rust-paths.rs create mode 100644 rust/scripts/version-and-commit.rs create mode 100644 rust/scripts/wait-for-crate.rs delete mode 100644 scripts/publish-to-crates.mjs delete mode 100644 scripts/sync-rust-version.mjs diff --git a/.github/DEPLOYMENT.md b/.github/DEPLOYMENT.md index 4fffc13..2eff66e 100644 --- a/.github/DEPLOYMENT.md +++ b/.github/DEPLOYMENT.md @@ -1,101 +1,81 @@ # Deployment Setup -This repository releases both packages from `.github/workflows/release.yml`: +This repository has separate release workflows for each language package: -- npm package: `command-stream` -- Rust crate: `command-stream` +- JavaScript npm package: `.github/workflows/js.yml` +- Rust crates.io package: `.github/workflows/rust.yml` -The workflow runs checks on pull requests and publishes on pushes to `main` after -the checks pass. +The workflows run independently on pull requests and pushes that touch their +language folders, workflow files, or shared repository files. -## Required Publishing Setup +## JavaScript Publishing -### npm +The JavaScript package lives in `js/` and is published to npm as +`command-stream`. -npm publishing uses trusted publishing through GitHub Actions OIDC. Do not add -or rotate an `NPM_TOKEN` for this workflow. - -Configure the trusted publisher in npm for: +npm publishing uses trusted publishing through GitHub Actions OIDC. Configure +the trusted publisher in npm for: - Repository: `link-foundation/command-stream` -- Workflow file: `.github/workflows/release.yml` +- Workflow file: `.github/workflows/js.yml` - Environment: none, unless the npm package is configured to require one -The workflow updates npm to a trusted-publishing compatible version before -running `changeset publish`. +The JavaScript workflow uses `id-token: write`, runs npm release scripts from +`js/`, and creates GitHub releases tagged as `js-v`. + +JavaScript PRs that change package code must add exactly one changeset in +`js/.changeset/`. -### crates.io +## Rust Publishing -Rust publishing uses Cargo token authentication. Configure one of these GitHub -Actions secrets at the repository or organization level: +The Rust crate lives in `rust/` and is published to crates.io as +`command-stream`. + +Configure one of these GitHub Actions secrets at the repository or organization +level: - `CARGO_REGISTRY_TOKEN` - Cargo's native environment variable name, preferred - `CARGO_TOKEN` - backwards-compatible fallback used by older organization workflows -The release workflow maps both names: - -```yaml -CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN || secrets.CARGO_TOKEN }} -CARGO_TOKEN: ${{ secrets.CARGO_TOKEN }} -``` - -The crates publisher first checks whether the current `rust/Cargo.toml` version -already exists on crates.io. If it exists, the step reports success and does not -require a token. If it is missing, the step requires a token and runs -`cargo publish`. - -## Pull Request Checks - -Pull requests must add exactly one changeset file in `.changeset/`. CI then runs: +The Rust workflow maps both names and runs Rust release scripts from +`rust/scripts/`. Rust GitHub releases are tagged as `rust-v`. -- changeset validation -- ESLint, Prettier, and duplication checks -- Bun tests on Ubuntu, macOS, and Windows -- Node.js module loading checks on Node 20, 22, and 24 -- Rust formatting, Clippy, tests, doc tests, and `cargo package` +Rust PRs that change crate code must add a changelog fragment in +`rust/changelog.d/`. -Command-stream trace output is off by default in CI. Set the repository variable -`COMMAND_STREAM_TRACE=true` only when a diagnostic rerun needs full tracing. +## Local Release Checks -## Release Flow +JavaScript: -On push to `main`: - -1. CI verifies JavaScript and Rust checks. -2. Changesets bump the npm package version, update changelog files, and sync - `rust/Cargo.toml` plus `rust/Cargo.lock` to the same version. -3. The workflow publishes the npm package with trusted publishing. -4. The workflow publishes `rust/Cargo.toml` to crates.io if that crate version is - not already published. -5. The workflow creates and formats the GitHub release. - -Manual instant releases use the same publishing steps through -`workflow_dispatch`. - -## Manual Publishing +```bash +cd js +bun install +bun run lint +bun run format:check +bun run check:duplication +bun run test +``` -Use manual publishing only for emergency recovery: +Rust: ```bash -# npm, after logging in locally -npm publish --access public - -# crates.io, after logging in locally -cargo publish --manifest-path rust/Cargo.toml +cd rust +cargo fmt --all -- --check +cargo clippy --all-targets --all-features +cargo test --all-features --verbose +cargo test --doc --all-features --verbose +cargo package --allow-dirty ``` -Prefer rerunning the GitHub Actions release workflow so npm, crates.io, and the -GitHub release stay aligned. - ## Troubleshooting -- Missing changeset: add one `.changeset/*.md` file to the PR. +- Missing JavaScript changeset: add one `js/.changeset/*.md` file. +- Missing Rust changelog: add one `rust/changelog.d/*.md` file. - npm trusted publishing failure: verify npm trusted publisher settings match - `.github/workflows/release.yml`. + `.github/workflows/js.yml`. - crates.io authentication failure: verify `CARGO_REGISTRY_TOKEN` or `CARGO_TOKEN` is available to Actions. -- crate version already exists: bump `rust/Cargo.toml` before trying to publish - new Rust crate contents, or rerun the normal release flow so - `scripts/sync-rust-version.mjs` syncs Cargo metadata from `package.json`. -- tests are too noisy: leave `COMMAND_STREAM_TRACE` unset or set it to `false`. +- crate version already exists: rerun the Rust workflow if a previous release + partially completed; the Rust scripts check crates.io and GitHub release + artifacts before deciding whether to bump. diff --git a/.github/workflows/release.yml b/.github/workflows/js.yml similarity index 56% rename from .github/workflows/release.yml rename to .github/workflows/js.yml index 270442c..b6b8aee 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/js.yml @@ -1,14 +1,21 @@ -name: Checks and release +name: JavaScript checks and release on: push: branches: - main + paths: + - 'js/**' + - '.github/workflows/js.yml' + - 'README.md' + - 'LICENSE' pull_request: types: [opened, synchronize, reopened] - # Manual release support - consolidated here to work with npm trusted publishing - # npm only allows ONE workflow file as trusted publisher, so all publishing - # must go through this workflow (release.yml) + paths: + - 'js/**' + - '.github/workflows/js.yml' + - 'README.md' + - 'LICENSE' workflow_dispatch: inputs: release_mode: @@ -36,13 +43,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} -env: - CARGO_TERM_COLOR: always - jobs: - # Changeset check - only runs on PRs changeset-check: - name: Check for Changesets + name: Check for JavaScript changesets runs-on: ubuntu-latest timeout-minutes: 10 if: github.event_name == 'pull_request' @@ -57,29 +60,25 @@ jobs: bun-version: latest - name: Install dependencies + working-directory: js run: bun install - name: Check for changesets + working-directory: js env: - # Pass PR context to the validation script GITHUB_BASE_REF: ${{ github.base_ref }} GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha }} GITHUB_HEAD_SHA: ${{ github.event.pull_request.head.sha }} run: | - # Skip changeset check for automated version PRs if [[ "${{ github.head_ref }}" == "changeset-release/"* ]]; then echo "Skipping changeset check for automated release PR" exit 0 fi - # Run changeset validation script - # This validates that exactly ONE changeset was ADDED by this PR - # Pre-existing changesets from other merged PRs are ignored bun scripts/validate-changeset.mjs - # Linting and formatting - runs after changeset check on PRs, immediately on main lint: - name: Lint and Format Check + name: Lint and format JavaScript runs-on: ubuntu-latest timeout-minutes: 10 needs: [changeset-check] @@ -93,20 +92,23 @@ jobs: bun-version: latest - name: Install dependencies + working-directory: js run: bun install - name: Run ESLint + working-directory: js run: bun run lint - name: Check formatting + working-directory: js run: bun run format:check - name: Check code duplication + working-directory: js run: bun run check:duplication - # Test matrix: Bun on multiple platforms + Node.js compatibility test: - name: Test (${{ matrix.runtime }} on ${{ matrix.os }}) + name: Test JavaScript (${{ matrix.runtime }} on ${{ matrix.os }}) runs-on: ${{ matrix.os }} timeout-minutes: 30 needs: [changeset-check] @@ -114,11 +116,9 @@ jobs: strategy: fail-fast: false matrix: - # Windows tests now enabled - tests with Unix-specific commands are skipped on Windows os: [ubuntu-latest, macos-latest, windows-latest] runtime: [bun] include: - # Also test Node.js compatibility on Ubuntu - os: ubuntu-latest runtime: node node-version: 20 @@ -145,21 +145,20 @@ jobs: - name: Install system dependencies (macOS) if: matrix.os == 'macos-latest' - run: | - brew install jq + run: brew install jq - name: Install system dependencies (Windows) if: matrix.os == 'windows-latest' - run: | - choco install jq -y + run: choco install jq -y - name: Install dependencies (Bun) if: matrix.runtime == 'bun' + working-directory: js run: bun install - name: Run tests (Bun) if: matrix.runtime == 'bun' - run: bun test js/tests/ + run: bun test js/tests/ --timeout 10000 env: COMMAND_STREAM_TRACE: ${{ vars.COMMAND_STREAM_TRACE || 'false' }} @@ -173,65 +172,20 @@ jobs: if: matrix.runtime == 'node' run: | node -e " - try { - const { $ } = require('./js/src/\$.mjs'); - console.log('✅ Module loads successfully in Node.js ${{ matrix.node-version }}'); - } catch (error) { - console.error('❌ Module failed to load:', error.message); - process.exit(1); - } + import('./js/src/\$.mjs') + .then(() => console.log('Module loads successfully in Node.js ${{ matrix.node-version }}')) + .catch((error) => { + console.error('Module failed to load:', error.message); + process.exit(1); + }); " - rust-check: - name: Rust Check - runs-on: ubuntu-latest - timeout-minutes: 30 - needs: [changeset-check] - if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success') - steps: - - uses: actions/checkout@v4 - - - name: Setup Rust - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt, clippy - - - name: Cache cargo registry - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - rust/target - key: ${{ runner.os }}-cargo-${{ hashFiles('rust/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo- - - - name: Check Rust formatting - run: cargo fmt --manifest-path rust/Cargo.toml --all -- --check - - - name: Run Clippy - run: cargo clippy --manifest-path rust/Cargo.toml --all-targets --all-features - - - name: Run Rust tests - run: cargo test --manifest-path rust/Cargo.toml --all-features --verbose - - - name: Run Rust doc tests - run: cargo test --manifest-path rust/Cargo.toml --doc --all-features --verbose - - - name: Check crates.io package - run: cargo package --manifest-path rust/Cargo.toml --allow-dirty - - # Release - only runs on main after tests pass (for push events) release: - name: Release - needs: [lint, test, rust-check] - # Use always() to ensure this job runs even if changeset-check was skipped - # This is needed because lint/test jobs have a transitive dependency on changeset-check - if: always() && github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint.result == 'success' && needs.test.result == 'success' && needs.rust-check.result == 'success' + name: Release JavaScript package + needs: [lint, test] + if: github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint.result == 'success' && needs.test.result == 'success' runs-on: ubuntu-latest timeout-minutes: 30 - # Permissions required for npm OIDC trusted publishing permissions: contents: write pull-requests: write @@ -252,71 +206,59 @@ jobs: with: bun-version: latest - - name: Setup Rust - uses: dtolnay/rust-toolchain@stable - - name: Install dependencies + working-directory: js run: bun install - name: Update npm for OIDC trusted publishing + working-directory: js run: bun scripts/setup-npm.mjs - name: Check for changesets id: check_changesets + working-directory: js run: | - # Count changeset files (excluding README.md and config.json) CHANGESET_COUNT=$(find .changeset -name "*.md" ! -name "README.md" | wc -l) - echo "Found $CHANGESET_COUNT changeset file(s)" + echo "Found $CHANGESET_COUNT JavaScript changeset file(s)" echo "has_changesets=$([[ $CHANGESET_COUNT -gt 0 ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT echo "changeset_count=$CHANGESET_COUNT" >> $GITHUB_OUTPUT - name: Merge multiple changesets - if: steps.check_changesets.outputs.has_changesets == 'true' && steps.check_changesets.outputs.changeset_count > 1 - run: | - echo "Multiple changesets detected, merging..." - bun scripts/merge-changesets.mjs + if: steps.check_changesets.outputs.has_changesets == 'true' && fromJSON(steps.check_changesets.outputs.changeset_count) > 1 + working-directory: js + run: bun scripts/merge-changesets.mjs - - name: Version packages and commit to main + - name: Version package and commit to main if: steps.check_changesets.outputs.has_changesets == 'true' id: version + working-directory: js run: bun scripts/version-and-commit.mjs --mode changeset - name: Publish to npm - # Run if version was committed OR if a previous attempt already committed (for re-runs) if: steps.version.outputs.version_committed == 'true' || steps.version.outputs.already_released == 'true' id: publish + working-directory: js run: bun scripts/publish-to-npm.mjs --should-pull - - name: Publish to crates.io - if: steps.publish.outputs.published == 'true' - id: publish_crate - env: - # Support both CARGO_REGISTRY_TOKEN (cargo's native env var) and CARGO_TOKEN. - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN || secrets.CARGO_TOKEN }} - CARGO_TOKEN: ${{ secrets.CARGO_TOKEN }} - run: bun scripts/publish-to-crates.mjs --working-dir rust - - - name: Create GitHub Release + - name: Create JavaScript GitHub Release if: steps.publish.outputs.published == 'true' + working-directory: js env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bun scripts/create-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" + run: bun scripts/create-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" --tag-prefix js-v - - name: Format GitHub release notes + - name: Format JavaScript GitHub release notes if: steps.publish.outputs.published == 'true' + working-directory: js env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bun scripts/format-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" --commit-sha "${{ github.sha }}" + run: bun scripts/format-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" --commit-sha "${{ github.sha }}" --tag-prefix js-v - # Manual Instant Release - triggered via workflow_dispatch with instant mode - # This job is in release.yml because npm trusted publishing - # only allows one workflow file to be registered as a trusted publisher instant-release: - name: Instant Release + name: Instant JavaScript release if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_mode == 'instant' runs-on: ubuntu-latest timeout-minutes: 30 - # Permissions required for npm OIDC trusted publishing permissions: contents: write pull-requests: write @@ -337,49 +279,41 @@ jobs: with: bun-version: latest - - name: Setup Rust - uses: dtolnay/rust-toolchain@stable - - name: Install dependencies + working-directory: js run: bun install - name: Update npm for OIDC trusted publishing + working-directory: js run: bun scripts/setup-npm.mjs - - name: Version packages and commit to main + - name: Version package and commit to main id: version + working-directory: js run: bun scripts/version-and-commit.mjs --mode instant --bump-type "${{ github.event.inputs.bump_type }}" --description "${{ github.event.inputs.description }}" - name: Publish to npm - # Run if version was committed OR if a previous attempt already committed (for re-runs) if: steps.version.outputs.version_committed == 'true' || steps.version.outputs.already_released == 'true' id: publish + working-directory: js run: bun scripts/publish-to-npm.mjs - - name: Publish to crates.io - if: steps.publish.outputs.published == 'true' - id: publish_crate - env: - # Support both CARGO_REGISTRY_TOKEN (cargo's native env var) and CARGO_TOKEN. - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN || secrets.CARGO_TOKEN }} - CARGO_TOKEN: ${{ secrets.CARGO_TOKEN }} - run: bun scripts/publish-to-crates.mjs --working-dir rust - - - name: Create GitHub Release + - name: Create JavaScript GitHub Release if: steps.publish.outputs.published == 'true' + working-directory: js env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bun scripts/create-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" + run: bun scripts/create-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" --tag-prefix js-v - - name: Format GitHub release notes + - name: Format JavaScript GitHub release notes if: steps.publish.outputs.published == 'true' + working-directory: js env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bun scripts/format-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" --commit-sha "${{ github.sha }}" + run: bun scripts/format-github-release.mjs --release-version "${{ steps.publish.outputs.published_version }}" --repository "${{ github.repository }}" --commit-sha "${{ github.sha }}" --tag-prefix js-v - # Manual Changeset PR - creates a pull request with the changeset for review changeset-pr: - name: Create Changeset PR + name: Create JavaScript changeset PR if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_mode == 'changeset-pr' runs-on: ubuntu-latest timeout-minutes: 10 @@ -397,38 +331,31 @@ jobs: bun-version: latest - name: Install dependencies + working-directory: js run: bun install - name: Create changeset file + working-directory: js run: bun scripts/create-manual-changeset.mjs --bump-type "${{ github.event.inputs.bump_type }}" --description "${{ github.event.inputs.description }}" - name: Format changeset with Prettier - run: | - # Run Prettier on the changeset file to ensure it matches project style - bunx prettier --write ".changeset/*.md" || true - - echo "Formatted changeset files" + working-directory: js + run: bunx prettier --write ".changeset/*.md" - name: Create Pull Request uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GITHUB_TOKEN }} - commit-message: 'chore: add changeset for manual ${{ github.event.inputs.bump_type }} release' - branch: changeset-manual-release-${{ github.run_id }} + commit-message: 'chore: add changeset for manual JavaScript ${{ github.event.inputs.bump_type }} release' + branch: changeset-js-manual-release-${{ github.run_id }} delete-branch: true - title: 'chore: manual ${{ github.event.inputs.bump_type }} release' + title: 'chore: manual JavaScript ${{ github.event.inputs.bump_type }} release' body: | - ## Manual Release Request + ## Manual JavaScript Release Request - This PR was created by a manual workflow trigger to prepare a **${{ github.event.inputs.bump_type }}** release. + This PR was created by a manual workflow trigger to prepare a **${{ github.event.inputs.bump_type }}** npm release. ### Release Details - - **Type:** ${{ github.event.inputs.bump_type }} - - **Description:** ${{ github.event.inputs.description || 'Manual release' }} - - **Triggered by:** @${{ github.actor }} - - ### Next Steps - 1. Review the changeset in this PR - 2. Merge this PR to main - 3. The automated release workflow will create a version PR - 4. Merge the version PR to publish to npm and create a GitHub release + - Type: ${{ github.event.inputs.bump_type }} + - Description: ${{ github.event.inputs.description || 'Manual JavaScript release' }} + - Triggered by: @${{ github.actor }} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..b2ceafe --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,303 @@ +name: Rust checks and release + +on: + push: + branches: + - main + paths: + - 'rust/**' + - '.github/workflows/rust.yml' + - 'README.md' + - 'LICENSE' + pull_request: + types: [opened, synchronize, reopened] + paths: + - 'rust/**' + - '.github/workflows/rust.yml' + - 'README.md' + - 'LICENSE' + workflow_dispatch: + inputs: + release_mode: + description: 'Manual release mode' + required: true + type: choice + default: 'instant' + options: + - instant + - changelog-pr + bump_type: + description: 'Version bump type' + required: true + type: choice + options: + - patch + - minor + - major + description: + description: 'Release description (optional)' + required: false + type: string + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +env: + CARGO_TERM_COLOR: always + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN || secrets.CARGO_TOKEN }} + CARGO_TOKEN: ${{ secrets.CARGO_TOKEN }} + +jobs: + changelog: + name: Rust changelog fragment check + runs-on: ubuntu-latest + timeout-minutes: 10 + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install rust-script + run: cargo install rust-script + + - name: Check for changelog fragments + env: + GITHUB_BASE_REF: ${{ github.base_ref }} + run: rust-script rust/scripts/check-changelog-fragment.rs + + lint: + name: Lint and format Rust + runs-on: ubuntu-latest + timeout-minutes: 10 + needs: [changelog] + if: always() && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || needs.changelog.result == 'success') + steps: + - uses: actions/checkout@v4 + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + rust/target + key: ${{ runner.os }}-cargo-${{ hashFiles('rust/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Check formatting + working-directory: rust + run: cargo fmt --all -- --check + + - name: Run Clippy + working-directory: rust + run: cargo clippy --all-targets --all-features + + test: + name: Test Rust (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + needs: [changelog] + if: always() && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || needs.changelog.result == 'success') + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + steps: + - uses: actions/checkout@v4 + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + rust/target + key: ${{ runner.os }}-cargo-${{ hashFiles('rust/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Run tests + working-directory: rust + run: cargo test --all-features --verbose + + - name: Run doc tests + working-directory: rust + run: cargo test --doc --all-features --verbose + + build: + name: Build Rust package + runs-on: ubuntu-latest + timeout-minutes: 10 + needs: [lint, test] + if: always() && !cancelled() && needs.lint.result == 'success' && needs.test.result == 'success' + steps: + - uses: actions/checkout@v4 + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + rust/target + key: ${{ runner.os }}-cargo-build-${{ hashFiles('rust/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-build- + + - name: Build release + working-directory: rust + run: cargo build --release --verbose + + - name: Check package + working-directory: rust + run: cargo package --allow-dirty + + release: + name: Release Rust crate + needs: [lint, test, build] + if: github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint.result == 'success' && needs.test.result == 'success' && needs.build.result == 'success' + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install rust-script + run: cargo install rust-script + + - name: Determine bump type + id: bump + run: rust-script rust/scripts/get-bump-type.rs + + - name: Check whether Rust release is needed + id: release_needed + env: + HAS_FRAGMENTS: ${{ steps.bump.outputs.has_fragments }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + run: rust-script rust/scripts/check-release-needed.rs --tag-prefix rust-v + + - name: Version Rust crate and commit to main + if: steps.release_needed.outputs.should_release == 'true' + id: version + run: rust-script rust/scripts/version-and-commit.rs --bump-type "${{ steps.bump.outputs.bump_type }}" --tag-prefix rust-v --release-label Rust + + - name: Read Rust release version + if: steps.release_needed.outputs.should_release == 'true' + id: current_version + run: rust-script rust/scripts/get-version.rs + + - name: Publish to crates.io + if: steps.version.outputs.version_committed == 'true' || steps.release_needed.outputs.skip_bump == 'true' + id: publish_crate + run: rust-script rust/scripts/publish-crate.rs + + - name: Create Rust GitHub Release + if: steps.publish_crate.outputs.publish_result == 'success' || steps.publish_crate.outputs.publish_result == 'already_exists' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: rust-script rust/scripts/create-github-release.rs --release-version "${{ steps.version.outputs.new_version || steps.current_version.outputs.version }}" --repository "${{ github.repository }}" --tag-prefix rust-v --language Rust --release-label Rust + + - name: Wait for crate availability + if: steps.publish_crate.outputs.publish_result == 'success' + run: rust-script rust/scripts/wait-for-crate.rs --version "${{ steps.version.outputs.new_version || steps.current_version.outputs.version }}" + + instant-release: + name: Instant Rust release + if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_mode == 'instant' + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install rust-script + run: cargo install rust-script + + - name: Version Rust crate and commit to main + id: version + run: rust-script rust/scripts/version-and-commit.rs --bump-type "${{ github.event.inputs.bump_type }}" --description "${{ github.event.inputs.description }}" --tag-prefix rust-v --release-label Rust + + - name: Publish to crates.io + if: steps.version.outputs.version_committed == 'true' + id: publish_crate + run: rust-script rust/scripts/publish-crate.rs + + - name: Create Rust GitHub Release + if: steps.publish_crate.outputs.publish_result == 'success' || steps.publish_crate.outputs.publish_result == 'already_exists' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: rust-script rust/scripts/create-github-release.rs --release-version "${{ steps.version.outputs.new_version }}" --repository "${{ github.repository }}" --tag-prefix rust-v --language Rust --release-label Rust + + - name: Wait for crate availability + if: steps.publish_crate.outputs.publish_result == 'success' + run: rust-script rust/scripts/wait-for-crate.rs --version "${{ steps.version.outputs.new_version }}" + + changelog-pr: + name: Create Rust changelog PR + if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_mode == 'changelog-pr' + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install rust-script + run: cargo install rust-script + + - name: Create changelog fragment + run: rust-script rust/scripts/create-changelog-fragment.rs --bump-type "${{ github.event.inputs.bump_type }}" --description "${{ github.event.inputs.description }}" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: 'chore: add changelog fragment for manual Rust ${{ github.event.inputs.bump_type }} release' + branch: changelog-rust-manual-release-${{ github.run_id }} + delete-branch: true + title: 'chore: manual Rust ${{ github.event.inputs.bump_type }} release' + body: | + ## Manual Rust Release Request + + This PR was created by a manual workflow trigger to prepare a **${{ github.event.inputs.bump_type }}** crates.io release. + + ### Release Details + - Type: ${{ github.event.inputs.bump_type }} + - Description: ${{ github.event.inputs.description || 'Manual Rust release' }} + - Triggered by: @${{ github.actor }} diff --git a/.husky/pre-commit b/.husky/pre-commit index 2312dc5..28dc8b3 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1 @@ -npx lint-staged +cd js && npx lint-staged diff --git a/README.md b/README.md index c8b7eb0..9136f22 100644 --- a/README.md +++ b/README.md @@ -1,1484 +1,59 @@ -[![npm](https://img.shields.io/npm/v/command-stream.svg)](https://npmjs.com/command-stream) -[![crates.io](https://img.shields.io/crates/v/command-stream.svg)](https://crates.io/crates/command-stream) -[![License](https://img.shields.io/badge/license-Unlicense-blue.svg)](https://github.com/link-foundation/command-stream/blob/main/LICENSE) -[![GitHub stars](https://img.shields.io/github/stars/link-foundation/command-stream?style=social)](https://github.com/link-foundation/command-stream/stargazers) - -[![Open in Gitpod](https://img.shields.io/badge/Gitpod-ready--to--code-f29718?logo=gitpod)](https://gitpod.io/#https://github.com/link-foundation/command-stream) -[![Open in GitHub Codespaces](https://img.shields.io/badge/GitHub%20Codespaces-Open-181717?logo=github)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=link-foundation/command-stream) - -# [command-$tream](https://github.com/link-foundation/command-stream) - -$treamable commands executor - -A modern $ shell utility library with streaming, async iteration, and EventEmitter support, optimized for Bun runtime. - -ray-so-export - -## Features - -- 🐚 **Shell-like by Default**: Commands behave exactly like running in terminal (stdout→stdout, stderr→stderr, stdin→stdin) -- 🎛️ **Fully Controllable**: Override default behavior with options (`mirror`, `capture`, `stdin`) -- 🚀 **Multiple Usage Patterns**: Classic await, async iteration, EventEmitter, .pipe() method, and mixed patterns -- 📡 **Real-time Streaming**: Process command output as it arrives, not after completion -- 🔄 **Bun Optimized**: Designed for Bun runtime with Node.js compatibility -- ⚡ **Performance**: Memory-efficient streaming prevents large buffer accumulation -- 🎯 **Backward Compatible**: Existing `await $` syntax continues to work + Bun.$ `.text()` method -- 🛡️ **Type Safe**: Full TypeScript support (coming soon) -- 🔧 **Built-in Commands**: 18 essential commands work identically across platforms - -## Comparison with Other Libraries - -| Feature | [**command-stream**](https://github.com/link-foundation/command-stream) | [**execa**](https://github.com/sindresorhus/execa) | [**cross-spawn**](https://github.com/moxystudio/node-cross-spawn) | [**Bun.$**](https://github.com/oven-sh/bun) | [**ShellJS**](https://github.com/shelljs/shelljs) | [**zx**](https://github.com/google/zx) | -| ------------------------------ | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -| **📦 NPM Package** | [![npm](https://img.shields.io/npm/v/command-stream.svg)](https://www.npmjs.com/package/command-stream) | [![npm](https://img.shields.io/npm/v/execa.svg)](https://www.npmjs.com/package/execa) | [![npm](https://img.shields.io/npm/v/cross-spawn.svg)](https://www.npmjs.com/package/cross-spawn) | N/A (Built-in) | [![npm](https://img.shields.io/npm/v/shelljs.svg)](https://www.npmjs.com/package/shelljs) | [![npm](https://img.shields.io/npm/v/zx.svg)](https://www.npmjs.com/package/zx) | -| **⭐ GitHub Stars** | [**⭐ 2** (Please ⭐ us!)](https://github.com/link-foundation/command-stream) | [⭐ 7,264](https://github.com/sindresorhus/execa) | [⭐ 1,149](https://github.com/moxystudio/node-cross-spawn) | [⭐ 80,169](https://github.com/oven-sh/bun) (Full Runtime) | [⭐ 14,375](https://github.com/shelljs/shelljs) | [⭐ 44,569](https://github.com/google/zx) | -| **📊 Monthly Downloads** | **893** (New project!) | **381M** | **409M** | N/A (Built-in) | **35M** | **4.2M** | -| **📈 Total Downloads** | **Growing** | **6B+** | **5.4B** | N/A (Built-in) | **596M** | **37M** | -| **Runtime Support** | ✅ Bun + Node.js | ✅ Node.js | ✅ Node.js | 🟡 Bun only | ✅ Node.js | ✅ Node.js | -| **Template Literals** | ✅ `` $`cmd` `` | ✅ `` $`cmd` `` | ❌ Function calls | ✅ `` $`cmd` `` | ❌ Function calls | ✅ `` $`cmd` `` | -| **Real-time Streaming** | ✅ Live output | 🟡 Limited | ❌ Buffer only | ❌ Buffer only | ❌ Buffer only | ❌ Buffer only | -| **Synchronous Execution** | ✅ `.sync()` with events | ✅ `execaSync` | ✅ `spawnSync` | ❌ No | ✅ Sync by default | ❌ No | -| **Async Iteration** | ✅ `for await (chunk of $.stream())` | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No | -| **EventEmitter Pattern** | ✅ `.on('data', ...)` | 🟡 Limited events | 🟡 Child process events | ❌ No | ❌ No | ❌ No | -| **Mixed Patterns** | ✅ Events + await/sync | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No | -| **Bun.$ Compatibility** | ✅ `.text()` method support | ❌ No | ❌ No | ✅ Native API | ❌ No | ❌ No | -| **Shell Injection Protection** | ✅ Smart auto-quoting | ✅ Safe by default | ✅ Safe by default | ✅ Built-in | 🟡 Manual escaping | ✅ Safe by default | -| **Cross-platform** | ✅ macOS/Linux/Windows | ✅ Yes | ✅ **Specialized** cross-platform | ✅ Yes | ✅ Yes | ✅ Yes | -| **Performance** | ⚡ Fast (Bun optimized) | 🐌 Moderate | ⚡ Fast | ⚡ Very fast | 🐌 Moderate | 🐌 Slow | -| **Memory Efficiency** | ✅ Streaming prevents buildup | 🟡 Buffers in memory | 🟡 Buffers in memory | 🟡 Buffers in memory | 🟡 Buffers in memory | 🟡 Buffers in memory | -| **Error Handling** | ✅ Configurable (`set -e`/`set +e`, non-zero OK by default) | ✅ Throws on error | ❌ Basic (exit codes) | ✅ Throws on error | ✅ Configurable | ✅ Throws on error | -| **Shell Settings** | ✅ `set -e`/`set +e` equivalent | ❌ No | ❌ No | ❌ No | 🟡 Limited (`set()`) | ❌ No | -| **Stdout Support** | ✅ Real-time streaming + events | ✅ Node.js streams + interleaved | ✅ Inherited/buffered | ✅ Shell redirection + buffered | ✅ Direct output | ✅ Readable streams + `.pipe.stdout` | -| **Stderr Support** | ✅ Real-time streaming + events | ✅ Streams + interleaved output | ✅ Inherited/buffered | ✅ Redirection + `.quiet()` access | ✅ Error output | ✅ Readable streams + `.pipe.stderr` | -| **Stdin Support** | ✅ string/Buffer/inherit/ignore | ✅ Input/output streams | ✅ Full stdio support | ✅ Pipe operations | 🟡 Basic | ✅ Basic stdin | -| **Built-in Commands** | ✅ **18 commands**: cat, ls, mkdir, rm, mv, cp, touch, basename, dirname, seq, yes + all Bun.$ commands | ❌ Uses system | ❌ Uses system | ✅ echo, cd, etc. | ✅ **20+ commands**: cat, ls, mkdir, rm, mv, cp, etc. | ❌ Uses system | -| **Virtual Commands Engine** | ✅ **Revolutionary**: Register JavaScript functions as shell commands with full pipeline support | ❌ No custom commands | ❌ No custom commands | ❌ No extensibility | ❌ No custom commands | ❌ No custom commands | -| **Pipeline/Piping Support** | ✅ **Advanced**: System + Built-ins + Virtual + Mixed + `.pipe()` method | ✅ Programmatic `.pipe()` + multi-destination | ❌ No piping | ✅ Standard shell piping | ✅ Shell piping + `.to()` method | ✅ Shell piping + `.pipe()` method | -| **Bundle Size** | 📦 **~20KB gzipped** | 📦 ~400KB+ (packagephobia) | 📦 ~2KB gzipped | 🎯 0KB (built-in) | 📦 ~15KB gzipped | 📦 ~50KB+ (estimated) | -| **Signal Handling** | ✅ **Advanced SIGINT/SIGTERM forwarding** with cleanup | 🟡 Basic | ✅ **Excellent** cross-platform | 🟡 Basic | 🟡 Basic | 🟡 Basic | -| **Process Management** | ✅ **Robust child process lifecycle** with proper termination | ✅ Good | ✅ **Excellent** spawn wrapper | ❌ Basic | 🟡 Limited | 🟡 Limited | -| **Debug Tracing** | ✅ **Comprehensive VERBOSE logging** for CI/debugging | 🟡 Limited | ❌ No | ❌ No | 🟡 Basic | ❌ No | -| **Test Coverage** | ✅ **518+ tests, 1165+ assertions** | ✅ Excellent | ✅ Good | 🟡 Good coverage | ✅ Good | 🟡 Good | -| **CI Reliability** | ✅ **Platform-specific handling** (macOS/Ubuntu) | ✅ Good | ✅ **Excellent** | 🟡 Basic | ✅ Good | 🟡 Basic | -| **Documentation** | ✅ **Comprehensive examples + guides** | ✅ Excellent | 🟡 Basic | ✅ Good | ✅ Good | 🟡 Limited | -| **TypeScript** | 🔄 Coming soon | ✅ Full support | ✅ Built-in | ✅ Built-in | 🟡 Community types | ✅ Full support | -| **License** | ✅ **Unlicense (Public Domain)** | 🟡 MIT | 🟡 MIT | 🟡 MIT (+ LGPL dependencies) | 🟡 BSD-3-Clause | 🟡 Apache 2.0 | - -**📊 Popularity & Adoption:** - -- **⭐ GitHub Stars:** [Bun: 80,169](https://github.com/oven-sh/bun) • [zx: 44,569](https://github.com/google/zx) • [ShellJS: 14,375](https://github.com/shelljs/shelljs) • [execa: 7,264](https://github.com/sindresorhus/execa) • [cross-spawn: 1,149](https://github.com/moxystudio/node-cross-spawn) • [**command-stream: 2 ⭐ us!**](https://github.com/link-foundation/command-stream) -- **📈 Total Downloads:** [execa: 6B+](https://www.npmjs.com/package/execa) • [cross-spawn: 5.4B](https://www.npmjs.com/package/cross-spawn) • [ShellJS: 596M](https://www.npmjs.com/package/shelljs) • [zx: 37M](https://www.npmjs.com/package/zx) • [command-stream: Growing](https://www.npmjs.com/package/command-stream) -- **📊 Monthly Downloads:** [cross-spawn: 409M](https://www.npmjs.com/package/cross-spawn) • [execa: 381M](https://www.npmjs.com/package/execa) • [ShellJS: 35M](https://www.npmjs.com/package/shelljs) • [zx: 4.2M](https://www.npmjs.com/package/zx) • [command-stream: 893 (growing!)](https://www.npmjs.com/package/command-stream) - -**⭐ Help Us Grow!** If command-stream's **revolutionary virtual commands** and **advanced streaming capabilities** help your project, [**please star us on GitHub**](https://github.com/link-foundation/command-stream) to help the project grow! - -### Why Choose command-stream? - -- **🆓 Truly Free**: **Unlicense (Public Domain)** - No restrictions, no attribution required, use however you want -- **🚀 Revolutionary Virtual Commands**: **World's first** fully customizable virtual commands engine - register JavaScript functions as shell commands! -- **🔗 Advanced Pipeline System**: **Only library** where virtual commands work seamlessly in pipelines with built-ins and system commands -- **🔧 Built-in Commands**: **18 essential commands** work identically across all platforms - no system dependencies! -- **📡 Real-time Processing**: Only library with true streaming and async iteration -- **🔄 Flexible Patterns**: Multiple usage patterns (await, events, iteration, mixed) -- **🐚 Shell Replacement**: Dynamic error handling with `set -e`/`set +e` equivalents for .sh file replacement -- **⚡ Bun Optimized**: Designed for Bun with Node.js fallback compatibility -- **💾 Memory Efficient**: Streaming prevents large buffer accumulation -- **🛡️ Production Ready**: **518+ tests, 1165+ assertions** with comprehensive coverage including CI reliability -- **🎯 Advanced Signal Handling**: Robust SIGINT/SIGTERM forwarding with proper child process cleanup -- **🔍 Debug-Friendly**: Comprehensive VERBOSE tracing for CI debugging and troubleshooting - -## Built-in Commands (🚀 NEW!) - -command-stream now includes **18 built-in commands** that work identically to their bash/sh counterparts, providing true cross-platform shell scripting without system dependencies: - -### 📁 **File System Commands** - -- `cat` - Read and display file contents -- `ls` - List directory contents (supports `-l`, `-a`, `-A`) -- `mkdir` - Create directories (supports `-p` recursive) -- `rm` - Remove files/directories (supports `-r`, `-f`) -- `mv` - Move/rename files and directories -- `cp` - Copy files/directories (supports `-r` recursive) -- `touch` - Create files or update timestamps - -### 🔧 **Utility Commands** - -- `basename` - Extract filename from path -- `dirname` - Extract directory from path -- `seq` - Generate number sequences -- `yes` - Output string repeatedly (streaming) - -### ⚡ **System Commands** - -- `cd` - Change directory -- `pwd` - Print working directory -- `echo` - Print arguments (supports `-n`) -- `sleep` - Wait for specified time -- `true`/`false` - Success/failure commands -- `which` - Locate commands -- `exit` - Exit with code -- `env` - Print environment variables -- `test` - File condition testing - -### ✨ **Key Advantages** - -- **🌍 Cross-Platform**: Works identically on Windows, macOS, and Linux -- **🚀 Performance**: No system calls - pure JavaScript execution -- **🔄 Pipeline Support**: All commands work in pipelines and virtual command chains -- **⚙️ Option Aware**: Commands respect `cwd`, `env`, and other options -- **🛡️ Safe by Default**: Proper error handling and safety checks (e.g., `rm` requires `-r` for directories) -- **📝 Bash Compatible**: Error messages and behavior match bash/sh exactly - -```javascript -import { $ } from 'command-stream'; - -// All these work without any system dependencies! -await $`mkdir -p project/src`; -await $`touch project/src/index.js`; -await $`echo "console.log('Hello!');" > project/src/index.js`; -await $`ls -la project/src`; -await $`cat project/src/index.js`; -await $`cp -r project project-backup`; -await $`rm -r project-backup`; - -// Mix built-ins with pipelines and virtual commands -await $`seq 1 5 | cat > numbers.txt`; -await $`basename /path/to/file.txt .txt`; // → "file" -``` - -## Installation - -```bash -# Using npm -npm install command-stream - -# Using bun -bun add command-stream -``` - -## Smart Quoting & Security - -Command-stream provides intelligent auto-quoting to protect against shell injection while avoiding unnecessary quotes for safe strings: - -### Smart Quoting Behavior - -```javascript -import { $ } from 'command-stream'; - -// Safe strings are NOT quoted (performance optimization) -await $`echo ${name}`; // name = "hello" → echo hello -await $`${cmd} --version`; // cmd = "/usr/bin/node" → /usr/bin/node --version - -// Dangerous strings are automatically quoted for safety -await $`echo ${userInput}`; // userInput = "test; rm -rf /" → echo 'test; rm -rf /' -await $`echo ${pathWithSpaces}`; // pathWithSpaces = "/my path/file" → echo '/my path/file' - -// Special characters that trigger auto-quoting: -// Spaces, $, ;, |, &, >, <, `, *, ?, [, ], {, }, (, ), !, #, and others - -// User-provided quotes are preserved -const quotedPath = "'/path with spaces/file'"; -await $`cat ${quotedPath}`; // → cat '/path with spaces/file' (no double-quoting!) - -const doubleQuoted = '"/path with spaces/file"'; -await $`cat ${doubleQuoted}`; // → cat '"/path with spaces/file"' (preserves intent) -``` - -### Shell Injection Protection - -All interpolated values are automatically secured: - -```javascript -// ✅ SAFE - All these injection attempts are neutralized -const dangerous = "'; rm -rf /; echo '"; -await $`echo ${dangerous}`; // → echo ''\'' rm -rf /; echo '\''' - -const cmdSubstitution = '$(whoami)'; -await $`echo ${cmdSubstitution}`; // → echo '$(whoami)' (literal text, not executed) - -const varExpansion = '$HOME'; -await $`echo ${varExpansion}`; // → echo '$HOME' (literal text, not expanded) - -// ✅ SAFE - Even complex injection attempts -const complex = '`cat /etc/passwd`'; -await $`echo ${complex}`; // → echo '`cat /etc/passwd`' (literal text) -``` - -### Disabling Auto-Escape (Advanced) - -**⚠️ WARNING: Use with extreme caution! Only use `raw()` with trusted input to prevent shell injection attacks.** - -For advanced use cases where you need to use command strings directly without auto-escaping, use the `raw()` function: - -```javascript -import { $, raw } from 'command-stream'; - -// ⚠️ DANGEROUS - Bypasses all safety checks -const userCommand = 'echo "hello" && ls -la'; -await $`${raw(userCommand)}`; // → Executes: echo "hello" && ls -la - -// ✅ Safe use case: Trusted command templates -const trustedCommand = 'git log --oneline --graph --all'; -await $`${raw(trustedCommand)}`; - -// ✅ Combining raw with safe interpolation -const branch = 'main'; // User input - will be auto-quoted -await $`${raw('git log --oneline')} ${branch}`; -// → git log --oneline 'main' (raw part unescaped, branch safely quoted) - -// 🎯 Use case: Pre-built command strings from configuration -const config = { - backupCommand: 'tar -czf backup.tar.gz --exclude="*.log" .', - cleanCommand: 'find . -name "*.tmp" -delete', -}; -await $`${raw(config.backupCommand)}`; - -// ⚠️ NEVER use raw() with user input -const userInput = req.body.command; // ❌ DANGEROUS! -await $`${raw(userInput)}`; // ❌ Shell injection vulnerability! - -// ✅ Instead, use normal interpolation for user input -await $`echo ${userInput}`; // ✅ Safe - auto-escaped -``` - -**When to use `raw()`:** - -- ✅ Trusted command templates from your codebase -- ✅ Configuration files you control -- ✅ Hardcoded command strings -- ✅ Complex shell operators that need to be preserved - -**When NOT to use `raw()`:** - -- ❌ User input (form fields, API parameters, CLI arguments) -- ❌ External data (database, API responses, files) -- ❌ Any untrusted source -- ❌ When you're unsure - use normal interpolation instead - -## Usage Patterns - -### Classic Await (Backward Compatible) - -```javascript -import { $ } from 'command-stream'; - -const result = await $`ls -la`; -console.log(result.stdout); -console.log(result.code); // exit code -``` - -### Custom Options with $({ options }) Syntax (NEW!) - -```javascript -import { $ } from 'command-stream'; - -// Create a $ with custom options -const $silent = $({ mirror: false, capture: true }); -const result = await $silent`echo "quiet operation"`; - -// Options for stdin handling -const $withInput = $({ stdin: 'input data\n' }); -await $withInput`cat`; // Pipes the input to cat - -// Custom environment variables -const $withEnv = $({ env: { ...process.env, MY_VAR: 'value' } }); -await $withEnv`printenv MY_VAR`; // Prints: value - -// Custom working directory -const $inTmp = $({ cwd: '/tmp' }); -await $inTmp`pwd`; // Prints: /tmp - -// Interactive mode for TTY commands (requires TTY environment) -const $interactive = $({ interactive: true }); -await $interactive`vim myfile.txt`; // Full TTY access for editor -await $interactive`less README.md`; // Proper pager interaction - -// Combine multiple options -const $custom = $({ - stdin: 'test data', - mirror: false, - capture: true, - cwd: '/tmp', -}); -await $custom`cat > output.txt`; // Writes to /tmp/output.txt silently - -// Reusable configurations -const $prod = $({ env: { NODE_ENV: 'production' }, capture: true }); -await $prod`npm start`; -await $prod`npm test`; -``` - -### Execution Control (NEW!) - -```javascript -import { $ } from 'command-stream'; - -// Commands don't auto-start when created -const cmd = $`echo "hello"`; - -// Three ways to start execution: - -// 1. Explicit start with options -cmd.start(); // Default async mode -cmd.start({ mode: 'async' }); // Explicitly async -cmd.start({ mode: 'sync' }); // Synchronous execution - -// 2. Convenience methods -cmd.async(); // Same as start({ mode: 'async' }) -cmd.sync(); // Same as start({ mode: 'sync' }) - -// 3. Auto-start by awaiting (always async) -await cmd; // Auto-starts in async mode - -// Event handlers can be attached before starting -const process = $`long-command` - .on('data', (chunk) => console.log('Received:', chunk)) - .on('end', (result) => console.log('Done!')); - -// Start whenever you're ready -process.start(); -``` - -### Synchronous Execution - -```javascript -import { $ } from 'command-stream'; - -// Use .sync() for blocking execution -const result = $`echo "hello"`.sync(); -console.log(result.stdout); // "hello\n" - -// Events still work but are batched after completion -$`echo "world"`.on('end', (result) => console.log('Done:', result)).sync(); -``` - -### Async Iteration (Real-time Streaming) - -```javascript -import { $ } from 'command-stream'; - -for await (const chunk of $`long-running-command`.stream()) { - if (chunk.type === 'stdout') { - console.log('Real-time output:', chunk.data.toString()); - } -} -``` - -### EventEmitter Pattern (Event-driven) - -```javascript -import { $ } from 'command-stream'; - -// Attach event handlers then start execution -$`command` - .on('data', (chunk) => { - if (chunk.type === 'stdout') { - console.log('Stdout:', chunk.data.toString()); - } - }) - .on('stderr', (chunk) => console.log('Stderr:', chunk)) - .on('end', (result) => console.log('Done:', result)) - .on('exit', (code) => console.log('Exit code:', code)) - .start(); // Explicitly start the command - -// Or auto-start by awaiting -const cmd = $`another-command`.on('data', (chunk) => console.log(chunk)); -await cmd; // Auto-starts in async mode -``` - -### Mixed Pattern (Best of Both Worlds) - -```javascript -import { $ } from 'command-stream'; - -// Async mode - events fire in real-time -const process = $`streaming-command`; -process.on('data', (chunk) => { - processRealTimeData(chunk); -}); -const result = await process; -console.log('Final output:', result.stdout); - -// Sync mode - events fire after completion (batched) -const syncCmd = $`another-command`; -syncCmd.on('end', (result) => { - console.log('Completed with:', result.stdout); -}); -const syncResult = syncCmd.sync(); -``` - -### Streaming Interfaces - -Advanced streaming interfaces for fine-grained process control: - -```javascript -import { $ } from 'command-stream'; - -// 🎯 STDIN CONTROL: Send data to interactive commands (real-time) -const grepCmd = $`grep "important"`; -const stdin = await grepCmd.streams.stdin; // Available immediately - -stdin.write('ignore this line\n'); -stdin.write('important message\n'); -stdin.write('skip this too\n'); -stdin.end(); - -const result = await grepCmd; -console.log(result.stdout); // "important message\n" - -// 🔧 BINARY DATA: Access raw buffers (after command finishes) -const cmd = $`echo "Hello World"`; -const buffer = await cmd.buffers.stdout; // Complete snapshot -console.log(buffer.length); // 12 - -// 📝 TEXT DATA: Access as strings (after command finishes) -const textCmd = $`echo "Hello World"`; -const text = await textCmd.strings.stdout; // Complete snapshot -console.log(text.trim()); // "Hello World" - -// ⚡ PROCESS CONTROL: Kill commands that ignore stdin -const pingCmd = $`ping google.com`; - -// Some commands ignore stdin input -const pingStdin = await pingCmd.streams.stdin; -if (pingStdin) { - pingStdin.write('q\n'); // ping ignores this -} - -// Use kill() for forceful termination -setTimeout(() => pingCmd.kill(), 2000); -const pingResult = await pingCmd; -console.log('Ping stopped with code:', pingResult.code); // 143 (SIGTERM) - -// 🔄 MIXED STDOUT/STDERR: Handle both streams (complete snapshots) -const mixedCmd = $`sh -c 'echo "out" && echo "err" >&2'`; -const [stdout, stderr] = await Promise.all([ - mixedCmd.strings.stdout, // Available after finish - mixedCmd.strings.stderr, // Available after finish -]); -console.log('Out:', stdout.trim()); // "out" -console.log('Err:', stderr.trim()); // "err" - -// 🏃‍♂️ AUTO-START: Streams auto-start processes when accessed -const cmd = $`echo "test"`; -console.log('Started?', cmd.started); // false - -const output = await cmd.streams.stdout; // Auto-starts, immediate access -console.log('Started?', cmd.started); // true - -// 🔙 BACKWARD COMPATIBLE: Traditional await still works -const traditional = await $`echo "still works"`; -console.log(traditional.stdout); // "still works\n" -``` - -**Key Features:** - -- `command.streams.stdin/stdout/stderr` - Direct access to Node.js streams -- `command.buffers.stdin/stdout/stderr` - Binary data as Buffer objects -- `command.strings.stdin/stdout/stderr` - Text data as strings -- `command.kill()` - Forceful process termination -- **Auto-start behavior:** Process starts only when accessing stream properties -- **Perfect for:** Interactive commands (grep, sort, bc), data processing, real-time control -- **Network commands (ping, wget) ignore stdin** → Use `kill()` method instead - -**🚀 Streams vs Buffers/Strings:** - -- **`streams.*`** - Available **immediately** when command starts, for real-time interaction -- **`buffers.*` & `strings.*`** - Complete **snapshots** available only **after** command finishes - -### Shell Replacement (.sh → .mjs) - -Replace bash scripts with JavaScript while keeping shell semantics: - -```javascript -import { $, shell, set, unset } from 'command-stream'; - -// set -e equivalent: exit on any error -shell.errexit(true); - -await $`mkdir -p build`; -await $`npm run build`; - -// set +e equivalent: allow errors (like bash) -shell.errexit(false); -const cleanup = await $`rm -rf temp`; // Won't throw if fails - -// set -e again for critical operations -shell.errexit(true); -await $`cp -r build/* deploy/`; - -// Other bash-like settings -shell.verbose(true); // set -v: print commands -shell.xtrace(true); // set -x: trace execution - -// Or use the bash-style API -set('e'); // set -e -unset('e'); // set +e -set('x'); // set -x -set('verbose'); // Long form also supported -``` - -### Cross-Platform File Operations (Built-in Commands) - -Replace system-dependent operations with built-in commands that work identically everywhere: - -```javascript -import { $ } from 'command-stream'; - -// File system operations work on Windows, macOS, and Linux identically -await $`mkdir -p project/src project/tests`; -await $`touch project/src/index.js project/tests/test.js`; - -// List files with details -const files = await $`ls -la project/src`; -console.log(files.stdout); - -// Copy and move operations -await $`cp project/src/index.js project/src/backup.js`; -await $`mv project/src/backup.js project/backup.js`; - -// File content operations -await $`echo "export default 'Hello World';" > project/src/index.js`; -const content = await $`cat project/src/index.js`; -console.log(content.stdout); - -// Path operations -const filename = await $`basename project/src/index.js .js`; // → "index" -const directory = await $`dirname project/src/index.js`; // → "project/src" - -// Generate sequences and process them -await $`seq 1 10 | cat > numbers.txt`; -const numbers = await $`cat numbers.txt`; - -// Cleanup -await $`rm -r project numbers.txt`; -``` - -### Virtual Commands (Extensible Shell) - -Create custom commands that work seamlessly alongside built-ins: - -```javascript -import { $, register, unregister, listCommands } from 'command-stream'; - -// Register a custom command -register('greet', async ({ args, stdin }) => { - const name = args[0] || 'World'; - return { stdout: `Hello, ${name}!\n`, code: 0 }; -}); - -// Use it like any other command -await $`greet Alice`; // → "Hello, Alice!" -await $`echo "Bob" | greet`; // → "Hello, Bob!" - -// Streaming virtual commands with async generators -register('countdown', async function* ({ args }) { - const start = parseInt(args[0] || 5); - for (let i = start; i >= 0; i--) { - yield `${i}\n`; - await new Promise((r) => setTimeout(r, 1000)); - } -}); - -// Use in pipelines with built-ins -await $`countdown 3 | cat > countdown.txt`; - -// Virtual commands work in all patterns -for await (const chunk of $`countdown 3`.stream()) { - console.log('Countdown:', chunk.data.toString().trim()); -} - -// Management functions -console.log(listCommands()); // List all registered commands -unregister('greet'); // Remove custom commands -``` - -#### 🔥 **Why Virtual Commands Are Revolutionary** - -**No other shell library offers this level of extensibility:** - -- **🚫 Bun.$**: Fixed set of built-in commands, no extensibility API -- **🚫 execa**: Transform/pipeline system, but no custom commands -- **🚫 zx**: JavaScript functions only, no shell command integration - -**command-stream breaks the barrier** between JavaScript functions and shell commands: - -```javascript -// ❌ Other libraries: Choose JavaScript OR shell -await execa('node', ['script.js']); // execa: separate processes -await $`node script.js`; // zx: shell commands only - -// ✅ command-stream: JavaScript functions AS shell commands -register('deploy', async ({ args }) => { - const env = args[0] || 'staging'; - await deployToEnvironment(env); - return { stdout: `Deployed to ${env}!\n`, code: 0 }; -}); - -await $`deploy production`; // JavaScript function as shell command! -await $`deploy staging | tee log.txt`; // Works in pipelines! -``` - -**Unique capabilities:** - -- **Seamless Integration**: Virtual commands work exactly like built-ins -- **Pipeline Support**: Full stdin/stdout passing between virtual and system commands -- **Streaming**: Async generators for real-time output -- **Dynamic Registration**: Add/remove commands at runtime -- **Option Awareness**: Virtual commands respect `cwd`, `env`, etc. - -### 🔗 **Advanced Pipeline Support** - -**command-stream offers the most advanced piping system in the JavaScript ecosystem:** - -#### **Shell-Style Piping (Traditional)** - -```javascript -import { $, register } from 'command-stream'; - -// ✅ Standard shell piping (like all libraries) -await $`echo "hello world" | wc -w`; // → "2" - -// ✅ Built-in to built-in piping -await $`seq 1 5 | cat > numbers.txt`; - -// ✅ System to built-in piping -await $`git log --oneline | head -n 5`; - -// 🚀 UNIQUE: Virtual command piping -register('uppercase', async ({ args, stdin }) => { - return { stdout: stdin.toUpperCase(), code: 0 }; -}); - -register('reverse', async ({ args, stdin }) => { - return { stdout: stdin.split('').reverse().join(''), code: 0 }; -}); - -// ✅ Built-in to virtual piping -await $`echo "hello" | uppercase`; // → "HELLO" - -// ✅ Virtual to virtual piping -await $`echo "hello" | uppercase | reverse`; // → "OLLEH" - -// ✅ Mixed pipelines (system + built-in + virtual) -await $`git log --oneline | head -n 3 | uppercase | cat > LOG.txt`; - -// ✅ Complex multi-stage pipelines -await $`find . -name "*.js" | head -n 10 | basename | sort | uniq`; -``` - -#### **🚀 Programmatic .pipe() Method (NEW!)** - -**World's first shell library with full `.pipe()` method support for virtual commands:** - -```javascript -import { $, register } from 'command-stream'; - -// ✅ Basic programmatic piping -const result = await $`echo "hello"`.pipe($`echo "World: $(cat)"`); - -// 🌟 Virtual command chaining -register('add-prefix', async ({ args, stdin }) => { - const prefix = args[0] || 'PREFIX:'; - return { stdout: `${prefix} ${stdin.trim()}\n`, code: 0 }; -}); - -register('add-suffix', async ({ args, stdin }) => { - const suffix = args[0] || 'SUFFIX'; - return { stdout: `${stdin.trim()} ${suffix}\n`, code: 0 }; -}); - -// ✅ Chain virtual commands with .pipe() -const result = await $`echo "Hello"` - .pipe($`add-prefix "[PROCESSED]"`) - .pipe($`add-suffix "!!!"`); -// → "[PROCESSED] Hello !!!" - -// ✅ Mix with built-in commands -const fileData = await $`cat large-file.txt` - .pipe($`head -n 100`) - .pipe($`add-prefix "Line:"`); - -// ✅ Error handling in pipelines -try { - const result = await $`cat nonexistent.txt`.pipe($`add-prefix "Data:"`); -} catch (error) { - // Source error propagates - destination never executes - console.log('File not found, pipeline stopped'); -} +# command-stream -// ✅ Complex data processing -register('json-parse', async ({ args, stdin }) => { - try { - const data = JSON.parse(stdin); - return { stdout: JSON.stringify(data, null, 2), code: 0 }; - } catch (error) { - return { stdout: '', stderr: `JSON Error: ${error.message}`, code: 1 }; - } -}); - -register('extract-field', async ({ args, stdin }) => { - const field = args[0]; - try { - const data = JSON.parse(stdin); - const value = data[field] || 'null'; - return { stdout: `${value}\n`, code: 0 }; - } catch (error) { - return { stdout: '', stderr: `Extract Error: ${error.message}`, code: 1 }; - } -}); - -// Real-world API processing pipeline -const userName = await $`curl -s https://api.github.com/users/octocat` - .pipe($`json-parse`) - .pipe($`extract-field name`); -// → "The Octocat" - -// Cleanup -unregister('add-prefix'); -unregister('add-suffix'); -unregister('json-parse'); -unregister('extract-field'); -``` - -#### **🆚 How We Compare** - -| Library | Pipeline Types | Custom Commands in Pipes | `.pipe()` Method | Real-time Streaming | -| ------------------ | --------------------------------------- | ------------------------ | ----------------------------------- | ------------------- | -| **command-stream** | ✅ System + Built-ins + Virtual + Mixed | ✅ **Full support** | ✅ **Full virtual command support** | ✅ **Yes** | -| **Bun.$** | ✅ System + Built-ins | ❌ No custom commands | ❌ No `.pipe()` method | ❌ No | -| **execa** | ✅ Programmatic `.pipe()` | ❌ No shell integration | ✅ Basic process piping | 🟡 Limited | -| **zx** | ✅ Shell piping + `.pipe()` | ❌ No custom commands | ✅ Stream piping only | ❌ No | - -**🎯 Unique Advantages:** - -- **Virtual commands work seamlessly in both shell pipes AND `.pipe()` method** - no other library can do this -- **Mixed pipeline types** - combine system, built-in, and virtual commands freely in both syntaxes -- **Real-time streaming** through virtual command pipelines -- **Full stdin/stdout passing** between all command types -- **Dual piping syntax** - use shell `|` OR programmatic `.pipe()` interchangeably - -## Default Behavior: Shell-like with Programmatic Control - -**command-stream behaves exactly like running commands in your shell by default:** - -```javascript -import { $ } from 'command-stream'; - -// This command will: -// 1. Print "Hello" to your terminal (stdout→stdout) -// 2. Print "Error!" to your terminal (stderr→stderr) -// 3. Capture both outputs for programmatic access -const result = await $`sh -c "echo 'Hello'; echo 'Error!' >&2"`; - -console.log('Captured stdout:', result.stdout); // "Hello\n" -console.log('Captured stderr:', result.stderr); // "Error!\n" -console.log('Exit code:', result.code); // 0 -``` - -**Key Default Options:** - -- `mirror: true` - Live output to terminal (like shell) -- `capture: true` - Capture output for later use (unlike shell) -- `stdin: 'inherit'` - Inherit stdin from parent process - -**Fully Controllable:** - -```javascript -import { $, create, sh } from 'command-stream'; - -// Disable terminal output but still capture -const result = await sh('echo "silent"', { mirror: false }); - -// Custom stdin input -const custom = await sh('cat', { stdin: 'custom input' }); - -// Create custom $ with different defaults -const quiet$ = create({ mirror: false }); -await quiet$`echo "silent"`; // Won't print to terminal - -// Disable both mirroring and capturing for performance -await sh('make build', { mirror: false, capture: false }); -``` - -**This gives you the best of both worlds:** shell-like behavior by default, but with full programmatic control and real-time streaming capabilities. - -## Real-world Examples - -### Log File Streaming with Session ID Extraction - -```javascript -import { $ } from 'command-stream'; -import { appendFileSync, writeFileSync } from 'fs'; - -let sessionId = null; -let logFile = null; - -for await (const chunk of $`your-streaming-command`.stream()) { - if (chunk.type === 'stdout') { - const data = chunk.data.toString(); - - // Extract session ID from output - if (!sessionId && data.includes('session_id')) { - try { - const parsed = JSON.parse(data); - sessionId = parsed.session_id; - logFile = `${sessionId}.log`; - console.log(`Session ID: ${sessionId}`); - } catch (e) { - // Handle JSON parse errors - } - } - - // Write to log file in real-time - if (logFile) { - appendFileSync(logFile, data); - } - } -} -``` - -### Progress Monitoring - -```javascript -import { $ } from 'command-stream'; - -let progress = 0; - -$`download-large-file` - .on('stdout', (chunk) => { - const output = chunk.toString(); - if (output.includes('Progress:')) { - progress = parseProgress(output); - updateProgressBar(progress); - } - }) - .on('end', (result) => { - console.log('Download completed!'); - }); -``` - -## API Reference - -### ProcessRunner Class - -The enhanced `$` function returns a `ProcessRunner` instance that extends `EventEmitter`. - -#### Events - -- `data`: Emitted for each chunk with `{type: 'stdout'|'stderr', data: Buffer}` -- `stdout`: Emitted for stdout chunks (Buffer) -- `stderr`: Emitted for stderr chunks (Buffer) -- `end`: Emitted when process completes with final result object -- `exit`: Emitted with exit code - -#### Methods - -- `start(options)`: Explicitly start command execution - - `options.mode`: `'async'` (default) or `'sync'` - execution mode -- `async()`: Shortcut for `start({ mode: 'async' })` - start async execution -- `sync()`: Shortcut for `start({ mode: 'sync' })` - execute synchronously (blocks until completion) -- `stream()`: Returns an async iterator for real-time chunk processing -- `pipe(destination)`: Programmatically pipe output to another command (returns new ProcessRunner) -- `then()`, `catch()`, `finally()`: Promise interface for await support (auto-starts in async mode) - -#### Properties - -- `stdout`: Direct access to child process stdout stream -- `stderr`: Direct access to child process stderr stream -- `stdin`: Direct access to child process stdin stream - -### Default Options - -**By default, command-stream behaves like running commands in the shell:** - -```javascript -{ - mirror: true, // Live output to terminal (stdout→stdout, stderr→stderr) - capture: true, // Capture output for programmatic access - stdin: 'inherit', // Inherit stdin from parent process - interactive: false // Explicitly request TTY forwarding for interactive commands -} -``` - -**Option Details:** - -- `mirror: boolean` - Whether to pipe output to terminal in real-time -- `capture: boolean` - Whether to capture output in result object -- `stdin: 'inherit' | 'ignore' | string | Buffer` - How to handle stdin -- `interactive: boolean` - Enable TTY forwarding for interactive commands (requires `stdin: 'inherit'` and TTY environment) -- `cwd: string` - Working directory for command -- `env: object` - Environment variables - -**Override defaults:** - -- Use `$({ options })` syntax for one-off configurations with template literals -- Use `sh(command, options)` for one-off overrides with string commands -- Use `create(defaultOptions)` to create custom `$` with different defaults - -### Shell Settings API - -Control shell behavior like bash `set`/`unset` commands: - -#### Functions - -- `shell.errexit(boolean)`: Enable/disable exit-on-error (like `set ±e`) -- `shell.verbose(boolean)`: Enable/disable command printing (like `set ±v`) -- `shell.xtrace(boolean)`: Enable/disable execution tracing (like `set ±x`) -- `set(option)`: Enable shell option (`'e'`, `'v'`, `'x'`, or long names) -- `unset(option)`: Disable shell option -- `shell.settings()`: Get current settings object - -#### Error Handling Modes - -```javascript -import { $, shell } from 'command-stream'; - -// ✅ Default behavior: Commands don't throw on non-zero exit -const result = await $`ls nonexistent-file`; // Won't throw -console.log(result.code); // → 2 (non-zero, but no exception) - -// ✅ Enable errexit: Commands throw on non-zero exit -shell.errexit(true); -try { - await $`ls nonexistent-file`; // Throws error -} catch (error) { - console.log('Command failed:', error.code); // → 2 -} - -// ✅ Disable errexit: Back to non-throwing behavior -shell.errexit(false); -await $`ls nonexistent-file`; // Won't throw, returns result with code 2 - -// ✅ One-time override without changing global settings -try { - const result = await $`ls nonexistent-file`; - if (result.code !== 0) { - throw new Error(`Command failed with code ${result.code}`); - } -} catch (error) { - console.log('Manual error handling'); -} -``` - -### Virtual Commands API - -Control and extend the command system with custom JavaScript functions: - -#### Functions - -- `register(name, handler)`: Register a virtual command - - `name`: Command name (string) - - `handler`: Function or async generator `(args, stdin, options) => result` -- `unregister(name)`: Remove a virtual command -- `listCommands()`: Get array of all registered command names -- `enableVirtualCommands()`: Enable virtual command processing -- `disableVirtualCommands()`: Disable virtual commands (use system commands only) - -#### Advanced Virtual Command Features - -```javascript -import { $, register } from 'command-stream'; - -// ✅ Cancellation support with AbortController -register('cancellable', async function* ({ args, stdin, abortSignal }) { - for (let i = 0; i < 10; i++) { - if (abortSignal?.aborted) { - break; // Proper cancellation handling - } - yield `Count: ${i}\n`; - await new Promise((resolve) => setTimeout(resolve, 1000)); - } -}); - -// ✅ Access to all process options -// All original options (built-in + custom) are available in the 'options' object -// Common options like cwd, env are also available at top level for convenience -// Runtime additions: isCancelled function, abortSignal -register( - 'debug-info', - async ({ args, stdin, cwd, env, options, isCancelled }) => { - return { - stdout: JSON.stringify( - { - args, - cwd, // Available at top level for convenience - env: Object.keys(env || {}), // Available at top level for convenience - stdinLength: stdin?.length || 0, - allOptions: options, // All original options (built-in + custom) - mirror: options.mirror, // Built-in option from options object - capture: options.capture, // Built-in option from options object - customOption: options.customOption || 'not provided', // Custom option - isCancelledAvailable: typeof isCancelled === 'function', - }, - null, - 2 - ), - code: 0, - }; - } -); - -// ✅ Error handling and non-zero exit codes -register('maybe-fail', async ({ args }) => { - if (Math.random() > 0.5) { - return { - stdout: 'Success!\n', - code: 0, - }; - } else { - return { - stdout: '', - stderr: 'Random failure occurred\n', - code: 1, - }; - } -}); - -// ✅ Example: User options flow through to virtual commands -register('show-options', async ({ args, stdin, options, cwd }) => { - return { - stdout: `Custom: ${options.customValue || 'none'}, CWD: ${cwd || options.cwd || 'default'}\n`, - code: 0, - }; -}); - -// Usage example showing options passed to virtual command: -const result = await $({ - customValue: 'hello world', - cwd: '/tmp', -})`show-options`; -console.log(result.stdout); // Output: Custom: hello world, CWD: /tmp -``` - -#### Handler Function Signature - -```javascript -// Regular async function -async function handler({ args, stdin, abortSignal, cwd, env, options, isCancelled }) { - // All original options available in 'options': options.mirror, options.capture, options.customValue, etc. - // Common options like cwd, env also available at top level for convenience - return { - code: 0, // Exit code (number) - stdout: "output", // Standard output (string) - stderr: "", // Standard error (string) - }; -} - -// Async generator for streaming -async function streamingHandler({ args, stdin, abortSignal, cwd, env, options, isCancelled }) { - // Access both built-in and custom options from 'options' object - if (options.customFlag) { - yield "custom behavior\n"; - } - yield "chunk1\n"; - yield "chunk2\n"; -} -``` - -### Utility Functions API - -Control how values are interpolated into commands: - -#### Functions - -- `quote(value)`: Manually quote a value using the same smart quoting logic as auto-interpolation -- `raw(value)`: **⚠️ Dangerous!** Bypass auto-escaping to use command strings directly (see [Disabling Auto-Escape](#disabling-auto-escape-advanced)) - -#### quote() - Manual Quoting - -Apply the same smart quoting logic manually: - -```javascript -import { $, quote } from 'command-stream'; - -const path = '/path with spaces/file.txt'; -const quoted = quote(path); -console.log(quoted); // → '/path with spaces/file.txt' - -// Use case: Pre-process values before interpolation -const args = ['hello world', 'test'].map(quote); -// → ["'hello world'", 'test'] -``` - -#### raw() - Disable Auto-Escape - -**⚠️ WARNING: Only use with trusted input!** See [Disabling Auto-Escape](#disabling-auto-escape-advanced) section for detailed documentation and security considerations. - -```javascript -import { $, raw } from 'command-stream'; - -// Bypass auto-escaping for trusted command strings -const trustedCommand = 'echo "hello" && ls -la'; -await $`${raw(trustedCommand)}`; -// → Executes: echo "hello" && ls -la (without escaping) - -// ⚠️ NEVER use with untrusted input - shell injection risk! -``` - -### Built-in Commands - -18 cross-platform commands that work identically everywhere: - -**File System**: `cat`, `ls`, `mkdir`, `rm`, `mv`, `cp`, `touch` -**Utilities**: `basename`, `dirname`, `seq`, `yes` -**System**: `cd`, `pwd`, `echo`, `sleep`, `true`, `false`, `which`, `exit`, `env`, `test` - -All built-in commands support: - -- Standard flags (e.g., `ls -la`, `mkdir -p`, `rm -rf`) -- Pipeline operations -- Option awareness (`cwd`, `env`, etc.) -- Bash-compatible error messages and exit codes - -#### Supported Options - -- `'e'` / `'errexit'`: Exit on command failure -- `'v'` / `'verbose'`: Print commands before execution -- `'x'` / `'xtrace'`: Trace command execution with `+` prefix -- `'u'` / `'nounset'`: Error on undefined variables (planned) -- `'pipefail'`: Pipe failure detection (planned) - -### Result Object - -```javascript -{ - code: number, // Exit code - stdout: string, // Complete stdout output - stderr: string, // Complete stderr output - stdin: string, // Input sent to process - child: ChildProcess, // Original child process object - async text() // Bun.$ compatibility method - returns stdout as string -} -``` - -#### `.text()` Method (Bun.$ Compatibility) - -For compatibility with Bun.$, all result objects include an async `.text()` method: - -```javascript -import { $ } from 'command-stream'; - -// Both sync and async execution support .text() -const result1 = await $`echo "hello world"`; -const text1 = await result1.text(); // "hello world\n" - -const result2 = $`echo "sync example"`.sync(); -const text2 = await result2.text(); // "sync example\n" - -// .text() is equivalent to accessing .stdout -expect(await result.text()).toBe(result.stdout); - -// Works with built-in commands -const result3 = await $`seq 1 3`; -const text3 = await result3.text(); // "1\n2\n3\n" - -// Works with .pipe() method -const result4 = await $`echo "pipe test"`.pipe($`cat`); -const text4 = await result4.text(); // "pipe test\n" -``` - -## Signal Handling (CTRL+C Support) - -The library provides **advanced CTRL+C handling** that properly manages signals across different scenarios: - -### How It Works - -1. **Smart Signal Forwarding**: CTRL+C is forwarded **only when child processes are active** -2. **User Handler Preservation**: When no children are running, your custom SIGINT handlers work normally -3. **Process Groups**: Child processes use detached spawning for proper signal isolation -4. **TTY Mode Support**: Raw TTY mode is properly managed and restored on interruption -5. **Graceful Termination**: Uses SIGTERM → SIGKILL escalation for robust process cleanup -6. **Exit Code Standards**: Proper signal exit codes (130 for SIGINT, 143 for SIGTERM) - -### Advanced Signal Behavior - -```javascript -// ✅ Smart signal handling - only interferes when necessary -import { $ } from 'command-stream'; - -// Case 1: No children active - your handlers work normally -process.on('SIGINT', () => { - console.log('My custom handler runs!'); - process.exit(42); // Custom exit code -}); -// Press CTRL+C → Your handler runs, exits with code 42 - -// Case 2: Children active - automatic forwarding -await $`ping 8.8.8.8`; // Press CTRL+C → Forwards to ping, exits with code 130 - -// Case 3: Multiple processes - all interrupted -await Promise.all([$`sleep 100`, $`ping google.com`]); // Press CTRL+C → All processes terminated, exits with code 130 -``` - -### Examples - -```javascript -// Long-running command that can be interrupted with CTRL+C -try { - await $`ping 8.8.8.8`; // Press CTRL+C to stop -} catch (error) { - console.log('Command interrupted:', error.code); // Exit code 130 (SIGINT) -} - -// Multiple concurrent processes - CTRL+C stops all -try { - await Promise.all([ - $`sleep 100`, - $`ping google.com`, - $`tail -f /var/log/system.log`, - ]); -} catch (error) { - // All processes are terminated when you press CTRL+C -} - -// Works with streaming patterns too -try { - for await (const chunk of $`ping 8.8.8.8`.stream()) { - console.log(chunk); - // Press CTRL+C to break the loop and stop the process - } -} catch (error) { - console.log('Streaming interrupted'); -} -``` - -### Signal Handling Behavior - -- **🎯 Smart Detection**: Only forwards CTRL+C when child processes are active -- **🛡️ Non-Interference**: Preserves user SIGINT handlers when no children running -- **⚡ Interactive Commands**: Use `interactive: true` option for commands like `vim`, `less`, `top` to enable proper TTY forwarding and signal handling -- **🔄 Process Groups**: Detached spawning ensures proper signal isolation -- **🧹 TTY Cleanup**: Raw terminal mode properly restored on interruption -- **📊 Standard Exit Codes**: - - `130` - SIGINT interruption (CTRL+C) - - `143` - SIGTERM termination (programmatic kill) - - `137` - SIGKILL force termination - -### Command Resolution Priority - -```javascript -// Understanding how commands are resolved: - -// 1. Virtual Commands (highest priority) -register('echo', () => ({ stdout: 'virtual!\n', code: 0 })); -await $`echo test`; // → "virtual!" - -// 2. Built-in Commands (if no virtual match) -unregister('echo'); -await $`echo test`; // → Uses built-in echo - -// 3. System Commands (if no built-in/virtual match) -await $`unknown-command`; // → Uses system PATH lookup - -// 4. Virtual Bypass (special case) -await $({ stdin: 'data' })`sleep 1`; // Bypasses virtual sleep, uses system sleep -``` - -## Execution Patterns Deep Dive - -### When to Use Different Patterns - -```javascript -import { $ } from 'command-stream'; - -// ✅ Use await for simple command execution -const result = await $`ls -la`; - -// ✅ Use .sync() when you need blocking execution with events -const syncCmd = $`build-script` - .on('stdout', (chunk) => updateProgress(chunk)) - .sync(); // Events fire after completion - -// ✅ Use .start() for non-blocking execution with real-time events -const asyncCmd = $`long-running-server` - .on('stdout', (chunk) => logOutput(chunk)) - .start(); // Events fire in real-time - -// ✅ Use .stream() for processing large outputs efficiently -for await (const chunk of $`generate-big-file`.stream()) { - processChunkInRealTime(chunk); -} // Memory efficient - processes chunks as they arrive - -// ✅ Use EventEmitter pattern for complex workflows -$`deployment-script` - .on('stdout', (chunk) => { - if (chunk.toString().includes('ERROR')) { - handleError(chunk); - } - }) - .on('stderr', (chunk) => logError(chunk)) - .on('end', (result) => { - if (result.code === 0) { - notifySuccess(); - } - }) - .start(); -``` - -### Performance Considerations - -```javascript -// 🚀 Memory Efficient: For large outputs, use streaming -for await (const chunk of $`cat huge-file.log`.stream()) { - processChunk(chunk); // Processes incrementally -} - -// 🐌 Memory Inefficient: Buffers entire output in memory -const result = await $`cat huge-file.log`; -processFile(result.stdout); // Loads everything into memory - -// ⚡ Fastest: Sync execution for small, quick commands -const quickResult = $`pwd`.sync(); - -// 🔄 Best for UX: Async with events for long-running commands -$`npm install`.on('stdout', showProgress).start(); -``` - -## Common Pitfalls - -### Array Argument Handling - -When passing multiple arguments, pass the array directly - **never use `.join(' ')`** before interpolation: - -```javascript -import { $ } from 'command-stream'; - -// WRONG - entire string becomes ONE argument -const args = ['file.txt', '--public', '--verbose']; -await $`command ${args.join(' ')}`; -// Shell receives: command 'file.txt --public --verbose' (1 argument!) -// Error: File does not exist: "file.txt --public --verbose" - -// CORRECT - each element becomes separate argument -await $`command ${args}`; -// Shell receives: command file.txt --public --verbose (3 arguments) -``` - -This is a common mistake that causes errors like: - -``` -Error: File does not exist: "/path/to/file.txt --flag --option" -``` - -### Why This Happens - -The `$` template tag handles arrays specially - each element is quoted separately: - -```javascript -if (Array.isArray(value)) { - return value.map(quote).join(' '); // Each element quoted individually -} -``` - -But when you call `.join(' ')` first: - -1. The array becomes a string: `"file.txt --public --verbose"` -2. Template receives a **string**, not an array -3. The entire string gets quoted as one argument -4. Command receives one argument containing spaces - -### Recommended Patterns - -```javascript -// Pattern 1: Direct array passing -const args = ['file.txt', '--verbose']; -await $`command ${args}`; - -// Pattern 2: Separate interpolations -const file = 'file.txt'; -const flags = ['--verbose', '--force']; -await $`command ${file} ${flags}`; - -// Pattern 3: Build array dynamically -const allArgs = ['input.txt']; -if (verbose) allArgs.push('--verbose'); -await $`command ${allArgs}`; -``` - -See [js/BEST-PRACTICES.md](js/BEST-PRACTICES.md) for more detailed guidance. - -## Testing - -```bash -# Run comprehensive test suite (518+ tests) -bun test - -# Run tests with coverage report -bun test --coverage - -# Run specific test categories -npm run test:features # Feature comparison tests -npm run test:builtin # Built-in commands tests -npm run test:pipe # .pipe() method tests -npm run test:sync # Synchronous execution tests -npm run test:signal # CTRL+C signal handling tests -``` +[![JavaScript package](https://img.shields.io/npm/v/command-stream.svg?label=js%20npm)](https://www.npmjs.com/package/command-stream) +[![Rust crate](https://img.shields.io/crates/v/command-stream.svg?label=rust%20crate)](https://crates.io/crates/command-stream) +[![License](https://img.shields.io/badge/license-Unlicense-blue.svg)](./LICENSE) +[![GitHub stars](https://img.shields.io/github/stars/link-foundation/command-stream?style=social)](https://github.com/link-foundation/command-stream/stargazers) -## Requirements +Command-stream provides stream-oriented shell command execution APIs in two +language implementations: -- **Bun**: >= 1.0.0 (primary runtime) -- **Node.js**: >= 20.0.0 (compatibility support) +- [JavaScript package](./js/README.md): Bun and Node.js package published to + npm as `command-stream`. +- [Rust crate](./rust/README.md): Rust library and binary published to crates.io + as `command-stream`. -## Roadmap +Both implementations focus on shell-like command execution, real-time output +handling, pipeline support, and cross-platform behavior. Language-specific API +examples, package-manager instructions, release notes, and best practices live +with each package. -### 🔄 **Coming Soon** +## Repository Layout -- **TypeScript Support**: Full .d.ts definitions and type safety -- **Enhanced Shell Options**: `set -u` (nounset) and `set -o pipefail` support -- **More Built-in Commands**: Additional cross-platform utilities +| Path | Purpose | +| ---------- | ---------------------------------------------------------- | +| `js/` | JavaScript package source, tests, docs, and CI/CD scripts. | +| `rust/` | Rust crate source, tests, docs, and CI/CD scripts. | +| `docs/` | Repository-level investigations and case studies. | +| `.github/` | GitHub workflow definitions and deployment notes. | -### 💡 **Planned Features** +## Releases -- **Performance Optimizations**: Further Bun runtime optimizations -- **Advanced Error Handling**: Enhanced error context and debugging -- **Plugin System**: Extensible architecture for custom integrations +JavaScript and Rust releases are independent: -## Contributing +- JavaScript workflow: `.github/workflows/js.yml` +- Rust workflow: `.github/workflows/rust.yml` +- JavaScript GitHub release tags: `js-v` +- Rust GitHub release tags: `rust-v` -We welcome contributions! Since command-stream is **public domain software**, your contributions will also be released into the public domain. +## Development -### 🚀 **Getting Started** +Run language-specific checks from the language folders: ```bash -git clone https://github.com/link-foundation/command-stream.git -cd command-stream +cd js bun install -bun test # Run the full test suite +bun run test +bun run check ``` -### 📋 **Development Guidelines** - -- All features must have comprehensive tests -- Built-in commands should match bash/sh behavior exactly -- Maintain cross-platform compatibility (Windows, macOS, Linux) -- Follow the existing code style and patterns - -### 🧪 **Running Tests** - ```bash -bun test # All 518+ tests -bun test tests/pipe.test.mjs # Specific test file -npm run test:builtin # Built-in commands only +cd rust +cargo fmt --all -- --check +cargo clippy --all-targets --all-features +cargo test --all-features ``` -## License - Our Biggest Advantage - -**The Unlicense (Public Domain)** - -Unlike other shell utilities that require attribution (MIT, Apache 2.0), command-stream is released into the **public domain**. This means: - -- ✅ **No attribution required** - Use it without crediting anyone -- ✅ **No license files to include** - Simplify your distribution -- ✅ **No restrictions** - Modify, sell, embed, whatever you want -- ✅ **No legal concerns** - It's as free as code can be -- ✅ **Corporate friendly** - No license compliance overhead - -This makes command-stream ideal for: - -- **Commercial products** where license attribution is inconvenient -- **Embedded systems** where every byte counts -- **Educational materials** that can be freely shared -- **Internal tools** without legal review requirements +## License -> "This is free and unencumbered software released into the public domain." +Command-stream is released under the [Unlicense](./LICENSE). diff --git a/docs/case-studies/issue-160/README.md b/docs/case-studies/issue-160/README.md new file mode 100644 index 0000000..609d953 --- /dev/null +++ b/docs/case-studies/issue-160/README.md @@ -0,0 +1,132 @@ +# Issue 160 Case Study: Separate JavaScript and Rust + +## Source Data + +- Issue: +- Pull request: +- Template snapshots: + - JavaScript template `2d77e242d1a1778b6fc7f3ca563b2a36ef555d0e` + - Rust template `702ea4036aea61b65652c8137b5480d50e710864` + - Python template `66abe798182316d568e748bec4b0e89828fac1a6` + - C# template `6872708aa3da13d5a67338cc8350c610c3af2275` +- Raw issue, PR, tree, template, and verification data is stored in + [data/](data/) and [templates/](templates/). + +## Requirements + +| Requirement | Resolution | +| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| Put JavaScript files under `js/` | Moved package metadata, lock files, changesets, scripts, changelog, lint/format config, and README into `js/`. | +| Put Rust files under `rust/` | Kept crate files under `rust/`, added Rust README, changelog, changelog fragments, and Rust release scripts under `rust/scripts/`. | +| Keep repository root common-only | Replaced the root README with shared project information and language links; removed root JS package/release files. | +| Control JS with `js.yml` | Replaced the combined release workflow with `.github/workflows/js.yml`, scoped to `js/**`, shared files, and JS npm release behavior. | +| Control Rust with `rust.yml` | Added `.github/workflows/rust.yml`, scoped to `rust/**`, shared files, and crates.io release behavior. | +| Separate package READMEs | Added `js/README.md` for npm package docs and `rust/README.md` for crate docs; root README links both. | +| Separate releases and badges | JS releases use `js-v` tags and npm badges; Rust releases use `rust-v` tags and crates.io badges. | +| Per-language scripts | JS npm scripts live in `js/scripts/`; Rust release scripts live in `rust/scripts/`. | +| Compare CI/CD templates | Captured file trees and script snapshots from JS, Rust, Python, and C# templates under `templates/`. | +| Report template issues found | Opened Rust template issue . | +| Add reproducing test | Added `js/tests/repository-layout.test.mjs`; before log failed, after log passes. | + +## External Facts Used + +- GitHub Actions supports `paths` filters on `push` and `pull_request`, so + separate `js/**` and `rust/**` workflow triggers are appropriate: + +- npm `package.json` `files` controls package tarball inclusion from the package + root, and README/LICENSE/main files have special inclusion behavior: + +- npm trusted publishing uses OIDC from authorized CI/CD workflows, which + matches the JavaScript workflow's `id-token: write` release path: + +- Cargo's `readme` field is relative to `Cargo.toml` and is published to the + registry, so `rust/Cargo.toml` now uses `readme = "README.md"`: + +- Cargo recommends `cargo package`/`cargo publish --dry-run` style verification + before publishing, which is why `rust.yml` keeps a package check: + + +## Template Comparison + +The JavaScript template keeps npm release state in root-level package files, +`.changeset/`, `scripts/*.mjs`, and `.github/workflows/release.yml`. For this +repository, those same conventions were translated into `js/` so package-local +commands still run from the JavaScript package root while CI triggers remain +language-scoped. + +The Rust template keeps `Cargo.toml`, `CHANGELOG.md`, `changelog.d/`, and +`scripts/*.rs` together. This repository already had the Rust crate under +`rust/`, so the template scripts were copied into `rust/scripts/` and adapted +for a nested crate root. + +The Python and C# templates were used as cross-checks for common release +patterns: per-language changelog/changeset validation, package-manager-specific +publish scripts, explicit version-and-commit steps, and release-note generation. +They did not require repository changes because this issue only asks for +JavaScript and Rust separation. + +## Design Decisions + +1. Keep one repository and two package roots. + This satisfies the issue without splitting history or changing package names. + +2. Keep release workflows separate. + Separate path filters and release tags reduce accidental cross-language + releases and make package status visible in GitHub Actions. + +3. Keep tests rooted at the repository where they already assumed repo-relative + fixture paths. + JS package scripts run `cd .. && bun test js/tests/...`, preserving existing + behavior after moving `bunfig.toml` into `js/`. Explicit `--timeout 10000` + keeps the previous timeout behavior. + +4. Use manifest paths for Rust publishing. + The copied Rust template used `cargo publish -p `, which assumes a + workspace. The adapted script uses `--manifest-path rust/Cargo.toml`, which + works for this nested single-crate layout. + +5. Remove consumed Rust changelog fragments. + The Rust template version script collected fragments but did not delete them, + which can cause repeat releases from the same fragments. This repository now + removes consumed fragments and stages `rust/changelog.d/` with `git add -A`. + +## Verification + +Reproducing layout test: + +- Before: `repository-layout-before.log` failed because JS package files and the + combined release workflow still lived at the repository root. +- After: `repository-layout-after.log` passes with 4 tests and 30 assertions. + +JavaScript checks: + +- `js-lint.log`: `cd js && bun run lint` +- `js-format-check.log`: `cd js && bun run format:check` +- `js-duplication.log`: `cd js && bun run check:duplication` +- `js-test.log`: `cd js && PATH=/tmp/issue-160-bin:$PATH bun run test` + - Result: 684 pass, 5 skip, 0 fail. + - Note: local sudo was unavailable, so a temporary `jq` binary was downloaded + for parity with `js.yml`, which installs `jq` on CI runners. + +Rust checks: + +- `rust-fmt.log`: `cd rust && cargo fmt --all -- --check` +- `rust-clippy.log`: `cd rust && cargo clippy --all-targets --all-features` +- `rust-test.log`: `cd rust && cargo test --all-features --verbose` +- `rust-doc-test.log`: `cd rust && cargo test --doc --all-features --verbose` +- `rust-package.log`: `cd rust && cargo package --allow-dirty` +- `rust-script-publish-crate-test.log`: + `rust-script --test rust/scripts/publish-crate.rs` +- `rust-script-version-and-commit-test.log`: + `rust-script --test rust/scripts/version-and-commit.rs` + +Workflow checks: + +- `workflow-yaml-parse.log`: Ruby YAML parse succeeded for `js.yml` and + `rust.yml`. +- `actionlint` was not installed locally, so no actionlint run was recorded. + +## Follow-up + +The only upstream template issue found during this case study is tracked at +. diff --git a/docs/case-studies/issue-160/data/bun-install-refresh.log b/docs/case-studies/issue-160/data/bun-install-refresh.log new file mode 100644 index 0000000..ce98d6c --- /dev/null +++ b/docs/case-studies/issue-160/data/bun-install-refresh.log @@ -0,0 +1,14 @@ +bun install v1.3.14 (0d9b296a) + +$ cd .. && js/node_modules/.bin/husky || true + ++ @changesets/cli@2.29.8 ++ eslint@9.39.2 ++ eslint-config-prettier@10.1.8 ++ eslint-plugin-prettier@5.5.4 ++ husky@9.1.7 ++ jscpd@4.0.5 ++ lint-staged@16.2.7 ++ prettier@3.7.4 + +301 packages installed [352.00ms] diff --git a/docs/case-studies/issue-160/data/csharp-ai-driven-development-pipeline-template.repo.json b/docs/case-studies/issue-160/data/csharp-ai-driven-development-pipeline-template.repo.json new file mode 100644 index 0000000..393e581 --- /dev/null +++ b/docs/case-studies/issue-160/data/csharp-ai-driven-development-pipeline-template.repo.json @@ -0,0 +1 @@ +{"id":1123888537,"node_id":"R_kgDOQv0tmQ","name":"csharp-ai-driven-development-pipeline-template","full_name":"link-foundation/csharp-ai-driven-development-pipeline-template","private":false,"owner":{"login":"link-foundation","id":176174013,"node_id":"O_kgDOCoAzvQ","avatar_url":"https://avatars.githubusercontent.com/u/176174013?v=4","gravatar_id":"","url":"https://api.github.com/users/link-foundation","html_url":"https://github.com/link-foundation","followers_url":"https://api.github.com/users/link-foundation/followers","following_url":"https://api.github.com/users/link-foundation/following{/other_user}","gists_url":"https://api.github.com/users/link-foundation/gists{/gist_id}","starred_url":"https://api.github.com/users/link-foundation/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/link-foundation/subscriptions","organizations_url":"https://api.github.com/users/link-foundation/orgs","repos_url":"https://api.github.com/users/link-foundation/repos","events_url":"https://api.github.com/users/link-foundation/events{/privacy}","received_events_url":"https://api.github.com/users/link-foundation/received_events","type":"Organization","user_view_type":"public","site_admin":false},"html_url":"https://github.com/link-foundation/csharp-ai-driven-development-pipeline-template","description":"A template for AI driven development pipeline for C#","fork":false,"url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template","forks_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/forks","keys_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/keys{/key_id}","collaborators_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/teams","hooks_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/hooks","issue_events_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/issues/events{/number}","events_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/events","assignees_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/assignees{/user}","branches_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/branches{/branch}","tags_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/tags","blobs_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/git/refs{/sha}","trees_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/git/trees{/sha}","statuses_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/statuses/{sha}","languages_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/languages","stargazers_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/stargazers","contributors_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/contributors","subscribers_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/subscribers","subscription_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/subscription","commits_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/commits{/sha}","git_commits_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/git/commits{/sha}","comments_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/comments{/number}","issue_comment_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/issues/comments{/number}","contents_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/contents/{+path}","compare_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/compare/{base}...{head}","merges_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/merges","archive_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/downloads","issues_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/issues{/number}","pulls_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/pulls{/number}","milestones_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/milestones{/number}","notifications_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/labels{/name}","releases_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/releases{/id}","deployments_url":"https://api.github.com/repos/link-foundation/csharp-ai-driven-development-pipeline-template/deployments","created_at":"2025-12-27T21:08:32Z","updated_at":"2026-06-04T18:13:07Z","pushed_at":"2026-06-04T18:13:03Z","git_url":"git://github.com/link-foundation/csharp-ai-driven-development-pipeline-template.git","ssh_url":"git@github.com:link-foundation/csharp-ai-driven-development-pipeline-template.git","clone_url":"https://github.com/link-foundation/csharp-ai-driven-development-pipeline-template.git","svn_url":"https://github.com/link-foundation/csharp-ai-driven-development-pipeline-template","homepage":null,"size":98,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"has_discussions":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"unlicense","name":"The Unlicense","spdx_id":"Unlicense","url":"https://api.github.com/licenses/unlicense","node_id":"MDc6TGljZW5zZTE1"},"allow_forking":true,"is_template":true,"web_commit_signoff_required":false,"has_pull_requests":true,"pull_request_creation_policy":"all","topics":[],"visibility":"public","forks":0,"open_issues":0,"watchers":0,"default_branch":"main","permissions":{"admin":true,"maintain":true,"push":true,"triage":true,"pull":true},"temp_clone_token":"","allow_squash_merge":true,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_auto_merge":false,"delete_branch_on_merge":false,"allow_update_branch":false,"use_squash_pr_title_as_default":false,"squash_merge_commit_message":"COMMIT_MESSAGES","squash_merge_commit_title":"COMMIT_OR_PR_TITLE","merge_commit_message":"PR_TITLE","merge_commit_title":"MERGE_MESSAGE","custom_properties":{},"organization":{"login":"link-foundation","id":176174013,"node_id":"O_kgDOCoAzvQ","avatar_url":"https://avatars.githubusercontent.com/u/176174013?v=4","gravatar_id":"","url":"https://api.github.com/users/link-foundation","html_url":"https://github.com/link-foundation","followers_url":"https://api.github.com/users/link-foundation/followers","following_url":"https://api.github.com/users/link-foundation/following{/other_user}","gists_url":"https://api.github.com/users/link-foundation/gists{/gist_id}","starred_url":"https://api.github.com/users/link-foundation/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/link-foundation/subscriptions","organizations_url":"https://api.github.com/users/link-foundation/orgs","repos_url":"https://api.github.com/users/link-foundation/repos","events_url":"https://api.github.com/users/link-foundation/events{/privacy}","received_events_url":"https://api.github.com/users/link-foundation/received_events","type":"Organization","user_view_type":"public","site_admin":false},"security_and_analysis":{"secret_scanning":{"status":"disabled"},"secret_scanning_push_protection":{"status":"disabled"},"dependabot_security_updates":{"status":"disabled"},"secret_scanning_non_provider_patterns":{"status":"disabled"},"secret_scanning_validity_checks":{"status":"disabled"}},"network_count":0,"subscribers_count":0} \ No newline at end of file diff --git a/docs/case-studies/issue-160/data/csharp-template-head.txt b/docs/case-studies/issue-160/data/csharp-template-head.txt new file mode 100644 index 0000000..1220f16 --- /dev/null +++ b/docs/case-studies/issue-160/data/csharp-template-head.txt @@ -0,0 +1 @@ +6872708aa3da13d5a67338cc8350c610c3af2275 diff --git a/docs/case-studies/issue-160/data/current-file-tree-after.txt b/docs/case-studies/issue-160/data/current-file-tree-after.txt new file mode 100644 index 0000000..7dde842 --- /dev/null +++ b/docs/case-studies/issue-160/data/current-file-tree-after.txt @@ -0,0 +1,749 @@ +.claude/settings.local.json +.github/DEPLOYMENT.md +.github/workflows/js.yml +.github/workflows/release.yml +.github/workflows/rust.yml +.gitignore +.gitkeep +.gitpod.Dockerfile +.gitpod.yml +.husky/pre-commit +LICENSE +README.md +claude-profile-list.sh +claude-profile-restore.sh +claude-profile-save.sh +claude-profiles.mjs +docs/case-studies/issue-158/README.md +docs/case-studies/issue-158/data/checks-release-27134991249.log.gz +docs/case-studies/issue-158/data/checks-release-27135178897.log.gz +docs/case-studies/issue-158/data/crates-command-stream.json +docs/case-studies/issue-158/data/csharp-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-158/data/issue-158-comments.json +docs/case-studies/issue-158/data/issue-158-gh-view.txt +docs/case-studies/issue-158/data/js-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-158/data/meta-language.repo.json +docs/case-studies/issue-158/data/pr-159-conversation-comments.json +docs/case-studies/issue-158/data/pr-159-review-comments.json +docs/case-studies/issue-158/data/pr-159-reviews.json +docs/case-studies/issue-158/data/pr-159.json +docs/case-studies/issue-158/data/python-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-158/data/recent-runs-branch.json +docs/case-studies/issue-158/data/run-27134991249.json +docs/case-studies/issue-158/data/run-27135178897.json +docs/case-studies/issue-158/data/rust-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-158/data/start.repo.json +docs/case-studies/issue-158/templates/csharp-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-158/templates/csharp-ai-driven-development-pipeline-template/release.yml +docs/case-studies/issue-158/templates/js-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-158/templates/js-ai-driven-development-pipeline-template/check-release-needed.mjs +docs/case-studies/issue-158/templates/js-ai-driven-development-pipeline-template/publish-to-npm.mjs +docs/case-studies/issue-158/templates/js-ai-driven-development-pipeline-template/release.yml +docs/case-studies/issue-158/templates/meta-language.file-tree.txt +docs/case-studies/issue-158/templates/meta-language/check-release-needed.rs +docs/case-studies/issue-158/templates/meta-language/publish-crate.rs +docs/case-studies/issue-158/templates/meta-language/release.yml +docs/case-studies/issue-158/templates/meta-language/wait-for-crate.rs +docs/case-studies/issue-158/templates/python-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-158/templates/python-ai-driven-development-pipeline-template/release.yml +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template/check-release-needed.rs +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template/publish-crate.rs +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template/release.yml +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template/rust-paths.rs +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template/wait-for-crate.rs +docs/case-studies/issue-158/templates/start.file-tree.txt +docs/case-studies/issue-158/templates/start/check-release-needed.mjs +docs/case-studies/issue-158/templates/start/preflight-credentials.mjs +docs/case-studies/issue-158/templates/start/publish-to-crates.mjs +docs/case-studies/issue-158/templates/start/rust.yml +docs/case-studies/issue-160/README.md +docs/case-studies/issue-160/data/csharp-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-160/data/csharp-template-head.txt +docs/case-studies/issue-160/data/current-file-tree-after.txt +docs/case-studies/issue-160/data/current-file-tree-before.txt +docs/case-studies/issue-160/data/issue-160-comments.json +docs/case-studies/issue-160/data/issue-160.json +docs/case-studies/issue-160/data/js-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-160/data/js-template-head.txt +docs/case-studies/issue-160/data/pr-161.json +docs/case-studies/issue-160/data/python-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-160/data/python-template-head.txt +docs/case-studies/issue-160/data/rust-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-160/data/rust-template-created-issue.txt +docs/case-studies/issue-160/data/rust-template-existing-issues.json +docs/case-studies/issue-160/data/rust-template-head.txt +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/.github/workflows/docs.yml +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/.github/workflows/release.yml +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/bump-version.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/check-file-size.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/check-release-needed.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/check-release-needed.test.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/create-github-release.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/create-github-release.test.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/detect-code-changes.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/merge-changesets.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/release-workflow-policy.test.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/validate-changeset.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/version-and-commit.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/version-and-commit.test.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/wait-for-nuget.mjs +docs/case-studies/issue-160/templates/csharp-ai-driven-development-pipeline-template/scripts/wait-for-nuget.test.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/.github/actions/publish-dockerhub/action.yml +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/.github/workflows/example-app.yml +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/.github/workflows/links.yml +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/.github/workflows/release.yml +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/changeset-version.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-changesets.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-docker-publish.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-file-line-limits.sh +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-mjs-syntax.sh +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-release-needed.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-version.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/check-web-archive.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/create-github-release.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/create-manual-changeset.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/detect-code-changes.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/format-github-release.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/format-release-notes-helpers.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/format-release-notes.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/instant-version-bump.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/js-paths.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/merge-changesets.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/package-info.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/publish-to-npm.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/setup-npm.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/simulate-fresh-merge.sh +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/update-preview-images.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/validate-changeset.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/version-and-commit.mjs +docs/case-studies/issue-160/templates/js-ai-driven-development-pipeline-template/scripts/wait-for-npm.mjs +docs/case-studies/issue-160/templates/js-ci-files.txt +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/.github/workflows/docs.yml +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/.github/workflows/release.yml +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/bump_version.py +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/check_file_size.py +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/create_github_release.py +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/create_manual_changeset.py +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/detect_code_changes.py +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/format_release_notes.py +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/publish_to_pypi.py +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/validate_changeset.py +docs/case-studies/issue-160/templates/python-ai-driven-development-pipeline-template/scripts/version_and_commit.py +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/.github/workflows/release.yml +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/bump-version.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/check-changelog-fragment.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/check-crate-size.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/check-file-size.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/check-release-needed.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/check-version-modification.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/collect-changelog.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/create-changelog-fragment.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/create-github-release.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/detect-code-changes.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/get-bump-type.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/get-version.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/git-config.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/publish-crate.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/rust-paths.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/version-and-commit.rs +docs/case-studies/issue-160/templates/rust-ai-driven-development-pipeline-template/scripts/wait-for-crate.rs +docs/case-studies/issue-160/templates/rust-ci-files.txt +experiments/issue-156/01-default-behavior.mjs +experiments/issue-156/02-errexit-enabled.mjs +experiments/issue-156/03-bash-comparison.sh +experiments/issue-156/04-calculator-bug-repro.mjs +gitpod-backup-auth.sh +gitpod-restore-auth.sh +js/.changeset/README.md +js/.changeset/config.json +js/.changeset/separate-language-releases.md +js/.jscpd.json +js/.npmignore +js/.prettierignore +js/.prettierrc +js/BEST-PRACTICES.md +js/CHANGELOG.md +js/README.md +js/bun.lock +js/bunfig.toml +js/deno.json +js/docs/IMPLEMENTATION_NOTES.md +js/docs/SHELL_OPERATORS_IMPLEMENTATION.md +js/docs/case-studies/issue-144/README.md +js/docs/case-studies/issue-144/failures-summary.md +js/docs/case-studies/issue-146/README.md +js/docs/case-studies/issue-153/README.md +js/docs/case-studies/issue-156/README.md +js/docs/shell-operators-implementation.md +js/eslint.config.js +js/examples/01-basic-streaming.mjs +js/examples/02-async-iterator.mjs +js/examples/03-file-and-console.mjs +js/examples/04-claude-jq-pipe.mjs +js/examples/CI-DEBUG-README.md +js/examples/README-examples.mjs +js/examples/README.md +js/examples/STREAMING_INTERFACES_SUMMARY.md +js/examples/add-test-timeouts.js +js/examples/ansi-default-preserved.mjs +js/examples/ansi-global-config.mjs +js/examples/ansi-reset-default.mjs +js/examples/ansi-strip-utils.mjs +js/examples/baseline-child-process.mjs +js/examples/baseline-claude-test.mjs +js/examples/baseline-working.mjs +js/examples/capture-mirror-comparison.mjs +js/examples/capture-mirror-default.mjs +js/examples/capture-mirror-performance.mjs +js/examples/capture-mirror-show-only.mjs +js/examples/capture-mirror-silent-processing.mjs +js/examples/ci-debug-baseline-vs-library.mjs +js/examples/ci-debug-es-module-loading.mjs +js/examples/ci-debug-signal-handling.mjs +js/examples/ci-debug-stdout-buffering.mjs +js/examples/ci-debug-test-timeouts.mjs +js/examples/claude-exact-file-output.mjs +js/examples/claude-exact-jq.mjs +js/examples/claude-exact-streaming.mjs +js/examples/claude-jq-pipeline.mjs +js/examples/claude-json-stream.mjs +js/examples/claude-streaming-basic.mjs +js/examples/claude-streaming-demo.mjs +js/examples/claude-streaming-final.mjs +js/examples/cleanup-verification-test.mjs +js/examples/colors-buffer-processing.mjs +js/examples/colors-default-preserved.mjs +js/examples/colors-per-command-config.mjs +js/examples/colors-strip-ansi.mjs +js/examples/commandstream-jq.mjs +js/examples/commandstream-working.mjs +js/examples/comprehensive-streams-demo.mjs +js/examples/ctrl-c-concurrent-processes.mjs +js/examples/ctrl-c-long-running-command.mjs +js/examples/ctrl-c-real-system-command.mjs +js/examples/ctrl-c-sleep-command.mjs +js/examples/ctrl-c-stdin-forwarding.mjs +js/examples/ctrl-c-virtual-command.mjs +js/examples/debug-already-started.mjs +js/examples/debug-ansi-processing.mjs +js/examples/debug-basic-streaming.mjs +js/examples/debug-buildshellcommand.mjs +js/examples/debug-child-process.mjs +js/examples/debug-child-state.mjs +js/examples/debug-chunking.mjs +js/examples/debug-command-parsing.mjs +js/examples/debug-complete-consolidation.mjs +js/examples/debug-echo-args.mjs +js/examples/debug-emit-timing.mjs +js/examples/debug-end-event.mjs +js/examples/debug-errexit.mjs +js/examples/debug-event-emission.mjs +js/examples/debug-event-timing.mjs +js/examples/debug-event-vs-result.mjs +js/examples/debug-exact-command.mjs +js/examples/debug-exact-test-scenario.mjs +js/examples/debug-execution-path.mjs +js/examples/debug-exit-command.mjs +js/examples/debug-exit-virtual.mjs +js/examples/debug-finish-consolidation.mjs +js/examples/debug-force-cleanup.mjs +js/examples/debug-getter-basic.mjs +js/examples/debug-getter-direct.mjs +js/examples/debug-getter-internals.mjs +js/examples/debug-handler-detection.mjs +js/examples/debug-idempotent-finish.mjs +js/examples/debug-idempotent-kill.mjs +js/examples/debug-interpolation-individual.mjs +js/examples/debug-interpolation-issue.mjs +js/examples/debug-jq-streaming.mjs +js/examples/debug-jq-tty-colors.mjs +js/examples/debug-kill-cleanup.mjs +js/examples/debug-kill-method.mjs +js/examples/debug-listener-interference.mjs +js/examples/debug-listener-lifecycle.mjs +js/examples/debug-listener-timing.mjs +js/examples/debug-listeners-property.mjs +js/examples/debug-map-methods.mjs +js/examples/debug-not-awaited-cleanup.mjs +js/examples/debug-off-method.mjs +js/examples/debug-option-merging.mjs +js/examples/debug-options.mjs +js/examples/debug-output.mjs +js/examples/debug-pattern-matching.mjs +js/examples/debug-pipeline-cat.mjs +js/examples/debug-pipeline-cleanup.mjs +js/examples/debug-pipeline-error-detailed.mjs +js/examples/debug-pipeline-error.mjs +js/examples/debug-pipeline-issue.mjs +js/examples/debug-pipeline-method.mjs +js/examples/debug-pipeline-stream.mjs +js/examples/debug-pipeline.mjs +js/examples/debug-process-exit-trace.mjs +js/examples/debug-process-path.mjs +js/examples/debug-property-check.mjs +js/examples/debug-resource-cleanup.mjs +js/examples/debug-shell-args.mjs +js/examples/debug-sigint-child-handler.mjs +js/examples/debug-sigint-forwarding.mjs +js/examples/debug-sigint-handler-install.mjs +js/examples/debug-sigint-handler-order.mjs +js/examples/debug-sigint-listeners.mjs +js/examples/debug-sigint-start-pattern.mjs +js/examples/debug-sigint-timer.mjs +js/examples/debug-simple-command.mjs +js/examples/debug-simple-getter.mjs +js/examples/debug-simple.mjs +js/examples/debug-simplified-finished.mjs +js/examples/debug-stack-overflow.mjs +js/examples/debug-stdin-simple.mjs +js/examples/debug-stdin.mjs +js/examples/debug-stream-emitter-isolated.mjs +js/examples/debug-stream-emitter.mjs +js/examples/debug-stream-events.mjs +js/examples/debug-stream-generator.mjs +js/examples/debug-stream-getter-issue.mjs +js/examples/debug-stream-getter.mjs +js/examples/debug-stream-internals.mjs +js/examples/debug-stream-method.mjs +js/examples/debug-stream-object.mjs +js/examples/debug-stream-properties.mjs +js/examples/debug-stream-timing.mjs +js/examples/debug-streaming.mjs +js/examples/debug-test-isolation.mjs +js/examples/debug-test-state.mjs +js/examples/debug-user-sigint.mjs +js/examples/debug-virtual-disable.mjs +js/examples/debug-virtual-vs-real.mjs +js/examples/debug-with-trace.mjs +js/examples/debug_parent_stream.mjs +js/examples/emulate-claude-stream.mjs +js/examples/emulated-streaming-direct.mjs +js/examples/emulated-streaming-jq-pipe.mjs +js/examples/emulated-streaming-sh-pipe.mjs +js/examples/events-build-process.mjs +js/examples/events-concurrent-streams.mjs +js/examples/events-error-handling.mjs +js/examples/events-file-monitoring.mjs +js/examples/events-interactive-simulation.mjs +js/examples/events-log-processing.mjs +js/examples/events-network-monitoring.mjs +js/examples/events-ping-basic.mjs +js/examples/events-progress-tracking.mjs +js/examples/events-stdin-input.mjs +js/examples/example-ansi-ls.mjs +js/examples/example-top.mjs +js/examples/final-ping-stdin-proof.mjs +js/examples/final-test-shell-operators.mjs +js/examples/final-working-examples.mjs +js/examples/gh-auth-test.mjs +js/examples/gh-delete-hang-test.mjs +js/examples/gh-gist-creation-test.mjs +js/examples/gh-gist-minimal-test.mjs +js/examples/gh-hang-exact-original.mjs +js/examples/gh-hang-reproduction.mjs +js/examples/gh-hang-test-with-redirect.mjs +js/examples/gh-hang-test-without-redirect.mjs +js/examples/gh-minimal-hang-check.mjs +js/examples/gh-operations-with-cd.mjs +js/examples/gh-output-test.mjs +js/examples/gh-reproduce-hang.mjs +js/examples/git-operations-with-cd.mjs +js/examples/interactive-math-calc.mjs +js/examples/interactive-top-fixed.mjs +js/examples/interactive-top-improved.mjs +js/examples/interactive-top-pty-logging.mjs +js/examples/interactive-top-pty.mjs +js/examples/interactive-top-with-logging.mjs +js/examples/interactive-top.mjs +js/examples/jq-color-demo.mjs +js/examples/jq-colors-streaming.mjs +js/examples/manual-ctrl-c-test.mjs +js/examples/methods-multiple-options.mjs +js/examples/methods-run-basic.mjs +js/examples/methods-start-basic.mjs +js/examples/node-compat-data-events.mjs +js/examples/node-compat-readable-event.mjs +js/examples/node-compat-small-buffer.mjs +js/examples/options-capture-false.mjs +js/examples/options-combined-settings.mjs +js/examples/options-custom-input.mjs +js/examples/options-default-behavior.mjs +js/examples/options-maximum-performance.mjs +js/examples/options-mirror-false.mjs +js/examples/options-performance-mode.mjs +js/examples/options-performance-optimization.mjs +js/examples/options-run-alias-demo.mjs +js/examples/options-run-alias.mjs +js/examples/options-silent-execution.mjs +js/examples/options-streaming-capture.mjs +js/examples/options-streaming-multiple.mjs +js/examples/options-streaming-silent.mjs +js/examples/options-streaming-stdin.mjs +js/examples/ping-streaming-filtered.mjs +js/examples/ping-streaming-interruptible.mjs +js/examples/ping-streaming-silent.mjs +js/examples/ping-streaming-simple.mjs +js/examples/ping-streaming-statistics.mjs +js/examples/ping-streaming-timestamps.mjs +js/examples/ping-streaming.mjs +js/examples/prove-ping-stdin-limitation.mjs +js/examples/readme-example.mjs +js/examples/realtime-json-stream.mjs +js/examples/reliable-stdin-commands.mjs +js/examples/reproduce-issue-135-v2.mjs +js/examples/reproduce-issue-135.mjs +js/examples/shell-cd-behavior.mjs +js/examples/sigint-forwarding-test.mjs +js/examples/sigint-handler-test.mjs +js/examples/simple-async-test.mjs +js/examples/simple-claude-test.mjs +js/examples/simple-event-test.mjs +js/examples/simple-jq-streaming.mjs +js/examples/simple-stream-demo.mjs +js/examples/simple-test-sleep.js +js/examples/simple-working-stdin.mjs +js/examples/streaming-behavior-test.mjs +js/examples/streaming-direct-command.mjs +js/examples/streaming-filtered-output.mjs +js/examples/streaming-grep-pipeline.mjs +js/examples/streaming-interactive-stdin.mjs +js/examples/streaming-jq-pipeline.mjs +js/examples/streaming-multistage-pipeline.mjs +js/examples/streaming-pipes-event-pattern.mjs +js/examples/streaming-pipes-multistage.mjs +js/examples/streaming-pipes-realtime-jq.mjs +js/examples/streaming-progress-tracking.mjs +js/examples/streaming-reusable-configs.mjs +js/examples/streaming-silent-capture.mjs +js/examples/streaming-test-simple.mjs +js/examples/streaming-virtual-pipeline.mjs +js/examples/syntax-basic-comparison.mjs +js/examples/syntax-basic-options.mjs +js/examples/syntax-combined-options.mjs +js/examples/syntax-command-chaining.mjs +js/examples/syntax-custom-directory.mjs +js/examples/syntax-custom-environment.mjs +js/examples/syntax-custom-stdin.mjs +js/examples/syntax-mixed-regular.mjs +js/examples/syntax-mixed-usage.mjs +js/examples/syntax-multiple-listeners.mjs +js/examples/syntax-piping-comparison.mjs +js/examples/syntax-reusable-config.mjs +js/examples/syntax-reusable-configs.mjs +js/examples/syntax-silent-operations.mjs +js/examples/syntax-stdin-option.mjs +js/examples/temp-sigint-test.mjs +js/examples/test-actual-buildshell.mjs +js/examples/test-async-streams-working.mjs +js/examples/test-async-streams.mjs +js/examples/test-auth-parse.mjs +js/examples/test-auto-quoting.mjs +js/examples/test-auto-start-fix.mjs +js/examples/test-baseline-sigint.mjs +js/examples/test-buffer-behavior.mjs +js/examples/test-buffers-simple.mjs +js/examples/test-bun-specific-issue.mjs +js/examples/test-bun-streaming.mjs +js/examples/test-cat-direct.mjs +js/examples/test-cat-pipe.mjs +js/examples/test-cd-behavior.mjs +js/examples/test-child-process-timing.mjs +js/examples/test-child-sigint-handler.mjs +js/examples/test-cleanup-simple.mjs +js/examples/test-comprehensive-tracing.mjs +js/examples/test-correct-space-handling.mjs +js/examples/test-ctrl-c-debug.mjs +js/examples/test-ctrl-c-inherit.mjs +js/examples/test-ctrl-c-sleep.mjs +js/examples/test-ctrl-c.mjs +js/examples/test-debug-new-options.mjs +js/examples/test-debug-pty.mjs +js/examples/test-debug-tee.mjs +js/examples/test-debug.mjs +js/examples/test-direct-jq.mjs +js/examples/test-direct-pipe-reading.mjs +js/examples/test-direct-pipe.sh +js/examples/test-double-quoting-prevention.mjs +js/examples/test-edge-cases-quoting.mjs +js/examples/test-events.mjs +js/examples/test-explicit-stdio.mjs +js/examples/test-final-streaming.mjs +js/examples/test-fix.mjs +js/examples/test-incremental-streaming.mjs +js/examples/test-individual-spawn.mjs +js/examples/test-inherit-stdout-not-stdin.mjs +js/examples/test-injection-protection.mjs +js/examples/test-interactive-streaming.mjs +js/examples/test-interactive-top.md +js/examples/test-interactive.mjs +js/examples/test-interpolation.mjs +js/examples/test-interrupt.mjs +js/examples/test-issue-135-comprehensive.mjs +js/examples/test-issue12-detailed.mjs +js/examples/test-issue12-exact.mjs +js/examples/test-jq-color.mjs +js/examples/test-jq-colors.mjs +js/examples/test-jq-compact.mjs +js/examples/test-jq-native.sh +js/examples/test-jq-pipeline-behavior.mjs +js/examples/test-jq-realtime.mjs +js/examples/test-manual-start.mjs +js/examples/test-mixed-quoting.mjs +js/examples/test-multi-stream.mjs +js/examples/test-multistage-debug.mjs +js/examples/test-native-spawn-vs-command-stream.mjs +js/examples/test-no-parse-pipeline.mjs +js/examples/test-non-virtual.mjs +js/examples/test-operators.mjs +js/examples/test-parent-continues.mjs +js/examples/test-path-interpolation.mjs +js/examples/test-ping-kill-and-stdin.mjs +js/examples/test-ping.mjs +js/examples/test-pty-spawn.mjs +js/examples/test-pty.mjs +js/examples/test-quote-behavior-summary.mjs +js/examples/test-quote-edge-cases.mjs +js/examples/test-quote-parsing.mjs +js/examples/test-raw-function.mjs +js/examples/test-raw-streaming.mjs +js/examples/test-readme-examples.mjs +js/examples/test-real-cat.mjs +js/examples/test-real-commands.mjs +js/examples/test-real-shell.mjs +js/examples/test-real-stdin-commands.mjs +js/examples/test-runner-batched.mjs +js/examples/test-runner-simple.mjs +js/examples/test-runner.mjs +js/examples/test-scope-parse.mjs +js/examples/test-sh-pipeline.mjs +js/examples/test-shell-detection.mjs +js/examples/test-shell-parser.mjs +js/examples/test-sigint-behavior.mjs +js/examples/test-sigint-handling.sh +js/examples/test-simple-pipe.mjs +js/examples/test-simple-streaming.mjs +js/examples/test-sleep-stdin.js +js/examples/test-sleep.mjs +js/examples/test-smart-quoting.mjs +js/examples/test-spaces-in-path.mjs +js/examples/test-special-chars-quoting.mjs +js/examples/test-stdin-after-start.mjs +js/examples/test-stdin-simple.mjs +js/examples/test-stdin-timing.mjs +js/examples/test-stdio-combinations.mjs +js/examples/test-stream-access.mjs +js/examples/test-stream-cleanup.mjs +js/examples/test-stream-readers.mjs +js/examples/test-streaming-final.mjs +js/examples/test-streaming-interfaces.mjs +js/examples/test-streaming-timing.mjs +js/examples/test-streaming.mjs +js/examples/test-streams-stdin-comprehensive.mjs +js/examples/test-streams-stdin-ctrl-c.mjs +js/examples/test-template-literal.mjs +js/examples/test-template-vs-interpolation.mjs +js/examples/test-timing.mjs +js/examples/test-top-inherit-stdout-stdin-control.mjs +js/examples/test-top-quit-stdin.mjs +js/examples/test-trace-option.mjs +js/examples/test-user-double-quotes.mjs +js/examples/test-user-single-quotes.mjs +js/examples/test-verbose.mjs +js/examples/test-verbose2.mjs +js/examples/test-virtual-streaming.mjs +js/examples/test-waiting-command.mjs +js/examples/test-waiting-commands.mjs +js/examples/test-watch-mode.mjs +js/examples/test-yes-cancellation.mjs +js/examples/test-yes-detailed.mjs +js/examples/test-yes-trace.mjs +js/examples/trace-abort-controller.mjs +js/examples/trace-error-handling.mjs +js/examples/trace-pipeline-command.mjs +js/examples/trace-signal-handling.mjs +js/examples/trace-simple-command.mjs +js/examples/trace-stderr-output.mjs +js/examples/verify-fix-both-runtimes.mjs +js/examples/verify-issue12-fixed.mjs +js/examples/which-command-common-commands.mjs +js/examples/which-command-gh-test.mjs +js/examples/which-command-nonexistent.mjs +js/examples/which-command-system-comparison.mjs +js/examples/working-example.mjs +js/examples/working-stdin-examples.mjs +js/examples/working-streaming-demo.mjs +js/package-lock.json +js/package.json +js/scripts/changeset-version.mjs +js/scripts/create-github-release.mjs +js/scripts/create-manual-changeset.mjs +js/scripts/format-github-release.mjs +js/scripts/format-release-notes.mjs +js/scripts/instant-version-bump.mjs +js/scripts/merge-changesets.mjs +js/scripts/publish-to-npm.mjs +js/scripts/setup-npm.mjs +js/scripts/validate-changeset.mjs +js/scripts/version-and-commit.mjs +js/src/$.ansi.mjs +js/src/$.mjs +js/src/$.process-runner-base.mjs +js/src/$.process-runner-execution.mjs +js/src/$.process-runner-orchestration.mjs +js/src/$.process-runner-pipeline.mjs +js/src/$.process-runner-stream-kill.mjs +js/src/$.process-runner-virtual.mjs +js/src/$.quote.mjs +js/src/$.result.mjs +js/src/$.shell-settings.mjs +js/src/$.shell.mjs +js/src/$.state.mjs +js/src/$.stream-emitter.mjs +js/src/$.stream-utils.mjs +js/src/$.trace.mjs +js/src/$.utils.mjs +js/src/$.virtual-commands.mjs +js/src/commands/$.basename.mjs +js/src/commands/$.cat.mjs +js/src/commands/$.cd.mjs +js/src/commands/$.cp.mjs +js/src/commands/$.dirname.mjs +js/src/commands/$.echo.mjs +js/src/commands/$.env.mjs +js/src/commands/$.exit.mjs +js/src/commands/$.false.mjs +js/src/commands/$.ls.mjs +js/src/commands/$.mkdir.mjs +js/src/commands/$.mv.mjs +js/src/commands/$.pwd.mjs +js/src/commands/$.rm.mjs +js/src/commands/$.seq.mjs +js/src/commands/$.sleep.mjs +js/src/commands/$.test.mjs +js/src/commands/$.touch.mjs +js/src/commands/$.true.mjs +js/src/commands/$.which.mjs +js/src/commands/$.yes.mjs +js/src/commands/index.mjs +js/src/shell-parser.mjs +js/tests/$.features.test.mjs +js/tests/$.test.mjs +js/tests/array-interpolation.test.mjs +js/tests/builtin-commands.test.mjs +js/tests/bun-shell-path-fix.test.mjs +js/tests/bun.features.test.mjs +js/tests/cd-virtual-command.test.mjs +js/tests/cleanup-verification.test.mjs +js/tests/ctrl-c-baseline.test.mjs +js/tests/ctrl-c-basic.test.mjs +js/tests/ctrl-c-library.test.mjs +js/tests/ctrl-c-signal.test.mjs +js/tests/examples.test.mjs +js/tests/execa.features.test.mjs +js/tests/gh-commands.test.mjs +js/tests/gh-gist-operations.test.mjs +js/tests/git-gh-cd.test.mjs +js/tests/interactive-option.test.mjs +js/tests/interactive-streaming.test.mjs +js/tests/issue-135-final.test.mjs +js/tests/jq-color-behavior.test.mjs +js/tests/jq.test.mjs +js/tests/options-examples.test.mjs +js/tests/options-syntax.test.mjs +js/tests/path-interpolation.test.mjs +js/tests/pipe.test.mjs +js/tests/raw-function.test.mjs +js/tests/readme-examples.test.mjs +js/tests/repository-layout.test.mjs +js/tests/resource-cleanup-internals.test.mjs +js/tests/shell-settings.test.mjs +js/tests/sigint-cleanup-isolated.test.mjs +js/tests/sigint-cleanup.test.mjs +js/tests/start-run-edge-cases.test.mjs +js/tests/start-run-options.test.mjs +js/tests/stderr-output-handling.test.mjs +js/tests/streaming-interfaces.test.mjs +js/tests/sync.test.mjs +js/tests/system-pipe.test.mjs +js/tests/test-cleanup.mjs +js/tests/test-helper-fixed.mjs +js/tests/test-helper-v2.mjs +js/tests/test-helper.mjs +js/tests/test-sigint-child.js +js/tests/text-method.test.mjs +js/tests/virtual.test.mjs +js/tests/yes-command-cleanup.test.mjs +js/tests/zx.features.test.mjs +rust/BEST-PRACTICES.md +rust/CHANGELOG.md +rust/Cargo.lock +rust/Cargo.toml +rust/README.md +rust/changelog.d/20260608_issue_160_separate_language_releases.md +rust/changelog.d/README.md +rust/scripts/bump-version.rs +rust/scripts/check-changelog-fragment.rs +rust/scripts/check-crate-size.rs +rust/scripts/check-file-size.rs +rust/scripts/check-release-needed.rs +rust/scripts/check-version-modification.rs +rust/scripts/collect-changelog.rs +rust/scripts/create-changelog-fragment.rs +rust/scripts/create-github-release.rs +rust/scripts/detect-code-changes.rs +rust/scripts/get-bump-type.rs +rust/scripts/get-version.rs +rust/scripts/git-config.rs +rust/scripts/publish-crate.rs +rust/scripts/rust-paths.rs +rust/scripts/version-and-commit.rs +rust/scripts/wait-for-crate.rs +rust/src/ansi.rs +rust/src/commands/basename.rs +rust/src/commands/cat.rs +rust/src/commands/cd.rs +rust/src/commands/cp.rs +rust/src/commands/dirname.rs +rust/src/commands/echo.rs +rust/src/commands/env.rs +rust/src/commands/exit.rs +rust/src/commands/false.rs +rust/src/commands/ls.rs +rust/src/commands/mkdir.rs +rust/src/commands/mod.rs +rust/src/commands/mv.rs +rust/src/commands/pwd.rs +rust/src/commands/rm.rs +rust/src/commands/seq.rs +rust/src/commands/sleep.rs +rust/src/commands/test.rs +rust/src/commands/touch.rs +rust/src/commands/true.rs +rust/src/commands/which.rs +rust/src/commands/yes.rs +rust/src/events.rs +rust/src/lib.rs +rust/src/macros.rs +rust/src/main.rs +rust/src/pipeline.rs +rust/src/quote.rs +rust/src/shell_parser.rs +rust/src/state.rs +rust/src/stream.rs +rust/src/trace.rs +rust/src/utils.rs +rust/tests/builtin_commands.rs +rust/tests/events.rs +rust/tests/macros.rs +rust/tests/pipeline.rs +rust/tests/process_runner.rs +rust/tests/shell_parser.rs +rust/tests/state.rs +rust/tests/stream.rs +rust/tests/utils.rs +rust/tests/virtual_commands.rs diff --git a/docs/case-studies/issue-160/data/current-file-tree-before.txt b/docs/case-studies/issue-160/data/current-file-tree-before.txt new file mode 100644 index 0000000..74ed202 --- /dev/null +++ b/docs/case-studies/issue-160/data/current-file-tree-before.txt @@ -0,0 +1,671 @@ +CHANGELOG.md +.gitpod.Dockerfile +package.json +.changeset/README.md +.changeset/config.json +gitpod-backup-auth.sh +.jscpd.json +gitpod-restore-auth.sh +package-lock.json +claude-profile-list.sh +claude-profile-restore.sh +.prettierignore +deno.json +.claude/settings.local.json +.github/DEPLOYMENT.md +experiments/issue-156/01-default-behavior.mjs +experiments/issue-156/04-calculator-bug-repro.mjs +experiments/issue-156/03-bash-comparison.sh +experiments/issue-156/02-errexit-enabled.mjs +.prettierrc +.gitpod.yml +.npmignore +claude-profiles.mjs +bunfig.toml +.gitignore +eslint.config.js +.github/workflows/release.yml +.husky/pre-commit +scripts/merge-changesets.mjs +scripts/setup-npm.mjs +scripts/changeset-version.mjs +scripts/validate-changeset.mjs +scripts/format-github-release.mjs +scripts/publish-to-crates.mjs +scripts/publish-to-npm.mjs +scripts/sync-rust-version.mjs +scripts/format-release-notes.mjs +scripts/create-github-release.mjs +scripts/version-and-commit.mjs +scripts/create-manual-changeset.mjs +scripts/instant-version-bump.mjs +.gitkeep +README.md +claude-profile-save.sh +LICENSE +bun.lock +docs/case-studies/issue-160/data/current-file-tree-before.txt +docs/case-studies/issue-160/data/issue-160.json +docs/case-studies/issue-160/data/issue-160-comments.json +.git/hooks/applypatch-msg.sample +.git/hooks/pre-commit.sample +.git/hooks/pre-rebase.sample +.git/hooks/pre-merge-commit.sample +.git/hooks/update.sample +.git/hooks/push-to-checkout.sample +.git/hooks/post-update.sample +.git/hooks/sendemail-validate.sample +.git/hooks/fsmonitor-watchman.sample +.git/hooks/pre-push.sample +.git/hooks/pre-applypatch.sample +.git/hooks/pre-receive.sample +.git/hooks/commit-msg.sample +.git/hooks/prepare-commit-msg.sample +.git/HEAD +.git/refs/remotes/origin/HEAD +.git/refs/remotes/origin/issue-160-a2a2313cf693 +.git/refs/heads/issue-160-a2a2313cf693 +.git/refs/heads/main +.git/info/exclude +.git/objects/40/c13d5f636f5c6beec7509ceeada6f38067cb15 +.git/objects/86/6cee6dddffc0b050dca29b1144846a0fca25cf +.git/objects/a6/7422e87093aa826e2ae4bcdfac8033f6d22b03 +.git/objects/pack/pack-62b221024bdb2da6252eaeb62f83ac09ea9c5e4b.rev +.git/objects/pack/pack-62b221024bdb2da6252eaeb62f83ac09ea9c5e4b.pack +.git/objects/pack/pack-62b221024bdb2da6252eaeb62f83ac09ea9c5e4b.idx +.git/FETCH_HEAD +.git/COMMIT_EDITMSG +.git/config +.git/description +.git/logs/HEAD +.git/logs/refs/remotes/origin/HEAD +.git/logs/refs/remotes/origin/issue-160-a2a2313cf693 +docs/case-studies/issue-158/README.md +.git/logs/refs/heads/issue-160-a2a2313cf693 +.git/logs/refs/heads/main +.git/packed-refs +.git/index +docs/case-studies/issue-158/data/rust-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-158/data/crates-command-stream.json +docs/case-studies/issue-158/data/pr-159-conversation-comments.json +docs/case-studies/issue-158/data/js-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-158/data/pr-159-review-comments.json +docs/case-studies/issue-158/data/issue-158-comments.json +docs/case-studies/issue-158/data/checks-release-27134991249.log.gz +docs/case-studies/issue-158/data/pr-159-reviews.json +docs/case-studies/issue-158/data/recent-runs-branch.json +docs/case-studies/issue-158/data/run-27134991249.json +docs/case-studies/issue-158/data/python-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-158/data/run-27135178897.json +docs/case-studies/issue-158/data/issue-158-gh-view.txt +docs/case-studies/issue-158/data/checks-release-27135178897.log.gz +docs/case-studies/issue-158/data/pr-159.json +docs/case-studies/issue-158/data/meta-language.repo.json +docs/case-studies/issue-158/data/start.repo.json +docs/case-studies/issue-158/data/csharp-ai-driven-development-pipeline-template.repo.json +docs/case-studies/issue-158/templates/csharp-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-158/templates/js-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-158/templates/meta-language.file-tree.txt +rust/BEST-PRACTICES.md +docs/case-studies/issue-158/templates/csharp-ai-driven-development-pipeline-template/release.yml +docs/case-studies/issue-158/templates/meta-language/check-release-needed.rs +docs/case-studies/issue-158/templates/meta-language/publish-crate.rs +docs/case-studies/issue-158/templates/meta-language/wait-for-crate.rs +docs/case-studies/issue-158/templates/meta-language/release.yml +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template.file-tree.txt +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template/check-release-needed.rs +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template/publish-crate.rs +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template/wait-for-crate.rs +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template/rust-paths.rs +docs/case-studies/issue-158/templates/rust-ai-driven-development-pipeline-template/release.yml +js/BEST-PRACTICES.md +docs/case-studies/issue-158/templates/start/check-release-needed.mjs +docs/case-studies/issue-158/templates/start/publish-to-crates.mjs +docs/case-studies/issue-158/templates/start/preflight-credentials.mjs +docs/case-studies/issue-158/templates/start/rust.yml +docs/case-studies/issue-158/templates/start.file-tree.txt +docs/case-studies/issue-158/templates/python-ai-driven-development-pipeline-template/release.yml +docs/case-studies/issue-158/templates/python-ai-driven-development-pipeline-template.file-tree.txt +js/tests/git-gh-cd.test.mjs +js/tests/sigint-cleanup.test.mjs +js/tests/jq-color-behavior.test.mjs +js/tests/array-interpolation.test.mjs +js/tests/readme-examples.test.mjs +js/tests/test-helper-v2.mjs +js/tests/ctrl-c-signal.test.mjs +js/tests/virtual.test.mjs +js/tests/yes-command-cleanup.test.mjs +js/tests/$.test.mjs +js/tests/text-method.test.mjs +js/tests/publish-to-crates.test.mjs +js/tests/$.features.test.mjs +js/tests/start-run-edge-cases.test.mjs +js/tests/options-examples.test.mjs +js/tests/system-pipe.test.mjs +js/tests/resource-cleanup-internals.test.mjs +js/tests/jq.test.mjs +js/tests/cleanup-verification.test.mjs +js/tests/test-helper-fixed.mjs +js/tests/streaming-interfaces.test.mjs +js/tests/bun-shell-path-fix.test.mjs +js/tests/raw-function.test.mjs +js/tests/sync.test.mjs +js/tests/execa.features.test.mjs +js/tests/zx.features.test.mjs +js/docs/SHELL_OPERATORS_IMPLEMENTATION.md +js/docs/shell-operators-implementation.md +js/docs/IMPLEMENTATION_NOTES.md +js/tests/cd-virtual-command.test.mjs +js/tests/pipe.test.mjs +js/tests/stderr-output-handling.test.mjs +js/tests/interactive-streaming.test.mjs +js/tests/bun.features.test.mjs +js/tests/test-cleanup.mjs +js/tests/ctrl-c-baseline.test.mjs +js/tests/options-syntax.test.mjs +js/tests/test-sigint-child.js +js/tests/builtin-commands.test.mjs +js/tests/ctrl-c-library.test.mjs +js/tests/interactive-option.test.mjs +js/tests/path-interpolation.test.mjs +js/tests/sigint-cleanup-isolated.test.mjs +js/tests/gh-commands.test.mjs +js/tests/shell-settings.test.mjs +js/tests/issue-135-final.test.mjs +js/tests/examples.test.mjs +js/tests/ctrl-c-basic.test.mjs +js/tests/test-helper.mjs +js/tests/gh-gist-operations.test.mjs +js/tests/start-run-options.test.mjs +js/tests/sync-rust-version.test.mjs +rust/Cargo.toml +rust/Cargo.lock +js/docs/case-studies/issue-156/README.md +rust/src/pipeline.rs +js/docs/case-studies/issue-146/README.md +rust/src/commands/false.rs +rust/src/commands/yes.rs +rust/src/commands/mv.rs +rust/src/commands/pwd.rs +rust/src/commands/sleep.rs +rust/src/commands/exit.rs +rust/src/commands/true.rs +rust/src/commands/cat.rs +rust/src/commands/dirname.rs +rust/src/commands/mod.rs +rust/src/commands/cp.rs +rust/src/commands/ls.rs +rust/src/commands/which.rs +rust/src/commands/cd.rs +rust/src/commands/rm.rs +rust/src/commands/test.rs +rust/src/commands/basename.rs +rust/src/commands/seq.rs +rust/src/commands/echo.rs +rust/src/commands/env.rs +rust/src/commands/touch.rs +rust/src/commands/mkdir.rs +rust/src/state.rs +rust/src/quote.rs +rust/src/trace.rs +rust/src/shell_parser.rs +rust/src/stream.rs +rust/src/macros.rs +rust/src/events.rs +rust/src/ansi.rs +rust/src/main.rs +rust/src/lib.rs +rust/src/utils.rs +js/docs/case-studies/issue-153/README.md +js/docs/case-studies/issue-144/failures-summary.md +js/docs/case-studies/issue-144/README.md +js/src/$.virtual-commands.mjs +js/src/commands/index.mjs +js/src/commands/$.true.mjs +js/src/commands/$.dirname.mjs +js/src/commands/$.pwd.mjs +js/src/commands/$.echo.mjs +js/src/commands/$.exit.mjs +js/src/commands/$.cd.mjs +js/src/commands/$.false.mjs +js/src/commands/$.sleep.mjs +js/src/commands/$.which.mjs +js/src/commands/$.cp.mjs +js/src/commands/$.yes.mjs +js/src/commands/$.seq.mjs +js/src/commands/$.mv.mjs +js/src/commands/$.ls.mjs +js/src/commands/$.mkdir.mjs +js/src/commands/$.cat.mjs +js/src/commands/$.rm.mjs +js/src/commands/$.basename.mjs +js/src/commands/$.touch.mjs +js/src/commands/$.env.mjs +js/src/commands/$.test.mjs +js/src/$.process-runner-orchestration.mjs +js/src/$.result.mjs +js/src/$.shell-settings.mjs +js/src/$.utils.mjs +js/src/$.ansi.mjs +js/src/$.quote.mjs +js/src/$.process-runner-base.mjs +js/src/$.stream-emitter.mjs +js/src/$.process-runner-pipeline.mjs +js/src/$.process-runner-virtual.mjs +js/src/$.stream-utils.mjs +js/src/$.shell.mjs +js/src/$.state.mjs +js/src/$.process-runner-execution.mjs +js/src/$.trace.mjs +js/src/$.mjs +js/src/$.process-runner-stream-kill.mjs +js/src/shell-parser.mjs +js/examples/which-command-nonexistent.mjs +js/examples/test-verbose2.mjs +js/examples/test-debug-new-options.mjs +js/examples/claude-json-stream.mjs +js/examples/which-command-system-comparison.mjs +js/examples/reliable-stdin-commands.mjs +js/examples/ci-debug-es-module-loading.mjs +js/examples/test-real-stdin-commands.mjs +js/examples/debug-sigint-timer.mjs +js/examples/debug-stdin.mjs +js/examples/test-sigint-handling.sh +js/examples/test-user-single-quotes.mjs +js/examples/test-ctrl-c-sleep.mjs +js/examples/test-scope-parse.mjs +js/examples/test-operators.mjs +js/examples/manual-ctrl-c-test.mjs +js/examples/test-streaming.mjs +js/examples/capture-mirror-performance.mjs +js/examples/test-cd-behavior.mjs +js/examples/test-buffers-simple.mjs +js/examples/trace-pipeline-command.mjs +js/examples/test-sigint-behavior.mjs +js/examples/debug-exit-virtual.mjs +js/examples/streaming-pipes-event-pattern.mjs +js/examples/debug-sigint-forwarding.mjs +js/examples/test-real-shell.mjs +js/examples/debug-exact-test-scenario.mjs +js/examples/test-virtual-streaming.mjs +js/examples/test-verbose.mjs +js/examples/test-interactive-top.md +js/examples/test-child-sigint-handler.mjs +js/examples/events-progress-tracking.mjs +js/examples/test-debug.mjs +js/examples/syntax-stdin-option.mjs +js/examples/colors-strip-ansi.mjs +js/examples/debug-pipeline-cleanup.mjs +js/examples/debug-test-state.mjs +js/examples/syntax-mixed-regular.mjs +js/examples/interactive-top-with-logging.mjs +js/examples/methods-start-basic.mjs +js/examples/test-yes-detailed.mjs +js/examples/test-cat-pipe.mjs +js/examples/claude-jq-pipeline.mjs +js/examples/emulated-streaming-jq-pipe.mjs +js/examples/debug-pipeline-cat.mjs +js/examples/test-jq-realtime.mjs +js/examples/baseline-working.mjs +js/examples/test-pty-spawn.mjs +js/examples/trace-abort-controller.mjs +js/examples/streaming-interactive-stdin.mjs +js/examples/test-simple-streaming.mjs +js/examples/debug-simplified-finished.mjs +js/examples/test-async-streams-working.mjs +js/examples/temp-sigint-test.mjs +js/examples/test-bun-specific-issue.mjs +js/examples/working-streaming-demo.mjs +js/examples/streaming-reusable-configs.mjs +js/examples/debug-complete-consolidation.mjs +js/examples/debug-simple-getter.mjs +js/examples/test-top-inherit-stdout-stdin-control.mjs +js/examples/debug-stream-events.mjs +js/examples/node-compat-readable-event.mjs +js/examples/claude-streaming-final.mjs +js/examples/debug-not-awaited-cleanup.mjs +js/examples/test-ping.mjs +js/examples/streaming-jq-pipeline.mjs +js/examples/debug-pipeline-error.mjs +js/examples/simple-working-stdin.mjs +js/examples/debug-simple-command.mjs +js/examples/test-quote-parsing.mjs +js/examples/streaming-multistage-pipeline.mjs +js/examples/options-streaming-silent.mjs +js/examples/debug-already-started.mjs +js/examples/options-maximum-performance.mjs +js/examples/debug-getter-internals.mjs +js/examples/streaming-virtual-pipeline.mjs +js/examples/syntax-reusable-configs.mjs +js/examples/test-interpolation.mjs +js/examples/debug-kill-cleanup.mjs +js/examples/test-final-streaming.mjs +js/examples/test-quote-edge-cases.mjs +js/examples/streaming-direct-command.mjs +js/examples/test-watch-mode.mjs +js/examples/which-command-common-commands.mjs +js/examples/debug-simple.mjs +js/examples/test-native-spawn-vs-command-stream.mjs +js/examples/events-network-monitoring.mjs +js/examples/baseline-child-process.mjs +js/examples/test-issue12-exact.mjs +js/examples/interactive-top-pty-logging.mjs +js/examples/syntax-piping-comparison.mjs +js/examples/claude-exact-jq.mjs +js/examples/options-performance-optimization.mjs +js/examples/test-waiting-command.mjs +js/examples/ctrl-c-concurrent-processes.mjs +js/examples/test-path-interpolation.mjs +js/examples/test-multistage-debug.mjs +js/examples/example-top.mjs +js/examples/events-file-monitoring.mjs +js/examples/test-runner-simple.mjs +js/examples/interactive-math-calc.mjs +js/examples/debug-stream-emitter-isolated.mjs +js/examples/test-jq-color.mjs +js/examples/debug-execution-path.mjs +js/examples/test-explicit-stdio.mjs +js/examples/test-jq-colors.mjs +js/examples/colors-default-preserved.mjs +js/examples/emulate-claude-stream.mjs +js/examples/debug-sigint-listeners.mjs +js/examples/test-incremental-streaming.mjs +js/examples/interactive-top-pty.mjs +js/examples/test-issue-135-comprehensive.mjs +js/examples/test-shell-parser.mjs +js/examples/methods-multiple-options.mjs +js/examples/debug-buildshellcommand.mjs +js/examples/test-jq-native.sh +js/examples/interactive-top-fixed.mjs +js/examples/ci-debug-stdout-buffering.mjs +js/examples/debug-pipeline-method.mjs +js/examples/debug-chunking.mjs +js/examples/syntax-mixed-usage.mjs +js/examples/debug-stream-object.mjs +js/examples/test-inherit-stdout-not-stdin.mjs +js/examples/debug-stream-properties.mjs +js/examples/test-streams-stdin-ctrl-c.mjs +js/examples/test-raw-function.mjs +js/examples/simple-jq-streaming.mjs +js/examples/baseline-claude-test.mjs +js/examples/debug-listeners-property.mjs +js/examples/debug-virtual-vs-real.mjs +js/examples/debug-idempotent-kill.mjs +js/examples/ping-streaming-simple.mjs +js/examples/debug-stream-getter-issue.mjs +js/examples/README-examples.mjs +js/examples/syntax-command-chaining.mjs +js/examples/test-manual-start.mjs +js/examples/streaming-pipes-multistage.mjs +js/examples/test-ctrl-c-inherit.mjs +js/examples/working-stdin-examples.mjs +js/examples/debug-sigint-start-pattern.mjs +js/examples/working-example.mjs +js/examples/debug-user-sigint.mjs +js/examples/capture-mirror-show-only.mjs +js/examples/events-log-processing.mjs +js/examples/test-bun-streaming.mjs +js/examples/streaming-behavior-test.mjs +js/examples/debug-ansi-processing.mjs +js/examples/test-trace-option.mjs +js/examples/options-mirror-false.mjs +js/examples/test-ping-kill-and-stdin.mjs +js/examples/test-no-parse-pipeline.mjs +js/examples/emulated-streaming-direct.mjs +js/examples/ping-streaming-silent.mjs +js/examples/test-readme-examples.mjs +js/examples/test-simple-pipe.mjs +js/examples/ping-streaming.mjs +js/examples/debug-stdin-simple.mjs +js/examples/test-debug-tee.mjs +js/examples/debug-interpolation-issue.mjs +js/examples/test-fix.mjs +js/examples/debug-process-path.mjs +js/examples/test-double-quoting-prevention.mjs +js/examples/debug-pipeline-error-detailed.mjs +js/examples/options-default-behavior.mjs +js/examples/debug-event-vs-result.mjs +js/examples/test-interrupt.mjs +js/examples/simple-test-sleep.js +js/examples/example-ansi-ls.mjs +js/examples/debug-option-merging.mjs +js/examples/options-streaming-multiple.mjs +js/examples/jq-color-demo.mjs +js/examples/debug-errexit.mjs +js/examples/syntax-combined-options.mjs +js/examples/test-debug-pty.mjs +js/examples/syntax-basic-options.mjs +js/examples/debug-jq-tty-colors.mjs +js/examples/options-run-alias.mjs +js/examples/verify-fix-both-runtimes.mjs +js/examples/debug-force-cleanup.mjs +js/examples/ansi-strip-utils.mjs +js/examples/debug-streaming.mjs +js/examples/sigint-handler-test.mjs +js/examples/debug-pipeline-issue.mjs +js/examples/debug-event-emission.mjs +js/examples/trace-error-handling.mjs +js/examples/events-stdin-input.mjs +js/examples/CI-DEBUG-README.md +js/examples/options-combined-settings.mjs +js/examples/03-file-and-console.mjs +js/examples/test-cat-direct.mjs +js/examples/interactive-top.mjs +js/examples/test-streaming-interfaces.mjs +js/examples/options-streaming-capture.mjs +js/examples/test-direct-pipe-reading.mjs +js/examples/test-special-chars-quoting.mjs +js/examples/ping-streaming-filtered.mjs +js/examples/capture-mirror-default.mjs +js/examples/debug-listener-interference.mjs +js/examples/debug-resource-cleanup.mjs +js/examples/claude-streaming-basic.mjs +js/examples/claude-exact-streaming.mjs +js/examples/test-ctrl-c.mjs +js/examples/debug-emit-timing.mjs +js/examples/ctrl-c-virtual-command.mjs +js/examples/debug-getter-direct.mjs +js/examples/streaming-grep-pipeline.mjs +js/examples/debug-stream-timing.mjs +js/examples/test-spaces-in-path.mjs +js/examples/options-streaming-stdin.mjs +js/examples/readme-example.mjs +js/examples/test-auth-parse.mjs +js/examples/test-streaming-timing.mjs +js/examples/options-performance-mode.mjs +js/examples/debug_parent_stream.mjs +js/examples/interactive-top-improved.mjs +js/examples/test-user-double-quotes.mjs +js/examples/claude-streaming-demo.mjs +js/examples/test-template-literal.mjs +js/examples/02-async-iterator.mjs +js/examples/test-auto-quoting.mjs +js/examples/debug-virtual-disable.mjs +js/examples/test-issue12-detailed.mjs +js/examples/01-basic-streaming.mjs +js/examples/test-buffer-behavior.mjs +js/examples/which-command-gh-test.mjs +js/examples/gh-hang-test-without-redirect.mjs +js/examples/test-stream-readers.mjs +js/examples/ctrl-c-sleep-command.mjs +js/examples/debug-kill-method.mjs +js/examples/debug-stack-overflow.mjs +js/examples/test-real-cat.mjs +js/examples/debug-child-process.mjs +js/examples/emulated-streaming-sh-pipe.mjs +js/examples/gh-output-test.mjs +js/examples/colors-buffer-processing.mjs +js/examples/test-yes-cancellation.mjs +js/examples/debug-map-methods.mjs +js/examples/gh-hang-test-with-redirect.mjs +js/examples/final-working-examples.mjs +js/examples/ctrl-c-real-system-command.mjs +js/examples/node-compat-data-events.mjs +js/examples/debug-pattern-matching.mjs +js/examples/events-interactive-simulation.mjs +js/examples/test-child-process-timing.mjs +js/examples/syntax-basic-comparison.mjs +js/examples/test-ctrl-c-debug.mjs +js/examples/options-capture-false.mjs +js/examples/debug-test-isolation.mjs +js/examples/sigint-forwarding-test.mjs +js/examples/trace-simple-command.mjs +js/examples/debug-exit-command.mjs +js/examples/options-run-alias-demo.mjs +js/examples/test-multi-stream.mjs +js/examples/options-custom-input.mjs +js/examples/test-stream-access.mjs +js/examples/ctrl-c-long-running-command.mjs +js/examples/test-direct-pipe.sh +js/examples/test-runner.mjs +js/examples/test-jq-compact.mjs +js/examples/simple-async-test.mjs +js/examples/test-comprehensive-tracing.mjs +js/examples/ci-debug-signal-handling.mjs +js/examples/verify-issue12-fixed.mjs +js/examples/events-concurrent-streams.mjs +js/examples/debug-shell-args.mjs +js/examples/comprehensive-streams-demo.mjs +js/examples/debug-stream-generator.mjs +js/examples/test-stdin-after-start.mjs +js/examples/test-shell-detection.mjs +js/examples/test-raw-streaming.mjs +js/examples/streaming-filtered-output.mjs +js/examples/trace-stderr-output.mjs +js/examples/ping-streaming-timestamps.mjs +js/examples/debug-stream-method.mjs +js/examples/test-interactive.mjs +js/examples/test-individual-spawn.mjs +js/examples/ansi-default-preserved.mjs +js/examples/test-direct-jq.mjs +js/examples/debug-options.mjs +js/examples/test-non-virtual.mjs +js/examples/test-parent-continues.mjs +js/examples/shell-cd-behavior.mjs +js/examples/debug-handler-detection.mjs +js/examples/options-silent-execution.mjs +js/examples/simple-stream-demo.mjs +js/examples/gh-auth-test.mjs +js/examples/04-claude-jq-pipe.mjs +js/examples/final-ping-stdin-proof.mjs +js/examples/test-edge-cases-quoting.mjs +js/examples/capture-mirror-silent-processing.mjs +js/examples/debug-off-method.mjs +js/examples/test-sleep.mjs +js/examples/test-smart-quoting.mjs +js/examples/debug-stream-emitter.mjs +js/examples/test-stream-cleanup.mjs +js/examples/ctrl-c-stdin-forwarding.mjs +js/examples/debug-finish-consolidation.mjs +js/examples/test-sh-pipeline.mjs +js/examples/ping-streaming-statistics.mjs +js/examples/git-operations-with-cd.mjs +js/examples/debug-pipeline-stream.mjs +js/examples/test-jq-pipeline-behavior.mjs +js/examples/simple-event-test.mjs +js/examples/debug-sigint-child-handler.mjs +js/examples/test-top-quit-stdin.mjs +js/examples/test-yes-trace.mjs +js/examples/ansi-reset-default.mjs +js/examples/test-stdin-timing.mjs +js/examples/commandstream-jq.mjs +js/examples/streaming-pipes-realtime-jq.mjs +js/examples/test-mixed-quoting.mjs +js/examples/test-real-commands.mjs +js/examples/jq-colors-streaming.mjs +js/examples/gh-minimal-hang-check.mjs +js/examples/test-stdio-combinations.mjs +js/examples/test-async-streams.mjs +js/examples/test-template-vs-interpolation.mjs +js/examples/debug-sigint-handler-install.mjs +js/examples/streaming-silent-capture.mjs +js/examples/cleanup-verification-test.mjs +js/examples/syntax-custom-environment.mjs +js/examples/claude-exact-file-output.mjs +js/examples/test-timing.mjs +js/examples/reproduce-issue-135-v2.mjs +js/examples/gh-delete-hang-test.mjs +js/examples/commandstream-working.mjs +js/examples/test-interactive-streaming.mjs +js/examples/ci-debug-baseline-vs-library.mjs +js/examples/STREAMING_INTERFACES_SUMMARY.md +js/examples/debug-output.mjs +js/examples/test-sleep-stdin.js +js/examples/debug-echo-args.mjs +js/examples/events-error-handling.mjs +js/examples/trace-signal-handling.mjs +js/examples/test-streaming-final.mjs +js/examples/test-injection-protection.mjs +js/examples/debug-jq-streaming.mjs +js/examples/node-compat-small-buffer.mjs +js/examples/syntax-custom-stdin.mjs +js/examples/test-cleanup-simple.mjs +js/examples/test-runner-batched.mjs +js/examples/test-quote-behavior-summary.mjs +js/examples/events-ping-basic.mjs +js/examples/debug-listener-lifecycle.mjs +js/examples/gh-hang-reproduction.mjs +js/examples/debug-command-parsing.mjs +js/examples/debug-child-state.mjs +js/examples/test-events.mjs +js/examples/ci-debug-test-timeouts.mjs +js/examples/debug-process-exit-trace.mjs +js/examples/test-correct-space-handling.mjs +js/examples/debug-stream-getter.mjs +js/examples/debug-exact-command.mjs +js/examples/gh-hang-exact-original.mjs +js/examples/syntax-custom-directory.mjs +js/examples/gh-gist-creation-test.mjs +js/examples/ansi-global-config.mjs +js/examples/debug-pipeline.mjs +js/examples/capture-mirror-comparison.mjs +js/examples/simple-claude-test.mjs +js/examples/test-baseline-sigint.mjs +js/examples/gh-operations-with-cd.mjs +js/examples/debug-event-timing.mjs +js/examples/ping-streaming-interruptible.mjs +js/examples/gh-reproduce-hang.mjs +js/examples/test-auto-start-fix.mjs +js/examples/test-actual-buildshell.mjs +js/examples/syntax-silent-operations.mjs +js/examples/debug-listener-timing.mjs +js/examples/syntax-reusable-config.mjs +js/examples/test-waiting-commands.mjs +js/examples/debug-with-trace.mjs +js/examples/README.md +js/examples/methods-run-basic.mjs +js/examples/reproduce-issue-135.mjs +js/examples/streaming-test-simple.mjs +js/examples/gh-gist-minimal-test.mjs +js/examples/realtime-json-stream.mjs +js/examples/debug-interpolation-individual.mjs +js/examples/debug-sigint-handler-order.mjs +js/examples/debug-idempotent-finish.mjs +js/examples/prove-ping-stdin-limitation.mjs +js/examples/test-stdin-simple.mjs +js/examples/debug-getter-basic.mjs +js/examples/final-test-shell-operators.mjs +js/examples/test-pty.mjs +js/examples/debug-basic-streaming.mjs +js/examples/streaming-progress-tracking.mjs +js/examples/debug-property-check.mjs +js/examples/debug-end-event.mjs +js/examples/debug-stream-internals.mjs +js/examples/colors-per-command-config.mjs +js/examples/add-test-timeouts.js +js/examples/test-streams-stdin-comprehensive.mjs +js/examples/events-build-process.mjs +js/examples/syntax-multiple-listeners.mjs +docs/case-studies/issue-158/templates/js-ai-driven-development-pipeline-template/check-release-needed.mjs +docs/case-studies/issue-158/templates/js-ai-driven-development-pipeline-template/publish-to-npm.mjs +docs/case-studies/issue-158/templates/js-ai-driven-development-pipeline-template/release.yml +rust/tests/pipeline.rs +rust/tests/state.rs +rust/tests/virtual_commands.rs +rust/tests/shell_parser.rs +rust/tests/stream.rs +rust/tests/macros.rs +rust/tests/events.rs +rust/tests/builtin_commands.rs +rust/tests/process_runner.rs +rust/tests/utils.rs diff --git a/docs/case-studies/issue-160/data/download-jq.log b/docs/case-studies/issue-160/data/download-jq.log new file mode 100644 index 0000000..38cd214 --- /dev/null +++ b/docs/case-studies/issue-160/data/download-jq.log @@ -0,0 +1,5 @@ + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 100 2.21M 100 2.21M 0 0 18.17M 0 0 100 2.21M 100 2.21M 0 0 18.15M 0 0 100 2.21M 100 2.21M 0 0 18.13M 0 0 +jq-1.7.1 diff --git a/docs/case-studies/issue-160/data/issue-160-comments.json b/docs/case-studies/issue-160/data/issue-160-comments.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/docs/case-studies/issue-160/data/issue-160-comments.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/docs/case-studies/issue-160/data/issue-160.json b/docs/case-studies/issue-160/data/issue-160.json new file mode 100644 index 0000000..78b0a9a --- /dev/null +++ b/docs/case-studies/issue-160/data/issue-160.json @@ -0,0 +1 @@ +{"author":{"id":"MDQ6VXNlcjE0MzE5MDQ=","is_bot":false,"login":"konard","name":"Konstantin Diachenko"},"body":"All JavaScript related files should go to ./js folder, and be controlled by js.yml. And rust goes to ./rust folder and controlled by rust.yml. Project files and other related files should be separated, and root of repository should contain only common files for both languages. Each language should have its own ./js/scripts and ./rust/scripts folder, with CI/CD scripts in js and rust as in templates.\n\nWe should clearly mark separate releases for JavaScript and Rust. They should have their own separate README.md files for examples and what actually will go to package managers and so on.\n\nGitHub releases should be separate and should contain corresponding badges.\n\nThe root README.md should contain common information that is valid for both languages, and links to specific language versions.\n\nUse all the best practices from CI/CD templates (check full file tree to compare for all GitHub workflow and CI/CD scripts file), if the same issue is found in template report issue also in templates:\n- https://github.com/link-foundation/js-ai-driven-development-pipeline-template\n- https://github.com/link-foundation/rust-ai-driven-development-pipeline-template\n- https://github.com/link-foundation/python-ai-driven-development-pipeline-template\n- https://github.com/link-foundation/csharp-ai-driven-development-pipeline-template\n\nWe should compare all files, so we don't have more CI/CD errors in the future and reuse all the best practices from these templates.\n\nWe need to collect data related about the issue to this repository, make sure we compile that data to `./docs/case-studies/issue-{id}` folder, and use it to do deep case study analysis (also make sure to search online for additional facts and data), list of each and all requirements from the issue, and propose possible solutions and solution plans for each requirement (we should also check known existing components/libraries, that solve similar problem or can help in solutions).\n\nPlease plan and execute everything in this single pull request, you have unlimited time and context, as context auto-compacts and you can continue indefinitely, until it is each and every requirement fully addressed, and everything is totally done.","createdAt":"2026-06-08T12:48:58Z","labels":[{"id":"LA_kwDOPc80Bs8AAAACHnbl7g","name":"bug","description":"Something isn't working","color":"d73a4a"},{"id":"LA_kwDOPc80Bs8AAAACHnbl7w","name":"documentation","description":"Improvements or additions to documentation","color":"0075ca"},{"id":"LA_kwDOPc80Bs8AAAACHnbl8Q","name":"enhancement","description":"New feature or request","color":"a2eeef"}],"number":160,"state":"OPEN","title":"We should clearly separate JavaScript and Rust","updatedAt":"2026-06-08T12:48:58Z","url":"https://github.com/link-foundation/command-stream/issues/160"} diff --git a/docs/case-studies/issue-160/data/js-ai-driven-development-pipeline-template.repo.json b/docs/case-studies/issue-160/data/js-ai-driven-development-pipeline-template.repo.json new file mode 100644 index 0000000..e28ce32 --- /dev/null +++ b/docs/case-studies/issue-160/data/js-ai-driven-development-pipeline-template.repo.json @@ -0,0 +1 @@ +{"id":1114106951,"node_id":"R_kgDOQmfsRw","name":"js-ai-driven-development-pipeline-template","full_name":"link-foundation/js-ai-driven-development-pipeline-template","private":false,"owner":{"login":"link-foundation","id":176174013,"node_id":"O_kgDOCoAzvQ","avatar_url":"https://avatars.githubusercontent.com/u/176174013?v=4","gravatar_id":"","url":"https://api.github.com/users/link-foundation","html_url":"https://github.com/link-foundation","followers_url":"https://api.github.com/users/link-foundation/followers","following_url":"https://api.github.com/users/link-foundation/following{/other_user}","gists_url":"https://api.github.com/users/link-foundation/gists{/gist_id}","starred_url":"https://api.github.com/users/link-foundation/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/link-foundation/subscriptions","organizations_url":"https://api.github.com/users/link-foundation/orgs","repos_url":"https://api.github.com/users/link-foundation/repos","events_url":"https://api.github.com/users/link-foundation/events{/privacy}","received_events_url":"https://api.github.com/users/link-foundation/received_events","type":"Organization","user_view_type":"public","site_admin":false},"html_url":"https://github.com/link-foundation/js-ai-driven-development-pipeline-template","description":"A template for AI driven development pipeline for JavaScript/TypeScript","fork":false,"url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template","forks_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/forks","keys_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/keys{/key_id}","collaborators_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/teams","hooks_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/hooks","issue_events_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/issues/events{/number}","events_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/events","assignees_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/assignees{/user}","branches_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/branches{/branch}","tags_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/tags","blobs_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/git/refs{/sha}","trees_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/git/trees{/sha}","statuses_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/statuses/{sha}","languages_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/languages","stargazers_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/stargazers","contributors_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/contributors","subscribers_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/subscribers","subscription_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/subscription","commits_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/commits{/sha}","git_commits_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/git/commits{/sha}","comments_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/comments{/number}","issue_comment_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/issues/comments{/number}","contents_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/contents/{+path}","compare_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/compare/{base}...{head}","merges_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/merges","archive_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/downloads","issues_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/issues{/number}","pulls_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/pulls{/number}","milestones_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/milestones{/number}","notifications_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/labels{/name}","releases_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/releases{/id}","deployments_url":"https://api.github.com/repos/link-foundation/js-ai-driven-development-pipeline-template/deployments","created_at":"2025-12-10T23:00:43Z","updated_at":"2026-06-04T17:31:49Z","pushed_at":"2026-06-04T17:31:45Z","git_url":"git://github.com/link-foundation/js-ai-driven-development-pipeline-template.git","ssh_url":"git@github.com:link-foundation/js-ai-driven-development-pipeline-template.git","clone_url":"https://github.com/link-foundation/js-ai-driven-development-pipeline-template.git","svn_url":"https://github.com/link-foundation/js-ai-driven-development-pipeline-template","homepage":null,"size":1793,"stargazers_count":1,"watchers_count":1,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"has_discussions":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"unlicense","name":"The Unlicense","spdx_id":"Unlicense","url":"https://api.github.com/licenses/unlicense","node_id":"MDc6TGljZW5zZTE1"},"allow_forking":true,"is_template":true,"web_commit_signoff_required":false,"has_pull_requests":true,"pull_request_creation_policy":"all","topics":[],"visibility":"public","forks":0,"open_issues":0,"watchers":1,"default_branch":"main","permissions":{"admin":true,"maintain":true,"push":true,"triage":true,"pull":true},"temp_clone_token":"","allow_squash_merge":true,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_auto_merge":false,"delete_branch_on_merge":false,"allow_update_branch":false,"use_squash_pr_title_as_default":false,"squash_merge_commit_message":"COMMIT_MESSAGES","squash_merge_commit_title":"COMMIT_OR_PR_TITLE","merge_commit_message":"PR_TITLE","merge_commit_title":"MERGE_MESSAGE","custom_properties":{},"organization":{"login":"link-foundation","id":176174013,"node_id":"O_kgDOCoAzvQ","avatar_url":"https://avatars.githubusercontent.com/u/176174013?v=4","gravatar_id":"","url":"https://api.github.com/users/link-foundation","html_url":"https://github.com/link-foundation","followers_url":"https://api.github.com/users/link-foundation/followers","following_url":"https://api.github.com/users/link-foundation/following{/other_user}","gists_url":"https://api.github.com/users/link-foundation/gists{/gist_id}","starred_url":"https://api.github.com/users/link-foundation/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/link-foundation/subscriptions","organizations_url":"https://api.github.com/users/link-foundation/orgs","repos_url":"https://api.github.com/users/link-foundation/repos","events_url":"https://api.github.com/users/link-foundation/events{/privacy}","received_events_url":"https://api.github.com/users/link-foundation/received_events","type":"Organization","user_view_type":"public","site_admin":false},"security_and_analysis":{"secret_scanning":{"status":"disabled"},"secret_scanning_push_protection":{"status":"disabled"},"dependabot_security_updates":{"status":"disabled"},"secret_scanning_non_provider_patterns":{"status":"disabled"},"secret_scanning_validity_checks":{"status":"disabled"}},"network_count":0,"subscribers_count":0} \ No newline at end of file diff --git a/docs/case-studies/issue-160/data/js-duplication.log b/docs/case-studies/issue-160/data/js-duplication.log new file mode 100644 index 0000000..5cf7088 --- /dev/null +++ b/docs/case-studies/issue-160/data/js-duplication.log @@ -0,0 +1,2 @@ +$ jscpd . +Detection time:: 0.238ms diff --git a/docs/case-studies/issue-160/data/js-format-check.log b/docs/case-studies/issue-160/data/js-format-check.log new file mode 100644 index 0000000..d90c69d --- /dev/null +++ b/docs/case-studies/issue-160/data/js-format-check.log @@ -0,0 +1,3 @@ +$ prettier --check . +Checking formatting... +All matched files use Prettier code style! diff --git a/docs/case-studies/issue-160/data/js-lint.log b/docs/case-studies/issue-160/data/js-lint.log new file mode 100644 index 0000000..dafda4a --- /dev/null +++ b/docs/case-studies/issue-160/data/js-lint.log @@ -0,0 +1 @@ +$ eslint . diff --git a/docs/case-studies/issue-160/data/js-template-head.txt b/docs/case-studies/issue-160/data/js-template-head.txt new file mode 100644 index 0000000..9becb08 --- /dev/null +++ b/docs/case-studies/issue-160/data/js-template-head.txt @@ -0,0 +1 @@ +2d77e242d1a1778b6fc7f3ca563b2a36ef555d0e diff --git a/docs/case-studies/issue-160/data/js-test.log b/docs/case-studies/issue-160/data/js-test.log new file mode 100644 index 0000000..8f3e994 --- /dev/null +++ b/docs/case-studies/issue-160/data/js-test.log @@ -0,0 +1,6779 @@ +$ cd .. && bun test js/tests/ --timeout 10000 +bun test v1.3.14 (0d9b296a) + +js/tests/$.test.mjs: +(pass) StreamEmitter > should add and emit events [3.68ms] +(pass) StreamEmitter > should support multiple listeners for same event [2.38ms] +(pass) StreamEmitter > should support chaining [2.35ms] +(pass) StreamEmitter > should remove listeners with off [2.43ms] +(pass) StreamEmitter > should handle non-existent event removal [3.32ms] +(pass) Utility Functions > quote > should not quote safe strings [2.42ms] +(pass) Utility Functions > quote > should quote strings with spaces [2.30ms] +(pass) Utility Functions > quote > should quote strings with special characters [2.25ms] +(pass) Utility Functions > quote > should handle empty string [2.22ms] +(pass) Utility Functions > quote > should handle null/undefined [2.23ms] +(pass) Utility Functions > quote > should escape single quotes [2.67ms] +(pass) Utility Functions > quote > should handle arrays [2.37ms] +(pass) Utility Functions > quote > should convert non-strings [2.27ms] +(pass) Utility Functions > quote > should preserve user-provided quotes [2.24ms] +(pass) Utility Functions > raw > should create raw object [2.29ms] +(pass) Utility Functions > raw > should convert to string [2.24ms] +hello world +(pass) ProcessRunner - Classic Await Pattern > should execute simple command [13.13ms] +stdout +stderr +(pass) ProcessRunner - Classic Await Pattern > should handle command with non-zero exit [9.59ms] +hello world +(pass) ProcessRunner - Classic Await Pattern > should interpolate variables with quoting [7.03ms] +raw test +(pass) ProcessRunner - Classic Await Pattern > should handle raw interpolation [5.70ms] +; rm -rf /; echo +(pass) ProcessRunner - Classic Await Pattern > should quote dangerous characters [7.58ms] +line1 +line2 +line3 +(pass) ProcessRunner - Async Iteration Pattern > should stream command output [7.94ms] +stdout +stderr +(pass) ProcessRunner - Async Iteration Pattern > should handle stderr in streaming [6.74ms] +(pass) ProcessRunner - EventEmitter Pattern > should emit data events [1003.50ms] +(pass) ProcessRunner - EventEmitter Pattern > should support event chaining [1003.73ms] +mixed test +(pass) ProcessRunner - Mixed Pattern > should support both events and await [8.73ms] +MaxListenersExceededWarning: Possible EventTarget memory leak detected. 11 close listeners added to [WriteStream]. MaxListeners is undefined. Use events.setMaxListeners() to increase limit + emitter: WriteStream { + fd: 1, + [Symbol(kFs)]: [Object ...], + _writev: undefined, + flush: false, + start: undefined, + pos: undefined, + bytesWritten: 0, + [Symbol(kWriteStreamFastPath)]: [FileSink ...], + _write: [Function: underscoreWriteFast], + write: [Function: writeFast], + _events: [Object ...], + _writableState: [Object ...], + _maxListeners: undefined, + [Symbol(kCapture)]: false, + _eventsCount: NaN, + readable: false, + _type: "fs", + destroySoon: [Function], + _destroy: [Function], + _final: [Function], + _isStdio: true, + open: [Function: open], + _construct: [Function: streamConstruct], + close: [Function], + autoClose: [Getter/Setter], + pending: [Getter], + pipe: [Function], + cork: [Function], + uncork: [Function], + setDefaultEncoding: [Function: setDefaultEncoding], + end: [Function], + closed: [Getter], + destroyed: [Getter/Setter], + writable: [Getter/Setter], + writableFinished: [Getter], + writableObjectMode: [Getter], + writableBuffer: [Getter], + writableEnded: [Getter], + writableNeedDrain: [Getter], + writableHighWaterMark: [Getter], + writableCorked: [Getter], + writableLength: [Getter], + errored: [Getter], + writableAborted: [Getter], + destroy: [Function], + _undestroy: [Function: undestroy], + [Symbol(nodejs.rejection)]: [Function], + [Symbol(Symbol.asyncDispose)]: [Function], + eventNames: [Function: eventNames], + setMaxListeners: [Function: setMaxListeners], + getMaxListeners: [Function: getMaxListeners], + emit: [Function: emit], + addListener: [Function: addListener], + on: [Function: addListener], + prependListener: [Function: prependListener], + once: [Function: once], + prependOnceListener: [Function: prependOnceListener], + removeListener: [Function: removeListener], + off: [Function: removeListener], + removeAllListeners: [Function: removeAllListeners], + listeners: [Function: listeners], + rawListeners: [Function: rawListeners], + listenerCount: [Function: listenerCount], +}, + type: "close", + count: 11, + + at overflowWarning (node:events:185:19) + at addListener (node:events:158:22) + at checkParentStream (/tmp/gh-issue-solver-1780922968363/js/src/$.state.mjs:292:14) + at monitorParentStreams (/tmp/gh-issue-solver-1780922968363/js/src/$.state.mjs:307:3) + at new ProcessRunner (/tmp/gh-issue-solver-1780922968363/js/src/$.process-runner-base.mjs:246:5) + at $tagged (/tmp/gh-issue-solver-1780922968363/js/src/$.mjs:195:18) + at (/tmp/gh-issue-solver-1780922968363/js/tests/$.test.mjs:381:21) + +MaxListenersExceededWarning: Possible EventTarget memory leak detected. 11 close listeners added to [WriteStream]. MaxListeners is undefined. Use events.setMaxListeners() to increase limit + emitter: WriteStream { + fd: 2, + [Symbol(kFs)]: [Object ...], + _writev: undefined, + flush: false, + start: undefined, + pos: undefined, + bytesWritten: 0, + [Symbol(kWriteStreamFastPath)]: [FileSink ...], + _write: [Function: underscoreWriteFast], + write: [Function: writeFast], + _events: [Object ...], + _writableState: [Object ...], + _maxListeners: undefined, + [Symbol(kCapture)]: false, + _eventsCount: NaN, + readable: false, + _type: "fs", + destroySoon: [Function], + _destroy: [Function], + _final: [Function], + _isStdio: true, + open: [Function: open], + _construct: [Function: streamConstruct], + close: [Function], + autoClose: [Getter/Setter], + pending: [Getter], + pipe: [Function], + cork: [Function], + uncork: [Function], + setDefaultEncoding: [Function: setDefaultEncoding], + end: [Function], + closed: [Getter], + destroyed: [Getter/Setter], + writable: [Getter/Setter], + writableFinished: [Getter], + writableObjectMode: [Getter], + writableBuffer: [Getter], + writableEnded: [Getter], + writableNeedDrain: [Getter], + writableHighWaterMark: [Getter], + writableCorked: [Getter], + writableLength: [Getter], + errored: [Getter], + writableAborted: [Getter], + destroy: [Function], + _undestroy: [Function: undestroy], + [Symbol(nodejs.rejection)]: [Function], + [Symbol(Symbol.asyncDispose)]: [Function], + eventNames: [Function: eventNames], + setMaxListeners: [Function: setMaxListeners], + getMaxListeners: [Function: getMaxListeners], + emit: [Function: emit], + addListener: [Function: addListener], + on: [Function: addListener], + prependListener: [Function: prependListener], + once: [Function: once], + prependOnceListener: [Function: prependOnceListener], + removeListener: [Function: removeListener], + off: [Function: removeListener], + removeAllListeners: [Function: removeAllListeners], + listeners: [Function: listeners], + rawListeners: [Function: rawListeners], + listenerCount: [Function: listenerCount], +}, + type: "close", + count: 11, + + at overflowWarning (node:events:185:19) + at addListener (node:events:158:22) + at checkParentStream (/tmp/gh-issue-solver-1780922968363/js/src/$.state.mjs:292:14) + at monitorParentStreams (/tmp/gh-issue-solver-1780922968363/js/src/$.state.mjs:308:3) + at new ProcessRunner (/tmp/gh-issue-solver-1780922968363/js/src/$.process-runner-base.mjs:246:5) + at $tagged (/tmp/gh-issue-solver-1780922968363/js/src/$.mjs:195:18) + at (/tmp/gh-issue-solver-1780922968363/js/tests/$.test.mjs:381:21) + +stream test +(pass) ProcessRunner - Stream Properties > should provide stream access [108.64ms] +sh test +(pass) Public APIs > sh > should execute shell command [7.63ms] +options test +(pass) Public APIs > sh > should accept options [7.03ms] +exec test +(pass) Public APIs > exec > should execute file with args [5.70ms] +/tmp/gh-issue-solver-1780922968363 +(pass) Public APIs > exec > should handle empty args [4.17ms] +(pass) Public APIs > run > should run string command [8.84ms] +(pass) Public APIs > run > should run array command [4.88ms] +create test +(pass) Public APIs > create > should create custom $ with default options [8.00ms] +/bin/sh: 1: nonexistent-command-123456: not found +(pass) Error Handling and Edge Cases > should handle command not found [9.37ms] +$HOME && echo "injection" +(pass) Error Handling and Edge Cases > should handle special characters in interpolation [7.37ms] +hello world +(pass) Error Handling and Edge Cases > should handle multiple interpolations [9.28ms] +one two three +(pass) Error Handling and Edge Cases > should handle arrays in interpolation [9.11ms] +(pass) Error Handling and Edge Cases > should handle empty command [7.71ms] +test input(pass) Error Handling and Edge Cases > should handle stdin options [11.17ms] +(pass) ProcessRunner Options > should handle mirror option [6.81ms] +(pass) ProcessRunner Options > should handle capture option [7.25ms] +/tmp +(pass) ProcessRunner Options > should handle cwd option [7.48ms] +promise test +(pass) Promise Interface > should support then/catch/finally [8.10ms] +(pass) Promise Interface > should handle catch for errors [14.48ms] +(pass) Promise Interface > should handle buildShellCommand function [2.54ms] +buffer test +(pass) Promise Interface > should handle asBuffer function via streaming [8.19ms] +test +buffer input(pass) Coverage for Internal Functions > should test ProcessRunner stdin handling [11.85ms] +piped input(pass) Coverage for Internal Functions > should test ProcessRunner _pumpStdinTo and _writeToStdin [8.90ms] +stream edge case +(pass) Coverage for Internal Functions > should test ProcessRunner stream method edge cases [7.09ms] +test_value +(pass) Coverage for Internal Functions > should test env and other options [6.59ms] +finally test +(pass) Coverage for Internal Functions > should test finally method with lazy promise creation [7.15ms] +catch test +(pass) Coverage for Internal Functions > should test catch method with lazy promise creation [6.64ms] +tty test +(pass) Coverage for Internal Functions > should test stdin inherit with TTY simulation [6.71ms] +test(pass) Coverage for Internal Functions > should test Uint8Array buffer handling in _writeToStdin [7.57ms] +(pass) Coverage for Internal Functions > should test direct ProcessRunner instantiation and manual start [7.68ms] +string inputbuffer input(pass) Coverage for Internal Functions > should test ProcessRunner with complex stdin scenarios [12.69ms] +ignore test +(pass) Coverage for Internal Functions > should test error handling in stdin operations [6.75ms] +default stdin +(pass) Coverage for Internal Functions > should test process with default stdin handling [6.92ms] +edge case +buffer test(pass) Coverage for Internal Functions > should test edge cases to improve coverage [12.08ms] +(pass) Coverage for Internal Functions > should test asBuffer function with different input types [2.44ms] +stdin test +manual test(pass) Coverage for Internal Functions > should test Bun-specific stdin handling paths [17.44ms] +uint8 test(pass) Coverage for Internal Functions > should test _writeToStdin with Uint8Array path [11.80ms] +exec stdin testhello(pass) Coverage for Internal Functions > should test alternative stdio handling [16.06ms] +mock test +(pass) Coverage for Internal Functions > should test process stdin simulation for coverage [11.03ms] +inherit test +(pass) Coverage for Internal Functions > should test stdin inherit edge cases [10.41ms] +test(pass) Coverage for Internal Functions > should test different buffer scenarios for coverage [11.81ms] +safe test +buffer testexec test +(pass) Coverage for Internal Functions > should test extreme edge cases for full coverage [19.06ms] +test +(pass) Coverage for Internal Functions > should test internal ProcessRunner methods directly for coverage [9.73ms] +delayed test +(pass) Coverage for Internal Functions > should test ProcessRunner with delayed execution [8.14ms] + +js/tests/yes-command-cleanup.test.mjs: +(pass) Yes Command Cleanup Tests > should stop yes command when breaking from async iteration [103.99ms] +(pass) Yes Command Cleanup Tests > should stop yes command when killed explicitly [65.15ms] +(pass) Yes Command Cleanup Tests > should stop yes command on timeout [108.36ms] +(pass) Yes Command Cleanup Tests > should stop yes when error occurs in handler [1.65ms] +(pass) Yes Command Cleanup Tests > should handle multiple yes commands without interference [0.64ms] +COUNT:3 +FINISHED:true +(pass) Yes Command Cleanup Tests > should cleanup yes command in subprocess [61.75ms] +(pass) Yes Command Cleanup Tests > critical: yes must stop within reasonable time when cancelled [113.17ms] + +js/tests/virtual.test.mjs: +Hello, Alice! +(pass) Virtual Commands System > Registration API > should register and execute custom virtual command [3.81ms] +/bin/sh: 1: temp: not found +(pass) Virtual Commands System > Registration API > should unregister commands [7.72ms] +(pass) Virtual Commands System > Registration API > should list registered commands [2.38ms] +(pass) Virtual Commands System > Built-in Commands > should execute virtual cd command [4.50ms] +/tmp/gh-issue-solver-1780922968363 +(pass) Virtual Commands System > Built-in Commands > should execute virtual pwd command [2.65ms] +Hello World +(pass) Virtual Commands System > Built-in Commands > should execute virtual echo command [2.53ms] +Hello(pass) Virtual Commands System > Built-in Commands > should execute echo with -n flag [2.46ms] +(pass) Virtual Commands System > Built-in Commands > should execute virtual sleep command [104.55ms] +(pass) Virtual Commands System > Built-in Commands > should execute virtual true command [2.88ms] +(pass) Virtual Commands System > Built-in Commands > should execute virtual false command [2.66ms] +echo: shell builtin +(pass) Virtual Commands System > Built-in Commands > should execute virtual which command [2.83ms] +Command failed with exit code 42(pass) Virtual Commands System > Built-in Commands > should execute virtual exit command [2.99ms] +NODE_ENV=test +TELEGRAM_BOT_VERBOSE=true +SHELL=/bin/sh +npm_command=run-script +CAML_LD_LIBRARY_PATH=/home/box/.opam/default/lib/stublibs:/home/box/.opam/default/lib/ocaml/stublibs:/home/box/.opam/default/lib/ocaml +CODEX_MANAGED_PACKAGE_ROOT=/home/box/.bun/install/global/node_modules/@openai/codex +OCAML_TOPLEVEL_PATH=/home/box/.opam/default/lib/toplevel +COLORTERM= +PYENV_SHELL=bash +NVM_INC=/home/box/.nvm/versions/node/v20.20.2/include/node +HOSTNAME=e8b479d6511b +CLAUDE_CODE_DISABLE_FAST_MODE=1 +NODE=/home/box/.nvm/versions/node/v20.20.2/bin/node +TERMCAP=SC|screen|VT 100/ANSI X3.64 virtual terminal:DO=\E[%dB:LE=\E[%dD:RI=\E[%dC:UP=\E[%dA:bs:bt=\E[Z:cd=\E[J:ce=\E[K:cl=\E[H\E[J:cm=\E[%i%d;%dH:ct=\E[3g:do=^J:nd=\E[C:pt:rc=\E8:rs=\Ec:sc=\E7:st=\EH:up=\EM:le=^H:bl=^G:cr=^M:it#8:ho=\E[H:nw=\EE:ta=^I:is=\E)0:li#24:co#80:am:xn:xv:LP:sr=\EM:al=\E[L:AL=\E[%dL:cs=\E[%i%d;%dr:dl=\E[M:DL=\E[%dM:dc=\E[P:DC=\E[%dP:im=\E[4h:ei=\E[4l:mi:IC=\E[%d@:ks=\E[?1h\E=:ke=\E[?1l\E>:vi=\E[?25l:ve=\E[34h\E[?25h:vs=\E[34l:ti=\E[?1049h:te=\E[?1049l:Km=\E[M:k0=\E[10~:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:k5=\E[15~:k6=\E[17~:k7=\E[18~:k8=\E[19~:k9=\E[20~:k;=\E[21~:F1=\E[23~:F2=\E[24~:kh=\E[1~:@1=\E[1~:kH=\E[4~:@7=\E[4~:kN=\E[6~:kP=\E[5~:kI=\E[2~:kD=\E[3~:ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD: +JAVA_HOME=/home/box/.sdkman/candidates/java/current +CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY=1 +WINDOW=0 +CODEX_MANAGED_BY_BUN=1 +npm_config_local_prefix=/tmp/gh-issue-solver-1780922968363/js +TELEGRAM_SOLVE_OVERRIDES=( + --attach-logs + --verbose + --no-tool-check + --disable-report-issue +) +SDKMAN_CANDIDATES_DIR=/home/box/.sdkman/candidates +RBENV_SHELL=bash +CLAUDE_CODE_ENABLE_TASKS=1 +PERLBREW_HOME=/home/box/.perlbrew +GH_PAGER=cat +SDKMAN_BROKER_API=https://broker.sdkman.io +OCAMLTOP_INCLUDE_PATH=/home/box/.opam/default/lib/toplevel +PERLBREW_SHELLRC_VERSION=1.02 +PWD=/tmp/gh-issue-solver-1780922968363 +CLAUDE_CODE_DISABLE_MOUSE=1 +MANPATH= +OPAM_SWITCH_PREFIX=/home/box/.opam/default +TELEGRAM_HIVE_OVERRIDES=( + --all-issues + --once + --skip-issues-with-prs + --attach-logs + --verbose + --no-tool-check + --disable-report-issue +) +DIND_STORAGE_DRIVER=vfs +HOME=/home/box +LANG=C.UTF-8 +TELEGRAM_BOT_TOKEN=8490528355:AAEYsflpqsH8ocHWgFL2U0GpFbWwFG9dJ1Y +CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 +CARGO_HOME=/home/box/.cargo +npm_package_version=0.9.5 +CLAUDE_CODE_RESUME_INTERRUPTED_TURN=1 +CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 +DENO_INSTALL=/home/box/.deno +CLAUDE_CODE_DISABLE_CRON=1 +DISABLE_FEEDBACK_COMMAND=1 +CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1 +GOROOT=/home/box/.go +DOTNET_BUNDLE_EXTRACT_BASE_DIR=/home/box/.cache/dotnet_bundle_extract +npm_lifecycle_script=cd .. && bun test js/tests/ --timeout 10000 +NVM_DIR=/home/box/.nvm +HIVE_MIND_IMAGE_VARIANT=dind +TERM=screen +npm_package_name=command-stream +CODEX_THREAD_ID=019ea748-3d12-74a0-9b77-f17e450c39c9 +GIT_PAGER=cat +KOTLIN_HOME=/home/box/.sdkman/candidates/kotlin/current +DIND_WAIT_SECONDS=180 +BOX_DIND_BASE_IMAGE=konard/box:2.1.4-amd64 +SDKMAN_DIR=/home/box/.sdkman +CLAUDE_CODE_ENABLE_AWAY_SUMMARY=0 +npm_lifecycle_event=test +SHLVL=2 +NVM_CD_FLAGS= +PAGER=cat +TELEGRAM_ALLOWED_CHATS=( + -1002975819706 + -1002861722681 +) +DIND_SKIP_DAEMON=0 +SDKMAN_CANDIDATES_API=https://api.sdkman.io/2 +npm_config_user_agent=bun/1.3.14 npm/? node/v24.3.0 linux x64 +NO_COLOR=1 +CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY=4 +npm_execpath=/home/box/.bun/bin/bun +CODEX_CI=1 +LC_CTYPE=C.UTF-8 +PYENV_ROOT=/home/box/.pyenv +npm_package_json=/tmp/gh-issue-solver-1780922968363/js/package.json +BUN_INSTALL=/home/box/.bun +LC_ALL=C.UTF-8 +PATH=/tmp/gh-issue-solver-1780922968363/js/node_modules/.bin:/tmp/gh-issue-solver-1780922968363/js/node_modules/.bin:/tmp/gh-issue-solver-1780922968363/node_modules/.bin:/tmp/node_modules/.bin:/node_modules/.bin:/tmp/issue-160-bin:/home/box/.elan/bin:/home/box/.swift/usr/bin:/home/box/.rbenv/shims:/home/box/.rbenv/bin:/home/box/.go/bin:/home/box/.go/path/bin:/home/box/.pyenv/shims:/home/box/.pyenv/bin:/home/box/.deno/bin:/home/box/.codex/tmp/arg0/codex-arg0Gi2jE6:/home/box/.bun/install/global/node_modules/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/codex-path:/home/box/.elan/bin:/home/box/.swift/usr/bin:/home/box/.rbenv/shims:/home/box/.rbenv/bin:/home/box/.go/bin:/home/box/.go/path/bin:/home/box/.pyenv/bin:/home/box/.deno/bin:/home/box/.perl5/bin:/home/box/.opam/default/bin:/home/box/.go/bin:/home/box/.go/path/bin:/home/box/.pyenv/bin:/home/box/.elan/bin:/home/box/.swift/usr/bin:/home/box/.rbenv/shims:/home/box/.rbenv/bin:/home/box/.sdkman/candidates/kotlin/current/bin:/home/box/.sdkman/candidates/java/current/bin:/home/box/.go/bin:/home/box/.go/path/bin:/home/box/.pyenv/bin:/home/box/.nvm/versions/node/v20.20.2/bin:/home/box/.deno/bin:/home/box/.node-bin:/home/linuxbrew/.linuxbrew/opt/php@8.3/bin:/home/linuxbrew/.linuxbrew/opt/php@8.3/sbin:/home/linuxbrew/.linuxbrew/bin:/home/box/.pyenv/bin:/home/box/.rbenv/bin:/home/box/.rbenv/shims:/home/box/.swift/usr/bin:/home/box/.elan/bin:/home/box/.local/bin:/home/box/.cargo/bin:/home/box/.deno/bin:/home/box/.bun/bin:/home/box/.go/bin:/home/box/.go/path/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/box/.dotnet/tools +STY=470475.1b3b5c63-c4a6-410c-8645-713ce40909e7 +PERLBREW_ROOT=/home/box/.perl5 +OPAMNOENVNOTICE=true +SDKMAN_PLATFORM=linuxx64 +RUST_LOG=debug +NVM_BIN=/home/box/.nvm/versions/node/v20.20.2/bin +RBENV_ROOT=/home/box/.rbenv +DEBIAN_FRONTEND=noninteractive +npm_node_execpath=/home/box/.nvm/versions/node/v20.20.2/bin/node +OLDPWD=/tmp/gh-issue-solver-1780922968363/js +GOPATH=/home/box/.go/path +OPAM_LAST_ENV=/home/box/.opam/.last-env/env-c0387f92ccf63cfe0b44dd86fdc92b5c-0 +_=/home/box/.bun/bin/bun +(pass) Virtual Commands System > Built-in Commands > should execute virtual env command [2.89ms] +(pass) Virtual Commands System > Built-in Commands > should execute virtual test command [4.34ms] +virtual ls output +LICENSE +README.md +claude-profile-list.sh +claude-profile-restore.sh +claude-profile-save.sh +claude-profiles.mjs +docs +experiments +gitpod-backup-auth.sh +gitpod-restore-auth.sh +js +rust +(pass) Virtual Commands System > Virtual vs System Commands > should prioritize virtual commands over system commands [9.29ms] +Mon Jun 8 13:14:00 UTC 2026 +(pass) Virtual Commands System > Virtual vs System Commands > should fall back to system commands when virtual not found [7.98ms] +1 +2 +3 +(pass) Virtual Commands System > Streaming Virtual Commands > should support async generator virtual commands [36.73ms] +chunk1 +chunk2 +(pass) Virtual Commands System > Streaming Virtual Commands > should handle events with streaming virtual commands [3.05ms] +Virtual command failed(pass) Virtual Commands System > Error Handling > should handle virtual command errors [2.61ms] +FailedFailedFailed(pass) Virtual Commands System > Error Handling > should respect errexit setting with virtual commands [5.10ms] +Args: [one, two three, four] +(pass) Virtual Commands System > Command Arguments and Stdin > should pass arguments correctly to virtual commands [2.68ms] +Received: test input + +(pass) Virtual Commands System > Command Arguments and Stdin > should pass stdin to virtual commands [4.34ms] +output(pass) Virtual Commands System > Shell Settings Integration > should respect verbose setting for virtual commands [2.92ms] +output(pass) Virtual Commands System > Shell Settings Integration > should respect xtrace setting for virtual commands [4.10ms] + +js/tests/ctrl-c-signal.test.mjs: +(pass) CTRL+C Signal Handling > BASELINE: should handle SIGINT with plain shell command [1506.65ms] +(pass) CTRL+C Signal Handling > should forward SIGINT to child process when external CTRL+C is sent [612.28ms] +(pass) CTRL+C Signal Handling > should not interfere with user SIGINT handling when no children active [509.52ms] +(pass) CTRL+C Signal Handling > should handle SIGINT in long-running commands via API [203.62ms] +(pass) CTRL+C Signal Handling > should handle multiple concurrent processes receiving signals [504.11ms] +(pass) CTRL+C Signal Handling > should properly handle signals in external process with sleep [4005.33ms] +(pass) CTRL+C Signal Handling > should not interfere with child process signal handlers [1109.58ms] +(pass) CTRL+C with Different stdin Modes > should handle kill regardless of stdin mode [906.43ms] +(pass) CTRL+C with Different stdin Modes > should properly clean up stdin forwarding on external SIGINT [3007.46ms] +(pass) CTRL+C with Different stdin Modes > should handle parent stream closure triggering process cleanup [1058.69ms] +(pass) CTRL+C with Different stdin Modes > should bypass virtual commands with custom stdin for proper signal handling [509.37ms] +(pass) CTRL+C with Different stdin Modes > should handle Bun vs Node.js signal differences [1011.80ms] +(pass) CTRL+C with Different stdin Modes > should properly cancel virtual commands and respect user SIGINT handlers (regression test) [1019.73ms] + +js/tests/readme-examples.test.mjs: +hello world +(pass) README Examples and Use Cases > 1. Classic Await Pattern > should work like README example: await $`ls -la` [8.26ms] +line1 +line2 +(pass) README Examples and Use Cases > 2. Async Iteration Pattern > should work like README example: for await streaming [11.91ms] +stdout +stderr +(pass) README Examples and Use Cases > 3. EventEmitter Pattern > should work like README example: .on() events [11.47ms] +streaming data +(pass) README Examples and Use Cases > 4. Mixed Pattern > should work like README example: events + await [10.75ms] +build success +ls: cannot access '/nonexistent-dir-12345': No such file or directory +critical operation ++ set -v ++ set -x ++ set -e ++ set +e ++ set -x ++ set -verbose +(pass) README Examples and Use Cases > 5. Shell Replacement (.sh → .mjs) > should work like README example: shell settings [43.64ms] +Hello +Error! +(pass) README Examples and Use Cases > 6. Default Behavior > should work like README example: stdout/stderr capture + mirroring [11.62ms] +custom input(pass) README Examples and Use Cases > 7. Options Override > should work like README example: sh() with options [18.48ms] +(pass) README Examples and Use Cases > 7. Options Override > should work like README example: create() with defaults [19.47ms] +{"session_id":"test-123","status":"started"} +{"data":"some log data"} +(pass) README Examples and Use Cases > 8. Real-world: Session ID Extraction > should work like README example: JSON parsing from streaming [10.77ms] +Starting download +Progress: 25% +Progress: 50% +Progress: 100% +Done! +(pass) README Examples and Use Cases > 9. Real-world: Progress Monitoring > should work like README example: progress parsing from stdout [10.35ms] +stdout +stderr +(pass) README Examples and Use Cases > 10. API Documentation Examples > should match ProcessRunner events from API docs [11.75ms] +output +error +(pass) README Examples and Use Cases > 10. API Documentation Examples > should match Result Object from API docs [9.49ms] +(pass) README Examples and Use Cases > 10. API Documentation Examples > should verify default options from API docs [2.61ms] +(pass) README Examples and Use Cases > Smart Quoting & Security (from README) > safe strings are NOT quoted [4.22ms] +(pass) README Examples and Use Cases > Smart Quoting & Security (from README) > dangerous strings are automatically quoted [2.60ms] +(pass) README Examples and Use Cases > Smart Quoting & Security (from README) > user-provided quotes are preserved [2.54ms] +(pass) README Examples and Use Cases > Smart Quoting & Security (from README) > shell injection attempts are neutralized [3.19ms] +$HOME +$(echo INJECTED) +(pass) README Examples and Use Cases > Smart Quoting & Security (from README) > actual execution prevents injection [16.49ms] + +js/tests/array-interpolation.test.mjs: +(pass) Array Interpolation > Direct Array Passing (Correct Usage) > should treat each array element as separate argument [0.23ms] +(pass) Array Interpolation > Direct Array Passing (Correct Usage) > should quote elements with spaces individually [0.10ms] +(pass) Array Interpolation > Direct Array Passing (Correct Usage) > should handle empty array [0.08ms] +(pass) Array Interpolation > Direct Array Passing (Correct Usage) > should handle single-element array [0.05ms] +(pass) Array Interpolation > Direct Array Passing (Correct Usage) > should handle array with special characters [0.03ms] +(pass) Array Interpolation > Direct Array Passing (Correct Usage) > should handle array with flags correctly [0.04ms] +(pass) Array Interpolation > Pre-joined Array (Anti-pattern) > joined array becomes single argument with spaces [0.07ms] +(pass) Array Interpolation > Pre-joined Array (Anti-pattern) > demonstrates the bug: flags become part of filename [0.03ms] +(pass) Array Interpolation > Pre-joined Array (Anti-pattern) > correct usage vs incorrect usage comparison [0.03ms] +(pass) Array Interpolation > Mixed Interpolation Patterns > should handle multiple separate interpolations [0.03ms] +(pass) Array Interpolation > Mixed Interpolation Patterns > should handle array with conditional elements [0.03ms] +(pass) Array Interpolation > Mixed Interpolation Patterns > should handle spread operator pattern [0.03ms] +(pass) Array Interpolation > Real-World Use Cases > git command with multiple flags [0.05ms] +(pass) Array Interpolation > Real-World Use Cases > npm install with packages [0.03ms] +(pass) Array Interpolation > Real-World Use Cases > file operations with paths containing spaces [0.06ms] +(pass) Array Interpolation > Real-World Use Cases > docker command with environment variables [0.09ms] +(pass) Array Interpolation > Real-World Use Cases > rsync with exclude patterns [0.04ms] +(pass) Array Interpolation > Edge Cases > array with empty strings [0.02ms] +(pass) Array Interpolation > Edge Cases > array with null-ish values coerced to strings [0.02ms] +(pass) Array Interpolation > Edge Cases > nested arrays are flattened by the user (not automatic) [0.02ms] +(pass) Array Interpolation > Edge Cases > array with numbers [0.05ms] +(pass) Array Interpolation > Edge Cases > array with boolean coercion [0.03ms] +(pass) quote() Function Direct Tests > quote function handles arrays correctly [0.03ms] +(pass) quote() Function Direct Tests > quote function handles nested arrays [0.01ms] +(pass) quote() Function Direct Tests > quote function handles mixed safe and unsafe elements [0.01ms] +(pass) Functional Tests (Command Execution) > array arguments work correctly with real command [0.47ms] +(pass) Functional Tests (Command Execution) > pre-joined array creates single argument (demonstrates bug) [0.29ms] +(pass) Functional Tests (Command Execution) > array with spaces handled correctly [0.17ms] +(pass) Functional Tests (Command Execution) > array elements become separate arguments for wc [6.07ms] +(pass) Documentation Examples Verification > README Common Pitfalls example - incorrect usage [0.30ms] +(pass) Documentation Examples Verification > README Common Pitfalls example - correct usage [0.07ms] +(pass) Documentation Examples Verification > BEST-PRACTICES.md Pattern 1: Direct array passing [0.03ms] +(pass) Documentation Examples Verification > BEST-PRACTICES.md Pattern 2: Separate interpolations [0.04ms] +(pass) Documentation Examples Verification > BEST-PRACTICES.md Pattern 3: Build array dynamically [0.04ms] + +js/tests/jq-color-behavior.test.mjs: +{ + "message": "hello", + "number": 42, + "active": true, + "data": null +} +(pass) jq behavior - default mirror mode shows output automatically [4.77ms] +{ + "message": "hello", + "number": 42, + "active": true, + "data": null +} +(pass) jq behavior - explicit color output contains ANSI codes [7.16ms] +{ + "message": "hello", + "number": 42, + "active": true, + "data": null +} +(pass) jq behavior - monochrome output has no ANSI codes [4.69ms] +hello +(pass) jq behavior - field extraction works correctly [4.32ms] +"Alice" +(pass) jq behavior - complex JSON processing [3.85ms] +"hello" +(pass) jq behavior - mirror mode vs capture mode [8.84ms] +{ + "message": "hello", + "number": 42, + "active": true, + "data": null +} +(pass) jq behavior - TTY detection and automatic coloring [4.22ms] +{ + "message": "hello", + "number": 42, + "active": true, + "data": null +} +{ + "message": "hello", + "number": 42, + "active": true, + "data": null +} +(pass) jq behavior - force colors work in any environment [7.68ms] +{ + "message": "hello", + "number": 42, + "active": true, + "data": null +} +(pass) jq behavior - streaming with colors works [4.79ms] + +js/tests/sigint-cleanup.test.mjs: +hello +(pass) SIGINT Handler Cleanup Tests > should remove SIGINT handler when all ProcessRunners finish [0.41ms] +test +(pass) SIGINT Handler Cleanup Tests > should not interfere with user SIGINT handlers after commands finish [50.62ms] +(pass) SIGINT Handler Cleanup Tests > should maintain SIGINT handler while commands are active [1.35ms] +one +two +three +(pass) SIGINT Handler Cleanup Tests > should handle multiple concurrent ProcessRunners correctly [0.53ms] + +js/tests/git-gh-cd.test.mjs: +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/git-test-gdhLqX/.git/ +On branch master + +No commits yet + +nothing to commit (create/copy files and use "git add" to track) +(pass) Git and GH commands with cd virtual command > Git operations in temp directories > should initialize git repo after cd to temp directory [23.19ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/git-test-WQMUwy/.git/ +(pass) Git and GH commands with cd virtual command > Git operations in temp directories > should handle git commands in temp directory with cd chain [22.75ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/git-test-VU6MHM/.git/ +[master (root-commit) 541f548] Initial commit + 1 file changed, 1 insertion(+) + create mode 100644 test.txt +541f548 Initial commit +(pass) Git and GH commands with cd virtual command > Git operations in temp directories > should create and commit files in temp git repo [59.77ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/git-test-LcJ82n/.git/ +[master (root-commit) d0f67e9] init + 1 file changed, 1 insertion(+) + create mode 100644 file.txt +master +Switched to a new branch 'feature-branch' +feature-branch +(pass) Git and GH commands with cd virtual command > Git operations in temp directories > should handle git branch operations with cd [81.60ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/git-test-YqNHQV/.git/ +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/git-test2-436a3P/.git/ +repo1 +repo2 +?? file.txt +?? file.txt +(pass) Git and GH commands with cd virtual command > Git operations in temp directories > should handle multiple temp directories with cd [66.84ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/git-test-vrxD5U/.git/ +[master (root-commit) 8194317] first + 1 file changed, 1 insertion(+) + create mode 100644 file.txt +diff --git a/file.txt b/file.txt +index a29bdeb..c0d0fb4 100644 +--- a/file.txt ++++ b/file.txt +@@ -1 +1,2 @@ + line1 ++line2 + M file.txt +(pass) Git and GH commands with cd virtual command > Git operations in temp directories > should handle git diff operations after cd [73.57ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/git-test-qgYsSs/.git/ +/tmp/gh-issue-solver-1780922968363 +On branch master + +No commits yet + +nothing to commit (create/copy files and use "git add" to track) +(pass) Git and GH commands with cd virtual command > Git operations in temp directories > should work with git in subshells [30.95ms] +github.com + ✓ Logged in to github.com account konard (/home/box/.config/gh/hosts.yml) + - Active account: true + - Git operations protocol: https + - Token: gho_************************************ + - Token scopes: 'gist', 'read:org', 'repo', 'user', 'workflow' +(pass) Git and GH commands with cd virtual command > GH CLI operations with cd > should check gh auth status [266.13ms] +not-authenticated +(pass) Git and GH commands with cd virtual command > GH CLI operations with cd > should handle gh api calls with cd to temp directory [376.55ms] +Cloning into '.'... +/tmp/gh-clone-jVc24W +(pass) Git and GH commands with cd virtual command > GH CLI operations with cd > should simulate gh repo clone pattern [898.72ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/gh-context-EpvL2J/.git/ +[master (root-commit) 23e64cd] Initial commit + 1 file changed, 1 insertion(+) + create mode 100644 README.md +No remote configured +(pass) Git and GH commands with cd virtual command > GH CLI operations with cd > should handle gh commands with directory context [73.94ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/workflow-Du7yMq/.git/ +master +Switched to a new branch 'feature-1780924459230' +feature-1780924459230 +A feature.js +[feature-1780924459230 (root-commit) 7d094e0] Add feature implementation + 1 file changed, 1 insertion(+) + create mode 100644 feature.js +7d094e0 Add feature implementation +(pass) Git and GH commands with cd virtual command > Combined git and gh workflows > should simulate solve.mjs workflow pattern [81.29ms] +not a git repo +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/error-test-subX6n/.git/ +On branch master + +No commits yet + +nothing to commit (create/copy files and use "git add" to track) +(pass) Git and GH commands with cd virtual command > Combined git and gh workflows > should handle error scenarios with cd and git [23.20ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/cwd-test-FuaKya/.git/ +test +/tmp/gh-issue-solver-1780922968363 +exists +(pass) Git and GH commands with cd virtual command > Combined git and gh workflows > should preserve cwd after command chains [17.09ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/complex-gh6qqe/.git/ +setup done +remote failed as expected +test +[master (root-commit) 05ecb79] test + 1 file changed, 1 insertion(+) + create mode 100644 file1.txt +committed +05ecb79 test +(pass) Git and GH commands with cd virtual command > Combined git and gh workflows > should work with complex git workflows using operators [55.66ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/space-test-mLKBUW/my test dir/.git/ +/tmp/space-test-mLKBUW/my test dir +[master (root-commit) 5161149] test + 1 file changed, 1 insertion(+) + create mode 100644 file.txt +5161149 test +(pass) Git and GH commands with cd virtual command > Path resolution and quoting with cd > should handle paths with spaces in git operations [63.27ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/special-chars-LEHrbv/test-'\''dir'\''-$1/.git/ +On branch master + +No commits yet + +nothing to commit (create/copy files and use "git add" to track) +(pass) Git and GH commands with cd virtual command > Path resolution and quoting with cd > should handle special characters in paths [25.96ms] + +js/tests/start-run-options.test.mjs: +(pass) Start/Run Options Passing > .start() method with options > should pass capture: false option correctly [0.59ms] +test with capture true +(pass) Start/Run Options Passing > .start() method with options > should pass capture: true option correctly [0.16ms] +(pass) Start/Run Options Passing > .start() method with options > should pass mirror: false option correctly [0.10ms] +(pass) Start/Run Options Passing > .start() method with options > should pass both capture and mirror options [0.08ms] +custom input data(pass) Start/Run Options Passing > .start() method with options > should pass stdin option correctly [6.62ms] +TemporaryDirectory.1CCCnP +TemporaryDirectory.1aBsFB +TemporaryDirectory.2E3ttA +TemporaryDirectory.31nGmi +TemporaryDirectory.3UudKR +TemporaryDirectory.8eQYMe +TemporaryDirectory.8znSTp +TemporaryDirectory.9hMvHU +TemporaryDirectory.9ijdbu +TemporaryDirectory.BaWcos +TemporaryDirectory.EOk3je +TemporaryDirectory.FG8Tbp +TemporaryDirectory.Fo2LlM +TemporaryDirectory.FyoqGx +TemporaryDirectory.JNm88N +TemporaryDirectory.JZdGbo +TemporaryDirectory.Je8ixu +TemporaryDirectory.JlxJqL +TemporaryDirectory.KghSKJ +TemporaryDirectory.KitLkr +TemporaryDirectory.KudACo +TemporaryDirectory.MKhrM8 +TemporaryDirectory.NEFEik +TemporaryDirectory.NZnSxQ +TemporaryDirectory.NrUoVA +TemporaryDirectory.NvbRzU +TemporaryDirectory.P5iuYE +TemporaryDirectory.P9iCZn +TemporaryDirectory.RYg7L0 +TemporaryDirectory.Sv23il +TemporaryDirectory.VG3DsL +TemporaryDirectory.VNsblL +TemporaryDirectory.WDkLpe +TemporaryDirectory.WjCdZ6 +TemporaryDirectory.Wor2yB +TemporaryDirectory.XdYAXO +TemporaryDirectory.XkUBzt +TemporaryDirectory.YSpHp7 +TemporaryDirectory.YWkXH4 +TemporaryDirectory.ZweB8T +TemporaryDirectory.aKOZ47 +TemporaryDirectory.aRpnpH +TemporaryDirectory.bbUJpy +TemporaryDirectory.dwtuJ2 +TemporaryDirectory.eBuCXR +TemporaryDirectory.eghMCe +TemporaryDirectory.gqN5GN +TemporaryDirectory.iSYyFs +TemporaryDirectory.iUJYH2 +TemporaryDirectory.jjqkbK +TemporaryDirectory.m06C03 +TemporaryDirectory.mokctw +TemporaryDirectory.oUmhMf +TemporaryDirectory.oj1N87 +TemporaryDirectory.qjM4Bj +TemporaryDirectory.r0f54l +TemporaryDirectory.rK2bW3 +TemporaryDirectory.rV0UPw +TemporaryDirectory.s3ydw6 +TemporaryDirectory.sO29K2 +TemporaryDirectory.sTjUjJ +TemporaryDirectory.saXjGJ +TemporaryDirectory.uYdLPc +TemporaryDirectory.vNJDGz +TemporaryDirectory.vS2CzO +TemporaryDirectory.vaHONu +TemporaryDirectory.wm4OPZ +TemporaryDirectory.xNypG8 +TemporaryDirectory.yGoTHl +TemporaryDirectory.zNyHok +agent_prompt_1780915594806_84019.txt +agent_prompt_1780915738542_99362.txt +agent_prompt_1780918291148_269594.txt +agent_prompt_1780922380698_406768.txt +agent_prompt_1780923531533_521627.txt +bunx-1001-node-gyp@latest +bunx-1001-prettier@latest +check-crate-size-found-1780915547897705276 +check-crate-size-found-1780916180190939685 +check-crate-size-found-1780922525875691187 +check-crate-size-found-1780922763656611773 +check-crate-size-found-1780923850476254019 +check-crate-size-missing-1780915547898161898 +check-crate-size-missing-1780916180190979415 +check-crate-size-missing-1780922525876273747 +check-crate-size-missing-1780922763656345946 +check-crate-size-missing-1780923850476286367 +check-file-size-lino-thresholds-1780924183709660112 +check-file-size-lino-thresholds-1780924299944092959 +check-file-size-lino-thresholds-1780924349377190170 +check-file-size-lino-thresholds-1780924396299050012 +check-file-size-thresholds-1780915547898256369 +check-file-size-thresholds-1780916180191324389 +check-file-size-thresholds-1780922525878807941 +check-file-size-thresholds-1780922763655887781 +check-file-size-thresholds-1780923850476940845 +check-file-size-thresholds-1780924183713338194 +check-file-size-thresholds-1780924299944130014 +check-file-size-thresholds-1780924349377487263 +check-file-size-thresholds-1780924396299089099 +check-no-src-tests-outside-src-1780922525875983563 +check-no-src-tests-outside-src-1780922763657368722 +check-no-src-tests-src-markers-1780922525880306989 +check-no-src-tests-src-markers-1780922763657064419 +claude-1001 +codex-auth-18hv0Q +codex-auth-8e5IlJ +codex-auth-ADSlNA +codex-auth-EMZV2J +codex-auth-KprQDu +codex-auth-NUeFa1 +codex-auth-Orpe2c +codex-auth-PlLH1T +codex-auth-SSJ5oi +codex-auth-TNjwUx +codex-auth-TUPdu0 +codex-auth-YobRpP +codex-auth-a99TcI +codex-auth-d8bJTb +codex-auth-g5DJkm +codex-auth-onPAlw +codex-auth-tm0U9I +codex-auth-uycmjS +codex_prompt_1780921329058_368027.txt +codex_prompt_1780922989393_470477.txt +codex_prompt_1780923064689_479328.txt +formal-ai-agent-tests +formal-ai-agent-tests-python-path +formal-ai-agent-workspaces +formal-ai-cache-hit-280295145 +formal-ai-cache-hit-363374055 +formal-ai-cache-hit-669818421 +formal-ai-cache-hit-931832614 +formal-ai-cache-offline-miss-285394824 +formal-ai-cache-offline-miss-370593280 +formal-ai-cache-offline-miss-668523077 +formal-ai-cache-offline-miss-933092009 +formal-ai-cache-online-miss-289552659 +formal-ai-cache-online-miss-375300021 +formal-ai-cache-online-miss-681308109 +formal-ai-cache-online-miss-939699567 +formal-ai-cache-seed-precedence-305450006 +formal-ai-cache-seed-precedence-403190285 +formal-ai-cache-seed-precedence-696467123 +formal-ai-cache-seed-precedence-978717676 +gemini-support-test-2I9cAe +gemini-support-test-2yxzjj +gemini-support-test-409kz4 +gemini-support-test-8VouwZ +gemini-support-test-AFWuND +gemini-support-test-AkicCl +gemini-support-test-EWa4j8 +gemini-support-test-IyM66n +gemini-support-test-JOzpI0 +gemini-support-test-ReErEd +gemini-support-test-TCCWvi +gemini-support-test-VJm3Qg +gemini-support-test-YmPj9o +gemini-support-test-iBNtsX +gemini-support-test-jsxN9N +gemini-support-test-mOsFFD +gemini-support-test-oR3Y7i +gemini-support-test-pDRfEY +gemini-support-test-riK3yX +gemini-support-test-wtKOPq +gh-issue-solver-1780914444673 +gh-issue-solver-1780914740585 +gh-issue-solver-1780914901692 +gh-issue-solver-1780915869051 +gh-issue-solver-1780917252584 +gh-issue-solver-1780918878243 +gh-issue-solver-1780921306925 +gh-issue-solver-1780921315099 +gh-issue-solver-1780921933912 +gh-issue-solver-1780922038008 +gh-issue-solver-1780922951770 +gh-issue-solver-1780922968363 +gh-issue-solver-1780923025774 +gh-issue-solver-1780923355444 +hive-auth-probe-X4CbsI +hive-mind-issue-1861-default-tests-node24.log +hive-mind-issue-1861-format-check.log +hive-mind-issue-1861-gh-run-27133205342-watch.log +hive-mind-issue-1861-line-limits.log +hive-mind-issue-1861-lint.log +hive-mind-issue-1861-npm-ci.log +hive-mind-issue-1861-npm-test.log +hive-mind-no-screen-bin-IDE4Rl +hive-mind-no-screen-bin-U8L6be +hive-mind-no-screen-bin-aIptm6 +hive-mind-no-screen-bin-nLia6s +hive-mind-no-screen-bin-vs4ndt +hive-mind-no-screen-bin-wu35VX +hive-mind-npm-test-1858.log +hive-mind-npm-test-1859-after-merge.log +hsperfdata_box +issue-160-bin +issue-160-templates +issue1834-home-2L9376 +issue1834-home-6MPTta +issue1834-home-6zriHA +issue1834-home-7ZFLMz +issue1834-home-9MuSeQ +issue1834-home-DODJPF +issue1834-home-HurtUC +issue1834-home-LCNpzb +issue1834-home-LNMiir +issue1834-home-LtJ0sn +issue1834-home-MAEU9B +issue1834-home-NFOJw4 +issue1834-home-NT0rFK +issue1834-home-OwJTYt +issue1834-home-ZVDWdE +issue1834-home-agsgI6 +issue1834-home-cFAxB4 +issue1834-home-ch8rGG +issue1834-home-eKI9QF +issue1834-home-kESvgJ +issue1834-home-mEJj1Z +issue1834-home-rq8gXP +issue1834-home-s61Pno +issue1834-home-y0JonQ +issue1834-home-z9e9mP +junit +log-tmp-solution-draft-log-pr-1780914367472.txt-1780914369132 +log-tmp-solution-draft-log-pr-1780915023524.txt-1780915025379 +log-tmp-solution-draft-log-pr-1780915027531.txt-1780915029049 +log-tmp-solution-draft-log-pr-1780916225581.txt-1780916235227 +log-tmp-solution-draft-log-pr-1780916264562.txt-1780916265910 +log-tmp-solution-draft-log-pr-1780916617183.txt-1780916620679 +log-tmp-solution-draft-log-pr-1780916834376.txt-1780916836115 +log-tmp-solution-draft-log-pr-1780917152229.txt-1780917153784 +log-tmp-solution-draft-log-pr-1780917272974.txt-1780917274949 +log-tmp-solution-draft-log-pr-1780917613248.txt-1780917615615 +log-tmp-solution-draft-log-pr-1780918444991.txt-1780918446789 +log-tmp-solution-draft-log-pr-1780919047545.txt-1780919049027 +log-tmp-solution-draft-log-pr-1780919973744.txt-1780919976295 +log-tmp-solution-draft-log-pr-1780921196763.txt-1780921198880 +log-tmp-solution-draft-log-pr-1780923333241.txt-1780923335080 +log-tmp-solution-draft-log-pr-1780923432501.txt-1780923434830 +log-tmp-solution-draft-log-pr-1780924423096.txt-1780924424714 +node-compile-cache +olcrtc-plugin-compile.jar +olcrtc-plugin-stubs +olcrtc-policy-tests.jar +olcrtc-policy.jar +opencode +opencode_prompt_1780915594804_84019.txt +opencode_prompt_1780915738540_99362.txt +opencode_prompt_1780918291146_269594.txt +opencode_prompt_1780922380696_406768.txt +opencode_prompt_1780923531531_521627.txt +pr-1862-body.md +pr-6-body.md +pr-body-1859.md +pr198-body.md +projects-mango-search.log +rust-paths-no-publishable-members-1780915547908016404 +rust-paths-no-publishable-members-1780916180202641279 +rust-paths-no-publishable-members-1780922525900339442 +rust-paths-no-publishable-members-1780922763676028877 +rust-paths-no-publishable-members-1780923850486723364 +rust-paths-no-publishable-members-1780924183754321085 +rust-paths-no-publishable-members-1780924299955917777 +rust-paths-no-publishable-members-1780924349387603169 +rust-paths-no-publishable-members-1780924396309813975 +rust-paths-root-package-1780915547908041251 +rust-paths-root-package-1780916180202814849 +rust-paths-root-package-1780922525901415308 +rust-paths-root-package-1780922763679312220 +rust-paths-root-package-1780923850488281220 +rust-paths-root-package-1780924183770342520 +rust-paths-root-package-1780924299959712333 +rust-paths-root-package-1780924349390611051 +rust-paths-root-package-1780924396313557666 +rust-paths-workspace-member-1780915547908030755 +rust-paths-workspace-member-1780916180202789090 +rust-paths-workspace-member-1780922525900550177 +rust-paths-workspace-member-1780922763676620590 +rust-paths-workspace-member-1780923850487524670 +rust-paths-workspace-member-1780924183764500917 +rust-paths-workspace-member-1780924299957156456 +rust-paths-workspace-member-1780924349390391945 +rust-paths-workspace-member-1780924396313305700 +stale-old-search.log +start-command +stdio-interceptor-stderr.log +stdio-interceptor-stdout.log +targeted-stale-search.final.log +targeted-stale-search.log +test-build +tsx-1001 +validate-frontmatter.after.log +validate-frontmatter.before.log +validate-frontmatter.final.log +validate-repository-structure.after.log +validate-repository-structure.before.log +validate-repository-structure.final.log +version-and-commit-lock-absent-1780915547906088725 +version-and-commit-lock-absent-1780916180198796718 +version-and-commit-lock-absent-1780922525889393578 +version-and-commit-lock-absent-1780922763663957532 +version-and-commit-lock-absent-1780923850483529053 +version-and-commit-lock-entry-absent-1780915547906338348 +version-and-commit-lock-entry-absent-1780916180198870178 +version-and-commit-lock-entry-absent-1780922525890427991 +version-and-commit-lock-entry-absent-1780922763664343478 +version-and-commit-lock-entry-absent-1780923850484194126 +version-and-commit-lock-idempotent-1780915547904281346 +version-and-commit-lock-idempotent-1780916180198344993 +version-and-commit-lock-idempotent-1780922525890289735 +version-and-commit-lock-idempotent-1780922763662227047 +version-and-commit-lock-idempotent-1780923850483469464 +version-and-commit-lock-update-1780915547906706608 +version-and-commit-lock-update-1780916180199340740 +version-and-commit-lock-update-1780922525893366100 +version-and-commit-lock-update-1780922763664777185 +version-and-commit-lock-update-1780923850485213909 +yougile-to-gh-check-logs +yougile-to-gh-fake-bin-1780915427857302756 +yougile-to-gh-fake-bin-1780915452632532192 +yougile-to-gh-fake-bin-1780923746734652232 +yougile-to-gh-fixture-1780915427856885834.json +yougile-to-gh-fixture-1780915452632203202.json +yougile-to-gh-fixture-1780923746734313036.json +yougile-to-gh-pr-4-body.md +(pass) Start/Run Options Passing > .start() method with options > should work with real shell commands [7.47ms] +already started test +(pass) Start/Run Options Passing > .start() method with options > should ignore options if process already started [0.51ms] +(pass) Start/Run Options Passing > .run() method (alias for .start()) > should work identically to .start() with capture: false [0.23ms] +test with run alias +(pass) Start/Run Options Passing > .run() method (alias for .start()) > should work identically to .start() with capture: true [0.10ms] +(pass) Start/Run Options Passing > .run() method (alias for .start()) > should work with multiple options [0.10ms] +run method input(pass) Start/Run Options Passing > .run() method (alias for .start()) > should work with stdin option [7.48ms] +default behavior +(pass) Start/Run Options Passing > Backward compatibility > direct await should still work with default options [0.32ms] +no options test +no options test +(pass) Start/Run Options Passing > Backward compatibility > .start() without options should work identically to direct await [0.17ms] +run no options +run no options +(pass) Start/Run Options Passing > Backward compatibility > .run() without options should work identically to direct await [0.14ms] +(pass) Start/Run Options Passing > Virtual commands support > should work with virtual echo command [0.08ms] +(pass) Start/Run Options Passing > Virtual commands support > should work with virtual commands using .run() [0.06ms] +empty options +(pass) Start/Run Options Passing > Edge cases > should handle empty options object [0.06ms] +(pass) Start/Run Options Passing > Edge cases > should handle mode option alongside other options [0.20ms] +(pass) Start/Run Options Passing > Edge cases > should reinitialize chunks when capture option changes [0.09ms] + +js/tests/gh-gist-operations.test.mjs: +(pass) GitHub Gist Operations with $.mjs > gh gist create should work with $.mjs and not hang [1113.29ms] +(pass) GitHub Gist Operations with $.mjs > gh gist view should retrieve gist details [315.01ms] +(pass) GitHub Gist Operations with $.mjs > gh api should work for gist operations [414.61ms] +(skip) GitHub Gist Operations with $.mjs > gh gist edit should add files to existing gist +(pass) GitHub Gist Operations with $.mjs > gh gist delete should remove gist [776.13ms] +(pass) GitHub Gist Operations with $.mjs > complex gh command with pipes should work [8562.15ms] + +js/tests/ctrl-c-basic.test.mjs: +(pass) CTRL+C Basic Handling > should be able to kill a long-running process [100.94ms] +(pass) CTRL+C Basic Handling > should spawn processes with detached flag on Unix [52.38ms] +inherit(pass) CTRL+C Basic Handling > should handle CTRL+C character in raw mode [101.28ms] +(pass) CTRL+C Virtual Commands > should cancel virtual command with AbortController [101.72ms] +hello +hello +hello +(pass) CTRL+C Virtual Commands > should cancel virtual async generator [1.35ms] +(pass) CTRL+C Different stdin Modes > should handle CTRL+C with string stdin [201.89ms] +(pass) CTRL+C Different stdin Modes > should handle CTRL+C with Buffer stdin [202.16ms] +(pass) CTRL+C Different stdin Modes > should handle CTRL+C with ignore stdin [101.55ms] +(pass) CTRL+C Pipeline Interruption > should interrupt simple pipeline [200.92ms] +(pass) CTRL+C Process Groups > should handle process group termination on Unix [202.09ms] + +js/tests/examples.test.mjs: +(skip) Examples Execution Tests > readme-example.mjs should execute and demonstrate new API signature +(skip) Examples Execution Tests > simple-jq-streaming.mjs should complete successfully +(pass) Examples Execution Tests > should have examples available for manual testing [0.15ms] +(pass) Examples Execution Tests > external process can be interrupted with SIGINT [505.37ms] +(pass) Examples Execution Tests > $.mjs should properly handle process interruption [200.96ms] +(pass) Examples Execution Tests > should not interfere with user SIGINT handling when no children active [508.72ms] +(pass) Examples Execution Tests > virtual commands should be properly cancelled by SIGINT (regression test) [201.36ms] + +js/tests/issue-135-final.test.mjs: +(pass) Issue #135: CI environment no longer auto-enables trace logs > should NOT emit trace logs when CI=true (main fix) [0.59ms] +(pass) Issue #135: CI environment no longer auto-enables trace logs > should allow JSON parsing in CI environment [0.17ms] +(pass) Issue #135: CI environment no longer auto-enables trace logs > should NOT produce trace logs by default (no env vars) [0.11ms] +(pass) Issue #135: CI environment no longer auto-enables trace logs > should work with mirror:false in CI environment [0.08ms] + +js/tests/shell-settings.test.mjs: +Command failed with exit code 1continued +(pass) Shell Settings (set -e / set +e equivalent) > Error Handling (set -e / set +e) > should continue execution by default (like bash without set -e) [0.41ms] +Command failed with exit code 42(pass) Shell Settings (set -e / set +e equivalent) > Error Handling (set -e / set +e) > should throw on error when errexit enabled (set -e) [0.21ms] +Command failed with exit code 1(pass) Shell Settings (set -e / set +e equivalent) > Error Handling (set -e / set +e) > should stop throwing when errexit disabled (set +e) [0.10ms] +Command failed with exit code 1Command failed with exit code 2Command failed with exit code 3(pass) Shell Settings (set -e / set +e equivalent) > Error Handling (set -e / set +e) > should allow mid-script changes (like bash) [0.25ms] +silent +(pass) Shell Settings (set -e / set +e equivalent) > Verbose Mode (set -v) > should not print commands by default [0.16ms] +verbose test ++ set +e +(pass) Shell Settings (set -e / set +e equivalent) > Verbose Mode (set -v) > should print commands when verbose enabled [0.22ms] +no trace +(pass) Shell Settings (set -e / set +e equivalent) > Trace Mode (set -x) > should not trace commands by default [0.10ms] +trace test +(pass) Shell Settings (set -e / set +e equivalent) > Trace Mode (set -x) > should trace commands when xtrace enabled [0.16ms] ++ set -v ++ set -x ++ set +e +(pass) Shell Settings (set -e / set +e equivalent) > Settings API > should allow setting options with set() function [0.06ms] ++ set -v ++ set +e +(pass) Shell Settings (set -e / set +e equivalent) > Settings API > should allow unsetting options with unset() function [0.03ms] ++ set -verbose ++ set +errexit ++ set +e +(pass) Shell Settings (set -e / set +e equivalent) > Settings API > should support long option names [0.04ms] ++ set -v ++ set +e +(pass) Shell Settings (set -e / set +e equivalent) > Settings API > should return current settings [0.03ms] +stdout +stderr +(pass) Shell Settings (set -e / set +e equivalent) > Shell Replacement Benefits > should provide better error objects than bash [5.59ms] +success1 +success2 +(pass) Shell Settings (set -e / set +e equivalent) > Shell Replacement Benefits > should allow JavaScript control flow with shell semantics [13.50ms] +setup complete +critical operation +(pass) Shell Settings (set -e / set +e equivalent) > Real-world Shell Script Pattern > should support common shell script patterns [5.85ms] + +js/tests/gh-commands.test.mjs: +(pass) GitHub CLI (gh) commands > gh auth status returns correct exit code and output structure [310.54ms] +(pass) GitHub CLI (gh) commands > gh command with invalid subcommand returns non-zero exit code [44.88ms] +(pass) GitHub CLI (gh) commands > gh api can be called with parameters [622.34ms] +(pass) GitHub CLI (gh) commands > gh gist list works with parameters [6672.86ms] +(pass) GitHub CLI (gh) commands > complex gh command with pipes and jq [647.00ms] + +js/tests/sigint-cleanup-isolated.test.mjs: +TEST: Starting SIGINT handler test +TEST: Check initial state +RESULT: initial_listeners=0 +TEST: Starting command +[TRACE 2026-06-08T13:14:43.969Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:43.970Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:43.970Z] [Utils] buildShellCommand EXIT | { + "command": "sleep 0.1" +} +[TRACE 2026-06-08T13:14:43.970Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "sleep 0.1" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:43.970Z] [StreamMonitor] Setting up parent stream monitoring +[TRACE 2026-06-08T13:14:43.970Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "sleep 0.1", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:43.970Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:43.970Z] [API] $tagged EXIT | { + "command": "sleep 0.1" +} +[TRACE 2026-06-08T13:14:43.970Z] [ProcessRunner] start ENTER | {"mode":"async","options":{},"started":false,"hasPromise":false,"hasChild":false,"command":"sleep 0.1"} +[TRACE 2026-06-08T13:14:43.970Z] [ProcessRunner] BRANCH: mode => async +[TRACE 2026-06-08T13:14:43.971Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"sleep 0.1"} +[TRACE 2026-06-08T13:14:43.971Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:43.971Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"sleep 0.1"} +[TRACE 2026-06-08T13:14:43.971Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"sleep","argsCount":1} +[TRACE 2026-06-08T13:14:43.971Z] [ProcessRunner] BRANCH: virtualCommand => sleep | {"isVirtual":true,"args":[{"value":"0.1","quoted":false}]} +[TRACE 2026-06-08T13:14:43.972Z] [ProcessRunner] _runVirtual | cmd=sleep +[TRACE 2026-06-08T13:14:43.972Z] [VirtualCommand] sleep: starting | { + "seconds": 0.1, + "hasSignal": true, + "signalAborted": false, + "hasIsCancelled": true +} +[TRACE 2026-06-08T13:14:43.972Z] [VirtualCommand] sleep: setting up abort signal listener | { + "signalAborted": false +} +[TRACE 2026-06-08T13:14:43.973Z] [VirtualCommand] sleep: setting up isCancelled polling | { + "seconds": 0.1 +} +RESULT: during_listeners=1 +[TRACE 2026-06-08T13:14:44.073Z] [VirtualCommand] sleep: completed naturally | { + "seconds": 0.1 +} +[TRACE 2026-06-08T13:14:44.073Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": false, + "hasStderr": false, + "command": "sleep 0.1" +} +[TRACE 2026-06-08T13:14:44.073Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.073Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.073Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.073Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.073Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.073Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.073Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.073Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.074Z] [VirtualCommand] sleep: abort signal received | { + "seconds": 0.1, + "signalAborted": true +} +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.074Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.074Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.074Z] [Utils] buildShellCommand EXIT | { + "command": "sleep 0.05" +} +RESULT: after_listeners=0 +TEST: Starting multiple concurrent commands +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "sleep 0.05" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.074Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "sleep 0.05", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.074Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.074Z] [API] $tagged EXIT | { + "command": "sleep 0.05" +} +[TRACE 2026-06-08T13:14:44.074Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.074Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.074Z] [Utils] buildShellCommand EXIT | { + "command": "sleep 0.05" +} +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "sleep 0.05" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.074Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "sleep 0.05", + "totalActive": 2 +} +[TRACE 2026-06-08T13:14:44.074Z] [API] $tagged EXIT | { + "command": "sleep 0.05" +} +[TRACE 2026-06-08T13:14:44.074Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.074Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.074Z] [Utils] buildShellCommand EXIT | { + "command": "sleep 0.05" +} +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "sleep 0.05" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.074Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "sleep 0.05", + "totalActive": 3 +} +[TRACE 2026-06-08T13:14:44.074Z] [API] $tagged EXIT | { + "command": "sleep 0.05" +} +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] start ENTER | {"mode":"async","options":{},"started":false,"hasPromise":false,"hasChild":false,"command":"sleep 0.05"} +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] BRANCH: mode => async +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"sleep 0.05"} +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.074Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"sleep 0.05"} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"sleep","argsCount":1} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] BRANCH: virtualCommand => sleep | {"isVirtual":true,"args":[{"value":"0.05","quoted":false}]} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] _runVirtual | cmd=sleep +[TRACE 2026-06-08T13:14:44.075Z] [VirtualCommand] sleep: starting | { + "seconds": 0.05, + "hasSignal": true, + "signalAborted": false, + "hasIsCancelled": true +} +[TRACE 2026-06-08T13:14:44.075Z] [VirtualCommand] sleep: setting up abort signal listener | { + "signalAborted": false +} +[TRACE 2026-06-08T13:14:44.075Z] [VirtualCommand] sleep: setting up isCancelled polling | { + "seconds": 0.05 +} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] start ENTER | {"mode":"async","options":{},"started":false,"hasPromise":false,"hasChild":false,"command":"sleep 0.05"} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] BRANCH: mode => async +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"sleep 0.05"} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"sleep 0.05"} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"sleep","argsCount":1} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] BRANCH: virtualCommand => sleep | {"isVirtual":true,"args":[{"value":"0.05","quoted":false}]} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] _runVirtual | cmd=sleep +[TRACE 2026-06-08T13:14:44.075Z] [VirtualCommand] sleep: starting | { + "seconds": 0.05, + "hasSignal": true, + "signalAborted": false, + "hasIsCancelled": true +} +[TRACE 2026-06-08T13:14:44.075Z] [VirtualCommand] sleep: setting up abort signal listener | { + "signalAborted": false +} +[TRACE 2026-06-08T13:14:44.075Z] [VirtualCommand] sleep: setting up isCancelled polling | { + "seconds": 0.05 +} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] start ENTER | {"mode":"async","options":{},"started":false,"hasPromise":false,"hasChild":false,"command":"sleep 0.05"} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] BRANCH: mode => async +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"sleep 0.05"} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"sleep 0.05"} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"sleep","argsCount":1} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] BRANCH: virtualCommand => sleep | {"isVirtual":true,"args":[{"value":"0.05","quoted":false}]} +[TRACE 2026-06-08T13:14:44.075Z] [ProcessRunner] _runVirtual | cmd=sleep +[TRACE 2026-06-08T13:14:44.075Z] [VirtualCommand] sleep: starting | { + "seconds": 0.05, + "hasSignal": true, + "signalAborted": false, + "hasIsCancelled": true +} +[TRACE 2026-06-08T13:14:44.075Z] [VirtualCommand] sleep: setting up abort signal listener | { + "signalAborted": false +} +[TRACE 2026-06-08T13:14:44.075Z] [VirtualCommand] sleep: setting up isCancelled polling | { + "seconds": 0.05 +} +RESULT: concurrent_listeners=1 +[TRACE 2026-06-08T13:14:44.124Z] [VirtualCommand] sleep: completed naturally | { + "seconds": 0.05 +} +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": false, + "hasStderr": false, + "command": "sleep 0.05" +} +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.125Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.125Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] _cleanup() | active=3 +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.125Z] [VirtualCommand] sleep: abort signal received | { + "seconds": 0.05, + "signalAborted": true +} +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.125Z] [VirtualCommand] sleep: completed naturally | { + "seconds": 0.05 +} +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": false, + "hasStderr": false, + "command": "sleep 0.05" +} +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.125Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.125Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] _cleanup() | active=2 +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.125Z] [VirtualCommand] sleep: abort signal received | { + "seconds": 0.05, + "signalAborted": true +} +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.125Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.126Z] [VirtualCommand] sleep: completed naturally | { + "seconds": 0.05 +} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": false, + "hasStderr": false, + "command": "sleep 0.05" +} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.126Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.126Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.126Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.126Z] [VirtualCommand] sleep: abort signal received | { + "seconds": 0.05, + "signalAborted": true +} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.126Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +RESULT: after_concurrent_listeners=0 +TEST: Testing error handling +[TRACE 2026-06-08T13:14:44.126Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.126Z] [Utils] buildShellCommand EXIT | { + "command": "exit 1" +} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "exit 1" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.126Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "exit 1", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.126Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.126Z] [API] $tagged EXIT | { + "command": "exit 1" +} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"exit 1"} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"exit 1"} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"exit","argsCount":1} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] BRANCH: virtualCommand => exit | {"isVirtual":true,"args":[{"value":"1","quoted":false}]} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] _runVirtual | cmd=exit +Command failed with exit code 1[TRACE 2026-06-08T13:14:44.126Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 31, + "options": {} +} +[TRACE 2026-06-08T13:14:44.126Z] [StreamEmitter] Emitting event | {"event":"stderr","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.126Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 1, + "hasStdout": false, + "hasStderr": true, + "command": "exit 1" +} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.126Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.126Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.127Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] 'exit' event emitted with code 1 +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.127Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.127Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.127Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.127Z] [Utils] buildShellCommand EXIT | { + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "sleep 10" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.127Z] [StreamMonitor] Parent streams already monitored, skipping +RESULT: after_error_listeners=0 +TEST: Testing kill cleanup +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "sleep 10", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.127Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.127Z] [API] $tagged EXIT | { + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] start ENTER | {"mode":"async","options":{},"started":false,"hasPromise":false,"hasChild":false,"command":"sleep 10"} +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] BRANCH: mode => async +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"sleep 10"} +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"sleep 10"} +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"sleep","argsCount":1} +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] BRANCH: virtualCommand => sleep | {"isVirtual":true,"args":[{"value":"10","quoted":false}]} +[TRACE 2026-06-08T13:14:44.127Z] [ProcessRunner] _runVirtual | cmd=sleep +[TRACE 2026-06-08T13:14:44.127Z] [VirtualCommand] sleep: starting | { + "seconds": 10, + "hasSignal": true, + "signalAborted": false, + "hasIsCancelled": true +} +[TRACE 2026-06-08T13:14:44.127Z] [VirtualCommand] sleep: setting up abort signal listener | { + "signalAborted": false +} +[TRACE 2026-06-08T13:14:44.127Z] [VirtualCommand] sleep: setting up isCancelled polling | { + "seconds": 10 +} +[TRACE 2026-06-08T13:14:44.137Z] [ProcessRunner] kill | signal=SIGTERM finished=false +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] Aborting internal controller | { + "wasAborted": false +} +[TRACE 2026-06-08T13:14:44.138Z] [VirtualCommand] sleep: abort signal received | { + "seconds": 10, + "signalAborted": true +} +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] Internal controller aborted | { + "nowAborted": true +} +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] No virtual generator to cleanup | { + "hasVirtualGenerator": false +} +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 143, + "hasStdout": false, + "hasStderr": true, + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.138Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.138Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] 'exit' event emitted with code 143 +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.138Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.138Z] [VirtualCommand] sleep: interrupted | { + "seconds": 10, + "error": "Sleep cancelled", + "errorName": "Error" +} +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] finish() called | { + "alreadyFinished": true, + "resultCode": 143, + "hasStdout": false, + "hasStderr": false, + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.138Z] [ProcessRunner] Already finished, returning existing result +RESULT: after_kill_listeners=0 +TEST: Complete +(pass) SIGINT Cleanup Tests (Isolated) > should properly manage SIGINT handlers [224.03ms] +TEST: Starting SIGINT forwarding test +TEST: Starting long-running command +[TRACE 2026-06-08T13:14:44.192Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.193Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.193Z] [Utils] buildShellCommand EXIT | { + "command": "sleep 30" +} +[TRACE 2026-06-08T13:14:44.193Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "sleep 30" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.193Z] [StreamMonitor] Setting up parent stream monitoring +[TRACE 2026-06-08T13:14:44.193Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "sleep 30", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.193Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.193Z] [API] $tagged EXIT | { + "command": "sleep 30" +} +[TRACE 2026-06-08T13:14:44.193Z] [ProcessRunner] start ENTER | {"mode":"async","options":{},"started":false,"hasPromise":false,"hasChild":false,"command":"sleep 30"} +[TRACE 2026-06-08T13:14:44.193Z] [ProcessRunner] BRANCH: mode => async +[TRACE 2026-06-08T13:14:44.193Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"sleep 30"} +[TRACE 2026-06-08T13:14:44.194Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.194Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"sleep 30"} +[TRACE 2026-06-08T13:14:44.194Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"sleep","argsCount":1} +[TRACE 2026-06-08T13:14:44.194Z] [ProcessRunner] BRANCH: virtualCommand => sleep | {"isVirtual":true,"args":[{"value":"30","quoted":false}]} +[TRACE 2026-06-08T13:14:44.194Z] [ProcessRunner] _runVirtual | cmd=sleep +[TRACE 2026-06-08T13:14:44.194Z] [VirtualCommand] sleep: starting | { + "seconds": 30, + "hasSignal": true, + "signalAborted": false, + "hasIsCancelled": true +} +[TRACE 2026-06-08T13:14:44.195Z] [VirtualCommand] sleep: setting up abort signal listener | { + "signalAborted": false +} +[TRACE 2026-06-08T13:14:44.195Z] [VirtualCommand] sleep: setting up isCancelled polling | { + "seconds": 30 +} +TEST: Sending SIGINT +[TRACE 2026-06-08T13:14:44.296Z] [ProcessRunner] Cancelling virtual command +[TRACE 2026-06-08T13:14:44.296Z] [ProcessRunner] kill | signal=SIGINT finished=false +[TRACE 2026-06-08T13:14:44.297Z] [ProcessRunner] Aborting internal controller | { + "wasAborted": false +} +[TRACE 2026-06-08T13:14:44.297Z] [VirtualCommand] sleep: abort signal received | { + "seconds": 30, + "signalAborted": true +} +[TRACE 2026-06-08T13:14:44.297Z] [ProcessRunner] Internal controller aborted | { + "nowAborted": true +} +[TRACE 2026-06-08T13:14:44.297Z] [ProcessRunner] No virtual generator to cleanup | { + "hasVirtualGenerator": false +} +[TRACE 2026-06-08T13:14:44.297Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 130, + "hasStdout": false, + "hasStderr": true, + "command": "sleep 30" +} +[TRACE 2026-06-08T13:14:44.297Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.297Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.297Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.297Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.297Z] [ProcessRunner] 'exit' event emitted with code 130 +[TRACE 2026-06-08T13:14:44.297Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.297Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.298Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.298Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.298Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.298Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.298Z] [ProcessRunner] SIGINT forwarded to 1 processes +RESULT: parent_received_sigint=true +[TRACE 2026-06-08T13:14:44.298Z] [VirtualCommand] sleep: interrupted | { + "seconds": 30, + "error": "Sleep cancelled", + "errorName": "Error" +} +[TRACE 2026-06-08T13:14:44.298Z] [ProcessRunner] finish() called | { + "alreadyFinished": true, + "resultCode": 130, + "hasStdout": false, + "hasStderr": false, + "command": "sleep 30" +} +[TRACE 2026-06-08T13:14:44.298Z] [ProcessRunner] Already finished, returning existing result +[TRACE 2026-06-08T13:14:44.396Z] [VirtualCommand] sleep: isCancelled returned true | { + "seconds": 30 +} +RESULT: sigint_received=true +[TRACE 2026-06-08T13:14:44.497Z] [ProcessRunner] kill | signal=SIGTERM finished=true +TEST: Complete +(pass) SIGINT Cleanup Tests (Isolated) > should forward SIGINT to child processes [360.02ms] +TEST: Starting cleanup verification +TEST: Virtual command cleanup +[TRACE 2026-06-08T13:14:44.556Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.557Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.557Z] [Utils] buildShellCommand EXIT | { + "command": "echo \"test1\"" +} +[TRACE 2026-06-08T13:14:44.557Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "echo \"test1\"" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.557Z] [StreamMonitor] Setting up parent stream monitoring +[TRACE 2026-06-08T13:14:44.557Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "echo \"test1\"", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.557Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.557Z] [API] $tagged EXIT | { + "command": "echo \"test1\"" +} +[TRACE 2026-06-08T13:14:44.558Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"echo \"test1\""} +[TRACE 2026-06-08T13:14:44.558Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.558Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"echo \"test1\""} +[TRACE 2026-06-08T13:14:44.558Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"echo","argsCount":1} +[TRACE 2026-06-08T13:14:44.558Z] [ProcessRunner] BRANCH: virtualCommand => echo | {"isVirtual":true,"args":[{"value":"test1","quoted":true,"quoteChar":"\""}]} +[TRACE 2026-06-08T13:14:44.558Z] [ProcessRunner] _runVirtual | cmd=echo +[TRACE 2026-06-08T13:14:44.559Z] [VirtualCommand] echo: processing | { + "argsCount": 1 +} +test1 +[TRACE 2026-06-08T13:14:44.559Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 6, + "options": {} +} +[TRACE 2026-06-08T13:14:44.559Z] [StreamEmitter] Emitting event | {"event":"stdout","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.560Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": true, + "hasStderr": false, + "command": "echo \"test1\"" +} +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.560Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.560Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.560Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] Cleanup completed +RESULT: virtual_finished=true +TEST: Real process cleanup +[TRACE 2026-06-08T13:14:44.560Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.560Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.560Z] [Utils] buildShellCommand EXIT | { + "command": "/bin/echo \"test2\"" +} +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "/bin/echo \"test2\"" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.560Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.560Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "/bin/echo \"test2\"", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.560Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.561Z] [API] $tagged EXIT | { + "command": "/bin/echo \"test2\"" +} +[TRACE 2026-06-08T13:14:44.561Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"/bin/echo \"test2\""} +[TRACE 2026-06-08T13:14:44.561Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.561Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"/bin/echo \"test2\""} +[TRACE 2026-06-08T13:14:44.561Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"/bin/echo","argsCount":1} +[TRACE 2026-06-08T13:14:44.561Z] [ShellDetection] Found shell at absolute path: /bin/sh +[TRACE 2026-06-08T13:14:44.561Z] [ProcessRunner] Constructed argv | {"mode":"shell","argv":["/bin/sh","-l","-c","/bin/echo \"test2\""],"originalCommand":"/bin/echo \"test2\""} +[TRACE 2026-06-08T13:14:44.561Z] [ProcessRunner] Interactive command detection | {"isInteractive":false,"stdinInherit":true,"interactiveOption":false} +[TRACE 2026-06-08T13:14:44.561Z] [ProcessRunner] About to spawn process | {"needsExplicitPipe":false,"preferNodeForInput":false,"runtime":"Node","command":"/bin/sh","args":["-l","-c","/bin/echo \"test2\""]} +[TRACE 2026-06-08T13:14:44.561Z] [ProcessRunner] spawnNode: Creating process | {"command":"/bin/sh","args":["-l","-c","/bin/echo \"test2\""],"isInteractive":false,"platform":"linux"} +[TRACE 2026-06-08T13:14:44.565Z] [ProcessRunner] spawnNode: Process created | {"pid":600010,"killed":false,"hasStdout":true,"hasStderr":true,"hasStdin":true} +[TRACE 2026-06-08T13:14:44.565Z] [ProcessRunner] Child process created | {"pid":600010,"killed":false,"hasStdout":true,"hasStderr":true,"hasStdin":true,"platform":"linux","command":"/bin/echo \"test2\""} +[TRACE 2026-06-08T13:14:44.565Z] [Utils] pumpReadable: Starting to pump readable stream +[TRACE 2026-06-08T13:14:44.566Z] [Utils] pumpReadable: Starting to pump readable stream +[TRACE 2026-06-08T13:14:44.566Z] [ProcessRunner] Setting up stdin handling | {"stdinType":"string","stdin":"inherit","isInteractive":false,"hasChildStdin":true} +[TRACE 2026-06-08T13:14:44.566Z] [ProcessRunner] stdin: Non-interactive inherit mode | {"isPipedIn":false} +[TRACE 2026-06-08T13:14:44.566Z] [ProcessRunner] stdin: Forwarding TTY stdin for non-interactive command +[TRACE 2026-06-08T13:14:44.566Z] [ProcessRunner] _forwardTTYStdin ENTER +[TRACE 2026-06-08T13:14:44.566Z] [ProcessRunner] Setting up child process event listeners for PID 600010 +[TRACE 2026-06-08T13:14:44.566Z] [ProcessRunner] Child process spawned successfully | {"pid":600010,"command":"/bin/echo \"test2\""} +[TRACE 2026-06-08T13:14:44.572Z] [ProcessRunner] stdout data received | {"pid":600010,"bufferLength":6,"capture":true,"mirror":true,"preview":"test2\n"} +test2 +[TRACE 2026-06-08T13:14:44.572Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 6, + "options": {} +} +[TRACE 2026-06-08T13:14:44.572Z] [StreamEmitter] Emitting event | {"event":"stdout","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.572Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.573Z] [Utils] pumpReadable: Finished pumping readable stream +[TRACE 2026-06-08T13:14:44.573Z] [Utils] pumpReadable: Finished pumping readable stream +[TRACE 2026-06-08T13:14:44.574Z] [ProcessRunner] Child process exit event | {"pid":600010,"code":0,"signal":null,"killed":false,"exitCode":0,"signalCode":null} +[TRACE 2026-06-08T13:14:44.574Z] [ProcessRunner] Child process close event | {"pid":600010,"code":0,"signal":null,"killed":false,"exitCode":0,"signalCode":null} +[TRACE 2026-06-08T13:14:44.574Z] [ProcessRunner] Raw exit code from child | {"code":0,"codeType":"number","cancelled":false,"isBun":false} +[TRACE 2026-06-08T13:14:44.574Z] [ProcessRunner] Process completed | {"finalExitCode":0,"captured":true,"hasStdout":true,"hasStderr":false,"stdoutLength":6,"stderrLength":0,"stdoutPreview":"test2\n","stderrPreview":"","childPid":600010,"cancelled":false,"cancellationSignal":null,"platform":"linux","runtime":"Node.js"} +[TRACE 2026-06-08T13:14:44.574Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": true, + "hasStderr": false, + "command": "/bin/echo \"test2\"" +} +[TRACE 2026-06-08T13:14:44.574Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.574Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.574Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.574Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.574Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.574Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.575Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] Cleaning up child process 600010 +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] Process finished, result set | {"finished":true,"resultCode":0} +[TRACE 2026-06-08T13:14:44.575Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.575Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.575Z] [Utils] buildShellCommand EXIT | { + "command": "exit 1" +} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "exit 1" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.575Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "exit 1", + "totalActive": 1 +} +RESULT: real_finished=true +TEST: Error cleanup +[TRACE 2026-06-08T13:14:44.575Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.575Z] [API] $tagged EXIT | { + "command": "exit 1" +} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"exit 1"} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"exit 1"} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"exit","argsCount":1} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] BRANCH: virtualCommand => exit | {"isVirtual":true,"args":[{"value":"1","quoted":false}]} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] _runVirtual | cmd=exit +Command failed with exit code 1[TRACE 2026-06-08T13:14:44.575Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 31, + "options": {} +} +[TRACE 2026-06-08T13:14:44.575Z] [StreamEmitter] Emitting event | {"event":"stderr","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.575Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 1, + "hasStdout": false, + "hasStderr": true, + "command": "exit 1" +} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.575Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.575Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] 'exit' event emitted with code 1 +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.575Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.575Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] Cleanup completed +RESULT: error_finished=true +TEST: Kill cleanup +[TRACE 2026-06-08T13:14:44.576Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.576Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.576Z] [Utils] buildShellCommand EXIT | { + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "sleep 10" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.576Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "sleep 10", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.576Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.576Z] [API] $tagged EXIT | { + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] start ENTER | {"mode":"async","options":{},"started":false,"hasPromise":false,"hasChild":false,"command":"sleep 10"} +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] BRANCH: mode => async +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"sleep 10"} +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"sleep 10"} +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"sleep","argsCount":1} +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] BRANCH: virtualCommand => sleep | {"isVirtual":true,"args":[{"value":"10","quoted":false}]} +[TRACE 2026-06-08T13:14:44.576Z] [ProcessRunner] _runVirtual | cmd=sleep +[TRACE 2026-06-08T13:14:44.576Z] [VirtualCommand] sleep: starting | { + "seconds": 10, + "hasSignal": true, + "signalAborted": false, + "hasIsCancelled": true +} +[TRACE 2026-06-08T13:14:44.576Z] [VirtualCommand] sleep: setting up abort signal listener | { + "signalAborted": false +} +[TRACE 2026-06-08T13:14:44.576Z] [VirtualCommand] sleep: setting up isCancelled polling | { + "seconds": 10 +} +[TRACE 2026-06-08T13:14:44.587Z] [ProcessRunner] kill | signal=SIGTERM finished=false +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] Aborting internal controller | { + "wasAborted": false +} +[TRACE 2026-06-08T13:14:44.588Z] [VirtualCommand] sleep: abort signal received | { + "seconds": 10, + "signalAborted": true +} +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] Internal controller aborted | { + "nowAborted": true +} +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] No virtual generator to cleanup | { + "hasVirtualGenerator": false +} +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 143, + "hasStdout": false, + "hasStderr": true, + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.588Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.588Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] 'exit' event emitted with code 143 +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.588Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.588Z] [VirtualCommand] sleep: interrupted | { + "seconds": 10, + "error": "Sleep cancelled", + "errorName": "Error" +} +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] finish() called | { + "alreadyFinished": true, + "resultCode": 143, + "hasStdout": false, + "hasStderr": false, + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.588Z] [ProcessRunner] Already finished, returning existing result +RESULT: kill_finished=true +TEST: Pipeline cleanup +[TRACE 2026-06-08T13:14:44.589Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.589Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.589Z] [Utils] buildShellCommand EXIT | { + "command": "echo \"test\" | /bin/cat | /bin/cat" +} +[TRACE 2026-06-08T13:14:44.589Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "echo \"test\" | /bin/cat | /bin/cat" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.589Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.589Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "echo \"test\" | /bin/cat | /bin/cat", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.589Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.589Z] [API] $tagged EXIT | { + "command": "echo \"test\" | /bin/cat | /bin/cat" +} +[TRACE 2026-06-08T13:14:44.589Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"echo \"test\" | /bin/cat | /bin/cat"} +[TRACE 2026-06-08T13:14:44.589Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.589Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"echo \"test\" | /bin/cat | /bin/cat"} +[TRACE 2026-06-08T13:14:44.589Z] [ProcessRunner] Parsed command | {"type":"pipeline"} +[TRACE 2026-06-08T13:14:44.589Z] [ProcessRunner] BRANCH: parsed.type => pipeline | {"commandCount":3} +[TRACE 2026-06-08T13:14:44.589Z] [ProcessRunner] _runPipeline ENTER | { + "commandsCount": 3 +} +[TRACE 2026-06-08T13:14:44.589Z] [ProcessRunner] BRANCH: _runPipeline => NODE_NON_STREAMING | {} +[TRACE 2026-06-08T13:14:44.589Z] [ProcessRunner] _runPipelineNonStreaming | cmds=3 +[TRACE 2026-06-08T13:14:44.589Z] [VirtualCommand] echo: processing | { + "argsCount": 1 +} +[TRACE 2026-06-08T13:14:44.590Z] [ShellDetection] Using cached shell: /bin/sh +[TRACE 2026-06-08T13:14:44.593Z] [ProcessRunner] spawnNodeAsync stdin write successful | { + "dataLength": 5 +} +[TRACE 2026-06-08T13:14:44.593Z] [ProcessRunner] spawnNodeAsync stdin ended successfully +[TRACE 2026-06-08T13:14:44.594Z] [ShellDetection] Using cached shell: /bin/sh +[TRACE 2026-06-08T13:14:44.597Z] [ProcessRunner] spawnNodeAsync stdin write successful | { + "dataLength": 5 +} +[TRACE 2026-06-08T13:14:44.597Z] [ProcessRunner] spawnNodeAsync stdin ended successfully +test +[TRACE 2026-06-08T13:14:44.599Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 5, + "options": {} +} +[TRACE 2026-06-08T13:14:44.599Z] [StreamEmitter] Emitting event | {"event":"stdout","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.599Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.599Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": true, + "hasStderr": false, + "command": "echo \"test\" | /bin/cat | /bin/cat" +} +[TRACE 2026-06-08T13:14:44.599Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.599Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.599Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.599Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.599Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.599Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.599Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.599Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.599Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.599Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.599Z] [ProcessRunner] Cleanup completed +RESULT: pipeline_output=test +TEST: Event listener cleanup +[TRACE 2026-06-08T13:14:44.599Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.599Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.599Z] [Utils] buildShellCommand EXIT | { + "command": "echo \"test\"" +} +[TRACE 2026-06-08T13:14:44.599Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "echo \"test\"" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.599Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "echo \"test\"", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.600Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.600Z] [API] $tagged EXIT | { + "command": "echo \"test\"" +} +[TRACE 2026-06-08T13:14:44.600Z] [StreamEmitter] on() called | {"event":"data","hasExistingListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.600Z] [StreamEmitter] on() called | {"event":"end","hasExistingListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"echo \"test\""} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"echo \"test\""} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"echo","argsCount":1} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] BRANCH: virtualCommand => echo | {"isVirtual":true,"args":[{"value":"test","quoted":true,"quoteChar":"\""}]} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] _runVirtual | cmd=echo +[TRACE 2026-06-08T13:14:44.600Z] [VirtualCommand] echo: processing | { + "argsCount": 1 +} +test +[TRACE 2026-06-08T13:14:44.600Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 5, + "options": {} +} +[TRACE 2026-06-08T13:14:44.600Z] [StreamEmitter] Emitting event | {"event":"stdout","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.600Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":true,"listenerCount":1} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": true, + "hasStderr": false, + "command": "echo \"test\"" +} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.600Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":true,"listenerCount":1} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.600Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.600Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] Cleanup completed +RESULT: event_listeners_size=0 +TEST: Concurrent command cleanup +[TRACE 2026-06-08T13:14:44.600Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.600Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.600Z] [Utils] buildShellCommand EXIT | { + "command": "echo \"c1\"" +} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "echo \"c1\"" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.600Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "echo \"c1\"", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.600Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.600Z] [API] $tagged EXIT | { + "command": "echo \"c1\"" +} +[TRACE 2026-06-08T13:14:44.600Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.600Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.600Z] [Utils] buildShellCommand EXIT | { + "command": "echo \"c2\"" +} +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "echo \"c2\"" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.600Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.600Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "echo \"c2\"", + "totalActive": 2 +} +[TRACE 2026-06-08T13:14:44.601Z] [API] $tagged EXIT | { + "command": "echo \"c2\"" +} +[TRACE 2026-06-08T13:14:44.601Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.601Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.601Z] [Utils] buildShellCommand EXIT | { + "command": "echo \"c3\"" +} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "echo \"c3\"" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.601Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "echo \"c3\"", + "totalActive": 3 +} +[TRACE 2026-06-08T13:14:44.601Z] [API] $tagged EXIT | { + "command": "echo \"c3\"" +} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"echo \"c1\""} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"echo \"c1\""} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"echo","argsCount":1} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] BRANCH: virtualCommand => echo | {"isVirtual":true,"args":[{"value":"c1","quoted":true,"quoteChar":"\""}]} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] _runVirtual | cmd=echo +[TRACE 2026-06-08T13:14:44.601Z] [VirtualCommand] echo: processing | { + "argsCount": 1 +} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"echo \"c2\""} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"echo \"c2\""} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"echo","argsCount":1} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] BRANCH: virtualCommand => echo | {"isVirtual":true,"args":[{"value":"c2","quoted":true,"quoteChar":"\""}]} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] _runVirtual | cmd=echo +[TRACE 2026-06-08T13:14:44.601Z] [VirtualCommand] echo: processing | { + "argsCount": 1 +} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"echo \"c3\""} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"echo \"c3\""} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"echo","argsCount":1} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] BRANCH: virtualCommand => echo | {"isVirtual":true,"args":[{"value":"c3","quoted":true,"quoteChar":"\""}]} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] _runVirtual | cmd=echo +[TRACE 2026-06-08T13:14:44.601Z] [VirtualCommand] echo: processing | { + "argsCount": 1 +} +c1 +[TRACE 2026-06-08T13:14:44.601Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 3, + "options": {} +} +[TRACE 2026-06-08T13:14:44.601Z] [StreamEmitter] Emitting event | {"event":"stdout","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.601Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.601Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 3, + "options": {} +} +c2 +[TRACE 2026-06-08T13:14:44.601Z] [StreamEmitter] Emitting event | {"event":"stdout","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.601Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":false,"listenerCount":0} +c3 +[TRACE 2026-06-08T13:14:44.601Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 3, + "options": {} +} +[TRACE 2026-06-08T13:14:44.601Z] [StreamEmitter] Emitting event | {"event":"stdout","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.601Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": true, + "hasStderr": false, + "command": "echo \"c1\"" +} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.601Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.601Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.601Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] _cleanup() | active=3 +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": true, + "hasStderr": false, + "command": "echo \"c2\"" +} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.602Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.602Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] _cleanup() | active=2 +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": true, + "hasStderr": false, + "command": "echo \"c3\"" +} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.602Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.602Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.602Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.602Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.602Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.602Z] [Utils] buildShellCommand EXIT | { + "command": "echo \"not awaited\"" +} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "echo \"not awaited\"" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.602Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "echo \"not awaited\"", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.602Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.602Z] [API] $tagged EXIT | { + "command": "echo \"not awaited\"" +} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] start ENTER | {"mode":"async","options":{},"started":false,"hasPromise":false,"hasChild":false,"command":"echo \"not awaited\""} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] BRANCH: mode => async +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"echo \"not awaited\""} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"echo \"not awaited\""} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"echo","argsCount":1} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] BRANCH: virtualCommand => echo | {"isVirtual":true,"args":[{"value":"not awaited","quoted":true,"quoteChar":"\""}]} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] _runVirtual | cmd=echo +[TRACE 2026-06-08T13:14:44.602Z] [VirtualCommand] echo: processing | { + "argsCount": 1 +} +[TRACE 2026-06-08T13:14:44.602Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 12, + "options": {} +} +[TRACE 2026-06-08T13:14:44.602Z] [StreamEmitter] Emitting event | {"event":"stdout","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.602Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 0, + "hasStdout": true, + "hasStderr": false, + "command": "echo \"not awaited\"" +} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.602Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.602Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] 'exit' event emitted with code 0 +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.602Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.603Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.603Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.603Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.603Z] [ProcessRunner] Cleanup completed +RESULT: concurrent_finished=true +TEST: Not awaited cleanup +not awaited +[TRACE 2026-06-08T13:14:44.677Z] [VirtualCommand] sleep: isCancelled returned true | { + "seconds": 10 +} +RESULT: not_awaited_finished=true +TEST: Stream iterator break cleanup +[TRACE 2026-06-08T13:14:44.703Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.703Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.703Z] [Utils] buildShellCommand EXIT | { + "command": "for i in 1 2 3; do echo $i; sleep 0.01; done" +} +[TRACE 2026-06-08T13:14:44.703Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "for i in 1 2 3; do echo $i; sleep 0.01; done" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.703Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.703Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "for i in 1 2 3; do echo $i; sleep 0.01; done", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.703Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.703Z] [API] $tagged EXIT | { + "command": "for i in 1 2 3; do echo $i; sleep 0.01; done" +} +[TRACE 2026-06-08T13:14:44.703Z] [ProcessRunner] stream ENTER | started=false +[TRACE 2026-06-08T13:14:44.703Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"for i in 1 2 3; do echo $i; sleep 0.01; done"} +[TRACE 2026-06-08T13:14:44.703Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.704Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":true,"shellOperatorsEnabled":true,"isStreamingPattern":true,"isStreaming":true,"shouldUseShellOperators":false,"command":"for i in 1 2 3; do echo $i; sleep 0.01; done"} +[TRACE 2026-06-08T13:14:44.704Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"for","argsCount":11} +[TRACE 2026-06-08T13:14:44.704Z] [StreamEmitter] on() called | {"event":"data","hasExistingListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.704Z] [StreamEmitter] on() called | {"event":"end","hasExistingListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.704Z] [ShellDetection] Using cached shell: /bin/sh +[TRACE 2026-06-08T13:14:44.704Z] [ProcessRunner] Constructed argv | {"mode":"shell","argv":["/bin/sh","-l","-c","for i in 1 2 3; do echo $i; sleep 0.01; done"],"originalCommand":"for i in 1 2 3; do echo $i; sleep 0.01; done"} +[TRACE 2026-06-08T13:14:44.704Z] [ProcessRunner] Interactive command detection | {"isInteractive":false,"stdinInherit":true,"interactiveOption":false} +[TRACE 2026-06-08T13:14:44.704Z] [ProcessRunner] About to spawn process | {"needsExplicitPipe":false,"preferNodeForInput":false,"runtime":"Node","command":"/bin/sh","args":["-l","-c","for i in 1 2 3; do echo $i; sleep 0.01; done"]} +[TRACE 2026-06-08T13:14:44.704Z] [ProcessRunner] spawnNode: Creating process | {"command":"/bin/sh","args":["-l","-c","for i in 1 2 3; do echo $i; sleep 0.01; done"],"isInteractive":false,"platform":"linux"} +[TRACE 2026-06-08T13:14:44.706Z] [ProcessRunner] spawnNode: Process created | {"pid":600034,"killed":false,"hasStdout":true,"hasStderr":true,"hasStdin":true} +[TRACE 2026-06-08T13:14:44.706Z] [ProcessRunner] Child process created | {"pid":600034,"killed":false,"hasStdout":true,"hasStderr":true,"hasStdin":true,"platform":"linux","command":"for i in 1 2 3; do echo $i; sleep 0.01; done"} +[TRACE 2026-06-08T13:14:44.706Z] [Utils] pumpReadable: Starting to pump readable stream +[TRACE 2026-06-08T13:14:44.707Z] [Utils] pumpReadable: Starting to pump readable stream +[TRACE 2026-06-08T13:14:44.707Z] [ProcessRunner] Setting up stdin handling | {"stdinType":"string","stdin":"inherit","isInteractive":false,"hasChildStdin":true} +[TRACE 2026-06-08T13:14:44.707Z] [ProcessRunner] stdin: Non-interactive inherit mode | {"isPipedIn":false} +[TRACE 2026-06-08T13:14:44.707Z] [ProcessRunner] stdin: Forwarding TTY stdin for non-interactive command +[TRACE 2026-06-08T13:14:44.707Z] [ProcessRunner] _forwardTTYStdin ENTER +[TRACE 2026-06-08T13:14:44.707Z] [ProcessRunner] Setting up child process event listeners for PID 600034 +[TRACE 2026-06-08T13:14:44.707Z] [ProcessRunner] Child process spawned successfully | {"pid":600034,"command":"for i in 1 2 3; do echo $i; sleep 0.01; done"} +[TRACE 2026-06-08T13:14:44.711Z] [ProcessRunner] stdout data received | {"pid":600034,"bufferLength":2,"capture":true,"mirror":true,"preview":"1\n"} +1 +[TRACE 2026-06-08T13:14:44.711Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 2, + "options": {} +} +[TRACE 2026-06-08T13:14:44.711Z] [StreamEmitter] Emitting event | {"event":"stdout","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.711Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":true,"listenerCount":1} +[TRACE 2026-06-08T13:14:44.722Z] [ProcessRunner] stdout data received | {"pid":600034,"bufferLength":2,"capture":true,"mirror":true,"preview":"2\n"} +2 +[TRACE 2026-06-08T13:14:44.722Z] [AnsiUtils] processOutput() called | { + "dataType": "object", + "dataLength": 2, + "options": {} +} +[TRACE 2026-06-08T13:14:44.722Z] [StreamEmitter] Emitting event | {"event":"stdout","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.722Z] [StreamEmitter] Emitting event | {"event":"data","hasListeners":true,"listenerCount":1} +[TRACE 2026-06-08T13:14:44.723Z] [StreamEmitter] off() called | {"event":"data","hasListeners":true,"listenerCount":1} +[TRACE 2026-06-08T13:14:44.723Z] [StreamEmitter] Removed listener at index 0 +[TRACE 2026-06-08T13:14:44.723Z] [StreamEmitter] off() called | {"event":"end","hasListeners":true,"listenerCount":1} +[TRACE 2026-06-08T13:14:44.723Z] [StreamEmitter] Removed listener at index 0 +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] kill | signal=SIGTERM finished=false +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Aborting internal controller | { + "wasAborted": false +} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Internal controller aborted | { + "nowAborted": true +} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] No virtual generator to cleanup | { + "hasVirtualGenerator": false +} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Killing child process 600034 +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Killing Node process | { + "pid": 600034 +} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Sent SIGTERM to process 600034 +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Sent SIGTERM to process group -600034 +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Sent SIGKILL to process 600034 +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Sent SIGKILL to process group -600034 +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Node kill operations attempted: SIGTERM to process, SIGTERM to group, SIGKILL to process, SIGKILL to group +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 143, + "hasStdout": false, + "hasStderr": true, + "command": "for i in 1 2 3; do echo $i; sleep 0.01; done" +} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.723Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":true,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.723Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] 'exit' event emitted with code 143 +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.723Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.723Z] [API] $tagged ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.723Z] [Utils] buildShellCommand ENTER | { + "stringsLength": 1, + "valuesLength": 0 +} +[TRACE 2026-06-08T13:14:44.723Z] [Utils] buildShellCommand EXIT | { + "command": "sleep 10" +} +RESULT: stream_iterator_finished=true +TEST: AbortController cleanup +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] constructor ENTER | { + "spec": { + "mode": "shell", + "command": "sleep 10" + }, + "options": { + "mirror": true, + "capture": true + } +} +[TRACE 2026-06-08T13:14:44.723Z] [StreamMonitor] Parent streams already monitored, skipping +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Added to activeProcessRunners | { + "command": "sleep 10", + "totalActive": 1 +} +[TRACE 2026-06-08T13:14:44.723Z] [SignalHandler] Installing SIGINT handler +[TRACE 2026-06-08T13:14:44.723Z] [API] $tagged EXIT | { + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] start ENTER | {"mode":"async","options":{},"started":false,"hasPromise":false,"hasChild":false,"command":"sleep 10"} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] BRANCH: mode => async +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] _doStartAsync ENTER | {"mode":"shell","command":"sleep 10"} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] BRANCH: spec.mode => shell | {} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Shell operator detection | {"hasShellOperators":false,"shellOperatorsEnabled":true,"isStreamingPattern":false,"shouldUseShellOperators":false,"command":"sleep 10"} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] Parsed command | {"type":"simple","cmd":"sleep","argsCount":1} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] BRANCH: virtualCommand => sleep | {"isVirtual":true,"args":[{"value":"10","quoted":false}]} +[TRACE 2026-06-08T13:14:44.723Z] [ProcessRunner] _runVirtual | cmd=sleep +[TRACE 2026-06-08T13:14:44.724Z] [VirtualCommand] sleep: starting | { + "seconds": 10, + "hasSignal": true, + "signalAborted": false, + "hasIsCancelled": true +} +[TRACE 2026-06-08T13:14:44.724Z] [VirtualCommand] sleep: setting up abort signal listener | { + "signalAborted": false +} +[TRACE 2026-06-08T13:14:44.724Z] [VirtualCommand] sleep: setting up isCancelled polling | { + "seconds": 10 +} +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] kill | signal=SIGTERM finished=false +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] Aborting internal controller | { + "wasAborted": false +} +[TRACE 2026-06-08T13:14:44.724Z] [VirtualCommand] sleep: abort signal received | { + "seconds": 10, + "signalAborted": true +} +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] Internal controller aborted | { + "nowAborted": true +} +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] No virtual generator to cleanup | { + "hasVirtualGenerator": false +} +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] finish() called | { + "alreadyFinished": false, + "resultCode": 143, + "hasStdout": false, + "hasStderr": true, + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] Result stored, about to emit events +[TRACE 2026-06-08T13:14:44.724Z] [StreamEmitter] Emitting event | {"event":"end","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] 'end' event emitted +[TRACE 2026-06-08T13:14:44.724Z] [StreamEmitter] Emitting event | {"event":"exit","hasListeners":false,"listenerCount":0} +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] 'exit' event emitted with code 143 +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] Marked as finished, calling cleanup +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] _cleanup() | active=1 +[TRACE 2026-06-08T13:14:44.724Z] [SignalHandler] Removing SIGINT handler | {"activeRunners":0} +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] Cleaning up abort controller +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] _cleanup() completed +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] Cleanup completed +[TRACE 2026-06-08T13:14:44.724Z] [VirtualCommand] sleep: interrupted | { + "seconds": 10, + "error": "Sleep cancelled", + "errorName": "Error" +} +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] finish() called | { + "alreadyFinished": true, + "resultCode": 143, + "hasStdout": false, + "hasStderr": false, + "command": "sleep 10" +} +[TRACE 2026-06-08T13:14:44.724Z] [ProcessRunner] Already finished, returning existing result +RESULT: had_abort_controller=true +RESULT: abort_controller_cleaned=true +RESULT: final_sigint_handlers=0 +TEST: Complete +(pass) SIGINT Cleanup Tests (Isolated) > should cleanup all resources properly [226.17ms] +test +(pass) SIGINT Cleanup Tests (Isolated) > should not interfere with user SIGINT handlers [51.59ms] + +js/tests/path-interpolation.test.mjs: +(pass) path interpolation - basic unquoted path [0.22ms] +(pass) path interpolation - path with spaces gets quoted [0.07ms] +(pass) path interpolation - path already wrapped in double quotes [0.05ms] +(pass) path interpolation - path already wrapped in single quotes [0.04ms] +(pass) path interpolation - environment variable inheritance works [0.11ms] +(pass) path interpolation - complex path scenarios [0.13ms] +(pass) path interpolation - stdin option with path works [0.13ms] +(pass) path interpolation - command building works correctly [0.03ms] +(pass) path interpolation - fixed escaping for simple pre-quoted paths [0.06ms] +(pass) path interpolation - environment variable scenario from GitHub issue [0.07ms] +(pass) path interpolation - improved handling of pre-quoted paths [0.03ms] +(pass) path interpolation - handles complex quoting edge cases [0.14ms] +(pass) shell injection - command substitution attempt [0.03ms] +(pass) shell injection - backtick command substitution [0.03ms] +(pass) shell injection - semicolon command chaining [0.03ms] +(pass) shell injection - pipe attempt [0.04ms] +(pass) shell injection - AND operator attempt [0.13ms] +(pass) shell injection - OR operator attempt [0.03ms] +(pass) shell injection - background process attempt [0.03ms] +(pass) shell injection - variable expansion attempt [0.02ms] +(pass) shell injection - glob expansion attempt [0.02ms] +(pass) shell injection - redirect attempt [0.04ms] +(pass) shell injection - newline injection [0.03ms] +(pass) shell injection - complex injection attempt [0.04ms] +(pass) safe strings - no unnecessary quoting [0.09ms] +(pass) double-quoting prevention - user quotes with spaces [0.06ms] +(pass) double-quoting prevention - user quotes with special chars [0.03ms] +(pass) double-quoting prevention - user unnecessarily quotes safe strings [0.03ms] +(pass) double-quoting prevention - mixed scenarios [0.09ms] +(pass) strings requiring quotes - proper quoting applied [0.24ms] + +js/tests/interactive-option.test.mjs: +(pass) Interactive Option Tests > interactive option - default behavior [3.02ms] +(pass) Interactive Option Tests > interactive option - explicit true [2.57ms] +(pass) Interactive Option Tests > interactive option - explicit false [2.42ms] +(pass) Interactive Option Tests > interactive option - passed through options merge [3.72ms] +(pass) Interactive Option Tests > interactive option - does not affect command execution with pipes/capture [2.71ms] +(pass) Interactive Option Tests > interactive option - behavior with stdin inherit but no TTY [2.45ms] +(pass) Interactive Option Tests > interactive option - works with template literal syntax [2.80ms] +(pass) Interactive Option Tests > interactive option - preserved in command chaining [2.65ms] +(pass) Interactive Option Tests > interactive option - type checking [3.50ms] + +js/tests/ctrl-c-library.test.mjs: +Sleep cancelled(pass) CTRL+C Library Tests (command-stream) > should handle command cancellation with kill() [602.44ms] +(skip) CTRL+C Library Tests (command-stream) > should test our library via external script - SKIP: uses test-sleep.mjs +(pass) CTRL+C Library Tests (command-stream) > should handle virtual command cancellation [3001.33ms] + +js/tests/builtin-commands.test.mjs: +Hello World +Line 2 +(pass) Built-in Commands (Bun.$ compatible) > File Reading Commands > cat should read file contents [0.90ms] +input +(pass) Built-in Commands (Bun.$ compatible) > File Reading Commands > cat should read from stdin when no files provided [0.65ms] +cat: nonexistent.txt: No such file or directory(pass) Built-in Commands (Bun.$ compatible) > File Reading Commands > cat should handle non-existent files [0.48ms] +file1.txt +file2.txt +subdir +(pass) Built-in Commands (Bun.$ compatible) > Directory Listing Commands > ls should list directory contents [8.30ms] +. +.. +.hidden +visible.txt +(pass) Built-in Commands (Bun.$ compatible) > Directory Listing Commands > ls should support -a flag for hidden files [8.63ms] +total 4 +-rw-r--r-- 1 box box 7 Jun 8 13:14 test.txt +(pass) Built-in Commands (Bun.$ compatible) > Directory Listing Commands > ls should support -l flag for long format [8.43ms] +(pass) Built-in Commands (Bun.$ compatible) > File Creation Commands > mkdir should create directories [0.76ms] +(pass) Built-in Commands (Bun.$ compatible) > File Creation Commands > mkdir -p should create parent directories [0.45ms] +(pass) Built-in Commands (Bun.$ compatible) > File Creation Commands > touch should create new files [0.69ms] +(pass) Built-in Commands (Bun.$ compatible) > File Creation Commands > touch should update existing file timestamps [12.34ms] +(pass) Built-in Commands (Bun.$ compatible) > File Removal Commands > rm should remove files [0.98ms] +rm: cannot remove 'test-builtin-commands/to-remove-dir': Is a directory(pass) Built-in Commands (Bun.$ compatible) > File Removal Commands > rm should fail on directories without -r [0.45ms] +(pass) Built-in Commands (Bun.$ compatible) > File Removal Commands > rm -r should remove directories recursively [0.62ms] +(pass) Built-in Commands (Bun.$ compatible) > File Removal Commands > rm -f should suppress errors on non-existent files [0.51ms] +(pass) Built-in Commands (Bun.$ compatible) > File Copy/Move Commands > cp should copy files [1.00ms] +(pass) Built-in Commands (Bun.$ compatible) > File Copy/Move Commands > cp -r should copy directories recursively [0.74ms] +(pass) Built-in Commands (Bun.$ compatible) > File Copy/Move Commands > mv should move/rename files [0.78ms] +(pass) Built-in Commands (Bun.$ compatible) > File Copy/Move Commands > mv should move files to directory [0.54ms] +file.txt +(pass) Built-in Commands (Bun.$ compatible) > Path Utility Commands > basename should extract filename [0.37ms] +file +(pass) Built-in Commands (Bun.$ compatible) > Path Utility Commands > basename should remove suffix [0.26ms] +/path/to +(pass) Built-in Commands (Bun.$ compatible) > Path Utility Commands > dirname should extract directory path [0.28ms] +1 +2 +3 +(pass) Built-in Commands (Bun.$ compatible) > Sequence Generation Commands > seq should generate number sequence [0.39ms] +1 +2 +3 +(pass) Built-in Commands (Bun.$ compatible) > Sequence Generation Commands > seq should handle single argument [0.24ms] +1 +3 +5 +(pass) Built-in Commands (Bun.$ compatible) > Sequence Generation Commands > seq should handle step argument [0.22ms] +hello +hello +hello +(pass) Built-in Commands (Bun.$ compatible) > Streaming Commands > yes should output repeatedly [2.29ms] +y +y +(pass) Built-in Commands (Bun.$ compatible) > Streaming Commands > yes should default to "y" [0.82ms] +/usr/bin/sh +(pass) Built-in Commands (Bun.$ compatible) > Command Location (which) > which should find existing system commands [1.00ms] +/home/box/.bun/bin/bun +(pass) Built-in Commands (Bun.$ compatible) > Command Location (which) > which should find node/bun executable [0.60ms] +/usr/bin/gh +(pass) Built-in Commands (Bun.$ compatible) > Command Location (which) > which should find homebrew-installed commands (if available) [0.78ms] +which: no nonexistent-command-12345 in PATH(pass) Built-in Commands (Bun.$ compatible) > Command Location (which) > which should return non-zero for non-existent commands [0.73ms] +echo: shell builtin +(pass) Built-in Commands (Bun.$ compatible) > Command Location (which) > which should find built-in virtual commands [0.24ms] +which: missing operand(pass) Built-in Commands (Bun.$ compatible) > Command Location (which) > which should handle missing arguments [0.26ms] +(pass) Built-in Commands (Bun.$ compatible) > Error Handling > commands should return proper exit codes [0.23ms] +cat: nonexistent.txt: No such file or directory(pass) Built-in Commands (Bun.$ compatible) > Error Handling > commands should provide helpful error messages [0.28ms] +mkdir: missing operandrm: missing operand(pass) Built-in Commands (Bun.$ compatible) > Error Handling > commands should handle missing operands [0.45ms] + +js/tests/options-syntax.test.mjs: +test input +(pass) $({ options }) syntax > should support $({ options }) syntax for custom options [9.03ms] +(pass) $({ options }) syntax > should support capture and mirror options [0.45ms] +(pass) $({ options }) syntax > should support multiple options at once [6.14ms] +custom_value +(pass) $({ options }) syntax > should work with environment variables [5.97ms] +/tmp +(pass) $({ options }) syntax > should work with custom working directory [0.36ms] +(pass) $({ options }) syntax > should be reusable for multiple commands [0.19ms] +regular +regular again +(pass) $({ options }) syntax > should work alongside regular $ usage [0.13ms] +test +(pass) $({ options }) syntax > should handle stdin as ignore [0.11ms] +test +(pass) $({ options }) syntax > should handle stdin as inherit (default) [0.12ms] +(pass) $({ options }) syntax > should work with interpolation [0.08ms] +(pass) $({ options }) syntax > should work with command chaining [3.26ms] +(pass) $({ options }) syntax > should handle errors with custom options [6.45ms] + +js/tests/ctrl-c-baseline.test.mjs: +(pass) CTRL+C Baseline Tests (Native Spawn) > should handle SIGINT with simple shell command [3502.97ms] +(pass) CTRL+C Baseline Tests (Native Spawn) > should handle Node.js inline script with SIGINT [507.09ms] +(pass) CTRL+C Baseline Tests (Native Spawn) > should handle Node.js script file [1007.20ms] + +js/tests/bun.features.test.mjs: +(pass) Bun.$ Feature Validation > Runtime Support > should only work in Bun runtime [0.66ms] +(pass) Bun.$ Feature Validation > Runtime Support > should be Bun-specific (conceptual test) [0.03ms] +bun template literal test +(pass) Bun.$ Feature Validation > Template Literals > should support $`cmd` syntax [0.73ms] +bun interpolation test +(pass) Bun.$ Feature Validation > Template Literals > should support variable interpolation [0.17ms] +bun buffered test +(pass) Bun.$ Feature Validation > Real-time Streaming > should NOT provide live streaming (buffers only) [0.15ms] +no async iteration +(pass) Bun.$ Feature Validation > Async Iteration > should NOT support for await iteration [0.10ms] +no events +(pass) Bun.$ Feature Validation > EventEmitter Pattern > should NOT support .on() events [0.10ms] +await only +(pass) Bun.$ Feature Validation > Mixed Patterns > should NOT support events + await (only await) [0.12ms] +'; rm -rf /; echo 'hacked +(pass) Bun.$ Feature Validation > Shell Injection Protection > should have built-in injection protection [0.11ms] +cross-platform +(pass) Bun.$ Feature Validation > Cross-platform Support > should work cross-platform [0.10ms] +performance test +(pass) Bun.$ Feature Validation > Performance > should be very fast (built-in to Bun) [0.15ms] +memory buffering +(pass) Bun.$ Feature Validation > Memory Efficiency > should buffer in memory (not streaming) [0.13ms] +(pass) Bun.$ Feature Validation > Error Handling > should throw exception on error by default [0.23ms] +(pass) Bun.$ Feature Validation > Error Handling > should support nothrow option [0.10ms] +(pass) Bun.$ Feature Validation > Stdin Support > should support pipe operations [0.18ms] +stdin input test +(pass) Bun.$ Feature Validation > Stdin Support > should support input through echo/pipe (conceptual) [0.10ms] +built-in echo +(pass) Bun.$ Feature Validation > Built-in Commands > should have built-in echo command [0.10ms] +/tmp/gh-issue-solver-1780922968363 +(pass) Bun.$ Feature Validation > Built-in Commands > should have built-in cd and other commands [0.09ms] +(pass) Bun.$ Feature Validation > Bundle Size > should have 0KB bundle size (built into Bun) [0.01ms] +(pass) Bun.$ Feature Validation > TypeScript Support > should have built-in TypeScript support [0.02ms] + +js/tests/interactive-streaming.test.mjs: +READY +RESULT: 3 +RESULT: 50 +RESULT: 25 +RESULT: 4 +RESULT: 256 +GOODBYE +(pass) Interactive Streaming > should support bidirectional streaming I/O while process is running [97.24ms] +READY +ERROR: Invalid expression: invalid expression +RESULT: 10 +GOODBYE +(pass) Interactive Streaming > should handle errors in expressions [69.31ms] +READY +GOODBYE +(pass) Interactive Streaming > should auto-start process when accessing streams [43.47ms] +READY +GOODBYE +(pass) Interactive Streaming > should return null for streams after process completes [37.65ms] +READY +RESULT: 2 +RESULT: 4 +RESULT: 6 +RESULT: 8 +RESULT: 10 +GOODBYE +(pass) Interactive Streaming > should handle multiple simultaneous calculations [70.52ms] + +js/tests/stderr-output-handling.test.mjs: +(pass) Stderr output handling in $.mjs > commands that output to stderr should not hang when captured [8.82ms] +(pass) Stderr output handling in $.mjs > gh commands with progress output to stderr should complete [35.14ms] +(pass) Stderr output handling in $.mjs > capturing with 2>&1 should combine stderr into stdout [7.72ms] +(pass) Stderr output handling in $.mjs > long-running commands with stderr output should not hang [322.17ms] +Skipping gh gist test - limited GitHub Actions token or API access (this is OK - we are testing $.mjs, not gh permissions) +(pass) Stderr output handling in $.mjs > gh gist create with stderr progress should work correctly [515.31ms] +line1 +err1 +line2 +err2 +(pass) Stderr output handling in $.mjs > streaming mode should handle stderr correctly [112.97ms] +(skip) Stderr output handling in $.mjs > timeout should work even with pending stderr + +js/tests/pipe.test.mjs: +Hello World +Piped: Hello World +(pass) Programmatic .pipe() Method > Basic Piping > should pipe between built-in commands [1.27ms] +hello +hellohello +10 +(pass) Programmatic .pipe() Method > Basic Piping > should pipe virtual commands [0.65ms] +test +[PIPED] test +(pass) Programmatic .pipe() Method > Basic Piping > should handle stdin properly in pipe chain [0.42ms] +cat: nonexistent-file.txt: No such file or directory(pass) Programmatic .pipe() Method > Error Handling > should propagate errors from source command [0.39ms] +hello +Virtual command failed(pass) Programmatic .pipe() Method > Error Handling > should handle errors in destination command [0.36ms] +hello +Something went wrong(pass) Programmatic .pipe() Method > Error Handling > should handle exceptions in virtual commands [0.36ms] +hello +HELLO + +OLLEH[OLLEH] +(pass) Programmatic .pipe() Method > Complex Pipelines > should support multiple pipe operations [0.48ms] +data +data +Warning from cmd1 +data +Warning from cmd2 +(pass) Programmatic .pipe() Method > Complex Pipelines > should preserve stderr from all commands [0.37ms] +Line 1 +Line 2 +Line 3 +3 +(pass) Programmatic .pipe() Method > Mixed Command Types > should pipe from built-in to virtual command [0.58ms] +1 +2 +3 +4 +5 +Got 5 lines +(pass) Programmatic .pipe() Method > Mixed Command Types > should pipe from virtual to built-in command [0.42ms] +Line 1 +Line 2 +Line 3 +Line 4 +Line 5 +Line 6 +Line 7 +Line 8 +Line 9 +Line 10 +Line 11 +Line 12 +Line 13 +Line 14 +Line 15 +Line 16 +Line 17 +Line 18 +Line 19 +Line 20 +Line 21 +Line 22 +Line 23 +Line 24 +Line 25 +Line 26 +Line 27 +Line 28 +Line 29 +Line 30 +Line 31 +Line 32 +Line 33 +Line 34 +Line 35 +Line 36 +Line 37 +Line 38 +Line 39 +Line 40 +Line 41 +Line 42 +Line 43 +Line 44 +Line 45 +Line 46 +Line 47 +Line 48 +Line 49 +Line 50 +Line 51 +Line 52 +Line 53 +Line 54 +Line 55 +Line 56 +Line 57 +Line 58 +Line 59 +Line 60 +Line 61 +Line 62 +Line 63 +Line 64 +Line 65 +Line 66 +Line 67 +Line 68 +Line 69 +Line 70 +Line 71 +Line 72 +Line 73 +Line 74 +Line 75 +Line 76 +Line 77 +Line 78 +Line 79 +Line 80 +Line 81 +Line 82 +Line 83 +Line 84 +Line 85 +Line 86 +Line 87 +Line 88 +Line 89 +Line 90 +Line 91 +Line 92 +Line 93 +Line 94 +Line 95 +Line 96 +Line 97 +Line 98 +Line 99 +Line 100 +100 +(pass) Programmatic .pipe() Method > Performance and Memory > should handle large data efficiently [0.51ms] +hello +hello processed +Formatted: hello processed +(pass) Programmatic .pipe() Method > Compatibility with Shell Piping > should work alongside shell pipe syntax [0.40ms] + +js/tests/cd-virtual-command.test.mjs: +/tmp/cd-test-Ab5I4u +(pass) cd Virtual Command - Core Behavior > should change to absolute path [5.04ms] +/tmp/cd-base-trg0im/subdir +(pass) cd Virtual Command - Core Behavior > should change to relative path [3.80ms] +/home/box +(pass) cd Virtual Command - Core Behavior > should handle cd with no arguments (go to home) [2.63ms] +/tmp/cd-dir1-aUuRgu +/tmp/cd-dir2-Knp24r +not implemented +(pass) cd Virtual Command - Core Behavior > should handle cd - (return to previous directory) [3.47ms] +/tmp/cd-parent-VFtc7V +(pass) cd Virtual Command - Core Behavior > should handle cd .. (parent directory) [3.00ms] +/tmp/cd-dot-snomBz +/tmp/cd-dot-snomBz +(pass) cd Virtual Command - Core Behavior > should handle cd . (current directory) [4.39ms] +failed +/tmp/gh-issue-solver-1780922968363 +(pass) cd Virtual Command - Core Behavior > should fail with non-existent directory [2.72ms] +/tmp/cd-spaces-gjq9Po/my test directory +(pass) cd Virtual Command - Core Behavior > should handle paths with spaces [3.11ms] +/tmp/cd-special-NCItPT/test-dir_123 +(pass) cd Virtual Command - Core Behavior > should handle special characters in paths [3.08ms] +test content(pass) cd Virtual Command - Command Chains > should persist directory change within command chain [5.29ms] +content1content2(pass) cd Virtual Command - Command Chains > should handle multiple cd commands in chain [3.98ms] +hint: Using 'master' as the name for the initial branch. This default branch name +hint: is subject to change. To configure the initial branch name to use in all +hint: of your new repositories, which will suppress this warning, call: +hint: +hint: git config --global init.defaultBranch +hint: +hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and +hint: 'development'. The just-created branch can be renamed via this command: +hint: +hint: git branch -m +Initialized empty Git repository in /tmp/cd-git-4HaL3t/.git/ +(pass) cd Virtual Command - Command Chains > should work with git commands in chain [16.08ms] +/tmp/cd-ctx1-1Y7ZbG +/tmp/cd-ctx1-1Y7ZbG +(pass) cd Virtual Command - Command Chains > should maintain separate directory context per command when not chained [3.66ms] +/tmp/gh-issue-solver-1780922968363 +(pass) cd Virtual Command - Subshell Behavior > should not affect parent shell when in subshell [3.40ms] +subshell test/tmp/gh-issue-solver-1780922968363 +(pass) cd Virtual Command - Subshell Behavior > should work in subshell with other commands [3.29ms] +/tmp/cd-symlink-18zbSh/real +(pass) cd Virtual Command - Edge Cases > should handle symlinks [12.19ms] +/tmp/cd-long-feXwfM/level0/level1/level2/level3/level4/level5/level6/level7/level8/level9 +(pass) cd Virtual Command - Edge Cases > should handle very long paths [5.27ms] +permission denied +/tmp/gh-issue-solver-1780922968363 +(pass) cd Virtual Command - Edge Cases > should handle permission errors gracefully [17.39ms] +/tmp/cd-slash-dmJmPI +(pass) cd Virtual Command - Edge Cases > should handle cd with trailing slash [3.62ms] +/tmp/cd-slashes-pX7zGK/sub +(pass) cd Virtual Command - Edge Cases > should handle cd with multiple slashes [3.13ms] +/tmp/cd-platform-3foMyw/cross/platform/test +(pass) cd Virtual Command - Platform Compatibility > should handle platform-specific path separators [3.60ms] +/tmp/cd-normalize-55JD3K/sub1/sub2 +(pass) cd Virtual Command - Platform Compatibility > should normalize paths correctly [4.25ms] + +js/tests/zx.features.test.mjs: +(pass) zx Feature Validation (Conceptual) > Runtime Support > should work in Node.js runtime [0.03ms] +(pass) zx Feature Validation (Conceptual) > Runtime Support > should NOT work natively in Bun without compatibility +(pass) zx Feature Validation (Conceptual) > Template Literals > should support $`cmd` syntax +(pass) zx Feature Validation (Conceptual) > Template Literals > should support variable interpolation +(pass) zx Feature Validation (Conceptual) > Real-time Streaming > should NOT provide real-time streaming (buffers only) +(pass) zx Feature Validation (Conceptual) > Real-time Streaming > should return complete buffered output +(pass) zx Feature Validation (Conceptual) > Async Iteration > should NOT support for await iteration +(pass) zx Feature Validation (Conceptual) > EventEmitter Pattern > should NOT support .on() events +(pass) zx Feature Validation (Conceptual) > Mixed Patterns > should NOT support events + await (only await) +(pass) zx Feature Validation (Conceptual) > Shell Injection Protection > should be safe by default +(pass) zx Feature Validation (Conceptual) > Cross-platform Support > should work cross-platform +(pass) zx Feature Validation (Conceptual) > Performance > should have slow performance +(pass) zx Feature Validation (Conceptual) > Memory Efficiency > should buffer in memory +(pass) zx Feature Validation (Conceptual) > Error Handling > should throw exception on error +(pass) zx Feature Validation (Conceptual) > Error Handling > should support nothrow mode +(pass) zx Feature Validation (Conceptual) > Stdin Support > should support basic stdin +(pass) zx Feature Validation (Conceptual) > Built-in Commands > should NOT have built-in commands +(pass) zx Feature Validation (Conceptual) > Bundle Size > should have ~50KB bundle size +(pass) zx Feature Validation (Conceptual) > TypeScript Support > should have full TypeScript support +(pass) zx Feature Validation (Conceptual) > Shell Scripting Features > should support convenient shell scripting helpers [0.02ms] +(pass) zx Feature Validation (Conceptual) > Shell Scripting Features > should support colorful output +(pass) zx Feature Validation (Conceptual) > Shell Scripting Features > should support file system utilities +(pass) zx Feature Validation (Conceptual) > Developer Experience > should have excellent DX for shell scripts +(pass) zx Feature Validation (Conceptual) > Developer Experience > should support shebang for executable scripts +(pass) zx Feature Validation (Conceptual) > Execution Model > should use system shell for all commands +(pass) zx Feature Validation (Conceptual) > Execution Model > should support shell-specific features [0.01ms] + +js/tests/execa.features.test.mjs: +(pass) execa Feature Validation (Conceptual) > Runtime Support > should work in Node.js runtime [0.02ms] +(pass) execa Feature Validation (Conceptual) > Runtime Support > should NOT work natively in Bun without compatibility +(pass) execa Feature Validation (Conceptual) > Template Literals > should support $`cmd` syntax with execa +(pass) execa Feature Validation (Conceptual) > Template Literals > should support variable interpolation +(pass) execa Feature Validation (Conceptual) > Real-time Streaming > should have LIMITED streaming capabilities +(pass) execa Feature Validation (Conceptual) > Real-time Streaming > should buffer output by default +(pass) execa Feature Validation (Conceptual) > Async Iteration > should NOT support for await iteration on result +(pass) execa Feature Validation (Conceptual) > EventEmitter Pattern > should have LIMITED event support on subprocess +(pass) execa Feature Validation (Conceptual) > Mixed Patterns > should NOT support events + await on same object +(pass) execa Feature Validation (Conceptual) > Shell Injection Protection > should be safe by default +(pass) execa Feature Validation (Conceptual) > Cross-platform Support > should work cross-platform +(pass) execa Feature Validation (Conceptual) > Performance > should have moderate performance +(pass) execa Feature Validation (Conceptual) > Memory Efficiency > should buffer in memory by default +(pass) execa Feature Validation (Conceptual) > Error Handling > should reject promise on error +(pass) execa Feature Validation (Conceptual) > Stdin Support > should support input/output streams +(pass) execa Feature Validation (Conceptual) > Built-in Commands > should NOT have built-in commands +(pass) execa Feature Validation (Conceptual) > Bundle Size > should have ~25KB bundle size +(pass) execa Feature Validation (Conceptual) > TypeScript Support > should have full TypeScript support +(pass) execa Feature Validation (Conceptual) > Advanced Features > should support timeout settings +(pass) execa Feature Validation (Conceptual) > Advanced Features > should support detailed error information [0.02ms] +(pass) execa Feature Validation (Conceptual) > Advanced Features > should support verbose and debugging modes + +js/tests/sync.test.mjs: +hello sync +(pass) Synchronous Execution (.sync()) > Basic Sync Functionality > should execute commands synchronously [6.29ms] +stdout +stderr +(pass) Synchronous Execution (.sync()) > Basic Sync Functionality > should handle stderr in sync mode [6.64ms] +(pass) Synchronous Execution (.sync()) > Basic Sync Functionality > should handle non-zero exit codes [4.99ms] +/bin/sh: 1: nonexistent-command-99999: not found +(pass) Synchronous Execution (.sync()) > Basic Sync Functionality > should handle command not found [5.11ms] +sync output +(pass) Synchronous Execution (.sync()) > Events in Sync Mode > should emit batched events after completion [4.95ms] +error +(pass) Synchronous Execution (.sync()) > Events in Sync Mode > should emit stderr events in sync mode [5.73ms] +mirrored +(pass) Synchronous Execution (.sync()) > Options in Sync Mode > should respect mirror option [7.84ms] +test +(pass) Synchronous Execution (.sync()) > Options in Sync Mode > should respect capture option [5.67ms] +custom inputbuffer inputignored +(pass) Synchronous Execution (.sync()) > Options in Sync Mode > should handle stdin options [17.32ms] +/tmp +(pass) Synchronous Execution (.sync()) > Options in Sync Mode > should handle cwd option [4.48ms] +(pass) Synchronous Execution (.sync()) > Shell Settings in Sync Mode > should respect errexit setting [8.25ms] +verbose test ++ set +e +(pass) Synchronous Execution (.sync()) > Shell Settings in Sync Mode > should respect verbose setting [4.68ms] +trace test +(pass) Synchronous Execution (.sync()) > Shell Settings in Sync Mode > should respect xtrace setting [4.36ms] +test +(pass) Synchronous Execution (.sync()) > Error Handling > should throw if command already started asynchronously [0.37ms] +output +error +(pass) Synchronous Execution (.sync()) > Error Handling > should include error details when errexit is enabled [5.76ms] +line1 +line2 +line3(pass) Synchronous Execution (.sync()) > Complex Scenarios > should handle multiline output [4.22ms] +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +(pass) Synchronous Execution (.sync()) > Complex Scenarios > should handle large output [5.87ms] +It's a 'test' with "quotes" +(pass) Synchronous Execution (.sync()) > Complex Scenarios > should handle commands with quotes and special characters [5.01ms] + +error + +error +(pass) Synchronous Execution (.sync()) > Comparison with Async > should produce same result as async version [13.24ms] +test +test +(pass) Synchronous Execution (.sync()) > Comparison with Async > should handle events differently than async [5.67ms] + +js/tests/raw-function.test.mjs: +(pass) raw() function - Disable auto-escape > basic functionality > should create raw object with string [0.09ms] +(pass) raw() function - Disable auto-escape > basic functionality > should convert numbers to string [0.01ms] +(pass) raw() function - Disable auto-escape > basic functionality > should convert boolean to string [0.01ms] +(pass) raw() function - Disable auto-escape > basic functionality > should handle empty string [0.04ms] +hello world +(pass) raw() function - Disable auto-escape > command execution with raw() > should execute simple raw command [5.34ms] +step1 +step2 +(pass) raw() function - Disable auto-escape > command execution with raw() > should execute command with && operator [11.02ms] +fallback +(pass) raw() function - Disable auto-escape > command execution with raw() > should execute command with || operator [9.93ms] +2 +(pass) raw() function - Disable auto-escape > command execution with raw() > should execute command with pipe [3.00ms] +first +second +(pass) raw() function - Disable auto-escape > command execution with raw() > should execute command with semicolon [9.73ms] +outer: inner +(pass) raw() function - Disable auto-escape > command execution with raw() > should handle command with subshell [4.42ms] +test-*.mjs +(pass) raw() function - Disable auto-escape > command execution with raw() > should handle command with wildcards [1.81ms] +prefix: test +(pass) raw() function - Disable auto-escape > combining raw() with safe interpolation > should mix raw command with safe variable [3.62ms] +User said: test; rm -rf / +(pass) raw() function - Disable auto-escape > combining raw() with safe interpolation > should safely quote user input when mixed with raw [4.07ms] +part1 +part2 +(pass) raw() function - Disable auto-escape > combining raw() with safe interpolation > should handle multiple raw() calls in one command [9.28ms] +test +test2 +echo "test" && echo "test2" +(pass) raw() function - Disable auto-escape > comparison with normal interpolation > raw() executes shell operators, normal interpolation escapes them [12.20ms] +2 +echo "hello world" | wc -w +(pass) raw() function - Disable auto-escape > comparison with normal interpolation > raw() allows pipes, normal interpolation escapes them [3.53ms] +test +$(echo test) +(pass) raw() function - Disable auto-escape > comparison with normal interpolation > raw() allows command substitution, normal interpolation escapes it [8.31ms] +single'quote double"quote +(pass) raw() function - Disable auto-escape > edge cases > should handle raw() with quotes in command [4.37ms] +/home/box +(pass) raw() function - Disable auto-escape > edge cases > should handle raw() with environment variables [3.94ms] +line1 +line2 +(pass) raw() function - Disable auto-escape > edge cases > should handle raw() with newlines [3.95ms] +start end +start +middle end +start +end +(pass) raw() function - Disable auto-escape > edge cases > should handle raw() at different positions [19.03ms] +Building... +Done +Testing... +Passed +(pass) raw() function - Disable auto-escape > practical use cases > configuration-based commands [16.77ms] +3 +(pass) raw() function - Disable auto-escape > practical use cases > complex shell pipelines [2.70ms] +success +(pass) raw() function - Disable auto-escape > practical use cases > conditional execution chains [13.07ms] +; rm -rf /tmp/test +(pass) raw() function - Disable auto-escape > security demonstrations > normal interpolation prevents injection [4.80ms] +safe +This would be dangerous with rm -rf +(pass) raw() function - Disable auto-escape > security demonstrations > raw() would execute injection (demonstration only) [9.93ms] +(pass) raw() function - Disable auto-escape > error handling > should handle failing commands in raw() [4.69ms] +/bin/sh: 1: nonexistent-command-12345: not found +(pass) raw() function - Disable auto-escape > error handling > should handle non-existent commands in raw() [4.98ms] +/bin/sh: 1: Syntax error: Unterminated quoted string +(pass) raw() function - Disable auto-escape > error handling > should handle syntax errors in raw() [4.77ms] + +js/tests/repository-layout.test.mjs: +(pass) repository language layout > keeps JavaScript package files inside js/ [0.41ms] +(pass) repository language layout > keeps Rust package release files inside rust/ [0.07ms] +(pass) repository language layout > uses separate JavaScript and Rust workflows and release tags [0.13ms] +(pass) repository language layout > keeps root README focused on shared project information [0.03ms] + +js/tests/bun-shell-path-fix.test.mjs: +hello +(pass) String interpolation fix for Bun > Template literal without interpolation should work [4.49ms] +hello +(pass) String interpolation fix for Bun > String interpolation with complete command should work [4.40ms] +hello world +(pass) String interpolation fix for Bun > String interpolation with command and args should work [4.57ms] +hello +(pass) String interpolation fix for Bun > Mixed template literal with interpolation should work [4.22ms] +1 +(pass) String interpolation fix for Bun > Complex shell commands via interpolation should work [2.58ms] +sh exists +(pass) String interpolation fix for Bun > Shell operators in interpolated commands should work [8.80ms] +test /home/box +(pass) String interpolation fix for Bun > Commands with special characters should work [3.57ms] +hello world with spaces +(pass) String interpolation fix for Bun > Multiple argument interpolation should still quote properly [4.52ms] +/bin/sh: 1: : Permission denied +(pass) String interpolation fix for Bun > Empty command string should not cause issues [5.27ms] +safe +also safe +(pass) String interpolation fix for Bun > Command with unsafe characters should be handled correctly [11.69ms] +/tmp/gh-issue-solver-1780922968363 +(pass) Bun-specific shell path tests > Bun.spawn compatibility is maintained [4.25ms] +(pass) Bun-specific shell path tests > Bun runtime detection works correctly [0.08ms] + +js/tests/streaming-interfaces.test.mjs: +Hello from streams.stdin! +Multiple lines work +(pass) streaming interfaces - basic functionality [7.16ms] +test +(pass) streaming interfaces - auto-start behavior [6.20ms] +Binary test(pass) streaming interfaces - buffers interface [6.31ms] +String test +(pass) streaming interfaces - strings interface [4.73ms] +stdout +stderr +(pass) streaming interfaces - mixed stdout/stderr [6.27ms] +(pass) streaming interfaces - kill method works [102.37ms] +Hello from stdin! +Multiple lines work +(pass) streaming interfaces - stdin control with cross-platform command [205.45ms] +immediate test +(pass) streaming interfaces - immediate access after completion [5.32ms] +backward compatible +(pass) streaming interfaces - backward compatibility [4.76ms] +apple +banana +zebra +(pass) streaming interfaces - stdin pipe mode works [8.13ms] +important message 1 +another important note +(pass) streaming interfaces - grep filtering via stdin [7.29ms] + +js/tests/cleanup-verification.test.mjs: +(pass) Cleanup Verification > should start in original directory [2.59ms] +/tmp/cleanup-test-V4Udcz +(pass) Cleanup Verification > should restore cwd after simple cd command [3.97ms] +(pass) Cleanup Verification > should be back in original directory after cd test [2.39ms] +test +(pass) Cleanup Verification > should restore cwd after cd with && operator [3.52ms] +(pass) Cleanup Verification > should verify restoration after && cd test [2.44ms] +/tmp/cleanup-test3-c0jAye +(pass) Cleanup Verification > should not affect cwd when cd is in subshell [3.65ms] +(pass) Cleanup Verification > should restore cwd after multiple cd commands [4.74ms] +/tmp/gh-issue-solver-1780922968363 +(pass) Cleanup Verification > final verification - should still be in original directory [2.85ms] + +js/tests/jq.test.mjs: +{"id":1,"name":"Alice"} +{"id":2,"name":"Bob"} +{"id":3,"name":"Charlie"} +{"id":1,"name":"Alice"} +{"id":2,"name":"Bob"} +{"id":3,"name":"Charlie"} +(pass) jq streaming tests > stream of JSON objects through jq -c [13.78ms] +{"id":1,"value":10} +{"id":2,"value":20} +{"id":3,"value":30} +{"id":2,"value":20} +{"id":3,"value":30} +(pass) jq streaming tests > stream JSON objects with filtering through jq [14.55ms] +{"index":1,"squared":1} +{"index":2,"squared":4} +{"index":3,"squared":9} +{"index":1,"squared":1} +{"index":2,"squared":4} +{"index":3,"squared":9} +(pass) jq streaming tests > generate JSON stream using echo in loop [11.97ms] +{"name":"Alice","age":30} +{"name":"Bob","age":25} +{"user":"Alice","years":30} +{"user":"Bob","years":25} +(pass) jq streaming tests > transform JSON stream with jq [10.13ms] +[{"x":1},{"x":2},{"x":3}] +{"x":1} +{"x":2} +{"x":3} +(pass) jq streaming tests > generate and process array elements as stream [6.13ms] +{"source":"A","data":100} +{"source":"B","data":200} +{"source":"A","data":100} +{"source":"B","data":200} +(pass) jq streaming tests > combine multiple JSON sources into stream [10.64ms] +{"id":1,"name":"Alice"} +{"id":2,"name":"Bob"} +{"id":3,"name":"Charlie"} +(pass) jq streaming with pipe | syntax > stream of JSON objects through jq -c using pipe syntax [4.05ms] +{"id":2,"value":20} +{"id":3,"value":30} +(pass) jq streaming with pipe | syntax > stream JSON with filtering using pipe syntax [4.31ms] +{"user":"Alice","years":30} +{"user":"Bob","years":25} +(pass) jq streaming with pipe | syntax > transform JSON stream with jq using pipe syntax [2.96ms] +{"x":1} +{"x":2} +{"x":3} +(pass) jq streaming with pipe | syntax > process array elements as stream using pipe syntax [3.13ms] +{"name":"alice","score":95} +{"name":"charlie","score":92} +(pass) jq streaming with pipe | syntax > multi-pipe JSON processing [4.13ms] +{"name":"alice","level":"silver"} +{"name":"bob","level":"gold"} +(pass) jq streaming with pipe | syntax > complex JSON stream manipulation with pipes [9.50ms] +{"timestamp":1780924495,"event":"event1","value":10} +{"timestamp":1780924495,"event":"event2","value":20} +{"timestamp":1780924495,"event":"event3","value":30} +{"timestamp":1780924495,"event":"event4","value":40} +{"timestamp":1780924495,"event":"event5","value":50} +(pass) realtime JSON streaming with delays > stream JSON with random delays between outputs [69.13ms] +{"id":1,"time":"now"} +{"id":2,"time":"now"} +{"id":3,"time":"now"} +(pass) realtime JSON streaming with delays > stream JSON with fixed delays using printf and sleep [39.51ms] +{"level":"info","msg":"Server starting","port":3000} +{"level":"info","msg":"Server ready","status":"listening"} +{"level":"warn","msg":"High memory usage","usage":85} +(pass) realtime JSON streaming with delays > simulate server logs with delayed JSON output [69.43ms] +{"metric":"cpu","value":65,"host":"server3"} +{"metric":"cpu","value":70,"host":"server4"} +{"metric":"cpu","value":75,"host":"server5"} +(pass) realtime JSON streaming with delays > process streaming metrics with delays and aggregation [86.82ms] +{"batch":1,"msg":"burst1"} +{"batch":1,"msg":"burst2"} +{"batch":1,"msg":"burst3"} +{"batch":2,"msg":"burst4"} +{"batch":2,"msg":"burst5"} +(pass) realtime JSON streaming with delays > handle burst then delay pattern [55.07ms] +{"id":1,"type":"none"} +{"id":2,"type":"1ms"} +{"id":3,"type":"10ms"} +{"id":4,"type":"20ms"} +{"id":5,"type":"5ms"} +(pass) realtime JSON streaming with delays > stream with varying delay intervals [44.58ms] +{"id":1} +{"id":2} +{"id":3} +(pass) realtime JSON streaming with delays > verify immediate streaming output from jq [408.39ms] + +js/tests/resource-cleanup-internals.test.mjs: +(pass) Resource Cleanup Internal Verification > SIGINT Handler Management > should install SIGINT handler when first command starts [22.27ms] +(pass) Resource Cleanup Internal Verification > SIGINT Handler Management > should share single SIGINT handler for multiple concurrent commands [23.14ms] +Command failed with exit code 1(pass) Resource Cleanup Internal Verification > SIGINT Handler Management > should remove SIGINT handler even on error [10.99ms] +(pass) Resource Cleanup Internal Verification > SIGINT Handler Management > should remove SIGINT handler when command is killed [23.42ms] +test +(pass) Resource Cleanup Internal Verification > ProcessRunner Lifecycle > should cleanup ProcessRunner on successful completion [10.88ms] +Command failed with exit code 1(pass) Resource Cleanup Internal Verification > ProcessRunner Lifecycle > should cleanup ProcessRunner on error [11.21ms] +(pass) Resource Cleanup Internal Verification > ProcessRunner Lifecycle > should cleanup ProcessRunner when killed [22.95ms] +not awaited +(pass) Resource Cleanup Internal Verification > ProcessRunner Lifecycle > should cleanup ProcessRunner when not awaited [61.56ms] +test +(pass) Resource Cleanup Internal Verification > Event Listener Management > should cleanup event listeners after command completion [10.97ms] +Command failed with exit code 1(pass) Resource Cleanup Internal Verification > Event Listener Management > should cleanup event listeners on error [12.17ms] +"line1"; echo "line2"; echo line3 +(pass) Resource Cleanup Internal Verification > Event Listener Management > should cleanup stream iterator listeners [31.99ms] +real process +(pass) Resource Cleanup Internal Verification > Child Process Management > should cleanup child process references [17.27ms] +(pass) Resource Cleanup Internal Verification > Child Process Management > should cleanup child process on kill [31.84ms] +(pass) Resource Cleanup Internal Verification > Child Process Management > should cleanup child process on timeout [32.77ms] +test +(pass) Resource Cleanup Internal Verification > AbortController Management > should cleanup AbortController after completion [11.67ms] +(pass) Resource Cleanup Internal Verification > AbortController Management > should abort controller when killed [32.55ms] +Command failed with exit code 1(pass) Resource Cleanup Internal Verification > AbortController Management > should cleanup AbortController on error [10.91ms] +virtual test +(pass) Resource Cleanup Internal Verification > Virtual Command Management > should cleanup after virtual command completion [10.78ms] +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +(pass) Resource Cleanup Internal Verification > Virtual Command Management > should cleanup virtual generator when killed [22.06ms] +test input(pass) Resource Cleanup Internal Verification > Stream Management > should cleanup stdin handlers on completion [18.12ms] +"stdout"; echo stderr >&2 +(pass) Resource Cleanup Internal Verification > Stream Management > should cleanup stdout/stderr streams [10.92ms] +test +(pass) Resource Cleanup Internal Verification > Stream Management > should cleanup streams when piping [11.91ms] +hello +(pass) Resource Cleanup Internal Verification > Pipeline Cleanup > should cleanup all processes in pipeline [11.82ms] +(pass) Resource Cleanup Internal Verification > Pipeline Cleanup > should cleanup pipeline on error [62.06ms] +(pass) Resource Cleanup Internal Verification > Pipeline Cleanup > should cleanup pipeline when killed [562.86ms] +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +(pass) Resource Cleanup Internal Verification > Memory Leak Prevention > should not leak memory with rapid command execution [13.34ms] +Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 1Command failed with exit code 10 +2 +4 +6 +8 +10 +12 +14 +16 +18 +20 +22 +24 +26 +28 +30 +32 +34 +36 +38 +40 +42 +44 +46 +48 +(pass) Resource Cleanup Internal Verification > Memory Leak Prevention > should cleanup when mixing success and failure [13.35ms] +test +(pass) Resource Cleanup Internal Verification > Memory Leak Prevention > should cleanup with nested event emitters [10.91ms] +Test left behind 1 SIGINT handlers, forcing cleanup... +(pass) Resource Cleanup Internal Verification > Edge Cases > should cleanup when promise is created but not started [10.88ms] +test +(pass) Resource Cleanup Internal Verification > Edge Cases > should cleanup when using finally without await [11.62ms] +start +Killed +(pass) Resource Cleanup Internal Verification > Edge Cases > should cleanup when command throws during execution [19.16ms] +inherit(pass) Resource Cleanup Internal Verification > Edge Cases > should cleanup when parent process streams close [11.55ms] +(pass) Resource Cleanup Internal Verification > Concurrent Execution Patterns > should cleanup with Promise.race [111.93ms] +success +another success +Command failed with exit code 1Command failed with exit code 2(pass) Resource Cleanup Internal Verification > Concurrent Execution Patterns > should cleanup with Promise.allSettled [62.19ms] +1 +2 +(pass) Resource Cleanup Internal Verification > Concurrent Execution Patterns > should cleanup with async iteration break [28.54ms] + +js/tests/system-pipe.test.mjs: +{ + "message": "hi", + "number": 42 +} +(pass) System Command Piping (Issue #8) > Piping to jq > should pipe echo output to jq for JSON processing [3.77ms] +hi +(pass) System Command Piping (Issue #8) > Piping to jq > should extract specific field with jq [2.51ms] +5 +(pass) System Command Piping (Issue #8) > Piping to jq > should handle jq array operations [2.89ms] +"bar" +(pass) System Command Piping (Issue #8) > Piping to jq > should pipe cat output to jq [2.36ms] +line2 +(pass) System Command Piping (Issue #8) > Piping to grep > should pipe to grep for pattern matching [2.32ms] +Line1 +line2 +LINE3 +(pass) System Command Piping (Issue #8) > Piping to grep > should handle grep with flags [2.83ms] +hello universe +(pass) System Command Piping (Issue #8) > Piping to sed > should pipe to sed for text substitution [2.23ms] +FOO bar BAZ +(pass) System Command Piping (Issue #8) > Piping to sed > should handle sed with multiple operations [2.92ms] +field2 +(pass) System Command Piping (Issue #8) > Piping to awk > should pipe to awk for field extraction [2.62ms] +6 +(pass) System Command Piping (Issue #8) > Piping to awk > should handle awk with calculations [2.29ms] +3 +(pass) System Command Piping (Issue #8) > Piping to wc > should pipe to wc for line counting [1.82ms] +5 +(pass) System Command Piping (Issue #8) > Piping to wc > should pipe to wc for word counting [1.87ms] +b +(pass) System Command Piping (Issue #8) > Piping to cut > should pipe to cut for field extraction [2.82ms] +2,4 +(pass) System Command Piping (Issue #8) > Piping to cut > should handle cut with multiple fields [4.87ms] +apple +banana +cherry +(pass) System Command Piping (Issue #8) > Piping to sort > should pipe to sort for sorting lines [3.12ms] +3 +2 +1 +(pass) System Command Piping (Issue #8) > Piping to sort > should handle sort with reverse flag [3.04ms] +1 +2 +(pass) System Command Piping (Issue #8) > Piping to head/tail > should pipe to head for first lines [2.67ms] +4 +5(pass) System Command Piping (Issue #8) > Piping to head/tail > should pipe to tail for last lines [3.06ms] +apple +(pass) System Command Piping (Issue #8) > Complex multi-pipe operations > should handle multiple system command pipes [3.70ms] +charlie +(pass) System Command Piping (Issue #8) > Complex multi-pipe operations > should combine jq with other tools [4.09ms] +5 +(pass) System Command Piping (Issue #8) > Complex multi-pipe operations > should handle pipes with text processing chain [2.54ms] + +js/tests/options-examples.test.mjs: +performance optimization +(pass) Options Examples (Feature Demo) > example: disable capture for performance [6.63ms] +(pass) Options Examples (Feature Demo) > example: disable mirroring for silent execution [5.45ms] +(pass) Options Examples (Feature Demo) > example: both disabled for maximum performance [5.27ms] +(pass) Options Examples (Feature Demo) > example: custom stdin with options [7.12ms] +using run method +using start method +(pass) Options Examples (Feature Demo) > example: using .run() alias [9.95ms] +(pass) Options Examples (Feature Demo) > example: comparison with sh() function [5.33ms] +virtual command +TemporaryDirectory.1CCCnP +TemporaryDirectory.1aBsFB +TemporaryDirectory.2E3ttA +TemporaryDirectory.31nGmi +TemporaryDirectory.3UudKR +TemporaryDirectory.8eQYMe +TemporaryDirectory.8znSTp +TemporaryDirectory.9hMvHU +TemporaryDirectory.9ijdbu +TemporaryDirectory.BaWcos +TemporaryDirectory.EOk3je +TemporaryDirectory.FG8Tbp +TemporaryDirectory.Fo2LlM +TemporaryDirectory.FyoqGx +TemporaryDirectory.JNm88N +TemporaryDirectory.JZdGbo +TemporaryDirectory.Je8ixu +TemporaryDirectory.JlxJqL +TemporaryDirectory.KghSKJ +TemporaryDirectory.KitLkr +TemporaryDirectory.KudACo +TemporaryDirectory.MKhrM8 +TemporaryDirectory.NEFEik +TemporaryDirectory.NZnSxQ +TemporaryDirectory.NrUoVA +TemporaryDirectory.NvbRzU +TemporaryDirectory.P5iuYE +TemporaryDirectory.P9iCZn +TemporaryDirectory.RYg7L0 +TemporaryDirectory.Sv23il +TemporaryDirectory.VG3DsL +TemporaryDirectory.VNsblL +TemporaryDirectory.WDkLpe +TemporaryDirectory.WjCdZ6 +TemporaryDirectory.Wor2yB +TemporaryDirectory.XdYAXO +TemporaryDirectory.XkUBzt +TemporaryDirectory.YSpHp7 +TemporaryDirectory.YWkXH4 +TemporaryDirectory.ZweB8T +TemporaryDirectory.aKOZ47 +TemporaryDirectory.aRpnpH +TemporaryDirectory.bbUJpy +TemporaryDirectory.dwtuJ2 +TemporaryDirectory.eBuCXR +TemporaryDirectory.eghMCe +TemporaryDirectory.gqN5GN +TemporaryDirectory.iSYyFs +TemporaryDirectory.iUJYH2 +TemporaryDirectory.jjqkbK +TemporaryDirectory.m06C03 +TemporaryDirectory.mokctw +TemporaryDirectory.oUmhMf +TemporaryDirectory.oj1N87 +TemporaryDirectory.qjM4Bj +TemporaryDirectory.r0f54l +TemporaryDirectory.rK2bW3 +TemporaryDirectory.rV0UPw +TemporaryDirectory.s3ydw6 +TemporaryDirectory.sO29K2 +TemporaryDirectory.sTjUjJ +TemporaryDirectory.saXjGJ +TemporaryDirectory.uYdLPc +TemporaryDirectory.vNJDGz +TemporaryDirectory.vS2CzO +TemporaryDirectory.vaHONu +TemporaryDirectory.wm4OPZ +TemporaryDirectory.xNypG8 +TemporaryDirectory.yGoTHl +TemporaryDirectory.zNyHok +agent_prompt_1780915594806_84019.txt +agent_prompt_1780915738542_99362.txt +agent_prompt_1780918291148_269594.txt +agent_prompt_1780922380698_406768.txt +agent_prompt_1780923531533_521627.txt +bunx-1001-node-gyp@latest +bunx-1001-prettier@latest +check-crate-size-found-1780915547897705276 +check-crate-size-found-1780916180190939685 +check-crate-size-found-1780922525875691187 +check-crate-size-found-1780922763656611773 +check-crate-size-found-1780923850476254019 +check-crate-size-missing-1780915547898161898 +check-crate-size-missing-1780916180190979415 +check-crate-size-missing-1780922525876273747 +check-crate-size-missing-1780922763656345946 +check-crate-size-missing-1780923850476286367 +check-file-size-lino-thresholds-1780924183709660112 +check-file-size-lino-thresholds-1780924299944092959 +check-file-size-lino-thresholds-1780924349377190170 +check-file-size-lino-thresholds-1780924396299050012 +check-file-size-thresholds-1780915547898256369 +check-file-size-thresholds-1780916180191324389 +check-file-size-thresholds-1780922525878807941 +check-file-size-thresholds-1780922763655887781 +check-file-size-thresholds-1780923850476940845 +check-file-size-thresholds-1780924183713338194 +check-file-size-thresholds-1780924299944130014 +check-file-size-thresholds-1780924349377487263 +check-file-size-thresholds-1780924396299089099 +check-no-src-tests-outside-src-1780922525875983563 +check-no-src-tests-outside-src-1780922763657368722 +check-no-src-tests-src-markers-1780922525880306989 +check-no-src-tests-src-markers-1780922763657064419 +claude-1001 +codex-auth-18hv0Q +codex-auth-8e5IlJ +codex-auth-ADSlNA +codex-auth-EMZV2J +codex-auth-KprQDu +codex-auth-NUeFa1 +codex-auth-Orpe2c +codex-auth-PlLH1T +codex-auth-SSJ5oi +codex-auth-TNjwUx +codex-auth-TUPdu0 +codex-auth-YobRpP +codex-auth-a99TcI +codex-auth-d8bJTb +codex-auth-g5DJkm +codex-auth-onPAlw +codex-auth-tm0U9I +codex-auth-uycmjS +codex_prompt_1780921329058_368027.txt +codex_prompt_1780922989393_470477.txt +codex_prompt_1780923064689_479328.txt +formal-ai-agent-tests +formal-ai-agent-tests-python-path +formal-ai-agent-workspaces +formal-ai-cache-hit-280295145 +formal-ai-cache-hit-363374055 +formal-ai-cache-hit-669818421 +formal-ai-cache-hit-931832614 +formal-ai-cache-offline-miss-285394824 +formal-ai-cache-offline-miss-370593280 +formal-ai-cache-offline-miss-668523077 +formal-ai-cache-offline-miss-933092009 +formal-ai-cache-online-miss-289552659 +formal-ai-cache-online-miss-375300021 +formal-ai-cache-online-miss-681308109 +formal-ai-cache-online-miss-939699567 +formal-ai-cache-seed-precedence-305450006 +formal-ai-cache-seed-precedence-403190285 +formal-ai-cache-seed-precedence-696467123 +formal-ai-cache-seed-precedence-978717676 +gemini-support-test-2I9cAe +gemini-support-test-2yxzjj +gemini-support-test-409kz4 +gemini-support-test-8VouwZ +gemini-support-test-AFWuND +gemini-support-test-AkicCl +gemini-support-test-EWa4j8 +gemini-support-test-IyM66n +gemini-support-test-JOzpI0 +gemini-support-test-ReErEd +gemini-support-test-TCCWvi +gemini-support-test-VJm3Qg +gemini-support-test-YmPj9o +gemini-support-test-iBNtsX +gemini-support-test-jsxN9N +gemini-support-test-mOsFFD +gemini-support-test-oR3Y7i +gemini-support-test-pDRfEY +gemini-support-test-riK3yX +gemini-support-test-wtKOPq +gh-issue-solver-1780914444673 +gh-issue-solver-1780914740585 +gh-issue-solver-1780914901692 +gh-issue-solver-1780915869051 +gh-issue-solver-1780917252584 +gh-issue-solver-1780918878243 +gh-issue-solver-1780921306925 +gh-issue-solver-1780921315099 +gh-issue-solver-1780921933912 +gh-issue-solver-1780922038008 +gh-issue-solver-1780922951770 +gh-issue-solver-1780922968363 +gh-issue-solver-1780923025774 +gh-issue-solver-1780923355444 +hive-auth-probe-X4CbsI +hive-mind-issue-1861-default-tests-node24.log +hive-mind-issue-1861-format-check.log +hive-mind-issue-1861-gh-run-27133205342-watch.log +hive-mind-issue-1861-line-limits.log +hive-mind-issue-1861-lint.log +hive-mind-issue-1861-npm-ci.log +hive-mind-issue-1861-npm-test.log +hive-mind-no-screen-bin-IDE4Rl +hive-mind-no-screen-bin-U8L6be +hive-mind-no-screen-bin-aIptm6 +hive-mind-no-screen-bin-nLia6s +hive-mind-no-screen-bin-vs4ndt +hive-mind-no-screen-bin-wu35VX +hive-mind-npm-test-1858.log +hive-mind-npm-test-1859-after-merge.log +hsperfdata_box +issue-160-bin +issue-160-templates +issue1834-home-2L9376 +issue1834-home-6MPTta +issue1834-home-6zriHA +issue1834-home-7ZFLMz +issue1834-home-9MuSeQ +issue1834-home-DODJPF +issue1834-home-HurtUC +issue1834-home-LCNpzb +issue1834-home-LNMiir +issue1834-home-LtJ0sn +issue1834-home-MAEU9B +issue1834-home-NFOJw4 +issue1834-home-NT0rFK +issue1834-home-OwJTYt +issue1834-home-ZVDWdE +issue1834-home-agsgI6 +issue1834-home-cFAxB4 +issue1834-home-ch8rGG +issue1834-home-eKI9QF +issue1834-home-kESvgJ +issue1834-home-mEJj1Z +issue1834-home-rq8gXP +issue1834-home-s61Pno +issue1834-home-y0JonQ +issue1834-home-z9e9mP +junit +log-tmp-solution-draft-log-pr-1780914367472.txt-1780914369132 +log-tmp-solution-draft-log-pr-1780915023524.txt-1780915025379 +log-tmp-solution-draft-log-pr-1780915027531.txt-1780915029049 +log-tmp-solution-draft-log-pr-1780916225581.txt-1780916235227 +log-tmp-solution-draft-log-pr-1780916264562.txt-1780916265910 +log-tmp-solution-draft-log-pr-1780916617183.txt-1780916620679 +log-tmp-solution-draft-log-pr-1780916834376.txt-1780916836115 +log-tmp-solution-draft-log-pr-1780917152229.txt-1780917153784 +log-tmp-solution-draft-log-pr-1780917272974.txt-1780917274949 +log-tmp-solution-draft-log-pr-1780917613248.txt-1780917615615 +log-tmp-solution-draft-log-pr-1780918444991.txt-1780918446789 +log-tmp-solution-draft-log-pr-1780919047545.txt-1780919049027 +log-tmp-solution-draft-log-pr-1780919973744.txt-1780919976295 +log-tmp-solution-draft-log-pr-1780921196763.txt-1780921198880 +log-tmp-solution-draft-log-pr-1780923333241.txt-1780923335080 +log-tmp-solution-draft-log-pr-1780923432501.txt-1780923434830 +log-tmp-solution-draft-log-pr-1780924423096.txt-1780924424714 +node-compile-cache +olcrtc-plugin-compile.jar +olcrtc-plugin-stubs +olcrtc-policy-tests.jar +olcrtc-policy.jar +opencode +opencode_prompt_1780915594804_84019.txt +opencode_prompt_1780915738540_99362.txt +opencode_prompt_1780918291146_269594.txt +opencode_prompt_1780922380696_406768.txt +opencode_prompt_1780923531531_521627.txt +pr-1862-body.md +pr-6-body.md +pr-body-1859.md +pr198-body.md +projects-mango-search.log +rust-paths-no-publishable-members-1780915547908016404 +rust-paths-no-publishable-members-1780916180202641279 +rust-paths-no-publishable-members-1780922525900339442 +rust-paths-no-publishable-members-1780922763676028877 +rust-paths-no-publishable-members-1780923850486723364 +rust-paths-no-publishable-members-1780924183754321085 +rust-paths-no-publishable-members-1780924299955917777 +rust-paths-no-publishable-members-1780924349387603169 +rust-paths-no-publishable-members-1780924396309813975 +rust-paths-root-package-1780915547908041251 +rust-paths-root-package-1780916180202814849 +rust-paths-root-package-1780922525901415308 +rust-paths-root-package-1780922763679312220 +rust-paths-root-package-1780923850488281220 +rust-paths-root-package-1780924183770342520 +rust-paths-root-package-1780924299959712333 +rust-paths-root-package-1780924349390611051 +rust-paths-root-package-1780924396313557666 +rust-paths-workspace-member-1780915547908030755 +rust-paths-workspace-member-1780916180202789090 +rust-paths-workspace-member-1780922525900550177 +rust-paths-workspace-member-1780922763676620590 +rust-paths-workspace-member-1780923850487524670 +rust-paths-workspace-member-1780924183764500917 +rust-paths-workspace-member-1780924299957156456 +rust-paths-workspace-member-1780924349390391945 +rust-paths-workspace-member-1780924396313305700 +stale-old-search.log +start-command +stdio-interceptor-stderr.log +stdio-interceptor-stdout.log +targeted-stale-search.final.log +targeted-stale-search.log +test-build +tsx-1001 +validate-frontmatter.after.log +validate-frontmatter.before.log +validate-frontmatter.final.log +validate-repository-structure.after.log +validate-repository-structure.before.log +validate-repository-structure.final.log +version-and-commit-lock-absent-1780915547906088725 +version-and-commit-lock-absent-1780916180198796718 +version-and-commit-lock-absent-1780922525889393578 +version-and-commit-lock-absent-1780922763663957532 +version-and-commit-lock-absent-1780923850483529053 +version-and-commit-lock-entry-absent-1780915547906338348 +version-and-commit-lock-entry-absent-1780916180198870178 +version-and-commit-lock-entry-absent-1780922525890427991 +version-and-commit-lock-entry-absent-1780922763664343478 +version-and-commit-lock-entry-absent-1780923850484194126 +version-and-commit-lock-idempotent-1780915547904281346 +version-and-commit-lock-idempotent-1780916180198344993 +version-and-commit-lock-idempotent-1780922525890289735 +version-and-commit-lock-idempotent-1780922763662227047 +version-and-commit-lock-idempotent-1780923850483469464 +version-and-commit-lock-update-1780915547906706608 +version-and-commit-lock-update-1780916180199340740 +version-and-commit-lock-update-1780922525893366100 +version-and-commit-lock-update-1780922763664777185 +version-and-commit-lock-update-1780923850485213909 +yougile-to-gh-check-logs +yougile-to-gh-fake-bin-1780915427857302756 +yougile-to-gh-fake-bin-1780915452632532192 +yougile-to-gh-fake-bin-1780923746734652232 +yougile-to-gh-fixture-1780915427856885834.json +yougile-to-gh-fixture-1780915452632203202.json +yougile-to-gh-fixture-1780923746734313036.json +yougile-to-gh-pr-4-body.md +(pass) Options Examples (Feature Demo) > example: real shell command vs virtual command [11.07ms] +(pass) Options Examples (Feature Demo) > example: chaining still works [4.73ms] + +js/tests/start-run-edge-cases.test.mjs: +(pass) Start/Run Edge Cases and Advanced Usage > should handle complex option combinations [5.86ms] +total 3392 +drwxrwxrwt 1 root root 20480 Jun 8 13:14 . +drwxr-xr-x 1 root root 4096 Jun 8 09:54 .. +drwxr-xr-x 2 box box 4096 Jun 5 20:45 .18b64a3aa0a430f9-00000008.node-gyp +drwxr-xr-x 2 box box 4096 Jun 5 20:45 .18b64a3ccb8fb8f9-00000006.node-gyp +drwxr-xr-x 2 box box 4096 Jun 8 12:05 .18b71996a9c73fb9-000000DC.node-gyp +drwxr-xr-x 2 box box 4096 Jun 8 13:08 .18b71d0a0b1ab2b9-00000002.node-gyp +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.1CCCnP +drwx------ 2 box box 4096 Jun 8 11:02 TemporaryDirectory.1aBsFB +drwx------ 2 box box 4096 Jun 8 12:50 TemporaryDirectory.2E3ttA +drwx------ 2 box box 4096 Jun 8 10:57 TemporaryDirectory.31nGmi +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.3UudKR +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.8eQYMe +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.8znSTp +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.9hMvHU +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.9ijdbu +drwx------ 2 box box 4096 Jun 8 12:50 TemporaryDirectory.BaWcos +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.EOk3je +drwx------ 2 box box 4096 Jun 8 12:50 TemporaryDirectory.FG8Tbp +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.Fo2LlM +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.FyoqGx +drwx------ 2 box box 4096 Jun 8 10:57 TemporaryDirectory.JNm88N +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.JZdGbo +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.Je8ixu +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.JlxJqL +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.KghSKJ +drwx------ 2 box box 4096 Jun 8 10:57 TemporaryDirectory.KitLkr +drwx------ 2 box box 4096 Jun 8 12:49 TemporaryDirectory.KudACo +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.MKhrM8 +drwx------ 2 box box 4096 Jun 8 12:50 TemporaryDirectory.NEFEik +drwx------ 2 box box 4096 Jun 8 12:49 TemporaryDirectory.NZnSxQ +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.NrUoVA +drwx------ 2 box box 4096 Jun 8 12:50 TemporaryDirectory.NvbRzU +drwx------ 2 box box 4096 Jun 8 12:50 TemporaryDirectory.P5iuYE +drwx------ 2 box box 4096 Jun 8 13:09 TemporaryDirectory.P9iCZn +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.RYg7L0 +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.Sv23il +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.VG3DsL +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.VNsblL +drwx------ 2 box box 4096 Jun 8 10:57 TemporaryDirectory.WDkLpe +drwx------ 2 box box 4096 Jun 8 10:57 TemporaryDirectory.WjCdZ6 +drwx------ 2 box box 4096 Jun 8 11:45 TemporaryDirectory.Wor2yB +drwx------ 2 box box 4096 Jun 8 12:50 TemporaryDirectory.XdYAXO +drwx------ 2 box box 4096 Jun 8 12:50 TemporaryDirectory.XkUBzt +drwx------ 2 box box 4096 Jun 8 10:56 TemporaryDirectory.YSpHp7 +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.YWkXH4 +drwx------ 2 box box 4096 Jun 8 12:50 TemporaryDirectory.ZweB8T +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.aKOZ47 +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.aRpnpH +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.bbUJpy +drwx------ 2 box box 4096 Jun 8 10:56 TemporaryDirectory.dwtuJ2 +drwx------ 2 box box 4096 Jun 8 10:56 TemporaryDirectory.eBuCXR +drwx------ 2 box box 4096 Jun 8 11:45 TemporaryDirectory.eghMCe +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.gqN5GN +drwx------ 2 box box 4096 Jun 8 10:56 TemporaryDirectory.iSYyFs +drwx------ 2 box box 4096 Jun 8 12:49 TemporaryDirectory.iUJYH2 +drwx------ 2 box box 4096 Jun 8 13:09 TemporaryDirectory.jjqkbK +drwx------ 2 box box 4096 Jun 8 11:02 TemporaryDirectory.m06C03 +drwx------ 2 box box 4096 Jun 8 11:02 TemporaryDirectory.mokctw +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.oUmhMf +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.oj1N87 +drwx------ 2 box box 4096 Jun 8 12:49 TemporaryDirectory.qjM4Bj +drwx------ 2 box box 4096 Jun 8 10:57 TemporaryDirectory.r0f54l +drwx------ 2 box box 4096 Jun 8 12:49 TemporaryDirectory.rK2bW3 +drwx------ 2 box box 4096 Jun 8 11:45 TemporaryDirectory.rV0UPw +drwx------ 2 box box 4096 Jun 8 10:57 TemporaryDirectory.s3ydw6 +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.sO29K2 +drwx------ 2 box box 4096 Jun 8 10:56 TemporaryDirectory.sTjUjJ +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.saXjGJ +drwx------ 2 box box 4096 Jun 8 10:57 TemporaryDirectory.uYdLPc +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.vNJDGz +drwx------ 2 box box 4096 Jun 8 10:57 TemporaryDirectory.vS2CzO +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.vaHONu +drwx------ 2 box box 4096 Jun 8 13:08 TemporaryDirectory.wm4OPZ +drwx------ 2 box box 4096 Jun 8 11:03 TemporaryDirectory.xNypG8 +drwx------ 2 box box 4096 Jun 8 13:09 TemporaryDirectory.yGoTHl +drwx------ 2 box box 4096 Jun 8 11:44 TemporaryDirectory.zNyHok +-rw-r--r-- 1 box box 11 Jun 8 10:46 agent_prompt_1780915594806_84019.txt +-rw-r--r-- 1 box box 11 Jun 8 10:48 agent_prompt_1780915738542_99362.txt +-rw-r--r-- 1 box box 11 Jun 8 11:31 agent_prompt_1780918291148_269594.txt +-rw-r--r-- 1 box box 11 Jun 8 12:39 agent_prompt_1780922380698_406768.txt +-rw-r--r-- 1 box box 11 Jun 8 12:58 agent_prompt_1780923531533_521627.txt +drwxr-xr-x 3 box box 4096 Jun 5 20:45 bunx-1001-node-gyp@latest +drwxr-xr-x 3 box box 4096 Jun 8 11:55 bunx-1001-prettier@latest +drwxr-xr-x 3 box box 4096 Jun 8 10:45 check-crate-size-found-1780915547897705276 +drwxr-xr-x 3 box box 4096 Jun 8 10:56 check-crate-size-found-1780916180190939685 +drwxr-xr-x 3 box box 4096 Jun 8 12:42 check-crate-size-found-1780922525875691187 +drwxr-xr-x 3 box box 4096 Jun 8 12:46 check-crate-size-found-1780922763656611773 +drwxr-xr-x 3 box box 4096 Jun 8 13:04 check-crate-size-found-1780923850476254019 +drwxr-xr-x 2 box box 4096 Jun 8 10:45 check-crate-size-missing-1780915547898161898 +drwxr-xr-x 2 box box 4096 Jun 8 10:56 check-crate-size-missing-1780916180190979415 +drwxr-xr-x 2 box box 4096 Jun 8 12:42 check-crate-size-missing-1780922525876273747 +drwxr-xr-x 2 box box 4096 Jun 8 12:46 check-crate-size-missing-1780922763656345946 +drwxr-xr-x 2 box box 4096 Jun 8 13:04 check-crate-size-missing-1780923850476286367 +drwxr-xr-x 3 box box 4096 Jun 8 13:09 check-file-size-lino-thresholds-1780924183709660112 +drwxr-xr-x 3 box box 4096 Jun 8 13:11 check-file-size-lino-thresholds-1780924299944092959 +drwxr-xr-x 3 box box 4096 Jun 8 13:12 check-file-size-lino-thresholds-1780924349377190170 +drwxr-xr-x 3 box box 4096 Jun 8 13:13 check-file-size-lino-thresholds-1780924396299050012 +drwxr-xr-x 3 box box 4096 Jun 8 10:45 check-file-size-thresholds-1780915547898256369 +drwxr-xr-x 3 box box 4096 Jun 8 10:56 check-file-size-thresholds-1780916180191324389 +drwxr-xr-x 3 box box 4096 Jun 8 12:42 check-file-size-thresholds-1780922525878807941 +drwxr-xr-x 3 box box 4096 Jun 8 12:46 check-file-size-thresholds-1780922763655887781 +drwxr-xr-x 3 box box 4096 Jun 8 13:04 check-file-size-thresholds-1780923850476940845 +drwxr-xr-x 3 box box 4096 Jun 8 13:09 check-file-size-thresholds-1780924183713338194 +drwxr-xr-x 3 box box 4096 Jun 8 13:11 check-file-size-thresholds-1780924299944130014 +drwxr-xr-x 3 box box 4096 Jun 8 13:12 check-file-size-thresholds-1780924349377487263 +drwxr-xr-x 3 box box 4096 Jun 8 13:13 check-file-size-thresholds-1780924396299089099 +drwxr-xr-x 3 box box 4096 Jun 8 12:42 check-no-src-tests-outside-src-1780922525875983563 +drwxr-xr-x 3 box box 4096 Jun 8 12:46 check-no-src-tests-outside-src-1780922763657368722 +drwxr-xr-x 3 box box 4096 Jun 8 12:42 check-no-src-tests-src-markers-1780922525880306989 +drwxr-xr-x 3 box box 4096 Jun 8 12:46 check-no-src-tests-src-markers-1780922763657064419 +drwx------ 2 box box 4096 Jun 8 09:54 claude-1001 +drwx------ 2 box box 4096 Jun 8 11:30 codex-auth-18hv0Q +drwx------ 2 box box 4096 Jun 8 11:28 codex-auth-8e5IlJ +drwx------ 2 box box 4096 Jun 8 10:48 codex-auth-ADSlNA +drwx------ 2 box box 4096 Jun 8 12:58 codex-auth-EMZV2J +drwx------ 2 box box 4096 Jun 8 12:38 codex-auth-KprQDu +drwx------ 2 box box 4096 Jun 8 12:38 codex-auth-NUeFa1 +drwx------ 2 box box 4096 Jun 8 10:48 codex-auth-Orpe2c +drwx------ 2 box box 4096 Jun 8 11:28 codex-auth-PlLH1T +drwx------ 2 box box 4096 Jun 8 10:45 codex-auth-SSJ5oi +drwx------ 2 box box 4096 Jun 8 12:58 codex-auth-TNjwUx +drwx------ 2 box box 4096 Jun 8 11:30 codex-auth-TUPdu0 +drwx------ 2 box box 4096 Jun 8 12:58 codex-auth-YobRpP +drwx------ 2 box box 4096 Jun 8 10:45 codex-auth-a99TcI +drwx------ 2 box box 4096 Jun 8 12:38 codex-auth-d8bJTb +drwx------ 2 box box 4096 Jun 8 10:48 codex-auth-g5DJkm +drwx------ 2 box box 4096 Jun 8 10:45 codex-auth-onPAlw +drwx------ 2 box box 4096 Jun 8 11:30 codex-auth-tm0U9I +drwx------ 2 box box 4096 Jun 8 11:28 codex-auth-uycmjS +-rw-r--r-- 1 box box 13767 Jun 8 12:22 codex_prompt_1780921329058_368027.txt +-rw-r--r-- 1 box box 13724 Jun 8 12:49 codex_prompt_1780922989393_470477.txt +-rw-r--r-- 1 box box 13657 Jun 8 12:51 codex_prompt_1780923064689_479328.txt +drwxr-xr-x 7 box box 4096 Jun 8 13:09 formal-ai-agent-tests +drwxr-xr-x 4 box box 4096 Jun 8 13:13 formal-ai-agent-tests-python-path +drwxr-xr-x 21 box box 4096 Jun 8 13:13 formal-ai-agent-workspaces +drwxr-xr-x 3 box box 4096 Jun 8 13:13 formal-ai-cache-hit-280295145 +drwxr-xr-x 3 box box 4096 Jun 8 13:12 formal-ai-cache-hit-363374055 +drwxr-xr-x 3 box box 4096 Jun 8 13:09 formal-ai-cache-hit-669818421 +drwxr-xr-x 3 box box 4096 Jun 8 13:11 formal-ai-cache-hit-931832614 +drwxr-xr-x 2 box box 4096 Jun 8 13:13 formal-ai-cache-offline-miss-285394824 +drwxr-xr-x 2 box box 4096 Jun 8 13:12 formal-ai-cache-offline-miss-370593280 +drwxr-xr-x 2 box box 4096 Jun 8 13:09 formal-ai-cache-offline-miss-668523077 +drwxr-xr-x 2 box box 4096 Jun 8 13:11 formal-ai-cache-offline-miss-933092009 +drwxr-xr-x 3 box box 4096 Jun 8 13:13 formal-ai-cache-online-miss-289552659 +drwxr-xr-x 3 box box 4096 Jun 8 13:12 formal-ai-cache-online-miss-375300021 +drwxr-xr-x 3 box box 4096 Jun 8 13:09 formal-ai-cache-online-miss-681308109 +drwxr-xr-x 3 box box 4096 Jun 8 13:11 formal-ai-cache-online-miss-939699567 +drwxr-xr-x 2 box box 4096 Jun 8 13:13 formal-ai-cache-seed-precedence-305450006 +drwxr-xr-x 2 box box 4096 Jun 8 13:12 formal-ai-cache-seed-precedence-403190285 +drwxr-xr-x 2 box box 4096 Jun 8 13:09 formal-ai-cache-seed-precedence-696467123 +drwxr-xr-x 2 box box 4096 Jun 8 13:11 formal-ai-cache-seed-precedence-978717676 +drwx------ 2 box box 4096 Jun 8 12:39 gemini-support-test-2I9cAe +drwx------ 2 box box 4096 Jun 8 10:46 gemini-support-test-2yxzjj +drwx------ 2 box box 4096 Jun 8 10:49 gemini-support-test-409kz4 +drwx------ 2 box box 4096 Jun 8 11:31 gemini-support-test-8VouwZ +drwx------ 2 box box 4096 Jun 8 10:49 gemini-support-test-AFWuND +drwx------ 2 box box 4096 Jun 8 10:46 gemini-support-test-AkicCl +drwx------ 2 box box 4096 Jun 8 10:46 gemini-support-test-EWa4j8 +drwx------ 2 box box 4096 Jun 8 12:59 gemini-support-test-IyM66n +drwx------ 2 box box 4096 Jun 8 10:49 gemini-support-test-JOzpI0 +drwx------ 2 box box 4096 Jun 8 11:31 gemini-support-test-ReErEd +drwx------ 2 box box 4096 Jun 8 12:39 gemini-support-test-TCCWvi +drwx------ 2 box box 4096 Jun 8 10:49 gemini-support-test-VJm3Qg +drwx------ 2 box box 4096 Jun 8 12:59 gemini-support-test-YmPj9o +drwx------ 2 box box 4096 Jun 8 12:59 gemini-support-test-iBNtsX +drwx------ 2 box box 4096 Jun 8 12:39 gemini-support-test-jsxN9N +drwx------ 2 box box 4096 Jun 8 12:59 gemini-support-test-mOsFFD +drwx------ 2 box box 4096 Jun 8 12:39 gemini-support-test-oR3Y7i +drwx------ 2 box box 4096 Jun 8 11:31 gemini-support-test-pDRfEY +drwx------ 2 box box 4096 Jun 8 10:46 gemini-support-test-riK3yX +drwx------ 2 box box 4096 Jun 8 11:31 gemini-support-test-wtKOPq +drwxr-xr-x 20 box box 4096 Jun 8 11:04 gh-issue-solver-1780914444673 +drwxr-xr-x 19 box box 4096 Jun 8 10:56 gh-issue-solver-1780914740585 +drwxr-xr-x 13 box box 4096 Jun 8 10:52 gh-issue-solver-1780914901692 +drwxr-xr-x 15 box box 4096 Jun 8 11:06 gh-issue-solver-1780915869051 +drwxr-xr-x 19 box box 4096 Jun 8 12:02 gh-issue-solver-1780917252584 +drwxr-xr-x 14 box box 4096 Jun 8 12:22 gh-issue-solver-1780918878243 +drwxr-xr-x 19 box box 4096 Jun 8 13:08 gh-issue-solver-1780921306925 +drwxr-xr-x 12 box box 4096 Jun 8 12:23 gh-issue-solver-1780921315099 +drwxr-xr-x 12 box box 4096 Jun 8 12:45 gh-issue-solver-1780921933912 +drwxr-xr-x 6 box box 4096 Jun 8 12:40 gh-issue-solver-1780922038008 +drwxr-xr-x 7 box box 4096 Jun 8 12:54 gh-issue-solver-1780922951770 +drwxr-xr-x 10 box box 4096 Jun 8 13:14 gh-issue-solver-1780922968363 +drwxr-xr-x 15 box box 4096 Jun 8 13:08 gh-issue-solver-1780923025774 +drwxr-xr-x 12 box box 4096 Jun 8 13:05 gh-issue-solver-1780923355444 +drwx------ 2 box box 4096 Jun 8 13:10 hive-auth-probe-X4CbsI +-rw-r--r-- 1 box box 473675 Jun 8 10:57 hive-mind-issue-1861-default-tests-node24.log +-rw-r--r-- 1 box box 66 Jun 8 10:59 hive-mind-issue-1861-format-check.log +-rw-r--r-- 1 box box 549890 Jun 8 11:13 hive-mind-issue-1861-gh-run-27133205342-watch.log +-rw-r--r-- 1 box box 55741 Jun 8 10:58 hive-mind-issue-1861-line-limits.log +-rw-r--r-- 1 box box 0 Jun 8 10:58 hive-mind-issue-1861-lint.log +-rw-r--r-- 1 box box 878 Jun 8 10:45 hive-mind-issue-1861-npm-ci.log +-rw-r--r-- 1 box box 3709 Jun 8 10:44 hive-mind-issue-1861-npm-test.log +drwx------ 2 box box 4096 Jun 8 13:04 hive-mind-no-screen-bin-IDE4Rl +drwx------ 2 box box 4096 Jun 8 11:28 hive-mind-no-screen-bin-U8L6be +drwx------ 2 box box 4096 Jun 8 12:45 hive-mind-no-screen-bin-aIptm6 +drwx------ 2 box box 4096 Jun 8 10:52 hive-mind-no-screen-bin-nLia6s +drwx------ 2 box box 4096 Jun 8 11:39 hive-mind-no-screen-bin-vs4ndt +drwx------ 2 box box 4096 Jun 8 10:57 hive-mind-no-screen-bin-wu35VX +-rw-r--r-- 1 box box 473586 Jun 8 12:50 hive-mind-npm-test-1858.log +-rw-r--r-- 1 box box 476800 Jun 8 13:09 hive-mind-npm-test-1859-after-merge.log +drwxr-xr-x 2 box box 4096 Jun 8 13:09 hsperfdata_box +drwxr-xr-x 2 box box 4096 Jun 8 13:13 issue-160-bin +drwxr-xr-x 6 box box 4096 Jun 8 12:53 issue-160-templates +drwx------ 3 box box 4096 Jun 8 12:43 issue1834-home-2L9376 +drwx------ 3 box box 4096 Jun 8 11:36 issue1834-home-6MPTta +drwx------ 3 box box 4096 Jun 8 12:43 issue1834-home-6zriHA +drwx------ 3 box box 4096 Jun 8 12:43 issue1834-home-7ZFLMz +drwx------ 3 box box 4096 Jun 8 12:43 issue1834-home-9MuSeQ +drwx------ 3 box box 4096 Jun 8 10:54 issue1834-home-DODJPF +drwx------ 3 box box 4096 Jun 8 13:02 issue1834-home-HurtUC +drwx------ 3 box box 4096 Jun 8 10:54 issue1834-home-LCNpzb +drwx------ 3 box box 4096 Jun 8 13:02 issue1834-home-LNMiir +drwx------ 3 box box 4096 Jun 8 10:50 issue1834-home-LtJ0sn +drwx------ 3 box box 4096 Jun 8 13:02 issue1834-home-MAEU9B +drwx------ 3 box box 4096 Jun 8 10:54 issue1834-home-NFOJw4 +drwx------ 3 box box 4096 Jun 8 10:50 issue1834-home-NT0rFK +drwx------ 3 box box 4096 Jun 8 10:50 issue1834-home-OwJTYt +drwx------ 3 box box 4096 Jun 8 13:02 issue1834-home-ZVDWdE +drwx------ 3 box box 4096 Jun 8 10:50 issue1834-home-agsgI6 +drwx------ 3 box box 4096 Jun 8 12:43 issue1834-home-cFAxB4 +drwx------ 3 box box 4096 Jun 8 11:36 issue1834-home-ch8rGG +drwx------ 3 box box 4096 Jun 8 11:36 issue1834-home-eKI9QF +drwx------ 3 box box 4096 Jun 8 10:54 issue1834-home-kESvgJ +drwx------ 3 box box 4096 Jun 8 13:02 issue1834-home-mEJj1Z +drwx------ 3 box box 4096 Jun 8 11:36 issue1834-home-rq8gXP +drwx------ 3 box box 4096 Jun 8 10:54 issue1834-home-s61Pno +drwx------ 3 box box 4096 Jun 8 11:36 issue1834-home-y0JonQ +drwx------ 3 box box 4096 Jun 8 10:50 issue1834-home-z9e9mP +drwxr-xr-x 2 box box 4096 Jun 8 12:39 junit +drwxr-xr-x 4 box box 4096 Jun 8 10:26 log-tmp-solution-draft-log-pr-1780914367472.txt-1780914369132 +drwxr-xr-x 4 box box 4096 Jun 8 10:37 log-tmp-solution-draft-log-pr-1780915023524.txt-1780915025379 +drwxr-xr-x 4 box box 4096 Jun 8 10:37 log-tmp-solution-draft-log-pr-1780915027531.txt-1780915029049 +drwxr-xr-x 4 box box 4096 Jun 8 10:57 log-tmp-solution-draft-log-pr-1780916225581.txt-1780916235227 +drwxr-xr-x 4 box box 4096 Jun 8 10:57 log-tmp-solution-draft-log-pr-1780916264562.txt-1780916265910 +drwxr-xr-x 4 box box 4096 Jun 8 11:03 log-tmp-solution-draft-log-pr-1780916617183.txt-1780916620679 +drwxr-xr-x 4 box box 4096 Jun 8 11:07 log-tmp-solution-draft-log-pr-1780916834376.txt-1780916836115 +drwxr-xr-x 4 box box 4096 Jun 8 11:12 log-tmp-solution-draft-log-pr-1780917152229.txt-1780917153784 +drwxr-xr-x 4 box box 4096 Jun 8 11:14 log-tmp-solution-draft-log-pr-1780917272974.txt-1780917274949 +drwxr-xr-x 4 box box 4096 Jun 8 11:20 log-tmp-solution-draft-log-pr-1780917613248.txt-1780917615615 +drwxr-xr-x 4 box box 4096 Jun 8 11:34 log-tmp-solution-draft-log-pr-1780918444991.txt-1780918446789 +drwxr-xr-x 4 box box 4096 Jun 8 11:44 log-tmp-solution-draft-log-pr-1780919047545.txt-1780919049027 +drwxr-xr-x 4 box box 4096 Jun 8 11:59 log-tmp-solution-draft-log-pr-1780919973744.txt-1780919976295 +drwxr-xr-x 4 box box 4096 Jun 8 12:20 log-tmp-solution-draft-log-pr-1780921196763.txt-1780921198880 +drwxr-xr-x 4 box box 4096 Jun 8 12:55 log-tmp-solution-draft-log-pr-1780923333241.txt-1780923335080 +drwxr-xr-x 4 box box 4096 Jun 8 12:57 log-tmp-solution-draft-log-pr-1780923432501.txt-1780923434830 +drwxr-xr-x 4 box box 4096 Jun 8 13:13 log-tmp-solution-draft-log-pr-1780924423096.txt-1780924424714 +drwxr-xr-x 4 box box 4096 Jun 8 10:56 node-compile-cache +-rw-r--r-- 1 box box 36591 Jun 8 12:40 olcrtc-plugin-compile.jar +drwxr-xr-x 6 box box 4096 Jun 8 12:38 olcrtc-plugin-stubs +-rw-r--r-- 1 box box 3624 Jun 8 12:40 olcrtc-policy-tests.jar +-rw-r--r-- 1 box box 1985 Jun 8 12:40 olcrtc-policy.jar +drwxrwxrwx 2 box box 4096 Jun 5 20:45 opencode +-rw-r--r-- 1 box box 11 Jun 8 10:46 opencode_prompt_1780915594804_84019.txt +-rw-r--r-- 1 box box 11 Jun 8 10:48 opencode_prompt_1780915738540_99362.txt +-rw-r--r-- 1 box box 11 Jun 8 11:31 opencode_prompt_1780918291146_269594.txt +-rw-r--r-- 1 box box 11 Jun 8 12:39 opencode_prompt_1780922380696_406768.txt +-rw-r--r-- 1 box box 11 Jun 8 12:58 opencode_prompt_1780923531531_521627.txt +-rw-r--r-- 1 box box 1493 Jun 8 11:07 pr-1862-body.md +-rw-r--r-- 1 box box 2299 Jun 8 12:42 pr-6-body.md +-rw-r--r-- 1 box box 2221 Jun 8 13:13 pr-body-1859.md +-rw-r--r-- 1 box box 2288 Jun 8 12:25 pr198-body.md +-rw-r--r-- 1 box box 3184 Jun 8 12:23 projects-mango-search.log +drwxr-xr-x 3 box box 4096 Jun 8 10:45 rust-paths-no-publishable-members-1780915547908016404 +drwxr-xr-x 3 box box 4096 Jun 8 10:56 rust-paths-no-publishable-members-1780916180202641279 +drwxr-xr-x 3 box box 4096 Jun 8 12:42 rust-paths-no-publishable-members-1780922525900339442 +drwxr-xr-x 3 box box 4096 Jun 8 12:46 rust-paths-no-publishable-members-1780922763676028877 +drwxr-xr-x 3 box box 4096 Jun 8 13:04 rust-paths-no-publishable-members-1780923850486723364 +drwxr-xr-x 3 box box 4096 Jun 8 13:09 rust-paths-no-publishable-members-1780924183754321085 +drwxr-xr-x 3 box box 4096 Jun 8 13:11 rust-paths-no-publishable-members-1780924299955917777 +drwxr-xr-x 3 box box 4096 Jun 8 13:12 rust-paths-no-publishable-members-1780924349387603169 +drwxr-xr-x 3 box box 4096 Jun 8 13:13 rust-paths-no-publishable-members-1780924396309813975 +drwxr-xr-x 2 box box 4096 Jun 8 10:45 rust-paths-root-package-1780915547908041251 +drwxr-xr-x 2 box box 4096 Jun 8 10:56 rust-paths-root-package-1780916180202814849 +drwxr-xr-x 2 box box 4096 Jun 8 12:42 rust-paths-root-package-1780922525901415308 +drwxr-xr-x 2 box box 4096 Jun 8 12:46 rust-paths-root-package-1780922763679312220 +drwxr-xr-x 2 box box 4096 Jun 8 13:04 rust-paths-root-package-1780923850488281220 +drwxr-xr-x 2 box box 4096 Jun 8 13:09 rust-paths-root-package-1780924183770342520 +drwxr-xr-x 2 box box 4096 Jun 8 13:11 rust-paths-root-package-1780924299959712333 +drwxr-xr-x 2 box box 4096 Jun 8 13:12 rust-paths-root-package-1780924349390611051 +drwxr-xr-x 2 box box 4096 Jun 8 13:13 rust-paths-root-package-1780924396313557666 +drwxr-xr-x 4 box box 4096 Jun 8 10:45 rust-paths-workspace-member-1780915547908030755 +drwxr-xr-x 4 box box 4096 Jun 8 10:56 rust-paths-workspace-member-1780916180202789090 +drwxr-xr-x 4 box box 4096 Jun 8 12:42 rust-paths-workspace-member-1780922525900550177 +drwxr-xr-x 4 box box 4096 Jun 8 12:46 rust-paths-workspace-member-1780922763676620590 +drwxr-xr-x 4 box box 4096 Jun 8 13:04 rust-paths-workspace-member-1780923850487524670 +drwxr-xr-x 4 box box 4096 Jun 8 13:09 rust-paths-workspace-member-1780924183764500917 +drwxr-xr-x 4 box box 4096 Jun 8 13:11 rust-paths-workspace-member-1780924299957156456 +drwxr-xr-x 4 box box 4096 Jun 8 13:12 rust-paths-workspace-member-1780924349390391945 +drwxr-xr-x 4 box box 4096 Jun 8 13:13 rust-paths-workspace-member-1780924396313305700 +-rw-r--r-- 1 box box 1891 Jun 8 12:23 stale-old-search.log +drwxr-xr-x 4 box box 4096 Jun 8 10:11 start-command +-rw-r--r-- 1 box box 270 Jun 8 13:04 stdio-interceptor-stderr.log +-rw-r--r-- 1 box box 270 Jun 8 13:04 stdio-interceptor-stdout.log +-rw-r--r-- 1 box box 3161 Jun 8 12:24 targeted-stale-search.final.log +-rw-r--r-- 1 box box 4297 Jun 8 12:23 targeted-stale-search.log +drwxr-xr-x 2 box box 4096 Jun 8 11:44 test-build +drwxr-xr-x 2 box box 4096 Jun 8 11:28 tsx-1001 +-rw-r--r-- 1 box box 784 Jun 8 12:23 validate-frontmatter.after.log +-rw-r--r-- 1 box box 784 Jun 8 12:23 validate-frontmatter.before.log +-rw-r--r-- 1 box box 784 Jun 8 12:24 validate-frontmatter.final.log +-rw-r--r-- 1 box box 366 Jun 8 12:23 validate-repository-structure.after.log +-rw-r--r-- 1 box box 114 Jun 8 12:23 validate-repository-structure.before.log +-rw-r--r-- 1 box box 40 Jun 8 12:24 validate-repository-structure.final.log +drwxr-xr-x 2 box box 4096 Jun 8 10:45 version-and-commit-lock-absent-1780915547906088725 +drwxr-xr-x 2 box box 4096 Jun 8 10:56 version-and-commit-lock-absent-1780916180198796718 +drwxr-xr-x 2 box box 4096 Jun 8 12:42 version-and-commit-lock-absent-1780922525889393578 +drwxr-xr-x 2 box box 4096 Jun 8 12:46 version-and-commit-lock-absent-1780922763663957532 +drwxr-xr-x 2 box box 4096 Jun 8 13:04 version-and-commit-lock-absent-1780923850483529053 +drwxr-xr-x 2 box box 4096 Jun 8 10:45 version-and-commit-lock-entry-absent-1780915547906338348 +drwxr-xr-x 2 box box 4096 Jun 8 10:56 version-and-commit-lock-entry-absent-1780916180198870178 +drwxr-xr-x 2 box box 4096 Jun 8 12:42 version-and-commit-lock-entry-absent-1780922525890427991 +drwxr-xr-x 2 box box 4096 Jun 8 12:46 version-and-commit-lock-entry-absent-1780922763664343478 +drwxr-xr-x 2 box box 4096 Jun 8 13:04 version-and-commit-lock-entry-absent-1780923850484194126 +drwxr-xr-x 2 box box 4096 Jun 8 10:45 version-and-commit-lock-idempotent-1780915547904281346 +drwxr-xr-x 2 box box 4096 Jun 8 10:56 version-and-commit-lock-idempotent-1780916180198344993 +drwxr-xr-x 2 box box 4096 Jun 8 12:42 version-and-commit-lock-idempotent-1780922525890289735 +drwxr-xr-x 2 box box 4096 Jun 8 12:46 version-and-commit-lock-idempotent-1780922763662227047 +drwxr-xr-x 2 box box 4096 Jun 8 13:04 version-and-commit-lock-idempotent-1780923850483469464 +drwxr-xr-x 2 box box 4096 Jun 8 10:45 version-and-commit-lock-update-1780915547906706608 +drwxr-xr-x 2 box box 4096 Jun 8 10:56 version-and-commit-lock-update-1780916180199340740 +drwxr-xr-x 2 box box 4096 Jun 8 12:42 version-and-commit-lock-update-1780922525893366100 +drwxr-xr-x 2 box box 4096 Jun 8 12:46 version-and-commit-lock-update-1780922763664777185 +drwxr-xr-x 2 box box 4096 Jun 8 13:04 version-and-commit-lock-update-1780923850485213909 +drwxr-xr-x 2 box box 4096 Jun 8 13:08 yougile-to-gh-check-logs +drwxr-xr-x 2 box box 4096 Jun 8 10:43 yougile-to-gh-fake-bin-1780915427857302756 +drwxr-xr-x 2 box box 4096 Jun 8 10:44 yougile-to-gh-fake-bin-1780915452632532192 +drwxr-xr-x 2 box box 4096 Jun 8 13:02 yougile-to-gh-fake-bin-1780923746734652232 +-rw-r--r-- 1 box box 153 Jun 8 10:43 yougile-to-gh-fixture-1780915427856885834.json +-rw-r--r-- 1 box box 153 Jun 8 10:44 yougile-to-gh-fixture-1780915452632203202.json +-rw-r--r-- 1 box box 153 Jun 8 13:02 yougile-to-gh-fixture-1780923746734313036.json +-rw-r--r-- 1 box box 1182 Jun 8 13:07 yougile-to-gh-pr-4-body.md +(pass) Start/Run Edge Cases and Advanced Usage > should work with real shell commands that produce large output [12.00ms] +ls: cannot access '/nonexistent-path-12345': No such file or directory +(pass) Start/Run Edge Cases and Advanced Usage > should handle stderr with capture: false [7.69ms] +ls: cannot access '/nonexistent-path-98765': No such file or directory +(pass) Start/Run Edge Cases and Advanced Usage > should handle stderr with capture: true [6.77ms] +multiple calls +(pass) Start/Run Edge Cases and Advanced Usage > should handle multiple consecutive start() calls correctly [6.38ms] +async mode +sync mode +(pass) Start/Run Edge Cases and Advanced Usage > should handle mixed sync/async mode correctly [11.67ms] +with start +with run +direct await +(pass) Start/Run Edge Cases and Advanced Usage > should preserve original behavior when no options passed [14.52ms] +hello world +hello world +(pass) Start/Run Edge Cases and Advanced Usage > should work with piped commands [12.53ms] +(pass) Start/Run Edge Cases and Advanced Usage > should handle buffer stdin correctly with options [6.31ms] +performance test +(pass) Start/Run Edge Cases and Advanced Usage > should maintain performance with capture: false [5.19ms] +(pass) Start/Run Edge Cases and Advanced Usage > should handle empty string stdin [7.16ms] + +js/tests/$.features.test.mjs: +(pass) command-stream Feature Validation > Runtime Support > should work in Bun runtime [0.08ms] +node compatibility +(pass) command-stream Feature Validation > Runtime Support > should work in Node.js runtime [4.92ms] +template literal test +(pass) command-stream Feature Validation > Template Literals > should support $`cmd` syntax [4.81ms] +interpolation test +(pass) command-stream Feature Validation > Template Literals > should support variable interpolation [3.70ms] +streaming test +(pass) command-stream Feature Validation > Real-time Streaming > should provide live output streaming [4.06ms] +immediate +(pass) command-stream Feature Validation > Real-time Streaming > should stream data as it arrives, not buffered [4.11ms] +async iteration test +(pass) command-stream Feature Validation > Async Iteration > should support for await (chunk of $.stream()) [4.56ms] +metadata test +(pass) command-stream Feature Validation > Async Iteration > should provide chunk metadata [4.23ms] +event test +(pass) command-stream Feature Validation > EventEmitter Pattern > should support .on("data", ...) events [15.90ms] +stdout +stderr +(pass) command-stream Feature Validation > EventEmitter Pattern > should support multiple event types [16.08ms] +mixed pattern test +(pass) command-stream Feature Validation > Mixed Patterns > should support events + await simultaneously [5.22ms] +'; rm -rf /; echo 'hacked +(pass) command-stream Feature Validation > Shell Injection Protection > should auto-quote dangerous input [4.07ms] +$HOME && echo "injection" +(pass) command-stream Feature Validation > Shell Injection Protection > should handle special characters safely [4.11ms] +cross-platform test +(pass) command-stream Feature Validation > Cross-platform Support > should work on current platform [4.53ms] +memory efficient streaming test +(pass) command-stream Feature Validation > Memory Efficiency > should stream without accumulating large buffers [4.61ms] +(pass) command-stream Feature Validation > Error Handling > should handle non-zero exit codes gracefully [4.57ms] +stdin string test(pass) command-stream Feature Validation > Stdin Support > should support string stdin through sh helper [5.63ms] +buffer stdin test(pass) command-stream Feature Validation > Stdin Support > should support Buffer stdin through sh helper [5.71ms] +ignore stdin test +(pass) command-stream Feature Validation > Stdin Support > should support ignore stdin through options [5.19ms] + +js/tests/text-method.test.mjs: +sync test +(pass) .text() method for Bun.$ compatibility > sync execution should have .text() method [4.18ms] +async test +(pass) .text() method for Bun.$ compatibility > async execution should have .text() method [3.95ms] +hello world +(pass) .text() method for Bun.$ compatibility > .text() should return stdout content (sync) [3.48ms] +hello async +(pass) .text() method for Bun.$ compatibility > .text() should return stdout content (async) [4.08ms] +(pass) .text() method for Bun.$ compatibility > .text() should handle empty output [3.84ms] +1 +2 +3 +(pass) .text() method for Bun.$ compatibility > .text() should handle multiline output [5.60ms] +1 +2 +3 +(pass) .text() method for Bun.$ compatibility > .text() should work with built-in commands [5.67ms] +test content +(pass) .text() method for Bun.$ compatibility > .text() should work with cat built-in command [15.38ms] +$.features.test.mjs +$.test.mjs +array-interpolation.test.mjs +builtin-commands.test.mjs +bun-shell-path-fix.test.mjs +bun.features.test.mjs +cd-virtual-command.test.mjs +cleanup-verification.test.mjs +ctrl-c-baseline.test.mjs +ctrl-c-basic.test.mjs +ctrl-c-library.test.mjs +ctrl-c-signal.test.mjs +examples.test.mjs +execa.features.test.mjs +gh-commands.test.mjs +gh-gist-operations.test.mjs +git-gh-cd.test.mjs +interactive-option.test.mjs +interactive-streaming.test.mjs +issue-135-final.test.mjs +jq-color-behavior.test.mjs +jq.test.mjs +options-examples.test.mjs +options-syntax.test.mjs +path-interpolation.test.mjs +pipe.test.mjs +raw-function.test.mjs +readme-examples.test.mjs +repository-layout.test.mjs +resource-cleanup-internals.test.mjs +shell-settings.test.mjs +sigint-cleanup-isolated.test.mjs +sigint-cleanup.test.mjs +start-run-edge-cases.test.mjs +start-run-options.test.mjs +stderr-output-handling.test.mjs +streaming-interfaces.test.mjs +sync.test.mjs +system-pipe.test.mjs +test-cleanup.mjs +test-helper-fixed.mjs +test-helper-v2.mjs +test-helper.mjs +test-sigint-child.js +text-method.test.mjs +virtual.test.mjs +yes-command-cleanup.test.mjs +zx.features.test.mjs +(pass) .text() method for Bun.$ compatibility > .text() should work with ls built-in command [6.16ms] +/tmp/gh-issue-solver-1780922968363 +(pass) .text() method for Bun.$ compatibility > .text() should work with pwd built-in command [4.64ms] +(pass) .text() method for Bun.$ compatibility > .text() should return empty string for commands with no stdout [16.97ms] +1 +2 +3 +(pass) .text() method for Bun.$ compatibility > .text() should work with piped commands (when supported) [2.95ms] +1 +2 +3 +(pass) .text() method for Bun.$ compatibility > .text() should work with complex pipeline (when supported) [26.45ms] +cat: nonexistent-file-text-test.txt: No such file or directory +(pass) .text() method for Bun.$ compatibility > .text() should handle commands with stderr but no stdout [5.69ms] +consistency test +(pass) .text() method for Bun.$ compatibility > .text() should be consistent with .stdout property [5.18ms] +multiple calls +(pass) .text() method for Bun.$ compatibility > .text() can be called multiple times [4.98ms] +promise test +(pass) .text() method for Bun.$ compatibility > .text() returns a Promise [4.76ms] +content with special chars: üñíçødé 🚀 +(pass) .text() method for Bun.$ compatibility > .text() should work with binary-safe content [22.02ms] +pipe test +pipe test +(pass) .text() method for Bun.$ compatibility > .text() should work with .pipe() method results [11.47ms] +test +(pass) .text() method for Bun.$ compatibility > .text() method should be accessible [5.72ms] +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +(pass) .text() method for Bun.$ compatibility > .text() should handle very large output efficiently [7.72ms] + +5 tests skipped: +(skip) GitHub Gist Operations with $.mjs > gh gist edit should add files to existing gist +(skip) Examples Execution Tests > readme-example.mjs should execute and demonstrate new API signature +(skip) Examples Execution Tests > simple-jq-streaming.mjs should complete successfully +(skip) CTRL+C Library Tests (command-stream) > should test our library via external script - SKIP: uses test-sleep.mjs +(skip) Stderr output handling in $.mjs > timeout should work even with pending stderr + + 684 pass + 5 skip + 0 fail + 1545 expect() calls +Ran 689 tests across 43 files. [61.05s] diff --git a/docs/case-studies/issue-160/data/npm-package-lock-refresh.log b/docs/case-studies/issue-160/data/npm-package-lock-refresh.log new file mode 100644 index 0000000..2986647 --- /dev/null +++ b/docs/case-studies/issue-160/data/npm-package-lock-refresh.log @@ -0,0 +1,12 @@ + +up to date, audited 320 packages in 1s + +74 packages are looking for funding + run `npm fund` for details + +6 vulnerabilities (3 moderate, 3 high) + +To address all issues, run: + npm audit fix + +Run `npm audit` for details. diff --git a/docs/case-studies/issue-160/data/pr-161.json b/docs/case-studies/issue-160/data/pr-161.json new file mode 100644 index 0000000..71db163 --- /dev/null +++ b/docs/case-studies/issue-160/data/pr-161.json @@ -0,0 +1 @@ +{"baseRefName":"main","body":"## 🤖 AI-Powered Solution Draft\n\nThis pull request is being automatically generated to solve issue #160.\n\n### 📋 Issue Reference\nFixes #160\n\n### 🚧 Status\n**Work in Progress** - The AI assistant is currently analyzing and implementing the solution draft.\n\n### 📝 Implementation Details\n_Details will be added as the solution draft is developed..._\n\n---\n*This PR was created automatically by the AI issue solver*","comments":[],"commits":[{"authoredDate":"2026-06-08T12:49:30Z","authors":[{"email":"drakonard@gmail.com","id":"MDQ6VXNlcjE0MzE5MDQ=","login":"konard","name":"konard"}],"committedDate":"2026-06-08T12:49:30Z","messageBody":"Adding .gitkeep for PR creation (default mode).\nThis file will be removed when the task is complete.\n\nIssue: https://github.com/link-foundation/command-stream/issues/160","messageHeadline":"Initial commit with task details","oid":"40c13d5f636f5c6beec7509ceeada6f38067cb15"}],"headRefName":"issue-160-a2a2313cf693","isDraft":true,"reviewDecision":"","state":"OPEN","title":"[WIP] We should clearly separate JavaScript and Rust","url":"https://github.com/link-foundation/command-stream/pull/161"} diff --git a/docs/case-studies/issue-160/data/python-ai-driven-development-pipeline-template.repo.json b/docs/case-studies/issue-160/data/python-ai-driven-development-pipeline-template.repo.json new file mode 100644 index 0000000..b6096da --- /dev/null +++ b/docs/case-studies/issue-160/data/python-ai-driven-development-pipeline-template.repo.json @@ -0,0 +1 @@ +{"id":1116413416,"node_id":"R_kgDOQosd6A","name":"python-ai-driven-development-pipeline-template","full_name":"link-foundation/python-ai-driven-development-pipeline-template","private":false,"owner":{"login":"link-foundation","id":176174013,"node_id":"O_kgDOCoAzvQ","avatar_url":"https://avatars.githubusercontent.com/u/176174013?v=4","gravatar_id":"","url":"https://api.github.com/users/link-foundation","html_url":"https://github.com/link-foundation","followers_url":"https://api.github.com/users/link-foundation/followers","following_url":"https://api.github.com/users/link-foundation/following{/other_user}","gists_url":"https://api.github.com/users/link-foundation/gists{/gist_id}","starred_url":"https://api.github.com/users/link-foundation/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/link-foundation/subscriptions","organizations_url":"https://api.github.com/users/link-foundation/orgs","repos_url":"https://api.github.com/users/link-foundation/repos","events_url":"https://api.github.com/users/link-foundation/events{/privacy}","received_events_url":"https://api.github.com/users/link-foundation/received_events","type":"Organization","user_view_type":"public","site_admin":false},"html_url":"https://github.com/link-foundation/python-ai-driven-development-pipeline-template","description":"A template for AI driven development in Python","fork":false,"url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template","forks_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/forks","keys_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/keys{/key_id}","collaborators_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/teams","hooks_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/hooks","issue_events_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/issues/events{/number}","events_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/events","assignees_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/assignees{/user}","branches_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/branches{/branch}","tags_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/tags","blobs_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/git/refs{/sha}","trees_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/git/trees{/sha}","statuses_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/statuses/{sha}","languages_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/languages","stargazers_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/stargazers","contributors_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/contributors","subscribers_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/subscribers","subscription_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/subscription","commits_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/commits{/sha}","git_commits_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/git/commits{/sha}","comments_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/comments{/number}","issue_comment_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/issues/comments{/number}","contents_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/contents/{+path}","compare_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/compare/{base}...{head}","merges_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/merges","archive_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/downloads","issues_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/issues{/number}","pulls_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/pulls{/number}","milestones_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/milestones{/number}","notifications_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/labels{/name}","releases_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/releases{/id}","deployments_url":"https://api.github.com/repos/link-foundation/python-ai-driven-development-pipeline-template/deployments","created_at":"2025-12-14T20:07:42Z","updated_at":"2026-06-04T18:11:55Z","pushed_at":"2026-06-04T18:11:50Z","git_url":"git://github.com/link-foundation/python-ai-driven-development-pipeline-template.git","ssh_url":"git@github.com:link-foundation/python-ai-driven-development-pipeline-template.git","clone_url":"https://github.com/link-foundation/python-ai-driven-development-pipeline-template.git","svn_url":"https://github.com/link-foundation/python-ai-driven-development-pipeline-template","homepage":null,"size":92,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"has_discussions":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"unlicense","name":"The Unlicense","spdx_id":"Unlicense","url":"https://api.github.com/licenses/unlicense","node_id":"MDc6TGljZW5zZTE1"},"allow_forking":true,"is_template":true,"web_commit_signoff_required":false,"has_pull_requests":true,"pull_request_creation_policy":"all","topics":[],"visibility":"public","forks":0,"open_issues":0,"watchers":1,"default_branch":"main","permissions":{"admin":true,"maintain":true,"push":true,"triage":true,"pull":true},"temp_clone_token":"","allow_squash_merge":true,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_auto_merge":false,"delete_branch_on_merge":false,"allow_update_branch":false,"use_squash_pr_title_as_default":false,"squash_merge_commit_message":"COMMIT_MESSAGES","squash_merge_commit_title":"COMMIT_OR_PR_TITLE","merge_commit_message":"PR_TITLE","merge_commit_title":"MERGE_MESSAGE","custom_properties":{},"organization":{"login":"link-foundation","id":176174013,"node_id":"O_kgDOCoAzvQ","avatar_url":"https://avatars.githubusercontent.com/u/176174013?v=4","gravatar_id":"","url":"https://api.github.com/users/link-foundation","html_url":"https://github.com/link-foundation","followers_url":"https://api.github.com/users/link-foundation/followers","following_url":"https://api.github.com/users/link-foundation/following{/other_user}","gists_url":"https://api.github.com/users/link-foundation/gists{/gist_id}","starred_url":"https://api.github.com/users/link-foundation/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/link-foundation/subscriptions","organizations_url":"https://api.github.com/users/link-foundation/orgs","repos_url":"https://api.github.com/users/link-foundation/repos","events_url":"https://api.github.com/users/link-foundation/events{/privacy}","received_events_url":"https://api.github.com/users/link-foundation/received_events","type":"Organization","user_view_type":"public","site_admin":false},"security_and_analysis":{"secret_scanning":{"status":"disabled"},"secret_scanning_push_protection":{"status":"disabled"},"dependabot_security_updates":{"status":"disabled"},"secret_scanning_non_provider_patterns":{"status":"disabled"},"secret_scanning_validity_checks":{"status":"disabled"}},"network_count":0,"subscribers_count":0} \ No newline at end of file diff --git a/docs/case-studies/issue-160/data/python-template-head.txt b/docs/case-studies/issue-160/data/python-template-head.txt new file mode 100644 index 0000000..e3b0318 --- /dev/null +++ b/docs/case-studies/issue-160/data/python-template-head.txt @@ -0,0 +1 @@ +66abe798182316d568e748bec4b0e89828fac1a6 diff --git a/docs/case-studies/issue-160/data/repository-layout-after.log b/docs/case-studies/issue-160/data/repository-layout-after.log new file mode 100644 index 0000000..bf4d51c --- /dev/null +++ b/docs/case-studies/issue-160/data/repository-layout-after.log @@ -0,0 +1,12 @@ +bun test v1.3.14 (0d9b296a) + +js/tests/repository-layout.test.mjs: +(pass) repository language layout > keeps JavaScript package files inside js/ [1.49ms] +(pass) repository language layout > keeps Rust package release files inside rust/ [0.12ms] +(pass) repository language layout > uses separate JavaScript and Rust workflows and release tags [0.23ms] +(pass) repository language layout > keeps root README focused on shared project information [0.07ms] + + 4 pass + 0 fail + 30 expect() calls +Ran 4 tests across 1 file. [32.00ms] diff --git a/docs/case-studies/issue-160/data/repository-layout-before.log b/docs/case-studies/issue-160/data/repository-layout-before.log new file mode 100644 index 0000000..2fcd99b --- /dev/null +++ b/docs/case-studies/issue-160/data/repository-layout-before.log @@ -0,0 +1,64 @@ +bun test v1.3.14 (0d9b296a) + +js/tests/repository-layout.test.mjs: +15 | return readFileSync(resolve(repoRoot, relativePath), 'utf8'); +16 | } +17 | +18 | describe('repository language layout', () => { +19 | test('keeps JavaScript package files inside js/', () => { +20 | expect(existsFromRepo('package.json')).toBe(false); + ^ +error: expect(received).toBe(expected) + +Expected: false +Received: true + + at (/tmp/gh-issue-solver-1780922968363/js/tests/repository-layout.test.mjs:20:44) +(fail) repository language layout > keeps JavaScript package files inside js/ [2.67ms] +34 | }); +35 | +36 | test('keeps Rust package release files inside rust/', () => { +37 | expect(existsFromRepo('rust/Cargo.toml')).toBe(true); +38 | expect(existsFromRepo('rust/Cargo.lock')).toBe(true); +39 | expect(existsFromRepo('rust/README.md')).toBe(true); + ^ +error: expect(received).toBe(expected) + +Expected: true +Received: false + + at (/tmp/gh-issue-solver-1780922968363/js/tests/repository-layout.test.mjs:39:46) +(fail) repository language layout > keeps Rust package release files inside rust/ [0.15ms] +41 | expect(existsFromRepo('rust/scripts/publish-crate.rs')).toBe(true); +42 | expect(existsFromRepo('rust/changelog.d/README.md')).toBe(true); +43 | }); +44 | +45 | test('uses separate JavaScript and Rust workflows and release tags', () => { +46 | expect(existsFromRepo('.github/workflows/release.yml')).toBe(false); + ^ +error: expect(received).toBe(expected) + +Expected: false +Received: true + + at (/tmp/gh-issue-solver-1780922968363/js/tests/repository-layout.test.mjs:46:61) +(fail) repository language layout > uses separate JavaScript and Rust workflows and release tags [0.07ms] +57 | }); +58 | +59 | test('keeps root README focused on shared project information', () => { +60 | const rootReadme = readFromRepo('README.md'); +61 | +62 | expect(rootReadme).toContain('[JavaScript package](./js/README.md)'); + ^ +error: expect(received).toContain(expected) + +Expected to contain: "[JavaScript package](./js/README.md)" +Received: "[![npm](https://img.shields.io/npm/v/command-stream.svg)](https://npmjs.com/command-stream)\n[![crates.io](https://img.shields.io/crates/v/command-stream.svg)](https://crates.io/crates/command-stream)\n[![License](https://img.shields.io/badge/license-Unlicense-blue.svg)](https://github.com/link-foundation/command-stream/blob/main/LICENSE)\n[![GitHub stars](https://img.shields.io/github/stars/link-foundation/command-stream?style=social)](https://github.com/link-foundation/command-stream/stargazers)\n\n[![Open in Gitpod](https://img.shields.io/badge/Gitpod-ready--to--code-f29718?logo=gitpod)](https://gitpod.io/#https://github.com/link-foundation/command-stream)\n[![Open in GitHub Codespaces](https://img.shields.io/badge/GitHub%20Codespaces-Open-181717?logo=github)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=link-foundation/command-stream)\n\n# [command-$tream](https://github.com/link-foundation/command-stream)\n\n$treamable commands executor\n\nA modern $ shell utility library with streaming, async iteration, and EventEmitter support, optimized for Bun runtime.\n\n\"ray-so-export\"\n\n## Features\n\n- 🐚 **Shell-like by Default**: Commands behave exactly like running in terminal (stdout→stdout, stderr→stderr, stdin→stdin)\n- 🎛️ **Fully Controllable**: Override default behavior with options (`mirror`, `capture`, `stdin`)\n- 🚀 **Multiple Usage Patterns**: Classic await, async iteration, EventEmitter, .pipe() method, and mixed patterns\n- 📡 **Real-time Streaming**: Process command output as it arrives, not after completion\n- 🔄 **Bun Optimized**: Designed for Bun runtime with Node.js compatibility\n- ⚡ **Performance**: Memory-efficient streaming prevents large buffer accumulation\n- 🎯 **Backward Compatible**: Existing `await $` syntax continues to work + Bun.$ `.text()` method\n- 🛡️ **Type Safe**: Full TypeScript support (coming soon)\n- 🔧 **Built-in Commands**: 18 essential commands work identically across platforms\n\n## Comparison with Other Libraries\n\n| Feature | [**command-stream**](https://github.com/link-foundation/command-stream) | [**execa**](https://github.com/sindresorhus/execa) | [**cross-spawn**](https://github.com/moxystudio/node-cross-spawn) | [**Bun.$**](https://github.com/oven-sh/bun) | [**ShellJS**](https://github.com/shelljs/shelljs) | [**zx**](https://github.com/google/zx) |\n| ------------------------------ | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |\n| **📦 NPM Package** | [![npm](https://img.shields.io/npm/v/command-stream.svg)](https://www.npmjs.com/package/command-stream) | [![npm](https://img.shields.io/npm/v/execa.svg)](https://www.npmjs.com/package/execa) | [![npm](https://img.shields.io/npm/v/cross-spawn.svg)](https://www.npmjs.com/package/cross-spawn) | N/A (Built-in) | [![npm](https://img.shields.io/npm/v/shelljs.svg)](https://www.npmjs.com/package/shelljs) | [![npm](https://img.shields.io/npm/v/zx.svg)](https://www.npmjs.com/package/zx) |\n| **⭐ GitHub Stars** | [**⭐ 2** (Please ⭐ us!)](https://github.com/link-foundation/command-stream) | [⭐ 7,264](https://github.com/sindresorhus/execa) | [⭐ 1,149](https://github.com/moxystudio/node-cross-spawn) | [⭐ 80,169](https://github.com/oven-sh/bun) (Full Runtime) | [⭐ 14,375](https://github.com/shelljs/shelljs) | [⭐ 44,569](https://github.com/google/zx) |\n| **📊 Monthly Downloads** | **893** (New project!) | **381M** | **409M** | N/A (Built-in) | **35M** | **4.2M** |\n| **📈 Total Downloads** | **Growing** | **6B+** | **5.4B** | N/A (Built-in) | **596M** | **37M** |\n| **Runtime Support** | ✅ Bun + Node.js | ✅ Node.js | ✅ Node.js | 🟡 Bun only | ✅ Node.js | ✅ Node.js |\n| **Template Literals** | ✅ `` $`cmd` `` | ✅ `` $`cmd` `` | ❌ Function calls | ✅ `` $`cmd` `` | ❌ Function calls | ✅ `` $`cmd` `` |\n| **Real-time Streaming** | ✅ Live output | 🟡 Limited | ❌ Buffer only | ❌ Buffer only | ❌ Buffer only | ❌ Buffer only |\n| **Synchronous Execution** | ✅ `.sync()` with events | ✅ `execaSync` | ✅ `spawnSync` | ❌ No | ✅ Sync by default | ❌ No |\n| **Async Iteration** | ✅ `for await (chunk of $.stream())` | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No |\n| **EventEmitter Pattern** | ✅ `.on('data', ...)` | 🟡 Limited events | 🟡 Child process events | ❌ No | ❌ No | ❌ No |\n| **Mixed Patterns** | ✅ Events + await/sync | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No |\n| **Bun.$ Compatibility** | ✅ `.text()` method support | ❌ No | ❌ No | ✅ Native API | ❌ No | ❌ No |\n| **Shell Injection Protection** | ✅ Smart auto-quoting | ✅ Safe by default | ✅ Safe by default | ✅ Built-in | 🟡 Manual escaping | ✅ Safe by default |\n| **Cross-platform** | ✅ macOS/Linux/Windows | ✅ Yes | ✅ **Specialized** cross-platform | ✅ Yes | ✅ Yes | ✅ Yes |\n| **Performance** | ⚡ Fast (Bun optimized) | 🐌 Moderate | ⚡ Fast | ⚡ Very fast | 🐌 Moderate | 🐌 Slow |\n| **Memory Efficiency** | ✅ Streaming prevents buildup | 🟡 Buffers in memory | 🟡 Buffers in memory | 🟡 Buffers in memory | 🟡 Buffers in memory | 🟡 Buffers in memory |\n| **Error Handling** | ✅ Configurable (`set -e`/`set +e`, non-zero OK by default) | ✅ Throws on error | ❌ Basic (exit codes) | ✅ Throws on error | ✅ Configurable | ✅ Throws on error |\n| **Shell Settings** | ✅ `set -e`/`set +e` equivalent | ❌ No | ❌ No | ❌ No | 🟡 Limited (`set()`) | ❌ No |\n| **Stdout Support** | ✅ Real-time streaming + events | ✅ Node.js streams + interleaved | ✅ Inherited/buffered | ✅ Shell redirection + buffered | ✅ Direct output | ✅ Readable streams + `.pipe.stdout` |\n| **Stderr Support** | ✅ Real-time streaming + events | ✅ Streams + interleaved output | ✅ Inherited/buffered | ✅ Redirection + `.quiet()` access | ✅ Error output | ✅ Readable streams + `.pipe.stderr` |\n| **Stdin Support** | ✅ string/Buffer/inherit/ignore | ✅ Input/output streams | ✅ Full stdio support | ✅ Pipe operations | 🟡 Basic | ✅ Basic stdin |\n| **Built-in Commands** | ✅ **18 commands**: cat, ls, mkdir, rm, mv, cp, touch, basename, dirname, seq, yes + all Bun.$ commands | ❌ Uses system | ❌ Uses system | ✅ echo, cd, etc. | ✅ **20+ commands**: cat, ls, mkdir, rm, mv, cp, etc. | ❌ Uses system |\n| **Virtual Commands Engine** | ✅ **Revolutionary**: Register JavaScript functions as shell commands with full pipeline support | ❌ No custom commands | ❌ No custom commands | ❌ No extensibility | ❌ No custom commands | ❌ No custom commands |\n| **Pipeline/Piping Support** | ✅ **Advanced**: System + Built-ins + Virtual + Mixed + `.pipe()` method | ✅ Programmatic `.pipe()` + multi-destination | ❌ No piping | ✅ Standard shell piping | ✅ Shell piping + `.to()` method | ✅ Shell piping + `.pipe()` method |\n| **Bundle Size** | 📦 **~20KB gzipped** | 📦 ~400KB+ (packagephobia) | 📦 ~2KB gzipped | 🎯 0KB (built-in) | 📦 ~15KB gzipped | 📦 ~50KB+ (estimated) |\n| **Signal Handling** | ✅ **Advanced SIGINT/SIGTERM forwarding** with cleanup | 🟡 Basic | ✅ **Excellent** cross-platform | 🟡 Basic | 🟡 Basic | 🟡 Basic |\n| **Process Management** | ✅ **Robust child process lifecycle** with proper termination | ✅ Good | ✅ **Excellent** spawn wrapper | ❌ Basic | 🟡 Limited | 🟡 Limited |\n| **Debug Tracing** | ✅ **Comprehensive VERBOSE logging** for CI/debugging | 🟡 Limited | ❌ No | ❌ No | 🟡 Basic | ❌ No |\n| **Test Coverage** | ✅ **518+ tests, 1165+ assertions** | ✅ Excellent | ✅ Good | 🟡 Good coverage | ✅ Good | 🟡 Good |\n| **CI Reliability** | ✅ **Platform-specific handling** (macOS/Ubuntu) | ✅ Good | ✅ **Excellent** | 🟡 Basic | ✅ Good | 🟡 Basic |\n| **Documentation** | ✅ **Comprehensive examples + guides** | ✅ Excellent | 🟡 Basic | ✅ Good | ✅ Good | 🟡 Limited |\n| **TypeScript** | 🔄 Coming soon | ✅ Full support | ✅ Built-in | ✅ Built-in | 🟡 Community types | ✅ Full support |\n| **License** | ✅ **Unlicense (Public Domain)** | 🟡 MIT | 🟡 MIT | 🟡 MIT (+ LGPL dependencies) | 🟡 BSD-3-Clause | 🟡 Apache 2.0 |\n\n**📊 Popularity & Adoption:**\n\n- **⭐ GitHub Stars:** [Bun: 80,169](https://github.com/oven-sh/bun) • [zx: 44,569](https://github.com/google/zx) • [ShellJS: 14,375](https://github.com/shelljs/shelljs) • [execa: 7,264](https://github.com/sindresorhus/execa) • [cross-spawn: 1,149](https://github.com/moxystudio/node-cross-spawn) • [**command-stream: 2 ⭐ us!**](https://github.com/link-foundation/command-stream)\n- **📈 Total Downloads:** [execa: 6B+](https://www.npmjs.com/package/execa) • [cross-spawn: 5.4B](https://www.npmjs.com/package/cross-spawn) • [ShellJS: 596M](https://www.npmjs.com/package/shelljs) • [zx: 37M](https://www.npmjs.com/package/zx) • [command-stream: Growing](https://www.npmjs.com/package/command-stream)\n- **📊 Monthly Downloads:** [cross-spawn: 409M](https://www.npmjs.com/package/cross-spawn) • [execa: 381M](https://www.npmjs.com/package/execa) • [ShellJS: 35M](https://www.npmjs.com/package/shelljs) • [zx: 4.2M](https://www.npmjs.com/package/zx) • [command-stream: 893 (growing!)](https://www.npmjs.com/package/command-stream)\n\n**⭐ Help Us Grow!** If command-stream's **revolutionary virtual commands** and **advanced streaming capabilities** help your project, [**please star us on GitHub**](https://github.com/link-foundation/command-stream) to help the project grow!\n\n### Why Choose command-stream?\n\n- **🆓 Truly Free**: **Unlicense (Public Domain)** - No restrictions, no attribution required, use however you want\n- **🚀 Revolutionary Virtual Commands**: **World's first** fully customizable virtual commands engine - register JavaScript functions as shell commands!\n- **🔗 Advanced Pipeline System**: **Only library** where virtual commands work seamlessly in pipelines with built-ins and system commands\n- **🔧 Built-in Commands**: **18 essential commands** work identically across all platforms - no system dependencies!\n- **📡 Real-time Processing**: Only library with true streaming and async iteration\n- **🔄 Flexible Patterns**: Multiple usage patterns (await, events, iteration, mixed)\n- **🐚 Shell Replacement**: Dynamic error handling with `set -e`/`set +e` equivalents for .sh file replacement\n- **⚡ Bun Optimized**: Designed for Bun with Node.js fallback compatibility\n- **💾 Memory Efficient**: Streaming prevents large buffer accumulation\n- **🛡️ Production Ready**: **518+ tests, 1165+ assertions** with comprehensive coverage including CI reliability\n- **🎯 Advanced Signal Handling**: Robust SIGINT/SIGTERM forwarding with proper child process cleanup\n- **🔍 Debug-Friendly**: Comprehensive VERBOSE tracing for CI debugging and troubleshooting\n\n## Built-in Commands (🚀 NEW!)\n\ncommand-stream now includes **18 built-in commands** that work identically to their bash/sh counterparts, providing true cross-platform shell scripting without system dependencies:\n\n### 📁 **File System Commands**\n\n- `cat` - Read and display file contents\n- `ls` - List directory contents (supports `-l`, `-a`, `-A`)\n- `mkdir` - Create directories (supports `-p` recursive)\n- `rm` - Remove files/directories (supports `-r`, `-f`)\n- `mv` - Move/rename files and directories\n- `cp` - Copy files/directories (supports `-r` recursive)\n- `touch` - Create files or update timestamps\n\n### 🔧 **Utility Commands**\n\n- `basename` - Extract filename from path\n- `dirname` - Extract directory from path\n- `seq` - Generate number sequences\n- `yes` - Output string repeatedly (streaming)\n\n### ⚡ **System Commands**\n\n- `cd` - Change directory\n- `pwd` - Print working directory\n- `echo` - Print arguments (supports `-n`)\n- `sleep` - Wait for specified time\n- `true`/`false` - Success/failure commands\n- `which` - Locate commands\n- `exit` - Exit with code\n- `env` - Print environment variables\n- `test` - File condition testing\n\n### ✨ **Key Advantages**\n\n- **🌍 Cross-Platform**: Works identically on Windows, macOS, and Linux\n- **🚀 Performance**: No system calls - pure JavaScript execution\n- **🔄 Pipeline Support**: All commands work in pipelines and virtual command chains\n- **⚙️ Option Aware**: Commands respect `cwd`, `env`, and other options\n- **🛡️ Safe by Default**: Proper error handling and safety checks (e.g., `rm` requires `-r` for directories)\n- **📝 Bash Compatible**: Error messages and behavior match bash/sh exactly\n\n```javascript\nimport { $ } from 'command-stream';\n\n// All these work without any system dependencies!\nawait $`mkdir -p project/src`;\nawait $`touch project/src/index.js`;\nawait $`echo \"console.log('Hello!');\" > project/src/index.js`;\nawait $`ls -la project/src`;\nawait $`cat project/src/index.js`;\nawait $`cp -r project project-backup`;\nawait $`rm -r project-backup`;\n\n// Mix built-ins with pipelines and virtual commands\nawait $`seq 1 5 | cat > numbers.txt`;\nawait $`basename /path/to/file.txt .txt`; // → \"file\"\n```\n\n## Installation\n\n```bash\n# Using npm\nnpm install command-stream\n\n# Using bun\nbun add command-stream\n```\n\n## Smart Quoting & Security\n\nCommand-stream provides intelligent auto-quoting to protect against shell injection while avoiding unnecessary quotes for safe strings:\n\n### Smart Quoting Behavior\n\n```javascript\nimport { $ } from 'command-stream';\n\n// Safe strings are NOT quoted (performance optimization)\nawait $`echo ${name}`; // name = \"hello\" → echo hello\nawait $`${cmd} --version`; // cmd = \"/usr/bin/node\" → /usr/bin/node --version\n\n// Dangerous strings are automatically quoted for safety\nawait $`echo ${userInput}`; // userInput = \"test; rm -rf /\" → echo 'test; rm -rf /'\nawait $`echo ${pathWithSpaces}`; // pathWithSpaces = \"/my path/file\" → echo '/my path/file'\n\n// Special characters that trigger auto-quoting:\n// Spaces, $, ;, |, &, >, <, `, *, ?, [, ], {, }, (, ), !, #, and others\n\n// User-provided quotes are preserved\nconst quotedPath = \"'/path with spaces/file'\";\nawait $`cat ${quotedPath}`; // → cat '/path with spaces/file' (no double-quoting!)\n\nconst doubleQuoted = '\"/path with spaces/file\"';\nawait $`cat ${doubleQuoted}`; // → cat '\"/path with spaces/file\"' (preserves intent)\n```\n\n### Shell Injection Protection\n\nAll interpolated values are automatically secured:\n\n```javascript\n// ✅ SAFE - All these injection attempts are neutralized\nconst dangerous = \"'; rm -rf /; echo '\";\nawait $`echo ${dangerous}`; // → echo ''\\'' rm -rf /; echo '\\'''\n\nconst cmdSubstitution = '$(whoami)';\nawait $`echo ${cmdSubstitution}`; // → echo '$(whoami)' (literal text, not executed)\n\nconst varExpansion = '$HOME';\nawait $`echo ${varExpansion}`; // → echo '$HOME' (literal text, not expanded)\n\n// ✅ SAFE - Even complex injection attempts\nconst complex = '`cat /etc/passwd`';\nawait $`echo ${complex}`; // → echo '`cat /etc/passwd`' (literal text)\n```\n\n### Disabling Auto-Escape (Advanced)\n\n**⚠️ WARNING: Use with extreme caution! Only use `raw()` with trusted input to prevent shell injection attacks.**\n\nFor advanced use cases where you need to use command strings directly without auto-escaping, use the `raw()` function:\n\n```javascript\nimport { $, raw } from 'command-stream';\n\n// ⚠️ DANGEROUS - Bypasses all safety checks\nconst userCommand = 'echo \"hello\" && ls -la';\nawait $`${raw(userCommand)}`; // → Executes: echo \"hello\" && ls -la\n\n// ✅ Safe use case: Trusted command templates\nconst trustedCommand = 'git log --oneline --graph --all';\nawait $`${raw(trustedCommand)}`;\n\n// ✅ Combining raw with safe interpolation\nconst branch = 'main'; // User input - will be auto-quoted\nawait $`${raw('git log --oneline')} ${branch}`;\n// → git log --oneline 'main' (raw part unescaped, branch safely quoted)\n\n// 🎯 Use case: Pre-built command strings from configuration\nconst config = {\n backupCommand: 'tar -czf backup.tar.gz --exclude=\"*.log\" .',\n cleanCommand: 'find . -name \"*.tmp\" -delete',\n};\nawait $`${raw(config.backupCommand)}`;\n\n// ⚠️ NEVER use raw() with user input\nconst userInput = req.body.command; // ❌ DANGEROUS!\nawait $`${raw(userInput)}`; // ❌ Shell injection vulnerability!\n\n// ✅ Instead, use normal interpolation for user input\nawait $`echo ${userInput}`; // ✅ Safe - auto-escaped\n```\n\n**When to use `raw()`:**\n\n- ✅ Trusted command templates from your codebase\n- ✅ Configuration files you control\n- ✅ Hardcoded command strings\n- ✅ Complex shell operators that need to be preserved\n\n**When NOT to use `raw()`:**\n\n- ❌ User input (form fields, API parameters, CLI arguments)\n- ❌ External data (database, API responses, files)\n- ❌ Any untrusted source\n- ❌ When you're unsure - use normal interpolation instead\n\n## Usage Patterns\n\n### Classic Await (Backward Compatible)\n\n```javascript\nimport { $ } from 'command-stream';\n\nconst result = await $`ls -la`;\nconsole.log(result.stdout);\nconsole.log(result.code); // exit code\n```\n\n### Custom Options with $({ options }) Syntax (NEW!)\n\n```javascript\nimport { $ } from 'command-stream';\n\n// Create a $ with custom options\nconst $silent = $({ mirror: false, capture: true });\nconst result = await $silent`echo \"quiet operation\"`;\n\n// Options for stdin handling\nconst $withInput = $({ stdin: 'input data\\n' });\nawait $withInput`cat`; // Pipes the input to cat\n\n// Custom environment variables\nconst $withEnv = $({ env: { ...process.env, MY_VAR: 'value' } });\nawait $withEnv`printenv MY_VAR`; // Prints: value\n\n// Custom working directory\nconst $inTmp = $({ cwd: '/tmp' });\nawait $inTmp`pwd`; // Prints: /tmp\n\n// Interactive mode for TTY commands (requires TTY environment)\nconst $interactive = $({ interactive: true });\nawait $interactive`vim myfile.txt`; // Full TTY access for editor\nawait $interactive`less README.md`; // Proper pager interaction\n\n// Combine multiple options\nconst $custom = $({\n stdin: 'test data',\n mirror: false,\n capture: true,\n cwd: '/tmp',\n});\nawait $custom`cat > output.txt`; // Writes to /tmp/output.txt silently\n\n// Reusable configurations\nconst $prod = $({ env: { NODE_ENV: 'production' }, capture: true });\nawait $prod`npm start`;\nawait $prod`npm test`;\n```\n\n### Execution Control (NEW!)\n\n```javascript\nimport { $ } from 'command-stream';\n\n// Commands don't auto-start when created\nconst cmd = $`echo \"hello\"`;\n\n// Three ways to start execution:\n\n// 1. Explicit start with options\ncmd.start(); // Default async mode\ncmd.start({ mode: 'async' }); // Explicitly async\ncmd.start({ mode: 'sync' }); // Synchronous execution\n\n// 2. Convenience methods\ncmd.async(); // Same as start({ mode: 'async' })\ncmd.sync(); // Same as start({ mode: 'sync' })\n\n// 3. Auto-start by awaiting (always async)\nawait cmd; // Auto-starts in async mode\n\n// Event handlers can be attached before starting\nconst process = $`long-command`\n .on('data', (chunk) => console.log('Received:', chunk))\n .on('end', (result) => console.log('Done!'));\n\n// Start whenever you're ready\nprocess.start();\n```\n\n### Synchronous Execution\n\n```javascript\nimport { $ } from 'command-stream';\n\n// Use .sync() for blocking execution\nconst result = $`echo \"hello\"`.sync();\nconsole.log(result.stdout); // \"hello\\n\"\n\n// Events still work but are batched after completion\n$`echo \"world\"`.on('end', (result) => console.log('Done:', result)).sync();\n```\n\n### Async Iteration (Real-time Streaming)\n\n```javascript\nimport { $ } from 'command-stream';\n\nfor await (const chunk of $`long-running-command`.stream()) {\n if (chunk.type === 'stdout') {\n console.log('Real-time output:', chunk.data.toString());\n }\n}\n```\n\n### EventEmitter Pattern (Event-driven)\n\n```javascript\nimport { $ } from 'command-stream';\n\n// Attach event handlers then start execution\n$`command`\n .on('data', (chunk) => {\n if (chunk.type === 'stdout') {\n console.log('Stdout:', chunk.data.toString());\n }\n })\n .on('stderr', (chunk) => console.log('Stderr:', chunk))\n .on('end', (result) => console.log('Done:', result))\n .on('exit', (code) => console.log('Exit code:', code))\n .start(); // Explicitly start the command\n\n// Or auto-start by awaiting\nconst cmd = $`another-command`.on('data', (chunk) => console.log(chunk));\nawait cmd; // Auto-starts in async mode\n```\n\n### Mixed Pattern (Best of Both Worlds)\n\n```javascript\nimport { $ } from 'command-stream';\n\n// Async mode - events fire in real-time\nconst process = $`streaming-command`;\nprocess.on('data', (chunk) => {\n processRealTimeData(chunk);\n});\nconst result = await process;\nconsole.log('Final output:', result.stdout);\n\n// Sync mode - events fire after completion (batched)\nconst syncCmd = $`another-command`;\nsyncCmd.on('end', (result) => {\n console.log('Completed with:', result.stdout);\n});\nconst syncResult = syncCmd.sync();\n```\n\n### Streaming Interfaces\n\nAdvanced streaming interfaces for fine-grained process control:\n\n```javascript\nimport { $ } from 'command-stream';\n\n// 🎯 STDIN CONTROL: Send data to interactive commands (real-time)\nconst grepCmd = $`grep \"important\"`;\nconst stdin = await grepCmd.streams.stdin; // Available immediately\n\nstdin.write('ignore this line\\n');\nstdin.write('important message\\n');\nstdin.write('skip this too\\n');\nstdin.end();\n\nconst result = await grepCmd;\nconsole.log(result.stdout); // \"important message\\n\"\n\n// 🔧 BINARY DATA: Access raw buffers (after command finishes)\nconst cmd = $`echo \"Hello World\"`;\nconst buffer = await cmd.buffers.stdout; // Complete snapshot\nconsole.log(buffer.length); // 12\n\n// 📝 TEXT DATA: Access as strings (after command finishes)\nconst textCmd = $`echo \"Hello World\"`;\nconst text = await textCmd.strings.stdout; // Complete snapshot\nconsole.log(text.trim()); // \"Hello World\"\n\n// ⚡ PROCESS CONTROL: Kill commands that ignore stdin\nconst pingCmd = $`ping google.com`;\n\n// Some commands ignore stdin input\nconst pingStdin = await pingCmd.streams.stdin;\nif (pingStdin) {\n pingStdin.write('q\\n'); // ping ignores this\n}\n\n// Use kill() for forceful termination\nsetTimeout(() => pingCmd.kill(), 2000);\nconst pingResult = await pingCmd;\nconsole.log('Ping stopped with code:', pingResult.code); // 143 (SIGTERM)\n\n// 🔄 MIXED STDOUT/STDERR: Handle both streams (complete snapshots)\nconst mixedCmd = $`sh -c 'echo \"out\" && echo \"err\" >&2'`;\nconst [stdout, stderr] = await Promise.all([\n mixedCmd.strings.stdout, // Available after finish\n mixedCmd.strings.stderr, // Available after finish\n]);\nconsole.log('Out:', stdout.trim()); // \"out\"\nconsole.log('Err:', stderr.trim()); // \"err\"\n\n// 🏃‍♂️ AUTO-START: Streams auto-start processes when accessed\nconst cmd = $`echo \"test\"`;\nconsole.log('Started?', cmd.started); // false\n\nconst output = await cmd.streams.stdout; // Auto-starts, immediate access\nconsole.log('Started?', cmd.started); // true\n\n// 🔙 BACKWARD COMPATIBLE: Traditional await still works\nconst traditional = await $`echo \"still works\"`;\nconsole.log(traditional.stdout); // \"still works\\n\"\n```\n\n**Key Features:**\n\n- `command.streams.stdin/stdout/stderr` - Direct access to Node.js streams\n- `command.buffers.stdin/stdout/stderr` - Binary data as Buffer objects\n- `command.strings.stdin/stdout/stderr` - Text data as strings\n- `command.kill()` - Forceful process termination\n- **Auto-start behavior:** Process starts only when accessing stream properties\n- **Perfect for:** Interactive commands (grep, sort, bc), data processing, real-time control\n- **Network commands (ping, wget) ignore stdin** → Use `kill()` method instead\n\n**🚀 Streams vs Buffers/Strings:**\n\n- **`streams.*`** - Available **immediately** when command starts, for real-time interaction\n- **`buffers.*` & `strings.*`** - Complete **snapshots** available only **after** command finishes\n\n### Shell Replacement (.sh → .mjs)\n\nReplace bash scripts with JavaScript while keeping shell semantics:\n\n```javascript\nimport { $, shell, set, unset } from 'command-stream';\n\n// set -e equivalent: exit on any error\nshell.errexit(true);\n\nawait $`mkdir -p build`;\nawait $`npm run build`;\n\n// set +e equivalent: allow errors (like bash)\nshell.errexit(false);\nconst cleanup = await $`rm -rf temp`; // Won't throw if fails\n\n// set -e again for critical operations\nshell.errexit(true);\nawait $`cp -r build/* deploy/`;\n\n// Other bash-like settings\nshell.verbose(true); // set -v: print commands\nshell.xtrace(true); // set -x: trace execution\n\n// Or use the bash-style API\nset('e'); // set -e\nunset('e'); // set +e\nset('x'); // set -x\nset('verbose'); // Long form also supported\n```\n\n### Cross-Platform File Operations (Built-in Commands)\n\nReplace system-dependent operations with built-in commands that work identically everywhere:\n\n```javascript\nimport { $ } from 'command-stream';\n\n// File system operations work on Windows, macOS, and Linux identically\nawait $`mkdir -p project/src project/tests`;\nawait $`touch project/src/index.js project/tests/test.js`;\n\n// List files with details\nconst files = await $`ls -la project/src`;\nconsole.log(files.stdout);\n\n// Copy and move operations\nawait $`cp project/src/index.js project/src/backup.js`;\nawait $`mv project/src/backup.js project/backup.js`;\n\n// File content operations\nawait $`echo \"export default 'Hello World';\" > project/src/index.js`;\nconst content = await $`cat project/src/index.js`;\nconsole.log(content.stdout);\n\n// Path operations\nconst filename = await $`basename project/src/index.js .js`; // → \"index\"\nconst directory = await $`dirname project/src/index.js`; // → \"project/src\"\n\n// Generate sequences and process them\nawait $`seq 1 10 | cat > numbers.txt`;\nconst numbers = await $`cat numbers.txt`;\n\n// Cleanup\nawait $`rm -r project numbers.txt`;\n```\n\n### Virtual Commands (Extensible Shell)\n\nCreate custom commands that work seamlessly alongside built-ins:\n\n```javascript\nimport { $, register, unregister, listCommands } from 'command-stream';\n\n// Register a custom command\nregister('greet', async ({ args, stdin }) => {\n const name = args[0] || 'World';\n return { stdout: `Hello, ${name}!\\n`, code: 0 };\n});\n\n// Use it like any other command\nawait $`greet Alice`; // → \"Hello, Alice!\"\nawait $`echo \"Bob\" | greet`; // → \"Hello, Bob!\"\n\n// Streaming virtual commands with async generators\nregister('countdown', async function* ({ args }) {\n const start = parseInt(args[0] || 5);\n for (let i = start; i >= 0; i--) {\n yield `${i}\\n`;\n await new Promise((r) => setTimeout(r, 1000));\n }\n});\n\n// Use in pipelines with built-ins\nawait $`countdown 3 | cat > countdown.txt`;\n\n// Virtual commands work in all patterns\nfor await (const chunk of $`countdown 3`.stream()) {\n console.log('Countdown:', chunk.data.toString().trim());\n}\n\n// Management functions\nconsole.log(listCommands()); // List all registered commands\nunregister('greet'); // Remove custom commands\n```\n\n#### 🔥 **Why Virtual Commands Are Revolutionary**\n\n**No other shell library offers this level of extensibility:**\n\n- **🚫 Bun.$**: Fixed set of built-in commands, no extensibility API\n- **🚫 execa**: Transform/pipeline system, but no custom commands\n- **🚫 zx**: JavaScript functions only, no shell command integration\n\n**command-stream breaks the barrier** between JavaScript functions and shell commands:\n\n```javascript\n// ❌ Other libraries: Choose JavaScript OR shell\nawait execa('node', ['script.js']); // execa: separate processes\nawait $`node script.js`; // zx: shell commands only\n\n// ✅ command-stream: JavaScript functions AS shell commands\nregister('deploy', async ({ args }) => {\n const env = args[0] || 'staging';\n await deployToEnvironment(env);\n return { stdout: `Deployed to ${env}!\\n`, code: 0 };\n});\n\nawait $`deploy production`; // JavaScript function as shell command!\nawait $`deploy staging | tee log.txt`; // Works in pipelines!\n```\n\n**Unique capabilities:**\n\n- **Seamless Integration**: Virtual commands work exactly like built-ins\n- **Pipeline Support**: Full stdin/stdout passing between virtual and system commands\n- **Streaming**: Async generators for real-time output\n- **Dynamic Registration**: Add/remove commands at runtime\n- **Option Awareness**: Virtual commands respect `cwd`, `env`, etc.\n\n### 🔗 **Advanced Pipeline Support**\n\n**command-stream offers the most advanced piping system in the JavaScript ecosystem:**\n\n#### **Shell-Style Piping (Traditional)**\n\n```javascript\nimport { $, register } from 'command-stream';\n\n// ✅ Standard shell piping (like all libraries)\nawait $`echo \"hello world\" | wc -w`; // → \"2\"\n\n// ✅ Built-in to built-in piping\nawait $`seq 1 5 | cat > numbers.txt`;\n\n// ✅ System to built-in piping\nawait $`git log --oneline | head -n 5`;\n\n// 🚀 UNIQUE: Virtual command piping\nregister('uppercase', async ({ args, stdin }) => {\n return { stdout: stdin.toUpperCase(), code: 0 };\n});\n\nregister('reverse', async ({ args, stdin }) => {\n return { stdout: stdin.split('').reverse().join(''), code: 0 };\n});\n\n// ✅ Built-in to virtual piping\nawait $`echo \"hello\" | uppercase`; // → \"HELLO\"\n\n// ✅ Virtual to virtual piping\nawait $`echo \"hello\" | uppercase | reverse`; // → \"OLLEH\"\n\n// ✅ Mixed pipelines (system + built-in + virtual)\nawait $`git log --oneline | head -n 3 | uppercase | cat > LOG.txt`;\n\n// ✅ Complex multi-stage pipelines\nawait $`find . -name \"*.js\" | head -n 10 | basename | sort | uniq`;\n```\n\n#### **🚀 Programmatic .pipe() Method (NEW!)**\n\n**World's first shell library with full `.pipe()` method support for virtual commands:**\n\n```javascript\nimport { $, register } from 'command-stream';\n\n// ✅ Basic programmatic piping\nconst result = await $`echo \"hello\"`.pipe($`echo \"World: $(cat)\"`);\n\n// 🌟 Virtual command chaining\nregister('add-prefix', async ({ args, stdin }) => {\n const prefix = args[0] || 'PREFIX:';\n return { stdout: `${prefix} ${stdin.trim()}\\n`, code: 0 };\n});\n\nregister('add-suffix', async ({ args, stdin }) => {\n const suffix = args[0] || 'SUFFIX';\n return { stdout: `${stdin.trim()} ${suffix}\\n`, code: 0 };\n});\n\n// ✅ Chain virtual commands with .pipe()\nconst result = await $`echo \"Hello\"`\n .pipe($`add-prefix \"[PROCESSED]\"`)\n .pipe($`add-suffix \"!!!\"`);\n// → \"[PROCESSED] Hello !!!\"\n\n// ✅ Mix with built-in commands\nconst fileData = await $`cat large-file.txt`\n .pipe($`head -n 100`)\n .pipe($`add-prefix \"Line:\"`);\n\n// ✅ Error handling in pipelines\ntry {\n const result = await $`cat nonexistent.txt`.pipe($`add-prefix \"Data:\"`);\n} catch (error) {\n // Source error propagates - destination never executes\n console.log('File not found, pipeline stopped');\n}\n\n// ✅ Complex data processing\nregister('json-parse', async ({ args, stdin }) => {\n try {\n const data = JSON.parse(stdin);\n return { stdout: JSON.stringify(data, null, 2), code: 0 };\n } catch (error) {\n return { stdout: '', stderr: `JSON Error: ${error.message}`, code: 1 };\n }\n});\n\nregister('extract-field', async ({ args, stdin }) => {\n const field = args[0];\n try {\n const data = JSON.parse(stdin);\n const value = data[field] || 'null';\n return { stdout: `${value}\\n`, code: 0 };\n } catch (error) {\n return { stdout: '', stderr: `Extract Error: ${error.message}`, code: 1 };\n }\n});\n\n// Real-world API processing pipeline\nconst userName = await $`curl -s https://api.github.com/users/octocat`\n .pipe($`json-parse`)\n .pipe($`extract-field name`);\n// → \"The Octocat\"\n\n// Cleanup\nunregister('add-prefix');\nunregister('add-suffix');\nunregister('json-parse');\nunregister('extract-field');\n```\n\n#### **🆚 How We Compare**\n\n| Library | Pipeline Types | Custom Commands in Pipes | `.pipe()` Method | Real-time Streaming |\n| ------------------ | --------------------------------------- | ------------------------ | ----------------------------------- | ------------------- |\n| **command-stream** | ✅ System + Built-ins + Virtual + Mixed | ✅ **Full support** | ✅ **Full virtual command support** | ✅ **Yes** |\n| **Bun.$** | ✅ System + Built-ins | ❌ No custom commands | ❌ No `.pipe()` method | ❌ No |\n| **execa** | ✅ Programmatic `.pipe()` | ❌ No shell integration | ✅ Basic process piping | 🟡 Limited |\n| **zx** | ✅ Shell piping + `.pipe()` | ❌ No custom commands | ✅ Stream piping only | ❌ No |\n\n**🎯 Unique Advantages:**\n\n- **Virtual commands work seamlessly in both shell pipes AND `.pipe()` method** - no other library can do this\n- **Mixed pipeline types** - combine system, built-in, and virtual commands freely in both syntaxes\n- **Real-time streaming** through virtual command pipelines\n- **Full stdin/stdout passing** between all command types\n- **Dual piping syntax** - use shell `|` OR programmatic `.pipe()` interchangeably\n\n## Default Behavior: Shell-like with Programmatic Control\n\n**command-stream behaves exactly like running commands in your shell by default:**\n\n```javascript\nimport { $ } from 'command-stream';\n\n// This command will:\n// 1. Print \"Hello\" to your terminal (stdout→stdout)\n// 2. Print \"Error!\" to your terminal (stderr→stderr)\n// 3. Capture both outputs for programmatic access\nconst result = await $`sh -c \"echo 'Hello'; echo 'Error!' >&2\"`;\n\nconsole.log('Captured stdout:', result.stdout); // \"Hello\\n\"\nconsole.log('Captured stderr:', result.stderr); // \"Error!\\n\"\nconsole.log('Exit code:', result.code); // 0\n```\n\n**Key Default Options:**\n\n- `mirror: true` - Live output to terminal (like shell)\n- `capture: true` - Capture output for later use (unlike shell)\n- `stdin: 'inherit'` - Inherit stdin from parent process\n\n**Fully Controllable:**\n\n```javascript\nimport { $, create, sh } from 'command-stream';\n\n// Disable terminal output but still capture\nconst result = await sh('echo \"silent\"', { mirror: false });\n\n// Custom stdin input\nconst custom = await sh('cat', { stdin: 'custom input' });\n\n// Create custom $ with different defaults\nconst quiet$ = create({ mirror: false });\nawait quiet$`echo \"silent\"`; // Won't print to terminal\n\n// Disable both mirroring and capturing for performance\nawait sh('make build', { mirror: false, capture: false });\n```\n\n**This gives you the best of both worlds:** shell-like behavior by default, but with full programmatic control and real-time streaming capabilities.\n\n## Real-world Examples\n\n### Log File Streaming with Session ID Extraction\n\n```javascript\nimport { $ } from 'command-stream';\nimport { appendFileSync, writeFileSync } from 'fs';\n\nlet sessionId = null;\nlet logFile = null;\n\nfor await (const chunk of $`your-streaming-command`.stream()) {\n if (chunk.type === 'stdout') {\n const data = chunk.data.toString();\n\n // Extract session ID from output\n if (!sessionId && data.includes('session_id')) {\n try {\n const parsed = JSON.parse(data);\n sessionId = parsed.session_id;\n logFile = `${sessionId}.log`;\n console.log(`Session ID: ${sessionId}`);\n } catch (e) {\n // Handle JSON parse errors\n }\n }\n\n // Write to log file in real-time\n if (logFile) {\n appendFileSync(logFile, data);\n }\n }\n}\n```\n\n### Progress Monitoring\n\n```javascript\nimport { $ } from 'command-stream';\n\nlet progress = 0;\n\n$`download-large-file`\n .on('stdout', (chunk) => {\n const output = chunk.toString();\n if (output.includes('Progress:')) {\n progress = parseProgress(output);\n updateProgressBar(progress);\n }\n })\n .on('end', (result) => {\n console.log('Download completed!');\n });\n```\n\n## API Reference\n\n### ProcessRunner Class\n\nThe enhanced `$` function returns a `ProcessRunner` instance that extends `EventEmitter`.\n\n#### Events\n\n- `data`: Emitted for each chunk with `{type: 'stdout'|'stderr', data: Buffer}`\n- `stdout`: Emitted for stdout chunks (Buffer)\n- `stderr`: Emitted for stderr chunks (Buffer)\n- `end`: Emitted when process completes with final result object\n- `exit`: Emitted with exit code\n\n#### Methods\n\n- `start(options)`: Explicitly start command execution\n - `options.mode`: `'async'` (default) or `'sync'` - execution mode\n- `async()`: Shortcut for `start({ mode: 'async' })` - start async execution\n- `sync()`: Shortcut for `start({ mode: 'sync' })` - execute synchronously (blocks until completion)\n- `stream()`: Returns an async iterator for real-time chunk processing\n- `pipe(destination)`: Programmatically pipe output to another command (returns new ProcessRunner)\n- `then()`, `catch()`, `finally()`: Promise interface for await support (auto-starts in async mode)\n\n#### Properties\n\n- `stdout`: Direct access to child process stdout stream\n- `stderr`: Direct access to child process stderr stream\n- `stdin`: Direct access to child process stdin stream\n\n### Default Options\n\n**By default, command-stream behaves like running commands in the shell:**\n\n```javascript\n{\n mirror: true, // Live output to terminal (stdout→stdout, stderr→stderr)\n capture: true, // Capture output for programmatic access\n stdin: 'inherit', // Inherit stdin from parent process\n interactive: false // Explicitly request TTY forwarding for interactive commands\n}\n```\n\n**Option Details:**\n\n- `mirror: boolean` - Whether to pipe output to terminal in real-time\n- `capture: boolean` - Whether to capture output in result object\n- `stdin: 'inherit' | 'ignore' | string | Buffer` - How to handle stdin\n- `interactive: boolean` - Enable TTY forwarding for interactive commands (requires `stdin: 'inherit'` and TTY environment)\n- `cwd: string` - Working directory for command\n- `env: object` - Environment variables\n\n**Override defaults:**\n\n- Use `$({ options })` syntax for one-off configurations with template literals\n- Use `sh(command, options)` for one-off overrides with string commands\n- Use `create(defaultOptions)` to create custom `$` with different defaults\n\n### Shell Settings API\n\nControl shell behavior like bash `set`/`unset` commands:\n\n#### Functions\n\n- `shell.errexit(boolean)`: Enable/disable exit-on-error (like `set ±e`)\n- `shell.verbose(boolean)`: Enable/disable command printing (like `set ±v`)\n- `shell.xtrace(boolean)`: Enable/disable execution tracing (like `set ±x`)\n- `set(option)`: Enable shell option (`'e'`, `'v'`, `'x'`, or long names)\n- `unset(option)`: Disable shell option\n- `shell.settings()`: Get current settings object\n\n#### Error Handling Modes\n\n```javascript\nimport { $, shell } from 'command-stream';\n\n// ✅ Default behavior: Commands don't throw on non-zero exit\nconst result = await $`ls nonexistent-file`; // Won't throw\nconsole.log(result.code); // → 2 (non-zero, but no exception)\n\n// ✅ Enable errexit: Commands throw on non-zero exit\nshell.errexit(true);\ntry {\n await $`ls nonexistent-file`; // Throws error\n} catch (error) {\n console.log('Command failed:', error.code); // → 2\n}\n\n// ✅ Disable errexit: Back to non-throwing behavior\nshell.errexit(false);\nawait $`ls nonexistent-file`; // Won't throw, returns result with code 2\n\n// ✅ One-time override without changing global settings\ntry {\n const result = await $`ls nonexistent-file`;\n if (result.code !== 0) {\n throw new Error(`Command failed with code ${result.code}`);\n }\n} catch (error) {\n console.log('Manual error handling');\n}\n```\n\n### Virtual Commands API\n\nControl and extend the command system with custom JavaScript functions:\n\n#### Functions\n\n- `register(name, handler)`: Register a virtual command\n - `name`: Command name (string)\n - `handler`: Function or async generator `(args, stdin, options) => result`\n- `unregister(name)`: Remove a virtual command\n- `listCommands()`: Get array of all registered command names\n- `enableVirtualCommands()`: Enable virtual command processing\n- `disableVirtualCommands()`: Disable virtual commands (use system commands only)\n\n#### Advanced Virtual Command Features\n\n```javascript\nimport { $, register } from 'command-stream';\n\n// ✅ Cancellation support with AbortController\nregister('cancellable', async function* ({ args, stdin, abortSignal }) {\n for (let i = 0; i < 10; i++) {\n if (abortSignal?.aborted) {\n break; // Proper cancellation handling\n }\n yield `Count: ${i}\\n`;\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n});\n\n// ✅ Access to all process options\n// All original options (built-in + custom) are available in the 'options' object\n// Common options like cwd, env are also available at top level for convenience\n// Runtime additions: isCancelled function, abortSignal\nregister(\n 'debug-info',\n async ({ args, stdin, cwd, env, options, isCancelled }) => {\n return {\n stdout: JSON.stringify(\n {\n args,\n cwd, // Available at top level for convenience\n env: Object.keys(env || {}), // Available at top level for convenience\n stdinLength: stdin?.length || 0,\n allOptions: options, // All original options (built-in + custom)\n mirror: options.mirror, // Built-in option from options object\n capture: options.capture, // Built-in option from options object\n customOption: options.customOption || 'not provided', // Custom option\n isCancelledAvailable: typeof isCancelled === 'function',\n },\n null,\n 2\n ),\n code: 0,\n };\n }\n);\n\n// ✅ Error handling and non-zero exit codes\nregister('maybe-fail', async ({ args }) => {\n if (Math.random() > 0.5) {\n return {\n stdout: 'Success!\\n',\n code: 0,\n };\n } else {\n return {\n stdout: '',\n stderr: 'Random failure occurred\\n',\n code: 1,\n };\n }\n});\n\n// ✅ Example: User options flow through to virtual commands\nregister('show-options', async ({ args, stdin, options, cwd }) => {\n return {\n stdout: `Custom: ${options.customValue || 'none'}, CWD: ${cwd || options.cwd || 'default'}\\n`,\n code: 0,\n };\n});\n\n// Usage example showing options passed to virtual command:\nconst result = await $({\n customValue: 'hello world',\n cwd: '/tmp',\n})`show-options`;\nconsole.log(result.stdout); // Output: Custom: hello world, CWD: /tmp\n```\n\n#### Handler Function Signature\n\n```javascript\n// Regular async function\nasync function handler({ args, stdin, abortSignal, cwd, env, options, isCancelled }) {\n // All original options available in 'options': options.mirror, options.capture, options.customValue, etc.\n // Common options like cwd, env also available at top level for convenience\n return {\n code: 0, // Exit code (number)\n stdout: \"output\", // Standard output (string)\n stderr: \"\", // Standard error (string)\n };\n}\n\n// Async generator for streaming\nasync function streamingHandler({ args, stdin, abortSignal, cwd, env, options, isCancelled }) {\n // Access both built-in and custom options from 'options' object\n if (options.customFlag) {\n yield \"custom behavior\\n\";\n }\n yield \"chunk1\\n\";\n yield \"chunk2\\n\";\n}\n```\n\n### Utility Functions API\n\nControl how values are interpolated into commands:\n\n#### Functions\n\n- `quote(value)`: Manually quote a value using the same smart quoting logic as auto-interpolation\n- `raw(value)`: **⚠️ Dangerous!** Bypass auto-escaping to use command strings directly (see [Disabling Auto-Escape](#disabling-auto-escape-advanced))\n\n#### quote() - Manual Quoting\n\nApply the same smart quoting logic manually:\n\n```javascript\nimport { $, quote } from 'command-stream';\n\nconst path = '/path with spaces/file.txt';\nconst quoted = quote(path);\nconsole.log(quoted); // → '/path with spaces/file.txt'\n\n// Use case: Pre-process values before interpolation\nconst args = ['hello world', 'test'].map(quote);\n// → [\"'hello world'\", 'test']\n```\n\n#### raw() - Disable Auto-Escape\n\n**⚠️ WARNING: Only use with trusted input!** See [Disabling Auto-Escape](#disabling-auto-escape-advanced) section for detailed documentation and security considerations.\n\n```javascript\nimport { $, raw } from 'command-stream';\n\n// Bypass auto-escaping for trusted command strings\nconst trustedCommand = 'echo \"hello\" && ls -la';\nawait $`${raw(trustedCommand)}`;\n// → Executes: echo \"hello\" && ls -la (without escaping)\n\n// ⚠️ NEVER use with untrusted input - shell injection risk!\n```\n\n### Built-in Commands\n\n18 cross-platform commands that work identically everywhere:\n\n**File System**: `cat`, `ls`, `mkdir`, `rm`, `mv`, `cp`, `touch` \n**Utilities**: `basename`, `dirname`, `seq`, `yes` \n**System**: `cd`, `pwd`, `echo`, `sleep`, `true`, `false`, `which`, `exit`, `env`, `test`\n\nAll built-in commands support:\n\n- Standard flags (e.g., `ls -la`, `mkdir -p`, `rm -rf`)\n- Pipeline operations\n- Option awareness (`cwd`, `env`, etc.)\n- Bash-compatible error messages and exit codes\n\n#### Supported Options\n\n- `'e'` / `'errexit'`: Exit on command failure\n- `'v'` / `'verbose'`: Print commands before execution\n- `'x'` / `'xtrace'`: Trace command execution with `+` prefix\n- `'u'` / `'nounset'`: Error on undefined variables (planned)\n- `'pipefail'`: Pipe failure detection (planned)\n\n### Result Object\n\n```javascript\n{\n code: number, // Exit code\n stdout: string, // Complete stdout output\n stderr: string, // Complete stderr output\n stdin: string, // Input sent to process\n child: ChildProcess, // Original child process object\n async text() // Bun.$ compatibility method - returns stdout as string\n}\n```\n\n#### `.text()` Method (Bun.$ Compatibility)\n\nFor compatibility with Bun.$, all result objects include an async `.text()` method:\n\n```javascript\nimport { $ } from 'command-stream';\n\n// Both sync and async execution support .text()\nconst result1 = await $`echo \"hello world\"`;\nconst text1 = await result1.text(); // \"hello world\\n\"\n\nconst result2 = $`echo \"sync example\"`.sync();\nconst text2 = await result2.text(); // \"sync example\\n\"\n\n// .text() is equivalent to accessing .stdout\nexpect(await result.text()).toBe(result.stdout);\n\n// Works with built-in commands\nconst result3 = await $`seq 1 3`;\nconst text3 = await result3.text(); // \"1\\n2\\n3\\n\"\n\n// Works with .pipe() method\nconst result4 = await $`echo \"pipe test\"`.pipe($`cat`);\nconst text4 = await result4.text(); // \"pipe test\\n\"\n```\n\n## Signal Handling (CTRL+C Support)\n\nThe library provides **advanced CTRL+C handling** that properly manages signals across different scenarios:\n\n### How It Works\n\n1. **Smart Signal Forwarding**: CTRL+C is forwarded **only when child processes are active**\n2. **User Handler Preservation**: When no children are running, your custom SIGINT handlers work normally\n3. **Process Groups**: Child processes use detached spawning for proper signal isolation\n4. **TTY Mode Support**: Raw TTY mode is properly managed and restored on interruption\n5. **Graceful Termination**: Uses SIGTERM → SIGKILL escalation for robust process cleanup\n6. **Exit Code Standards**: Proper signal exit codes (130 for SIGINT, 143 for SIGTERM)\n\n### Advanced Signal Behavior\n\n```javascript\n// ✅ Smart signal handling - only interferes when necessary\nimport { $ } from 'command-stream';\n\n// Case 1: No children active - your handlers work normally\nprocess.on('SIGINT', () => {\n console.log('My custom handler runs!');\n process.exit(42); // Custom exit code\n});\n// Press CTRL+C → Your handler runs, exits with code 42\n\n// Case 2: Children active - automatic forwarding\nawait $`ping 8.8.8.8`; // Press CTRL+C → Forwards to ping, exits with code 130\n\n// Case 3: Multiple processes - all interrupted\nawait Promise.all([$`sleep 100`, $`ping google.com`]); // Press CTRL+C → All processes terminated, exits with code 130\n```\n\n### Examples\n\n```javascript\n// Long-running command that can be interrupted with CTRL+C\ntry {\n await $`ping 8.8.8.8`; // Press CTRL+C to stop\n} catch (error) {\n console.log('Command interrupted:', error.code); // Exit code 130 (SIGINT)\n}\n\n// Multiple concurrent processes - CTRL+C stops all\ntry {\n await Promise.all([\n $`sleep 100`,\n $`ping google.com`,\n $`tail -f /var/log/system.log`,\n ]);\n} catch (error) {\n // All processes are terminated when you press CTRL+C\n}\n\n// Works with streaming patterns too\ntry {\n for await (const chunk of $`ping 8.8.8.8`.stream()) {\n console.log(chunk);\n // Press CTRL+C to break the loop and stop the process\n }\n} catch (error) {\n console.log('Streaming interrupted');\n}\n```\n\n### Signal Handling Behavior\n\n- **🎯 Smart Detection**: Only forwards CTRL+C when child processes are active\n- **🛡️ Non-Interference**: Preserves user SIGINT handlers when no children running\n- **⚡ Interactive Commands**: Use `interactive: true` option for commands like `vim`, `less`, `top` to enable proper TTY forwarding and signal handling\n- **🔄 Process Groups**: Detached spawning ensures proper signal isolation\n- **🧹 TTY Cleanup**: Raw terminal mode properly restored on interruption\n- **📊 Standard Exit Codes**:\n - `130` - SIGINT interruption (CTRL+C)\n - `143` - SIGTERM termination (programmatic kill)\n - `137` - SIGKILL force termination\n\n### Command Resolution Priority\n\n```javascript\n// Understanding how commands are resolved:\n\n// 1. Virtual Commands (highest priority)\nregister('echo', () => ({ stdout: 'virtual!\\n', code: 0 }));\nawait $`echo test`; // → \"virtual!\"\n\n// 2. Built-in Commands (if no virtual match)\nunregister('echo');\nawait $`echo test`; // → Uses built-in echo\n\n// 3. System Commands (if no built-in/virtual match)\nawait $`unknown-command`; // → Uses system PATH lookup\n\n// 4. Virtual Bypass (special case)\nawait $({ stdin: 'data' })`sleep 1`; // Bypasses virtual sleep, uses system sleep\n```\n\n## Execution Patterns Deep Dive\n\n### When to Use Different Patterns\n\n```javascript\nimport { $ } from 'command-stream';\n\n// ✅ Use await for simple command execution\nconst result = await $`ls -la`;\n\n// ✅ Use .sync() when you need blocking execution with events\nconst syncCmd = $`build-script`\n .on('stdout', (chunk) => updateProgress(chunk))\n .sync(); // Events fire after completion\n\n// ✅ Use .start() for non-blocking execution with real-time events\nconst asyncCmd = $`long-running-server`\n .on('stdout', (chunk) => logOutput(chunk))\n .start(); // Events fire in real-time\n\n// ✅ Use .stream() for processing large outputs efficiently\nfor await (const chunk of $`generate-big-file`.stream()) {\n processChunkInRealTime(chunk);\n} // Memory efficient - processes chunks as they arrive\n\n// ✅ Use EventEmitter pattern for complex workflows\n$`deployment-script`\n .on('stdout', (chunk) => {\n if (chunk.toString().includes('ERROR')) {\n handleError(chunk);\n }\n })\n .on('stderr', (chunk) => logError(chunk))\n .on('end', (result) => {\n if (result.code === 0) {\n notifySuccess();\n }\n })\n .start();\n```\n\n### Performance Considerations\n\n```javascript\n// 🚀 Memory Efficient: For large outputs, use streaming\nfor await (const chunk of $`cat huge-file.log`.stream()) {\n processChunk(chunk); // Processes incrementally\n}\n\n// 🐌 Memory Inefficient: Buffers entire output in memory\nconst result = await $`cat huge-file.log`;\nprocessFile(result.stdout); // Loads everything into memory\n\n// ⚡ Fastest: Sync execution for small, quick commands\nconst quickResult = $`pwd`.sync();\n\n// 🔄 Best for UX: Async with events for long-running commands\n$`npm install`.on('stdout', showProgress).start();\n```\n\n## Common Pitfalls\n\n### Array Argument Handling\n\nWhen passing multiple arguments, pass the array directly - **never use `.join(' ')`** before interpolation:\n\n```javascript\nimport { $ } from 'command-stream';\n\n// WRONG - entire string becomes ONE argument\nconst args = ['file.txt', '--public', '--verbose'];\nawait $`command ${args.join(' ')}`;\n// Shell receives: command 'file.txt --public --verbose' (1 argument!)\n// Error: File does not exist: \"file.txt --public --verbose\"\n\n// CORRECT - each element becomes separate argument\nawait $`command ${args}`;\n// Shell receives: command file.txt --public --verbose (3 arguments)\n```\n\nThis is a common mistake that causes errors like:\n\n```\nError: File does not exist: \"/path/to/file.txt --flag --option\"\n```\n\n### Why This Happens\n\nThe `$` template tag handles arrays specially - each element is quoted separately:\n\n```javascript\nif (Array.isArray(value)) {\n return value.map(quote).join(' '); // Each element quoted individually\n}\n```\n\nBut when you call `.join(' ')` first:\n\n1. The array becomes a string: `\"file.txt --public --verbose\"`\n2. Template receives a **string**, not an array\n3. The entire string gets quoted as one argument\n4. Command receives one argument containing spaces\n\n### Recommended Patterns\n\n```javascript\n// Pattern 1: Direct array passing\nconst args = ['file.txt', '--verbose'];\nawait $`command ${args}`;\n\n// Pattern 2: Separate interpolations\nconst file = 'file.txt';\nconst flags = ['--verbose', '--force'];\nawait $`command ${file} ${flags}`;\n\n// Pattern 3: Build array dynamically\nconst allArgs = ['input.txt'];\nif (verbose) allArgs.push('--verbose');\nawait $`command ${allArgs}`;\n```\n\nSee [js/BEST-PRACTICES.md](js/BEST-PRACTICES.md) for more detailed guidance.\n\n## Testing\n\n```bash\n# Run comprehensive test suite (518+ tests)\nbun test\n\n# Run tests with coverage report\nbun test --coverage\n\n# Run specific test categories\nnpm run test:features # Feature comparison tests\nnpm run test:builtin # Built-in commands tests\nnpm run test:pipe # .pipe() method tests\nnpm run test:sync # Synchronous execution tests\nnpm run test:signal # CTRL+C signal handling tests\n```\n\n## Requirements\n\n- **Bun**: >= 1.0.0 (primary runtime)\n- **Node.js**: >= 20.0.0 (compatibility support)\n\n## Roadmap\n\n### 🔄 **Coming Soon**\n\n- **TypeScript Support**: Full .d.ts definitions and type safety\n- **Enhanced Shell Options**: `set -u` (nounset) and `set -o pipefail` support\n- **More Built-in Commands**: Additional cross-platform utilities\n\n### 💡 **Planned Features**\n\n- **Performance Optimizations**: Further Bun runtime optimizations\n- **Advanced Error Handling**: Enhanced error context and debugging\n- **Plugin System**: Extensible architecture for custom integrations\n\n## Contributing\n\nWe welcome contributions! Since command-stream is **public domain software**, your contributions will also be released into the public domain.\n\n### 🚀 **Getting Started**\n\n```bash\ngit clone https://github.com/link-foundation/command-stream.git\ncd command-stream\nbun install\nbun test # Run the full test suite\n```\n\n### 📋 **Development Guidelines**\n\n- All features must have comprehensive tests\n- Built-in commands should match bash/sh behavior exactly\n- Maintain cross-platform compatibility (Windows, macOS, Linux)\n- Follow the existing code style and patterns\n\n### 🧪 **Running Tests**\n\n```bash\nbun test # All 518+ tests\nbun test tests/pipe.test.mjs # Specific test file\nnpm run test:builtin # Built-in commands only\n```\n\n## License - Our Biggest Advantage\n\n**The Unlicense (Public Domain)**\n\nUnlike other shell utilities that require attribution (MIT, Apache 2.0), command-stream is released into the **public domain**. This means:\n\n- ✅ **No attribution required** - Use it without crediting anyone\n- ✅ **No license files to include** - Simplify your distribution\n- ✅ **No restrictions** - Modify, sell, embed, whatever you want\n- ✅ **No legal concerns** - It's as free as code can be\n- ✅ **Corporate friendly** - No license compliance overhead\n\nThis makes command-stream ideal for:\n\n- **Commercial products** where license attribution is inconvenient\n- **Embedded systems** where every byte counts\n- **Educational materials** that can be freely shared\n- **Internal tools** without legal review requirements\n\n> \"This is free and unencumbered software released into the public domain.\"\n" + + at (/tmp/gh-issue-solver-1780922968363/js/tests/repository-layout.test.mjs:62:24) +(fail) repository language layout > keeps root README focused on shared project information [1.52ms] + + 0 pass + 4 fail + 6 expect() calls +Ran 4 tests across 1 file. [34.00ms] diff --git a/docs/case-studies/issue-160/data/rust-ai-driven-development-pipeline-template.repo.json b/docs/case-studies/issue-160/data/rust-ai-driven-development-pipeline-template.repo.json new file mode 100644 index 0000000..921afb2 --- /dev/null +++ b/docs/case-studies/issue-160/data/rust-ai-driven-development-pipeline-template.repo.json @@ -0,0 +1 @@ +{"id":1123288454,"node_id":"R_kgDOQvQFhg","name":"rust-ai-driven-development-pipeline-template","full_name":"link-foundation/rust-ai-driven-development-pipeline-template","private":false,"owner":{"login":"link-foundation","id":176174013,"node_id":"O_kgDOCoAzvQ","avatar_url":"https://avatars.githubusercontent.com/u/176174013?v=4","gravatar_id":"","url":"https://api.github.com/users/link-foundation","html_url":"https://github.com/link-foundation","followers_url":"https://api.github.com/users/link-foundation/followers","following_url":"https://api.github.com/users/link-foundation/following{/other_user}","gists_url":"https://api.github.com/users/link-foundation/gists{/gist_id}","starred_url":"https://api.github.com/users/link-foundation/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/link-foundation/subscriptions","organizations_url":"https://api.github.com/users/link-foundation/orgs","repos_url":"https://api.github.com/users/link-foundation/repos","events_url":"https://api.github.com/users/link-foundation/events{/privacy}","received_events_url":"https://api.github.com/users/link-foundation/received_events","type":"Organization","user_view_type":"public","site_admin":false},"html_url":"https://github.com/link-foundation/rust-ai-driven-development-pipeline-template","description":"A template for AI driven development pipeline for Rust","fork":false,"url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template","forks_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/forks","keys_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/keys{/key_id}","collaborators_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/teams","hooks_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/hooks","issue_events_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/issues/events{/number}","events_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/events","assignees_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/assignees{/user}","branches_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/branches{/branch}","tags_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/tags","blobs_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/git/refs{/sha}","trees_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/git/trees{/sha}","statuses_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/statuses/{sha}","languages_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/languages","stargazers_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/stargazers","contributors_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/contributors","subscribers_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/subscribers","subscription_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/subscription","commits_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/commits{/sha}","git_commits_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/git/commits{/sha}","comments_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/comments{/number}","issue_comment_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/issues/comments{/number}","contents_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/contents/{+path}","compare_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/compare/{base}...{head}","merges_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/merges","archive_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/downloads","issues_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/issues{/number}","pulls_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/pulls{/number}","milestones_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/milestones{/number}","notifications_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/labels{/name}","releases_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/releases{/id}","deployments_url":"https://api.github.com/repos/link-foundation/rust-ai-driven-development-pipeline-template/deployments","created_at":"2025-12-26T15:04:17Z","updated_at":"2026-06-04T17:37:53Z","pushed_at":"2026-06-04T17:37:50Z","git_url":"git://github.com/link-foundation/rust-ai-driven-development-pipeline-template.git","ssh_url":"git@github.com:link-foundation/rust-ai-driven-development-pipeline-template.git","clone_url":"https://github.com/link-foundation/rust-ai-driven-development-pipeline-template.git","svn_url":"https://github.com/link-foundation/rust-ai-driven-development-pipeline-template","homepage":null,"size":2632,"stargazers_count":2,"watchers_count":2,"language":"Rust","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"has_discussions":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"unlicense","name":"The Unlicense","spdx_id":"Unlicense","url":"https://api.github.com/licenses/unlicense","node_id":"MDc6TGljZW5zZTE1"},"allow_forking":true,"is_template":true,"web_commit_signoff_required":false,"has_pull_requests":true,"pull_request_creation_policy":"all","topics":[],"visibility":"public","forks":0,"open_issues":0,"watchers":2,"default_branch":"main","permissions":{"admin":true,"maintain":true,"push":true,"triage":true,"pull":true},"temp_clone_token":"","allow_squash_merge":true,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_auto_merge":false,"delete_branch_on_merge":false,"allow_update_branch":false,"use_squash_pr_title_as_default":false,"squash_merge_commit_message":"COMMIT_MESSAGES","squash_merge_commit_title":"COMMIT_OR_PR_TITLE","merge_commit_message":"PR_TITLE","merge_commit_title":"MERGE_MESSAGE","custom_properties":{},"organization":{"login":"link-foundation","id":176174013,"node_id":"O_kgDOCoAzvQ","avatar_url":"https://avatars.githubusercontent.com/u/176174013?v=4","gravatar_id":"","url":"https://api.github.com/users/link-foundation","html_url":"https://github.com/link-foundation","followers_url":"https://api.github.com/users/link-foundation/followers","following_url":"https://api.github.com/users/link-foundation/following{/other_user}","gists_url":"https://api.github.com/users/link-foundation/gists{/gist_id}","starred_url":"https://api.github.com/users/link-foundation/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/link-foundation/subscriptions","organizations_url":"https://api.github.com/users/link-foundation/orgs","repos_url":"https://api.github.com/users/link-foundation/repos","events_url":"https://api.github.com/users/link-foundation/events{/privacy}","received_events_url":"https://api.github.com/users/link-foundation/received_events","type":"Organization","user_view_type":"public","site_admin":false},"security_and_analysis":{"secret_scanning":{"status":"disabled"},"secret_scanning_push_protection":{"status":"disabled"},"dependabot_security_updates":{"status":"disabled"},"secret_scanning_non_provider_patterns":{"status":"disabled"},"secret_scanning_validity_checks":{"status":"disabled"}},"network_count":0,"subscribers_count":0} \ No newline at end of file diff --git a/docs/case-studies/issue-160/data/rust-clippy.log b/docs/case-studies/issue-160/data/rust-clippy.log new file mode 100644 index 0000000..73a7375 --- /dev/null +++ b/docs/case-studies/issue-160/data/rust-clippy.log @@ -0,0 +1,317 @@ + Compiling libc v0.2.178 + Compiling proc-macro2 v1.0.104 + Compiling unicode-ident v1.0.22 + Compiling quote v1.0.42 + Checking cfg-if v1.0.4 + Compiling parking_lot_core v0.9.12 + Checking memchr v2.7.6 + Checking scopeguard v1.2.0 + Checking smallvec v1.15.1 + Checking lock_api v0.4.14 + Checking bitflags v2.10.0 + Compiling rustix v1.1.3 + Compiling autocfg v1.5.0 + Checking pin-project-lite v0.2.16 + Checking regex-syntax v0.8.8 + Checking aho-corasick v1.1.4 + Compiling serde_core v1.0.228 + Compiling num-traits v0.2.19 + Compiling syn v2.0.111 + Checking linux-raw-sys v0.11.0 + Checking bytes v1.11.0 + Compiling zmij v1.0.2 + Compiling cfg_aliases v0.2.1 + Compiling nix v0.29.0 + Checking errno v0.3.14 + Checking parking_lot v0.12.5 + Checking signal-hook-registry v1.4.8 + Checking regex-automata v0.4.13 + Checking socket2 v0.6.1 + Checking mio v1.1.1 + Compiling serde v1.0.228 + Compiling serde_json v1.0.148 + Compiling thiserror v2.0.17 + Checking itoa v1.0.17 + Checking either v1.15.0 + Checking predicates-core v1.0.9 + Checking iana-time-zone v0.1.64 + Compiling getrandom v0.3.4 + Checking futures-core v0.3.31 + Checking env_home v0.1.0 + Checking once_cell v1.21.3 + Checking chrono v0.4.42 + Checking which v7.0.3 + Checking filetime v0.2.26 + Checking difflib v0.4.0 + Checking glob v0.3.3 + Checking termtree v0.5.1 + Checking anstyle v1.0.13 + Compiling assert_cmd v2.1.1 + Checking predicates v3.1.3 + Checking predicates-tree v1.0.12 + Checking wait-timeout v0.2.1 + Checking regex v1.12.2 + Checking bstr v1.12.1 + Checking fastrand v2.3.0 + Checking tempfile v3.24.0 + Compiling tokio-macros v2.6.0 + Compiling serde_derive v1.0.228 + Compiling thiserror-impl v2.0.17 + Compiling async-stream-impl v0.3.6 + Compiling async-trait v0.1.89 + Checking async-stream v0.3.6 + Checking tokio v1.48.0 + Checking tokio-stream v0.1.17 + Checking command-stream v0.9.5 (/tmp/gh-issue-solver-1780922968363/rust) +warning: unused import: `std::path::Path` + --> src/commands/mod.rs:53:5 + | +53 | use std::path::Path; + | ^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default + + Checking tokio-test v0.4.4 +warning: unused variable: `e` + --> src/commands/touch.rs:33:24 + | +33 | if let Err(e) = + | ^ help: if this is intentional, prefix it with an underscore: `_e` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default + +warning: unused variable: `file_type` + --> src/commands/ls.rs:124:9 + | +124 | let file_type = if metadata.is_dir() { "d" } else { "-" }; + | ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_file_type` + +warning: field `output_rx` is never read + --> src/lib.rs:184:5 + | +175 | pub struct ProcessRunner { + | ------------- field in this struct +... +184 | output_rx: Option>, + | ^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default + +warning: method `add` can be confused for the standard trait method `std::ops::Add::add` + --> src/pipeline.rs:75:5 + | +75 | / pub fn add(mut self, command: impl Into) -> Self { +76 | | self.commands.push(command.into()); +77 | | self +78 | | } + | |_____^ + | + = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name + = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.96.0/index.html#should_implement_trait + = note: `#[warn(clippy::should_implement_trait)]` on by default + +warning: manual implementation of `Option::map` + --> src/stream.rs:238:25 + | +238 | let stdout_handle = if let Some(stdout) = stdout { + | _________________________^ +239 | | Some(tokio::spawn(async move { +240 | | let mut reader = BufReader::new(stdout); +241 | | let mut buf = vec![0u8; 8192]; +... | +260 | | None +261 | | }; + | |_____^ + | + = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.96.0/index.html#manual_map + = note: `#[warn(clippy::manual_map)]` on by default +help: try + | +238 ~ let stdout_handle = stdout.map(|stdout| tokio::spawn(async move { +239 + let mut reader = BufReader::new(stdout); +240 + let mut buf = vec![0u8; 8192]; +241 + loop { +242 + use tokio::io::AsyncReadExt; +243 + match reader.read(&mut buf).await { +244 + Ok(0) => break, +245 + Ok(n) => { +246 + if tx_stdout +247 + .send(OutputChunk::Stdout(buf[..n].to_vec())) +248 + .await +249 + .is_err() +250 + { +251 + break; +252 + } +253 + } +254 + Err(_) => break, +255 + } +256 + } +257 ~ })); + | + +warning: manual implementation of `Option::map` + --> src/stream.rs:266:25 + | +266 | let stderr_handle = if let Some(stderr) = stderr { + | _________________________^ +267 | | Some(tokio::spawn(async move { +268 | | let mut reader = BufReader::new(stderr); +269 | | let mut buf = vec![0u8; 8192]; +... | +288 | | None +289 | | }; + | |_____^ + | + = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.96.0/index.html#manual_map +help: try + | +266 ~ let stderr_handle = stderr.map(|stderr| tokio::spawn(async move { +267 + let mut reader = BufReader::new(stderr); +268 + let mut buf = vec![0u8; 8192]; +269 + loop { +270 + use tokio::io::AsyncReadExt; +271 + match reader.read(&mut buf).await { +272 + Ok(0) => break, +273 + Ok(n) => { +274 + if tx_stderr +275 + .send(OutputChunk::Stderr(buf[..n].to_vec())) +276 + .await +277 + .is_err() +278 + { +279 + break; +280 + } +281 + } +282 + Err(_) => break, +283 + } +284 + } +285 ~ })); + | + +warning: unnecessary `if let` since only the `Ok` variant of the iterator element is used + --> src/commands/ls.rs:70:21 + | +70 | / for entry in entries { +71 | | if let Ok(entry) = entry { +72 | | let name = entry.file_name().to_string_lossy().to_string(); +... | +85 | | } + | |_____________________^ + | +help: try `.flatten()` and remove the `if let` statement in the for loop + --> src/commands/ls.rs:71:25 + | +71 | / if let Ok(entry) = entry { +72 | | let name = entry.file_name().to_string_lossy().to_string(); +... | +84 | | } + | |_________________________^ + = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.96.0/index.html#manual_flatten + = note: `#[warn(clippy::manual_flatten)]` on by default +help: try + | +70 ~ for entry in entries.flatten() { +71 + let name = entry.file_name().to_string_lossy().to_string(); +72 + +73 + // Skip hidden files unless -a is specified +74 + if !show_all && name.starts_with('.') { +75 + continue; +76 + } +77 + +78 + if long_format { +79 + entry_strs.push(format_entry(&entry.path(), true)); +80 + } else { +81 + entry_strs.push(name); +82 + } +83 + } + | + +warning: useless use of `format!` + --> src/commands/sleep.rs:50:17 + | +50 | format!("sleep: cancelled after partial sleep") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"sleep: cancelled after partial sleep".to_string()` + | + = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.96.0/index.html#useless_format + = note: `#[warn(clippy::useless_format)]` on by default + +warning: this can be `std::io::Error::other(_)` + --> src/lib.rs:292:23 + | +292 | Error::Io(std::io::Error::new( + | _______________________^ +293 | | std::io::ErrorKind::Other, +294 | | "Process not started", +295 | | )) + | |_____________^ + | + = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.96.0/index.html#io_other_error + = note: `#[warn(clippy::io_other_error)]` on by default +help: use `std::io::Error::other` + | +292 ~ Error::Io(std::io::Error::other( +293 ~ "Process not started", + | + +warning: `command-stream` (lib) generated 10 warnings (run `cargo clippy --fix --lib -p command-stream -- ` to apply 7 suggestions) +warning: unused imports: `ProcessRunner` and `RunOptions` + --> src/main.rs:5:27 + | +5 | use command_stream::{run, ProcessRunner, RunOptions}; + | ^^^^^^^^^^^^^ ^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default + +warning: unused imports: `PipelineExt`, `ProcessRunner`, and `RunOptions` + --> tests/pipeline.rs:3:32 + | +3 | use command_stream::{Pipeline, PipelineExt, ProcessRunner, RunOptions}; + | ^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default + +warning: `command-stream` (bin "command-stream" test) generated 1 warning (run `cargo clippy --fix --bin "command-stream" -p command-stream --tests -- ` to apply 1 suggestion) +warning: `command-stream` (test "pipeline") generated 1 warning (run `cargo clippy --fix --test "pipeline" -p command-stream -- ` to apply 1 suggestion) +warning: unused import: `cd` + --> tests/builtin_commands.rs:6:20 + | +6 | basename, cat, cd, cp, dirname, echo, env, exit, ls, mkdir, mv, pwd, rm, seq, sleep, test, + | ^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default + +warning: unused import: `command_stream::utils::CommandResult` + --> tests/builtin_commands.rs:9:5 + | +9 | use command_stream::utils::CommandResult; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused import: `std::path::PathBuf` + --> tests/process_runner.rs:7:5 + | +7 | use std::path::PathBuf; + | ^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default + +warning: `command-stream` (bin "command-stream") generated 1 warning (1 duplicate) +warning: unused import: `AsyncIterator` + --> tests/stream.rs:3:22 + | +3 | use command_stream::{AsyncIterator, OutputChunk, StreamingRunner}; + | ^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default + +warning: `command-stream` (test "process_runner") generated 1 warning (run `cargo clippy --fix --test "process_runner" -p command-stream -- ` to apply 1 suggestion) +warning: `command-stream` (test "stream") generated 1 warning +warning: function `ctx_with_cwd` is never used + --> tests/builtin_commands.rs:27:4 + | +27 | fn ctx_with_cwd(args: Vec<&str>, cwd: PathBuf) -> CommandContext { + | ^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default + +warning: `command-stream` (test "builtin_commands") generated 3 warnings (run `cargo clippy --fix --test "builtin_commands" -p command-stream -- ` to apply 2 suggestions) +warning: `command-stream` (lib test) generated 10 warnings (10 duplicates) + Finished `dev` profile [unoptimized + debuginfo] target(s) in 8.20s diff --git a/docs/case-studies/issue-160/data/rust-doc-test.log b/docs/case-studies/issue-160/data/rust-doc-test.log new file mode 100644 index 0000000..fb5fb4b --- /dev/null +++ b/docs/case-studies/issue-160/data/rust-doc-test.log @@ -0,0 +1,120 @@ + Fresh libc v0.2.178 + Fresh unicode-ident v1.0.22 + Fresh cfg-if v1.0.4 + Fresh memchr v2.7.6 + Fresh scopeguard v1.2.0 + Fresh smallvec v1.15.1 + Fresh aho-corasick v1.1.4 + Fresh proc-macro2 v1.0.104 + Fresh parking_lot_core v0.9.12 + Fresh lock_api v0.4.14 + Fresh errno v0.3.14 + Fresh regex-syntax v0.8.8 + Fresh quote v1.0.42 + Fresh bitflags v2.10.0 + Fresh autocfg v1.5.0 + Fresh pin-project-lite v0.2.16 + Fresh parking_lot v0.12.5 + Fresh syn v2.0.111 + Fresh regex-automata v0.4.13 + Fresh signal-hook-registry v1.4.8 + Fresh tokio-macros v2.6.0 + Fresh socket2 v0.6.1 + Fresh mio v1.1.1 + Fresh linux-raw-sys v0.11.0 + Fresh cfg_aliases v0.2.1 + Fresh bytes v1.11.0 + Fresh rustix v1.1.3 + Fresh tokio v1.48.0 + Fresh serde_core v1.0.228 + Fresh predicates-core v1.0.9 + Fresh futures-core v0.3.31 + Fresh zmij v1.0.2 + Fresh num-traits v0.2.19 + Fresh serde_derive v1.0.228 + Fresh async-stream-impl v0.3.6 + Fresh thiserror-impl v2.0.17 + Fresh either v1.15.0 + Fresh env_home v0.1.0 + Fresh itoa v1.0.17 + Fresh iana-time-zone v0.1.64 + Fresh anstyle v1.0.13 + Fresh difflib v0.4.0 + Fresh termtree v0.5.1 + Fresh once_cell v1.21.3 + Fresh serde_json v1.0.148 + Fresh which v7.0.3 + Fresh predicates v3.1.3 + Fresh predicates-tree v1.0.12 + Fresh chrono v0.4.42 + Fresh thiserror v2.0.17 + Fresh nix v0.29.0 + Fresh serde v1.0.228 + Fresh async-stream v0.3.6 + Fresh getrandom v0.3.4 + Fresh tokio-stream v0.1.17 + Fresh bstr v1.12.1 + Fresh regex v1.12.2 + Fresh async-trait v0.1.89 + Fresh filetime v0.2.26 + Fresh wait-timeout v0.2.1 + Fresh fastrand v2.3.0 + Fresh glob v0.3.3 + Fresh tokio-test v0.4.4 +warning: unused import: `std::path::Path` + --> src/commands/mod.rs:53:5 + | +53 | use std::path::Path; + | ^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default + +warning: unused variable: `e` + --> src/commands/touch.rs:33:24 + | +33 | if let Err(e) = + | ^ help: if this is intentional, prefix it with an underscore: `_e` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default + +warning: unused variable: `file_type` + --> src/commands/ls.rs:124:9 + | +124 | let file_type = if metadata.is_dir() { "d" } else { "-" }; + | ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_file_type` + +warning: field `output_rx` is never read + --> src/lib.rs:184:5 + | +175 | pub struct ProcessRunner { + | ------------- field in this struct +... +184 | output_rx: Option>, + | ^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default + + Fresh tempfile v3.24.0 + Fresh assert_cmd v2.1.1 +warning: `command-stream` (lib) generated 4 warnings (run `cargo fix --lib -p command-stream` to apply 3 suggestions) + Fresh command-stream v0.9.5 (/tmp/gh-issue-solver-1780922968363/rust) + Finished `test` profile [unoptimized + debuginfo] target(s) in 0.05s + Doc-tests command_stream + Running `/home/box/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustdoc --edition=2021 --crate-type lib --color auto --crate-name command_stream --test src/lib.rs --test-run-directory /tmp/gh-issue-solver-1780922968363/rust --extern assert_cmd=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libassert_cmd-e52e48642b473a59.rlib --extern async_trait=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libasync_trait-25af62ef852c13f1.so --extern chrono=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libchrono-a696dd4767533fa7.rlib --extern command_stream=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libcommand_stream-4ddf24d0f2043cba.rlib --extern filetime=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libfiletime-6d7642e2f9f8bde0.rlib --extern glob=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libglob-ddf34b48c2f727a7.rlib --extern libc=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/liblibc-7a49c4074e502b3b.rlib --extern nix=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libnix-de25de586ff8d1fb.rlib --extern once_cell=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libonce_cell-7551b3a1dae149bb.rlib --extern regex=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libregex-3f4827befad472b3.rlib --extern serde=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libserde-46203e8a6c9e58c4.rlib --extern serde_json=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libserde_json-85fcef24435a3155.rlib --extern tempfile=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libtempfile-9f5406b362cb6593.rlib --extern thiserror=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libthiserror-e62624a28117d3cb.rlib --extern tokio=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libtokio-0354b47b7111be41.rlib --extern tokio_test=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libtokio_test-c8bf71467468b09a.rlib --extern which=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps/libwhich-f1ef33cf79378bd0.rlib -L dependency=/tmp/gh-issue-solver-1780922968363/rust/target/debug/deps -C embed-bitcode=no --cfg 'feature="default"' --cfg 'feature="json"' --cfg 'feature="serde"' --cfg 'feature="serde_json"' --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values("default", "json", "serde", "serde_json"))' --error-format human` + +running 13 tests +test src/events.rs - events::StreamEmitter::on (line 93) ... ignored +test src/pipeline.rs - pipeline (line 9) - compile ... ok +test src/macros.rs - macros (line 17) - compile ... ok +test src/macros.rs - macros::cmd (line 84) - compile ... ok +test src/lib.rs - (line 38) - compile ... ok +test src/stream.rs - stream (line 8) - compile ... ok +test src/ansi.rs - ansi::AnsiUtils::strip_control_chars (line 37) ... ok +test src/ansi.rs - ansi::AnsiUtils::strip_ansi (line 17) ... ok +test src/quote.rs - quote::needs_quoting (line 88) ... ok +test src/quote.rs - quote::quote_all (line 67) ... ok +test src/quote.rs - quote::quote (line 13) ... ok +test src/trace.rs - trace::trace (line 33) ... ok +test src/trace.rs - trace::trace_lazy (line 55) ... ok + +test result: ok. 12 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.62s diff --git a/docs/case-studies/issue-160/data/rust-fmt.log b/docs/case-studies/issue-160/data/rust-fmt.log new file mode 100644 index 0000000..e69de29 diff --git a/docs/case-studies/issue-160/data/rust-package.log b/docs/case-studies/issue-160/data/rust-package.log new file mode 100644 index 0000000..4a372e8 --- /dev/null +++ b/docs/case-studies/issue-160/data/rust-package.log @@ -0,0 +1,54 @@ + Packaging command-stream v0.9.5 (/tmp/gh-issue-solver-1780922968363/rust) + Updating crates.io index + Packaged 70 files, 414.6KiB (87.2KiB compressed) + Verifying command-stream v0.9.5 (/tmp/gh-issue-solver-1780922968363/rust) + Compiling rustix v1.1.3 + Compiling regex-automata v0.4.13 + Compiling tokio v1.48.0 + Compiling which v7.0.3 + Compiling regex v1.12.2 + Compiling command-stream v0.9.5 (/tmp/gh-issue-solver-1780922968363/rust/target/package/command-stream-0.9.5) +warning: unused import: `std::path::Path` + --> src/commands/mod.rs:53:5 + | +53 | use std::path::Path; + | ^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default + +warning: unused variable: `e` + --> src/commands/touch.rs:33:24 + | +33 | if let Err(e) = + | ^ help: if this is intentional, prefix it with an underscore: `_e` + | + = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default + +warning: unused variable: `file_type` + --> src/commands/ls.rs:124:9 + | +124 | let file_type = if metadata.is_dir() { "d" } else { "-" }; + | ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_file_type` + +warning: field `output_rx` is never read + --> src/lib.rs:184:5 + | +175 | pub struct ProcessRunner { + | ------------- field in this struct +... +184 | output_rx: Option>, + | ^^^^^^^^^ + | + = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default + +warning: `command-stream` (lib) generated 4 warnings (run `cargo fix --lib -p command-stream` to apply 3 suggestions) +warning: unused imports: `ProcessRunner` and `RunOptions` + --> src/main.rs:5:27 + | +5 | use command_stream::{run, ProcessRunner, RunOptions}; + | ^^^^^^^^^^^^^ ^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default + +warning: `command-stream` (bin "command-stream") generated 1 warning (run `cargo fix --bin "command-stream" -p command-stream` to apply 1 suggestion) + Finished `dev` profile [unoptimized + debuginfo] target(s) in 5.38s diff --git a/docs/case-studies/issue-160/data/rust-script-publish-crate-test.log b/docs/case-studies/issue-160/data/rust-script-publish-crate-test.log new file mode 100644 index 0000000..9e1fa69 --- /dev/null +++ b/docs/case-studies/issue-160/data/rust-script-publish-crate-test.log @@ -0,0 +1,51 @@ +[2026-06-08T13:16:26Z INFO rust_script] Arguments: Args { script: Some("rust/scripts/publish-crate.rs"), script_args: [], expr: false, loop_: false, count: false, base_path: None, pkg_path: None, gen_pkg_only: false, cargo_output: false, clear_cache: false, debug: false, dep: [], extern_: [], force: false, unstable_features: [], build_kind: Test, toolchain_version: None, wrapper: None } +[2026-06-08T13:16:26Z INFO rust_script] input: File("publish-crate", "/tmp/gh-issue-solver-1780922968363/rust/scripts/publish-crate.rs", "#!/usr/bin/env rust-script\n//! Publish package to crates.io\n//!\n//! This script publishes the Rust package to crates.io and handles\n//! the case where the version already exists.\n//!\n//! Supports both single-language and multi-language repository structures:\n//! - Single-language: Cargo.toml in repository root\n//! - Multi-language: Cargo.toml in rust/ subfolder\n//!\n//! Usage: rust-script scripts/publish-crate.rs [--token ] [--rust-root ]\n//!\n//! Environment variables (checked in order of priority):\n//! - CARGO_REGISTRY_TOKEN: Cargo's native crates.io token (preferred)\n//! - CARGO_TOKEN: Alternative token name for backwards compatibility\n//!\n//! Outputs (written to GITHUB_OUTPUT):\n//! - publish_result: one of\n//! 'success' - the crate version was published to crates.io\n//! 'already_exists' - the version is already on crates.io (version-bump bug)\n//! 'auth_failed' - missing or invalid crates.io authentication token\n//! 'rate_limited' - crates.io returned HTTP 429 (too many versions in 24h);\n//! deferred, automatically-recoverable outcome — the\n//! script exits 0 and the same version is retried on the\n//! next push to 'main' once the throttle window clears\n//! 'skipped' - publish skipped (e.g. template default package name)\n//! 'failed' - publish failed for an unrecognised reason\n//!\n//! ```cargo\n//! [dependencies]\n//! regex = \"1\"\n//! ```\n\nuse std::env;\nuse std::fs;\nuse std::io::Write;\nuse std::process::{Command, exit};\n\n#[path = \"rust-paths.rs\"]\nmod rust_paths;\n\nfn get_arg(name: &str) -> Option {\n let args: Vec = env::args().collect();\n let flag = format!(\"--{}\", name);\n\n if let Some(idx) = args.iter().position(|a| a == &flag) {\n return args.get(idx + 1).cloned();\n }\n\n None\n}\n\nfn set_output(key: &str, value: &str) {\n if let Ok(output_file) = env::var(\"GITHUB_OUTPUT\") {\n if let Ok(mut file) = fs::OpenOptions::new().create(true).append(true).open(&output_file) {\n let _ = writeln!(file, \"{}={}\", key, value);\n }\n }\n println!(\"Output: {}={}\", key, value);\n}\n\n/// Classification of a failed `cargo publish` attempt.\n///\n/// Every failure branch funnels through this single enum so the `publish_result`\n/// output value and the catch-all behaviour cannot drift apart over time.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\nenum FailureKind {\n AlreadyExists,\n AuthFailed,\n RateLimited,\n Unknown,\n}\n\nimpl FailureKind {\n fn output_value(self) -> &'static str {\n match self {\n FailureKind::AlreadyExists => \"already_exists\",\n FailureKind::AuthFailed => \"auth_failed\",\n FailureKind::RateLimited => \"rate_limited\",\n FailureKind::Unknown => \"failed\",\n }\n }\n\n /// Whether this failure is a *deferred*, automatically-recoverable outcome\n /// rather than a hard error.\n ///\n /// A crates.io HTTP 429 throttle is transient: the same version is re-tried\n /// on the next push to `main` once the 24-hour window clears (see\n /// `scripts/check-release-needed.rs`). The script therefore exits\n /// successfully for this case so a recoverable throttle does not turn the\n /// whole release job red. Every other failure stays non-zero.\n fn is_deferred(self) -> bool {\n matches!(self, FailureKind::RateLimited)\n }\n}\n\n/// Classify a combined stdout/stderr blob from `cargo publish` into a\n/// [`FailureKind`].\n///\n/// Note: the rate-limit checks come before the auth checks because a crates.io\n/// 429 body never contains the auth-token markers, while the rate-limit markers\n/// are unambiguous.\nfn classify_failure(combined: &str) -> FailureKind {\n if combined.contains(\"already uploaded\") || combined.contains(\"already exists\") {\n FailureKind::AlreadyExists\n } else if combined.contains(\"429 Too Many Requests\")\n || combined.contains(\"Too Many Requests\")\n || combined.contains(\"too many versions\")\n || combined.contains(\"too many requests\")\n {\n FailureKind::RateLimited\n } else if combined.contains(\"non-empty token\")\n || combined.contains(\"please provide a\")\n || combined.contains(\"unauthorized\")\n || combined.contains(\"authentication\")\n {\n FailureKind::AuthFailed\n } else {\n FailureKind::Unknown\n }\n}\n\nfn main() {\n let rust_root = match rust_paths::get_rust_root(None, true) {\n Ok(root) => root,\n Err(e) => {\n eprintln!(\"Error: {}\", e);\n exit(1);\n }\n };\n let cargo_toml = rust_paths::get_cargo_toml_path(&rust_root);\n let package_manifest = match rust_paths::get_package_manifest_path(&cargo_toml) {\n Ok(path) => path,\n Err(e) => {\n eprintln!(\"Error: {}\", e);\n exit(1);\n }\n };\n\n // Get token from CLI arg, then env vars\n let token = get_arg(\"token\")\n .or_else(|| env::var(\"CARGO_REGISTRY_TOKEN\").ok().filter(|s| !s.is_empty()))\n .or_else(|| env::var(\"CARGO_TOKEN\").ok().filter(|s| !s.is_empty()));\n\n let package_info = match rust_paths::read_package_info(&package_manifest) {\n Ok(info) => info,\n Err(e) => {\n eprintln!(\"Error: {}\", e);\n exit(1);\n }\n };\n let name = package_info.name;\n let version = package_info.version;\n\n println!(\"Package: {}@{}\", name, version);\n\n if name == \"example-sum-package-name\" {\n println!(\"Skipping publish: package name is the template default 'example-sum-package-name'\");\n println!(\"Rename the package in Cargo.toml before publishing to crates.io\");\n set_output(\"publish_result\", \"skipped\");\n return;\n }\n\n println!();\n println!(\"=== Attempting to publish to crates.io ===\");\n\n if token.is_none() {\n println!(\"::warning::Neither CARGO_REGISTRY_TOKEN nor CARGO_TOKEN is set, attempting publish without explicit token\");\n println!();\n println!(\"To fix this, ensure one of the following secrets is configured:\");\n println!(\" - CARGO_REGISTRY_TOKEN (Cargo's native env var, preferred)\");\n println!(\" - CARGO_TOKEN (alternative for backwards compatibility)\");\n println!();\n println!(\"For organization secrets, you may need to map the secret name in your workflow:\");\n println!(\" env:\");\n println!(\" CARGO_REGISTRY_TOKEN: ${{{{ secrets.CARGO_TOKEN }}}}\");\n println!();\n } else {\n println!(\"Using provided authentication token\");\n }\n\n // Build the cargo publish command. Use the manifest path so this works for\n // both a standalone crate and a crate nested under rust/.\n let mut cmd = Command::new(\"cargo\");\n cmd.arg(\"publish\")\n .arg(\"--allow-dirty\")\n .arg(\"--manifest-path\")\n .arg(&package_manifest);\n\n if let Some(t) = &token {\n cmd.arg(\"--token\").arg(t);\n }\n\n let output = cmd.output().expect(\"Failed to execute cargo publish\");\n\n if output.status.success() {\n println!(\"Successfully published {}@{} to crates.io\", name, version);\n set_output(\"publish_result\", \"success\");\n } else {\n let stderr = String::from_utf8_lossy(&output.stderr);\n let stdout = String::from_utf8_lossy(&output.stdout);\n let combined = format!(\"{}\\n{}\", stdout, stderr);\n\n let kind = classify_failure(&combined);\n match kind {\n FailureKind::AlreadyExists => {\n eprintln!();\n eprintln!(\"=== VERSION ALREADY PUBLISHED ===\");\n eprintln!();\n eprintln!(\"Version {} already exists on crates.io.\", version);\n eprintln!(\"The release pipeline must always publish a version greater than what is already published.\");\n eprintln!(\"This indicates a bug in version bumping: the pipeline should have computed a new, unpublished version.\");\n eprintln!();\n }\n FailureKind::RateLimited => {\n eprintln!();\n eprintln!(\"=== CRATES.IO RATE LIMIT (HTTP 429) ===\");\n eprintln!();\n eprintln!(\"crates.io rejected the publish because too many versions of this\");\n eprintln!(\"crate have been published in the last 24 hours.\");\n eprintln!();\n eprintln!(\"Original cargo publish error:\");\n eprintln!(\"{}\", combined.trim());\n eprintln!();\n eprintln!(\"This is a TRANSIENT, automatically-recoverable throttle, not a pipeline bug.\");\n eprintln!(\"No action is required other than waiting for the 24-hour window to roll over.\");\n eprintln!(\"scripts/check-release-needed.rs will re-attempt the same version on the next\");\n eprintln!(\"push to 'main' once the throttle window has cleared.\");\n eprintln!();\n eprintln!(\"See: https://doc.rust-lang.org/cargo/reference/publishing.html#publishing-a-new-version-of-an-existing-crate\");\n eprintln!();\n }\n FailureKind::AuthFailed => {\n eprintln!();\n eprintln!(\"=== AUTHENTICATION FAILURE ===\");\n eprintln!();\n eprintln!(\"Failed to publish due to missing or invalid authentication token.\");\n eprintln!();\n eprintln!(\"SOLUTION: Configure one of these secrets in your repository or organization:\");\n eprintln!(\" 1. CARGO_REGISTRY_TOKEN - Cargo's native environment variable (preferred)\");\n eprintln!(\" 2. CARGO_TOKEN - Alternative name for backwards compatibility\");\n eprintln!();\n eprintln!(\"If using organization secrets with a different name, map it in your workflow:\");\n eprintln!(\" - name: Publish to Crates.io\");\n eprintln!(\" env:\");\n eprintln!(\" CARGO_REGISTRY_TOKEN: ${{{{ secrets.YOUR_SECRET_NAME }}}}\");\n eprintln!();\n eprintln!(\"See: https://doc.rust-lang.org/cargo/reference/publishing.html\");\n eprintln!();\n }\n FailureKind::Unknown => {\n eprintln!(\"Failed to publish for unknown reason\");\n eprintln!(\"{}\", combined);\n }\n }\n\n set_output(\"publish_result\", kind.output_value());\n\n // A rate-limit is a deferred, automatically-recoverable outcome: exit\n // successfully so the release job does not go red over a transient\n // crates.io throttle. Downstream release-artifact steps are gated on a\n // successful publish (see .github/workflows/rust.yml), so a deferred\n // upload never produces partial Docker/GitHub release artifacts.\n if kind.is_deferred() {\n return;\n }\n\n exit(1);\n }\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn classifies_already_exists_response() {\n let body = \"error: crate version 0.1.0 is already uploaded\";\n assert_eq!(classify_failure(body), FailureKind::AlreadyExists);\n assert_eq!(FailureKind::AlreadyExists.output_value(), \"already_exists\");\n }\n\n #[test]\n fn classifies_rate_limit_response() {\n let body = \"\\\nerror: failed to publish my-crate v0.42.0 to registry at https://crates.io\n\nCaused by:\n the remote server responded with an error (status 429 Too Many Requests): \\\nYou have published too many versions of this crate in the last 24 hours\n\";\n assert_eq!(classify_failure(body), FailureKind::RateLimited);\n assert_eq!(FailureKind::RateLimited.output_value(), \"rate_limited\");\n }\n\n #[test]\n fn classifies_rate_limit_from_too_many_versions_marker() {\n let body = \"the remote server responded: You have published too many versions\";\n assert_eq!(classify_failure(body), FailureKind::RateLimited);\n }\n\n #[test]\n fn classifies_auth_failure_response() {\n let body = \"error: failed to publish: please provide a non-empty token\";\n assert_eq!(classify_failure(body), FailureKind::AuthFailed);\n assert_eq!(FailureKind::AuthFailed.output_value(), \"auth_failed\");\n }\n\n #[test]\n fn classifies_unknown_response() {\n let body = \"error: some brand new failure mode nobody has seen before\";\n assert_eq!(classify_failure(body), FailureKind::Unknown);\n assert_eq!(FailureKind::Unknown.output_value(), \"failed\");\n }\n\n #[test]\n fn rate_limit_takes_precedence_over_auth_markers() {\n // A 429 body that also happens to mention \"authentication\" must still be\n // classified as rate-limited, since the throttle is the actionable cause.\n let body = \"status 429 Too Many Requests: authentication retry later\";\n assert_eq!(classify_failure(body), FailureKind::RateLimited);\n }\n\n #[test]\n fn only_rate_limit_is_deferred() {\n // A rate-limit is the single deferred (exit-0) outcome; every other\n // failure must remain a hard, non-zero error.\n assert!(FailureKind::RateLimited.is_deferred());\n assert!(!FailureKind::AlreadyExists.is_deferred());\n assert!(!FailureKind::AuthFailed.is_deferred());\n assert!(!FailureKind::Unknown.is_deferred());\n }\n}\n", "/tmp/gh-issue-solver-1780922968363/rust/scripts") +[2026-06-08T13:16:26Z INFO rust_script] prelude_items: [] +[2026-06-08T13:16:26Z INFO rust_script] id: "373bbd2ac91324bbead60b56" +[2026-06-08T13:16:26Z INFO rust_script] pkg_path: "/home/box/.cache/rust-script/projects/373bbd2ac91324bbead60b56" +[2026-06-08T13:16:26Z INFO rust_script] using_cache: true +[2026-06-08T13:16:26Z INFO rust_script::manifest] part_mani: {"dependencies": Table({"regex": String("1")})} +[2026-06-08T13:16:26Z INFO rust_script::manifest] source: None +[2026-06-08T13:16:26Z INFO rust_script::manifest] manifest: [[bin]] + name = "publish-crate_373bbd2ac91324bbead60b56" + path = "/tmp/gh-issue-solver-1780922968363/rust/scripts/publish-crate.rs" + + [dependencies] + regex = "1" + + [package] + authors = ["Anonymous"] + edition = "2021" + name = "publish-crate_373bbd2ac91324bbead60b56" + version = "0.1.0" + + [profile.release] + strip = true + +[2026-06-08T13:16:26Z INFO rust_script] action: InputAction { cargo_output: false, force_compile: false, execute: true, pkg_path: "/home/box/.cache/rust-script/projects/373bbd2ac91324bbead60b56", script_path: "/tmp/gh-issue-solver-1780922968363/rust/scripts/publish-crate.rs", using_cache: true, toolchain_version: None, debug: true, manifest: "[[bin]]\nname = \"publish-crate_373bbd2ac91324bbead60b56\"\npath = \"/tmp/gh-issue-solver-1780922968363/rust/scripts/publish-crate.rs\"\n\n[dependencies]\nregex = \"1\"\n\n[package]\nauthors = [\"Anonymous\"]\nedition = \"2021\"\nname = \"publish-crate_373bbd2ac91324bbead60b56\"\nversion = \"0.1.0\"\n\n[profile.release]\nstrip = true\n", script: None, build_kind: Test, bin_name: "publish-crate_373bbd2ac91324bbead60b56", original_script_path: Some("rust/scripts/publish-crate.rs") } +[2026-06-08T13:16:26Z INFO rust_script] creating pkg dir... +[2026-06-08T13:16:26Z INFO rust_script] generating Cargo package... +[2026-06-08T13:16:26Z DEBUG rust_script] overwrite_file("/home/box/.cache/rust-script/projects/373bbd2ac91324bbead60b56/Cargo.toml", _) +[2026-06-08T13:16:26Z DEBUG rust_script] .. files differ +[2026-06-08T13:16:26Z INFO rust_script] disarming pkg dir cleanup... + Updating crates.io index + Locking 5 packages to latest compatible versions + Compiling memchr v2.8.1 + Compiling regex-syntax v0.8.10 + Compiling aho-corasick v1.1.4 + Compiling regex-automata v0.4.14 + Compiling regex v1.12.3 + Compiling publish-crate_373bbd2ac91324bbead60b56 v0.1.0 (/home/box/.cache/rust-script/projects/373bbd2ac91324bbead60b56) + Finished `test` profile [unoptimized + debuginfo] target(s) in 3.24s + Running unittests /tmp/gh-issue-solver-1780922968363/rust/scripts/publish-crate.rs (/home/box/.cache/rust-script/binaries/debug/deps/publish_crate_373bbd2ac91324bbead60b56-04bad5a32c571bb5) + +running 7 tests +test tests::classifies_already_exists_response ... ok +test tests::classifies_auth_failure_response ... ok +test tests::classifies_rate_limit_from_too_many_versions_marker ... ok +test tests::classifies_rate_limit_response ... ok +test tests::only_rate_limit_is_deferred ... ok +test tests::rate_limit_takes_precedence_over_auth_markers ... ok +test tests::classifies_unknown_response ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s diff --git a/docs/case-studies/issue-160/data/rust-script-version-and-commit-test.log b/docs/case-studies/issue-160/data/rust-script-version-and-commit-test.log new file mode 100644 index 0000000..36bba18 --- /dev/null +++ b/docs/case-studies/issue-160/data/rust-script-version-and-commit-test.log @@ -0,0 +1,197 @@ +[2026-06-08T13:16:39Z INFO rust_script] Arguments: Args { script: Some("rust/scripts/version-and-commit.rs"), script_args: [], expr: false, loop_: false, count: false, base_path: None, pkg_path: None, gen_pkg_only: false, cargo_output: false, clear_cache: false, debug: false, dep: [], extern_: [], force: false, unstable_features: [], build_kind: Test, toolchain_version: None, wrapper: None } +[2026-06-08T13:16:39Z INFO rust_script] input: File("version-and-commit", "/tmp/gh-issue-solver-1780922968363/rust/scripts/version-and-commit.rs", "#!/usr/bin/env rust-script\n//! Bump version in Cargo.toml and commit changes\n//! Used by the CI/CD pipeline for releases\n//!\n//! IMPORTANT: This script checks crates.io (the source of truth for Rust packages),\n//! NOT git tags. This is critical because:\n//! - Git tags can exist without the package being published\n//! - GitHub releases create tags but don't publish to crates.io\n//! - Only crates.io publication means users can actually install the package\n//!\n//! Supports both single-language and multi-language repository structures:\n//! - Single-language: Cargo.toml and changelog.d/ in repository root\n//! - Multi-language: Cargo.toml and changelog.d/ in rust/ subfolder\n//!\n//! Usage: rust-script scripts/version-and-commit.rs --bump-type [--description ] [--rust-root ] [--tag-prefix ] [--release-label