@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.
- package/.vscodeignore +21 -0
- package/README.md +136 -0
- package/agent/index.ts +263 -0
- package/agent/tsconfig.json +17 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/log-collector.d.ts +73 -0
- package/dist/log-collector.d.ts.map +1 -0
- package/dist/log-collector.js +349 -0
- package/dist/log-collector.js.map +1 -0
- package/dist/process-inspector.d.ts +44 -0
- package/dist/process-inspector.d.ts.map +1 -0
- package/dist/process-inspector.js +190 -0
- package/dist/process-inspector.js.map +1 -0
- package/dist/runtime-interceptor.d.ts +18 -0
- package/dist/runtime-interceptor.d.ts.map +1 -0
- package/dist/runtime-interceptor.js +133 -0
- package/dist/runtime-interceptor.js.map +1 -0
- package/dist/server.d.ts +26 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +301 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +280 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +102 -0
- package/dist/types.js.map +1 -0
- package/eslint.config.js +41 -0
- package/extension/decorator.ts +144 -0
- package/extension/extension.ts +98 -0
- package/extension/runtime-bridge.ts +206 -0
- package/extension/tsconfig.json +17 -0
- package/package.json +134 -0
- package/src/index.ts +18 -0
- package/src/log-collector.ts +441 -0
- package/src/process-inspector.ts +235 -0
- package/src/runtime-interceptor.ts +152 -0
- package/src/server.ts +387 -0
- package/src/types.ts +128 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +13 -0
package/.vscodeignore
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
src/**
|
|
2
|
+
extension/**/*.ts
|
|
3
|
+
agent/**/*.ts
|
|
4
|
+
node_modules/**
|
|
5
|
+
coverage/**
|
|
6
|
+
examples/**
|
|
7
|
+
.gitignore
|
|
8
|
+
*.tsbuildinfo
|
|
9
|
+
tsconfig.json
|
|
10
|
+
**/tsconfig.json
|
|
11
|
+
vitest.config.ts
|
|
12
|
+
eslint.config.js
|
|
13
|
+
pnpm-lock.yaml
|
|
14
|
+
**/*.map
|
|
15
|
+
dist/index.d.ts
|
|
16
|
+
dist/log-collector.d.ts
|
|
17
|
+
dist/process-inspector.d.ts
|
|
18
|
+
dist/runtime-interceptor.d.ts
|
|
19
|
+
dist/server.d.ts
|
|
20
|
+
dist/types.d.ts
|
|
21
|
+
dist/agent/index.debug.js
|
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# @arvoretech/runtime-lens-mcp
|
|
2
|
+
|
|
3
|
+
Runtime Lens — Runtime inspection with inline values for React, NestJS and Next.js.
|
|
4
|
+
|
|
5
|
+
Two components in one package:
|
|
6
|
+
1. VS Code/Cursor/Kiro extension with inline value display
|
|
7
|
+
2. MCP server for AI-assisted debugging
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
### 1. Build
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
cd packages/runtime-lens
|
|
15
|
+
pnpm install
|
|
16
|
+
pnpm build:all # builds MCP server + extension + agent
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 2. Install the Extension
|
|
20
|
+
|
|
21
|
+
After building, package and install the `.vsix`:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm package # generates runtime-lens-1.0.0.vsix
|
|
25
|
+
code --install-extension runtime-lens-1.0.0.vsix # VS Code
|
|
26
|
+
cursor --install-extension runtime-lens-1.0.0.vsix # Cursor
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For Kiro, use the Extensions panel to install from VSIX.
|
|
30
|
+
|
|
31
|
+
### 3. Configure the MCP Server
|
|
32
|
+
|
|
33
|
+
Add to your editor's MCP config (`.kiro/settings/mcp.json`, `.cursor/mcp.json`, etc.):
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"runtime-lens": {
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["-y", "@arvoretech/runtime-lens-mcp"],
|
|
41
|
+
"env": {
|
|
42
|
+
"RUNTIME_LENS_PROJECT_ROOT": "."
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
### Option A — Command Palette (per session)
|
|
52
|
+
|
|
53
|
+
1. Open the command palette and run `Runtime Lens: Start`
|
|
54
|
+
2. Then run `Runtime Lens: Inject Environment into Terminal`
|
|
55
|
+
3. Start your app normally in that terminal (`pnpm dev`, `npm start`, etc.)
|
|
56
|
+
4. Runtime values appear inline in the editor
|
|
57
|
+
|
|
58
|
+
### Option B — Permanent Setup (recommended)
|
|
59
|
+
|
|
60
|
+
Add this to your `~/.zshrc` (or `~/.bashrc`):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Runtime Lens — inject agent into all Node.js processes
|
|
64
|
+
export RUNTIME_LENS_AGENT_PATH="/Users/$USER/path-to/arvore-mcp-servers/packages/runtime-lens/dist/agent/index.js"
|
|
65
|
+
export NODE_OPTIONS="--require $RUNTIME_LENS_AGENT_PATH"
|
|
66
|
+
export RUNTIME_LENS_PORT="9500"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Then reload your shell:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
source ~/.zshrc
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Now every Node.js process you start will automatically connect to Runtime Lens. Just open the editor and run `Runtime Lens: Start` — no need to inject every time.
|
|
76
|
+
|
|
77
|
+
> **Note:** If `NODE_OPTIONS` conflicts with other tools, you can wrap it in a function:
|
|
78
|
+
>
|
|
79
|
+
> ```bash
|
|
80
|
+
> lens() {
|
|
81
|
+
> NODE_OPTIONS="--require $RUNTIME_LENS_AGENT_PATH" RUNTIME_LENS_PORT=9500 "$@"
|
|
82
|
+
> }
|
|
83
|
+
> # Usage: lens pnpm dev
|
|
84
|
+
> ```
|
|
85
|
+
|
|
86
|
+
## Extension Commands
|
|
87
|
+
|
|
88
|
+
| Command | Description |
|
|
89
|
+
|---------|-------------|
|
|
90
|
+
| `Runtime Lens: Start` | Start listening for runtime values |
|
|
91
|
+
| `Runtime Lens: Stop` | Stop and clear decorations |
|
|
92
|
+
| `Runtime Lens: Toggle` | Toggle on/off (status bar) |
|
|
93
|
+
| `Runtime Lens: Clear Inline Values` | Clear all inline decorations |
|
|
94
|
+
| `Runtime Lens: Connect to Running App` | Connect to an already running agent |
|
|
95
|
+
| `Runtime Lens: Inject Environment into Terminal` | Set NODE_OPTIONS in the active terminal |
|
|
96
|
+
| `Runtime Lens: Show Output` | Show the output channel |
|
|
97
|
+
|
|
98
|
+
## Extension Settings
|
|
99
|
+
|
|
100
|
+
| Setting | Default | Description |
|
|
101
|
+
|---------|---------|-------------|
|
|
102
|
+
| `runtimeLens.port` | `9500` | WebSocket port for the agent |
|
|
103
|
+
| `runtimeLens.autoStart` | `false` | Auto-start on workspace open |
|
|
104
|
+
| `runtimeLens.maxInlineLength` | `80` | Max inline text length |
|
|
105
|
+
| `runtimeLens.showTimestamp` | `false` | Show timestamp in inline values |
|
|
106
|
+
|
|
107
|
+
## MCP Tools
|
|
108
|
+
|
|
109
|
+
14 tools for AI-assisted runtime inspection:
|
|
110
|
+
|
|
111
|
+
| Tool | Description |
|
|
112
|
+
|------|-------------|
|
|
113
|
+
| `tail_logs` | Recent log entries with filtering |
|
|
114
|
+
| `search_logs` | Regex search through logs |
|
|
115
|
+
| `get_errors` | Errors with stack traces, groupable |
|
|
116
|
+
| `inspect_requests` | HTTP request/response inspection |
|
|
117
|
+
| `get_performance` | Memory, CPU metrics |
|
|
118
|
+
| `get_env_info` | Processes, ports, framework detection |
|
|
119
|
+
| `get_stats` | Log statistics by level/framework |
|
|
120
|
+
| `clear_logs` | Clear log buffer |
|
|
121
|
+
| `start_interceptor` / `stop_interceptor` | Real-time console capture |
|
|
122
|
+
| `collect_from_files` | Collect from log files |
|
|
123
|
+
| `scan_project` | Detect framework and configs |
|
|
124
|
+
| `find_processes` | Running Node.js processes |
|
|
125
|
+
| `get_listening_ports` | TCP ports in use |
|
|
126
|
+
|
|
127
|
+
## Development
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
pnpm install
|
|
131
|
+
pnpm build # MCP server (tsc)
|
|
132
|
+
pnpm build:ext # VS Code extension (esbuild)
|
|
133
|
+
pnpm build:agent # Runtime agent (esbuild)
|
|
134
|
+
pnpm build:all # Everything
|
|
135
|
+
pnpm test # Run tests
|
|
136
|
+
```
|
package/agent/index.ts
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import type { IncomingMessage } from "node:http";
|
|
4
|
+
import type { Socket } from "node:net";
|
|
5
|
+
|
|
6
|
+
const PORT = parseInt(process.env.RUNTIME_LENS_PORT || "9500", 10);
|
|
7
|
+
|
|
8
|
+
interface LogMessage {
|
|
9
|
+
type: "log" | "error" | "warn" | "info" | "debug" | "result";
|
|
10
|
+
file: string;
|
|
11
|
+
line: number;
|
|
12
|
+
column: number;
|
|
13
|
+
values: string[];
|
|
14
|
+
timestamp: number;
|
|
15
|
+
expression?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let client: Socket | null = null;
|
|
19
|
+
const buffer: LogMessage[] = [];
|
|
20
|
+
const MAX_BUFFER = 500;
|
|
21
|
+
|
|
22
|
+
function serialize(value: unknown, depth = 0): string {
|
|
23
|
+
if (depth > 3) return "[...]";
|
|
24
|
+
if (value === null) return "null";
|
|
25
|
+
if (value === undefined) return "undefined";
|
|
26
|
+
if (typeof value === "string") return value.length > 100 ? `"${value.slice(0, 100)}..."` : `"${value}"`;
|
|
27
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
28
|
+
if (typeof value === "function") return `fn ${value.name || "anonymous"}()`;
|
|
29
|
+
if (typeof value === "symbol") return value.toString();
|
|
30
|
+
if (typeof value === "bigint") return `${value}n`;
|
|
31
|
+
if (value instanceof Error) return `${value.name}: ${value.message}`;
|
|
32
|
+
if (value instanceof Date) return value.toISOString();
|
|
33
|
+
if (value instanceof RegExp) return value.toString();
|
|
34
|
+
if (value instanceof Map) return `Map(${value.size})`;
|
|
35
|
+
if (value instanceof Set) return `Set(${value.size})`;
|
|
36
|
+
if (value instanceof Promise) return "Promise";
|
|
37
|
+
if (Array.isArray(value)) {
|
|
38
|
+
if (value.length === 0) return "[]";
|
|
39
|
+
const items = value.slice(0, 5).map(v => serialize(v, depth + 1));
|
|
40
|
+
const suffix = value.length > 5 ? `, ...+${value.length - 5}` : "";
|
|
41
|
+
return `[${items.join(", ")}${suffix}]`;
|
|
42
|
+
}
|
|
43
|
+
if (typeof value === "object") {
|
|
44
|
+
const keys = Object.keys(value);
|
|
45
|
+
if (keys.length === 0) return "{}";
|
|
46
|
+
const entries = keys.slice(0, 5).map(k => `${k}: ${serialize((value as Record<string, unknown>)[k], depth + 1)}`);
|
|
47
|
+
const suffix = keys.length > 5 ? `, ...+${keys.length - 5}` : "";
|
|
48
|
+
return `{${entries.join(", ")}${suffix}}`;
|
|
49
|
+
}
|
|
50
|
+
return typeof value === "object" ? Object.prototype.toString.call(value) : String(value);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function wsSend(msg: LogMessage): void {
|
|
54
|
+
const payload = JSON.stringify(msg);
|
|
55
|
+
if (client && !client.destroyed) {
|
|
56
|
+
const buf = Buffer.from(payload, "utf-8");
|
|
57
|
+
const frame = buildWsFrame(buf);
|
|
58
|
+
client.write(frame);
|
|
59
|
+
} else {
|
|
60
|
+
buffer.push(msg);
|
|
61
|
+
if (buffer.length > MAX_BUFFER) buffer.shift();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function flushBuffer(): void {
|
|
66
|
+
while (buffer.length > 0 && client && !client.destroyed) {
|
|
67
|
+
const msg = buffer.shift();
|
|
68
|
+
if (msg) {
|
|
69
|
+
const buf = Buffer.from(JSON.stringify(msg), "utf-8");
|
|
70
|
+
client.write(buildWsFrame(buf));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function buildWsFrame(data: Buffer): Buffer {
|
|
76
|
+
const len = data.length;
|
|
77
|
+
let header: Buffer;
|
|
78
|
+
if (len < 126) {
|
|
79
|
+
header = Buffer.alloc(2);
|
|
80
|
+
header[0] = 0x81;
|
|
81
|
+
header[1] = len;
|
|
82
|
+
} else if (len < 65536) {
|
|
83
|
+
header = Buffer.alloc(4);
|
|
84
|
+
header[0] = 0x81;
|
|
85
|
+
header[1] = 126;
|
|
86
|
+
header.writeUInt16BE(len, 2);
|
|
87
|
+
} else {
|
|
88
|
+
header = Buffer.alloc(10);
|
|
89
|
+
header[0] = 0x81;
|
|
90
|
+
header[1] = 127;
|
|
91
|
+
header.writeBigUInt64BE(BigInt(len), 2);
|
|
92
|
+
}
|
|
93
|
+
return Buffer.concat([header, data]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function parseWsFrame(data: Buffer): string | null {
|
|
97
|
+
if (data.length < 2) return null;
|
|
98
|
+
const masked = (data[1] & 0x80) !== 0;
|
|
99
|
+
let payloadLen = data[1] & 0x7f;
|
|
100
|
+
let offset = 2;
|
|
101
|
+
|
|
102
|
+
if (payloadLen === 126) {
|
|
103
|
+
payloadLen = data.readUInt16BE(2);
|
|
104
|
+
offset = 4;
|
|
105
|
+
} else if (payloadLen === 127) {
|
|
106
|
+
payloadLen = Number(data.readBigUInt64BE(2));
|
|
107
|
+
offset = 10;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
let maskKey: Buffer | null = null;
|
|
111
|
+
if (masked) {
|
|
112
|
+
maskKey = data.subarray(offset, offset + 4);
|
|
113
|
+
offset += 4;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const payload = data.subarray(offset, offset + payloadLen);
|
|
117
|
+
if (maskKey) {
|
|
118
|
+
for (let i = 0; i < payload.length; i++) {
|
|
119
|
+
payload[i] ^= maskKey[i % 4];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return payload.toString("utf-8");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function extractCallSite(): { file: string; line: number; column: number } {
|
|
126
|
+
const stack = new Error().stack || "";
|
|
127
|
+
const lines = stack.split("\n");
|
|
128
|
+
for (let i = 2; i < lines.length; i++) {
|
|
129
|
+
const line = lines[i];
|
|
130
|
+
if (line.includes("node:") || line.includes("dist/agent/index.js")) continue;
|
|
131
|
+
const match = /\((.+):(\d+):(\d+)\)/.exec(line) || /at (.+):(\d+):(\d+)/.exec(line);
|
|
132
|
+
if (match) {
|
|
133
|
+
return { file: match[1], line: parseInt(match[2], 10), column: parseInt(match[3], 10) };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return { file: "unknown", line: 0, column: 0 };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
type ConsoleMethod = "log" | "info" | "warn" | "error" | "debug";
|
|
140
|
+
const originalConsole: Record<ConsoleMethod, (...args: unknown[]) => void> = {
|
|
141
|
+
log: console.log.bind(console),
|
|
142
|
+
info: console.info.bind(console),
|
|
143
|
+
warn: console.warn.bind(console),
|
|
144
|
+
error: console.error.bind(console),
|
|
145
|
+
debug: console.debug.bind(console),
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
function patchConsole(): void {
|
|
149
|
+
const methods: ConsoleMethod[] = ["log", "info", "warn", "error", "debug"];
|
|
150
|
+
for (const method of methods) {
|
|
151
|
+
console[method] = (...args: unknown[]) => {
|
|
152
|
+
const site = extractCallSite();
|
|
153
|
+
wsSend({
|
|
154
|
+
type: method,
|
|
155
|
+
file: site.file,
|
|
156
|
+
line: site.line,
|
|
157
|
+
column: site.column,
|
|
158
|
+
values: args.map(a => serialize(a)),
|
|
159
|
+
timestamp: Date.now(),
|
|
160
|
+
});
|
|
161
|
+
originalConsole[method](...args);
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const server = createServer((_req, res) => {
|
|
167
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
168
|
+
res.end(JSON.stringify({ status: "ok", pid: process.pid, uptime: process.uptime() }));
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
server.on("upgrade", (req: IncomingMessage, socket: Socket) => {
|
|
172
|
+
const key = req.headers["sec-websocket-key"];
|
|
173
|
+
if (!key) {
|
|
174
|
+
socket.destroy();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const acceptKey = createHash("sha1")
|
|
179
|
+
.update(key + "258EAFA5-E914-47DA-95CA-5AB5DC11650B")
|
|
180
|
+
.digest("base64");
|
|
181
|
+
|
|
182
|
+
socket.write(
|
|
183
|
+
"HTTP/1.1 101 Switching Protocols\r\n" +
|
|
184
|
+
"Upgrade: websocket\r\n" +
|
|
185
|
+
"Connection: Upgrade\r\n" +
|
|
186
|
+
`Sec-WebSocket-Accept: ${acceptKey}\r\n` +
|
|
187
|
+
"\r\n"
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
client = socket;
|
|
191
|
+
flushBuffer();
|
|
192
|
+
|
|
193
|
+
socket.on("data", (data: Buffer) => {
|
|
194
|
+
const text = parseWsFrame(data);
|
|
195
|
+
if (!text) return;
|
|
196
|
+
try {
|
|
197
|
+
const msg = JSON.parse(text);
|
|
198
|
+
if (msg.type === "eval") {
|
|
199
|
+
try {
|
|
200
|
+
const fn = new Function(`return (${msg.expression})`);
|
|
201
|
+
const result = fn();
|
|
202
|
+
wsSend({
|
|
203
|
+
type: "result",
|
|
204
|
+
file: msg.file || "eval",
|
|
205
|
+
line: msg.line || 0,
|
|
206
|
+
column: msg.column || 0,
|
|
207
|
+
values: [serialize(result)],
|
|
208
|
+
timestamp: Date.now(),
|
|
209
|
+
expression: msg.expression,
|
|
210
|
+
});
|
|
211
|
+
} catch (err: unknown) {
|
|
212
|
+
wsSend({
|
|
213
|
+
type: "error",
|
|
214
|
+
file: msg.file || "eval",
|
|
215
|
+
line: msg.line || 0,
|
|
216
|
+
column: msg.column || 0,
|
|
217
|
+
values: [err instanceof Error ? err.message : String(err)],
|
|
218
|
+
timestamp: Date.now(),
|
|
219
|
+
expression: msg.expression,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} catch {
|
|
224
|
+
// invalid JSON
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
socket.on("close", () => {
|
|
229
|
+
client = null;
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
socket.on("error", () => {
|
|
233
|
+
client = null;
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
server.on("error", (err: NodeJS.ErrnoException) => {
|
|
238
|
+
if (err.code === "EADDRINUSE") {
|
|
239
|
+
originalConsole.log(`[runtime-lens] port ${PORT} in use, skipping agent server`);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
server.listen(PORT, () => {
|
|
244
|
+
originalConsole.log(`[runtime-lens] agent listening on ws://localhost:${PORT}`);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
server.unref();
|
|
248
|
+
|
|
249
|
+
patchConsole();
|
|
250
|
+
|
|
251
|
+
(globalThis as Record<string, unknown>).__runtimeLens = {
|
|
252
|
+
log: (...args: unknown[]) => {
|
|
253
|
+
const site = extractCallSite();
|
|
254
|
+
wsSend({
|
|
255
|
+
type: "result",
|
|
256
|
+
file: site.file,
|
|
257
|
+
line: site.line,
|
|
258
|
+
column: site.column,
|
|
259
|
+
values: args.map(a => serialize(a)),
|
|
260
|
+
timestamp: Date.now(),
|
|
261
|
+
});
|
|
262
|
+
},
|
|
263
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"moduleResolution": "Node",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"declaration": false,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"outDir": "../dist/agent",
|
|
13
|
+
"rootDir": "."
|
|
14
|
+
},
|
|
15
|
+
"include": ["./**/*.ts"],
|
|
16
|
+
"exclude": ["node_modules"]
|
|
17
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export { RuntimeLensMCPServer } from "./server.js";
|
|
3
|
+
export { LogCollector } from "./log-collector.js";
|
|
4
|
+
export { ProcessInspector } from "./process-inspector.js";
|
|
5
|
+
export { RuntimeInterceptor } from "./runtime-interceptor.js";
|
|
6
|
+
export * from "./types.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAaA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,cAAc,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { RuntimeLensMCPServer } from "./server.js";
|
|
3
|
+
try {
|
|
4
|
+
const server = RuntimeLensMCPServer.fromEnvironment();
|
|
5
|
+
server.setupGracefulShutdown();
|
|
6
|
+
await server.start();
|
|
7
|
+
}
|
|
8
|
+
catch (error) {
|
|
9
|
+
console.error("Failed to start Runtime Lens MCP Server:", error);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
export { RuntimeLensMCPServer } from "./server.js";
|
|
13
|
+
export { LogCollector } from "./log-collector.js";
|
|
14
|
+
export { ProcessInspector } from "./process-inspector.js";
|
|
15
|
+
export { RuntimeInterceptor } from "./runtime-interceptor.js";
|
|
16
|
+
export * from "./types.js";
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,IAAI,CAAC;IACH,MAAM,MAAM,GAAG,oBAAoB,CAAC,eAAe,EAAE,CAAC;IACtD,MAAM,CAAC,qBAAqB,EAAE,CAAC;IAC/B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;IACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { LogEntry, LogLevel, Framework, HttpRequest, PerformanceMetric } from "./types.js";
|
|
2
|
+
export declare class LogCollector {
|
|
3
|
+
private buffer;
|
|
4
|
+
private logPaths;
|
|
5
|
+
private projectRoot;
|
|
6
|
+
constructor(projectRoot?: string, logPaths?: string[]);
|
|
7
|
+
collectFromFiles(): Promise<void>;
|
|
8
|
+
collectFromProcess(): Promise<void>;
|
|
9
|
+
scanProjectStructure(): Promise<{
|
|
10
|
+
framework: Framework;
|
|
11
|
+
logFiles: string[];
|
|
12
|
+
configFiles: string[];
|
|
13
|
+
}>;
|
|
14
|
+
addLog(entry: Omit<LogEntry, "id" | "timestamp">): void;
|
|
15
|
+
addLogs(entries: LogEntry[]): void;
|
|
16
|
+
addRequest(request: Omit<HttpRequest, "id" | "timestamp">): void;
|
|
17
|
+
addMetric(metric: PerformanceMetric): void;
|
|
18
|
+
getLogs(options?: {
|
|
19
|
+
lines?: number;
|
|
20
|
+
level?: LogLevel;
|
|
21
|
+
framework?: Framework;
|
|
22
|
+
source?: string;
|
|
23
|
+
}): LogEntry[];
|
|
24
|
+
searchLogs(options: {
|
|
25
|
+
query: string;
|
|
26
|
+
level?: LogLevel;
|
|
27
|
+
framework?: Framework;
|
|
28
|
+
limit?: number;
|
|
29
|
+
since?: string;
|
|
30
|
+
}): LogEntry[];
|
|
31
|
+
getErrors(options?: {
|
|
32
|
+
limit?: number;
|
|
33
|
+
framework?: Framework;
|
|
34
|
+
grouped?: boolean;
|
|
35
|
+
}): LogEntry[] | {
|
|
36
|
+
message: string;
|
|
37
|
+
count: number;
|
|
38
|
+
lastSeen: string;
|
|
39
|
+
sample: LogEntry;
|
|
40
|
+
}[];
|
|
41
|
+
getRequests(options?: {
|
|
42
|
+
id?: string;
|
|
43
|
+
method?: string;
|
|
44
|
+
urlPattern?: string;
|
|
45
|
+
statusCode?: number;
|
|
46
|
+
limit?: number;
|
|
47
|
+
}): HttpRequest[];
|
|
48
|
+
getMetrics(options?: {
|
|
49
|
+
metric?: string;
|
|
50
|
+
since?: string;
|
|
51
|
+
limit?: number;
|
|
52
|
+
}): PerformanceMetric[];
|
|
53
|
+
clearLogs(): {
|
|
54
|
+
cleared: number;
|
|
55
|
+
};
|
|
56
|
+
getStats(): {
|
|
57
|
+
totalLogs: number;
|
|
58
|
+
totalRequests: number;
|
|
59
|
+
totalMetrics: number;
|
|
60
|
+
byLevel: Record<string, number>;
|
|
61
|
+
byFramework: Record<string, number>;
|
|
62
|
+
};
|
|
63
|
+
private parseLogFile;
|
|
64
|
+
private parseLogLine;
|
|
65
|
+
private tryParseJson;
|
|
66
|
+
private normalizeLevel;
|
|
67
|
+
private inferFramework;
|
|
68
|
+
private detectFramework;
|
|
69
|
+
private discoverLogFiles;
|
|
70
|
+
private discoverConfigFiles;
|
|
71
|
+
private trimBuffer;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=log-collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-collector.d.ts","sourceRoot":"","sources":["../src/log-collector.ts"],"names":[],"mappings":"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"}
|