ADR 0162: Monaco как опциональный хост Forward-редактора (WebView2, не Photino-shell)
Статус: Proposed
Дата: 2026-06-20
Обновляет: 0103 §2.3 — Monaco перестаёт быть «молчаливо отклонённым» baseline; становится явно разрешённой опциональной линией при включении в конфиге.
Связанные ADR
| ADR | Роль |
|---|---|
| 0103 | IEditorSurfaceAdapter, Editor HUD substrate, hi-freq bounded-контур |
| 0108 | WebView2 в процессе IDE, Host Object / WebMessageReceived — транспортный прецедент |
| 0035 | Граница доверия веб ≠ MCP; редактор Forward — controlled origin, не чужой HTTPS |
| 0084 | Буфер редактора — источник применяемой правды; versioned apply |
| 0085 | Inline vs HUD banner |
| 0009 | Dual-path: AvaloniaEdit остаётся до parity |
| 0120 | Forward / primary work surface |
| 0152 | Virtual spacing CF — перенос на Monaco decorations / gutter lane |
Вне ADR
| Документ | Роль |
|---|---|
| editor-surface-candidates-comparison-v1 | Сравнение хостов (аппендикс) |
| editor-hud-inline-migration-inventory-v1 | Inventory inline-рендера для strangler |
| editor-forward-ui-cleanup-roadmap-v1 | Roadmap полировки Forward |
1. Контекст
Продуктовая боль: Avalonia как фюзеляж приемлема (окна, dock, focus, OS integration), но текстовый UX Forward на AvaloniaEdit систематически слабее зрелых web-редакторов:
- рендеринг текста, caret, selection, scroll;
- IntelliSense / completion / hover / Quick Info — кастомный chrome, визуальный и поведенческий разрыв с VS Code-подобным опытом;
- inline HUD (squiggles, inlays, ghost) — дорогая борьба с
IBackgroundRendererи adorners вDockDocumentView.
0103 уже ввёл IEditorSurfaceAdapter и зафиксировал AvaloniaEdit как baseline; Monaco/WebView2 — «вне спайка v1». Субстрат HUD (SemanticProjectionPipeline, EditorHudEngine, DAL/CCU) не привязан к AvaloniaEdit — второй адаптер архитектурно ожидаем.
Внешние рекомендации (Photino / «лёгкий Electron»): часто смешивают три разных тезиса:
- OS WebView легче упаковки Electron — верно;
- «C# и JS в одном address space», «zero-latency IPC» — неверно для WebView2 (renderer out-of-process);
- «30–40 МБ на IDE» — нереалистично для Monaco + нескольких поверхностей; память уходит в процессы Edge/WebView2, а не исчезает.
Photino-shell (весь UI в web) не требуется, чтобы снять боль редактора: достаточно Monaco-island в уже принятом WebView2 (Avalonia.Controls.WebView / NativeWebView, см. 0108).
2. Решение
2.1 Направление
Ввести
MonacoWebViewSurfaceAdapter— реализацияIEditorSurfaceAdapterповерх Monaco Editor во встроенном WebView2 в слотеDockDocumentView(Forward), без миграции всего CIDE на Photino.Avalonia остаётся фюзеляжом: dock, окна, terminal, Skia-острова (Intercom, cockpit), MFD — без изменения 0044 / 0123.
Strangler dual-path (0009): конфиг
[editor].forward_host=avalonia_edit(default) |monaco_webview2. Переключатель на уровне workspace или глобально вsettings.toml; без silent fallback между хостами на одном документе.LSP, Roslyn, DAL, agent MCP — без изменения контрактов; только транспорт текста/offsets/decorations через адаптер.
2.2 Что не делаем
- Полный Photino-shell (все панели в HTML) — отдельная линия, не блокер и не замена этого ADR.
- Electron — не рассматриваем (bundled Chromium).
- WebView для forge write path — по-прежнему FORGE ADR-0002 / CIDE native; Monaco — редактор кода, не forge SPA.
- Monaco как единственный default — только после явного sign-off parity (фазы ниже).
2.3 Инварианты (не ломать)
- 0084: канонический текст для apply — версионированный буфер; Monaco не «тихий master» без sync protocol.
- 0085: inline и banner — разные слои; маппинг на Monaco
deltaDecorations/ content widgets / overlay, не один DOM-хак. - 0103 §2.2: hi-freq caret/pointer — bounded channel + throttle, не DataBus на каждую клавишу.
- 0035: origin редактора —
cide-editor:/// bundled asset, не произвольный HTTPS; Host Object allowlist отдельный от Web AI Portal (0108).
3. IPC и память (честные ожидания)
3.1 WebView2 — не «zero latency»
| Утверждение | Факт |
|---|---|
| C# и страница в одном процессе | Нет: renderer WebView2 — out-of-process (Edge/Chromium) |
| IPC быстрее localhost HTTP | Да: PostWebMessage / Host Object |
| IPC быстрее in-process AvaloniaEdit | Нет: async marshaling; hi-freq path coalesce (16–50 ms throttle уже в 0103) |
| Photino даёт иной IPC, чем Avalonia WebView | Нет на Windows: тот же WebView2 под капотом |
3.2 Память
- Пустое окно Photino/WebView — десятки МБ; IDE + Monaco + language services + N webviews — сотни МБ суммарно по процессам Edge — норма.
- Выигрыш vs Electron — не тащим свой Chromium; vs AvaloniaEdit-only — дополнительный renderer process на Forward-документ.
4. Контракт cide-editor (мост C# ↔ Monaco)
Namespace сообщений: cide-editor/* (ортогонально executeIdeCommand из 0108).
Транспорт: WebMessageReceived + опционально Host Object для sync read (caret snapshot); JSON camelCase.
Минимальный набор (v0):
| Направление | Message | Назначение |
|---|---|---|
| C# → JS | editor/setModel |
uri, languageId, text, version |
| C# → JS | editor/applyEdits |
edits[], expectedVersion |
| C# → JS | editor/setDecorations |
decoration sets (diagnostics, agent range, CF gutter) |
| C# → JS | editor/setTheme |
tokens из UI theme pipeline 0086 |
| JS → C# | editor/didChange |
contentChanges[], version |
| JS → C# | editor/didChangeCursorSelection |
offsets, reason |
| JS → C# | editor/ready |
handshake после load |
Source of truth (0084): v0 — C# master: push setModel / applyEdits после локальных и agent mutations; JS шлёт deltas, C# мержит и инкрементирует version. Инверсия (Monaco master) — только с отдельным ADR и тестами race.
Assets: bundled static (Assets/editor/ или wwwroot/cide-editor/), загрузка через WebView2 virtual host или file:// под контролируемым path — детали реализации, origin не third-party.
5. Фазы внедрения (strangler)
| Фаза | Объём | Критерий |
|---|---|---|
| M0 | Monaco в WebView: open/edit file, caret events | Лог + ручной smoke |
| M1 | MonacoWebViewSurfaceAdapter + [editor].forward_host |
Переключение host без падения dock |
| M2 | Diagnostics → decorations из EditorHudEngine snapshot |
Parity squiggles с AvaloniaEdit на одном файле |
| M3 | Inline inventory → Monaco (hover, inlay, agent reveal 0130) | Item-by-item из migration inventory |
| M4 | Agent applyEdits + 0084 integration tests | Version mismatch → reject, не silent corrupt |
| M5 | CF virtual spacing 0152 на Monaco gutter lane | Визуальный sign-off |
| M6 | Default flip to monaco_webview2 (optional) |
Product sign-off; ADR status → Accepted · Implemented |
Dual-path до M6: AvaloniaEdit не удаляем; regression на avalonia_edit для CI matrix optional.
6. Последствия
Положительные
- Текст, selection, completion UI, diff editor — зрелый API Monaco; снимает класс боли AvaloniaEdit без смены фюзеляжа.
- Переиспользование WebView2-инфраструктуры и паттернов 0108.
IEditorSurfaceAdapterи Editor HUD substrate получают реальную вторую реализацию — проверка абстракции.
Отрицательные / trade-offs
- Две темы (Avalonia + Monaco CSS) — генератор из канона 0086, не ручной drift.
- IPC-latency на hi-freq path — дисциплина throttle; возможен micro-jank vs native.
DockDocumentViewstrangler: AvaloniaEdit-specific renderers отмирают по inventory, не одним PR.- Windows-first (текущий
win-x64RID); Linux/macOS WebView — отдельный roadmap (0093), не блокер Proposed.
7. Отклонённые альтернативы
| Альтернатива | Почему нет |
|---|---|
| Photino-shell для всего CIDE | Снимает не ту боль; переписывает dock/terminal/Skia; тот же WebView2 IPC |
| Electron | Bundled Chromium + Node; против целей lean desktop |
| Оставить только AvaloniaEdit | Принято как default до M6; не отменяет optional Monaco |
| Monaco в MFD, не Forward | Не заменяет primary editor; только preview |
| CodeMirror 6 вместо Monaco | Допустимый spike; ADR фиксирует Monaco как первый кандидат (LSP ecosystem, diff, VS Code parity) |
8. Конфиг (sketch)
[editor]
# avalonia_edit | monaco_webview2
forward_host = "avalonia_edit"
Per-workspace override — через существующий stack settings.toml / workspace profile (детали при M1).
9. Ownership (sketch)
| Компонент | Расположение |
|---|---|
MonacoWebViewSurfaceAdapter |
Features/Editor/Application/ |
cide-editor bridge (TS) |
Assets/cide-editor/ или wwwroot/cide-editor/ |
| WebView host control | Views/ или Features/Editor/Presentation/ |
| Theme token export | рядом с 0086 pipeline |
История изменений
| Дата | Изменение |
|---|---|
| 2026-06-20 | Proposed: Monaco Forward host, WebView2 island, anti-hype IPC/memory, strangler phases |
| 2026-06-21 | Уточнение: ветка feature/monaco-forward-editor-m0 убрала Avalonia TextEditor из dock; полный перевод и bus — 0163 |