proofscan 0.9.2 → 0.10.1

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 (43) hide show
  1. package/dist/cli.js +6 -2
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/index.d.ts +2 -0
  4. package/dist/commands/index.d.ts.map +1 -1
  5. package/dist/commands/index.js +4 -0
  6. package/dist/commands/index.js.map +1 -1
  7. package/dist/commands/log.d.ts +10 -0
  8. package/dist/commands/log.d.ts.map +1 -0
  9. package/dist/commands/log.js +126 -0
  10. package/dist/commands/log.js.map +1 -0
  11. package/dist/commands/proxy.d.ts +12 -0
  12. package/dist/commands/proxy.d.ts.map +1 -0
  13. package/dist/commands/proxy.js +220 -0
  14. package/dist/commands/proxy.js.map +1 -0
  15. package/dist/proxy/index.d.ts +10 -0
  16. package/dist/proxy/index.d.ts.map +1 -0
  17. package/dist/proxy/index.js +10 -0
  18. package/dist/proxy/index.js.map +1 -0
  19. package/dist/proxy/logger.d.ts +110 -0
  20. package/dist/proxy/logger.d.ts.map +1 -0
  21. package/dist/proxy/logger.js +248 -0
  22. package/dist/proxy/logger.js.map +1 -0
  23. package/dist/proxy/mcp-server.d.ts +101 -0
  24. package/dist/proxy/mcp-server.d.ts.map +1 -0
  25. package/dist/proxy/mcp-server.js +391 -0
  26. package/dist/proxy/mcp-server.js.map +1 -0
  27. package/dist/proxy/request-router.d.ts +26 -0
  28. package/dist/proxy/request-router.d.ts.map +1 -0
  29. package/dist/proxy/request-router.js +90 -0
  30. package/dist/proxy/request-router.js.map +1 -0
  31. package/dist/proxy/runtime-state.d.ts +131 -0
  32. package/dist/proxy/runtime-state.d.ts.map +1 -0
  33. package/dist/proxy/runtime-state.js +241 -0
  34. package/dist/proxy/runtime-state.js.map +1 -0
  35. package/dist/proxy/tool-aggregator.d.ts +46 -0
  36. package/dist/proxy/tool-aggregator.d.ts.map +1 -0
  37. package/dist/proxy/tool-aggregator.js +112 -0
  38. package/dist/proxy/tool-aggregator.js.map +1 -0
  39. package/dist/proxy/types.d.ts +117 -0
  40. package/dist/proxy/types.d.ts.map +1 -0
  41. package/dist/proxy/types.js +21 -0
  42. package/dist/proxy/types.js.map +1 -0
  43. package/package.json +1 -1
@@ -0,0 +1,391 @@
1
+ /**
2
+ * MCP Proxy Server (Phase 5.0+)
3
+ *
4
+ * A stdio-based MCP server that aggregates tools from multiple backend
5
+ * connectors and routes requests accordingly.
6
+ *
7
+ * Supported methods:
8
+ * - initialize
9
+ * - notifications/initialized
10
+ * - tools/list
11
+ * - tools/call
12
+ */
13
+ import { EventEmitter } from 'events';
14
+ import { join } from 'path';
15
+ import { logger, initializeRingBuffer, isVerbose } from './logger.js';
16
+ import { ToolAggregator } from './tool-aggregator.js';
17
+ import { RequestRouter } from './request-router.js';
18
+ import { RuntimeStateManager, } from './runtime-state.js';
19
+ import { MCP_ERROR, } from './types.js';
20
+ const PROTOCOL_VERSION = '2024-11-05';
21
+ const SERVER_NAME = 'proofscan-proxy';
22
+ const SERVER_VERSION = '0.7.0';
23
+ /** Maximum buffer size in bytes (1MB) - prevents memory exhaustion attacks */
24
+ const MAX_BUFFER_SIZE = 1024 * 1024;
25
+ /** Maximum log lines in ring buffer */
26
+ const MAX_LOG_LINES = 1000;
27
+ /**
28
+ * MCP Proxy Server
29
+ *
30
+ * Reads JSON-RPC from stdin, writes responses to stdout.
31
+ * All logging goes to stderr.
32
+ */
33
+ export class McpProxyServer extends EventEmitter {
34
+ options;
35
+ aggregator;
36
+ router;
37
+ stateManager;
38
+ buffer = '';
39
+ initialized = false;
40
+ running = false;
41
+ /** Current client info (extracted from initialize) */
42
+ currentClient = null;
43
+ constructor(options) {
44
+ super();
45
+ this.options = options;
46
+ this.aggregator = new ToolAggregator(options);
47
+ this.router = new RequestRouter(options, this.aggregator);
48
+ this.stateManager = new RuntimeStateManager(options.configDir);
49
+ }
50
+ /**
51
+ * Start the proxy server
52
+ *
53
+ * Begins reading from stdin and processing JSON-RPC messages.
54
+ */
55
+ async start() {
56
+ if (this.running) {
57
+ throw new Error('Server is already running');
58
+ }
59
+ this.running = true;
60
+ logger.info('MCP proxy server starting...', 'server');
61
+ // Initialize ring buffer for log viewing
62
+ initializeRingBuffer({
63
+ maxLines: MAX_LOG_LINES,
64
+ logPath: join(this.options.configDir, 'proxy-logs.jsonl'),
65
+ onCountChange: (count) => {
66
+ this.stateManager.updateLogCount(count);
67
+ },
68
+ });
69
+ // Build connector summaries for status display
70
+ const connectorSummaries = await this.buildConnectorSummaries();
71
+ // Initialize runtime state
72
+ const logLevel = isVerbose() ? 'INFO' : 'WARN';
73
+ await this.stateManager.initialize(connectorSummaries, logLevel);
74
+ this.stateManager.startHeartbeat();
75
+ // Set up stdin
76
+ process.stdin.setEncoding('utf-8');
77
+ process.stdin.on('data', (chunk) => this.handleData(chunk));
78
+ process.stdin.on('end', () => this.handleEnd());
79
+ process.stdin.on('error', (err) => this.handleError(err));
80
+ // Resume stdin
81
+ process.stdin.resume();
82
+ logger.info(`Proxy started with ${connectorSummaries.length} connector(s)`, 'server');
83
+ }
84
+ /**
85
+ * Build connector summaries for status display
86
+ */
87
+ async buildConnectorSummaries() {
88
+ const summaries = [];
89
+ for (const connector of this.options.connectors) {
90
+ try {
91
+ // Try to get tool count - this doesn't actually connect yet
92
+ // The actual connection happens when tools/list is called
93
+ summaries.push({
94
+ id: connector.id,
95
+ toolCount: 0, // Will be updated on first tools/list
96
+ healthy: true,
97
+ });
98
+ }
99
+ catch (error) {
100
+ summaries.push({
101
+ id: connector.id,
102
+ toolCount: 0,
103
+ healthy: false,
104
+ error: error instanceof Error ? error.message : String(error),
105
+ });
106
+ }
107
+ }
108
+ return summaries;
109
+ }
110
+ /**
111
+ * Stop the proxy server
112
+ */
113
+ stop() {
114
+ if (!this.running) {
115
+ return;
116
+ }
117
+ this.running = false;
118
+ logger.info('MCP proxy server stopping...', 'server');
119
+ // Stop heartbeat
120
+ this.stateManager.stopHeartbeat();
121
+ // Mark proxy as stopped (async but we don't wait)
122
+ this.stateManager.markStopped().catch(() => {
123
+ // Ignore errors during shutdown
124
+ });
125
+ // Clean up stdin
126
+ process.stdin.pause();
127
+ process.stdin.removeAllListeners();
128
+ this.emit('stopped');
129
+ }
130
+ /**
131
+ * Handle incoming data from stdin
132
+ */
133
+ handleData(chunk) {
134
+ this.buffer += chunk;
135
+ // Prevent memory exhaustion from large messages without newlines
136
+ if (this.buffer.length > MAX_BUFFER_SIZE) {
137
+ logger.error(`Buffer overflow: ${this.buffer.length} bytes exceeds ${MAX_BUFFER_SIZE}`, 'server');
138
+ this.sendError(null, MCP_ERROR.INVALID_REQUEST, 'Message too large');
139
+ this.buffer = '';
140
+ return;
141
+ }
142
+ this.processBuffer();
143
+ }
144
+ /**
145
+ * Handle stdin end
146
+ */
147
+ handleEnd() {
148
+ logger.info('stdin closed', 'server');
149
+ // Mark current client as gone
150
+ if (this.currentClient) {
151
+ this.stateManager
152
+ .updateClient(this.currentClient.name, { state: 'gone' })
153
+ .catch(() => {
154
+ // Ignore errors during shutdown
155
+ });
156
+ }
157
+ this.stop();
158
+ }
159
+ /**
160
+ * Handle stdin error
161
+ */
162
+ handleError(err) {
163
+ logger.error(`stdin error: ${err.message}`);
164
+ this.stop();
165
+ }
166
+ /**
167
+ * Process buffered data and extract complete JSON-RPC messages
168
+ *
169
+ * Messages are newline-delimited JSON.
170
+ */
171
+ processBuffer() {
172
+ let newlineIndex;
173
+ while ((newlineIndex = this.buffer.indexOf('\n')) !== -1) {
174
+ const line = this.buffer.slice(0, newlineIndex).trim();
175
+ this.buffer = this.buffer.slice(newlineIndex + 1);
176
+ if (line) {
177
+ this.processMessage(line).catch((err) => {
178
+ logger.error(`Message processing error: ${err instanceof Error ? err.message : err}`);
179
+ });
180
+ }
181
+ }
182
+ }
183
+ /**
184
+ * Process a single JSON-RPC message
185
+ */
186
+ async processMessage(line) {
187
+ let parsed;
188
+ try {
189
+ parsed = JSON.parse(line);
190
+ }
191
+ catch {
192
+ logger.error('JSON parse error');
193
+ this.sendError(null, MCP_ERROR.PARSE_ERROR, 'Parse error');
194
+ return;
195
+ }
196
+ // Validate JSON-RPC structure
197
+ if (typeof parsed !== 'object' || parsed === null) {
198
+ logger.error('Invalid request: not an object');
199
+ this.sendError(null, MCP_ERROR.INVALID_REQUEST, 'Invalid Request');
200
+ return;
201
+ }
202
+ const msg = parsed;
203
+ if (msg.jsonrpc !== '2.0') {
204
+ logger.error('Invalid request: not JSON-RPC 2.0');
205
+ this.sendError(null, MCP_ERROR.INVALID_REQUEST, 'Invalid Request');
206
+ return;
207
+ }
208
+ // Check if it's a request (has id) or notification (no id)
209
+ const hasId = 'id' in msg && msg.id !== undefined;
210
+ const method = msg.method;
211
+ if (!method || typeof method !== 'string') {
212
+ logger.error('Invalid request: missing method');
213
+ if (hasId) {
214
+ this.sendError(msg.id, MCP_ERROR.INVALID_REQUEST, 'Invalid Request');
215
+ }
216
+ return;
217
+ }
218
+ if (hasId) {
219
+ // It's a request - needs response
220
+ await this.handleRequest(msg);
221
+ }
222
+ else {
223
+ // It's a notification - no response needed
224
+ this.handleNotification(msg);
225
+ }
226
+ }
227
+ /**
228
+ * Handle a JSON-RPC request (requires response)
229
+ */
230
+ async handleRequest(request) {
231
+ // Check if server is still running (prevents race condition on shutdown)
232
+ if (!this.running) {
233
+ return;
234
+ }
235
+ const { id, method, params } = request;
236
+ logger.info(`Request: ${method}`);
237
+ switch (method) {
238
+ case 'initialize':
239
+ await this.handleInitialize(id, params);
240
+ break;
241
+ case 'tools/list':
242
+ await this.handleToolsList(id);
243
+ break;
244
+ case 'tools/call':
245
+ await this.handleToolsCall(id, params);
246
+ break;
247
+ default:
248
+ logger.warn(`Unknown method: ${method}`);
249
+ this.sendError(id, MCP_ERROR.METHOD_NOT_FOUND, `Method not found: ${method}`);
250
+ }
251
+ }
252
+ /**
253
+ * Handle a JSON-RPC notification (no response)
254
+ */
255
+ handleNotification(notification) {
256
+ const { method } = notification;
257
+ logger.info(`Notification: ${method}`);
258
+ switch (method) {
259
+ case 'notifications/initialized':
260
+ // Client acknowledged initialization
261
+ logger.info('Client initialized');
262
+ break;
263
+ default:
264
+ // Unknown notifications are silently ignored per MCP spec
265
+ logger.info(`Ignoring notification: ${method}`);
266
+ }
267
+ }
268
+ /**
269
+ * Handle initialize request
270
+ */
271
+ async handleInitialize(id, params) {
272
+ if (this.initialized) {
273
+ logger.warn('Already initialized', 'init');
274
+ }
275
+ const clientVersion = params?.protocolVersion || 'unknown';
276
+ const clientName = params?.clientInfo?.name || 'unknown';
277
+ logger.info(`Client: ${clientName} (protocol=${clientVersion})`, 'init');
278
+ // Track client
279
+ this.currentClient = {
280
+ name: clientName,
281
+ protocolVersion: clientVersion,
282
+ };
283
+ // Update client state
284
+ await this.stateManager.updateClient(clientName, {
285
+ name: clientName,
286
+ protocolVersion: clientVersion,
287
+ state: 'active',
288
+ });
289
+ this.initialized = true;
290
+ const result = {
291
+ protocolVersion: PROTOCOL_VERSION,
292
+ capabilities: {
293
+ tools: {},
294
+ },
295
+ serverInfo: {
296
+ name: SERVER_NAME,
297
+ version: SERVER_VERSION,
298
+ },
299
+ };
300
+ this.sendResult(id, result);
301
+ }
302
+ /**
303
+ * Handle tools/list request
304
+ */
305
+ async handleToolsList(id) {
306
+ if (!this.initialized) {
307
+ logger.warn('tools/list before initialize');
308
+ }
309
+ try {
310
+ const tools = await this.aggregator.getAggregatedTools();
311
+ const result = {
312
+ tools: tools.map((t) => ({
313
+ name: t.namespacedName,
314
+ description: t.description,
315
+ inputSchema: t.inputSchema,
316
+ })),
317
+ };
318
+ logger.info(`Returning ${tools.length} tool(s)`);
319
+ this.sendResult(id, result);
320
+ }
321
+ catch (error) {
322
+ const errorMessage = error instanceof Error ? error.message : String(error);
323
+ logger.error(`tools/list failed: ${errorMessage}`);
324
+ this.sendError(id, MCP_ERROR.INTERNAL_ERROR, errorMessage);
325
+ }
326
+ }
327
+ /**
328
+ * Handle tools/call request
329
+ */
330
+ async handleToolsCall(id, params) {
331
+ if (!this.initialized) {
332
+ logger.warn('tools/call before initialize');
333
+ }
334
+ if (!params || typeof params.name !== 'string') {
335
+ logger.error('tools/call: missing or invalid name');
336
+ this.sendError(id, MCP_ERROR.INVALID_PARAMS, 'Missing required parameter: name');
337
+ return;
338
+ }
339
+ const { name, arguments: args = {} } = params;
340
+ logger.info(`tools/call name=${name}`);
341
+ // Record tool call for client tracking
342
+ if (this.currentClient) {
343
+ await this.stateManager.recordToolCall(this.currentClient.name);
344
+ }
345
+ const result = await this.router.routeToolCall(name, args);
346
+ if (!result.success) {
347
+ // Routing or backend error
348
+ this.sendError(id, MCP_ERROR.INTERNAL_ERROR, result.error || 'Unknown error');
349
+ return;
350
+ }
351
+ const callResult = {
352
+ content: result.content,
353
+ isError: result.isError,
354
+ };
355
+ this.sendResult(id, callResult);
356
+ }
357
+ /**
358
+ * Send a JSON-RPC response with result
359
+ */
360
+ sendResult(id, result) {
361
+ const response = {
362
+ jsonrpc: '2.0',
363
+ id,
364
+ result,
365
+ };
366
+ this.send(response);
367
+ }
368
+ /**
369
+ * Send a JSON-RPC error response
370
+ */
371
+ sendError(id, code, message, data) {
372
+ const response = {
373
+ jsonrpc: '2.0',
374
+ id,
375
+ error: {
376
+ code,
377
+ message,
378
+ ...(data !== undefined ? { data } : {}),
379
+ },
380
+ };
381
+ this.send(response);
382
+ }
383
+ /**
384
+ * Send a message to stdout
385
+ */
386
+ send(message) {
387
+ const json = JSON.stringify(message);
388
+ process.stdout.write(json + '\n');
389
+ }
390
+ }
391
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../src/proxy/mcp-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Request Router (Phase 5.0)
3
+ *
4
+ * Routes tools/call requests to the appropriate backend connector
5
+ * based on the namespace prefix.
6
+ */
7
+ import { type ProxyOptions, type RouteResult } from './types.js';
8
+ import { ToolAggregator } from './tool-aggregator.js';
9
+ /**
10
+ * Routes tool call requests to backend connectors
11
+ */
12
+ export declare class RequestRouter {
13
+ private readonly aggregator;
14
+ private readonly configDir;
15
+ private readonly timeout;
16
+ constructor(options: ProxyOptions, aggregator: ToolAggregator);
17
+ /**
18
+ * Route a tools/call request to the appropriate backend
19
+ *
20
+ * @param namespacedName - Tool name with namespace prefix (e.g., "time__get_current_time")
21
+ * @param args - Tool arguments
22
+ * @returns Route result with content or error
23
+ */
24
+ routeToolCall(namespacedName: string, args: Record<string, unknown>): Promise<RouteResult>;
25
+ }
26
+ //# sourceMappingURL=request-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-router.d.ts","sourceRoot":"","sources":["../../src/proxy/request-router.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAmB,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc;IAM7D;;;;;;OAMG;IACG,aAAa,CACjB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,WAAW,CAAC;CAmExB"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Request Router (Phase 5.0)
3
+ *
4
+ * Routes tools/call requests to the appropriate backend connector
5
+ * based on the namespace prefix.
6
+ */
7
+ import { callTool } from '../tools/adapter.js';
8
+ import { logger } from './logger.js';
9
+ import { DEFAULT_TIMEOUT } from './types.js';
10
+ /**
11
+ * Routes tool call requests to backend connectors
12
+ */
13
+ export class RequestRouter {
14
+ aggregator;
15
+ configDir;
16
+ timeout;
17
+ constructor(options, aggregator) {
18
+ this.aggregator = aggregator;
19
+ this.configDir = options.configDir;
20
+ this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
21
+ }
22
+ /**
23
+ * Route a tools/call request to the appropriate backend
24
+ *
25
+ * @param namespacedName - Tool name with namespace prefix (e.g., "time__get_current_time")
26
+ * @param args - Tool arguments
27
+ * @returns Route result with content or error
28
+ */
29
+ async routeToolCall(namespacedName, args) {
30
+ // Parse namespace
31
+ const parsed = this.aggregator.parseNamespace(namespacedName);
32
+ if (!parsed) {
33
+ logger.error(`Invalid namespace format: ${namespacedName}`);
34
+ return {
35
+ success: false,
36
+ error: `Invalid tool name format. Expected: <connector>__<tool>, got: ${namespacedName}`,
37
+ };
38
+ }
39
+ const { connectorId, toolName } = parsed;
40
+ logger.info(`Routing → connector=${connectorId} tool=${toolName}`);
41
+ // Find connector
42
+ const connector = this.aggregator.findConnector(connectorId);
43
+ if (!connector) {
44
+ logger.error(`Connector not found: ${connectorId}`);
45
+ return {
46
+ success: false,
47
+ error: `Connector not found: ${connectorId}`,
48
+ };
49
+ }
50
+ if (!connector.enabled) {
51
+ logger.error(`Connector disabled: ${connectorId}`);
52
+ return {
53
+ success: false,
54
+ error: `Connector is disabled: ${connectorId}`,
55
+ };
56
+ }
57
+ // Call the backend tool
58
+ const ctx = {
59
+ connectorId,
60
+ configDir: this.configDir,
61
+ };
62
+ try {
63
+ const result = await callTool(ctx, connector, toolName, args, {
64
+ timeout: this.timeout,
65
+ });
66
+ if (result.success) {
67
+ logger.info(`Result: success sessionId=${result.sessionId.slice(0, 8)}`);
68
+ }
69
+ else {
70
+ logger.error(`Result: failed sessionId=${result.sessionId.slice(0, 8)} error=${result.error}`);
71
+ }
72
+ return {
73
+ success: result.success,
74
+ content: result.content,
75
+ isError: result.isError,
76
+ error: result.error,
77
+ sessionId: result.sessionId,
78
+ };
79
+ }
80
+ catch (error) {
81
+ const errorMessage = error instanceof Error ? error.message : String(error);
82
+ logger.error(`Backend call failed: ${errorMessage}`);
83
+ return {
84
+ success: false,
85
+ error: errorMessage,
86
+ };
87
+ }
88
+ }
89
+ }
90
+ //# sourceMappingURL=request-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-router.js","sourceRoot":"","sources":["../../src/proxy/request-router.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,eAAe,EAAuC,MAAM,YAAY,CAAC;AAGlF;;GAEG;AACH,MAAM,OAAO,aAAa;IACP,UAAU,CAAiB;IAC3B,SAAS,CAAS;IAClB,OAAO,CAAS;IAEjC,YAAY,OAAqB,EAAE,UAA0B;QAC3D,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,eAAe,CAAC;IACpD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,aAAa,CACjB,cAAsB,EACtB,IAA6B;QAE7B,kBAAkB;QAClB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;QAE9D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,CAAC,KAAK,CAAC,6BAA6B,cAAc,EAAE,CAAC,CAAC;YAC5D,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,iEAAiE,cAAc,EAAE;aACzF,CAAC;QACJ,CAAC;QAED,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,uBAAuB,WAAW,SAAS,QAAQ,EAAE,CAAC,CAAC;QAEnE,iBAAiB;QACjB,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QAE7D,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,wBAAwB,WAAW,EAAE,CAAC,CAAC;YACpD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,wBAAwB,WAAW,EAAE;aAC7C,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,CAAC,KAAK,CAAC,uBAAuB,WAAW,EAAE,CAAC,CAAC;YACnD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,0BAA0B,WAAW,EAAE;aAC/C,CAAC;QACJ,CAAC;QAED,wBAAwB;QACxB,MAAM,GAAG,GAAG;YACV,WAAW;YACX,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC5D,OAAO,EAAE,IAAI,CAAC,OAAO;aACtB,CAAC,CAAC;YAEH,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,CAAC,6BAA6B,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3E,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,4BAA4B,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YACjG,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,SAAS,EAAE,MAAM,CAAC,SAAS;aAC5B,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5E,MAAM,CAAC,KAAK,CAAC,wBAAwB,YAAY,EAAE,CAAC,CAAC;YACrD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,YAAY;aACpB,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Runtime State Manager (Phase 5.0+)
3
+ *
4
+ * Manages persistent runtime state for IPC between proxy and CLI.
5
+ * State is written to a JSON file in configDir.
6
+ */
7
+ /** Client connection state */
8
+ export type ClientState = 'active' | 'idle' | 'gone';
9
+ /** Individual client tracking info */
10
+ export interface ClientInfo {
11
+ /** Client name from initialize params */
12
+ name: string;
13
+ /** Protocol version */
14
+ protocolVersion: string;
15
+ /** Current state */
16
+ state: ClientState;
17
+ /** When client was first seen (ISO timestamp) */
18
+ connectedAt: string;
19
+ /** When client was last active (ISO timestamp) */
20
+ lastSeen: string;
21
+ /** Number of sessions (reinitializations) */
22
+ sessions: number;
23
+ /** Total tool calls made */
24
+ toolCalls: number;
25
+ }
26
+ /** Connector summary for status display */
27
+ export interface ConnectorSummary {
28
+ /** Connector ID */
29
+ id: string;
30
+ /** Number of tools published */
31
+ toolCount: number;
32
+ /** Whether tools were successfully loaded */
33
+ healthy: boolean;
34
+ /** Error message if unhealthy */
35
+ error?: string;
36
+ }
37
+ /** Proxy runtime state persisted to JSON file */
38
+ export interface ProxyRuntimeState {
39
+ /** Schema version for forward compatibility */
40
+ version: 1;
41
+ /** Proxy state */
42
+ proxy: {
43
+ /** Current state */
44
+ state: 'RUNNING' | 'STOPPED';
45
+ /** Communication mode */
46
+ mode: 'stdio';
47
+ /** When proxy started (ISO timestamp) */
48
+ startedAt: string;
49
+ /** Process ID for staleness detection */
50
+ pid: number;
51
+ /** Last heartbeat (ISO timestamp) */
52
+ heartbeat: string;
53
+ };
54
+ /** Published connectors */
55
+ connectors: ConnectorSummary[];
56
+ /** Connected clients (for stdio mode, typically 1) */
57
+ clients: Record<string, ClientInfo>;
58
+ /** Logging configuration */
59
+ logging: {
60
+ /** Current log level */
61
+ level: 'INFO' | 'WARN' | 'ERROR';
62
+ /** Number of lines in ring buffer */
63
+ bufferedLines: number;
64
+ /** Max lines before rotation */
65
+ maxLines: number;
66
+ };
67
+ }
68
+ /** Default state when proxy is not running */
69
+ export declare const DEFAULT_RUNTIME_STATE: ProxyRuntimeState;
70
+ /**
71
+ * Manages proxy runtime state with file-based persistence.
72
+ *
73
+ * Used by the proxy process to track state and by CLI commands to read it.
74
+ */
75
+ export declare class RuntimeStateManager {
76
+ private readonly statePath;
77
+ private state;
78
+ private heartbeatTimer;
79
+ constructor(configDir: string);
80
+ /**
81
+ * Initialize state when proxy starts
82
+ */
83
+ initialize(connectors: ConnectorSummary[], logLevel: 'INFO' | 'WARN' | 'ERROR'): Promise<void>;
84
+ /**
85
+ * Start heartbeat updates
86
+ */
87
+ startHeartbeat(): void;
88
+ /**
89
+ * Stop heartbeat on shutdown
90
+ */
91
+ stopHeartbeat(): void;
92
+ /**
93
+ * Update client state (called on each RPC)
94
+ */
95
+ updateClient(clientName: string, update: Partial<ClientInfo>): Promise<void>;
96
+ /**
97
+ * Record tool call
98
+ */
99
+ recordToolCall(clientName: string): Promise<void>;
100
+ /**
101
+ * Mark proxy as stopped
102
+ */
103
+ markStopped(): Promise<void>;
104
+ /**
105
+ * Update log buffer count
106
+ */
107
+ updateLogCount(count: number): Promise<void>;
108
+ /**
109
+ * Get current state (for internal use)
110
+ */
111
+ getState(): ProxyRuntimeState;
112
+ /**
113
+ * Persist state to file (atomic write using rename)
114
+ */
115
+ private persist;
116
+ /**
117
+ * Read current state (for CLI)
118
+ *
119
+ * Static method that can be called without a proxy running.
120
+ */
121
+ static read(configDir: string): Promise<ProxyRuntimeState | null>;
122
+ /**
123
+ * Check if proxy is likely still running (heartbeat within threshold + PID check)
124
+ */
125
+ static isProxyAlive(state: ProxyRuntimeState): boolean;
126
+ /**
127
+ * Determine effective client state based on lastSeen timestamp
128
+ */
129
+ static determineClientState(client: ClientInfo, idleThresholdMs?: number): ClientState;
130
+ }
131
+ //# sourceMappingURL=runtime-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-state.d.ts","sourceRoot":"","sources":["../../src/proxy/runtime-state.ts"],"names":[],"mappings":"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"}