diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..826b84c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,17 @@ +# Agent CLI Notes + +The `pubcli` CLI is intentionally tolerant of minor syntax mistakes when intent is clear. + +Accepted flexible forms include: +- `-zip 33101` -> interpreted as `--zip 33101` +- `zip=33101` -> interpreted as `--zip=33101` +- `--ziip 33101` -> interpreted as `--zip 33101` +- `categoriess` -> interpreted as `categories` + +The CLI prints a `note:` line when it auto-corrects input. Use canonical syntax in future commands: +- `pubcli --zip 33101` +- `pubcli --store 1425 --bogo` +- `pubcli categories --zip 33101` +- `pubcli stores --zip 33101 --json` + +When intent is unclear, errors include a direct explanation and relevant examples. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cb84b53 --- /dev/null +++ b/README.md @@ -0,0 +1,219 @@ +# pubcli + +`pubcli` is a Go CLI for fetching current Publix weekly ad deals by store number or ZIP code. + +## Features + +- Fetch weekly ad deals for a specific store +- Resolve nearest Publix store from a ZIP code +- Filter deals by category, department, keyword, and BOGO status +- List weekly categories with deal counts +- Output data as formatted terminal text or JSON +- Generate shell completions (`bash`, `zsh`, `fish`, `powershell`) +- Tolerate minor CLI syntax mistakes when intent is clear +- Robot-mode behavior for AI agents (compact help, auto JSON when piped, structured errors, meaningful exit codes) + +## Requirements + +- Go `1.24.4` or newer to build from source +- Network access to: + - `https://services.publix.com/api/v4/savings` + - `https://services.publix.com/api/v1/storelocation` + +## Installation + +### Build locally + +```bash +git clone https://github.com/tayloree/publix-deals.git +cd publix-deals +go build -o pubcli ./cmd/pubcli +``` + +### Install with `go install` + +```bash +go install github.com/tayloree/publix-deals/cmd/pubcli@latest +``` + +## Quick Start + +Find nearby stores: + +```bash +pubcli stores --zip 33101 +``` + +Fetch deals using a store number: + +```bash +pubcli --store 1425 +``` + +Fetch deals by ZIP (uses the nearest store): + +```bash +pubcli --zip 33101 +``` + +Fetch JSON output: + +```bash +pubcli --zip 33101 --json +``` + +## Commands + +### `pubcli` + +Fetch weekly ad deals. + +```bash +pubcli [flags] +``` + +### `pubcli stores` + +List up to 5 nearby stores for a ZIP code. + +```bash +pubcli stores --zip 33101 +pubcli stores -z 32801 --json +``` + +### `pubcli categories` + +List available categories for the current week. + +```bash +pubcli categories --store 1425 +pubcli categories -z 33101 --json +``` + +## Flags + +Global flags: + +- `-s, --store string` Publix store number (example: `1425`) +- `-z, --zip string` ZIP code for store lookup +- `--json` Output JSON instead of styled terminal output + +Deal filtering flags (`pubcli` root command): + +- `--bogo` Show only BOGO deals +- `-c, --category string` Filter by category (example: `bogo`, `meat`, `produce`) +- `-d, --department string` Filter by department (substring match, case-insensitive) +- `-q, --query string` Search title/description (case-insensitive) +- `-n, --limit int` Limit results (`0` means no limit) + +## Behavior Notes + +- Either `--store` or `--zip` is required for deal and category lookups. +- If only `--zip` is provided, the nearest store is selected automatically. +- When using text output and ZIP-based store resolution, the selected store is shown. +- Filtering is applied in this order: `bogo`, `category`, `department`, `query`, `limit`. +- Category matching is exact and case-insensitive. +- Department and query filters use case-insensitive substring matching. +- Running `pubcli` with no args prints compact quick-start help. +- When stdout is not a TTY (for example piping to another process), JSON output is enabled automatically unless explicitly set. + +## CLI Input Tolerance + +The CLI auto-corrects common input mistakes and prints a `note:` describing the normalization: + +- `-zip 33101` -> `--zip 33101` +- `zip=33101` -> `--zip=33101` +- `--ziip 33101` -> `--zip 33101` +- `stores zip 33101` -> `stores --zip 33101` + +Command argument tokens are preserved for command workflows like: + +- `pubcli completion zsh` +- `pubcli help stores` + +## JSON Output + +### Deals (`pubcli ... --json`) + +Array of objects with fields: + +- `title` (string) +- `savings` (string) +- `description` (string) +- `department` (string) +- `categories` (string[]) +- `additionalDealInfo` (string) +- `brand` (string) +- `validFrom` (string) +- `validTo` (string) +- `isBogo` (boolean) +- `imageUrl` (string) + +### Stores (`pubcli stores ... --json`) + +Array of objects with fields: + +- `number` (string) +- `name` (string) +- `address` (string) +- `distance` (string) + +### Categories (`pubcli categories ... --json`) + +Object map of category name to deal count: + +```json +{ + "bogo": 175, + "meat": 88, + "produce": 81 +} +``` + +## Structured Errors + +When command execution fails, errors include: + +- `code` (example: `INVALID_ARGS`, `NOT_FOUND`, `UPSTREAM_ERROR`) +- `message` +- `suggestions` (when available) +- `exitCode` + +JSON-mode errors are emitted as: + +```json +{"error":{"code":"INVALID_ARGS","message":"unknown flag: --ziip","suggestions":["Try `--zip`.","pubcli --zip 33101"],"exitCode":2}} +``` + +## Exit Codes + +- `0` success +- `1` not found +- `2` invalid arguments +- `3` upstream/network failure +- `4` internal failure + +## Shell Completion + +Generate completions: + +```bash +pubcli completion bash +pubcli completion zsh +pubcli completion fish +pubcli completion powershell +``` + +## Development + +Run tests: + +```bash +go test ./... +``` + +Run without building: + +```bash +go run ./cmd/pubcli --zip 33101 --limit 10 +```