@stackbilt/aegis-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/package.json +96 -0
  2. package/schema.sql +586 -0
  3. package/src/adapters/voice/cloudflare-agent.ts +34 -0
  4. package/src/auth.ts +124 -0
  5. package/src/bluesky.ts +464 -0
  6. package/src/claude-tools/content.ts +188 -0
  7. package/src/claude-tools/email.ts +69 -0
  8. package/src/claude-tools/github.ts +440 -0
  9. package/src/claude-tools/goals.ts +116 -0
  10. package/src/claude-tools/index.ts +353 -0
  11. package/src/claude-tools/web.ts +59 -0
  12. package/src/claude.ts +406 -0
  13. package/src/codebeast.ts +200 -0
  14. package/src/composite.ts +715 -0
  15. package/src/content/column.ts +80 -0
  16. package/src/content/hero-image.ts +47 -0
  17. package/src/content/index.ts +27 -0
  18. package/src/content/journal.ts +91 -0
  19. package/src/content/roundtable.ts +163 -0
  20. package/src/core.ts +309 -0
  21. package/src/dashboard.ts +620 -0
  22. package/src/decision-docs.ts +284 -0
  23. package/src/dispatch.ts +13 -0
  24. package/src/edge-env.ts +58 -0
  25. package/src/email.ts +850 -0
  26. package/src/exports.ts +156 -0
  27. package/src/github-projects.ts +312 -0
  28. package/src/github.ts +670 -0
  29. package/src/groq.ts +247 -0
  30. package/src/health-page.ts +578 -0
  31. package/src/index.ts +89 -0
  32. package/src/kernel/argus-actions.ts +397 -0
  33. package/src/kernel/argus-correlation.ts +639 -0
  34. package/src/kernel/board.ts +91 -0
  35. package/src/kernel/briefing.ts +177 -0
  36. package/src/kernel/classify-memory-topic.ts +166 -0
  37. package/src/kernel/cognition.ts +377 -0
  38. package/src/kernel/court-cards.ts +163 -0
  39. package/src/kernel/dispatch.ts +587 -0
  40. package/src/kernel/domain.ts +50 -0
  41. package/src/kernel/dynamic-tools.ts +322 -0
  42. package/src/kernel/executor-port.ts +45 -0
  43. package/src/kernel/executors/claude.ts +73 -0
  44. package/src/kernel/executors/direct.ts +237 -0
  45. package/src/kernel/executors/groq.ts +18 -0
  46. package/src/kernel/executors/index.ts +87 -0
  47. package/src/kernel/executors/tarotscript.ts +104 -0
  48. package/src/kernel/executors/workers-ai.ts +54 -0
  49. package/src/kernel/insight-cache.ts +76 -0
  50. package/src/kernel/memory/agenda.ts +200 -0
  51. package/src/kernel/memory/blocks.ts +188 -0
  52. package/src/kernel/memory/consolidation.ts +194 -0
  53. package/src/kernel/memory/episodic.ts +241 -0
  54. package/src/kernel/memory/goals.ts +156 -0
  55. package/src/kernel/memory/graph.ts +290 -0
  56. package/src/kernel/memory/index.ts +11 -0
  57. package/src/kernel/memory/insights.ts +316 -0
  58. package/src/kernel/memory/procedural.ts +467 -0
  59. package/src/kernel/memory/pruning.ts +67 -0
  60. package/src/kernel/memory/recall.ts +367 -0
  61. package/src/kernel/memory/semantic.ts +315 -0
  62. package/src/kernel/memory/synthesis.ts +161 -0
  63. package/src/kernel/memory-adapter.ts +369 -0
  64. package/src/kernel/memory-guardrails.ts +76 -0
  65. package/src/kernel/port.ts +23 -0
  66. package/src/kernel/resilience.ts +322 -0
  67. package/src/kernel/router.ts +471 -0
  68. package/src/kernel/scheduled/agent-dispatch.ts +252 -0
  69. package/src/kernel/scheduled/argus-analytics.ts +247 -0
  70. package/src/kernel/scheduled/argus-heartbeat.ts +320 -0
  71. package/src/kernel/scheduled/argus-notify.ts +348 -0
  72. package/src/kernel/scheduled/board-sync.ts +110 -0
  73. package/src/kernel/scheduled/ci-watcher.ts +125 -0
  74. package/src/kernel/scheduled/cognitive-metrics.ts +377 -0
  75. package/src/kernel/scheduled/consolidation.ts +229 -0
  76. package/src/kernel/scheduled/content-drip.ts +47 -0
  77. package/src/kernel/scheduled/content.ts +6 -0
  78. package/src/kernel/scheduled/conversation-facts.ts +204 -0
  79. package/src/kernel/scheduled/cost-report.ts +84 -0
  80. package/src/kernel/scheduled/curiosity.ts +219 -0
  81. package/src/kernel/scheduled/dev-activity.ts +44 -0
  82. package/src/kernel/scheduled/digest.ts +317 -0
  83. package/src/kernel/scheduled/dreaming/agenda-triage.ts +115 -0
  84. package/src/kernel/scheduled/dreaming/facts.ts +239 -0
  85. package/src/kernel/scheduled/dreaming/index.ts +8 -0
  86. package/src/kernel/scheduled/dreaming/llm.ts +33 -0
  87. package/src/kernel/scheduled/dreaming/pattern-synthesis.ts +124 -0
  88. package/src/kernel/scheduled/dreaming/persona.ts +75 -0
  89. package/src/kernel/scheduled/dreaming/symbolic.ts +31 -0
  90. package/src/kernel/scheduled/dreaming/task-proposals.ts +80 -0
  91. package/src/kernel/scheduled/dreaming.ts +66 -0
  92. package/src/kernel/scheduled/entropy.ts +149 -0
  93. package/src/kernel/scheduled/escalation.ts +192 -0
  94. package/src/kernel/scheduled/feed-watcher.ts +206 -0
  95. package/src/kernel/scheduled/goals.ts +214 -0
  96. package/src/kernel/scheduled/governance.ts +41 -0
  97. package/src/kernel/scheduled/heartbeat.ts +220 -0
  98. package/src/kernel/scheduled/inbox-processor.ts +174 -0
  99. package/src/kernel/scheduled/index.ts +245 -0
  100. package/src/kernel/scheduled/issue-proposer.ts +478 -0
  101. package/src/kernel/scheduled/issue-watcher.ts +128 -0
  102. package/src/kernel/scheduled/pr-automerge.ts +213 -0
  103. package/src/kernel/scheduled/product-health.ts +107 -0
  104. package/src/kernel/scheduled/reflection.ts +373 -0
  105. package/src/kernel/scheduled/self-improvement.ts +114 -0
  106. package/src/kernel/scheduled/social-engage.ts +175 -0
  107. package/src/kernel/scheduled/task-audit.ts +60 -0
  108. package/src/kernel/symbolic.ts +156 -0
  109. package/src/kernel/types.ts +145 -0
  110. package/src/landing.ts +1190 -0
  111. package/src/lib/audit-chain/chain.ts +28 -0
  112. package/src/lib/audit-chain/types.ts +12 -0
  113. package/src/lib/observability/errors.ts +55 -0
  114. package/src/markdown.ts +164 -0
  115. package/src/mcp/handlers.ts +647 -0
  116. package/src/mcp/server.ts +184 -0
  117. package/src/mcp/tools.ts +316 -0
  118. package/src/mcp-client.ts +275 -0
  119. package/src/mcp-server.ts +2 -0
  120. package/src/operator/config.example.ts +60 -0
  121. package/src/operator/config.ts +60 -0
  122. package/src/operator/index.ts +46 -0
  123. package/src/operator/persona.example.ts +34 -0
  124. package/src/operator/persona.ts +34 -0
  125. package/src/operator/prompt-builder.ts +190 -0
  126. package/src/operator/types.ts +43 -0
  127. package/src/pulse.ts +1179 -0
  128. package/src/routes/bluesky.ts +116 -0
  129. package/src/routes/cc-tasks.ts +328 -0
  130. package/src/routes/codebeast.ts +1 -0
  131. package/src/routes/content.ts +194 -0
  132. package/src/routes/conversations.ts +25 -0
  133. package/src/routes/dynamic-tools.ts +111 -0
  134. package/src/routes/feedback.ts +192 -0
  135. package/src/routes/health.ts +147 -0
  136. package/src/routes/messages.ts +228 -0
  137. package/src/routes/observability.ts +82 -0
  138. package/src/routes/operator-logs.ts +42 -0
  139. package/src/routes/pages.ts +96 -0
  140. package/src/routes/sessions.ts +54 -0
  141. package/src/sanitize.ts +73 -0
  142. package/src/schema-enums.ts +155 -0
  143. package/src/search.ts +112 -0
  144. package/src/task-intelligence.ts +497 -0
  145. package/src/types.ts +194 -0
  146. package/src/ui.ts +5 -0
  147. package/src/version.ts +3 -0
  148. package/src/workers-ai-chat.ts +333 -0
@@ -0,0 +1,578 @@
1
+ /**
2
+ * Health status page — visual system dashboard at /health
3
+ * Returns HTML when Accept header prefers it, JSON otherwise.
4
+ * Designed to look impressive without leaking sensitive info.
5
+ */
6
+
7
+ export interface HealthData {
8
+ version: string;
9
+ kernel: { learned: number; learning: number; degraded: number; broken: number };
10
+ tasks: Array<{ task_name: string; runs: number; ok: number; errors: number; last_run: string }>;
11
+ memoryCount: number;
12
+ agendaCount: number;
13
+ goalCount: number;
14
+ uptimeHours: number;
15
+ docsSyncStatus?: { lastSyncAge: number | null; status: 'ok' | 'warn' | 'alert' };
16
+ }
17
+
18
+ export function healthPage(data: HealthData): string {
19
+ const totalRuns = data.tasks.reduce((s, t) => s + t.runs, 0);
20
+ const totalErrors = data.tasks.reduce((s, t) => s + t.errors, 0);
21
+ const successRate = totalRuns > 0 ? ((totalRuns - totalErrors) / totalRuns * 100).toFixed(1) : '100.0';
22
+ const kernelTotal = data.kernel.learned + data.kernel.learning + data.kernel.degraded + data.kernel.broken;
23
+ const healthScore = kernelTotal > 0
24
+ ? Math.round((data.kernel.learned / kernelTotal) * 100)
25
+ : 100;
26
+
27
+ const statusClass = totalErrors === 0 ? 'nominal' : totalErrors <= 2 ? 'degraded' : 'alert';
28
+ const statusText = totalErrors === 0 ? 'ALL SYSTEMS NOMINAL' : totalErrors <= 2 ? 'MINOR DEGRADATION' : 'ATTENTION REQUIRED';
29
+
30
+ const taskRows = data.tasks.map(t => {
31
+ const status = t.errors === 0 ? 'ok' : 'err';
32
+ const lastRun = t.last_run ? new Date(t.last_run + 'Z').toISOString().replace('T', ' ').slice(0, 19) : '—';
33
+ return `
34
+ <tr class="task-row ${status}">
35
+ <td class="task-status"><span class="dot dot-${status}"></span></td>
36
+ <td class="task-name">${esc(t.task_name)}</td>
37
+ <td class="task-runs">${t.runs}</td>
38
+ <td class="task-ok">${t.ok}</td>
39
+ <td class="task-err">${t.errors}</td>
40
+ <td class="task-last">${lastRun}</td>
41
+ </tr>`;
42
+ }).join('');
43
+
44
+ return `<!DOCTYPE html>
45
+ <html lang="en">
46
+ <head>
47
+ <meta charset="utf-8">
48
+ <meta name="viewport" content="width=device-width, initial-scale=1">
49
+ <title>AEGIS — System Health</title>
50
+ <meta name="description" content="Live system health dashboard for AEGIS, a persistent autonomous AI agent running on Cloudflare's edge.">
51
+ <meta name="theme-color" content="#04040a">
52
+ <link rel="preconnect" href="https://fonts.googleapis.com">
53
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
54
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&family=Syne:wght@700;800&display=swap" rel="stylesheet">
55
+ <style>
56
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
57
+
58
+ :root {
59
+ --bg: #04040a;
60
+ --bg-card: #080812;
61
+ --border: rgba(123, 123, 223, 0.08);
62
+ --border-bright: rgba(123, 123, 223, 0.15);
63
+ --accent: #7b7bdf;
64
+ --accent-glow: #8b8bff;
65
+ --teal: #3dd6c8;
66
+ --green: #2dd4a0;
67
+ --amber: #f5a623;
68
+ --red: #ef4444;
69
+ --text: #c8c8d8;
70
+ --text-dim: #5a5a70;
71
+ --text-muted: #2e2e3e;
72
+ --mono: 'JetBrains Mono', monospace;
73
+ --display: 'Syne', sans-serif;
74
+ }
75
+
76
+ html { -webkit-font-smoothing: antialiased; }
77
+
78
+ body {
79
+ background: var(--bg);
80
+ color: var(--text);
81
+ font-family: var(--mono);
82
+ font-size: 13px;
83
+ line-height: 1.6;
84
+ min-height: 100vh;
85
+ overflow-x: hidden;
86
+ }
87
+
88
+ /* Noise overlay */
89
+ body::before {
90
+ content: '';
91
+ position: fixed;
92
+ inset: 0;
93
+ opacity: 0.02;
94
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
95
+ background-size: 256px 256px;
96
+ pointer-events: none;
97
+ z-index: 1;
98
+ }
99
+
100
+ /* Ambient glow */
101
+ .ambient {
102
+ position: fixed;
103
+ top: -40%;
104
+ left: 50%;
105
+ transform: translateX(-50%);
106
+ width: 140%;
107
+ height: 70%;
108
+ background: radial-gradient(ellipse at center, rgba(123,123,223,0.04) 0%, transparent 65%);
109
+ pointer-events: none;
110
+ z-index: 0;
111
+ animation: breathe 10s ease-in-out infinite;
112
+ }
113
+
114
+ @keyframes breathe {
115
+ 0%, 100% { opacity: 1; }
116
+ 50% { opacity: 0.3; }
117
+ }
118
+
119
+ /* Scan line */
120
+ .scan {
121
+ position: fixed;
122
+ left: 0; right: 0;
123
+ height: 1px;
124
+ background: linear-gradient(90deg, transparent 5%, rgba(123,123,223,0.06) 50%, transparent 95%);
125
+ pointer-events: none;
126
+ z-index: 50;
127
+ animation: scan-move 6s linear infinite;
128
+ }
129
+
130
+ @keyframes scan-move {
131
+ 0% { top: -1px; }
132
+ 100% { top: 100vh; }
133
+ }
134
+
135
+ .wrap {
136
+ position: relative;
137
+ z-index: 2;
138
+ max-width: 960px;
139
+ margin: 0 auto;
140
+ padding: 2rem 1.5rem 4rem;
141
+ }
142
+
143
+ /* ── Header ──────────────────────────── */
144
+ .header {
145
+ display: flex;
146
+ align-items: center;
147
+ justify-content: space-between;
148
+ padding-bottom: 2rem;
149
+ border-bottom: 1px solid var(--border);
150
+ margin-bottom: 2rem;
151
+ }
152
+
153
+ .header-left {
154
+ display: flex;
155
+ align-items: center;
156
+ gap: 1rem;
157
+ }
158
+
159
+ .logo-mark {
160
+ width: 36px;
161
+ height: 36px;
162
+ border-radius: 8px;
163
+ background: linear-gradient(135deg, rgba(123,123,223,0.15), rgba(61,214,200,0.1));
164
+ border: 1px solid var(--border-bright);
165
+ display: flex;
166
+ align-items: center;
167
+ justify-content: center;
168
+ font-family: var(--display);
169
+ font-weight: 800;
170
+ font-size: 14px;
171
+ color: var(--accent-glow);
172
+ }
173
+
174
+ .header-title {
175
+ display: flex;
176
+ flex-direction: column;
177
+ }
178
+
179
+ .header-title h1 {
180
+ font-family: var(--display);
181
+ font-size: 18px;
182
+ font-weight: 800;
183
+ color: var(--text);
184
+ letter-spacing: -0.02em;
185
+ }
186
+
187
+ .header-title span {
188
+ font-size: 11px;
189
+ color: var(--text-dim);
190
+ letter-spacing: 0.06em;
191
+ text-transform: uppercase;
192
+ }
193
+
194
+ .version-tag {
195
+ font-size: 11px;
196
+ padding: 0.25rem 0.65rem;
197
+ border-radius: 4px;
198
+ background: rgba(123,123,223,0.08);
199
+ border: 1px solid var(--border-bright);
200
+ color: var(--accent);
201
+ font-weight: 500;
202
+ }
203
+
204
+ /* ── Status Banner ───────────────────── */
205
+ .status-banner {
206
+ display: flex;
207
+ align-items: center;
208
+ gap: 0.75rem;
209
+ padding: 0.85rem 1.25rem;
210
+ border-radius: 8px;
211
+ margin-bottom: 2rem;
212
+ font-size: 12px;
213
+ font-weight: 500;
214
+ letter-spacing: 0.08em;
215
+ text-transform: uppercase;
216
+ }
217
+
218
+ .status-banner.nominal {
219
+ background: rgba(45, 212, 160, 0.06);
220
+ border: 1px solid rgba(45, 212, 160, 0.15);
221
+ color: var(--green);
222
+ }
223
+
224
+ .status-banner.degraded {
225
+ background: rgba(245, 166, 35, 0.06);
226
+ border: 1px solid rgba(245, 166, 35, 0.15);
227
+ color: var(--amber);
228
+ }
229
+
230
+ .status-banner.alert {
231
+ background: rgba(239, 68, 68, 0.06);
232
+ border: 1px solid rgba(239, 68, 68, 0.15);
233
+ color: var(--red);
234
+ }
235
+
236
+ .status-pulse {
237
+ width: 8px;
238
+ height: 8px;
239
+ border-radius: 50%;
240
+ animation: pulse 2s ease-in-out infinite;
241
+ }
242
+
243
+ .nominal .status-pulse { background: var(--green); box-shadow: 0 0 8px rgba(45,212,160,0.5); }
244
+ .degraded .status-pulse { background: var(--amber); box-shadow: 0 0 8px rgba(245,166,35,0.5); }
245
+ .alert .status-pulse { background: var(--red); box-shadow: 0 0 8px rgba(239,68,68,0.5); }
246
+
247
+ @keyframes pulse {
248
+ 0%, 100% { opacity: 1; transform: scale(1); }
249
+ 50% { opacity: 0.5; transform: scale(1.2); }
250
+ }
251
+
252
+ /* ── Metrics Grid ────────────────────── */
253
+ .metrics {
254
+ display: grid;
255
+ grid-template-columns: repeat(4, 1fr);
256
+ gap: 1rem;
257
+ margin-bottom: 2rem;
258
+ }
259
+
260
+ .metric {
261
+ background: var(--bg-card);
262
+ border: 1px solid var(--border);
263
+ border-radius: 8px;
264
+ padding: 1.25rem;
265
+ transition: border-color 0.2s;
266
+ }
267
+
268
+ .metric:hover {
269
+ border-color: var(--border-bright);
270
+ }
271
+
272
+ .metric-label {
273
+ font-size: 10px;
274
+ color: var(--text-dim);
275
+ text-transform: uppercase;
276
+ letter-spacing: 0.08em;
277
+ margin-bottom: 0.5rem;
278
+ }
279
+
280
+ .metric-value {
281
+ font-size: 28px;
282
+ font-weight: 700;
283
+ color: var(--accent-glow);
284
+ line-height: 1;
285
+ }
286
+
287
+ .metric-value.teal { color: var(--teal); }
288
+ .metric-value.green { color: var(--green); }
289
+ .metric-value.amber { color: var(--amber); }
290
+ .metric-value.red { color: var(--red); }
291
+
292
+ .metric-sub {
293
+ font-size: 10px;
294
+ color: var(--text-dim);
295
+ margin-top: 0.35rem;
296
+ }
297
+
298
+ /* ── Kernel Bar ──────────────────────── */
299
+ .kernel-section {
300
+ margin-bottom: 2rem;
301
+ }
302
+
303
+ .section-label {
304
+ font-size: 10px;
305
+ color: var(--text-dim);
306
+ text-transform: uppercase;
307
+ letter-spacing: 0.1em;
308
+ margin-bottom: 0.75rem;
309
+ }
310
+
311
+ .kernel-bar-wrap {
312
+ background: var(--bg-card);
313
+ border: 1px solid var(--border);
314
+ border-radius: 8px;
315
+ padding: 1.25rem;
316
+ }
317
+
318
+ .kernel-bar {
319
+ display: flex;
320
+ height: 6px;
321
+ border-radius: 3px;
322
+ overflow: hidden;
323
+ margin-bottom: 0.75rem;
324
+ background: rgba(255,255,255,0.02);
325
+ }
326
+
327
+ .kernel-bar .seg-learned { background: var(--green); }
328
+ .kernel-bar .seg-learning { background: var(--teal); }
329
+ .kernel-bar .seg-degraded { background: var(--amber); }
330
+ .kernel-bar .seg-broken { background: var(--red); }
331
+
332
+ .kernel-legend {
333
+ display: flex;
334
+ gap: 1.5rem;
335
+ flex-wrap: wrap;
336
+ }
337
+
338
+ .kernel-legend-item {
339
+ display: flex;
340
+ align-items: center;
341
+ gap: 0.4rem;
342
+ font-size: 11px;
343
+ color: var(--text-dim);
344
+ }
345
+
346
+ .legend-dot {
347
+ width: 6px;
348
+ height: 6px;
349
+ border-radius: 50%;
350
+ }
351
+
352
+ .legend-dot.learned { background: var(--green); }
353
+ .legend-dot.learning { background: var(--teal); }
354
+ .legend-dot.degraded { background: var(--amber); }
355
+ .legend-dot.broken { background: var(--red); }
356
+
357
+ .kernel-legend-item strong {
358
+ color: var(--text);
359
+ font-weight: 500;
360
+ }
361
+
362
+ /* ── Task Table ──────────────────────── */
363
+ .task-section {
364
+ margin-bottom: 2rem;
365
+ }
366
+
367
+ .task-table-wrap {
368
+ background: var(--bg-card);
369
+ border: 1px solid var(--border);
370
+ border-radius: 8px;
371
+ overflow: hidden;
372
+ }
373
+
374
+ table {
375
+ width: 100%;
376
+ border-collapse: collapse;
377
+ }
378
+
379
+ thead th {
380
+ font-size: 10px;
381
+ color: var(--text-dim);
382
+ text-transform: uppercase;
383
+ letter-spacing: 0.06em;
384
+ text-align: left;
385
+ padding: 0.75rem 1rem;
386
+ border-bottom: 1px solid var(--border);
387
+ font-weight: 400;
388
+ }
389
+
390
+ thead th:nth-child(n+3) { text-align: right; }
391
+
392
+ .task-row td {
393
+ padding: 0.6rem 1rem;
394
+ border-bottom: 1px solid rgba(255,255,255,0.02);
395
+ font-size: 12px;
396
+ }
397
+
398
+ .task-row:last-child td { border-bottom: none; }
399
+
400
+ .task-row:hover { background: rgba(123,123,223,0.03); }
401
+
402
+ .task-status { width: 24px; }
403
+ .dot {
404
+ display: inline-block;
405
+ width: 6px;
406
+ height: 6px;
407
+ border-radius: 50%;
408
+ }
409
+ .dot-ok { background: var(--green); box-shadow: 0 0 4px rgba(45,212,160,0.4); }
410
+ .dot-err { background: var(--red); box-shadow: 0 0 4px rgba(239,68,68,0.4); }
411
+
412
+ .task-name { color: var(--text); font-weight: 500; }
413
+ .task-runs, .task-ok, .task-err, .task-last { text-align: right; color: var(--text-dim); }
414
+ .task-row.err .task-err { color: var(--red); font-weight: 500; }
415
+ .task-row.ok .task-ok { color: var(--green); }
416
+
417
+ /* ── Footer ──────────────────────────── */
418
+ .footer {
419
+ display: flex;
420
+ align-items: center;
421
+ justify-content: space-between;
422
+ padding-top: 2rem;
423
+ border-top: 1px solid var(--border);
424
+ font-size: 11px;
425
+ color: var(--text-muted);
426
+ }
427
+
428
+ .footer a {
429
+ color: var(--text-dim);
430
+ text-decoration: none;
431
+ transition: color 0.2s;
432
+ }
433
+
434
+ .footer a:hover { color: var(--accent); }
435
+
436
+ .json-link {
437
+ display: inline-flex;
438
+ align-items: center;
439
+ gap: 0.4rem;
440
+ padding: 0.3rem 0.7rem;
441
+ border-radius: 4px;
442
+ background: rgba(123,123,223,0.06);
443
+ border: 1px solid var(--border);
444
+ color: var(--text-dim);
445
+ text-decoration: none;
446
+ font-size: 11px;
447
+ transition: all 0.2s;
448
+ }
449
+
450
+ .json-link:hover {
451
+ border-color: var(--accent);
452
+ color: var(--accent);
453
+ }
454
+
455
+ /* ── Responsive ──────────────────────── */
456
+ @media (max-width: 640px) {
457
+ .metrics { grid-template-columns: repeat(2, 1fr); }
458
+ .metric-value { font-size: 22px; }
459
+ .header { flex-direction: column; align-items: flex-start; gap: 0.75rem; }
460
+ }
461
+
462
+ /* ── Timestamp Animation ─────────────── */
463
+ @keyframes blink {
464
+ 0%, 100% { opacity: 1; }
465
+ 50% { opacity: 0.3; }
466
+ }
467
+
468
+ .ts-blink {
469
+ animation: blink 1.5s step-end infinite;
470
+ }
471
+ </style>
472
+ </head>
473
+ <body>
474
+ <div class="ambient"></div>
475
+ <div class="scan"></div>
476
+
477
+ <div class="wrap">
478
+ <header class="header">
479
+ <div class="header-left">
480
+ <div class="logo-mark">A</div>
481
+ <div class="header-title">
482
+ <h1>AEGIS</h1>
483
+ <span>System Health Monitor</span>
484
+ </div>
485
+ </div>
486
+ <span class="version-tag">v${esc(data.version)}</span>
487
+ </header>
488
+
489
+ <div class="status-banner ${statusClass}">
490
+ <span class="status-pulse"></span>
491
+ ${statusText}
492
+ </div>
493
+
494
+ <div class="metrics">
495
+ <div class="metric">
496
+ <div class="metric-label">Task Runs (24h)</div>
497
+ <div class="metric-value">${totalRuns}</div>
498
+ <div class="metric-sub">${data.tasks.length} scheduled tasks</div>
499
+ </div>
500
+ <div class="metric">
501
+ <div class="metric-label">Success Rate</div>
502
+ <div class="metric-value green">${successRate}%</div>
503
+ <div class="metric-sub">${totalErrors} error${totalErrors === 1 ? '' : 's'} in 24h</div>
504
+ </div>
505
+ <div class="metric">
506
+ <div class="metric-label">Kernel Health</div>
507
+ <div class="metric-value teal">${healthScore}%</div>
508
+ <div class="metric-sub">${kernelTotal} procedures tracked</div>
509
+ </div>
510
+ <div class="metric">
511
+ <div class="metric-label">Cognitive State</div>
512
+ <div class="metric-value">${data.memoryCount}</div>
513
+ <div class="metric-sub">${data.goalCount} goals / ${data.agendaCount} agenda</div>
514
+ </div>
515
+ <div class="metric">
516
+ <div class="metric-label">Docs Sync</div>
517
+ <div class="metric-value ${data.docsSyncStatus?.status === 'ok' ? 'green' : data.docsSyncStatus?.status === 'alert' ? 'red' : 'amber'}">${data.docsSyncStatus?.lastSyncAge != null ? (data.docsSyncStatus.lastSyncAge < 24 ? data.docsSyncStatus.lastSyncAge + 'h' : Math.round(data.docsSyncStatus.lastSyncAge / 24) + 'd') : '—'}</div>
518
+ <div class="metric-sub">${data.docsSyncStatus?.status === 'ok' ? 'in sync' : data.docsSyncStatus?.lastSyncAge != null ? 'drift detected' : 'no watermark'}</div>
519
+ </div>
520
+ </div>
521
+
522
+ <div class="kernel-section">
523
+ <div class="section-label">Procedural Memory Kernel</div>
524
+ <div class="kernel-bar-wrap">
525
+ <div class="kernel-bar">
526
+ ${kernelTotal > 0 ? `
527
+ <div class="seg-learned" style="width:${(data.kernel.learned / kernelTotal * 100).toFixed(1)}%"></div>
528
+ <div class="seg-learning" style="width:${(data.kernel.learning / kernelTotal * 100).toFixed(1)}%"></div>
529
+ <div class="seg-degraded" style="width:${(data.kernel.degraded / kernelTotal * 100).toFixed(1)}%"></div>
530
+ <div class="seg-broken" style="width:${(data.kernel.broken / kernelTotal * 100).toFixed(1)}%"></div>
531
+ ` : '<div class="seg-learned" style="width:100%"></div>'}
532
+ </div>
533
+ <div class="kernel-legend">
534
+ <div class="kernel-legend-item"><span class="legend-dot learned"></span> Learned <strong>${data.kernel.learned}</strong></div>
535
+ <div class="kernel-legend-item"><span class="legend-dot learning"></span> Learning <strong>${data.kernel.learning}</strong></div>
536
+ <div class="kernel-legend-item"><span class="legend-dot degraded"></span> Degraded <strong>${data.kernel.degraded}</strong></div>
537
+ <div class="kernel-legend-item"><span class="legend-dot broken"></span> Broken <strong>${data.kernel.broken}</strong></div>
538
+ </div>
539
+ </div>
540
+ </div>
541
+
542
+ <div class="task-section">
543
+ <div class="section-label">Task Pipeline (Last 24h)</div>
544
+ <div class="task-table-wrap">
545
+ <table>
546
+ <thead>
547
+ <tr>
548
+ <th></th>
549
+ <th>Task</th>
550
+ <th>Runs</th>
551
+ <th>OK</th>
552
+ <th>Errors</th>
553
+ <th>Last Run (UTC)</th>
554
+ </tr>
555
+ </thead>
556
+ <tbody>
557
+ ${taskRows}
558
+ </tbody>
559
+ </table>
560
+ </div>
561
+ </div>
562
+
563
+ <footer class="footer">
564
+ <span>AEGIS v${esc(data.version)} &middot; edge-native &middot; <span class="ts-blink">&#9679;</span> ${new Date().toISOString().replace('T', ' ').slice(0, 19)} UTC</span>
565
+ <div style="display:flex;gap:1rem;align-items:center">
566
+ <a href="/pulse" class="json-link">Neural Pulse</a>
567
+ <a href="/" class="json-link">Landing</a>
568
+ <a href="/health?format=json" class="json-link">{} JSON</a>
569
+ </div>
570
+ </footer>
571
+ </div>
572
+ </body>
573
+ </html>`;
574
+ }
575
+
576
+ function esc(s: string): string {
577
+ return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
578
+ }
package/src/index.ts ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Default standalone Worker entry point.
3
+ *
4
+ * This file deploys aegis-oss as a self-contained Worker. Consumers who
5
+ * use @stackbilt/aegis-core as a dependency should use createAegisApp()
6
+ * from ./core.ts instead — this file is for standalone deployments only.
7
+ */
8
+
9
+ import { Hono } from 'hono';
10
+ import OAuthProvider from '@cloudflare/workers-oauth-provider';
11
+ import { bearerAuth } from './auth.js';
12
+ import { runScheduledTasks } from './kernel/scheduled/index.js';
13
+ import type { Env } from './types.js';
14
+ import { handleMcpRequest } from './mcp-server.js';
15
+ import { buildEdgeEnv } from './edge-env.js';
16
+
17
+ // Core route modules
18
+ import { health } from './routes/health.js';
19
+ import { sessions } from './routes/sessions.js';
20
+ import { operatorLogs } from './routes/operator-logs.js';
21
+ import { feedback } from './routes/feedback.js';
22
+ import { conversations } from './routes/conversations.js';
23
+ import { observability } from './routes/observability.js';
24
+ import { pages } from './routes/pages.js';
25
+ import { ccTasks } from './routes/cc-tasks.js';
26
+ import { messages } from './routes/messages.js';
27
+ import { content } from './routes/content.js';
28
+ import { codebeast } from './routes/codebeast.js';
29
+ import { bluesky } from './routes/bluesky.js';
30
+ import { dynamicToolsRoutes } from './routes/dynamic-tools.js';
31
+
32
+ const app = new Hono<{ Bindings: Env }>();
33
+
34
+ // ─── Auth ────────────────────────────────────────────────────
35
+ app.use('*', bearerAuth);
36
+
37
+ // ─── Core Route modules ─────────────────────────────────────
38
+ app.route('/', health);
39
+ app.route('/', sessions);
40
+ app.route('/', operatorLogs);
41
+ app.route('/', feedback);
42
+ app.route('/', conversations);
43
+ app.route('/', observability);
44
+ app.route('/', pages);
45
+ app.route('/', ccTasks);
46
+ app.route('/', messages);
47
+ app.route('/', content);
48
+ app.route('/', codebeast);
49
+ app.route('/', bluesky);
50
+ app.route('/', dynamicToolsRoutes);
51
+
52
+ // ─── OAuth 2.1 Provider (wraps /mcp with token auth) ────────
53
+
54
+ function createDefaultOAuthHandler(appFetch: typeof app.fetch) {
55
+ return {
56
+ fetch: (request: Request, env: Env, ctx: ExecutionContext) => {
57
+ return appFetch(request, env, ctx);
58
+ },
59
+ };
60
+ }
61
+
62
+ const oauthProvider = new OAuthProvider<Env>({
63
+ apiRoute: '/mcp',
64
+ apiHandler: {
65
+ fetch: (request: Request, env: Env, ctx: ExecutionContext) =>
66
+ handleMcpRequest(request, buildEdgeEnv(env, ctx)),
67
+ },
68
+ defaultHandler: createDefaultOAuthHandler(app.fetch.bind(app)),
69
+ authorizeEndpoint: '/authorize',
70
+ tokenEndpoint: '/token',
71
+ clientRegistrationEndpoint: '/register',
72
+ scopesSupported: ['mcp'],
73
+ accessTokenTTL: 86400,
74
+ refreshTokenTTL: 2592000,
75
+ resolveExternalToken: async ({ token, env: rawEnv }) => {
76
+ const env = rawEnv as Env;
77
+ if (token === env.AEGIS_TOKEN) {
78
+ return { props: { userId: 'operator', source: 'static_bearer' } };
79
+ }
80
+ return null;
81
+ },
82
+ });
83
+
84
+ export default {
85
+ fetch: oauthProvider.fetch.bind(oauthProvider),
86
+ async scheduled(_event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void> {
87
+ ctx.waitUntil(runScheduledTasks(buildEdgeEnv(env)));
88
+ },
89
+ };