Metadata-Version: 2.4
Name: answer42
Version: 0.2.0
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
Author: Marvin (AI Assistant), 42Clouds, and contributors
Author-email: "Kosolapov Stanislav (proDOOMman)" <prodoomman@gmail.com>
License: MIT
License-File: LICENSE
Keywords: 1c,1c-enterprise,mcp,test-client,ui-automation
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.11
Requires-Dist: mcp>=1.9.0
Requires-Dist: pydantic>=2.0
Requires-Dist: websockets>=12.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Provides-Extra: linux-window-control
Requires-Dist: python-xlib>=0.33; extra == 'linux-window-control'
Provides-Extra: screenshot
Requires-Dist: mss>=9.0.0; extra == 'screenshot'
Provides-Extra: window-control
Requires-Dist: python-xlib>=0.33; extra == 'window-control'
Provides-Extra: windows-window-control
Requires-Dist: pywin32>=306; extra == 'windows-window-control'
Description-Content-Type: text/markdown

# Answer42

<p align="center">
  <img src="docs/assets/answer42-logo.png" alt="Answer42 logo" width="220">
</p>

**Answer42** — MCP-инструмент для интерактивного управления UI **1С:Предприятия** через клиент тестирования. Он позволяет AI-агенту открывать формы 1С, нажимать кнопки, заполнять поля, выбирать ссылки из форм выбора, работать с таблицами, динамическими списками и табличными документами.

> **The Answer to Life, Universe, and 1C — UI Driver**

Проект даёт AI-агенту три способности:

1. **Интерактивное управление UI 1С** — открыть форму, кликнуть кнопку, активировать поле, заполнить значение, выбрать строку, провести сценарий через `/TESTMANAGER` + `/TESTCLIENT`.
2. **Доказательная запись клиентского тестирования** — записывать аннотированные PDF-слайды с MCP method/request/response и скриншотами окна 1С.
3. **RAG-индекс метаданных** — локальный SQLite/FTS индекс конфигураций 1С (EDT, XML-выгрузка Конфигуратора, base + extensions), включая подсказки для `ui_tree` и dynamic-list settings.

## Быстрый старт

```bash
# Рекомендуется для обычной установки из PyPI
pipx install 'answer42[screenshot,linux-window-control]'

# Альтернатива без pipx
python3 -m venv .venv
. .venv/bin/activate
pip install 'answer42[screenshot,linux-window-control]'

# Разработка из git checkout
pip install -e '.[screenshot,dev,linux-window-control]'

# Windows: запускать из интерактивной пользовательской сессии, не как service
# pipx install "answer42[screenshot,windows-window-control]"
# pip install "answer42[screenshot,windows-window-control]"

# Запуск MCP-сервера (transport: stdio)
answer42 --ws-host 127.0.0.1 --ws-port 8765
```

Запуск сессии и подключение тестируемой базы выполняются одним MCP-вызовом:

```text
start_session(
  session_id="my-session",
  base_url="<TARGET_INFOBASE_URL>",
  idle_timeout_minutes=60,
  execute="/path/to/external.epf",  # опционально: /Execute
  command_parameter="InitScenario" # опционально: /C
)
```

`start_session` определяет версию 1С по `base_url`, поднимает инфраструктуру Answer42 (на Linux — Xvfb, если нужен headless; на Windows — интерактивная desktop-сессия), свободные порты, WebSocket bridge, файловую базу менеджера и test-manager. Если доступны серверные компоненты 1С (`ibsrv`), менеджер и встроенная тестовая база публикуются через автономный сервер; если доступен только тонкий клиент и `ibcmd`, Answer42 автоматически использует fallback `file-direct` (`/F`) для файловых баз менеджера и клиента. После `idle_timeout_minutes` минут неактивности сессия автоматически завершается; значение по умолчанию — 60 минут. Для запуска клиента можно передать `extra_args`, `execute` (параметр командной строки `/Execute`) и `command_parameter` (параметр `/C`); если `/C` уже указан в `extra_args`, значения склеиваются через `;`.

Логин/пароль рекомендуется **не передавать явно**: `start_session` умеет брать их из локального credentials-файла по `base_url`. Параметры `username`/`password` остаются в API для разовых сценариев и обратной совместимости, но при передаче в MCP-вызове они видны вызывающему агенту в аргументах tool-call.

## Безопасное хранение логинов и паролей

Чтобы креды были доступны MCP-серверу, но не попадали в чат и аргументы tool-call, храните их в локальном файле за пределами репозитория и передайте путь в окружение процесса Answer42:

```bash
export ONEC_MCP_CREDENTIALS_FILE=/secure/path/credentials.json
```

Если переменная окружения не задана, MCP-сервер читает файл по умолчанию:

```text
~/.onec-mcp-credentials.json
```

Формат файла:

```json
{
  "entries": [
    {
      "url": "https://example.invalid/infobase",
      "username": "<USERNAME>",
      "password": "<PASSWORD>"
    },
    {
      "url": "https://*.example.invalid/*",
      "username": "<WILDCARD_USERNAME>",
      "password": "<WILDCARD_PASSWORD>"
    }
  ]
}
```

Рекомендуемые права на файл: `0600`.

Правила матчинга: сначала точное совпадение `url`, затем wildcard (`*`, `?`) через `fnmatch`; первое совпадение побеждает. Пароли не логируются и не возвращаются наружу.

Для сохранения или обновления записи можно использовать MCP-tool:

```text
credentials_save(
  url="<TARGET_INFOBASE_URL>",
  username="<USERNAME>",
  password="<PASSWORD>"
)
```

Для удаления записи:

```text
credentials_remove(url="<TARGET_INFOBASE_URL>")
```

Для проверки, что для адреса есть сохранённые креды, используйте MCP-tool:

```text
credentials_check(base_url="<TARGET_INFOBASE_URL>")
```

Ответы этих tools содержат только факт наличия/изменения/удаления записи и URL; логины и пароли не возвращаются. Tool `credentials_list()` оставлен в коде для локальной диагностики, но в OpenClaw-конфигурации его рекомендуется скрывать через `toolFilter.exclude`, чтобы агент не мог получить список URL-шаблонов.

Остановка сессии:

```text
stop_session(session_id="my-session", clean_data=False)
```

## Требования

- Python 3.11+
- 1С:Предприятие 8.3.27+
- Пакеты Python: `mcp`, `websockets`, `pydantic`; для скриншотов — `mss`
- Linux/X11: `python-xlib`/`wmctrl`/`xdotool`, GUI/Xvfb для headless-сервера
- Windows: интерактивная пользовательская desktop-сессия; window-control и screenshots работают через WinAPI/`mss`

## Безопасность стендов и учётных данных

В репозитории не должно быть реальных URL стендов, логинов или паролей. Для штатного запуска передавайте только `base_url`, а логин/пароль храните в локальном credentials-файле, доступном процессу Answer42 через `ONEC_MCP_CREDENTIALS_FILE`.

`start_session` всё ещё принимает `username` и `password` напрямую для разовых сценариев и обратной совместимости. Используйте это только когда осознанно готовы раскрыть значения вызывающему агенту: параметры MCP-вызова могут попасть в историю чата, логи клиента или отладочный вывод. Если вместо реального пароля передан редактированный плейсхолдер из звёздочек (`***`, `********` и т.п.), Answer42 остановит запуск с явной ошибкой: нужно указать настоящий пароль или сохранить корректные креды через `credentials_save()`.

Примеры в документации используют только плейсхолдеры (`<TARGET_INFOBASE_URL>`, `<USERNAME>`, `<PASSWORD>`). Перед публикацией артефактов проверяйте, что параметры вызовов заредактированы: recorder маскирует ключи вроде `password`, но URL и логин тоже не должны попадать в публичные материалы.

## Архитектура

Поток выполнения:

1. MCP-клиент вызывает tools через stdio MCP.
2. Answer42 принимает MCP-вызовы и передаёт команды в WebSocket bridge.
3. 1С test manager подключается к bridge и выполняет BSL-dispatch.
4. Test manager управляет 1С test client через API `ТестируемоеПриложение`.
5. Test client выполняет интерактивные операции в целевой информационной базе.

Подробнее: [`docs/architecture.md`](docs/architecture.md).

## Сборка конфигураций 1С

Конфигурация менеджера тестирования собирается из XML-исходников `src/cf/` через `ibcmd config import` (приоритетный способ) или через Конфигуратор/DESIGNER (fallback, если `ibcmd` отсутствует):

```bash
python scripts/build_cf.py src/cf build/MCPTestManager.cf
```

PowerShell:

```powershell
python scripts/build_cf.py src/cf build/MCPTestManager.cf
```

Тестовая конфигурация для E2E собирается из XML-исходников `src/client_cf/`:

```bash
python scripts/build_cf.py src/client_cf build/MCPTestClient.cf
```

PowerShell:

```powershell
python scripts/build_cf.py src/client_cf build/MCPTestClient.cf
```

`start_session` автоматически собирает `build/MCPTestManager.cf`, если файл отсутствует или XML-исходники `src/cf/` новее. Встроенный demo-клиент аналогично собирает `build/MCPTestClient.cf` из `src/client_cf/`. E2E-сценарий также пересобирает `build/MCPTestClient.cf`, чтобы тесты не использовали устаревший артефакт.

E2E можно запускать целиком или по независимым сценариям:

```bash
python3 scripts/e2e_stable.py                         # full
E2E_SCENARIO=smoke python3 scripts/e2e_stable.py       # быстрый smoke
E2E_SCENARIO=dynamic python3 scripts/e2e_stable.py     # legacy: таблицы/dynamic-list/отчёт
E2E_SCENARIO=dynamic-tables python3 scripts/e2e_stable.py
E2E_SCENARIO=dynamic-lists python3 scripts/e2e_stable.py
E2E_SCENARIO=dynamic-reports python3 scripts/e2e_stable.py
E2E_SCENARIO=coverage python3 scripts/e2e_stable.py    # diagnostic/negative tools
```

Для реального распараллеливания сценарий умеет сам запустить пять разные сессий (`smoke`, `dynamic-tables`, `dynamic-lists`, `dynamic-reports`, `coverage`), а не копии одного и того же теста. Встроенная тестовая файловая база публикуется через один общий `ibsrv`, когда серверные компоненты доступны; без `ibsrv` demo-клиент запускается через `file-direct` (`/F`):

```bash
E2E_PARALLEL=1 E2E_SESSION_ID=e2e-split python3 scripts/e2e_stable.py
```

`start_session` также переиспользует общий автономный сервер для одинаковой файловой базы. Последний `stop_session` освобождает refcount и завершает shared `ibsrv`.

## MCP-инструменты

### Жизненный цикл

- `start_session(...)` — единый запуск: определение версии по `base_url`, Xvfb на Linux при необходимости, свободные порты, bridge, файловая база менеджера, `ibsrv` или fallback `file-direct`, test-manager и подключение клиента тестирования. Если `username`/`password` не переданы, берёт их из credentials-файла по `base_url`. Поддерживает `extra_args`, `execute` → `/Execute`, `command_parameter` → `/C`; несколько частей `/C` объединяются через `;`.
- `session_status(session_id)` — состояние bridge, runtime, клиента тестирования и RAG snapshot.
- `stop_session(session_id, clean_data)` — отключение клиента тестирования и остановка всех процессов, Xvfb и bridge.

### Автоматизация UI

- `active_window()` — активное окно тестируемого приложения через `ТестируемоеПриложение.ПолучитьАктивноеОкно()`.
- `windows_list(max_depth)` — список окон тестируемого приложения; если открыто два окна клиента, возвращает оба, потому что читает подчинённые объекты `ТестируемоеПриложение`, а не окна менеджера тестирования.
- `activate_window(index, title, name)` — переключить активное окно по индексу, заголовку или имени.
- `goto_start_page()`, `goto_previous_window()`, `goto_next_window()` — навигация основного окна: `ПерейтиКНачальнойСтранице`, `ПерейтиКПредыдущемуОкну`, `ПерейтиКСледующемуОкну`.
- `ui_tree(max_depth, include_rag_types, include_hidden, rag_snapshot)` — дерево UI с `visible`, `available`, `enabled`, `read_only`; скрытые элементы и неактивные страницы page-group по умолчанию опускаются, `include_hidden=true` возвращает полное дерево. RAG-типы добавляются, когда доступен индекс метаданных.
- `command_bar()` — диагностическая информация по командной панели, когда она доступна API тест-клиента.
- `current_element()` — диагностическая информация по текущему элементу, когда она доступна API тест-клиента.
- `find_object(name, title, type)` — найти объект в дереве UI.
- `activate_object(name, title, type)` — активировать объект.
- `open_navigation_link(navigation_link)` — открыть навигационную ссылку `e1cib/...`.
- `click_button(name, search_by_title)` — нажать кнопку.
- `set_field_value(field_name, value, search_by_title)` — установить значение поля.
- `create_new_item()` — создать новый элемент.
- `save_form()` — сохранить форму.
- `close_form()` — закрыть форму.
- `screenshot(path)` — скриншот экрана.

### Таблицы и табличные части

- `table_rows(...)` — строки таблицы.
- `table_find_row(...)` — найти строку по подстроке.
- `table_goto_row(...)` — перейти к строке.
- `table_current_row(...)` — текущая строка.
- `table_selected_rows(...)` — выделенные строки.
- `table_set_field(...)` — установить значение в ячейке.
- `table_choose_field_from_list(...)` — открыть форму выбора для ссылочного поля в строке табличной части.
- `table_edit_info(...)` — информация о редактировании таблицы.
- `table_move_row(...)` — перейти к первой/следующей/предыдущей/последней строке.

### Динамические списки

- `dynamic_list_available_fields(object, rag_snapshot)` — поля, доступные для отбора/сортировки по RAG-индексу.
- `dynamic_list_apply_settings(filters, orders, clear_first)` — применить сортировки через API тест-клиента и best-effort отборы через стандартную форму **Настроить список**.
- `dynamic_list_set_order(column_title, name="Список")` — сортировка по видимому заголовку колонки.
- `dynamic_list_output()` — команда **Вывести список** с возвратом текста табличного документа, когда он доступен.
- `dynamic_list_open_settings()` — открыть **Настроить список**.
- `dynamic_list_clear_settings()` — сбросить настройки динамического списка.
- `dynamic_list_open_form_settings()` — открыть **Изменить форму**.

### Табличные документы

- `tabular_documents(include_text)` — список табличных документов в активном окне.
- `tabular_document_text(...)` — текст табличного документа.
- `tabular_document_save(path, format)` — сохранить табличный документ в выбранном формате.


### Доказательная запись

- `recording_start(output_dir, display, window)` — включить доказательную запись.
- `recording_capture(action, note)` — вручную добавить доказательный слайд.
- `recording_stop()` — собрать `manifest.json`, `recording.pdf` (если доступен backend PDF).

### RAG / индекс метаданных

- `rag_source_add(name, path, kind, format="auto")` — зарегистрировать источник; формат определяется автоматически при `format="auto"`.
- `rag_sources_list()` — список источников.
- `rag_snapshot_create(name, base, extensions, sources)` — создать effective snapshot.
- `rag_snapshots_list()` — список snapshot-ов.
- `rag_index_build(snapshot, source)` — построить индекс.
- `rag_lookup_object(object, snapshot)` — найти объект метаданных.
- `rag_query(query, snapshot, limit)` — полнотекстовый поиск.

CLI-пример:

```bash
python3 scripts/rag_cli.py add-source Configuration /path/to/configuration/src --kind base
python3 scripts/rag_cli.py add-source Extension1 /path/to/extension/src --kind extension
python3 scripts/rag_cli.py snapshot Configuration+Extension1 --base Configuration --extension Extension1
python3 scripts/rag_cli.py build --snapshot Configuration+Extension1
python3 scripts/rag_cli.py lookup РегистрСведений.Регистр1 --snapshot Configuration+Extension1
```

## Ограничения

- Форма пользовательской настройки **«Изменить форму»** частично недоступна для надёжной автоматизации через API клиента тестирования. В частности, команда **«Добавить поля»** в верхней панели формы настройки может быть видна на скриншоте и в диагностическом тексте, но не нажиматься как обычная `ТестируемаяКнопкаФормы`: `click_button` может не находить её, а `activate_object` может вернуть `activated=true` без открытия диалога добавления полей.

## Лицензия

MIT

## Copyright

Copyright (c) 2026 Kosolapov Stanislav aka proDOOMman <prodoomman@gmail.com>, Marvin (AI Assistant), 42Clouds, and contributors.

Licensed under the MIT License.

## Публикация пакета

Рекомендуемый канал установки для пользователей — PyPI:

```bash
pipx install 'answer42[screenshot,linux-window-control]'
# Windows:
# pipx install "answer42[screenshot,windows-window-control]"
```

Публикация автоматизирована в `.gitlab-ci.yml` и оставлена только для PyPI:

1. tag `vX.Y.Z` запускает unit/ruff/package checks;
2. `package` собирает wheel/sdist и проверяет их через `twine check`;
3. `publish_pypi` публикует wheel/sdist в PyPI через `PYPI_API_TOKEN`;
4. `create_gitlab_release` создаёт GitLab Release для tag.


One-command релиз:

```bash
answer42 release 0.2.1
```

Команда меняет `pyproject.toml`, создаёт commit `Release v0.2.1`, annotated tag `v0.2.1`, пушит branch и tag. Tag запускает CI: публикацию в PyPI и создание GitLab Release.

Секрет GitLab CI:

- `PYPI_API_TOKEN` — PyPI token для проекта `answer42`.

Перед релизом проверьте, что `src/mcp_1c/assets/MCPTestManager.cf` и `src/mcp_1c/assets/MCPTestClient.cf` пересобраны из актуальных XML-исходников. Runtime использует XML+`scripts/build_cf.py` в git checkout, а в установленном PyPI wheel при отсутствии исходников копирует packaged `.cf` из `mcp_1c.assets`.

### Установка packaged skills

PyPI сам по себе не устанавливает agent skills в пользовательские каталоги, поэтому в CLI добавлена команда:

```bash
answer42 install-skills
```

По умолчанию она устанавливает `answer42` и `answer42-rag` в OpenClaw:

```text
~/.openclaw/workspace/skills
```

Другие агенты/варианты:

```bash
answer42 install-skills --agent claude
answer42 install-skills --agent codex
answer42 install-skills --agent opencode
answer42 install-skills --agent pi
answer42 install-skills --agent hermes
answer42 install-skills --agent all
answer42 install-skills --target-dir /path/to/skills
answer42 install-skills --list-agents
answer42 install-skills --dry-run --agent all
```

Для агентов без стабильного стандарта skill-директорий (`codex`, `opencode`, `pi`, `hermes`) presets best-effort; если у конкретной установки другой путь, используйте `--target-dir`.
