answer42 0.2.28__tar.gz → 0.2.29__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {answer42-0.2.28 → answer42-0.2.29}/PKG-INFO +1 -1
- {answer42-0.2.28 → answer42-0.2.29}/pyproject.toml +1 -1
- {answer42-0.2.28 → answer42-0.2.29}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form/Module.bsl +174 -22
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/assets/MCPTestManager.cf +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/protocol.py +1 -1
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/server.py +127 -14
- {answer42-0.2.28 → answer42-0.2.29}/.gitignore +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/LICENSE +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/README.md +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/credentials.example.json +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/docs/agent-installation.md +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/docs/architecture.md +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/docs/assets/answer42-logo.png +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/docs/assets/platform42-logo.svg +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/docs/installation.md +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/scripts/build_cf.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/scripts/build_pages.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/scripts/e2e_stable.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/scripts/openclaw_mcp_autoreload.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/scripts/rag_cli.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/cf/Configuration.xml +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/cf/DataProcessors/MCPTestManager/Ext/ObjectModule.bsl +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form.xml" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260.xml" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/cf/DataProcessors/MCPTestManager.xml +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/cf/Ext/ManagedApplicationModule.bsl +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/client_cf/Catalogs//320/237/320/241_/320/222/320/273/320/260/320/264/320/265/320/273/320/265/321/206.xml" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/client_cf/Catalogs//320/237/320/241_/320/241/320/277/321/200/320/260/320/262/320/276/321/207/320/275/320/270/320/2721.xml" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/client_cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/client_cf/Configuration.xml +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/client_cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Ext/ManagerModule.bsl" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Ext/ObjectModule.bsl" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Templates//320/236/321/201/320/275/320/276/320/262/320/275/320/260/321/217/320/241/321/205/320/265/320/274/320/260/320/232/320/276/320/274/320/277/320/276/320/275/320/276/320/262/320/272/320/270/320/224/320/260/320/275/320/275/321/213/321/205/Ext/Template.xml" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Templates//320/236/321/201/320/275/320/276/320/262/320/275/320/260/321/217/320/241/321/205/320/265/320/274/320/260/320/232/320/276/320/274/320/277/320/276/320/275/320/276/320/262/320/272/320/270/320/224/320/260/320/275/320/275/321/213/321/205.xml" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262.xml" +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/__init__.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/assets/MCPTestClient.cf +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/assets/__init__.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/assets/skills/answer42/SKILL.md +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/assets/skills/answer42-rag/SKILL.md +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/bridge.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/credentials.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/os_support.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/platform.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/rag/__init__.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/rag/detect.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/rag/model.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/rag/parsers.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/rag/service.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/rag/store.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/recorder.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/release_helper.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/runtime.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/skill_installer.py +0 -0
- {answer42-0.2.28 → answer42-0.2.29}/src/mcp_1c/window_control.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: answer42
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.29
|
|
4
4
|
Summary: Answer42 — The Answer to Life, Universe, and 1C — UI Driver. MCP-powered 1C:Enterprise UI automation: click, fill, navigate, test, and introspect managed forms through the test-client API
|
|
5
5
|
Author: Marvin (AI Assistant), 42Clouds, and contributors
|
|
6
6
|
Author-email: "Kosolapov Stanislav (proDOOMman)" <prodoomman@gmail.com>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "answer42"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.29"
|
|
4
4
|
description = "Answer42 — The Answer to Life, Universe, and 1C — UI Driver. MCP-powered 1C:Enterprise UI automation: click, fill, navigate, test, and introspect managed forms through the test-client API"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -240,7 +240,7 @@
|
|
|
240
240
|
|
|
241
241
|
&НаКлиенте
|
|
242
242
|
Функция ВерсияПротоколаМенеджераMCP()
|
|
243
|
-
Возврат "2026.07.02.
|
|
243
|
+
Возврат "2026.07.02.4";
|
|
244
244
|
КонецФункции
|
|
245
245
|
|
|
246
246
|
&НаКлиенте
|
|
@@ -294,6 +294,8 @@
|
|
|
294
294
|
Возврат НажатьКнопку(Параметры);
|
|
295
295
|
ИначеЕсли Метод = "find_object" Тогда
|
|
296
296
|
Возврат НайтиОбъектИнтерфейса(Параметры);
|
|
297
|
+
ИначеЕсли Метод = "search_objects" Тогда
|
|
298
|
+
Возврат НайтиВсеОбъектыИнтерфейса(Параметры);
|
|
297
299
|
ИначеЕсли Метод = "get_object" Тогда
|
|
298
300
|
Возврат ПолучитьОбъектПриложенияMCP(Параметры);
|
|
299
301
|
ИначеЕсли Метод = "activate_object" Тогда
|
|
@@ -2565,6 +2567,51 @@
|
|
|
2565
2567
|
Возврат Неопределено;
|
|
2566
2568
|
КонецФункции
|
|
2567
2569
|
|
|
2570
|
+
&НаКлиенте
|
|
2571
|
+
Функция НайтиВсеОбъектыИнтерфейса(Параметры)
|
|
2572
|
+
Если ТестируемоеПриложение = Неопределено Тогда
|
|
2573
|
+
ВызватьИсключение "Тестируемое приложение не подключено.";
|
|
2574
|
+
КонецЕсли;
|
|
2575
|
+
АктивноеОкно = ТестируемоеПриложение.ПолучитьАктивноеОкно();
|
|
2576
|
+
Имя = СвойствоСтруктуры(Параметры, "name", "");
|
|
2577
|
+
Заголовок = СвойствоСтруктуры(Параметры, "title", "");
|
|
2578
|
+
ТипОбъекта = СвойствоСтруктуры(Параметры, "type", "");
|
|
2579
|
+
Глубина = СвойствоСтруктуры(Параметры, "max_depth", 8);
|
|
2580
|
+
Лимит = СвойствоСтруктуры(Параметры, "limit", 50);
|
|
2581
|
+
Найденные = Новый Массив;
|
|
2582
|
+
НайтиВсеОбъектыРекурсивно(АктивноеОкно, Имя, Заголовок, ТипОбъекта, 0, Глубина, Лимит, Найденные);
|
|
2583
|
+
Возврат Новый Структура("found,count,limit,objects", Найденные.Количество() > 0, Найденные.Количество(), Лимит, Найденные);
|
|
2584
|
+
КонецФункции
|
|
2585
|
+
|
|
2586
|
+
&НаКлиенте
|
|
2587
|
+
Процедура НайтиВсеОбъектыРекурсивно(РодительскийОбъект, Имя, Заголовок, ТипОбъекта, ТекущаяГлубина, МаксимальнаяГлубина, Лимит, Найденные)
|
|
2588
|
+
Если ТекущаяГлубина > МаксимальнаяГлубина Тогда
|
|
2589
|
+
Возврат;
|
|
2590
|
+
КонецЕсли;
|
|
2591
|
+
Если Найденные.Количество() >= Лимит Тогда
|
|
2592
|
+
Возврат;
|
|
2593
|
+
КонецЕсли;
|
|
2594
|
+
Попытка
|
|
2595
|
+
ИмяТекущего = БезопасноеСвойство(РодительскийОбъект, "Имя", "");
|
|
2596
|
+
ЗаголовокТекущего = БезопасныйЗаголовок(РодительскийОбъект);
|
|
2597
|
+
ТипТекущего = Строка(ТипЗнч(РодительскийОбъект));
|
|
2598
|
+
НормализованныйТип = НормализованноеИмяТипа(ТипТекущего);
|
|
2599
|
+
Если ОбъектСоответствует(ИмяТекущего, ЗаголовокТекущего, НормализованныйТип, Имя, Заголовок, ТипОбъекта) Тогда
|
|
2600
|
+
Найденные.Добавить(ОбъектВСтруктуру(РодительскийОбъект, 0, 0));
|
|
2601
|
+
КонецЕсли;
|
|
2602
|
+
Подчиненные = БезопасныеПодчиненные(РодительскийОбъект);
|
|
2603
|
+
Для Каждого Подчиненный Из Подчиненные Цикл
|
|
2604
|
+
Если Найденные.Количество() >= Лимит Тогда
|
|
2605
|
+
Прервать;
|
|
2606
|
+
КонецЕсли;
|
|
2607
|
+
НайтиВсеОбъектыРекурсивно(Подчиненный, Имя, Заголовок, ТипОбъекта, ТекущаяГлубина + 1, МаксимальнаяГлубина, Лимит, Найденные);
|
|
2608
|
+
КонецЦикла;
|
|
2609
|
+
Исключение
|
|
2610
|
+
Инфо = ИнформацияОбОшибке();
|
|
2611
|
+
Лог("Подавленное исключение: " + ПодробноеПредставлениеОшибки(Инфо));
|
|
2612
|
+
КонецПопытки;
|
|
2613
|
+
КонецПроцедуры
|
|
2614
|
+
|
|
2568
2615
|
&НаКлиенте
|
|
2569
2616
|
Функция ОбъектСоответствует(ИмяОбъекта, ЗаголовокОбъекта, ТипОбъекта, ИскомоеИмя, ИскомыйЗаголовок, ИскомыйТип)
|
|
2570
2617
|
НормализованноеИмя = НРег(СокрЛП(ИмяОбъекта));
|
|
@@ -3727,7 +3774,7 @@
|
|
|
3727
3774
|
Если Представления.Количество() > 0 Тогда
|
|
3728
3775
|
ИндексВыбора = ИндексРелевантногоВариантаСпискаВыбораMCP(Представления, Значение);
|
|
3729
3776
|
Если ИндексВыбора = Неопределено Тогда
|
|
3730
|
-
|
|
3777
|
+
ОтменитьРедактированиеПоляЕслиНужноMCP(Поле);
|
|
3731
3778
|
ВызватьИсключение "Выпадающий список открыт, но релевантный вариант для значения " + Значение + " не найден";
|
|
3732
3779
|
КонецЕсли;
|
|
3733
3780
|
ПредставлениеВыбираемогоВарианта = ПредставлениеВариантаСпискаВыбораMCP(Представления[ИндексВыбора]);
|
|
@@ -3783,6 +3830,7 @@
|
|
|
3783
3830
|
КонецПопытки;
|
|
3784
3831
|
|
|
3785
3832
|
Если ТекстовыйВводВыполнен Тогда
|
|
3833
|
+
ОтменитьРедактированиеПоляЕслиНужноMCP(Поле);
|
|
3786
3834
|
ВызватьИсключение "Не удалось установить поле " + ИмяПоля + ": ВвестиТекст выполнен, но значение не подтвердилось; текущее представление: " + НеподтвержденноеПредставлениеПослеВвода;
|
|
3787
3835
|
КонецЕсли;
|
|
3788
3836
|
|
|
@@ -3878,6 +3926,7 @@
|
|
|
3878
3926
|
Ошибки.Добавить("УстановитьЗначение=" + ОписаниеОшибки());
|
|
3879
3927
|
КонецПопытки;
|
|
3880
3928
|
|
|
3929
|
+
ОтменитьРедактированиеПоляЕслиНужноMCP(Поле);
|
|
3881
3930
|
ВызватьИсключение "Не удалось установить поле " + ИмяПоля + ": " + СтрСоединить(Ошибки, "; ");
|
|
3882
3931
|
КонецФункции
|
|
3883
3932
|
|
|
@@ -4324,15 +4373,93 @@
|
|
|
4324
4373
|
КонецФункции
|
|
4325
4374
|
|
|
4326
4375
|
&НаКлиенте
|
|
4327
|
-
|
|
4376
|
+
Функция ОбеспечитьРедактированиеТекущейСтрокиТаблицыMCP(Таблица)
|
|
4328
4377
|
Таблица.Активизировать();
|
|
4378
|
+
УжеРедактируется = ТаблицаВРежимеРедактированияMCP(Таблица);
|
|
4379
|
+
Если УжеРедактируется Тогда
|
|
4380
|
+
Возврат Новый Структура("editing,changed,error", Истина, Ложь, "");
|
|
4381
|
+
КонецЕсли;
|
|
4329
4382
|
Попытка
|
|
4330
|
-
|
|
4331
|
-
|
|
4383
|
+
Таблица.ИзменитьСтроку();
|
|
4384
|
+
Возврат Новый Структура("editing,changed,error", ТаблицаВРежимеРедактированияMCP(Таблица), Истина, "");
|
|
4385
|
+
Исключение
|
|
4386
|
+
// После ДобавитьСтроку() таблица может быть в промежуточном состоянии
|
|
4387
|
+
// добавления/редактирования, где ИзменитьСтроку() уже неприменима
|
|
4388
|
+
// ("Неподходящее состояние элемента управления"), но редактор текущей
|
|
4389
|
+
// строки уже доступен. Не падаем здесь: дальше ищем поле редактора;
|
|
4390
|
+
// если его нет — вернём точную ошибку поиска/установки.
|
|
4391
|
+
Возврат Новый Структура("editing,changed,error", ТаблицаВРежимеРедактированияMCP(Таблица), Ложь, ОписаниеОшибки());
|
|
4392
|
+
КонецПопытки;
|
|
4393
|
+
КонецФункции
|
|
4394
|
+
|
|
4395
|
+
&НаКлиенте
|
|
4396
|
+
Функция ТаблицаВРежимеРедактированияMCP(Таблица)
|
|
4397
|
+
Попытка
|
|
4398
|
+
Возврат Таблица.ТекущийРежимРедактирование();
|
|
4399
|
+
Исключение
|
|
4400
|
+
Возврат Ложь;
|
|
4401
|
+
КонецПопытки;
|
|
4402
|
+
КонецФункции
|
|
4403
|
+
|
|
4404
|
+
&НаКлиенте
|
|
4405
|
+
Функция ЗавершитьРедактированиеСтрокиТаблицыMCP(Таблица)
|
|
4406
|
+
ОшибкаЗавершения = "";
|
|
4407
|
+
БылаВРедактировании = ТаблицаВРежимеРедактированияMCP(Таблица);
|
|
4408
|
+
Попытка
|
|
4409
|
+
Если БылаВРедактировании Тогда
|
|
4410
|
+
Таблица.ЗакончитьРедактированиеСтроки(Ложь);
|
|
4332
4411
|
КонецЕсли;
|
|
4333
4412
|
Исключение
|
|
4334
|
-
|
|
4413
|
+
ОшибкаЗавершения = ОписаниеОшибки();
|
|
4335
4414
|
КонецПопытки;
|
|
4415
|
+
|
|
4416
|
+
ОсталасьВРедактировании = ТаблицаВРежимеРедактированияMCP(Таблица);
|
|
4417
|
+
ОтменаВыполнена = Ложь;
|
|
4418
|
+
ОшибкаОтмены = "";
|
|
4419
|
+
Если ОсталасьВРедактировании Тогда
|
|
4420
|
+
Попытка
|
|
4421
|
+
Таблица.ЗакончитьРедактированиеСтроки(Истина);
|
|
4422
|
+
ОтменаВыполнена = Истина;
|
|
4423
|
+
Исключение
|
|
4424
|
+
ОшибкаОтмены = ОписаниеОшибки();
|
|
4425
|
+
КонецПопытки;
|
|
4426
|
+
КонецЕсли;
|
|
4427
|
+
|
|
4428
|
+
ВсеЕщеВРедактировании = ТаблицаВРежимеРедактированияMCP(Таблица);
|
|
4429
|
+
Возврат Новый Структура("was_editing,commit_error,remained_editing,cancel_done,cancel_error,still_editing", БылаВРедактировании, ОшибкаЗавершения, ОсталасьВРедактировании, ОтменаВыполнена, ОшибкаОтмены, ВсеЕщеВРедактировании);
|
|
4430
|
+
КонецФункции
|
|
4431
|
+
|
|
4432
|
+
&НаКлиенте
|
|
4433
|
+
Функция НайтиРодительскуюТаблицуMCP(Объект)
|
|
4434
|
+
Текущий = Объект;
|
|
4435
|
+
Пока Текущий <> Неопределено Цикл
|
|
4436
|
+
Если НормализованноеИмяТипа(ТипЗнч(Текущий)) = "тестируемаятаблицаформы" Тогда
|
|
4437
|
+
Возврат Текущий;
|
|
4438
|
+
КонецЕсли;
|
|
4439
|
+
Попытка
|
|
4440
|
+
Текущий = Текущий.ПолучитьРодителя();
|
|
4441
|
+
Исключение
|
|
4442
|
+
Возврат Неопределено;
|
|
4443
|
+
КонецПопытки;
|
|
4444
|
+
КонецЦикла;
|
|
4445
|
+
Возврат Неопределено;
|
|
4446
|
+
КонецФункции
|
|
4447
|
+
|
|
4448
|
+
&НаКлиенте
|
|
4449
|
+
Процедура ОтменитьРедактированиеПоляЕслиНужноMCP(Поле)
|
|
4450
|
+
Попытка
|
|
4451
|
+
Если ОткрытВыпадающийСписокПоляMCP(Поле) Тогда
|
|
4452
|
+
Поле.ЗакрытьВыпадающийСписок();
|
|
4453
|
+
КонецЕсли;
|
|
4454
|
+
Исключение
|
|
4455
|
+
КонецПопытки;
|
|
4456
|
+
Таблица = НайтиРодительскуюТаблицуMCP(Поле);
|
|
4457
|
+
Если Таблица <> Неопределено И ТаблицаВРежимеРедактированияMCP(Таблица) Тогда
|
|
4458
|
+
Попытка
|
|
4459
|
+
Таблица.ЗакончитьРедактированиеСтроки(Истина);
|
|
4460
|
+
Исключение
|
|
4461
|
+
КонецПопытки;
|
|
4462
|
+
КонецЕсли;
|
|
4336
4463
|
КонецПроцедуры
|
|
4337
4464
|
|
|
4338
4465
|
&НаКлиенте
|
|
@@ -4407,11 +4534,12 @@
|
|
|
4407
4534
|
ВызватьИсключение "Таблица не найдена: " + ИмяТаблицы;
|
|
4408
4535
|
КонецЕсли;
|
|
4409
4536
|
|
|
4410
|
-
ОбеспечитьРедактированиеТекущейСтрокиТаблицыMCP(Таблица);
|
|
4537
|
+
РезультатНачалаРедактирования = ОбеспечитьРедактированиеТекущейСтрокиТаблицыMCP(Таблица);
|
|
4411
4538
|
АктивноеОкно = ТестируемоеПриложение.ПолучитьАктивноеОкно();
|
|
4412
4539
|
Поле = НайтиПолеРедактораТаблицыMCP(АктивноеОкно, Таблица, ИмяТаблицы, ИмяПоля, ИскатьПоЗаголовку, МаксимальнаяГлубина);
|
|
4413
4540
|
Если Поле = Неопределено Тогда
|
|
4414
|
-
|
|
4541
|
+
ДополнениеОшибкиРедактирования = ?(ПустаяСтрока(РезультатНачалаРедактирования.error), "", "; ошибка начала редактирования: " + РезультатНачалаРедактирования.error);
|
|
4542
|
+
ВызватьИсключение "Поле редактора таблицы не найдено: " + ИмяПоля + ДополнениеОшибкиРедактирования;
|
|
4415
4543
|
КонецЕсли;
|
|
4416
4544
|
ИмяРедактора = БезопасноеСвойство(Поле, "Имя", "");
|
|
4417
4545
|
Поле.Активизировать();
|
|
@@ -4429,14 +4557,13 @@
|
|
|
4429
4557
|
ОшибкаУстановки = ОписаниеОшибки();
|
|
4430
4558
|
КонецПопытки;
|
|
4431
4559
|
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
КонецПопытки;
|
|
4560
|
+
РезультатЗавершенияРедактирования = ЗавершитьРедактированиеСтрокиТаблицыMCP(Таблица);
|
|
4561
|
+
Если Не ПустаяСтрока(РезультатЗавершенияРедактирования.commit_error) Тогда
|
|
4562
|
+
ВызватьИсключение "Не удалось завершить редактирование строки таблицы " + ИмяТаблицы + ": " + РезультатЗавершенияРедактирования.commit_error;
|
|
4563
|
+
КонецЕсли;
|
|
4564
|
+
Если РезультатЗавершенияРедактирования.still_editing Тогда
|
|
4565
|
+
ВызватьИсключение "Таблица " + ИмяТаблицы + " осталась в режиме редактирования после попытки завершить и отменить редактирование строки";
|
|
4566
|
+
КонецЕсли;
|
|
4440
4567
|
|
|
4441
4568
|
Проверка = ЗначениеКолонкиТекущейСтрокиMCP(Таблица, ИмяПоля, ИскатьПоЗаголовку);
|
|
4442
4569
|
Проверено = Проверка.found И ЗначенияСовпадаютДляПроверкиMCP(Проверка.value, Значение);
|
|
@@ -4449,7 +4576,7 @@
|
|
|
4449
4576
|
Если Не ПустаяСтрока(ОшибкаУстановки) Тогда
|
|
4450
4577
|
МетодУстановки = МетодУстановки + "+verified_after_exception";
|
|
4451
4578
|
КонецЕсли;
|
|
4452
|
-
Возврат Новый Структура("set,table,field,value,editor_field,verified,verified_key,verified_value,method,current_row", Истина, ИмяТаблицы, ИмяПоля, Значение, ИмяРедактора, Проверено, Проверка.key, Проверка.value, МетодУстановки, СоответствиеВСтруктуру(Таблица.ПолучитьТекущуюСтроку()));
|
|
4579
|
+
Возврат Новый Структура("set,table,field,value,editor_field,verified,verified_key,verified_value,method,edit_start,edit_finish,current_row", Истина, ИмяТаблицы, ИмяПоля, Значение, ИмяРедактора, Проверено, Проверка.key, Проверка.value, МетодУстановки, РезультатНачалаРедактирования, РезультатЗавершенияРедактирования, СоответствиеВСтруктуру(Таблица.ПолучитьТекущуюСтроку()));
|
|
4453
4580
|
КонецФункции
|
|
4454
4581
|
|
|
4455
4582
|
&НаКлиенте
|
|
@@ -4588,6 +4715,18 @@
|
|
|
4588
4715
|
СписокКнопок.Добавить(Новый Структура("name,title", "", "Вывести список..."));
|
|
4589
4716
|
СписокКнопок.Добавить(Новый Структура("name,title", "", "Вывести список"));
|
|
4590
4717
|
РезультатКнопки = НажатьПервуюКнопкуОкна(СписокКнопок, СвойствоСтруктуры(Параметры, "max_depth", 8));
|
|
4718
|
+
|
|
4719
|
+
// After pressing "Вывести список", a dialog opens. Confirm it.
|
|
4720
|
+
КнопкиПодтверждения = Новый Массив;
|
|
4721
|
+
КнопкиПодтверждения.Добавить(Новый Структура("name,title", "", "Сформировать"));
|
|
4722
|
+
КнопкиПодтверждения.Добавить(Новый Структура("name,title", "", "ОК"));
|
|
4723
|
+
КнопкиПодтверждения.Добавить(Новый Структура("name,title", "", "Ok"));
|
|
4724
|
+
Попытка
|
|
4725
|
+
НажатьПервуюКнопкуОкна(КнопкиПодтверждения, СвойствоСтруктуры(Параметры, "max_depth", 8));
|
|
4726
|
+
Исключение
|
|
4727
|
+
// Dialog may not appear or may auto-close; proceed anyway.
|
|
4728
|
+
КонецПопытки;
|
|
4729
|
+
|
|
4591
4730
|
Пауза = ТекущаяДата() + СвойствоСтруктуры(Параметры, "wait_seconds", 2);
|
|
4592
4731
|
Пока ТекущаяДата() < Пауза Цикл КонецЦикла;
|
|
4593
4732
|
Документы = ТабличныеДокументы(Новый Структура("include_text,max_depth", Истина, СвойствоСтруктуры(Параметры, "max_depth", 8)));
|
|
@@ -4614,7 +4753,7 @@
|
|
|
4614
4753
|
КонецЕсли;
|
|
4615
4754
|
Поле = СвойствоСтруктуры(Параметры, "field", "");
|
|
4616
4755
|
Значение = СвойствоСтруктуры(Параметры, "value", "");
|
|
4617
|
-
ВидСравнения = СвойствоСтруктуры(Параметры, "comparison", "Equal");
|
|
4756
|
+
ВидСравненияMCP = СвойствоСтруктуры(Параметры, "comparison", "Equal");
|
|
4618
4757
|
Если ПустаяСтрока(Поле) Тогда
|
|
4619
4758
|
ВызватьИсключение "Не задано поле отбора dynamic list.";
|
|
4620
4759
|
КонецЕсли;
|
|
@@ -4643,7 +4782,7 @@
|
|
|
4643
4782
|
Ошибки.Добавить("Левое значение: " + ОписаниеОшибки());
|
|
4644
4783
|
КонецПопытки;
|
|
4645
4784
|
Попытка
|
|
4646
|
-
УстановитьЗначениеПоля(Новый Структура("field_name,value,search_by_title", "Вид сравнения",
|
|
4785
|
+
УстановитьЗначениеПоля(Новый Структура("field_name,value,search_by_title", "Вид сравнения", ВидСравненияMCP, Истина));
|
|
4647
4786
|
Исключение
|
|
4648
4787
|
Ошибки.Добавить("Вид сравнения: " + ОписаниеОшибки());
|
|
4649
4788
|
КонецПопытки;
|
|
@@ -4659,9 +4798,9 @@
|
|
|
4659
4798
|
КонецПопытки;
|
|
4660
4799
|
|
|
4661
4800
|
Если Ошибки.Количество() > 0 Тогда
|
|
4662
|
-
Возврат Новый Структура("applied,field,value,comparison,errors,settings_tree", Ложь, Поле, Значение,
|
|
4801
|
+
Возврат Новый Структура("applied,field,value,comparison,errors,settings_tree", Ложь, Поле, Значение, ВидСравненияMCP, Ошибки, ДиагностикаДо);
|
|
4663
4802
|
КонецЕсли;
|
|
4664
|
-
Возврат Новый Структура("applied,field,value,comparison", Истина, Поле, Значение, ВидСравнения);
|
|
4803
|
+
Возврат Новый Структура("applied,field,value,comparison", Истина, Поле, Значение, ВидСравненияMCP);
|
|
4665
4804
|
КонецФункции
|
|
4666
4805
|
|
|
4667
4806
|
&НаКлиенте
|
|
@@ -4961,7 +5100,13 @@
|
|
|
4961
5100
|
Возврат Неопределено;
|
|
4962
5101
|
КонецЕсли;
|
|
4963
5102
|
Если ТекущаяГлубина > МаксимальнаяГлубина Тогда
|
|
4964
|
-
|
|
5103
|
+
РезультатОбрезки = Новый Структура;
|
|
5104
|
+
РезультатОбрезки.Вставить("truncated", Истина);
|
|
5105
|
+
РезультатОбрезки.Вставить("truncated_reason", "max_depth");
|
|
5106
|
+
РезультатОбрезки.Вставить("type", Строка(ТипЗнч(Объект)));
|
|
5107
|
+
РезультатОбрезки.Вставить("name", БезопасноеСвойство(Объект, "Имя", ""));
|
|
5108
|
+
РезультатОбрезки.Вставить("title", БезопасныйЗаголовок(Объект));
|
|
5109
|
+
Возврат РезультатОбрезки;
|
|
4965
5110
|
КонецЕсли;
|
|
4966
5111
|
СобственнаяВидимость = БезопасноеЗначениеМетода(Объект, "ТекущаяВидимость", БезопасноеСвойство(Объект, "Видимость", Истина));
|
|
4967
5112
|
СобственнаяДоступность = БезопасноеЗначениеМетода(Объект, "ТекущаяДоступность", БезопасноеСвойство(Объект, "Доступность", Истина));
|
|
@@ -5036,18 +5181,25 @@
|
|
|
5036
5181
|
КонецЕсли;
|
|
5037
5182
|
Исключение
|
|
5038
5183
|
КонецПопытки;
|
|
5184
|
+
СкрытыхДетей = 0;
|
|
5039
5185
|
Для Каждого Ребенок Из Дети Цикл
|
|
5040
5186
|
ИмяРебенка = БезопасноеСвойство(Ребенок, "Имя", "");
|
|
5041
5187
|
Если Не ПоказыватьСкрытые И Не ПустаяСтрока(ИмяТекущейСтраницы) И ИмяРебенка <> ИмяТекущейСтраницы Тогда
|
|
5188
|
+
СкрытыхДетей = СкрытыхДетей + 1;
|
|
5042
5189
|
Продолжить;
|
|
5043
5190
|
КонецЕсли;
|
|
5044
5191
|
РебенокДляСериализации = ?(Не ПустаяСтрока(ИмяТекущейСтраницы) И ИмяРебенка = ИмяТекущейСтраницы И ТекущаяСтраницаГруппы <> Неопределено, ТекущаяСтраницаГруппы, Ребенок);
|
|
5045
5192
|
СтруктураРебенка = ОбъектВСтруктуру(РебенокДляСериализации, ТекущаяГлубина + 1, МаксимальнаяГлубина, ПоказыватьСкрытые, Видимость, Доступность, ТолькоПросмотр);
|
|
5046
5193
|
Если СтруктураРебенка <> Неопределено Тогда
|
|
5047
5194
|
МассивДетей.Добавить(СтруктураРебенка);
|
|
5195
|
+
Иначе
|
|
5196
|
+
СкрытыхДетей = СкрытыхДетей + 1;
|
|
5048
5197
|
КонецЕсли;
|
|
5049
5198
|
КонецЦикла;
|
|
5050
5199
|
Результат.Вставить("children", МассивДетей);
|
|
5200
|
+
Если СкрытыхДетей > 0 Тогда
|
|
5201
|
+
Результат.Вставить("hidden_children_count", СкрытыхДетей);
|
|
5202
|
+
КонецЕсли;
|
|
5051
5203
|
КонецЕсли;
|
|
5052
5204
|
|
|
5053
5205
|
Возврат Результат;
|
|
Binary file
|
|
@@ -978,6 +978,29 @@ def _walk_ui_tree(node: Any):
|
|
|
978
978
|
yield from _walk_ui_tree(child)
|
|
979
979
|
|
|
980
980
|
|
|
981
|
+
def _summarize_ui_tree(tree: Any, max_depth: int, include_hidden: bool) -> dict[str, Any]:
|
|
982
|
+
"""Return compact diagnostics about omitted/truncated UI tree parts."""
|
|
983
|
+
nodes = list(_walk_ui_tree(tree))
|
|
984
|
+
truncated_nodes = [node for node in nodes if node.get("truncated")]
|
|
985
|
+
hidden_children_total = 0
|
|
986
|
+
hidden_nodes = []
|
|
987
|
+
for node in nodes:
|
|
988
|
+
hidden_count = node.get("hidden_children_count", 0)
|
|
989
|
+
if isinstance(hidden_count, int):
|
|
990
|
+
hidden_children_total += hidden_count
|
|
991
|
+
if node.get("visible") is False:
|
|
992
|
+
hidden_nodes.append(node)
|
|
993
|
+
return {
|
|
994
|
+
"max_depth": max_depth,
|
|
995
|
+
"include_hidden": include_hidden,
|
|
996
|
+
"nodes_count": len(nodes),
|
|
997
|
+
"truncated": bool(truncated_nodes),
|
|
998
|
+
"truncated_nodes_count": len(truncated_nodes),
|
|
999
|
+
"hidden_children_count": hidden_children_total,
|
|
1000
|
+
"hidden_nodes_count": len(hidden_nodes),
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
|
|
981
1004
|
def _metadata_name_from_navigation_url(url: str) -> str:
|
|
982
1005
|
"""Best-effort conversion from e1cib/list/... to a metadata full name."""
|
|
983
1006
|
value = str(url or "")
|
|
@@ -3120,6 +3143,8 @@ async def ui_tree(max_depth: Annotated[int, "Maximum UI tree depth"] = 4,
|
|
|
3120
3143
|
omitted by default; pass include_hidden=true to inspect the full 1C form tree.
|
|
3121
3144
|
"""
|
|
3122
3145
|
tree = await _bridge_call_recorded(session_id, "ui_tree", {"max_depth": max_depth, "include_hidden": include_hidden})
|
|
3146
|
+
if isinstance(tree, dict):
|
|
3147
|
+
tree["tree_summary"] = _summarize_ui_tree(tree, max_depth=max_depth, include_hidden=include_hidden)
|
|
3123
3148
|
if include_rag_types:
|
|
3124
3149
|
sess = _session(session_id)
|
|
3125
3150
|
if _RAG_ENABLED and sess.rag_enabled:
|
|
@@ -3163,6 +3188,20 @@ async def find_object(
|
|
|
3163
3188
|
return await _bridge_call_recorded(session_id, "find_object", {"name": name, "title": title, "type": type, "max_depth": max_depth})
|
|
3164
3189
|
|
|
3165
3190
|
|
|
3191
|
+
@mcp.tool()
|
|
3192
|
+
async def search_objects(
|
|
3193
|
+
name: Annotated[str, "Object technical name, exact match when specified"] = "",
|
|
3194
|
+
title: Annotated[str, "Object visible title/caption, exact match when specified"] = "",
|
|
3195
|
+
type: Annotated[str, "1C test object type, e.g. ТестируемаяФорма"] = "",
|
|
3196
|
+
limit: Annotated[int, "Maximum number of matched objects to return"] = 50,
|
|
3197
|
+
max_depth: Annotated[int, "Maximum search depth"] = 8,
|
|
3198
|
+
*,
|
|
3199
|
+
session_id: Annotated[str, "Session id"] = DEFAULT_SESSION,
|
|
3200
|
+
) -> Any:
|
|
3201
|
+
"""Find all UI objects matching name, title and/or 1C test object type."""
|
|
3202
|
+
return await _bridge_call_recorded(session_id, "search_objects", {"name": name, "title": title, "type": type, "limit": limit, "max_depth": max_depth})
|
|
3203
|
+
|
|
3204
|
+
|
|
3166
3205
|
@mcp.tool()
|
|
3167
3206
|
async def get_object(
|
|
3168
3207
|
name: Annotated[str, "Object name pattern"] = "",
|
|
@@ -3297,7 +3336,11 @@ async def tabular_documents(
|
|
|
3297
3336
|
*,
|
|
3298
3337
|
session_id: Annotated[str, "Session id"] = DEFAULT_SESSION,
|
|
3299
3338
|
) -> Any:
|
|
3300
|
-
"""List tabular document fields with dimensions; optionally include a cells range.
|
|
3339
|
+
"""List tabular document fields with dimensions; optionally include a cells range.
|
|
3340
|
+
|
|
3341
|
+
include_text is intended for small/partial ranges. For large tabular
|
|
3342
|
+
documents, save/export the report to a file and analyze that file instead.
|
|
3343
|
+
"""
|
|
3301
3344
|
return await _bridge_call_recorded(session_id, "tabular_documents", {"include_text": include_text, "max_depth": max_depth, "row_start": row_start, "row_end": row_end, "column_start": column_start, "column_end": column_end, "max_rows": max_rows, "max_columns": max_columns})
|
|
3302
3345
|
|
|
3303
3346
|
|
|
@@ -3315,7 +3358,13 @@ async def tabular_document_text(
|
|
|
3315
3358
|
*,
|
|
3316
3359
|
session_id: Annotated[str, "Session id"] = DEFAULT_SESSION,
|
|
3317
3360
|
) -> Any:
|
|
3318
|
-
"""Return dimensions and a cells range of a tabular document field in the active window.
|
|
3361
|
+
"""Return dimensions and a cells range of a tabular document field in the active window.
|
|
3362
|
+
|
|
3363
|
+
Use this for small tables or partial reads (headers, totals, spot checks). For
|
|
3364
|
+
large reports/tabular documents, prefer tabular_document_save/report export
|
|
3365
|
+
and analyze the saved PDF/XLSX/TXT/HTML file instead of reading UI cells one
|
|
3366
|
+
by one.
|
|
3367
|
+
"""
|
|
3319
3368
|
return await _bridge_call_recorded(session_id, "tabular_document_text", {"name": name, "title": title, "max_depth": max_depth, "row_start": row_start, "row_end": row_end, "column_start": column_start, "column_end": column_end, "max_rows": max_rows, "max_columns": max_columns})
|
|
3320
3369
|
|
|
3321
3370
|
|
|
@@ -3885,30 +3934,88 @@ async def configuration_name_version_from_subsystems(
|
|
|
3885
3934
|
) -> dict[str, Any]:
|
|
3886
3935
|
"""Open the 'Subsystem versions' information register and return the main configuration name/version.
|
|
3887
3936
|
|
|
3888
|
-
The tool reads
|
|
3889
|
-
|
|
3937
|
+
The tool reads `РегистрСведений.ВерсииПодсистем` via the list output
|
|
3938
|
+
command so that columns available to the dynamic list, including
|
|
3939
|
+
`Это основная конфигурация`, are visible even when they are not displayed
|
|
3940
|
+
in the default form table.
|
|
3890
3941
|
"""
|
|
3891
3942
|
navigation_link = "e1cib/list/РегистрСведений.ВерсииПодсистем"
|
|
3892
3943
|
await _bridge_call_recorded(session_id, "open_navigation_link", {"navigation_link": navigation_link})
|
|
3893
|
-
rows_result = await _bridge_call_recorded(session_id, "table_rows", {"name": "Список", "title": "", "limit": 200, "max_depth": 8})
|
|
3894
|
-
rows = rows_result.get("rows", []) if isinstance(rows_result, dict) else []
|
|
3895
3944
|
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3945
|
+
output_result = await _bridge_call_recorded(session_id, "dynamic_list_output", {
|
|
3946
|
+
"button": "",
|
|
3947
|
+
"wait_seconds": 3,
|
|
3948
|
+
"max_depth": 8,
|
|
3949
|
+
})
|
|
3950
|
+
tabular_docs = output_result.get("tabular_documents", {}) if isinstance(output_result, dict) else {}
|
|
3951
|
+
items = tabular_docs.get("items", []) if isinstance(tabular_docs, dict) else []
|
|
3952
|
+
|
|
3953
|
+
main: dict[str, str] = {}
|
|
3954
|
+
cells: list[list[str]] = []
|
|
3955
|
+
if items:
|
|
3956
|
+
doc_name = items[0].get("name", "")
|
|
3957
|
+
text_result = await _bridge_call_recorded(session_id, "tabular_document_text", {
|
|
3958
|
+
"name": doc_name,
|
|
3959
|
+
"max_rows": 50,
|
|
3960
|
+
"max_columns": 20,
|
|
3961
|
+
})
|
|
3962
|
+
cells = text_result.get("cells", []) if isinstance(text_result, dict) else []
|
|
3963
|
+
main = _find_main_configuration_in_tabular_cells(cells)
|
|
3899
3964
|
|
|
3900
3965
|
return {
|
|
3901
3966
|
"found": bool(main),
|
|
3902
|
-
"configuration_name":
|
|
3903
|
-
"configuration_version":
|
|
3967
|
+
"configuration_name": main.get("configuration_name", ""),
|
|
3968
|
+
"configuration_version": main.get("configuration_version", ""),
|
|
3904
3969
|
"main_configuration_row": main,
|
|
3905
|
-
"main_configuration_rows_count":
|
|
3906
|
-
"rows_count": len(
|
|
3970
|
+
"main_configuration_rows_count": 1 if main else 0,
|
|
3971
|
+
"rows_count": max(0, len(cells) - 1),
|
|
3907
3972
|
"navigation_link": navigation_link,
|
|
3908
3973
|
"source": "РегистрСведений.ВерсииПодсистем",
|
|
3909
3974
|
}
|
|
3910
3975
|
|
|
3911
3976
|
|
|
3977
|
+
def _find_main_configuration_in_tabular_cells(cells: list[list[str]]) -> dict[str, str]:
|
|
3978
|
+
"""Scan tabular document cells for the main configuration row."""
|
|
3979
|
+
if not cells or len(cells) < 2:
|
|
3980
|
+
return {}
|
|
3981
|
+
|
|
3982
|
+
header_row_idx = -1
|
|
3983
|
+
name_col = -1
|
|
3984
|
+
version_col = -1
|
|
3985
|
+
main_cfg_col = -1
|
|
3986
|
+
for i, row in enumerate(cells):
|
|
3987
|
+
local_name_col = local_version_col = local_main_cfg_col = -1
|
|
3988
|
+
for j, cell in enumerate(row):
|
|
3989
|
+
cell_norm = str(cell).strip()
|
|
3990
|
+
if cell_norm == "Имя подсистемы":
|
|
3991
|
+
local_name_col = j
|
|
3992
|
+
elif cell_norm == "Версия":
|
|
3993
|
+
local_version_col = j
|
|
3994
|
+
elif cell_norm == "Это основная конфигурация":
|
|
3995
|
+
local_main_cfg_col = j
|
|
3996
|
+
if local_name_col >= 0 and local_version_col >= 0 and local_main_cfg_col >= 0:
|
|
3997
|
+
header_row_idx = i
|
|
3998
|
+
name_col = local_name_col
|
|
3999
|
+
version_col = local_version_col
|
|
4000
|
+
main_cfg_col = local_main_cfg_col
|
|
4001
|
+
break
|
|
4002
|
+
|
|
4003
|
+
if header_row_idx < 0:
|
|
4004
|
+
return {}
|
|
4005
|
+
|
|
4006
|
+
for row in cells[header_row_idx + 1:]:
|
|
4007
|
+
if len(row) <= max(name_col, version_col, main_cfg_col):
|
|
4008
|
+
continue
|
|
4009
|
+
if _is_truthy_1c(str(row[main_cfg_col])):
|
|
4010
|
+
return {
|
|
4011
|
+
"configuration_name": str(row[name_col]).strip(),
|
|
4012
|
+
"configuration_version": str(row[version_col]).strip(),
|
|
4013
|
+
"Это основная конфигурация": str(row[main_cfg_col]).strip(),
|
|
4014
|
+
}
|
|
4015
|
+
|
|
4016
|
+
return {}
|
|
4017
|
+
|
|
4018
|
+
|
|
3912
4019
|
@mcp.tool()
|
|
3913
4020
|
async def installed_extensions_from_catalog(
|
|
3914
4021
|
*,
|
|
@@ -4468,7 +4575,13 @@ def screenshot(
|
|
|
4468
4575
|
*,
|
|
4469
4576
|
session_id: Annotated[str, "Session id"] = DEFAULT_SESSION,
|
|
4470
4577
|
) -> dict[str, Any]:
|
|
4471
|
-
"""Capture a screenshot from the MCP host. Defaults to the active visible 1C window.
|
|
4578
|
+
"""Capture a screenshot from the MCP host. Defaults to the active visible 1C window.
|
|
4579
|
+
|
|
4580
|
+
Screenshots are for user evidence and UI diagnostics only. Do not use them
|
|
4581
|
+
to analyze report/table/tabular-document/list data; use structured tools
|
|
4582
|
+
such as tabular_document_text, tabular_documents, table_rows,
|
|
4583
|
+
dynamic_list_output, or report export/save tools instead.
|
|
4584
|
+
"""
|
|
4472
4585
|
output_path = Path(path)
|
|
4473
4586
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
4474
4587
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{answer42-0.2.28 → answer42-0.2.29}/src/cf/DataProcessors/MCPTestManager/Ext/ObjectModule.bsl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|