code-yeongyu / code-yeongyu/pi-cua-integration
Windows: daemon emits Proactor WinError 6 when reading stdin during reload
- Dominant language
- TypeScript
- Stars
- 6
- Forks
- 3
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
On Windows with Python 3.13, the daemon reports ready successfully but emits a large asyncio traceback during reload or shutdown:
```text
Exception in callback _ProactorReadPipeTransport._loop_reading()
OSError: [WinError 6] The handle is invalid
AttributeError: '_ProactorReadPipeTransport' object has no attribute '_empty_waiter'
```
The daemon currently connects `asyncio` directly to `sys.stdin`:
```python
reader = asyncio.StreamReader(loop=loop)
protocol = asyncio.StreamReaderProtocol(reader)
await loop.connect_read_pipe(lambda: protocol, sys.stdin)
```
Windows' Proactor event loop cannot reliably register this standard-input handle with IOCP. This is the same limitation documented in:
- https://github.com/python/cpython/issues/87694
- https://github.com/python/cpython/issues/71019
## Steps to reproduce
1. Configure the extension to use Python 3.13 on Windows.
2. Install a compatible Cua SDK and reload the extension.
3. Confirm the daemon reports:
```text
[pi-cua] ready (mode=local, ...)
```
4. Reload the extension again or shut down the daemon.
5. Observe the `_ProactorReadPipeTransport` traceback on stderr.
## Expected behavior
Daemon startup, reload, and shutdown should complete without Python stderr output.
## Actual behavior
The daemon becomes ready, but its stdin transport emits `WinError 6` and then an `_empty_waiter` `AttributeError`.
## Suggested fix
Avoid `connect_read_pipe()` for standard input and perform each blocking read in asyncio's worker thread:
```python
while not self._stop.is_set():
line = await asyncio.to_thread(sys.stdin.buffer.readline)
if not line:
break
# existing JSON-RPC parsing and dispatch
```
This preserves the async request handlers without using the unsupported Windows Proactor stdin transport.
Add an integration regression test that:
1. Starts the real Python daemon through `startDaemon()`.
2. Captures `onLog`/stderr before startup.
3. Waits for the ready event.
4. Calls `shutdown()`.
5. Asserts `cuaAvailable === true`, exit is clean, and captured stderr is empty.
The test should use the configured `PI_CUA_PYTHON` interpreter and run in Windows CI with Python 3.13.
## Acceptance criteria
- Two consecutive daemon start/shutdown cycles complete on Windows.
- Both cycles report ready.
- Neither cycle emits `_ProactorReadPipeTransport`, `WinError 6`, or any other stderr traceback.
- Existing JSON-RPC integration tests continue to pass.
Contributor guide
Research direction
Start with the daemon's current connect_read_pipe stdin path and the startDaemon()/shutdown() integration entry points; use PI_CUA_PYTHON and existing JSON-RPC integration tests as the map. Run the Windows CI scenario with Python 3.13 and verify two start/shutdown cycles reach ready, exit cleanly, and capture no stderr traceback.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, typescript
- Domain
- backend, operating-systems, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100