Forge
markdowndeeb25a2
1# ADR 0090: Профили запуска и несколько стартовых конфигураций отладки (как launch profiles в VS)
2
3**Статус:** Accepted · Implemented
4**Дата:** 2026-04-23
5## Связанные ADR
6
7| ADR | Роль |
8|-----|------|
9| [0002](0002-debug-human-agent-parity.md) | единый слой отладки для человека и агента |
10| [0028](0028-user-settings-toml-localappdata-and-secrets.md) | Пользовательские настройки — `settings.toml`, каталог `%LocalAppData%\CascadeIDE\`, секреты отдельно |
11| [0029](0029-configuration-toml-canonical-ui-facade.md) | Конфигурация — **TOML-first** (канон на диске); **целостный** UI настроек — **deferred**; точечный UI — **фасад канона**, не вторая правда |
12| [0093](0093-mfd-embedded-browser-for-launch-url.md) | Встроенный просмотр URL запуска на MFD (расширение к профилям и launchBrowser) |
13
14### Вне ADR
15
16| Документ | Роль |
17|----------|------|
18| [MCP-PROTOCOL.md](../MCP-PROTOCOL.md) | `debug_launch` и родственные тулы |
19| [MsBuildDebugTargetResolver.cs](../../Services/MsBuildDebugTargetResolver.cs) | MsBuildDebugTargetResolver.cs |
20
21## Резюме
22
23- **Launch profiles** и несколько стартовых конфигураций отладки (как в VS).
24- Хранение, MCP, миграция с `startup-project.json`.
25- Опциональный URL на MFD — [0093](0093-mfd-embedded-browser-for-launch-url.md).
26
27---
28## Контекст
29
30Сейчас на **одно решение** приходится **не больше одного** явного стартового проекта: путь к `.csproj` хранится в `.cascade-ide/startup-project.json` как одно поле `StartupProjectRelativePath`. F5 и интерактивный `debug_launch` резолвят **одну** цель; конфигурация MSBuild для отладки фактически зашита как **Debug** в резолвере.
31
32В Visual Studio и в SDK-проектах привычна другая модель: **несколько именованных профилей** (launch profiles) — разные проекты, конфигурации (Debug/Release/…), аргументы командной строки, рабочий каталог, переменные окружения. Разработчик переключает «текущий профиль» и жмёт F5, не переустанавливая «стартовый проект» вручную каждый раз.
33
34Без этого Cascade IDE остаётся ближе к «один старт на solution», что слабо масштабируется на монорепы, несколько исполняемых в одном `.sln` и сценарии «запусти API / консоль / тест-хост» без отдельного файлового диалога.
35
36**Веб (ASP.NET Core)** — не «потом»: типичные портальные/SPA-host решения (в т.ч. продуктовый контур **EDW.Portal**, scope `portal` в оперативной памяти) по сути **зависят** от `Properties/launchSettings.json`: Kestrel **URL** (`http://localhost:…` / `https://…`, несколько endpoints), `ASPNETCORE_ENVIRONMENT`, иногда `launchBrowser`, разные профили (`http` / `https` / IIS). Без маппинга этих полей в DAP-launch (переменные окружения процесса + при необходимости аргументы хоста) F5 в CIDE **не** совпадёт с привычным `dotnet run` / VS. Консольные exe — подмножество; **веб — обязательный** горизонт v1 согласно этому ADR (детализация полей — ниже).
37
38<a id="adr0090-decision"></a>
39
40## Решение (направление)
41
42Ввести **каталог профилей запуска** (launch profiles) в зоне workspace, с **текущим выбранным профилем**, и прогонять отладку (DAP launch) **через активный профиль**, а не через единственный `StartupProjectRelativePath`.
43
44<a id="adr0090-profile-model-v1"></a>
45
46### Минимальная модель профиля (v1)
47
48Для каждого профиля, как минимум:
49
50- **Идентификатор** — стабильное имя в пределах решения (строка; отображаемое имя может совпадать или локализоваться отдельно).
51- **Проект** — путь к `.csproj` / `.fsproj` **относительно корня «решения»** (тот же базовый каталог, что и для `BreakpointsFileService.GetWorkspaceRoot(solutionPath)`), в духе текущего store.
52- **Конфигурация MSBuild** — например `Debug` / `Release` (строка; по умолчанию `Debug` для отладки).
53- **Аргументы программы** — опционально, список строк или одна строка с правилами кавычек (уточнить при реализации).
54- **Рабочий каталог** — опционально; если пусто — наследовать правила из [IdeDapDebugSession](../../Services/IdeDapDebugSession.cs) (уже есть логика вокруг `ResolveLaunchWorkingDirectory`).
55
56- **Переменные окружения** процесса — для веба как минимум передавать/мерджить с тем, что приходит из профиля (часто `ASPNETCORE_ENVIRONMENT=Development` и кастомные ключи). Реализация: env в DAP `launch` (расширение [IdeDapDebugSession](../../Services/IdeDapDebugSession.cs), если сейчас нет), без «тихого» отбрасывания.
57
58<a id="adr0090-aspnet-v1"></a>
59
60### ASP.NET Core / веб (v1, не откладывать)
61
62Профиль должен уметь выражать то, что **уже** в `launchSettings.json` для `commandName: Project` (Kestrel):
63
64- **`applicationUrl`** — одна или несколько привязок (строка с `;` как в шаблоне SDK, либо массив URL в TOML); при запуске подставляется в окружение так же, как делает `dotnet` (типично `ASPNETCORE_URLS` или согласованный с хостом способ — уточнить при реализации по `dotnet` / hosts).
65- **`launchBrowser`** — опционально; при `true` открытие URL после старта (если в CIDE появляется обёртка; иначе зафиксировать «deferred / v2» явно, но не молчать).
66- **Раздельные профили** вроде `http` / `https` — несколько именованных записей в TOML, как в `launchSettings.profiles`, с импортом 1:1 по именам, где возможно.
67
68**IIS Express** (`commandName: IISExpress`) и полный паритет с VS для IIS — **может** оказаться отдельной фазой (другой процесс, другой путь к рабочему каталогу); в ADR зафиксировать **минимум**: Kestrel + `Project` — baseline для веб v1, IIS — либо «best effort», либо отдельный тикет после baseline.
69
70**Импорт:** при чтении `Properties/launchSettings.json` веб-проекта схема TOML в `.cascade-ide` должна **сохранять семантику** URL и env, чтобы сценарии вроде портала не ломались относительно `dotnet run --launch-profile …`.
71
72<a id="adr0090-storage"></a>
73
74### Хранение
75
76- **Каноничный формат: TOML**, не JSON — например `.cascade-ide/launch-profiles.toml` (плюс ключ/секция версии схемы, напр. `version = 1`). Такая же философия, что и пользовательский/канонический конфиг в IDE ([0028](0028-user-settings-toml-localappdata-and-secrets.md), [0029](0029-configuration-toml-canonical-ui-facade.md)): **читаемость, комментарии, один стиль** с `settings` / `workspace` рядом с репозиторием.
77- **Один файл** на открытое решение (путь к `.sln` / standalone `.csproj` — как сейчас для брейкпоинтов и startup): в нём и **список профилей**, и **активный** профиль (`active_profile` / аналог — уточнить при реализации), без второго файла, чтобы не рассинхронизировать.
78- **JSON** (`Properties/launchSettings.json`) остаётся **внешним** де-факто стандартом SDK/VS — не дублировать его как основной канон в `.cascade-ide`, а **импортировать/экспортировать** в TOML-модель (маппинг полей, см. «Согласование с .NET»).
79
80**Миграция:** если существует только `startup-project.json`, при первом чтении построить **один** профиль по умолчанию (имя вроде `Default` / из имени проекта), выставить его активным, записать `launch-profiles.toml`, старый JSON оставить как совместимость до явного удаления (strangler).
81
82<a id="adr0090-ui"></a>
83
84### UI
85
86- Видимый **селектор текущего профиля** (toolbar или полоса у обозревателя / баннер отладки) — **keyboard-first** согласованно с [0013](0013-command-surface-and-discoverability.md).
87- Команды: «управление профилями» (добавить/удалить/дублировать) — MFD или модалка по объёму ([0074](0074-settings-ui-mfd-compact-layout-overflow.md) как политика нехватки места).
88- F5 / «запустить отладку» используют **активный профиль**, без диалога выбора `.dll`, если резолв успешен (согласуется с паритетом [0002](0002-debug-human-agent-parity.md)).
89
90<a id="adr0090-mcp-parity"></a>
91
92### Паритет агента (MCP / IdeCommands) — контракт v1
93
94Контракт запуска отладки фиксируется на уровне `IdeCommands.DebugLaunch` и `MCP-PROTOCOL`:
95
96- Команда: `debug_launch`.
97- Режим A (явная цель): `workspace_path` + `target_path` (как сейчас, backward compatible).
98- Режим B (профиль): `profile_name` (опционально) + контекст открытого workspace/solution.
99 - если `profile_name` не задан, используется `active_profile`;
100 - если профиль не найден — явная ошибка контракта (не молчаливый fallback на «случайный» startup).
101- Доп. параметры остаются: `netcoredbg_path`, `program_args`.
102- При одновременной передаче `target_path` и `profile_name` приоритет у `target_path` (явный путь агента сильнее профиля).
103
104Это позволяет человеку и агенту использовать один смысл F5/Launch: «запуск по активному профилю», а для точечных сценариев сохраняется прямой запуск по `target_path`.
105
106<a id="adr0090-dotnet-alignment"></a>
107
108### Согласование с .NET
109
110- **Опциональный импорт** из `Properties/launchSettings.json` (после v1) — уменьшить трение для проектов, уже настроенных под `dotnet` / VS. Канон по-прежнему **TOML в `.cascade-ide`**; с **стандартным** `launchSettings` обеспечивается **семантическая совместимость** (маппинг полей), а не побитовая идентичность одного файла.
111- По желанию **экспорт** профиля обратно в форму, близкую к `launchSettings`, для совместимости с другими инструментами — без обязательности.
112
113<a id="adr0090-build-resolve"></a>
114
115### Резолв сборки
116
117- [MsBuildDebugTargetResolver](../../Services/MsBuildDebugTargetResolver.cs): передавать **конфигурацию** из профиля (`-p:Configuration=...`), а не только константу `Debug`, когда источник истины — активный профиль.
118
119<a id="adr0090-consequences"></a>
120
121## Последствия
122
123- Потребуется рефакторинг `MainWindowViewModel` / `StartupProjectStore` в сторону **модели «набор + активный»**; старые API — strangler.
124- Тесты: парсинг TOML, миграция с одного `startup-project.json`, импорт **веб-**`launchSettings` (см. пример в репо: [OpenVoiceTts.Service launchSettings.json](../../../voice-tts/OpenVoiceTts.Service/Properties/launchSettings.json) — `applicationUrl`, `environmentVariables`), сценарий F5: консоль + **Kestrel** с валидным URL.
125- Документация для пользователя (User Guide) — продуктовый слой, не обязательный объём самого ADR (см. [README](README.md) про User Guide).
126
127<a id="adr0090-rejected"></a>
128
129## Отклонённые / отложенные альтернативы
130
131- **Только** читать `launchSettings.json` и не иметь собственного файла — отклонено как хуже для MVP паритета IDE (монорепы, пути относительно solution, и агенту нужен стабильный контракт в `.cascade-ide` рядом с брейкпоинтами).
132- **Несколько параллельных отладок** в одной IDE — вне scope этого ADR (остаётся одна DAP-сессия, как сейчас, если иное не зафиксировано отдельно).
133
134<a id="adr0090-implementation-status"></a>
135
136## Статус внедрения
137
138- Канон хранения: `.cascade-ide/launch-profiles.toml`, миграция из `startup-project.json`, `MsBuildDebugTargetResolver` с конфигурацией из профиля, DAP `launch` с `env` и опциональным cwd, `debug_launch` с `profile_name` и явными ошибками контракта; тесты `LaunchProfilesStoreTests`, документация `IdeCommands` / `MCP-PROTOCOL.md`.
139
140<a id="adr0090-implementation-checklist"></a>
141
142## Implementation checklist (из решения в код)
143
1441. Ввести `.cascade-ide/launch-profiles.toml` (список профилей + `active_profile`) и миграцию из `startup-project.json`.
1452. Обновить резолв отладки: `MsBuildDebugTargetResolver` получает `Configuration` из профиля (не только `Debug`).
1463. Обновить `debug_launch` pipeline:
147 - поддержка `profile_name`,
148 - однозначные ошибки (`profile_not_found`, `active_profile_missing`, `profile_target_unresolved`),
149 - совместимость с текущим `workspace_path + target_path`.
1504. Синхронизировать документацию:
151 - XML-doc `IdeCommands.DebugLaunch`,
152 - `docs/MCP-PROTOCOL.md` (сгенерированный блок),
153 - при необходимости ADR-индекс/ссылки.
1545. Test plan (минимум):
155 - консольный проект: профили `Debug`/`Release` с разными аргументами;
156 - ASP.NET Core (Kestrel): импорт `applicationUrl`/env и запуск по профилю;
157 - негатив: отсутствующий профиль и неразрешимая цель дают явную ошибку.
158
View only · write via MCP/CIDE