Tarkkailijan raportti: klikkaa avataria → modal + kehäväri arvosanalla

Tarkkailijan vastaus alkaa VERDICT-rivillä:
- GREEN → vihreä kehä → "OK"
- ORANGE → oranssi kehä → "HUOMIOITA"
- RED → punainen kehä → "KRIITTISTÄ"

Kehäväri ja glow jäävät näkyviin pipelinen jälkeen.
Klikkaamalla Tarkkailija-avataria avautuu raportti-modal jossa
README.md renderöidään markdown-muotoiltuna (taulukot, koodi, listat).
Modal sulkeutuu ✕-napista tai klikkaamalla taustaa.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jaakko Vanhala
2026-04-10 07:33:11 +03:00
parent c731c18360
commit 7d842529b1

View File

@@ -239,6 +239,15 @@ OUTPUT FORMAT:
const config = document.getElementById('agent-config'); const config = document.getElementById('agent-config');
if (!selectedAgent) { config.style.display = 'none'; return; } if (!selectedAgent) { config.style.display = 'none'; return; }
// Tarkkailija-klikkaus: avaa raportti modalina jos se on generoitu
if (key === 'observer' && window._lastReport) {
config.style.display = 'none';
showReportModal(window._lastReport);
selectedAgent = null;
renderAgentBar();
return;
}
const a = agents[key]; const a = agents[key];
config.style.display = 'block'; config.style.display = 'block';
document.getElementById('config-avatar').src = a.avatar; document.getElementById('config-avatar').src = a.avatar;
@@ -830,25 +839,42 @@ OUTPUT FORMAT:
if (dockerfile) files['Dockerfile'] = dockerfile; if (dockerfile) files['Dockerfile'] = dockerfile;
stepN++; stepN++;
// Tarkkailija: yhteenveto + raportti // Tarkkailija: yhteenveto + raportti + arvosana
const obs = agents.observer || Object.values(agents)[5]; const obs = agents.observer || Object.values(agents)[5];
if (obs) { if (obs) {
termLog(`\n<span style="color:#8b949e;font-weight:bold">[${stepN}] ${esc(obs.name)}</span> — projektin yhteenveto`); termLog(`\n<span style="color:#8b949e;font-weight:bold">[${stepN}] ${esc(obs.name)}</span> — projektin yhteenveto`);
highlightAgent('observer'); highlightAgent('observer');
explainStep('Raportti', `${obs.name} kokoaa yhteenvedon projektin rakenteesta, riskeistä ja käyttöönotosta.`); explainStep('Raportti', `${obs.name} kokoaa yhteenvedon ja antaa arvosanan.`);
const finalCode = Object.entries(files).map(([n,c]) => `--- ${n} ---\n${c}`).join('\n\n'); const finalCode = Object.entries(files).map(([n,c]) => `--- ${n} ---\n${c}`).join('\n\n');
const obsPrompt = (obs.prompt ? obs.prompt+'\n\n' : '') + const obsPrompt = (obs.prompt ? obs.prompt+'\n\n' : '') +
`Write a project README.md report in markdown for this project: ${task}\n\n` + `Write a project README.md report in markdown for: ${task}\n\n` +
`Include these sections:\n` + `IMPORTANT: Start the FIRST LINE with exactly one of these verdicts:\n` +
`VERDICT: GREEN — project is production-ready, no issues\n` +
`VERDICT: ORANGE — project works but has warnings or improvements needed\n` +
`VERDICT: RED — project has critical issues that must be fixed\n\n` +
`Then include:\n` +
`# Project: ${task}\n` + `# Project: ${task}\n` +
`## Files (list each file and its purpose)\n` + `## Files\n## How to run\n## API Endpoints\n## Architecture\n## Risk assessment\n\n` +
`## How to run (uv + Docker commands)\n` +
`## API Endpoints (table: method, path, description)\n` +
`## Architecture notes\n` +
`## Risk assessment (security, reliability)\n\n` +
`Project code:\n${finalCode}`; `Project code:\n${finalCode}`;
const readme = await kpnRun(obs.model, obsPrompt); const readme = await kpnRun(obs.model, obsPrompt);
if (readme) files['README.md'] = readme; if (readme) {
files['README.md'] = readme;
// Tallennetaan raportti globaalisti jotta tarkkailija-klikkaus avaa sen
window._lastReport = readme;
// Parsitaan arvosana → tarkkailijan kehäväri
const firstLine = readme.split('\n')[0].toUpperCase();
let verdictColor = '#3fb950'; // oletus: vihreä
let verdictText = 'OK';
if (firstLine.includes('RED')) { verdictColor = '#f85149'; verdictText = 'KRIITTISTÄ'; }
else if (firstLine.includes('ORANGE')) { verdictColor = '#d29922'; verdictText = 'HUOMIOITA'; }
// Asetetaan tarkkailijan kehäväri
const obsAvatar = document.querySelector('.agent-avatar[data-agent="observer"] img');
if (obsAvatar) {
obsAvatar.style.borderColor = verdictColor;
obsAvatar.style.boxShadow = `0 0 12px ${verdictColor}`;
}
termLog(` <span style="color:${verdictColor};font-weight:bold">● ${verdictText}</span> — klikkaa Tarkkailijaa nähdäksesi raportin`);
}
stepN++; stepN++;
} }
@@ -1118,6 +1144,24 @@ OUTPUT FORMAT:
saveSettings(); saveSettings();
initSettings(); initSettings();
}; };
// === Raportti-modal ===
window.showReportModal = function(markdown) {
let modal = document.getElementById('report-modal');
if (!modal) {
modal = document.createElement('div');
modal.id = 'report-modal';
modal.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);z-index:1000;display:flex;align-items:center;justify-content:center;backdrop-filter:blur(4px)';
modal.innerHTML = `<div style="background:var(--panel);border:1px solid var(--border);border-radius:8px;max-width:800px;width:90%;max-height:85vh;overflow-y:auto;padding:24px;position:relative">
<button onclick="document.getElementById('report-modal').style.display='none'" style="position:absolute;top:12px;right:12px;background:none;border:none;color:#8b949e;font-size:20px;cursor:pointer">✕</button>
<div id="report-modal-content" style="line-height:1.7;font-size:15px"></div>
</div>`;
document.body.appendChild(modal);
}
document.getElementById('report-modal-content').innerHTML = renderMd(markdown);
document.getElementById('report-modal-content').querySelectorAll('pre code').forEach(b => { if (typeof hljs !== 'undefined') hljs.highlightElement(b); });
modal.style.display = 'flex';
modal.addEventListener('click', (e) => { if (e.target === modal) modal.style.display = 'none'; });
};
</script> </script>
</body> </body>
</html> </html>