-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.html
More file actions
130 lines (124 loc) · 7.34 KB
/
index.html
File metadata and controls
130 lines (124 loc) · 7.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<!-- CSP disabled: iOS Safari has issues with wildcard connect-src (*.supabase.co) -->
<!-- TODO: re-enable with explicit origins once verified on iOS -->
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: blob: https:; connect-src 'self' https://*.supabase.co wss://*.supabase.co https://*.posthog.com https://*.sentry.io https://api.anthropic.com; worker-src 'self'; manifest-src 'self'; frame-src 'none'; object-src 'none'; base-uri 'self';" /> -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="theme-color" content="#1F1E1D" />
<meta name="description" content="kbot — Terminal AI agent with 560+ tools, 35 specialists, 20 providers. Science lab, finance stack, cybersecurity suite. Runs offline, learns your patterns, MIT licensed." />
<meta name="keywords" content="AI agent, terminal, CLI, science tools, research, physics, chemistry, biology, neuroscience, finance, coding, open source, MIT, offline AI, local models, MCP" />
<link rel="apple-touch-icon" href="/logo-mark-192.png" />
<title>kbot — The AI That Gets Smarter Every Time Anyone Uses It</title>
<link rel="canonical" href="https://kernel.chat/" />
<!-- Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebApplication",
"name": "Kernel",
"url": "https://kernel.chat",
"description": "kbot — Terminal AI agent with 560+ tools, 35 specialists, 20 providers. Science lab, finance stack, cybersecurity suite. Runs offline, learns your patterns, MIT licensed.",
"applicationCategory": "Productivity",
"operatingSystem": "Web",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
}
}
</script>
<!-- Social / Open Graph -->
<meta property="og:title" content="kbot — The AI That Gets Smarter Every Time Anyone Uses It" />
<meta property="og:description" content="kbot — Terminal AI agent with 560+ tools, 35 specialists, 20 providers. Science lab, finance stack, cybersecurity. Runs offline, learns your patterns, MIT licensed." />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://kernel.chat/concepts/og-card-bg.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="kbot — The AI That Gets Smarter Every Time Anyone Uses It" />
<meta name="twitter:description" content="kbot — Terminal AI agent with 560+ tools, 35 specialists, 20 providers. Science lab, finance stack, cybersecurity. Runs offline, learns your patterns, MIT licensed." />
<meta name="twitter:image" content="https://kernel.chat/concepts/og-card-bg.png" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="dns-prefetch" href="https://eoxxpyixdieprsxlpwcs.supabase.co">
<!-- Non-blocking font load: media="print" prevents render-blocking, onload swaps to "all" -->
<link
href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=Courier+Prime:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet" media="print" onload="this.media='all'">
<noscript><link href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=Courier+Prime:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet"></noscript>
</head>
<body>
<div id="root">
<!-- Inline loading indicator — visible instantly while JS loads -->
<div id="splash" style="display:flex;align-items:center;justify-content:center;height:100vh;background:#FAF9F6;font-family:Georgia,'Times New Roman',serif;color:#1F1E1D">
<div style="opacity:.35;font-size:15px;letter-spacing:.08em">kernel</div>
</div>
</div>
<noscript><h1>Kernel — A personal AI that learns you</h1></noscript>
<script type="module" src="/src/main.tsx" onerror="_kernelRecover()"></script>
<script>
// Recovery: if the app JS fails to load (stale SW cache after deploy),
// clear all caches, unregister SW, and reload.
// Debounce: only run once per recovery attempt.
var _recovering = false;
function _kernelRecover() {
if (_recovering) return;
_recovering = true;
var count = parseInt(sessionStorage.getItem('_rc') || '0', 10);
if (count >= 3) {
// Exhausted retries — show manual reload that nukes everything
var splash = document.getElementById('splash');
if (splash) {
splash.innerHTML = '<div style="text-align:center;max-width:280px">'
+ '<div style="opacity:.35;font-size:15px;letter-spacing:.08em;margin-bottom:24px">kernel</div>'
+ '<div style="font-size:14px;opacity:.6;margin-bottom:16px">Updating — one moment.</div>'
+ '<button onclick="sessionStorage.clear();location.reload()" style="font-family:inherit;font-size:14px;padding:10px 24px;border:1px solid #1F1E1D;border-radius:8px;background:none;color:#1F1E1D;cursor:pointer">Reload</button>'
+ '</div>';
}
return;
}
sessionStorage.setItem('_rc', String(count + 1));
// Wait for BOTH SW unregister AND cache clear before reloading
var swDone = Promise.resolve();
if ('serviceWorker' in navigator) {
swDone = navigator.serviceWorker.getRegistrations().then(function(regs) {
return Promise.all(regs.map(function(r) { return r.unregister(); }));
}).catch(function() {});
}
var cacheDone = caches.keys().then(function(names) {
return Promise.all(names.map(function(n) { return caches.delete(n); }));
}).catch(function() {});
Promise.all([swDone, cacheDone]).then(function() {
var url = new URL(location.href);
url.searchParams.set('_cb', Date.now().toString(36));
location.replace(url.toString());
});
}
// Catch JS asset load errors (404 on hashed bundles)
// e.target.src catches <script> load failures; e.filename catches runtime errors
window.addEventListener('error', function(e) {
var src = (e.target && e.target.src) || e.filename || '';
if (/assets\/.*\.(js|css)/.test(src)) _kernelRecover();
}, true);
// Backup: stuck splash screen (8s — enough for slow 3G, fast enough to not frustrate)
setTimeout(function() {
var root = document.getElementById('root');
if (root && root.querySelector('#splash')) _kernelRecover();
}, 8000);
// Clear recovery counter on successful load
window.addEventListener('load', function() {
setTimeout(function() {
if (!document.getElementById('splash')) sessionStorage.removeItem('_rc');
}, 2000);
});
</script>
</body>
</html>