feat: initial SleepGuard implementation

Wake-on-demand proxy + agent system with SvelteKit dashboard.
Monorepo: shared types, proxy (Hono + http-proxy), agent (monitors + locks), web (SvelteKit SPA).

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Vadim Sobinin
2026-02-10 13:46:51 +03:00
commit 852e01df39
64 changed files with 4864 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
export function getWakingPageHtml(serviceName: string): string {
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Waking up — ${serviceName}</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
background: #0f172a;
color: #e2e8f0;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.container {
text-align: center;
padding: 2rem;
}
.spinner {
width: 48px; height: 48px;
border: 4px solid #334155;
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 1.5rem;
}
@keyframes spin { to { transform: rotate(360deg); } }
h1 { font-size: 1.5rem; margin-bottom: 0.5rem; }
p { color: #94a3b8; font-size: 0.95rem; }
.status { margin-top: 1rem; font-size: 0.85rem; color: #64748b; }
.status.ready { color: #22c55e; }
</style>
</head>
<body>
<div class="container">
<div class="spinner" id="spinner"></div>
<h1>Waking up ${serviceName}...</h1>
<p>The server is starting. This page will reload automatically.</p>
<p class="status" id="status">Waiting for response...</p>
</div>
<script>
const CHECK_INTERVAL = 3000;
let attempt = 0;
async function check() {
attempt++;
const el = document.getElementById('status');
el.textContent = 'Checking... (attempt ' + attempt + ')';
try {
const res = await fetch(window.location.href, { redirect: 'follow' });
const text = await res.text();
if (!text.includes('Waking up')) {
el.textContent = 'Ready! Reloading...';
el.className = 'status ready';
window.location.reload();
return;
}
} catch (e) {}
setTimeout(check, CHECK_INTERVAL);
}
setTimeout(check, CHECK_INTERVAL);
</script>
</body>
</html>`;
}