@juspay/neurolink 4.0.0 → 4.1.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 (56) hide show
  1. package/CHANGELOG.md +20 -5
  2. package/README.md +59 -1
  3. package/dist/lib/mcp/dynamic-chain-executor.d.ts +201 -0
  4. package/dist/lib/mcp/dynamic-chain-executor.js +489 -0
  5. package/dist/lib/mcp/dynamic-orchestrator.d.ts +109 -0
  6. package/dist/lib/mcp/dynamic-orchestrator.js +351 -0
  7. package/dist/lib/mcp/error-manager.d.ts +254 -0
  8. package/dist/lib/mcp/error-manager.js +501 -0
  9. package/dist/lib/mcp/error-recovery.d.ts +158 -0
  10. package/dist/lib/mcp/error-recovery.js +405 -0
  11. package/dist/lib/mcp/health-monitor.d.ts +256 -0
  12. package/dist/lib/mcp/health-monitor.js +621 -0
  13. package/dist/lib/mcp/orchestrator.d.ts +136 -5
  14. package/dist/lib/mcp/orchestrator.js +316 -9
  15. package/dist/lib/mcp/registry.d.ts +22 -0
  16. package/dist/lib/mcp/registry.js +24 -0
  17. package/dist/lib/mcp/semaphore-manager.d.ts +137 -0
  18. package/dist/lib/mcp/semaphore-manager.js +329 -0
  19. package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
  20. package/dist/lib/mcp/session-manager.d.ts +186 -0
  21. package/dist/lib/mcp/session-manager.js +400 -0
  22. package/dist/lib/mcp/session-persistence.d.ts +93 -0
  23. package/dist/lib/mcp/session-persistence.js +298 -0
  24. package/dist/lib/mcp/transport-manager.d.ts +153 -0
  25. package/dist/lib/mcp/transport-manager.js +330 -0
  26. package/dist/lib/mcp/unified-registry.d.ts +42 -1
  27. package/dist/lib/mcp/unified-registry.js +122 -2
  28. package/dist/lib/neurolink.d.ts +75 -0
  29. package/dist/lib/neurolink.js +104 -0
  30. package/dist/mcp/dynamic-chain-executor.d.ts +201 -0
  31. package/dist/mcp/dynamic-chain-executor.js +489 -0
  32. package/dist/mcp/dynamic-orchestrator.d.ts +109 -0
  33. package/dist/mcp/dynamic-orchestrator.js +351 -0
  34. package/dist/mcp/error-manager.d.ts +254 -0
  35. package/dist/mcp/error-manager.js +501 -0
  36. package/dist/mcp/error-recovery.d.ts +158 -0
  37. package/dist/mcp/error-recovery.js +405 -0
  38. package/dist/mcp/health-monitor.d.ts +256 -0
  39. package/dist/mcp/health-monitor.js +621 -0
  40. package/dist/mcp/orchestrator.d.ts +136 -5
  41. package/dist/mcp/orchestrator.js +316 -9
  42. package/dist/mcp/registry.d.ts +22 -0
  43. package/dist/mcp/registry.js +24 -0
  44. package/dist/mcp/semaphore-manager.d.ts +137 -0
  45. package/dist/mcp/semaphore-manager.js +329 -0
  46. package/dist/mcp/session-manager.d.ts +186 -0
  47. package/dist/mcp/session-manager.js +400 -0
  48. package/dist/mcp/session-persistence.d.ts +93 -0
  49. package/dist/mcp/session-persistence.js +299 -0
  50. package/dist/mcp/transport-manager.d.ts +153 -0
  51. package/dist/mcp/transport-manager.js +331 -0
  52. package/dist/mcp/unified-registry.d.ts +42 -1
  53. package/dist/mcp/unified-registry.js +122 -2
  54. package/dist/neurolink.d.ts +75 -0
  55. package/dist/neurolink.js +104 -0
  56. package/package.json +2 -1
@@ -0,0 +1,400 @@
1
+ /**
2
+ * NeuroLink MCP Session Management System
3
+ * Enables continuous tool calling with persistent state across executions
4
+ * Based on patterns from Cline's session management implementation
5
+ */
6
+ import { v4 as uuidv4 } from "uuid";
7
+ import { SessionPersistence, initializeSessionPersistence, } from "./session-persistence.js";
8
+ /**
9
+ * Session Manager for maintaining state across tool executions
10
+ * Implements session lifecycle management with automatic cleanup
11
+ */
12
+ export class SessionManager {
13
+ sessions = new Map();
14
+ sessionCounter = 0;
15
+ stats = {
16
+ activeSessions: 0,
17
+ totalSessionsCreated: 0,
18
+ totalSessionsExpired: 0,
19
+ averageSessionDuration: 0,
20
+ averageToolsPerSession: 0,
21
+ peakConcurrentSessions: 0,
22
+ lastCleanup: Date.now(),
23
+ };
24
+ cleanupInterval = null;
25
+ defaultTTL = 3600000; // 1 hour default
26
+ cleanupIntervalMs = 300000; // 5 minutes
27
+ persistence = null;
28
+ persistenceEnabled = false;
29
+ constructor(defaultTTL, cleanupIntervalMs, autoCleanup = true, enablePersistence = true) {
30
+ if (defaultTTL) {
31
+ this.defaultTTL = defaultTTL;
32
+ }
33
+ if (cleanupIntervalMs) {
34
+ this.cleanupIntervalMs = cleanupIntervalMs;
35
+ }
36
+ if (autoCleanup) {
37
+ this.startAutoCleanup();
38
+ }
39
+ this.persistenceEnabled = enablePersistence;
40
+ }
41
+ /**
42
+ * Initialize session manager with persistence
43
+ */
44
+ async initialize(persistenceOptions) {
45
+ if (this.persistenceEnabled && !this.persistence) {
46
+ this.persistence = await initializeSessionPersistence(this.sessions, persistenceOptions);
47
+ if (process.env.NEUROLINK_DEBUG === "true") {
48
+ console.log("[SessionManager] Persistence layer initialized");
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * Create a new session
54
+ *
55
+ * @param context Execution context for the session
56
+ * @param options Session configuration options
57
+ * @returns Created session
58
+ */
59
+ createSession(context, options = {}) {
60
+ const sessionId = options.metadata?.tags?.includes("custom-id") && context.sessionId
61
+ ? context.sessionId
62
+ : this.generateSessionId();
63
+ const now = Date.now();
64
+ const ttl = options.ttl || this.defaultTTL;
65
+ const session = {
66
+ id: sessionId,
67
+ context: {
68
+ ...context,
69
+ sessionId, // Ensure context has the session ID
70
+ },
71
+ toolHistory: [],
72
+ state: new Map(),
73
+ metadata: options.metadata || {},
74
+ createdAt: now,
75
+ lastActivity: now,
76
+ expiresAt: now + ttl,
77
+ };
78
+ this.sessions.set(sessionId, session);
79
+ this.updateStats("create");
80
+ // Save to disk if persistence is enabled
81
+ if (this.persistence) {
82
+ this.persistence.saveSession(sessionId, session).catch(console.error);
83
+ }
84
+ if (process.env.NEUROLINK_DEBUG === "true") {
85
+ console.log(`[SessionManager] Created session ${sessionId} with TTL ${ttl}ms`);
86
+ }
87
+ return session;
88
+ }
89
+ /**
90
+ * Get an existing session
91
+ *
92
+ * @param sessionId Session identifier
93
+ * @param extend Whether to extend the session's expiration
94
+ * @returns Session if found and not expired
95
+ */
96
+ getSession(sessionId, extend = true) {
97
+ let session = this.sessions.get(sessionId) || null;
98
+ // For sync compatibility, skip disk loading in getSession
99
+ // Use async getSessionAsync() for full persistence features
100
+ if (!session) {
101
+ return null;
102
+ }
103
+ // Check if expired
104
+ if (session.expiresAt < Date.now()) {
105
+ this.removeSession(sessionId);
106
+ return null;
107
+ }
108
+ // Update activity and optionally extend expiration
109
+ session.lastActivity = Date.now();
110
+ if (extend) {
111
+ const ttl = session.expiresAt - session.createdAt;
112
+ session.expiresAt = Date.now() + ttl;
113
+ // Save updated expiration to disk
114
+ if (this.persistence) {
115
+ this.persistence.saveSession(sessionId, session).catch(console.error);
116
+ }
117
+ }
118
+ return session;
119
+ }
120
+ /**
121
+ * Update session with new tool result
122
+ *
123
+ * @param sessionId Session identifier
124
+ * @param toolResult Result from tool execution
125
+ * @returns Updated session or null if not found
126
+ */
127
+ updateSession(sessionId, toolResult) {
128
+ const session = this.getSession(sessionId);
129
+ if (!session) {
130
+ return null;
131
+ }
132
+ // Add to tool history
133
+ session.toolHistory.push(toolResult);
134
+ session.lastActivity = Date.now();
135
+ // Update stats
136
+ this.updateStats("update", session);
137
+ // Save to disk if persistence is enabled
138
+ if (this.persistence) {
139
+ this.persistence.saveSession(sessionId, session).catch(console.error);
140
+ }
141
+ if (process.env.NEUROLINK_DEBUG === "true") {
142
+ console.log(`[SessionManager] Updated session ${sessionId} with tool result`);
143
+ }
144
+ return session;
145
+ }
146
+ /**
147
+ * Set session state value
148
+ *
149
+ * @param sessionId Session identifier
150
+ * @param key State key
151
+ * @param value State value
152
+ * @returns Updated session or null if not found
153
+ */
154
+ setSessionState(sessionId, key, value) {
155
+ const session = this.getSession(sessionId);
156
+ if (!session) {
157
+ return null;
158
+ }
159
+ session.state.set(key, value);
160
+ session.lastActivity = Date.now();
161
+ // Save to disk if persistence is enabled
162
+ if (this.persistence) {
163
+ this.persistence.saveSession(sessionId, session).catch(console.error);
164
+ }
165
+ return session;
166
+ }
167
+ /**
168
+ * Get session state value
169
+ *
170
+ * @param sessionId Session identifier
171
+ * @param key State key
172
+ * @returns State value or undefined
173
+ */
174
+ getSessionState(sessionId, key) {
175
+ const session = this.getSession(sessionId, false);
176
+ return session?.state.get(key);
177
+ }
178
+ /**
179
+ * Remove a session
180
+ *
181
+ * @param sessionId Session identifier
182
+ * @returns True if session was removed
183
+ */
184
+ removeSession(sessionId) {
185
+ const session = this.sessions.get(sessionId);
186
+ if (!session) {
187
+ return false;
188
+ }
189
+ this.sessions.delete(sessionId);
190
+ this.updateStats("remove", session);
191
+ // Delete from disk if persistence is enabled (fire-and-forget)
192
+ if (this.persistence) {
193
+ this.persistence.deleteSession(sessionId).catch(console.error);
194
+ }
195
+ if (process.env.NEUROLINK_DEBUG === "true") {
196
+ console.log(`[SessionManager] Removed session ${sessionId}`);
197
+ }
198
+ return true;
199
+ }
200
+ /**
201
+ * Clean up expired sessions
202
+ *
203
+ * @returns Number of sessions cleaned up
204
+ */
205
+ async cleanup() {
206
+ const now = Date.now();
207
+ let cleaned = 0;
208
+ for (const [sessionId, session] of this.sessions) {
209
+ if (session.expiresAt < now) {
210
+ this.removeSession(sessionId);
211
+ cleaned++;
212
+ }
213
+ }
214
+ this.stats.lastCleanup = now;
215
+ if (cleaned > 0 && process.env.NEUROLINK_DEBUG === "true") {
216
+ console.log(`[SessionManager] Cleaned up ${cleaned} expired sessions`);
217
+ }
218
+ return cleaned;
219
+ }
220
+ /**
221
+ * Get an existing session with async persistence loading
222
+ *
223
+ * @param sessionId Session identifier
224
+ * @param extend Whether to extend the session's expiration
225
+ * @returns Session if found and not expired, or null
226
+ */
227
+ async getSessionAsync(sessionId, extend = true) {
228
+ let session = this.sessions.get(sessionId) || null;
229
+ // If not in memory and persistence is enabled, try loading from disk
230
+ if (!session && this.persistence) {
231
+ try {
232
+ session = await this.persistence.loadSession(sessionId);
233
+ if (session) {
234
+ // Add to memory cache
235
+ this.sessions.set(sessionId, session);
236
+ if (process.env.NEUROLINK_DEBUG === "true") {
237
+ console.log(`[SessionManager] Loaded session ${sessionId} from persistence`);
238
+ }
239
+ }
240
+ }
241
+ catch (error) {
242
+ if (process.env.NEUROLINK_DEBUG === "true") {
243
+ console.log(`[SessionManager] Failed to load session ${sessionId} from persistence:`, error);
244
+ }
245
+ }
246
+ }
247
+ if (!session) {
248
+ return null;
249
+ }
250
+ // Check if session has expired
251
+ if (session.expiresAt < Date.now()) {
252
+ this.sessions.delete(sessionId);
253
+ if (this.persistence) {
254
+ this.persistence.deleteSession(sessionId).catch(console.error);
255
+ }
256
+ return null;
257
+ }
258
+ // Extend session if requested
259
+ if (extend && session.expiresAt > Date.now()) {
260
+ // Calculate remaining TTL and extend by the same amount
261
+ const remainingTtl = session.expiresAt - Date.now();
262
+ const originalTtl = session.expiresAt - session.createdAt;
263
+ if (originalTtl > 0) {
264
+ session.expiresAt = Date.now() + originalTtl;
265
+ if (this.persistence) {
266
+ this.persistence.saveSession(sessionId, session).catch(console.error);
267
+ }
268
+ }
269
+ }
270
+ session.lastActivity = Date.now();
271
+ return session;
272
+ }
273
+ /**
274
+ * Get all active sessions
275
+ *
276
+ * @returns Array of active sessions
277
+ */
278
+ async getActiveSessions() {
279
+ await this.cleanup(); // Clean up first
280
+ return Array.from(this.sessions.values());
281
+ }
282
+ /**
283
+ * Get session statistics
284
+ *
285
+ * @returns Session statistics
286
+ */
287
+ getStats() {
288
+ return { ...this.stats };
289
+ }
290
+ /**
291
+ * Clear all sessions
292
+ */
293
+ clearAll() {
294
+ const count = this.sessions.size;
295
+ this.sessions.clear();
296
+ this.stats.totalSessionsExpired += count;
297
+ this.stats.activeSessions = 0;
298
+ if (process.env.NEUROLINK_DEBUG === "true") {
299
+ console.log(`[SessionManager] Cleared all ${count} sessions`);
300
+ }
301
+ }
302
+ /**
303
+ * Start automatic cleanup interval
304
+ *
305
+ * @private
306
+ */
307
+ startAutoCleanup() {
308
+ if (this.cleanupInterval) {
309
+ return;
310
+ }
311
+ this.cleanupInterval = setInterval(async () => {
312
+ await this.cleanup();
313
+ }, this.cleanupIntervalMs);
314
+ if (process.env.NEUROLINK_DEBUG === "true") {
315
+ console.log(`[SessionManager] Started auto-cleanup with ${this.cleanupIntervalMs}ms interval`);
316
+ }
317
+ }
318
+ /**
319
+ * Stop automatic cleanup interval
320
+ */
321
+ stopAutoCleanup() {
322
+ if (this.cleanupInterval) {
323
+ clearInterval(this.cleanupInterval);
324
+ this.cleanupInterval = null;
325
+ if (process.env.NEUROLINK_DEBUG === "true") {
326
+ console.log("[SessionManager] Stopped auto-cleanup");
327
+ }
328
+ }
329
+ }
330
+ /**
331
+ * Generate unique session ID
332
+ *
333
+ * @private
334
+ */
335
+ generateSessionId() {
336
+ this.sessionCounter++;
337
+ return `nlsess-${Date.now()}-${this.sessionCounter}-${uuidv4().substring(0, 8)}`;
338
+ }
339
+ /**
340
+ * Update statistics
341
+ *
342
+ * @private
343
+ */
344
+ updateStats(action, session) {
345
+ switch (action) {
346
+ case "create":
347
+ this.stats.totalSessionsCreated++;
348
+ this.stats.activeSessions = this.sessions.size;
349
+ if (this.sessions.size > this.stats.peakConcurrentSessions) {
350
+ this.stats.peakConcurrentSessions = this.sessions.size;
351
+ }
352
+ break;
353
+ case "update":
354
+ if (session) {
355
+ // Update average tools per session
356
+ const totalTools = Array.from(this.sessions.values()).reduce((sum, s) => sum + s.toolHistory.length, 0);
357
+ this.stats.averageToolsPerSession =
358
+ this.sessions.size > 0 ? totalTools / this.sessions.size : 0;
359
+ }
360
+ break;
361
+ case "remove":
362
+ this.stats.totalSessionsExpired++;
363
+ this.stats.activeSessions = this.sessions.size;
364
+ if (session) {
365
+ // Update average session duration
366
+ const duration = session.lastActivity - session.createdAt;
367
+ const totalDuration = this.stats.averageSessionDuration *
368
+ (this.stats.totalSessionsExpired - 1) +
369
+ duration;
370
+ this.stats.averageSessionDuration =
371
+ totalDuration / this.stats.totalSessionsExpired;
372
+ }
373
+ break;
374
+ }
375
+ }
376
+ }
377
+ /**
378
+ * Default session manager instance
379
+ */
380
+ export const defaultSessionManager = new SessionManager();
381
+ /**
382
+ * Utility function to create session with default manager
383
+ *
384
+ * @param context Execution context
385
+ * @param options Session options
386
+ * @returns Created session
387
+ */
388
+ export async function createSession(context, options) {
389
+ return defaultSessionManager.createSession(context, options);
390
+ }
391
+ /**
392
+ * Utility function to get session with default manager
393
+ *
394
+ * @param sessionId Session identifier
395
+ * @param extend Whether to extend expiration
396
+ * @returns Session or null
397
+ */
398
+ export async function getSession(sessionId, extend) {
399
+ return defaultSessionManager.getSession(sessionId, extend);
400
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * NeuroLink Session Persistence Layer
3
+ * Provides file-based persistence for sessions with atomic writes and recovery
4
+ */
5
+ import type { OrchestratorSession } from "./session-manager.js";
6
+ /**
7
+ * Persistence options
8
+ */
9
+ export interface PersistenceOptions {
10
+ directory?: string;
11
+ snapshotInterval?: number;
12
+ retentionPeriod?: number;
13
+ enableChecksum?: boolean;
14
+ maxRetries?: number;
15
+ }
16
+ /**
17
+ * Session Persistence Manager
18
+ * Handles saving and loading sessions to/from disk with recovery mechanisms
19
+ */
20
+ export declare class SessionPersistence {
21
+ private directory;
22
+ private snapshotInterval;
23
+ private retentionPeriod;
24
+ private enableChecksum;
25
+ private maxRetries;
26
+ private snapshotTimer;
27
+ private sessionMap;
28
+ constructor(sessionMap: Map<string, OrchestratorSession>, options?: PersistenceOptions);
29
+ /**
30
+ * Initialize persistence layer
31
+ */
32
+ initialize(): Promise<void>;
33
+ /**
34
+ * Ensure sessions directory exists
35
+ */
36
+ private ensureDirectory;
37
+ /**
38
+ * Calculate checksum for data integrity
39
+ */
40
+ private calculateChecksum;
41
+ /**
42
+ * Serialize session to JSON with metadata
43
+ */
44
+ private serializeSession;
45
+ /**
46
+ * Deserialize session from JSON
47
+ */
48
+ private deserializeSession;
49
+ /**
50
+ * Save single session with atomic write
51
+ */
52
+ saveSession(sessionId: string, session: OrchestratorSession): Promise<boolean>;
53
+ /**
54
+ * Load single session from disk
55
+ */
56
+ loadSession(sessionId: string): Promise<OrchestratorSession | null>;
57
+ /**
58
+ * Load all sessions from disk on startup
59
+ */
60
+ loadSessions(): Promise<void>;
61
+ /**
62
+ * Save all active sessions (snapshot)
63
+ */
64
+ saveAllSessions(): Promise<void>;
65
+ /**
66
+ * Delete session file
67
+ */
68
+ deleteSession(sessionId: string): Promise<void>;
69
+ /**
70
+ * Clean up old session files
71
+ */
72
+ cleanupOldSessions(): Promise<void>;
73
+ /**
74
+ * Start periodic snapshot timer
75
+ */
76
+ private startSnapshotTimer;
77
+ /**
78
+ * Stop snapshot timer
79
+ */
80
+ stopSnapshotTimer(): void;
81
+ /**
82
+ * Shutdown persistence layer
83
+ */
84
+ shutdown(): Promise<void>;
85
+ }
86
+ /**
87
+ * Default session persistence instance
88
+ */
89
+ export declare let defaultSessionPersistence: SessionPersistence | null;
90
+ /**
91
+ * Initialize default session persistence
92
+ */
93
+ export declare function initializeSessionPersistence(sessionMap: Map<string, OrchestratorSession>, options?: PersistenceOptions): Promise<SessionPersistence>;