Forge
csharp4405de34
1using System.Text.Json;
2
3namespace CascadeIDE.Services;
4
5/// <summary>
6/// Callbacks from IDE MCP server into the application (UI/ViewModel).
7/// </summary>
8public interface IIdeMcpActions
9{
10 /// <summary>Выполнить команду по коду (IdeCommands). args — аргументы в том же формате, что у соответствующих тулов. Унифицированный вход для MCP и будущих меню/хоткеев. Реализация в главном окне маршалит на UI-поток.</summary>
11 Task<string> ExecuteCommandAsync(string commandId, IReadOnlyDictionary<string, JsonElement>? args, CancellationToken cancellationToken = default);
12
13 void OpenFile(string path);
14 /// <summary>Загрузить решение (.sln / .slnx / .slnf), один проект (.csproj / .fsproj) или каталог — дерево в обозревателе обновится (fire-and-forget на UI, для меню).</summary>
15 void LoadSolution(string path);
16
17 /// <summary>То же, что <see cref="LoadSolution"/>, но дожидается <c>LoadSolutionAsync</c> и возвращает <c>OK</c> или текст ошибки (для MCP <c>load_solution</c>).</summary>
18 Task<string> LoadSolutionAndWaitAsync(string path, CancellationToken cancellationToken = default);
19 /// <summary>Выделить диапазон в редакторе (1-based line/column). Если файл не открыт — открыть.</summary>
20 void SelectInEditor(string? filePath, int startLine, int startColumn, int endLine, int endColumn);
21 /// <summary>Текущее состояние редактора (файл, каретка, выделение, content_length, is_empty, content_preview). JSON. maxPreviewChars: 0 = без превью, null/2000 = первые 2000 символов.</summary>
22 Task<string> GetEditorStateAsync(int? maxPreviewChars = null);
23 /// <summary>Содержимое редактора по строкам (1-based). JSON: file_path, start_line, end_line, content.</summary>
24 Task<string> GetEditorContentRangeAsync(int startLine, int endLine);
25 /// <summary>Полный текст открытой вкладки из модели документа. JSON: file_path, length, truncated, is_dirty, text; или error. filePath null — текущий файл; maxChars — опциональная обрезка.</summary>
26 Task<string> GetOpenDocumentTextAsync(string? filePath, int? maxChars);
27 /// <summary>Применить правку: заменить диапазон (1-based). Открывает файл при необходимости; любая открытая вкладка.</summary>
28 Task<string> ApplyEditAsync(string filePath, int startLine, int startColumn, int endLine, int endColumn, string newText);
29 /// <summary>Прочитать текст файла workspace с диска. JSON.</summary>
30 Task<string> ReadWorkspaceFileAsync(string filePath, int? offset, int? limit, int? maxChars);
31 /// <summary>Сохранить на диск (буфер вкладки или content). JSON.</summary>
32 Task<string> SaveDocumentAsync(string? filePath, string? content);
33 /// <summary>Перейти на позицию (и опционально выделить до end). Если файл не открыт — открыть.</summary>
34 void GoToPosition(string? filePath, int line, int column, int? endLine = null, int? endColumn = null);
35 void RevealEditorRange(string? filePath, int startLine, int endLine, int? durationMs);
36 /// <summary>Информация о решении и открытом файле. JSON.</summary>
37 string GetSolutionInfo();
38 /// <summary>Список файлов в дереве решения (обозреватель). JSON: file_entries [{ path, title }]. Выполняется в UI-потоке.</summary>
39 Task<string> GetSolutionFilesAsync();
40 /// <summary>Поиск текста по корню workspace через внешний <c>rg</c> (ripgrep). JSON: matches [{ path, line_number, line_text }], truncated, error?.</summary>
41 Task<string> SearchWorkspaceTextAsync(string pattern, string? subPath, bool fixedString, string? glob, int maxMatches, string? rgPath);
42 /// <summary>Краткая справка из интернета (HTTPS, DuckDuckGo Instant Answer: abstract, связанные темы; без API-ключа). Запрос уходит на duckduckgo.com. JSON: query, heading, abstract_text, abstract_url, answer?, related_topics[], backend, note? | offline_or_error.</summary>
43 Task<string> SearchWebPublicQueryAsync(string query, CancellationToken cancellationToken = default);
44 /// <summary>Загрузить публичный HTTPS-документ по URL, вернуть тело как читаемый текст (HTML упрощён). JSON: url, resolved_url, text, extraction, лимиты. Только https; блок частных хостов — базовый SSRF-фильтр.</summary>
45 Task<string> FetchWebPublicUrlAsync(string url, int? maxChars, CancellationToken cancellationToken = default);
46 /// <summary>Диагностики текущего открытого .cs файла (ошибки/предупреждения Roslyn). JSON: массив { id, message, severity, line, column }. Не-C# — [].</summary>
47 Task<string> GetCurrentFileDiagnosticsAsync();
48 /// <summary>Семантическая навигация (ADR 0039, CNC): режим <c>related</c> — список связанных файлов; <c>subgraph</c> — узлы и рёбра с капами. В JSON subgraph опционально <c>graph_kind</c> (<c>code_intent_code_navigation_map</c> | <c>related_files</c> | <c>repository_module_tree</c>, ADR 0065; устар. <c>code_intent_semantic_map</c> — принимается). Без <c>file_path</c> — якорь = текущий файл. Опционально <c>preset</c> (имя из <c>settings.toml</c> секции <c>[code_navigation]</c>), <c>include_kinds</c> / <c>exclude_kinds</c>; <c>level</c> (file/controlFlow) — override уровня карты на один вызов. JSON.</summary>
49 Task<string> GetCodeNavigationContextAsync(string mode, string? filePath, int? line, int? column, int? maxRelated, int? maxNodes, int? maxEdges, string? preset, IReadOnlyList<string>? includeKinds, IReadOnlyList<string>? excludeKinds, string? level);
50 /// <summary>Запустить сборку решения, вернуть вывод.</summary>
51 Task<string> BuildAsync();
52 /// <summary>Запустить сборку и вернуть структурированный результат: success, exit_code, errors[], warnings[], raw_output (обрезано). JSON.</summary>
53 Task<string> BuildStructuredAsync();
54 /// <summary>Запустить тесты решения (dotnet test) и вернуть структурированный результат: success, total, passed, failed, skipped, failed_tests[] (name, message?, duration_ms?). JSON.</summary>
55 Task<string> RunTestsAsync();
56 /// <summary>Запустить затронутые тесты (по переданным путям) или fallback на полный прогон. JSON: success, total, passed, failed, skipped, failed_tests[], mode, filter.</summary>
57 Task<string> RunAffectedTestsAsync(IReadOnlyList<string>? changedPaths = null);
58 /// <summary>Запустить code cleanup через dotnet format для решения. Опционально includePath — конкретный файл/путь для точечной чистки. JSON: success, exit_code, raw_output.</summary>
59 Task<string> RunCodeCleanupAsync(string? includePath = null);
60 /// <summary>Посчитать метрики кода (LOC, классы, методы, cyclomatic complexity) для current_file/file/path/solution. JSON.</summary>
61 Task<string> GetCodeMetricsAsync(string? scope = null, string? path = null);
62 /// <summary>Одна сводка состояния IDE: solution/current file/selection/debug/build output/diagnostics. JSON.</summary>
63 Task<string> GetIdeStateAsync();
64 /// <summary>Только CDS (<c>CockpitSurfaceState</c>): тот же JSON, что поле <c>cockpit_surface</c> в <see cref="GetIdeStateAsync"/>.</summary>
65 Task<string> GetCockpitSurfaceAsync();
66 /// <summary>Диагностика загрузки UI-режимов (UiModes TOML vs встроенный список, Flight в меню). JSON.</summary>
67 Task<string> GetUiModesDiagnosticsAsync();
68 /// <summary>Git status в каталоге решения/workspace. JSON с short/branch/output.</summary>
69 Task<string> GitStatusAsync();
70 /// <summary>Git diff в каталоге решения/workspace. Опционально path, staged. JSON.</summary>
71 Task<string> GitDiffAsync(string? path = null, bool staged = false);
72 /// <summary>Git commit в каталоге решения/workspace: message обязателен, paths опциональны (иначе add -A). JSON.</summary>
73 Task<string> GitCommitAsync(string message, IReadOnlyList<string>? paths = null);
74 /// <summary>Git push в каталоге решения/workspace. Опционально remote/branch; dry_run — <c>git push --dry-run</c>. JSON.</summary>
75 Task<string> GitPushAsync(string? remote = null, string? branch = null, bool dryRun = false);
76 /// <summary>Git log (--oneline). Опционально n (число коммитов). JSON.</summary>
77 Task<string> GitLogAsync(int n = 20);
78 /// <summary>Git fetch. Опционально remote, all, prune; dry_run — <c>git fetch --dry-run</c>. JSON.</summary>
79 Task<string> GitFetchAsync(string? remote = null, bool all = false, bool prune = false, bool dryRun = false);
80 /// <summary>Git pull. Оба remote и branch или ни одного; ff_only по умолчанию true; dry_run — <c>git pull --dry-run</c> (Git 2.27+). JSON.</summary>
81 Task<string> GitPullAsync(string? remote = null, string? branch = null, bool ffOnly = true, bool dryRun = false);
82 /// <summary>Git branch: list | create | delete. JSON.</summary>
83 Task<string> GitBranchAsync(string? action = null, string? name = null, string? startPoint = null, bool force = false);
84 /// <summary>Git show. rev обязателен. JSON.</summary>
85 Task<string> GitShowAsync(string rev, string? path = null, bool statOnly = false);
86 /// <summary>Git submodule: status | update. JSON.</summary>
87 Task<string> GitSubmoduleAsync(string? action = null, string? path = null, bool recursive = true);
88 /// <summary>Git preflight: классификация изменений на semantic/whitespace/eol/bom + untracked. JSON.</summary>
89 Task<string> GitPreflightAsync(bool staged = false, bool includeUntracked = true, bool includePatches = true);
90 /// <summary>Git preflight safe-fix: apply renormalize и вернуть обновлённую классификацию. JSON.</summary>
91 Task<string> GitPreflightFixSafeAsync(bool includePatches = true);
92 /// <summary>Текущий текст панели «Вывод сборки» и цвета её оформления (background, foreground). JSON. Чтобы агент видел содержимое панели.</summary>
93 string GetBuildOutput();
94 void SetBreakpoint(string filePath, int line, string? condition = null);
95 void RemoveBreakpoint(string filePath, int line);
96 void ShowPreview(string title, string content);
97 /// <summary>Показать превью текущего файла из редактора в отдельном окне. Контент берётся из IDE, не передаётся по MCP — удобно для длинных .md.</summary>
98 void ShowEditorPreview();
99 Task<string> RequestConfirmationAsync(string message, CancellationToken cancellationToken = default);
100 void FocusEditor();
101 /// <summary>Параметры темы UI (цвета, фоны, кнопки, шрифты). JSON.</summary>
102 string GetUiTheme();
103 /// <summary>Применить тему UI из JSON (тот же формат, что get_ui_theme). Выполняется в UI-потоке. Возвращает "OK" или сообщение об ошибке (например, невалидный JSON).</summary>
104 Task<string> SetUiThemeAsync(string themeJson);
105 /// <summary>Дерево элементов UI: тип, имя, видимость, границы (x,y,w,h), контент, дочерние. JSON. Вызов на UI-потоке.</summary>
106 Task<string> GetUiLayoutAsync();
107 /// <summary>Цвета фона и текста под текущим курсором мыши. JSON: type, name, background, foreground (hex). Вызов на UI-потоке.</summary>
108 Task<string> GetColorsUnderCursorAsync();
109 /// <summary>Эффективный вид любого контрола: тип, имя, bounds, visible, content, background, foreground, border, font. Без name — под курсором; с name — поиск по имени в дереве. Вызов на UI-потоке.</summary>
110 Task<string> GetControlAppearanceAsync(string? name);
111 /// <summary>Применить к контролу параметры layout на лету (margin, grid_row/column, canvas_left/top, dock). JSON. Вызов на UI-потоке.</summary>
112 Task<string> SetControlLayoutAsync(string controlName, string layoutJson);
113 /// <summary>Добавить контрол в конец Children панели (только Debug-сборка). parent_name — имя Panel, control_type — Button|TextBlock|Border, content — текст, name — опционально.</summary>
114 Task<string> AddControlAsync(string parentName, string controlType, string? content, string? name);
115 /// <summary>Установить текст в контрол с вводом (TextBox и т.п.) по имени. Вызов на UI-потоке.</summary>
116 Task<string> SetControlTextAsync(string controlName, string text);
117 /// <summary>Клик по контролу: без name — под курсором (должен быть Button); с name — по имени. Вызов на UI-потоке.</summary>
118 Task<string> ClickControlAsync(string? controlName);
119 /// <summary>Отправить сочетание клавиш в эффективный контрол (под курсором или по name). keys — текст вида Ctrl+Enter, Alt+F4. Вызов на UI-потоке.</summary>
120 Task<string> SendKeysAsync(string? controlName, string keys);
121 /// <summary>Выбрать сообщение в чате по индексу (0-based, полный ChatMessages) для сценариев MCP/агента.</summary>
122 Task<string> SelectChatMessageAsync(int index);
123 /// <summary>Выбрать по номеру gutter (1-based) в активной detail-ветке; <paramref name="endOrdinal"/> — конец диапазона (активным станет он).</summary>
124 Task<string> SelectChatMessageByOrdinalAsync(int ordinal, int endOrdinal);
125 /// <summary>Получить выбранное сообщение чата в JSON (глобальный индекс + feed_ordinal в ветке).</summary>
126 Task<string> GetSelectedChatMessageAsync();
127 /// <summary>Найти сообщения ветки по коду (inferred attach, ADR 0137). returns: json.</summary>
128 Task<string> FindIntercomMessagesForCodeAsync(IReadOnlyDictionary<string, JsonElement>? args);
129
130 /// <summary>Явная связь диапазона gutter-сообщений с кодом (ADR 0137).</summary>
131 Task<string> RelateIntercomMessageRangeToCodeAsync(IReadOnlyDictionary<string, JsonElement>? args);
132 /// <summary>Заменить текст ответа ассистента по message_id; в event log пишется message_edited.</summary>
133 Task<string> EditChatAssistantMessageAsync(string messageId, string newContent, string? reason = null);
134 /// <summary>Экспорт текущего чата в Markdown; при write_file — запись в .cascade-ide/chat-sessions/exports/.</summary>
135 Task<string> ExportChatReadableAsync(bool writeFile = false, string? fileName = null);
136 /// <summary>Передать фокус на эффективный контрол: по имени или на элемент под курсором. Вызов на UI-потоке.</summary>
137 Task<string> SetFocusAsync(string? controlName);
138 /// <summary>Подсветить эффективный контрол (рамка/оверлей), чтобы пользователь видел, где агент «находится». Без name — под курсором; с name — по имени. Вызов на UI-потоке.</summary>
139 Task<string> HighlightControlAsync(string? controlName);
140 /// <summary>Изменить размер панели: solution_explorer, chat — width (px); build_output, terminal — height (px). Вызов на UI-потоке.</summary>
141 Task<string> SetPanelSizeAsync(string panel, double? width, double? height);
142 /// <summary>Список языков/расширений редактора с подсветкой синтаксиса. JSON: массив { "extension", "language" }.</summary>
143 string GetSupportedEditorLanguages();
144
145 /// <summary>JSON: канонический снимок встроенной DAP-сессии (стек, переменные, останов) — тот же источник, что UI (ADR 0002).</summary>
146 Task<string> GetDebugSnapshotAsync(CancellationToken cancellationToken = default);
147
148 /// <summary>Записать заметки агента. Формат и структура на усмотрение агента. Хранятся в каталоге решения в .cascade-ide/agent-notes (расширение не задано — агент может писать markdown, json, текст). Без открытого решения — ошибка.</summary>
149 Task<string> WriteAgentNotesAsync(string content, CancellationToken cancellationToken = default);
150 /// <summary>Прочитать заметки агента. Возвращает содержимое файла или пустую строку, если файла нет или решение не загружено.</summary>
151 Task<string> ReadAgentNotesAsync(CancellationToken cancellationToken = default);
152 /// <summary>Добавить блок в конец заметок агента без полной перезаписи. Возвращает "OK" или ошибку.</summary>
153 Task<string> AppendAgentNotesAsync(string content, CancellationToken cancellationToken = default);
154 /// <summary>Список ревизий заметок агента. JSON: массив { file, size_bytes, modified_utc }.</summary>
155 Task<string> ListAgentNotesRevisionsAsync(int? limit = null, CancellationToken cancellationToken = default);
156 /// <summary>Откатить заметки к ревизии (или к последней, если revisionFile null). Возвращает OK/NO_CHANGES с именем ревизии.</summary>
157 Task<string> RollbackAgentNotesAsync(string? revisionFile = null, CancellationToken cancellationToken = default);
158 /// <summary>Прочитать только горячий контекст (L0/L1) без архивного хвоста. JSON: active_scope, loaded_sections, content.</summary>
159 Task<string> ReadHotContextAsync(string? activeScope = null, CancellationToken cancellationToken = default);
160 /// <summary>Router-first контекст пакет по запросу. JSON: assembled_context, loaded_sections, scores.</summary>
161 Task<string> RouteContextAsync(string query, string? activeScope = null, int? maxSections = null, int? maxChars = null, CancellationToken cancellationToken = default);
162 /// <summary>Health-check памяти по hot-context бюджетам. JSON.</summary>
163 Task<string> MemoryHealthAsync(string? activeScope = null, CancellationToken cancellationToken = default);
164 /// <summary>Ужать hot-context (preview/apply). JSON.</summary>
165 Task<string> CompactHotContextAsync(bool apply = false, CancellationToken cancellationToken = default);
166 /// <summary>Поиск по архивной ревизии заметок (или последней), с контекстом строк. JSON.</summary>
167 Task<string> ExtractFromArchiveAsync(string query, string? revisionFile = null, int? headLimit = null, int? contextLines = null, CancellationToken cancellationToken = default);
168
169 /// <summary>Вставить/обновить секцию в заметках агента. section_id — стабильный идентификатор, content — новое содержимое секции. Возвращает "OK" или ошибку.</summary>
170 Task<string> UpsertAgentNotesSectionAsync(string sectionId, string content, CancellationToken cancellationToken = default);
171 /// <summary>Поиск по заметкам агента (case-insensitive). Возвращает JSON: matches [{ line, text }].</summary>
172 Task<string> SearchAgentNotesAsync(string query, int? headLimit = null, CancellationToken cancellationToken = default);
173 /// <summary>Прочитать knowledge-файл. Корень: knowledge_path, knowledge_root_id или primary из TOML.</summary>
174 Task<string> ReadKnowledgeFileAsync(string filePath, int? offset = null, int? limit = null, string? knowledgeRootId = null, CancellationToken cancellationToken = default);
175 /// <summary>Список knowledge-файлов. subdir — относительный подкаталог (например "work").</summary>
176 Task<string> ListKnowledgeFilesAsync(string? subdir = null, string? knowledgeRootId = null, CancellationToken cancellationToken = default);
177 /// <summary>Записать knowledge-файл (полная замена). Запись только в primary; read-only roots отклоняются.</summary>
178 Task<string> WriteKnowledgeFileAsync(string filePath, string content, string? knowledgePath = null, bool saveRevision = true, string? knowledgeRootId = null, CancellationToken cancellationToken = default);
179 /// <summary>Добавить блок в конец knowledge-файла.</summary>
180 Task<string> AppendKnowledgeFileAsync(string filePath, string content, string? knowledgePath = null, bool saveRevision = true, string? knowledgeRootId = null, CancellationToken cancellationToken = default);
181 /// <summary>Вставить/обновить секцию в knowledge-файле по section_id.</summary>
182 Task<string> UpsertKnowledgeSectionAsync(string filePath, string sectionId, string content, string? knowledgePath = null, bool saveRevision = true, string? knowledgeRootId = null, CancellationToken cancellationToken = default);
183 /// <summary>Удалить knowledge-файл.</summary>
184 Task<string> DeleteKnowledgeFileAsync(string filePath, string? knowledgePath = null, string? knowledgeRootId = null, CancellationToken cancellationToken = default);
185 /// <summary>Удалить секцию из knowledge-файла.</summary>
186 Task<string> DeleteKnowledgeSectionAsync(string filePath, string sectionId, string? knowledgePath = null, string? knowledgeRootId = null, CancellationToken cancellationToken = default);
187
188 /// <summary>Статус гибридного индекса (паритет MCP <c>codebase_index_status</c>). JSON.</summary>
189 Task<string> CodebaseIndexStatusAsync(string? workspacePath, string? solutionPath, CancellationToken cancellationToken = default);
190 /// <summary>Гибридный поиск (паритет <c>codebase_index_search</c>). JSON.</summary>
191 Task<string> CodebaseIndexSearchAsync(string? workspacePath, string? solutionPath, string query, int topN, string? pathPrefix, IReadOnlyList<string>? excludePathPrefixes, IReadOnlyList<string>? extensions, bool semantic, double alpha, double beta, int vecTopK, CancellationToken cancellationToken = default);
192 /// <summary>Explain hit (паритет <c>codebase_index_explain</c>). JSON.</summary>
193 Task<string> CodebaseIndexExplainAsync(string? workspacePath, string? solutionPath, long hitId, CancellationToken cancellationToken = default);
194 /// <summary>Reindex (паритет <c>codebase_index_reindex</c>; после успеха публикуется снимок в DataBus для MFD). JSON.</summary>
195 Task<string> CodebaseIndexReindexAsync(string? workspacePath, string? solutionPath, bool fullRebuild, CancellationToken cancellationToken = default);
196
197 /// <summary>Verification ladder (ADR 0148). args: policy?, sandbox_profile?, solution_path?; JSON.</summary>
198 Task<string> IdeAgentVerifyAsync(string? policy, string? sandboxProfile, string? solutionPath, CancellationToken cancellationToken = default);
199
200 Task<string> IdeAgentVerifyBatchAsync(
201 string? policy,
202 string? sandboxProfile,
203 string? solutionPath,
204 bool useWorktree,
205 CancellationToken cancellationToken = default);
206
207 Task<string> IdeAgentCancelAsync(CancellationToken cancellationToken = default);
208
209 Task<string> IdeAgentStatusAsync(CancellationToken cancellationToken = default);
210
211 Task<string> IdeAgentLastAsync(CancellationToken cancellationToken = default);
212
213 /// <summary>Prepare sandbox substrate. args: profile?, workspace_root?; JSON.</summary>
214 Task<string> IdeAgentSandboxPrepareAsync(string? profile, string? workspaceRoot, CancellationToken cancellationToken = default);
215}
216
View only · write via MCP/CIDE