Цель: превратить navi-code из простого click-CLI в полноэкранный терминальный UI, вдохновлённый OpenCode, сохранив click-CLI как navi-code --raw.
ws_client.py, api.py, config.py, state.py.┌─────────────────────────────────────────────────────────────┐
│ NaviCodeApp (Textual) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ ChatPanel │ │ StatusPanel │ │ SessionsPanel │ │
│ │ (messages) │ │ (profile, │ │ (optional/right)│ │
│ │ │ │ model, │ │ │ │
│ │ │ │ connection) │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ InputBox (prompt frame, slash commands, @/! parsing) │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ EventBus / Dispatcher │
│ - WebSocket events → ChatPanel/StatusPanel │
│ - User input → CommandParser → execute command/send message │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Shared services │
│ - NaviWebSocketClient │
│ - api (REST wrappers) │
│ - StateManager (~/.navi_code/state.json) │
│ - Settings │
└─────────────────────────────────────────────────────────────┘
textual>=0.70 в pyproject.toml.clients/terminal/tui_app.py с базовым App:
ChatPanel — ScrollableContainer + RichLog для сообщений.StatusPanel — Static/Label с профилем, сессией, моделью, статусом.InputBox — кастомный виджет ввода с рамкой в стиле OpenCode.navi-code по умолчанию запускает TUI; navi-code --raw — старый click-CLI.NaviWebSocketClient с Textual event loop через asyncio.create_task + call_from_thread/post_message.stream_delta, thinking_delta/thinking_end, tool_started/tool_call, error, stream_end.TuiRenderer, который превращает WebSocket-события в Rich renderables./help, /new, /sessions, /switch, /profile, /thinking, /compact, /quit, /models.Ctrl+P, поиск по командам и настройкам.@ file references: fuzzy autocomplete файлов в CWD при вводе @.! shell pre-command: если сообщение начинается с !, выполнить shell и подставить вывод.rm, overwrite, format), кнопки Allow once / Allow always / Reject.rich.markdown + rich.syntax в ChatPanel.ContentRenderer registry — code, diff, plain, image mention./themes + ~/.navi_code/tui.json с theme, keybinds, diff_style, mouse, scroll_speed./export сохраняет текущий чат в markdown и открывает $EDITOR.Command registry (clients/terminal/commands/registry.py)
name, aliases, description, keybind, async execute(ctx).@register_command.Content renderers (clients/terminal/renderers/)
BaseRenderer → CodeRenderer, DiffRenderer, MarkdownRenderer, ToolCallRenderer, ErrorRenderer.RendererRegistry выбирает по type/mime.Themes (clients/terminal/themes/)
Theme dataclass: цвета рамок, фона, акцента, статуса, ошибок, thinking.ThemeRegistry с built-in темами и загрузкой из tui.json.Event bus (clients/terminal/events.py)
post_message, но с типизированными событиями WsEvent, CommandEvent, PermissionEvent.Permission engine (clients/terminal/permissions.py)
PermissionStore хранит allow_always в ~/.navi_code/permissions.json.cli.py остаётся, получает флаг --raw.tui_app.py импортирует Settings, StateManager, api, NaviWebSocketClient.render.py остаётся для --raw; TUI использует новые renderers поверх Rich.tests/clients/test_tui_app.py — монтирование App, проверка layout.tests/clients/test_tui_commands.py — unit tests командного парсера и registry.tests/clients/test_tui_renderers.py — рендеринг разных типов контента.tests/clients/test_tui_permissions.py — permission prompt и allow_always.navi-code --help и navi-code --version работают в обоих режимах.navi-code запускается в полноэкранном TUI.navi-code --raw.docs/navi_code_cli.md обновлена с TUI-режимом.