@claudecam/server 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 (52) hide show
  1. package/dist/db/index.js +68 -0
  2. package/dist/db/index.js.map +1 -0
  3. package/dist/db/queries.js +658 -0
  4. package/dist/db/queries.js.map +1 -0
  5. package/dist/db/schema.sql +259 -0
  6. package/dist/index.js +128 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/routes/agents.js +68 -0
  9. package/dist/routes/agents.js.map +1 -0
  10. package/dist/routes/correlation-audit.js +31 -0
  11. package/dist/routes/correlation-audit.js.map +1 -0
  12. package/dist/routes/events.js +81 -0
  13. package/dist/routes/events.js.map +1 -0
  14. package/dist/routes/files.js +24 -0
  15. package/dist/routes/files.js.map +1 -0
  16. package/dist/routes/parse-prd.js +38 -0
  17. package/dist/routes/parse-prd.js.map +1 -0
  18. package/dist/routes/projects.js +96 -0
  19. package/dist/routes/projects.js.map +1 -0
  20. package/dist/routes/registry.js +88 -0
  21. package/dist/routes/registry.js.map +1 -0
  22. package/dist/routes/session-groups.js +182 -0
  23. package/dist/routes/session-groups.js.map +1 -0
  24. package/dist/routes/sessions.js +109 -0
  25. package/dist/routes/sessions.js.map +1 -0
  26. package/dist/routes/sprints.js +58 -0
  27. package/dist/routes/sprints.js.map +1 -0
  28. package/dist/routes/stats.js +63 -0
  29. package/dist/routes/stats.js.map +1 -0
  30. package/dist/routes/stream.js +21 -0
  31. package/dist/routes/stream.js.map +1 -0
  32. package/dist/routes/tasks.js +198 -0
  33. package/dist/routes/tasks.js.map +1 -0
  34. package/dist/services/correlation-engine.js +577 -0
  35. package/dist/services/correlation-engine.js.map +1 -0
  36. package/dist/services/event-processor.js +857 -0
  37. package/dist/services/event-processor.js.map +1 -0
  38. package/dist/services/prd-parser.js +142 -0
  39. package/dist/services/prd-parser.js.map +1 -0
  40. package/dist/services/project-manager.js +351 -0
  41. package/dist/services/project-manager.js.map +1 -0
  42. package/dist/services/project-router.js +56 -0
  43. package/dist/services/project-router.js.map +1 -0
  44. package/dist/services/session-manager.js +76 -0
  45. package/dist/services/session-manager.js.map +1 -0
  46. package/dist/services/sse-manager.js +115 -0
  47. package/dist/services/sse-manager.js.map +1 -0
  48. package/dist/services/string-similarity.js +256 -0
  49. package/dist/services/string-similarity.js.map +1 -0
  50. package/dist/services/task-completion.js +251 -0
  51. package/dist/services/task-completion.js.map +1 -0
  52. package/package.json +59 -0
@@ -0,0 +1,259 @@
1
+ -- Claude Agent Monitor - Database Schema
2
+ -- SQLite tables for both Pilar 1 (Agent Monitor) and Pilar 2 (PRD Tracker)
3
+
4
+ -- === Pilar 1: Agent Monitor ===
5
+
6
+ CREATE TABLE IF NOT EXISTS sessions (
7
+ id TEXT PRIMARY KEY,
8
+ started_at TEXT NOT NULL DEFAULT (datetime('now')),
9
+ ended_at TEXT,
10
+ working_directory TEXT NOT NULL DEFAULT '',
11
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'completed', 'error')),
12
+ agent_count INTEGER NOT NULL DEFAULT 0,
13
+ event_count INTEGER NOT NULL DEFAULT 0,
14
+ metadata TEXT
15
+ );
16
+
17
+ CREATE TABLE IF NOT EXISTS agents (
18
+ id TEXT NOT NULL,
19
+ session_id TEXT NOT NULL,
20
+ name TEXT NOT NULL,
21
+ type TEXT NOT NULL DEFAULT 'general-purpose',
22
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'idle', 'error', 'completed', 'shutdown')),
23
+ first_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
24
+ last_activity_at TEXT NOT NULL DEFAULT (datetime('now')),
25
+ current_task TEXT,
26
+ tool_call_count INTEGER NOT NULL DEFAULT 0,
27
+ error_count INTEGER NOT NULL DEFAULT 0,
28
+ PRIMARY KEY (id, session_id),
29
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
30
+ );
31
+
32
+ CREATE TABLE IF NOT EXISTS events (
33
+ id TEXT PRIMARY KEY,
34
+ session_id TEXT NOT NULL,
35
+ agent_id TEXT NOT NULL,
36
+ timestamp TEXT NOT NULL,
37
+ hook_type TEXT NOT NULL,
38
+ category TEXT NOT NULL,
39
+ tool TEXT,
40
+ file_path TEXT,
41
+ input TEXT,
42
+ output TEXT,
43
+ error TEXT,
44
+ duration REAL,
45
+ metadata TEXT,
46
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
47
+ );
48
+
49
+ CREATE INDEX IF NOT EXISTS idx_events_session ON events(session_id);
50
+ CREATE INDEX IF NOT EXISTS idx_events_agent ON events(session_id, agent_id);
51
+ CREATE INDEX IF NOT EXISTS idx_events_category ON events(session_id, category);
52
+ CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
53
+ CREATE INDEX IF NOT EXISTS idx_events_tool ON events(tool);
54
+
55
+ CREATE TABLE IF NOT EXISTS file_changes (
56
+ file_path TEXT NOT NULL,
57
+ session_id TEXT NOT NULL,
58
+ agent_id TEXT NOT NULL,
59
+ change_type TEXT NOT NULL CHECK (change_type IN ('created', 'modified', 'read')),
60
+ first_touched_at TEXT NOT NULL DEFAULT (datetime('now')),
61
+ last_touched_at TEXT NOT NULL DEFAULT (datetime('now')),
62
+ touch_count INTEGER NOT NULL DEFAULT 1,
63
+ PRIMARY KEY (file_path, session_id, agent_id),
64
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
65
+ );
66
+
67
+ CREATE TABLE IF NOT EXISTS task_items (
68
+ id TEXT PRIMARY KEY,
69
+ session_id TEXT NOT NULL,
70
+ subject TEXT NOT NULL,
71
+ status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'in_progress', 'completed')),
72
+ owner TEXT,
73
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
74
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
75
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
76
+ );
77
+
78
+ -- === Session Groups (DEPRECATED Sprint 8: replaced by project_registry) ===
79
+ -- Tables kept for backward compatibility with existing databases.
80
+
81
+ CREATE TABLE IF NOT EXISTS session_groups (
82
+ id TEXT PRIMARY KEY,
83
+ name TEXT,
84
+ main_session_id TEXT NOT NULL,
85
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
86
+ FOREIGN KEY (main_session_id) REFERENCES sessions(id) ON DELETE CASCADE
87
+ );
88
+
89
+ CREATE TABLE IF NOT EXISTS session_group_members (
90
+ group_id TEXT NOT NULL,
91
+ session_id TEXT NOT NULL,
92
+ agent_name TEXT,
93
+ agent_type TEXT,
94
+ joined_at TEXT NOT NULL DEFAULT (datetime('now')),
95
+ PRIMARY KEY (group_id, session_id),
96
+ FOREIGN KEY (group_id) REFERENCES session_groups(id) ON DELETE CASCADE,
97
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
98
+ );
99
+
100
+ CREATE INDEX IF NOT EXISTS idx_session_group_members_session ON session_group_members(session_id);
101
+
102
+ -- === Pilar 2: PRD Tracker ===
103
+
104
+ CREATE TABLE IF NOT EXISTS projects (
105
+ id TEXT PRIMARY KEY,
106
+ name TEXT NOT NULL,
107
+ description TEXT,
108
+ prd_source TEXT NOT NULL DEFAULT '',
109
+ prd_content TEXT NOT NULL DEFAULT '',
110
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
111
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
112
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'completed', 'archived')),
113
+ total_tasks INTEGER NOT NULL DEFAULT 0,
114
+ completed_tasks INTEGER NOT NULL DEFAULT 0,
115
+ current_sprint_id TEXT,
116
+ metadata TEXT
117
+ );
118
+
119
+ CREATE TABLE IF NOT EXISTS sprints (
120
+ id TEXT PRIMARY KEY,
121
+ project_id TEXT NOT NULL,
122
+ name TEXT NOT NULL,
123
+ description TEXT,
124
+ "order" INTEGER NOT NULL DEFAULT 1,
125
+ status TEXT NOT NULL DEFAULT 'planned' CHECK (status IN ('planned', 'active', 'completed')),
126
+ started_at TEXT,
127
+ completed_at TEXT,
128
+ total_tasks INTEGER NOT NULL DEFAULT 0,
129
+ completed_tasks INTEGER NOT NULL DEFAULT 0,
130
+ metadata TEXT,
131
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
132
+ );
133
+
134
+ CREATE INDEX IF NOT EXISTS idx_sprints_project ON sprints(project_id);
135
+
136
+ CREATE TABLE IF NOT EXISTS prd_tasks (
137
+ id TEXT PRIMARY KEY,
138
+ project_id TEXT NOT NULL,
139
+ sprint_id TEXT,
140
+ external_id TEXT,
141
+ title TEXT NOT NULL,
142
+ description TEXT NOT NULL DEFAULT '',
143
+ acceptance_criteria TEXT,
144
+ status TEXT NOT NULL DEFAULT 'backlog' CHECK (status IN ('backlog', 'planned', 'pending', 'in_progress', 'in_review', 'completed', 'blocked', 'deferred')),
145
+ priority TEXT NOT NULL DEFAULT 'medium' CHECK (priority IN ('critical', 'high', 'medium', 'low')),
146
+ complexity INTEGER,
147
+ tags TEXT,
148
+ depends_on TEXT NOT NULL DEFAULT '[]',
149
+ blocked_by TEXT NOT NULL DEFAULT '[]',
150
+ assigned_agent TEXT,
151
+ started_at TEXT,
152
+ completed_at TEXT,
153
+ session_id TEXT,
154
+ prd_section TEXT,
155
+ prd_subsection TEXT,
156
+ prd_line_start INTEGER,
157
+ prd_line_end INTEGER,
158
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
159
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
160
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
161
+ FOREIGN KEY (sprint_id) REFERENCES sprints(id) ON DELETE SET NULL
162
+ );
163
+
164
+ CREATE INDEX IF NOT EXISTS idx_prd_tasks_project ON prd_tasks(project_id);
165
+ CREATE INDEX IF NOT EXISTS idx_prd_tasks_sprint ON prd_tasks(sprint_id);
166
+ CREATE INDEX IF NOT EXISTS idx_prd_tasks_status ON prd_tasks(status);
167
+
168
+ CREATE TABLE IF NOT EXISTS task_activities (
169
+ id TEXT PRIMARY KEY,
170
+ prd_task_id TEXT NOT NULL,
171
+ event_id TEXT NOT NULL,
172
+ session_id TEXT NOT NULL,
173
+ agent_id TEXT NOT NULL,
174
+ activity_type TEXT NOT NULL,
175
+ timestamp TEXT NOT NULL DEFAULT (datetime('now')),
176
+ details TEXT,
177
+ FOREIGN KEY (prd_task_id) REFERENCES prd_tasks(id) ON DELETE CASCADE,
178
+ FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE
179
+ );
180
+
181
+ CREATE INDEX IF NOT EXISTS idx_task_activities_task ON task_activities(prd_task_id);
182
+
183
+ CREATE TABLE IF NOT EXISTS prd_documents (
184
+ id TEXT PRIMARY KEY,
185
+ project_id TEXT NOT NULL,
186
+ version INTEGER NOT NULL DEFAULT 1,
187
+ raw_content TEXT NOT NULL,
188
+ sections TEXT NOT NULL DEFAULT '[]',
189
+ parsed_at TEXT NOT NULL DEFAULT (datetime('now')),
190
+ parse_method TEXT NOT NULL DEFAULT 'structured' CHECK (parse_method IN ('structured', 'ai_assisted', 'manual')),
191
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
192
+ );
193
+
194
+ CREATE INDEX IF NOT EXISTS idx_prd_documents_project ON prd_documents(project_id);
195
+
196
+ -- === Correlation Audit Log (Sprint 7) ===
197
+
198
+ CREATE TABLE IF NOT EXISTS correlation_audit_log (
199
+ id TEXT PRIMARY KEY,
200
+ event_id TEXT NOT NULL,
201
+ prd_task_id TEXT,
202
+ session_id TEXT NOT NULL,
203
+ agent_id TEXT NOT NULL,
204
+ layer TEXT NOT NULL,
205
+ score REAL NOT NULL DEFAULT 0,
206
+ matched INTEGER NOT NULL DEFAULT 0,
207
+ reason TEXT,
208
+ timestamp TEXT NOT NULL DEFAULT (datetime('now')),
209
+ FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE,
210
+ FOREIGN KEY (prd_task_id) REFERENCES prd_tasks(id) ON DELETE SET NULL
211
+ );
212
+
213
+ CREATE INDEX IF NOT EXISTS idx_correlation_audit_event ON correlation_audit_log(event_id);
214
+ CREATE INDEX IF NOT EXISTS idx_correlation_audit_task ON correlation_audit_log(prd_task_id);
215
+ CREATE INDEX IF NOT EXISTS idx_correlation_audit_timestamp ON correlation_audit_log(timestamp);
216
+
217
+ -- === Session-Project Bindings (Sprint 7) ===
218
+
219
+ CREATE TABLE IF NOT EXISTS session_project_bindings (
220
+ session_id TEXT PRIMARY KEY,
221
+ project_id TEXT NOT NULL,
222
+ bound_at TEXT NOT NULL DEFAULT (datetime('now')),
223
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE,
224
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
225
+ );
226
+
227
+ -- === Project Registry (Sprint 8) ===
228
+
229
+ CREATE TABLE IF NOT EXISTS project_registry (
230
+ working_directory TEXT PRIMARY KEY,
231
+ project_id TEXT NOT NULL,
232
+ registered_at TEXT NOT NULL DEFAULT (datetime('now')),
233
+ prd_path TEXT,
234
+ hooks_installed INTEGER NOT NULL DEFAULT 0,
235
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
236
+ );
237
+
238
+ CREATE INDEX IF NOT EXISTS idx_project_registry_project ON project_registry(project_id);
239
+
240
+ -- === Agent-Task Bindings (Sprint 7) ===
241
+
242
+ CREATE TABLE IF NOT EXISTS agent_task_bindings (
243
+ id TEXT PRIMARY KEY,
244
+ agent_id TEXT NOT NULL,
245
+ session_id TEXT NOT NULL,
246
+ prd_task_id TEXT NOT NULL,
247
+ confidence REAL NOT NULL DEFAULT 0.5,
248
+ bound_at TEXT NOT NULL DEFAULT (datetime('now')),
249
+ expired_at TEXT,
250
+ FOREIGN KEY (prd_task_id) REFERENCES prd_tasks(id) ON DELETE CASCADE
251
+ );
252
+
253
+ CREATE INDEX IF NOT EXISTS idx_agent_task_bindings_agent ON agent_task_bindings(agent_id, session_id);
254
+ CREATE INDEX IF NOT EXISTS idx_agent_task_bindings_task ON agent_task_bindings(prd_task_id);
255
+ CREATE INDEX IF NOT EXISTS idx_agent_task_bindings_active ON agent_task_bindings(agent_id, session_id, expired_at);
256
+
257
+ -- For existing databases, run these ALTER TABLE statements manually:
258
+ -- ALTER TABLE events ADD COLUMN correlation_id TEXT;
259
+ -- ALTER TABLE events ADD COLUMN causation_id TEXT;
package/dist/index.js ADDED
@@ -0,0 +1,128 @@
1
+ import express from "express";
2
+ import cors from "cors";
3
+ import { existsSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { DEFAULT_SERVER_PORT, DEFAULT_BIND_HOST, AGENT_IDLE_TIMEOUT_MS, } from "@claudecam/shared";
6
+ import { initDb, closeDb } from "./db/index.js";
7
+ import { sseManager } from "./services/sse-manager.js";
8
+ import { agentQueries } from "./db/queries.js";
9
+ // Stale session cleanup REMOVED: sessions only end via SessionEnd hook
10
+ // Routes
11
+ import { eventsRouter } from "./routes/events.js";
12
+ import { sessionsRouter } from "./routes/sessions.js";
13
+ import { agentsRouter } from "./routes/agents.js";
14
+ import { filesRouter } from "./routes/files.js";
15
+ import { statsRouter } from "./routes/stats.js";
16
+ import { streamRouter } from "./routes/stream.js";
17
+ import { projectsRouter } from "./routes/projects.js";
18
+ import { sprintsRouter } from "./routes/sprints.js";
19
+ import { tasksRouter } from "./routes/tasks.js";
20
+ import { parsePrdRouter } from "./routes/parse-prd.js";
21
+ import { correlationAuditRouter } from "./routes/correlation-audit.js";
22
+ import { registryRouter } from "./routes/registry.js";
23
+ import { getSessionsForProject } from "./services/project-router.js";
24
+ export function createApp() {
25
+ const app = express();
26
+ // Middleware
27
+ app.use(cors());
28
+ app.use(express.json({ limit: "1mb" }));
29
+ // Health check
30
+ app.get("/api/health", (_req, res) => {
31
+ res.json({
32
+ status: "ok",
33
+ timestamp: new Date().toISOString(),
34
+ connections: sseManager.getConnectionCount(),
35
+ });
36
+ });
37
+ // Pilar 1 routes
38
+ app.use("/api/events", eventsRouter);
39
+ app.use("/api/sessions", sessionsRouter);
40
+ app.use("/api/sessions", agentsRouter); // /api/sessions/:id/agents
41
+ app.use("/api/sessions", filesRouter); // /api/sessions/:id/files
42
+ app.use("/api/sessions", statsRouter); // /api/sessions/:id/stats
43
+ app.use("/api/sessions", eventsRouter); // /api/sessions/:id/events (mounted on eventsRouter)
44
+ app.use("/api/stream", streamRouter);
45
+ // Correlation audit log
46
+ app.use("/api/correlation-audit", correlationAuditRouter);
47
+ // Project registry (Sprint 8 - Project-First Architecture)
48
+ app.use("/api/registry", registryRouter);
49
+ // Pilar 2 routes
50
+ app.use("/api/projects", projectsRouter);
51
+ app.use("/api/projects", sprintsRouter); // /api/projects/:id/sprints
52
+ app.use("/api/projects", tasksRouter); // /api/projects/:id/tasks
53
+ app.use("/api/parse-prd", parsePrdRouter);
54
+ // Serve dashboard static files in production mode
55
+ const dashboardPath = process.env["CAM_DASHBOARD_PATH"];
56
+ if (dashboardPath && existsSync(dashboardPath)) {
57
+ app.use(express.static(dashboardPath));
58
+ // SPA fallback: serve index.html for non-API routes
59
+ app.get("*", (_req, res) => {
60
+ res.sendFile(join(dashboardPath, "index.html"));
61
+ });
62
+ }
63
+ return app;
64
+ }
65
+ export function startServer(options) {
66
+ const port = options?.port ?? DEFAULT_SERVER_PORT;
67
+ // Initialize database
68
+ initDb(options?.dbPath);
69
+ const app = createApp();
70
+ // Connect SSE Manager to Project Router for project-level filtering
71
+ sseManager.setProjectSessionResolver(getSessionsForProject);
72
+ const bindHost = process.env["CAM_BIND_HOST"] || DEFAULT_BIND_HOST;
73
+ const server = app.listen(port, bindHost, () => {
74
+ console.log(`Claude Agent Monitor server running at http://${bindHost}:${port}`);
75
+ console.log(` API: http://localhost:${port}/api/health`);
76
+ console.log(` SSE: http://localhost:${port}/api/stream`);
77
+ console.log(` Events: POST http://localhost:${port}/api/events`);
78
+ });
79
+ // Idle detection: periodically check for agents that went stale
80
+ const idleCheckInterval = setInterval(() => {
81
+ try {
82
+ const cutoff = new Date(Date.now() - AGENT_IDLE_TIMEOUT_MS).toISOString();
83
+ const staleAgents = agentQueries.getActiveStale().all(cutoff);
84
+ for (const agent of staleAgents) {
85
+ const agentId = agent["id"];
86
+ const sessionId = agent["session_id"];
87
+ const now = new Date().toISOString();
88
+ agentQueries.updateStatus().run("idle", now, agentId, sessionId);
89
+ sseManager.broadcast("agent_status", {
90
+ agent: agentId,
91
+ sessionId,
92
+ status: "idle",
93
+ previousStatus: "active",
94
+ }, sessionId);
95
+ }
96
+ }
97
+ catch {
98
+ // DB not ready yet or query error, skip silently
99
+ }
100
+ }, AGENT_IDLE_TIMEOUT_MS);
101
+ // Graceful shutdown
102
+ const shutdown = () => {
103
+ console.log("\nShutting down...");
104
+ clearInterval(idleCheckInterval);
105
+ sseManager.shutdown();
106
+ server.close(() => {
107
+ closeDb();
108
+ process.exit(0);
109
+ });
110
+ // Force exit after 5 seconds
111
+ setTimeout(() => {
112
+ process.exit(1);
113
+ }, 5000);
114
+ };
115
+ process.on("SIGINT", shutdown);
116
+ process.on("SIGTERM", shutdown);
117
+ return server;
118
+ }
119
+ // Start server when run directly
120
+ const isMain = process.argv[1] &&
121
+ (process.argv[1].endsWith("index.ts") ||
122
+ process.argv[1].endsWith("index.js"));
123
+ if (isMain) {
124
+ const port = parseInt(process.env["CAM_PORT"] || "") || DEFAULT_SERVER_PORT;
125
+ const dbPath = process.env["CAM_DB_PATH"] || undefined;
126
+ startServer({ port, dbPath });
127
+ }
128
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { Router } from 'express';
2
+ import { agentQueries, eventQueries } from '../db/queries.js';
3
+ import { DEFAULT_EVENT_LIMIT } from '@claudecam/shared';
4
+ export const agentsRouter = Router();
5
+ function mapAgent(row) {
6
+ return {
7
+ id: row.id,
8
+ sessionId: row.session_id,
9
+ name: row.name,
10
+ type: row.type,
11
+ status: row.status,
12
+ firstSeenAt: row.first_seen_at,
13
+ lastActivityAt: row.last_activity_at,
14
+ currentTask: row.current_task ?? undefined,
15
+ toolCallCount: row.tool_call_count,
16
+ errorCount: row.error_count,
17
+ };
18
+ }
19
+ // GET /api/sessions/:id/agents
20
+ agentsRouter.get('/:id/agents', (req, res) => {
21
+ try {
22
+ const sessionId = req.params['id'];
23
+ // Return all agents for the session - frontend handles display limits
24
+ const rows = agentQueries.getBySession().all(sessionId);
25
+ const agents = rows.map(mapAgent);
26
+ res.json({ agents });
27
+ }
28
+ catch (err) {
29
+ res.status(500).json({ error: 'Internal server error' });
30
+ }
31
+ });
32
+ // GET /api/sessions/:id/agents/:agentId/events
33
+ agentsRouter.get('/:id/agents/:agentId/events', (req, res) => {
34
+ try {
35
+ const sessionId = req.params['id'];
36
+ const agentId = req.params['agentId'];
37
+ const category = req.query['category'];
38
+ const limit = parseInt(req.query['limit']) || DEFAULT_EVENT_LIMIT;
39
+ const offset = parseInt(req.query['offset']) || 0;
40
+ let rows;
41
+ if (category) {
42
+ rows = eventQueries.getByAgentAndCategory().all(sessionId, agentId, category, limit, offset);
43
+ }
44
+ else {
45
+ rows = eventQueries.getBySessionAndAgent().all(sessionId, agentId, limit, offset);
46
+ }
47
+ const events = rows.map(row => ({
48
+ id: row['id'],
49
+ sessionId: row['session_id'],
50
+ agentId: row['agent_id'],
51
+ timestamp: row['timestamp'],
52
+ hookType: row['hook_type'],
53
+ category: row['category'],
54
+ tool: row['tool'] ?? undefined,
55
+ filePath: row['file_path'] ?? undefined,
56
+ input: row['input'] ?? undefined,
57
+ output: row['output'] ?? undefined,
58
+ error: row['error'] ?? undefined,
59
+ duration: row['duration'] ?? undefined,
60
+ metadata: row['metadata'] ? JSON.parse(row['metadata']) : undefined,
61
+ }));
62
+ res.json({ events });
63
+ }
64
+ catch (err) {
65
+ res.status(500).json({ error: 'Internal server error' });
66
+ }
67
+ });
68
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/routes/agents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { Router } from "express";
2
+ import { correlationAuditQueries } from "../db/queries.js";
3
+ export const correlationAuditRouter = Router();
4
+ // GET /api/correlation-audit
5
+ correlationAuditRouter.get("/", (req, res) => {
6
+ try {
7
+ const limit = parseInt(req.query["limit"]) || 50;
8
+ const offset = parseInt(req.query["offset"]) || 0;
9
+ const rows = correlationAuditQueries
10
+ .getRecent()
11
+ .all(limit, offset);
12
+ res.json({ entries: rows, limit, offset });
13
+ }
14
+ catch {
15
+ res.status(500).json({ error: "Internal server error" });
16
+ }
17
+ });
18
+ // GET /api/correlation-audit/:eventId
19
+ correlationAuditRouter.get("/:eventId", (req, res) => {
20
+ try {
21
+ const eventId = req.params["eventId"];
22
+ const rows = correlationAuditQueries
23
+ .getByEvent()
24
+ .all(eventId);
25
+ res.json({ entries: rows });
26
+ }
27
+ catch {
28
+ res.status(500).json({ error: "Internal server error" });
29
+ }
30
+ });
31
+ //# sourceMappingURL=correlation-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation-audit.js","sourceRoot":"","sources":["../../src/routes/correlation-audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,EAAE,CAAC;AAgB/C,6BAA6B;AAC7B,sBAAsB,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IAC9D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAW,CAAC,IAAI,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAW,CAAC,IAAI,CAAC,CAAC;QAE5D,MAAM,IAAI,GAAG,uBAAuB;aACjC,SAAS,EAAE;aACX,GAAG,CAAC,KAAK,EAAE,MAAM,CAAe,CAAC;QAEpC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,sCAAsC;AACtC,sBAAsB,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACtE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAE,CAAC;QAEvC,MAAM,IAAI,GAAG,uBAAuB;aACjC,UAAU,EAAE;aACZ,GAAG,CAAC,OAAO,CAAe,CAAC;QAE9B,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,81 @@
1
+ import { Router } from 'express';
2
+ import { incomingEventSchema } from '@claudecam/shared';
3
+ import { processEvent } from '../services/event-processor.js';
4
+ import { correlateEvent } from '../services/correlation-engine.js';
5
+ import { eventQueries } from '../db/queries.js';
6
+ import { DEFAULT_EVENT_LIMIT } from '@claudecam/shared';
7
+ export const eventsRouter = Router();
8
+ // POST /api/events - Main event ingestion endpoint
9
+ eventsRouter.post('/', (req, res) => {
10
+ try {
11
+ const parsed = incomingEventSchema.safeParse(req.body);
12
+ if (!parsed.success) {
13
+ res.status(400).json({ ok: false, error: 'Invalid event payload', details: parsed.error.issues });
14
+ return;
15
+ }
16
+ const event = processEvent(parsed.data);
17
+ // Run correlation in the background (non-blocking)
18
+ try {
19
+ correlateEvent(event);
20
+ }
21
+ catch {
22
+ // Correlation errors should not break event ingestion
23
+ }
24
+ res.status(200).json({ ok: true, event_id: event.id });
25
+ }
26
+ catch (err) {
27
+ res.status(500).json({ ok: false, error: 'Internal server error' });
28
+ }
29
+ });
30
+ // GET /api/sessions/:id/events - List events for a session
31
+ // Note: This route is mounted on /api/sessions, so the path here is /:id/events
32
+ eventsRouter.get('/:id/events', (req, res) => {
33
+ try {
34
+ const sessionId = req.params['id'];
35
+ const category = req.query['category'];
36
+ const agentId = req.query['agent_id'];
37
+ const tool = req.query['tool'];
38
+ const since = req.query['since'];
39
+ const limit = parseInt(req.query['limit']) || DEFAULT_EVENT_LIMIT;
40
+ const offset = parseInt(req.query['offset']) || 0;
41
+ let rows;
42
+ if (category && agentId) {
43
+ rows = eventQueries.getByAgentAndCategory().all(sessionId, agentId, category, limit, offset);
44
+ }
45
+ else if (category) {
46
+ rows = eventQueries.getBySessionAndCategory().all(sessionId, category, limit, offset);
47
+ }
48
+ else if (agentId) {
49
+ rows = eventQueries.getBySessionAndAgent().all(sessionId, agentId, limit, offset);
50
+ }
51
+ else if (tool) {
52
+ rows = eventQueries.getBySessionAndTool().all(sessionId, tool, limit, offset);
53
+ }
54
+ else if (since) {
55
+ rows = eventQueries.getBySessionSince().all(sessionId, since, limit, offset);
56
+ }
57
+ else {
58
+ rows = eventQueries.getBySession().all(sessionId, limit, offset);
59
+ }
60
+ const events = rows.map(row => ({
61
+ id: row['id'],
62
+ sessionId: row['session_id'],
63
+ agentId: row['agent_id'],
64
+ timestamp: row['timestamp'],
65
+ hookType: row['hook_type'],
66
+ category: row['category'],
67
+ tool: row['tool'] ?? undefined,
68
+ filePath: row['file_path'] ?? undefined,
69
+ input: row['input'] ?? undefined,
70
+ output: row['output'] ?? undefined,
71
+ error: row['error'] ?? undefined,
72
+ duration: row['duration'] ?? undefined,
73
+ metadata: row['metadata'] ? JSON.parse(row['metadata']) : undefined,
74
+ }));
75
+ res.json({ events });
76
+ }
77
+ catch (err) {
78
+ res.status(500).json({ error: 'Internal server error' });
79
+ }
80
+ });
81
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/routes/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { Router } from 'express';
2
+ import { fileChangeQueries } from '../db/queries.js';
3
+ export const filesRouter = Router();
4
+ // GET /api/sessions/:id/files
5
+ filesRouter.get('/:id/files', (req, res) => {
6
+ try {
7
+ const sessionId = req.params['id'];
8
+ const rows = fileChangeQueries.getBySession().all(sessionId);
9
+ const files = rows.map(row => ({
10
+ filePath: row.file_path,
11
+ sessionId: row.session_id,
12
+ agentId: row.agent_id,
13
+ changeType: row.change_type,
14
+ firstTouchedAt: row.first_touched_at,
15
+ lastTouchedAt: row.last_touched_at,
16
+ touchCount: row.touch_count,
17
+ }));
18
+ res.json({ files });
19
+ }
20
+ catch (err) {
21
+ res.status(500).json({ error: 'Internal server error' });
22
+ }
23
+ });
24
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/routes/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC;AAYpC,8BAA8B;AAC9B,WAAW,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IAC5D,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAE,CAAC;QACpC,MAAM,IAAI,GAAG,iBAAiB,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,SAAS,CAAoB,CAAC;QAEhF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC7B,QAAQ,EAAE,GAAG,CAAC,SAAS;YACvB,SAAS,EAAE,GAAG,CAAC,UAAU;YACzB,OAAO,EAAE,GAAG,CAAC,QAAQ;YACrB,UAAU,EAAE,GAAG,CAAC,WAAW;YAC3B,cAAc,EAAE,GAAG,CAAC,gBAAgB;YACpC,aAAa,EAAE,GAAG,CAAC,eAAe;YAClC,UAAU,EAAE,GAAG,CAAC,WAAW;SAC5B,CAAC,CAAC,CAAC;QAEJ,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC,CAAC,CAAC"}