Raportti: Mermaid → custom swimlane (kompakti, tooltipsit)

Agenteittain ryhmitelty visualisointi:
  Manageri  ✓ Suunnittelu
  Koodari   ✓ models.py → ✓ main.py → ✓ index.html
  DevOps    ✓ Review → ✓ Dockerfile → ✓ Compose → ✓ README
  QA        ✓ Testit → ✓ Validointi
Hover näyttää selityksen + output-esikatselun.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 11:39:23 +03:00
parent 01622a960f
commit 1b75c89320

View File

@@ -2828,9 +2828,7 @@ ${fixableFiles}`;
<p style="color:#8b949e;margin-bottom:20px">${task}${new Date().toLocaleString('fi-FI')}${fileEntries.length} tiedostoa, ${steps.length} vaihetta</p> <p style="color:#8b949e;margin-bottom:20px">${task}${new Date().toLocaleString('fi-FI')}${fileEntries.length} tiedostoa, ${steps.length} vaihetta</p>
<h2>🔄 Agenttien workflow</h2> <h2>🔄 Agenttien workflow</h2>
<div class="mermaid"> ${generateWorkflowSwimlane(steps)}
${generateMermaidDiagram(steps)}
</div>
<h2>📋 Pipeline-vaiheet</h2> <h2>📋 Pipeline-vaiheet</h2>
${stepsHtml} ${stepsHtml}
@@ -2843,41 +2841,44 @@ ${filesHtml}
<hr style="border-color:#30363d;margin:24px 0"> <hr style="border-color:#30363d;margin:24px 0">
<p style="color:#8b949e;font-size:12px">Generoitu Kipinä Agentic Playground v0.2.2 — <a href="https://kipina.studio">kipina.studio</a></p> <p style="color:#8b949e;font-size:12px">Generoitu Kipinä Agentic Playground v0.2.2 — <a href="https://kipina.studio">kipina.studio</a></p>
<` + `script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true, theme: 'dark', themeVariables: { primaryColor: '#58a6ff', primaryTextColor: '#c9d1d9', lineColor: '#30363d', primaryBorderColor: '#30363d' } });
</` + `script>
</body></html>`; </body></html>`;
} }
function generateMermaidDiagram(steps) { function generateWorkflowSwimlane(steps) {
const agentLabels = { manager: 'Manageri', coder: 'Koodari', tester: 'DevOps', qa: 'QA', data: 'Data' }; const agentLabels = { manager: 'Manageri', coder: 'Koodari', tester: 'DevOps', qa: 'QA', data: 'Data' };
const agentStyles = { manager: 'fill:#1c1206,stroke:#d29922,color:#d29922', coder: 'fill:#0d1a0d,stroke:#3fb950,color:#3fb950', tester: 'fill:#0d1117,stroke:#58a6ff,color:#58a6ff', qa: 'fill:#170d22,stroke:#a371f7,color:#a371f7', data: 'fill:#1a0d22,stroke:#d2a8ff,color:#d2a8ff' }; const agentColors = { manager: '#d29922', coder: '#3fb950', tester: '#58a6ff', qa: '#a371f7', data: '#d2a8ff' };
const agentBgs = { manager: '#1c1206', coder: '#0d1a0d', tester: '#0d1520', qa: '#170d22', data: '#1a0d22' };
const stepDescs = { 'Suunnittelu': 'Jakaa projektin tiedostoiksi', 'Review': 'Tarkistaa koodin laadun', 'Testit': 'Kirjoittaa pytest-testit', 'Dockerfile': 'Generoi Docker-imagen', 'Compose': 'Palvelumääritys', 'README': 'Käyttöohjeet', 'Validointi': 'Tarkistaa yhteensopivuuden', 'Korjaukset': 'Korjaa löydetyt ongelmat' }; const stepDescs = { 'Suunnittelu': 'Jakaa projektin tiedostoiksi', 'Review': 'Tarkistaa koodin laadun', 'Testit': 'Kirjoittaa pytest-testit', 'Dockerfile': 'Generoi Docker-imagen', 'Compose': 'Palvelumääritys', 'README': 'Käyttöohjeet', 'Validointi': 'Tarkistaa yhteensopivuuden', 'Korjaukset': 'Korjaa löydetyt ongelmat' };
let lines = ['graph LR']; var agents = [];
let prevId = null; var agentMap = {};
for (var si = 0; si < steps.length; si++) {
var s = steps[si];
if (!agentMap[s.agent]) { agentMap[s.agent] = []; agents.push(s.agent); }
agentMap[s.agent].push(s);
}
steps.forEach((s, i) => { var rows = '';
const id = `S${i}`; for (var ai = 0; ai < agents.length; ai++) {
const agent = agentLabels[s.agent] || s.agent; var agent = agents[ai];
const label = s.label.replace(/"/g, "'").replace(/[<>]/g, ''); var color = agentColors[agent] || '#8b949e';
const desc = stepDescs[s.label] || s.label; var bg = agentBgs[agent] || '#161b22';
const outputPreview = (s.output || '').substring(0, 80).replace(/"/g, "'").replace(/\n/g, ' ').replace(/[<>]/g, ''); var label = agentLabels[agent] || agent;
var badges = '';
lines.push(` ${id}["${agent}<br/>${label}"]`); var aSteps = agentMap[agent];
// Mermaid tooltip: click event + title for (var bi = 0; bi < aSteps.length; bi++) {
lines.push(` click ${id} callback "${desc}${outputPreview ? ' — ' + outputPreview : ''}"`); var st = aSteps[bi];
if (prevId) { var desc = stepDescs[st.label] || st.label;
lines.push(` ${prevId} --> ${id}`); var outPrev = (st.output || '').substring(0, 100).replace(/</g, '&lt;').replace(/\n/g, ' ');
var tip = desc + (outPrev ? ' — ' + outPrev : '');
var icon = st.status === 'done' ? '✓' : '◷';
if (bi > 0) badges += '<span style="color:#30363d;margin:0 1px">→</span>';
badges += '<span title="' + tip.replace(/"/g, '&quot;') + '" style="display:inline-block;background:' + bg + ';border:1px solid ' + color + ';border-radius:4px;padding:3px 8px;margin:2px;font-size:11px;color:' + color + ';cursor:help;white-space:nowrap">' + icon + ' ' + st.label.replace(/</g, '&lt;') + '</span>';
} }
if (agentStyles[s.agent]) { rows += '<div style="display:flex;align-items:center;gap:8px;margin:4px 0"><span style="min-width:70px;font-weight:600;font-size:12px;color:' + color + '">' + label + '</span><div style="display:flex;flex-wrap:wrap;align-items:center">' + badges + '</div></div>';
lines.push(` style ${id} ${agentStyles[s.agent]}`); }
}
prevId = id;
});
return lines.join('\n'); return '<div style="background:#0d1117;border:1px solid #30363d;border-radius:6px;padding:12px">' + rows + '</div>';
} }
// Yksinkertainen pipeline (vanha: manageri → koodari → testaaja) // Yksinkertainen pipeline (vanha: manageri → koodari → testaaja)