<feed xmlns='http://www.w3.org/2005/Atom'>
<title>sz-chrome-remote-cdp.git/test, branch master</title>
<subtitle>pi-browser-harness, patched to drive a Chrome on another host over CDP, with castle_cdp_search web search
</subtitle>
<id>https://git.soarez.net/sz/sz-chrome-remote-cdp.git/atom?h=master</id>
<link rel='self' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/'/>
<updated>2026-10-17T10:20:04+00:00</updated>
<entry>
<title>Start a local Chrome when the target is an explicit local and none answers</title>
<updated>2026-10-17T10:20:04+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-17T10:20:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/commit/?id=f61c43418d704cccb67132540ed7feceacef1d2a'/>
<id>urn:sha1:f61c43418d704cccb67132540ed7feceacef1d2a</id>
<content type='text'>
Dedicated profile (~/.chrome-cdp-profile), macOS only, never for the
castle default. BU_LOCAL_CHROME_LAUNCH=off disables it.
</content>
</entry>
<entry>
<title>feat(cdp): report a BU_CDP_WS pin in status, /browser-target and the prompt</title>
<updated>2026-10-15T06:07:58+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-15T06:07:58+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/commit/?id=3e761274fe7b0e6be4a162e880293150ad9d9fbe'/>
<id>urn:sha1:3e761274fe7b0e6be4a162e880293150ad9d9fbe</id>
<content type='text'>
Upstream 0.11.0 made BU_CDP_WS reach the daemon, and discoverEndpoint()
returns it before the fork's target is consulted. resolveCdpTarget() did
not know about it, so /browser-status and the system prompt named the
BU_CDP_HTTP/stored/default target while the daemon dialled the pinned URL,
and /browser-target claimed to switch browsers when it could not.

resolveCdpTarget() now puts BU_CDP_WS first, as a remote target with
source "ws". /browser-target warns that it takes precedence, as it already
did for BU_CDP_HTTP. Only host:port is ever shown: the path carries the
browser id and a proxied URL may carry a token. /browser-status does not
probe a pinned URL, since /json/version answering says nothing about
whether the pinned browser id is still current.
</content>
</entry>
<entry>
<title>feat(cdp): /browser-target to switch browsers without leaving pi</title>
<updated>2026-10-14T11:19:26+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-07-29T09:38:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/commit/?id=08e558753e8ef9b2aa96114981a5a1dd37357bad'/>
<id>urn:sha1:08e558753e8ef9b2aa96114981a5a1dd37357bad</id>
<content type='text'>
Switching between the shared browser and this machine's own previously meant
leaving pi and relaunching with BU_CDP_HTTP — and, less obviously, killing the
daemon first, or the switch silently did not happen.

  /browser-target                 show the current target
  /browser-target local           this machine's browser
  /browser-target default         the built-in default
  /browser-target host:port       somewhere else

Precedence becomes env &gt; stored &gt; default. The environment still wins so a
one-off `BU_CDP_HTTP=… pi` is never silently overridden by a choice made days
ago; when it is set, the command says so rather than pretending to obey.
Clearing falls back to the default rather than to local — "use the usual
browser", not "go local".

The daemon is the reason this needed more than a settings write. It is
machine-wide, resolves its target once per process, and holds the WebSocket to
the old browser, so re-reading the store would leave tool calls going to the
old browser while /browser-status reported the new one. The command therefore
replaces the process: the daemon now honours an inbound control/shutdown (the
action already existed in the protocol, previously only sent daemon→client),
and stopDaemon() asks for it and polls until the process is really gone before
ensureDaemon() respawns it against the new target. /browser-status now reads
the store too, so it cannot disagree with what the tools will do.

Persistence mirrors the profile pin: atomic temp-file-plus-rename, and every
read failure degrades to "nothing stored" so a corrupt file falls back to the
default instead of breaking browser control. It is a separate file from the
pin, so damage to one cannot cost you the other. The stored value stays in
BU_CDP_HTTP's vocabulary so there is exactly one resolution path.

62 tests: the full precedence table including the stored tier, that a bad value
is blamed on the source that set it rather than sending you hunting through
shell config, that the command only accepts values resolution can actually use,
and eight ways of damaging the store file.
</content>
</entry>
<entry>
<title>feat(cdp): default to the shared browser, and say so in /browser-status</title>
<updated>2026-10-14T11:17:59+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-07-28T21:08:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/commit/?id=95ff5e8eaefb35d79109f7ddfa1de5bf45a8daff'/>
<id>urn:sha1:95ff5e8eaefb35d79109f7ddfa1de5bf45a8daff</id>
<content type='text'>
Two follow-ups to BU_CDP_HTTP.

Default the endpoint. The remote host is now a built-in default
(DEFAULT_REMOTE_CDP), so nothing has to export BU_CDP_HTTP just to get the
usual setup. The variable becomes an override rather than a requirement.

Precedence is deliberately asymmetric, in src/cdp/endpoint.ts:

  BU_CDP_HTTP=host:port   that endpoint; unreachable is a hard error
  BU_CDP_HTTP=local|off   upstream behaviour, this machine's own browser
  unset                   the default, falling back to local when unreachable

An explicitly configured endpoint is an instruction, so failing to reach it must
not quietly automate a different browser - that would drive the operator's own
signed-in Chrome instead of the shared one. The built-in default is only a
preference, so a laptop away from the network still gets the local browser the
extension was originally written for.

Resolution is pure, with no I/O, so the status command can report the
configured intent without touching the network and the daemon can resolve the
same way in its own process.

/browser-status no longer reports a bare "Disconnected". The connection is lazy
- nothing dials the browser until the first browser_* tool runs - so a fresh
session always showed a red light that reads as a fault. It now distinguishes
"not connected yet, connects on first use" from "target unreachable", and names
the target with a reachability check, so the common confusion answers itself.

26 tests for the resolution table, covering the aliases, malformed values that
must be rejected rather than coerced, and that the default constant is itself
well-formed - if it ever stopped parsing, every machine would silently fall
back to local.
</content>
</entry>
<entry>
<title>fix(daemon): let pi exit after a session has connected to the daemon (#40)</title>
<updated>2026-10-11T19:11:12+00:00</updated>
<author>
<name>Aman Kumar</name>
<email>145339995+amankumarsingh77@users.noreply.github.com</email>
</author>
<published>2026-10-11T19:11:12+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/commit/?id=384688bf85ba5c806a40a059983f43ca537385cb'/>
<id>urn:sha1:384688bf85ba5c806a40a059983f43ca537385cb</id>
<content type='text'>
The client's daemon socket is kept open across sessions by design; in pi -p it was the last
handle keeping Node alive, so a run that had connected to the browser hung after its answer.
Unref the socket; in-flight requests hold their own timers.

Fixes #39

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>fix: browser_download no longer hijacks the user's own downloads (#33)</title>
<updated>2026-10-11T18:39:18+00:00</updated>
<author>
<name>Uttkarsh</name>
<email>38376852+uttkarsh-26@users.noreply.github.com</email>
</author>
<published>2026-10-11T18:39:18+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/commit/?id=2601c90bc0ec54f1e6234d05112c99c458d4ae5e'/>
<id>urn:sha1:2601c90bc0ec54f1e6234d05112c99c458d4ae5e</id>
<content type='text'>
Browser.setDownloadBehavior was sent without a browserContextId, so the override applied to the
user's default context and outlived the session. browser_download now takes restore:true, tracks
the override this process set, and a clean session shutdown restores Chrome's default with a
bounded call that is skipped when the browser is already gone.

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>refactor: remove duplicate browser prompt instructions (#35)</title>
<updated>2026-10-11T18:25:38+00:00</updated>
<author>
<name>Patrick Barattin</name>
<email>p.barattin@gmail.com</email>
</author>
<published>2026-10-11T18:25:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/commit/?id=014de0ec21936a7a2fd64db9d151e73c79bb44ad'/>
<id>urn:sha1:014de0ec21936a7a2fd64db9d151e73c79bb44ad</id>
<content type='text'>
Remove browser instruction text repeated across tool descriptions, parameter schemas, tool
guidelines and the global browser prompt. Tool names, schemas, handlers and concurrency are
unchanged; shared recovery and ownership guidance is now available before and after the browser
connects, and the prompt names which tools are serialized versus observations.

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>test: keep host-provided packages out of dependencies (#36)</title>
<updated>2026-10-11T18:10:29+00:00</updated>
<author>
<name>Uttkarsh</name>
<email>38376852+uttkarsh-26@users.noreply.github.com</email>
</author>
<published>2026-10-11T18:10:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/commit/?id=79526b01f4d3cf16c3cfb46313cf1179f0db40ac'/>
<id>urn:sha1:79526b01f4d3cf16c3cfb46313cf1179f0db40ac</id>
<content type='text'>
Adds a manifest guard (scripts/check-manifest.ts + test/util/manifest-test.ts) so npm run check
fails if a host-provided package such as typebox lands in dependencies, plus a daemon-startup
troubleshooting section in the skill.

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>fix(daemon): stop importing typebox in the daemon process (#38)</title>
<updated>2026-10-11T18:03:25+00:00</updated>
<author>
<name>Aman Kumar</name>
<email>145339995+amankumarsingh77@users.noreply.github.com</email>
</author>
<published>2026-10-11T18:03:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/commit/?id=0fe64593bcc3379032840b35833ea39f23aa9322'/>
<id>urn:sha1:0fe64593bcc3379032840b35833ea39f23aa9322</id>
<content type='text'>
pi installs packages with dev and peer dependencies omitted and supplies typebox only to the
extension host. The daemon is a separate Node process whose import graph reached typebox via
src/cdp/discovery.ts, so from a pi-managed install it crashed with "Cannot find module 'typebox'"
before binding its socket. Parse /json/version with the package's own guards, and add a test that
keeps every package reachable from the daemon a runtime dependency.

Fixes #34

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>fix: append browser state to the session only when it changes (#37)</title>
<updated>2026-10-11T17:58:39+00:00</updated>
<author>
<name>Aman Kumar</name>
<email>145339995+amankumarsingh77@users.noreply.github.com</email>
</author>
<published>2026-10-11T17:58:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-cdp.git/commit/?id=7833e2ecd5dc5fd9d7e63322680711d341d885ee'/>
<id>urn:sha1:7833e2ecd5dc5fd9d7e63322680711d341d885ee</id>
<content type='text'>
persistState appended a browser-harness-state entry on every ownership callback, session_tree
and shutdown, so the append-only session file and Pi Web's "+N custom" chain grew without bound.
A snapshot is now written only when it differs from the last one persisted or restored.

Fixes #26

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;</content>
</entry>
</feed>
