fix: исправить навигацию клавиатуры в TUI через GlobalKeyboardService
- Добавить GlobalKeyboardService — выделенный поток с блокирующим Console.ReadKey, единственный источник клавишных событий для TUI - Убрать FocusManager из App.razor: перехватывал Tab до компонентов - Удалить @onkeydown с <Select>: RazorConsole не пробрасывает Tab/стрелки через этот механизм - Использовать FocusedValue вместо Value в Select для корректной подсветки - Обновить CLAUDE.md и AGENTS.md: архитектура TUI, RazorConsole gotchas - Добавить docs/tui_log.md: разбор проблемы и справочник по RazorConsole Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
11
CLAUDE.md
11
CLAUDE.md
@@ -32,7 +32,7 @@ LazyBear is a .NET 10 MCP server exposing Jira, Confluence, and Kubernetes integ
|
||||
1. **TUI (foreground)** — RazorConsole terminal UI (`App.razor`), owns the console, handles keyboard navigation
|
||||
2. **HTTP MCP endpoint (background)** — `McpWebHostedService` runs as a hosted service, serves MCP tool calls on port 5000
|
||||
|
||||
Both share the same singletons: `ToolRegistryService`, `InMemoryLogSink`, and the three client providers.
|
||||
Both share the same singletons: `ToolRegistryService`, `InMemoryLogSink`, `GlobalKeyboardService`, and the three client providers.
|
||||
|
||||
### Plugin System (IToolModule)
|
||||
|
||||
@@ -50,6 +50,12 @@ Each client (`K8sClientProvider`, `JiraClientProvider`, `ConfluenceClientProvide
|
||||
|
||||
`InMemoryLogSink` maintains a 500-entry circular `ConcurrentQueue`. All .NET logs flow through `InMemoryLoggerProvider` → sink → `OnLog` event → TUI Logs tab live view.
|
||||
|
||||
### TUI Keyboard Input
|
||||
|
||||
`GlobalKeyboardService` (`TUI/GlobalKeyboardService.cs`) is the **single source of keyboard events** for the entire TUI. It runs a dedicated background thread with a blocking `Console.ReadKey(intercept: true)` — no polling. `App.razor` subscribes to `OnKeyPressed`, converts `ConsoleKeyInfo` to `KeyboardEventArgs`, and dispatches via `InvokeAsync`.
|
||||
|
||||
Do **not** use `@onkeydown` on `<Select>` or other RazorConsole components for navigation logic — the framework intercepts Tab and arrow keys internally before they reach component-level callbacks. See `docs/tui_log.md` for the full breakdown.
|
||||
|
||||
### TUI Navigation
|
||||
|
||||
Tabs: Overview → Logs → Settings (switch with `Tab`/`Shift+Tab`). In Settings: arrow keys navigate the module→tool tree, `Space` toggles enable/disable, `Enter` expands/collapses. In Overview, `Enter` on a module jumps to its Settings entry.
|
||||
@@ -60,6 +66,9 @@ Tabs: Overview → Logs → Settings (switch with `Tab`/`Shift+Tab`). In Setting
|
||||
- **K8s kubeconfig fallback order:** explicit `Kubernetes:KubeconfigPath` → `~/.kube/config` → in-cluster config
|
||||
- **Source of truth:** `Program.cs`, not `README.md` (README is aspirational)
|
||||
- `Pages/` directory exists but Razor Pages are **not enabled** in `Program.cs` — do not use them
|
||||
- **RazorConsole keyboard gotchas:** `@onkeydown` on interactive components doesn't propagate Tab/arrows; `FocusManager` intercepts Tab globally; there is no public global key-intercept API. Full notes: `docs/tui_log.md`
|
||||
- **`GlobalKeyboardService` registration pattern** — registered as both singleton and hosted service so it can be injected into Razor components: `services.AddSingleton<T>()` + `services.AddHostedService(sp => sp.GetRequiredService<T>())`
|
||||
- **`Console.KeyAvailable` polling causes rendering lag** — it acquires the console mutex on every call and competes with RazorConsole's renderer. Always use blocking `Console.ReadKey` in a dedicated thread instead
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
|
||||
Reference in New Issue
Block a user