# Agent Instructions

## Project

CLI tool that fetches places from public Google Maps saved lists and searches for places using Google Maps' internal APIs. Built with Bun, TypeScript, Commander, and Chalk.

## Stack

- **Runtime**: Bun (run TS directly, no build step)
- **Language**: TypeScript with strictest settings (`strict`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`)
- **CLI framework**: Commander
- **Styling**: Chalk
- **No external HTTP libraries** — uses Bun's built-in `fetch`

## Install

```bash
# Run directly
bunx @kvendrik/gmaps search "Eiffel Tower"

# Or install globally
bun install -g @kvendrik/gmaps
```

## Commands

```
gmaps list <url|alias> [-q query] [-e] [-f json|table]
gmaps search <query> [-f json|table]
gmaps lists add|rm|ls
```

## Architecture

```
src/
  index.ts          # Entry point, Commander setup, orchestration
  types.ts          # All shared type definitions
  lib/
    url.ts          # URL resolution and list ID extraction
    api.ts          # entitylist/getlist endpoint (fetches all places from a list)
    search.ts       # /search?tbm=map endpoint (place details: ratings, categories, etc.)
    enrich.ts       # Enriches list places with search data
    filter.ts       # Text-based place filtering
    output.ts       # Table and JSON formatters
    config.ts       # Alias storage (~/.gmaps.json)
```

## Key APIs

Both endpoints are undocumented Google internals. Response format is JSON prefixed with `)]}'\n` (XSSI protection — strip before parsing). Full details in `planning/research.md`.

- **List endpoint**: `GET /maps/preview/entitylist/getlist?pb=!1m1!1s{LIST_ID}!2e2!3e2!4i10000!16b1` — returns all places in one request. No auth needed.
- **Search endpoint**: `GET /search?tbm=map&hl=en&q={QUERY}` — returns place details (rating, categories, phone, website, hours). Works for specific place names, not generic queries.

## Response Parsing

Google's responses use deeply nested arrays with numeric indices (protobuf-like). The `noUncheckedIndexedAccess` TS flag is critical — every array access must be null-checked. See `api.ts` and `search.ts` for the parsing logic.

## Type Checking

```
bunx tsc --noEmit
```

## Testing

No test framework. Test manually:

```bash
# Basic list fetch
gmaps list https://maps.app.goo.gl/your-list-url

# Filtered + enriched
gmaps list https://maps.app.goo.gl/your-list-url -q "De Waaghals" -e

# Search
gmaps search "Eiffel Tower"

# JSON output
gmaps search "Eiffel Tower" -f json
```

## Config

Aliases stored in `~/.gmaps.json` (override with `GMAPS_CONFIG` env variable). Format:

```json
{
  "lists": {
    "alias": "https://maps.app.goo.gl/..."
  }
}
```
