|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## What is DockerLens |
| 6 | + |
| 7 | +A macOS menu bar app that monitors and cleans unused Docker images. Built with Tauri v2 (Rust backend + React frontend). Runs as a tray icon (no dock icon), shows a popover window on click. |
| 8 | + |
| 9 | +## Build & Run |
| 10 | + |
| 11 | +```bash |
| 12 | +npm install # frontend deps (first time) |
| 13 | +npx tauri dev # development with hot reload (Vite on :1420 + Rust rebuild) |
| 14 | +npx tauri build # production .app bundle |
| 15 | +cargo check --manifest-path src-tauri/Cargo.toml # Rust-only type check |
| 16 | +``` |
| 17 | + |
| 18 | +### Key Constraints |
| 19 | + |
| 20 | +- **hyperlocal 0.8** pins hyper to 0.14 — uses `hyper::Client::unix()` and `hyper::Body` which were removed in hyper 1.0. Do not upgrade hyper. |
| 21 | +- **tauri-plugin-positioner** `move_window()` panics if the OS hasn't reported tray position yet — wrapped in `catch_unwind` in `toggle_window()`. |
| 22 | +- **macOSPrivateApi** is enabled in `tauri.conf.json` for transparent window support. |
| 23 | +- Docker socket detection checks `/var/run/docker.sock` first, then `$HOME/.docker/run/docker.sock` (Docker Desktop on macOS). |
| 24 | + |
| 25 | +## Architecture |
| 26 | + |
| 27 | +### Rust Backend (Tauri) |
| 28 | + |
| 29 | +Three modules under `src-tauri/src/`: |
| 30 | + |
| 31 | +- **`lib.rs`** — App entry point. Sets up tray icon, hides dock icon (`ActivationPolicy::Accessory`), manages window toggle/positioning via `tauri-plugin-positioner`, and runs a tokio background polling loop. The polling loop checks unused image size against the user's limit and either auto-cleans or sends a macOS notification (once per breach, reset when usage drops). |
| 32 | +- **`docker.rs`** — Direct Docker Engine API client over Unix socket using `hyperlocal`. No Docker CLI dependency. Provides `list_unused_images()`, `remove_image()`, `remove_all_unused()`, `get_storage_stats()`. V1 only tracks dangling images (no tags). |
| 33 | +- **`commands.rs`** — Thin IPC bridge: each `#[tauri::command]` delegates directly to `docker.rs` or reads/writes settings via `tauri-plugin-store`. |
| 34 | +- **`settings.rs`** — `Settings` struct with `limit_gb`, `auto_clean`, `poll_interval_secs`, `breach_notified`. Persisted via tauri-plugin-store as `settings.json`. |
| 35 | + |
| 36 | +### Frontend (React + Vite) |
| 37 | + |
| 38 | +Source lives in `src/`. Vite dev server runs on `:1420`. |
| 39 | + |
| 40 | +- **`hooks/useDockerImages.ts`** — Central hook that owns all `invoke()` calls. Fetches images, stats, settings in parallel on mount. Listens for `docker-stats-updated` events from the backend polling loop to auto-refresh. |
| 41 | +- **`App.tsx`** — Two tabs: Images (list of dangling images with remove buttons) and Settings (limit slider, auto-clean toggle, poll interval). |
| 42 | +- **`components/`** — `TrayHeader`, `StorageBar`, `ImageList`, `SettingsPanel`. |
| 43 | +- **`types.ts`** — Shared TypeScript interfaces (`DockerImage`, `StorageStats`, `Settings`) mirroring the Rust structs. |
| 44 | +- **`index.css`** — Complete dark-mode styling targeting macOS popover aesthetic. Uses CSS custom properties for theming. |
| 45 | + |
| 46 | +### Data Flow |
| 47 | + |
| 48 | +1. Backend polling loop (`lib.rs`) runs on an interval, checks `docker.rs` for stats, emits `docker-stats-updated` event to frontend. |
| 49 | +2. Frontend hook listens for that event and calls `refresh()` which re-invokes all commands in parallel. |
| 50 | +3. Settings are persisted via `tauri-plugin-store` and read by both the polling loop (Rust side) and the settings panel (frontend side). |
| 51 | + |
| 52 | +### Tauri Plugins Used |
| 53 | + |
| 54 | +- `tauri-plugin-store` — JSON key-value persistence for settings |
| 55 | +- `tauri-plugin-positioner` — Window positioning relative to tray icon |
| 56 | +- `tauri-plugin-notification` — macOS notifications for storage alerts |
| 57 | + |
| 58 | +### IPC Commands |
| 59 | + |
| 60 | +| Command | Args | Returns | |
| 61 | +|---------|------|---------| |
| 62 | +| `list_unused_images` | — | `Vec<DockerImage>` | |
| 63 | +| `remove_image` | `imageId: String` | `()` | |
| 64 | +| `remove_all_unused` | — | `usize` (count removed) | |
| 65 | +| `get_storage_stats` | — | `StorageStats` | |
| 66 | +| `is_docker_running` | — | `bool` | |
| 67 | +| `get_settings` | — | `Settings` | |
| 68 | +| `save_settings` | `settings: Settings` | `()` | |
0 commit comments