718a6e6ff3
Переписаны nd() блоки для 14 Superpowers-скилов (sk_brainstorm/sk_tdd/sk_debug/sk_wplans/sk_eplans/sk_verify/sk_parallel/sk_worktree/sk_pr/sk_subagent/sk_wskills/sk_spreview/sk_coderev/sk_elements), 2 проектных (sk_rls/sk_qitem), 5 хуков (hk_pre_claude/hk_post_md/hk_post_schema/hk_session/hk_economy). Жаргон-блэклист убран, параграф-ссылки сохранены. Iter2 spec §3 group B. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1255 lines
89 KiB
HTML
1255 lines
89 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Система автоматизации Лидерры</title>
|
||
<script src="https://unpkg.com/vis-network@9.1.9/standalone/umd/vis-network.min.js"></script>
|
||
<style>
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body { background: #0d0d1a; color: #fdf6e3; font-family: 'Segoe UI', system-ui, sans-serif; height: 100vh; display: flex; flex-direction: column; overflow: hidden; }
|
||
|
||
/* ── Toolbar ── */
|
||
#toolbar { background: #073642; border-bottom: 1px solid #586e75; padding: 8px 12px; display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
|
||
#toolbar h1 { font-size: 14px; color: #93a1a1; white-space: nowrap; margin-right: 6px; }
|
||
#search { background: #002b36; border: 1px solid #586e75; color: #fdf6e3; border-radius: 5px; padding: 5px 10px; font-size: 13px; width: 220px; outline: none; }
|
||
#search:focus { border-color: #268bd2; }
|
||
#search::placeholder { color: #586e75; }
|
||
.btn { background: #073642; border: 1px solid #586e75; color: #93a1a1; border-radius: 5px; padding: 5px 12px; font-size: 12px; cursor: pointer; transition: all 0.15s; }
|
||
.btn:hover { background: #0d4a5a; color: #fdf6e3; border-color: #839496; }
|
||
#btn-clear { margin-left: auto; }
|
||
|
||
/* ── Main area ── */
|
||
#main { flex: 1; display: flex; overflow: hidden; }
|
||
|
||
/* ── Graph canvas ── */
|
||
#network { flex: 1; background: #1e1e2e; }
|
||
#network canvas { background: #1e1e2e; }
|
||
|
||
/* ── Legend panel ── */
|
||
#legend-panel { width: 300px; min-width: 300px; background: #002b36; border-left: 1px solid #586e75; overflow-y: auto; padding: 16px; display: none; flex-direction: column; gap: 14px; position: relative; }
|
||
#legend-handle {
|
||
position: absolute; left: 0; top: 0;
|
||
width: 6px; height: 100%;
|
||
cursor: col-resize;
|
||
background: transparent;
|
||
transition: background 0.15s;
|
||
z-index: 10;
|
||
}
|
||
#legend-handle:hover, #legend-handle.dragging { background: #0d4a5a; }
|
||
#legend-panel.visible { display: flex; }
|
||
#legend-close { align-self: flex-end; background: none; border: none; color: #586e75; font-size: 18px; cursor: pointer; line-height: 1; padding: 0; }
|
||
#legend-close:hover { color: #fdf6e3; }
|
||
#legend-title { font-size: 15px; font-weight: 600; color: #fdf6e3; overflow-wrap: break-word; }
|
||
#legend-category { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; }
|
||
.legend-section { background: #073642; border-radius: 6px; padding: 10px 12px; }
|
||
.legend-section h4 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: #839496; margin-bottom: 6px; }
|
||
.legend-section p { font-size: 13px; color: #eee8d5; line-height: 1.5; }
|
||
.legend-section ul { list-style: none; display: flex; flex-direction: column; gap: 4px; }
|
||
.legend-section li { font-size: 12px; color: #eee8d5; line-height: 1.4; }
|
||
.legend-section li span.cond { color: #839496; font-style: italic; }
|
||
.conflict-item { background: #2d0000; border-radius: 4px; padding: 6px 8px; }
|
||
.conflict-item .cname { color: #ff5f57; font-weight: 600; font-size: 12px; }
|
||
.conflict-item .cdesc { color: #cb9b96; font-size: 11px; margin-top: 2px; line-height: 1.4; }
|
||
#legend-no-conflicts { font-size: 12px; color: #586e75; }
|
||
|
||
/* ── Category legend footer ── */
|
||
#cat-legend { background: #073642; border-top: 1px solid #586e75; padding: 7px 14px; display: flex; flex-wrap: wrap; gap: 12px; flex-shrink: 0; }
|
||
.cat-item { display: flex; align-items: center; gap: 5px; font-size: 11px; color: #839496; }
|
||
.cat-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div id="toolbar">
|
||
<h1>🗺 Лидерра — карта автоматизации</h1>
|
||
<input id="search" type="text" placeholder="Поиск узла…" autocomplete="off">
|
||
<button class="btn" id="btn-freeze">❄ Зафиксировать</button>
|
||
<button class="btn" id="btn-unfreeze">▶ Расшевелить</button>
|
||
<button class="btn" id="btn-reset">⊙ Сбросить вид</button>
|
||
<button class="btn" id="btn-clear">✕ Снять выделение</button>
|
||
</div>
|
||
|
||
<div id="main">
|
||
<div id="network"></div>
|
||
<div id="legend-panel">
|
||
<div id="legend-handle" title="Перетащи, чтобы изменить ширину"></div>
|
||
<button id="legend-close">×</button>
|
||
<div id="legend-title">—</div>
|
||
<div id="legend-category"></div>
|
||
<div class="legend-section"><h4>Что делает</h4><p id="ld-desc">—</p></div>
|
||
<div class="legend-section"><h4>Когда используется</h4><p id="ld-when">—</p></div>
|
||
<div class="legend-section"><h4>Ограничения</h4><p id="ld-limits">—</p></div>
|
||
<div class="legend-section"><h4>Кому подчиняется</h4><ul id="ld-reports"></ul></div>
|
||
<div class="legend-section"><h4>Кто подчиняется ему</h4><ul id="ld-manages"></ul></div>
|
||
<div class="legend-section"><h4>С кем работает одновременно</h4><ul id="ld-together"></ul></div>
|
||
<div class="legend-section" id="conflicts-section">
|
||
<h4>⚡ Конфликты</h4>
|
||
<div id="ld-conflicts"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="cat-legend">
|
||
<div class="cat-item"><div class="cat-dot" style="background:#268bd2"></div>Правила</div>
|
||
<div class="cat-item"><div class="cat-dot" style="background:#859900"></div>Плагины</div>
|
||
<div class="cat-item"><div class="cat-dot" style="background:#6c71c4"></div>Скилы Superpowers</div>
|
||
<div class="cat-item"><div class="cat-dot" style="background:#d33682"></div>Скилы проекта</div>
|
||
<div class="cat-item"><div class="cat-dot" style="background:#2aa198"></div>Хуки</div>
|
||
<div class="cat-item"><div class="cat-dot" style="background:#b58900"></div>Агенты</div>
|
||
<div class="cat-item"><div class="cat-dot" style="background:#cb4b16"></div>MCP-серверы</div>
|
||
<div class="cat-item"><div class="cat-dot" style="background:#dc322f"></div>Lefthook jobs</div>
|
||
<div class="cat-item"><div class="cat-dot" style="background:#586e75"></div>Memory files</div>
|
||
<div class="cat-item"><div class="cat-dot" style="background:#ff5f57; border: 1px dashed #ff5f57;"></div>— конфликт</div>
|
||
</div>
|
||
|
||
<script>
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 1: NODES
|
||
// ════════════════════════════════════════════════════
|
||
|
||
// Радиально-секторная компоновка.
|
||
// Сектора (по 90°): N=workflow (0–90), E=UI (90–180), S=infra (180–270), W=data/RLS (270–360).
|
||
const RADII = [0, 220, 400, 600, 800, 1000, 1180];
|
||
function pos(ring, angleDeg) {
|
||
const r = RADII[ring];
|
||
const a = angleDeg * Math.PI / 180;
|
||
return { x: Math.round(r * Math.cos(a)), y: Math.round(r * Math.sin(a)) };
|
||
}
|
||
|
||
const NODES = [
|
||
// ── ПРАВИЛА (4) ── центр + первое кольцо ───────
|
||
{ id: 'pravila', label: 'Pravila v1.13', group: 'rules', size: 38, ring: 0, ...pos(0, 0) },
|
||
{ id: 'claude_md', label: 'CLAUDE.md v1.92', group: 'rules', size: 34, ring: 1, ...pos(1, 30) },
|
||
{ id: 'psr_v1', label: 'PSR_v1 v2.1', group: 'rules', size: 32, ring: 1, ...pos(1, 150) },
|
||
{ id: 'tooling', label: 'Tooling v1.17', group: 'rules', size: 30, ring: 1, ...pos(1, 270) },
|
||
|
||
// ── ПЛАГИНЫ (5) ── второе кольцо ───────────────
|
||
{ id: 'superpowers', label: 'Superpowers v5.1', group: 'plugins', size: 30, ring: 2, ...pos(2, 45) },
|
||
{ id: 'fd_plugin', label: 'Frontend Design', group: 'plugins', size: 26, ring: 2, ...pos(2, 135) },
|
||
{ id: 'upm', label: 'UI UX Pro Max', group: 'plugins', size: 22, ring: 2, ...pos(2, 165) },
|
||
{ id: 'claude_md_mgmt', label: 'claude-md-mgmt', group: 'plugins', size: 22, ring: 2, ...pos(2, 225) },
|
||
{ id: 'hookify_plugin', label: 'hookify (плагин)', group: 'plugins', size: 22, ring: 2, ...pos(2, 200) },
|
||
|
||
// ── СКИЛЫ SUPERPOWERS (14) — N sector (0–90) ────
|
||
{ id: 'sk_brainstorm', label: 'brainstorming', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 5) },
|
||
{ id: 'sk_wplans', label: 'writing-plans', group: 'skills_sp', size: 20, ring: 3, ...pos(3, 11) },
|
||
{ id: 'sk_eplans', label: 'executing-plans', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 17) },
|
||
{ id: 'sk_subagent', label: 'subagent-driven', group: 'skills_sp', size: 20, ring: 3, ...pos(3, 23) },
|
||
{ id: 'sk_tdd', label: 'TDD', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 29) },
|
||
{ id: 'sk_verify', label: 'verification-before-completion', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 36) },
|
||
{ id: 'sk_debug', label: 'systematic-debugging', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 43) },
|
||
{ id: 'sk_parallel', label: 'parallel-work', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 50) },
|
||
{ id: 'sk_worktree', label: 'worktree', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 57) },
|
||
{ id: 'sk_pr', label: 'finishing-pr', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 64) },
|
||
{ id: 'sk_coderev', label: 'code-review', group: 'skills_sp', size: 16, ring: 3, ...pos(3, 71) },
|
||
{ id: 'sk_spreview', label: 'spec-review', group: 'skills_sp', size: 16, ring: 3, ...pos(3, 78) },
|
||
{ id: 'sk_wskills', label: 'writing-skills', group: 'skills_sp', size: 16, ring: 3, ...pos(3, 85) },
|
||
{ id: 'sk_elements', label: 'elements-of-style', group: 'skills_sp', size: 16, ring: 3, ...pos(3, 92) },
|
||
|
||
// ── СКИЛЫ ПРОЕКТА (2) — W sector (RLS) ─────────
|
||
{ id: 'sk_rls', label: 'rls-check', group: 'skills_proj', size: 20, ring: 3, ...pos(3, 305) },
|
||
{ id: 'sk_qitem', label: 'q-item-add', group: 'skills_proj', size: 20, ring: 3, ...pos(3, 220) },
|
||
|
||
// ── ХУКИ (5) — S+infra ────────────────────────
|
||
{ id: 'hk_session', label: 'SessionStart:\ncontext-inject', group: 'hooks', size: 24, ring: 4, ...pos(4, 100) },
|
||
{ id: 'hk_economy', label: 'UserPromptSubmit:\neconomy-mode', group: 'hooks', size: 22, ring: 4, ...pos(4, 95) },
|
||
{ id: 'hk_pre_claude', label: 'PreToolUse:\nCLAUDE.md-warn', group: 'hooks', size: 22, ring: 4, ...pos(4, 215) },
|
||
{ id: 'hk_post_md', label: 'PostToolUse:\nmarkdownlint', group: 'hooks', size: 20, ring: 4, ...pos(4, 195) },
|
||
{ id: 'hk_post_schema', label: 'PostToolUse:\nschema-changelog',group: 'hooks', size: 20, ring: 4, ...pos(4, 300) },
|
||
|
||
// ── АГЕНТЫ (11) — N (workflow) + W (RLS) ──────
|
||
{ id: 'ag_explore', label: 'Explore', group: 'agents', size: 20, ring: 4, ...pos(4, 10) },
|
||
{ id: 'ag_general', label: 'general-purpose', group: 'agents', size: 20, ring: 4, ...pos(4, 25) },
|
||
{ id: 'ag_plan', label: 'Plan', group: 'agents', size: 20, ring: 4, ...pos(4, 40) },
|
||
{ id: 'ag_pest', label: 'pest-parallel-debugger', group: 'agents', size: 24, ring: 4, ...pos(4, 55) },
|
||
{ id: 'ag_guide', label: 'claude-code-guide', group: 'agents', size: 18, ring: 4, ...pos(4, 70) },
|
||
{ id: 'ag_statusline', label: 'statusline-setup', group: 'agents', size: 18, ring: 4, ...pos(4, 85) },
|
||
{ id: 'ag_hookify', label: 'hookify:\nconversation-analyzer', group: 'agents', size: 18, ring: 4, ...pos(4, 230) },
|
||
{ id: 'ag_pcreator', label: 'plugin-dev:\nagent-creator', group: 'agents', size: 16, ring: 4, ...pos(4, 245) },
|
||
{ id: 'ag_pvalid', label: 'plugin-dev:\nplugin-validator',group: 'agents', size: 16, ring: 4, ...pos(4, 260) },
|
||
{ id: 'ag_skreview', label: 'plugin-dev:\nskill-reviewer', group: 'agents', size: 16, ring: 4, ...pos(4, 275) },
|
||
{ id: 'ag_rls', label: 'rls-reviewer', group: 'agents', size: 22, ring: 4, ...pos(4, 315) },
|
||
|
||
// ── MCP-СЕРВЕРЫ (7) — E (UI) + W (data) ───────
|
||
{ id: 'mcp_21st', label: 'MCP: 21st.dev Magic', group: 'mcp', size: 20, ring: 5, ...pos(5, 130) },
|
||
{ id: 'mcp_pw', label: 'MCP: playwright', group: 'mcp', size: 22, ring: 5, ...pos(5, 110) },
|
||
{ id: 'mcp_gh', label: 'MCP: github', group: 'mcp', size: 22, ring: 5, ...pos(5, 75) },
|
||
{ id: 'mcp_boost', label: 'MCP: laravel-boost', group: 'mcp', size: 24, ring: 5, ...pos(5, 290) },
|
||
{ id: 'mcp_redis', label: 'MCP: redis', group: 'mcp', size: 22, ring: 5, ...pos(5, 310) },
|
||
{ id: 'mcp_sentry', label: 'MCP: sentry', group: 'mcp', size: 22, ring: 5, ...pos(5, 330) },
|
||
{ id: 'mcp_semgrep', label: 'MCP: semgrep', group: 'mcp', size: 20, ring: 5, ...pos(5, 350) },
|
||
|
||
// ── LEFTHOOK JOBS (10) — S+W (infra/data) ─────
|
||
{ id: 'lh_mdlint', label: 'lefthook:\nmarkdownlint', group: 'lefthook', size: 18, ring: 5, ...pos(5, 185) },
|
||
{ id: 'lh_cspell', label: 'lefthook:\ncspell', group: 'lefthook', size: 18, ring: 5, ...pos(5, 200) },
|
||
{ id: 'lh_stylelint', label: 'lefthook:\nstylelint', group: 'lefthook', size: 16, ring: 5, ...pos(5, 215) },
|
||
{ id: 'lh_eslint', label: 'lefthook:\neslint-vue', group: 'lefthook', size: 18, ring: 5, ...pos(5, 230) },
|
||
{ id: 'lh_lychee', label: 'lefthook:\nlychee-links', group: 'lefthook', size: 18, ring: 5, ...pos(5, 245) },
|
||
{ id: 'lh_gitleaks', label: 'lefthook:\ngitleaks', group: 'lefthook', size: 18, ring: 5, ...pos(5, 260) },
|
||
{ id: 'lh_gitleaks2', label: 'lefthook:\ngitleaks pre-push', group: 'lefthook', size: 18, ring: 5, ...pos(5, 275) },
|
||
{ id: 'lh_pint', label: 'lefthook:\npint', group: 'lefthook', size: 18, ring: 5, ...pos(5, 25) },
|
||
{ id: 'lh_larastan', label: 'lefthook:\nlarastan', group: 'lefthook', size: 18, ring: 5, ...pos(5, 50) },
|
||
{ id: 'lh_squawk', label: 'lefthook:\nsquawk', group: 'lefthook', size: 18, ring: 5, ...pos(5, 320) },
|
||
|
||
// ── MEMORY FILES (15) — внешнее кольцо ──────────
|
||
{ id: 'mem_user', label: 'memory:\nuser_profile', group: 'memory', size: 16, ring: 6, ...pos(6, 0) },
|
||
{ id: 'mem_comm', label: 'memory:\nfeedback_comm', group: 'memory', size: 14, ring: 6, ...pos(6, 24) },
|
||
{ id: 'mem_env', label: 'memory:\nfeedback_env', group: 'memory', size: 16, ring: 6, ...pos(6, 48) },
|
||
{ id: 'mem_sp', label: 'memory:\nfeedback_superpowers',group: 'memory', size: 16, ring: 6, ...pos(6, 72) },
|
||
{ id: 'mem_plugins', label: 'memory:\nfeedback_plugins', group: 'memory', size: 16, ring: 6, ...pos(6, 96) },
|
||
{ id: 'mem_handoff', label: 'memory:\nreference_handoff', group: 'memory', size: 14, ring: 6, ...pos(6, 120) },
|
||
{ id: 'mem_redesign', label: 'memory:\nportal_redesign', group: 'memory', size: 14, ring: 6, ...pos(6, 144) },
|
||
{ id: 'mem_devindices', label: 'memory:\ndev_indices', group: 'memory', size: 12, ring: 6, ...pos(6, 168) },
|
||
{ id: 'mem_phase1', label: 'memory:\nphase1_strategy', group: 'memory', size: 14, ring: 6, ...pos(6, 192) },
|
||
{ id: 'mem_state', label: 'memory:\nproject_state', group: 'memory', size: 16, ring: 6, ...pos(6, 216) },
|
||
{ id: 'mem_brain', label: 'memory:\nclaude_brain', group: 'memory', size: 14, ring: 6, ...pos(6, 240) },
|
||
{ id: 'mem_supplier', label: 'memory:\nsupplier_integration',group: 'memory', size: 14, ring: 6, ...pos(6, 264) },
|
||
{ id: 'mem_audit', label: 'memory:\naudit_2026-05-13', group: 'memory', size: 14, ring: 6, ...pos(6, 288) },
|
||
{ id: 'mem_archive', label: 'memory:\nreference_archive', group: 'memory', size: 14, ring: 6, ...pos(6, 312) },
|
||
{ id: 'mem_github', label: 'memory:\nreference_github', group: 'memory', size: 14, ring: 6, ...pos(6, 336) },
|
||
];
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 2: EDGES
|
||
// ════════════════════════════════════════════════════
|
||
const E = (from, to, label) => ({
|
||
from, to,
|
||
title: label,
|
||
color: { color: '#586e75', highlight: '#93a1a1', hover: '#93a1a1' },
|
||
arrows: { to: { enabled: true, scaleFactor: 0.6 } },
|
||
smooth: { type: 'continuous', roundness: 0.5 }
|
||
});
|
||
const CONFLICT = (from, to, label) => ({
|
||
from, to,
|
||
title: label,
|
||
label: '⚡',
|
||
dashes: true,
|
||
width: 2,
|
||
color: { color: '#ff5f57', highlight: '#ff8880', hover: '#ff8880' },
|
||
arrows: { to: { enabled: true, scaleFactor: 0.7 }, from: { enabled: true, scaleFactor: 0.7 } },
|
||
font: { color: '#ff5f57', size: 14, align: 'middle', strokeWidth: 3, strokeColor: '#1e1e2e' },
|
||
smooth: { type: 'curvedCW', roundness: 0.35 }
|
||
});
|
||
|
||
const EDGES = [
|
||
// ── ПРАВИЛА — иерархия ──────────────────────────
|
||
E('pravila', 'claude_md', 'подчиняет\n(уровень 1→2a)'),
|
||
E('pravila', 'psr_v1', 'подчиняет\n(уровень 1→3)'),
|
||
E('claude_md', 'tooling', 'ссылается\nна реестр'),
|
||
E('pravila', 'superpowers', '§12: обязывает\nинвокировать 1-м'),
|
||
|
||
// ── PSR_v1 координирует плагины ─────────────────
|
||
E('psr_v1', 'superpowers', 'R5: координирует\nпарный стек'),
|
||
E('psr_v1', 'fd_plugin', 'R5: координирует\nпарный стек'),
|
||
E('psr_v1', 'upm', 'R14.3: активирует\nтолько через pipeline'),
|
||
E('psr_v1', 'mcp_21st', 'R14.4: активирует\nтолько через pipeline'),
|
||
E('psr_v1', 'claude_md_mgmt','R10.1 блок 1:\nинфраструктурный'),
|
||
|
||
// ── CLAUDE.md ────────────────────────────────────
|
||
E('claude_md', 'mcp_boost', 'описывает §3.2'),
|
||
E('claude_md', 'mcp_sentry', 'описывает §4.8'),
|
||
E('claude_md', 'mcp_redis', 'описывает §4.9'),
|
||
E('claude_md', 'claude_md_mgmt', '§5п.10:\nединственный канал'),
|
||
E('claude_md', 'ag_pest', 'описывает\nкогда вызывать'),
|
||
E('claude_md', 'ag_rls', 'описывает\nкогда вызывать'),
|
||
|
||
// ── ХУКИ ────────────────────────────────────────
|
||
E('hk_pre_claude', 'claude_md', 'проверяет\nпри Edit/Write'),
|
||
E('hk_post_md', 'lh_mdlint', 'дублирует задачу\n(локально)'),
|
||
E('hk_post_schema', 'claude_md', 'напоминает про\nCHANGELOG_schema'),
|
||
E('hk_session', 'mem_user', 'читает\nпри старте'),
|
||
E('hk_session', 'mem_env', 'читает\nпри старте'),
|
||
E('hk_session', 'mem_sp', 'читает\nпри старте'),
|
||
E('hk_session', 'mem_plugins', 'читает\nпри старте'),
|
||
E('hk_session', 'mem_state', 'читает\nпри старте'),
|
||
E('hk_economy', 'superpowers', 'парсит уровень\nэкономии'),
|
||
|
||
// ── SUPERPOWERS содержит скилы ──────────────────
|
||
E('superpowers', 'sk_brainstorm', 'содержит'),
|
||
E('superpowers', 'sk_tdd', 'содержит'),
|
||
E('superpowers', 'sk_debug', 'содержит'),
|
||
E('superpowers', 'sk_wplans', 'содержит'),
|
||
E('superpowers', 'sk_eplans', 'содержит'),
|
||
E('superpowers', 'sk_verify', 'содержит'),
|
||
E('superpowers', 'sk_parallel', 'содержит'),
|
||
E('superpowers', 'sk_worktree', 'содержит'),
|
||
E('superpowers', 'sk_pr', 'содержит'),
|
||
E('superpowers', 'sk_subagent', 'содержит'),
|
||
E('superpowers', 'sk_wskills', 'содержит'),
|
||
E('superpowers', 'sk_spreview', 'содержит'),
|
||
E('superpowers', 'sk_coderev', 'содержит'),
|
||
E('superpowers', 'sk_elements', 'содержит'),
|
||
|
||
// ── СКИЛЫ вызывают друг друга ───────────────────
|
||
E('sk_brainstorm', 'sk_wplans', 'вызывает\nпосле дизайна'),
|
||
E('sk_wplans', 'sk_eplans', 'вызывает\nдля выполнения'),
|
||
E('sk_wplans', 'sk_subagent','альтернатива\nexecuting-plans'),
|
||
E('sk_subagent', 'ag_explore', 'запускает\nдля поиска'),
|
||
E('sk_subagent', 'ag_general', 'запускает\nдля задач'),
|
||
E('sk_subagent', 'ag_plan', 'запускает\nдля архитектуры'),
|
||
E('sk_parallel', 'sk_worktree','использует\nдля изоляции'),
|
||
|
||
// ── СКИЛЫ ПРОЕКТА ───────────────────────────────
|
||
E('sk_rls', 'tooling', 'использует\nsquawk + grep §3.2'),
|
||
E('sk_rls', 'mcp_boost', 'SQL запросы\nк схеме'),
|
||
E('sk_qitem', 'claude_md_mgmt','делегирует\nправку CLAUDE.md'),
|
||
|
||
// ── CLAUDE-MD-MGMT ──────────────────────────────
|
||
E('claude_md_mgmt', 'claude_md', 'единственный\nканал правок'),
|
||
|
||
// ── HOOKIFY ─────────────────────────────────────
|
||
E('ag_hookify', 'hookify_plugin', 'передаёт\nанализ'),
|
||
E('hookify_plugin', 'hk_pre_claude', 'может создавать\nновые хуки'),
|
||
E('hookify_plugin', 'hk_economy', 'может создавать\nновые хуки'),
|
||
|
||
// ── АГЕНТЫ используют MCP ───────────────────────
|
||
E('ag_pest', 'mcp_redis', 'читает\nочереди/кэш'),
|
||
E('ag_rls', 'mcp_boost', 'SQL запросы\nк БД'),
|
||
E('ag_guide', 'mcp_gh', 'ищет\nв репозитории'),
|
||
|
||
// ── LEFTHOOK вызывается git ──────────────────────
|
||
E('lh_gitleaks', 'mem_plugins', 'блокирует коммит\nпри ПДн в staged'),
|
||
E('lh_larastan', 'mcp_boost', 'Boost даёт\nконтекст типов'),
|
||
E('lh_squawk', 'tooling', 'соответствует\n§3.2 #15'),
|
||
E('lh_gitleaks2', 'lh_gitleaks', 'строже:\nвся история'),
|
||
E('lh_lychee', 'claude_md', 'проверяет\nссылки в .md'),
|
||
|
||
// ── MEMORY читается Claude ──────────────────────
|
||
E('mem_env', 'ag_pest', 'квирки 72/77\nиспользует агент'),
|
||
E('mem_plugins', 'psr_v1', 'отражает\nтекущие версии'),
|
||
E('mem_archive', 'claude_md', 'синхронизирует\nверсии доков'),
|
||
|
||
// ── MCP ─────────────────────────────────────────
|
||
E('mcp_pw', 'hk_session', 'используется\nдля a11y smoke'),
|
||
E('mcp_gh', 'sk_pr', 'PR, issues\nпри finishing-pr'),
|
||
E('mcp_boost', 'ag_rls', 'схема БД\nдля RLS-review'),
|
||
|
||
// ══════════════════════════════════════════════════
|
||
// КОНФЛИКТЫ (красные пунктирные рёбра)
|
||
// ══════════════════════════════════════════════════
|
||
CONFLICT('psr_v1', 'claude_md', '⚡ T2.2'),
|
||
CONFLICT('upm', 'fd_plugin', '⚡ R14.5'),
|
||
CONFLICT('mcp_21st', 'fd_plugin', '⚡ R14.5'),
|
||
CONFLICT('sk_rls', 'ag_rls', '⚡ перекрытие RLS'),
|
||
CONFLICT('hookify_plugin','hk_pre_claude', '⚡ может затенить'),
|
||
CONFLICT('hk_economy', 'superpowers', '⚡ §12 vs Economy'),
|
||
];
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 3: NODE DETAILS
|
||
// ════════════════════════════════════════════════════
|
||
const CATEGORY_LABELS = {
|
||
rules: 'Правило', plugins: 'Плагин', skills_sp: 'Скил Superpowers',
|
||
skills_proj: 'Скил проекта', hooks: 'Хук .claude', agents: 'Агент',
|
||
mcp: 'MCP-сервер', lefthook: 'Lefthook job', memory: 'Memory-файл'
|
||
};
|
||
|
||
function nd(desc, when, limits, reportsTo, manages, together, conflicts) {
|
||
// Backward-compat: old 5-arg signature was nd(desc, reportsTo, manages, together, conflicts).
|
||
// If 2nd arg is an array, treat as old-style call and shift args.
|
||
if (Array.isArray(when)) {
|
||
return {
|
||
desc,
|
||
when: '',
|
||
limits: '',
|
||
reportsTo: when,
|
||
manages: limits,
|
||
together: reportsTo,
|
||
conflicts: (manages || []),
|
||
};
|
||
}
|
||
return { desc, when: when || '', limits: limits || '', reportsTo, manages, together, conflicts: conflicts || [] };
|
||
}
|
||
|
||
const NODE_DETAILS = {
|
||
// ── ПРАВИЛА ──────────────────────────────────────
|
||
pravila: nd(
|
||
'Главный свод правил работы Клода — кто чем командует, что запрещено, какие обязательные действия.',
|
||
'Действует всегда — Клод читает его при старте каждой сессии.',
|
||
'Правило §12 (обязательные скилы) нельзя отменить — даже режимом экономии или просьбой «не используй сейчас». Расходимость с другими документами — нарушение §7.',
|
||
[],
|
||
[
|
||
{ name: 'CLAUDE.md', cond: 'подчинён, уровень 2a в цепочке приоритетов' },
|
||
{ name: 'PSR_v1', cond: 'подчинён, уровень 3 в цепочке приоритетов' },
|
||
{ name: 'Superpowers', cond: '§12 обязывает запускать скил первым' },
|
||
{ name: 'Все компоненты', cond: 'через цепочку приоритетов §1' }
|
||
],
|
||
[{ name: 'CLAUDE.md', cond: 'оба читаются при старте сессии' }]
|
||
),
|
||
claude_md: nd(
|
||
'Оперативная карта проекта — список технологий, команд, фаз, ссылок на документы.',
|
||
'Читается при старте каждой сессии; обновляется при новом инструменте или новой фазе.',
|
||
'Править можно только через скил `/claude-md-management:claude-md-improver` или `:revise-claude-md` (правило §5 п.10). Прямые Edit/Write блокируются хуком предупреждения.',
|
||
[{ name: 'Pravila', cond: 'всегда подчинён (уровень 2a)' }],
|
||
[
|
||
{ name: 'Tooling v1.17', cond: 'ссылается как на реестр инструментов' },
|
||
{ name: 'claude-md-mgmt', cond: 'правило §5 п.10 — единственный канал правок' }
|
||
],
|
||
[
|
||
{ name: 'Pravila', cond: 'оба читаются при старте сессии' },
|
||
{ name: 'Tooling', cond: 'оба — оперативные карты уровня 2' }
|
||
],
|
||
[{ name: 'PSR_v1', desc: 'Правило §5 п.10 запрещает прямые правки, но PSR_v1 это явно не повторяет — есть риск Edit без скила' }]
|
||
),
|
||
psr_v1: nd(
|
||
'Правила совместной работы плагинов — кто с кем работает, какая процедура обязательна.',
|
||
'При выборе UI-инструмента (FD против UPM против 21st), при координации парных плагинов, при включении off-phase MCP.',
|
||
'Обязательное правило R14.5: UPM, 21st, FD — нельзя одновременно. Обязательное правило R6.0 (фильтр стека) и R6.1 (палитра Forest) — нужно соблюдать при UI-выводе плагинов.',
|
||
[{ name: 'Pravila', cond: 'подчинён, уровень 3 в цепочке' }],
|
||
[
|
||
{ name: 'Superpowers + Frontend Design', cond: 'координирует как пару плагинов' },
|
||
{ name: 'UI UX Pro Max', cond: 'R14.3: включается только через процедуру' },
|
||
{ name: '21st Magic MCP', cond: 'R14.4: включается только через процедуру' }
|
||
],
|
||
[{ name: 'CLAUDE.md', cond: 'обе — оперативные карты, правятся согласованно' }],
|
||
[{ name: 'CLAUDE.md', desc: 'CLAUDE.md §5 п.10 требует править только через скил claude-md-mgmt, а PSR_v1 это ограничение не повторяет — риск прямых Edit' }]
|
||
),
|
||
tooling: nd(
|
||
'Реестр 35 инструментов — когда что использовать, команды установки, конфликты.',
|
||
'При выборе инструмента для фазы (0/1/2/3), при добавлении нового инструмента, при обновлении версий.',
|
||
'При прямом конфликте с CLAUDE.md побеждает CLAUDE.md (оперативная карта уровня 2a). Любая правка требует синхронизации с CLAUDE.md §3.',
|
||
[
|
||
{ name: 'Pravila', cond: 'уровень 2b — оперативная карта рядом с CLAUDE.md' },
|
||
{ name: 'CLAUDE.md', cond: 'при прямом конфликте побеждает CLAUDE.md' }
|
||
],
|
||
[],
|
||
[{ name: 'CLAUDE.md', cond: 'обе — оперативные карты, правятся синхронно' }]
|
||
),
|
||
|
||
// ── ПЛАГИНЫ ──────────────────────────────────────
|
||
superpowers: nd(
|
||
'Плагин поведения Клода — 14 скилов для тестов, отладки, планирования, параллельной работы.',
|
||
'При творческих, отладочных, тестовых и многошаговых задачах: brainstorm / TDD / debug / verify / writing-plans / parallel-work / work-tree / finishing-PR / subagent / writing-skills (карта типов в §12.2 Pravila).',
|
||
'Обязательное правило §12: единственная отмена — явная просьба заказчика «не используй superpowers сейчас» на текущее действие. Раздел §9 «Отступления» к §12 не применяется.',
|
||
[
|
||
{ name: 'Pravila §12', cond: 'обязательное правило: скил запускается первым' },
|
||
{ name: 'PSR_v1', cond: 'координирует как пару с Frontend Design' }
|
||
],
|
||
[{ name: 'Все 14 Superpowers-скилов', cond: 'содержит' }],
|
||
[{ name: 'Frontend Design', cond: 'пара — работают вместе при UI-задачах' }],
|
||
[{ name: 'economy-mode хук', desc: 'Режим экономии 100% теоретически может «сэкономить» запуск скила и нарушить обязательное правило §12 (§12 нельзя отменить)' }]
|
||
),
|
||
fd_plugin: nd(
|
||
'Плагин знаний о UI — Vue, Vuetify, доступность, паттерны компонентов для Лидерры.',
|
||
'При UI/UX задачах — компоненты, экраны, паттерны взаимодействия; в паре с Superpowers (процесс).',
|
||
'Фильтр стека R6.0: срезать React/Tailwind/shadcn/JSX в Vue 3 + Vuetify 3. Обязательное правило палитры Forest R6.1 для цветов, шрифтов и иконок.',
|
||
[{ name: 'PSR_v1', cond: 'R5: подчинён как часть пары плагинов' }],
|
||
[],
|
||
[{ name: 'Superpowers', cond: 'пара — FD даёт UI-знания, Superpowers даёт процесс' }],
|
||
[
|
||
{ name: 'UI UX Pro Max', desc: 'Правило PSR_v1 R14.5: нельзя одновременно — оба включены в настройках, но должны чередоваться' },
|
||
{ name: '21st Magic MCP', desc: 'Правило PSR_v1 R14.5: нельзя одновременно с FD — оба потенциально доступны' }
|
||
]
|
||
),
|
||
upm: nd(
|
||
'Резервная библиотека UI — 50+ стилей, 161 палитра, 99 правил-подсказок UX. Только по процедуре.',
|
||
'Только по процедуре PSR_v1 R14.3: запасной вариант к FD ИЛИ «третий вариант» в архитектурном решении.',
|
||
'R14.5: нельзя одновременно с FD/21st. Фильтр стека R6.0 и обязательное правило палитры Forest R6.1 — обязательны. Проверка доступности Pa11y перед выкаткой.',
|
||
[{ name: 'PSR_v1', cond: 'R14.3: включается только через процедуру, не сам по себе' }],
|
||
[],
|
||
[],
|
||
[{ name: 'Frontend Design', desc: 'Правило PSR_v1 R14.5: нельзя одновременно — UPM как материал, FD как решатель; риск смешать роли' }]
|
||
),
|
||
claude_md_mgmt: nd(
|
||
'Единственный разрешённый способ править CLAUDE.md — через скил claude-md-improver или revise-claude-md.',
|
||
'При любой правке CLAUDE.md (новая фаза, новый инструмент, смена версии, новые особенности — всё через скил).',
|
||
'Правило PSR_v1 R10.1 блок 1 (инфраструктурная категория). Внутри процедуры продолжают действовать §4 правил Клода (синхронизация Pravila + Tooling).',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 Блок 1: инфраструктурная категория' }],
|
||
[{ name: 'CLAUDE.md', cond: 'правило §5 п.10: единственный канал правок' }],
|
||
[{ name: 'q-item-add скил', cond: 'скил делегирует правки CLAUDE.md через этот плагин' }]
|
||
),
|
||
hookify_plugin: nd(
|
||
'Плагин создания хуков — анализирует разговоры и предлагает новые автоматизации в виде хуков.',
|
||
'При запросе «давай повесим хук на это поведение» или после серии повторяющихся ошибок — анализ через агента conversation-analyzer.',
|
||
'Правило PSR_v1 R10.1. Новые хуки могут конфликтовать с существующими (см. конфликты ниже) — обязательная проверка файла настроек до создания.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1: формализован' }],
|
||
[{ name: 'hookify:conversation-analyzer агент', cond: 'запускает анализ разговоров' }],
|
||
[{ name: 'hookify:conversation-analyzer', cond: 'плагин и агент работают в паре' }],
|
||
[
|
||
{ name: 'PreToolUse:CLAUDE.md-warn', desc: 'hookify создаёт новые PreToolUse-хуки на лету — может перезаписать или конкурировать с этим хуком' },
|
||
{ name: 'economy-mode хук', desc: 'новые хуки от hookify могут конфликтовать с логикой парсера режима экономии' }
|
||
]
|
||
),
|
||
|
||
// ── СКИЛЫ SUPERPOWERS ────────────────────────────
|
||
sk_brainstorm: nd(
|
||
'Продумывает задачу вместе с заказчиком, формулирует варианты A/B/C и согласует дизайн до написания кода.',
|
||
'При творческой задаче — новая фича, непростой рефакторинг, дизайн-решение; ДО любого кода или плана.',
|
||
'Обязательно явное «Approved» от заказчика до перехода к writing-plans. Запрет: нельзя запускать скилы реализации до утверждения дизайна.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }, { name: 'Pravila §12', cond: 'обязательное правило (см. §12) для творческих задач' }],
|
||
[],
|
||
[{ name: 'writing-plans', cond: 'вызывается сразу после brainstorming для создания плана' }]
|
||
),
|
||
sk_tdd: nd(
|
||
'Ведёт разработку через написание падающего теста до кода: сначала RED (тест провален), потом GREEN (тест проходит).',
|
||
'При любом новом боевом коде — backend (Pest) и frontend (Vitest).',
|
||
'Падающий тест пишется ДО реализации; формулировка «код должен работать» без проверенного теста — нарушение правила §12.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }, { name: 'Pravila §12', cond: 'обязательное правило (см. §12) для любого нового кода' }],
|
||
[],
|
||
[{ name: 'executing-plans', cond: 'TDD встроен в каждый шаг плана выполнения' }]
|
||
),
|
||
sk_debug: nd(
|
||
'Системная отладка: минимум 3 гипотезы, опровержение каждой реальной проверкой до того, как править код — никаких «должно работать».',
|
||
'При неожиданном поведении, падении теста, ошибке во время работы, неожиданном выводе.',
|
||
'Минимум 3 гипотезы. Опровержение через реальные команды и тесты, а не «логика подсказывает». Никаких «попробую исправить» без подтверждённой причины.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }, { name: 'Pravila §12', cond: 'обязательное правило (см. §12) при неожиданном поведении' }],
|
||
[],
|
||
[{ name: 'MCP: redis', cond: 'используется для отладки Redis-очередей' }]
|
||
),
|
||
sk_wplans: nd(
|
||
'Создаёт детальный план реализации с полным кодом, командами и шагами по 2-5 минут.',
|
||
'После brainstorming (творческая задача) или сразу для многошаговой (≥3 шагов) технической задачи.',
|
||
'Никаких заглушек (TBD, TODO, «add validation»). Каждый шаг — реальный код или команда. Покрытие спецификации обязательно.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }, { name: 'Pravila §12', cond: 'обязательное правило (см. §12) для многошаговых задач (≥3 шагов)' }],
|
||
[],
|
||
[{ name: 'executing-plans или subagent-driven', cond: 'план передаётся в один из них для выполнения' }]
|
||
),
|
||
sk_eplans: nd(
|
||
'Выполняет готовый план шаг за шагом, отмечает чекбоксы, делает коммиты после каждого шага.',
|
||
'После writing-plans (если выбрано выполнение в текущей сессии); альтернатива — subagent-driven в той же сессии.',
|
||
'Каждый шаг отмечается галочкой, коммиты не объединяются — атомарно по одному за шаг (Pravila §4.2).',
|
||
[{ name: 'Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'writing-plans', cond: 'получает план от writing-plans' }, { name: 'subagent-driven', cond: 'альтернатива — зависит от выбора пользователя' }]
|
||
),
|
||
sk_verify: nd(
|
||
'Обязательная проверка перед заявлением «готово»: запускает тесты, видит реальный вывод, никаких предположений.',
|
||
'Перед любым заявлением «готово»/«passed»/«closed»/«merged» — обязательно (правило §12 + экономия 0% как жёсткое требование).',
|
||
'Реальный запуск, не «должно пройти». Вывод тестов виден полностью. Выборочные результаты запрещены («tests pass» = ровно столько, сколько действительно прошло).',
|
||
[{ name: 'Superpowers', cond: 'содержит' }, { name: 'Pravila §12', cond: 'обязательное правило (см. §12) перед любым заявлением «готово»' }],
|
||
[],
|
||
[{ name: 'MCP: laravel-boost', cond: 'запросы к БД для проверки данных' }]
|
||
),
|
||
sk_parallel: nd(
|
||
'Разбивает независимые задачи на параллельные потоки с изоляцией через git worktrees (отдельные рабочие копии репозитория).',
|
||
'При нескольких независимых рабочих фронтах одновременно (CTO-задача + Plan-задача + audit-fix).',
|
||
'Изоляция через worktree обязательна — никакого «работаю в одной директории на 3 ветках сразу». Иначе риск конфликта файлов и веток.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'worktree скил', cond: 'parallel-work использует worktree для изоляции' }]
|
||
),
|
||
sk_worktree: nd(
|
||
'Создаёт изолированную копию репозитория (worktree) для рискованной или параллельной работы.',
|
||
'При параллельной работе нескольких задач или при рискованной работе (рефакторинг с возможным откатом, ветка экспериментов).',
|
||
'Очистка через ExitWorktree обязательна. Не оставлять забытые worktree — захламляют файловую систему.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'parallel-work', cond: 'worktree — инструмент для parallel-work' }]
|
||
),
|
||
sk_pr: nd(
|
||
'Чеклист финальной готовности PR: тесты, документация, чистота кода, проверки перед push.',
|
||
'Перед `gh pr create` или `git push` в общую ветку — обязательная проверка готовности.',
|
||
'Проверки перед push (gitleaks по всей истории + lychee) — не обходить через `--no-verify`. Pravila §4.2.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'MCP: github', cond: 'создаёт PR через GitHub MCP' }, { name: 'lefthook pre-push', cond: 'запускает gitleaks + lychee' }]
|
||
),
|
||
sk_subagent: nd(
|
||
'Запускает суб-агентов для крупных задач — каждый в отдельном контексте без накопленного шума.',
|
||
'При выполнении плана в той же сессии ИЛИ при делегировании поиска/анализа большого объёма.',
|
||
'Суб-агент в режиме экономии 0%: запрашивать полный сырой вывод, а не сводку — решения принимать самому.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }],
|
||
[
|
||
{ name: 'Explore агент', cond: 'запускает для поиска по кодовой базе' },
|
||
{ name: 'general-purpose агент', cond: 'запускает для сложных задач' },
|
||
{ name: 'Plan агент', cond: 'запускает для архитектурного планирования' }
|
||
],
|
||
[{ name: 'writing-plans', cond: 'subagent-driven — основной способ выполнения планов' }]
|
||
),
|
||
sk_wskills: nd(
|
||
'Создаёт новые скилы по стандартному шаблону: файл SKILL.md, заголовочный блок (frontmatter), описание процесса.',
|
||
'При формализации повторяющегося процесса в переиспользуемый скил (после 2-3 примеров одинаковой работы).',
|
||
'Шаблон SKILL.md, заголовочный блок (name, description, when_to_use, allowed-tools), описание процесса с DOT-диаграммой.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'plugin-dev:skill-reviewer', cond: 'агент проверяет созданный скил' }]
|
||
),
|
||
sk_spreview: nd(
|
||
'Проверяет документ-спецификацию на полноту, противоречия, заглушки и объём работ.',
|
||
'После writing-plans на отдельном этапе ДО реализации — для крупных планов с несколькими задачами.',
|
||
'Самопроверка прямо в brainstorming достаточна для небольшой спецификации; для крупных — отдельный запуск этого скила.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'brainstorming', cond: 'spec-review вызывается в конце brainstorming после записи спека' }]
|
||
),
|
||
sk_coderev: nd(
|
||
'Систематический разбор кода — безопасность, тесты, архитектура, соответствие правилам.',
|
||
'Перед merge PR; после крупной серии коммитов; при подготовке к релизу; при подозрении на регрессию.',
|
||
'Без выборочности: разбор всех изменений, а не только подозрительных. SAST (статический анализ кода на уязвимости, Semgrep) включается обязательно.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'MCP: semgrep', cond: 'SAST-проверка при code review' }]
|
||
),
|
||
sk_elements: nd(
|
||
'Улучшает написание текстов и документации — ясность, лаконичность, без воды.',
|
||
'При написании спецификации/плана/CHANGELOG/описания PR — для общения с командой.',
|
||
'Без воды. Без «легко», «просто», «всего лишь». Каждое утверждение измеримо.',
|
||
[{ name: 'Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[]
|
||
),
|
||
|
||
// ── СКИЛЫ ПРОЕКТА ────────────────────────────────
|
||
sk_rls: nd(
|
||
'7-шаговый чеклист RLS (защита строк по тенанту) для новой таблицы: tenant_id, ENABLE RLS (включение защиты), политики, права для 5 ролей, CHANGELOG, squawk, smoke-тест.',
|
||
'При создании новой таблицы в db/schema.sql ИЛИ при правках существующих политик RLS.',
|
||
'Права для 5 ролей обязательны (crm_app_user / crm_app_admin / crm_supplier_worker BYPASSRLS (право обходить RLS — для системных задач) / crm_readonly / crm_migrator). Запись в CHANGELOG_schema.md обязательна.',
|
||
[{ name: 'Tooling §3.2', cond: 'использует squawk (#15) и команды grep' }],
|
||
[],
|
||
[{ name: 'MCP: laravel-boost', cond: 'SQL запросы к schema.sql для проверки' }],
|
||
[{ name: 'rls-reviewer агент', desc: 'оба проверяют соответствие политик RLS — скил для ручной проверки таблицы, агент для разбора PR/diff; нет чёткой границы когда какой' }]
|
||
),
|
||
sk_qitem: nd(
|
||
'Добавляет новый открытый вопрос в реестр Открытые_вопросы_v8_3.md с обновлением счётчиков §0 и версии.',
|
||
'При появлении нового открытого вопроса (Биз-/CTO-/Ю-/Диз-/DO-/OPEN-) — формальная запись в реестр.',
|
||
'Категория (Биз-/CTO-/...) обязательна. Связанные документы (CLAUDE.md/Pravila/PSR_v1/Tooling) — синхронизируются.',
|
||
[],
|
||
[],
|
||
[{ name: 'claude-md-mgmt', cond: 'скил делегирует правку CLAUDE.md через плагин (правило §5п.10 в нормативке)' }]
|
||
),
|
||
|
||
// ── ХУКИ ─────────────────────────────────────────
|
||
hk_pre_claude: nd(
|
||
'Блокирует прямое редактирование CLAUDE.md — срабатывает на Edit/Write по этому файлу.',
|
||
'PreToolUse — перед каждым вызовом Edit/Write, фильтр путей нацелен на CLAUDE.md.',
|
||
'Обход запрещён. Единственный способ редактировать — скил claude-md-mgmt (правило §5п.10 в нормативке).',
|
||
[{ name: '.claude/settings.json', cond: 'описан как хук PreToolUse' }],
|
||
[],
|
||
[],
|
||
[{ name: 'hookify (плагин)', desc: 'hookify динамически создаёт новые хуки PreToolUse — может перезаписать или конкурировать с этим хуком' }]
|
||
),
|
||
hk_post_md: nd(
|
||
'После каждого Edit .md-файла запускает markdownlint --fix автоматически.',
|
||
'PostToolUse — после Edit/Write на *.md (кроме корневого CLAUDE.md, чтобы не зациклить).',
|
||
'Не правит CLAUDE.md (исключён из фильтра путей). При неисправимой ошибке (например, битая ссылка) — предупреждение, не блокировка.',
|
||
[{ name: '.claude/settings.json', cond: 'описан как хук PostToolUse' }],
|
||
[],
|
||
[{ name: 'lefthook:markdownlint', cond: 'дублируют задачу: хук — в сессии, lefthook — при коммите' }]
|
||
),
|
||
hk_post_schema: nd(
|
||
'После правки db/schema.sql напоминает обновить db/CHANGELOG_schema.md.',
|
||
'PostToolUse — после Edit/Write на `db/schema.sql`.',
|
||
'Напоминание, не блокировка. Дисциплина ведения CHANGELOG_schema — на разработчике (§4.2 Pravila).',
|
||
[{ name: '.claude/settings.json', cond: 'описан как хук PostToolUse' }],
|
||
[],
|
||
[{ name: 'lefthook:squawk', cond: 'оба реагируют на изменения SQL' }]
|
||
),
|
||
hk_session: nd(
|
||
'При старте каждой сессии подгружает CLAUDE.md, Pravila и ключевые memory-файлы в контекст.',
|
||
'SessionStart — единожды при инициализации сессии Claude Code.',
|
||
'Список memory-файлов фиксированный — для расширения править настройку хука. Не читает 80+ квирков целиком — выборочно по релевантности.',
|
||
[{ name: '.claude/settings.json', cond: 'описан как хук SessionStart' }],
|
||
[
|
||
{ name: 'memory:user_profile', cond: 'читает' },
|
||
{ name: 'memory:feedback_env', cond: 'читает' },
|
||
{ name: 'memory:project_state', cond: 'читает' },
|
||
{ name: 'memory:feedback_superpowers', cond: 'читает' },
|
||
{ name: 'memory:feedback_plugins', cond: 'читает' }
|
||
],
|
||
[]
|
||
),
|
||
hk_economy: nd(
|
||
'Перед каждым промптом разбирает «экономия X%» и выставляет режим строгости (0% = максимальное качество, 100% = по умолчанию).',
|
||
'UserPromptSubmit — перед каждым промптом пользователя; ищет шаблон /экономия\\s*(\\d+)%/.',
|
||
'Правило §12 **НЕ** отменяется этим режимом ни на каком уровне. Действует только на текущую задачу — следующий промпт разбирается заново.',
|
||
[{ name: '.claude/settings.json', cond: 'описан как хук UserPromptSubmit' }],
|
||
[],
|
||
[],
|
||
[{ name: 'Superpowers (§12)', desc: 'Экономия=100% теоретически может «сэкономить» вызов скила, нарушая обязательное правило (см. §12) — §12 неотменяем, экономия его не отменяет' }]
|
||
),
|
||
|
||
// ── АГЕНТЫ ───────────────────────────────────────
|
||
ag_pest: nd(
|
||
'Диагностирует падения Pest --parallel: классифицирует как реальный баг или один из 5 квирков (72-73-77...).',
|
||
'При падении Pest --parallel ИЛИ при subdir-only flake (как в audit Phase 3 SyncSupplierProjectsJobTest).',
|
||
'READ-ONLY на коде, не правит самостоятельно. Falsify каждую гипотезу через реальный запуск, не «вероятно квирк».',
|
||
[{ name: 'CLAUDE.md §6', cond: 'описывает когда вызывать' }],
|
||
[],
|
||
[{ name: 'MCP: redis', cond: 'читает Redis для дебага quirk 72 (supplier:session race)' }]
|
||
),
|
||
ag_rls: nd(
|
||
'Проверяет RLS compliance в миграциях — 7-item чеклист с реальными запусками команд, READ-ONLY.',
|
||
'При создании/правке миграции в db/migrations/ ИЛИ при правке db/schema.sql ИЛИ при PR review с DB-изменениями.',
|
||
'READ-ONLY (только Read/Grep/Glob/Bash) — не пишет код. Не альтернатива sk_rls skill, у них разные сценарии.',
|
||
[{ name: 'CLAUDE.md', cond: 'описывает в §6 и агенты/ директории' }],
|
||
[],
|
||
[{ name: 'MCP: laravel-boost', cond: 'SQL запросы к db/schema.sql' }],
|
||
[{ name: 'rls-check скил', desc: 'оба покрывают RLS compliance, нет чёткой границы: агент — для PR/diff, скил — для ручной таблицы' }]
|
||
),
|
||
ag_statusline: nd(
|
||
'Настраивает строку состояния Claude Code через редактирование файла конфига.',
|
||
'При запросе пользователя «настрой statusline» — редкая разовая задача.',
|
||
'Правит только settings.json statusline-секцию, не другие части конфига.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
ag_guide: nd(
|
||
'Отвечает на вопросы об API Claude Code, SDK, MCP серверах, хуках, slash commands.',
|
||
'При вопросе про возможности Claude Code/SDK/API — «Can Claude...», «How do I...», «Does Claude...».',
|
||
'READ-ONLY: ищет в документации, не правит код. Не для дебага кода — только для вопросов о platform.',
|
||
[],
|
||
[],
|
||
[{ name: 'MCP: github', cond: 'ищет примеры в репозитории при необходимости' }]
|
||
),
|
||
ag_explore: nd(
|
||
'Быстрый поиск файлов по паттерну или символу — только чтение, без анализа.',
|
||
'При targeted lookup — найти файл по имени или grep по символу/keyword.',
|
||
'Не для open-ended exploration. Не для review/audit (читает excerpts, миссует content past read window).',
|
||
[{ name: 'subagent-driven скил', cond: 'запускается для задач поиска' }],
|
||
[],
|
||
[]
|
||
),
|
||
ag_general: nd(
|
||
'Универсальный агент для сложных multi-step исследований с полным доступом к инструментам.',
|
||
'При сложных multi-step research / coding задачах, когда Explore недостаточно (нужен анализ, не только поиск).',
|
||
'Полный доступ к инструментам — может писать код. Дороже Explore по токенам.',
|
||
[{ name: 'subagent-driven скил', cond: 'запускается для основных задач' }],
|
||
[],
|
||
[]
|
||
),
|
||
ag_plan: nd(
|
||
'Архитектор: разрабатывает планы реализации, выявляет критичные файлы, рассматривает trade-offs.',
|
||
'При архитектурном планировании multi-component задачи (не для small refactor).',
|
||
'READ-ONLY (no Edit/Write/NotebookEdit). Возвращает план, не реализует его.',
|
||
[{ name: 'subagent-driven скил', cond: 'запускается для архитектурных задач' }],
|
||
[],
|
||
[{ name: 'writing-plans скил', cond: 'Plan агент и writing-plans решают похожую задачу для разных контекстов' }]
|
||
),
|
||
ag_hookify: nd(
|
||
'Анализирует транскрипты разговоров для поиска поведений, которые стоит предотвратить хуком.',
|
||
'При триггере /hookify без аргументов ИЛИ при запросе «look back at this conversation, what mistakes to prevent».',
|
||
'READ-ONLY (Read+Grep only). Рекомендует хуки, не создаёт их сам — передаёт в hookify plugin.',
|
||
[],
|
||
[],
|
||
[{ name: 'hookify (плагин)', cond: 'агент передаёт рекомендации в плагин' }]
|
||
),
|
||
ag_pcreator: nd(
|
||
'Создаёт конфигурацию новых агентов по описанию пользователя.',
|
||
'При запросе «create an agent that...» — генерация agent.md по описанию функциональности.',
|
||
'Только Write/Read tools. Не валидирует созданного агента — передаёт в plugin-validator.',
|
||
[],
|
||
[],
|
||
[{ name: 'plugin-dev:plugin-validator', cond: 'validator проверяет созданного агента' }]
|
||
),
|
||
ag_pvalid: nd(
|
||
'Проверяет структуру плагина на корректность — plugin.json, tools, manifest.',
|
||
'После создания/изменения plugin.json или plugin component\'ов — proactive validation.',
|
||
'READ-ONLY (Read/Grep/Glob/Bash). Сам не правит — даёт список нарушений.',
|
||
[],
|
||
[],
|
||
[{ name: 'plugin-dev:agent-creator', cond: 'validator и creator работают в паре' }]
|
||
),
|
||
ag_skreview: nd(
|
||
'Оценивает качество написанного скила — описание, workflow, примеры, best practices.',
|
||
'После создания/изменения скила через writing-skills — proactive review.',
|
||
'READ-ONLY (Read/Grep/Glob). Не правит — выдаёт рекомендации.',
|
||
[],
|
||
[],
|
||
[{ name: 'writing-skills скил', cond: 'skill-reviewer проверяет то, что writing-skills создал' }]
|
||
),
|
||
|
||
// ── MCP-СЕРВЕРЫ ──────────────────────────────────
|
||
mcp_pw: nd(
|
||
'Управляет браузером — снимает скриншоты, кликает, заполняет формы для smoke и a11y тестов.',
|
||
'При визуальной проверке прототипов (фаза 0), при a11y smoke (axe-core), при UI integration smoke.',
|
||
'Не для production users. На каждой сессии один shared browser — конфликты при parallel-work (см. квирк #2 в memory).',
|
||
[{ name: 'CLAUDE.md §3.1 #2', cond: 'активен с фазы 0' }],
|
||
[],
|
||
[{ name: 'SessionStart хук', cond: 'используется для визуальной проверки прототипов' }]
|
||
),
|
||
mcp_gh: nd(
|
||
'GitHub API — читает/создаёт PR, issues, коммиты, branches в репозитории CoralMinister/lidpotok.',
|
||
'При работе с PR/issues, при поиске в репозитории, при создании PR через finishing-pr skill.',
|
||
'Не push на main без явного одобрения. Pravila §4: атомарные коммиты, не batch\'ить через MCP.',
|
||
[{ name: 'CLAUDE.md §3.1 #3', cond: 'активен с фазы 0' }],
|
||
[],
|
||
[{ name: 'finishing-pr скил', cond: 'создаёт PR через этот MCP' }]
|
||
),
|
||
mcp_boost: nd(
|
||
'Laravel Boost — SQL запросы к dev-БД, схема таблиц, логи ошибок, поиск в docs Laravel.',
|
||
'Фаза 1+: при SQL запросах, при поиске в Laravel docs, при работе с Eloquent моделями.',
|
||
'**READ-ONLY к prod** — `.env.production` не должен попадать в локальный конфиг. Не использовать Inertia/Livewire/Tailwind/Filament guidelines.',
|
||
[{ name: 'CLAUDE.md §3.2 #10', cond: 'активен с фазы 1, READ-ONLY к prod запрещено' }],
|
||
[],
|
||
[{ name: 'ag_rls агент', cond: 'rls-reviewer использует Boost для SQL' }, { name: 'sk_rls скил', cond: 'rls-check использует Boost' }]
|
||
),
|
||
mcp_semgrep: nd(
|
||
'SAST анализ кода — ищет уязвимости, XSS, SQLi, нарушения правил по паттернам.',
|
||
'Фаза 3 pre-production: при code review (sk_coderev), при CI перед релизом.',
|
||
'Конфигурация в .semgrep.yml. False-positive\'ы документируются inline.',
|
||
[{ name: 'CLAUDE.md §3.4 #25', cond: 'фаза 3 pre-production' }],
|
||
[],
|
||
[{ name: 'code-review скил', cond: 'Semgrep MCP используется при code review' }]
|
||
),
|
||
mcp_sentry: nd(
|
||
'Читает ошибки из self-hosted Sentry в Yandex Cloud — события, стектрейсы, метрики. READ-ONLY.',
|
||
'При расследовании production runtime ошибок (после deployment Б-1).',
|
||
'**READ-ONLY** scope (org:read/project:read/event:read). Pending Sentry instance deployment Б-1 (зависит от ООО registration).',
|
||
[{ name: 'CLAUDE.md §3.3 #34', cond: 'off-phase debug-runtime; pending Sentry deployment Б-1' }],
|
||
[],
|
||
[]
|
||
),
|
||
mcp_redis: nd(
|
||
'Читает Redis/Memurai — ключи, очереди, кэш для дебага race conditions. СТРОГО READ-ONLY.',
|
||
'При дебаге Redis-очередей (Pest --parallel quirk 72), при анализе кэш-инвалидации.',
|
||
'**СТРОГО READ-ONLY** — никаких DEL/FLUSHDB/SET/LPUSH из Claude (только GET/KEYS/LIST). Deprecated Anthropic source — миграция post-MVP.',
|
||
[{ name: 'CLAUDE.md §3.3 #35', cond: 'off-phase debug-runtime; PSR_v1 R10.1 блок 3' }],
|
||
[],
|
||
[{ name: 'pest-parallel-debugger агент', cond: 'агент использует для quirk 72 (Redis race)' }]
|
||
),
|
||
mcp_21st: nd(
|
||
'Генератор стартовых шаблонов UI-компонентов через LLM. Активация только через R14.4 pipeline.',
|
||
'Только через PSR_v1 R14.4 pipeline: pre-check 9 условий (брендовый App*? Vuetify-эквивалент? существующий компонент?).',
|
||
'R14.5: не параллельно с FD/UPM. JSX→Vue, Tailwind→utility, shadcn→Vuetify обязательны. Pa11y a11y на deployable.',
|
||
[{ name: 'PSR_v1 R14.4', cond: 'строгий pre-check: 9 условий перед активацией' }],
|
||
[],
|
||
[],
|
||
[{ name: 'Frontend Design', desc: 'PSR_v1 R14.5: нельзя параллельно — 21st как генератор материала, FD как решатель; риск смешивания ролей и нарушения R6 фильтра стека' }]
|
||
),
|
||
|
||
// ── LEFTHOOK JOBS ─────────────────────────────────
|
||
lh_gitleaks: nd(
|
||
'pre-commit: ищет ПДн, токены и API-ключи в staged-файлах. Блокирует коммит при находке.',
|
||
'pre-commit stage: на каждый `git commit` — сканирует только staged файлы.',
|
||
'Bypass через `--no-verify` запрещён (Pravila §4.2). Находка = blocking error, не warning. Обновление словаря — `.gitleaksignore` для known-false-positives.',
|
||
[{ name: 'lefthook.yml', cond: 'job #1 в pre-commit, parallel:false' }],
|
||
[],
|
||
[{ name: 'lefthook:gitleaks pre-push', cond: 'pre-push версия сканирует всю историю' }]
|
||
),
|
||
lh_mdlint: nd(
|
||
'pre-commit: проверяет и авто-исправляет стиль Markdown файлов перед коммитом.',
|
||
'pre-commit stage: на каждый `git commit` со staged `.md` файлами.',
|
||
'Конфиг `.markdownlint-cli2.cjs`. Auto-fix включён (stage_fixed: true) — fixed файлы повторно staged.',
|
||
[{ name: 'lefthook.yml', cond: 'job #2 в pre-commit' }],
|
||
[],
|
||
[{ name: 'PostToolUse:markdownlint-fix хук', cond: 'оба делают одно — хук немедленно, lefthook при коммите' }]
|
||
),
|
||
lh_cspell: nd(
|
||
'pre-commit: проверяет орфографию в .md файлах по словарю cspell-words.txt.',
|
||
'pre-commit stage: на каждый `git commit` со staged `.md` файлами.',
|
||
'Словарь: `cspell-words.txt`. Кириллица в нижнем регистре. Не bypass\'ить — добавлять валидные слова в словарь.',
|
||
[{ name: 'lefthook.yml', cond: 'job #3 в pre-commit' }],
|
||
[],
|
||
[]
|
||
),
|
||
lh_stylelint: nd(
|
||
'pre-commit: линтует CSS в HTML-прототипах (web/v8/*.html).',
|
||
'pre-commit stage: на staged `.html`/`.css` файлах.',
|
||
'Stylelint конфиг в `.stylelintrc`. Deprecated keywords (`word-break: break-word`) блокируют commit.',
|
||
[{ name: 'lefthook.yml', cond: 'job #4 в pre-commit' }],
|
||
[],
|
||
[]
|
||
),
|
||
lh_pint: nd(
|
||
'pre-commit: авто-форматирует PHP код по PSR-стандарту, stage_fixed:true.',
|
||
'pre-commit stage: на каждый staged `.php` файл (root: app/).',
|
||
'Auto-fix включён — fixed файлы повторно staged. Конфиг `app/pint.json`.',
|
||
[{ name: 'lefthook.yml', cond: 'job #5 в pre-commit, root:app/' }],
|
||
[],
|
||
[]
|
||
),
|
||
lh_larastan: nd(
|
||
'pre-commit: статический анализ PHP — находит ошибки типов выше baseline (Larastan L9).',
|
||
'pre-commit stage: на staged `.php` файлах (root: app/).',
|
||
'Baseline `phpstan-baseline.neon` фиксирован — новые ошибки блокируют commit. Не bump\'ить baseline без обоснования.',
|
||
[{ name: 'lefthook.yml', cond: 'job #6 в pre-commit, root:app/' }],
|
||
[],
|
||
[{ name: 'MCP: laravel-boost', cond: 'Boost даёт контекст типов через IDE stubs' }]
|
||
),
|
||
lh_squawk: nd(
|
||
'pre-commit: линтует SQL миграции на безопасные паттерны (lock-safe, concurrent, etc.).',
|
||
'pre-commit stage: на staged `database/migrations/*.php` или `db/*.sql` файлах.',
|
||
'Конфиг squawk.toml. Не разрешать UNSAFE миграции (`ALTER TABLE ADD COLUMN NOT NULL DEFAULT`) без явного `-- squawk-ignore`.',
|
||
[{ name: 'lefthook.yml', cond: 'job #7 в pre-commit, glob:*.sql' }],
|
||
[],
|
||
[{ name: 'Tooling #15 squawk', cond: 'соответствует §3.2 entry' }]
|
||
),
|
||
lh_eslint: nd(
|
||
'pre-commit: линтует Vue/TypeScript файлы в app/resources/js/.',
|
||
'pre-commit stage: на staged `.vue`/`.ts`/`.tsx` файлах (root: app/).',
|
||
'Flat-config eslint 10 + plugin-vue 10. Не bypass\'ить через `--no-verify`. Errors blocking, warnings allowed.',
|
||
[{ name: 'lefthook.yml', cond: 'job #8 в pre-commit, root:app/' }],
|
||
[],
|
||
[]
|
||
),
|
||
lh_gitleaks2: nd(
|
||
'pre-push: полный скан всей истории коммитов на секреты (строже pre-commit job).',
|
||
'pre-push stage: перед `git push` к remote — сканирует всю history новых коммитов.',
|
||
'Bypass через `--no-verify` запрещён. На больших push (200+ commits) занимает 30+ сек.',
|
||
[{ name: 'lefthook.yml', cond: 'job в pre-push' }],
|
||
[],
|
||
[{ name: 'lefthook:gitleaks', cond: 'pre-push версия строже pre-commit: проверяет всю историю' }]
|
||
),
|
||
lh_lychee: nd(
|
||
'pre-push: проверяет все ссылки в .md файлах на битые (docs/**/*.md, db/**/*.md, *.md).',
|
||
'pre-push stage: перед `git push` — проверяет ссылки во всех `.md` файлах в монорепе.',
|
||
'Внешние ссылки проверяются с timeout 10s; offline — fail. Конфиг `lychee.toml`. Не bypass\'ить через `--no-verify`.',
|
||
[{ name: 'lefthook.yml', cond: 'job в pre-push' }],
|
||
[],
|
||
[{ name: 'CLAUDE.md', cond: 'проверяет ссылки в CLAUDE.md в том числе' }]
|
||
),
|
||
|
||
// ── MEMORY FILES ─────────────────────────────────
|
||
mem_user: nd(
|
||
'Профиль заказчика: Дмитрий, Windows Server 2022, VSCode, русский язык, путь к проекту.',
|
||
'Читается при старте каждой сессии через SessionStart хук — для language/preferences.',
|
||
'Не содержит секретов. При смене заказчика — переписать полностью.',
|
||
[],
|
||
[],
|
||
[{ name: 'SessionStart хук', cond: 'читается при старте каждой сессии' }]
|
||
),
|
||
mem_comm: nd(
|
||
'Стиль общения: короткие команды («а», «б», «делай»), варианты A/B/C, фиксация переоткрытий.',
|
||
'Читается при работе с пользователем — для соответствия стилю общения.',
|
||
'Не путь к code, а meta-rules коммуникации. Корректировки через явное feedback от заказчика.',
|
||
[],
|
||
[],
|
||
[{ name: 'memory:user_profile', cond: 'дополняет профиль пользователя' }]
|
||
),
|
||
mem_env: nd(
|
||
'80+ квирков окружения: специфика Windows Server, баги инструментов, митигации.',
|
||
'При unexpected behavior — сначала проверка memory_env на известный квирк.',
|
||
'Не дубль — добавлять только новые квирки. Quirk count актуализируется в `project_state.md`.',
|
||
[],
|
||
[],
|
||
[
|
||
{ name: 'pest-parallel-debugger агент', cond: 'квирки 72/77 используются агентом' },
|
||
{ name: 'SessionStart хук', cond: 'читается при старте' }
|
||
]
|
||
),
|
||
mem_sp: nd(
|
||
'Hard rule §12 + economy hook architecture из 6 компонентов — дисциплина инвокации скилов.',
|
||
'При работе со скилами — для соответствия §12 hard rule.',
|
||
'Описывает архитектуру economy hook (6 компонентов) — менять только при изменении самого хука.',
|
||
[],
|
||
[],
|
||
[{ name: 'economy-mode хук', cond: 'связаны: memory описывает архитектуру хука' }]
|
||
),
|
||
mem_plugins: nd(
|
||
'Правила парного стека плагинов, debug-runtime MCP, tier-структура PSR_v1.',
|
||
'При работе с плагинами FD/UPM/21st/Sentry/Redis MCP — для tier-разделения.',
|
||
'Синхронизируется с PSR_v1 — изменения в memory только если изменился сам PSR_v1.',
|
||
[],
|
||
[],
|
||
[{ name: 'PSR_v1', cond: 'memory отражает актуальные версии PSR_v1' }]
|
||
),
|
||
mem_state: nd(
|
||
'Текущее состояние: ветка, тесты (Pest/Vitest), последние коммиты, активные задачи.',
|
||
'Читается при старте сессии — для быстрого контекста; обновляется после крупных вех.',
|
||
'Может становиться stale — re-Read при сомнении. Не доверять данным более 2-3 дней без verify.',
|
||
[],
|
||
[],
|
||
[{ name: 'SessionStart хук', cond: 'читается при старте для быстрого контекста' }]
|
||
),
|
||
mem_phase1: nd(
|
||
'Стратегия фазы 1: native Windows стек без Docker, pg_partman заменён Artisan cron.',
|
||
'При работе с infrastructure фазы 1 (PG/Redis/PHP-CLI на Windows native).',
|
||
'Стратегия фиксированная до закрытия Б-1 (Managed PG в YC) или 6 месяцев — переоценка указана в файле.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_archive: nd(
|
||
'Карта источников истины: версии всех 13+ ключевых документов проекта.',
|
||
'При вопросах «какая версия документа X» или «где источник истины для Y».',
|
||
'Синхронизируется с CLAUDE.md §0. Изменения в memory только если изменился CLAUDE.md §0.',
|
||
[],
|
||
[],
|
||
[{ name: 'CLAUDE.md', cond: 'memory синхронизирует версии с CLAUDE.md §0' }]
|
||
),
|
||
mem_github: nd(
|
||
'GitHub репозиторий CoralMinister/lidpotok: HEAD, hooks, правила push.',
|
||
'При работе с GitHub — push, PR, branch operations.',
|
||
'Не push --force на main (warning в Pravila). Pre-push hooks обязательны.',
|
||
[],
|
||
[],
|
||
[{ name: 'MCP: github', cond: 'MCP и memory дополняют друг друга для работы с GitHub' }]
|
||
),
|
||
mem_handoff: nd(
|
||
'Дизайн-handoff Платона: что из liderra_v8_handoff/ используем, что нет.',
|
||
'При UI/дизайн задачах — для разделения «брендбук используем» vs «состав фич — по ТЗ v8.5».',
|
||
'Handoff — только дизайн/токены/компоненты. Функционал, состав экранов — НЕ из handoff (берём из ТЗ).',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_audit: nd(
|
||
'Полный аудит портала 13.05.2026: 38 находок, вердикт 🟡, 10 Q-items закрыты.',
|
||
'При вопросах про аудит или его последствия (Q.DEFER, P0/P1/P2 распределение).',
|
||
'Снимок состояния — не редактировать при последующих аудитах, создавать новые memory-файлы.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_supplier: nd(
|
||
'Прогресс интеграции поставщика Plans 1-5: Tasks, коммиты, блокеры.',
|
||
'При работе с supplier integration (Plans 1-5) — для текущего state и blockers.',
|
||
'Блокеры (Б-1, credentials) — внешние, не разрешаются Claude\'ом. Только трекинг.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_brain: nd(
|
||
'Claude Brain v1.0 — extracted brain repo, тег brain-v1.0, install.sh.',
|
||
'При работе с brain repository или install.sh для consumer sync.',
|
||
'GitHub push на brain repo blocked (8.2). Не пытаться push без разрешения.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_redesign: nd(
|
||
'Редизайн Quiet Luxury: 20 коммитов, foundation CSS + composables + AppSidebar rewrite.',
|
||
'При работе с portal redesign (frontend, AppSidebar, foundation CSS).',
|
||
'I2 backlog в spec §15 — 10 пунктов отложены до I2. Не реализовывать I2 пункты без явного запроса.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_devindices: nd(
|
||
'Dev Element Indices — временная feedback-фича для разработки; к удалению в продакшене.',
|
||
'При работе с dev feedback (e.g. «1030 измени цвет») — для понимания number → element mapping.',
|
||
'**TEMPORARY** — заказчик прямо сказал «уберём в конечном релизе». Не вкладываться в долгосрочную инфраструктуру.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
};
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 4: VIS INIT
|
||
// ════════════════════════════════════════════════════
|
||
const GROUPS = {
|
||
rules: { color: { background: '#073642', border: '#268bd2', highlight: { border: '#93a1a1', background: '#0d4a5a' } }, font: { color: '#fdf6e3', size: 13, bold: true } },
|
||
plugins: { color: { background: '#001a00', border: '#859900', highlight: { border: '#b8cc00', background: '#002600' } }, font: { color: '#fdf6e3', size: 12 } },
|
||
skills_sp: { color: { background: '#1a0033', border: '#6c71c4', highlight: { border: '#9b9fea', background: '#250047' } }, font: { color: '#fdf6e3', size: 11 } },
|
||
skills_proj: { color: { background: '#2d0020', border: '#d33682', highlight: { border: '#e869a8', background: '#3d0028' } }, font: { color: '#fdf6e3', size: 12 } },
|
||
hooks: { color: { background: '#002233', border: '#2aa198', highlight: { border: '#4dd7ce', background: '#003344' } }, font: { color: '#fdf6e3', size: 11 } },
|
||
agents: { color: { background: '#1a1200', border: '#b58900', highlight: { border: '#e0ad00', background: '#261a00' } }, font: { color: '#fdf6e3', size: 11 } },
|
||
mcp: { color: { background: '#2d1200', border: '#cb4b16', highlight: { border: '#ff6b30', background: '#3d1900' } }, font: { color: '#fdf6e3', size: 11 } },
|
||
lefthook: { color: { background: '#2d0000', border: '#dc322f', highlight: { border: '#ff5f5c', background: '#3d0000' } }, font: { color: '#fdf6e3', size: 10 } },
|
||
memory: { color: { background: '#112233', border: '#586e75', highlight: { border: '#839496', background: '#1a2f40' } }, font: { color: '#eee8d5', size: 10 } },
|
||
};
|
||
|
||
const nodesDS = new vis.DataSet(NODES);
|
||
const edgesDS = new vis.DataSet(EDGES);
|
||
|
||
const network = new vis.Network(
|
||
document.getElementById('network'),
|
||
{ nodes: nodesDS, edges: edgesDS },
|
||
{
|
||
groups: GROUPS,
|
||
nodes: {
|
||
shape: 'dot',
|
||
borderWidth: 2,
|
||
borderWidthSelected: 3,
|
||
font: { multi: 'html' },
|
||
},
|
||
edges: {
|
||
smooth: { type: 'continuous', roundness: 0.5 },
|
||
selectionWidth: 2,
|
||
},
|
||
physics: {
|
||
enabled: false,
|
||
},
|
||
interaction: {
|
||
hover: true,
|
||
tooltipDelay: 400,
|
||
multiselect: false,
|
||
},
|
||
}
|
||
);
|
||
|
||
network.once('afterDrawing', () => {
|
||
network.fit({ animation: { duration: 600, easingFunction: 'easeInOutQuad' } });
|
||
});
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 5: LEGEND PANEL
|
||
// ════════════════════════════════════════════════════
|
||
function renderLegendItem(item) {
|
||
return `<li>${item.name}${item.cond ? ` <span class="cond">— ${item.cond}</span>` : ''}</li>`;
|
||
}
|
||
|
||
function showLegend(nodeId) {
|
||
const node = NODES.find(n => n.id === nodeId);
|
||
const details = NODE_DETAILS[nodeId];
|
||
const panel = document.getElementById('legend-panel');
|
||
|
||
if (!node || !details) { panel.classList.remove('visible'); return; }
|
||
|
||
document.getElementById('legend-title').textContent = node.label.replace(/\n/g, ' ');
|
||
|
||
const catLabel = CATEGORY_LABELS[node.group] || node.group;
|
||
const catColor = GROUPS[node.group] && GROUPS[node.group].color ? GROUPS[node.group].color.border : '#839496';
|
||
document.getElementById('legend-category').innerHTML =
|
||
`<span style="color:${catColor}; font-weight:600;">● ${catLabel}</span>`;
|
||
|
||
document.getElementById('ld-desc').textContent = details.desc;
|
||
document.getElementById('ld-when').textContent = details.when || '—';
|
||
document.getElementById('ld-limits').textContent = details.limits || 'без особых ограничений';
|
||
|
||
const ldReports = document.getElementById('ld-reports');
|
||
ldReports.innerHTML = details.reportsTo.length
|
||
? details.reportsTo.map(renderLegendItem).join('')
|
||
: '<li style="color:#586e75; font-style:italic;">Не подчиняется никому</li>';
|
||
|
||
const ldManages = document.getElementById('ld-manages');
|
||
ldManages.innerHTML = details.manages.length
|
||
? details.manages.map(renderLegendItem).join('')
|
||
: '<li style="color:#586e75; font-style:italic;">Никто не подчиняется</li>';
|
||
|
||
const ldTogether = document.getElementById('ld-together');
|
||
ldTogether.innerHTML = details.together.length
|
||
? details.together.map(renderLegendItem).join('')
|
||
: '<li style="color:#586e75; font-style:italic;">Нет особых одновременных связей</li>';
|
||
|
||
const ldConflicts = document.getElementById('ld-conflicts');
|
||
if (details.conflicts && details.conflicts.length) {
|
||
ldConflicts.innerHTML = details.conflicts.map(c =>
|
||
`<div class="conflict-item"><div class="cname">⚡ ${c.name}</div><div class="cdesc">${c.desc}</div></div>`
|
||
).join('');
|
||
} else {
|
||
ldConflicts.innerHTML = '<div id="legend-no-conflicts" style="font-size:12px;color:#586e75;">Конфликтов не выявлено</div>';
|
||
}
|
||
document.getElementById('conflicts-section').style.display = '';
|
||
|
||
panel.classList.add('visible');
|
||
}
|
||
|
||
network.on('click', params => {
|
||
if (params.nodes.length === 1) {
|
||
showLegend(params.nodes[0]);
|
||
} else if (params.nodes.length === 0 && params.edges.length === 0) {
|
||
document.getElementById('legend-panel').classList.remove('visible');
|
||
}
|
||
});
|
||
|
||
document.getElementById('legend-close').addEventListener('click', () => {
|
||
document.getElementById('legend-panel').classList.remove('visible');
|
||
});
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 6: TOOLBAR
|
||
// ════════════════════════════════════════════════════
|
||
let highlightedNode = null;
|
||
|
||
document.getElementById('search').addEventListener('input', function () {
|
||
const q = this.value.trim().toLowerCase();
|
||
if (!q) {
|
||
nodesDS.update(NODES.map(n => ({ id: n.id, borderWidth: 2, opacity: 1.0 })));
|
||
highlightedNode = null;
|
||
return;
|
||
}
|
||
const matches = NODES.filter(n => n.label.toLowerCase().includes(q));
|
||
const updates = NODES.map(n => {
|
||
const match = matches.some(m => m.id === n.id);
|
||
return {
|
||
id: n.id,
|
||
borderWidth: match ? 5 : 1,
|
||
opacity: match ? 1.0 : 0.25,
|
||
};
|
||
});
|
||
nodesDS.update(updates);
|
||
if (matches.length === 1) {
|
||
network.focus(matches[0].id, { scale: 1.4, animation: { duration: 500, easingFunction: 'easeInOutQuad' } });
|
||
showLegend(matches[0].id);
|
||
highlightedNode = matches[0].id;
|
||
}
|
||
});
|
||
|
||
document.getElementById('btn-freeze').addEventListener('click', () => {
|
||
network.setOptions({ physics: { enabled: false } });
|
||
});
|
||
|
||
document.getElementById('btn-unfreeze').addEventListener('click', () => {
|
||
network.setOptions({
|
||
physics: {
|
||
enabled: true,
|
||
solver: 'forceAtlas2Based',
|
||
forceAtlas2Based: {
|
||
gravitationalConstant: -50,
|
||
centralGravity: 0.0,
|
||
springLength: 100,
|
||
springConstant: 0.02,
|
||
damping: 0.6,
|
||
avoidOverlap: 0.4,
|
||
},
|
||
},
|
||
});
|
||
});
|
||
|
||
document.getElementById('btn-reset').addEventListener('click', () => {
|
||
// (a) Restore radial positions
|
||
nodesDS.update(NODES.map(n => ({ id: n.id, x: n.x, y: n.y })));
|
||
// (b) Refit camera
|
||
network.fit({ animation: { duration: 600, easingFunction: 'easeInOutQuad' } });
|
||
});
|
||
|
||
document.getElementById('btn-clear').addEventListener('click', () => {
|
||
document.getElementById('search').value = '';
|
||
nodesDS.update(NODES.map(n => ({ id: n.id, borderWidth: 2, opacity: 1.0 })));
|
||
document.getElementById('legend-panel').classList.remove('visible');
|
||
highlightedNode = null;
|
||
});
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 7: RESIZE HANDLE + LOCALSTORAGE
|
||
// ════════════════════════════════════════════════════
|
||
const LEGEND_STORAGE_KEY = 'liderra-map-legend-width';
|
||
const LEGEND_MIN_W = 300, LEGEND_MAX_W = 900;
|
||
|
||
let redrawScheduled = false;
|
||
function applyLegendWidth(w) {
|
||
const clamped = Math.max(LEGEND_MIN_W, Math.min(LEGEND_MAX_W, w));
|
||
const panel = document.getElementById('legend-panel');
|
||
panel.style.width = clamped + 'px';
|
||
panel.style.minWidth = clamped + 'px';
|
||
if (typeof network !== 'undefined' && network && !redrawScheduled) {
|
||
redrawScheduled = true;
|
||
requestAnimationFrame(() => {
|
||
redrawScheduled = false;
|
||
network.redraw();
|
||
});
|
||
}
|
||
}
|
||
|
||
function restoreLegendWidth() {
|
||
let saved = 300;
|
||
try {
|
||
saved = parseInt(localStorage.getItem(LEGEND_STORAGE_KEY) || '300', 10);
|
||
} catch (e) { /* private mode or quota — keep default */ }
|
||
applyLegendWidth(saved);
|
||
}
|
||
|
||
(function setupResizeHandle() {
|
||
const handle = document.getElementById('legend-handle');
|
||
if (!handle) return;
|
||
let dragging = false;
|
||
handle.addEventListener('mousedown', e => {
|
||
dragging = true;
|
||
handle.classList.add('dragging');
|
||
document.body.style.userSelect = 'none';
|
||
e.preventDefault();
|
||
});
|
||
document.addEventListener('mousemove', e => {
|
||
if (!dragging) return;
|
||
const w = window.innerWidth - e.clientX;
|
||
applyLegendWidth(w);
|
||
});
|
||
document.addEventListener('mouseup', () => {
|
||
if (!dragging) return;
|
||
dragging = false;
|
||
handle.classList.remove('dragging');
|
||
document.body.style.userSelect = '';
|
||
const w = parseInt(document.getElementById('legend-panel').style.width, 10);
|
||
try { localStorage.setItem(LEGEND_STORAGE_KEY, String(w)); } catch (e) { /* private mode or quota */ }
|
||
});
|
||
})();
|
||
|
||
window.addEventListener('DOMContentLoaded', restoreLegendWidth);
|
||
</script>
|
||
</body>
|
||
</html>
|