@arvoretech/runtime-lens-mcp 1.0.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 (42) hide show
  1. package/.vscodeignore +21 -0
  2. package/README.md +136 -0
  3. package/agent/index.ts +263 -0
  4. package/agent/tsconfig.json +17 -0
  5. package/dist/index.d.ts +7 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +17 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/log-collector.d.ts +73 -0
  10. package/dist/log-collector.d.ts.map +1 -0
  11. package/dist/log-collector.js +349 -0
  12. package/dist/log-collector.js.map +1 -0
  13. package/dist/process-inspector.d.ts +44 -0
  14. package/dist/process-inspector.d.ts.map +1 -0
  15. package/dist/process-inspector.js +190 -0
  16. package/dist/process-inspector.js.map +1 -0
  17. package/dist/runtime-interceptor.d.ts +18 -0
  18. package/dist/runtime-interceptor.d.ts.map +1 -0
  19. package/dist/runtime-interceptor.js +133 -0
  20. package/dist/runtime-interceptor.js.map +1 -0
  21. package/dist/server.d.ts +26 -0
  22. package/dist/server.d.ts.map +1 -0
  23. package/dist/server.js +301 -0
  24. package/dist/server.js.map +1 -0
  25. package/dist/types.d.ts +280 -0
  26. package/dist/types.d.ts.map +1 -0
  27. package/dist/types.js +102 -0
  28. package/dist/types.js.map +1 -0
  29. package/eslint.config.js +41 -0
  30. package/extension/decorator.ts +144 -0
  31. package/extension/extension.ts +98 -0
  32. package/extension/runtime-bridge.ts +206 -0
  33. package/extension/tsconfig.json +17 -0
  34. package/package.json +134 -0
  35. package/src/index.ts +18 -0
  36. package/src/log-collector.ts +441 -0
  37. package/src/process-inspector.ts +235 -0
  38. package/src/runtime-interceptor.ts +152 -0
  39. package/src/server.ts +387 -0
  40. package/src/types.ts +128 -0
  41. package/tsconfig.json +20 -0
  42. package/vitest.config.ts +13 -0
@@ -0,0 +1,152 @@
1
+ import { LogCollector } from "./log-collector.js";
2
+ import type { Framework, LogLevel } from "./types.js";
3
+
4
+ type ConsoleMethod = "log" | "info" | "warn" | "error" | "debug";
5
+
6
+ const LEVEL_MAP: Record<ConsoleMethod, LogLevel> = {
7
+ log: "info",
8
+ info: "info",
9
+ warn: "warn",
10
+ error: "error",
11
+ debug: "debug",
12
+ };
13
+
14
+ export class RuntimeInterceptor {
15
+ private originalConsole: Record<ConsoleMethod, (...args: unknown[]) => void> = {} as any;
16
+ private intercepting = false;
17
+ private readonly collector: LogCollector;
18
+ private readonly framework: Framework;
19
+
20
+ constructor(collector: LogCollector, framework: Framework = "unknown") {
21
+ this.collector = collector;
22
+ this.framework = framework;
23
+ }
24
+
25
+ startIntercepting(): void {
26
+ if (this.intercepting) return;
27
+
28
+ const methods: ConsoleMethod[] = ["log", "info", "warn", "error", "debug"];
29
+
30
+ for (const method of methods) {
31
+ this.originalConsole[method] = console[method].bind(console);
32
+
33
+ console[method] = (...args: unknown[]) => {
34
+ this.collector.addLog({
35
+ level: LEVEL_MAP[method],
36
+ message: args.map((a) => this.serialize(a)).join(" "),
37
+ source: "console",
38
+ framework: this.framework,
39
+ stackTrace: method === "error" ? this.captureStack() : undefined,
40
+ metadata: args.length === 1 && typeof args[0] === "object" ? args[0] as Record<string, unknown> : undefined,
41
+ });
42
+
43
+ this.originalConsole[method](...args);
44
+ };
45
+ }
46
+
47
+ this.interceptStderr();
48
+ this.interceptUncaughtErrors();
49
+
50
+ this.intercepting = true;
51
+ }
52
+
53
+ stopIntercepting(): void {
54
+ if (!this.intercepting) return;
55
+
56
+ const methods: ConsoleMethod[] = ["log", "info", "warn", "error", "debug"];
57
+ for (const method of methods) {
58
+ if (this.originalConsole[method]) {
59
+ console[method] = this.originalConsole[method];
60
+ }
61
+ }
62
+
63
+ this.intercepting = false;
64
+ }
65
+
66
+ isActive(): boolean {
67
+ return this.intercepting;
68
+ }
69
+
70
+ private interceptStderr(): void {
71
+ const originalWrite = process.stderr.write.bind(process.stderr);
72
+
73
+ process.stderr.write = ((
74
+ chunk: string | Uint8Array,
75
+ encodingOrCallback?: BufferEncoding | ((error?: Error | null) => void),
76
+ callback?: (error?: Error | null) => void
77
+ ): boolean => {
78
+ const text = typeof chunk === "string" ? chunk : chunk.toString();
79
+
80
+ if (text.trim() && !text.includes("MCP Server")) {
81
+ this.collector.addLog({
82
+ level: this.inferLevel(text),
83
+ message: text.trim(),
84
+ source: "stderr",
85
+ framework: this.framework,
86
+ stackTrace: text.includes("Error") ? text : undefined,
87
+ });
88
+ }
89
+
90
+ if (typeof encodingOrCallback === "function") {
91
+ return originalWrite(chunk, encodingOrCallback);
92
+ }
93
+ return originalWrite(chunk, encodingOrCallback, callback);
94
+ }) as typeof process.stderr.write;
95
+ }
96
+
97
+ private interceptUncaughtErrors(): void {
98
+ process.on("uncaughtException", (error) => {
99
+ this.collector.addLog({
100
+ level: "fatal",
101
+ message: error.message,
102
+ source: "uncaughtException",
103
+ framework: this.framework,
104
+ stackTrace: error.stack,
105
+ metadata: { name: error.name },
106
+ });
107
+ });
108
+
109
+ process.on("unhandledRejection", (reason) => {
110
+ this.collector.addLog({
111
+ level: "error",
112
+ message: reason instanceof Error ? reason.message : String(reason),
113
+ source: "unhandledRejection",
114
+ framework: this.framework,
115
+ stackTrace: reason instanceof Error ? reason.stack : undefined,
116
+ });
117
+ });
118
+ }
119
+
120
+ private serialize(value: unknown): string {
121
+ if (value === null) return "null";
122
+ if (value === undefined) return "undefined";
123
+ if (typeof value === "string") return value;
124
+ if (value instanceof Error) return `${value.name}: ${value.message}\n${value.stack}`;
125
+ if (typeof value === "object") {
126
+ try {
127
+ return JSON.stringify(value, null, 2);
128
+ } catch {
129
+ return Object.prototype.toString.call(value);
130
+ }
131
+ }
132
+ return String(value);
133
+ }
134
+
135
+ private captureStack(): string {
136
+ const stack = new Error().stack || "";
137
+ return stack
138
+ .split("\n")
139
+ .slice(3)
140
+ .filter((line) => !line.includes("runtime-interceptor"))
141
+ .join("\n");
142
+ }
143
+
144
+ private inferLevel(text: string): LogLevel {
145
+ const lower = text.toLowerCase();
146
+ if (lower.includes("fatal") || lower.includes("critical")) return "fatal";
147
+ if (lower.includes("error")) return "error";
148
+ if (lower.includes("warn")) return "warn";
149
+ if (lower.includes("debug") || lower.includes("verbose")) return "debug";
150
+ return "info";
151
+ }
152
+ }
package/src/server.ts ADDED
@@ -0,0 +1,387 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { LogCollector } from "./log-collector.js";
4
+ import { ProcessInspector } from "./process-inspector.js";
5
+ import { RuntimeInterceptor } from "./runtime-interceptor.js";
6
+ import {
7
+ TailLogsParamsSchema,
8
+ SearchLogsParamsSchema,
9
+ GetErrorsParamsSchema,
10
+ InspectRequestParamsSchema,
11
+ GetPerformanceParamsSchema,
12
+ } from "./types.js";
13
+
14
+ export class RuntimeLensMCPServer {
15
+ private readonly server: McpServer;
16
+ private readonly collector: LogCollector;
17
+ private readonly inspector: ProcessInspector;
18
+ private readonly interceptor: RuntimeInterceptor;
19
+
20
+ constructor(projectRoot?: string, logPaths?: string[]) {
21
+ this.server = new McpServer({
22
+ name: "runtime-lens-mcp",
23
+ version: "1.0.0",
24
+ });
25
+
26
+ this.collector = new LogCollector(projectRoot, logPaths);
27
+ this.inspector = new ProcessInspector(projectRoot);
28
+ this.interceptor = new RuntimeInterceptor(this.collector);
29
+
30
+ this.setupTools();
31
+ }
32
+
33
+ static fromEnvironment(): RuntimeLensMCPServer {
34
+ const projectRoot = process.env.RUNTIME_LENS_PROJECT_ROOT || process.cwd();
35
+ const logPaths = process.env.RUNTIME_LENS_LOG_PATHS?.split(",").filter(Boolean) || [];
36
+ return new RuntimeLensMCPServer(projectRoot, logPaths);
37
+ }
38
+
39
+ private setupTools(): void {
40
+ this.registerTailLogs();
41
+ this.registerSearchLogs();
42
+ this.registerGetErrors();
43
+ this.registerInspectRequests();
44
+ this.registerGetPerformance();
45
+ this.registerGetEnvInfo();
46
+ this.registerClearLogs();
47
+ this.registerGetStats();
48
+ this.registerStartInterceptor();
49
+ this.registerStopInterceptor();
50
+ this.registerCollectLogs();
51
+ this.registerScanProject();
52
+ this.registerFindProcesses();
53
+ this.registerGetPorts();
54
+ }
55
+
56
+ private registerTailLogs(): void {
57
+ this.server.registerTool(
58
+ "tail_logs",
59
+ {
60
+ title: "Tail Logs",
61
+ description: "Retrieve recent log entries from the application buffer. Supports filtering by level, framework, and source.",
62
+ inputSchema: {
63
+ lines: TailLogsParamsSchema.shape.lines,
64
+ level: TailLogsParamsSchema.shape.level,
65
+ framework: TailLogsParamsSchema.shape.framework,
66
+ source: TailLogsParamsSchema.shape.source,
67
+ },
68
+ },
69
+ async (params) => {
70
+ const logs = this.collector.getLogs(params);
71
+ return {
72
+ content: [{
73
+ type: "text" as const,
74
+ text: JSON.stringify(logs, null, 2),
75
+ }],
76
+ };
77
+ }
78
+ );
79
+ }
80
+
81
+ private registerSearchLogs(): void {
82
+ this.server.registerTool(
83
+ "search_logs",
84
+ {
85
+ title: "Search Logs",
86
+ description: "Search through collected logs using regex patterns. Filter by level, framework, and time range.",
87
+ inputSchema: {
88
+ query: SearchLogsParamsSchema.shape.query,
89
+ level: SearchLogsParamsSchema.shape.level,
90
+ framework: SearchLogsParamsSchema.shape.framework,
91
+ limit: SearchLogsParamsSchema.shape.limit,
92
+ since: SearchLogsParamsSchema.shape.since,
93
+ },
94
+ },
95
+ async (params) => {
96
+ const logs = this.collector.searchLogs(params as any);
97
+ return {
98
+ content: [{
99
+ type: "text" as const,
100
+ text: JSON.stringify(logs, null, 2),
101
+ }],
102
+ };
103
+ }
104
+ );
105
+ }
106
+
107
+ private registerGetErrors(): void {
108
+ this.server.registerTool(
109
+ "get_errors",
110
+ {
111
+ title: "Get Errors",
112
+ description: "Retrieve recent errors with stack traces. Optionally group similar errors together to identify patterns.",
113
+ inputSchema: {
114
+ limit: GetErrorsParamsSchema.shape.limit,
115
+ framework: GetErrorsParamsSchema.shape.framework,
116
+ grouped: GetErrorsParamsSchema.shape.grouped,
117
+ },
118
+ },
119
+ async (params) => {
120
+ const errors = this.collector.getErrors(params);
121
+ return {
122
+ content: [{
123
+ type: "text" as const,
124
+ text: JSON.stringify(errors, null, 2),
125
+ }],
126
+ };
127
+ }
128
+ );
129
+ }
130
+
131
+ private registerInspectRequests(): void {
132
+ this.server.registerTool(
133
+ "inspect_requests",
134
+ {
135
+ title: "Inspect HTTP Requests",
136
+ description: "Inspect captured HTTP requests and responses. Filter by method, URL pattern, status code, or specific request ID.",
137
+ inputSchema: {
138
+ id: InspectRequestParamsSchema.shape.id,
139
+ method: InspectRequestParamsSchema.shape.method,
140
+ urlPattern: InspectRequestParamsSchema.shape.urlPattern,
141
+ statusCode: InspectRequestParamsSchema.shape.statusCode,
142
+ limit: InspectRequestParamsSchema.shape.limit,
143
+ },
144
+ },
145
+ async (params) => {
146
+ const requests = this.collector.getRequests(params);
147
+ return {
148
+ content: [{
149
+ type: "text" as const,
150
+ text: JSON.stringify(requests, null, 2),
151
+ }],
152
+ };
153
+ }
154
+ );
155
+ }
156
+
157
+ private registerGetPerformance(): void {
158
+ this.server.registerTool(
159
+ "get_performance",
160
+ {
161
+ title: "Get Performance Metrics",
162
+ description: "Retrieve performance metrics including memory usage, CPU, and custom metrics from the application.",
163
+ inputSchema: {
164
+ metric: GetPerformanceParamsSchema.shape.metric,
165
+ since: GetPerformanceParamsSchema.shape.since,
166
+ limit: GetPerformanceParamsSchema.shape.limit,
167
+ },
168
+ },
169
+ async (params) => {
170
+ await this.collector.collectFromProcess();
171
+ const metrics = this.collector.getMetrics(params);
172
+ return {
173
+ content: [{
174
+ type: "text" as const,
175
+ text: JSON.stringify(metrics, null, 2),
176
+ }],
177
+ };
178
+ }
179
+ );
180
+ }
181
+
182
+ private registerGetEnvInfo(): void {
183
+ this.server.registerTool(
184
+ "get_env_info",
185
+ {
186
+ title: "Get Environment Info",
187
+ description: "Get comprehensive environment information including running Node.js processes, listening ports, project framework detection, and system resources.",
188
+ inputSchema: {},
189
+ },
190
+ async () => {
191
+ const info = await this.inspector.getEnvironmentInfo();
192
+ return {
193
+ content: [{
194
+ type: "text" as const,
195
+ text: JSON.stringify(info, null, 2),
196
+ }],
197
+ };
198
+ }
199
+ );
200
+ }
201
+
202
+ private registerClearLogs(): void {
203
+ this.server.registerTool(
204
+ "clear_logs",
205
+ {
206
+ title: "Clear Log Buffer",
207
+ description: "Clear all collected logs, requests, and metrics from the buffer.",
208
+ inputSchema: {},
209
+ },
210
+ async () => {
211
+ const result = this.collector.clearLogs();
212
+ return {
213
+ content: [{
214
+ type: "text" as const,
215
+ text: JSON.stringify({ message: `Cleared ${result.cleared} entries` }),
216
+ }],
217
+ };
218
+ }
219
+ );
220
+ }
221
+
222
+ private registerGetStats(): void {
223
+ this.server.registerTool(
224
+ "get_stats",
225
+ {
226
+ title: "Get Log Statistics",
227
+ description: "Get statistics about collected logs including counts by level and framework.",
228
+ inputSchema: {},
229
+ },
230
+ async () => {
231
+ const stats = this.collector.getStats();
232
+ return {
233
+ content: [{
234
+ type: "text" as const,
235
+ text: JSON.stringify(stats, null, 2),
236
+ }],
237
+ };
238
+ }
239
+ );
240
+ }
241
+
242
+ private registerStartInterceptor(): void {
243
+ this.server.registerTool(
244
+ "start_interceptor",
245
+ {
246
+ title: "Start Console Interceptor",
247
+ description: "Start intercepting console.log/warn/error/debug calls and stderr output in real-time. Captured output is stored in the log buffer.",
248
+ inputSchema: {},
249
+ },
250
+ async () => {
251
+ this.interceptor.startIntercepting();
252
+ return {
253
+ content: [{
254
+ type: "text" as const,
255
+ text: JSON.stringify({ message: "Console interceptor started", active: true }),
256
+ }],
257
+ };
258
+ }
259
+ );
260
+ }
261
+
262
+ private registerStopInterceptor(): void {
263
+ this.server.registerTool(
264
+ "stop_interceptor",
265
+ {
266
+ title: "Stop Console Interceptor",
267
+ description: "Stop intercepting console output. Previously captured logs remain in the buffer.",
268
+ inputSchema: {},
269
+ },
270
+ async () => {
271
+ this.interceptor.stopIntercepting();
272
+ return {
273
+ content: [{
274
+ type: "text" as const,
275
+ text: JSON.stringify({ message: "Console interceptor stopped", active: false }),
276
+ }],
277
+ };
278
+ }
279
+ );
280
+ }
281
+
282
+ private registerCollectLogs(): void {
283
+ this.server.registerTool(
284
+ "collect_from_files",
285
+ {
286
+ title: "Collect Logs from Files",
287
+ description: "Scan and collect logs from log files in the project directory. Automatically discovers .log and .json files in common log directories.",
288
+ inputSchema: {},
289
+ },
290
+ async () => {
291
+ await this.collector.collectFromFiles();
292
+ const stats = this.collector.getStats();
293
+ return {
294
+ content: [{
295
+ type: "text" as const,
296
+ text: JSON.stringify({ message: "Log collection complete", stats }),
297
+ }],
298
+ };
299
+ }
300
+ );
301
+ }
302
+
303
+ private registerScanProject(): void {
304
+ this.server.registerTool(
305
+ "scan_project",
306
+ {
307
+ title: "Scan Project Structure",
308
+ description: "Analyze the project to detect framework (React/Next.js/NestJS), find log files, and list configuration files.",
309
+ inputSchema: {},
310
+ },
311
+ async () => {
312
+ const structure = await this.collector.scanProjectStructure();
313
+ return {
314
+ content: [{
315
+ type: "text" as const,
316
+ text: JSON.stringify(structure, null, 2),
317
+ }],
318
+ };
319
+ }
320
+ );
321
+ }
322
+
323
+ private registerFindProcesses(): void {
324
+ this.server.registerTool(
325
+ "find_processes",
326
+ {
327
+ title: "Find Running Node Processes",
328
+ description: "Find running Node.js processes related to React, Next.js, or NestJS applications.",
329
+ inputSchema: {},
330
+ },
331
+ async () => {
332
+ const processes = await this.inspector.findRunningProcesses();
333
+ return {
334
+ content: [{
335
+ type: "text" as const,
336
+ text: JSON.stringify(processes, null, 2),
337
+ }],
338
+ };
339
+ }
340
+ );
341
+ }
342
+
343
+ private registerGetPorts(): void {
344
+ this.server.registerTool(
345
+ "get_listening_ports",
346
+ {
347
+ title: "Get Listening Ports",
348
+ description: "List all TCP ports currently being listened on by Node.js processes.",
349
+ inputSchema: {},
350
+ },
351
+ async () => {
352
+ const ports = await this.inspector.getPortListeners();
353
+ return {
354
+ content: [{
355
+ type: "text" as const,
356
+ text: JSON.stringify(ports, null, 2),
357
+ }],
358
+ };
359
+ }
360
+ );
361
+ }
362
+
363
+ async start(): Promise<void> {
364
+ try {
365
+ const transport = new StdioServerTransport();
366
+ await this.server.connect(transport);
367
+ console.error("Runtime Lens MCP Server started successfully");
368
+ } catch (error) {
369
+ console.error(
370
+ "Failed to start Runtime Lens MCP Server:",
371
+ error instanceof Error ? error.message : error
372
+ );
373
+ process.exit(1);
374
+ }
375
+ }
376
+
377
+ setupGracefulShutdown(): void {
378
+ const shutdown = async (signal: string): Promise<void> => {
379
+ console.error(`Received ${signal}, shutting down gracefully...`);
380
+ this.interceptor.stopIntercepting();
381
+ process.exit(0);
382
+ };
383
+
384
+ process.on("SIGINT", () => shutdown("SIGINT"));
385
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
386
+ }
387
+ }
package/src/types.ts ADDED
@@ -0,0 +1,128 @@
1
+ import { z } from "zod";
2
+
3
+ export const LogLevel = z.enum(["debug", "info", "warn", "error", "fatal"]);
4
+ export type LogLevel = z.infer<typeof LogLevel>;
5
+
6
+ export const Framework = z.enum(["react", "nextjs", "nestjs", "unknown"]);
7
+ export type Framework = z.infer<typeof Framework>;
8
+
9
+ export const LogEntrySchema = z.object({
10
+ id: z.string(),
11
+ timestamp: z.string(),
12
+ level: LogLevel,
13
+ message: z.string(),
14
+ source: z.string().optional(),
15
+ framework: Framework.optional(),
16
+ metadata: z.record(z.unknown()).optional(),
17
+ stackTrace: z.string().optional(),
18
+ });
19
+ export type LogEntry = z.infer<typeof LogEntrySchema>;
20
+
21
+ export const HttpRequestSchema = z.object({
22
+ id: z.string(),
23
+ timestamp: z.string(),
24
+ method: z.string(),
25
+ url: z.string(),
26
+ statusCode: z.number().optional(),
27
+ duration: z.number().optional(),
28
+ requestHeaders: z.record(z.string()).optional(),
29
+ responseHeaders: z.record(z.string()).optional(),
30
+ requestBody: z.unknown().optional(),
31
+ responseBody: z.unknown().optional(),
32
+ framework: Framework.optional(),
33
+ error: z.string().optional(),
34
+ });
35
+ export type HttpRequest = z.infer<typeof HttpRequestSchema>;
36
+
37
+ export const PerformanceMetricSchema = z.object({
38
+ name: z.string(),
39
+ value: z.number(),
40
+ unit: z.string(),
41
+ timestamp: z.string(),
42
+ tags: z.record(z.string()).optional(),
43
+ });
44
+ export type PerformanceMetric = z.infer<typeof PerformanceMetricSchema>;
45
+
46
+ export const ProcessInfoSchema = z.object({
47
+ pid: z.number(),
48
+ uptime: z.number(),
49
+ memoryUsage: z.object({
50
+ rss: z.number(),
51
+ heapTotal: z.number(),
52
+ heapUsed: z.number(),
53
+ external: z.number(),
54
+ }),
55
+ cpuUsage: z.object({
56
+ user: z.number(),
57
+ system: z.number(),
58
+ }),
59
+ nodeVersion: z.string(),
60
+ platform: z.string(),
61
+ arch: z.string(),
62
+ cwd: z.string(),
63
+ env: z.record(z.string()).optional(),
64
+ });
65
+ export type ProcessInfo = z.infer<typeof ProcessInfoSchema>;
66
+
67
+ export const TailLogsParamsSchema = z.object({
68
+ lines: z.number().min(1).max(1000).default(50).describe("Number of recent log lines to retrieve"),
69
+ level: LogLevel.optional().describe("Filter by log level"),
70
+ framework: Framework.optional().describe("Filter by framework"),
71
+ source: z.string().optional().describe("Filter by source file or module"),
72
+ });
73
+ export type TailLogsParams = z.infer<typeof TailLogsParamsSchema>;
74
+
75
+ export const SearchLogsParamsSchema = z.object({
76
+ query: z.string().min(1).describe("Search pattern (supports regex)"),
77
+ level: LogLevel.optional().describe("Filter by log level"),
78
+ framework: Framework.optional().describe("Filter by framework"),
79
+ limit: z.number().min(1).max(500).default(50).describe("Maximum results to return"),
80
+ since: z.string().optional().describe("ISO timestamp to search from"),
81
+ });
82
+ export type SearchLogsParams = z.infer<typeof SearchLogsParamsSchema>;
83
+
84
+ export const GetErrorsParamsSchema = z.object({
85
+ limit: z.number().min(1).max(100).default(20).describe("Maximum errors to return"),
86
+ framework: Framework.optional().describe("Filter by framework"),
87
+ grouped: z.boolean().default(false).describe("Group similar errors together"),
88
+ });
89
+ export type GetErrorsParams = z.infer<typeof GetErrorsParamsSchema>;
90
+
91
+ export const InspectRequestParamsSchema = z.object({
92
+ id: z.string().optional().describe("Specific request ID to inspect"),
93
+ method: z.string().optional().describe("Filter by HTTP method"),
94
+ urlPattern: z.string().optional().describe("Filter by URL pattern (supports regex)"),
95
+ statusCode: z.number().optional().describe("Filter by status code"),
96
+ limit: z.number().min(1).max(100).default(20).describe("Maximum requests to return"),
97
+ });
98
+ export type InspectRequestParams = z.infer<typeof InspectRequestParamsSchema>;
99
+
100
+ export const GetPerformanceParamsSchema = z.object({
101
+ metric: z.string().optional().describe("Specific metric name to retrieve"),
102
+ since: z.string().optional().describe("ISO timestamp to get metrics from"),
103
+ limit: z.number().min(1).max(100).default(20).describe("Maximum metrics to return"),
104
+ });
105
+ export type GetPerformanceParams = z.infer<typeof GetPerformanceParamsSchema>;
106
+
107
+ export const ExecuteInContextParamsSchema = z.object({
108
+ expression: z.string().min(1).describe("JavaScript expression to evaluate"),
109
+ framework: Framework.optional().describe("Target framework context"),
110
+ });
111
+ export type ExecuteInContextParams = z.infer<typeof ExecuteInContextParamsSchema>;
112
+
113
+ export const WatchParamsSchema = z.object({
114
+ pattern: z.string().min(1).describe("File glob pattern or log pattern to watch"),
115
+ duration: z.number().min(1).max(300).default(30).describe("Watch duration in seconds"),
116
+ });
117
+ export type WatchParams = z.infer<typeof WatchParamsSchema>;
118
+
119
+ export class RuntimeLensError extends Error {
120
+ constructor(
121
+ message: string,
122
+ public code: string,
123
+ public details?: unknown
124
+ ) {
125
+ super(message);
126
+ this.name = "RuntimeLensError";
127
+ }
128
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Node",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "declaration": true,
11
+ "declarationMap": true,
12
+ "sourceMap": true,
13
+ "outDir": "./dist",
14
+ "rootDir": "./src",
15
+ "resolveJsonModule": true,
16
+ "allowSyntheticDefaultImports": true
17
+ },
18
+ "include": ["src/**/*"],
19
+ "exclude": ["node_modules", "dist"]
20
+ }
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: "node",
7
+ passWithNoTests: true,
8
+ coverage: {
9
+ provider: "v8",
10
+ reporter: ["text", "json", "html"],
11
+ },
12
+ },
13
+ });