answer42 0.2.26__tar.gz → 0.2.27__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.26 → answer42-0.2.27}/PKG-INFO +1 -1
- {answer42-0.2.26 → answer42-0.2.27}/pyproject.toml +1 -1
- {answer42-0.2.26 → answer42-0.2.27}/scripts/openclaw_mcp_autoreload.py +73 -2
- {answer42-0.2.26 → answer42-0.2.27}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form/Module.bsl +88 -35
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/assets/MCPTestManager.cf +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/protocol.py +1 -1
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/server.py +7 -2
- {answer42-0.2.26 → answer42-0.2.27}/.gitignore +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/LICENSE +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/README.md +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/credentials.example.json +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/docs/agent-installation.md +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/docs/architecture.md +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/docs/assets/answer42-logo.png +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/docs/assets/platform42-logo.svg +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/docs/installation.md +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/scripts/build_cf.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/scripts/build_pages.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/scripts/e2e_stable.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/scripts/rag_cli.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/cf/Configuration.xml +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/cf/DataProcessors/MCPTestManager/Ext/ObjectModule.bsl +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form.xml" +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260.xml" +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/cf/DataProcessors/MCPTestManager.xml +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/cf/Ext/ManagedApplicationModule.bsl +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/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.26 → answer42-0.2.27}/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.26 → answer42-0.2.27}/src/client_cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/client_cf/Configuration.xml +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/client_cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/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.26 → answer42-0.2.27}/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.26 → answer42-0.2.27}/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.26 → answer42-0.2.27}/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.26 → answer42-0.2.27}/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.26 → answer42-0.2.27}/src/mcp_1c/__init__.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/assets/MCPTestClient.cf +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/assets/__init__.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/assets/skills/answer42/SKILL.md +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/assets/skills/answer42-rag/SKILL.md +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/bridge.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/credentials.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/os_support.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/platform.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/rag/__init__.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/rag/detect.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/rag/model.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/rag/parsers.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/rag/service.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/rag/store.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/recorder.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/release_helper.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/runtime.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/src/mcp_1c/skill_installer.py +0 -0
- {answer42-0.2.26 → answer42-0.2.27}/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.27
|
|
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.27"
|
|
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"
|
|
@@ -11,6 +11,7 @@ import argparse
|
|
|
11
11
|
import atexit
|
|
12
12
|
import hashlib
|
|
13
13
|
import os
|
|
14
|
+
import signal
|
|
14
15
|
import subprocess
|
|
15
16
|
import sys
|
|
16
17
|
import time
|
|
@@ -35,12 +36,73 @@ def snapshot(root: Path, patterns: tuple[str, ...]) -> str:
|
|
|
35
36
|
return digest.hexdigest()
|
|
36
37
|
|
|
37
38
|
|
|
39
|
+
def _active_answer42_pids() -> list[int]:
|
|
40
|
+
"""Return active Answer42 MCP stdio process PIDs, excluding this watcher."""
|
|
41
|
+
current_pid = os.getpid()
|
|
42
|
+
try:
|
|
43
|
+
result = subprocess.run(
|
|
44
|
+
["ps", "-eo", "pid=,args="],
|
|
45
|
+
text=True,
|
|
46
|
+
stdout=subprocess.PIPE,
|
|
47
|
+
stderr=subprocess.DEVNULL,
|
|
48
|
+
check=False,
|
|
49
|
+
)
|
|
50
|
+
except Exception:
|
|
51
|
+
return []
|
|
52
|
+
pids: list[int] = []
|
|
53
|
+
for line in result.stdout.splitlines():
|
|
54
|
+
stripped = line.strip()
|
|
55
|
+
if not stripped:
|
|
56
|
+
continue
|
|
57
|
+
pid_text, _, cmd = stripped.partition(" ")
|
|
58
|
+
try:
|
|
59
|
+
pid = int(pid_text)
|
|
60
|
+
except ValueError:
|
|
61
|
+
continue
|
|
62
|
+
if pid == current_pid:
|
|
63
|
+
continue
|
|
64
|
+
if "openclaw_mcp_autoreload.py" in cmd:
|
|
65
|
+
continue
|
|
66
|
+
if "--dev openclaw" not in cmd:
|
|
67
|
+
continue
|
|
68
|
+
if "/answer42" in cmd or "mcp_1c.server" in cmd:
|
|
69
|
+
pids.append(pid)
|
|
70
|
+
return pids
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def kill_active_answer42(timeout: float = 5.0) -> list[int]:
|
|
74
|
+
"""Terminate active Answer42 MCP processes so next tool call starts fresh code/env."""
|
|
75
|
+
pids = _active_answer42_pids()
|
|
76
|
+
if not pids:
|
|
77
|
+
return []
|
|
78
|
+
for pid in pids:
|
|
79
|
+
try:
|
|
80
|
+
os.kill(pid, signal.SIGTERM)
|
|
81
|
+
except ProcessLookupError:
|
|
82
|
+
pass
|
|
83
|
+
deadline = time.monotonic() + timeout
|
|
84
|
+
remaining = set(pids)
|
|
85
|
+
while remaining and time.monotonic() < deadline:
|
|
86
|
+
time.sleep(0.2)
|
|
87
|
+
for pid in list(remaining):
|
|
88
|
+
try:
|
|
89
|
+
os.kill(pid, 0)
|
|
90
|
+
except ProcessLookupError:
|
|
91
|
+
remaining.discard(pid)
|
|
92
|
+
for pid in sorted(remaining):
|
|
93
|
+
try:
|
|
94
|
+
os.kill(pid, signal.SIGKILL)
|
|
95
|
+
except ProcessLookupError:
|
|
96
|
+
pass
|
|
97
|
+
return pids
|
|
98
|
+
|
|
99
|
+
|
|
38
100
|
def run_reload(server: str | None) -> int:
|
|
39
101
|
cmd = ["openclaw", "mcp", "reload"]
|
|
40
102
|
# Current OpenClaw reload command is global; keep --server support ready if added later.
|
|
41
103
|
if server:
|
|
42
104
|
probe = subprocess.run(["openclaw", "mcp", "reload", "--help"], text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
43
|
-
if
|
|
105
|
+
if "--server" in probe.stdout:
|
|
44
106
|
cmd.extend(["--server", server])
|
|
45
107
|
result = subprocess.run(cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
46
108
|
sys.stdout.write(result.stdout)
|
|
@@ -59,7 +121,12 @@ def main() -> int:
|
|
|
59
121
|
default=30.0,
|
|
60
122
|
help="seconds to wait after the last detected change before reloading OpenClaw MCP runtimes",
|
|
61
123
|
)
|
|
62
|
-
parser.add_argument("--server", default="
|
|
124
|
+
parser.add_argument("--server", default="Answer42")
|
|
125
|
+
parser.add_argument(
|
|
126
|
+
"--no-kill-active",
|
|
127
|
+
action="store_true",
|
|
128
|
+
help="do not terminate active Answer42 stdio processes after OpenClaw cache reload",
|
|
129
|
+
)
|
|
63
130
|
parser.add_argument("--once", action="store_true", help="wait for one change, reload once, exit")
|
|
64
131
|
parser.add_argument("--pid-file", default="", help="write watcher pid to this file and remove it on exit")
|
|
65
132
|
args = parser.parse_args()
|
|
@@ -108,6 +175,10 @@ def main() -> int:
|
|
|
108
175
|
print("[mcp-autoreload] change detected; running openclaw mcp reload", flush=True)
|
|
109
176
|
code = run_reload(args.server)
|
|
110
177
|
print(f"[mcp-autoreload] reload exit code {code}", flush=True)
|
|
178
|
+
if code == 0 and not args.no_kill_active:
|
|
179
|
+
killed = kill_active_answer42()
|
|
180
|
+
if killed:
|
|
181
|
+
print(f"[mcp-autoreload] terminated active Answer42 MCP processes: {killed}", flush=True)
|
|
111
182
|
if args.once:
|
|
112
183
|
return code
|
|
113
184
|
|
|
@@ -240,7 +240,7 @@
|
|
|
240
240
|
|
|
241
241
|
&НаКлиенте
|
|
242
242
|
Функция ВерсияПротоколаМенеджераMCP()
|
|
243
|
-
Возврат "2026.07.02.
|
|
243
|
+
Возврат "2026.07.02.3";
|
|
244
244
|
КонецФункции
|
|
245
245
|
|
|
246
246
|
&НаКлиенте
|
|
@@ -1646,11 +1646,13 @@
|
|
|
1646
1646
|
АктивноеОкно = КомандныйИнтерфейсЦелевоеОкно(Параметры);
|
|
1647
1647
|
Интерфейс = АктивноеОкно.ПолучитьКомандныйИнтерфейс();
|
|
1648
1648
|
Если Интерфейс = Неопределено Тогда
|
|
1649
|
-
|
|
1649
|
+
РезультатКоманды = Новый Структура("available,reason,window", Ложь, "not_available", ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1650
1650
|
Иначе
|
|
1651
1651
|
Дерево = КомандныйИнтерфейсОбъектВСтруктуру(Интерфейс, 0, Глубина);
|
|
1652
|
-
|
|
1652
|
+
РезультатКоманды = Новый Структура("available,interface,window", Истина, Дерево, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1653
1653
|
КонецЕсли;
|
|
1654
|
+
ЗакрытьКомандныйИнтерфейсПослеРаботыMCP(АктивноеОкно);
|
|
1655
|
+
Возврат РезультатКоманды;
|
|
1654
1656
|
Исключение
|
|
1655
1657
|
Возврат Новый Структура("available,reason,error", Ложь, "not_supported", ОписаниеОшибки());
|
|
1656
1658
|
КонецПопытки;
|
|
@@ -1666,11 +1668,13 @@
|
|
|
1666
1668
|
АктивноеОкно = КомандныйИнтерфейсЦелевоеОкно(Параметры);
|
|
1667
1669
|
Интерфейс = АктивноеОкно.ПолучитьКомандныйИнтерфейс();
|
|
1668
1670
|
Если Интерфейс = Неопределено Тогда
|
|
1669
|
-
|
|
1671
|
+
РезультатКоманды = Новый Структура("available,reason,window", Ложь, "not_available", ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1672
|
+
Иначе
|
|
1673
|
+
Разделы = РазделыКомандногоИнтерфейса(Интерфейс);
|
|
1674
|
+
РезультатКоманды = Новый Структура("available,sections,window", Истина, Разделы, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1670
1675
|
КонецЕсли;
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
Возврат Новый Структура("available,sections,window", Истина, Разделы, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1676
|
+
ЗакрытьКомандныйИнтерфейсПослеРаботыMCP(АктивноеОкно);
|
|
1677
|
+
Возврат РезультатКоманды;
|
|
1674
1678
|
Исключение
|
|
1675
1679
|
Возврат Новый Структура("available,reason,error", Ложь, "not_supported", ОписаниеОшибки());
|
|
1676
1680
|
КонецПопытки;
|
|
@@ -1682,30 +1686,41 @@
|
|
|
1682
1686
|
ВызватьИсключение "Тестируемое приложение не подключено.";
|
|
1683
1687
|
КонецЕсли;
|
|
1684
1688
|
|
|
1689
|
+
АктивноеОкно = Неопределено;
|
|
1690
|
+
КнопкаРаздела = Неопределено;
|
|
1685
1691
|
Попытка
|
|
1686
1692
|
Глубина = СвойствоСтруктуры(Параметры, "max_depth", 4);
|
|
1687
1693
|
ЗаголовокРаздела = СвойствоСтруктуры(Параметры, "section", "");
|
|
1688
1694
|
АктивноеОкно = КомандныйИнтерфейсЦелевоеОкно(Параметры);
|
|
1689
1695
|
Интерфейс = АктивноеОкно.ПолучитьКомандныйИнтерфейс();
|
|
1690
1696
|
Если Интерфейс = Неопределено Тогда
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
Корень = Интерфейс;
|
|
1695
|
-
Если Не ПустаяСтрока(ЗаголовокРаздела) Тогда
|
|
1696
|
-
КнопкаРаздела = КомандныйИнтерфейсНайтиРаздел(Интерфейс, ЗаголовокРаздела);
|
|
1697
|
-
Если КнопкаРаздела = Неопределено Тогда
|
|
1698
|
-
Возврат Новый Структура("available,found,reason,section,window", Истина, Ложь, "section_not_found", ЗаголовокРаздела, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1699
|
-
КонецЕсли;
|
|
1700
|
-
КнопкаРаздела.Нажать();
|
|
1701
|
-
Интерфейс = АктивноеОкно.ПолучитьКомандныйИнтерфейс();
|
|
1697
|
+
РезультатКоманды = Новый Структура("available,reason,window", Ложь, "not_available", ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1698
|
+
Иначе
|
|
1702
1699
|
Корень = Интерфейс;
|
|
1700
|
+
Если Не ПустаяСтрока(ЗаголовокРаздела) Тогда
|
|
1701
|
+
КнопкаРаздела = КомандныйИнтерфейсНайтиРаздел(Интерфейс, ЗаголовокРаздела);
|
|
1702
|
+
Если КнопкаРаздела = Неопределено Тогда
|
|
1703
|
+
РезультатКоманды = Новый Структура("available,found,reason,section,window", Истина, Ложь, "section_not_found", ЗаголовокРаздела, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1704
|
+
Иначе
|
|
1705
|
+
КнопкаРаздела.Нажать();
|
|
1706
|
+
Интерфейс = АктивноеОкно.ПолучитьКомандныйИнтерфейс();
|
|
1707
|
+
Корень = Интерфейс;
|
|
1708
|
+
Дерево = КомандныйИнтерфейсОбъектВСтруктуру(Корень, 0, Глубина);
|
|
1709
|
+
ЛокКоманды = КомандыКомандногоИнтерфейса(Корень, Истина);
|
|
1710
|
+
РезультатКоманды = Новый Структура("available,found,section,tree,commands,window", Истина, Истина, ЗаголовокРаздела, Дерево, ЛокКоманды, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1711
|
+
КонецЕсли;
|
|
1712
|
+
Иначе
|
|
1713
|
+
Дерево = КомандныйИнтерфейсОбъектВСтруктуру(Корень, 0, Глубина);
|
|
1714
|
+
ЛокКоманды = КомандыКомандногоИнтерфейса(Корень, Истина);
|
|
1715
|
+
РезультатКоманды = Новый Структура("available,found,section,tree,commands,window", Истина, Истина, ЗаголовокРаздела, Дерево, ЛокКоманды, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1716
|
+
КонецЕсли;
|
|
1703
1717
|
КонецЕсли;
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
ЛокКоманды = КомандыКомандногоИнтерфейса(Корень, Истина);
|
|
1707
|
-
Возврат Новый Структура("available,found,section,tree,commands,window", Истина, Истина, ЗаголовокРаздела, Дерево, ЛокКоманды, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1718
|
+
ЗакрытьКомандныйИнтерфейсПослеРаботыMCP(АктивноеОкно, КнопкаРаздела);
|
|
1719
|
+
Возврат РезультатКоманды;
|
|
1708
1720
|
Исключение
|
|
1721
|
+
Если АктивноеОкно <> Неопределено Тогда
|
|
1722
|
+
ЗакрытьКомандныйИнтерфейсПослеРаботыMCP(АктивноеОкно, КнопкаРаздела);
|
|
1723
|
+
КонецЕсли;
|
|
1709
1724
|
Возврат Новый Структура("available,reason,error", Ложь, "not_supported", ОписаниеОшибки());
|
|
1710
1725
|
КонецПопытки;
|
|
1711
1726
|
КонецФункции
|
|
@@ -1716,6 +1731,8 @@
|
|
|
1716
1731
|
ВызватьИсключение "Тестируемое приложение не подключено.";
|
|
1717
1732
|
КонецЕсли;
|
|
1718
1733
|
|
|
1734
|
+
АктивноеОкно = Неопределено;
|
|
1735
|
+
КнопкаРаздела = Неопределено;
|
|
1719
1736
|
Попытка
|
|
1720
1737
|
СтрокаПоиска = СокрЛП(СвойствоСтруктуры(Параметры, "query", ""));
|
|
1721
1738
|
Если ПустаяСтрока(СтрокаПоиска) Тогда
|
|
@@ -1727,26 +1744,62 @@
|
|
|
1727
1744
|
АктивноеОкно = КомандныйИнтерфейсЦелевоеОкно(Параметры);
|
|
1728
1745
|
Интерфейс = АктивноеОкно.ПолучитьКомандныйИнтерфейс();
|
|
1729
1746
|
Если Интерфейс = Неопределено Тогда
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1747
|
+
РезультатПоиска = Новый Структура("available,reason,window", Ложь, "not_available", ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1748
|
+
Иначе
|
|
1749
|
+
Если Не ПустаяСтрока(ЗаголовокРаздела) Тогда
|
|
1750
|
+
КнопкаРаздела = КомандныйИнтерфейсНайтиРаздел(Интерфейс, ЗаголовокРаздела);
|
|
1751
|
+
Если КнопкаРаздела = Неопределено Тогда
|
|
1752
|
+
РезультатПоиска = Новый Структура("available,found,reason,query,section,matches,window", Истина, Ложь, "section_not_found", СтрокаПоиска, ЗаголовокРаздела, Новый Массив, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1753
|
+
Иначе
|
|
1754
|
+
КнопкаРаздела.Нажать();
|
|
1755
|
+
Интерфейс = АктивноеОкно.ПолучитьКомандныйИнтерфейс();
|
|
1756
|
+
ВсеКоманды = КомандыКомандногоИнтерфейса(Интерфейс, Истина);
|
|
1757
|
+
Совпадения = ПоискВКомандахКомандногоИнтерфейса(ВсеКоманды, СтрокаПоиска, Максимум);
|
|
1758
|
+
РезультатПоиска = Новый Структура("available,found,query,section,count,matches,window", Истина, Совпадения.Количество() > 0, СтрокаПоиска, ЗаголовокРаздела, Совпадения.Количество(), Совпадения, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1759
|
+
КонецЕсли;
|
|
1760
|
+
Иначе
|
|
1761
|
+
ВсеКоманды = КомандыКомандногоИнтерфейса(Интерфейс, Истина);
|
|
1762
|
+
Совпадения = ПоискВКомандахКомандногоИнтерфейса(ВсеКоманды, СтрокаПоиска, Максимум);
|
|
1763
|
+
РезультатПоиска = Новый Структура("available,found,query,section,count,matches,window", Истина, Совпадения.Количество() > 0, СтрокаПоиска, ЗаголовокРаздела, Совпадения.Количество(), Совпадения, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1737
1764
|
КонецЕсли;
|
|
1738
|
-
КнопкаРаздела.Нажать();
|
|
1739
|
-
Интерфейс = АктивноеОкно.ПолучитьКомандныйИнтерфейс();
|
|
1740
1765
|
КонецЕсли;
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
Совпадения = ПоискВКомандахКомандногоИнтерфейса(ВсеКоманды, СтрокаПоиска, Максимум);
|
|
1744
|
-
Возврат Новый Структура("available,found,query,section,count,matches,window", Истина, Совпадения.Количество() > 0, СтрокаПоиска, ЗаголовокРаздела, Совпадения.Количество(), Совпадения, ОбъектВСтруктуру(АктивноеОкно, 0, 0));
|
|
1766
|
+
ЗакрытьКомандныйИнтерфейсПослеРаботыMCP(АктивноеОкно, КнопкаРаздела);
|
|
1767
|
+
Возврат РезультатПоиска;
|
|
1745
1768
|
Исключение
|
|
1769
|
+
Если АктивноеОкно <> Неопределено Тогда
|
|
1770
|
+
ЗакрытьКомандныйИнтерфейсПослеРаботыMCP(АктивноеОкно, КнопкаРаздела);
|
|
1771
|
+
КонецЕсли;
|
|
1746
1772
|
Возврат Новый Структура("available,reason,error", Ложь, "not_supported", ОписаниеОшибки());
|
|
1747
1773
|
КонецПопытки;
|
|
1748
1774
|
КонецФункции
|
|
1749
1775
|
|
|
1776
|
+
&НаКлиенте
|
|
1777
|
+
Процедура ЗакрытьКомандныйИнтерфейсПослеРаботыMCP(Окно, КнопкаРаздела = Неопределено)
|
|
1778
|
+
// Некоторые методы test-client оставляют раскрытый командный интерфейс поверх
|
|
1779
|
+
// формы. После этого интерактивные действия по форме могут падать с
|
|
1780
|
+
// "Недоступный пользователю элемент управления...". Возвращаем UI в форму:
|
|
1781
|
+
// если нажимали кнопку раздела — нажимаем её повторно (переключатель панели),
|
|
1782
|
+
// затем активизируем окно и первую найденную форму.
|
|
1783
|
+
Если КнопкаРаздела <> Неопределено Тогда
|
|
1784
|
+
Попытка
|
|
1785
|
+
КнопкаРаздела.Нажать();
|
|
1786
|
+
Исключение
|
|
1787
|
+
// Игнорируем: cleanup не должен ломать полезный результат команды.
|
|
1788
|
+
КонецПопытки;
|
|
1789
|
+
КонецЕсли;
|
|
1790
|
+
Попытка
|
|
1791
|
+
Окно.Активизировать();
|
|
1792
|
+
Исключение
|
|
1793
|
+
КонецПопытки;
|
|
1794
|
+
Попытка
|
|
1795
|
+
Форма = НайтиОбъектРекурсивно(Окно, "", "", "тестируемаяформа", 0, 8);
|
|
1796
|
+
Если Форма <> Неопределено Тогда
|
|
1797
|
+
Форма.Активизировать();
|
|
1798
|
+
КонецЕсли;
|
|
1799
|
+
Исключение
|
|
1800
|
+
КонецПопытки;
|
|
1801
|
+
КонецПроцедуры
|
|
1802
|
+
|
|
1750
1803
|
&НаКлиенте
|
|
1751
1804
|
Функция КомандныйИнтерфейсЦелевоеОкно(Параметры)
|
|
1752
1805
|
ОкноЗаголовок = СвойствоСтруктуры(Параметры, "window_title", "");
|
|
Binary file
|
|
@@ -1699,8 +1699,13 @@ async def start_session(
|
|
|
1699
1699
|
) -> dict[str, Any]:
|
|
1700
1700
|
"""One-shot session factory: detect version, start infrastructure and connect the 1C test client."""
|
|
1701
1701
|
credential_ref = _resolve_credential_reference(base_url)
|
|
1702
|
-
|
|
1703
|
-
|
|
1702
|
+
input_looks_like_url = bool(re.match(r"^[A-Za-z][A-Za-z0-9+.-]*://", str(base_url or "")))
|
|
1703
|
+
if credential_ref is not None:
|
|
1704
|
+
# For saved titles/aliases, replace title -> real URL. For URL/wildcard matches,
|
|
1705
|
+
# keep the original requested URL; using the wildcard pattern itself as /WS value
|
|
1706
|
+
# would make the 1C client fail with invalid connection parameters.
|
|
1707
|
+
if credential_ref.get("url") and not input_looks_like_url:
|
|
1708
|
+
base_url = str(credential_ref["url"])
|
|
1704
1709
|
if not username:
|
|
1705
1710
|
username = str(credential_ref.get("username", ""))
|
|
1706
1711
|
if not password:
|
|
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.26 → answer42-0.2.27}/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
|