10 KiB
Perplexity Pack — План 1 (v6): провенанс-вет + безопасный перенос конфигурации
For agentic workers: REQUIRED SUB-SKILL: superpowers:executing-plans (inline). Steps use checkbox syntax.
Goal: Провести провенанс-вет трёх MCP-пакетов research-слоя и аддитивно перенести их блоки в main .mcp.json с защитой бэкапа в .gitignore, идемпотентным бэкапом, пост-валидацией JSON и авто-откатом.
Architecture: Факты по пакетам берутся npm view (метаданные + README) и best-effort gh api. По фактам пишутся docs/research/research-vet.md и docs/research/README.md. Бэкап-паттерн .mcp.json.bak-* сначала заносится в .gitignore; бэкап снимается ТОЛЬКО если ещё не существует (не затирает точку отката); правка .mcp.json аддитивная; после правки JSON валидируется, при невалидности — авто-откат.
Tech Stack: npm CLI, GitHub API (gh), Node.js (fs/JSON.parse), JSON config .mcp.json.
Цель
Доделать первую часть интеграции «Perplexity Pack»: вет происхождения трёх пакетов и
безопасный перенос их конфигурации в main. Реализует якоря спеки {#D2} (провенанс-вет)
и {#D3} (перенос конфигурации) из
docs/superpowers/specs/2026-06-14-perplexity-pack-research-tooling-design-v3.md.
[]
[
{"op":"Bash","object":"npm view @perplexity-ai/mcp-server --json","ref":"D2"},
{"op":"Bash","object":"npm view @perplexity-ai/mcp-server readme","ref":"D2"},
{"op":"Bash","object":"npm view exa-mcp-server --json","ref":"D2"},
{"op":"Bash","object":"npm view exa-mcp-server readme","ref":"D2"},
{"op":"Bash","object":"npm view firecrawl-mcp --json","ref":"D2"},
{"op":"Bash","object":"npm view firecrawl-mcp readme","ref":"D2"},
{"op":"Bash","object":"gh api repos/exa-labs/exa-mcp-server","ref":"D2"},
{"op":"Bash","object":"gh api repos/firecrawl/firecrawl-mcp-server","ref":"D2"},
{"op":"Write","object":"docs/research/research-vet.md","ref":"D2"},
{"op":"Write","object":"docs/research/README.md","ref":"D2"},
{"op":"Bash","object":"node -e \"const fs=require('fs'),p='.gitignore',l='.mcp.json.bak-*';let c='';try{c=fs.readFileSync(p,'utf8')}catch(e){}if(!c.includes(l))fs.appendFileSync(p,'\\n'+l+'\\n')\"","ref":"D3"},
{"op":"Bash","object":"node -e \"const fs=require('fs'),b='.mcp.json.bak-perplexity-pack-20260614';if(!fs.existsSync(b))fs.copyFileSync('.mcp.json',b)\"","ref":"D3"},
{"op":"Edit","object":".mcp.json","ref":"D3"},
{"op":"Bash","object":"node -e \"const fs=require('fs');try{JSON.parse(fs.readFileSync('.mcp.json','utf8'));console.log('JSON OK')}catch(e){fs.copyFileSync('.mcp.json.bak-perplexity-pack-20260614','.mcp.json');console.error('INVALID JSON, rolled back from backup');process.exit(1)}\"","ref":"D3"}
]
[
{"id":"vc1","kind":"EXTRACTED","ref":".mcp.json","anchor":"\"$schema\": \"https://raw.githubusercontent.com/anthropics/claude-code/main/schemas/mcp.json\""},
{"id":"vc2","kind":"EXTRACTED","ref":"docs/security/infosec-vet.md","anchor":"Провенанс-вет внешних инструментов A8 infosec-tooling"},
{"id":"vc3","kind":"EXTRACTED","ref":"tools/cost-pricing.mjs","anchor":"export const PRICING = Object.freeze("}
]
Task 1: Сбор фактов по пакетам (провенанс-вет)
Files: Read-only внешние источники (npm registry, GitHub API).
- Step 1: Метаданные perplexity — Run:
npm view @perplexity-ai/mcp-server --json— Expected: JSONname/version/license/repository/maintainers/time. - Step 2: README perplexity — Run:
npm view @perplexity-ai/mcp-server readme— Expected: текст README. - Step 3: Метаданные exa — Run:
npm view exa-mcp-server --json— Expected: JSON метаданных. - Step 4: README exa — Run:
npm view exa-mcp-server readme— Expected: текст README. - Step 5: Метаданные firecrawl — Run:
npm view firecrawl-mcp --json— Expected: JSON метаданных. - Step 6: README firecrawl — Run:
npm view firecrawl-mcp readme— Expected: текст README. - Step 7: GitHub-активность exa — Run:
gh api repos/exa-labs/exa-mcp-server— Expected:stargazers_count/pushed_at/license. Best-effort: при 404 берётсяrepository.urlиз Step 3, degraded. - Step 8: GitHub-активность firecrawl — Run:
gh api repos/firecrawl/firecrawl-mcp-server— Expected: звёзды/активность. Best-effort: при 404 берётсяrepository.urlиз Step 5, degraded.
Task 2: Вет-док и дом раздела
Files: Create docs/research/research-vet.md, docs/research/README.md.
- Step 9: Написать вет-док — Создать
docs/research/research-vet.mdпо образцуdocs/security/infosec-vet.md: дата 2026-06-14, методология (npm view + gh api), на каждый пакет таблица (владелец/мейнтейнеры, лицензия, версия/пин, активность/последний релиз, что исполняет, сеть/телеметрия) и вердикт ПРИНЯТ/ОТКЛОНЁН. Итоговая таблица вердиктов. Состав — все три, если у всех ПРИНЯТ; любой ОТКЛОНЁН исключается из переноса. Раздел «Ограничения вета»: глубокий разбор исходников за пределами README — degraded. - Step 10: Написать дом-README — Создать
docs/research/README.md: назначение research-tooling, ссылка на вет-док, три сервера и роли (perplexity — ранжированный ответ + sonar; exa — семантическое обнаружение; firecrawl — глубокое чтение + обход), пометка про ключи в user env и риск bulk-load MCP-инструментов при субагент-прогонах.
Task 3: Безопасный перенос блоков в main .mcp.json
Files: Modify .gitignore, .mcp.json (с защитой бэкапа + идемпотентным бэкапом + валидацией).
- Step 11: Защитить бэкап в .gitignore — Run:
node -e "const fs=require('fs'),p='.gitignore',l='.mcp.json.bak-*';let c='';try{c=fs.readFileSync(p,'utf8')}catch(e){}if(!c.includes(l))fs.appendFileSync(p,'\n'+l+'\n')"— Expected: паттерн.mcp.json.bak-*присутствует в.gitignore(идемпотентно). - Step 12: Идемпотентный бэкап
.mcp.json— Run:node -e "const fs=require('fs'),b='.mcp.json.bak-perplexity-pack-20260614';if(!fs.existsSync(b))fs.copyFileSync('.mcp.json',b)"— Expected: бэкап.mcp.json.bak-perplexity-pack-20260614существует; при повторном запуске НЕ перезаписывается (точка отката = исходное состояние сохраняется). - Step 13: Добавить три блока серверов — Edit
.mcp.json: перед ключом_disabled_marketing_servers_noteдобавить три блокаmcpServers(perplexity/exa/firecrawl) по образцуopenapi/sentry:command/args/env(ключ через${VAR})/comment(назначение, источник пакета, вердикт вета, пин). Перенести только пакеты с вердиктом ПРИНЯТ из Step 9. Существующие блоки не трогать. - Step 14: Пост-валидация JSON + авто-откат — Run:
node -e "const fs=require('fs');try{JSON.parse(fs.readFileSync('.mcp.json','utf8'));console.log('JSON OK')}catch(e){fs.copyFileSync('.mcp.json.bak-perplexity-pack-20260614','.mcp.json');console.error('INVALID JSON, rolled back from backup');process.exit(1)}"— Expected:JSON OK. Если JSON битый — команда восстанавливает.mcp.jsonиз бэкапа и завершается с ошибкой (откат, прод-конфиг цел).
Безопасность правки конфига
- gitignore бэкапа — Step 11 (
.mcp.json.bak-*→.gitignore). - Идемпотентный бэкап — Step 12 (
existsSync-гард: повтор не затирает исходную точку отката). - Пост-валидация JSON — Step 14 (
JSON.parse). - Откат — Step 14 авто-восстанавливает из бэкапа при невалидном JSON; ручной откат:
node -e "require('fs').copyFileSync('.mcp.json.bak-perplexity-pack-20260614','.mcp.json')". - Правка аддитивная (только +3 блока), существующие серверы не трогаются.
Self-Review
- Покрытие спеки: Task 1+2 — {#D2}; Task 3 — {#D3} (gitignore/идемпотентный бэкап/валидация/откат). {#D4}–{#D9} — Планы 2 и 3.
- Плейсхолдеров нет: команды точные.
- Согласованность: имена пакетов/серверов едины; бэкап-файл один в Step 12/14; паттерн Step 11 покрывает имя бэкапа Step 12; Step 12 не затирает существующий бэкап.
Примечания
gh api— best-effort: при недоступности репо-slug истина изrepository.urlnpm-метаданных; в вет-доке degraded.- Регрессия vitest и реестр/нормативка/роутер — Планы 2 и 3.