Перейти к содержанию

ADR 0086: Тема UI — канон в TOML, JSON как транспорт MCP (strangler от Themes/*.json)

Статус: Proposed
Дата: 2026-04-21

Связанные ADR

ADR Роль
0028 settings.toml, путь пользователя
0029 канон на диске, UI как фасад
0008 контракты MCP
0079 оверлеи; ортогонально цветам кистей

Вне ADR

Документ Роль
MCP-PROTOCOL.md ide_get_ui_theme, ide_set_ui_theme — JSON

Контекст

Сейчас применение палитры к Application.Resources идёт из JSON: UiThemeApply.Apply(themeJson) — тот же формат, что возвращает и принимает MCP (ide_get_ui_theme / ide_set_ui_theme). Пресеты «светлая / тёмная / …» читают файлы Themes/*.json рядом с exe или встроенный текст (UiThemeApply). Дефолты кистей также живут в App.axaml (CascadeTheme.*).

По продуктовой линии (0028, 0029) человек и репозиторий опираются на TOML как единый канон настроек. Два параллельных «источника правды» для цветов (JSON на диске + TOML для всего остального) ухудшают discoverability и паритет агент ↔ пользователь: агент правит JSON-строкой в туле, человек — не там.

Решение (намерение)

  1. Канон для человека и для репо: описание темы UI (кисти CascadeTheme.*, совместимые с UiThemeApply.Keys) — прежде всего в пользовательском settings.toml (или согласованное имя секции, например [ui_theme] с плоскими или вложенными ключами под те же семантические группы, что в JSON сегодня: main_window, editor, menu, …). Комментарии в файле — часть DX, не отдельный «секретный» JSON.

  1. JSON не исчезает как контракт MCP: ide_get_ui_theme / ide_set_ui_theme остаются транспортом для агента: на чтении — сериализация resolved темы (merge дефолтов + TOML + опциональные оверлеи); на записи — применение того же merge-пайплайна, что и при сохранении TOML из UI. Так паритет «агент на равных» сохраняется без обязанности человеку руками редактировать JSON.

  1. Strangler: файлы Themes/*.json и встроенные пресеты — временные источники дефолтов до переноса пресетов во встроенный TOML/ресурсы или генерации из одной таблицы; новые кисти (например палитра команд) сначала попадают в App.axaml и в схему TOML, а не только в отдельный JSON без ключа в UiThemeApply.

  1. Реализация по этапам: (а) парсер секции TOML → тот же внутренний словарь, что сейчас строится из JSON, → UiThemeApply.Apply без дублирования логики Set(res, key, hex); (б) загрузка при старте: merge App.axaml → пресет → settings.toml [ui_theme]; (в) меню «Тема» и MCP вызывают один сервис; (г) документация MCP: «канон на диске — TOML; JSON — снимок».

Последствия

  • Один взгляд в settings.toml — видно и AI-режим, и палитру; меньше вопросов «где поменять фон».
  • MCP-агенты продолжают работать через JSON без смены семантики ответа ide_get_ui_theme.
  • Потребуется миграция/совместимость: при наличии только старых Themes/*.json — поведение как сейчас, пока пользователь не сохранит тему в TOML.

Отклонённые / отложенные альтернативы

  • Только JSON как канон — противоречит 0029 для пользовательских предпочтений; оставить только как wire-формат.
  • Ломать MCP и заменить на TOML-строку в теле тула в одном шаге — высокий налог на агентов и скрипты; не делаем без версии протокола.

Открытые вопросы

  • Точная форма секции TOML: плоская ui_theme.editor_background vs вложенные таблицы [ui_theme.editor] / background — согласовать с snake_case и merge из 0028.
  • Нужен ли явный ui_theme.preset = "dark" при частичном оверлее полей.
  • Версионирование ответа ide_get_ui_theme (если добавится поле canonical_path: settings.toml) — по необходимости вне этого ADR.