# Changelog

All notable changes to gsearch-mcp-cli will be documented in this file.

Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.0.8] - 2026-03-28

### Fixed

- **macOS Keychain dialogs** — headless Chrome launched by gsearch was triggering repeated "Keychain Not Found" system dialogs on macOS. Added `--use-mock-keychain` and `--password-store=basic` to the Darwin Chrome launch flags, replacing macOS Keychain access with an in-memory mock. The dialog no longer appears and does not affect user-facing Chrome or other tools.

## [0.0.7] - 2026-03-27

### Fixed

- **Parallel CLI exit 21 race condition** — three concurrent `gsearch` invocations would all attempt to launch Chrome, causing profile lock contention. Added a cross-process `fcntl.flock` launch lock (`chrome-launch.lock`) in `connect_or_launch()` so only one process enters the check-then-launch critical section at a time.
- **Search retry killing shared Chrome** — when a websocket error occurred during search, the retry path called `_invalidate_browser()` which killed Chrome and disrupted other parallel CLI processes. Replaced with `_soft_reconnect()` which drops the cached CDP reference without killing the Chrome process, allowing re-discovery through the port map.

### Added

- **`_soft_reconnect()`** — gentle browser state reset that clears the cached `BrowserCDP` without terminating Chrome, preserving shared access for parallel CLI/MCP operations.
- **Exponential backoff in `connect_or_launch`** — if launch fails with exit 1/21 inside the lock, polls `connect_existing()` with backoff delays (1s, 2s, 4s) to wait for a peer process's Chrome to become available.

## [0.0.6] - 2026-03-26

### Fixed

- **`gsearch ai` fails with "Chrome exited with code 21"** — caused by profile lock contention when the MCP server (long-running) and CLI (one-shot) both launched Chrome against the same `--user-data-dir`. CLI now detects and reuses an already-running Chrome instance via the port map instead of launching a second one
- **Port map never cleaned up** — `shared.shutdown()` was not passing the port to `shutdown_chrome()`, leaving stale entries in `chrome-port-map.json` after every CLI run

### Added

- **`connect_existing()`** — checks the port map for a live Chrome instance and reuses it, preventing profile collision between MCP server and CLI
- **`connect_or_launch()` orchestrator** — wraps the retry and connection logic to first attempt connecting to an existing session before launching, preventing CLI conflicts with a running MCP server.
- **Port map file locking** — implemented robust concurrent `fcntl` locks for `chrome-port-map.json` reads and writes.
- **`ChromeLaunchError` exception** — structured error with `exit_code` and `stderr` fields replaces the bare `CDPConnectionError("Chrome exited with code N")`
- **Search-level retry** — implemented resilience logic to automatically re-try an active search if the CDP connection dies mid-flight.
- **Chrome stderr capture** — `_drain_stderr()` captures Chrome's error output on crash (previously discarded entirely)
- **Profile lock cleanup + retry** — `_clear_profile_locks()` removes stale `SingletonLock`/`SingletonSocket`/`SingletonCookie` files, and `launch_chrome()` retries once unconditionally on exit codes 1 or 21, even if the contention is from an active process rather than stale files.
- **Crash dump isolation** — disabled Chrome standard crash dumps into the profile path to prevent further file locking errors.
- 14 new tests (112 total)

## [0.0.4] - 2026-03-22

### Added

- **`gsearch setup add all`** — now actually installs MCP server to every supported tool (was only listing tools previously)
- **`gsearch skill install all`** — install skill files to all tool directories in one command, with path deduplication
- **Version transition on `gsearch skill update`** — shows `Updating tool (user): v0.0.3 → v0.0.4` with installed file listing, matching the NLM update format
- **Added/Updated detection for MCP setup** — `gsearch setup add` now detects existing configs and displays `Updated gsearch-mcp (v0.0.4)` vs `Added gsearch-mcp (v0.0.4)` with package version
- **Comma-separated tool support** — both `gsearch setup add cursor,gemini-cli` and `gsearch skill install claude-code,cline` now work for installing to multiple tools in one command

### Changed

- `_setup_claude_code()` and `_setup_codex()` simplified — extracted shared `_add_single_tool()` helper with unified error handling
- 98 tests (up from 86), including 8 new tests for all new features

## [0.0.3] - 2026-03-22

### Fixed

- **`--type news` + `--json` returns empty results** — Google's News tab (`tbm=nws`) uses `role="heading"` instead of `h3` elements, so the standard DOM extractor found nothing. Added `NEWS_EXTRACT_JS` with two-strategy extraction (role="heading" primary, external-link fallback) and automatic routing when `search_type="news"`

## [0.0.2] - 2026-03-22

### Added

- **Search type filtering** -- `--type` flag for news, images, videos, shopping, books, forums, short_videos. Combines with time filters for powerful queries like `gsearch "AI news" --type news --time day`
- **Granular time filters** -- 12h, arbitrary Nh patterns (e.g., 6h), and aliases (1h, 24h, 7d, 1w, 1m, 1y)
- **MCP setup command** -- `gsearch setup add <tool>` configures MCP server for Claude Code, Gemini CLI, Cursor, Windsurf, Cline, Antigravity, Codex, OpenCode
- **Expanded skill targets** -- cc-claw, opencode, antigravity, cline, agents, other (11 total)
- **Default command** -- `gsearch "query"` works without typing `search`
- **Date range filtering** -- `--after` and `--before` flags with YYYY-MM-DD format

### Fixed

- Lint clean (ruff) across all source and test files
- CDP test race condition on Python 3.11
- `uv tool install` in README (was `uv pip install`)
- `--ai` flag restored (was incorrectly renamed to `--docs`)

## [0.0.1] - 2026-03-22

### Added

- **Google Search** (`gsearch search` / `gsearch "query"`) — regular Google search with AI Overview, organic results, People Also Ask, and related searches
- **Google AI Mode** (`gsearch ai`) — synthesized AI response with structured sections and cited sources, equivalent to g.ai
- **Page Fetching** (`gsearch fetch`) — fetch any URL and convert to clean Markdown using trafilatura + html-to-markdown. SSRF-safe with IPv4/IPv6 validation
- **MCP Server** (`gsearch-mcp`) — 3 tools: `gsearch_search`, `gsearch_ai`, `gsearch_fetch` for AI agent integration via Model Context Protocol
- **Time/Date Filtering** — `--time` flag (hour, 1h, 12h, day, 24h, week, 7d, month, year) and `--after`/`--before` for custom date ranges. Supports arbitrary `Nh` patterns (e.g., 6h = last 6 hours)
- **Browser Automation** — headless Chrome via CDP (Chrome DevTools Protocol) with persistent warmed profile. No authentication needed
- **Multi-Browser Support** — auto-detects Chrome, Brave, Edge, Chromium, Vivaldi, Opera, Opera GX on macOS, Linux, and Windows
- **MCP Setup** (`gsearch setup add`) — configure MCP server for Claude Code, Gemini CLI, Cursor, Windsurf, Cline, Antigravity, Codex, and OpenCode
- **Skill Installer** (`gsearch skill install`) — install SKILL.md for Claude Code, Cursor, Codex, Gemini CLI, OpenCode, Antigravity, Cline, OpenClaw, CC-Claw, and generic agents
- **Profile Warmup** (`gsearch setup`) — one-time ~8s warmup establishes BotGuard trust cookies for anonymous Google access
- **Configuration** (`gsearch config`) — persistent config for browser preference, language, region, rate limits, timeouts
- **Diagnostics** (`gsearch doctor`) — check browser, profile, config, and connectivity
- **Rate Limiting** — built-in token bucket (default 1 search/2s, burst of 3) to prevent Google blocking
- **Crash Recovery** — auto-relaunch Chrome on CDP connection failure
- **Tab Context Manager** — guaranteed tab cleanup on error, max 5 concurrent tabs
- **Error Sanitization** — MCP responses strip file paths, PIDs, and port numbers
- **JSON Output** — `--json` flag on all search/fetch commands for programmatic use
- **AI Documentation** — `gsearch --docs` prints LLM-optimized reference for AI agents

### Security

- SSRF prevention in `gsearch fetch`: scheme whitelist (http/https only), private IP blocklist, DNS pre-resolution, IPv6 validation
- CDP restricted to `--remote-allow-origins=http://localhost`
- TOCTOU-safe port allocation via `--remote-debugging-port=0` + stderr parsing
- Error sanitization prevents information leakage to MCP clients

### Technical

- Python 3.10+, async throughout (websockets library for CDP)
- Pydantic BaseModel for all data models with automatic JSON serialization
- Single shared backend (`shared.py`) serves both CLI and MCP
- Click + rich-click for CLI, FastMCP for MCP server
- 86 unit tests, 1 integration test
