agent-relay 2.0.23 → 2.0.24

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 (168) hide show
  1. package/dist/src/cli/index.js +66 -13
  2. package/package.json +18 -52
  3. package/packages/api-types/package.json +1 -1
  4. package/packages/bridge/package.json +8 -8
  5. package/packages/cli-tester/package.json +1 -1
  6. package/packages/config/package.json +2 -2
  7. package/packages/continuity/package.json +1 -1
  8. package/packages/daemon/package.json +12 -12
  9. package/packages/hooks/package.json +4 -4
  10. package/packages/mcp/package.json +2 -2
  11. package/packages/memory/package.json +2 -2
  12. package/packages/policy/package.json +2 -2
  13. package/packages/protocol/package.json +1 -1
  14. package/packages/resiliency/package.json +1 -1
  15. package/packages/sdk/package.json +2 -2
  16. package/packages/spawner/package.json +1 -1
  17. package/packages/state/package.json +1 -1
  18. package/packages/storage/package.json +2 -2
  19. package/packages/telemetry/package.json +1 -1
  20. package/packages/trajectory/package.json +2 -2
  21. package/packages/user-directory/package.json +2 -2
  22. package/packages/utils/package.json +1 -1
  23. package/packages/wrapper/package.json +6 -6
  24. package/deploy/init-db.sql +0 -5
  25. package/deploy/scripts/setup-fly-workspaces.sh +0 -69
  26. package/deploy/scripts/setup-railway.sh +0 -75
  27. package/dist/src/cloud/index.d.ts +0 -8
  28. package/dist/src/cloud/index.js +0 -8
  29. package/packages/cloud/dist/api/admin.d.ts +0 -8
  30. package/packages/cloud/dist/api/admin.js +0 -225
  31. package/packages/cloud/dist/api/auth.d.ts +0 -20
  32. package/packages/cloud/dist/api/auth.js +0 -138
  33. package/packages/cloud/dist/api/billing.d.ts +0 -7
  34. package/packages/cloud/dist/api/billing.js +0 -564
  35. package/packages/cloud/dist/api/cli-pty-runner.d.ts +0 -53
  36. package/packages/cloud/dist/api/cli-pty-runner.js +0 -175
  37. package/packages/cloud/dist/api/codex-auth-helper.d.ts +0 -21
  38. package/packages/cloud/dist/api/codex-auth-helper.js +0 -327
  39. package/packages/cloud/dist/api/consensus.d.ts +0 -13
  40. package/packages/cloud/dist/api/consensus.js +0 -261
  41. package/packages/cloud/dist/api/coordinators.d.ts +0 -8
  42. package/packages/cloud/dist/api/coordinators.js +0 -750
  43. package/packages/cloud/dist/api/daemons.d.ts +0 -12
  44. package/packages/cloud/dist/api/daemons.js +0 -535
  45. package/packages/cloud/dist/api/email-auth.d.ts +0 -11
  46. package/packages/cloud/dist/api/email-auth.js +0 -347
  47. package/packages/cloud/dist/api/generic-webhooks.d.ts +0 -8
  48. package/packages/cloud/dist/api/generic-webhooks.js +0 -129
  49. package/packages/cloud/dist/api/git.d.ts +0 -8
  50. package/packages/cloud/dist/api/git.js +0 -269
  51. package/packages/cloud/dist/api/github-app.d.ts +0 -11
  52. package/packages/cloud/dist/api/github-app.js +0 -223
  53. package/packages/cloud/dist/api/middleware/planLimits.d.ts +0 -43
  54. package/packages/cloud/dist/api/middleware/planLimits.js +0 -202
  55. package/packages/cloud/dist/api/monitoring.d.ts +0 -11
  56. package/packages/cloud/dist/api/monitoring.js +0 -578
  57. package/packages/cloud/dist/api/nango-auth.d.ts +0 -9
  58. package/packages/cloud/dist/api/nango-auth.js +0 -741
  59. package/packages/cloud/dist/api/onboarding.d.ts +0 -15
  60. package/packages/cloud/dist/api/onboarding.js +0 -679
  61. package/packages/cloud/dist/api/policy.d.ts +0 -8
  62. package/packages/cloud/dist/api/policy.js +0 -229
  63. package/packages/cloud/dist/api/provider-env.d.ts +0 -26
  64. package/packages/cloud/dist/api/provider-env.js +0 -141
  65. package/packages/cloud/dist/api/providers.d.ts +0 -7
  66. package/packages/cloud/dist/api/providers.js +0 -574
  67. package/packages/cloud/dist/api/repos.d.ts +0 -8
  68. package/packages/cloud/dist/api/repos.js +0 -577
  69. package/packages/cloud/dist/api/sessions.d.ts +0 -11
  70. package/packages/cloud/dist/api/sessions.js +0 -302
  71. package/packages/cloud/dist/api/teams.d.ts +0 -7
  72. package/packages/cloud/dist/api/teams.js +0 -281
  73. package/packages/cloud/dist/api/test-helpers.d.ts +0 -10
  74. package/packages/cloud/dist/api/test-helpers.js +0 -745
  75. package/packages/cloud/dist/api/usage.d.ts +0 -7
  76. package/packages/cloud/dist/api/usage.js +0 -111
  77. package/packages/cloud/dist/api/webhooks.d.ts +0 -8
  78. package/packages/cloud/dist/api/webhooks.js +0 -645
  79. package/packages/cloud/dist/api/workspaces.d.ts +0 -25
  80. package/packages/cloud/dist/api/workspaces.js +0 -1799
  81. package/packages/cloud/dist/billing/index.d.ts +0 -9
  82. package/packages/cloud/dist/billing/index.js +0 -9
  83. package/packages/cloud/dist/billing/plans.d.ts +0 -39
  84. package/packages/cloud/dist/billing/plans.js +0 -245
  85. package/packages/cloud/dist/billing/service.d.ts +0 -80
  86. package/packages/cloud/dist/billing/service.js +0 -388
  87. package/packages/cloud/dist/billing/types.d.ts +0 -141
  88. package/packages/cloud/dist/billing/types.js +0 -7
  89. package/packages/cloud/dist/config.d.ts +0 -5
  90. package/packages/cloud/dist/config.js +0 -5
  91. package/packages/cloud/dist/db/bulk-ingest.d.ts +0 -89
  92. package/packages/cloud/dist/db/bulk-ingest.js +0 -268
  93. package/packages/cloud/dist/db/drizzle.d.ts +0 -290
  94. package/packages/cloud/dist/db/drizzle.js +0 -1422
  95. package/packages/cloud/dist/db/index.d.ts +0 -56
  96. package/packages/cloud/dist/db/index.js +0 -70
  97. package/packages/cloud/dist/db/schema.d.ts +0 -5117
  98. package/packages/cloud/dist/db/schema.js +0 -656
  99. package/packages/cloud/dist/index.d.ts +0 -11
  100. package/packages/cloud/dist/index.js +0 -38
  101. package/packages/cloud/dist/provisioner/index.d.ts +0 -207
  102. package/packages/cloud/dist/provisioner/index.js +0 -2118
  103. package/packages/cloud/dist/server.d.ts +0 -17
  104. package/packages/cloud/dist/server.js +0 -2055
  105. package/packages/cloud/dist/services/auto-scaler.d.ts +0 -152
  106. package/packages/cloud/dist/services/auto-scaler.js +0 -439
  107. package/packages/cloud/dist/services/capacity-manager.d.ts +0 -148
  108. package/packages/cloud/dist/services/capacity-manager.js +0 -449
  109. package/packages/cloud/dist/services/ci-agent-spawner.d.ts +0 -49
  110. package/packages/cloud/dist/services/ci-agent-spawner.js +0 -373
  111. package/packages/cloud/dist/services/cloud-message-bus.d.ts +0 -28
  112. package/packages/cloud/dist/services/cloud-message-bus.js +0 -19
  113. package/packages/cloud/dist/services/compute-enforcement.d.ts +0 -57
  114. package/packages/cloud/dist/services/compute-enforcement.js +0 -175
  115. package/packages/cloud/dist/services/coordinator.d.ts +0 -62
  116. package/packages/cloud/dist/services/coordinator.js +0 -389
  117. package/packages/cloud/dist/services/index.d.ts +0 -17
  118. package/packages/cloud/dist/services/index.js +0 -25
  119. package/packages/cloud/dist/services/intro-expiration.d.ts +0 -60
  120. package/packages/cloud/dist/services/intro-expiration.js +0 -252
  121. package/packages/cloud/dist/services/mention-handler.d.ts +0 -65
  122. package/packages/cloud/dist/services/mention-handler.js +0 -405
  123. package/packages/cloud/dist/services/nango.d.ts +0 -219
  124. package/packages/cloud/dist/services/nango.js +0 -424
  125. package/packages/cloud/dist/services/persistence.d.ts +0 -131
  126. package/packages/cloud/dist/services/persistence.js +0 -200
  127. package/packages/cloud/dist/services/planLimits.d.ts +0 -147
  128. package/packages/cloud/dist/services/planLimits.js +0 -335
  129. package/packages/cloud/dist/services/presence-registry.d.ts +0 -56
  130. package/packages/cloud/dist/services/presence-registry.js +0 -91
  131. package/packages/cloud/dist/services/scaling-orchestrator.d.ts +0 -159
  132. package/packages/cloud/dist/services/scaling-orchestrator.js +0 -502
  133. package/packages/cloud/dist/services/scaling-policy.d.ts +0 -121
  134. package/packages/cloud/dist/services/scaling-policy.js +0 -415
  135. package/packages/cloud/dist/services/ssh-security.d.ts +0 -31
  136. package/packages/cloud/dist/services/ssh-security.js +0 -63
  137. package/packages/cloud/dist/services/workspace-keepalive.d.ts +0 -76
  138. package/packages/cloud/dist/services/workspace-keepalive.js +0 -234
  139. package/packages/cloud/dist/shims/consensus.d.ts +0 -23
  140. package/packages/cloud/dist/shims/consensus.js +0 -5
  141. package/packages/cloud/dist/webhooks/index.d.ts +0 -24
  142. package/packages/cloud/dist/webhooks/index.js +0 -29
  143. package/packages/cloud/dist/webhooks/parsers/github.d.ts +0 -8
  144. package/packages/cloud/dist/webhooks/parsers/github.js +0 -234
  145. package/packages/cloud/dist/webhooks/parsers/index.d.ts +0 -23
  146. package/packages/cloud/dist/webhooks/parsers/index.js +0 -30
  147. package/packages/cloud/dist/webhooks/parsers/linear.d.ts +0 -9
  148. package/packages/cloud/dist/webhooks/parsers/linear.js +0 -258
  149. package/packages/cloud/dist/webhooks/parsers/slack.d.ts +0 -9
  150. package/packages/cloud/dist/webhooks/parsers/slack.js +0 -214
  151. package/packages/cloud/dist/webhooks/responders/github.d.ts +0 -8
  152. package/packages/cloud/dist/webhooks/responders/github.js +0 -73
  153. package/packages/cloud/dist/webhooks/responders/index.d.ts +0 -23
  154. package/packages/cloud/dist/webhooks/responders/index.js +0 -30
  155. package/packages/cloud/dist/webhooks/responders/linear.d.ts +0 -9
  156. package/packages/cloud/dist/webhooks/responders/linear.js +0 -149
  157. package/packages/cloud/dist/webhooks/responders/slack.d.ts +0 -20
  158. package/packages/cloud/dist/webhooks/responders/slack.js +0 -178
  159. package/packages/cloud/dist/webhooks/router.d.ts +0 -25
  160. package/packages/cloud/dist/webhooks/router.js +0 -504
  161. package/packages/cloud/dist/webhooks/rules-engine.d.ts +0 -24
  162. package/packages/cloud/dist/webhooks/rules-engine.js +0 -287
  163. package/packages/cloud/dist/webhooks/types.d.ts +0 -186
  164. package/packages/cloud/dist/webhooks/types.js +0 -8
  165. package/packages/cloud/package.json +0 -60
  166. package/scripts/run-migrations.js +0 -43
  167. package/scripts/setup-stripe-products.ts +0 -312
  168. package/scripts/verify-schema.js +0 -134
@@ -1,578 +0,0 @@
1
- /**
2
- * Agent Monitoring API Routes
3
- *
4
- * Provides endpoints for:
5
- * - Real-time memory metrics collection
6
- * - Crash insights and history
7
- * - Proactive alerting
8
- * - System health dashboard
9
- */
10
- import { Router } from 'express';
11
- import { createHash } from 'crypto';
12
- import { eq, desc, and, gte, sql } from 'drizzle-orm';
13
- import { requireAuth } from './auth.js';
14
- import { db as dbModule } from '../db/index.js';
15
- import { getDb } from '../db/drizzle.js';
16
- import { agentMetrics, agentCrashes, memoryAlerts, } from '../db/schema.js';
17
- export const monitoringRouter = Router();
18
- /**
19
- * Hash an API key for lookup
20
- */
21
- function hashApiKey(apiKey) {
22
- return createHash('sha256').update(apiKey).digest('hex');
23
- }
24
- /**
25
- * Middleware to authenticate daemon by API key
26
- */
27
- async function requireDaemonAuth(req, res, next) {
28
- const authHeader = req.headers.authorization;
29
- if (!authHeader || !authHeader.startsWith('Bearer ar_live_')) {
30
- res.status(401).json({ error: 'Invalid API key format' });
31
- return;
32
- }
33
- const apiKey = authHeader.replace('Bearer ', '');
34
- const apiKeyHash = hashApiKey(apiKey);
35
- try {
36
- const daemon = await dbModule.linkedDaemons.findByApiKeyHash(apiKeyHash);
37
- if (!daemon) {
38
- res.status(401).json({ error: 'Invalid API key' });
39
- return;
40
- }
41
- req.daemon = daemon;
42
- next();
43
- }
44
- catch (error) {
45
- console.error('Daemon auth error:', error);
46
- res.status(500).json({ error: 'Authentication failed' });
47
- }
48
- }
49
- // ============================================================================
50
- // Daemon API (authenticated with API key)
51
- // ============================================================================
52
- /**
53
- * POST /api/monitoring/metrics
54
- * Report agent memory metrics from daemon
55
- */
56
- monitoringRouter.post('/metrics', requireDaemonAuth, async (req, res) => {
57
- const daemon = req.daemon;
58
- const { agents } = req.body;
59
- if (!agents || !Array.isArray(agents)) {
60
- return res.status(400).json({ error: 'agents array is required' });
61
- }
62
- try {
63
- const db = getDb();
64
- const now = new Date();
65
- // Insert metrics for each agent
66
- for (const agent of agents) {
67
- const metricsData = {
68
- rssBytes: agent.rssBytes || 0,
69
- heapUsedBytes: agent.heapUsedBytes || 0,
70
- heapTotalBytes: agent.heapTotalBytes || 0,
71
- cpuPercent: agent.cpuPercent || 0,
72
- trend: agent.trend || 'unknown',
73
- trendRatePerMinute: agent.trendRatePerMinute || 0,
74
- alertLevel: agent.alertLevel || 'normal',
75
- highWatermark: agent.highWatermark || 0,
76
- averageRss: agent.averageRss || 0,
77
- };
78
- await db.insert(agentMetrics).values({
79
- daemonId: daemon.id,
80
- agentName: agent.name,
81
- pid: agent.pid,
82
- status: agent.status || 'unknown',
83
- rssBytes: agent.rssBytes,
84
- heapUsedBytes: agent.heapUsedBytes,
85
- cpuPercent: Math.round(agent.cpuPercent || 0),
86
- trend: agent.trend,
87
- trendRatePerMinute: Math.round(agent.trendRatePerMinute || 0),
88
- alertLevel: agent.alertLevel,
89
- highWatermark: agent.highWatermark,
90
- averageRss: Math.round(agent.averageRss || 0),
91
- metricsData,
92
- uptimeMs: agent.uptimeMs,
93
- startedAt: agent.startedAt ? new Date(agent.startedAt) : null,
94
- recordedAt: now,
95
- });
96
- }
97
- res.json({ success: true, recorded: agents.length });
98
- }
99
- catch (error) {
100
- console.error('Error recording metrics:', error);
101
- res.status(500).json({ error: 'Failed to record metrics' });
102
- }
103
- });
104
- /**
105
- * POST /api/monitoring/crash
106
- * Report an agent crash from daemon
107
- */
108
- monitoringRouter.post('/crash', requireDaemonAuth, async (req, res) => {
109
- const daemon = req.daemon;
110
- const { crash } = req.body;
111
- if (!crash || !crash.agentName) {
112
- return res.status(400).json({ error: 'crash object with agentName is required' });
113
- }
114
- try {
115
- const db = getDb();
116
- const insightData = {
117
- likelyCause: crash.likelyCause || 'unknown',
118
- confidence: crash.confidence || 'low',
119
- summary: crash.summary || '',
120
- details: crash.details || [],
121
- recommendations: crash.recommendations || [],
122
- peakMemory: crash.peakMemory || 0,
123
- lastKnownMemory: crash.lastKnownMemory || null,
124
- };
125
- const [inserted] = await db.insert(agentCrashes).values({
126
- daemonId: daemon.id,
127
- agentName: crash.agentName,
128
- pid: crash.pid,
129
- exitCode: crash.exitCode,
130
- signal: crash.signal,
131
- reason: crash.reason,
132
- likelyCause: crash.likelyCause,
133
- confidence: crash.confidence,
134
- summary: crash.summary,
135
- peakMemory: crash.peakMemory,
136
- lastKnownMemory: crash.lastKnownMemory,
137
- memoryTrend: crash.memoryTrend,
138
- insightData,
139
- lastOutput: crash.lastOutput?.slice(0, 10000), // Limit to 10KB
140
- crashedAt: crash.crashedAt ? new Date(crash.crashedAt) : new Date(),
141
- }).returning();
142
- res.json({ success: true, crashId: inserted.id });
143
- }
144
- catch (error) {
145
- console.error('Error recording crash:', error);
146
- res.status(500).json({ error: 'Failed to record crash' });
147
- }
148
- });
149
- /**
150
- * POST /api/monitoring/alert
151
- * Report a memory alert from daemon
152
- */
153
- monitoringRouter.post('/alert', requireDaemonAuth, async (req, res) => {
154
- const daemon = req.daemon;
155
- const { alert } = req.body;
156
- if (!alert || !alert.agentName || !alert.alertType) {
157
- return res.status(400).json({ error: 'alert object with agentName and alertType is required' });
158
- }
159
- try {
160
- const db = getDb();
161
- const [inserted] = await db.insert(memoryAlerts).values({
162
- daemonId: daemon.id,
163
- agentName: alert.agentName,
164
- alertType: alert.alertType,
165
- currentRss: alert.currentRss,
166
- threshold: alert.threshold,
167
- message: alert.message,
168
- recommendation: alert.recommendation,
169
- }).returning();
170
- res.json({ success: true, alertId: inserted.id });
171
- }
172
- catch (error) {
173
- console.error('Error recording alert:', error);
174
- res.status(500).json({ error: 'Failed to record alert' });
175
- }
176
- });
177
- // ============================================================================
178
- // Browser API (authenticated with session)
179
- // ============================================================================
180
- /**
181
- * GET /api/monitoring/overview
182
- * Get monitoring overview for user's daemons
183
- */
184
- monitoringRouter.get('/overview', requireAuth, async (req, res) => {
185
- const userId = req.session.userId;
186
- try {
187
- const db = getDb();
188
- // Get all user's daemons
189
- const daemons = await dbModule.linkedDaemons.findByUserId(userId);
190
- if (daemons.length === 0) {
191
- return res.json({
192
- daemons: [],
193
- summary: {
194
- totalAgents: 0,
195
- healthyAgents: 0,
196
- warningAgents: 0,
197
- criticalAgents: 0,
198
- totalCrashes24h: 0,
199
- totalAlerts24h: 0,
200
- },
201
- });
202
- }
203
- const daemonIds = daemons.map(d => d.id);
204
- const last24h = new Date(Date.now() - 24 * 60 * 60 * 1000);
205
- // Get latest metrics for each agent (subquery to get latest per agent)
206
- const latestMetrics = await db
207
- .select()
208
- .from(agentMetrics)
209
- .where(and(sql `${agentMetrics.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`, gte(agentMetrics.recordedAt, last24h)))
210
- .orderBy(desc(agentMetrics.recordedAt))
211
- .limit(100);
212
- // Get crash count in last 24h
213
- const crashCount = await db
214
- .select({ count: sql `count(*)` })
215
- .from(agentCrashes)
216
- .where(and(sql `${agentCrashes.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`, gte(agentCrashes.crashedAt, last24h)));
217
- // Get alert count in last 24h
218
- const alertCount = await db
219
- .select({ count: sql `count(*)` })
220
- .from(memoryAlerts)
221
- .where(and(sql `${memoryAlerts.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`, gte(memoryAlerts.createdAt, last24h)));
222
- // Aggregate by alert level
223
- const byAlertLevel = {
224
- normal: 0,
225
- warning: 0,
226
- critical: 0,
227
- oom_imminent: 0,
228
- };
229
- // Deduplicate by agent name (keep latest)
230
- const agentLatest = new Map();
231
- for (const m of latestMetrics) {
232
- const key = `${m.daemonId}:${m.agentName}`;
233
- if (!agentLatest.has(key)) {
234
- agentLatest.set(key, m);
235
- byAlertLevel[m.alertLevel] =
236
- (byAlertLevel[m.alertLevel] || 0) + 1;
237
- }
238
- }
239
- res.json({
240
- daemons: daemons.map(d => ({
241
- id: d.id,
242
- name: d.name,
243
- machineId: d.machineId,
244
- status: d.status,
245
- lastSeenAt: d.lastSeenAt,
246
- })),
247
- summary: {
248
- totalAgents: agentLatest.size,
249
- healthyAgents: byAlertLevel.normal,
250
- warningAgents: byAlertLevel.warning,
251
- criticalAgents: byAlertLevel.critical + byAlertLevel.oom_imminent,
252
- totalCrashes24h: Number(crashCount[0]?.count || 0),
253
- totalAlerts24h: Number(alertCount[0]?.count || 0),
254
- },
255
- latestMetrics: Array.from(agentLatest.values()),
256
- });
257
- }
258
- catch (error) {
259
- console.error('Error fetching monitoring overview:', error);
260
- res.status(500).json({ error: 'Failed to fetch monitoring overview' });
261
- }
262
- });
263
- /**
264
- * GET /api/monitoring/agents/:agentName/metrics
265
- * Get detailed metrics history for an agent
266
- */
267
- monitoringRouter.get('/agents/:agentName/metrics', requireAuth, async (req, res) => {
268
- const userId = req.session.userId;
269
- const agentName = req.params.agentName;
270
- const { daemonId, hours = '24' } = req.query;
271
- try {
272
- const db = getDb();
273
- // Verify daemon belongs to user
274
- if (daemonId) {
275
- const daemon = await dbModule.linkedDaemons.findById(daemonId);
276
- if (!daemon || daemon.userId !== userId) {
277
- return res.status(404).json({ error: 'Daemon not found' });
278
- }
279
- }
280
- const since = new Date(Date.now() - parseInt(hours) * 60 * 60 * 1000);
281
- // Get user's daemons
282
- const daemons = await dbModule.linkedDaemons.findByUserId(userId);
283
- const daemonIds = daemonId ? [daemonId] : daemons.map(d => d.id);
284
- const metrics = await db
285
- .select()
286
- .from(agentMetrics)
287
- .where(and(sql `${agentMetrics.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`, eq(agentMetrics.agentName, agentName), gte(agentMetrics.recordedAt, since)))
288
- .orderBy(desc(agentMetrics.recordedAt))
289
- .limit(1000);
290
- // Calculate statistics
291
- const rssSamples = metrics.map(m => Number(m.rssBytes || 0));
292
- const stats = {
293
- count: metrics.length,
294
- avgRss: rssSamples.length > 0 ? rssSamples.reduce((a, b) => a + b, 0) / rssSamples.length : 0,
295
- maxRss: rssSamples.length > 0 ? Math.max(...rssSamples) : 0,
296
- minRss: rssSamples.length > 0 ? Math.min(...rssSamples) : 0,
297
- latestTrend: metrics[0]?.trend || 'unknown',
298
- latestAlertLevel: metrics[0]?.alertLevel || 'normal',
299
- };
300
- res.json({
301
- agentName,
302
- metrics,
303
- stats,
304
- });
305
- }
306
- catch (error) {
307
- console.error('Error fetching agent metrics:', error);
308
- res.status(500).json({ error: 'Failed to fetch agent metrics' });
309
- }
310
- });
311
- /**
312
- * GET /api/monitoring/crashes
313
- * Get crash history
314
- */
315
- monitoringRouter.get('/crashes', requireAuth, async (req, res) => {
316
- const userId = req.session.userId;
317
- const { daemonId, agentName, limit = '50' } = req.query;
318
- try {
319
- const db = getDb();
320
- // Get user's daemons
321
- const daemons = await dbModule.linkedDaemons.findByUserId(userId);
322
- const daemonIds = daemonId ? [daemonId] : daemons.map(d => d.id);
323
- let query = db
324
- .select()
325
- .from(agentCrashes)
326
- .where(sql `${agentCrashes.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`);
327
- if (agentName) {
328
- query = db
329
- .select()
330
- .from(agentCrashes)
331
- .where(and(sql `${agentCrashes.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`, eq(agentCrashes.agentName, agentName)));
332
- }
333
- const crashes = await query
334
- .orderBy(desc(agentCrashes.crashedAt))
335
- .limit(parseInt(limit));
336
- // Get crash statistics by cause
337
- const byCause = {};
338
- for (const crash of crashes) {
339
- const cause = crash.likelyCause || 'unknown';
340
- byCause[cause] = (byCause[cause] || 0) + 1;
341
- }
342
- res.json({
343
- crashes,
344
- stats: {
345
- total: crashes.length,
346
- byCause,
347
- },
348
- });
349
- }
350
- catch (error) {
351
- console.error('Error fetching crashes:', error);
352
- res.status(500).json({ error: 'Failed to fetch crashes' });
353
- }
354
- });
355
- /**
356
- * GET /api/monitoring/crashes/:id
357
- * Get detailed crash information
358
- */
359
- monitoringRouter.get('/crashes/:id', requireAuth, async (req, res) => {
360
- const userId = req.session.userId;
361
- const id = req.params.id;
362
- try {
363
- const db = getDb();
364
- const [crash] = await db
365
- .select()
366
- .from(agentCrashes)
367
- .where(eq(agentCrashes.id, id))
368
- .limit(1);
369
- if (!crash) {
370
- return res.status(404).json({ error: 'Crash not found' });
371
- }
372
- // Verify user owns this daemon
373
- const daemon = await dbModule.linkedDaemons.findById(crash.daemonId);
374
- if (!daemon || daemon.userId !== userId) {
375
- return res.status(404).json({ error: 'Crash not found' });
376
- }
377
- res.json({ crash, daemon: { id: daemon.id, name: daemon.name } });
378
- }
379
- catch (error) {
380
- console.error('Error fetching crash:', error);
381
- res.status(500).json({ error: 'Failed to fetch crash' });
382
- }
383
- });
384
- /**
385
- * GET /api/monitoring/alerts
386
- * Get memory alerts
387
- */
388
- monitoringRouter.get('/alerts', requireAuth, async (req, res) => {
389
- const userId = req.session.userId;
390
- const { daemonId, acknowledged, limit = '100' } = req.query;
391
- try {
392
- const db = getDb();
393
- // Get user's daemons
394
- const daemons = await dbModule.linkedDaemons.findByUserId(userId);
395
- const daemonIds = daemonId ? [daemonId] : daemons.map(d => d.id);
396
- const whereConditions = [
397
- sql `${memoryAlerts.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`
398
- ];
399
- if (acknowledged !== undefined) {
400
- whereConditions.push(eq(memoryAlerts.acknowledged, acknowledged === 'true'));
401
- }
402
- const alerts = await db
403
- .select()
404
- .from(memoryAlerts)
405
- .where(and(...whereConditions))
406
- .orderBy(desc(memoryAlerts.createdAt))
407
- .limit(parseInt(limit));
408
- // Count unacknowledged
409
- const unacknowledgedCount = await db
410
- .select({ count: sql `count(*)` })
411
- .from(memoryAlerts)
412
- .where(and(sql `${memoryAlerts.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`, eq(memoryAlerts.acknowledged, false)));
413
- res.json({
414
- alerts,
415
- unacknowledgedCount: Number(unacknowledgedCount[0]?.count || 0),
416
- });
417
- }
418
- catch (error) {
419
- console.error('Error fetching alerts:', error);
420
- res.status(500).json({ error: 'Failed to fetch alerts' });
421
- }
422
- });
423
- /**
424
- * POST /api/monitoring/alerts/:id/acknowledge
425
- * Acknowledge an alert
426
- */
427
- monitoringRouter.post('/alerts/:id/acknowledge', requireAuth, async (req, res) => {
428
- const userId = req.session.userId;
429
- const id = req.params.id;
430
- try {
431
- const db = getDb();
432
- // Get the alert
433
- const [alert] = await db
434
- .select()
435
- .from(memoryAlerts)
436
- .where(eq(memoryAlerts.id, id))
437
- .limit(1);
438
- if (!alert) {
439
- return res.status(404).json({ error: 'Alert not found' });
440
- }
441
- // Verify user owns this daemon
442
- const daemon = await dbModule.linkedDaemons.findById(alert.daemonId);
443
- if (!daemon || daemon.userId !== userId) {
444
- return res.status(404).json({ error: 'Alert not found' });
445
- }
446
- // Update alert
447
- await db
448
- .update(memoryAlerts)
449
- .set({
450
- acknowledged: true,
451
- acknowledgedAt: new Date(),
452
- })
453
- .where(eq(memoryAlerts.id, id));
454
- res.json({ success: true });
455
- }
456
- catch (error) {
457
- console.error('Error acknowledging alert:', error);
458
- res.status(500).json({ error: 'Failed to acknowledge alert' });
459
- }
460
- });
461
- /**
462
- * GET /api/monitoring/insights
463
- * Get overall system insights and recommendations
464
- */
465
- monitoringRouter.get('/insights', requireAuth, async (req, res) => {
466
- const userId = req.session.userId;
467
- try {
468
- const db = getDb();
469
- // Get user's daemons
470
- const daemons = await dbModule.linkedDaemons.findByUserId(userId);
471
- if (daemons.length === 0) {
472
- return res.json({
473
- healthScore: 100,
474
- summary: 'No daemons connected. Link a daemon to start monitoring.',
475
- issues: [],
476
- recommendations: ['Connect a local daemon using `agent-relay cloud link`'],
477
- });
478
- }
479
- const daemonIds = daemons.map(d => d.id);
480
- const last24h = new Date(Date.now() - 24 * 60 * 60 * 1000);
481
- const last7d = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
482
- // Get crash stats
483
- const crashes24h = await db
484
- .select()
485
- .from(agentCrashes)
486
- .where(and(sql `${agentCrashes.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`, gte(agentCrashes.crashedAt, last24h)));
487
- const crashes7d = await db
488
- .select()
489
- .from(agentCrashes)
490
- .where(and(sql `${agentCrashes.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`, gte(agentCrashes.crashedAt, last7d)));
491
- // Get unacknowledged alerts
492
- const pendingAlerts = await db
493
- .select()
494
- .from(memoryAlerts)
495
- .where(and(sql `${memoryAlerts.daemonId} IN (${sql.join(daemonIds.map(id => sql `${id}`), sql `, `)})`, eq(memoryAlerts.acknowledged, false)))
496
- .limit(10);
497
- // Calculate health score
498
- let healthScore = 100;
499
- const issues = [];
500
- const recommendations = [];
501
- // Deduct for OOM crashes
502
- const oomCrashes = crashes24h.filter(c => c.likelyCause === 'oom').length;
503
- if (oomCrashes > 0) {
504
- healthScore -= oomCrashes * 15;
505
- issues.push({
506
- severity: 'critical',
507
- message: `${oomCrashes} out-of-memory crash${oomCrashes > 1 ? 'es' : ''} in last 24 hours`,
508
- });
509
- recommendations.push('Increase memory limits or optimize agent memory usage');
510
- }
511
- // Deduct for memory leak crashes
512
- const leakCrashes = crashes24h.filter(c => c.likelyCause === 'memory_leak').length;
513
- if (leakCrashes > 0) {
514
- healthScore -= leakCrashes * 10;
515
- issues.push({
516
- severity: 'high',
517
- message: `${leakCrashes} likely memory leak crash${leakCrashes > 1 ? 'es' : ''} detected`,
518
- });
519
- recommendations.push('Investigate agents for memory leaks');
520
- }
521
- // Deduct for other crashes
522
- const otherCrashes = crashes24h.length - oomCrashes - leakCrashes;
523
- if (otherCrashes > 0) {
524
- healthScore -= otherCrashes * 5;
525
- issues.push({
526
- severity: 'medium',
527
- message: `${otherCrashes} other crash${otherCrashes > 1 ? 'es' : ''} in last 24 hours`,
528
- });
529
- }
530
- // Deduct for pending critical alerts
531
- const criticalAlerts = pendingAlerts.filter(a => a.alertType === 'critical' || a.alertType === 'oom_imminent').length;
532
- if (criticalAlerts > 0) {
533
- healthScore -= criticalAlerts * 8;
534
- issues.push({
535
- severity: 'high',
536
- message: `${criticalAlerts} unacknowledged critical alert${criticalAlerts > 1 ? 's' : ''}`,
537
- });
538
- recommendations.push('Review and acknowledge pending alerts');
539
- }
540
- // Clamp health score
541
- healthScore = Math.max(0, Math.min(100, healthScore));
542
- // Generate summary
543
- let summary;
544
- if (healthScore >= 90) {
545
- summary = 'System is healthy. All agents operating normally.';
546
- }
547
- else if (healthScore >= 70) {
548
- summary = 'Some issues detected. Review warnings and recommendations.';
549
- }
550
- else if (healthScore >= 50) {
551
- summary = 'Multiple issues detected. Action recommended.';
552
- }
553
- else {
554
- summary = 'Critical issues detected. Immediate action required.';
555
- }
556
- res.json({
557
- healthScore,
558
- summary,
559
- issues: issues.sort((a, b) => {
560
- const order = { critical: 0, high: 1, medium: 2, low: 3 };
561
- return (order[a.severity] || 4) - (order[b.severity] || 4);
562
- }),
563
- recommendations,
564
- stats: {
565
- crashes24h: crashes24h.length,
566
- crashes7d: crashes7d.length,
567
- pendingAlerts: pendingAlerts.length,
568
- connectedDaemons: daemons.filter(d => d.status === 'online').length,
569
- totalDaemons: daemons.length,
570
- },
571
- });
572
- }
573
- catch (error) {
574
- console.error('Error fetching insights:', error);
575
- res.status(500).json({ error: 'Failed to fetch insights' });
576
- }
577
- });
578
- //# sourceMappingURL=monitoring.js.map
@@ -1,9 +0,0 @@
1
- /**
2
- * Nango Auth API Routes
3
- *
4
- * Handles GitHub OAuth via Nango with two-connection pattern:
5
- * - github: User login (identity)
6
- * - github-app-oauth: Repository access
7
- */
8
- export declare const nangoAuthRouter: import("express-serve-static-core").Router;
9
- //# sourceMappingURL=nango-auth.d.ts.map