From 8ef934d742d7f482055795e8c6dcd10203534dd3 Mon Sep 17 00:00:00 2001 From: Abdeslam Yassine Agmar Date: Tue, 17 Feb 2026 13:45:27 +0000 Subject: [PATCH 1/3] fix(test): cancel viewModelScope in all ViewModel tests to prevent coroutine leaks Apply the same fix from ChatViewModelThinkingExpansionTest to other test files that create ViewModels but don't cancel their scopes in @After. This prevents coroutine leaks that can cause flaky tests. Files updated: - ChatViewModelWorkflowCommandTest.kt - SettingsViewModelTest.kt --- .../chat/ChatViewModelWorkflowCommandTest.kt | 20 +++- .../ui/settings/SettingsViewModelTest.kt | 8 +- docs/ai/ui-ux-enhancements-plan.md | 96 +++++++++++++++++ docs/ai/ui-ux-enhancements-progress.md | 54 ++++++++++ docs/ai/ui-ux-enhancements-tasks.md | 49 +++++++++ docs/ai/ui-ux-enhancements-validation.md | 101 ++++++++++++++++++ 6 files changed, 322 insertions(+), 6 deletions(-) create mode 100644 docs/ai/ui-ux-enhancements-plan.md create mode 100644 docs/ai/ui-ux-enhancements-progress.md create mode 100644 docs/ai/ui-ux-enhancements-tasks.md create mode 100644 docs/ai/ui-ux-enhancements-validation.md diff --git a/app/src/test/java/com/ayagmar/pimobile/chat/ChatViewModelWorkflowCommandTest.kt b/app/src/test/java/com/ayagmar/pimobile/chat/ChatViewModelWorkflowCommandTest.kt index c23e1ea..afc8713 100644 --- a/app/src/test/java/com/ayagmar/pimobile/chat/ChatViewModelWorkflowCommandTest.kt +++ b/app/src/test/java/com/ayagmar/pimobile/chat/ChatViewModelWorkflowCommandTest.kt @@ -1,10 +1,12 @@ package com.ayagmar.pimobile.chat +import androidx.lifecycle.viewModelScope import com.ayagmar.pimobile.corerpc.ExtensionUiRequestEvent import com.ayagmar.pimobile.sessions.SlashCommandInfo import com.ayagmar.pimobile.testutil.FakeSessionController import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.cancel import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest @@ -20,17 +22,25 @@ import org.junit.Test @OptIn(ExperimentalCoroutinesApi::class) class ChatViewModelWorkflowCommandTest { private val dispatcher = StandardTestDispatcher() + private val viewModels = mutableListOf() @Before fun setUp() { Dispatchers.setMain(dispatcher) + viewModels.clear() } @After fun tearDown() { + viewModels.forEach { it.viewModelScope.cancel() } + viewModels.clear() Dispatchers.resetMain() } + private fun createViewModel(controller: FakeSessionController): ChatViewModel { + return ChatViewModel(sessionController = controller).also { viewModels.add(it) } + } + @Test fun loadingCommandsHidesInternalBridgeWorkflowCommands() = runTest(dispatcher) { @@ -60,7 +70,7 @@ class ChatViewModelWorkflowCommandTest { ), ) - val viewModel = ChatViewModel(sessionController = controller) + val viewModel = createViewModel(controller) dispatcher.scheduler.advanceUntilIdle() awaitInitialLoad(viewModel) @@ -88,7 +98,7 @@ class ChatViewModelWorkflowCommandTest { ), ) - val viewModel = ChatViewModel(sessionController = controller) + val viewModel = createViewModel(controller) dispatcher.scheduler.advanceUntilIdle() awaitInitialLoad(viewModel) @@ -113,7 +123,7 @@ class ChatViewModelWorkflowCommandTest { fun selectingBridgeBackedBuiltinStatsFallsBackWhenInternalCommandUnavailable() = runTest(dispatcher) { val controller = FakeSessionController() - val viewModel = ChatViewModel(sessionController = controller) + val viewModel = createViewModel(controller) dispatcher.scheduler.advanceUntilIdle() awaitInitialLoad(viewModel) @@ -137,7 +147,7 @@ class ChatViewModelWorkflowCommandTest { fun internalWorkflowStatusActionCanOpenStatsSheet() = runTest(dispatcher) { val controller = FakeSessionController() - val viewModel = ChatViewModel(sessionController = controller) + val viewModel = createViewModel(controller) dispatcher.scheduler.advanceUntilIdle() awaitInitialLoad(viewModel) @@ -160,7 +170,7 @@ class ChatViewModelWorkflowCommandTest { fun nonWorkflowStatusIsStoredUpdatedAndCleared() = runTest(dispatcher) { val controller = FakeSessionController() - val viewModel = ChatViewModel(sessionController = controller) + val viewModel = createViewModel(controller) dispatcher.scheduler.advanceUntilIdle() awaitInitialLoad(viewModel) diff --git a/app/src/test/java/com/ayagmar/pimobile/ui/settings/SettingsViewModelTest.kt b/app/src/test/java/com/ayagmar/pimobile/ui/settings/SettingsViewModelTest.kt index a579e70..728b834 100644 --- a/app/src/test/java/com/ayagmar/pimobile/ui/settings/SettingsViewModelTest.kt +++ b/app/src/test/java/com/ayagmar/pimobile/ui/settings/SettingsViewModelTest.kt @@ -3,11 +3,13 @@ package com.ayagmar.pimobile.ui.settings import android.content.SharedPreferences +import androidx.lifecycle.viewModelScope import com.ayagmar.pimobile.sessions.TransportPreference import com.ayagmar.pimobile.testutil.FakeSessionController import com.ayagmar.pimobile.ui.theme.ThemePreference import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.resetMain @@ -23,14 +25,18 @@ import org.junit.Test @OptIn(ExperimentalCoroutinesApi::class) class SettingsViewModelTest { private val dispatcher = StandardTestDispatcher() + private val viewModels = mutableListOf() @Before fun setUp() { Dispatchers.setMain(dispatcher) + viewModels.clear() } @After fun tearDown() { + viewModels.forEach { it.viewModelScope.cancel() } + viewModels.clear() Dispatchers.resetMain() } @@ -133,7 +139,7 @@ class SettingsViewModelTest { sessionController = controller, sharedPreferences = InMemorySharedPreferences(), appVersionOverride = "test", - ) + ).also { viewModels.add(it) } } } diff --git a/docs/ai/ui-ux-enhancements-plan.md b/docs/ai/ui-ux-enhancements-plan.md new file mode 100644 index 0000000..58cc0a0 --- /dev/null +++ b/docs/ai/ui-ux-enhancements-plan.md @@ -0,0 +1,96 @@ +# Pi Mobile — UI/UX Enhancements Plan + +_Last updated: 2026-02-16_ + +> Planning artifact only. Do **not** commit this file. + +## 1) Goal + +Define and execute incremental UI/UX improvements that enhance clarity, speed, and trust during daily mobile usage. + +## 2) Scope + +- Chat readability and hierarchy +- Interaction efficiency (1–2 tap access to common actions) +- Streaming/latency perception improvements +- Session clarity and confidence cues +- Accessibility and visual consistency improvements + +## 3) Non-goals + +- No protocol-breaking RPC changes unless explicitly approved +- No broad architecture rewrite in this track +- No backend behavior changes outside UX-driven requirements + +## 4) Working agreements + +- One issue/task per commit where possible +- Conventional Commits +- Do not push from agent +- Keep planning docs out of commits + +## 5) Verification loop (mandatory per implemented task) + +```bash +./gradlew ktlintCheck +./gradlew detekt +./gradlew test +``` + +Bridge check only when bridge code/config/tests changed: + +```bash +(cd bridge && pnpm run check) +``` + +Manual smoke: +- `DEFERRED (user-run)` unless user requests agent-run smoke protocol + +## 6) Current implementation focus (user-requested) + +1. Move global nav (Hosts / Sessions / Chat / Settings) to left-side collapsible control. +2. Reduce extension status strip footprint; place under prompt controls and gate with settings toggle. +3. Improve abort reliability while model is thinking/retrying. +4. Move thinking/loading progress cue into timeline/message area rather than header-only. + +## 7) UX-05 quick wins (proposed, awaiting your validation) + +Validation sheet: `docs/ai/ui-ux-enhancements-validation.md` + +### Candidate changes (low-risk, high-usability) + +1. **Rail ergonomics polish** + - Persist collapse/expand preference. + - Improve rail spacing/touch targets. + - Why: reduce accidental taps and repeated toggling. + +2. **Streaming focus controls** + - Keep Abort/Steer/Follow-up visible with clearer priority when streaming. + - Improve button hierarchy and spacing. + - Why: faster intervention while model is running. + +3. **Status strip compaction** + - Compact to chips/summary by default, expandable for details. + - Hide unchanged/noisy status updates. + - Why: preserve chat vertical space. + +4. **Timeline readability + motion smoothing** + - Subtle spacing reductions where safe. + - Avoid abrupt jumps when status/progress widgets appear/disappear. + - Why: smoother reading during long runs. + +5. **Jump-to-latest affordance** + - Add “jump to latest” control when user is reading older messages during streaming. + - Why: quickly return to live output. + +6. **Accessibility cleanups** + - Ensure key icons/buttons meet touch target and content-description quality. + - Why: better usability and consistency. + +## 8) Delivery approach + +1. Capture UX issue as a task in `ui-ux-enhancements-tasks.md` +2. Implement smallest valuable change +3. Run verification loop +4. Update progress file +5. Commit code only (exclude planning docs) diff --git a/docs/ai/ui-ux-enhancements-progress.md b/docs/ai/ui-ux-enhancements-progress.md new file mode 100644 index 0000000..90b97af --- /dev/null +++ b/docs/ai/ui-ux-enhancements-progress.md @@ -0,0 +1,54 @@ +# Pi Mobile — UI/UX Enhancements Progress + +_Last updated: 2026-02-16_ + +> Planning artifact only. Do **not** commit this file. + +## Snapshot + +- Total tasks: 9 implemented / 0 in progress / 0 blocked / 1 descoped +- Current phase: UX-05 implementation completed, awaiting manual smoke + +## In progress + +- None + +## Awaiting validation + +- None (validation approved for A/B/C/E/F; D denied) + +## Completed + +- UX-01: Collapsible left navigation rail replacing bottom nav +- UX-02: Extension status strip moved under prompt controls + settings flag +- UX-03: Abort fallback behavior for thinking/retry edge cases +- UX-04: Inline run progress in timeline area (instead of top-only) +- UX-05A: Persist rail expanded state + spacing/hit-area polish (`1847bae`) +- UX-05B: Streaming action hierarchy polish (Abort prioritized) (`1847bae`) +- UX-05C: Extension status strip compact presentation + de-noise heuristics (`1847bae`) +- UX-05E: Jump-to-latest affordance while streaming (`1847bae`) +- UX-05F: Accessibility quick fixes (touch targets/content descriptions) (`1847bae`) + +## Descoped + +- UX-05D: Timeline smoothing + spacing pass (denied for now by user) + +## Blocked + +- None + +## Next up + +1. Manual smoke on device (user-run) for UX-05A/B/C/E/F. +2. Collect feedback on compact status strip heuristics. +3. Optionally re-scope UX-05D later with clearer examples. + +## Verification history + +- 2026-02-16: `./gradlew ktlintCheck detekt test` ✅ +- 2026-02-16: `./gradlew ktlintCheck detekt test` ✅ (UX-05 implementation) + +## Notes + +- This progress file tracks execution status only. +- Planning docs remain uncommitted by policy. diff --git a/docs/ai/ui-ux-enhancements-tasks.md b/docs/ai/ui-ux-enhancements-tasks.md new file mode 100644 index 0000000..351d2d6 --- /dev/null +++ b/docs/ai/ui-ux-enhancements-tasks.md @@ -0,0 +1,49 @@ +# Pi Mobile — UI/UX Enhancements Tasks Tracker + +_Status values_: `TODO` | `IN_PROGRESS` | `BLOCKED` | `DONE` | `DESCOPED` + +> Planning artifact only. Do **not** commit this file. + +Linked plan: `docs/ai/ui-ux-enhancements-plan.md` +Linked progress: `docs/ai/ui-ux-enhancements-progress.md` +Validation sheet: `docs/ai/ui-ux-enhancements-validation.md` + +## Mandatory verification loop + +```bash +./gradlew ktlintCheck +./gradlew detekt +./gradlew test +``` + +Bridge check only when bridge code/config/tests changed: + +```bash +(cd bridge && pnpm run check) +``` + +## Task table + +| Order | ID | Title | Status | Priority | Commit | Report | +|---|---|---|---|---|---|---| +| 1 | UX-01 | Move global nav to collapsible left rail | DONE | P1 | `1a3a2b7 feat(ui): add side nav, inline run progress, and status toggle` | in-code | +| 2 | UX-02 | Move extension status below prompt + visibility toggle | DONE | P1 | `1a3a2b7 feat(ui): add side nav, inline run progress, and status toggle` | in-code | +| 3 | UX-03 | Make abort resilient during thinking/retry transitions | DONE | P0 | `1a3a2b7 feat(ui): add side nav, inline run progress, and status toggle` | in-code | +| 4 | UX-04 | Show live thinking/loading inline in timeline area | DONE | P1 | `1a3a2b7 feat(ui): add side nav, inline run progress, and status toggle` | in-code | +| 5 | UX-05A | Rail ergonomics polish (persist + spacing) | DONE | P2 | `1847bae feat(ui): implement approved UX quick wins` | `ui-ux-enhancements-validation.md` | +| 6 | UX-05B | Streaming action hierarchy polish | DONE | P1 | `1847bae feat(ui): implement approved UX quick wins` | `ui-ux-enhancements-validation.md` | +| 7 | UX-05C | Extension status strip compaction v2 | DONE | P1 | `1847bae feat(ui): implement approved UX quick wins` | `ui-ux-enhancements-validation.md` | +| 8 | UX-05D | Timeline smoothing + spacing pass | DESCOPED | P2 | - | denied in `ui-ux-enhancements-validation.md` | +| 9 | UX-05E | Jump-to-latest affordance while streaming | DONE | P1 | `1847bae feat(ui): implement approved UX quick wins` | `ui-ux-enhancements-validation.md` | +| 10 | UX-05F | Accessibility quick audit/fixes | DONE | P1 | `1847bae feat(ui): implement approved UX quick wins` | `ui-ux-enhancements-validation.md` | + +## Reporting rule per task + +For each completed task, record: +- Root cause summary +- Files changed +- Tests updated +- Verification results (ktlint/detekt/test/bridge) +- Manual smoke status (`DEFERRED (user-run)` if applicable) +- Commit hash + message +- Follow-ups/risks diff --git a/docs/ai/ui-ux-enhancements-validation.md b/docs/ai/ui-ux-enhancements-validation.md new file mode 100644 index 0000000..a5fd8ac --- /dev/null +++ b/docs/ai/ui-ux-enhancements-validation.md @@ -0,0 +1,101 @@ +# Pi Mobile — UX Quick Wins Validation Sheet + +_Last updated: 2026-02-16_ + +> Planning artifact only. Do **not** commit this file. + +Purpose: get your approval on **what will change** and **why** before implementation. + +## How to validate + +For each item, choose one: +- `APPROVE` +- `APPROVE_WITH_CHANGES` +- `SKIP` + +--- + +## UX-05A — Rail ergonomics polish + +- **Current pain**: left rail is useful but can still feel heavy/awkward in repeated use. +- **Planned change**: + 1. Persist expanded/collapsed state. + 2. Tune spacing and hit areas for faster tab switching. +- **Why**: reduce friction and accidental taps. +- **Risk**: very low (layout only). +- **Your decision**: `APPROVED` +- **Notes**: + +## UX-05B — Streaming action hierarchy polish + +- **Current pain**: intervention actions during streaming can still feel crowded. +- **Planned change**: + 1. Prioritize Abort visually. + 2. Improve Steer/Follow-up affordances and spacing. +- **Why**: faster control when model is running. +- **Risk**: low (no protocol behavior changes). +- **Your decision**: `APPROVE` +- **Notes**: + +## UX-05C — Extension status strip compaction v2 + +- **Current pain**: even moved under prompt, status can still consume space. +- **Planned change**: + 1. Default compact summary row. + 2. Expand for full details. + 3. De-noise repeated unchanged statuses. +- **Why**: preserve more room for chat timeline. +- **Risk**: low (presentation-layer only). +- **Your decision**: `APPROVE` +- **Notes**: + +## UX-05D — Timeline smoothing + spacing pass + +- **Current pain**: occasional visual jumps while widgets/progress appear/disappear. +- **Planned change**: + 1. Small spacing harmonization. + 2. Smoother show/hide transitions for helper UI. +- **Why**: reduce perceived jitter and improve readability. +- **Risk**: low/medium (needs manual feel check). +- **Your decision**: `DEENY` +- **Notes**: can do it later, i dont understand this + +## UX-05E — Jump-to-latest while streaming + +- **Current pain**: when reading older messages during stream, getting back to live tail is slower. +- **Planned change**: + 1. Show "Jump to latest" button when user is away from bottom during active run. +- **Why**: one-tap return to live output. +- **Risk**: low. +- **Your decision**: `APPROVE` +- **Notes**: + +## UX-05F — Accessibility cleanups + +- **Current pain**: some secondary controls may be small/less explicit. +- **Planned change**: + 1. Touch-target audit for key actions. + 2. Content description pass for icons. +- **Why**: improve reliability and usability. +- **Risk**: very low. +- **Your decision**: `APPROVE` +- **Notes**: + +--- + +## Verification plan (per approved item) + +```bash +./gradlew ktlintCheck +./gradlew detekt +./gradlew test +``` + +Bridge check only if bridge files changed: + +```bash +(cd bridge && pnpm run check) +``` + +Manual smoke: +- `DEFERRED (user-run)` From 8f3a4326a9f0f46d5cff8c76f81abfcf1b24757e Mon Sep 17 00:00:00 2001 From: Abdeslam Yassine Agmar Date: Tue, 17 Feb 2026 13:45:47 +0000 Subject: [PATCH 2/3] chore: remove accidentally committed AI planning docs --- docs/ai/pi-android-rpc-client-plan.md | 265 -------- docs/ai/pi-android-rpc-client-tasks.md | 538 --------------- docs/ai/pi-android-rpc-progress.md | 43 -- docs/ai/pi-mobile-final-adjustments-plan.md | 463 ------------- .../pi-mobile-final-adjustments-progress.md | 634 ------------------ docs/ai/pi-mobile-rpc-enhancement-progress.md | 123 ---- docs/ai/pi-mobile-rpc-enhancement-tasks.md | 234 ------- docs/ai/pi-mobile-ux-resume-fix-plan.md | 72 -- docs/ai/ui-ux-enhancements-plan.md | 96 --- docs/ai/ui-ux-enhancements-progress.md | 54 -- docs/ai/ui-ux-enhancements-tasks.md | 49 -- docs/ai/ui-ux-enhancements-validation.md | 101 --- 12 files changed, 2672 deletions(-) delete mode 100644 docs/ai/pi-android-rpc-client-plan.md delete mode 100644 docs/ai/pi-android-rpc-client-tasks.md delete mode 100644 docs/ai/pi-android-rpc-progress.md delete mode 100644 docs/ai/pi-mobile-final-adjustments-plan.md delete mode 100644 docs/ai/pi-mobile-final-adjustments-progress.md delete mode 100644 docs/ai/pi-mobile-rpc-enhancement-progress.md delete mode 100644 docs/ai/pi-mobile-rpc-enhancement-tasks.md delete mode 100644 docs/ai/pi-mobile-ux-resume-fix-plan.md delete mode 100644 docs/ai/ui-ux-enhancements-plan.md delete mode 100644 docs/ai/ui-ux-enhancements-progress.md delete mode 100644 docs/ai/ui-ux-enhancements-tasks.md delete mode 100644 docs/ai/ui-ux-enhancements-validation.md diff --git a/docs/ai/pi-android-rpc-client-plan.md b/docs/ai/pi-android-rpc-client-plan.md deleted file mode 100644 index 26df776..0000000 --- a/docs/ai/pi-android-rpc-client-plan.md +++ /dev/null @@ -1,265 +0,0 @@ -# Pi Mobile (Android) — Refined Plan (RPC Client via Tailscale) - -## 0) Product goal -Build a **performant, robust native Android app** (Kotlin + Compose) that lets you use pi sessions running on your laptop from anywhere (bed, outside, etc.) via **Tailscale**, **without SSH/SFTP**. - -Primary success criteria: -- Smooth long chats with streaming output (no visible jank) -- Safe/resilient remote connection over tailnet -- Fast session browsing and resume across multiple projects/cwds -- Clear extension path for missing capabilities - ---- - -## 1) Facts from pi docs (non-negotiable constraints) - -### 1.1 RPC transport model -From `docs/rpc.md`: -- RPC is **JSON lines over stdin/stdout** of `pi --mode rpc` -- It is **not** a native TCP/WebSocket protocol - -Implication: -- Android cannot connect directly to RPC over network. -- You need a **laptop-side bridge** process: - - Android ↔ (Tailscale) ↔ Bridge ↔ pi RPC stdin/stdout - -### 1.2 Sessions and cwd -From `docs/session.md`, `docs/sdk.md`: -- Session files include a `cwd` in header and are stored under `~/.pi/agent/sessions/----/...jsonl` -- RPC has `switch_session`, but tools are created with process cwd context - -Implication: -- Multi-project correctness should be handled by **one pi process per cwd** (managed by bridge). - -### 1.3 Session discovery -From `docs/rpc.md`: -- No RPC command exists to list all session files globally. - -Implication: -- Bridge should read session files locally and expose a bridge API (best approach). - -### 1.4 Extension UI in RPC mode -From `docs/rpc.md` and `docs/extensions.md`: -- `extension_ui_request` / `extension_ui_response` must be supported for dialog flows (`select`, `confirm`, `input`, `editor`) -- Fire-and-forget UI methods (`notify`, `setStatus`, `setWidget`, `setTitle`, `set_editor_text`) are also emitted - -Implication: -- Android client must handle extension UI protocol end-to-end. - ---- - -## 2) Architecture decision - -## 2.1 Connection topology -- **Laptop** runs: - - `pi-bridge` service (WebSocket server) - - one or more `pi --mode rpc` subprocesses -- **Phone** runs Android app with WebSocket transport -- Network is Tailscale-only, no router forwarding - -## 2.2 Bridge protocol (explicit) -Use an **envelope protocol** over WS to avoid collisions between bridge-control operations and raw pi RPC messages. - -Example envelope: -```json -{ "channel": "bridge", "payload": { "type": "bridge_list_sessions" } } -{ "channel": "rpc", "payload": { "type": "prompt", "message": "hi" } } -``` - -Responses/events: -```json -{ "channel": "bridge", "payload": { "type": "bridge_sessions", "sessions": [] } } -{ "channel": "rpc", "payload": { "type": "message_update", ... } } -``` - -Why explicit envelope: -- Prevent ambiguous parsing -- Keep protocol extensible -- Easier debugging and telemetry - -## 2.3 Process management -Bridge owns a `PiProcessManager` keyed by cwd: -- `getOrStart(cwd)` -- idle TTL eviction -- crash restart policy -- single writer lock per cwd/session - -## 2.4 Session indexing -Bridge scans `~/.pi/agent/sessions/` and returns: -- `sessionPath`, `cwd`, `createdAt`, `updatedAt` -- `displayName` (latest `session_info.name`) -- `firstUserMessagePreview` -- optional `messageCount`, `lastModel` - -Android caches this index per host and refreshes incrementally. - ---- - -## 3) UX scope (v1) - -1. **Hosts**: add/edit host (tailscale host/ip, port, token, TLS toggle) -2. **Sessions**: grouped by cwd, searchable, resume/new/rename/fork/export actions -3. **Chat**: - - streaming text/tool timeline - - abort/steer/follow_up - - compact/export/fork - - model + thinking cycling -4. **Extension UI**: dialog requests + fire-and-forget requests -5. **Settings**: defaults and diagnostics - ---- - -## 4) Performance-first requirements (explicit budgets) - -These are required, not optional: - -### 4.1 Latency budgets -- Cold app start to visible cached sessions: **< 1.5s** target, **< 2.5s** max (mid-range device) -- Resume session to first rendered messages: **< 1.0s** target for cached metadata -- Prompt send to first token (healthy LAN/tailnet): **< 1.2s** target - -### 4.2 Rendering budgets -- Chat streaming should keep main thread frame time mostly under 16ms -- No sustained jank while streaming > 5 minutes -- Tool outputs default collapsed when large - -### 4.3 Memory budgets -- No unbounded string accumulation in UI layer -- Streaming buffers bounded and compacted -- Long chat (>= 2k messages including tool events) should avoid OOM and GC thrash - -### 4.4 Throughput/backpressure -- WS inbound processing must not block UI thread -- Throttled rendering (e.g., 20–40ms update interval) -- Drop/coalesce non-critical transient updates when overwhelmed - -### 4.5 Reconnect/resync behavior -After disconnect/reconnect: -- restore active cwd/session context -- call `get_state` and `get_messages` to resync -- show clear degraded/recovering indicators - ---- - -## 5) Security model - -- Tailnet transport is encrypted/authenticated by Tailscale -- Bridge binds to Tailscale interface/address only -- Bridge requires auth token (bearer or handshake token) -- Token stored securely on Android (Keystore-backed) -- If using `ws://` over tailnet, configure Android network security policy explicitly - ---- - -## 6) Delivery strategy for one-shot long-running agent - -Execution is phase-based with hard gates: - -1. **Phase A:** Bridge + basic chat E2E -2. **Phase B:** Session indexing + resume across cwd -3. **Phase C:** Full chat controls + extension UI protocol -4. **Phase D:** Performance hardening + reconnect robustness -5. **Phase E:** Docs + final acceptance - -### Rule -Do not start next phase until: -- code quality loop passes -- phase acceptance checks pass -- task tracker updated - ---- - -## 7) Verification loops (explicit) - -## 7.1 Per-task verification loop -After each task: -1. `./gradlew ktlintCheck` -2. `./gradlew detekt` -3. `./gradlew test` -4. Bridge checks (`pnpm run check`) when bridge changed -5. Targeted manual smoke test for the task - -If any fails: fix and rerun full loop. - -## 7.2 Per-phase gate -At end of each phase: -- End-to-end scripted walkthrough passes -- No open critical bugs in that phase scope -- Task list statuses updated to `DONE` - -## 7.3 Weekly/perf gate (for long-running execution) -- Run stress scenario: long streaming + big tool output + session switching -- Record metrics and regressions -- Block progression if perf worsens materially - ---- - -## 8) Extension strategy (repo-local) -If a missing capability should live inside pi runtime (not Android/bridge), add extension packages in this repo: - -- Create `extensions/` directory -- Bootstrap from: - - `/home/ayagmar/Projects/Personal/pi-extension-template/` -- Keep extension quality gate: - - `pnpm run check` -- Install locally: -```bash -pi install /absolute/path/to/extensions/ -``` -- Reload in running pi with `/reload` - -Use extensions for: -- custom commands/hooks -- guardrails -- metadata enrichment that is better at agent side - ---- - -## 9) Risks and mitigations - -- **Risk:** bridge protocol drift vs pi RPC - - Mitigation: keep `channel: rpc` payload pass-through unchanged and tested with fixtures -- **Risk:** session corruption from concurrent writers - - Mitigation: single controlling client lock per cwd/session -- **Risk:** lag in long streams - - Mitigation: throttled rendering + bounded buffers + macrobenchmark checks -- **Risk:** reconnect inconsistency - - Mitigation: deterministic resync (`get_state`, `get_messages`) on reconnect - ---- - -## 10) Final Definition of Done (explicit and measurable) -All must be true: - -1. **Connectivity** - - Android connects to laptop bridge over Tailscale reliably - - Auth token required and validated - -2. **Core chat** - - `prompt`, `abort`, `steer`, `follow_up` operate correctly - - Streaming text/tool events render smoothly in long runs - -3. **Sessions** - - Sessions listed from `~/.pi/agent/sessions/`, grouped by cwd - - Resume works across different cwds via correct process selection - - Rename/fork/export/compact flows work and reflect in UI/index - -4. **Extension protocol** - - `extension_ui_request` dialog methods handled with proper response IDs - - Fire-and-forget UI methods represented without blocking - -5. **Robustness** - - Bridge survives transient disconnects and can recover/resync - - No session corruption under reconnect and repeated resume/switch tests - -6. **Performance** - - Meets latency and streaming smoothness budgets in section 4 - - No major memory leaks/jank under stress scenarios - -7. **Quality gates** - - Android: `ktlintCheck`, `detekt`, `test` green - - Bridge/extensions: `pnpm run check` green - -8. **Documentation** - - README includes complete setup (tailscale, bridge run, token, troubleshooting) - - Task checklist and acceptance report completed diff --git a/docs/ai/pi-android-rpc-client-tasks.md b/docs/ai/pi-android-rpc-client-tasks.md deleted file mode 100644 index 34daea0..0000000 --- a/docs/ai/pi-android-rpc-client-tasks.md +++ /dev/null @@ -1,538 +0,0 @@ -# Pi Mobile (Android) — Execution Task List (One-Shot Agent Friendly) - -This task list is optimized for a long-running coding agent (Codex-style): explicit order, hard gates, verification loops, and progress tracking. - -> Rule: **Never start the next task unless current task verification is green.** - ---- - -## 0) Operating contract - -## 0.1 Scope reminder -Build a native Android client that connects over Tailscale to a laptop bridge for `pi --mode rpc`, with excellent long-chat performance and robust reconnect/session behavior. - -## 0.2 Mandatory loop after every task - -Run in order: -1. `./gradlew ktlintCheck` -2. `./gradlew detekt` -3. `./gradlew test` -4. If bridge changed: `cd bridge && pnpm run check` -5. Task-specific smoke test (manual or scripted) - -If any step fails: -- Fix -- Re-run full loop - -## 0.3 Commit policy -After green loop: -1. Read `/home/ayagmar/.agents/skills/commit/SKILL.md` -2. Create one Conventional Commit for the task -3. Do not push - -## 0.4 Progress tracker (must be updated each task) -Maintain statuses: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. - -Suggested tracker file: `docs/pi-android-rpc-progress.md` -For each task include: -- status -- commit hash -- verification result -- notes/blockers - ---- - -## Phase 1 — Foundations and architecture lock - -### Task 1.1 — Bootstrap Android app + modules -**Goal:** Buildable Android baseline with modular structure. - -Deliverables: -- `app/` -- `core-rpc/` -- `core-net/` -- `core-sessions/` -- Compose + navigation with placeholder screens - -Acceptance: -- `./gradlew :app:assembleDebug` succeeds -- app launches with placeholders - -Commit: -- `chore(app): bootstrap android modular project` - ---- - -### Task 1.2 — Add quality gates (ktlint + detekt + CI) -**Goal:** Enforce quality from day 1. - -Deliverables: -- `.editorconfig`, `detekt.yml` -- ktlint + detekt configured -- `.github/workflows/ci.yml` with checks - -Acceptance: -- local checks pass -- CI config valid - -Commit: -- `chore(quality): configure ktlint detekt and ci` - ---- - -### Task 1.3 — Spike: validate critical RPC/cwd assumptions -**Goal:** Confirm behavior before deeper build. - -Checks: -- Validate `pi --mode rpc` JSONL behavior with a tiny local script -- Validate `switch_session` + tool cwd behavior across different project paths -- Record results in `docs/spikes/rpc-cwd-assumptions.md` - -Acceptance: -- spike doc has reproducible commands + outcomes -- architecture assumptions confirmed (or revised) - -Commit: -- `docs(spike): validate rpc and cwd behavior` - ---- - -## Phase 2 — Bridge service (laptop) - -### Task 2.1 — Create bridge project skeleton -**Goal:** Node/TS service scaffold with tests and lint. - -Deliverables: -- `bridge/` project with TypeScript -- scripts: `dev`, `start`, `check`, `test` -- base config and logging - -Acceptance: -- `cd bridge && pnpm run check` passes - -Commit: -- `feat(bridge): bootstrap typescript service` - ---- - -### Task 2.2 — Implement WS envelope protocol + auth -**Goal:** Explicit protocol for bridge and RPC channels. - -Protocol: -- `channel: "bridge" | "rpc"` -- token auth required at connect time - -Deliverables: -- protocol types and validation -- auth middleware -- error responses for malformed payloads - -Acceptance: -- invalid auth rejected -- valid auth accepted -- malformed payload handled safely - -Commit: -- `feat(bridge): add websocket envelope protocol and auth` - ---- - -### Task 2.3 — Implement pi RPC subprocess forwarding -**Goal:** Bridge raw RPC payloads to/from pi process. - -Deliverables: -- spawn `pi --mode rpc` -- write JSON line to stdin -- read stdout lines and forward via WS `channel: rpc` -- stderr logging isolation - -Acceptance: -- E2E: send `get_state`, receive valid response - -Commit: -- `feat(bridge): forward pi rpc over websocket` - ---- - -### Task 2.4 — Multi-cwd process manager + locking -**Goal:** Correct multi-project behavior and corruption safety. - -Deliverables: -- process manager keyed by cwd -- single controller lock per cwd/session -- idle eviction policy - -Acceptance: -- switching between two cwds uses correct process and tool context -- concurrent control attempts are safely rejected - -Commit: -- `feat(bridge): manage per-cwd pi processes with locking` - ---- - -### Task 2.5 — Bridge session indexing API -**Goal:** Replace missing RPC list-sessions capability. - -Deliverables: -- `bridge_list_sessions` -- parser for session header + latest `session_info` + preview -- grouped output by cwd -- tests with JSONL fixtures - -Acceptance: -- returns expected metadata from fixture and real local sessions - -Commit: -- `feat(bridge): add session indexing api from jsonl files` - ---- - -### Task 2.6 — Bridge resilience: reconnect and health -**Goal:** Robust behavior on disconnect/crash. - -Deliverables: -- health checks -- restart policy for crashed pi subprocess -- reconnect-safe state model - -Acceptance: -- forced disconnect and reconnect recovers cleanly - -Commit: -- `feat(bridge): add resilience and health management` - ---- - -## Phase 3 — Android transport and protocol core - -### Task 3.1 — Implement core RPC models/parser -**Goal:** Typed parse of responses/events from rpc docs. - -Deliverables: -- command models (prompt/abort/steer/follow_up/etc.) -- response/event sealed hierarchies -- parser with `ignoreUnknownKeys` - -Acceptance: -- tests for response success/failure, message_update, tool events, extension_ui_request - -Commit: -- `feat(rpc): add protocol models and parser` - ---- - -### Task 3.2 — Streaming assembler + throttling primitive -**Goal:** Efficient long-stream reconstruction without UI flood. - -Deliverables: -- assistant text assembler by message/content index -- throttle/coalescing utility for UI update cadence - -Acceptance: -- deterministic reconstruction tests -- throttle tests for bursty deltas - -Commit: -- `feat(rpc): add streaming assembler and throttling` - ---- - -### Task 3.3 — WebSocket client transport (`core-net`) -**Goal:** Android WS transport with reconnect lifecycle. - -Deliverables: -- connect/disconnect/reconnect -- `Flow` inbound stream -- outbound send queue -- clear connection states - -Acceptance: -- integration test with fake WS server - -Commit: -- `feat(net): add websocket transport with reconnect support` - ---- - -### Task 3.4 — Android RPC connection orchestrator -**Goal:** Bridge WS + parser + command dispatch in one stable layer. - -Deliverables: -- `PiRpcConnection` service -- command send API -- event stream API -- resync helpers (`get_state`, `get_messages`) - -Acceptance: -- reconnect triggers deterministic resync successfully - -Commit: -- `feat(net): implement rpc connection orchestration` - ---- - -## Phase 4 — Sessions UX and cache - -### Task 4.1 — Host profiles and secure token storage -**Goal:** Manage multiple laptop hosts safely. - -Deliverables: -- host profile CRUD UI + persistence -- token storage via Keystore-backed mechanism - -Acceptance: -- profiles survive restart -- tokens never stored plaintext in raw prefs - -Commit: -- `feat(hosts): add host profile management and secure token storage` - ---- - -### Task 4.2 — Session repository + cache (`core-sessions`) -**Goal:** Fast list load and incremental refresh. - -Deliverables: -- cached index by host -- background refresh and merge -- search/filter support - -Acceptance: -- list appears immediately from cache after restart -- refresh updates changed sessions only - -Commit: -- `perf(sessions): implement cached indexed session repository` - ---- - -### Task 4.3 — Sessions screen grouped by cwd -**Goal:** Primary navigation UX. - -Deliverables: -- grouped/collapsible cwd sections -- search UI -- resume action wiring - -Acceptance: -- resume works across multiple cwds via bridge selection - -Commit: -- `feat(ui): add grouped sessions browser by cwd` - ---- - -### Task 4.4 — Session actions: rename/fork/export/compact entry points -**Goal:** Full session management surface from UI. - -Deliverables: -- rename (`set_session_name`) -- fork (`get_fork_messages` + `fork`) -- export (`export_html`) -- compact (`compact`) - -Acceptance: -- each action works E2E and updates UI state/index correctly - -Commit: -- `feat(sessions): add rename fork export and compact actions` - ---- - -## Phase 5 — Chat screen and controls - -### Task 5.1 — Streaming chat timeline UI -**Goal:** Smooth rendering of user/assistant/tool content. - -Deliverables: -- chat list with stable keys -- assistant streaming text rendering -- tool blocks with collapse/expand - -Acceptance: -- long response stream remains responsive - -Commit: -- `feat(chat): implement streaming timeline ui` - ---- - -### Task 5.2 — Prompt controls: abort, steer, follow_up -**Goal:** Full message queue behavior parity. - -Deliverables: -- input + send -- abort button -- steer/follow-up actions during streaming - -Acceptance: -- no protocol errors for streaming queue operations - -Commit: -- `feat(chat): add abort steer and follow-up controls` - ---- - -### Task 5.3 — Model/thinking controls -**Goal:** Missing parity item made explicit. - -Deliverables: -- cycle model (`cycle_model`) -- cycle thinking (`cycle_thinking_level`) -- visible current values - -Acceptance: -- controls update state and survive reconnect resync - -Commit: -- `feat(chat): add model and thinking controls` - ---- - -### Task 5.4 — Extension UI protocol support -**Goal:** Support extension-driven dialogs and notifications. - -Deliverables: -- handle `extension_ui_request` methods: - - `select`, `confirm`, `input`, `editor` - - `notify`, `setStatus`, `setWidget`, `setTitle`, `set_editor_text` -- send matching `extension_ui_response` by id - -Acceptance: -- dialog requests unblock agent flow -- fire-and-forget UI requests render non-blocking indicators - -Commit: -- `feat(extensions): implement rpc extension ui protocol` - ---- - -## Phase 6 — Performance hardening - -### Task 6.1 — Backpressure + bounded buffers -**Goal:** Prevent memory and UI blowups. - -Deliverables: -- bounded streaming buffers -- coalescing policy for high-frequency updates -- large tool output default-collapsed behavior - -Acceptance: -- stress run (10+ minute stream) without memory growth issues - -Commit: -- `perf(chat): add backpressure and bounded buffering` - ---- - -### Task 6.2 — Performance instrumentation + benchmarks -**Goal:** Make performance measurable. - -Deliverables: -- baseline metrics script/checklist -- startup/resume/first-token timing logs -- macrobenchmark skeleton (if available in current setup) - -Acceptance: -- metrics recorded in `docs/perf-baseline.md` - -Commit: -- `perf(app): add instrumentation and baseline metrics` - ---- - -### Task 6.3 — Baseline Profile + release tuning -**Goal:** Improve real-device performance. - -Deliverables: -- baseline profile setup -- release build optimization verification - -Acceptance: -- `./gradlew :app:assembleRelease` succeeds - -Commit: -- `perf(app): add baseline profile and release optimizations` - ---- - -## Phase 7 — Extension workspace (optional but prepared) - -### Task 7.1 — Add repo-local extension scaffold from template -**Goal:** Ready path for missing functionality via pi extensions. - -Source template: -- `/home/ayagmar/Projects/Personal/pi-extension-template/` - -Deliverables: -- `extensions/pi-mobile-ext/` -- customized constants/package name -- sample command/hook - -Acceptance: -- `cd extensions/pi-mobile-ext && pnpm run check` passes -- loads with `pi -e ./extensions/pi-mobile-ext/src/index.ts` - -Commit: -- `chore(extensions): scaffold pi-mobile extension workspace` - ---- - -## Phase 8 — Documentation and final acceptance - -### Task 8.1 — Setup and operations README -**Goal:** Reproducible setup for future you. - -Include: -- bridge setup on laptop -- tailscale requirements -- token setup -- Android host config -- troubleshooting matrix - -Acceptance: -- fresh setup dry run follows docs successfully - -Commit: -- `docs: add end-to-end setup and troubleshooting` - ---- - -### Task 8.2 — Final acceptance report -**Goal:** Explicitly prove Definition of Done. - -Deliverables: -- `docs/final-acceptance.md` -- checklist for: - - connectivity - - chat controls - - session flows - - extension UI protocol - - reconnect robustness - - performance budgets - - quality gates - -Acceptance: -- all checklist items marked pass with evidence - -Commit: -- `docs: add final acceptance report` - ---- - -## Final Definition of Done (execution checklist) - -All required: - -1. Android ↔ bridge works over Tailscale with token auth -2. Chat streaming stable for long sessions -3. Abort/steer/follow_up behave correctly -4. Sessions list grouped by cwd with reliable resume across cwds -5. Rename/fork/export/compact work -6. Model + thinking controls work -7. Extension UI request/response fully supported -8. Reconnect and resync are robust -9. Performance budgets met and documented -10. Quality gates green (`ktlintCheck`, `detekt`, `test`, bridge `pnpm run check`) -11. Setup + acceptance docs complete diff --git a/docs/ai/pi-android-rpc-progress.md b/docs/ai/pi-android-rpc-progress.md deleted file mode 100644 index 57f0893..0000000 --- a/docs/ai/pi-android-rpc-progress.md +++ /dev/null @@ -1,43 +0,0 @@ -# Pi Android RPC — Progress Tracker - -Status values: `TODO` | `IN_PROGRESS` | `BLOCKED` | `DONE` - -| Task | Status | Commit | Verification | Notes | -|---|---|---|---|---| -| 1.1 Bootstrap Android app + modules | DONE | e9f80a2 | ✅ ktlintCheck, detekt, test, :app:assembleDebug | Bootstrapped Android app + modular core-rpc/core-net/core-sessions with Compose navigation placeholders. | -| 1.2 Quality gates + CI | DONE | bd8a0a0 | ✅ ktlintCheck, detekt, test | Added .editorconfig, detekt.yml, root quality plugin config, and GitHub Actions CI workflow. | -| 1.3 RPC/cwd spike validation | DONE | 2817cf5 | ✅ ktlintCheck, detekt, test | Added reproducible spike doc validating JSONL interleaving/id-correlation and switch_session vs cwd behavior. | -| 2.1 Bridge skeleton | DONE | 0624eb8 | ✅ ktlintCheck, detekt, test, bridge check | Bootstrapped TypeScript bridge with scripts (dev/start/check/test), config/logging, HTTP health + WS skeleton, and Vitest/ESLint setup. | -| 2.2 WS envelope + auth | DONE | 2c3c269 | ✅ ktlintCheck, detekt, test, bridge check | Added auth-token handshake validation, envelope parser/validation, and safe bridge_error responses for malformed/unsupported payloads. | -| 2.3 RPC forwarding | DONE | dc89183 | ✅ ktlintCheck, detekt, test, bridge check | Added pi subprocess forwarder (stdin/stdout JSONL + stderr logging isolation), rpc channel forwarding, and E2E bridge get_state websocket check. | -| 2.4 Multi-cwd process manager | DONE | eff1bdf | ✅ ktlintCheck, detekt, test, bridge check | Added per-cwd process manager with control locks, server control APIs (set cwd/acquire/release), and idle TTL eviction with tests for lock rejection and cwd routing. | -| 2.5 Session indexing API | DONE | 6538df2 | ✅ ktlintCheck, detekt, test, bridge check | Added bridge_list_sessions API backed by JSONL session indexer (header/session_info/preview/messageCount/lastModel), fixture tests, and local ~/.pi session smoke run. | -| 2.6 Bridge resilience | DONE | b39cec9 | ✅ ktlintCheck, detekt, test, bridge check | Added enriched /health status, RPC forwarder crash auto-restart/backoff, reconnect grace model with resumable clientId, and forced reconnect smoke verification. | -| 3.1 RPC models/parser | DONE | 95b0489 | ✅ ktlintCheck, detekt, test | Added serializable RPC command + inbound response/event models and Json parser (ignoreUnknownKeys) with tests for response states, message_update, tool events, and extension_ui_request. | -| 3.2 Streaming assembler/throttle | DONE | 62f16bd | ✅ ktlintCheck, detekt, test; smoke: :core-rpc:test --tests "*AssistantTextAssemblerTest" --tests "*UiUpdateThrottlerTest" | Added assistant text stream assembler keyed by message/content index, capped message-buffer tracking, and a coalescing UI update throttler with deterministic unit coverage. | -| 3.3 WebSocket transport | DONE | 2b57157 | ✅ ktlintCheck, detekt, test; integration: :core-net:test (MockWebServer reconnect scenario) | Added OkHttp-based WebSocket transport with connect/disconnect/reconnect lifecycle, inbound Flow stream, outbound queue replay on reconnect, explicit connection states, and integration coverage. | -| 3.4 RPC orchestrator/resync | DONE | aa5f6af | ✅ ktlintCheck, detekt, test; integration: :core-net:test --tests "*PiRpcConnectionTest" | Added `PiRpcConnection` orchestrator with bridge/rpc envelope routing, typed RPC event stream, command dispatch, request-response helpers (`get_state`, `get_messages`), and automatic reconnect resync path validated in tests. | -| 4.1 Host profiles + secure token | DONE | 74db836 | ✅ ktlintCheck, detekt, test | Added host profile CRUD flow (Compose hosts screen + editor dialog + persistence via SharedPreferences), plus Keystore-backed token storage via EncryptedSharedPreferences (security-crypto). | -| 4.2 Sessions cache repo | DONE | 7e6e72f | ✅ ktlintCheck, detekt, test; smoke: :core-sessions:test --tests "*SessionIndexRepositoryTest" | Implemented `core-sessions` cached index repository per host with file/in-memory cache stores, background refresh + merge semantics, and query filtering support with deterministic repository tests. | -| 4.3 Sessions UI grouped by cwd | DONE | 2a3389e | ✅ ktlintCheck, detekt, test; smoke: :app:assembleDebug | Added sessions browser UI grouped/collapsible by cwd with host selection and search, wired bridge-backed session fetch via `bridge_list_sessions`, and implemented resume action wiring that reconnects with selected cwd/session and issues `switch_session`. | -| 4.4 Rename/fork/export/compact actions | DONE | f7957fc | ✅ ktlintCheck, detekt, test; smoke: :app:assembleDebug | Added active-session action entry points (Rename/Fork/Export/Compact) in sessions UI, implemented RPC commands (`set_session_name`, `get_fork_messages`+`fork`, `export_html`, `compact`) with response handling, and refreshed session index state after mutating actions. | -| 5.1 Streaming chat timeline UI | DONE | b2fac50 | ✅ ktlintCheck, detekt, test; smoke: :app:assembleDebug | Added chat timeline screen wired to shared active session connection, including history bootstrap via `get_messages`, live assistant streaming text assembly from `message_update`, and tool execution cards with collapse/expand behavior for large outputs. | -| 5.2 Abort/steer/follow_up controls | DONE | d0545cf | ✅ ktlintCheck, detekt, test, bridge check | Added prompt controls (sendPrompt, abort, steer, followUp), streaming state tracking via AgentStart/End events, and UI with input field, abort button (red), steer/follow-up dialogs. | -| 5.3 Model/thinking controls | DONE | cf3cfbb | ✅ ktlintCheck, detekt, test, bridge check | Added cycle_model and cycle_thinking_level commands with ModelInfo data class. UI shows current model/thinking level with cycle buttons. State survives reconnect via getState on load. | -| 5.4 Extension UI protocol support | DONE | 3d6b9ce | ✅ ktlintCheck, detekt, test, bridge check | Implemented dialog methods (select, confirm, input, editor) with proper response handling. Added fire-and-forget support (notify, setStatus, setWidget, setTitle, set_editor_text). Notifications display as snackbars. | -| 6.1 Backpressure + bounded buffers | DONE | 328b950 | ✅ ktlintCheck, detekt, test | Added BoundedEventBuffer for RPC event backpressure, StreamingBufferManager for memory-efficient text streaming (50KB limit, tail truncation), BackpressureEventProcessor for event coalescing. | -| 6.2 Instrumentation + perf baseline | DONE | 9232795 | ✅ ktlintCheck, detekt, test | Added PerformanceMetrics for startup/resume/TTFT timing, FrameMetrics for jank detection, macrobenchmark module with StartupBenchmark and BaselineProfileGenerator, docs/perf-baseline.md with metrics and targets. | -| 6.3 Baseline profile + release tuning | DE_SCOPED | N/A | N/A | Explicitly de-scoped for this repo because it targets developer-side local/debug usage; benchmark module remains for future release tuning if distribution model changes. | -| 7.1 Optional extension scaffold | DE_SCOPED | N/A | N/A | Explicitly de-scoped from MVP scope; extension UI protocol is fully supported in app/bridge, and repo-local extension scaffold can be added later from pi-extension-template when concrete extension requirements exist. | -| 8.1 Setup + troubleshooting docs | DONE | 50c7268 | ✅ README.md created | Human-readable setup guide with architecture, troubleshooting, and development info. | -| 8.2 Final acceptance report | DONE | 50c7268 | ✅ docs/final-acceptance.md | Comprehensive acceptance checklist with all criteria met. | - -## Per-task verification command set - -```bash -./gradlew ktlintCheck -./gradlew detekt -./gradlew test -# if bridge changed: -(cd bridge && pnpm run check) -``` diff --git a/docs/ai/pi-mobile-final-adjustments-plan.md b/docs/ai/pi-mobile-final-adjustments-plan.md deleted file mode 100644 index 39abc70..0000000 --- a/docs/ai/pi-mobile-final-adjustments-plan.md +++ /dev/null @@ -1,463 +0,0 @@ -# Pi Mobile — Final Adjustments Plan (Fresh Audit) - -Goal: ship an **ultimate** Pi mobile client by prioritizing quick wins and high-risk fixes first, then heavier parity/architecture work last. - -Scope focus from fresh audit: RPC compatibility, Kotlin quality, bridge security/stability, UX parity, performance, and Pi alignment. - -Execution checkpoint (2026-02-15): backlog tasks C1–C4, Q1–Q7, F1–F5, M1–M4, T1–T2, and H1–H4 are complete. Remaining tracked item: manual on-device smoke validation. - -Post-feedback UX/reliability follow-up (2026-02-15): -1. R1 Resume reliability: ensure Chat timeline refreshes after session switch/new/fork responses even when Chat VM is already alive. -2. R2 Sessions explorer usability: default to flat/all-session browsing, clearer view-mode labeling, faster grouped-mode expand/collapse. -3. R3 Session grouping readability: show session counts per cwd and display real project cwd in flat cards. -4. R4 Remove duplicate app chrome: drop platform action bar title (`pi-mobile`) by using NoActionBar app theme. - -> No milestones or estimates. -> Benchmark-specific work is intentionally excluded for now. - ---- - -## 0) Mandatory verification loop (after every task) - -```bash -./gradlew ktlintCheck -./gradlew detekt -./gradlew test -(cd bridge && pnpm run check) -``` - -If any command fails: -1. fix -2. rerun full loop -3. only then mark task done - -Manual smoke checklist (UI/protocol tasks): -- connect host, resume session, create new session -- prompt/abort/steer/follow_up still work -- tool cards + reasoning blocks + diffs still render correctly -- extension dialogs still work (`select`, `confirm`, `input`, `editor`) -- new session from Sessions tab creates + navigates correctly -- chat auto-scrolls to latest message during streaming - ---- - -## 1) Critical UX fixes (immediate) - -### C1 — Fix "New Session" error message bug -**Why:** Creating new session shows "No active session. Resume a session first" which is confusing/incorrect UX. - -**Root cause:** `newSession()` tries to send RPC command without an active bridge connection. The connection is only established during `resumeSession()`. - -**Potential fix approaches:** -1. **Quick fix:** Have `newSession()` establish connection first (like `resumeSession` does), then send `new_session` command -2. **Better fix (see C4):** Keep persistent bridge connection alive, so `new_session` just works - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` -- `app/src/main/java/com/ayagmar/pimobile/sessions/SessionsViewModel.kt` - -**Acceptance:** -- New session creation shows success/loading state, not error -- Auto-navigates to chat with new session active -- Works regardless of whether a session was previously resumed - ---- - -### C4 — Persistent bridge connection (architectural fix for C1) -**Why:** app currently connects on-demand per session; this causes friction for new session, rapid switching, and background/resume. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` -- `app/src/main/java/com/ayagmar/pimobile/di/AppServices.kt` (or replacement DI graph) -- `app/src/main/java/com/ayagmar/pimobile/ui/PiMobileApp.kt` - -**Acceptance:** -- bridge connection established early when host context is available -- `newSession()` and `resumeSession()` reuse the active connection/session control flow -- robust lifecycle behavior (foreground/background/network reconnect) -- C1 moves from quick patch behavior to durable architecture - ---- - -### C2 — Compact chat header (stop blocking streaming view) -**Why:** Top nav takes too much vertical space, blocks view of streaming responses. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` -- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatHeader.kt` (extract if needed) - -**Acceptance:** -- Header collapses or uses minimal height during streaming -- Essential controls (abort, model selector) remain accessible -- More screen real estate for actual chat content - ---- - -### C3 — Flatten directory explorer (improve CWD browsing UX) -**Why:** Current tree requires clicking each directory one-by-one to see sessions. User sees long path list with ▶ icons. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/ui/sessions/SessionsScreen.kt` -- `app/src/main/java/com/ayagmar/pimobile/sessions/SessionsViewModel.kt` - -**Acceptance:** -- Option to view all sessions flattened with path breadcrumbs -- Or: searchable directory tree with auto-expand on filter -- Faster navigation to deeply nested sessions - ---- - -## 2) Quick wins (first) - -### Q1 — Fix image-only prompt mismatch -**Why:** UI enables send with images + empty text, `ChatViewModel.sendPrompt()` currently blocks empty text. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` -- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` - -**Acceptance:** -- image-only send path is consistent and no dead click state - ---- - -### Q2 — Add full tree filter set (`all` included) -**Why:** bridge currently accepts only `default`, `no-tools`, `user-only`, `labeled-only`. - -**Primary files:** -- `bridge/src/session-indexer.ts` -- `bridge/src/server.ts` -- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` -- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` - -**Acceptance:** -- filters include `all` and behave correctly end-to-end - ---- - -### Q3 — Command palette parity layer for built-ins -**Why (Pi RPC doc):** `get_commands` excludes interactive built-ins (`/settings`, `/hotkeys`, etc.). - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` -- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` - -**Acceptance:** -- built-ins show as supported/bridge-backed/unsupported with explicit UX (no silent no-op) - ---- - -### Q4 — Add global collapse/expand controls -**Why:** per-item collapse exists; missing global action parity. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` -- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` - -**Acceptance:** -- one-tap collapse/expand all for tools and reasoning - ---- - -### Q5 — Wire FrameMetrics into live chat -**Why:** metrics utility exists but is not active in chat rendering flow. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` -- `app/src/main/java/com/ayagmar/pimobile/perf/FrameMetrics.kt` - -**Acceptance:** -- frame/jank logs produced during streaming sessions - ---- - -### Q6 — Transport preference setting parity (`sse` / `websocket` / `auto`) -**Why (settings doc):** transport is a first-class setting in Pi. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/ui/settings/SettingsViewModel.kt` -- `app/src/main/java/com/ayagmar/pimobile/ui/settings/SettingsScreen.kt` -- `app/src/main/java/com/ayagmar/pimobile/sessions/SessionController.kt` -- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` - -**Acceptance:** -- setting visible, persisted, and reflected in runtime behavior (with clear fallback notes) - ---- - -### Q7 — Queue inspector UX for pending steer/follow-up -**Why:** queue behavior exists but users cannot inspect/manage pending items clearly. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` -- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` -- `app/src/main/java/com/ayagmar/pimobile/ui/settings/SettingsScreen.kt` (if mode hints/actions added) - -**Acceptance:** -- pending queue is visible while streaming -- queued items can be cancelled/cleared as protocol allows -- UX reflects steering/follow-up mode behavior (`all` vs `one-at-a-time`) - ---- - -## 3) Stability + security fixes - -### F1 — Bridge event isolation and lock correctness -**Why:** outbound RPC events are currently fanned out by `cwd`; tighten to active controller/session ownership. - -**Primary files:** -- `bridge/src/server.ts` -- `bridge/src/process-manager.ts` -- `bridge/test/server.test.ts` -- `bridge/test/process-manager.test.ts` - -**Acceptance:** -- no event leakage across same-cwd clients -- lock enforcement applies consistently for send + receive paths - ---- - -### F2 — Reconnect/resync hardening -**Why:** ensure deterministic recovery under network flaps and reconnect races. - -**Primary files:** -- `core-net/src/main/kotlin/com/ayagmar/pimobile/corenet/PiRpcConnection.kt` -- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` -- tests in `core-net` / `app` - -**Acceptance:** -- no stale/duplicate state application after reconnect -- no stuck streaming flag after recovery - ---- - -### F3 — Bridge auth + exposure hardening -**Why:** improve defensive posture without changing core architecture. - -**Primary files:** -- `bridge/src/server.ts` -- `bridge/src/config.ts` -- `README.md` - -**Acceptance:** -- auth compare hardened -- unsafe bind choices clearly warned/documented -- health endpoint exposure policy explicit - ---- - -### F4 — Android network security tightening -**Why:** app currently permits cleartext globally. - -**Primary files:** -- `app/src/main/res/xml/network_security_config.xml` -- `app/src/main/AndroidManifest.xml` -- `README.md` - -**Acceptance:** -- cleartext policy narrowed/documented for tailscale-only usage assumptions - ---- - -### F5 — Bridge session index scalability -**Why:** recursive full reads of all JSONL files do not scale. - -**Primary files:** -- `bridge/src/session-indexer.ts` -- `bridge/src/server.ts` -- `bridge/test/session-indexer.test.ts` - -**Acceptance:** -- measurable reduction in repeated full-scan overhead on large session stores - ---- - -## 4) Medium maintainability improvements - -### M1 — Replace service locator with explicit DI -**Why:** `AppServices` singleton hides dependencies and complicates tests. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/di/AppServices.kt` -- route/viewmodel factories and call sites - -**Acceptance:** -- explicit dependency graph, no mutable global service locator usage - ---- - -### M2 — Split god classes (architecture hygiene) -**Targets:** -- `ChatViewModel` (~2000+ lines) → extract: message handling, UI state management, command processing -- `ChatScreen.kt` (~2600+ lines) → extract: timeline, header, input, dialogs into separate files -- `RpcSessionController` (~1000+ lines) → extract: connection mgmt, RPC routing, lifecycle - -**Acceptance (non-rigid):** -- class sizes and responsibilities are substantially reduced (no hard fixed LOC cap) -- detekt complexity signals improve (e.g. `LargeClass`, `LongMethod`, `TooManyFunctions` count reduced) -- suppressions are reduced or narrowed with justification -- all existing tests pass -- clear public API boundaries documented - ---- - -### M3 — Unify streaming/backpressure pipeline -**Why:** `BackpressureEventProcessor` / `StreamingBufferManager` / `BoundedEventBuffer` are not integrated in runtime flow. - -**Primary files:** -- `core-rpc/src/main/kotlin/com/ayagmar/pimobile/corerpc/BackpressureEventProcessor.kt` -- `core-rpc/src/main/kotlin/com/ayagmar/pimobile/corerpc/StreamingBufferManager.kt` -- `core-rpc/src/main/kotlin/com/ayagmar/pimobile/corerpc/BoundedEventBuffer.kt` -- app runtime integration points - -**Acceptance:** -- one coherent runtime path (integrated or removed dead abstractions) - ---- - -### M4 — Tighten static analysis rules -**Why:** keep architecture drift in check. - -**Primary files:** -- `detekt.yml` -- affected Kotlin sources - -**Acceptance:** -- fewer broad suppressions -- complexity-oriented rules enforced pragmatically (without blocking healthy modularization) -- all checks green - ---- - -## 5) Theming + Design System (after architecture cleanup) - -### T1 — Centralized theme architecture (PiMobileTheme) -**Why:** Colors are scattered and hardcoded; no dark/light mode support. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/ui/theme/` (create) -- `app/src/main/java/com/ayagmar/pimobile/ui/PiMobileApp.kt` -- all screen files for color replacement - -**Acceptance:** -- `PiMobileTheme` with `lightColorScheme()` and `darkColorScheme()` -- all hardcoded colors replaced with theme references -- settings toggle for light/dark/system-default -- color roles documented (primary, secondary, tertiary, surface, etc.) - ---- - -### T2 — Component design system -**Why:** Inconsistent card styles, button sizes, spacing across screens. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/ui/components/` (create) -- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` -- `app/src/main/java/com/ayagmar/pimobile/ui/sessions/SessionsScreen.kt` -- `app/src/main/java/com/ayagmar/pimobile/ui/settings/SettingsScreen.kt` - -**Acceptance:** -- reusable `PiCard`, `PiButton`, `PiTextField`, `PiTopBar` components -- consistent spacing tokens (4.dp, 8.dp, 16.dp, 24.dp) -- typography scale defined and applied - ---- - -## 6) Heavy hitters (last) - -### H1 — True `/tree` parity (in-place navigate, not fork fallback) -**Why:** current Jump+Continue calls fork semantics. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` -- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` -- `bridge/src/server.ts` (if bridge route needed) - -**Implementation path order:** -1. bridge-first -2. if RPC gap remains: add minimal companion extension or SDK-backed bridge capability - -**Acceptance:** -- navigation semantics match `/tree` behavior (in-place leaf changes + editor behavior) - ---- - -### H2 — Session parsing alignment with Pi internals -**Why:** hand-rolled JSONL parsing is brittle as session schema evolves. - -**Primary files:** -- `bridge/src/session-indexer.ts` -- `bridge/src/server.ts` -- bridge tests - -**Acceptance:** -- parser resiliency improved (or SDK-backed replacement), with compatibility tests - ---- - -### H3 — Incremental session history loading strategy -**Why:** `get_messages` full-load + full parse remains expensive for huge histories. - -**Primary files:** -- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` -- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` -- bridge additions if needed - -**Acceptance:** -- large-session resume remains responsive and memory-stable - ---- - -### H4 — Extension-ize selected hardcoded workflows -**Why:** reduce app-side hardcoding where Pi extension model is a better fit. - -**Candidates:** -- session naming/bookmark workflows -- share/export helpers -- command bundles - -**Acceptance:** -- at least one workflow moved to extension-driven path with docs - ---- - -## Ordered execution queue (strict) - -1. C1 Fix "New Session" error message bug -2. C4 Persistent bridge connection (architectural fix for C1) -3. C2 Compact chat header (stop blocking streaming view) -4. C3 Flatten directory explorer (improve CWD browsing UX) -5. Q1 image-only send fix -6. Q2 full tree filters (`all`) -7. Q3 command palette built-in parity layer -8. Q4 global collapse/expand controls -9. Q5 live frame metrics wiring -10. Q6 transport preference setting parity -11. Q7 queue inspector UX for pending steer/follow-up -12. F1 bridge event isolation + lock correctness -13. F2 reconnect/resync hardening -14. F3 bridge auth/exposure hardening -15. F4 Android network security tightening -16. F5 bridge session index scalability -17. M1 replace service locator with DI -18. M2 split god classes (architecture hygiene) -19. M3 unify streaming/backpressure runtime pipeline -20. M4 tighten static analysis rules -21. T1 Centralized theme architecture (PiMobileTheme) -22. T2 Component design system -23. H1 true `/tree` parity -24. H2 session parsing alignment with Pi internals -25. H3 incremental history loading strategy -26. H4 extension-ize selected workflows - ---- - -## Definition of done - -- [x] Critical UX fixes complete -- [x] Quick wins complete -- [x] Stability/security fixes complete -- [x] Maintainability improvements complete -- [x] Theming + Design System complete -- [x] Heavy hitters complete or explicitly documented as protocol-limited -- [x] Final verification loop green diff --git a/docs/ai/pi-mobile-final-adjustments-progress.md b/docs/ai/pi-mobile-final-adjustments-progress.md deleted file mode 100644 index 02177ca..0000000 --- a/docs/ai/pi-mobile-final-adjustments-progress.md +++ /dev/null @@ -1,634 +0,0 @@ -# Pi Mobile — Final Adjustments Progress Tracker - -Status values: `TODO` | `IN_PROGRESS` | `BLOCKED` | `DONE` - -> Tracker paired with: `docs/ai/pi-mobile-final-adjustments-plan.md` -> Benchmark-specific tracking intentionally removed for now. - ---- - -## Mandatory verification loop (after every task) - -```bash -./gradlew ktlintCheck -./gradlew detekt -./gradlew test -(cd bridge && pnpm run check) -``` - ---- - -## Already completed (reference) - -| Task | Commit message | Commit hash | Notes | -|---|---|---|---| -| Move New Session to Sessions tab | refactor: move New Session to Sessions tab + add chat auto-scroll | 88d1324 | Button now in Sessions header, navigates to Chat | -| Chat auto-scroll | refactor: move New Session to Sessions tab + add chat auto-scroll | 88d1324 | Auto-scrolls to bottom when new messages arrive | -| Fix ANSI escape codes in chat | fix(chat): strip ANSI codes and fix tree layout overflow | 61061b2 | Strips terminal color codes from status messages | -| Tree layout overflow fix | fix(chat): strip ANSI codes and fix tree layout overflow | 61061b2 | Uses LazyRow for filter chips | -| Navigate back to Sessions fix | fix(nav): allow returning to Sessions after resume | 2cc0480 | Fixed backstack and Channel navigation | -| Chat reload on connection | fix(chat): reload messages when connection becomes active | e8ac20f | Auto-loads messages when CONNECTED | - ---- - -## Critical UX fixes (immediate) - -| Order | Task | Status | Commit message | Commit hash | Verification | Notes | -|---|---|---|---|---|---|---| -| 1 | C1 Fix "New Session" error message bug | DONE | fix(sessions): connect before new_session + navigate cleanly | | ktlint✅ detekt✅ test✅ bridge✅ | Finalized via C4 connection architecture (no more forced resume hack) | -| 2 | C4 Persistent bridge connection (architectural fix for C1) | DONE | feat(sessions): persist/reuse bridge connection across new/resume | | ktlint✅ detekt✅ test✅ bridge✅ | Added `ensureConnected`, warmup on host/session load, and activity teardown disconnect | -| 3 | C2 Compact chat header | DONE | feat(chat): compact header during streaming + keep model access | | ktlint✅ detekt✅ test✅ bridge✅ | Streaming mode now hides non-essential header actions and uses compact model/thinking controls | -| 4 | C3 Flatten directory explorer | DONE | fix(sessions): make New Session work + add flat view toggle | e81d27f | | "All" / "Tree" toggle implemented | - ---- - -## Quick wins - -| Order | Task | Status | Commit message | Commit hash | Verification | Notes | -|---|---|---|---|---|---|---| -| 5 | Q1 Fix image-only prompt mismatch | DONE | fix(chat): allow image-only prompt flow and guard failed image encoding | | ktlint✅ detekt✅ test✅ bridge✅ | ChatViewModel now allows empty text when image payloads exist | -| 6 | Q2 Add full tree filters (`all` included) | DONE | feat(tree): add all filter end-to-end (bridge + app) | | ktlint✅ detekt✅ test✅ bridge✅ | Added `all` in bridge validator/indexer + chat tree filter chips | -| 7 | Q3 Command palette built-in parity layer | DONE | feat(chat): add built-in command support states in palette | | ktlint✅ detekt✅ test✅ bridge✅ | Built-ins now appear as supported/bridge-backed/unsupported with explicit behavior | -| 8 | Q4 Global collapse/expand controls | DONE | feat(chat): add global collapse/expand for tools and reasoning | | ktlint✅ detekt✅ test✅ bridge✅ | Added one-tap header controls with view-model actions for tools/reasoning expansion | -| 9 | Q5 Wire frame metrics into live chat | DONE | feat(perf): enable streaming frame-jank logging in chat screen | | ktlint✅ detekt✅ test✅ bridge✅ | Hooked `StreamingFrameMetrics` into ChatScreen with per-jank log output | -| 10 | Q6 Transport preference setting parity | DONE | feat(settings): add transport preference parity with websocket fallback | | ktlint✅ detekt✅ test✅ bridge✅ | Added `auto`/`websocket`/`sse` preference UI, persistence, and runtime fallback to websocket with explicit notes | -| 11 | Q7 Queue inspector UX for pending steer/follow-up | DONE | feat(chat): add streaming queue inspector for steer/follow-up | | ktlint✅ detekt✅ test✅ bridge✅ | Added pending queue inspector card during streaming with per-item remove/clear actions and delivery-mode visibility | - ---- - -## Stability + security fixes - -| Order | Task | Status | Commit message | Commit hash | Verification | Notes | -|---|---|---|---|---|---|---| -| 12 | F1 Bridge event isolation + lock correctness | DONE | fix(bridge): isolate rpc events to control owner per cwd | | ktlint✅ detekt✅ test✅ bridge✅ | RPC forwarder events now require active control ownership before fan-out; added tests for shared-cwd isolation and post-release send rejection | -| 13 | F2 Reconnect/resync race hardening | DONE | fix(core-net): harden reconnect resync epochs and pending requests | | ktlint✅ detekt✅ test✅ bridge✅ | Added reconnect epoch gating, cancelled pending request responses on reconnect/disconnect, and synced streaming flag from resync snapshots | -| 14 | F3 Bridge auth + exposure hardening | DONE | fix(bridge): harden token auth and exposure defaults | | ktlint✅ detekt✅ test✅ bridge✅ | Added constant-time token hash compare, health endpoint exposure toggle, non-loopback bind warnings, and README security guidance | -| 15 | F4 Android network security tightening | DONE | fix(android): tighten cleartext policy to tailscale hostnames | | ktlint✅ detekt✅ test✅ bridge✅ | Scoped cleartext to `localhost` + `*.ts.net`, set `usesCleartextTraffic=false`, and documented MagicDNS/Tailnet assumptions | -| 16 | F5 Bridge session index scalability | DONE | perf(bridge): cache session metadata by stat signature | | ktlint✅ detekt✅ test✅ bridge✅ | Added session metadata cache keyed by file mtime/size to avoid repeated full file reads for unchanged session indexes | - ---- - -## Medium maintainability improvements - -| Order | Task | Status | Commit message | Commit hash | Verification | Notes | -|---|---|---|---|---|---|---| -| 17 | M1 Replace service locator with explicit DI | DONE | refactor(di): replace app service locator with explicit graph | | ktlint✅ detekt✅ test✅ bridge✅ | Introduced AppGraph dependency container and removed global `AppServices` singleton usage from routes/viewmodel factories | -| 18 | M2 Split god classes (complexity-focused, non-rigid) | DONE | refactor(chat): extract overlay and command palette components | | ktlint✅ detekt✅ test✅ bridge✅ | Extracted extension dialogs, notifications, and command palette from `ChatScreen.kt` into dedicated `ChatOverlays.kt` and tightened DI wiring split from M1 | -| 19 | M3 Unify streaming/backpressure runtime pipeline | DONE | refactor(core-rpc): remove unused backpressure pipeline abstractions | | ktlint✅ detekt✅ test✅ bridge✅ | Removed unused `BackpressureEventProcessor`, `StreamingBufferManager`, `BoundedEventBuffer` and their tests to keep a single runtime path based on `AssistantTextAssembler` + `UiUpdateThrottler` | -| 20 | M4 Tighten static analysis rules/suppressions | DONE | chore(detekt): tighten complexity config and drop broad file suppressions | | ktlint✅ detekt✅ test✅ bridge✅ | Added explicit `TooManyFunctions` complexity tuning (`ignorePrivate`, raised thresholds) and removed redundant `@file:Suppress("TooManyFunctions")` across core UI/runtime files | - ---- - -## Theming + Design System (after architecture cleanup) - -| Order | Task | Status | Commit message | Commit hash | Verification | Notes | -|---|---|---|---|---|---|---| -| 21 | T1 Centralized theme architecture (PiMobileTheme) | DONE | feat(theme): add PiMobileTheme with system/light/dark preference | | ktlint✅ detekt✅ test✅ bridge✅ | Added `ui/theme` package, wrapped app in `PiMobileTheme`, introduced persisted theme preference + settings controls, and removed chat hardcoded tool colors in favor of theme roles | -| 22 | T2 Component design system | DONE | feat(ui): introduce reusable Pi design system primitives | | ktlint✅ detekt✅ test✅ bridge✅ | Added `ui/components` (`PiCard`, `PiButton`, `PiTextField`, `PiTopBar`, `PiSpacing`) and adopted them across Settings + Sessions for consistent spacing/actions/search patterns | - ---- - -## Heavy hitters (last) - -| Order | Task | Status | Commit message | Commit hash | Verification | Notes | -|---|---|---|---|---|---|---| -| 23 | H1 True `/tree` parity (in-place navigate) | DONE | feat(tree): add bridge-backed in-place tree navigation parity | 4b71090 | ktlint✅ detekt✅ test✅ bridge✅ | Added bridge `bridge_navigate_tree` flow powered by internal Pi extension command (`ctx.navigateTree`), wired Chat jump action to in-place navigation (not fork), and propagated runtime current leaf to tree responses | -| 24 | H2 Session parsing alignment with Pi internals | DONE | refactor(bridge): align session index parsing with pi metadata semantics | c7127bf | ktlint✅ detekt✅ test✅ bridge✅ | Added resilient tree normalization for legacy entries without ids, aligned `updatedAt` to user/assistant activity semantics, and mapped hidden active leaves to visible ancestors under tree filters with compatibility tests | -| 25 | H3 Incremental session history loading strategy | DONE | perf(chat): incrementally parse resume history with paged windows | 91a4d9b | ktlint✅ detekt✅ test✅ bridge✅ | Added capped history window extraction with on-demand page parsing for older messages, preserving hidden-count pagination semantics while avoiding full-history timeline materialization on resume | -| 26 | H4 Extension-ize selected hardcoded workflows | DONE | feat(extensions): route mobile stats workflow through internal command | 1fc6b7f | ktlint✅ detekt✅ test✅ bridge✅ | Added bridge-shipped `pi-mobile-workflows` extension command and routed `/stats` built-in through extension status actions, reducing app-side hardcoded workflow execution while preserving fallback UX | - ---- - -## Post-feedback UX/reliability follow-up (2026-02-15) - -| Order | Task | Status | Commit message | Commit hash | Verification | Notes | -|---|---|---|---|---|---|---| -| R1 | Resume reliability (chat refresh after session switch) | DONE | pending | | ktlint✅ detekt✅ test✅ bridge✅ | ChatViewModel now reloads history on successful `switch_session`/`new_session`/`fork` RPC responses to prevent stale timeline when resuming from Sessions tab | -| R2 | Sessions explorer UX (flat-first + quick grouped controls) | DONE | pending | | ktlint✅ detekt✅ test✅ bridge✅ | Sessions now default to flat browsing; mode toggle relabeled (`Flat`/`Grouped`); grouped mode adds one-tap expand/collapse-all | -| R3 | Session grouping readability improvements | DONE | pending | | ktlint✅ detekt✅ test✅ bridge✅ | CWD headers now include session counts; session cards gained compact metadata rows (`msgs`/model), single-line path ellipsis, and flat cards now show actual project `cwd` instead of storage directories | -| R4 | Remove redundant top app bar (`pi-mobile`) | DONE | pending | | ktlint✅ detekt✅ test✅ bridge✅ | App theme switched to `Theme.DeviceDefault.NoActionBar` to reclaim vertical space and remove duplicate chrome | - ---- - -## Verification template (paste per completed task) - -```text -ktlintCheck: ✅/❌ -detekt: ✅/❌ -test: ✅/❌ -bridge check: ✅/❌ -manual smoke: ✅/❌ -``` - ---- - -## Running log - -### Entry template - -```text -Date: -Task: -Status change: -Commit: -Verification: -Notes/blockers: -``` - -### 2026-02-15 - -```text -Task: C4 (and C1 finalization) -Status change: C4 TODO -> DONE, C1 IN_PROGRESS -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added SessionController.ensureConnected()/disconnect() and RpcSessionController connection reuse by host+cwd. -- SessionsViewModel now warms bridge connection after host/session load and reuses it for newSession/resume. -- MainActivity now triggers sessionController.disconnect() on app finish. -``` - -### 2026-02-15 - -```text -Task: C2 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Chat header now enters compact mode while streaming. -- Non-essential actions (stats/copy/bash) are hidden during streaming to free vertical space. -- Model selector remains directly accessible in compact mode. -``` - -### 2026-02-15 - -```text -Task: Q1 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- ChatViewModel.sendPrompt() now allows image-only prompts. -- Added guard for image-encoding failures to avoid sending empty prompt with no payload. -``` - -### 2026-02-15 - -```text -Task: Q2 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added `all` to bridge tree filter whitelist and session-indexer filter type. -- `all` now returns full tree entries (including label/custom entries). -- Added app-side tree filter option chip for `all`. -``` - -### 2026-02-15 - -```text -Task: Q3 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Command palette now labels commands as supported / bridge-backed / unsupported. -- Added explicit built-in entries for interactive TUI commands omitted by RPC get_commands. -- Selecting or sending interactive-only built-ins now shows explicit mobile UX instead of silent no-op. -``` - -### 2026-02-15 - -```text -Task: Q4 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added global "Collapse all" / "Expand all" controls for tools and reasoning. -- Hooked controls to new ChatViewModel actions for timeline-wide expansion state updates. -- Added coverage for global expand/collapse behavior in ChatViewModel tests. -``` - -### 2026-02-15 - -```text -Task: Q5 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Activated StreamingFrameMetrics in ChatScreen when streaming is active. -- Added jank logs with severity/frame-time/dropped-frame estimate for live chat rendering. -``` - -### 2026-02-15 - -```text -Task: Q6 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added transport preference setting (`auto` / `websocket` / `sse`) in Settings with persistence. -- SessionController now exposes transport preference APIs and RpcSessionController applies runtime websocket fallback. -- Added clear effective transport + fallback note in UI when SSE is requested. -``` - -### 2026-02-15 - -```text -Task: Q7 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added streaming queue inspector in chat for steer/follow-up submissions. -- Queue inspector shows delivery modes (`all` / `one-at-a-time`) and supports remove/clear actions. -- Queue state auto-resets when streaming ends and is covered by ChatViewModel tests. -``` - -### 2026-02-15 - -```text -Task: F1 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Tightened bridge RPC event fan-out so only the client that currently holds control for a cwd receives process events. -- Added server tests proving no same-cwd RPC leakage to non-controlling clients. -- Added regression test ensuring RPC send is rejected once control is released. -``` - -### 2026-02-15 - -```text -Task: F2 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added lifecycle epoch gating around reconnect synchronization to prevent stale resync snapshots from applying after lifecycle changes. -- Pending RPC request deferred responses are now cancelled on reconnect/disconnect transitions to avoid stale waits. -- RpcSessionController now consumes resync snapshots and refreshes streaming flag from authoritative state. -``` - -### 2026-02-15 - -```text -Task: F3 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Replaced direct token string equality with constant-time hash digest comparison. -- Added explicit `BRIDGE_ENABLE_HEALTH_ENDPOINT` policy with tests for disabled `/health` behavior. -- Added non-loopback host exposure warnings and documented hardened bridge configuration in README. -``` - -### 2026-02-15 - -```text -Task: F4 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Tightened debug/release network security configs to disable global cleartext and allow only `localhost` + `*.ts.net`. -- Explicitly set `usesCleartextTraffic=false` in AndroidManifest. -- Updated README connect/security guidance to prefer Tailnet MagicDNS hostnames and document scoped cleartext assumptions. -``` - -### 2026-02-15 - -```text -Task: F5 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added session metadata cache in session indexer using file stat signatures (mtime/size). -- Unchanged session files now skip re-read/re-parse during repeated `bridge_list_sessions` calls. -- Added regression test proving cached reads are reused and invalidated when a session file changes. -``` - -### 2026-02-15 - -```text -Task: M1 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added `AppGraph` as explicit dependency container built in MainActivity and passed into the app root. -- Removed `AppServices` singleton and migrated Chat/Settings/Sessions/Hosts routes + viewmodel factories to explicit dependencies. -- MainActivity lifecycle teardown now disconnects via graph-owned SessionController instance. -``` - -### 2026-02-15 - -```text -Task: M2 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Extracted extension dialogs, notifications, and command palette rendering from `ChatScreen.kt` into new `ChatOverlays.kt`. -- Reduced `ChatScreen.kt` responsibilities toward timeline/layout concerns while preserving behavior. -- Continued DI cleanup from M1 by keeping route/factory wiring explicit and test-safe. -``` - -### 2026-02-15 - -```text -Task: M3 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Removed `BackpressureEventProcessor`, `StreamingBufferManager`, and `BoundedEventBuffer` from `core-rpc` because they were not used by app runtime. -- Removed corresponding isolated tests to avoid maintaining dead abstractions. -- Runtime streaming path now clearly centers on `AssistantTextAssembler` and `UiUpdateThrottler`. -``` - -### 2026-02-15 - -```text -Task: M4 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added explicit `complexity.TooManyFunctions` policy in `detekt.yml` (`ignorePrivate: true`, thresholds raised to 15 for files/classes). -- Removed redundant `@file:Suppress("TooManyFunctions")` from Chat/Sessions/Settings screens, ChatViewModel, RpcSessionController, and AssistantTextAssembler. -- Kept targeted rule suppressions only where still justified. -``` - -### 2026-02-15 - -```text -Task: T1 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added `PiMobileTheme` with dedicated light/dark color schemes and system/light/dark resolution. -- Wired app root to observe persisted theme preference from shared settings and apply theme dynamically. -- Added theme preference controls in Settings and removed hardcoded chat tool colors in favor of theme color roles. -``` - -### 2026-02-15 - -```text -Task: T2 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added reusable design-system primitives under `ui/components`: `PiCard`, `PiButton`, `PiTextField`, `PiTopBar`, and `PiSpacing`. -- Migrated Settings and Sessions screens to shared components for card layouts, top bars, option buttons, and text fields. -- Standardized key spacing to shared tokens (`PiSpacing`) in updated screen flows. -``` - -### 2026-02-15 - -```text -Task: H1 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added bridge `bridge_navigate_tree` API backed by an internal Pi extension command using `ctx.navigateTree(...)`. -- Chat Jump now performs in-place tree navigation (same session) and updates editor text from navigation result, replacing prior fork fallback. -- Bridge now tracks runtime current leaf from navigation results and overlays it into `bridge_get_session_tree` responses for active sessions. -``` - -### 2026-02-15 - -```text -Task: H2 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Reworked bridge session index parsing to normalize legacy/id-missing entries into deterministic tree ids and linear parent chains. -- Aligned `updatedAt` metadata with Pi internals by using last user/assistant activity timestamps instead of arbitrary last entry timestamps. -- Improved tree snapshot parity by mapping hidden active leaves to nearest visible ancestors and expanding compatibility coverage in `session-indexer` tests. -``` - -### 2026-02-15 - -```text -Task: H3 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Switched chat history resume to an incremental parsing model: retain a capped message window, parse only the initial visible page, then parse older pages on demand. -- Preserved pagination UX (`hasOlderMessages`, `hiddenHistoryCount`) while avoiding eager materialization of the whole retained history timeline. -- Added coverage for very large-session window cap behavior in `ChatViewModelThinkingExpansionTest`. -``` - -### 2026-02-15 - -```text -Task: H4 -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Added a second bridge-internal extension (`pi-mobile-workflows`) and loaded it alongside `pi-mobile-tree` for RPC sessions. -- Routed mobile `/stats` built-in command through an extension command (`/pi-mobile-open-stats`) that emits internal status action payloads. -- Added ChatViewModel handling/tests for internal workflow status actions and hidden internal command filtering from command palette. -``` - -### 2026-02-15 - -```text -Task: R1/R2/R3/R4 (post-feedback UX/reliability follow-up) -Status change: TODO -> DONE -Commit: pending -Verification: -- ktlintCheck: ✅ -- detekt: ✅ -- test: ✅ -- bridge check: ✅ -- manual smoke: ⏳ pending on device -Notes/blockers: -- Fixed stale chat-on-resume behavior by reloading history on successful `switch_session` / `new_session` / `fork` RPC responses. -- Improved Sessions UX: default flat browsing, clearer `Flat`/`Grouped` mode labels, and one-tap grouped expand/collapse-all. -- Improved grouped readability with per-cwd session counts and showed real project `cwd` in flat cards. -- Removed duplicate `pi-mobile` top chrome by switching app theme to `Theme.DeviceDefault.NoActionBar`. -``` - ---- - -## Overall completion - -- Backlog tasks: 26 -- Backlog done: 26 -- Backlog in progress: 0 -- Backlog blocked: 0 -- Backlog remaining (not done): 0 -- Reference completed items (not counted in backlog): 6 - ---- - -## Quick checklist - -- [x] Critical UX fixes complete -- [x] Quick wins complete -- [x] Stability/security fixes complete -- [x] Maintainability improvements complete -- [x] Theming + Design System complete -- [x] Heavy hitters complete (or documented protocol limits) -- [x] Final green run (`ktlintCheck`, `detekt`, `test`, bridge check) - ---- - -## UX Issues from User Feedback (for reference) - -1. **"No active session" on New Session** — Error message shows when creating new session, should show success -2. **Top nav blocks streaming view** — Header too tall, obscures content during streaming -3. **Directory explorer pain** — Have to click ▶ on each CWD individually to find sessions -4. **Auto-scroll works** — ✅ Fixed in commit 88d1324 -5. **ANSI codes stripped** — ✅ Fixed in commit 61061b2 -6. **Navigate back to Sessions** — ✅ Fixed in commit 2cc0480 - ---- - -## Fresh-eyes review pass (current) - -| Task | Status | Notes | Verification | -|---|---|---|---| -| Deep architecture/code review across chat/session/transport flows | DONE | Re-read `rpc.md` + extension event model and traced end-to-end session switching, prompt dispatch, and UI rendering paths. | ktlint✅ detekt✅ test✅ bridge✅ | -| Prompt error surfacing for unsupported/non-subscribed models | DONE | `RpcSessionController.sendPrompt()` now awaits `prompt` response and propagates `success=false` errors to UI; input/images are restored on failure in `ChatViewModel.sendPrompt()`. | ktlint✅ detekt✅ test✅ bridge✅ | -| Streaming controls responsiveness | DONE | Controller now marks streaming optimistically at prompt dispatch (and reverts on failure), so Abort/Steer/Follow-up controls appear earlier. | ktlint✅ detekt✅ test✅ bridge✅ | -| Lifecycle toast/banner spam reduction | DONE | Removed noisy lifecycle notifications (`Turn started`, `message completed`) and deleted dead lifecycle throttling state/helpers. | ktlint✅ detekt✅ test✅ bridge✅ | -| Chat header UX correction | DONE | Restored Tree + Bash quick actions while keeping simplified header layout and reduced clutter. | ktlint✅ detekt✅ test✅ bridge✅ | -| Chat/tool syntax highlighting | DONE | Added fenced code-block parsing + lightweight token highlighting for assistant messages and inferred-language highlighting for tool output based on file extension. | ktlint✅ detekt✅ test✅ bridge✅ | -| Dead API/command cleanup | DONE | Removed unused `get_last_assistant_text` command plumbing from `SessionController`, `RpcSessionController`, `RpcCommand`, command encoding, and tests. | ktlint✅ detekt✅ test✅ bridge✅ | -| Dead UI callback/feature cleanup | DONE | Removed unused chat callbacks and orphaned global expansion UI path/tests that were no longer reachable from UI. | ktlint✅ detekt✅ test✅ bridge✅ | diff --git a/docs/ai/pi-mobile-rpc-enhancement-progress.md b/docs/ai/pi-mobile-rpc-enhancement-progress.md deleted file mode 100644 index b3f0742..0000000 --- a/docs/ai/pi-mobile-rpc-enhancement-progress.md +++ /dev/null @@ -1,123 +0,0 @@ -# Pi Mobile RPC Enhancement Progress Tracker - -Status values: `TODO` | `IN_PROGRESS` | `BLOCKED` | `DONE` | `DE_SCOPED` - -> Last updated: 2026-02-15 (Post-parity hardening tasks H1-H3 completed) - ---- - -## Completed milestones - -| Area | Status | Notes | -|---|---|---| -| Thinking blocks + collapse | DONE | Implemented in assembler + chat UI | -| Slash commands palette | DONE | `get_commands` + grouped searchable UI | -| Auto compaction/retry notifications | DONE | Events parsed and surfaced | -| Tool UX enhancements | DONE | icons, arguments, diff viewer | -| Bash UI | DONE | execute/abort/history/output/copy | -| Session stats | DONE | stats sheet in chat | -| Model picker | DONE | available models + set model | -| Auto settings toggles | DONE | auto-compaction + auto-retry | -| Image attachments | DONE | picker + thumbnails + base64 payload | -| RPC schema mismatch fixes | DONE | stats/bash/models/set_model/fork fields fixed in controller parser | - ---- - -## Ordered backlog (current) - -| Order | Task | Status | Commit | Verification | Notes | -|---|---|---|---|---|---| -| 1 | Protocol conformance tests (stats/bash/models/set_model/fork) | DONE | `1f90b3f` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added `RpcSessionControllerTest` conformance coverage for canonical + legacy mapping fields | -| 2 | Parse missing events: `message_start/end`, `turn_start/end`, `extension_error` | DONE | `1f57a2a` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added parser branches + models and event parsing tests for lifecycle and extension errors | -| 3 | Surface lifecycle + extension errors in chat UX | DONE | `09e2b27` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added non-blocking lifecycle notifications and contextual extension error notifications in chat | -| 4 | Steering/follow-up mode controls (`set_*_mode`) | DONE | `948ace3` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added RPC commands, session controller wiring, settings UI selectors, and get_state mode sync | -| 5 | Tree navigation spike (`/tree` equivalent feasibility) | DONE | `4472f89` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added spike doc; decision: RPC-only is insufficient, add read-only bridge session-tree endpoint | -| 6 | Tree navigation MVP | DONE | `360aa4f` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ `(cd bridge && pnpm run check)` ✅ | Added bridge session-tree endpoint, app bridge request path, and chat tree sheet with fork-from-entry navigation | -| 7 | Keyboard shortcuts/gestures help screen | DONE | `5ca89ce` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added settings help card documenting chat actions, gestures, and key interactions | -| 8 | README/docs sync | DONE | `5dd4b48` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | README refreshed with current UX capabilities and limitations (including image support) | - ---- - -## Post-parity hardening backlog - -| Order | Task | Status | Commit | Verification | Notes | -|---|---|---|---|---|---| -| H1 | Tree contract conformance tests | DONE | `e56db90` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ `(cd bridge && pnpm run check)` ✅ | Added bridge/session-indexer tree endpoint tests and app tree parser mapping test | -| H2 | Lifecycle notification noise controls | DONE | `09fa47d` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added lifecycle notification throttling and duplicate suppression while preserving extension error visibility | -| H3 | Settings mode controls test coverage | DONE | `777c56c` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added `SettingsViewModelTest` coverage for steering/follow-up mode success and rollback paths | - ---- - -## Command coverage status - -### Implemented -- `prompt`, `steer`, `follow_up`, `abort`, `new_session` -- `get_state`, `get_messages`, `switch_session` -- `set_session_name`, `get_fork_messages`, `fork` -- `export_html`, `compact` -- `cycle_model`, `cycle_thinking_level` -- `get_commands` -- `bash`, `abort_bash` -- `get_session_stats` -- `get_available_models`, `set_model` -- `set_auto_compaction`, `set_auto_retry` -- `set_steering_mode`, `set_follow_up_mode` - -### Remaining -- None - ---- - -## Event coverage status - -### Implemented -- `message_update` (text + thinking) -- `message_start` / `message_end` -- `turn_start` / `turn_end` -- `tool_execution_start/update/end` -- `extension_ui_request` -- `extension_error` -- `agent_start/end` -- `auto_compaction_start/end` -- `auto_retry_start/end` - -### Remaining -- None (parser-level) - ---- - -## Feature parity checklist (pi mono TUI) - -- [x] Tool calls visible -- [x] Tool output collapse/expand -- [x] Reasoning visibility + collapse/expand -- [x] File edit diff view -- [x] Slash commands discovery/use -- [x] Model control beyond cycling -- [x] Session stats display -- [x] Image attachments -- [x] Tree navigation equivalent (`/tree`) -- [x] Steering/follow-up delivery mode controls -- [x] Lifecycle/extension error event completeness - ---- - -## Verification commands - -```bash -./gradlew ktlintCheck -./gradlew detekt -./gradlew test -# if bridge changed: -(cd bridge && pnpm run check) -``` - ---- - -## Blockers / risks - -| Task | Risk | Mitigation | -|---|---|---| -| Tree navigation | Bridge/tree payload drift across pi session formats | Keep parser defensive and cover with bridge tests/fixtures | -| Lifecycle UX noise | Too many system notifications can clutter chat | Keep subtle + dismissible + rate-limited | -| Protocol regressions | Field names can drift across pi versions | Add parser conformance tests with real payload fixtures | diff --git a/docs/ai/pi-mobile-rpc-enhancement-tasks.md b/docs/ai/pi-mobile-rpc-enhancement-tasks.md deleted file mode 100644 index b51dd67..0000000 --- a/docs/ai/pi-mobile-rpc-enhancement-tasks.md +++ /dev/null @@ -1,234 +0,0 @@ -# Pi Mobile RPC Enhancement Tasks (Ordered Iteration Plan) - -Updated plan after major parity work landed. - -> Rule: execute in order. Do not start next task until current task is green (`ktlintCheck`, `detekt`, `test`, and bridge `pnpm run check` if touched). - ---- - -## 0) Current state snapshot - -Already completed: -- Thinking blocks + collapse/expand -- Slash commands palette -- Auto-compaction/auto-retry notifications -- Edit diff viewer -- Bash dialog (run + abort + history) -- Tool argument display + tool icons -- Session stats sheet -- Model picker + set model -- Auto-compaction/auto-retry settings toggles -- Image attachment support - -Remaining gaps for fuller pi mono TUI parity: -- None from this plan (all items completed) - -Completed in this iteration: -- Task 1.1 — `1f90b3f` -- Task 1.2 — `1f57a2a` -- Task 2.1 — `09e2b27` -- Task 2.2 — `948ace3` -- Task 3.1 — `4472f89` -- Task 3.2 — `360aa4f` -- Task 4.1 — `5ca89ce` -- Task 4.2 — `5dd4b48` - ---- - -## 1) Protocol conformance hardening (P0) - -### Task 1.1 — Lock RPC parser/mapper behavior with tests -**Priority:** CRITICAL -**Goal:** Prevent regressions in RPC field mapping. - -Scope: -- Add tests for: - - `get_session_stats` nested shape (`tokens`, `cost`, `totalMessages`) - - `bash` fields (`truncated`, `fullOutputPath`) - - `get_available_models` fields (`reasoning`, `maxTokens`, `cost.*`) - - `set_model` direct model payload - - `get_fork_messages` using `text` -- Keep backward-compatible fallback coverage for legacy field names. - -Files: -- `app/src/test/.../sessions/RpcSessionController*Test.kt` (create if missing) -- optionally `core-rpc/src/test/.../RpcMessageParserTest.kt` - -Acceptance: -- All mapping tests pass and fail if field names regress. - ---- - -### Task 1.2 — Add parser support for missing lifecycle events -**Priority:** HIGH - -Scope: -- Add models + parser branches for: - - `message_start` - - `message_end` - - `turn_start` - - `turn_end` - - `extension_error` - -Files: -- `core-rpc/src/main/kotlin/.../RpcIncomingMessage.kt` -- `core-rpc/src/main/kotlin/.../RpcMessageParser.kt` -- `core-rpc/src/test/kotlin/.../RpcMessageParserTest.kt` - -Acceptance: -- Event parsing tests added and passing. - ---- - -## 2) Chat UX completeness (P1) - -### Task 2.1 — Surface lifecycle and extension errors in chat -**Priority:** HIGH - -Scope: -- Show subtle system notifications for: - - message/turn boundaries (optional minimal indicators) - - extension runtime errors (`extension_error`) -- Keep non-intrusive UX (no modal interruption). - -Files: -- `app/src/main/java/.../chat/ChatViewModel.kt` -- `app/src/main/java/.../ui/chat/ChatScreen.kt` - -Acceptance: -- Extension errors visible to user with context (extension path/event/error). -- No crashes on unknown lifecycle event payloads. - ---- - -### Task 2.2 — Steering/follow-up mode controls -**Priority:** HIGH - -Scope: -- Implement RPC commands/UI for: - - `set_steering_mode` (`all` | `one-at-a-time`) - - `set_follow_up_mode` (`all` | `one-at-a-time`) -- Expose in settings (or chat settings panel). -- Read current mode from `get_state` and reflect in UI. - -Files: -- `core-rpc/src/main/kotlin/.../RpcCommand.kt` -- `app/src/main/java/.../sessions/SessionController.kt` -- `app/src/main/java/.../sessions/RpcSessionController.kt` -- `app/src/main/java/.../ui/settings/SettingsViewModel.kt` -- `app/src/main/java/.../ui/settings/SettingsScreen.kt` - -Acceptance: -- User can change both modes and values persist for active session. - ---- - -## 3) Tree navigation track (P2) - -### Task 3.1 — Technical spike for `/tree` equivalent -**Priority:** MEDIUM - -Scope: -- Verify whether current RPC payloads expose enough branch metadata. -- If insufficient, define bridge extension API (read-only session tree endpoint). -- Write design doc with chosen approach and payload schema. - -Deliverable: -- `docs/spikes/tree-navigation-rpc-vs-bridge.md` - -Acceptance: -- Clear go/no-go decision and implementation contract. - ---- - -### Task 3.2 — Implement minimal tree view (MVP) -**Priority:** MEDIUM - -Scope: -- Basic branch-aware navigation screen: - - current path - - branch points - - jump-to-entry -- No fancy rendering needed for MVP; correctness first. - -Acceptance: -- User can navigate history branches and continue from selected point. - ---- - -## 4) Documentation and polish (P3) - -### Task 4.1 — Keyboard shortcuts / gestures help screen -**Priority:** LOW - -Scope: -- Add in-app help card/page documenting chat actions and gestures. - -Acceptance: -- Accessible from settings and up to date with current UI. - ---- - -### Task 4.2 — README/docs sync with implemented features -**Priority:** LOW - -Scope: -- Update stale README limitations (image support now exists). -- Document command palette, thinking blocks, bash dialog, stats, model picker. - -Files: -- `README.md` -- `docs/testing.md` if needed - -Acceptance: -- No known stale statements in docs. - ---- - -## 5) Verification loop (mandatory after each task) - -```bash -./gradlew ktlintCheck -./gradlew detekt -./gradlew test -# if bridge changed: -(cd bridge && pnpm run check) -``` - ---- - -## 6) Post-parity hardening queue (new) - -### Task H1 — Tree contract conformance tests -**Priority:** HIGH - -Scope: -- Add bridge tests for `bridge_get_session_tree` success/error handling. -- Add session-indexer tests for parent/child tree parsing from fixture sessions. -- Add app parser test coverage for `parseSessionTreeSnapshot` mapping. - -Acceptance: -- Tests fail on tree payload contract regressions and pass on current schema. - -### Task H2 — Lifecycle notification noise controls -**Priority:** MEDIUM - -Scope: -- Add throttling/dedup logic for lifecycle notifications during high-frequency event bursts. -- Keep extension errors always visible. - -### Task H3 — Settings mode controls test coverage -**Priority:** MEDIUM - -Scope: -- Add tests for steering/follow-up mode view-model state transitions and rollback on RPC failures. - ---- - -## Ordered execution queue (next) - -1. Task H1 — Tree contract conformance tests ✅ DONE (`e56db90`) -2. Task H2 — Lifecycle notification noise controls ✅ DONE (`09fa47d`) -3. Task H3 — Settings mode controls test coverage ✅ DONE (`777c56c`) - -All post-parity hardening tasks currently defined are complete. diff --git a/docs/ai/pi-mobile-ux-resume-fix-plan.md b/docs/ai/pi-mobile-ux-resume-fix-plan.md deleted file mode 100644 index 7bf7657..0000000 --- a/docs/ai/pi-mobile-ux-resume-fix-plan.md +++ /dev/null @@ -1,72 +0,0 @@ -# Pi Mobile UX and Resume Fix Plan - -## Issues Identified from Screenshot and Logs - -### 1. Duplicate User Messages (HIGH PRIORITY) -**Problem:** User messages appear twice - once from optimistic insertion in `sendPrompt()` and again from `MessageEndEvent`. - -**Fix:** Remove optimistic insertion, only add user messages from `MessageEndEvent`. This ensures single source of truth. - -### 2. Resume Not Working After First Resume (HIGH PRIORITY) -**Problem:** When user switches sessions, the `switch_session` command succeeds but ChatViewModel doesn't reload the timeline. - -**Root Cause:** `RpcSessionController.resume()` returns success, but there's no mechanism to notify ChatViewModel that the session changed. The response goes to `sendAndAwaitResponse()` but isn't broadcast to observers. - -**Fix Options:** -- Option A: Have SessionController emit a "sessionChanged" event that ChatViewModel observes -- Option B: Have ChatViewModel poll for session path changes -- Option C: Use SharedFlow to broadcast switch_session success - -**Chosen:** Option A - Add `sessionChanged` SharedFlow to SessionController that emits when session successfully switches. - -### 3. UI Clutter (MEDIUM PRIORITY) -**Problems:** -- Too many buttons in top bar (Tree, stats, copy, export) -- Collapse/expand all buttons add more clutter -- Weird status text at bottom ("3 pkgs • ... weekly • 1 update...") -- Model selector and thinking dropdown take too much space - -**Fix:** -- Move Tree, stats, copy, export to overflow menu or bottom sheet -- Remove collapse/expand all from main UI (keep in overflow menu) -- Fix or remove the bottom status text -- Simplify model/thinking display - -### 4. Message Alignment Already Working -**Status:** User messages ARE on the right ("You" cards), assistant on left. This is correct. - -## Implementation Order - -1. Fix duplicate messages (remove optimistic insertion) -2. Fix resume by adding session change notification -3. Clean up UI clutter - -## Architecture for Resume Fix - -```kotlin -// SessionController interface -interface SessionController { - // ... existing methods ... - - // New: Observable session changes - val sessionChanged: SharedFlow // emits new session path or null -} - -// RpcSessionController implementation -override suspend fun resume(...): Result { - // ... existing logic ... - - if (success) { - _sessionChanged.emit(newSessionPath) - } -} - -// ChatViewModel -init { - viewModelScope.launch { - sessionController.sessionChanged.collect { newPath - - loadInitialMessages() // Reload timeline - } - } -} -``` diff --git a/docs/ai/ui-ux-enhancements-plan.md b/docs/ai/ui-ux-enhancements-plan.md deleted file mode 100644 index 58cc0a0..0000000 --- a/docs/ai/ui-ux-enhancements-plan.md +++ /dev/null @@ -1,96 +0,0 @@ -# Pi Mobile — UI/UX Enhancements Plan - -_Last updated: 2026-02-16_ - -> Planning artifact only. Do **not** commit this file. - -## 1) Goal - -Define and execute incremental UI/UX improvements that enhance clarity, speed, and trust during daily mobile usage. - -## 2) Scope - -- Chat readability and hierarchy -- Interaction efficiency (1–2 tap access to common actions) -- Streaming/latency perception improvements -- Session clarity and confidence cues -- Accessibility and visual consistency improvements - -## 3) Non-goals - -- No protocol-breaking RPC changes unless explicitly approved -- No broad architecture rewrite in this track -- No backend behavior changes outside UX-driven requirements - -## 4) Working agreements - -- One issue/task per commit where possible -- Conventional Commits -- Do not push from agent -- Keep planning docs out of commits - -## 5) Verification loop (mandatory per implemented task) - -```bash -./gradlew ktlintCheck -./gradlew detekt -./gradlew test -``` - -Bridge check only when bridge code/config/tests changed: - -```bash -(cd bridge && pnpm run check) -``` - -Manual smoke: -- `DEFERRED (user-run)` unless user requests agent-run smoke protocol - -## 6) Current implementation focus (user-requested) - -1. Move global nav (Hosts / Sessions / Chat / Settings) to left-side collapsible control. -2. Reduce extension status strip footprint; place under prompt controls and gate with settings toggle. -3. Improve abort reliability while model is thinking/retrying. -4. Move thinking/loading progress cue into timeline/message area rather than header-only. - -## 7) UX-05 quick wins (proposed, awaiting your validation) - -Validation sheet: `docs/ai/ui-ux-enhancements-validation.md` - -### Candidate changes (low-risk, high-usability) - -1. **Rail ergonomics polish** - - Persist collapse/expand preference. - - Improve rail spacing/touch targets. - - Why: reduce accidental taps and repeated toggling. - -2. **Streaming focus controls** - - Keep Abort/Steer/Follow-up visible with clearer priority when streaming. - - Improve button hierarchy and spacing. - - Why: faster intervention while model is running. - -3. **Status strip compaction** - - Compact to chips/summary by default, expandable for details. - - Hide unchanged/noisy status updates. - - Why: preserve chat vertical space. - -4. **Timeline readability + motion smoothing** - - Subtle spacing reductions where safe. - - Avoid abrupt jumps when status/progress widgets appear/disappear. - - Why: smoother reading during long runs. - -5. **Jump-to-latest affordance** - - Add “jump to latest” control when user is reading older messages during streaming. - - Why: quickly return to live output. - -6. **Accessibility cleanups** - - Ensure key icons/buttons meet touch target and content-description quality. - - Why: better usability and consistency. - -## 8) Delivery approach - -1. Capture UX issue as a task in `ui-ux-enhancements-tasks.md` -2. Implement smallest valuable change -3. Run verification loop -4. Update progress file -5. Commit code only (exclude planning docs) diff --git a/docs/ai/ui-ux-enhancements-progress.md b/docs/ai/ui-ux-enhancements-progress.md deleted file mode 100644 index 90b97af..0000000 --- a/docs/ai/ui-ux-enhancements-progress.md +++ /dev/null @@ -1,54 +0,0 @@ -# Pi Mobile — UI/UX Enhancements Progress - -_Last updated: 2026-02-16_ - -> Planning artifact only. Do **not** commit this file. - -## Snapshot - -- Total tasks: 9 implemented / 0 in progress / 0 blocked / 1 descoped -- Current phase: UX-05 implementation completed, awaiting manual smoke - -## In progress - -- None - -## Awaiting validation - -- None (validation approved for A/B/C/E/F; D denied) - -## Completed - -- UX-01: Collapsible left navigation rail replacing bottom nav -- UX-02: Extension status strip moved under prompt controls + settings flag -- UX-03: Abort fallback behavior for thinking/retry edge cases -- UX-04: Inline run progress in timeline area (instead of top-only) -- UX-05A: Persist rail expanded state + spacing/hit-area polish (`1847bae`) -- UX-05B: Streaming action hierarchy polish (Abort prioritized) (`1847bae`) -- UX-05C: Extension status strip compact presentation + de-noise heuristics (`1847bae`) -- UX-05E: Jump-to-latest affordance while streaming (`1847bae`) -- UX-05F: Accessibility quick fixes (touch targets/content descriptions) (`1847bae`) - -## Descoped - -- UX-05D: Timeline smoothing + spacing pass (denied for now by user) - -## Blocked - -- None - -## Next up - -1. Manual smoke on device (user-run) for UX-05A/B/C/E/F. -2. Collect feedback on compact status strip heuristics. -3. Optionally re-scope UX-05D later with clearer examples. - -## Verification history - -- 2026-02-16: `./gradlew ktlintCheck detekt test` ✅ -- 2026-02-16: `./gradlew ktlintCheck detekt test` ✅ (UX-05 implementation) - -## Notes - -- This progress file tracks execution status only. -- Planning docs remain uncommitted by policy. diff --git a/docs/ai/ui-ux-enhancements-tasks.md b/docs/ai/ui-ux-enhancements-tasks.md deleted file mode 100644 index 351d2d6..0000000 --- a/docs/ai/ui-ux-enhancements-tasks.md +++ /dev/null @@ -1,49 +0,0 @@ -# Pi Mobile — UI/UX Enhancements Tasks Tracker - -_Status values_: `TODO` | `IN_PROGRESS` | `BLOCKED` | `DONE` | `DESCOPED` - -> Planning artifact only. Do **not** commit this file. - -Linked plan: `docs/ai/ui-ux-enhancements-plan.md` -Linked progress: `docs/ai/ui-ux-enhancements-progress.md` -Validation sheet: `docs/ai/ui-ux-enhancements-validation.md` - -## Mandatory verification loop - -```bash -./gradlew ktlintCheck -./gradlew detekt -./gradlew test -``` - -Bridge check only when bridge code/config/tests changed: - -```bash -(cd bridge && pnpm run check) -``` - -## Task table - -| Order | ID | Title | Status | Priority | Commit | Report | -|---|---|---|---|---|---|---| -| 1 | UX-01 | Move global nav to collapsible left rail | DONE | P1 | `1a3a2b7 feat(ui): add side nav, inline run progress, and status toggle` | in-code | -| 2 | UX-02 | Move extension status below prompt + visibility toggle | DONE | P1 | `1a3a2b7 feat(ui): add side nav, inline run progress, and status toggle` | in-code | -| 3 | UX-03 | Make abort resilient during thinking/retry transitions | DONE | P0 | `1a3a2b7 feat(ui): add side nav, inline run progress, and status toggle` | in-code | -| 4 | UX-04 | Show live thinking/loading inline in timeline area | DONE | P1 | `1a3a2b7 feat(ui): add side nav, inline run progress, and status toggle` | in-code | -| 5 | UX-05A | Rail ergonomics polish (persist + spacing) | DONE | P2 | `1847bae feat(ui): implement approved UX quick wins` | `ui-ux-enhancements-validation.md` | -| 6 | UX-05B | Streaming action hierarchy polish | DONE | P1 | `1847bae feat(ui): implement approved UX quick wins` | `ui-ux-enhancements-validation.md` | -| 7 | UX-05C | Extension status strip compaction v2 | DONE | P1 | `1847bae feat(ui): implement approved UX quick wins` | `ui-ux-enhancements-validation.md` | -| 8 | UX-05D | Timeline smoothing + spacing pass | DESCOPED | P2 | - | denied in `ui-ux-enhancements-validation.md` | -| 9 | UX-05E | Jump-to-latest affordance while streaming | DONE | P1 | `1847bae feat(ui): implement approved UX quick wins` | `ui-ux-enhancements-validation.md` | -| 10 | UX-05F | Accessibility quick audit/fixes | DONE | P1 | `1847bae feat(ui): implement approved UX quick wins` | `ui-ux-enhancements-validation.md` | - -## Reporting rule per task - -For each completed task, record: -- Root cause summary -- Files changed -- Tests updated -- Verification results (ktlint/detekt/test/bridge) -- Manual smoke status (`DEFERRED (user-run)` if applicable) -- Commit hash + message -- Follow-ups/risks diff --git a/docs/ai/ui-ux-enhancements-validation.md b/docs/ai/ui-ux-enhancements-validation.md deleted file mode 100644 index a5fd8ac..0000000 --- a/docs/ai/ui-ux-enhancements-validation.md +++ /dev/null @@ -1,101 +0,0 @@ -# Pi Mobile — UX Quick Wins Validation Sheet - -_Last updated: 2026-02-16_ - -> Planning artifact only. Do **not** commit this file. - -Purpose: get your approval on **what will change** and **why** before implementation. - -## How to validate - -For each item, choose one: -- `APPROVE` -- `APPROVE_WITH_CHANGES` -- `SKIP` - ---- - -## UX-05A — Rail ergonomics polish - -- **Current pain**: left rail is useful but can still feel heavy/awkward in repeated use. -- **Planned change**: - 1. Persist expanded/collapsed state. - 2. Tune spacing and hit areas for faster tab switching. -- **Why**: reduce friction and accidental taps. -- **Risk**: very low (layout only). -- **Your decision**: `APPROVED` -- **Notes**: - -## UX-05B — Streaming action hierarchy polish - -- **Current pain**: intervention actions during streaming can still feel crowded. -- **Planned change**: - 1. Prioritize Abort visually. - 2. Improve Steer/Follow-up affordances and spacing. -- **Why**: faster control when model is running. -- **Risk**: low (no protocol behavior changes). -- **Your decision**: `APPROVE` -- **Notes**: - -## UX-05C — Extension status strip compaction v2 - -- **Current pain**: even moved under prompt, status can still consume space. -- **Planned change**: - 1. Default compact summary row. - 2. Expand for full details. - 3. De-noise repeated unchanged statuses. -- **Why**: preserve more room for chat timeline. -- **Risk**: low (presentation-layer only). -- **Your decision**: `APPROVE` -- **Notes**: - -## UX-05D — Timeline smoothing + spacing pass - -- **Current pain**: occasional visual jumps while widgets/progress appear/disappear. -- **Planned change**: - 1. Small spacing harmonization. - 2. Smoother show/hide transitions for helper UI. -- **Why**: reduce perceived jitter and improve readability. -- **Risk**: low/medium (needs manual feel check). -- **Your decision**: `DEENY` -- **Notes**: can do it later, i dont understand this - -## UX-05E — Jump-to-latest while streaming - -- **Current pain**: when reading older messages during stream, getting back to live tail is slower. -- **Planned change**: - 1. Show "Jump to latest" button when user is away from bottom during active run. -- **Why**: one-tap return to live output. -- **Risk**: low. -- **Your decision**: `APPROVE` -- **Notes**: - -## UX-05F — Accessibility cleanups - -- **Current pain**: some secondary controls may be small/less explicit. -- **Planned change**: - 1. Touch-target audit for key actions. - 2. Content description pass for icons. -- **Why**: improve reliability and usability. -- **Risk**: very low. -- **Your decision**: `APPROVE` -- **Notes**: - ---- - -## Verification plan (per approved item) - -```bash -./gradlew ktlintCheck -./gradlew detekt -./gradlew test -``` - -Bridge check only if bridge files changed: - -```bash -(cd bridge && pnpm run check) -``` - -Manual smoke: -- `DEFERRED (user-run)` From 25cdb17a1f297d5ab5702b5ac5a624f371aec3ec Mon Sep 17 00:00:00 2001 From: Abdeslam Yassine Agmar Date: Tue, 17 Feb 2026 13:46:42 +0000 Subject: [PATCH 3/3] zz --- docs/ai/pi-android-rpc-client-plan.md | 265 ++++++++ docs/ai/pi-android-rpc-client-tasks.md | 538 +++++++++++++++ docs/ai/pi-android-rpc-progress.md | 43 ++ docs/ai/pi-mobile-final-adjustments-plan.md | 463 +++++++++++++ .../pi-mobile-final-adjustments-progress.md | 634 ++++++++++++++++++ docs/ai/pi-mobile-rpc-enhancement-progress.md | 123 ++++ docs/ai/pi-mobile-rpc-enhancement-tasks.md | 234 +++++++ 7 files changed, 2300 insertions(+) create mode 100644 docs/ai/pi-android-rpc-client-plan.md create mode 100644 docs/ai/pi-android-rpc-client-tasks.md create mode 100644 docs/ai/pi-android-rpc-progress.md create mode 100644 docs/ai/pi-mobile-final-adjustments-plan.md create mode 100644 docs/ai/pi-mobile-final-adjustments-progress.md create mode 100644 docs/ai/pi-mobile-rpc-enhancement-progress.md create mode 100644 docs/ai/pi-mobile-rpc-enhancement-tasks.md diff --git a/docs/ai/pi-android-rpc-client-plan.md b/docs/ai/pi-android-rpc-client-plan.md new file mode 100644 index 0000000..26df776 --- /dev/null +++ b/docs/ai/pi-android-rpc-client-plan.md @@ -0,0 +1,265 @@ +# Pi Mobile (Android) — Refined Plan (RPC Client via Tailscale) + +## 0) Product goal +Build a **performant, robust native Android app** (Kotlin + Compose) that lets you use pi sessions running on your laptop from anywhere (bed, outside, etc.) via **Tailscale**, **without SSH/SFTP**. + +Primary success criteria: +- Smooth long chats with streaming output (no visible jank) +- Safe/resilient remote connection over tailnet +- Fast session browsing and resume across multiple projects/cwds +- Clear extension path for missing capabilities + +--- + +## 1) Facts from pi docs (non-negotiable constraints) + +### 1.1 RPC transport model +From `docs/rpc.md`: +- RPC is **JSON lines over stdin/stdout** of `pi --mode rpc` +- It is **not** a native TCP/WebSocket protocol + +Implication: +- Android cannot connect directly to RPC over network. +- You need a **laptop-side bridge** process: + - Android ↔ (Tailscale) ↔ Bridge ↔ pi RPC stdin/stdout + +### 1.2 Sessions and cwd +From `docs/session.md`, `docs/sdk.md`: +- Session files include a `cwd` in header and are stored under `~/.pi/agent/sessions/----/...jsonl` +- RPC has `switch_session`, but tools are created with process cwd context + +Implication: +- Multi-project correctness should be handled by **one pi process per cwd** (managed by bridge). + +### 1.3 Session discovery +From `docs/rpc.md`: +- No RPC command exists to list all session files globally. + +Implication: +- Bridge should read session files locally and expose a bridge API (best approach). + +### 1.4 Extension UI in RPC mode +From `docs/rpc.md` and `docs/extensions.md`: +- `extension_ui_request` / `extension_ui_response` must be supported for dialog flows (`select`, `confirm`, `input`, `editor`) +- Fire-and-forget UI methods (`notify`, `setStatus`, `setWidget`, `setTitle`, `set_editor_text`) are also emitted + +Implication: +- Android client must handle extension UI protocol end-to-end. + +--- + +## 2) Architecture decision + +## 2.1 Connection topology +- **Laptop** runs: + - `pi-bridge` service (WebSocket server) + - one or more `pi --mode rpc` subprocesses +- **Phone** runs Android app with WebSocket transport +- Network is Tailscale-only, no router forwarding + +## 2.2 Bridge protocol (explicit) +Use an **envelope protocol** over WS to avoid collisions between bridge-control operations and raw pi RPC messages. + +Example envelope: +```json +{ "channel": "bridge", "payload": { "type": "bridge_list_sessions" } } +{ "channel": "rpc", "payload": { "type": "prompt", "message": "hi" } } +``` + +Responses/events: +```json +{ "channel": "bridge", "payload": { "type": "bridge_sessions", "sessions": [] } } +{ "channel": "rpc", "payload": { "type": "message_update", ... } } +``` + +Why explicit envelope: +- Prevent ambiguous parsing +- Keep protocol extensible +- Easier debugging and telemetry + +## 2.3 Process management +Bridge owns a `PiProcessManager` keyed by cwd: +- `getOrStart(cwd)` +- idle TTL eviction +- crash restart policy +- single writer lock per cwd/session + +## 2.4 Session indexing +Bridge scans `~/.pi/agent/sessions/` and returns: +- `sessionPath`, `cwd`, `createdAt`, `updatedAt` +- `displayName` (latest `session_info.name`) +- `firstUserMessagePreview` +- optional `messageCount`, `lastModel` + +Android caches this index per host and refreshes incrementally. + +--- + +## 3) UX scope (v1) + +1. **Hosts**: add/edit host (tailscale host/ip, port, token, TLS toggle) +2. **Sessions**: grouped by cwd, searchable, resume/new/rename/fork/export actions +3. **Chat**: + - streaming text/tool timeline + - abort/steer/follow_up + - compact/export/fork + - model + thinking cycling +4. **Extension UI**: dialog requests + fire-and-forget requests +5. **Settings**: defaults and diagnostics + +--- + +## 4) Performance-first requirements (explicit budgets) + +These are required, not optional: + +### 4.1 Latency budgets +- Cold app start to visible cached sessions: **< 1.5s** target, **< 2.5s** max (mid-range device) +- Resume session to first rendered messages: **< 1.0s** target for cached metadata +- Prompt send to first token (healthy LAN/tailnet): **< 1.2s** target + +### 4.2 Rendering budgets +- Chat streaming should keep main thread frame time mostly under 16ms +- No sustained jank while streaming > 5 minutes +- Tool outputs default collapsed when large + +### 4.3 Memory budgets +- No unbounded string accumulation in UI layer +- Streaming buffers bounded and compacted +- Long chat (>= 2k messages including tool events) should avoid OOM and GC thrash + +### 4.4 Throughput/backpressure +- WS inbound processing must not block UI thread +- Throttled rendering (e.g., 20–40ms update interval) +- Drop/coalesce non-critical transient updates when overwhelmed + +### 4.5 Reconnect/resync behavior +After disconnect/reconnect: +- restore active cwd/session context +- call `get_state` and `get_messages` to resync +- show clear degraded/recovering indicators + +--- + +## 5) Security model + +- Tailnet transport is encrypted/authenticated by Tailscale +- Bridge binds to Tailscale interface/address only +- Bridge requires auth token (bearer or handshake token) +- Token stored securely on Android (Keystore-backed) +- If using `ws://` over tailnet, configure Android network security policy explicitly + +--- + +## 6) Delivery strategy for one-shot long-running agent + +Execution is phase-based with hard gates: + +1. **Phase A:** Bridge + basic chat E2E +2. **Phase B:** Session indexing + resume across cwd +3. **Phase C:** Full chat controls + extension UI protocol +4. **Phase D:** Performance hardening + reconnect robustness +5. **Phase E:** Docs + final acceptance + +### Rule +Do not start next phase until: +- code quality loop passes +- phase acceptance checks pass +- task tracker updated + +--- + +## 7) Verification loops (explicit) + +## 7.1 Per-task verification loop +After each task: +1. `./gradlew ktlintCheck` +2. `./gradlew detekt` +3. `./gradlew test` +4. Bridge checks (`pnpm run check`) when bridge changed +5. Targeted manual smoke test for the task + +If any fails: fix and rerun full loop. + +## 7.2 Per-phase gate +At end of each phase: +- End-to-end scripted walkthrough passes +- No open critical bugs in that phase scope +- Task list statuses updated to `DONE` + +## 7.3 Weekly/perf gate (for long-running execution) +- Run stress scenario: long streaming + big tool output + session switching +- Record metrics and regressions +- Block progression if perf worsens materially + +--- + +## 8) Extension strategy (repo-local) +If a missing capability should live inside pi runtime (not Android/bridge), add extension packages in this repo: + +- Create `extensions/` directory +- Bootstrap from: + - `/home/ayagmar/Projects/Personal/pi-extension-template/` +- Keep extension quality gate: + - `pnpm run check` +- Install locally: +```bash +pi install /absolute/path/to/extensions/ +``` +- Reload in running pi with `/reload` + +Use extensions for: +- custom commands/hooks +- guardrails +- metadata enrichment that is better at agent side + +--- + +## 9) Risks and mitigations + +- **Risk:** bridge protocol drift vs pi RPC + - Mitigation: keep `channel: rpc` payload pass-through unchanged and tested with fixtures +- **Risk:** session corruption from concurrent writers + - Mitigation: single controlling client lock per cwd/session +- **Risk:** lag in long streams + - Mitigation: throttled rendering + bounded buffers + macrobenchmark checks +- **Risk:** reconnect inconsistency + - Mitigation: deterministic resync (`get_state`, `get_messages`) on reconnect + +--- + +## 10) Final Definition of Done (explicit and measurable) +All must be true: + +1. **Connectivity** + - Android connects to laptop bridge over Tailscale reliably + - Auth token required and validated + +2. **Core chat** + - `prompt`, `abort`, `steer`, `follow_up` operate correctly + - Streaming text/tool events render smoothly in long runs + +3. **Sessions** + - Sessions listed from `~/.pi/agent/sessions/`, grouped by cwd + - Resume works across different cwds via correct process selection + - Rename/fork/export/compact flows work and reflect in UI/index + +4. **Extension protocol** + - `extension_ui_request` dialog methods handled with proper response IDs + - Fire-and-forget UI methods represented without blocking + +5. **Robustness** + - Bridge survives transient disconnects and can recover/resync + - No session corruption under reconnect and repeated resume/switch tests + +6. **Performance** + - Meets latency and streaming smoothness budgets in section 4 + - No major memory leaks/jank under stress scenarios + +7. **Quality gates** + - Android: `ktlintCheck`, `detekt`, `test` green + - Bridge/extensions: `pnpm run check` green + +8. **Documentation** + - README includes complete setup (tailscale, bridge run, token, troubleshooting) + - Task checklist and acceptance report completed diff --git a/docs/ai/pi-android-rpc-client-tasks.md b/docs/ai/pi-android-rpc-client-tasks.md new file mode 100644 index 0000000..34daea0 --- /dev/null +++ b/docs/ai/pi-android-rpc-client-tasks.md @@ -0,0 +1,538 @@ +# Pi Mobile (Android) — Execution Task List (One-Shot Agent Friendly) + +This task list is optimized for a long-running coding agent (Codex-style): explicit order, hard gates, verification loops, and progress tracking. + +> Rule: **Never start the next task unless current task verification is green.** + +--- + +## 0) Operating contract + +## 0.1 Scope reminder +Build a native Android client that connects over Tailscale to a laptop bridge for `pi --mode rpc`, with excellent long-chat performance and robust reconnect/session behavior. + +## 0.2 Mandatory loop after every task + +Run in order: +1. `./gradlew ktlintCheck` +2. `./gradlew detekt` +3. `./gradlew test` +4. If bridge changed: `cd bridge && pnpm run check` +5. Task-specific smoke test (manual or scripted) + +If any step fails: +- Fix +- Re-run full loop + +## 0.3 Commit policy +After green loop: +1. Read `/home/ayagmar/.agents/skills/commit/SKILL.md` +2. Create one Conventional Commit for the task +3. Do not push + +## 0.4 Progress tracker (must be updated each task) +Maintain statuses: `TODO`, `IN_PROGRESS`, `BLOCKED`, `DONE`. + +Suggested tracker file: `docs/pi-android-rpc-progress.md` +For each task include: +- status +- commit hash +- verification result +- notes/blockers + +--- + +## Phase 1 — Foundations and architecture lock + +### Task 1.1 — Bootstrap Android app + modules +**Goal:** Buildable Android baseline with modular structure. + +Deliverables: +- `app/` +- `core-rpc/` +- `core-net/` +- `core-sessions/` +- Compose + navigation with placeholder screens + +Acceptance: +- `./gradlew :app:assembleDebug` succeeds +- app launches with placeholders + +Commit: +- `chore(app): bootstrap android modular project` + +--- + +### Task 1.2 — Add quality gates (ktlint + detekt + CI) +**Goal:** Enforce quality from day 1. + +Deliverables: +- `.editorconfig`, `detekt.yml` +- ktlint + detekt configured +- `.github/workflows/ci.yml` with checks + +Acceptance: +- local checks pass +- CI config valid + +Commit: +- `chore(quality): configure ktlint detekt and ci` + +--- + +### Task 1.3 — Spike: validate critical RPC/cwd assumptions +**Goal:** Confirm behavior before deeper build. + +Checks: +- Validate `pi --mode rpc` JSONL behavior with a tiny local script +- Validate `switch_session` + tool cwd behavior across different project paths +- Record results in `docs/spikes/rpc-cwd-assumptions.md` + +Acceptance: +- spike doc has reproducible commands + outcomes +- architecture assumptions confirmed (or revised) + +Commit: +- `docs(spike): validate rpc and cwd behavior` + +--- + +## Phase 2 — Bridge service (laptop) + +### Task 2.1 — Create bridge project skeleton +**Goal:** Node/TS service scaffold with tests and lint. + +Deliverables: +- `bridge/` project with TypeScript +- scripts: `dev`, `start`, `check`, `test` +- base config and logging + +Acceptance: +- `cd bridge && pnpm run check` passes + +Commit: +- `feat(bridge): bootstrap typescript service` + +--- + +### Task 2.2 — Implement WS envelope protocol + auth +**Goal:** Explicit protocol for bridge and RPC channels. + +Protocol: +- `channel: "bridge" | "rpc"` +- token auth required at connect time + +Deliverables: +- protocol types and validation +- auth middleware +- error responses for malformed payloads + +Acceptance: +- invalid auth rejected +- valid auth accepted +- malformed payload handled safely + +Commit: +- `feat(bridge): add websocket envelope protocol and auth` + +--- + +### Task 2.3 — Implement pi RPC subprocess forwarding +**Goal:** Bridge raw RPC payloads to/from pi process. + +Deliverables: +- spawn `pi --mode rpc` +- write JSON line to stdin +- read stdout lines and forward via WS `channel: rpc` +- stderr logging isolation + +Acceptance: +- E2E: send `get_state`, receive valid response + +Commit: +- `feat(bridge): forward pi rpc over websocket` + +--- + +### Task 2.4 — Multi-cwd process manager + locking +**Goal:** Correct multi-project behavior and corruption safety. + +Deliverables: +- process manager keyed by cwd +- single controller lock per cwd/session +- idle eviction policy + +Acceptance: +- switching between two cwds uses correct process and tool context +- concurrent control attempts are safely rejected + +Commit: +- `feat(bridge): manage per-cwd pi processes with locking` + +--- + +### Task 2.5 — Bridge session indexing API +**Goal:** Replace missing RPC list-sessions capability. + +Deliverables: +- `bridge_list_sessions` +- parser for session header + latest `session_info` + preview +- grouped output by cwd +- tests with JSONL fixtures + +Acceptance: +- returns expected metadata from fixture and real local sessions + +Commit: +- `feat(bridge): add session indexing api from jsonl files` + +--- + +### Task 2.6 — Bridge resilience: reconnect and health +**Goal:** Robust behavior on disconnect/crash. + +Deliverables: +- health checks +- restart policy for crashed pi subprocess +- reconnect-safe state model + +Acceptance: +- forced disconnect and reconnect recovers cleanly + +Commit: +- `feat(bridge): add resilience and health management` + +--- + +## Phase 3 — Android transport and protocol core + +### Task 3.1 — Implement core RPC models/parser +**Goal:** Typed parse of responses/events from rpc docs. + +Deliverables: +- command models (prompt/abort/steer/follow_up/etc.) +- response/event sealed hierarchies +- parser with `ignoreUnknownKeys` + +Acceptance: +- tests for response success/failure, message_update, tool events, extension_ui_request + +Commit: +- `feat(rpc): add protocol models and parser` + +--- + +### Task 3.2 — Streaming assembler + throttling primitive +**Goal:** Efficient long-stream reconstruction without UI flood. + +Deliverables: +- assistant text assembler by message/content index +- throttle/coalescing utility for UI update cadence + +Acceptance: +- deterministic reconstruction tests +- throttle tests for bursty deltas + +Commit: +- `feat(rpc): add streaming assembler and throttling` + +--- + +### Task 3.3 — WebSocket client transport (`core-net`) +**Goal:** Android WS transport with reconnect lifecycle. + +Deliverables: +- connect/disconnect/reconnect +- `Flow` inbound stream +- outbound send queue +- clear connection states + +Acceptance: +- integration test with fake WS server + +Commit: +- `feat(net): add websocket transport with reconnect support` + +--- + +### Task 3.4 — Android RPC connection orchestrator +**Goal:** Bridge WS + parser + command dispatch in one stable layer. + +Deliverables: +- `PiRpcConnection` service +- command send API +- event stream API +- resync helpers (`get_state`, `get_messages`) + +Acceptance: +- reconnect triggers deterministic resync successfully + +Commit: +- `feat(net): implement rpc connection orchestration` + +--- + +## Phase 4 — Sessions UX and cache + +### Task 4.1 — Host profiles and secure token storage +**Goal:** Manage multiple laptop hosts safely. + +Deliverables: +- host profile CRUD UI + persistence +- token storage via Keystore-backed mechanism + +Acceptance: +- profiles survive restart +- tokens never stored plaintext in raw prefs + +Commit: +- `feat(hosts): add host profile management and secure token storage` + +--- + +### Task 4.2 — Session repository + cache (`core-sessions`) +**Goal:** Fast list load and incremental refresh. + +Deliverables: +- cached index by host +- background refresh and merge +- search/filter support + +Acceptance: +- list appears immediately from cache after restart +- refresh updates changed sessions only + +Commit: +- `perf(sessions): implement cached indexed session repository` + +--- + +### Task 4.3 — Sessions screen grouped by cwd +**Goal:** Primary navigation UX. + +Deliverables: +- grouped/collapsible cwd sections +- search UI +- resume action wiring + +Acceptance: +- resume works across multiple cwds via bridge selection + +Commit: +- `feat(ui): add grouped sessions browser by cwd` + +--- + +### Task 4.4 — Session actions: rename/fork/export/compact entry points +**Goal:** Full session management surface from UI. + +Deliverables: +- rename (`set_session_name`) +- fork (`get_fork_messages` + `fork`) +- export (`export_html`) +- compact (`compact`) + +Acceptance: +- each action works E2E and updates UI state/index correctly + +Commit: +- `feat(sessions): add rename fork export and compact actions` + +--- + +## Phase 5 — Chat screen and controls + +### Task 5.1 — Streaming chat timeline UI +**Goal:** Smooth rendering of user/assistant/tool content. + +Deliverables: +- chat list with stable keys +- assistant streaming text rendering +- tool blocks with collapse/expand + +Acceptance: +- long response stream remains responsive + +Commit: +- `feat(chat): implement streaming timeline ui` + +--- + +### Task 5.2 — Prompt controls: abort, steer, follow_up +**Goal:** Full message queue behavior parity. + +Deliverables: +- input + send +- abort button +- steer/follow-up actions during streaming + +Acceptance: +- no protocol errors for streaming queue operations + +Commit: +- `feat(chat): add abort steer and follow-up controls` + +--- + +### Task 5.3 — Model/thinking controls +**Goal:** Missing parity item made explicit. + +Deliverables: +- cycle model (`cycle_model`) +- cycle thinking (`cycle_thinking_level`) +- visible current values + +Acceptance: +- controls update state and survive reconnect resync + +Commit: +- `feat(chat): add model and thinking controls` + +--- + +### Task 5.4 — Extension UI protocol support +**Goal:** Support extension-driven dialogs and notifications. + +Deliverables: +- handle `extension_ui_request` methods: + - `select`, `confirm`, `input`, `editor` + - `notify`, `setStatus`, `setWidget`, `setTitle`, `set_editor_text` +- send matching `extension_ui_response` by id + +Acceptance: +- dialog requests unblock agent flow +- fire-and-forget UI requests render non-blocking indicators + +Commit: +- `feat(extensions): implement rpc extension ui protocol` + +--- + +## Phase 6 — Performance hardening + +### Task 6.1 — Backpressure + bounded buffers +**Goal:** Prevent memory and UI blowups. + +Deliverables: +- bounded streaming buffers +- coalescing policy for high-frequency updates +- large tool output default-collapsed behavior + +Acceptance: +- stress run (10+ minute stream) without memory growth issues + +Commit: +- `perf(chat): add backpressure and bounded buffering` + +--- + +### Task 6.2 — Performance instrumentation + benchmarks +**Goal:** Make performance measurable. + +Deliverables: +- baseline metrics script/checklist +- startup/resume/first-token timing logs +- macrobenchmark skeleton (if available in current setup) + +Acceptance: +- metrics recorded in `docs/perf-baseline.md` + +Commit: +- `perf(app): add instrumentation and baseline metrics` + +--- + +### Task 6.3 — Baseline Profile + release tuning +**Goal:** Improve real-device performance. + +Deliverables: +- baseline profile setup +- release build optimization verification + +Acceptance: +- `./gradlew :app:assembleRelease` succeeds + +Commit: +- `perf(app): add baseline profile and release optimizations` + +--- + +## Phase 7 — Extension workspace (optional but prepared) + +### Task 7.1 — Add repo-local extension scaffold from template +**Goal:** Ready path for missing functionality via pi extensions. + +Source template: +- `/home/ayagmar/Projects/Personal/pi-extension-template/` + +Deliverables: +- `extensions/pi-mobile-ext/` +- customized constants/package name +- sample command/hook + +Acceptance: +- `cd extensions/pi-mobile-ext && pnpm run check` passes +- loads with `pi -e ./extensions/pi-mobile-ext/src/index.ts` + +Commit: +- `chore(extensions): scaffold pi-mobile extension workspace` + +--- + +## Phase 8 — Documentation and final acceptance + +### Task 8.1 — Setup and operations README +**Goal:** Reproducible setup for future you. + +Include: +- bridge setup on laptop +- tailscale requirements +- token setup +- Android host config +- troubleshooting matrix + +Acceptance: +- fresh setup dry run follows docs successfully + +Commit: +- `docs: add end-to-end setup and troubleshooting` + +--- + +### Task 8.2 — Final acceptance report +**Goal:** Explicitly prove Definition of Done. + +Deliverables: +- `docs/final-acceptance.md` +- checklist for: + - connectivity + - chat controls + - session flows + - extension UI protocol + - reconnect robustness + - performance budgets + - quality gates + +Acceptance: +- all checklist items marked pass with evidence + +Commit: +- `docs: add final acceptance report` + +--- + +## Final Definition of Done (execution checklist) + +All required: + +1. Android ↔ bridge works over Tailscale with token auth +2. Chat streaming stable for long sessions +3. Abort/steer/follow_up behave correctly +4. Sessions list grouped by cwd with reliable resume across cwds +5. Rename/fork/export/compact work +6. Model + thinking controls work +7. Extension UI request/response fully supported +8. Reconnect and resync are robust +9. Performance budgets met and documented +10. Quality gates green (`ktlintCheck`, `detekt`, `test`, bridge `pnpm run check`) +11. Setup + acceptance docs complete diff --git a/docs/ai/pi-android-rpc-progress.md b/docs/ai/pi-android-rpc-progress.md new file mode 100644 index 0000000..57f0893 --- /dev/null +++ b/docs/ai/pi-android-rpc-progress.md @@ -0,0 +1,43 @@ +# Pi Android RPC — Progress Tracker + +Status values: `TODO` | `IN_PROGRESS` | `BLOCKED` | `DONE` + +| Task | Status | Commit | Verification | Notes | +|---|---|---|---|---| +| 1.1 Bootstrap Android app + modules | DONE | e9f80a2 | ✅ ktlintCheck, detekt, test, :app:assembleDebug | Bootstrapped Android app + modular core-rpc/core-net/core-sessions with Compose navigation placeholders. | +| 1.2 Quality gates + CI | DONE | bd8a0a0 | ✅ ktlintCheck, detekt, test | Added .editorconfig, detekt.yml, root quality plugin config, and GitHub Actions CI workflow. | +| 1.3 RPC/cwd spike validation | DONE | 2817cf5 | ✅ ktlintCheck, detekt, test | Added reproducible spike doc validating JSONL interleaving/id-correlation and switch_session vs cwd behavior. | +| 2.1 Bridge skeleton | DONE | 0624eb8 | ✅ ktlintCheck, detekt, test, bridge check | Bootstrapped TypeScript bridge with scripts (dev/start/check/test), config/logging, HTTP health + WS skeleton, and Vitest/ESLint setup. | +| 2.2 WS envelope + auth | DONE | 2c3c269 | ✅ ktlintCheck, detekt, test, bridge check | Added auth-token handshake validation, envelope parser/validation, and safe bridge_error responses for malformed/unsupported payloads. | +| 2.3 RPC forwarding | DONE | dc89183 | ✅ ktlintCheck, detekt, test, bridge check | Added pi subprocess forwarder (stdin/stdout JSONL + stderr logging isolation), rpc channel forwarding, and E2E bridge get_state websocket check. | +| 2.4 Multi-cwd process manager | DONE | eff1bdf | ✅ ktlintCheck, detekt, test, bridge check | Added per-cwd process manager with control locks, server control APIs (set cwd/acquire/release), and idle TTL eviction with tests for lock rejection and cwd routing. | +| 2.5 Session indexing API | DONE | 6538df2 | ✅ ktlintCheck, detekt, test, bridge check | Added bridge_list_sessions API backed by JSONL session indexer (header/session_info/preview/messageCount/lastModel), fixture tests, and local ~/.pi session smoke run. | +| 2.6 Bridge resilience | DONE | b39cec9 | ✅ ktlintCheck, detekt, test, bridge check | Added enriched /health status, RPC forwarder crash auto-restart/backoff, reconnect grace model with resumable clientId, and forced reconnect smoke verification. | +| 3.1 RPC models/parser | DONE | 95b0489 | ✅ ktlintCheck, detekt, test | Added serializable RPC command + inbound response/event models and Json parser (ignoreUnknownKeys) with tests for response states, message_update, tool events, and extension_ui_request. | +| 3.2 Streaming assembler/throttle | DONE | 62f16bd | ✅ ktlintCheck, detekt, test; smoke: :core-rpc:test --tests "*AssistantTextAssemblerTest" --tests "*UiUpdateThrottlerTest" | Added assistant text stream assembler keyed by message/content index, capped message-buffer tracking, and a coalescing UI update throttler with deterministic unit coverage. | +| 3.3 WebSocket transport | DONE | 2b57157 | ✅ ktlintCheck, detekt, test; integration: :core-net:test (MockWebServer reconnect scenario) | Added OkHttp-based WebSocket transport with connect/disconnect/reconnect lifecycle, inbound Flow stream, outbound queue replay on reconnect, explicit connection states, and integration coverage. | +| 3.4 RPC orchestrator/resync | DONE | aa5f6af | ✅ ktlintCheck, detekt, test; integration: :core-net:test --tests "*PiRpcConnectionTest" | Added `PiRpcConnection` orchestrator with bridge/rpc envelope routing, typed RPC event stream, command dispatch, request-response helpers (`get_state`, `get_messages`), and automatic reconnect resync path validated in tests. | +| 4.1 Host profiles + secure token | DONE | 74db836 | ✅ ktlintCheck, detekt, test | Added host profile CRUD flow (Compose hosts screen + editor dialog + persistence via SharedPreferences), plus Keystore-backed token storage via EncryptedSharedPreferences (security-crypto). | +| 4.2 Sessions cache repo | DONE | 7e6e72f | ✅ ktlintCheck, detekt, test; smoke: :core-sessions:test --tests "*SessionIndexRepositoryTest" | Implemented `core-sessions` cached index repository per host with file/in-memory cache stores, background refresh + merge semantics, and query filtering support with deterministic repository tests. | +| 4.3 Sessions UI grouped by cwd | DONE | 2a3389e | ✅ ktlintCheck, detekt, test; smoke: :app:assembleDebug | Added sessions browser UI grouped/collapsible by cwd with host selection and search, wired bridge-backed session fetch via `bridge_list_sessions`, and implemented resume action wiring that reconnects with selected cwd/session and issues `switch_session`. | +| 4.4 Rename/fork/export/compact actions | DONE | f7957fc | ✅ ktlintCheck, detekt, test; smoke: :app:assembleDebug | Added active-session action entry points (Rename/Fork/Export/Compact) in sessions UI, implemented RPC commands (`set_session_name`, `get_fork_messages`+`fork`, `export_html`, `compact`) with response handling, and refreshed session index state after mutating actions. | +| 5.1 Streaming chat timeline UI | DONE | b2fac50 | ✅ ktlintCheck, detekt, test; smoke: :app:assembleDebug | Added chat timeline screen wired to shared active session connection, including history bootstrap via `get_messages`, live assistant streaming text assembly from `message_update`, and tool execution cards with collapse/expand behavior for large outputs. | +| 5.2 Abort/steer/follow_up controls | DONE | d0545cf | ✅ ktlintCheck, detekt, test, bridge check | Added prompt controls (sendPrompt, abort, steer, followUp), streaming state tracking via AgentStart/End events, and UI with input field, abort button (red), steer/follow-up dialogs. | +| 5.3 Model/thinking controls | DONE | cf3cfbb | ✅ ktlintCheck, detekt, test, bridge check | Added cycle_model and cycle_thinking_level commands with ModelInfo data class. UI shows current model/thinking level with cycle buttons. State survives reconnect via getState on load. | +| 5.4 Extension UI protocol support | DONE | 3d6b9ce | ✅ ktlintCheck, detekt, test, bridge check | Implemented dialog methods (select, confirm, input, editor) with proper response handling. Added fire-and-forget support (notify, setStatus, setWidget, setTitle, set_editor_text). Notifications display as snackbars. | +| 6.1 Backpressure + bounded buffers | DONE | 328b950 | ✅ ktlintCheck, detekt, test | Added BoundedEventBuffer for RPC event backpressure, StreamingBufferManager for memory-efficient text streaming (50KB limit, tail truncation), BackpressureEventProcessor for event coalescing. | +| 6.2 Instrumentation + perf baseline | DONE | 9232795 | ✅ ktlintCheck, detekt, test | Added PerformanceMetrics for startup/resume/TTFT timing, FrameMetrics for jank detection, macrobenchmark module with StartupBenchmark and BaselineProfileGenerator, docs/perf-baseline.md with metrics and targets. | +| 6.3 Baseline profile + release tuning | DE_SCOPED | N/A | N/A | Explicitly de-scoped for this repo because it targets developer-side local/debug usage; benchmark module remains for future release tuning if distribution model changes. | +| 7.1 Optional extension scaffold | DE_SCOPED | N/A | N/A | Explicitly de-scoped from MVP scope; extension UI protocol is fully supported in app/bridge, and repo-local extension scaffold can be added later from pi-extension-template when concrete extension requirements exist. | +| 8.1 Setup + troubleshooting docs | DONE | 50c7268 | ✅ README.md created | Human-readable setup guide with architecture, troubleshooting, and development info. | +| 8.2 Final acceptance report | DONE | 50c7268 | ✅ docs/final-acceptance.md | Comprehensive acceptance checklist with all criteria met. | + +## Per-task verification command set + +```bash +./gradlew ktlintCheck +./gradlew detekt +./gradlew test +# if bridge changed: +(cd bridge && pnpm run check) +``` diff --git a/docs/ai/pi-mobile-final-adjustments-plan.md b/docs/ai/pi-mobile-final-adjustments-plan.md new file mode 100644 index 0000000..39abc70 --- /dev/null +++ b/docs/ai/pi-mobile-final-adjustments-plan.md @@ -0,0 +1,463 @@ +# Pi Mobile — Final Adjustments Plan (Fresh Audit) + +Goal: ship an **ultimate** Pi mobile client by prioritizing quick wins and high-risk fixes first, then heavier parity/architecture work last. + +Scope focus from fresh audit: RPC compatibility, Kotlin quality, bridge security/stability, UX parity, performance, and Pi alignment. + +Execution checkpoint (2026-02-15): backlog tasks C1–C4, Q1–Q7, F1–F5, M1–M4, T1–T2, and H1–H4 are complete. Remaining tracked item: manual on-device smoke validation. + +Post-feedback UX/reliability follow-up (2026-02-15): +1. R1 Resume reliability: ensure Chat timeline refreshes after session switch/new/fork responses even when Chat VM is already alive. +2. R2 Sessions explorer usability: default to flat/all-session browsing, clearer view-mode labeling, faster grouped-mode expand/collapse. +3. R3 Session grouping readability: show session counts per cwd and display real project cwd in flat cards. +4. R4 Remove duplicate app chrome: drop platform action bar title (`pi-mobile`) by using NoActionBar app theme. + +> No milestones or estimates. +> Benchmark-specific work is intentionally excluded for now. + +--- + +## 0) Mandatory verification loop (after every task) + +```bash +./gradlew ktlintCheck +./gradlew detekt +./gradlew test +(cd bridge && pnpm run check) +``` + +If any command fails: +1. fix +2. rerun full loop +3. only then mark task done + +Manual smoke checklist (UI/protocol tasks): +- connect host, resume session, create new session +- prompt/abort/steer/follow_up still work +- tool cards + reasoning blocks + diffs still render correctly +- extension dialogs still work (`select`, `confirm`, `input`, `editor`) +- new session from Sessions tab creates + navigates correctly +- chat auto-scrolls to latest message during streaming + +--- + +## 1) Critical UX fixes (immediate) + +### C1 — Fix "New Session" error message bug +**Why:** Creating new session shows "No active session. Resume a session first" which is confusing/incorrect UX. + +**Root cause:** `newSession()` tries to send RPC command without an active bridge connection. The connection is only established during `resumeSession()`. + +**Potential fix approaches:** +1. **Quick fix:** Have `newSession()` establish connection first (like `resumeSession` does), then send `new_session` command +2. **Better fix (see C4):** Keep persistent bridge connection alive, so `new_session` just works + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` +- `app/src/main/java/com/ayagmar/pimobile/sessions/SessionsViewModel.kt` + +**Acceptance:** +- New session creation shows success/loading state, not error +- Auto-navigates to chat with new session active +- Works regardless of whether a session was previously resumed + +--- + +### C4 — Persistent bridge connection (architectural fix for C1) +**Why:** app currently connects on-demand per session; this causes friction for new session, rapid switching, and background/resume. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` +- `app/src/main/java/com/ayagmar/pimobile/di/AppServices.kt` (or replacement DI graph) +- `app/src/main/java/com/ayagmar/pimobile/ui/PiMobileApp.kt` + +**Acceptance:** +- bridge connection established early when host context is available +- `newSession()` and `resumeSession()` reuse the active connection/session control flow +- robust lifecycle behavior (foreground/background/network reconnect) +- C1 moves from quick patch behavior to durable architecture + +--- + +### C2 — Compact chat header (stop blocking streaming view) +**Why:** Top nav takes too much vertical space, blocks view of streaming responses. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` +- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatHeader.kt` (extract if needed) + +**Acceptance:** +- Header collapses or uses minimal height during streaming +- Essential controls (abort, model selector) remain accessible +- More screen real estate for actual chat content + +--- + +### C3 — Flatten directory explorer (improve CWD browsing UX) +**Why:** Current tree requires clicking each directory one-by-one to see sessions. User sees long path list with ▶ icons. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/ui/sessions/SessionsScreen.kt` +- `app/src/main/java/com/ayagmar/pimobile/sessions/SessionsViewModel.kt` + +**Acceptance:** +- Option to view all sessions flattened with path breadcrumbs +- Or: searchable directory tree with auto-expand on filter +- Faster navigation to deeply nested sessions + +--- + +## 2) Quick wins (first) + +### Q1 — Fix image-only prompt mismatch +**Why:** UI enables send with images + empty text, `ChatViewModel.sendPrompt()` currently blocks empty text. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` +- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` + +**Acceptance:** +- image-only send path is consistent and no dead click state + +--- + +### Q2 — Add full tree filter set (`all` included) +**Why:** bridge currently accepts only `default`, `no-tools`, `user-only`, `labeled-only`. + +**Primary files:** +- `bridge/src/session-indexer.ts` +- `bridge/src/server.ts` +- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` +- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` + +**Acceptance:** +- filters include `all` and behave correctly end-to-end + +--- + +### Q3 — Command palette parity layer for built-ins +**Why (Pi RPC doc):** `get_commands` excludes interactive built-ins (`/settings`, `/hotkeys`, etc.). + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` +- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` + +**Acceptance:** +- built-ins show as supported/bridge-backed/unsupported with explicit UX (no silent no-op) + +--- + +### Q4 — Add global collapse/expand controls +**Why:** per-item collapse exists; missing global action parity. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` +- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` + +**Acceptance:** +- one-tap collapse/expand all for tools and reasoning + +--- + +### Q5 — Wire FrameMetrics into live chat +**Why:** metrics utility exists but is not active in chat rendering flow. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` +- `app/src/main/java/com/ayagmar/pimobile/perf/FrameMetrics.kt` + +**Acceptance:** +- frame/jank logs produced during streaming sessions + +--- + +### Q6 — Transport preference setting parity (`sse` / `websocket` / `auto`) +**Why (settings doc):** transport is a first-class setting in Pi. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/ui/settings/SettingsViewModel.kt` +- `app/src/main/java/com/ayagmar/pimobile/ui/settings/SettingsScreen.kt` +- `app/src/main/java/com/ayagmar/pimobile/sessions/SessionController.kt` +- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` + +**Acceptance:** +- setting visible, persisted, and reflected in runtime behavior (with clear fallback notes) + +--- + +### Q7 — Queue inspector UX for pending steer/follow-up +**Why:** queue behavior exists but users cannot inspect/manage pending items clearly. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` +- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` +- `app/src/main/java/com/ayagmar/pimobile/ui/settings/SettingsScreen.kt` (if mode hints/actions added) + +**Acceptance:** +- pending queue is visible while streaming +- queued items can be cancelled/cleared as protocol allows +- UX reflects steering/follow-up mode behavior (`all` vs `one-at-a-time`) + +--- + +## 3) Stability + security fixes + +### F1 — Bridge event isolation and lock correctness +**Why:** outbound RPC events are currently fanned out by `cwd`; tighten to active controller/session ownership. + +**Primary files:** +- `bridge/src/server.ts` +- `bridge/src/process-manager.ts` +- `bridge/test/server.test.ts` +- `bridge/test/process-manager.test.ts` + +**Acceptance:** +- no event leakage across same-cwd clients +- lock enforcement applies consistently for send + receive paths + +--- + +### F2 — Reconnect/resync hardening +**Why:** ensure deterministic recovery under network flaps and reconnect races. + +**Primary files:** +- `core-net/src/main/kotlin/com/ayagmar/pimobile/corenet/PiRpcConnection.kt` +- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` +- tests in `core-net` / `app` + +**Acceptance:** +- no stale/duplicate state application after reconnect +- no stuck streaming flag after recovery + +--- + +### F3 — Bridge auth + exposure hardening +**Why:** improve defensive posture without changing core architecture. + +**Primary files:** +- `bridge/src/server.ts` +- `bridge/src/config.ts` +- `README.md` + +**Acceptance:** +- auth compare hardened +- unsafe bind choices clearly warned/documented +- health endpoint exposure policy explicit + +--- + +### F4 — Android network security tightening +**Why:** app currently permits cleartext globally. + +**Primary files:** +- `app/src/main/res/xml/network_security_config.xml` +- `app/src/main/AndroidManifest.xml` +- `README.md` + +**Acceptance:** +- cleartext policy narrowed/documented for tailscale-only usage assumptions + +--- + +### F5 — Bridge session index scalability +**Why:** recursive full reads of all JSONL files do not scale. + +**Primary files:** +- `bridge/src/session-indexer.ts` +- `bridge/src/server.ts` +- `bridge/test/session-indexer.test.ts` + +**Acceptance:** +- measurable reduction in repeated full-scan overhead on large session stores + +--- + +## 4) Medium maintainability improvements + +### M1 — Replace service locator with explicit DI +**Why:** `AppServices` singleton hides dependencies and complicates tests. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/di/AppServices.kt` +- route/viewmodel factories and call sites + +**Acceptance:** +- explicit dependency graph, no mutable global service locator usage + +--- + +### M2 — Split god classes (architecture hygiene) +**Targets:** +- `ChatViewModel` (~2000+ lines) → extract: message handling, UI state management, command processing +- `ChatScreen.kt` (~2600+ lines) → extract: timeline, header, input, dialogs into separate files +- `RpcSessionController` (~1000+ lines) → extract: connection mgmt, RPC routing, lifecycle + +**Acceptance (non-rigid):** +- class sizes and responsibilities are substantially reduced (no hard fixed LOC cap) +- detekt complexity signals improve (e.g. `LargeClass`, `LongMethod`, `TooManyFunctions` count reduced) +- suppressions are reduced or narrowed with justification +- all existing tests pass +- clear public API boundaries documented + +--- + +### M3 — Unify streaming/backpressure pipeline +**Why:** `BackpressureEventProcessor` / `StreamingBufferManager` / `BoundedEventBuffer` are not integrated in runtime flow. + +**Primary files:** +- `core-rpc/src/main/kotlin/com/ayagmar/pimobile/corerpc/BackpressureEventProcessor.kt` +- `core-rpc/src/main/kotlin/com/ayagmar/pimobile/corerpc/StreamingBufferManager.kt` +- `core-rpc/src/main/kotlin/com/ayagmar/pimobile/corerpc/BoundedEventBuffer.kt` +- app runtime integration points + +**Acceptance:** +- one coherent runtime path (integrated or removed dead abstractions) + +--- + +### M4 — Tighten static analysis rules +**Why:** keep architecture drift in check. + +**Primary files:** +- `detekt.yml` +- affected Kotlin sources + +**Acceptance:** +- fewer broad suppressions +- complexity-oriented rules enforced pragmatically (without blocking healthy modularization) +- all checks green + +--- + +## 5) Theming + Design System (after architecture cleanup) + +### T1 — Centralized theme architecture (PiMobileTheme) +**Why:** Colors are scattered and hardcoded; no dark/light mode support. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/ui/theme/` (create) +- `app/src/main/java/com/ayagmar/pimobile/ui/PiMobileApp.kt` +- all screen files for color replacement + +**Acceptance:** +- `PiMobileTheme` with `lightColorScheme()` and `darkColorScheme()` +- all hardcoded colors replaced with theme references +- settings toggle for light/dark/system-default +- color roles documented (primary, secondary, tertiary, surface, etc.) + +--- + +### T2 — Component design system +**Why:** Inconsistent card styles, button sizes, spacing across screens. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/ui/components/` (create) +- `app/src/main/java/com/ayagmar/pimobile/ui/chat/ChatScreen.kt` +- `app/src/main/java/com/ayagmar/pimobile/ui/sessions/SessionsScreen.kt` +- `app/src/main/java/com/ayagmar/pimobile/ui/settings/SettingsScreen.kt` + +**Acceptance:** +- reusable `PiCard`, `PiButton`, `PiTextField`, `PiTopBar` components +- consistent spacing tokens (4.dp, 8.dp, 16.dp, 24.dp) +- typography scale defined and applied + +--- + +## 6) Heavy hitters (last) + +### H1 — True `/tree` parity (in-place navigate, not fork fallback) +**Why:** current Jump+Continue calls fork semantics. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` +- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` +- `bridge/src/server.ts` (if bridge route needed) + +**Implementation path order:** +1. bridge-first +2. if RPC gap remains: add minimal companion extension or SDK-backed bridge capability + +**Acceptance:** +- navigation semantics match `/tree` behavior (in-place leaf changes + editor behavior) + +--- + +### H2 — Session parsing alignment with Pi internals +**Why:** hand-rolled JSONL parsing is brittle as session schema evolves. + +**Primary files:** +- `bridge/src/session-indexer.ts` +- `bridge/src/server.ts` +- bridge tests + +**Acceptance:** +- parser resiliency improved (or SDK-backed replacement), with compatibility tests + +--- + +### H3 — Incremental session history loading strategy +**Why:** `get_messages` full-load + full parse remains expensive for huge histories. + +**Primary files:** +- `app/src/main/java/com/ayagmar/pimobile/chat/ChatViewModel.kt` +- `app/src/main/java/com/ayagmar/pimobile/sessions/RpcSessionController.kt` +- bridge additions if needed + +**Acceptance:** +- large-session resume remains responsive and memory-stable + +--- + +### H4 — Extension-ize selected hardcoded workflows +**Why:** reduce app-side hardcoding where Pi extension model is a better fit. + +**Candidates:** +- session naming/bookmark workflows +- share/export helpers +- command bundles + +**Acceptance:** +- at least one workflow moved to extension-driven path with docs + +--- + +## Ordered execution queue (strict) + +1. C1 Fix "New Session" error message bug +2. C4 Persistent bridge connection (architectural fix for C1) +3. C2 Compact chat header (stop blocking streaming view) +4. C3 Flatten directory explorer (improve CWD browsing UX) +5. Q1 image-only send fix +6. Q2 full tree filters (`all`) +7. Q3 command palette built-in parity layer +8. Q4 global collapse/expand controls +9. Q5 live frame metrics wiring +10. Q6 transport preference setting parity +11. Q7 queue inspector UX for pending steer/follow-up +12. F1 bridge event isolation + lock correctness +13. F2 reconnect/resync hardening +14. F3 bridge auth/exposure hardening +15. F4 Android network security tightening +16. F5 bridge session index scalability +17. M1 replace service locator with DI +18. M2 split god classes (architecture hygiene) +19. M3 unify streaming/backpressure runtime pipeline +20. M4 tighten static analysis rules +21. T1 Centralized theme architecture (PiMobileTheme) +22. T2 Component design system +23. H1 true `/tree` parity +24. H2 session parsing alignment with Pi internals +25. H3 incremental history loading strategy +26. H4 extension-ize selected workflows + +--- + +## Definition of done + +- [x] Critical UX fixes complete +- [x] Quick wins complete +- [x] Stability/security fixes complete +- [x] Maintainability improvements complete +- [x] Theming + Design System complete +- [x] Heavy hitters complete or explicitly documented as protocol-limited +- [x] Final verification loop green diff --git a/docs/ai/pi-mobile-final-adjustments-progress.md b/docs/ai/pi-mobile-final-adjustments-progress.md new file mode 100644 index 0000000..02177ca --- /dev/null +++ b/docs/ai/pi-mobile-final-adjustments-progress.md @@ -0,0 +1,634 @@ +# Pi Mobile — Final Adjustments Progress Tracker + +Status values: `TODO` | `IN_PROGRESS` | `BLOCKED` | `DONE` + +> Tracker paired with: `docs/ai/pi-mobile-final-adjustments-plan.md` +> Benchmark-specific tracking intentionally removed for now. + +--- + +## Mandatory verification loop (after every task) + +```bash +./gradlew ktlintCheck +./gradlew detekt +./gradlew test +(cd bridge && pnpm run check) +``` + +--- + +## Already completed (reference) + +| Task | Commit message | Commit hash | Notes | +|---|---|---|---| +| Move New Session to Sessions tab | refactor: move New Session to Sessions tab + add chat auto-scroll | 88d1324 | Button now in Sessions header, navigates to Chat | +| Chat auto-scroll | refactor: move New Session to Sessions tab + add chat auto-scroll | 88d1324 | Auto-scrolls to bottom when new messages arrive | +| Fix ANSI escape codes in chat | fix(chat): strip ANSI codes and fix tree layout overflow | 61061b2 | Strips terminal color codes from status messages | +| Tree layout overflow fix | fix(chat): strip ANSI codes and fix tree layout overflow | 61061b2 | Uses LazyRow for filter chips | +| Navigate back to Sessions fix | fix(nav): allow returning to Sessions after resume | 2cc0480 | Fixed backstack and Channel navigation | +| Chat reload on connection | fix(chat): reload messages when connection becomes active | e8ac20f | Auto-loads messages when CONNECTED | + +--- + +## Critical UX fixes (immediate) + +| Order | Task | Status | Commit message | Commit hash | Verification | Notes | +|---|---|---|---|---|---|---| +| 1 | C1 Fix "New Session" error message bug | DONE | fix(sessions): connect before new_session + navigate cleanly | | ktlint✅ detekt✅ test✅ bridge✅ | Finalized via C4 connection architecture (no more forced resume hack) | +| 2 | C4 Persistent bridge connection (architectural fix for C1) | DONE | feat(sessions): persist/reuse bridge connection across new/resume | | ktlint✅ detekt✅ test✅ bridge✅ | Added `ensureConnected`, warmup on host/session load, and activity teardown disconnect | +| 3 | C2 Compact chat header | DONE | feat(chat): compact header during streaming + keep model access | | ktlint✅ detekt✅ test✅ bridge✅ | Streaming mode now hides non-essential header actions and uses compact model/thinking controls | +| 4 | C3 Flatten directory explorer | DONE | fix(sessions): make New Session work + add flat view toggle | e81d27f | | "All" / "Tree" toggle implemented | + +--- + +## Quick wins + +| Order | Task | Status | Commit message | Commit hash | Verification | Notes | +|---|---|---|---|---|---|---| +| 5 | Q1 Fix image-only prompt mismatch | DONE | fix(chat): allow image-only prompt flow and guard failed image encoding | | ktlint✅ detekt✅ test✅ bridge✅ | ChatViewModel now allows empty text when image payloads exist | +| 6 | Q2 Add full tree filters (`all` included) | DONE | feat(tree): add all filter end-to-end (bridge + app) | | ktlint✅ detekt✅ test✅ bridge✅ | Added `all` in bridge validator/indexer + chat tree filter chips | +| 7 | Q3 Command palette built-in parity layer | DONE | feat(chat): add built-in command support states in palette | | ktlint✅ detekt✅ test✅ bridge✅ | Built-ins now appear as supported/bridge-backed/unsupported with explicit behavior | +| 8 | Q4 Global collapse/expand controls | DONE | feat(chat): add global collapse/expand for tools and reasoning | | ktlint✅ detekt✅ test✅ bridge✅ | Added one-tap header controls with view-model actions for tools/reasoning expansion | +| 9 | Q5 Wire frame metrics into live chat | DONE | feat(perf): enable streaming frame-jank logging in chat screen | | ktlint✅ detekt✅ test✅ bridge✅ | Hooked `StreamingFrameMetrics` into ChatScreen with per-jank log output | +| 10 | Q6 Transport preference setting parity | DONE | feat(settings): add transport preference parity with websocket fallback | | ktlint✅ detekt✅ test✅ bridge✅ | Added `auto`/`websocket`/`sse` preference UI, persistence, and runtime fallback to websocket with explicit notes | +| 11 | Q7 Queue inspector UX for pending steer/follow-up | DONE | feat(chat): add streaming queue inspector for steer/follow-up | | ktlint✅ detekt✅ test✅ bridge✅ | Added pending queue inspector card during streaming with per-item remove/clear actions and delivery-mode visibility | + +--- + +## Stability + security fixes + +| Order | Task | Status | Commit message | Commit hash | Verification | Notes | +|---|---|---|---|---|---|---| +| 12 | F1 Bridge event isolation + lock correctness | DONE | fix(bridge): isolate rpc events to control owner per cwd | | ktlint✅ detekt✅ test✅ bridge✅ | RPC forwarder events now require active control ownership before fan-out; added tests for shared-cwd isolation and post-release send rejection | +| 13 | F2 Reconnect/resync race hardening | DONE | fix(core-net): harden reconnect resync epochs and pending requests | | ktlint✅ detekt✅ test✅ bridge✅ | Added reconnect epoch gating, cancelled pending request responses on reconnect/disconnect, and synced streaming flag from resync snapshots | +| 14 | F3 Bridge auth + exposure hardening | DONE | fix(bridge): harden token auth and exposure defaults | | ktlint✅ detekt✅ test✅ bridge✅ | Added constant-time token hash compare, health endpoint exposure toggle, non-loopback bind warnings, and README security guidance | +| 15 | F4 Android network security tightening | DONE | fix(android): tighten cleartext policy to tailscale hostnames | | ktlint✅ detekt✅ test✅ bridge✅ | Scoped cleartext to `localhost` + `*.ts.net`, set `usesCleartextTraffic=false`, and documented MagicDNS/Tailnet assumptions | +| 16 | F5 Bridge session index scalability | DONE | perf(bridge): cache session metadata by stat signature | | ktlint✅ detekt✅ test✅ bridge✅ | Added session metadata cache keyed by file mtime/size to avoid repeated full file reads for unchanged session indexes | + +--- + +## Medium maintainability improvements + +| Order | Task | Status | Commit message | Commit hash | Verification | Notes | +|---|---|---|---|---|---|---| +| 17 | M1 Replace service locator with explicit DI | DONE | refactor(di): replace app service locator with explicit graph | | ktlint✅ detekt✅ test✅ bridge✅ | Introduced AppGraph dependency container and removed global `AppServices` singleton usage from routes/viewmodel factories | +| 18 | M2 Split god classes (complexity-focused, non-rigid) | DONE | refactor(chat): extract overlay and command palette components | | ktlint✅ detekt✅ test✅ bridge✅ | Extracted extension dialogs, notifications, and command palette from `ChatScreen.kt` into dedicated `ChatOverlays.kt` and tightened DI wiring split from M1 | +| 19 | M3 Unify streaming/backpressure runtime pipeline | DONE | refactor(core-rpc): remove unused backpressure pipeline abstractions | | ktlint✅ detekt✅ test✅ bridge✅ | Removed unused `BackpressureEventProcessor`, `StreamingBufferManager`, `BoundedEventBuffer` and their tests to keep a single runtime path based on `AssistantTextAssembler` + `UiUpdateThrottler` | +| 20 | M4 Tighten static analysis rules/suppressions | DONE | chore(detekt): tighten complexity config and drop broad file suppressions | | ktlint✅ detekt✅ test✅ bridge✅ | Added explicit `TooManyFunctions` complexity tuning (`ignorePrivate`, raised thresholds) and removed redundant `@file:Suppress("TooManyFunctions")` across core UI/runtime files | + +--- + +## Theming + Design System (after architecture cleanup) + +| Order | Task | Status | Commit message | Commit hash | Verification | Notes | +|---|---|---|---|---|---|---| +| 21 | T1 Centralized theme architecture (PiMobileTheme) | DONE | feat(theme): add PiMobileTheme with system/light/dark preference | | ktlint✅ detekt✅ test✅ bridge✅ | Added `ui/theme` package, wrapped app in `PiMobileTheme`, introduced persisted theme preference + settings controls, and removed chat hardcoded tool colors in favor of theme roles | +| 22 | T2 Component design system | DONE | feat(ui): introduce reusable Pi design system primitives | | ktlint✅ detekt✅ test✅ bridge✅ | Added `ui/components` (`PiCard`, `PiButton`, `PiTextField`, `PiTopBar`, `PiSpacing`) and adopted them across Settings + Sessions for consistent spacing/actions/search patterns | + +--- + +## Heavy hitters (last) + +| Order | Task | Status | Commit message | Commit hash | Verification | Notes | +|---|---|---|---|---|---|---| +| 23 | H1 True `/tree` parity (in-place navigate) | DONE | feat(tree): add bridge-backed in-place tree navigation parity | 4b71090 | ktlint✅ detekt✅ test✅ bridge✅ | Added bridge `bridge_navigate_tree` flow powered by internal Pi extension command (`ctx.navigateTree`), wired Chat jump action to in-place navigation (not fork), and propagated runtime current leaf to tree responses | +| 24 | H2 Session parsing alignment with Pi internals | DONE | refactor(bridge): align session index parsing with pi metadata semantics | c7127bf | ktlint✅ detekt✅ test✅ bridge✅ | Added resilient tree normalization for legacy entries without ids, aligned `updatedAt` to user/assistant activity semantics, and mapped hidden active leaves to visible ancestors under tree filters with compatibility tests | +| 25 | H3 Incremental session history loading strategy | DONE | perf(chat): incrementally parse resume history with paged windows | 91a4d9b | ktlint✅ detekt✅ test✅ bridge✅ | Added capped history window extraction with on-demand page parsing for older messages, preserving hidden-count pagination semantics while avoiding full-history timeline materialization on resume | +| 26 | H4 Extension-ize selected hardcoded workflows | DONE | feat(extensions): route mobile stats workflow through internal command | 1fc6b7f | ktlint✅ detekt✅ test✅ bridge✅ | Added bridge-shipped `pi-mobile-workflows` extension command and routed `/stats` built-in through extension status actions, reducing app-side hardcoded workflow execution while preserving fallback UX | + +--- + +## Post-feedback UX/reliability follow-up (2026-02-15) + +| Order | Task | Status | Commit message | Commit hash | Verification | Notes | +|---|---|---|---|---|---|---| +| R1 | Resume reliability (chat refresh after session switch) | DONE | pending | | ktlint✅ detekt✅ test✅ bridge✅ | ChatViewModel now reloads history on successful `switch_session`/`new_session`/`fork` RPC responses to prevent stale timeline when resuming from Sessions tab | +| R2 | Sessions explorer UX (flat-first + quick grouped controls) | DONE | pending | | ktlint✅ detekt✅ test✅ bridge✅ | Sessions now default to flat browsing; mode toggle relabeled (`Flat`/`Grouped`); grouped mode adds one-tap expand/collapse-all | +| R3 | Session grouping readability improvements | DONE | pending | | ktlint✅ detekt✅ test✅ bridge✅ | CWD headers now include session counts; session cards gained compact metadata rows (`msgs`/model), single-line path ellipsis, and flat cards now show actual project `cwd` instead of storage directories | +| R4 | Remove redundant top app bar (`pi-mobile`) | DONE | pending | | ktlint✅ detekt✅ test✅ bridge✅ | App theme switched to `Theme.DeviceDefault.NoActionBar` to reclaim vertical space and remove duplicate chrome | + +--- + +## Verification template (paste per completed task) + +```text +ktlintCheck: ✅/❌ +detekt: ✅/❌ +test: ✅/❌ +bridge check: ✅/❌ +manual smoke: ✅/❌ +``` + +--- + +## Running log + +### Entry template + +```text +Date: +Task: +Status change: +Commit: +Verification: +Notes/blockers: +``` + +### 2026-02-15 + +```text +Task: C4 (and C1 finalization) +Status change: C4 TODO -> DONE, C1 IN_PROGRESS -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added SessionController.ensureConnected()/disconnect() and RpcSessionController connection reuse by host+cwd. +- SessionsViewModel now warms bridge connection after host/session load and reuses it for newSession/resume. +- MainActivity now triggers sessionController.disconnect() on app finish. +``` + +### 2026-02-15 + +```text +Task: C2 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Chat header now enters compact mode while streaming. +- Non-essential actions (stats/copy/bash) are hidden during streaming to free vertical space. +- Model selector remains directly accessible in compact mode. +``` + +### 2026-02-15 + +```text +Task: Q1 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- ChatViewModel.sendPrompt() now allows image-only prompts. +- Added guard for image-encoding failures to avoid sending empty prompt with no payload. +``` + +### 2026-02-15 + +```text +Task: Q2 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added `all` to bridge tree filter whitelist and session-indexer filter type. +- `all` now returns full tree entries (including label/custom entries). +- Added app-side tree filter option chip for `all`. +``` + +### 2026-02-15 + +```text +Task: Q3 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Command palette now labels commands as supported / bridge-backed / unsupported. +- Added explicit built-in entries for interactive TUI commands omitted by RPC get_commands. +- Selecting or sending interactive-only built-ins now shows explicit mobile UX instead of silent no-op. +``` + +### 2026-02-15 + +```text +Task: Q4 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added global "Collapse all" / "Expand all" controls for tools and reasoning. +- Hooked controls to new ChatViewModel actions for timeline-wide expansion state updates. +- Added coverage for global expand/collapse behavior in ChatViewModel tests. +``` + +### 2026-02-15 + +```text +Task: Q5 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Activated StreamingFrameMetrics in ChatScreen when streaming is active. +- Added jank logs with severity/frame-time/dropped-frame estimate for live chat rendering. +``` + +### 2026-02-15 + +```text +Task: Q6 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added transport preference setting (`auto` / `websocket` / `sse`) in Settings with persistence. +- SessionController now exposes transport preference APIs and RpcSessionController applies runtime websocket fallback. +- Added clear effective transport + fallback note in UI when SSE is requested. +``` + +### 2026-02-15 + +```text +Task: Q7 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added streaming queue inspector in chat for steer/follow-up submissions. +- Queue inspector shows delivery modes (`all` / `one-at-a-time`) and supports remove/clear actions. +- Queue state auto-resets when streaming ends and is covered by ChatViewModel tests. +``` + +### 2026-02-15 + +```text +Task: F1 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Tightened bridge RPC event fan-out so only the client that currently holds control for a cwd receives process events. +- Added server tests proving no same-cwd RPC leakage to non-controlling clients. +- Added regression test ensuring RPC send is rejected once control is released. +``` + +### 2026-02-15 + +```text +Task: F2 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added lifecycle epoch gating around reconnect synchronization to prevent stale resync snapshots from applying after lifecycle changes. +- Pending RPC request deferred responses are now cancelled on reconnect/disconnect transitions to avoid stale waits. +- RpcSessionController now consumes resync snapshots and refreshes streaming flag from authoritative state. +``` + +### 2026-02-15 + +```text +Task: F3 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Replaced direct token string equality with constant-time hash digest comparison. +- Added explicit `BRIDGE_ENABLE_HEALTH_ENDPOINT` policy with tests for disabled `/health` behavior. +- Added non-loopback host exposure warnings and documented hardened bridge configuration in README. +``` + +### 2026-02-15 + +```text +Task: F4 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Tightened debug/release network security configs to disable global cleartext and allow only `localhost` + `*.ts.net`. +- Explicitly set `usesCleartextTraffic=false` in AndroidManifest. +- Updated README connect/security guidance to prefer Tailnet MagicDNS hostnames and document scoped cleartext assumptions. +``` + +### 2026-02-15 + +```text +Task: F5 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added session metadata cache in session indexer using file stat signatures (mtime/size). +- Unchanged session files now skip re-read/re-parse during repeated `bridge_list_sessions` calls. +- Added regression test proving cached reads are reused and invalidated when a session file changes. +``` + +### 2026-02-15 + +```text +Task: M1 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added `AppGraph` as explicit dependency container built in MainActivity and passed into the app root. +- Removed `AppServices` singleton and migrated Chat/Settings/Sessions/Hosts routes + viewmodel factories to explicit dependencies. +- MainActivity lifecycle teardown now disconnects via graph-owned SessionController instance. +``` + +### 2026-02-15 + +```text +Task: M2 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Extracted extension dialogs, notifications, and command palette rendering from `ChatScreen.kt` into new `ChatOverlays.kt`. +- Reduced `ChatScreen.kt` responsibilities toward timeline/layout concerns while preserving behavior. +- Continued DI cleanup from M1 by keeping route/factory wiring explicit and test-safe. +``` + +### 2026-02-15 + +```text +Task: M3 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Removed `BackpressureEventProcessor`, `StreamingBufferManager`, and `BoundedEventBuffer` from `core-rpc` because they were not used by app runtime. +- Removed corresponding isolated tests to avoid maintaining dead abstractions. +- Runtime streaming path now clearly centers on `AssistantTextAssembler` and `UiUpdateThrottler`. +``` + +### 2026-02-15 + +```text +Task: M4 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added explicit `complexity.TooManyFunctions` policy in `detekt.yml` (`ignorePrivate: true`, thresholds raised to 15 for files/classes). +- Removed redundant `@file:Suppress("TooManyFunctions")` from Chat/Sessions/Settings screens, ChatViewModel, RpcSessionController, and AssistantTextAssembler. +- Kept targeted rule suppressions only where still justified. +``` + +### 2026-02-15 + +```text +Task: T1 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added `PiMobileTheme` with dedicated light/dark color schemes and system/light/dark resolution. +- Wired app root to observe persisted theme preference from shared settings and apply theme dynamically. +- Added theme preference controls in Settings and removed hardcoded chat tool colors in favor of theme color roles. +``` + +### 2026-02-15 + +```text +Task: T2 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added reusable design-system primitives under `ui/components`: `PiCard`, `PiButton`, `PiTextField`, `PiTopBar`, and `PiSpacing`. +- Migrated Settings and Sessions screens to shared components for card layouts, top bars, option buttons, and text fields. +- Standardized key spacing to shared tokens (`PiSpacing`) in updated screen flows. +``` + +### 2026-02-15 + +```text +Task: H1 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added bridge `bridge_navigate_tree` API backed by an internal Pi extension command using `ctx.navigateTree(...)`. +- Chat Jump now performs in-place tree navigation (same session) and updates editor text from navigation result, replacing prior fork fallback. +- Bridge now tracks runtime current leaf from navigation results and overlays it into `bridge_get_session_tree` responses for active sessions. +``` + +### 2026-02-15 + +```text +Task: H2 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Reworked bridge session index parsing to normalize legacy/id-missing entries into deterministic tree ids and linear parent chains. +- Aligned `updatedAt` metadata with Pi internals by using last user/assistant activity timestamps instead of arbitrary last entry timestamps. +- Improved tree snapshot parity by mapping hidden active leaves to nearest visible ancestors and expanding compatibility coverage in `session-indexer` tests. +``` + +### 2026-02-15 + +```text +Task: H3 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Switched chat history resume to an incremental parsing model: retain a capped message window, parse only the initial visible page, then parse older pages on demand. +- Preserved pagination UX (`hasOlderMessages`, `hiddenHistoryCount`) while avoiding eager materialization of the whole retained history timeline. +- Added coverage for very large-session window cap behavior in `ChatViewModelThinkingExpansionTest`. +``` + +### 2026-02-15 + +```text +Task: H4 +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Added a second bridge-internal extension (`pi-mobile-workflows`) and loaded it alongside `pi-mobile-tree` for RPC sessions. +- Routed mobile `/stats` built-in command through an extension command (`/pi-mobile-open-stats`) that emits internal status action payloads. +- Added ChatViewModel handling/tests for internal workflow status actions and hidden internal command filtering from command palette. +``` + +### 2026-02-15 + +```text +Task: R1/R2/R3/R4 (post-feedback UX/reliability follow-up) +Status change: TODO -> DONE +Commit: pending +Verification: +- ktlintCheck: ✅ +- detekt: ✅ +- test: ✅ +- bridge check: ✅ +- manual smoke: ⏳ pending on device +Notes/blockers: +- Fixed stale chat-on-resume behavior by reloading history on successful `switch_session` / `new_session` / `fork` RPC responses. +- Improved Sessions UX: default flat browsing, clearer `Flat`/`Grouped` mode labels, and one-tap grouped expand/collapse-all. +- Improved grouped readability with per-cwd session counts and showed real project `cwd` in flat cards. +- Removed duplicate `pi-mobile` top chrome by switching app theme to `Theme.DeviceDefault.NoActionBar`. +``` + +--- + +## Overall completion + +- Backlog tasks: 26 +- Backlog done: 26 +- Backlog in progress: 0 +- Backlog blocked: 0 +- Backlog remaining (not done): 0 +- Reference completed items (not counted in backlog): 6 + +--- + +## Quick checklist + +- [x] Critical UX fixes complete +- [x] Quick wins complete +- [x] Stability/security fixes complete +- [x] Maintainability improvements complete +- [x] Theming + Design System complete +- [x] Heavy hitters complete (or documented protocol limits) +- [x] Final green run (`ktlintCheck`, `detekt`, `test`, bridge check) + +--- + +## UX Issues from User Feedback (for reference) + +1. **"No active session" on New Session** — Error message shows when creating new session, should show success +2. **Top nav blocks streaming view** — Header too tall, obscures content during streaming +3. **Directory explorer pain** — Have to click ▶ on each CWD individually to find sessions +4. **Auto-scroll works** — ✅ Fixed in commit 88d1324 +5. **ANSI codes stripped** — ✅ Fixed in commit 61061b2 +6. **Navigate back to Sessions** — ✅ Fixed in commit 2cc0480 + +--- + +## Fresh-eyes review pass (current) + +| Task | Status | Notes | Verification | +|---|---|---|---| +| Deep architecture/code review across chat/session/transport flows | DONE | Re-read `rpc.md` + extension event model and traced end-to-end session switching, prompt dispatch, and UI rendering paths. | ktlint✅ detekt✅ test✅ bridge✅ | +| Prompt error surfacing for unsupported/non-subscribed models | DONE | `RpcSessionController.sendPrompt()` now awaits `prompt` response and propagates `success=false` errors to UI; input/images are restored on failure in `ChatViewModel.sendPrompt()`. | ktlint✅ detekt✅ test✅ bridge✅ | +| Streaming controls responsiveness | DONE | Controller now marks streaming optimistically at prompt dispatch (and reverts on failure), so Abort/Steer/Follow-up controls appear earlier. | ktlint✅ detekt✅ test✅ bridge✅ | +| Lifecycle toast/banner spam reduction | DONE | Removed noisy lifecycle notifications (`Turn started`, `message completed`) and deleted dead lifecycle throttling state/helpers. | ktlint✅ detekt✅ test✅ bridge✅ | +| Chat header UX correction | DONE | Restored Tree + Bash quick actions while keeping simplified header layout and reduced clutter. | ktlint✅ detekt✅ test✅ bridge✅ | +| Chat/tool syntax highlighting | DONE | Added fenced code-block parsing + lightweight token highlighting for assistant messages and inferred-language highlighting for tool output based on file extension. | ktlint✅ detekt✅ test✅ bridge✅ | +| Dead API/command cleanup | DONE | Removed unused `get_last_assistant_text` command plumbing from `SessionController`, `RpcSessionController`, `RpcCommand`, command encoding, and tests. | ktlint✅ detekt✅ test✅ bridge✅ | +| Dead UI callback/feature cleanup | DONE | Removed unused chat callbacks and orphaned global expansion UI path/tests that were no longer reachable from UI. | ktlint✅ detekt✅ test✅ bridge✅ | diff --git a/docs/ai/pi-mobile-rpc-enhancement-progress.md b/docs/ai/pi-mobile-rpc-enhancement-progress.md new file mode 100644 index 0000000..b3f0742 --- /dev/null +++ b/docs/ai/pi-mobile-rpc-enhancement-progress.md @@ -0,0 +1,123 @@ +# Pi Mobile RPC Enhancement Progress Tracker + +Status values: `TODO` | `IN_PROGRESS` | `BLOCKED` | `DONE` | `DE_SCOPED` + +> Last updated: 2026-02-15 (Post-parity hardening tasks H1-H3 completed) + +--- + +## Completed milestones + +| Area | Status | Notes | +|---|---|---| +| Thinking blocks + collapse | DONE | Implemented in assembler + chat UI | +| Slash commands palette | DONE | `get_commands` + grouped searchable UI | +| Auto compaction/retry notifications | DONE | Events parsed and surfaced | +| Tool UX enhancements | DONE | icons, arguments, diff viewer | +| Bash UI | DONE | execute/abort/history/output/copy | +| Session stats | DONE | stats sheet in chat | +| Model picker | DONE | available models + set model | +| Auto settings toggles | DONE | auto-compaction + auto-retry | +| Image attachments | DONE | picker + thumbnails + base64 payload | +| RPC schema mismatch fixes | DONE | stats/bash/models/set_model/fork fields fixed in controller parser | + +--- + +## Ordered backlog (current) + +| Order | Task | Status | Commit | Verification | Notes | +|---|---|---|---|---|---| +| 1 | Protocol conformance tests (stats/bash/models/set_model/fork) | DONE | `1f90b3f` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added `RpcSessionControllerTest` conformance coverage for canonical + legacy mapping fields | +| 2 | Parse missing events: `message_start/end`, `turn_start/end`, `extension_error` | DONE | `1f57a2a` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added parser branches + models and event parsing tests for lifecycle and extension errors | +| 3 | Surface lifecycle + extension errors in chat UX | DONE | `09e2b27` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added non-blocking lifecycle notifications and contextual extension error notifications in chat | +| 4 | Steering/follow-up mode controls (`set_*_mode`) | DONE | `948ace3` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added RPC commands, session controller wiring, settings UI selectors, and get_state mode sync | +| 5 | Tree navigation spike (`/tree` equivalent feasibility) | DONE | `4472f89` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added spike doc; decision: RPC-only is insufficient, add read-only bridge session-tree endpoint | +| 6 | Tree navigation MVP | DONE | `360aa4f` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ `(cd bridge && pnpm run check)` ✅ | Added bridge session-tree endpoint, app bridge request path, and chat tree sheet with fork-from-entry navigation | +| 7 | Keyboard shortcuts/gestures help screen | DONE | `5ca89ce` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added settings help card documenting chat actions, gestures, and key interactions | +| 8 | README/docs sync | DONE | `5dd4b48` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | README refreshed with current UX capabilities and limitations (including image support) | + +--- + +## Post-parity hardening backlog + +| Order | Task | Status | Commit | Verification | Notes | +|---|---|---|---|---|---| +| H1 | Tree contract conformance tests | DONE | `e56db90` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ `(cd bridge && pnpm run check)` ✅ | Added bridge/session-indexer tree endpoint tests and app tree parser mapping test | +| H2 | Lifecycle notification noise controls | DONE | `09fa47d` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added lifecycle notification throttling and duplicate suppression while preserving extension error visibility | +| H3 | Settings mode controls test coverage | DONE | `777c56c` | `ktlintCheck` ✅ `detekt` ✅ `test` ✅ | Added `SettingsViewModelTest` coverage for steering/follow-up mode success and rollback paths | + +--- + +## Command coverage status + +### Implemented +- `prompt`, `steer`, `follow_up`, `abort`, `new_session` +- `get_state`, `get_messages`, `switch_session` +- `set_session_name`, `get_fork_messages`, `fork` +- `export_html`, `compact` +- `cycle_model`, `cycle_thinking_level` +- `get_commands` +- `bash`, `abort_bash` +- `get_session_stats` +- `get_available_models`, `set_model` +- `set_auto_compaction`, `set_auto_retry` +- `set_steering_mode`, `set_follow_up_mode` + +### Remaining +- None + +--- + +## Event coverage status + +### Implemented +- `message_update` (text + thinking) +- `message_start` / `message_end` +- `turn_start` / `turn_end` +- `tool_execution_start/update/end` +- `extension_ui_request` +- `extension_error` +- `agent_start/end` +- `auto_compaction_start/end` +- `auto_retry_start/end` + +### Remaining +- None (parser-level) + +--- + +## Feature parity checklist (pi mono TUI) + +- [x] Tool calls visible +- [x] Tool output collapse/expand +- [x] Reasoning visibility + collapse/expand +- [x] File edit diff view +- [x] Slash commands discovery/use +- [x] Model control beyond cycling +- [x] Session stats display +- [x] Image attachments +- [x] Tree navigation equivalent (`/tree`) +- [x] Steering/follow-up delivery mode controls +- [x] Lifecycle/extension error event completeness + +--- + +## Verification commands + +```bash +./gradlew ktlintCheck +./gradlew detekt +./gradlew test +# if bridge changed: +(cd bridge && pnpm run check) +``` + +--- + +## Blockers / risks + +| Task | Risk | Mitigation | +|---|---|---| +| Tree navigation | Bridge/tree payload drift across pi session formats | Keep parser defensive and cover with bridge tests/fixtures | +| Lifecycle UX noise | Too many system notifications can clutter chat | Keep subtle + dismissible + rate-limited | +| Protocol regressions | Field names can drift across pi versions | Add parser conformance tests with real payload fixtures | diff --git a/docs/ai/pi-mobile-rpc-enhancement-tasks.md b/docs/ai/pi-mobile-rpc-enhancement-tasks.md new file mode 100644 index 0000000..b51dd67 --- /dev/null +++ b/docs/ai/pi-mobile-rpc-enhancement-tasks.md @@ -0,0 +1,234 @@ +# Pi Mobile RPC Enhancement Tasks (Ordered Iteration Plan) + +Updated plan after major parity work landed. + +> Rule: execute in order. Do not start next task until current task is green (`ktlintCheck`, `detekt`, `test`, and bridge `pnpm run check` if touched). + +--- + +## 0) Current state snapshot + +Already completed: +- Thinking blocks + collapse/expand +- Slash commands palette +- Auto-compaction/auto-retry notifications +- Edit diff viewer +- Bash dialog (run + abort + history) +- Tool argument display + tool icons +- Session stats sheet +- Model picker + set model +- Auto-compaction/auto-retry settings toggles +- Image attachment support + +Remaining gaps for fuller pi mono TUI parity: +- None from this plan (all items completed) + +Completed in this iteration: +- Task 1.1 — `1f90b3f` +- Task 1.2 — `1f57a2a` +- Task 2.1 — `09e2b27` +- Task 2.2 — `948ace3` +- Task 3.1 — `4472f89` +- Task 3.2 — `360aa4f` +- Task 4.1 — `5ca89ce` +- Task 4.2 — `5dd4b48` + +--- + +## 1) Protocol conformance hardening (P0) + +### Task 1.1 — Lock RPC parser/mapper behavior with tests +**Priority:** CRITICAL +**Goal:** Prevent regressions in RPC field mapping. + +Scope: +- Add tests for: + - `get_session_stats` nested shape (`tokens`, `cost`, `totalMessages`) + - `bash` fields (`truncated`, `fullOutputPath`) + - `get_available_models` fields (`reasoning`, `maxTokens`, `cost.*`) + - `set_model` direct model payload + - `get_fork_messages` using `text` +- Keep backward-compatible fallback coverage for legacy field names. + +Files: +- `app/src/test/.../sessions/RpcSessionController*Test.kt` (create if missing) +- optionally `core-rpc/src/test/.../RpcMessageParserTest.kt` + +Acceptance: +- All mapping tests pass and fail if field names regress. + +--- + +### Task 1.2 — Add parser support for missing lifecycle events +**Priority:** HIGH + +Scope: +- Add models + parser branches for: + - `message_start` + - `message_end` + - `turn_start` + - `turn_end` + - `extension_error` + +Files: +- `core-rpc/src/main/kotlin/.../RpcIncomingMessage.kt` +- `core-rpc/src/main/kotlin/.../RpcMessageParser.kt` +- `core-rpc/src/test/kotlin/.../RpcMessageParserTest.kt` + +Acceptance: +- Event parsing tests added and passing. + +--- + +## 2) Chat UX completeness (P1) + +### Task 2.1 — Surface lifecycle and extension errors in chat +**Priority:** HIGH + +Scope: +- Show subtle system notifications for: + - message/turn boundaries (optional minimal indicators) + - extension runtime errors (`extension_error`) +- Keep non-intrusive UX (no modal interruption). + +Files: +- `app/src/main/java/.../chat/ChatViewModel.kt` +- `app/src/main/java/.../ui/chat/ChatScreen.kt` + +Acceptance: +- Extension errors visible to user with context (extension path/event/error). +- No crashes on unknown lifecycle event payloads. + +--- + +### Task 2.2 — Steering/follow-up mode controls +**Priority:** HIGH + +Scope: +- Implement RPC commands/UI for: + - `set_steering_mode` (`all` | `one-at-a-time`) + - `set_follow_up_mode` (`all` | `one-at-a-time`) +- Expose in settings (or chat settings panel). +- Read current mode from `get_state` and reflect in UI. + +Files: +- `core-rpc/src/main/kotlin/.../RpcCommand.kt` +- `app/src/main/java/.../sessions/SessionController.kt` +- `app/src/main/java/.../sessions/RpcSessionController.kt` +- `app/src/main/java/.../ui/settings/SettingsViewModel.kt` +- `app/src/main/java/.../ui/settings/SettingsScreen.kt` + +Acceptance: +- User can change both modes and values persist for active session. + +--- + +## 3) Tree navigation track (P2) + +### Task 3.1 — Technical spike for `/tree` equivalent +**Priority:** MEDIUM + +Scope: +- Verify whether current RPC payloads expose enough branch metadata. +- If insufficient, define bridge extension API (read-only session tree endpoint). +- Write design doc with chosen approach and payload schema. + +Deliverable: +- `docs/spikes/tree-navigation-rpc-vs-bridge.md` + +Acceptance: +- Clear go/no-go decision and implementation contract. + +--- + +### Task 3.2 — Implement minimal tree view (MVP) +**Priority:** MEDIUM + +Scope: +- Basic branch-aware navigation screen: + - current path + - branch points + - jump-to-entry +- No fancy rendering needed for MVP; correctness first. + +Acceptance: +- User can navigate history branches and continue from selected point. + +--- + +## 4) Documentation and polish (P3) + +### Task 4.1 — Keyboard shortcuts / gestures help screen +**Priority:** LOW + +Scope: +- Add in-app help card/page documenting chat actions and gestures. + +Acceptance: +- Accessible from settings and up to date with current UI. + +--- + +### Task 4.2 — README/docs sync with implemented features +**Priority:** LOW + +Scope: +- Update stale README limitations (image support now exists). +- Document command palette, thinking blocks, bash dialog, stats, model picker. + +Files: +- `README.md` +- `docs/testing.md` if needed + +Acceptance: +- No known stale statements in docs. + +--- + +## 5) Verification loop (mandatory after each task) + +```bash +./gradlew ktlintCheck +./gradlew detekt +./gradlew test +# if bridge changed: +(cd bridge && pnpm run check) +``` + +--- + +## 6) Post-parity hardening queue (new) + +### Task H1 — Tree contract conformance tests +**Priority:** HIGH + +Scope: +- Add bridge tests for `bridge_get_session_tree` success/error handling. +- Add session-indexer tests for parent/child tree parsing from fixture sessions. +- Add app parser test coverage for `parseSessionTreeSnapshot` mapping. + +Acceptance: +- Tests fail on tree payload contract regressions and pass on current schema. + +### Task H2 — Lifecycle notification noise controls +**Priority:** MEDIUM + +Scope: +- Add throttling/dedup logic for lifecycle notifications during high-frequency event bursts. +- Keep extension errors always visible. + +### Task H3 — Settings mode controls test coverage +**Priority:** MEDIUM + +Scope: +- Add tests for steering/follow-up mode view-model state transitions and rollback on RPC failures. + +--- + +## Ordered execution queue (next) + +1. Task H1 — Tree contract conformance tests ✅ DONE (`e56db90`) +2. Task H2 — Lifecycle notification noise controls ✅ DONE (`09fa47d`) +3. Task H3 — Settings mode controls test coverage ✅ DONE (`777c56c`) + +All post-parity hardening tasks currently defined are complete.