Forge
markdowndeeb25a2
1# ADR 0157: Magic Link `cide://` — deep link из браузера и доков в Cascade IDE
2
3**Статус:** Accepted
4**Дата:** 2026-05-28
5
6## Резюме
7
8- Кастомная схема **`cide://`** (Magic Link) позволяет с публичного сайта документации, ADR на GitHub Pages или внутреннего портала **открыть Cascade IDE**, загрузить workspace и **перейти к коду или markdown**.
9- v1 переиспользует **CodeAnchor / bracket** ([0128](0128-intercom-attachment-anchors-and-code-references.md), [0156](0156-correspondence-mfd-surface-and-reverse-code-anchors.md)) и существующие пути **`IdeMcp.GoToPosition`** / **Markdown Preview**.
10- Регистрация протокола в ОС — **opt-in** (скрипт `tools/Register-CideMagicLinkProtocol.ps1` для dev); в installer — отдельный этап.
11
12## Связанные ADR
13
14| ADR | Роль |
15|-----|------|
16| [0156](0156-correspondence-mfd-surface-and-reverse-code-anchors.md) | Bracket / CodeAnchor, CRS |
17| [0155](0155-documentation-code-correspondence-and-architectural-drift.md) | Док ↔ код |
18| [0128](0128-intercom-attachment-anchors-and-code-references.md) | `AttachmentAnchor`, bracket parse |
19| [0061](0061-context-aware-adr-map-pfd-knowledge-indicator.md) | ADR map, preview opener |
20
21---
22
23## Контекст
24
25Preview в IDE уже умеет `cascade-code-anchor:` и клик → редактор. Документация на **внешнем сайте** не может вызвать IDE без **зарегистрированного URL handler**. Аналоги: `vscode://`, `cursor://`, `jetbrains://idea/navigate/...`.
26
27Цель: ссылка в prose ADR на сайте вида «открыть в Cascade IDE» без копирования пути.
28
29---
30
31## Решение
32
33### 1. Схема и команды (v1)
34
35| Команда (`host`) | Назначение |
36|------------------|------------|
37| **`reveal`** | Открыть файл в редакторе, опционально строка / bracket |
38| **`open`** | Загрузить solution/workspace, затем опционально `reveal` |
39| **`md`** | Открыть markdown в MFD Markdown Preview, опционально scroll |
40
41Общие query-параметры:
42
43| Параметр | Обязателен | Смысл |
44|----------|------------|--------|
45| `root` | для `open` / когда workspace ещё не загружен | Абсолютный путь к **корню workspace** (каталог с `.cascade/workspace.toml` или `.sln`) |
46| `f` | для `reveal` (если нет `b`) | Repo-relative путь к файлу |
47| `l`, `le` | нет | 1-based строки |
48| `b` | альтернатива `f`+`l` | Bracket inner (URL-encoded): `F:…; M:…` или H1 |
49| `sln` | для `open` | Относительный или абсолютный путь к `.sln` / `.slnx` |
50| `doc` | для `md` | Repo-relative путь к `.md` |
51| `c` | для `md` | 1-based column (зарезервировано) |
52
53Примеры:
54
55```text
56cide://reveal?root=D:%2Frepo%2Fcascade-ide&f=Features%2FWorkspaceNavigation%2FApplication%2FDocReverseAnchorResolver.cs&l=84
57
58cide://reveal?root=D:%2Frepo%2Fcascade-ide&b=F%3AFeatures%2FWorkspaceNavigation%2FApplication%2FDocReverseAnchorResolver.cs%3B%20M%3AResolve
59
60cide://open?root=D:%2Frepo%2Fcascade-ide&sln=CascadeIDE.sln
61
62cide://md?root=D:%2Frepo%2Fcascade-ide&doc=docs%2Fadr%2F0156-correspondence-mfd-surface-and-reverse-code-anchors.md&l=120
63```
64
65На HTML-сайте рядом — fallback: обычная ссылка на GitHub + подпись «требуется Cascade IDE».
66
67### 2. Безопасность (threat model v1)
68
69| Угроза | Митигация |
70|--------|-----------|
71| Произвольное чтение файлов | `root` должен пройти **workspace validation**: каталог существует и содержит `.cascade/workspace.toml` **или** discoverable `.sln` |
72| Path traversal в `f` / `doc` | Нормализация; итоговый путь должен оставаться **под** `root` |
73| Запуск произвольных exe | Handler только на `CascadeIDE.exe`, аргумент — один URI |
74| Фишинг с поддельным `root` | Пользователь подтверждает открытие IDE; v1 без silent cross-drive |
75
76Не поддерживается в v1: `file://`, выполнение shell, произвольные MCP-команды через URI.
77
78**Публичный сайт (пока не делаем):** ссылка с **абсолютным** `root=D:\…` или `%USERPROFILE%\…` в HTML — утечка layout машины автора и почти всегда **битая** у читателя. Это не RCE, но фишинг (`root` на чужой клон) и путаница. Для сайта — только после **M3** (`workspace.id` → resolve на клиенте) или кнопка «скопировать bracket» без URI. До тех пор: GitHub fallback + opt-in dev script.
79
80### 3. Single instance
81
82| Сценарий | Поведение |
83|----------|-----------|
84| IDE не запущен, URI в argv | Старт IDE → после `MainWindow` Loaded — выполнить link |
85| IDE запущен, второй процесс с URI | **Named pipe** `CascadeIDE.MagicLink.v1` → передать URI первому процессу → второй **exit 0** |
86| IDE запущен, второй процесс без URI | Обычный второй экземпляр (не блокируем) |
87
88Реализация: `CideMagicLinkSingleInstance` + `CideMagicLinkPipeHost`.
89
90### 4. Код (v1)
91
92| Компонент | Путь |
93|-----------|------|
94| Parse | [F:Features/MagicLink/CideMagicLinkUri.cs] |
95| Execute | [F:Features/MagicLink/CideMagicLinkExecutor.cs] |
96| Single instance | [F:Features/MagicLink/CideMagicLinkSingleInstance.cs] |
97| VM hook | [F:ViewModels/MainWindowViewModel.MagicLink.cs] |
98| Startup argv | [F:Program.cs] |
99| Dev registry | [F:tools/Register-CideMagicLinkProtocol.ps1] |
100
101Цепочка `reveal` + `b`: `BracketCodeReferenceParser.TryParse` → `TryToAttachmentAnchor` → `IdeMcp.GoToPosition` (как preview code-anchor).
102
103### 5. Генерация ссылок для сайта (не IDE)
104
105Рекомендация для CI/docs build (будущее):
106
107- Шаблон из `root` = canonical clone path или placeholder `%CIDE_WORKSPACE_ROOT%` с подстановкой на машине разработчика.
108- Bracket в ADR → `cide://reveal?root=…&b=…` через тот же expander, что preview (`MarkdownCodeAnchorPreviewExpander` — только схема `cide`).
109
110---
111
112## Альтернативы (отклонены)
113
114| Альтернатива | Почему нет |
115|--------------|------------|
116| Только `vscode://` | Не открывает CRS / correspondence / Cascade MCP |
117| Custom protocol без `root` | Нельзя безопасно infer workspace на чужой машине |
118| HTTP localhost redirect | Firewall, второй сервер; хуже UX чем OS handler |
119
120---
121
122## Дорожная карта
123
124| Этап | Работа | Критерий |
125|------|--------|----------|
126| **M1** | ADR 0157 + parse + `reveal`/`open`/`md` | Клик из `Register-CideMagicLinkProtocol.ps1` открывает файл |
127| **M2** | Single-instance pipe | Второй клик не плодит окна |
128| **M3** | Docs site generator + `workspace.id` в TOML | Стабильный `root` без абсолютного пути |
129| **M4** | Installer protocol registration | Production setup |
130
131---
132
133## Статус реализации
134
135| Компонент | Статус |
136|-----------|--------|
137| ADR 0157 | **Accepted** |
138| Parse + security | **Implemented** (M1) |
139| `reveal` / `open` / `md` | **Implemented** (M1) |
140| Single-instance pipe | **Implemented** (M2) |
141| Dev protocol script | **Implemented** (M1) |
142| Docs site generator | **Deferred (M3)** — публичный сайт без `workspace.id`; не класть абсолютный `root` в HTML |
143
View only · write via MCP/CIDE