Expose cancellable child process handles in JavaScript and Rust - #126
Conversation
Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: #20
This change enables users to access and kill child processes immediately
without having to await the process result first. The implementation
addresses both virtual commands and real child processes.
Key changes:
- Add child getter that provides immediate access to process for killing
- For virtual commands: return proxy object with kill() method that delegates
- For real commands: auto-start process when child is accessed
- Update internal references from this.child to this._child
- Fix kill() method to properly handle virtual commands
The solution allows both patterns to work:
- Virtual: $`sleep 5`.child.kill('SIGTERM')
- Real: $`/bin/sleep 5`.child.kill('SIGTERM')
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
|
We need to double check that all requirements are fully delivered for all programming languages we currently support. |
|
🤖 AI Work Session Started Starting automated work session at 2026-09-21T07:28:43.825Z The PR has been converted to draft mode while work is in progress. This comment marks the beginning of an AI work session. Please wait for the session to finish, and provide your feedback. Runtime: solve |
Working session summaryImplemented and finalized PR #126.
Final commit: This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost estimation:
📊 Context and tokens usage:
Total: (491.9K + 13.2M cached) input tokens, 53.2K output tokens, $16.078063 cost 🤖 Models used:
📎 Log file uploaded as Gist (6084KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
🎉 Auto-mergedThis pull request has been automatically merged by hive-mind.
Auto-merged by hive-mind with --auto-merge flag |
Summary
Expose the owned child process through supported, cancellable handles in both implementations.
runner.childstarts a lazy command and synchronously returns a stable pending handle.runner.child.kill('SIGTERM')can cancel before shell parsing/spawn, can stop in-process built-ins, and later reflects the native Node.js or Bun child. After cleanup,runner.childisnull.ProcessRunner::child()returns a borrowedProcessChildafterstart().await, with PID/native Tokio child access and signal-awarekill()/kill_with()methods._child, so internal lifecycle checks do not accidentally trigger the public auto-starting getter.Closes #20.
Reproduction and regression coverage
Before this change, a newly-created JavaScript runner had no accessible child, so the requested synchronous call could not stop it:
js/tests/child-access.test.mjsnow verifies immediate cancellation before spawn, the real-shell/redirection startup race, native-child delegation after spawn, built-in cancellation, and cleanup.rust/tests/child_access.rsverifies the corresponding Rust lifecycle, native access, and child-handle termination.Validation
bun test js/tests/ --timeout 10000— 1,609 passed, 6 skipped, 0 failedbun run lint,bun run format:check,bun run check:duplicationcargo test --all-features --verboseandcargo test --doc --all-features --verbosecargo fmt --check, Clippy with warnings denied, rustdoc with warnings denied, andcargo package --allow-dirtymain