Bump to v2.3.0: replace polling with SSE stream, fix detector imports

- Add GET /stream SSE endpoint to aggregator.py; state is pushed
  instantly on every change instead of fetched every 2s
- Replace setInterval polling in index.html with EventSource;
  onerror shows the ( ?.?) face and auto-reconnect is handled by
  the browser natively
- Fix ModuleNotFoundError in detectors: inject project root into
  PYTHONPATH when launching subprocesses from kao.py
- Update openapi.yaml, CLAUDE.md, README.md with /stream endpoint
- Remove completed SSE item from TODO.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 17:25:15 -06:00
parent 9291066263
commit aaae20281d
7 changed files with 114 additions and 33 deletions

View File

@@ -216,8 +216,7 @@
<script>
const emoteEl = document.getElementById("emote");
const messageEl = document.getElementById("message");
const POLL_INTERVAL = 2000;
const VERSION = "v2.2.0";
const VERSION = "v2.3.0";
// Sound system
let audioCtx = null;
@@ -501,20 +500,21 @@
document.addEventListener("DOMContentLoaded", initAudio);
}
async function fetchStatus() {
try {
const response = await fetch("/status");
if (!response.ok) throw new Error("Failed to fetch");
const data = await response.json();
updateDisplay(data);
} catch (err) {
// Connection lost state
function connectStream() {
const es = new EventSource("/stream");
es.onmessage = (e) => {
try {
updateDisplay(JSON.parse(e.data));
} catch (_) {}
};
es.onerror = () => {
// Connection lost — EventSource will auto-reconnect
emoteEl.textContent = "( ?.?)";
emoteEl.style.color = "#888888";
emoteEl.className = "searching";
messageEl.style.color = "#888888";
messageEl.textContent = "";
}
};
}
function updateDisplay(data) {
@@ -541,9 +541,7 @@
}
}
// Initial fetch and start polling
fetchStatus();
setInterval(fetchStatus, POLL_INTERVAL);
connectStream();
</script>
</body>
</html>