diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..d2abdef --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,300 @@ +# AGENTS.md + +## Project Overview + +`xone_macos` is a user-space macOS app that speaks to the Xbox Wireless +Dongle (MediaTek MT76xx chip) and exposes connected controllers as HID +gamepads. It ports the Linux kernel driver `medusalix/xone` to macOS: a C++ +protocol stack (USB, MT76 chip, GIP, auth) plus a Swift app layer. + +Current state: build system and module scaffolding are in place. The +protocol ports land phase by phase; see `PLAN.md`. + +## Build System + +- **Generator:** Ninja (the Xcode generator also works; Unix Makefiles do + not support Swift) +- **CMake minimum:** 3.21 +- **Languages:** C++23 (protocol stack), Swift (app layer) + +### Commands + +Configure: + +```sh +cmake -S . -B build -GNinja -DBUILD_TESTING=ON +``` + +Build: + +```sh +ninja -C build +``` + +Run: + +```sh +./build/xone_app +``` + +Run tests (full Unity output): + +```sh +ninja -C build check +``` + +Run a single test (requires prior build): + +```sh +ninja -C build test_version && ninja -C build test +``` + +> Prefer `ninja -C build check` for everyday use; it builds and runs in +> one step. The built-in `test` target only executes CTest and does not +> trigger a rebuild, so the binaries must already be up to date. + +Configure with AddressSanitizer: + +```sh +cmake -S . -B build-asan -GNinja -DBUILD_TESTING=ON -DENABLE_ASAN=ON +``` + +### Dependencies + +Dependencies are managed via custom `Find*.cmake` scripts in `deps/`. +These scripts use `FetchContent` under the hood to download and build +libraries automatically. + +To add a new dependency: + +1. Add the corresponding `Find.cmake` to `deps/` +2. Add `find_package( REQUIRED)` to `CMakeLists.txt` +3. Link with `::` in `target_link_libraries()` + +### Static Libraries + +The project is split into static libraries, layered bottom-up: + +- **`xone_usb`**: USB transport (IOKit / IOUSBFamily) +- **`xone_auth`**: auth + crypto (ECDH, RSA, SHA transcript/PRF) +- **`xone_mt76`**: MT76 chip protocol (firmware load, EFUSE, radio init, + beacons, pairing, WCID key setup) +- **`xone_gip`**: GIP protocol (client lifecycle, handshake, status + reports) +- **`xone_hid`**: virtual HID gamepad presentation +- **`xone_api`**: C ABI bridge consumed by the Swift app and tests + +The Swift executable `xone_app` links against `xone_api`. + +### CMake Module Path + +`deps/` is added to `CMAKE_MODULE_PATH` so `find_package()` resolves to +the custom scripts instead of system-installed packages. + +## Coding Conventions + +### C++ (protocol stack) + +- **Language:** C++23 +- **Trailing return type** for function signatures + (e.g. `auto fn() -> void`) +- **4-space indentation** +- **No semicolons after closing braces** for namespaces/classes +- `auto` for obvious types (e.g. `auto main(...) -> int`) +- **East const** (e.g. `char const*` not `const char*`) +- **Public members first** in class declarations, private members at the + bottom +- `<>` includes only for system headers (std, OS, etc.) +- `""` includes for third-party dependencies +- **Naming:** `snake_case` for variables, functions, and classes +- **Naming:** `SCREAMING_SNAKE_CASE` only for macros and constants +- **Header extensions:** C++ headers use `.hpp`, C headers use `.h` +- Include order: + 1. C++ standard library headers (``, ``, etc.) + 2. *(blank line)* + 3. C standard library headers (``, ``, etc.) + 4. *(blank line)* + 5. OS-specific headers (IOKit, CoreFoundation, POSIX, etc.) + 6. *(blank line)* + 7. Third-party dependencies (`"unity.h"`, etc.) + 8. *(blank line)* + 9. Local/project headers + +### Swift (app layer) + +- **4-space indentation** +- Types: `UpperCamelCase`; functions, properties, and parameters: + `lowerCamelCase` +- Prefer `let` over `var`; default to immutability +- Use `guard let` for early return; no force-unwraps outside tests +- Keep the app layer thin (UI + lifecycle); protocol work lives in C++ + +### C bridge (`include/app/xone_api.h`) + +- Pure C only: no C++ syntax. The header is imported into Swift via + `-import-objc-header`, so it must compile as C. +- Standard C declaration style; trailing returns and east const do not + apply here. +- Use `stdbool.h` types so Swift sees `Bool`. + +## Shell Scripts + +- Always use `#!/bin/sh` shebang for shell scripts +- Scripts must be POSIX compliant (no bashisms) +- When providing commands to users: + - Windows/PowerShell: use `` ` `` for line continuation + - Unix/Linux/macOS: use `\` for line continuation + +## Commit Messages + +- Follow the 50/72 rule: + - Subject line: max 50 characters + - Body lines: wrapped at 72 characters +- Use conventional commit prefixes (`feat:`, `fix:`, `docs:`, `chore:`, + `ci:`, etc.) +- Separate subject from body with a blank line +- Keep messages concise: no one wants to read a novel in the log +- Always include a `Co-Authored-By:` trailer listing every agent or + model that contributed to the commit. Use one line per co-author: + + ``` + Co-Authored-By: porter (anthropic/claude): scaffolded build system + Co-Authored-By: luna (openai/gpt-5.6-luna): reviewed edge cases + ``` + +Example: + +``` +feat: add C ABI bridge for the Swift app + +Expose xone_version() and xone_dongle_present() through a pure C header +so the Swift app can query the protocol stack. +``` + +## Versioning + +This project follows [Semantic Versioning](https://semver.org). The +version is set in the top-level `CMakeLists.txt` (`project(xone_macos +VERSION ...)`). + +- **Patch** (`x.y.Z`): bump on every commit that changes code. No commit + is too small. +- **Minor** (`x.Y.z`): bump when adding a feature or significant new + capability. +- **Major** (`X.y.z`): bump on breaking API changes. + +## Documentation (Markdown) + +- Wrap normal text and lists at **max 80 columns** (for readability in + terminals and editors). +- **Exceptions**: Tables and code blocks (```` ``` ````) can exceed 80 + columns when formatting requires it (e.g. trees, alignment). +- Use standard Markdown: `**bold**`, `` `inline code` ``, `##` headings, + `-` or numbered lists, fenced code blocks with language hints + (```` ```cpp ````, ```` ```sh ````). +- Keep examples concise, up-to-date, and self-documenting. +- This file (`AGENTS.md`) follows its own rules. +- Do not use em dashes (`—`). Use a colon or rewrite the sentence. + +## Source Layout + +```text +xone_macos/ + CMakeLists.txt # Build configuration + src/ # Protocol stack + app layer + usb/ # USB transport (IOKit / IOUSBFamily) + mt76/ # MT76 chip protocol (port of transport/mt76.c) + gip/ # GIP protocol (port of bus/protocol.c) + auth/ # Auth + crypto (port of auth/) + hid/ # Virtual HID gamepad presentation + app/ # Swift entry point + C ABI bridge + include/ # Headers (common, usb, mt76, gip, auth, hid, app) + tests/ # Unity test suites + deps/ # Custom Find*.cmake scripts (FetchContent) + firmware/ # Downloaded firmware binaries (gitignored) +``` + +## Upstream Reference + +Protocol logic is ported from the Linux kernel driver +[`medusalix/xone`](https://github.com/medusalix/xone). See the "Source +Files to Port" table in `PLAN.md` for the module-by-module mapping and +the "Quick Reference" table in `README.md` for the Linux-to-macOS API +replacements. Kernel idioms (kzalloc, spin locks, URBs, uinput) must be +replaced with their user-space / IOKit equivalents when porting. + +## Behavioral Guidelines + +Reduce common LLM coding mistakes. These guidelines bias toward caution +over speed. For trivial tasks, use judgment. + +### 1. Think Before Coding + +Don't assume. Don't hide confusion. Surface tradeoffs. + +Before implementing: + +- State your assumptions explicitly. If uncertain, ask. +- If multiple interpretations exist, present them, don't pick silently. +- If a simpler approach exists, say so. Push back when warranted. +- If something is unclear, stop. Name what's confusing. Ask. + +### 2. Simplicity First + +Minimum code that solves the problem. Nothing speculative. + +- No features beyond what was asked. +- No abstractions for single-use code. +- No "flexibility" or "configurability" that wasn't requested. +- No error handling for impossible scenarios. +- If you write 200 lines and it could be 50, rewrite it. + +Ask yourself: "Would a senior engineer say this is overcomplicated?" +If yes, simplify. + +### 3. Surgical Changes + +Touch only what you must. Clean up only your own mess. + +When editing existing code: + +- Don't "improve" adjacent code, comments, or formatting. +- Don't refactor things that aren't broken. +- Match existing style, even if you'd do it differently. +- If you notice unrelated dead code, mention it, don't delete it. + +When your changes create orphans: + +- Remove imports/variables/functions that YOUR changes made unused. +- Don't remove pre-existing dead code unless asked. + +Every changed line should trace directly to the user's request. + +### 4. Goal-Driven Execution + +Define success criteria. Loop until verified. + +Transform tasks into verifiable goals: + +- "Add validation" means: write tests for invalid inputs, then make + them pass. +- "Fix the bug" means: write a test that reproduces it, then make it + pass. +- "Refactor X" means: ensure tests pass before and after. + +For multi-step tasks, state a brief plan: + +``` +1. [Step] → verify: [check] +2. [Step] → verify: [check] +3. [Step] → verify: [check] +``` + +Strong success criteria let you loop independently. Weak criteria +("make it work") require constant clarification. + +## Platform Support + +The project targets macOS only (Intel and Apple Silicon). Platform and +compiler detection lives in `deps/Platform.cmake` and `deps/Flags.cmake`. +Swift is compiled by CMake, which requires the Ninja or Xcode generator. diff --git a/PLAN.md b/PLAN.md index 80aeac4..d1ac31d 100644 --- a/PLAN.md +++ b/PLAN.md @@ -214,15 +214,15 @@ Downloaded via `scripts/download-firmware.sh` (port of `install/firmware.sh`). | Linux source | Target | Notes | | ----------------------- | -------------------------- | ---------------------------------- | | `transport/mt76.c` | `src/mt76/mt76.c` | Replace USB calls, remove cfg80211 | -| `transport/mt76.h` | `include/mt76/mt76.h` | Clean up kernel types | -| `transport/mt76_defs.h` | `include/mt76/mt76_defs.h` | Mostly copy (register defs) | +| `transport/mt76.h` | `include/mt76/mt76.hpp` | Clean up kernel types | +| `transport/mt76_defs.h` | `include/mt76/mt76_defs.hpp` | Mostly copy (register defs) | | `bus/protocol.c` | `src/gip/protocol.c` | Replace kernel alloc/lock/debug | -| `bus/protocol.h` | `include/gip/protocol.h` | Clean up kernel types | +| `bus/protocol.h` | `include/gip/protocol.hpp` | Clean up kernel types | | `bus/bus.c` | `src/gip/bus.c` | Client lifecycle management | | `auth/auth.c` | `src/auth/auth.c` | Pure crypto, mostly copy | -| `auth/auth.h` | `include/auth/auth.h` | Copy | -| `auth/crypto.c` | `src/auth/crypto.c` | AES-CCMP, mostly copy | -| `auth/crypto.h` | `include/auth/crypto.h` | Copy | +| `auth/auth.h` | `include/auth/auth.hpp` | Copy | +| `auth/crypto.c` | `src/auth/crypto.cpp` | AES-CCMP, mostly copy | +| `auth/crypto.h` | `include/auth/crypto.hpp` | Copy | | `driver/gamepad.c` | N/A | Replaced by HID layer | ## Build System