Forge
markdowndeeb25a2
1# ADR 0162: Monaco как опциональный хост Forward-редактора (WebView2, не Photino-shell)
2
3**Статус:** Proposed
4**Дата:** 2026-06-20
5**Обновляет:** [0103 §2.3](0103-editor-hud-substrate-semantic-projection-and-surface-adapter.md#adr0103-web-vs-native-forward) — Monaco перестаёт быть «молчаливо отклонённым» baseline; становится **явно разрешённой опциональной линией** при включении в конфиге.
6
7## Связанные ADR
8
9| ADR | Роль |
10|-----|------|
11| [0103](0103-editor-hud-substrate-semantic-projection-and-surface-adapter.md) | `IEditorSurfaceAdapter`, Editor HUD substrate, hi-freq bounded-контур |
12| [0108](0108-web-ai-portal-host-object-tools-bridge.md) | WebView2 в процессе IDE, Host Object / `WebMessageReceived` — транспортный прецедент |
13| [0035](0035-mfd-embedded-webview-external-llm-and-mcp-boundary.md) | Граница доверия веб ≠ MCP; **редактор Forward** — controlled origin, не чужой HTTPS |
14| [0084](0084-agent-edits-editor-source-of-truth-presence-channel.md) | Буфер редактора — источник применяемой правды; versioned apply |
15| [0085](0085-editor-hud-inline-layer-and-hud-banner.md) | Inline vs HUD banner |
16| [0009](0009-strangler-migration-and-exceptions.md) | Dual-path: AvaloniaEdit остаётся до parity |
17| [0120](0120-primary-work-surface-intercom-or-editor.md) | Forward / primary work surface |
18| [0152](0152-editor-control-flow-virtual-spacing.md) | Virtual spacing CF — перенос на Monaco decorations / gutter lane |
19
20### Вне ADR
21
22| Документ | Роль |
23|----------|------|
24| [editor-surface-candidates-comparison-v1](../design/editor-surface-candidates-comparison-v1.md) | Сравнение хостов (аппендикс) |
25| [editor-hud-inline-migration-inventory-v1](../design/editor-hud-inline-migration-inventory-v1.md) | Inventory inline-рендера для strangler |
26| [editor-forward-ui-cleanup-roadmap-v1](../ui-ux/editor-forward-ui-cleanup-roadmap-v1.md) | Roadmap полировки Forward |
27
28---
29
30<a id="adr0162-context"></a>
31
32## 1. Контекст
33
34**Продуктовая боль:** Avalonia как **фюзеляж** приемлема (окна, dock, focus, OS integration), но **текстовый UX Forward** на **AvaloniaEdit** систематически слабее зрелых web-редакторов:
35
36- рендеринг текста, caret, selection, scroll;
37- IntelliSense / completion / hover / Quick Info — кастомный chrome, визуальный и поведенческий разрыв с VS Code-подобным опытом;
38- inline HUD (squiggles, inlays, ghost) — дорогая борьба с `IBackgroundRenderer` и adorners в `DockDocumentView`.
39
40[0103](0103-editor-hud-substrate-semantic-projection-and-surface-adapter.md) уже ввёл **`IEditorSurfaceAdapter`** и зафиксировал AvaloniaEdit как baseline; Monaco/WebView2 — «вне спайка v1». Субстрат HUD (`SemanticProjectionPipeline`, `EditorHudEngine`, DAL/CCU) **не привязан** к AvaloniaEdit — второй адаптер архитектурно ожидаем.
41
42**Внешние рекомендации (Photino / «лёгкий Electron»):** часто смешивают три разных тезиса:
43
441. OS WebView легче упаковки Electron — **верно**;
452. «C# и JS в одном address space», «zero-latency IPC» — **неверно** для WebView2 (renderer out-of-process);
463. «30–40 МБ на IDE» — **нереалистично** для Monaco + нескольких поверхностей; память уходит в процессы Edge/WebView2, а не исчезает.
47
48**Photino-shell** (весь UI в web) **не** требуется, чтобы снять боль редактора: достаточно **Monaco-island** в уже принятом **WebView2** (`Avalonia.Controls.WebView` / `NativeWebView`, см. [0108](0108-web-ai-portal-host-object-tools-bridge.md)).
49
50---
51
52<a id="adr0162-decision"></a>
53
54## 2. Решение
55
56### 2.1 Направление
57
581. Ввести **`MonacoWebViewSurfaceAdapter`** — реализация **`IEditorSurfaceAdapter`** поверх **Monaco Editor** во **встроенном WebView2** в слоте `DockDocumentView` (Forward), **без** миграции всего CIDE на Photino.
59
602. **Avalonia остаётся фюзеляжом:** dock, окна, terminal, Skia-острова (Intercom, cockpit), MFD — без изменения [0044](0044-avalonia-host-skia-agent-chat-surface.md) / [0123](0123-intercom-full-skia-surface-evolution.md).
61
623. **Strangler dual-path** ([0009](0009-strangler-migration-and-exceptions.md)): конфиг **`[editor].forward_host`** = `avalonia_edit` (default) \| `monaco_webview2`. Переключатель на уровне workspace или глобально в `settings.toml`; без silent fallback между хостами на одном документе.
63
644. **LSP, Roslyn, DAL, agent MCP** — **без изменения контрактов**; только транспорт текста/offsets/decorations через адаптер.
65
66### 2.2 Что **не** делаем
67
68- **Полный Photino-shell** (все панели в HTML) — отдельная линия, не блокер и не замена этого ADR.
69- **Electron** — не рассматриваем (bundled Chromium).
70- **WebView для forge write path** — по-прежнему [FORGE ADR-0002](https://github.com/AI-Guiders/agent-forge/blob/main/design/FORGE-ADR-0002-mcp-first-web-view-only.md) / CIDE native; Monaco — **редактор кода**, не forge SPA.
71- **Monaco как единственный default** — только после явного sign-off parity (фазы ниже).
72
73### 2.3 Инварианты (не ломать)
74
75- [0084](0084-agent-edits-editor-source-of-truth-presence-channel.md): канонический текст для apply — **версионированный буфер**; Monaco не «тихий master» без sync protocol.
76- [0085](0085-editor-hud-inline-layer-and-hud-banner.md): inline и banner — разные слои; маппинг на Monaco `deltaDecorations` / content widgets / overlay, не один DOM-хак.
77- [0103 §2.2](0103-editor-hud-substrate-semantic-projection-and-surface-adapter.md#adr0103-layering-table): hi-freq caret/pointer — **bounded channel + throttle**, не DataBus на каждую клавишу.
78- [0035](0035-mfd-embedded-webview-external-llm-and-mcp-boundary.md): origin редактора — **`cide-editor://` / bundled asset**, не произвольный HTTPS; Host Object allowlist **отдельный** от Web AI Portal ([0108](0108-web-ai-portal-host-object-tools-bridge.md)).
79
80---
81
82<a id="adr0162-ipc"></a>
83
84## 3. IPC и память (честные ожидания)
85
86### 3.1 WebView2 — не «zero latency»
87
88| Утверждение | Факт |
89|-------------|------|
90| C# и страница в одном процессе | **Нет:** renderer WebView2 — **out-of-process** (Edge/Chromium) |
91| IPC быстрее localhost HTTP | **Да:** `PostWebMessage` / Host Object |
92| IPC быстрее in-process AvaloniaEdit | **Нет:** async marshaling; hi-freq path **coalesce** (16–50 ms throttle уже в 0103) |
93| Photino даёт иной IPC, чем Avalonia WebView | **Нет** на Windows: тот же WebView2 под капотом |
94
95### 3.2 Память
96
97- Пустое окно Photino/WebView — десятки МБ; **IDE + Monaco + language services + N webviews** — **сотни МБ** суммарно по процессам Edge — норма.
98- Выигрыш vs Electron — **не тащим свой Chromium**; vs AvaloniaEdit-only — **дополнительный** renderer process на Forward-документ.
99
100---
101
102<a id="adr0162-bridge"></a>
103
104## 4. Контракт `cide-editor` (мост C# ↔ Monaco)
105
106**Namespace сообщений:** `cide-editor/*` (ортогонально `executeIdeCommand` из [0108](0108-web-ai-portal-host-object-tools-bridge.md)).
107
108**Транспорт:** `WebMessageReceived` + опционально Host Object для sync read (caret snapshot); JSON camelCase.
109
110**Минимальный набор (v0):**
111
112| Направление | Message | Назначение |
113|-------------|---------|------------|
114| C# → JS | `editor/setModel` | uri, languageId, text, version |
115| C# → JS | `editor/applyEdits` | edits[], expectedVersion |
116| C# → JS | `editor/setDecorations` | decoration sets (diagnostics, agent range, CF gutter) |
117| C# → JS | `editor/setTheme` | tokens из UI theme pipeline [0086](0086-ui-theme-toml-canonical-json-mcp-wire.md) |
118| JS → C# | `editor/didChange` | contentChanges[], version |
119| JS → C# | `editor/didChangeCursorSelection` | offsets, reason |
120| JS → C# | `editor/ready` | handshake после load |
121
122**Source of truth (0084):** v0 — **C# master**: push `setModel` / `applyEdits` после локальных и agent mutations; JS шлёт deltas, C# мержит и инкрементирует version. Инверсия (Monaco master) — только с отдельным ADR и тестами race.
123
124**Assets:** bundled static (`Assets/editor/` или `wwwroot/cide-editor/`), загрузка через `WebView2` virtual host или `file://` под контролируемым path — детали реализации, origin **не** third-party.
125
126---
127
128<a id="adr0162-phases"></a>
129
130## 5. Фазы внедрения (strangler)
131
132| Фаза | Объём | Критерий |
133|------|--------|----------|
134| **M0** | Monaco в WebView: open/edit file, caret events | Лог + ручной smoke |
135| **M1** | `MonacoWebViewSurfaceAdapter` + `[editor].forward_host` | Переключение host без падения dock |
136| **M2** | Diagnostics → decorations из `EditorHudEngine` snapshot | Parity squiggles с AvaloniaEdit на одном файле |
137| **M3** | Inline inventory → Monaco (hover, inlay, agent reveal [0130](0130-editor-agent-range-reveal-without-selection.md)) | Item-by-item из migration inventory |
138| **M4** | Agent applyEdits + 0084 integration tests | Version mismatch → reject, не silent corrupt |
139| **M5** | CF virtual spacing [0152](0152-editor-control-flow-virtual-spacing.md) на Monaco gutter lane | Визуальный sign-off |
140| **M6** | Default flip to `monaco_webview2` (optional) | Product sign-off; ADR status → Accepted · Implemented |
141
142**Dual-path до M6:** AvaloniaEdit не удаляем; regression на `avalonia_edit` для CI matrix optional.
143
144---
145
146<a id="adr0162-consequences"></a>
147
148## 6. Последствия
149
150### Положительные
151
152- Текст, selection, completion UI, diff editor — зрелый API Monaco; снимает класс боли AvaloniaEdit без смены фюзеляжа.
153- Переиспользование WebView2-инфраструктуры и паттернов [0108](0108-web-ai-portal-host-object-tools-bridge.md).
154- `IEditorSurfaceAdapter` и Editor HUD substrate получают **реальную вторую реализацию** — проверка абстракции.
155
156### Отрицательные / trade-offs
157
158- Две темы (Avalonia + Monaco CSS) — генератор из канона [0086](0086-ui-theme-toml-canonical-json-mcp-wire.md), не ручной drift.
159- IPC-latency на hi-freq path — дисциплина throttle; возможен micro-jank vs native.
160- `DockDocumentView` strangler: AvaloniaEdit-specific renderers отмирают **по inventory**, не одним PR.
161- Windows-first (текущий `win-x64` RID); Linux/macOS WebView — отдельный roadmap ([0093](0093-mfd-embedded-browser-for-launch-url.md)), не блокер Proposed.
162
163---
164
165<a id="adr0162-alternatives"></a>
166
167## 7. Отклонённые альтернативы
168
169| Альтернатива | Почему нет |
170|--------------|------------|
171| **Photino-shell** для всего CIDE | Снимает не ту боль; переписывает dock/terminal/Skia; тот же WebView2 IPC |
172| **Electron** | Bundled Chromium + Node; против целей lean desktop |
173| **Оставить только AvaloniaEdit** | Принято как **default до M6**; не отменяет optional Monaco |
174| **Monaco в MFD, не Forward** | Не заменяет primary editor; только preview |
175| **CodeMirror 6** вместо Monaco | Допустимый spike; ADR фиксирует Monaco как первый кандидат (LSP ecosystem, diff, VS Code parity) |
176
177---
178
179<a id="adr0162-config"></a>
180
181## 8. Конфиг (sketch)
182
183```toml
184[editor]
185# avalonia_edit | monaco_webview2
186forward_host = "avalonia_edit"
187```
188
189Per-workspace override — через существующий stack `settings.toml` / workspace profile (детали при M1).
190
191---
192
193<a id="adr0162-implementation"></a>
194
195## 9. Ownership (sketch)
196
197| Компонент | Расположение |
198|-----------|--------------|
199| `MonacoWebViewSurfaceAdapter` | `Features/Editor/Application/` |
200| `cide-editor` bridge (TS) | `Assets/cide-editor/` или `wwwroot/cide-editor/` |
201| WebView host control | `Views/` или `Features/Editor/Presentation/` |
202| Theme token export | рядом с [0086](0086-ui-theme-toml-canonical-json-mcp-wire.md) pipeline |
203
204---
205
206<a id="adr0162-history"></a>
207
208## История изменений
209
210| Дата | Изменение |
211|------|-----------|
212| 2026-06-20 | Proposed: Monaco Forward host, WebView2 island, anti-hype IPC/memory, strangler phases |
213| 2026-06-21 | Уточнение: ветка `feature/monaco-forward-editor-m0` убрала Avalonia `TextEditor` из dock; полный перевод и bus — [0163](0163-monaco-native-capability-bus-full-forward-migration.md) |
214
View only · write via MCP/CIDE