diff --git a/docs/navi_code_cli.md b/docs/navi_code_cli.md index 15336f6..a5ade75 100644 --- a/docs/navi_code_cli.md +++ b/docs/navi_code_cli.md @@ -41,6 +41,7 @@ | `--ws-url URL` | URL WebSocket (по умолчанию производный от `--base-url`). | | `--profile-id ID` | Профиль для новой сессии. | | `--new-session` | Создать новую сессию, даже если сохранена старая. | +| `--resume ` | Возобновить конкретную сессию по id (взаимоисключающе с `--new-session`). | | `--show-thinking` | Показывать блоки рассуждений модели. | | `--no-events` | Скрывать события `tool_started` / `tool_call`. | | `--mouse` / `--no-mouse` | Включить/выключить мышь в TUI на один запуск (перекрывает `tui.json`). | @@ -51,60 +52,98 @@ Любой позиционный аргумент воспринимается как запрос и запускает plain CLI в one-shot режиме (например `navi-code "объясни этот файл"`). Неизвестные флаги передаются как часть запроса. +При закрытии TUI печатается подсказка вида `Resume with: navi-code --resume ` — чтобы продолжить ту же сессию в следующий раз. + ## Команды в интерактивном режиме -| Команда | Описание | -|---|---| -| `/help` | Список команд. | -| `/new` | Создать новую сессию. | -| `/sessions` | Список сессий на сервере. | -| `/switch ` | Переключиться на другую сессию (можно по префиксу id). | -| `/profile` | Показать текущий профиль и id сессии. | -| `/export [path]` | Экспортировать текущую сессию в Markdown; без пути — во временный файл и `$EDITOR`. Если редактор не запускается, ошибка выводится в чат. | -| `/themes` | Открыть выбор темы с live-preview. | -| `/mouse on|off` | Включить/выключить поддержку мыши (требует перезапуска). | -| `/thinking` | Переключить отображение thinking-блоков в текущей сессии. | -| `/compact` | Вручную запустить сжатие контекста текущей сессии. | -| `/clear` | Очистить локально сохранённый `session_id`. -| `/quit` | Выйти. | +| Команда | Алиасы | Описание | +|---|---|---| +| `/help` | | Список команд. | +| `/new` | `clear` | Создать новую сессию (в TUI `clear` — алиас `new`, а не очистка локального state). | +| `/sessions` | `resume`, `continue` | Открыть picker сессий, отфильтрованный по профилю `navi_code`, с кнопкой «✚ New session» и поиском по типу. | +| `/switch [id]` | | Гибридный режим: без аргумента / неоднозначный префикс → picker, префильтрованный по вводу; точный id или уникальный префикс `navi_code` → мгновенное переключение. | +| `/profile` | | Показать текущий профиль и id сессии. | +| `/export [path]` | `save` | Экспортировать текущую сессию в Markdown; без пути — во временный файл и `$EDITOR`. | +| `/themes` | | Открыть выбор темы с live-preview. | +| `/mouse on\|off` | | Включить/выключить поддержку мыши (требует перезапуска). | +| `/thinking` | | Переключить отображение thinking-блоков в текущей сессии. | +| `/compact` | | Вручную запустить сжатие контекста текущей сессии (шлёт `{"type":"compact"}`). | +| `/quit` | `exit`, `q` | Выйти. | + +Подсказки к slash-командам появляются inline над полем ввода при вводе `/`: `Up`/`Down` подсвечивают вариант, `Enter` выполняет подсвеченный, `Tab` дополняет имя. ## Интерфейс TUI -В интерактивном режиме (`navi-code`) экран разделён на три зоны: +В интерактивном режиме (`navi-code`) экран состоит из пяти регионов: -- **Левая панель (`ChatPanel`)** — история сообщений, поле ввода и текущий статус. -- **Правая верхняя панель (`StatusPanel`)** — текущий профиль, модель, статус соединения, токены и оставшиеся итерации. -- **Правая нижняя панель (`SessionsPanel`)** — список сессий на сервере с колонками ID, профиль и превью. Клик или `Enter` на строке переключает сессию. +- **`ChatPanel`** (левая колонка) — история сообщений и карточки событий. +- **Правая колонка** `Vertical(StatusPanel, TodoPanel)`: + - **`StatusPanel`** — профиль, сессия, текущая модель, статус соединения, backend, тема, hotkey-подсказки. + - **`TodoPanel`** — живой список todo текущей сессии: `in_progress` наверху, затем `pending`, потом `failed`/`skipped`, `done` внизу. Todo субагентов сюда не попадают (они изолированы). Обновляется по событию `todo_updated`, при подключении подтягивается через REST. +- **`InputBox`** (под чатом) — многострочное поле ввода. +- **`StatusBar`** (нижняя строка, заменяет стандартный Textual Footer) — activity-индикатор (анимированный braille-спиннер + фаза), live-таймер длительности запроса, gauge заполнения контекстного окна (`used/max · pct%`, цвет по уровню), hotkey-комбинации. -Список сессий обновляется автоматически при запуске и при выполнении `/new`, `/sessions`, `/switch`. +Sessions-панели в правой колонке больше нет — переключение сессий через модальный **picker** (`/sessions`, `/switch`). ### Поле ввода -Поле ввода многострочное — перенос текста по ширине автоматический, высота поля растёт вместе с содержимым (в пределах ограничения). `Enter` отправляет сообщение целиком (вместе с переносами). Принудительный перенос строки не поддерживается: терминалы не различают `Ctrl+Enter` от обычного `Enter`, поэтому сделан только автоматический перенос. +Поле ввода многострочное — перенос текста по ширине автоматический, высота поля растёт вместе с содержимым. `Enter` отправляет сообщение целиком. Префикс `!` выполняет локальную shell-команду (passthrough, не уходит на сервер). `@путь` раскрывает ссылку на файл и прикрепляет его к сообщению. + +### Рендеринг чата + +- **Per-message виджеты.** Каждое сообщение — отдельный виджет; при стриминге перерисовывается только активный пузырь, а не весь список. +- **Markdown.** Ответы Navi рендерятся как themed markdown с подсветкой кода, прямо во время стриминга. +- **Ограничение стоимости рендера.** Видимых элементов ограничено (`max_visible_items`); более старые сворачиваются в подсказку «… N earlier messages not shown». Рендер кэшируется по сигнатуре. +- **История при resume.** При возобновлении/переключении сессии история сообщений подгружается в чат через REST. +- **Auto-reconnect.** При обрыве WebSocket переподключается с экспоненциальным backoff (1с→30с); отправленные во время обрыва сообщения переотправляются, в `StatusPanel` показывается «reconnecting…». ### Карточки в чате -Помимо обычных сообщений и блоков рассуждений, чат рендерит карточки для специальных событий: +- **Планирование.** Пока работает планировщик — rolling-индикатор `⚙ Planning · <фаза>` (обновляется на месте). Когда план готов — карточка `Plan`. +- **Субагент (`spawn_agent`).** Карточка `↘ subagent · <профиль>` при запуске и `↙ subagent · <профиль> ✓/✗` с результатом; задача и брифинг — в теле. +- **Вложенные события субагента.** Рассуждения, планирование, карточки инструментов и todo субагента — с отступом и приглушённым стилем (плоская модель, вложенность через отступ). +- **Compression summary.** При сжатии контекста (авто или `/compact`) — карточка `Context compressed: N → M messages` с dim markdown-текстом саммари внутри. +- **Метаданные хода.** На `stream_end` — строка `⏱ …` с длительностью запроса и gauge заполнения контекста. -- **Планирование.** Пока работает планировщик, показывается rolling-индикатор `⚙ Planning · <фаза>` (обновляется на месте, а не плодит строки). Когда план готов — карточка `Plan` с содержимым плана. -- **Субагент (`spawn_agent`).** Отдельная карточка `↘ subagent · <профиль>` при запуске и `↙ subagent · <профиль> ✓/✗` с результатом. Имя задачи и брифинг показаны в теле карточки. -- **Вложенные события субагента.** Рассуждения, планирование, карточки инструментов и плана субагента показываются с отступом и приглушённым стилем, чтобы визуально отделить их от основного хода сессии (TUI использует плоскую модель, вложенность передаётся через отступ). +### Диалоги и палитра + +- **Command palette** (`Ctrl+P`) — поиск команд по имени. +- **Permission dialog** — запрос подтверждения на запуск инструмента: allow once/always, deny once/always. +- **Sessions picker** — модальный выбор сессии. +- **Theme picker** — выбор темы с live-preview. + +### Hotkeys + +| Комбинация | Действие | +|---|---| +| `Ctrl+P` | Command palette | +| `Ctrl+X C` | `/compact` (сжатие контекста) | +| `Ctrl+X T` | `/thinking` (toggle thinking-блоков) | +| `Ctrl+X Q` | `/quit` | +| `Esc` | Остановить стрим | ## Состояние -Клиент сохраняет `session_id` в `~/.navi_code/state.json`, чтобы восстановить диалог при следующем запуске. Удалите файл или используйте `/clear`, чтобы начать с чистого листа. +Клиент сохраняет `session_id` в `~/.navi_code/state.json`, чтобы восстановить диалог при следующем запуске. Удалите файл или используйте `--new-session`, чтобы начать с чистого листа. TUI-настройки (тема, мышь, `max_visible_items`) хранятся в `~/.navi_code/tui.json`. ## Рендеринг событий События WebSocket рендерятся по-разному в TUI и в plain CLI (`--raw`): +- `stream_start` — запускает activity-индикатор и live-таймер. - `stream_delta` — печатается inline, как в обычном чате. -- `tool_started` / `tool_call` — карточки инструментов: имя, аргументы, краткий результат (если включено `--show-events` / `--no-events` не задан). -- `thinking_delta` / `thinking_end` — блоки рассуждений, показываются только с `--show-thinking`. -- `planning_status` — индикатор текущей фазы планирования (в TUI — rolling-строка `⚙ Planning · <фаза>`; в plain CLI — `[planning] <фаза>`). -- `plan_ready` — готовый план (в TUI — карточка `Plan`; в plain CLI — блок `[plan]…[/plan]`). -- `turn_thinking` — полный блок рассуждений субагента целиком (не стримится по частям); в TUI это `subagent thinking` с отступом, в plain CLI — `[thinking]…(subagent)`. +- `stream_end` — метаданные хода (`⏱` длительность + gauge контекста). +- `stream_stopped` — отметка об остановке пользователем. +- `tool_started` / `tool_call` — карточки инструментов: имя, аргументы, краткий результат (если не задан `--no-events`). В `metadata.step_text` для todo-update передаётся текст изменённого шага. +- `thinking_delta` / `thinking_end` / `turn_thinking` — блоки рассуждений (только с `--show-thinking`); `turn_thinking` — полный блок субагента целиком. +- `planning_status` — rolling-строка фазы (в plain CLI — `[planning] <фаза>`). +- `plan_ready` — карточка `Plan` (в plain CLI — `[plan]…[/plan]`). +- `model_info` — обновляет модель в `StatusPanel`. +- `todo_updated` — обновляет `TodoPanel`. +- `compression_started` — activity-фаза «compression». +- `context_compressed` — карточка `Context compressed: N → M messages` с саммари. - `error` — красным цветом. +- `heartbeat` / `session_sync` — служебные, в чат не выводятся. ## Пример сессии @@ -120,22 +159,28 @@ Я насчитал 42 файла в текущей директории и её поддиректориях. You: /quit +Resume with: navi-code --resume a1b2c3d4 ``` ## Разработка Код CLI находится в `clients/terminal/`: -- `cli.py` — точка входа и интерактивный цикл. -- `ws_client.py` — WebSocket-клиент. +- `cli.py` — точка входа, разбор аргументов, raw-режим, resume-hint. +- `ws_client.py` — низкоуровневый WebSocket-клиент. - `api.py` — REST-запросы к серверу. -- `render.py` — рендеринг событий в терминал. +- `render.py` — рендеринг событий в терминал (plain CLI). - `state.py` — сохранение `session_id` в `~/.navi_code/state.json`. - `config.py` — настройки из переменных окружения `NAVI_CODE_*`. -- `tui/tui_app.py` — Textual-приложение. -- `tui/widgets/` — виджеты (`ChatPanel`, `StatusPanel`, `SessionsPanel`, `InputBox`). -- `tui/renderers/` — рендереры карточек по типам событий (сообщения, рассуждения, инструменты, планирование, субагент); диспетчеризация через `RendererRegistry`. -- `tui/commands/` — slash-команды (`/new`, `/sessions`, `/switch`, `/export`, `/themes`, `/mouse`). +- `tui/tui_app.py` — Textual-приложение, bindings, диспетчер событий. +- `tui/ws_bridge.py` — владеет жизненным циклом WebSocket в TUI (включая auto-reconnect). +- `tui/chat_model.py` — модель чат-айтемов и преобразование WS-событий. +- `tui/widgets/` — `ChatPanel`, `InputBox`, `CommandHints`, `StatusBar`, `StatusPanel`, `TodoList` (+ `ActivityIndicator`, `ElapsedTime`). +- `tui/renderers/` — рендереры карточек по типам событий (сообщения, markdown, рассуждения, инструменты, планирование, субагент, todo, summary, turn_meta, diff, artifact, error); диспетчеризация через `RendererRegistry`. +- `tui/commands/` — slash-команды (`builtin.py`: `/help`, `/new`, `/sessions`, `/switch`, `/profile`, `/export`, `/themes`, `/mouse`, `/thinking`, `/compact`, `/quit`). +- `tui/screens/` — модальные экраны: `command_palette`, `sessions_picker`, `theme_picker`, `permission_dialog`. +- `tui/permissions.py`, `tui/shell_runner.py`, `tui/file_refs.py`, `tui/duration.py`, `tui/context.py`, `tui/events.py` — диалоги разрешений, `!`shell, `@`file-refs, таймеры, контекст, вспомогательные события. - `tui/settings.py` — persisted TUI config (`~/.navi_code/tui.json`). +- `tui/themes.py` — палитры тем. Тесты: `tests/clients/test_terminal_client.py`, `tests/clients/test_terminal_ws.py`, `tests/clients/test_tui_*.py`.