Forge
markdowndeeb25a2
1# Playbook: TCI (Text-Command Interface) v1
2
3**TCI** — семейство Skia-полос ввода со slash-иерархией, popup и отдельным буфером в VM. Не путать с MFD Terminal (OS/process).
4
5## Экземпляры
6
7| Экземпляр | Буфер VM | Enter | Strip |
8|-----------|----------|-------|-------|
9| Composer | `ChatInput` / `ComposerText` | send агенту | `SkiaComposerStrip` |
10| CCL (Cockpit Command Line) | `CockpitCommandLineText` | execute slash | `SkiaCommandLineStrip` |
11| Navigator search | `TopicNavigatorSearchQuery` | фильтр тем | однострочный hit-test |
12| Chord overlay | короткий ввод | handoff | отдельный UX |
13
14## Общий слой
15
16- **`SkiaPlainTextLayout`** — RichTextKit: measure, caret, hit-test.
17- **`SkiaTciTextField`** — selection, horizontal scroll (CCL), caret draw, merge preedit.
18
19Синхронизация VM:
20
211. Control держит текст и caret (`ComposerText`, `CommandLineText`, …).
222. События `ComposerDraftChanged` / `CommandLineDraftChanged` — **caret до текста**, затем autocomplete.
233. Avalonia binding догоняет VM; не полагаться на порядок `PropertyChanged` от setter VM.
24
25## CCL (ADR 0138 фаза A)
26
27- Mono: `Cascadia Mono` через RichTextKit (`SkiaCommandLineStrip.MonoFontFamily`).
28- Click-to-caret, selection (Shift+стрелки), Ctrl+A/C/X/V, Home/End.
29- Горизонтальный scroll колёсиком при длинной команде.
30- Slash-validation — **pill вокруг команды** (как attach-chip / CodeAnchors): примитив `SkiaStatusChip` + обёртка `SkiaSlashCommandChip`; severity из `SlashCommandPreviewKind`; отдельной строки под полем нет.
31- Высота полосы масштабируется с `command_line_pt` (defaults 15pt): строка ввода ≈ `fontSize × 22/12`, preview ≈ `previewPt × 16/10`; не фиксированные 22px (иначе при 15pt режется снизу).
32- IME: `IntercomSkiaTextInputClient` в режиме `IsCommandLineInputActive` (без preedit).
33
34### Preview severity (не канал EICAS)
35
36Визуальная валидация slash — **отдельный контур** от W/C/A в [ADR 0021](../adr/0021-pfd-mfd-cockpit-attention-model.md): не попадает в `EicasAlertsBar`/CAS, Enter не блокируется (как chip attach, ADR 0128 §9.1). Рисование: `SkiaStatusChip` (примитив) → `SkiaSlashCommandChip` / `SkiaSlashPreviewChrome`. Контракт глифов ✓ / ✕ / **P(n)** — [ADR 0140](../adr/0140-tci-slash-status-glyphs-and-args-counter.md).
37
38**Иконка в pill:** по умолчанию **справа** от slash-текста (`[intercom] tci_validation_icon = right`). Варианты: `left` (gutter + clip union), `highlight_only` (без глифа). Clip поля ввода — union `textBounds` и `chipRect`, иначе глиф обрезается.
39
40**Палитру** берём из кокпита (красный / янтарь / зелёный / серый), **семантику** — свою:
41
42| TCI (`SlashCommandPreviewKind`) | Глиф (целевой) | Смысл | Цвет |
43|---------------------------------------|----------------|-------|------|
44| `Ok` (**Ready**) | ✓ | команда + args готовы | зелёный |
45| `Incomplete` | **P** / **P(n)** (сейчас ⚠) | не хватает args, id допечатывается | янтарь |
46| `Error` (**Invalid**) | ✕ | нет команды, опечатка, синтаксис | красный |
47| `Hint` | ℹ | мягкая подсказка (редко) | серый |
48
49Примеры: `/intercom test` → `Error` (✕); `/intercom message select` → `Incomplete` (P); `… select 5 7` → `Ok` (✓); `/intercom mesage select 5?7` → `Error` (✕).
50
51**Слой:** `SlashCommandPreviewService` → `SlashCommandPreviewRulePipeline` (правила); маппинг severity — **только** `SlashCommandPreviewVisualMapper` → `SkiaSlashPreviewChrome.ToChipSeverity`; chrome — `SkiaStatusChip`. В UI — pill, не вторая строка.
52
53**A11y (P1):** при `Error` / `Incomplete` / `Hint` полный текст — `IntercomSlashPreviewToolTip` на `IntercomSkiaSurface` (`ToolTip.Tip`), плюс поля `CommandLineSlashPreview` / `ComposerSlashPreview` в VM. Сессия CCL: `ICockpitCommandLineSession.PreviewAccessibilityToolTip`.
54
55### SkiaStatusChip (общий примитив)
56
57`Views/SkiaKit/SkiaStatusChip.cs` — скруглённая рамка, заливка, иконка слева; палитра `SkiaStatusChipColors` (Border, Fill, Icon, Accent). Используют: `SkiaSlashCommandChip`, `SkiaIntercomAttachLinkChip` (лента). API: `ComputeRectAroundTextStart`, `DrawFrame`, `DrawChrome`, `ResolveColors(theme, severity)`.
58
59**Composer:** `EvaluateComposerAtCaret` (линия по каретке); VM: `ComposerSlashPreview` / `ComposerSlashPreviewKind`. **CCL:** `Evaluate(buffer)`; VM: `CommandLineSlashPreview` / `CommandLineSlashPreviewKind`. При открытом CCL composer-preview скрывается.
60
61## Composer
62
63См. `playbook-skia-text-surface-v1.md`: многострочный scroll по Y, preedit, send.
64
65## Чеклист при новом TCI-поле
66
671. Strip на `SkiaPlainTextLayout` + при необходимости `SkiaTciTextField`.
682. `*DraftChanged` с caret-before-text.
693. Hit-test и caret rect для IME (`Get*CaretScreenRect`).
704. Chrome-only invalidate при blink (`InvalidateComposerChrome`).
715. Тесты hit-test/caret в `CascadeIDE.Tests`.
72
73## Связанные ADR
74
75- 0119 — slash commands Intercom
76- 0123 — full Skia surface
77- 0138 — CCL и parametric ranges (фаза B — preview ranges)
78
View only · write via MCP/CIDE