From d18cd7c5c0f7298ae2f139d71fb832e8f7f91744 Mon Sep 17 00:00:00 2001 From: wuxu Date: Tue, 9 Jun 2026 14:40:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 ++ AGENTS.md | 28 +++++++ CLIPBOARD_SYNC_PLAN.md | 166 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 CLIPBOARD_SYNC_PLAN.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9274af1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.vscode/ +.idea/ +.DS_Store +Thumbs.db +*.log diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e80b358 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,28 @@ +# Repository Guidelines + +## Project Structure & Module Organization +This workspace contains two related repositories. `Xime/` is the Android input method built with Kotlin, Jetpack Compose, Gradle, CMake, and JNI. Its main app code lives in `Xime/app/src/main/java`, Android resources in `Xime/app/src/main/res`, bundled Rime/config assets in `Xime/app/src/main/assets`, JVM tests in `Xime/app/src/test`, and instrumented tests in `Xime/app/src/androidTest`. Shared plugin APIs are in `Xime/plugin-core`, sample plugins in `Xime/plugins`, and docs/screenshots in `Xime/docs`. + +`winxime/` is the Windows/Rust TSF implementation. Rust crates live under `winxime/crates`, installer WiX files under `winxime/crates/winxime-server/wix`, runtime resources under `winxime/resources`, and vendored/native dependencies under `winxime/librime` and `winxime/rime-wubi`. + +## Build, Test, and Development Commands +Run commands from the relevant subproject directory. + +- Android build: `cd Xime; .\gradlew.bat assembleDebug --quiet` builds debug APKs. +- Android unit tests: `cd Xime; .\gradlew.bat :app:testDebugUnitTest` runs JVM tests. +- Android instrumented tests: `cd Xime; .\gradlew.bat :app:connectedDebugAndroidTest` requires a device or emulator. +- Docs: `cd Xime; pnpm docs:dev` serves VitePress docs locally. +- Windows build: `cd winxime; cargo build --quiet` validates the Rust workspace. +- Windows package: `cd winxime; .\msi-build.ps1` creates an MSI. `.\rebuild.ps1` rebuilds/registers locally; automated agents should not run it unless explicitly asked. + +## Coding Style & Naming Conventions +Use Kotlin/JVM 17 and Rust 2021. Follow existing package namespaces such as `com.kingzcheung.xime.*` and Compose naming conventions: composables and screens use `PascalCase`, helpers/managers use descriptive `PascalCase` class names, and tests end in `Test`. Keep Gradle Kotlin DSL files as `*.gradle.kts`. In Rust, keep crate names kebab-case and modules snake_case. For `winxime`, do not introduce `unwrap()` or `expect()`. + +## Testing Guidelines +Add or update tests when changing input logic, settings parsers, plugins, speech, association, or IPC behavior. Android unit tests use JUnit, Mockito, coroutines-test, and Compose test utilities; instrumented tests live in `androidTest`. Rust changes should at minimum pass `cargo build --quiet`; add crate-level tests where behavior is pure and deterministic. + +## Commit & Pull Request Guidelines +Recent history uses Conventional Commit-style subjects such as `feat(settings): ...`, `docs(readme): ...`, and `chore(config): ...`; keep scopes specific. PRs should describe the user-visible change, list commands run, link related issues, and include screenshots or screen recordings for keyboard/settings UI changes. + +## Security & Configuration Tips +Do not commit local signing material such as `Xime/app/keystore.properties`; use `keystore.properties.example` as the template. Treat `winxime/librime` as read-only unless the task explicitly targets native dependency updates. Automated agents should not commit changes unless requested. diff --git a/CLIPBOARD_SYNC_PLAN.md b/CLIPBOARD_SYNC_PLAN.md new file mode 100644 index 0000000..9d44f3f --- /dev/null +++ b/CLIPBOARD_SYNC_PLAN.md @@ -0,0 +1,166 @@ +# Clipboard Sync Implementation Plan + +## 1. Goal and Scope + +Build clipboard synchronization between the Android input method in `Xime/` and the Windows input method in `winxime/`, using a Docker-deployable HTTPS relay server. + +MVP scope: + +- Sync text clipboard content only. +- Devices join the same sync chain by entering a sync code. +- Remote content is written to the local system clipboard, equivalent to a user copy action. +- Android additionally exposes received synced text in the IME candidate bar so users can commit it directly. +- Users can enable/disable sync in settings and must configure an HTTPS relay server URL. + +Out of MVP scope: + +- Image/file/rich-text clipboard sync. +- Automatic paste into the currently focused field. +- Multi-user administration UI. +- Cloud-hosted default relay. + +## 2. Repository Layout Proposal + +Add a new backend service at workspace root: + +```text +sync-server/ + Dockerfile + docker-compose.yml + src/ + README.md +``` + +Client integrations: + +- Android: `Xime/app/src/main/java/com/kingzcheung/xime/settings`, `service`, `clipboard`, and `ui`. +- Windows: `winxime/crates/winxime-server` for clipboard watching, WebSocket sync, and local clipboard writes. +- Shared protocol docs: `CLIPBOARD_SYNC_PROTOCOL.md` or `sync-server/docs/protocol.md`. + +## 3. Core Product Rules + +- A sync chain is a group of devices allowed to exchange clipboard events. +- A sync code authorizes a device to join a chain. It must be random, revocable, and regeneratable. +- The server must reject non-HTTPS client relay URLs. For local development, allow explicit debug-only overrides such as `http://localhost`. +- Every synced item must be inserted into the local clipboard and local clipboard history where the platform/app supports it. +- Android must show the latest remote synced text in the candidate bar. Tapping it should commit the text through the IME. +- Sync must be opt-in and pauseable per device. + +## 4. Architecture + +Use HTTPS REST for setup and WSS for live sync: + +```text +Android Xime <--- HTTPS/WSS ---> Sync Relay Server <--- HTTPS/WSS ---> WinXime +``` + +The server is a relay, not an editor. It authenticates devices, tracks sync chains, forwards clipboard events, and keeps short-lived replay data for reconnects. + +Recommended backend stack: + +- Rust with `tokio`, `axum`, `tower`, `serde`, and `sqlx`/SQLite for a small self-hosted binary. +- Docker image exposing one port, with TLS handled either by the service or by a reverse proxy such as Caddy/Nginx. +- WebSocket heartbeat, reconnect support, and event replay by last acknowledged sequence. + +## 5. Protocol and Data Model + +REST endpoints: + +```text +GET /healthz +POST /v1/chains +POST /v1/chains/join +POST /v1/chains/{chainId}/sync-code/rotate +GET /v1/ws +``` + +Minimum tables/entities: + +```text +chains(id, code_hash, code_expires_at, created_at) +devices(id, chain_id, name, platform, token_hash, last_seen_at) +clipboard_events(id, chain_id, source_device_id, seq, content_type, content_hash, encrypted_payload, created_at, expires_at) +``` + +WebSocket event shape: + +```json +{ + "type": "clipboard.publish", + "eventId": "uuid", + "chainId": "uuid", + "sourceDeviceId": "uuid", + "sequence": 42, + "contentType": "text/plain", + "contentHash": "sha256:...", + "payload": "base64 encrypted or encoded text", + "createdAt": "2026-06-09T00:00:00Z", + "ttlSeconds": 86400 +} +``` + +Client requirements: + +- Ignore events from the same `deviceId`. +- Cache recent `eventId` and `contentHash` values to prevent duplicate imports. +- Suppress the next local clipboard-change callback after writing a remote event to avoid echo loops. +- Limit payload size, for example 64 KiB for MVP. + +## 6. Security Requirements + +- Relay URL validation must require `https://`; WebSocket connections must use `wss://`. +- Store only token hashes and sync code hashes on the server. +- Use TLS in all production deployments. +- Prefer end-to-end encryption for clipboard payloads. At minimum, server-side event storage must be short-lived with a configurable TTL. +- Sync codes should expire by default, for example after 10 minutes or after first successful join. Provide a manual rotate/revoke action. +- Never log raw clipboard content on clients or server. + +## 7. Android Implementation Plan + +1. Add settings fields: enable sync, relay server URL, sync code, device name, connection status, pause/resume, and disconnect. +2. Persist config in `SettingsPreferences.kt` or a dedicated sync preferences class. +3. Add a `ClipboardSyncClient` responsible for HTTPS join, WSS connection, heartbeats, reconnects, and event acknowledgements. +4. Add a clipboard bridge that publishes local text copies and writes remote text via Android `ClipboardManager`. +5. Add a local synced-item state source consumed by `CandidateBar.kt` or the relevant keyboard UI layer. +6. When remote text arrives, update system clipboard and display it as a candidate. Tapping the candidate commits the text. +7. Add unit tests for URL validation, dedupe, echo-loop suppression, and event parsing. + +## 8. Windows Implementation Plan + +1. Add sync configuration to the existing Windows settings/config layer. +2. Implement a WebSocket sync client inside `winxime-server`. +3. Watch local clipboard changes from the server process and publish text changes. +4. Write remote text into the Windows clipboard using the existing server/background process. +5. Prevent loops by tagging remote writes and suppressing the resulting local notification. +6. Surface connection status in tray/setup UI if practical. +7. Validate with `cargo build --quiet`; do not use `unwrap()` or `expect()`. + +## 9. Backend Implementation Plan + +1. Scaffold `sync-server` with health check, config loading, structured logging, and Dockerfile. +2. Implement chain creation, sync-code join, device token issuance, and code rotation. +3. Implement authenticated WebSocket sessions with heartbeat and reconnect. +4. Implement event fan-out to online devices in the same chain. +5. Persist recent events for replay after reconnect, bounded by TTL and size limits. +6. Add Docker Compose example with a reverse proxy HTTPS configuration. +7. Add integration tests for join, auth failure, event fan-out, replay, TTL expiry, and duplicate suppression expectations. + +## 10. Acceptance Criteria + +- A user can deploy the relay with Docker and access it over HTTPS. +- Android and Windows settings reject plain `http://` relay URLs outside debug/local mode. +- Device A can create or rotate a sync code; Device B can join using that code. +- Copying text on Windows updates Android clipboard and shows the text in the Android candidate bar. +- Copying text on Android updates the Windows clipboard. +- The same event is not re-broadcast indefinitely. +- Reconnect after network loss resumes sync without requiring a new sync code. +- Raw clipboard content does not appear in logs. + +## 11. Implementation Order for Agents + +1. Protocol agent: finalize event schema, sync-code lifecycle, error codes, and protocol doc. +2. Backend agent: implement relay, Docker image, tests, and deployment README. +3. Windows agent: implement local clipboard watcher/writer and WSS client. +4. Android agent: implement settings, WSS client, clipboard bridge, and candidate bar display. +5. Integration agent: run end-to-end tests across one Android device/emulator, one Windows client, and the Docker relay. +