@juspay/neurolink 13.8.4 → 13.8.6
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.
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { EventEmitter } from "events";
|
|
10
10
|
import { mcpLogger } from "../utils/logger.js";
|
|
11
|
-
import { MCPClientFactory,
|
|
11
|
+
import { MCPClientFactory, terminateLiveStdioServers, } from "./mcpClientFactory.js";
|
|
12
12
|
import { ToolDiscoveryService } from "./toolDiscoveryService.js";
|
|
13
13
|
import { toolRegistry } from "./toolRegistry.js";
|
|
14
14
|
import { HITLUserRejectedError, HITLTimeoutError } from "../hitl/hitlErrors.js";
|
|
@@ -372,9 +372,9 @@ const shutdownOnSignal = (signal) => {
|
|
|
372
372
|
// re-raise and nowhere else.
|
|
373
373
|
if (!hadOtherListeners) {
|
|
374
374
|
process.removeListener(signal, shutdownOnSignal);
|
|
375
|
-
// Dying of a signal runs no `exit` handler, and the cleanup above
|
|
376
|
-
//
|
|
377
|
-
|
|
375
|
+
// Dying of a signal runs no `exit` handler, and the cleanup above reaches
|
|
376
|
+
// only the servers a manager has recorded and that close when asked.
|
|
377
|
+
terminateLiveStdioServers();
|
|
378
378
|
process.kill(process.pid, signal);
|
|
379
379
|
}
|
|
380
380
|
});
|
|
@@ -14,7 +14,7 @@ import type { MCPTransportType, MCPServerInfo, MCPClientResult } from "../types/
|
|
|
14
14
|
* `exit` event, and SIGTERM is delivered by the kernel even though this
|
|
15
15
|
* process is already on its way out.
|
|
16
16
|
*/
|
|
17
|
-
export declare const
|
|
17
|
+
export declare const terminateLiveStdioServers: () => void;
|
|
18
18
|
/**
|
|
19
19
|
* MCPClientFactory
|
|
20
20
|
* Factory class for creating MCP clients with different transports
|
|
@@ -63,25 +63,29 @@ class StderrTail {
|
|
|
63
63
|
}
|
|
64
64
|
const stderrTails = new WeakMap();
|
|
65
65
|
/**
|
|
66
|
-
* Stdio servers
|
|
66
|
+
* Stdio servers this process has spawned and has not yet seen close.
|
|
67
67
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
68
|
+
* A transport is tracked from creation to close, not only until the server
|
|
69
|
+
* answers `initialize`, because two things leave a server running with nothing
|
|
70
|
+
* to stop it. Until the manager records the client, which happens only after
|
|
71
|
+
* `connect()` and the handshake, no shutdown path knows the server exists, and
|
|
72
|
+
* `npx -y <pkg>` does not read its stdin until the package has downloaded.
|
|
73
|
+
* After that, a server holding a timer, a connection pool or a file watcher
|
|
74
|
+
* ignores its stdin closing, and `process.exit()` runs neither `beforeExit`
|
|
75
|
+
* nor the manager's async shutdown.
|
|
76
|
+
*
|
|
77
|
+
* `transport.close()` takes a transport out through `onclose` once the child
|
|
78
|
+
* has exited, so a server the manager closed is not signalled again.
|
|
75
79
|
*/
|
|
76
|
-
const
|
|
77
|
-
let
|
|
80
|
+
const liveStdioTransports = new Set();
|
|
81
|
+
let stdioExitHookInstalled = false;
|
|
78
82
|
/**
|
|
79
83
|
* Synchronous on purpose: it is the one thing that can run inside the
|
|
80
84
|
* `exit` event, and SIGTERM is delivered by the kernel even though this
|
|
81
85
|
* process is already on its way out.
|
|
82
86
|
*/
|
|
83
|
-
export const
|
|
84
|
-
for (const transport of
|
|
87
|
+
export const terminateLiveStdioServers = () => {
|
|
88
|
+
for (const transport of liveStdioTransports) {
|
|
85
89
|
if ("pid" in transport && typeof transport.pid === "number") {
|
|
86
90
|
try {
|
|
87
91
|
process.kill(transport.pid, "SIGTERM");
|
|
@@ -92,16 +96,18 @@ export const terminateStartingStdioServers = () => {
|
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
};
|
|
95
|
-
const
|
|
96
|
-
if (!
|
|
97
|
-
|
|
98
|
-
process.on("exit",
|
|
99
|
+
const trackStdioTransport = (transport) => {
|
|
100
|
+
if (!stdioExitHookInstalled) {
|
|
101
|
+
stdioExitHookInstalled = true;
|
|
102
|
+
process.on("exit", terminateLiveStdioServers);
|
|
99
103
|
}
|
|
100
|
-
|
|
104
|
+
liveStdioTransports.add(transport);
|
|
101
105
|
// Client.connect() chains an onclose that is already set rather than
|
|
102
|
-
// replacing it, and
|
|
106
|
+
// replacing it, and the manager listens on client.onclose, so this one
|
|
107
|
+
// survives for the life of the connection. A spawn that fails still closes
|
|
108
|
+
// the transport.
|
|
103
109
|
transport.onclose = () => {
|
|
104
|
-
|
|
110
|
+
liveStdioTransports.delete(transport);
|
|
105
111
|
};
|
|
106
112
|
};
|
|
107
113
|
/**
|
|
@@ -265,7 +271,6 @@ export class MCPClientFactory {
|
|
|
265
271
|
}
|
|
266
272
|
// Connect with timeout
|
|
267
273
|
await this.raceWithTimeout(client.connect(transport, { timeout }), timeout, `Client connection timeout for ${config.id}`);
|
|
268
|
-
startingStdioTransports.delete(transport);
|
|
269
274
|
// Perform handshake to get server capabilities
|
|
270
275
|
const serverCapabilities = await this.performHandshake(client, timeout);
|
|
271
276
|
mcpLogger.debug(`[MCPClientFactory] Handshake completed for ${config.id}`, {
|
|
@@ -361,7 +366,7 @@ export class MCPClientFactory {
|
|
|
361
366
|
cwd: config.cwd,
|
|
362
367
|
stderr: "pipe",
|
|
363
368
|
});
|
|
364
|
-
|
|
369
|
+
trackStdioTransport(transport);
|
|
365
370
|
const tail = new StderrTail();
|
|
366
371
|
stderrTails.set(transport, tail);
|
|
367
372
|
transport.stderr?.on("data", (chunk) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "13.8.
|
|
3
|
+
"version": "13.8.6",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002/call) for routing, tool selection and context budgeting. MCP-native (4 transports), voice TTS/STT/realtime, RAG, agents, memory, compaction, 9 observability exporters. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · TypeSafe Jev and more.",
|
|
6
6
|
"author": {
|