Bump to v1.1.0, enable network and docker detectors

- Version bump reflecting new features (sounds, tap reaction, docker detector)
- Rename title to Kao
- Enable network and docker detectors by default

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 20:57:18 -06:00
parent da6613ada3
commit 66c9790d2b
2 changed files with 352 additions and 325 deletions

View File

@@ -45,7 +45,7 @@
},
{
"name": "network",
"enabled": false,
"enabled": true,
"script": "detectors/network.py",
"env": {
"CHECK_INTERVAL": "60",
@@ -55,7 +55,7 @@
},
{
"name": "docker",
"enabled": false,
"enabled": true,
"script": "detectors/docker.py",
"env": {
"CHECK_INTERVAL": "60",

View File

@@ -1,9 +1,12 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Sentry-Emote</title>
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no"
/>
<title>Kao</title>
<style>
* {
margin: 0;
@@ -42,7 +45,8 @@
}
@keyframes breathe {
0%, 100% {
0%,
100% {
opacity: 1;
transform: scale(1);
}
@@ -58,9 +62,16 @@
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
0%,
100% {
transform: translateX(0);
}
25% {
transform: translateX(-5px);
}
75% {
transform: translateX(5px);
}
}
/* Popping animation - scale up for Notifications */
@@ -69,7 +80,8 @@
}
@keyframes pop {
0%, 100% {
0%,
100% {
transform: scale(1);
}
50% {
@@ -83,7 +95,8 @@
}
@keyframes celebrate {
0%, 100% {
0%,
100% {
transform: translateY(0) rotate(0deg);
}
25% {
@@ -100,7 +113,8 @@
}
@keyframes float {
0%, 100% {
0%,
100% {
transform: translateY(0);
}
50% {
@@ -114,7 +128,8 @@
}
@keyframes bounce {
0%, 100% {
0%,
100% {
transform: translateY(0);
}
50% {
@@ -128,7 +143,8 @@
}
@keyframes sway {
0%, 100% {
0%,
100% {
transform: rotate(0deg);
}
25% {
@@ -145,7 +161,8 @@
}
@keyframes blink {
0%, 100% {
0%,
100% {
opacity: 1;
}
50% {
@@ -159,7 +176,8 @@
}
@keyframes search {
0%, 100% {
0%,
100% {
transform: translateX(0);
opacity: 0.6;
}
@@ -179,7 +197,8 @@
}
@keyframes sleep {
0%, 100% {
0%,
100% {
opacity: 0.4;
transform: scale(1);
}
@@ -189,20 +208,21 @@
}
}
</style>
</head>
<body>
</head>
<body>
<div id="emote" class="breathing">( ^_^)</div>
<div id="message">Loading...</div>
<script>
const emoteEl = document.getElementById('emote');
const messageEl = document.getElementById('message');
const emoteEl = document.getElementById("emote");
const messageEl = document.getElementById("message");
const POLL_INTERVAL = 2000;
const VERSION = 'v1.0.0';
const VERSION = "v1.1.0";
// Sound system
let audioCtx = null;
let soundEnabled = new URLSearchParams(window.location.search).get('sound') === 'on';
let soundEnabled =
new URLSearchParams(window.location.search).get("sound") === "on";
let lastState = null;
let lastData = null;
let isReacting = false;
@@ -211,19 +231,22 @@
if (!audioCtx) {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
}
if (audioCtx.state === 'suspended') {
if (audioCtx.state === "suspended") {
audioCtx.resume();
}
}
function playTone(frequency, duration, type = 'sine', volume = 0.1) {
function playTone(frequency, duration, type = "sine", volume = 0.1) {
if (!soundEnabled || !audioCtx) return;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = type;
osc.frequency.value = frequency;
gain.gain.value = volume;
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + duration);
gain.gain.exponentialRampToValueAtTime(
0.001,
audioCtx.currentTime + duration,
);
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start();
@@ -244,7 +267,7 @@
function playNotifySound() {
// Gentle ping
playTone(880, 0.1, 'sine', 0.08);
playTone(880, 0.1, "sine", 0.08);
}
function playRecoverySound() {
@@ -256,7 +279,7 @@
function playReactSound() {
// Cute surprised chirp
playTone(600, 0.08, 'sine', 0.06);
playTone(600, 0.08, "sine", 0.06);
}
function handleStateChange(newState, newEmote) {
@@ -267,13 +290,17 @@
// State transitions that trigger sounds
if (newState !== lastState) {
if (newState === 'critical') {
if (newState === "critical") {
playCriticalSound();
} else if (newState === 'warning') {
} else if (newState === "warning") {
playWarningSound();
} else if (newState === 'notify') {
} else if (newState === "notify") {
playNotifySound();
} else if (newState === 'optimal' && lastState !== 'optimal' && lastState !== 'sleeping') {
} else if (
newState === "optimal" &&
lastState !== "optimal" &&
lastState !== "sleeping"
) {
// Recovery - also check for celebration emote
playRecoverySound();
}
@@ -282,7 +309,7 @@
}
// Handle tap - enable sound and show reaction
document.body.addEventListener('click', () => {
document.body.addEventListener("click", () => {
// Enable sound on first tap (browser autoplay policy)
if (!soundEnabled) {
soundEnabled = true;
@@ -298,8 +325,8 @@
const prevMsg = messageEl.textContent;
// Surprised face!
emoteEl.textContent = '( °o°)';
emoteEl.className = 'popping';
emoteEl.textContent = "( °o°)";
emoteEl.className = "popping";
messageEl.textContent = `Kao ${VERSION}`;
playReactSound();
@@ -320,22 +347,22 @@
// Also init if ?sound=on
if (soundEnabled) {
document.addEventListener('DOMContentLoaded', initAudio);
document.addEventListener("DOMContentLoaded", initAudio);
}
async function fetchStatus() {
try {
const response = await fetch('/status');
if (!response.ok) throw new Error('Failed to fetch');
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
emoteEl.textContent = '( ?.?)';
emoteEl.style.color = '#888888';
emoteEl.className = 'searching';
messageEl.style.color = '#888888';
messageEl.textContent = '';
emoteEl.textContent = "( ?.?)";
emoteEl.style.color = "#888888";
emoteEl.className = "searching";
messageEl.style.color = "#888888";
messageEl.textContent = "";
}
}
@@ -354,10 +381,10 @@
// Only show message when there's something to report
const topEvent = data.active_events && data.active_events[0];
messageEl.textContent = (topEvent && topEvent.message) || '';
messageEl.textContent = (topEvent && topEvent.message) || "";
// Update animation class
emoteEl.className = '';
emoteEl.className = "";
if (data.animation) {
emoteEl.classList.add(data.animation);
}
@@ -367,5 +394,5 @@
fetchStatus();
setInterval(fetchStatus, POLL_INTERVAL);
</script>
</body>
</body>
</html>