You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Document the embedded terminal's Windows printable hardware-key fallback and AltGr support in ADR-027, BEHAVIOR.md, and CODEBASE.md. Sync AGENTS.md ADR quick-reference line ranges after the ADR-027 update.
Copy file name to clipboardExpand all lines: ADR.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1313,6 +1313,7 @@ ADR-026 specified a local PTY shell spawned on the client device using `flutter_
1313
1313
5.**Composer auto-hide on compact/mobile**: On compact and mobile layouts, the composer input area is hidden while the terminal panel is open. The composer reappears when the terminal is minimized or closed.
1314
1314
6.**Project directory integration**: The server-side PTY launches in the active project's working directory (the `scopeId` from the current `serverId::scopeId` context), ensuring the shell operates in the same workspace the chat conversation is about.
1315
1315
7.**No server API contract changes**: The terminal transport reuses existing OpenCode streaming infrastructure (WebSocket or SSE). No new dedicated terminal endpoints are introduced — the server exposes PTY data through the established event stream contract.
1316
+
8.**Windows printable hardware-key fallback and AltGr support**: The vendored `xterm``TerminalView` includes a Windows-only fallback that handles printable hardware-key events (raw scan codes) and AltGr key composition. This guards against input regression on international keyboard layouts where AltGr produces alternate characters (e.g. European layouts). The fallback is gated behind `TargetPlatform.windows` (Flutter platform gate) and does not affect other platforms.
1316
1317
1317
1318
### Rationale
1318
1319
@@ -1324,7 +1325,7 @@ ADR-026 specified a local PTY shell spawned on the client device using `flutter_
1324
1325
1325
1326
### Consequences
1326
1327
1327
-
- ✅ Terminal works identically on all client platforms (desktop, mobile, web) with no platform-specific native dependencies.
1328
+
- ✅ Terminal works identically on all client platforms (desktop, mobile, web) with no platform-specific native dependencies. Windows AltGr and hardware-key fallback preserves input parity for international keyboard layouts.
1328
1329
- ✅ Server-side PTY runs in the correct project environment with full toolchain access.
1329
1330
- ✅ Removes `flutter_pty` native compilation complexity from the client build pipeline.
1330
1331
- ✅ Close/minimize/maximize semantics and composer auto-hide on compact/mobile are preserved.
Copy file name to clipboardExpand all lines: AGENTS.md
+11-11Lines changed: 11 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -56,17 +56,17 @@ This rule is **supreme** for any app behavior change and overrides conflicting l
56
56
| 024 | Modal Enter keyboard policy for safe dialogs — speed up keyboard confirmation without enabling destructive or ambiguous modal flows | 1106–1180 |
| 026 | ⚠️ SUPERSEDED — Local PTY shell replaced by server-hosted PTY (ADR-027) | 1233–1291 |
59
-
| 027 | Server-hosted PTY terminal with embedded client rendering — runs on OpenCode host in active project directory, client renders via streaming transport, local flutter_pty removed, close/minimize/maximize semantics preserved, composer hides on compact/mobile| 1292–1353|
60
-
| 028 | Unified scroll ownership via `_ScrollOwner` enum — eliminate scroll jumping across send/return/pagination triggers, user drag priority, force scroll bypass; additive guardrails cover passive provider scroll suppression, manual follow pause near bottom, response-settle shrink-snap suppression, duplicate return-to-chat scoping, queued cached restore targets for settled-vs-active session return, active-turn/global-fallback guards against passive background settle, a single reading-mode final reveal path for long answers, deferred tool-only merge until settlement to prevent active-turn structural shrink, and a narrow active-turn shrink heal while passive follow remains enabled |1354–1434|
61
-
| 029 | Host-discovered quota and rate-limit monitoring for OpenChamber parity — server-host quota ownership, strategy-chain transport (REST/Shell), popup-only UI (compact-first), grouped providers with pace/progress, explicit parity opt-in; narrow `opencode-go` exception for dashboard credential opt-in (workspace ID + auth cookie, scoped by serverId, quota-probe only, removable via UI); Codex `providerId` guard prevents single-window label collapse |1435–1514|
62
-
| 030 | OpenChamber-driven realtime hardening and permission continuity — atomic refresh consolidation, mutation guard during reconnect failures, authoritative pruning delay, and bounded reconnect helpers |1515–1557|
63
-
| 031 | Historical inline revert through the official session revert endpoint — `revertToTurn`, duplicate-revert guard, `local_user_*` validation, composer draft restoration, distinct inline rewind action for server-confirmed user messages, and permission `remember: true` companion fix for `always` replies |1560–1624|
64
-
| 032 | LaTeX math rendering with `flutter_math_fork` (pure-Dart KaTeX port), custom `$…$`/`$$…$$` Markdown delimiters, `MathExpressionWidget` with styled fallback, and `showMathRendering` toggle in `ExperienceSettings` — typeset math in chat without WebView |1629–1679|
65
-
| 033 | Cloudflare Managed OAuth as optional desktop + Android reverse-proxy auth (ADR-023 exception) — `ServerProfile.oauthEnabled`, `OAuthService` conditional export (io/stub), auth code + PKCE S256, DCR, `OAuthTokenStorage` in `flutter_secure_storage` scoped by profileId+serverUrl, Bearer token for matching origin only, OAuth/Basic Auth mutually exclusive per profile, desktop (local HTTP redirect) and Android (flutter_appauth) via `AppProvider.supportsCloudflareAccessOAuth`, `/oauth/callback` with state/duplicate rejection, health checks record OAuth challenges, rollback by disabling `oauthEnabled` + clearing credentials |1683–1792|
| 035 | Message-derived selection fallback with explicit-override precedence — 3-tier restoration (explicit override → message scan → global defaults), LRU cache-first backward scan for `providerId`/`modelId`/`mode`/`variant`, neutral-message filtering, isExplicit flag, override promotion on fallback success; OpenChamber parity for `restoreSessionStateFromMessages()`|1852–1901|
68
-
| 036 | Userspace Tailscale transport with vendored `package:tailscale`, `hook/build.dart` no-op on Windows, `ServerProfile.tailscaleEnabled`, one node per process, active-profile-only transport, inactive health returns unknown, custom Dio HttpClientAdapter preserving SSE + cancellation, interactive auth UX via `AppProvider` reactive state + `authenticateTailscale()`, auth panels in onboarding/settings, no auto-launch of auth URLs, no Web/Windows |1903–1960|
69
-
| 037 | Chat Viewport and Scroll/Follow Synchronization Revamp — consolidation of viewport flags to `_ScrollFollowMode`, turn-scoped reveal guard, time-windowed REST status guard, build-phase sync extraction, no entrance motion on timeline entries (passive auto-follow uses non-animated `jumpTo` with bounded retry), and reader-owned viewport preservation during active incoming response growth |1964–2011|
59
+
| 027 | Server-hosted PTY terminal with embedded client rendering — runs on OpenCode host in active project directory, client renders via streaming transport, local flutter_pty removed, close/minimize/maximize semantics preserved, composer hides on compact/mobile, Windows AltGr/hardware-key fallback for international keyboards | 1294–1356|
60
+
| 028 | Unified scroll ownership via `_ScrollOwner` enum — eliminate scroll jumping across send/return/pagination triggers, user drag priority, force scroll bypass; additive guardrails cover passive provider scroll suppression, manual follow pause near bottom, response-settle shrink-snap suppression, duplicate return-to-chat scoping, queued cached restore targets for settled-vs-active session return, active-turn/global-fallback guards against passive background settle, a single reading-mode final reveal path for long answers, deferred tool-only merge until settlement to prevent active-turn structural shrink, and a narrow active-turn shrink heal while passive follow remains enabled |1357–1437|
61
+
| 029 | Host-discovered quota and rate-limit monitoring for OpenChamber parity — server-host quota ownership, strategy-chain transport (REST/Shell), popup-only UI (compact-first), grouped providers with pace/progress, explicit parity opt-in; narrow `opencode-go` exception for dashboard credential opt-in (workspace ID + auth cookie, scoped by serverId, quota-probe only, removable via UI); Codex `providerId` guard prevents single-window label collapse |1438–1517|
62
+
| 030 | OpenChamber-driven realtime hardening and permission continuity — atomic refresh consolidation, mutation guard during reconnect failures, authoritative pruning delay, and bounded reconnect helpers |1518–1561|
63
+
| 031 | Historical inline revert through the official session revert endpoint — `revertToTurn`, duplicate-revert guard, `local_user_*` validation, composer draft restoration, distinct inline rewind action for server-confirmed user messages, and permission `remember: true` companion fix for `always` replies |1562–1629|
64
+
| 032 | LaTeX math rendering with `flutter_math_fork` (pure-Dart KaTeX port), custom `$…$`/`$$…$$` Markdown delimiters, `MathExpressionWidget` with styled fallback, and `showMathRendering` toggle in `ExperienceSettings` — typeset math in chat without WebView |1630–1683|
65
+
| 033 | Cloudflare Managed OAuth as optional desktop + Android reverse-proxy auth (ADR-023 exception) — `ServerProfile.oauthEnabled`, `OAuthService` conditional export (io/stub), auth code + PKCE S256, DCR, `OAuthTokenStorage` in `flutter_secure_storage` scoped by profileId+serverUrl, Bearer token for matching origin only, OAuth/Basic Auth mutually exclusive per profile, desktop (local HTTP redirect) and Android (flutter_appauth) via `AppProvider.supportsCloudflareAccessOAuth`, `/oauth/callback` with state/duplicate rejection, health checks record OAuth challenges, rollback by disabling `oauthEnabled` + clearing credentials |1684–1796|
| 035 | Message-derived selection fallback with explicit-override precedence — 3-tier restoration (explicit override → message scan → global defaults), LRU cache-first backward scan for `providerId`/`modelId`/`mode`/`variant`, neutral-message filtering, isExplicit flag, override promotion on fallback success; OpenChamber parity for `restoreSessionStateFromMessages()`|1854–1904|
68
+
| 036 | Userspace Tailscale transport with vendored `package:tailscale`, `hook/build.dart` no-op on Windows, `ServerProfile.tailscaleEnabled`, one node per process, active-profile-only transport, inactive health returns unknown, custom Dio HttpClientAdapter preserving SSE + cancellation, interactive auth UX via `AppProvider` reactive state + `authenticateTailscale()`, auth panels in onboarding/settings, no auto-launch of auth URLs, no Web/Windows |1905–1964|
69
+
| 037 | Chat Viewport and Scroll/Follow Synchronization Revamp — consolidation of viewport flags to `_ScrollFollowMode`, turn-scoped reveal guard, time-windowed REST status guard, build-phase sync extraction, no entrance motion on timeline entries (passive auto-follow uses non-animated `jumpTo` with bounded retry), and reader-owned viewport preservation during active incoming response growth |1965–2012|
70
70
71
71
## 🗺 CODEBASE Quick Reference (details in `CODEBASE.md`)
Copy file name to clipboardExpand all lines: BEHAVIOR.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -819,6 +819,7 @@ Additional commands may be provided by the connected OpenCode server and merged
819
819
-**Then** CodeWalk creates or reconnects to a server-hosted PTY terminal rooted in the active project directory on the OpenCode host and renders it inside the embedded panel
820
820
-**Then**`Close terminal` fully closes the panel and terminates the active server PTY session, while `Minimize terminal` hides the panel without stopping that session
821
821
-**Then**`Maximize terminal` expands the panel to a larger workspace view and `Restore terminal size` returns it to the saved panel height
822
+
-**Then** on Windows, printable hardware keyboard input, including AltGr characters from international layouts, is forwarded to the terminal session instead of being dropped after focus
822
823
-**Given** the user is on a compact/mobile chat layout
823
824
-**When** the embedded terminal is open
824
825
-**Then** CodeWalk hides the composer input area until the terminal is minimized or closed so the terminal can use the available screen space
codewalk_terminal_url_test.dart # WebSocket terminal URL construction
360
360
read_aloud_service_test.dart # Text-to-speech service lifecycle, options (pitch/rate/voice), and message tracking
361
-
test/widget/ # Widget tests (includes icon assertions with Symbols.*, explicit compact/mobile collapsed-copy coverage for chat message and session todo surfaces, historical rewind action coverage, desktop/mobile spacing for ChatSessionList, toolbar undo/redo, slash-command parity, and terminal mobile backspace simulation coverage)
361
+
test/widget/ # Widget tests (includes icon assertions with Symbols.*, explicit compact/mobile collapsed-copy coverage for chat message and session todo surfaces, historical rewind action coverage, desktop/mobile spacing for ChatSessionList, toolbar undo/redo, slash-command parity, terminal mobile backspace simulation, Windows printable hardware key forwarding, and Windows AltGr printable forwarding)
362
362
test/integration/ # Integration tests; includes data-usage optimization and permission `remember` contract coverage in `opencode_server_integration_test.dart`
test/support/ # Test helpers/fakes; `mock_opencode_server.dart` includes extra counters for usage optimization tracking; `pump_localized_app.dart` wraps widgets with all l10n delegates for locale-aware tests
0 commit comments