Forge
markdowndeeb25a2
1# ADR 0119: Слэш-команды в чате — unified command line (Intercom + IDE)
2
3**Статус:** Accepted · Implemented
4**Дата:** 2026-05-17
5**Обновлено:** 2026-05-17 — расширение до IDE-глаголов (`/build run`, `/test run`, `/debug launch`); autocomplete обязателен. [§ История](#adr0119-history)
6
7## Связанные ADR
8
9| ADR | Роль |
10|-----|------|
11| [0080](0080-intercom-naming-and-multi-party-channel-model.md) | Чат как **Intercom** — центральный канал, не «окно к боту» |
12| [0072](0072-chat-topic-cards-intent-melody-keyboard-contract.md) | Topic cards, overview/detail, **intent-first** навигация (Melody/Chords) |
13| [0096](0096-intercom-topic-card-summary-and-product-spine.md) | Содержимое карточек, spine, carry-forward в тред |
14| [0013](0013-command-surface-and-discoverability.md) | Палитра и discoverability — слэши **дополняют**, не заменяют |
15| [0030](0030-command-ids-hotkeys-and-ui-registry-layers.md) | Канон `command_id`, реестр, паритет MCP |
16| [0060](0060-keyboard-chord-stack-fms-tactical-strategic.md) | CascadeChord, Command Melody `c:` — **ортогональный** вход |
17| [0008](0008-mcp-contracts-and-testable-infrastructure.md) | Паритет агента: те же эффекты через `ide_execute_command` |
18| [0048](0048-cursor-acp-chat-ide-parity-and-mcp-tool-surface.md) | Что уходит агенту vs локальное действие IDE |
19| [0057](0057-chat-surface-pipeline-adoption.md) | Snapshot/layout после смены состояния VM |
20| [0116](0116-intercom-session-tree-and-agent-message-steering.md) | Дерево сессии, steer — не смешивать со слэш-парсером |
21| [0002](0002-debug-human-agent-parity.md) | `/build`, `/test`, `/debug` — те же `command_id`, что агент через MCP |
22| [0018](0018-ide-commands-canonical-xml-documentation.md) | Канон имён `IdeCommands` для проекции каталога |
23| [0120](0120-primary-work-surface-intercom-or-editor.md) | Intercom в Forward — слэши как основной CLI сессии |
24| [0124](0124-slash-parametric-editor-line-commands.md) | Параметрический слэш: `/editor line select|delete` (паритет `c:els` / `c:eld`) |
25| [0125](0125-slash-workspace-file-commands-and-dynamic-completion.md) | Workspace/file: `/file open`, `/solution new`, динамические подсказки по файлам solution |
26| [0126](0126-intercom-inspect-slash-and-compact-chrome-status.md) | `kind=report`: `/topic`/`/spine` list\|tree; compact chrome status |
27| [0136](0136-intercom-feed-gutter-and-slash-namespace.md) | Канон `/intercom …`; top-level `/topic` — non-goal |
28| [0150](0150-slash-line-canonical-resolution.md) | `SlashLineResolver`, `arg_tail`; autocomplete · Enter · execute |
29| [0153](0153-slash-catalog-only-resolution.md) | **Исполнение пути:** только `intent-catalog` + codegen trie; без parser shape |
30
31### Вне ADR
32
33| Документ | Роль |
34|----------|------|
35| [MCP-PROTOCOL.md](../MCP-PROTOCOL.md) | `ide_execute_command`, `send_chat`, chat_* MCP |
36| [intent-melody-language-v1.md](../intent-melody-language-v1.md) | Грамматика `c:` — **не** грамматика `/` в чате |
37| [intercom-ux-reference-slack-mattermost-v1.md](../design/intercom-ux-reference-slack-mattermost-v1.md) | Slack/MM как вдохновение для composer и слэшей; границы vs внешний чат [0080 §5](0080-intercom-naming-and-multi-party-channel-model.md#adr0080-p5) |
38
39## Резюме
40
41- **`ChatInput`** — **альтернативная command line** IDE: можно **не уходить из чата** для Intercom *и* для частых действий (`/build run`, `/test run`, `/debug launch`, `/card …`).
42- Слэш → **`command_id`** ([0030](0030-command-ids-hotkeys-and-ui-registry-layers.md)); каталог — **проекция** реестра на **читаемые** slash-пути (`/build run`, `/overview`), не второй исполнитель в VM.
43- **Discoverability — через autocomplete** (иерархия namespace → action, подсказки, `/help`), **не** через короткие мнемоники вроде `/br` (сжатые формы — слой **`c:`** Melody и аккорды, [0060](0060-keyboard-chord-stack-fms-tactical-strategic.md)).
44- **Autocomplete обязателен** — без него расширенный каталог не принимается.
45- Палитра, Melody `c:` и аккорды остаются; слэш — **равноправный вход** для тех, кто уже в поле сообщения ([0013](0013-command-surface-and-discoverability.md)).
46- Внедрение **по фазам**: Intercom-глаголы → IDE namespaces → расширение из палитры.
47
48---
49
50## Контекст
51
52Intercom в CIDE ([0080](0080-intercom-naming-and-multi-party-channel-model.md)) всё чаще — **центральная поверхность**: диалог с агентом, картотека тем ([0072](0072-chat-topic-cards-intent-melody-keyboard-contract.md)), product spine ([0096](0096-intercom-topic-card-summary-and-product-spine.md)), уточнения ([0031](0031-agent-chat-clarification-batches-and-threading.md)).
53
54Для power-user уже есть:
55
56- **палитра** и fuzzy-поиск ([0013](0013-command-surface-and-discoverability.md));
57- **глобальные хоткеи** и **CascadeChord** ([0060](0060-keyboard-chord-stack-fms-tactical-strategic.md));
58- **Command Melody** `c:` в палитре ([0112](0112-command-palette-query-modes-strategy.md));
59- **chat navigation intents** с паритетом в MCP (`chat_show_thread_overview`, `chat_open_selected_thread`, … — [0072 §4](0072-chat-topic-cards-intent-melody-keyboard-contract.md)).
60
61Этого **недостаточно**, когда оператор **уже печатает в поле сообщения** и ожидает модель «как в Slack/Discord» или **CLI внутри чата**:
62
63- Intercom: `/card Новая тема`, `/overview`, `/spine focus=…`;
64- IDE: `/build run`, `/test run`, `/debug launch` — **без** переключения на палитру, тулбар и без обязательных аккордов.
65
66Продуктовая гипотеза: если Intercom — **центральная поверхность**, чат становится **единой точкой управления сессией**, а не только каналом к агенту.
67
68---
69
70## Проблема
71
721. **Разрыв discoverability:** команды чата есть в реестре и MCP, но **не видны** в контексте ввода, где живёт основной поток мысли.
732. **Риск дублирования:** ad-hoc парсинг `/card` в `SendChatAsync` обходит intent-слой [0072 §5](0072-chat-topic-cards-intent-melody-keyboard-contract.md) и плодит расхождение с pointer/MCP.
743. **Смешение с агентом:** без правила «слэш = локально» строка `/export` может уехать в LLM как обычный текст.
754. **Конфликт префиксов:** `c:` зарезервирован за палитрой/Melody ([0112](0112-command-palette-query-modes-strategy.md)); **`/`** — отдельное пространство **только в ChatInput**.
76
77---
78
79## Решение
80
81<a id="adr0119-p1"></a>
82
83### 1. ChatInput как **unified command line** (слэш-префикс)
84
85- Строка, начинающаяся с **`/`** (после trim), трактуется как **слэш-команда** (одно- или двухуровневая, см. [§4](#adr0119-p4)).
86- Разбор **при отправке** (Enter) и **инкрементально** для autocomplete ([§6](#adr0119-p6)) — autocomplete **не опционален** для принятого объёма каталога.
87- **Не** перехватывать `/` в середине обычного сообщения; обычный диалог с агентом — **без** слэша.
88
89<a id="adr0119-p2"></a>
90
91### 2. Intent-first: слэш → `command_id` → VM → snapshot
92
93**Инвариант** (расширение [0072 §5](0072-chat-topic-cards-intent-melody-keyboard-contract.md)):
94
95```text
96ChatInput (/path …args)
97 → SlashLineResolver (longest-prefix по intent-catalog, ADR 0150/0153)
98 → ChatSlashCommandCatalog → descriptor (command_id, handlers, arg_tail)
99 → ChatSlashCommandRunner / Intercom local handlers / IdeMcpCommandExecutor
100 → ChatPanelViewModel state → ChatSurfaceCompositor → Skia render
101```
102
103*(Историческая схема v1: `ChatSlashCommandParser.TryParse` → `head`/`action` — снята, [0153](0153-slash-catalog-only-resolution.md).)*
104
105- Слэш-команда **не** меняет Skia напрямую и **не** читает hit-target геометрию.
106- Pointer, Melody, Chords, палитра, MCP и слэш **сходятся** в одном `command_id`, где это возможно.
107
108<a id="adr0119-p3"></a>
109
110### 3. Режимы исполнения
111
112| Режим | Поведение | Пример |
113|-------|-----------|--------|
114| **Local** | Сообщение **не** уходит агенту; выполняется `command_id`; поле ввода очищается (или остаётся статус одной строкой). | `/overview`, `/export` |
115| **Local + echo** | Локально + короткая системная запись в ленте (опционально, v1+). | `/card` с подтверждением «создана тема …» |
116| **Reject** | Неизвестный verb — ошибка в UI, **без** отправки агенту. | `/foo` |
117| **Pass-through** *(запрещено по умолчанию)* | Отправить текст агенту как есть. | **Не** использовать для нераспознанных `/` |
118
119**Правило v1:** нераспознанная строка с ведущим `/` → **Reject** с подсказкой «неизвестная команда, Tab — список».
120
121<a id="adr0119-p4"></a>
122
123### 4. Грамматика v1
124
125**Два уровня** (как «namespace / action»):
126
127```ebnf
128slash_line = "/" head (WS tail)? WS? ;
129head = flat_verb | namespace ;
130flat_verb = letter { letter | digit | "-" } ; (* overview, card, help, export *)
131namespace = letter { letter | digit } ; (* build, test, debug, git, chat *)
132tail = action (WS arg_token)* | arg_tail ; (* run | launch | … OR rest for flat *)
133action = letter { letter | digit | "-" } ;
134arg_tail = { arg_token } ; (* /card Имя темы — всё после head *)
135arg_token = quoted_string | bare_token ;
136```
137
138**Примеры:**
139
140| Ввод | Разбор |
141|------|--------|
142| `/overview` | flat: `overview` |
143| `/card ADR 0119` | flat: `card`, args: `ADR 0119` |
144| `/build run` | namespace: `build`, action: `run` |
145| `/test run` | namespace: `test`, action: `run` |
146| `/debug launch` | namespace: `debug`, action: `launch` |
147| `/editor line select 5 10` | namespace: `editor`, action: `line`, subAction: `select`, args: `5 10` — [0124](0124-slash-parametric-editor-line-commands.md) |
148
149- **Регистр:** case-insensitive.
150- **Три уровня** (`/editor line select`) — исключение для параметрического редактора; не общий прецедент для всех namespace ([0124](0124-slash-parametric-editor-line-commands.md)).
151- **Именованные аргументы** (`configuration=Release`) — v2; v1 — позиционный хвост где нужен.
152
153<a id="adr0119-p5"></a>
154
155### 5. Каталог: проекция на `command_id`, не второй реестр
156
157<a id="adr0119-p5a"></a>
158
159#### 5a. Источник правды
160
161- **Исполнение** — только через существующий контур `ide_execute_command` / `IdeMcpCommandExecutor` ([0030](0030-command-ids-hotkeys-and-ui-registry-layers.md), [0008](0008-mcp-contracts-and-testable-infrastructure.md)).
162- **Каталог слэшей** (`ChatSlashCommandCatalog`) — **отображение** (slash-путь → `command_id` + шаблон args), собираемое из:
163 1. **Curated** таблицы в коде (v1);
164 2. v2+ — **проекция** подмножества `IdeCommandPaletteCatalog` / метаданных `IdeCommands` (заголовок палитры → не обязан совпадать со слэшем; slash-путь задаётся явно).
165- **Не путать** с Melody: в каталоге **нет** отдельных записей «2–3 буквы» (`/br`, `/tr`) как сокращений к `namespace action` — оператор выбирает **`/build` → `run`** из autocomplete или вводит полную форму.
166- **Запрещено:** дублировать логику `dotnet build` / тестов / отладки в `ChatPanelViewModel`.
167
168<a id="adr0119-p5b"></a>
169
170#### 5b. Intercom (flat verbs) — фаза A
171
172| Слэш | `command_id` | Примечание |
173|------|----------------|------------|
174| `/overview` | `chat_show_thread_overview` | |
175| `/open` | `chat_open_selected_thread` | |
176| `/card <title>` | *новый* или `fork_chat_thread` + title | продуктово |
177| `/spine …` | `chat_set_product_spine` | хвост → focus / milestones |
178| `/spine-toggle` | `chat_toggle_product_spine_in_agent_context` | |
179| `/export` | `chat_export_readable` | |
180| `/help` | локальный каталог | `kind=help`, без MCP |
181| `/topic list` \| `/topic tree` | локальный отчёт | `kind=report`, [0126](0126-intercom-inspect-slash-and-compact-chrome-status.md) |
182| `/topic open` | открыть detail темы | `kind=intercom`, [0126](0126-intercom-inspect-slash-and-compact-chrome-status.md) |
183| `/spine list` \| `/spine tree` | локальный отчёт | `kind=report`, [0126](0126-intercom-inspect-slash-and-compact-chrome-status.md) |
184| `/topic cards` | картотека тем (overview) | `kind=intercom`, [0126](0126-intercom-inspect-slash-and-compact-chrome-status.md) |
185| `/spine open` | то же, что `/topic cards` | `kind=intercom`, [0126](0126-intercom-inspect-slash-and-compact-chrome-status.md) |
186
187<a id="adr0119-p5c"></a>
188
189#### 5c. IDE namespaces — фаза B (не уходя из чата)
190
191| Слэш | `command_id` | Примечание |
192|------|----------------|------------|
193| `/build run` | `build` или `build_structured` | structured JSON в ленту/панель — политика UI |
194| `/build ui` | `build_solution_ui` | тулбарный путь, текст в output |
195| `/test run` | `run_tests` | |
196| `/test affected` | `run_affected_tests` | опционально `changed_paths` из git |
197| `/debug launch` | `debug_launch` | target из launch profile / текущий |
198| `/debug continue` | *debug_start_or_continue* (UI id) | если нет в `IdeCommands` — добавить константу |
199| `/git status` | `git_status` | фаза C, когда есть в реестре |
200
201Дальнейшие namespace (`nav`, `index`, `palette`) — **по мере discoverability**, не «весь IdeCommands одним махом».
202
203**Паритет:** агент вызывает тот же `build` / `run_tests` / `debug_launch` через MCP; оператор — `/build run` в чате.
204
205<a id="adr0119-p6"></a>
206
207### 6. Discoverability: autocomplete и help (обязательно)
208
209Без autocomplete расширение до `/build`, `/test`, … **не принимается** — оператор **не обязан** помнить namespace и action и **не должен** полагаться на сжатые слэш-мнемоники (в отличие от `c:` в палитре).
210
211**Поведение UI (v1 минимум):**
212
213| Шаг ввода | Popup показывает |
214|-----------|------------------|
215| `/` | top-level: flat verbs + namespaces (`build`, `test`, `debug`, `card`, …) |
216| `/build ` | actions: `run`, `ui`, … + однострочное описание |
217| `/build r` | фильтр по префиксу (`run`) |
218| неизвестный префикс | «нет совпадений» + ссылка на `/help` |
219
220- **`Tab`** — дополнить токен / выбрать highlighted; **↑↓** — навигация; **Esc** — закрыть popup, не очищая строку.
221- Под каждым пунктом — **краткий help** (из `IdeCommands` doc / curated catalog) и опционально **hotkey** из TOML, если есть ([0030](0030-command-ids-hotkeys-and-ui-registry-layers.md)).
222- **`/help`** и **`/help build`** — текстовый/интерактивный список в ленте или overlay (local).
223- Источник v1: `ChatSlashCommandCatalog` в коде; v2 — TOML `chat-slash-aliases.toml` по аналогии [0109](0109-declarative-parametric-melody-catalog-toml-and-code-binders.md).
224
225<a id="adr0119-p7"></a>
226
227### 7. Связь с агентом и spine ([0096](0096-intercom-topic-card-summary-and-product-spine.md))
228
229- Слэш-команды **по умолчанию local** — **не** расширяют промпт агента.
230- `/spine-toggle` и `/spine` меняют метаданные сессии; включение spine в контекст агента — **явное** ([0096 §4](0096-intercom-topic-card-summary-and-product-spine.md#adr0096-p4)), не побочный эффект любой слэш-команды.
231- **Carry-forward** в тред по-прежнему **обычным сообщением** или отдельным intent; слэш **не обязан** генерировать текст для агента.
232
233<a id="adr0119-p8"></a>
234
235### 8. Non-goals и границы
236
237**Non-goals:**
238
239- **Полная замена** Command Palette: fuzzy-поиск по *всем* командам без структуры namespace остаётся в палитре.
240- Автоматическое **1:1** «каждая строка палитры = слэш» без curated aliases и UX-фильтра (слишком шумно).
241- Слэш-команды в **других** полях (терминал, редактор, палитра) — только `ChatInput`.
242- Плагины с произвольными verb **без** записи в каталог / `command_id`.
243- Pass-through нераспознанного `/…` агенту.
244- **Короткие слэш-алиасы** (2–3 символа, «мелодия после `/»): `/br` вместо `/build run`, автогенерация из [0109](0109-declarative-parametric-melody-catalog-toml-and-code-binders.md) без отдельного slash-пути — discoverability только **иерархический autocomplete** и читаемые `namespace` / `action` / flat verbs.
245
246**В scope (осознанно):**
247
248- **Альтернативный вход** в те же IDE-действия, что палитра/аккорды/MCP — в т.ч. `/build run`, `/test run`, `/debug launch`.
249- Оператор **может не уходить из чата** для частого цикла «спросил агента → собрал → прогнал тесты → отладил».
250
251---
252
253## Ортогональность входов (сводка)
254
255| Вход | Где | Префикс / форма |
256|------|-----|-----------------|
257| Палитра | overlay | fuzzy, `c:` Melody |
258| Hotkeys / Chord | глобально | TOML → `command_id` |
259| Chat Melody aliases | палитра / intents | `ato`, `atb`, … ([0072](0072-chat-topic-cards-intent-melody-keyboard-contract.md)) |
260| **Chat slash** | `ChatInput` | `/verb` или `/namespace action` (**этот ADR**) |
261| MCP | агент | `ide_execute_command` |
262
263---
264
265## Диаграмма
266
267```mermaid
268flowchart TD
269 input[ChatInput]
270 input -->|starts with /| resolver[SlashLineResolver]
271 input -->|normal text| agent[SendToAgent]
272 resolver --> catalog[ChatSlashCommandCatalog]
273 catalog -->|known path| cmd[command_id / intercom handler]
274 catalog -->|unknown| err[Inline error + help]
275 cmd --> vm[ChatPanelViewModel]
276 vm --> snap[ChatSurfaceSnapshot]
277 snap --> skia[SkiaChatSurfaceControl]
278 palette[Palette Melody Chords MCP] --> cmd
279```
280
281---
282
283## Якоря реализации (план)
284
285| Компонент | Роль |
286|-----------|------|
287| `IntentMelody/intent-catalog.toml` | Канон slash `path`, `arg_tail`, handlers ([0153](0153-slash-catalog-only-resolution.md)) |
288| `Services/Generated/SlashRouteCatalogPathsGenerated.g.cs` | Codegen trie (build, ProtocolDocGen) |
289| `Features/Chat/SlashLineResolver.cs` | Канонический путь + `ArgTail` ([0150](0150-slash-line-canonical-resolution.md)) |
290| `Features/Chat/ChatSlashCommandCatalog.cs` | path → descriptor (`command_id`, help, execution kind) |
291| `Features/Chat/ChatSlashCommandParser.cs` | `IsSlashLine`, `ShouldAutoExecuteAfterAutocompleteCommit` — **без** `TryParse` |
292| `Features/Chat/ChatSlashCommandRunner.cs` | local execution, args из резолва |
293| [`IntercomOutboundSendOrchestrator`](../../Features/Chat/Application/IntercomOutboundSendOrchestrator.cs) | сценарий Send: Slash → BuildOutbound (фон + Roslyn cache) → PrepareMessage → CommitFeed → DispatchProvider; trace по фазам |
294| [`ChatPanelViewModel`](../../Features/Chat/ChatPanelViewModel.cs) | порты через `IntercomOutboundSendHost`; `SendChatCommand` → оркестратор |
295| [`IdeMcpCommandExecutor`](../../ViewModels/IdeMcpCommandExecutor.cs) | исполнение тех же `command_id`, что MCP |
296| [`ChatPanelView.axaml`](../../Views/ChatPanelView.axaml) | popup autocomplete (**обязателен** до фазы B) |
297| `ChatSlashAutocompleteControl` *(новый)* | иерархический popup, привязка к `ChatInput` |
298| [`IdeCommands`](../../Services/IdeCommands.SolutionWorkspace.cs) | новые `command_id` только если нет покрытия (`chat_create_or_rename_topic`) |
299
300**Порядок внедрения:**
301
302| Фаза | Содержание | Критерий готовности |
303|------|------------|---------------------|
304| **A** | Parser (flat + namespace/action), catalog Intercom, local execution | `/overview`, `/export` не уходят агенту |
305| **A′** | **Autocomplete** для flat + namespace list | после `/` и `/build ` есть подсказки |
306| **B** | IDE: `/build run`, `/test run`, `/debug launch` → `command_id` | паритет с MCP `build` / `run_tests` / `debug_launch` |
307| **C** | Расширение каталога (`/git status`, `/nav`, проекция из палитры) | по discoverability + autocomplete, не big-bang |
308
309Тесты: parser unit-tests; интеграция «слэш local»; снапшоты каталога help.
310
311---
312
313## Отклонённые альтернативы
314
3151. **Парсить слэши в палитре** (`/card` в Command Palette) — смешивает overlay и Intercom; отвергнуто.
3162. **Отдельные MCP-only команды без `command_id`** — ломает [0030](0030-command-ids-hotkeys-and-ui-registry-layers.md); отвергнуто.
3173. **Отправлять нераспознанный `/` агенту** — шум и утечки; отвергнуто.
3184. **Короткие слэши как у Melody** (`/br` = build run) — дублирует `c:` / аккорды, коллизии и второй парсер; discoverability в Intercom — **autocomplete**, не мнемоники; отвергнуто.
319
320---
321
322## История изменений
323
324<a id="adr0119-history"></a>
325
326| Дата | Изменение |
327|------|-----------|
328| 2026-05-17 | Proposed: слэш-команды в ChatInput, каталог v1, intent-first, non-goals. |
329| 2026-05-17 | Расширение: unified command line — IDE namespaces (`/build run`, `/test run`, `/debug launch`); autocomplete обязателен; фазы A–C. |
330| 2026-05-17 | Уточнение: discoverability слэша — **autocomplete**; короткие алиасы (`/br`) и «мелодия после `/`» — **non-goal** (сжатие — `c:` Melody). |
331| 2026-05-17 | Accepted · Implemented: фазы **A**, **A′**, **B** (`ChatSlashCommand*`, autocomplete, IDE namespaces); фаза **C** — backlog. |
332| 2026-05-20 | `/help` — справка Intercom (`Intercom/intercom-help.ru.md`, EmbeddedResource + override на диске); ось **`audience`** (`channel` \| `self`) на сообщении и в `intent-catalog.toml`. |
333| 2026-05-17 | См. [0124](0124-slash-parametric-editor-line-commands.md): полный slash-паритет каталога IML (`wire_class`, `/editor line …`, `/portal open`). |
334| 2026-05-28 | Исполнение пути: [0153](0153-slash-catalog-only-resolution.md) — catalog-only; диаграмма и якоря реализации обновлены. |
335
View only · write via MCP/CIDE