diff --git a/README.md b/README.md index 7fe695c..e8d530f 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,7 @@ an explicit `adapted-from` marker in its frontmatter. | `code-review` | `adapted-from: mattpocock/skills @ 84fdeffd` (MIT) — two-axis + Fowler baseline; output: caveman-review format | | `writing-skills` | `adapted-from: obra/superpowers @ 6.2.0` (MIT) — TDD-for-skills core + ideya 8 self-skill-authoring | | `web-search` | `author: ours` — search_web tool (pi-extension) + policy: when to search, «без поиска» session-off | +| `browser-operator` | `author: ours` — браузер ОПЕРАТОРА (его Chrome/логины): канал по харнессу (Hermes `browser_exec` / pi тул `browser` / CC `chrome-devtools`), аренда «один водитель за раз», границы «человек vs агент», рецепты тяжёлых страниц. Закрывает провал базового прогона 2026-09-11 («куки из Chrome + curl + ввод пароля» мимо канала); анонимные прогоны — `browser-cdp` | | `review-subagent` | `author: ours` — review_subagent tool (pi-extension): clean-context review by your own model, optional `model` override | | `report-mappa-issue` | `author: ours` — TEMPORARY stopgap: mappa deviation reporting (mail to `mappa` + `.workshop`) while the service is unstable; retire when stabilized | | all other `skills/*` | `author: ours` | diff --git a/README.ru.md b/README.ru.md index 42ae7ea..8b10b84 100644 --- a/README.ru.md +++ b/README.ru.md @@ -91,6 +91,7 @@ bash scripts/build.sh caveman # один | `code-search` | `author: ours` — rg-first код-поиск (замер: 15 мин → 0 сек; роутинг: rg / git grep / interns repo_read / grep_audit) | | `code-review` | `adapted-from: mattpocock/skills @ 84fdeffd` (MIT) — двухосевость + Fowler-база; формат вывода: caveman-review | | `writing-skills` | `adapted-from: obra/superpowers @ 6.2.0` (MIT) — TDD-for-skills ядро + идея 8 self-skill-authoring | +| `browser-operator` | `author: ours` — браузер ОПЕРАТОРА (его Chrome/логины): канал по харнессу (Hermes `browser_exec` / pi тул `browser` / CC `chrome-devtools`), аренда «один водитель за раз», границы «человек vs агент»; анонимные прогоны — `browser-cdp` | | остальные `skills/*` | `author: ours` | Политика адаптации: клон переписывается под наши конвенции (доски `.tasks/`, diff --git a/dist/browser-cdp.skill b/dist/browser-cdp.skill index 9695100..5cee20a 100644 Binary files a/dist/browser-cdp.skill and b/dist/browser-cdp.skill differ diff --git a/dist/browser-operator.skill b/dist/browser-operator.skill new file mode 100644 index 0000000..7f03cf5 Binary files /dev/null and b/dist/browser-operator.skill differ diff --git a/hermes/mapping.yaml b/hermes/mapping.yaml index 0d47c3f..5ebbf4a 100644 --- a/hermes/mapping.yaml +++ b/hermes/mapping.yaml @@ -55,6 +55,10 @@ skills: mode: auto category: software-development + browser-operator: + mode: auto + category: software-development + using-markitdown: mode: auto category: productivity diff --git a/skills/browser-cdp/SKILL.md b/skills/browser-cdp/SKILL.md index 8b88f35..e6eec9d 100644 --- a/skills/browser-cdp/SKILL.md +++ b/skills/browser-cdp/SKILL.md @@ -1,13 +1,14 @@ --- name: browser-cdp author: ours -version: 0.1.0 +version: 0.1.1 description: > Веб-автоматизация через минимальные CDP CLI-тулы в bash — вместо playwright-mcp / Chrome-DevTools-MCP (подход «what if you don't need MCP»). Запуск Chrome с remote debugging, навигация, eval JS, скриншоты. Trigger: «браузер», «скрейпинг», «открой страницу», «перейди на», «сделай скриншот», «playwright», «веб-автоматизация», - «web scraping», «browser». + «web scraping», «browser». Для ЛИЧНЫХ КАБИНЕТОВ оператора (его логины, антибот) — + НЕ этот скил, а `browser-operator`. --- # browser-cdp @@ -20,6 +21,9 @@ description: > снять скриншот, собрать данные (скрейпинг). Использовать **вместо** playwright-mcp или Chrome-DevTools-MCP. +- ⚠️ **Для личных кабинетов оператора этот путь НЕ годится:** здесь свой Chrome и свой + профиль (без его логинов). Нужен браузер оператора — скил `browser-operator`. + ## Процесс 1. **Прочитай полную справку** (обязательно, первый шаг): diff --git a/skills/browser-operator/SKILL.md b/skills/browser-operator/SKILL.md new file mode 100644 index 0000000..ddb2a95 --- /dev/null +++ b/skills/browser-operator/SKILL.md @@ -0,0 +1,119 @@ +--- +name: browser-operator +author: ours +version: 0.1.0 +description: > + Работа в браузере ОПЕРАТОРА — его Chrome, его профиль, его живые логины: личные + кабинеты поставщиков (ЧипДип, ДКО, Промэлектроника, ТМ), Avito, порталы под + антиботом. Trigger: «зайди в личный кабинет», «открой ЛК», «собери заказы», + «посмотри в браузере», «нужна его сессия», «ЧипДип/Ozon/Avito», «browser». + НЕ для публичных страниц (там сначала обычный fetch/curl) и НЕ для анонимных + прогонов (там скил browser-cdp). +--- + +# Browser operator — браузер оператора + +**Браузер оператора — разделяемый ресурс с его живыми сессиями.** Работай через +готовый канал своего харнесса и **только под арендой «один водитель за раз»**. +Не вытаскивай его куки, не логинься сам, не поднимай свой Chrome. + +## Когда браузер действительно нужен + +Сначала спроси себя, нужен ли браузер вообще: + +- **Нет** — публичная страница, API, доки: обычный fetch/curl/поиск. Браузер тут лишний. +- **Да** — страница требует взаимодействия (клик/форма/навигация), JS-рендер, + **его логин** (личный кабинет, Avito), либо портал режет не-браузерный трафик. + +## Канал по харнессу (не изобретай свой) + +| Харнесс | Чем работать | Аренда | +|---|---|---| +| **Hermes** | тул `browser_exec` (демон `browser-use`, тот же профиль оператора) | автоматически: shell-хук `pre_tool_call` берёт аренду и блокирует вызов при чужой | +| **pi** | тул `browser`: `open` / `read` / `js` / `click` / `screenshot` / `lease` | автоматически внутри тула; `lease` покажет, кто держит | +| **Claude Code** | MCP `chrome-devtools` (`list_pages`, `navigate_page`, `take_snapshot`, `evaluate_script`, `click`, `fill`, `take_screenshot`) | автоматически: обёртка берёт аренду перед стартом сервера | + +**Никогда:** `curl` с куками из его профиля, `browser_cookie3`-выгрузка куки, +свой `chrome --remote-debugging-port` с пустым профилем (там нет его логинов), +`pip install`-стек ради одного кабинета. + +## Аренда: «один водитель в браузере за раз» + +Браузер один. Если его держит другой харнесс — **не ломиться**, сказать «занято, +держит X» и вернуться позже (или попросить оператора освободить). + +Идёшь в браузер **в обход** тула (например, скриптом или `browser-use` из терминала) — +бери аренду сам: + +```bash +BL="$HOME/.config/browser-harness/bin/browser-lease.sh" +bash "$BL" acquire --holder "pi:$$" --ttl 900 --pid $$ --tool browser # 0 = взял, 3 = занято, 2 = ошибка +# … работа … +bash "$BL" release --holder "pi:$$" +``` + +Контракт аренды (формат файла, TTL, кого связывать): вики mappa +`concepts/browser-lease-contract`. + +## Как работать в страницах (рецепты) + +- **Первым делом — своя вкладка.** `ensure_real_tab()` / `new_tab(url)`; не полагайся + на активную вкладку оператора: тяжёлая или аудио-страница подвешивает демон + (все вызовы падают в таймаут, хотя `browser-use --doctor` говорит «alive»). +- **Тяжёлые страницы — читать изнутри, а не обходом.** Если у сайта есть внутренний + JSON-эндпоинт, зови его `fetch(path, {credentials:'include'})` из уже открытой + страницы: это быстрее и надёжнее десятков навигаций. +- **По одной штуке за раз, с паузами.** Паузы — в Python/процессе, **не** в JS `await` + (иначе `Runtime.evaluate timed out`). Ориентир оператора: 1 запрос, пауза 7–13 с, + перекур каждые ~40, стоп после 3 ошибок подряд. +- **Клики:** сначала дерево доступности (`Accessibility.getFullAXTree`) или + `querySelector` → центр элемента (`getBoundingClientRect`) → `click_at_xy` → **проверь + результат** отдельным `js(...)`/`page_info()`. Не кликай «на глаз» по скриншоту. +- **Прогресс — сразу на диск** (jsonl/atomic), а не в конце прогона: длинные обходы + обрываются. +- **Долгие обходы** — в фоновый процесс, а не в цикл интерактивных вызовов. + +## Границы: где человек, а где агент + +- **Пароли и второй фактор — никогда.** Не вводим и не просим в аргументах командной + строки. Уже залогиненная сессия оператора — вот твой доступ. +- **Попап «Разрешить удалённую отладку?»** — это человеческое подтверждение: агент его + не жмёт, а просит оператора нажать «Разрешить» и повторяет попытку. +- **Деньги/платежи/отправка форм с персональными данными** — только с явным + подтверждением оператора. +- **Секреты и содержимое залогиненных страниц** не пишем в логи, файлы репозитория и + вики: в mappa — только агрегаты и идентификаторы. + +## Проверенные адреса и факты + +- **ЧипДип, кабинет заказов:** `https://www.chipdip.ru/order/list` + (⚠️ `/cabinet` и `/orders` отдают 404 — не перебирай наугад, ссылка есть в шапке). +- Залогиненность видна в шапке кабинета (имя оператора); если видишь форму логина — + **сессия потеряна: стоп и скажи оператору**, не логинься сам. +- `about:blank`-вкладка с титулом-лошадкой в `document.title` = страницу ведёт агент. + +## Так делать НЕ надо + +| Соблазн | Почему нет | +|---|---| +| «Вытащу куки из Chrome и пойду `curl`'ом» | мимо канала и мимо аренды; пароль/2FA оказываются рядом; ломается при смене защиты | +| «Подниму свой Chrome с отладкой» | там **нет** его логинов → выкинет на логин/капчу, плюс это второй водитель | +| «Введу логин/пароль через `read -s`» | пароли и 2FA не вводим никогда | +| «Проверю ещё пяток URL кабинета» | адрес подтверждай по ссылке в интерфейсе, а не перебором | +| «Налью 20 запросов параллельно, быстрее» | антибот + оператор останавливает такие прогоны; один водитель, одна очередь | + +Основание: базовый прогон без скила (2026-09-11) ушёл именно в «куки + curl + пароль» +мимо канала; скил закрывает этот путь. + +## Красные флаги (стоп и перечитай) + +- Собираешься вытащить куки / поднять свой браузер / ввести пароль или код. +- Работаешь с браузером **без** аренды (или ломишься, когда «занято»). +- Полливаешь запросами без паузы или ждёшь паузу в JS. +- Пишешь содержимое залогиненных страниц/секреты в файл, лог или вики. + +## Вне скоупа + +- Анонимные/антидетект-прогоны, свой профиль, `mode: fresh` — скил `browser-cdp`. +- Облачные браузеры (Browser Use Cloud и прочие) — не берём. +- Свой stdio-MCP-сервер поверх общего демона — отдельная тема.