No description
Find a file
2026-08-18 15:31:15 +03:00
.forgejo/workflows chore(ci): forgejo-ран на шаблоне ci-bun (ref VERTA-3544) 2026-08-17 16:54:30 +03:00
cdp feat(cdp): driver on native websocket, named timeouts, mimic probe 2026-08-13 20:33:31 +03:00
cli fix(profiles): runId и profileId как сегменты пути 2026-08-17 14:17:43 +03:00
core feat(trace): run header line and compile(trace) back into a scenario 2026-08-13 23:56:46 +03:00
docs fix(profiles): runId и profileId как сегменты пути 2026-08-17 14:17:43 +03:00
exec fix(test): сборка бинаря внутри ROOT — rename не через границу устройства (ref VERTA-3556) 2026-08-18 15:31:15 +03:00
fixtures chore(stand): acceptance stand, compose, seed smoke 2026-08-13 19:56:32 +03:00
profiles fix(profiles): runId и profileId как сегменты пути 2026-08-17 14:17:43 +03:00
scenarios feat(run): scenario interpreter, jsonl trace, summary and exit codes 2026-08-13 21:48:39 +03:00
schemas feat(blocks): zod registry, schema dump, mimic validate 2026-08-13 21:11:27 +03:00
scripts feat(gate): приёмка недели 1 одной командой с негативным прогоном 2026-08-14 09:56:01 +03:00
stand chore(stand): acceptance stand, compose, seed smoke 2026-08-13 19:56:32 +03:00
testing feat(exec): worker per profile, parallel run, compiled binary entry 2026-08-13 23:51:20 +03:00
trace feat(trace): run header line and compile(trace) back into a scenario 2026-08-13 23:56:46 +03:00
.gitignore fix(test): сборка бинаря внутри ROOT — rename не через границу устройства (ref VERTA-3556) 2026-08-18 15:31:15 +03:00
AGENTS.md chore: bootstrap repo 2026-08-13 10:59:28 +03:00
bun.lock feat(blocks): zod registry, schema dump, mimic validate 2026-08-13 21:11:27 +03:00
CLAUDE.md feat(gate): приёмка недели 1 одной командой с негативным прогоном 2026-08-14 09:56:01 +03:00
cli.ts feat(run): scenario interpreter, jsonl trace, summary and exit codes 2026-08-13 21:48:39 +03:00
CONTEXT.md chore: bootstrap repo 2026-08-13 10:59:28 +03:00
docker-compose.yml chore(stand): pin compose project name, record keyless smoke result 2026-08-13 20:03:59 +03:00
package.json chore(ci): forgejo-ран на шаблоне ci-bun (ref VERTA-3544) 2026-08-17 16:54:30 +03:00
profiles.example.json feat(profiles): cloakserve provider, profiles.json split, mimic profiles up 2026-08-13 21:31:42 +03:00
README.md feat(gate): приёмка недели 1 одной командой с негативным прогоном 2026-08-14 09:56:01 +03:00
tsconfig.json chore: bootstrap repo 2026-08-13 10:59:28 +03:00
worker.ts feat(exec): worker per profile, parallel run, compiled binary entry 2026-08-13 23:51:20 +03:00

Mimic

Движок автоматизации браузера. Сценарий — обычный JSON из готовых блоков, рантайм их исполняет. Браузеры Mimic не запускает: он подключается к уже работающим по CDP (Chrome DevTools Protocol), поэтому работает с любым Chromium и с антидетект-браузером, где у каждого профиля свой отпечаток.

Ключевой принцип: сценарий это данные, а не код. Ни eval, ни генерации TypeScript — модель отдаёт JSON, он проходит проверку схемой до запуска.

Документы

Что Где
Что система делает и для кого docs/prd.md
Как устроена docs/design.md
Почему принято так docs/decisions/
Словарь терминов CONTEXT.md

План работы живёт в Linear (product:mimic, Initiative Mimic), не в этом файле.

Стек

TypeScript на Bun 1.2+, TS strict, Zod для схем блоков, воркеры Bun для параллелизма. Ноль зависимостей в слое CDP — свой тонкий клиент на нативном WebSocket (docs/decisions/ADR-1-own-cdp-client.md). Поставка — один самодостаточный бинарь.

Запуск

bun install

# самая короткая проверка живости: печатает document.title первой страницы
bun run cli.ts probe --ws <browser-level endpoint>

# проверка формы сценария по схемам блоков — браузер не нужен вовсе
bun run cli.ts validate scenarios/login-upload.json

# схемы блоков → schemas/*.json (артефакт в git, вход компилятора сценариев)
bun run schemas:dump

# адреса профилей: по строке <id> <wsEndpoint>, ничего не поднимая
bun run cli.ts profiles up --profiles profiles.example.json

# прогон сценария на всех профилях
bun run cli.ts run scenarios/login-upload.json --profiles profiles.json --run-id run-1

# сборка бинаря: воркер обязан быть второй точкой входа
bun build --compile --outfile mimic cli.ts worker.ts

--ws ждёт browser-level endpoint — поле webSocketDebuggerUrl из GET /json/version. document.title с него не читается: page-таргет клиент находит сам через Target.getTargets и цепляется Target.attachToTarget {flatten: true}. Годится любой уже запущенный Chromium, CloakBrowser не нужен:

"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
  --headless=new --remote-debugging-port=9333 --user-data-dir=/tmp/mimic-probe about:blank &
bun run cli.ts probe --ws "$(curl -s http://127.0.0.1:9333/json/version | jq -r .webSocketDebuggerUrl)"

Два таймаута названы и разведены по типам ошибки, чтобы в трассе было видно, что именно не уложилось: CDP_COMMAND_TIMEOUT_MS (одна команда CDP, умолчание 10000, читается из окружения) и params.timeoutMs шага (умолчание 15000).

Браузеры и приёмочный стенд поднимаются отдельно и живут своей жизнью:

docker compose up -d
curl 'http://localhost:9222/json/version?fingerprint=11111' | jq -r .webSocketDebuggerUrl

Поднимать стек только из основного чекаута, не из worktree. ./fixtures в compose превращается в абсолютный путь хоста: контейнер, поднятый из worktree, переживает его снос, но монтирование указывает в никуда — файлы внутри /files исчезают, а uploadFile падает ERR_FILE_NOT_FOUND на пустом месте.

--idle-timeout=0 в compose обязателен: иначе бездействующий профиль умирает в окне между двумя прогонами.

Профили описываются файлом profiles.json (образец — profiles.example.json): [{id, options, vars}]. options уходит провайдеру браузеров как есть — это параметры cloakserve, ядро их не знает; vars — переменные сценария, провайдер их не видит. Погасить профиль командой нельзя: cloakserve такой ручки не отдаёт, и прогон её всё равно не зовёт — браузеры обязаны переживать смерть рантайма.

Стенд (stand/) в поставку не входит — сценарии гейта ходят на него, а не на живой сайт. Изнутри контейнера браузера он доступен как http://stand:3000, с хоста — http://127.0.0.1:3000. Фикстуры загрузки лежат в fixtures/<profileId>/ и видны браузеру как /files/<profileId>/<filename>.

Проверка

bun test              # CDP-клиент, таймауты, схемы, маскирование, round-trip трассы
bun run smoke:seeds   # два сида в одном контейнере одновременно + фикстуры
bun run smoke:idle    # --idle-timeout=0: сид переживает 5 минут простоя
./scripts/gate.sh     # приёмка: 4 исполнения профиля + проверка изоляции

Гейт судит по двум вещам — коду выхода и summary.json. Логи и формат трассы на вердикт не влияют. Ретраев нет.

Ему нужен поднятый стек (docker compose up -d из основного чекаута) — сам он браузеры не поднимает и не гасит. Что делает: два вызова CLI по два профиля (gate-1, gate-2, между ними процесс умирает целиком), сверка browser-id и StartedAt контейнера, затем негативный прогон — профилю подменяют файл на соседский, и он обязан покраснеть. Переменные: MIMIC_PROFILES (умолчание profiles.example.json), MIMIC_SCENARIO, MIMIC_ARTIFACTS, MIMIC_RUN (MIMIC_RUN=./mimic — гнать собранный бинарь).

Коды выхода: 0 прошло · 1 прогон упал · 2 кривой сценарий или конфиг (браузеры не трогали) · 130 прервали руками.