answer42 0.4.89__tar.gz → 0.4.91__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.4.89 → answer42-0.4.91}/PKG-INFO +1 -1
- {answer42-0.4.89 → answer42-0.4.91}/pyproject.toml +1 -1
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/server.py +190 -66
- {answer42-0.4.89 → answer42-0.4.91}/.gitignore +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/LICENSE +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/README.md +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/credentials.example.json +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/docs/agent-installation.md +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/docs/architecture.md +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/docs/assets/answer42-logo.png +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/docs/assets/platform42-logo.svg +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/docs/installation.md +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/scripts/build_cf.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/scripts/build_pages.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/scripts/e2e_http_smoke.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/scripts/e2e_stable.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/scripts/openclaw_mcp_autoreload.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/scripts/rag_cli.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/cf/Configuration.xml +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/cf/DataProcessors/MCPTestManager/Ext/ObjectModule.bsl +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form/Module.bsl" +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form.xml" +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260.xml" +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/cf/DataProcessors/MCPTestManager.xml +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/cf/Ext/ManagedApplicationModule.bsl +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/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.4.89 → answer42-0.4.91}/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.4.89 → answer42-0.4.91}/src/client_cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/client_cf/Configuration.xml +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/client_cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/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.4.89 → answer42-0.4.91}/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.4.89 → answer42-0.4.91}/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.4.89 → answer42-0.4.91}/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.4.89 → answer42-0.4.91}/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.4.89 → answer42-0.4.91}/src/mcp_1c/__init__.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/assets/MCPTestClient.cf +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/assets/MCPTestManager.cf +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/assets/__init__.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/assets/skills/answer42/SKILL.md +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/assets/skills/answer42-rag/SKILL.md +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/assets/skills/answer42-universal-report/SKILL.md +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/auth.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/bridge.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/credentials.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/os_support.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/platform.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/protocol.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/rag/__init__.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/rag/detect.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/rag/dump.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/rag/model.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/rag/parsers.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/rag/service.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/rag/store.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/rag/summary_backend.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/rag/summary_vector.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/recorder.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/release_helper.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/runtime.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/skill_installer.py +0 -0
- {answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/window_control.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: answer42
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.91
|
|
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.4.
|
|
3
|
+
version = "0.4.91"
|
|
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"
|
|
@@ -16,6 +16,7 @@ import sys
|
|
|
16
16
|
import time
|
|
17
17
|
import urllib.request
|
|
18
18
|
import uuid
|
|
19
|
+
from collections.abc import Sequence
|
|
19
20
|
from contextlib import contextmanager, suppress
|
|
20
21
|
from dataclasses import dataclass, field
|
|
21
22
|
from datetime import UTC, datetime
|
|
@@ -8118,6 +8119,62 @@ async def _add_universal_report_filter(
|
|
|
8118
8119
|
return True
|
|
8119
8120
|
|
|
8120
8121
|
|
|
8122
|
+
def _active_window_matches_self_opened_form(
|
|
8123
|
+
active_window: Any,
|
|
8124
|
+
*,
|
|
8125
|
+
title_markers: Sequence[str] = (),
|
|
8126
|
+
form_names: Sequence[str] = (),
|
|
8127
|
+
) -> bool:
|
|
8128
|
+
if not isinstance(active_window, dict):
|
|
8129
|
+
return False
|
|
8130
|
+
normalized_form_names = {str(name or "").casefold() for name in form_names if str(name or "").strip()}
|
|
8131
|
+
form_name = str(active_window.get("form_name") or "").casefold()
|
|
8132
|
+
if form_name and form_name in normalized_form_names:
|
|
8133
|
+
return True
|
|
8134
|
+
diagnostics = active_window.get("client_diagnostics") if isinstance(active_window.get("client_diagnostics"), dict) else {}
|
|
8135
|
+
titles = [
|
|
8136
|
+
active_window.get("title"),
|
|
8137
|
+
active_window.get("window_title"),
|
|
8138
|
+
diagnostics.get("active_window_title"),
|
|
8139
|
+
diagnostics.get("modal_title"),
|
|
8140
|
+
]
|
|
8141
|
+
normalized_markers = [_normalize_match_text(marker) for marker in title_markers if str(marker or "").strip()]
|
|
8142
|
+
return any(
|
|
8143
|
+
marker and marker in _normalize_match_text(str(title or ""))
|
|
8144
|
+
for marker in normalized_markers
|
|
8145
|
+
for title in titles
|
|
8146
|
+
)
|
|
8147
|
+
|
|
8148
|
+
|
|
8149
|
+
async def _close_self_opened_form(
|
|
8150
|
+
session_id: str,
|
|
8151
|
+
warnings: list[str],
|
|
8152
|
+
*,
|
|
8153
|
+
title_markers: Sequence[str] = (),
|
|
8154
|
+
form_names: Sequence[str] = (),
|
|
8155
|
+
description: str = "form",
|
|
8156
|
+
) -> bool:
|
|
8157
|
+
"""Close a form opened by a high-level helper without touching unrelated user UI."""
|
|
8158
|
+
try:
|
|
8159
|
+
active = await _bridge_call_recorded(session_id, "active_window", {})
|
|
8160
|
+
except Exception as exc:
|
|
8161
|
+
warnings.append(f"Self-opened {description} cleanup active-window probe failed: {exc}")
|
|
8162
|
+
return False
|
|
8163
|
+
if not _active_window_matches_self_opened_form(
|
|
8164
|
+
active,
|
|
8165
|
+
title_markers=title_markers,
|
|
8166
|
+
form_names=form_names,
|
|
8167
|
+
):
|
|
8168
|
+
return False
|
|
8169
|
+
try:
|
|
8170
|
+
await _bridge_call_recorded(session_id, "close_form", {})
|
|
8171
|
+
warnings.append(f"Self-opened {description} form was closed after tool completion")
|
|
8172
|
+
return True
|
|
8173
|
+
except Exception as exc:
|
|
8174
|
+
warnings.append(f"Self-opened {description} form cleanup failed: {exc}")
|
|
8175
|
+
return False
|
|
8176
|
+
|
|
8177
|
+
|
|
8121
8178
|
async def _close_message_box_from_command_diagnostics(
|
|
8122
8179
|
session_id: str,
|
|
8123
8180
|
command_result: Any,
|
|
@@ -8411,8 +8468,11 @@ async def _metadata_rows_from_universal_report(
|
|
|
8411
8468
|
"""
|
|
8412
8469
|
warnings: list[str] = []
|
|
8413
8470
|
navigation_link = "e1cib/app/Отчет.УниверсальныйОтчет"
|
|
8471
|
+
cleanup_enabled = False
|
|
8472
|
+
cleanup_allowed = True
|
|
8414
8473
|
try:
|
|
8415
8474
|
open_result = await _bridge_call_recorded(session_id, "open_navigation_link", {"navigation_link": navigation_link})
|
|
8475
|
+
cleanup_enabled = True
|
|
8416
8476
|
await _close_message_box_from_command_diagnostics(session_id, open_result, warnings)
|
|
8417
8477
|
source_configured = await _ensure_universal_report_metadata_source(
|
|
8418
8478
|
session_id,
|
|
@@ -8430,6 +8490,7 @@ async def _metadata_rows_from_universal_report(
|
|
|
8430
8490
|
form_warnings = await _form_universal_report_metadata_source(session_id)
|
|
8431
8491
|
warnings.extend(form_warnings)
|
|
8432
8492
|
if any("form action is still running or blocked" in warning for warning in form_warnings):
|
|
8493
|
+
cleanup_allowed = False
|
|
8433
8494
|
return [], warnings
|
|
8434
8495
|
ready, readiness_warnings, readiness = await _wait_tabular_document_ready(
|
|
8435
8496
|
session_id,
|
|
@@ -8469,6 +8530,7 @@ async def _metadata_rows_from_universal_report(
|
|
|
8469
8530
|
"Universal report MXL save is still running or blocked the interface;"
|
|
8470
8531
|
f" save_result={_truncate_value(selected_result)}"
|
|
8471
8532
|
)
|
|
8533
|
+
cleanup_allowed = False
|
|
8472
8534
|
return [], [*warnings, *read_warnings]
|
|
8473
8535
|
save_diagnostics = selected_result
|
|
8474
8536
|
selected = selected_result.get("selected") if isinstance(selected_result, dict) else None
|
|
@@ -8491,7 +8553,7 @@ async def _metadata_rows_from_universal_report(
|
|
|
8491
8553
|
"Universal report MXL became parseable"
|
|
8492
8554
|
f"; rows={readiness.get('rows')}; columns={readiness.get('columns')}; path={last_saved_path}"
|
|
8493
8555
|
)
|
|
8494
|
-
return rows[:max_rows], warnings
|
|
8556
|
+
return rows if max_rows <= 0 else rows[:max_rows], warnings
|
|
8495
8557
|
|
|
8496
8558
|
report_path = _runtime_output_file("metadata_objects", session_id, ".xlsx")
|
|
8497
8559
|
try:
|
|
@@ -8512,6 +8574,7 @@ async def _metadata_rows_from_universal_report(
|
|
|
8512
8574
|
"Universal report XLSX save is still running or blocked the interface;"
|
|
8513
8575
|
f" save_result={_truncate_value(selected_result)}"
|
|
8514
8576
|
)
|
|
8577
|
+
cleanup_allowed = False
|
|
8515
8578
|
return [], [*warnings, *read_warnings]
|
|
8516
8579
|
save_diagnostics = selected_result
|
|
8517
8580
|
selected = selected_result.get("selected") if isinstance(selected_result, dict) else None
|
|
@@ -8541,9 +8604,20 @@ async def _metadata_rows_from_universal_report(
|
|
|
8541
8604
|
"Universal report XLSX became parseable"
|
|
8542
8605
|
f"; rows={readiness.get('rows')}; columns={readiness.get('columns')}; path={last_saved_path}"
|
|
8543
8606
|
)
|
|
8544
|
-
return rows[:max_rows], warnings
|
|
8607
|
+
return rows if max_rows <= 0 else rows[:max_rows], warnings
|
|
8545
8608
|
except Exception as exc:
|
|
8546
8609
|
return [], [f"Universal report metadata read failed: {exc}"]
|
|
8610
|
+
finally:
|
|
8611
|
+
current_task = asyncio.current_task()
|
|
8612
|
+
is_cancelling = bool(current_task and current_task.cancelling())
|
|
8613
|
+
if cleanup_enabled and cleanup_allowed and not is_cancelling:
|
|
8614
|
+
await _close_self_opened_form(
|
|
8615
|
+
session_id,
|
|
8616
|
+
warnings,
|
|
8617
|
+
title_markers=("Универсальный отчет", "Идентификаторы объектов метаданных"),
|
|
8618
|
+
form_names=("ОбщаяФорма.ФормаОтчета",),
|
|
8619
|
+
description="Universal report metadata source",
|
|
8620
|
+
)
|
|
8547
8621
|
|
|
8548
8622
|
|
|
8549
8623
|
async def _metadata_catalog_rows_from_output(session_id: str, max_rows: int) -> tuple[list[dict[str, str]], list[str]]:
|
|
@@ -8908,17 +8982,21 @@ async def _metadata_rows_from_target_catalog_list(
|
|
|
8908
8982
|
) -> tuple[list[dict[str, str]], list[str]]:
|
|
8909
8983
|
warnings: list[str] = []
|
|
8910
8984
|
navigation_link = "e1cib/list/Справочник.ИдентификаторыОбъектовМетаданных"
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
"open_navigation_link",
|
|
8914
|
-
{"navigation_link": navigation_link},
|
|
8915
|
-
timeout=15,
|
|
8916
|
-
danger="metadata_target_catalog_list_open_may_block_thin_client",
|
|
8917
|
-
)
|
|
8918
|
-
if isinstance(open_result, dict) and open_result.get("started_long_action"):
|
|
8919
|
-
warnings.append("Target metadata catalog list open watchdog timeout")
|
|
8920
|
-
return [], warnings
|
|
8985
|
+
cleanup_enabled = False
|
|
8986
|
+
cleanup_allowed = True
|
|
8921
8987
|
try:
|
|
8988
|
+
open_result = await _dangerous_bridge_call_recorded(
|
|
8989
|
+
session_id,
|
|
8990
|
+
"open_navigation_link",
|
|
8991
|
+
{"navigation_link": navigation_link},
|
|
8992
|
+
timeout=15,
|
|
8993
|
+
danger="metadata_target_catalog_list_open_may_block_thin_client",
|
|
8994
|
+
)
|
|
8995
|
+
cleanup_enabled = True
|
|
8996
|
+
if isinstance(open_result, dict) and open_result.get("started_long_action"):
|
|
8997
|
+
cleanup_allowed = False
|
|
8998
|
+
warnings.append("Target metadata catalog list open watchdog timeout")
|
|
8999
|
+
return [], warnings
|
|
8922
9000
|
result = await _bridge_call_recorded(
|
|
8923
9001
|
session_id,
|
|
8924
9002
|
"table_rows",
|
|
@@ -8927,6 +9005,17 @@ async def _metadata_rows_from_target_catalog_list(
|
|
|
8927
9005
|
)
|
|
8928
9006
|
except Exception as exc:
|
|
8929
9007
|
return [], [f"Target metadata catalog list read failed: {exc}"]
|
|
9008
|
+
finally:
|
|
9009
|
+
current_task = asyncio.current_task()
|
|
9010
|
+
is_cancelling = bool(current_task and current_task.cancelling())
|
|
9011
|
+
if cleanup_enabled and cleanup_allowed and not is_cancelling:
|
|
9012
|
+
await _close_self_opened_form(
|
|
9013
|
+
session_id,
|
|
9014
|
+
warnings,
|
|
9015
|
+
title_markers=("Идентификаторы объектов метаданных",),
|
|
9016
|
+
form_names=("Справочник.ИдентификаторыОбъектовМетаданных.ФормаСписка",),
|
|
9017
|
+
description="metadata identifiers catalog list",
|
|
9018
|
+
)
|
|
8930
9019
|
raw_rows = result.get("rows", []) if isinstance(result, dict) else []
|
|
8931
9020
|
parsed_rows: list[dict[str, str]] = []
|
|
8932
9021
|
for row in raw_rows:
|
|
@@ -9006,7 +9095,7 @@ async def _load_metadata_objects_from_catalog(session_id: str, limit: int, query
|
|
|
9006
9095
|
del query, max_results
|
|
9007
9096
|
navigation_link = "e1cib/app/Отчет.УниверсальныйОтчет"
|
|
9008
9097
|
requested_limit = max(1, int(limit or 1))
|
|
9009
|
-
parsed_rows, warnings = await _metadata_rows_from_universal_report(session_id,
|
|
9098
|
+
parsed_rows, warnings = await _metadata_rows_from_universal_report(session_id, 0)
|
|
9010
9099
|
if not parsed_rows:
|
|
9011
9100
|
warnings.append("Universal report returned no metadata rows for cache build")
|
|
9012
9101
|
data = _metadata_catalog_data_from_rows(
|
|
@@ -9076,7 +9165,7 @@ async def _metadata_objects_from_catalog_impl(
|
|
|
9076
9165
|
@mcp.tool()
|
|
9077
9166
|
async def metadata_objects_from_catalog(
|
|
9078
9167
|
query: Annotated[str, "Substring to search in presentation, full name, type, name or synonym"] = "",
|
|
9079
|
-
limit: Annotated[int, "
|
|
9168
|
+
limit: Annotated[int, "Deprecated compatibility parameter; cache refresh always reads the full saved Universal report. Use max_results to limit returned matches"] = 10000,
|
|
9080
9169
|
max_results: Annotated[int, "Maximum matched objects to return"] = 200,
|
|
9081
9170
|
refresh_cache: Annotated[bool, "Force rebuilding the Universal report snapshot instead of using the session cache"] = False,
|
|
9082
9171
|
include_groups: Annotated[bool, "Include hierarchy group rows in results"] = False,
|
|
@@ -9224,64 +9313,78 @@ async def configuration_name_version_from_subsystems(
|
|
|
9224
9313
|
`Это основная конфигурация`, are visible even when they are not displayed
|
|
9225
9314
|
in the default form table.
|
|
9226
9315
|
"""
|
|
9227
|
-
navigation_link = "e1cib/list/РегистрСведений.ВерсииПодсистем"
|
|
9228
|
-
await _bridge_call_recorded(session_id, "open_navigation_link", {"navigation_link": navigation_link})
|
|
9229
|
-
|
|
9230
9316
|
warnings: list[str] = []
|
|
9231
9317
|
main: dict[str, str] = {}
|
|
9232
9318
|
cells: list[list[str]] = []
|
|
9233
9319
|
source_method = "sorted_edge_row"
|
|
9234
9320
|
current_row: dict[str, str] = {}
|
|
9235
9321
|
sort_attempts: list[dict[str, Any]] = []
|
|
9322
|
+
navigation_link = "e1cib/list/РегистрСведений.ВерсииПодсистем"
|
|
9323
|
+
cleanup_enabled = False
|
|
9236
9324
|
|
|
9237
|
-
|
|
9238
|
-
"
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
ordered = bool(sort_result.get("ordered")) if isinstance(sort_result, dict) else False
|
|
9243
|
-
for direction, label in (("first", "first_after_sort"), ("last", "last_after_sort")):
|
|
9244
|
-
move_result = await _bridge_call_recorded(session_id, "table_move_row", {
|
|
9325
|
+
try:
|
|
9326
|
+
await _bridge_call_recorded(session_id, "open_navigation_link", {"navigation_link": navigation_link})
|
|
9327
|
+
cleanup_enabled = True
|
|
9328
|
+
|
|
9329
|
+
sort_result = await _bridge_call_recorded(session_id, "dynamic_list_sort_by_column", {
|
|
9245
9330
|
"name": "Список",
|
|
9246
9331
|
"title": "",
|
|
9247
|
-
"
|
|
9248
|
-
"steps": 1,
|
|
9249
|
-
})
|
|
9250
|
-
row_result = await _bridge_call_recorded(session_id, "table_current_row", {"name": "Список", "title": ""})
|
|
9251
|
-
current_row = _table_row_pairs(row_result)
|
|
9252
|
-
main = _configuration_from_sorted_first_row(current_row)
|
|
9253
|
-
sort_attempts.append({
|
|
9254
|
-
"attempt": len(sort_attempts) + 1,
|
|
9255
|
-
"ordered": ordered,
|
|
9256
|
-
"move_direction": direction,
|
|
9257
|
-
"move_result": move_result if isinstance(move_result, dict) else {},
|
|
9258
|
-
"read_method": label,
|
|
9259
|
-
"row_is_main": bool(main),
|
|
9260
|
-
"row_main_marker": _row_value(current_row, "Это основная конфигурация", "ЭтоОсновнаяКонфигурация"),
|
|
9332
|
+
"column_title": "Это основная конфигурация",
|
|
9261
9333
|
})
|
|
9262
|
-
if
|
|
9263
|
-
|
|
9334
|
+
ordered = bool(sort_result.get("ordered")) if isinstance(sort_result, dict) else False
|
|
9335
|
+
for direction, label in (("first", "first_after_sort"), ("last", "last_after_sort")):
|
|
9336
|
+
move_result = await _bridge_call_recorded(session_id, "table_move_row", {
|
|
9337
|
+
"name": "Список",
|
|
9338
|
+
"title": "",
|
|
9339
|
+
"direction": direction,
|
|
9340
|
+
"steps": 1,
|
|
9341
|
+
})
|
|
9342
|
+
row_result = await _bridge_call_recorded(session_id, "table_current_row", {"name": "Список", "title": ""})
|
|
9343
|
+
current_row = _table_row_pairs(row_result)
|
|
9344
|
+
main = _configuration_from_sorted_first_row(current_row)
|
|
9345
|
+
sort_attempts.append({
|
|
9346
|
+
"attempt": len(sort_attempts) + 1,
|
|
9347
|
+
"ordered": ordered,
|
|
9348
|
+
"move_direction": direction,
|
|
9349
|
+
"move_result": move_result if isinstance(move_result, dict) else {},
|
|
9350
|
+
"read_method": label,
|
|
9351
|
+
"row_is_main": bool(main),
|
|
9352
|
+
"row_main_marker": _row_value(current_row, "Это основная конфигурация", "ЭтоОсновнаяКонфигурация"),
|
|
9353
|
+
})
|
|
9354
|
+
if main:
|
|
9355
|
+
break
|
|
9264
9356
|
|
|
9265
|
-
|
|
9266
|
-
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
|
|
9272
|
-
|
|
9273
|
-
|
|
9274
|
-
|
|
9275
|
-
|
|
9276
|
-
|
|
9277
|
-
|
|
9278
|
-
|
|
9357
|
+
if not main:
|
|
9358
|
+
warnings.append("Sorted edge list rows did not expose the main configuration; falling back to MXL list output")
|
|
9359
|
+
source_method = "list_output_mxl"
|
|
9360
|
+
output_result = await _bridge_call_recorded(session_id, "dynamic_list_output", {
|
|
9361
|
+
"button": "",
|
|
9362
|
+
"wait_seconds": 3,
|
|
9363
|
+
"include_text": False,
|
|
9364
|
+
})
|
|
9365
|
+
tabular_docs = output_result.get("tabular_documents", {}) if isinstance(output_result, dict) else {}
|
|
9366
|
+
items = tabular_docs.get("items", []) if isinstance(tabular_docs, dict) else []
|
|
9367
|
+
if items:
|
|
9368
|
+
first_item = items[0]
|
|
9369
|
+
doc_name = first_item.get("name", "") if isinstance(first_item, dict) else ""
|
|
9370
|
+
cells = await _save_output_tabular_document_to_mxl(
|
|
9371
|
+
session_id,
|
|
9372
|
+
doc_name,
|
|
9373
|
+
"configuration_name_version_from_subsystems",
|
|
9374
|
+
warnings,
|
|
9375
|
+
)
|
|
9376
|
+
main = _find_main_configuration_in_tabular_cells(cells)
|
|
9377
|
+
finally:
|
|
9378
|
+
current_task = asyncio.current_task()
|
|
9379
|
+
is_cancelling = bool(current_task and current_task.cancelling())
|
|
9380
|
+
if cleanup_enabled and not is_cancelling:
|
|
9381
|
+
await _close_self_opened_form(
|
|
9279
9382
|
session_id,
|
|
9280
|
-
doc_name,
|
|
9281
|
-
"configuration_name_version_from_subsystems",
|
|
9282
9383
|
warnings,
|
|
9384
|
+
title_markers=("Версии подсистем",),
|
|
9385
|
+
form_names=("РегистрСведений.ВерсииПодсистем.ФормаСписка",),
|
|
9386
|
+
description="subsystem versions list",
|
|
9283
9387
|
)
|
|
9284
|
-
main = _find_main_configuration_in_tabular_cells(cells)
|
|
9285
9388
|
|
|
9286
9389
|
return {
|
|
9287
9390
|
"found": bool(main),
|
|
@@ -9376,15 +9479,35 @@ async def installed_extensions_from_catalog(
|
|
|
9376
9479
|
returned as extensions.
|
|
9377
9480
|
"""
|
|
9378
9481
|
navigation_link = "e1cib/list/Справочник.ВерсииРасширений"
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9482
|
+
warnings: list[str] = []
|
|
9483
|
+
cleanup_enabled = False
|
|
9484
|
+
parsed_rows: list[dict[str, str]] = []
|
|
9485
|
+
actual_rows: list[dict[str, str]] = []
|
|
9486
|
+
selected_row: dict[str, str] = {}
|
|
9487
|
+
extensions: list[dict[str, str]] = []
|
|
9382
9488
|
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
|
|
9387
|
-
|
|
9489
|
+
try:
|
|
9490
|
+
await _bridge_call_recorded(session_id, "open_navigation_link", {"navigation_link": navigation_link})
|
|
9491
|
+
cleanup_enabled = True
|
|
9492
|
+
rows_result = await _bridge_call_recorded(session_id, "table_rows", {"name": "Список", "title": "", "limit": 500})
|
|
9493
|
+
rows = rows_result.get("rows", []) if isinstance(rows_result, dict) else []
|
|
9494
|
+
|
|
9495
|
+
parsed_rows = [_table_row_pairs(row) for row in rows]
|
|
9496
|
+
actual_rows = [row for row in parsed_rows if _is_not_deleted_catalog_row(row)]
|
|
9497
|
+
selected_row = max(actual_rows, key=_extension_catalog_row_sort_key) if actual_rows else {}
|
|
9498
|
+
description = _row_value(selected_row, "Описание метаданных", "ОписаниеМетаданных")
|
|
9499
|
+
extensions = _parse_extension_metadata_description(description)
|
|
9500
|
+
finally:
|
|
9501
|
+
current_task = asyncio.current_task()
|
|
9502
|
+
is_cancelling = bool(current_task and current_task.cancelling())
|
|
9503
|
+
if cleanup_enabled and not is_cancelling:
|
|
9504
|
+
await _close_self_opened_form(
|
|
9505
|
+
session_id,
|
|
9506
|
+
warnings,
|
|
9507
|
+
title_markers=("Версии расширений",),
|
|
9508
|
+
form_names=("Справочник.ВерсииРасширений.ФормаСписка",),
|
|
9509
|
+
description="extension versions list",
|
|
9510
|
+
)
|
|
9388
9511
|
|
|
9389
9512
|
return {
|
|
9390
9513
|
"found": bool(selected_row),
|
|
@@ -9397,6 +9520,7 @@ async def installed_extensions_from_catalog(
|
|
|
9397
9520
|
"non_deleted_rows_count": len(actual_rows),
|
|
9398
9521
|
"navigation_link": navigation_link,
|
|
9399
9522
|
"source": "Справочник.ВерсииРасширений",
|
|
9523
|
+
"warnings": warnings,
|
|
9400
9524
|
}
|
|
9401
9525
|
|
|
9402
9526
|
|
|
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
|
{answer42-0.4.89 → answer42-0.4.91}/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
|
{answer42-0.4.89 → answer42-0.4.91}/src/mcp_1c/assets/skills/answer42-universal-report/SKILL.md
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
|