文件历史

提交图

58 次代码提交

作者 SHA1 备注 提交日期
Alezander9 82ef2a13ab feat(_ipc): BH_TMP_DIR overrides sock/port/pid/log + screenshot dir
Lets callers (e.g. browsercode per-session scratch) redirect all harness
file output via one env var. Default behavior unchanged when unset:
/tmp on POSIX, gettempdir() on Windows.

helpers.capture_screenshot and the debug-click overlay now route through
ipc._TMP so the same knob covers screenshots.
2026-04-28 15:21:48 -07:00
cryptoshrine 06aad12d91 fix(admin): catch SystemError raised by os.kill on Windows
On Windows, `os.kill(pid, 0)` does not behave like its POSIX
counterpart. Instead of returning silently when the process
exists or raising ProcessLookupError when it doesn't, CPython
on Windows raises:

    SystemError: <built-in function kill> returned a result
                 with an exception set

This happens because the underlying Win32 TerminateProcess API
does not accept signal 0 as an "is alive?" probe — Python's C
implementation hits an internal error path that doesn't set a
proper exception, and the interpreter surfaces SystemError.

`restart_daemon()` already catches `(ProcessLookupError, OSError)`
around both `os.kill(pid, 0)` and `os.kill(pid, signal.SIGTERM)`,
but SystemError isn't a subclass of either, so the harness crashes
on every second invocation on Windows: the daemon's stale pid file
points at a no-longer-running pid, the probe raises SystemError,
and the whole `browser-harness -c '...'` call dies with a stack
trace.

Repro on Windows 11 (Python 3.12, browser-harness 0.1.0):

    browser-harness --reload      # ok
    browser-harness -c 'print(page_info())'   # ok
    browser-harness -c 'print(page_info())'   # CRASH

Fix: add SystemError to the existing except clauses in
restart_daemon(). One-word change in two places, matches the
intent of the existing handlers (treat any "couldn't probe/signal
the pid" failure as "process is gone, move on").
2026-04-28 22:56:48 +01:00
Alezander9 1dd4f60252 fix(admin): route ensure_daemon CDP probe through ipc.connect (Windows)
The stale-daemon probe in ensure_daemon used raw socket.AF_UNIX, which:
1. Doesn't exist on uv-bundled Python on Windows (AttributeError).
2. Would point at a TCP display string '127.0.0.1:<port>', not a socket
   path, even if AF_UNIX existed.

Either way the probe always raised, was swallowed by 'except Exception',
and fell through to restart_daemon — killing and respawning the daemon
on every warm call. Symptom is most visible on Windows where the warm
path is the common case.

Fix: use ipc.connect(name) which already does the right thing per
platform (AF_UNIX on POSIX, TCP loopback on Windows). Same call
daemon_alive and restart_daemon already use.

Also drop the now-unused _paths() helper; restart_daemon only needed
the pid_path half, inline that.
2026-04-28 13:16:28 -07:00
Vlad Rafeev ac71315eda fix: prevent chrome://inspect tab flooding during setup (#232)
When remote-debugging is not enabled, `run_setup` opens chrome://inspect
once, then retries `ensure_daemon` in a loop. But `ensure_daemon` itself
also calls `_open_chrome_inspect()` on failure — opening a new tab every
~7 seconds and flooding the browser.

Add `_open_inspect` parameter to `ensure_daemon` so the retry loop in
`run_setup` can suppress redundant tab opens after the first one.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Saurav Panda <sgp65@cornell.edu>
2026-04-28 12:01:13 -07:00
Sarath S Menon fefca43ab5 feat(doctor): show live browser connections and attached pages in run_doctor (#234)
Add browser_connections() / active_browser_connections() to admin, which probe
each daemon socket via a new connection_status meta message. The daemon tracks
target_id (set on attach and on set_session) and returns the live page title/URL
via Target.getTargetInfo. switch_tab now forwards target_id in set_session so the
daemon stays in sync after tab switches. run_doctor shows the count, each daemon
name, and the truncated active-page title and URL.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 17:42:47 +05:30
Sarath S Menon 64dafa2805 refactor(js): proper return-statement parsing, unserializable value decoding, unified eval helpers (#231)
Replace naive `"return " in expression` check with a character-level parser that
ignores strings, line comments, and block comments. Add `_decode_unserializable_js_value`
to handle NaN, ±Infinity, -0, and BigInt. Extract `_runtime_value` and
`_runtime_evaluate` to unify error handling across `js()` and `page_info()`.
Wrap Runtime.evaluate TimeoutErrors in RuntimeError with expression context.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:33:28 +05:30
Sarath S Menon 5a77ea5525 fix(js): raise RuntimeError on JS evaluation errors instead of returning None (#230)
Previously js() silently returned None when Chrome reported a syntax or
runtime error. Now it raises RuntimeError with the error description,
line/column location, and a snippet of the failing expression.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:04:33 +05:30
Sarath S Menon fb1a51dd9b refactor: move to src layout, agent-workspace, and fix SKILL.md invocation format (#229)
* refactor(tests): reorganize into tests/unit and tests/integration

Moves all root-level test_*.py files into a structured tests/ directory:
- tests/unit/ — admin, helpers (was test_screenshot), run
- tests/integration/ — js expression tests
- tests/conftest.py — shared fake_png pytest fixture, eliminating duplication

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: move to src layout, agent-workspace, and fix SKILL.md invocation format

- Move package to src/browser_harness/ and domain-skills/interaction-skills to agent-workspace/
- Fix all browser-harness <<'PY' heredoc examples in SKILL.md and run.py HELP string to use the correct -c '...' flag format (heredoc was never supported by the CLI)
- Update SKILL.md path references from domain-skills/ to agent-workspace/domain-skills/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 15:38:11 +05:30