О проекте
Команда: Larpsec
Кейс HackAlem.ai: Спецтрек — Казахтелеком
Стадия: Доведённый продукт
Задача кейса: Агент, сравнивающий документы оргструктуры до и после реорганизации
Суть
Веб-приложение, которое сравнивает комплекты оргдокументов до и после реорганизации. Сопоставляет подразделения и функции, находит потерю, дублирование и передачу функций, а также смену подчинения, и подкрепляет каждый вывод цитатой с переходом к источнику.
Как устроено
Загружаются DOCX/PDF/XLSX/TXT, текст извлекается с адресацией (пункт, абзац, страница, ячейка) через python-docx, pypdf и openpyxl. В фоновом задании (ThreadPoolExecutor) извлекаются владельцы и функции и сопоставляются версии. В режиме demo это делают правила по нормализованным формулировкам, в режиме llm модель через Responses API со strict JSON Schema. Сервер проверяет идентификаторы и дословность цитат и собирает статусы. В браузере есть пословный дифф и поиск повторов, сотрудник подтверждает или отклоняет замечания. Экспорт в Markdown/JSON.
Ключевые решения
- OpenAI Responses API strict JSON Schema
- проверка дословных цитат
- правиловое сопоставление функций
- пословный text diff
- поиск повторов
Особенности
Проверка доказательств: каждый вывод LLM должен опираться на дословную цитату из нужной версии документа, иначе отклоняется. При ошибке модели демо-результат не подставляется. Явно учитывается полнота комплектов и покрытие анализа. Есть человеческая верификация замечаний и история сравнений.
Стек
Python · FastAPI · Uvicorn · Pydantic · SQLite · React 19 · TypeScript · Vite · Mammoth · python-docx · pypdf · openpyxl · Docker Compose · uv · pnpm · Playwright · Vitest
Модели
OpenAI Responses API (модель задаётся через LLM_MODEL)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-85aebd11-larpsec.
README
README.mdLarpsec — анализ изменений организационной структуры и функций
Larpsec — веб-приложение для HackAlem, которое сравнивает комплекты организационных документов до и после изменений: положения о подразделениях, должностные инструкции и перечни функций. Результат — сопоставление подразделений и полномочий, замечания и цитаты, по которым сотрудник может проверить каждый вывод.
При реорганизации обязанность может исчезнуть из документов, перейти другому подразделению или оказаться одновременно у нескольких владельцев. Larpsec помогает сотрудникам внутреннего аудита, организационного развития и кадровых служб проверять такие изменения. Приложение анализирует описанное в документах распределение функций; фактическое исполнение обязанностей оно не проверяет.
В текущем прототипе есть два режима: demo — анализ по правилам без ИИ и
llm — извлечение и сопоставление с помощью модели через Responses API.
Учебный сценарий можно воспроизвести без ключа модели.
1. Что реализовано
| Возможность | Что получает пользователь |
|---|---|
| Комплекты «до» и «после» | Загрузка нескольких DOCX, PDF, XLSX или TXT в одно сравнение |
| Извлечение текста | Текст с адресами источников: пунктами, абзацами, страницами, листами и ячейками — в зависимости от формата |
| Текстовое сравнение | Две колонки, подсветка изменений по словам, отдельные счётчики добавленных, удалённых и изменённых строк |
| Анализ структуры | Подразделения, должности, группы и их сопоставления между версиями, включая переименования |
| Анализ функций | Обязанности, права, запреты и область действия; сохранённые, переданные, изменённые, добавленные и несопоставленные функции |
| Замечания | Возможная потеря функции, дублирование, противоречие, изменение подчинения и недостаточное покрытие анализа |
| Проверка источников | Цитаты с переходом к исходному фрагменту и подсветкой соответствующего текста |
| Проверка сотрудником | Подтверждение или отклонение замечания, сохранение комментария; фильтры по типу и статусу проверки |
| Повторы текста | Поиск повторяющихся формулировок внутри документов, выбор версии и переход к источникам |
| История | Открытие предыдущих сравнений и удаление сравнения вместе с его файлами, результатами и оценками |
| Темы интерфейса | Переключение светлой и тёмной темы с сохранением выбора в браузере |
| Экспорт | Русскоязычный Markdown-отчёт и JSON с метаданными документов, исходными фрагментами и адресами цитат |
Полнота комплектов задаётся пользователем отдельно для каждой стороны. Ограничения извлечения показываются предупреждениями и влияют на покрытие анализа. Если структура не распознана, результат сообщает об этом; извлечённый текст остаётся доступен для сравнения. Повтор формулировки сам по себе не считается доказательством дублирования полномочий.
2. Как работает решение
- Создайте сравнение. Загрузите документы в комплекты «до изменений» и «после изменений».
- Проверьте извлечённый текст. Сервер проверит формат файлов, сохранит оригиналы, извлечёт текст и покажет предупреждения. Текстовое сравнение доступно до запуска анализа функций.
- Укажите полноту комплектов. Отмечайте комплект полным, только если загрузили все необходимые документы.
- Запустите сравнение. Сервер в фоне извлечёт владельцев и функции, сопоставит версии и проверит ссылки на исходные фрагменты. Браузер опрашивает состояние задания.
- Изучите результат. Просмотрите изменения подразделений и функций, замечания, смену подчинения и подтверждающие цитаты.
- Зафиксируйте решение. Подтвердите или отклоните замечания, добавьте комментарии, скачайте отчёт. Результаты сохраняются на сервере и доступны в истории.
Где используется ИИ
| Режим | Как выполняется анализ | Что требуется |
|---|---|---|
demo | Правила распознают обозначения владельцев, заголовки, списки функций, прежние названия, виды полномочий и подчинение. Сопоставляются нормализованные формулировки | Только локальное приложение; обращения к модели отсутствуют |
llm | Модель извлекает структуру из порций текста, затем сопоставляет извлечённые элементы двух комплектов и предлагает замечания | Ключ, доступная модель и endpoint с поддержкой Responses API и strict JSON Schema |
В режиме llm сервер проверяет структуру ответа, идентификаторы, принадлежность
элементов нужной версии и наличие дословных цитат. Итоговые статусы и числовая сводка
формируются сервером. Проверка цитаты подтверждает её наличие в документе, но не гарантирует
правильность смыслового вывода — для этого предусмотрена проверка сотрудником.
Текстовый дифф выполняется алгоритмом в браузере. Чтение файлов, хранение, проверка доказательств и экспорт также реализованы кодом приложения. Ошибка модели не подменяется демонстрационным результатом.
3. Технологии
| Компонент | Технологии |
|---|---|
| Интерфейс | TypeScript 5.9, React 19, Vite 7, CSS, Lucide React; Mammoth для локального просмотра DOCX |
| Сервер | Python 3.12–3.14, FastAPI, Uvicorn, Pydantic и pydantic-settings |
| Чтение документов | python-docx, pypdf, openpyxl; обработка TXT на Python |
| Хранение | SQLite и локальная файловая система |
| AI-интеграция | HTTP-клиент httpx, OpenAI Responses API, структурированные ответы по JSON Schema |
| Фоновые задания | ThreadPoolExecutor в процессе сервера |
| Проверки | pytest, Ruff, Vitest, Playwright; ReportLab для тестовых PDF |
| Установка и сборка | uv, pnpm 10.30.3, Docker Compose |
Конкретная AI-модель не зафиксирована в исходном коде: её идентификатор задаётся
через LLM_MODEL. По умолчанию endpoint — https://api.openai.com/v1, а режим — demo.
Зависимости зафиксированы в backend/uv.lock
и frontend/pnpm-lock.yaml.
4. Архитектура проекта
flowchart TD
UI["Браузер: React + TypeScript"] --> API["FastAPI: /api/v1"]
API --> Parse["Чтение DOCX / PDF / XLSX / TXT"]
Parse --> DB[("SQLite + оригиналы файлов")]
API --> Jobs["Очередь фоновых заданий"]
Jobs --> Analysis["Извлечение и сопоставление"]
Analysis --> Demo["demo: правила"]
Analysis --> LLM["llm: Responses API"]
Demo --> Validate["Проверка источников и сборка результата"]
LLM --> Validate
Validate --> DB
DB --> API
API --> UI
API --> Export["Markdown / JSON"]
После сборки FastAPI раздаёт frontend/dist, поэтому сайт и API работают на одном
адресе. В режиме разработки Vite запускается отдельно и проксирует запросы к серверу.
Текстовый дифф и поиск повторов используют извлечённый текст на стороне клиента.
.
├── run.sh # Сборка интерфейса и запуск приложения
├── compose.yaml # Запуск в Docker с постоянным томом данных
├── backend/
│ ├── app/
│ │ ├── main.py # HTTP API, доступ и раздача интерфейса
│ │ ├── parsing.py # Чтение файлов и адресация фрагментов
│ │ ├── analysis.py # Оркестрация анализа и вычисление результатов
│ │ ├── demo.py / llm.py # Два режима анализа
│ │ ├── evidence.py # Проверка цитат и ссылок
│ │ ├── jobs.py / store.py # Фоновые задания и хранение
│ │ └── report.py # Экспорт отчётов
│ ├── scripts/ # Генерация примеров, API-демо, экспорт OpenAPI
│ └── tests/ # Серверные и регрессионные тесты
├── frontend/
│ ├── src/ # Страницы, API-клиент и текстовое сравнение
│ ├── public/examples/ # Учебная пара DOCX для интерфейса
│ └── tests/ # Модульные и браузерные тесты
├── examples/scenario.json # Синтетические данные и ожидаемые изменения
└── docs/ # Архитектура, API, схема и результаты проверок
Подробнее: архитектура, контракт API, OpenAPI, пример результата.
5. Установка и запуск
Вариант A: локальный запуск
Необходимы Git, Node.js 22.12+ с npm/npx, Python 3.12–3.14 и uv. Команды рассчитаны на Linux/macOS; на Windows используйте WSL или Docker. Для приватного репозитория нужен доступ на GitHub.
1. Получите проект либо перейдите в уже существующую копию:
git clone [email protected]:BAITC-Hacks/hack-85aebd11-larpsec.git
cd hack-85aebd11-larpsec
2. Запустите воспроизводимый режим без модели:
ANALYSIS_MODE=demo ./run.sh
Скрипт устанавливает зависимости по lock-файлам, собирает интерфейс и запускает сервер.
Глобальная установка pnpm не нужна: используется версия из package.json через npx.
Первый запуск требует доступа к реестрам зависимостей. Локальный .env скрипт не перезаписывает.
3. Откройте приложение:
- Сайт: http://127.0.0.1:8000.
- Состояние сервера: http://127.0.0.1:8000/health.
- Swagger UI: http://127.0.0.1:8000/docs, если не включена защита токеном.
Для запуска с настройками из backend/.env используйте ./run.sh без переопределения
ANALYSIS_MODE. Другой порт: PORT=8001 ./run.sh. Остановка — Ctrl+C;
база и загруженные документы сохраняются между запусками.
Настройка AI-анализа
Если backend/.env ещё нет, создайте его из шаблона:
cp -n backend/.env.example backend/.env
Заполните значения в локальном файле:
ANALYSIS_MODE=llm
LLM_API_KEY=YOUR_API_KEY
LLM_MODEL=YOUR_MODEL_ID
LLM_BASE_URL=https://api.openai.com/v1
Замените YOUR_API_KEY и YOUR_MODEL_ID своими значениями и перезапустите приложение
командой ./run.sh. Модель должна поддерживать Responses API и strict JSON Schema.
Сервис, поддерживающий только Chat Completions, не подходит для существующего адаптера.
LLM_API_KEY хранится только на сервере; .env исключён из Git. Переменные VITE_*
попадают в браузерную сборку, поэтому секреты в них размещать нельзя.
В режиме llm текст документов передаётся провайдеру, а запросы оплачиваются по его тарифам.
Дополнительные настройки находятся в backend/.env.example и backend/app/config.py: лимиты, таймауты, каталог данных, число фоновых заданий и общий токен приложения.
Вариант B: Docker Compose
Из корня репозитория:
docker compose up --build
Нужен Docker Compose с поддержкой необязательного env_file (required: false).
Node.js, Python и uv на хосте не требуются: сборка выполняется внутри контейнера.
Сайт доступен на http://127.0.0.1:8000; настройки читаются из backend/.env, если файл
существует. Без него используется demo. Данные сохраняются в томе analysis_data.
Порт опубликован только на localhost. Docker-сценарий присутствует в репозитории,
но его запуск не подтверждён в отчёте проверки.
Разработка интерфейса
Первый терминал, корень репозитория:
./backend/run.sh
Второй терминал, корень репозитория:
cd frontend
npx --yes [email protected] install --frozen-lockfile
npx --yes [email protected] dev
Интерфейс откроется на http://127.0.0.1:5173; /api и /health проксируются на порт 8000.
Подробности подключения: frontend/README.md.
6. Как проверить решение: сценарий для жюри
Через интерфейс
Для повторяемого результата запустите сервер с ANALYSIS_MODE=demo по инструкции выше.
- Откройте сайт. Если уже есть сравнение, нажмите «Новое сравнение».
- Нажмите «Загрузить пример „до/после“». Учебная пара DOCX будет загружена на сервер.
- Откройте «Сравнить текст», выберите документы обеих версий и посмотрите подсветку изменений.
- Проверьте, что оба учебных комплекта отмечены полными, затем нажмите «Запустить сравнение».
- После завершения откройте результаты. В учебном сценарии предусмотрены следующие изменения:
| Что проверить | Ожидаемый результат |
|---|---|
| Департамент непрерывного мониторинга → Департамент непрерывного аудита | Переименование подразделения |
| «Готовит отчёт о результатах непрерывного аудита» | Передача функции в департамент контроля качества аудита и методологии |
| «Проверяет сохранность активов» | Возможная потеря функции |
| «Проверяет права доступа к информационным системам» | Возможное дублирование у разных владельцев |
| Утверждение платежей поставщикам при сохранённом запрете | Противоречие полномочий |
| Отдел аналитики | Создание подразделения |
- В замечании откройте «Источники» и проверьте цитату в документе.
- Подтвердите или отклоните замечание, добавьте комментарий и перезагрузите страницу: решение должно сохраниться.
- Скачайте отчёт Markdown и JSON. Откройте сравнение через «История»; ненужное завершённое сравнение можно удалить вместе с его файлами.
Двойное функциональное/административное подчинение и одинаковые действия в разных областях включены как контрольные случаи без нарушения. Исходные тексты и ожидаемые изменения находятся в examples/scenario.json. Это синтетические данные; результат вычисляется при запуске анализа.
Через API
При работающем сервере откройте второй терминал в корне репозитория:
cd backend
uv run --frozen --no-dev python -m scripts.demo_client
Скрипт создаёт учебные документы, новое сравнение, загружает оба файла, запускает анализ
и сохраняет результат в backend/data/demo/result.json, отчёт — в
backend/data/demo/report.md. Он использует текущий режим сервера: при llm будут
выполнены обращения к модели. Если включён API_TOKEN, передайте его скрипту
одноимённой переменной окружения.
Для генерации только учебных DOCX/XLSX, без запросов к серверу, из каталога backend:
uv run --frozen --no-dev python -m scripts.make_demo
Автоматические проверки
Из корня репозитория — серверные тесты, линтер и экспорт схемы:
cd backend
uv sync --frozen --group dev
uv run --frozen pytest -q
uv run --frozen ruff check .
uv run --frozen python -m scripts.export_openapi
В другом терминале, из корня репозитория — интерфейс и браузерные сценарии:
cd frontend
npx --yes [email protected] install --frozen-lockfile
npx --yes [email protected] test
npx --yes [email protected] build
npx --yes [email protected] exec playwright install chromium firefox
npx --yes [email protected] test:e2e
npx --yes [email protected] test:api
В docs/VALIDATION.md за 23 сентября 2026 года зафиксированы:
217 серверных, 71 модульный тест интерфейса, 33 браузерных сценария и 5 сценариев
восстановления API; Ruff и сборка также прошли. Браузерные проверки используют
отдельный сервер в режиме demo и временную БД. Автотесты модельного адаптера работают
с тестовым HTTP-провайдером и не подтверждают качество анализа живой моделью.
7. Данные и интеграции
Входные данные
| Формат | Что читается и как адресуется источник |
|---|---|
| DOCX | Абзацы, таблицы, колонтитулы, номера списков; ссылки на разделы, абзацы и пункты |
| Текстовый слой, объединение переносов; ссылки на страницы и фрагменты | |
| XLSX | Листы и значения ячеек, таблицы с распознаваемыми заголовками владельца и функции; ссылки на лист и диапазон |
| TXT | Строки текста; UTF-8, UTF-16/UTF-32 с BOM, Windows-1251 с предупреждением |
Источники анализа — загруженные пользователем файлы. Учебные данные хранятся в
examples/scenario.json и frontend/public/examples/. Подключённых справочников
законодательства, внешних корпоративных систем или баз для сравнения организаций нет.
Хранение и доступ
- При обычном локальном запуске SQLite находится в
backend/data/analysis.sqlite3, оригиналы — вbackend/data/uploads/. Корень хранения меняется черезDATA_DIR. - В БД сохраняются метаданные, SHA-256 файлов, фрагменты, состояние анализа, результаты и решения проверяющего. Данные не исчезают при перезагрузке страницы.
- Удаление сравнения очищает связанные записи и оригиналы. Удалять задания в очереди или в процессе анализа нельзя.
- Необязательный
API_TOKENзащищает API и/docs,/redoc,/openapi.json. На сайте он вводится в «Доступ к серверу» → «Токен доступа» и сохраняется вsessionStorageтекущей вкладки. Это отдельный токен приложения, не ключ модели. /healthи статические файлы интерфейса доступны без токена.
Внешний API
В режиме llm сервер отправляет извлечённые фрагменты и структурированные данные в
настроенный Responses API. В запросе указано store: false; это не обещание полного
отсутствия хранения данных у провайдера. Модели не предоставляются инструменты,
доступ к shell или поиск в интернете. В режиме demo внешний AI-сервис не используется.
8. Ограничения текущей версии
- Качество выводов.
demoограничен правилами и не гарантирует распознавание свободных перефразирований, неявных слияний и разделений. Сложные конфликты между должностью и подразделением через подразумеваемые связи полномочий в этом режиме не реализованы. Выводыllmтакже требуют проверки человеком; измерений точности на реальном корпусе в репозитории нет. - Качество входных файлов. OCR, чтение графических оргструктур, старые бинарные DOC/XLS и вычисление формул Excel не реализованы. Изображения, непринятые исправления Word и неоднозначные таблицы могут снизить полноту извлечения. Внешний вид страницы Word или PDF в текстовом сравнении не воспроизводится.
- Полнота. Отметка «все документы загружены» не гарантирует полноту извлечения. При обнаруженных ограничениях сервис сообщает о недостаточном покрытии; отсутствие замечаний не является доказательством отсутствия организационных проблем.
- Доступ и масштабирование. Прототип рассчитан на одну доверенную команду: отдельных
аккаунтов и разграничения доступа между пользователями нет. Сервер запускается одним
процессом (
--workers 1); очередь локальная, без распределённых обработчиков. - Прерывание работы. После аварийного завершения незавершённый анализ помечается ошибкой и требует повторного запуска. Продолжения с последнего обработанного фрагмента нет. Ранее завершённые сравнения после изменения кода автоматически не пересчитываются.
- Внешние нормы. Проверка законодательства и сравнение с другими организациями не реализованы.
Основные лимиты по умолчанию заданы в конфигурации:
| Ограничение | Значение |
|---|---|
| Документов в сравнении | 20 суммарно для двух сторон |
| Размер одного файла | 20 МБ |
| Извлечённых символов в одном документе | 200 000 |
| Извлечённых символов в сравнении | 400 000 |
| Извлечённых функций | 1000 на каждую сторону |
| Сериализованный вход одного запроса к модели | 300 000 символов |
| Таймаут HTTP-запроса к модели | 120 секунд |
| Параллельных фоновых заданий | 2 |
Лимиты настраиваются переменными окружения. Символы не равны токенам: ограничения контекста выбранной модели действуют дополнительно. Анализ больших документов включает несколько запросов; процент прогресса обновляется по этапам и документам, поэтому не отражает продвижение каждого отдельного запроса.
9. Развёрнутая версия
Публичная ссылка на развёрнутое приложение в репозитории не указана. Подтверждённый способ демонстрации — локальный запуск по инструкции выше: http://127.0.0.1:8000. Это адрес приложения на вашем компьютере. Для развёртывания подготовлены Dockerfile и compose.yaml; конкретный облачный хостинг не настроен в репозитории.
Авторы коммитов
История коммитов
- 2026-09-23 17:58docs: add comprehensive Russian project guide for hackathon judgesSkyZim-fr
- 2026-09-23 17:50feat(frontend): add persistent light and dark themesCodex
- 2026-09-23 17:30fix: clear stale analysis errors when documents changeCodex
- 2026-09-23 17:20fix: resolve QA regressions and integrate document comparison featuresSkyZim-fr
- 2026-09-23 16:21feat: support TXT uploads and improve PDF and Excel comparisonCodex
- 2026-09-23 16:07fix(frontend): surface repeated document text and result filtersCodex
- 2026-09-23 15:20feat(frontend): add side-by-side document text comparisonCodex
- 2026-09-23 15:08fix(backend): defer store annotations for Python 3.12 and 3.13Codex
Все коммиты (13)
- 2026-09-23 14:56Connect document workspace to comparison backendSkyZim-fr
- 2026-09-23 14:54docs: add revision 8 and 9 semantic comparison referenceCodex
- 2026-09-23 14:31Merge DOCX frontend into mainCodex
- 2026-09-23 14:25Implement organizational analysis backend with evidence-backed reportsSkyZim-fr
- 2026-09-23 14:25feat(frontend): add DOCX upload and document workspaceCodex
Структура репозитория (102 файлов)
.dockerignore .gitignore README.md backend/.dockerignore backend/.env.example backend/Dockerfile backend/app/__init__.py backend/app/analysis.py backend/app/config.py backend/app/demo.py backend/app/errors.py backend/app/evidence.py backend/app/jobs.py backend/app/llm.py backend/app/main.py backend/app/models.py backend/app/parsing.py backend/app/report.py backend/app/store.py backend/pyproject.toml backend/run.sh backend/scripts/demo_client.py backend/scripts/export_openapi.py backend/scripts/make_demo.py backend/tests/__init__.py backend/tests/conftest.py backend/tests/test_api.py backend/tests/test_github_merge.py backend/tests/test_llm.py backend/tests/test_parsing.py backend/tests/test_qa_analysis.py backend/tests/test_qa_api_reports.py backend/tests/test_qa_parsing.py backend/tests/test_qa_round2.py backend/tests/test_static.py backend/uv.lock compose.yaml docs/API.md docs/ARCHITECTURE.md docs/QA_FIXES.md docs/VALIDATION.md docs/example-comparison.json docs/example-result.json docs/example-sources.json docs/openapi.json examples/scenario.json frontend/.env.example frontend/.gitignore frontend/README.md frontend/docs/API_CONTRACT.md frontend/index.html frontend/package.json frontend/playwright.api.config.ts frontend/playwright.config.ts frontend/pnpm-lock.yaml frontend/public/examples/after.docx frontend/public/examples/audit-example.docx frontend/public/examples/before.docx frontend/public/favicon.svg frontend/public/theme-init.js frontend/scripts/generate-example.py frontend/src/App.tsx frontend/src/ComparisonControls.tsx frontend/src/ComparisonHistory.tsx frontend/src/ComparisonResults.tsx frontend/src/ConnectionSettings.tsx frontend/src/DocumentDiff.tsx frontend/src/TextRepetitions.tsx frontend/src/ThemeToggle.tsx frontend/src/comparison.css frontend/src/document-diff.css frontend/src/integration.css frontend/src/lib/api.ts frontend/src/lib/documents.ts frontend/src/lib/docx.worker.ts frontend/src/lib/local-reader.ts frontend/src/lib/preferences.ts frontend/src/lib/presentation.ts frontend/src/lib/textDiff.ts frontend/src/lib/textRepetitions.ts frontend/src/lib/types.ts frontend/src/lib/xlsxText.ts frontend/src/main.tsx frontend/src/styles.css frontend/src/text-repetitions.css frontend/src/theme-layout.css frontend/src/theme-results.css frontend/src/theme.css frontend/src/useDocuments.ts frontend/src/workers/textDiff.worker.ts frontend/tests/e2e/api.spec.ts frontend/tests/e2e/documents.spec.ts frontend/tests/e2e/integration.spec.ts frontend/tests/servers.ts frontend/tests/unit/documents.test.ts frontend/tests/unit/github-merge.test.ts frontend/tests/unit/qa-regressions.test.ts frontend/tests/unit/qa-round2.test.ts frontend/tsconfig.json frontend/vite.config.ts frontend/vitest.config.ts run.sh
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.