Forge
markdowndeeb25a2
1# ADR 0028: Пользовательские настройки — `settings.toml`, каталог `%LocalAppData%\CascadeIDE\`, секреты отдельно
2
3**Статус:** Accepted · Implemented
4**Дата:** 2026-04-08
5**Обновлено:** 2026-04-13 — LSP-пресеты в `settings.toml` ([0040](0040-lsp-launch-line-settings-toml-presets-and-environment.md)). Подробности — [§ История](#adr0028-history).
6
7## Связанные ADR
8
9| ADR | Роль |
10|-----|------|
11| [0010](0010-ui-modes-toml-configuration.md) | TOML для **бандла режимов** и **репозиторного** `workspace.toml` — другой слой, не путать с пользовательским файлом |
12| [0013](0013-command-surface-and-discoverability.md) | `hotkeys.toml` рядом с `settings.toml` — задумано, не обязательно реализовано |
13| [0026](0026-markdown-preview-surfaces-and-placement.md) | часть пресетов в **merged** `workspace.toml`; пользовательский override размещения — не только `settings.toml` |
14| [0027](0027-small-team-focus-vs-public-maturity.md) | предсказуемые пути конфигурации |
15| [0029](0029-configuration-toml-canonical-ui-facade.md) | TOML как канон; UI — фасад над тем же файлом |
16| [0017](0017-multi-window-workspace-and-agent-surfaces.md) | `presentation` — прежде всего **`settings.toml`**, не репо |
17| [0040](0040-lsp-launch-line-settings-toml-presets-and-environment.md) | C#/Markdown LSP: пресеты, опциональные ключи `executable`/`arguments`, опционально окружение |
18
19### Снимок реализации
20
21| Элемент | Значение |
22|---------|----------|
23| Сервис | `SettingsService` |
24| Каталог | `%LocalAppData%\CascadeIDE\` |
25| Настройки | `settings.toml` (Tomlyn, snake_case) |
26| Секреты | `ai-keys.toml` (отдельно от настроек) |
27
28## Резюме
29
30- Пользовательский канон: **`%LocalAppData%\CascadeIDE\settings.toml`** (Tomlyn).
31- Секреты — **`ai-keys.toml`**, не в основном файле настроек.
32- Отдельно от бандла `UiModes/` и merge `.cascade/workspace.toml` ([0010](0010-ui-modes-toml-configuration.md)).
33- LSP-пресеты — [0040](0040-lsp-launch-line-settings-toml-presets-and-environment.md).
34
35---
36## Контекст
37
38В продукте уже есть **несколько слоёв** конфигурации: шипнутый бандл `UiModes/`, merge с `.cascade/workspace.toml` в открытом репозитории ([0010](0010-ui-modes-toml-configuration.md)), глобальные пользовательские предпочтения (AI, MCP, LSP, видимость панелей, локаль UI и т.д.). При этом **отдельного ADR**, который фиксирует **именно пользовательский** канал (путь на диске, формат, что куда кладём), не было — ссылки размазаны по [0010](0010-ui-modes-toml-configuration.md), [0015](0015-editor-toml-syntax-highlighting.md), UX-докам.
39
40Нужна **одна точка канона**: где лежит «мой компьютер», что в TOML, что нельзя класть в TOML, как соотносится с репозиторным слоем.
41
42---
43
44## Решение
45
46### 1. Каталог пользовательских данных CascadeIDE
47
48- **Базовый путь:** `%LocalAppData%\CascadeIDE\` (через `Environment.SpecialFolder.LocalApplicationData` + сегмент `CascadeIDE`).
49- Каталог **создаётся** при первом обращении, если отсутствует (`SettingsService.GetSettingsDirectory()`).
50- Этот каталог — **не** каталог решения и **не** `AppContext.BaseDirectory`; он **привязан к пользователю Windows** и установке приложения на машине.
51
52### 2. Основной файл настроек: `settings.toml`
53
54- **Полный путь:** `%LocalAppData%\CascadeIDE\settings.toml`.
55- **Модель:** `CascadeIdeSettings` — единственный источник правды по **набору полей** и смыслам (AI-провайдеры, MCP, LSP C#/Markdown, Kroki, видимость панелей, `UiMode`, локаль UI и т.д.).
56- **Сериализация:** Tomlyn через `CascadeTomlSerializer`: ключи в файле — **snake_case**, свойства C# — PascalCase (`TomlSerializerOptions` с `JsonNamingPolicy.SnakeCaseLower`).
57- **Загрузка:** при старте `SettingsService.Load()`; при ошибке чтения/парсинга — **модель по умолчанию** из кода, без падения IDE.
58- **Сохранение:** `SettingsService.Save(CascadeIdeSettings)` — перезапись целого файла; ошибки записи **глотаются** (текущая политика реализации — не блокировать UI).
59
60**До публичного релиза:** не наращивать в `SettingsService` автоматические миграции при переименовании/переносе ключей TOML — см. подраздел **«До публичного релиза»** в [корневом README](../../README.md#до-публичного-релиза). После появления массовых установок — отдельное решение (версия файла, одноразовый мигратор, changelog).
61
62### 3. Исторически: JSON больше не поддерживается
63
64- Ранее в коде была однократная миграция **`settings.json` → `settings.toml`**; по состоянию на принятие этого ADR **поддерживаемых старых установок нет**, ветка миграции **удалена** из `SettingsService.Load()`.
65- **Канон** — только **`settings.toml`**; при отсутствии файла — merge заводских дефолтов из встроенного **`Settings/defaults-settings.toml`** (EmbeddedResource), затем пользовательский overlay. Пользовательский **`settings.json`** в `%LocalAppData%\CascadeIDE\` **не** читается (если файл остался вручную — его нужно перенести в TOML самостоятельно или удалить).
66
67### 4. Секреты: не в `settings.toml`
68
69- **API-ключи** (Anthropic, OpenAI, DeepSeek и т.п.) хранятся в **`%LocalAppData%\CascadeIDE\ai-keys.toml`**, отдельная модель `AiKeys`, сериализация через **`CascadeTomlSerializer`** (как у `settings.toml`: ключи в файле — **snake_case**), `AiKeysStorage.Load` / `Save`.
70- **Причины разделения:** не светить секреты в том же файле, что удобно копировать/показывать в логах; проще политика бэкапа и `.gitignore` для пользователя; соответствует направлению [0013](0013-command-surface-and-discoverability.md) (не смешивать всё в одном «комке»). Формат **TOML**, а не отдельный JSON — один стек сериализации с пользовательскими настройками.
71- **Не коммитить** `ai-keys.toml`; в документации для разработчиков предполагается только локальная машина. Файл **`ai-keys.json`** не читается (если остался руками — перенести в TOML или удалить).
72
73### 5. Что этот ADR *не* описывает (явное разграничение с [0010](0010-ui-modes-toml-configuration.md))
74
75| Слой | Где | Назначение |
76|------|-----|------------|
77| Пользователь | `%LocalAppData%\CascadeIDE\settings.toml` | Предпочтения **пользователя** на этой машине (модель `CascadeIdeSettings`). |
78| Бандл приложения | `UiModes/` рядом с exe | Режимы UI, индекс, **шипнутый** `workspace.toml` бандла. |
79| Репозиторий | `<solution>/.cascade/workspace.toml` | Overlay команды/проекта поверх бандла (merge в [0010](0010-ui-modes-toml-configuration.md)). |
80
81#### Имя `workspace.toml`: один контракт merge, не «два смысла» — и где файла нет
82
83- **Хром и пресеты режимов ([0010](0010-ui-modes-toml-configuration.md)):** одна модель данных (`UiWorkspaceToml`), два **источника** одного имени файла — шипнутый **`UiModes/workspace.toml`** и при открытом решении опционально **`<repo>/.cascade/workspace.toml`**. Это **цепочка merge** (бандл → overlay репо), а не два разных продукта с одним именем.
84- **`%LocalAppData%\CascadeIDE\`:** файла **`workspace.toml` нет** и в текущем каноне **не задуман** — глобальные пользовательские настройки живут в **`settings.toml`**. Типичная путаница при чтении доков: искать «user workspace» рядом с `settings.toml` под тем же именем.
85
86**Переименование** `workspace.toml` в бандле/репо (например в `ui-workspace.toml`) **не делаем** только ради уникальности имени на диске: затронет сборку, merge, ключи в [0026](0026-markdown-preview-surfaces-and-placement.md), примеры и ожидания «workspace = раскладка IDE». Если когда-то понадобится — **отдельный ADR** + миграция путей и версии бандла.
87
88Состояние, привязанное к **конкретному решению** (например выбранный стартовый проект для отладки: `Services/StartupProjectStore` → `<каталог .sln>/.cascade-ide/startup-project.json`), **не** лежит в `%LocalAppData%\CascadeIDE\` — это отдельный канал «рядом с репо», не глобальные пользовательские настройки.
89
90### 6. Будущие файлы в том же каталоге
91
92- **`hotkeys.toml`** — по намерению [0013](0013-command-surface-and-discoverability.md), рядом с `settings.toml`, только переопределения; до реализации этот ADR не обязует их наличие.
93- Раскладка по **физическим дисплеям** (`presentation` / `zone_screen_layout` и токены грамматики по [0017](0017-multi-window-workspace-and-agent-surfaces.md)) — **персональный** слой, **прежде всего** поля в **`settings.toml`**, а не обязательство команды через репозиторный `workspace.toml` ([0017 § слой хранения](0017-multi-window-workspace-and-agent-surfaces.md#adr0017-presentation-grammar)).
94- Дополнительные пользовательские файлы (например состояние окон по [0017](0017-multi-window-workspace-and-agent-surfaces.md)) — **отдельным ADR** при появлении договорённости, с явной привязкой к этому каталогу или к новому ключу в `settings.toml`.
95
96---
97
98## Последствия
99
100- Документация и агенты: при слове «настройки пользователя» — путь к **`settings.toml`** и модель **`CascadeIdeSettings`**; при «секретах API» — **`ai-keys.toml`**.
101- Новые поля в пользовательских настройках добавляются в **`CascadeIdeSettings`** + при необходимости UI/сохранение; при смене смысла слоя — **обновлять этот ADR** или ссылаться на новый.
102- Тесты могут подменять загрузку через существующие механизмы или экземпляры модели без записи на диск — без изменения канона путей.
103
104---
105
106## Отклонённые альтернативы
107
108- **Держать пользовательские настройки в JSON как основной формат** — отклонено: канон — **TOML**; автоматическая миграция с `settings.json` **снята** с кода при отсутствии поддерживаемых legacy-профилей.
109- **Хранить API-ключи в `settings.toml`** — отклонено: смешение секретов с переносимым/редактируемым конфигом и риск утечки при обмене файлами.
110- **Держать секреты в отдельном JSON (`ai-keys.json`)** — отклонено в пользу **`ai-keys.toml`**: единый формат с `settings.toml` и тот же `CascadeTomlSerializer`; отдельный файл по-прежнему изолирует секреты от «обычного» конфига.
111- **Один ADR на все TOML** — отклонено: [0010](0010-ui-modes-toml-configuration.md) остаётся про режимы и merge; пользовательский файл — отдельный контракт пути и содержимого.
112- **Переименовать `workspace.toml` в бандле/репо только из‑за совпадения имени с ожиданиями** — отклонено без отдельного ADR и миграции (см. §5.1).
113
114---
115
116## История изменений
117
118<a id="adr0028-history"></a>
119
120| Дата | Изменение |
121|------|-----------|
122| 2026-04-08 | Канон: `settings.toml`, каталог LocalAppData; `workspace.toml` в merge-слое ([0010](0010-ui-modes-toml-configuration.md)). |
123| 2026-04-08 | Удалена миграция `settings.json` → TOML; legacy не поддерживается. |
124| 2026-04-08 | Секреты: `ai-keys.toml` вместо JSON; миграции с JSON нет. |
125| 2026-04-11 | До публичного релиза — без auto-migrate схемы ([README § До публичного релиза](../../README.md#до-публичного-релиза)). |
126| 2026-04-11 | `presentation` → [0017](0017-multi-window-workspace-and-agent-surfaces.md). |
127| 2026-04-13 | LSP в `settings.toml` → [0040](0040-lsp-launch-line-settings-toml-presets-and-environment.md). |
128
View only · write via MCP/CIDE