Forge

docs/ / adr/0162-monaco-forward-editor-webview2-host.md · branch develop

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»): часто смешивают три разных тезиса:

  1. OS WebView легче упаковки Electron — верно;
  2. «C# и JS в одном address space», «zero-latency IPC» — неверно для WebView2 (renderer out-of-process);
  3. «30–40 МБ на IDE» — нереалистично для Monaco + нескольких поверхностей; память уходит в процессы Edge/WebView2, а не исчезает.

Photino-shell (весь UI в web) не требуется, чтобы снять боль редактора: достаточно Monaco-island в уже принятом WebView2 (Avalonia.Controls.WebView / NativeWebView, см. 0108).


2. Решение

2.1 Направление

  1. Ввести MonacoWebViewSurfaceAdapter — реализация IEditorSurfaceAdapter поверх Monaco Editor во встроенном WebView2 в слоте DockDocumentView (Forward), без миграции всего CIDE на Photino.

  2. Avalonia остаётся фюзеляжом: dock, окна, terminal, Skia-острова (Intercom, cockpit), MFD — без изменения 0044 / 0123.

  3. Strangler dual-path (0009): конфиг [editor].forward_host = avalonia_edit (default) | monaco_webview2. Переключатель на уровне workspace или глобально в settings.toml; без silent fallback между хостами на одном документе.

  4. 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.
  • DockDocumentView strangler: AvaloniaEdit-specific renderers отмирают по inventory, не одним PR.
  • Windows-first (текущий win-x64 RID); 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
View only · write via MCP/CIDE