Skip to content

Commit 0b2c193

Browse files
authored
docs: refresh AGENTS project guide (#38)
1 parent 1d1af4c commit 0b2c193

1 file changed

Lines changed: 93 additions & 36 deletions

File tree

AGENTS.md

Lines changed: 93 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,21 @@ PR Buddy is a lightweight, cross-platform system tray desktop app that monitors
3131
```
3232
pr-buddy/
3333
├── src/ # Svelte 5 frontend
34-
│ ├── App.svelte # Root component (auth routing, event listener)
34+
│ ├── App.svelte # Root component (auth routing + event listeners)
3535
│ ├── main.ts # Entry point, mounts App
3636
│ ├── lib/
3737
│ │ ├── types.ts # TS interfaces mirroring Rust models (snake_case)
38-
│ │ ├── stores.ts # Svelte stores + groupPrs() section logic
38+
│ │ ├── stores.ts # groupPrs() + shared writable stores
3939
│ │ ├── AuthScreen.svelte # GitHub Device Flow login UI
4040
│ │ ├── PRPanel.svelte # Main panel with grouped sections
4141
│ │ ├── PRSection.svelte # Collapsible section group
4242
│ │ ├── PRCard.svelte # Individual PR row
43-
│ │ └── StatusBadge.svelte # Color-coded status dot
43+
│ │ ├── SettingsPage.svelte # Notification/theme/repo visibility settings
44+
│ │ ├── UpdateDialog.svelte # In-app updater UI
45+
│ │ ├── TitleBar.svelte # Custom frameless title bar controls
46+
│ │ ├── StatusBadge.svelte # Color-coded status dot
47+
│ │ └── theme.svelte.ts # Global theme preference + dark-mode toggling
48+
│ ├── __mocks__/ # Tauri API stubs for vitest/jsdom
4449
│ └── styles/
4550
│ └── app.css # Tailwind directives + dark theme overrides
4651
├── src-tauri/ # Rust backend
@@ -52,20 +57,27 @@ pr-buddy/
5257
│ └── src/
5358
│ ├── main.rs # Desktop entry: calls lib::run()
5459
│ ├── lib.rs # Tauri setup: plugins, tray, commands, poller
55-
│ ├── models.rs # Data types: PullRequest, PrState, CheckStatus, etc.
60+
│ ├── models.rs # Shared data types (PullRequest, PrState, etc.)
5661
│ ├── state.rs # AppState (Mutex-wrapped shared state)
57-
│ ├── auth.rs # Device Flow OAuth commands
62+
│ ├── auth.rs # Device Flow OAuth + token persistence
5863
│ ├── github.rs # GraphQL client + Tauri commands
64+
│ ├── menu.rs # Native tray menu construction + section grouping
5965
│ ├── poller.rs # Background adaptive polling loop
60-
│ └── notifications.rs # Event diffing + OS notification dispatch
66+
│ ├── notifications.rs # Event diffing + OS notification dispatch
67+
│ ├── settings.rs # User settings load/save + IPC commands
68+
│ ├── updater.rs # Update check/install commands + events
69+
│ └── avatars.rs # Avatar fetch/cache for tray menu icons
6170
├── scripts/
62-
│ ├── generate_icons.py # Python3+Pillow icon generator (idempotent)
63-
│ └── smoke-test.sh # Dev server import smoke test
64-
├── src/__mocks__/ # Tauri API stubs for vitest/jsdom
71+
│ ├── smoke-test.sh # Vite dev import-resolution smoke test
72+
│ ├── check_pr_reviews.sh # CI helper: unresolved review thread check
73+
│ ├── check_codex_comments.sh # CI helper: Codex approval/comment status
74+
│ ├── wait_pr_checks.sh # Poll helper: wait until checks/mergeability pass
75+
│ ├── wait_pr_codex.sh # Poll helper: wait for Codex final signal
76+
│ └── generate_icons.py # Python icon generator (cairosvg + Pillow)
6577
├── package.json
66-
├── Makefile # dev/build/check/test/smoke/ci targets
78+
├── Makefile # install/dev/build/check/test/smoke/ci/clean targets
6779
├── vite.config.ts
68-
├── vitest.config.ts # Test runner config (jsdom + Tauri mocks)
80+
├── vitest.config.ts # Test config (jsdom + Tauri mocks)
6981
├── svelte.config.js
7082
├── tailwind.config.js
7183
├── postcss.config.js
@@ -74,14 +86,16 @@ pr-buddy/
7486

7587
### Key Files
7688

77-
- **`src-tauri/src/lib.rs`** — App entry point. Registers all plugins, builds the tray icon, wires Tauri commands, starts the background poller.
78-
- **`src-tauri/src/models.rs`** — Canonical data types shared across backend. Frontend types in `src/lib/types.ts` must stay in sync (use `snake_case` field names, matching Rust's `#[serde(rename_all = "lowercase")]`).
79-
- **`src-tauri/src/auth.rs`** — GitHub Device Flow. Client ID is hardcoded with env var override (`GITHUB_CLIENT_ID`).
80-
- **`src-tauri/src/poller.rs`** — Adaptive polling: 30s when PRs have pending checks or are in merge queue, 120s otherwise.
81-
- **`src-tauri/src/notifications.rs`**`diff_pr_states()` compares old/new PR snapshots to detect state transitions.
82-
- **`src-tauri/tauri.conf.json`** — Window is hidden by default (tray-only), 380×520px, no decorations, `alwaysOnTop`.
83-
- **`src/lib/stores.ts`**`groupPrs()` categorises PRs into ordered sections (merge queue → failing → changes requested → waiting → approved → draft → merged).
84-
- **`src/App.svelte`** — Root component. Handles auth check, Tauri event subscription (`prs-updated`), routing between AuthScreen and PRPanel.
89+
- **`src-tauri/src/lib.rs`** — App entry point. Registers plugins, tray, IPC commands, menu events, and starts the poller.
90+
- **`src-tauri/src/models.rs`** + **`src/lib/types.ts`** — Canonical cross-layer types. Keep fields and enum values in sync.
91+
- **`src-tauri/src/menu.rs`** + **`src/lib/stores.ts`** — Two implementations of PR grouping (tray menu + Svelte panel). Keep section logic aligned.
92+
- **`src-tauri/src/auth.rs`** — GitHub Device Flow plus persisted token load/save/delete.
93+
- **`src-tauri/src/settings.rs`** — User settings storage (`settings.json`) and settings commands.
94+
- **`src-tauri/src/updater.rs`** + **`src/lib/UpdateDialog.svelte`** — Update check/install flow and download progress events.
95+
- **`src-tauri/src/poller.rs`** — Adaptive polling (30s active / 120s idle) plus periodic update checks.
96+
- **`src-tauri/src/notifications.rs`**`diff_pr_states()` and notification dispatch (gated by settings).
97+
- **`src-tauri/tauri.conf.json`** — Hidden-by-default tray window (380×520), CSP allowlist, updater endpoint config.
98+
- **`src/App.svelte`** — Root runtime: auth bootstrap, event listeners (`prs-updated`, `auth-cleared`, `open-settings`), and view routing.
8599

86100
### Tauri Commands (IPC boundary)
87101

@@ -94,14 +108,21 @@ All commands are registered in `lib.rs` via `invoke_handler`. Frontend calls the
94108
| `logout_cmd` | auth.rs | `()` |
95109
| `is_authenticated_cmd` | auth.rs | `bool` |
96110
| `get_pull_requests_cmd` | github.rs | `Vec<PullRequest>` |
97-
| `get_user_info_cmd` | github.rs | `GitHubUser` |
111+
| `get_user_info_cmd` | github.rs | `Option<GitHubUser>` |
98112
| `refresh_prs_cmd` | github.rs | `Vec<PullRequest>` |
113+
| `get_settings_cmd` | settings.rs | `UserSettings` |
114+
| `save_settings_cmd` | settings.rs | `()` |
115+
| `check_for_update_cmd` | updater.rs | `UpdateCheckResult` |
116+
| `install_update_cmd` | updater.rs | `()` |
99117

100118
### Tauri Events
101119

102120
| Event | Direction | Payload |
103121
|-------|-----------|---------|
104122
| `prs-updated` | Rust → Frontend | `PullRequest[]` |
123+
| `auth-cleared` | Rust → Frontend | `()` |
124+
| `open-settings` | Rust → Frontend | `()` |
125+
| `update-download-progress` | Rust → Frontend | `{ chunk_length, content_length }` |
105126

106127
### Linux Prerequisites
107128

@@ -121,31 +142,42 @@ The `.deb` and `.rpm` bundles declare this as a package dependency so it install
121142
# Install frontend dependencies (required before any other command)
122143
npm install # or: make install
123144

124-
# Full Tauri app — Rust backend + Vite frontend (requires Rust 1.77+)
145+
# Full desktop dev loop (Tauri backend + Vite frontend)
125146
make dev # or: npm run dev
126147

127-
# Build release binary (output in src-tauri/target/release/bundle/)
128-
make build # or: npm run build
129-
130-
# Frontend-only dev server (no Rust compilation, for UI iteration)
148+
# Frontend-only dev server (no Rust compilation)
131149
npm run vite:dev
132150

133-
# Frontend production build only
134-
npm run vite:build
151+
# Production builds
152+
make build # or: npm run build
153+
npm run vite:build # frontend-only production bundle
135154

136-
# TypeScript + Svelte type checking
155+
# Type-check + tests
137156
make check # or: npm run check
138-
139-
# Run component tests (vitest + jsdom)
140157
make test # or: npm run test
141-
142-
# Smoke test — starts Vite dev server and verifies no import errors
143158
make smoke # or: npm run smoke
144159

145-
# Run ALL pre-push checks (check + test + smoke + build)
160+
# Rust checks (run when touching src-tauri)
161+
(cd src-tauri && cargo check)
162+
163+
# Formatting
164+
(cd src-tauri && cargo fmt)
165+
# Frontend: no dedicated formatter script is configured yet.
166+
167+
# Linting
168+
(cd src-tauri && cargo clippy -- -D warnings)
169+
# Frontend: no ESLint script is configured yet.
170+
171+
# CI shortcut (check + test + smoke + build)
146172
make ci
147173

148-
# Regenerate app icons (requires Python 3 + Pillow)
174+
# PR workflow helper scripts
175+
./scripts/check_pr_reviews.sh <pr_number>
176+
./scripts/check_codex_comments.sh <pr_number>
177+
./scripts/wait_pr_checks.sh <pr_number>
178+
./scripts/wait_pr_codex.sh <pr_number>
179+
180+
# Regenerate app and tray icons (requires Python 3, cairosvg, Pillow)
149181
python3 scripts/generate_icons.py
150182

151183
# Clean build artifacts
@@ -172,9 +204,32 @@ export type PrState = "open" | "closed" | "merged";
172204

173205
When adding a field to `PullRequest`, update **both** `models.rs` and `types.ts`.
174206

207+
### Frontend ↔ Tray Section Parity
208+
209+
PR grouping logic exists in **two places**:
210+
- `src/lib/stores.ts` (`groupPrs()` for the Svelte panel)
211+
- `src-tauri/src/menu.rs` (`group_prs()` for the native tray menu)
212+
213+
When adding/removing/renaming a section, update both implementations in the same change.
214+
Also update assertions in `src/lib/components.test.ts` so section behavior stays covered.
215+
216+
### Interpreting User Requests (Tray-First Default)
217+
218+
This app has two UI surfaces:
219+
- **Native tray menu** (Rust): `src-tauri/src/menu.rs`
220+
- **Svelte webview panel/windows**: `src/App.svelte` + `src/lib/*.svelte`
221+
222+
When a user asks for a "UI", "menu", "section", or "status" change **without naming a surface**, assume they mean the **native tray menu first**. Most day-to-day usability is in the tray.
223+
224+
Only treat a request as webview-only when the user explicitly references panel/window behavior (for example: settings page, updater dialog, title bar, Auth screen, PR cards).
225+
226+
If both surfaces are plausible, either:
227+
1. ask a clarifying question, or
228+
2. state the assumption explicitly and implement tray-first.
229+
175230
### Tauri Command Pattern
176231

177-
Rust commands use `#[tauri::command]` and return `Result<T, AuthError>`. The `AuthError` type implements `Serialize` so Tauri can pass errors to the frontend. Commands access shared state via `State<'_, AppState>`:
232+
Rust commands use `#[tauri::command]` and return `Result<T, E>` where `E` is serializable (`AuthError` for auth/github commands, `String` for settings/updater). Commands that need shared state access it via `State<'_, AppState>`:
178233

179234
```rust
180235
#[tauri::command]
@@ -227,6 +282,8 @@ Do **not** write `onMount(async () => { ... return cleanup; })`.
227282
## Anti-Patterns
228283

229284
- **Do not change `npm run dev`/`npm run build` to call Vite.** These must call `tauri dev`/`tauri build`. Frontend-only scripts are `vite:dev`/`vite:build`.
285+
- **Do not update PR section grouping in only one layer.** `src/lib/stores.ts` and `src-tauri/src/menu.rs` must stay in sync, and `src/lib/components.test.ts` should be updated when section behavior changes.
286+
- **Do not assume ambiguous UX requests target the Svelte webview.** Default to tray-menu changes unless the user clearly asks for panel/window behavior.
230287
- **Do not pass arguments to `TrayIconBuilder::new()`.** Tauri v2.10 takes zero arguments. Use `.icon()` to set the icon separately.
231288
- **Do not use `async` `onMount` callbacks that return cleanup functions** in Svelte 5 — it causes type errors. See the pattern above.
232289
- **Do not use the bundle identifier `com.prbuddy.app`.** The `.app` suffix conflicts with macOS bundle extensions. Current identifier: `com.prbuddy.dev`.
@@ -286,7 +343,7 @@ Common prefixes: `feat`, `fix`, `chore`, `refactor`, `docs`.
286343

287344
1. Run `make ci` — this runs type-check, unit tests, smoke test, and production build in sequence.
288345
2. Alternatively, run them individually: `npm run check`, `npm run test`, `npm run smoke`, `npm run vite:build`.
289-
3. If Rust code changed and Rust 1.77+ is available, run `cargo check` in `src-tauri/`.
346+
3. If Rust code changed and Rust 1.77+ is available, run `(cd src-tauri && cargo fmt && cargo clippy -- -D warnings && cargo check)`.
290347
4. Do not push to `origin/main` or `origin/master` directly.
291348
5. Branch names must be prefixed with `mike/` (e.g., `mike/fix-tray-click`).
292349
6. **Do not claim imports or dependencies work without running `make smoke`**`vite build` and `svelte-check` do not catch all import resolution errors that appear in the Vite dev server.

0 commit comments

Comments
 (0)