From da5d31af999b728c31ab0169373531cab4543f0c Mon Sep 17 00:00:00 2001 From: Aman Kumar <145339995+amankumarsingh77@users.noreply.github.com> Date: Sun, 21 Jun 2026 00:46:44 +0530 Subject: release: v0.6.0 — per-tab isolation, Unix socket daemon, on-demand init (#6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Unix socket daemon with auto-reconnect for persistent Chrome CDP Eliminates the 'Allow Remote Debugging' Chrome prompt that appeared on every pi session by multiplexing pi instances through a single persistent daemon process. Key additions: - Unix socket IPC (net.createServer + readline JSON framing) - CdpBridge with ID multiplexer + event router - DaemonTransport implementing CdpTransport interface - Auto-spawn with ensureDaemon() (lazy, checks socket) Fixes since initial implementation: - Bridge auto-reconnects to Chrome with exponential backoff (1s-60s). Previously the bridge tried once at startup and permanently failed if Chrome wasn't ready — causing 'Chrome not connected' on every browser tool call. - Daemon spawn uses project-local tsx binary instead of global --import flag, fixing silent spawn failure (ERR_MODULE_NOT_FOUND). - Stale ctx crash: persistState in onOwnershipChange wrapped in try/catch to prevent CDP event consumer crashes. 49 test assertions across 4 test files. Zero TypeScript errors. * feat: on-demand browser initialization Browser daemon no longer auto-starts on session_start. Instead: - session_start creates the client lazily but does NOT connect or spawn the daemon. Zero Chrome prompts for non-browser pi sessions. - Browser tool wrapper checks for daemon socket before each call. Socket missing → clear error: 'Run /browser-setup first'. Socket exists → proceeds silently (daemon already running). - /browser-setup is the explicit, one-time init point. It spawns the daemon and connects to Chrome only when the user opts in. - SKILL.md updated with Connection Setup instructions telling agents to direct users to /browser-setup when socket is missing. * fix: checkChromeRunning on macOS — match by substring not exact ps -A -o comm= returns full executable paths on modern macOS (e.g. /Applications/Google Chrome.app/Contents/MacOS/Google Chrome), not the basename. The old exact-match check (browserProcesses.includes(l)) never matched, causing false 'No browser instance running' errors. Changed to substring includes() with helper/renderer/crashpad filtering. * feat: browser_setup as agent-callable tool The agent can now self-recover from 'Browser harness not initialized' errors by calling browser_setup directly — no user mediation needed. - Extracted shared performSetup() from the slash command into setup.ts - Created src/domains/setup.ts with ensureAlive:false to bypass the socket guard (this tool IS the setup, can't require itself) - Registered browser_setup in the tool registry - Updated SKILL.md: agent calls browser_setup directly, not ask user - Removed stale test/manual/spawn-test.ts * release: v0.6.0 — per-tab isolation, Unix socket daemon, on-demand init --- src/util/tool.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src/util') diff --git a/src/util/tool.ts b/src/util/tool.ts index c2bb3f8..1e33c43 100644 --- a/src/util/tool.ts +++ b/src/util/tool.ts @@ -9,6 +9,8 @@ import type { ToolRenderResultOptions, } from "@mariozechner/pi-coding-agent"; import type { Component } from "@mariozechner/pi-tui"; +import { access } from "node:fs/promises"; +import { DAEMON_SOCKET_PATH } from "../daemon/protocol"; import type { BrowserClient } from "../client"; import type { Result } from "./result"; @@ -142,6 +144,23 @@ export const registerBrowserTool = ( : {}), async execute(_toolCallId, args, signal, onUpdate, extensionCtx) { if (def.ensureAlive !== false) { + // Check daemon socket exists before attempting browser control. + // If missing, the user hasn't run /browser-setup yet. Return a clear + // error so the agent knows to direct the user to initialize. + try { + await access(DAEMON_SOCKET_PATH); + } catch { + return toToolResult( + { + success: false, + error: { + kind: "not_connected", + message: "Browser harness not initialized. Run /browser-setup first", + }, + }, + def.name, + ); + } const alive = await client.ensureAlive(); if (!alive.success) { return toToolResult( -- cgit v1.2.3