Claude Code plugin • MIT License
Claude Code плагин, который подключает браузер Perplexity Comet как источник веб-поиска — с минимальным расходом токенов и приватностью истории.
- 💬
comet_answerвозвращает синтезированный ответ Perplexity (Pro) + цитаты[{n, title, url}]— выжимку по нескольким источникам одним вызовом. - 🔎
comet_searchвозвращает сжатый список[{title, url, snippet≤200}](до 10), а не полный HTML/текст страницы. - 📄
comet_read_pageотдаёт только основной текст статьи, обрезанный доmax_tokens, с пометкой[TRUNCATED]. Полный текст лежит локально в кэше. Страница открывается в анонимной вкладке — ваши cookie на чужой сайт не уходят, а его трекеры не оседают в вашем профиле. - ➕
comet_get_moreдозагружает следующий фрагмент из кэша (не тратя браузер). - 🧠
comet_task_startотдаёт Perplexity задачу, а не запрос: внутри одного треда проходит несколько промптов (план → проработка подвопросов → синтез), а наружу возвращает только итог и однострочные выжимки шагов. - 🕵️ Поиск идёт в основном (залогиненном) профиле с включённым Incognito/Temporary Perplexity: сохраняется Pro, но треды не попадают в постоянную историю и истекают за 24 часа.
- ⚡ Локальный кэш: повторный URL и повторный поиск отдаются мгновенно (без браузера); кэш с TTL и лимитом (LRU-вытеснение), не растёт бесконечно.
- 🚫 Никакого Perplexity/Sonar API — только управление реальным Comet через CDP под вашей веб-подпиской.
- 🪶 Сырой CDP через нативный WebSocket — без puppeteer (одна зависимость, выше отказоустойчивость; совместимо с движком Comet Chrome 150).
- 🔁 Само восстанавливается: если вкладку закрыли руками или оборвалось CDP-соединение — переподключается, пересоздаёт вкладку и повторяет операцию.
- macOS, установленный Comet (
/Applications/Comet.app). - Подписка Perplexity Pro/Max (для снятия лимитов).
- Node.js ≥ 22 (нужен встроенный
WebSocket; проверено на v22.18). - Claude Code с авторизацией через
/login(API-ключ не нужен).
Репозиторий публичный — авторизация в GitHub не нужна.
curl -fsSL https://raw.githubusercontent.com/ArkHak/comet-research/main/bootstrap.sh | bashСкачает bootstrap.sh, склонирует репозиторий в ~/comet-research и запустит
установку. Передать параметры (см. ниже) или другой каталог:
# без вопросов и с авто-перезапуском Comet:
curl -fsSL https://raw.githubusercontent.com/ArkHak/comet-research/main/bootstrap.sh | bash -s -- ~/comet-research -- --yesgit clone https://github.com/ArkHak/comet-research.git
cd comet-research
./install.shОдин скрипт делает всё: проверяет окружение, ставит зависимости, подключает плагин к Claude Code навсегда и запускает Comet с нужным флагом.
cd comet-research
./install.shЧто делает install.sh:
- Проверяет Node.js ≥ 22 и наличие Comet (иначе — понятная ошибка с подсказкой).
- Ставит зависимости MCP-сервера (
npm install). - Регистрирует плагин в Claude Code навсегда (marketplace + install, scope user) —
больше не нужно каждый раз запускать
--plugin-dir. - Если CDP-порт закрыт — предлагает запустить Comet с флагом отладки (спросит перед закрытием текущих окон Comet), затем проверяет порт.
После этого перезапустите Claude Code — плагин загрузится сам в каждой сессии.
Режимы (меньше вопросов — больше автоматизации):
./install.sh --yes # не спрашивать, перезапустить Comet автоматически
./install.sh --no-launch # не трогать Comet (зависимости + постоянная регистрация)
./install.sh --no-register # не регистрировать в Claude Code (только зависимости)
./install.sh --helpБольше ничего запускать вручную не нужно: если при первом поиске Comet окажется не запущен, MCP-сервер сам стартует его с флагом отладки (
COMET_AUTO_LAUNCH=1в.mcp.json). Исключение — если Comet уже запущен без флага: тогда выполните./launch-comet.sh(сам не закрывает чужие окна).
Плагин управляет Comet по Chrome DevTools Protocol, поэтому Comet должен работать с флагом удалённой отладки. Удобнее всего — скриптом (сам закроет старый экземпляр и дождётся порта):
./launch-comet.shЭквивалент вручную:
# Полностью закройте Comet, затем:
/Applications/Comet.app/Contents/MacOS/Comet --remote-debugging-port=9222
# Проверка, что порт слушается:
curl -s http://localhost:9222/json/version # вернётся JSON с версией браузераПорт можно поменять в
.mcp.json(env.COMET_CDP_PORT).
Плагин работает в вашем основном (залогиненном) профиле Comet — чтобы сохранить Perplexity Pro, — но включает встроенный Incognito/Temporary-режим Perplexity: треды не сохраняются в постоянную историю и удаляются через 24 часа.
⚠️ Почему НЕ браузерное инкогнито: отдельное окно инкогнито (CDPcreateBrowserContextили ⌘⇧N) даёт анонимную сессию без логина — то есть без Pro. Проверено эмпирически. Поэтому плагин использует не браузерное инкогнито, а собственный приватный режим Perplexity в залогиненном профиле.
Что делает плагин автоматически перед первым поиском в сессии:
- Открывает
perplexity.aiв вашем основном профиле. - Проверяет, включён ли приватный режим; если нет — нажимает кнопку-призрак инкогнито (настоящим кликом мыши через CDP) и убеждается, что режим включён.
- Если включить приватный режим не удалось — возвращает предупреждение и не выполняет поиск (чтобы не засорять историю).
- Если вы не залогинены в Perplexity — сообщит, что Pro недоступен (войдите в аккаунт в Comet).
Требование: вы должны быть залогинены в Perplexity в Comet (для Pro).
Режим перепроверяется, а не подтверждается один раз. Приватный режим может
слететь: вы нажали «Выйти из режима инкогнито», Perplexity сбросил состояние,
истекли сутки. Раньше плагин верил первому подтверждению до конца сессии — и в
таком случае молча писал бы в постоянную историю. Теперь у подтверждения есть
срок годности (privateRecheckMs, по умолчанию 10 минут), а внутри срока перед
каждым запросом состояние дёшево перепроверяется прямо на текущей странице
(один вызов, без навигации). Если режим слетел — плагин включает его заново и
сообщает об этом в notices.
comet_read_page открывает чужие сайты не в вашем профиле, а в одноразовой
анонимной вкладке:
- сайт не получает ваши cookie, то есть не узнаёт вас;
- его трекеры и cookie не оседают в основном профиле, а визит не попадает в историю браузера;
- контекст уничтожается после каждого чтения, поэтому cookie сайта A не доживают до чтения сайта B.
Обратная сторона: страницы, требующие вашего логина (закрытые разделы, часть
paywall), в анонимной вкладке не прочитаются. Для таких случаев —
COMET_READER_ANONYMOUS=0, тогда чтение идёт в основном профиле, как раньше.
URL проверяется перед открытием. Разрешены только http/https и только
публичные адреса. Локальные и внутренние ресурсы (localhost, 127.0.0.1,
192.168.*, 10.*, 172.16–31.*, 169.254.169.254, *.local) отклоняются —
иначе плагин можно было бы навести на ваши локальные сервисы или на метаданные
облака. Имя хоста при этом резолвится: домен, указывающий на внутренний
адрес, тоже отклоняется.
Плагин подключается навсегда (загружается в каждой сессии, без --plugin-dir)
через механизм маркетплейсов Claude Code. install.sh делает это сам, но можно и
вручную:
# из каталога плагина (после клона + npm install в mcp-server/):
claude plugin marketplace add "$(pwd)" # добавить маркетплейс (scope user)
claude plugin install comet-research@mys_ya # установить плагин навсегдаПлагин копируется в кэш Claude Code (
~/.claude/plugins/cache/…) вместе с зависимостями, поэтому работает независимо от исходного каталога — его можно потом переместить или удалить.
Перезапустите Claude Code, затем проверьте:
/mcp— сервер comet-research в списке, инструментыcomet_search,comet_read_page,comet_get_moreдоступны./context— навыкcomet-research(SKILL.md) подхватился.claude plugin list— строкаcomet-research@mys_ya … ✔ enabled.
Управление:
claude plugin update comet-research@mys_ya # обновить после git pull (требует restart)
claude plugin disable comet-research@mys_ya # временно отключить
claude plugin uninstall comet-research@mys_ya # удалить плагин
claude plugin marketplace remove mys_ya # удалить маркетплейсПри обновлении кода поднимите
versionв.claude-plugin/plugin.jsonиmarketplace.json, затемclaude plugin marketplace update mys_ya+claude plugin install comet-research@mys_ya— иначе кэш той же версии не перечитается.
claude --plugin-dir .| Инструмент | Что возвращает |
|---|---|
comet_answer(query, max_tokens=800) |
Синтезированный ответ Perplexity + citations: [{n, title, url}] |
comet_search(query) |
Сжатый список источников [{title, url, snippet≤200}] (до 10) |
comet_read_page(url, max_tokens=600) |
Основной текст статьи, [TRUNCATED] + cache_id |
comet_get_more(cache_id, offset) |
Следующий фрагмент из кэша (работает и с cache_id из comet_answer) |
comet_healthcheck() |
Самодиагностика: CDP, логин, приватный режим, парсинг ответа/источников, статус DOM-якорей |
comet_task_start({task, context?, steps?, max_steps=4}) |
Запускает многошаговую проработку задачи в фоне, возвращает task_id |
comet_task_status(task_id) |
Прогресс и выжимки шагов; по готовности — итог, цитаты, cache_id стенограммы |
comet_task_cancel(task_id) |
Остановить проработку после текущего шага |
comet_list_models() |
Модели ИИ, доступные сейчас в Perplexity: {current, models: [{name, badges, locked, checked}]} |
comet_set_model(model) |
Переключить модель по подстроке названия (глобально, персистентно — см. ниже) |
В диалоге с Claude:
Чем StateFlow отличается от SharedFlow в Kotlin?
Claude вызовет comet_answer(...) и получит готовую выжимку с цитатами — часто
это закрывает вопрос одним вызовом. Если нужен список ссылок — comet_search(...);
если нужно углубиться в конкретную страницу — comet_read_page(url).
Когда вопрос не закрывается одним ответом:
Разберись, какой подход к офлайн-синхронизации выбрать для нашего KMP-приложения.
Claude вызовет comet_task_start(...), и внутри одного треда Perplexity
пройдёт несколько промптов:
план → шаг 1 → шаг 2 → шаг 3 → синтез
(каждый шаг видит контекст предыдущих — тред общий)
Работа идёт в фоне (обычно 1–6 минут), Claude опрашивает comet_task_status.
В контекст возвращается только итог + по одной строке на шаг; полная
стенограмма всех ответов остаётся в локальном кэше и доступна по cache_id
через comet_get_more. На реальном прогоне: 4 запроса к Perplexity за 59 секунд,
стенограмма 5992 символа, в контекст ушло 1651.
Задача не блокирует остальные инструменты: вкладка захватывается пошагово, и
между шагами в неё пролезают обычные comet_search/comet_answer. Если такой
вызов увёл вкладку, задача перед следующим шагом возвращается в свой тред по URL
— контекст диалога при этом сохраняется.
Ограничения:
- одновременно выполняется одна задача — вкладка у плагина одна;
- каждый шаг тратит запрос Pro, поэтому
max_stepsограничен (по умолчанию 4, максимум 6); - состояние задач живёт в памяти MCP-сервера: после перезапуска Claude Code
старые
task_idнедоступны (стенограмма при этом остаётся в кэше).
По умолчанию comet_search/comet_answer/comet_task_start отвечают той
моделью, что выбрана в вашем профиле Perplexity. Управлять этим можно двумя
инструментами:
comet_list_models()— список моделей, доступных прямо сейчас, и какая из них активна:{current, models: [{name, badges, locked, checked}]}.comet_set_model({model})— переключить модель. Сопоставление — по регистронезависимой подстроке названия ("sonar","claude","gemini"сработают), точное совпадение приоритетнее частичного.
Важно — это настройка ПРОФИЛЯ, а не одного вызова. Переключив модель, вы
меняете её ровно так же, как ручным кликом в интерфейсе Perplexity: она
остаётся активной для всех последующих запросов (comet_search,
comet_answer, comet_task_start) любых сессий, пока её не сменят снова.
Автоматического отката нет.
Список моделей нигде не захардкожен — comet_list_models/comet_set_model
читают его из живого меню «Модель» в интерфейсе при каждом вызове, поэтому
инструмент остаётся рабочим и после того, как Perplexity переименует или
добавит модели. Модели уровня Max (в списке — locked: true) требуют
отдельной подписки Perplexity Max: comet_set_model откажет с понятной
ошибкой и ничего не переключит, если попросить такую модель. Среди нескольких
совпадений по подстроке доступная модель приоритетнее запертой (Max).
Вместо точного названия модели comet_set_model принимает готовый пресет:
comet_set_model({ preset: "general" }) // по умолчанию GPT
comet_set_model({ preset: "code" }) // по умолчанию Claude
Настраиваются в mcp-server/config.js (modelPresets) или переменными
окружения COMET_MODEL_GENERAL/COMET_MODEL_CODE (это подстроки для поиска
в живом меню, а не точные имена — так же, как в comet_set_model({model})).
Пресет general применяется автоматически при первом запросе за сессию
MCP-сервера — отдельно вызывать его не нужно, если только до этого не
переключали на code. Для вопросов по коду переключайтесь на code явно
через comet_set_model({preset:"code"}); автоматического отката обратно на
general нет — при следующем не-кодовом вопросе переключайте вручную.
MCP-сервер держит одну рабочую вкладку на всю сессию (getWorkPage в
incognito.js) — так поиски идут быстро, без пересоздания вкладки на каждый
вызов. Но при завершении процесса (закрыли Claude Code, SIGINT/SIGTERM,
естественное завершение stdio) вкладка теперь закрывается сама
(closeSessionPage) — иначе она годами копилась бы в Comet между запусками
Claude Code, засоряя окно вкладками-сиротами.
После теста:
- Откройте Perplexity → Library / История.
- Убедитесь, что новых тредов от автоматических запросов там не появилось (в приватном режиме они не сохраняются и истекают за 24 часа).
| Параметр | Назначение | По умолчанию |
|---|---|---|
cdpPort |
Порт CDP Comet | 9222 (env COMET_CDP_PORT) |
autoLaunch |
Сам запускать Comet, если он не работает | true (env COMET_AUTO_LAUNCH, 0 = выкл.) |
maxResults |
Сколько результатов отдавать | 10 |
snippetMaxChars |
Длина snippet | 200 |
defaultReadMaxTokens |
Лимит текста в read_page | 600 |
maxSearchesPerSession |
Лимит поисков за сессию (0 = выкл.) | 0 (env COMET_MAX_SEARCHES) |
cacheTtlMs |
TTL кэша страниц/ответов | 86400000 (24ч, env COMET_CACHE_TTL_MS) |
cacheMaxEntries |
Лимит записей в кэше (LRU-вытеснение) | 300 (env COMET_CACHE_MAX) |
searchCacheTtlMs |
TTL кэша результатов поиска | 600000 (10 мин, env COMET_SEARCH_CACHE_TTL_MS) |
taskDefaultSteps |
Шагов в проработке задачи по умолчанию | 4 (env COMET_TASK_STEPS) |
taskMaxSteps |
Максимум шагов | 6 (env COMET_TASK_MAX_STEPS) |
defaultTaskMaxTokens |
Лимит объёма итога задачи | 1200 (env COMET_TASK_MAX_TOKENS) |
taskStepTimeout |
Тайм-аут одного шага | 120000 (env COMET_TASK_STEP_TIMEOUT_MS) |
tabQueueTimeout |
Сколько ждать своей очереди на вкладку | 180000 (env COMET_TAB_QUEUE_TIMEOUT_MS) |
requirePrivate |
Отказ искать, если не включён приватный режим | true |
readerAnonymous |
Читать внешние страницы в анонимной вкладке | true (env COMET_READER_ANONYMOUS, 0 = основной профиль) |
privateRecheckMs |
Срок годности подтверждения приватного режима | 600000 (10 мин, env COMET_PRIVATE_RECHECK_MS) |
modelPresets.general |
Пресет модели для большинства задач (подстрока для поиска в меню) | GPT (env COMET_MODEL_GENERAL) |
modelPresets.code |
Пресет модели для вопросов по коду | Claude (env COMET_MODEL_CODE) |
autoApplyDefaultModel |
Применять пресет general автоматически при первом запросе за сессию |
true (env COMET_MODEL_AUTO_APPLY, 0 = выкл.) |
# например, не более 20 поисков
COMET_MAX_SEARCHES=20 claude --plugin-dir .или измените maxSearchesPerSession в config.js.
| Симптом | Причина / решение |
|---|---|
| «CDP недоступен» | Comet запущен без флага отладки. Выполните ./launch-comet.sh (авто-запуск не закрывает уже работающий Comet). |
| «Не удалось включить приватный режим» | Включите инкогнито Perplexity вручную (кнопка-призрак в шапке или ⌘⇧N) и повторите. |
| «Не залогинены в Perplexity» | Войдите в свой аккаунт Perplexity в Comet (для Pro). |
| Пустые результаты | Вызовите comet_healthcheck — покажет, что сломалось (CDP/логин/приватность/парсинг). Часто помогает повтор запроса. |
| Парсинг «поехал» после обновления Perplexity | Все DOM-селекторы собраны в mcp-server/selectors.js — правьте там; comet_healthcheck покажет, какие якоря не нашлись. |
| «Вкладка Comet занята» | У плагина одна вкладка, операции идут по очереди. Обычно достаточно повторить; если держит долгая задача — снимите её через comet_task_cancel (кто держит вкладку, видно в comet_healthcheck → tabQueue). |
| Закрыли вкладку плагина / перезапустили Comet | Ничего делать не нужно: следующий вызов сам переподключится и создаст вкладку заново. Шаг comet_task, попавший на обрыв, помечается провальным, а работа продолжается со следующего. |
Репозиторий — сам является плагином (без вложенности): .claude-plugin/ лежит
в корне, поэтому claude plugin marketplace add <репозиторий> находит манифест
сразу.
comet-research/
├── LICENSE # MIT
├── bootstrap.sh # скачать плагин с GitHub и установить (с нуля)
├── install.sh # авто-установка (если файлы уже есть)
├── launch-comet.sh # запуск Comet с CDP-флагом (перезапуск при нужде)
├── .claude-plugin/
│ ├── plugin.json # манифест плагина
│ └── marketplace.json # манифест маркетплейса (source: "./" — репозиторий сам плагин)
├── .mcp.json # регистрация stdio MCP-сервера (+ COMET_AUTO_LAUNCH)
├── skills/comet-research/SKILL.md
├── mcp-server/
│ ├── package.json # зависимости + метаданные npm-пакета (см. «Публикация»)
│ ├── index.js # точка входа MCP (10 инструментов), версия — из package.json
│ ├── cdp.js # сырой CDP-клиент (WebSocket), подключение + переподключение
│ ├── page.js # обёртка вкладки: navigate / evaluate / waitForFunction
│ ├── incognito.js # приватный режим Perplexity (профиль + Temporary) + перепроверка
│ ├── anon.js # одноразовая анонимная вкладка для чтения чужих страниц
│ ├── url-guard.js # запрет локальных/внутренних адресов (SSRF)
│ ├── selectors.js # ВСЕ DOM-эвристики в одном месте (устойчивость к вёрстке)
│ ├── search.js # comet_search + collectSources (вкладка «Ссылки»)
│ ├── answer.js # comet_answer (ответ Perplexity + цитаты)
│ ├── reader.js # comet_read_page / comet_get_more
│ ├── healthcheck.js# comet_healthcheck (самодиагностика)
│ ├── composer.js # ввод в поле Perplexity: диалог в одном треде
│ ├── model.js # comet_list_models/comet_set_model (выбор модели ИИ)
│ ├── tab-lock.js # FIFO-очередь на единственную вкладку (withTab)
│ ├── tab-lock.test.mjs # тест очереди (нужен запущенный Comet)
│ ├── reconnect.test.mjs # тест восстановления после обрывов
│ ├── private-recheck.test.mjs # тест перепроверки приватного режима
│ ├── reader-privacy.test.mjs # тест изоляции cookie и URL-guard
│ ├── task/
│ │ ├── runner.js # comet_task_* — план → шаги → синтез, фоновое выполнение
│ │ └── prompts.js# шаблоны промптов и парсеры плана/выжимок
│ ├── cache.js # файловый кэш + анти-дублирование
│ └── config.js # настройки и лимиты
└── README.md
При изменении кода: поднять version в трёх местах — .claude-plugin/plugin.json,
.claude-plugin/marketplace.json (поле plugins[0].version) и
mcp-server/package.json — затем закоммитить и слить в main. Пользователи с
постоянной установкой обновятся через claude plugin marketplace update mys_ya
claude plugin update comet-research@mys_ya.
mcp-server/package.json подготовлен к публикации в npm (имя
comet-research-mcp, без scope, bin со ссылкой на index.js). Публикация не
обязательна — плагин полностью работает через клон + install.sh. Она даёт
альтернативный, ещё более короткий способ установки (npx вместо локального
node_modules), но требует отдельного npm-аккаунта и выполняется только вручную:
cd mcp-server
npm login # интерактивно, свои учётные данные npm
npm publish --access public