60cf26f739
- PartModeler: ResetAsync/Dispose освобождают RCW и чистят реестр эскизов/операций; Editor освобождается после EndEdit (C1) - DocumentTools: сброс реестра при create/open/close — нет устаревших id (C2) - DocumentService: освобождение транзитных IDocuments/IKompasDocument (m9) - KompasSession.Dispose: ограниченное ожидание 5с вместо вечного блока (M3) - PartModeler.ExtrudeAsync: убран dynamic -> конкретные definition-типы; throughAll только для cut (M4) - FeatureTools.extrude_cut: дефолт throughAll=false, без подмены depth (m7) - tests: регрессия на сброс реестра (старый id недействителен) - docs/OPEN_QUESTIONS.md: итоги ревью (исправлено/отложено) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
74 lines
3.5 KiB
C#
74 lines
3.5 KiB
C#
using System.ComponentModel;
|
|
using Kompas.Mcp.Core;
|
|
using Kompas.Mcp.Core.Documents;
|
|
using Kompas.Mcp.Core.Modeling;
|
|
using ModelContextProtocol.Server;
|
|
|
|
namespace Kompas.Mcp.Host.Tools;
|
|
|
|
/// <summary>Инструменты управления документами.</summary>
|
|
[McpServerToolType]
|
|
public sealed class DocumentTools(KompasSession session, DocumentService docs, PartModeler modeler)
|
|
{
|
|
[McpServerTool(Name = "document_create")]
|
|
[Description("Создать новый документ и сделать его активным. type: part | assembly | drawing | fragment | specification | text.")]
|
|
public async Task<string> Create([Description("Тип документа")] string type)
|
|
{
|
|
await session.ConnectAsync();
|
|
var info = await docs.CreateAsync(DocumentTypes.Parse(type));
|
|
await modeler.ResetAsync(); // прежние id эскизов/операций недействительны
|
|
return $"Создан документ типа {info.Type}.";
|
|
}
|
|
|
|
[McpServerTool(Name = "document_open")]
|
|
[Description("Открыть документ КОМПАС с диска по полному пути.")]
|
|
public async Task<string> Open(
|
|
[Description("Полный путь к файлу")] string path,
|
|
[Description("Открыть только для чтения")] bool readOnly = false)
|
|
{
|
|
await session.ConnectAsync();
|
|
var info = await docs.OpenAsync(path, readOnly);
|
|
await modeler.ResetAsync();
|
|
return $"Открыт документ: {info.Name} ({info.Type}).";
|
|
}
|
|
|
|
[McpServerTool(Name = "document_save_as")]
|
|
[Description("Сохранить активный документ по указанному пути. Безопасно для новых документов. Расширения: .m3d (деталь), .a3d (сборка), .cdw (чертёж), .frw (фрагмент).")]
|
|
public async Task<string> SaveAs([Description("Полный путь файла с расширением")] string path)
|
|
{
|
|
await session.ConnectAsync();
|
|
await docs.SaveAsAsync(path);
|
|
return $"Сохранено: {path}";
|
|
}
|
|
|
|
[McpServerTool(Name = "document_save")]
|
|
[Description("Сохранить активный документ (для уже сохранённого ранее).")]
|
|
public async Task<string> Save()
|
|
{
|
|
await session.ConnectAsync();
|
|
await docs.SaveAsync();
|
|
return "Документ сохранён.";
|
|
}
|
|
|
|
[McpServerTool(Name = "document_close")]
|
|
[Description("Закрыть активный документ. save — сохранять ли изменения при закрытии.")]
|
|
public async Task<string> Close([Description("Сохранять изменения")] bool save = false)
|
|
{
|
|
await session.ConnectAsync();
|
|
var ok = await docs.CloseAsync(save);
|
|
await modeler.ResetAsync();
|
|
return ok ? "Документ закрыт." : "Не удалось закрыть документ.";
|
|
}
|
|
|
|
[McpServerTool(Name = "document_active")]
|
|
[Description("Сведения об активном документе.")]
|
|
public async Task<string> Active()
|
|
{
|
|
await session.ConnectAsync();
|
|
var i = await docs.GetActiveAsync();
|
|
if (i is null) return "Нет активного документа.";
|
|
var where = string.IsNullOrEmpty(i.PathName) ? "не сохранён" : i.PathName;
|
|
return $"{i.Type}: {i.Name} ({where}).";
|
|
}
|
|
}
|