From bc415ce6a1eb929d5effd2aaecd2a65341b4cf12 Mon Sep 17 00:00:00 2001 From: wenil Date: Fri, 19 Jun 2026 11:44:18 +0300 Subject: [PATCH] docs: full README with architecture, setup, tech details --- README.md | 197 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 128 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index eebd352..85af176 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,136 @@ -# Claude Meter — лимит Claude Code на часах +# Claude Meter -Минимальное Wear OS приложение для Galaxy Watch 6 Classic (и любых Wear OS 3+). -Опрашивает `api.anthropic.com` так же, как [Clawdmeter](https://github.com/HermannBjorgvin/Clawdmeter), -но без ESP32/демона/BLE — часы ходят на API сами по WiFi. +Минимальное Wear OS приложение для **Galaxy Watch 6 Classic** (и любых Wear OS 3+). +Показывает утилизацию rate-limit Claude Code прямо на часах — 5h и 7d окна. -Показывает: -- **5h** — загрузка 5-часового окна (%) и минуты до сброса -- **7d** — загрузка недельного окна (%) и минуты до сброса -- **status** — `normal` / `banned` / `unknown` +灵感: [Clawdmeter](https://github.com/HermannBjorgvin/Clawdmeter) — но на часах, без ESP32 и без ПК-демона. -Цвет: зелёный <70%, янтарь 70–90%, красный ≥90%. +## Архитектура -## Архитектура (минимум) - -- **mobile** (телефон) — одно приложение, две функции: - 1. Поле ввода OAuth-токена + кнопка «Отправить токен» (через Wearable Data Layer). - 2. Установка wear APK на часы по WiFi ADB — без компьютера, прямо с телефона. - Использует [dadb](https://github.com/mobile-dev-inc/dadb) — pure-Kotlin ADB-клиент. - Wear APK встроен в mobile APK (assets), копируется при установке. -- **wear** (часы): - - `TokenReceiverService` — `WearableListenerService`, ловит `/token` даже когда app закрыто. - - `TokenStore` — `EncryptedSharedPreferences` (токен шифруется на устройстве). - - `ApiPoller` — один `HttpURLConnection` POST к `api.anthropic.com/v1/messages` - (`max_tokens=1`, haiku — самый дешёвый запрос ради rate-limit заголовков). - - `MainActivity` — Compose for Wear, авто-опрос при запуске + кнопка «Обновить». - -## APK - -После `./gradlew assembleDebug`: -- `mobile/build/outputs/apk/debug/mobile-debug.apk` — для телефона (27 МБ, включает wear APK) -- `wear/build/outputs/apk/debug/wear-debug.apk` — для часов (22 МБ, можно ставить и вручную) - -## Установка - -### Шаг 1: поставить mobile APK на телефон ``` -adb install -r mobile/build/outputs/apk/debug/mobile-debug.apk -``` -Или скопировать APK на телефон и открыть. - -### Шаг 2: включить отладку по WiFi на часах -1. На часах: Settings → About watch → тапнуть 7 раз по «Build number» → Developer mode. -2. Settings → Developer options → **Debug over WiFi** → включить. -3. Запомнить IP-адрес (показан в Developer options под «Debug over WiFi»). - -### Шаг 3: установить wear APK с телефона -1. Открыть **Claude Meter Setup** на телефоне. -2. В секции «2. Установка приложения на часы» ввести IP часов и порт (5555). -3. Нажать «Установить на часы». -4. При первом подключении — подтвердить RSA-ключ на часах (появится диалог). -5. Готово — приложение Claude Meter появилось на часах. - -> ADB-ключ генерируется один раз, хранится в `filesDir` приложения на телефоне. -> При следующих установках подтверждение на часах не нужно. - -### Шаг 4: отправить токен -1. Скопировать `accessToken` из `~/.claude/.credentials.json` на ПК. -2. В секции «1. Токен Claude Code» вставить токен → «Отправить токен». -3. На часах открыть **Claude Meter** — увидит токен → покажет проценты. - -Токен протухает (OAuth) — перепастить на телефоне, «Отправить» снова. -`// ponytail: token on-device, re-paste on OAuth expiry.` - -## Где взять токен - -Claude Code хранит OAuth-токен в `~/.claude/.credentials.json`: -```json -{"claudeAiOauth": {"accessToken": "***..."}} +┌─────────────────┐ Data Layer API ┌──────────────────┐ +│ mobile (телефон) │ ──────────────────▶ │ wear (часы) │ +│ │ /token │ │ +│ • ввод OAuth │ │ • опрос API │ +│ • спаривание │ │ • Compose UI │ +│ • установка APK │ ──── WiFi ADB ──────▶ │ • EncryptedShared │ +│ │ pair → connect → │ Preferences │ +│ │ pm install │ │ +└─────────────────┘ └──────────────────┘ ``` -## Что добавлять потом (не сейчас) +## Модули -- **Фоновое обновление** — `WorkManager` periodic (~15 мин). Сейчас по тапу + при запуске. -- **Complication на циферблате** — always-on виджет с %. Больше бойлерплейта, делаем когда v0 зайдёт. -- **График истории** — Room + простая диаграмма. YAGNI пока. -- **Авто-рефреш токена** — если Claude Code добавит refresh-token flow. Сейчас ручная перепоставка. +| Модуль | Назначение | +|--------|-----------| +| `wear/` | Часы: Compose for Wear UI, HTTP-опрос `api.anthropic.com`, хранение токена | +| `mobile/` | Телефон: ввод токена, отправка через Data Layer API, ADB-спаривание + установка | + +## Сборка + +```bash +gradlew assembleDebug +``` + +APK: +- `mobile/build/outputs/apk/debug/mobile-debug.apk` — телефон (38 МБ, включает wear APK в assets) +- `wear/build/outputs/apk/debug/wear-debug.apk` — часы (22 МБ) + +## Установка и использование + +### Шаг 1: Установить mobile-приложение на телефон + +```bash +adb install mobile/build/outputs/apk/debug/mobile-debug.apk +``` + +### Шаг 2: Спаривание с часами + +1. На часах: **Settings → Developer options → Wireless debugging → «Pair device with pairing code»** +2. На телефоне в приложении **Claude Meter Setup**: + - Ввести IP часов (виден на экране Wireless debugging) + - Ввести pairing порт (виден на экране pairing) + - Ввести 6-значный код + - Нажать «Спарить» +3. Дождаться «✅ Спарено!» + +### Шаг 3: Установка приложения на часы + +1. На часах: вернуться на главный экран Wireless debugging (виден session порт) +2. На телефоне: ввести session порт → «Установить на часы» +3. APK пушится через `shell:cat` и устанавливается через `pm install` + +### Шаг 4: Отправка токена + +1. На ПК: найти `accessToken` в `~/.claude/.credentials.json` +2. На телефоне: вставить токен → «Отправить токен» +3. На часах: открыть **Claude Meter** → видит проценты + +## Технические детали + +### API + +Опрашивает `https://api.anthropic.com/v1/messages` — POST (haiku, max_tokens=1). +Rate-limit заголовки: +- `anthropic-ratelimit-unified-5h-utilization` (0–1) — 5-часовое окно +- `anthropic-ratelimit-unified-5h-reset` (unix timestamp) — сброс 5h +- `anthropic-ratelimit-unified-7d-utilization` (0–1) — 7-дневное окно +- `anthropic-ratelimit-unified-7d-reset` (unix timestamp) — сброс 7d +- `anthropic-ratelimit-unified-5h-status` — статус (ok/throttled/blocked) + +### WiFi ADB + +Использует [libadb-android](https://github.com/MuntashirAkon/libadb-android) — полный ADB протокол на Kotlin: +- **SPAKE2 pairing** — ключевой обмен с 6-значным кодом +- **TLS 1.3** — через Conscrypt +- **RSA 2048** — самоподписанный X.509 сертификат, хранится в `filesDir` +- **HiddenApiBypass** — доступ к `android.sun.security.x509.*` + +Поток: pair (pairing port + code) → connect (session port) → push APK → `pm install` + +### Стек + +| Компонент | Технология | +|-----------|-----------| +| UI (wear) | Compose for Wear, ScalingLazyColumn | +| UI (mobile) | Compose Material3 | +| HTTP | `HttpURLConnection` (stdlib) | +| Хранение токена | `EncryptedSharedPreferences` | +| Передача токена | Wearable Data Layer API | +| ADB | libadb-android (SPAKE2 + TLS) | +| TLS | Conscrypt | +| Build | AGP 8.7.3, Gradle 8.13, Kotlin 1.9.22, compileSdk 35 | + +## Структура проекта + +``` +ClaudeMeter/ +├── settings.gradle.kts # :mobile, :wear +├── build.gradle.kts # AGP 8.7.3, Kotlin 1.9.22 +├── gradle.properties +├── gradle/wrapper/ +├── mobile/ +│ ├── build.gradle.kts # libadb-android, Conscrypt, Compose, Data Layer +│ └── src/main/ +│ ├── AndroidManifest.xml +│ └── java/com/eps/claudemeter/ +│ ├── App.kt # HiddenApiBypass + Conscrypt init +│ ├── AdbConnectionManager.kt # RSA ключ + X.509 сертификат +│ └── MainActivity.kt # UI: токен + спаривание + установка +├── wear/ +│ ├── build.gradle.kts # Compose for Wear +│ └── src/main/ +│ ├── AndroidManifest.xml +│ └── java/com/eps/claudemeter/ +│ ├── ApiPoller.kt # HTTP-опрос + парсинг заголовков +│ ├── TokenStore.kt # EncryptedSharedPreferences +│ ├── TokenReceiverService.kt # WearableListenerService +│ └── MainActivity.kt # Compose for Wear UI +└── README.md +``` + +## Ограничения (v0) + +- Обновление по тапу, не фоновое (WorkManager — отложено) +- Нет complication (виджет на циферблате — отложено) +- Токен протухает → нужно перепастить на телефоне