feat: per-tab agent isolation via BROWSE_TAB environment variable

Prevents parallel sidebar agents from interfering with each other's tab context.

Three-layer fix:
- sidebar-agent.ts: passes BROWSE_TAB=<tabId> env var to each claude process,
  per-tab processing set allows concurrent agents across tabs
- cli.ts: reads process.env.BROWSE_TAB and includes tabId in command request body
- server.ts: handleCommand() temporarily switches activeTabId when tabId is present,
  restores after command completes (safe: Bun event loop is single-threaded)

Also: per-tab agent state (TabAgentState map), per-tab message queuing,
per-tab chat buffers, verbose streaming narration, stop button endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-03-29 22:19:26 -07:00
parent dcf1b0d7ef
commit 54fec2dc08
3 changed files with 313 additions and 95 deletions

View File

@@ -376,7 +376,9 @@ async function ensureServer(): Promise<ServerState> {
// ─── Command Dispatch ──────────────────────────────────────────
async function sendCommand(state: ServerState, command: string, args: string[], retries = 0): Promise<void> {
const body = JSON.stringify({ command, args });
// BROWSE_TAB env var pins commands to a specific tab (set by sidebar-agent per-tab)
const browseTab = process.env.BROWSE_TAB;
const body = JSON.stringify({ command, args, ...(browseTab ? { tabId: parseInt(browseTab, 10) } : {}) });
try {
const resp = await fetch(`http://127.0.0.1:${state.port}/command`, {