feat(transport): cross-platform IPC — rebased #180 on current main#192
feat(transport): cross-platform IPC — rebased #180 on current main#192midirectiekade14-debug wants to merge 3 commits intobrowser-use:mainfrom
Conversation
New transport.py owns OS-specific state paths and IPC server/client
creation: AF_UNIX on POSIX, AF_INET on 127.0.0.1:<kernel-assigned-port>
on Windows. daemon/admin/helpers route all state access through transport;
zero sys.platform checks outside the module.
- endpoint descriptor JSON {v: 1, kind, host|path, port?} written
atomically after the listener binds, cleaned up on shutdown (incl.
stale-endpoint cleanup in ensure_daemon / restart_daemon)
- log / pid / version-cache paths move to %TEMP% on Windows; daemon
previously crashed on start because /tmp/ does not exist there
- subprocess.Popen uses DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP on
Windows instead of the POSIX-only start_new_session=True
- os.chmod on the UDS socket is guarded (no-op on TCP; loopback-only
bind IS the access control on Windows)
- --doctor gains a transport row: "tcp 127.0.0.1:<port>" or
"uds <path>"
- helpers.screenshot() default path uses transport.state_dir() so it
stops crashing on Windows with "/tmp/" missing
- tests/test_transport.py: 25 pytest cases — logic cases cover both
OS branches via monkeypatch, one real-socket roundtrip exercises the
host OS end-to-end (UDS on POSIX, TCP on Windows)
Verified on Windows 10 x64 + Python 3.13 + Chrome 147:
$ browser-harness --doctor
platform Windows 10
transport tcp 127.0.0.1:52137 (name=default)
[ok ] chrome running
[ok ] daemon alive
$ browser-harness <<'PY'
print(page_info())
PY
{'url': 'about:blank', 'title': '', 'w': 929, 'h': 925, ...}
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…pass subprocess.DETACHED_PROCESS / CREATE_NEW_PROCESS_GROUP are Windows-only attributes. The monkeypatched cross-platform test reaches them on Linux runners, which raised AttributeError. Use getattr fallbacks in transport.popen_detach_kwargs and the test asserts the numeric MSDN values (0x00000008 / 0x00000200) directly so both OS CI runs pass. Verified: Windows 10 + Python 3.13: 24 passed, 1 skipped (uds chmod) Linux WSL Ubuntu + Python 3.12: 24 passed, 1 skipped (tcp loopback) The real POSIX UDS roundtrip + 0o600 chmod test now runs end-to-end (was only reachable via monkeypatch before). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
✅ Skill review passedReviewed 1 file(s) — no findings. |
There was a problem hiding this comment.
1 issue found across 8 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="transport.py">
<violation number="1" location="transport.py:171">
P1: `is_alive()` catches a narrow exception tuple that does not cover all errors from malformed endpoint descriptors, violating its documented contract that malformed descriptors return `False`. `open_client_sync()` can raise `KeyError`, `TypeError`, or `AttributeError` for bad JSON shapes, missing keys, or platform-incompatible kinds, none of which are caught.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| """ | ||
| try: | ||
| s = open_client_sync(name, timeout=timeout) | ||
| except (FileNotFoundError, ConnectionRefusedError, socket.timeout, OSError, ValueError): |
There was a problem hiding this comment.
P1: is_alive() catches a narrow exception tuple that does not cover all errors from malformed endpoint descriptors, violating its documented contract that malformed descriptors return False. open_client_sync() can raise KeyError, TypeError, or AttributeError for bad JSON shapes, missing keys, or platform-incompatible kinds, none of which are caught.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At transport.py, line 171:
<comment>`is_alive()` catches a narrow exception tuple that does not cover all errors from malformed endpoint descriptors, violating its documented contract that malformed descriptors return `False`. `open_client_sync()` can raise `KeyError`, `TypeError`, or `AttributeError` for bad JSON shapes, missing keys, or platform-incompatible kinds, none of which are caught.</comment>
<file context>
@@ -0,0 +1,174 @@
+ """
+ try:
+ s = open_client_sync(name, timeout=timeout)
+ except (FileNotFoundError, ConnectionRefusedError, socket.timeout, OSError, ValueError):
+ return False
+ s.close()
</file context>
| except (FileNotFoundError, ConnectionRefusedError, socket.timeout, OSError, ValueError): | |
| except (FileNotFoundError, ConnectionRefusedError, socket.timeout, OSError, ValueError, KeyError, TypeError, AttributeError): |
|
Hi, daemon.serve() assumes transport.read_endpoint() returns a dict and calls desc.get()/indexes keys; if the endpoint file is missing or malformed it returns None and the daemon crashes during startup logging. This can turn a recoverable endpoint-file issue into a fatal daemon startup failure. Severity: action required | Category: reliability How to fix: Guard/validate endpoint descriptor Agent prompt to fix - you can give this to your LLM of choice:
We noticed a couple of other issues in this PR as well - happy to share if helpful. Found by Qodo. Free code review for open-source maintainers. |
Summary
Rebases @MICORT's PR #180 (
feat(transport): cross-platform IPC with TCP loopback on Windows) onto currentmain, with one merge conflict resolved, and verifies all transport tests pass on Windows 11 + Python 3.14.Credit belongs to @MICORT — the transport module, tests, and Windows bootstrap logic are entirely their work. This PR exists only because #180 went
mergeable: falseaftermainmoved on, and it's useful to have a ready-to-merge version. Maintainers: happy to close this in favor of #180 being refreshed by the original author.What changed vs. #180
One conflict in
helpers.py:mainrenamedscreenshot()→capture_screenshot()(breaking API — used by 20+ domain-skills files)transport.state_dir()Resolution keeps the
capture_screenshotname (main's API) and the platform-aware default (#180's fix):SKILL.mdconflict was resolved by takingmain's version (the doc reorganization that happened after #180 was opened).Verification
On Windows 11 Pro, Python 3.14.3:
End-to-end smoke test against local Chrome (remote-debugging on port 9222):
browser-harness --doctorreportstransport tcp 127.0.0.1:<port>correctly; previously it traceback'd onsocket.AF_UNIXmissing.Windows install notes (not code changes — just observations for maintainers)
Two things I had to work around locally but that aren't in-scope for this PR:
print(page_info())crashes withUnicodeEncodeError. Workaround:PYTHONIOENCODING=utf-8. Could be fixed inrun.pywithsys.stdout.reconfigure(encoding='utf-8').uv run daemon.py) needsuvon PATH. On Windows that path (%APPDATA%\Python\Python3xx\Scripts\) isn't always on the default user PATH.Happy to submit these as a follow-up PR if useful.
Summary by cubic
Introduces a cross-platform IPC transport: UDS on macOS/Linux and loopback TCP on Windows. Centralizes paths, server/client creation, and process spawn logic in
transport.py, fixing Windows startup and improving diagnostics.New Features
transport.pyexposes endpoint discovery and IPC: descriptor JSON{v:1, kind, host|path, port}with atomic writes and cleanup.127.0.0.1:<ephemeral>; POSIX uses UDS with0600perms.--doctornow shows transport and endpoint for the currentBU_NAME.capture_screenshot()usestransport.state_dir()when no path is given.Bug Fixes
%TEMP%on Windows (no/tmpdependency).DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; POSIX keepsstart_new_session=True.admin.ensure_daemon/restart_daemonanddaemonusetransportfor probing, endpoint writes, and cleanup.Written for commit 2accac4. Summary will update on new commits.