ADR 0138: Cockpit Command Line — параметрический CLI для Commander и Pilot¶
Статус: Accepted · In progress (парсер, slash, CCL IntercomHost фаза A, anchor CLI)
Дата: 2026-05-20
Связанные ADR¶
| ADR | Роль |
|---|---|
| 0133 | Роли Commander (Intercom-first) и Pilot (редактор-first) |
| 0120 | Forward = Intercom или Editor |
| 0119 | Слэш → command_id; каталог; autocomplete |
| 0060 | CascadeChord (Ctrl+K): тактика, короткий таймаут — не длинный CLI |
| 0124 | /editor line select — contiguous L, L R, L:R |
| 0136 | Gutter ordinals; /intercom message select |
| 0137 | Contiguous relate/find; disjoint relate — не MVP |
| 0072 | Chat navigation intents; chord ≠ CLI |
| 0013 | Палитра, command_id, discoverability |
| 0030 | Реестр команд |
Резюме¶
Cockpit Command Line (CCL) — общая для всего primary workplace полоса полноценного CLI (slash + autocomplete + сложный синтаксис), не привязанная только к Intercom.
| Роль (0133) | Primary Forward | Сложные команды |
|---|---|---|
| Commander / Lead | Intercom | Уже «дома» в ленте + composer; CCL усиливает: длинный /intercom …, превью, без путаницы с репликой агенту |
| Pilot | Редактор | Аккорды для тактики; сложный параметрический ввод (напр. несколько диапазонов строк) — в CCL, не в chord overlay |
Единый вход: CascadeChord → / (Ctrl+K, затем /) переводит фокус в CCL независимо от того, открыт Intercom или Editor. Дальше — полный ввод, в т.ч. [3;5] [8;15] [20] и превью эффекта до применения.
Не цель: заменить палитру, Melody c: или тактические буквы chord; дублировать MCP.
Контекст (формулировка автора)¶
Две роли — одна IDE, разный фокус Forward¶
Commander сидит в Intercom: ему нужна богатая, легко расширяемая командная поверхность — autocomplete, иерархия /intercom …, сложные хвосты (relate, find, multi-select сообщений). Смешивать это с полем «сообщение агенту» неудобно (0119).
Pilot сидит в редакторе: основной поток — код и короткие аккорды (0060). Но часто нужна сложная команда, которую физически не ввести в chord window, например выделить в файле:
[3;5] [8;15] [20]
→ строки 3–5 включительно и 8–15 включительно и строка 20 (disjoint multi-range).
Тот же класс задач у Commander для gutter сообщений:
/intercom message select [3;5] [8;15] [20]
→ сообщения #3–#5, #8–#15 и #20.
Вывод: Command Line — слой кокпита, а не «фича Intercom». Intercom получает экземпляр CCL у composer; Editor — экземпляр у нижнего края Forward (или dock-adjacent). Ctrl+K / открывает тот же режим везде.
Почему не Chord и не только Composer¶
| Поверхность | Ограничение |
|---|---|
| Chord overlay | Короткий таймаут второй клавиши; Melody — короткие токены, не [3;5] [8;15] [20] |
| Composer (Intercom) | Enter = отправить агенту; черновик портится длинным slash |
| Палитра | Fuzzy discoverability, не замена параметрического REPL у активной зоны |
Решение 1: Cockpit Command Line (CCL)¶
Термины¶
| Термин | Значение |
|---|---|
| CCL | Cockpit Command Line — режим полноценного slash-CLI в Forward |
| Host | Конкретная полоса UI: IntercomHost (над/под Skia composer) · EditorHost (над статусной зоной редактора / dock) |
| Chord handoff | Ctrl+K → / завершает chord-сессию и фокусирует CCL активного host |
Инварианты¶
- Один parser, один runner —
ChatSlashCommandParser+ существующие runners для Intercom; для Editor — те жеcommand_id(0124, 0119, палитра). - Контекст host задаёт подсказки по умолчанию (префикс
/intercomvs/editor), но не запрещает команды другой зоны, если оператор явно набрал полный путь. - Отдельный буфер — не
ComposerText, неCascadeChordOverlayInputText. - Enter = выполнить (после опционального preview); Esc = закрыть CCL без побочных эффектов на черновик сообщения / выделение редактора до Apply.
Размещение host (предложение)¶
| Host | Когда виден | Позиция |
|---|---|---|
| IntercomHost | PrimaryWorkSurface == Intercom (Commander preset) |
Над composer ленты (по умолчанию): команда → результат в ленте ниже |
| EditorHost | PrimaryWorkSurface == Editor (Pilot preset) |
Над нижним краем Forward editor / под HUD — уточнить в макете 0120 |
Оба host могут существовать в layout, но активен один; chord / фокусирует host, соответствующий текущему Forward.
IntercomHost: Command Deck (2026-05-21)¶
На Skia-ленте Intercom нижний chrome — один Command Deck, а не «popup поверх сообщений»:
| Слой (сверху вниз внутри deck) | Содержимое |
|---|---|
| Верх deck | Slash autocomplete (SkiaPopupList), max 6 строк, скролл внутри deck |
| Середина | CCL (SkiaCommandLineStrip), если открыт |
| Низ deck | Composer (отправка агенту) |
Инварианты: лента сообщений отступает на SkiaIntercomCommandDeckLayout.TotalHeight; подсказки не рисуются выше верхней границы deck. Реализация: Views/Chat/SkiaIntercomCommandDeckLayout.cs.
Aviation alignment (CDU / PFD, не HUD-menu)¶
В кабине не кладут выпадающий список FMS поверх PFD (attitude / flight path). Длинный ввод идёт в CDU scratchpad + EXEC; тактика — glareshield / LSK (0060: префикс → вторая клавиша). MFD — отдельная страница (карта, план), не полупрозрачный слой на лобовом.
| Авиация | Cascade |
|---|---|
| PFD — «куда смотрю» | Forward: лента Intercom / редактор |
| CDU scratchpad + line select | Command Deck: popup → CCL → composer |
| EXEC / CLR | Enter commit / Esc в CCL |
| Прозрачное меню на PFD | Отклонено — непрозрачный deck, верхняя граница, inset ленты (0021) |
| Длинный route на MFD-странице | EditorHost / MFD Terminal — не overlay на Commander-ленту |
Вывод: Command Deck — не «косметика», а перенос CDU-панели под PFD: командный ввод вне зоны первичного внимания, но в том же Forward, без перекрытия сообщений.
flowchart TB
subgraph cockpit [Cascade IDE Cockpit]
chord[Ctrl+K then slash]
chord --> ccl[CCL active host]
ccl --> intercomHost[IntercomHost near composer]
ccl --> editorHost[EditorHost near editor]
intercomHost --> runner[Slash command runner]
editorHost --> runner
runner --> cmd[command_id handlers]
end
commander[Commander role] -.-> intercomHost
pilot[Pilot role] -.-> editorHost
Решение 2: Chord Ctrl+K → / (глобальный handoff)¶
| Шаг | Поведение |
|---|---|
| 1 | CascadeChord (Ctrl+K) |
| 2 | Вторая клавиша / |
| 3 | Chord overlay закрывается (таймаут снят) |
| 4 | Открывается CCL активного Forward host: /, фокус, autocomplete |
| 5 | Пользователь вводит произвольную команду (в т.ч. multi-range) |
command_id (рабочее имя): cockpit.open_command_line — не intercom.*-only.
Отклонено: набор [3;5] [8;15] [20] внутри chord HUD (0060).
Решение 3: Параметрические multi-range ([L;R] …)¶
Единый микросинтаксис сегментов (предложение)¶
Сегмент в квадратных скобках; внутри — contiguous диапазон с ; между границами (включительно):
| Сегмент | Разбор |
|---|---|
[3;5] |
3, 4, 5 |
[20] |
только 20 |
[8;15] |
8…15 |
Список сегментов — через пробел (как перечисление интервалов):
[3;5] [8;15] [20]
Применение по домену¶
| Домен | Пример CCL | Эффект |
|---|---|---|
| Editor lines | /editor line select [3;5] [8;15] [20] |
Multi-range selection / highlight в активном файле (0124 — расширение) |
| Intercom gutter | /intercom message select [3;5] [8;15] [20] |
Multi-select сообщений в detail-ветке (0136 — расширение) |
Паритет с 0124: legacy формы 5 10, 5:10 остаются для одного contiguous сегмента; [a;b] — канон для явного сегмента; несколько сегментов — повтор скобок.
Связь с 0137: relate / event log в MVP — один contiguous диапазон (3:5 relate …). Multi-segment [3;5] [8;15] для select/highlight — этот ADR; relate на disjoint — отдельная фаза / отдельное решение.
Решение 4: Preview перед применением¶
Для сложных команд CCL показывает превью ожидаемого эффекта до commit (Enter второй раз или явная кнопка Apply — деталь UX в фазе B).
| Пример команды | Превью (иллюстрация) |
|---|---|
/editor line select [3;5] [8;15] [20] |
Подсветка ghost/рамкой диапазонов в редакторе; текст: «Строки: 3–5, 8–15, 20 (17 строк)» |
/intercom message select [3;5] [8;15] [20] |
Подсветка строк ленты #3…#5, #8…#15, #20; «Активно: #20» |
Режимы (фазы):
| Фаза | Preview |
|---|---|
| A | Только текстовый summary под строкой CCL (низкая стоимость) |
| B | Визуальный ghost highlight в editor / feed |
| C | «Dry-run» без мутации + Apply / Enter |
Инвариант: preview не меняет selection buffer / не пишет event log до Apply.
Ортогональность входов (обновлённая)¶
| Вход | Commander | Pilot | Сложный синтаксис |
|---|---|---|---|
| Chord (буква) | next/prev topic, тактика | save, debug, … | Нет |
Chord / |
→ CCL IntercomHost | → CCL EditorHost | Handoff |
| CCL | /intercom … |
/editor … |
Да |
| Composer | prose агенту | — | Короткий slash опционально |
Палитра / c: |
discoverability | discoverability | Средний |
| MCP | полные args | полные args | Да |
Принятые решения (по уточнению автора)¶
| # | Решение |
|---|---|
| D1 | CCL — кокпит-wide, не только Intercom |
| D2 | Ctrl+K / — единый вход в CCL для Commander и Pilot |
| D3 | Сложные disjoint диапазоны — синтаксис [a;b] сегментов, несколько сегментов через пробел |
| D4 | Pilot получает тот же CLI у редактора; chord остаётся для короткой тактики |
| D5 | Preview перед apply — желательная часть дизайна CCL (фаза A текст → B визуал) |
Позиция и обоснование¶
CCL — не «ещё одна фича Intercom», а слой между chord и палитрой: локальный REPL активной зоны внимания (Forward). Три типа ввода остаются ортогональными:
| Ввод | Намерение | Договорённость | Реплика |
|---|---|---|---|
| Chord (буква) | тактика «сейчас» | короткий command_id |
— |
CCL (Ctrl+K → /) |
параметрика, сложный хвост | полный slash + preview | — |
| Composer | — | короткий slash опционально | prose агенту |
Почему согласовано с кокпитом
- 0133: Commander и Pilot — preset’ы одного workplace; им нужны разные дефолты Forward, но одна механика сложных команд и один muscle memory (
Ctrl+K→/). - 0060: аккорд не масштабируется на микро-язык
[3;5] [8;15] [20]— таймаут и Melody нечитаемы; handoff в CCL сохраняет chord «коротким». - 0119: composer + Enter = агент; длинный slash портит черновик — CCL даёт второй буфер без дублирования parser/runner.
- 0137: multi-segment select/highlight (этот ADR) отделён от disjoint relate в event log (не MVP).
Риски (принять осознанно)
| Риск | Смягчение |
|---|---|
| Два host UI (Skia + Avalonia) | Общая VM/сессия; один parser; UI только host-specific chrome |
| Третий буфер в голове (chord / CCL / composer / палитра) | Chord help: «/ → command line»; autocomplete в CCL |
| Preview на больших файлах | Лимит строк в ghost; фаза A — только текст |
| Relate на disjoint ranges | Не смешивать с CCL v1; отдельное решение после 0137 MVP |
| Четвёртая «Shell»-поверхность в Forward | См. § Инварианты внимания |
Инварианты внимания (Forward vs Shell)¶
Не смешивать зону внимания (0021) и режим ввода в Forward (таблица выше).
| Инвариант | Смысл |
|---|---|
| CCL — единственный REPL Forward | Сложный slash, preview, multi-range, anchor peek — только в CCL (или handoff из composer в CCL). Один parser + один runner (0119). |
| Отдельной Shell-страницы в Forward нет | Не вводим вторую постоянную REPL-панель в лобовом стеке (лента + shell + composer). «Shell» в коде/доках = хром полосы CCL (CCL shell), не новая primary surface. |
| MFD Terminal — OS/process | dotnet build, git, пайпы, scrollback — страница MFD (0063 MfdShellPage), не дубль command_id slash из CCL. |
| CCL — modal по Esc | Пока CCL открыт, Forward в режиме «команда»; Close() не трогает composer, selection, event log (см. Инварианты сессии ниже). |
| Один активный CCL host | IntercomHost или EditorHost — не оба видимы (0120). |
Валидация в стиле attach (0128 §9.1): debounced preview в CCL показывает исход (resolved / degraded / failed) без блокировки Enter, как chip в ленте — не отдельный «терминал ошибок».
Preview severity ≠ канал EICAS (0021 W/C/A): TCI slash-preview — SlashCommandPreviewService / SlashCommandPreviewKind (CCL + composer). Таблица — playbook-tci-v1.md § Preview severity. Глифы ✓ / ✕ / P(n) — 0140.
Рекомендуемый порядок внедрения
- CCL shell +
cockpit.open_command_line+ chord/(хотя бы EditorHost для Pilot). ParametricSegmentListParser+/editor line select […]+ текстовый preview.- IntercomHost +
/intercom message select […]+ multi-highlight ленты. - Ghost preview (фаза B); Commander polish; опционально disjoint relate.
Набросок API (реализация)¶
Черновик контрактов для фазы A. Имена и namespace — ориентир; точное размещение файлов — при имплементации. Не дублировать ChatSlashCommandParser / ChatSlashCommandRunner — CCL переиспользует их.
Размещение (предложение)¶
| Слой | Файл / тип | Роль |
|---|---|---|
| Domain | Features/Cockpit/CockpitCommandLineHostKind.cs |
Intercom | Editor |
| Session | Features/Cockpit/ICockpitCommandLineSession.cs |
буфер, preview, commit |
| VM | ViewModels/CockpitCommandLineViewModel.cs |
binding для обоих host |
| Parse | Features/Chat/ParametricSegmentListParser.cs |
[a;b] … → IReadOnlyList<IntRange> |
| Wiring | MainWindowViewModel + chord handler |
cockpit.open_command_line |
CockpitCommandLineHostKind¶
public enum CockpitCommandLineHostKind
{
Intercom,
Editor,
}
ICockpitCommandLineSession¶
Единая сессия на главное окно; активный host следует за PrimaryWorkSurface (0120), пока CCL открыт.
public interface ICockpitCommandLineSession
{
bool IsOpen { get; }
CockpitCommandLineHostKind ActiveHost { get; }
string BufferText { get; set; }
int CaretIndex { get; set; }
/// <summary>Текстовое превью (фаза A); null если команда не распознана или preview выключен.</summary>
string? PreviewSummary { get; }
/// <summary>Опционально: сегменты для ghost highlight (фаза B).</summary>
IReadOnlyList<IntRange>? PreviewSegments { get; }
/// <summary>Ctrl+K → / или palette: cockpit.open_command_line.</summary>
void Open(CockpitCommandLineHostKind? host = null, string initialText = "/");
void Close(); // Esc — без commit
/// <summary>Пересчитать preview при изменении BufferText (debounced).</summary>
void RefreshPreview();
/// <summary>Enter: parse → runner → side effects; затем Close или очистка буфера.</summary>
Task<CockpitCommandLineCommitResult> TryCommitAsync(CancellationToken cancellationToken = default);
}
public readonly record struct CockpitCommandLineCommitResult(
bool Handled,
bool Success,
string? UserMessage);
Инварианты сессии
BufferText≠ComposerText/ChatInput/CascadeChordOverlayInputText.Close()не вызывает handlers; не трогает selection/editor/event log.TryCommitAsyncделегирует в существующийChatSlashCommandRunner.TryRunAsync(BufferText)(0119); host влияет только на default autocomplete prefix, не на whitelist команд.- Не дублирует MFD Terminal и не заменяет его; workplace-команды (
/intercom,/editor,/anchor,/file) — только здесь (§ Инварианты внимания).
Chord handoff¶
// IdeCommands / chord registry
public const string OpenCommandLine = "cockpit.open_command_line";
// MainWindowViewModel (псевдокод)
void OnChordSlash()
{
CascadeChord.EndSession();
var host = PrimaryWorkSurface == PrimaryWorkSurfaceKind.Intercom
? CockpitCommandLineHostKind.Intercom
: CockpitCommandLineHostKind.Editor;
CommandLineSession.Open(host, initialText: "/");
}
ParametricSegmentListParser¶
Расширение ChatSlashParametricArgsBuilder.TryParseLineRangeTail (один contiguous сегмент) → список сегментов в скобках.
public readonly record struct IntRange(int Start, int End); // inclusive, 1-based
public static class ParametricSegmentListParser
{
/// <summary>
/// Разбор хвоста args: <c>[3;5] [8;15] [20]</c> или legacy один сегмент
/// (<c>3:5</c>, <c>3 5</c>, <c>5</c>) как один <see cref="IntRange"/>.
/// </summary>
public static bool TryParse(
string? argsTail,
out IReadOnlyList<IntRange> segments,
out string error);
public static string FormatSummary(IReadOnlyList<IntRange> segments, string unitLabel);
// unitLabel: "строки" | "сообщения"
}
Потребители
| Команда | После parse |
|---|---|
/editor line select … |
EditorLineSelectHandler — multi-range selection |
/intercom message select … |
ChatSlashIntercomHandlers — multi-highlight + active ordinal = последний сегмент |
Preview: FormatSummary → PreviewSummary; PreviewSegments → ghost (фаза B).
Preview pipeline (фаза A)¶
public sealed class SlashCommandPreviewService
{
public SlashCommandPreviewResult Evaluate(string? slashBuffer);
public SlashCommandPreviewResult EvaluateComposerAtCaret(string? chatInput, int caretIndex);
}
// правила: internal SlashCommandPreviewEvaluator
Логика: ChatSlashCommandParser.TryParse → если action известен и tail содержит segment syntax → summary без мутации VM.
TOML ([cockpit.command_line]) — черновик¶
[cockpit.command_line]
preview_enabled = true
preview_mode = "text" # "text" | "ghost" (фаза B)
intercom_host = "above_composer" # Q1
Критерии «API готов к фазе A»¶
ICockpitCommandLineSessionподключён к IntercomHost и EditorHost (хотя бы один видимый).ParametricSegmentListParser.TryParseпокрыт unit-тестами (наследие форм из 0124 + bracket segments).TryCommitAsync→ChatSlashCommandRunnerбез форка parser.RefreshPreviewне меняет editor/feed до commit.
Принятые решения по открытым вопросам (Q1–Q5)¶
| # | Решение |
|---|---|
| Q1 | IntercomHost над composer — CLI между лентой и полем prose; граница «дискурс / команда» видна при взгляде сверху вниз |
| Q2 | Slash в composer — да, для коротких команд (/help, /clear, короткий /overview). Любая параметрика со скобками […] или несколькими сегментами → handoff в CCL (Ctrl+K → /) |
| Q3 | Preview MVP — фаза A: только текстовый summary под строкой CCL. Ghost (фаза B) — после стабилизации парсера |
| Q4 | Debounced preview при наборе + один Enter = Apply. Не два Enter и не отдельный Ctrl+Enter |
| Q5 | 3:5 / 3 5 / 5 остаются alias одного contiguous сегмента (0124). Disjoint — только [3;5] [8;15] [20] |
Остаются открытыми¶
| # | Вопрос |
|---|---|
| Q6 | TOML: [cockpit.command_line] — height, preview_enabled |
| Q7 | Disjoint relate на [3;5] [8;15] — отдельно от MVP 0137 (contiguous relate only) |
Альтернативы¶
| Альтернатива | Почему отклонена |
|---|---|
| Только Intercom CLI | Не закрывает Pilot multi-line select |
| Только палитра | Нет параметрического REPL у зоны внимания |
| Chord Melody для ranges | Нечитаемо; таймаут |
| Два разных parser | Нарушает 0119 / 0030 |
Последствия¶
- 0060:
/= handoff в CCL; обновить chord help. - 0119: CCL — второй host буфера; composer остаётся для prose.
- 0124: парсер multi-segment
[;]; preview для line select. - 0136: multi-highlight + парсер для message select.
- 0133: CCL как shared instrument для обеих ролей.
- 0137: явная граница select multi-range vs relate contiguous.
- Реализация:
MainWindowViewModel+ Skia Intercom host + Avalonia/editor host;cockpit.open_command_line.
Критерии приёмки¶
Фаза A (CCL + chord + текстовый preview)¶
- Ctrl+K →
/в Intercom → IntercomHost CCL с/и autocomplete. - Ctrl+K →
/в Editor → EditorHost CCL с/и autocomplete. /editor line select [3;5] [8;15] [20]— текстовое превью диапазонов; Enter — selection в файле./intercom message select [3;5] [8;15] [20]— превью ordinals; Enter — multi-highlight в ленте.- Esc не портит composer и не меняет editor до Apply.
Фаза B (визуальный preview)¶
- Ghost highlight в редакторе и ленте при наборе в CCL (до Apply).
Статус реализации¶
| Компонент | Состояние |
|---|---|
| ADR | Accepted — D1–D5, Q1–Q5 |
ParametricSegmentListParser |
Implemented — legacy + [a;b]; unit-тесты |
/intercom message select […] multi-highlight |
Implemented — slash/composer; Skia feed |
SlashCommandPreviewService / SlashCommandPreviewEvaluator |
Implemented — текстовый summary для slash (CCL + composer) |
/editor line select multi-segment |
Partial — один contiguous; disjoint → ошибка до CCL/editor union |
| CCL IntercomHost (полоса над composer, preview, Enter/Esc) | Partial — фаза A; ICockpitCommandLineSession + CommandLineSession |
| CCL EditorHost | — |
cockpit.open_command_line + chord Ctrl+K / |
Partial — палитра/MCP; chord — |
| Preview в CCL UI (текст при наборе) | Implemented — SlashCommandPreviewService (CCL + composer) |
| Ghost preview (фаза B) | — |
/intercom message anchors list, /anchor peek |
Implemented — slash + CCL; chip a:… (0128 §10.1) |
История¶
| Дата | Изменение |
|---|---|
| 2026-05-20 | Черновик (Intercom-only ICL) |
| 2026-05-20 | Пересмотр: CCL кокпит-wide; Commander/Pilot; [3;5] [8;15] [20]; preview; Ctrl+K / глобально |
| 2026-05-20 | § «Позиция и обоснование»; § «Набросок API» (ICockpitCommandLineSession, ParametricSegmentListParser) |
| 2026-05-21 | Accepted; Q1–Q5 закрыты; ParametricSegmentListParser + multi message select + preview builder |
| 2026-05-21 | § Инварианты внимания: CCL = единственный REPL Forward; MFD Terminal для OS/process |
| 2026-05-20 | Фаза A: IntercomHost CCL, /intercom message anchors list, /anchor peek, chip a:… |