@yu_robotics/remote-cli-router 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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -0
  3. package/bin/remote-cli-router.js +2 -0
  4. package/dist/binding/BindingManager.d.ts +62 -0
  5. package/dist/binding/BindingManager.d.ts.map +1 -0
  6. package/dist/binding/BindingManager.js +119 -0
  7. package/dist/binding/BindingManager.js.map +1 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +32 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands/config.d.ts +19 -0
  13. package/dist/commands/config.d.ts.map +1 -0
  14. package/dist/commands/config.js +206 -0
  15. package/dist/commands/config.js.map +1 -0
  16. package/dist/commands/start.d.ts +5 -0
  17. package/dist/commands/start.d.ts.map +1 -0
  18. package/dist/commands/start.js +65 -0
  19. package/dist/commands/start.js.map +1 -0
  20. package/dist/commands/status.d.ts +5 -0
  21. package/dist/commands/status.d.ts.map +1 -0
  22. package/dist/commands/status.js +103 -0
  23. package/dist/commands/status.js.map +1 -0
  24. package/dist/commands/stop.d.ts +5 -0
  25. package/dist/commands/stop.d.ts.map +1 -0
  26. package/dist/commands/stop.js +56 -0
  27. package/dist/commands/stop.js.map +1 -0
  28. package/dist/config/ConfigManager.d.ts +46 -0
  29. package/dist/config/ConfigManager.d.ts.map +1 -0
  30. package/dist/config/ConfigManager.js +101 -0
  31. package/dist/config/ConfigManager.js.map +1 -0
  32. package/dist/feishu/FeishuClient.d.ts +46 -0
  33. package/dist/feishu/FeishuClient.d.ts.map +1 -0
  34. package/dist/feishu/FeishuClient.js +130 -0
  35. package/dist/feishu/FeishuClient.js.map +1 -0
  36. package/dist/feishu/FeishuLongConnHandler.d.ts +149 -0
  37. package/dist/feishu/FeishuLongConnHandler.d.ts.map +1 -0
  38. package/dist/feishu/FeishuLongConnHandler.js +632 -0
  39. package/dist/feishu/FeishuLongConnHandler.js.map +1 -0
  40. package/dist/server.d.ts +80 -0
  41. package/dist/server.d.ts.map +1 -0
  42. package/dist/server.js +533 -0
  43. package/dist/server.js.map +1 -0
  44. package/dist/storage/JsonStore.d.ts +90 -0
  45. package/dist/storage/JsonStore.d.ts.map +1 -0
  46. package/dist/storage/JsonStore.js +215 -0
  47. package/dist/storage/JsonStore.js.map +1 -0
  48. package/dist/storage/MemoryStore.d.ts +69 -0
  49. package/dist/storage/MemoryStore.d.ts.map +1 -0
  50. package/dist/storage/MemoryStore.js +117 -0
  51. package/dist/storage/MemoryStore.js.map +1 -0
  52. package/dist/types/config.d.ts +53 -0
  53. package/dist/types/config.d.ts.map +1 -0
  54. package/dist/types/config.js +31 -0
  55. package/dist/types/config.js.map +1 -0
  56. package/dist/types/index.d.ts +93 -0
  57. package/dist/types/index.d.ts.map +1 -0
  58. package/dist/types/index.js +18 -0
  59. package/dist/types/index.js.map +1 -0
  60. package/dist/utils/PidManager.d.ts +28 -0
  61. package/dist/utils/PidManager.d.ts.map +1 -0
  62. package/dist/utils/PidManager.js +90 -0
  63. package/dist/utils/PidManager.js.map +1 -0
  64. package/dist/utils/ToolFormatter.d.ts +41 -0
  65. package/dist/utils/ToolFormatter.d.ts.map +1 -0
  66. package/dist/utils/ToolFormatter.js +273 -0
  67. package/dist/utils/ToolFormatter.js.map +1 -0
  68. package/dist/websocket/ConnectionHub.d.ts +73 -0
  69. package/dist/websocket/ConnectionHub.d.ts.map +1 -0
  70. package/dist/websocket/ConnectionHub.js +177 -0
  71. package/dist/websocket/ConnectionHub.js.map +1 -0
  72. package/package.json +70 -0
@@ -0,0 +1,80 @@
1
+ import { ConfigManager } from './config/ConfigManager';
2
+ import { JsonStore } from './storage/JsonStore';
3
+ /**
4
+ * Router Server
5
+ * Handles Feishu WebSocket long connection, local WebSocket connections, and message routing
6
+ */
7
+ export declare class RouterServer {
8
+ private app;
9
+ private httpServer;
10
+ private wss;
11
+ private config;
12
+ private store;
13
+ private feishuLongConnHandler;
14
+ private connectionHub;
15
+ private bindingManager;
16
+ private cleanupInterval;
17
+ private streamingMessages;
18
+ private readonly STREAMING_SESSION_TIMEOUT_MS;
19
+ constructor(config: ConfigManager, store: JsonStore);
20
+ /**
21
+ * Setup Koa middleware
22
+ */
23
+ private setupMiddleware;
24
+ /**
25
+ * Setup HTTP routes
26
+ */
27
+ private setupRoutes;
28
+ /**
29
+ * Setup WebSocket server
30
+ */
31
+ private setupWebSocket;
32
+ /**
33
+ * Start the server
34
+ */
35
+ start(): Promise<void>;
36
+ private lastStreamUpdateTime;
37
+ private readonly STREAM_UPDATE_INTERVAL_MS;
38
+ private readonly STREAM_UPDATE_MIN_LENGTH;
39
+ /**
40
+ * Handle streaming chunk from device
41
+ */
42
+ /**
43
+ * Handle text streaming chunk
44
+ */
45
+ private handleTextChunk;
46
+ /**
47
+ * Handle tool use event
48
+ */
49
+ private handleToolUse;
50
+ /**
51
+ * Handle tool result event
52
+ */
53
+ private handleToolResult;
54
+ /**
55
+ * Finalize streaming message
56
+ */
57
+ private finalizeStreamingMessage;
58
+ /**
59
+ * Cleanup stale streaming sessions that have timed out
60
+ * This prevents memory leaks when devices disconnect without sending a response
61
+ */
62
+ private cleanupStaleStreamingSessions;
63
+ /**
64
+ * Cleanup streaming sessions for a specific device when it disconnects
65
+ * @param deviceId Device ID that disconnected
66
+ */
67
+ private cleanupStreamingSessionsForDevice;
68
+ /**
69
+ * Stop the server
70
+ */
71
+ stop(): Promise<void>;
72
+ /**
73
+ * Get connection statistics
74
+ */
75
+ getStats(): {
76
+ totalConnections: number;
77
+ deviceIds: string[];
78
+ };
79
+ }
80
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAOhD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,qBAAqB,CAAwB;IACrD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,eAAe,CAA+B;IAEtD,OAAO,CAAC,iBAAiB,CAQV;IACf,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAkB;gBAEnD,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS;IAsCnD;;OAEG;IACH,OAAO,CAAC,eAAe;IA0BvB;;OAEG;IACH,OAAO,CAAC,WAAW;IA2DnB;;OAEG;IACH,OAAO,CAAC,cAAc;IA8KtB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmC5B,OAAO,CAAC,oBAAoB,CAAkC;IAC9D,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAO;IACjD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAM;IAE/C;;OAEG;IACH;;OAEG;YACW,eAAe;IAiD7B;;OAEG;YACW,aAAa;IA+B3B;;OAEG;YACW,gBAAgB;IA+B9B;;OAEG;YACW,wBAAwB;IA2CtC;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IAkBrC;;;OAGG;IACH,OAAO,CAAC,iCAAiC;IAiBzC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuC3B;;OAEG;IACH,QAAQ;;;;CAGT"}
package/dist/server.js ADDED
@@ -0,0 +1,533 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RouterServer = void 0;
7
+ const koa_1 = __importDefault(require("koa"));
8
+ const koa_bodyparser_1 = __importDefault(require("koa-bodyparser"));
9
+ const router_1 = __importDefault(require("@koa/router"));
10
+ const ws_1 = require("ws");
11
+ const FeishuLongConnHandler_1 = require("./feishu/FeishuLongConnHandler");
12
+ const ConnectionHub_1 = require("./websocket/ConnectionHub");
13
+ const BindingManager_1 = require("./binding/BindingManager");
14
+ const types_1 = require("./types");
15
+ const ToolFormatter_1 = require("./utils/ToolFormatter");
16
+ /**
17
+ * Router Server
18
+ * Handles Feishu WebSocket long connection, local WebSocket connections, and message routing
19
+ */
20
+ class RouterServer {
21
+ app;
22
+ httpServer = null;
23
+ wss = null;
24
+ config;
25
+ store;
26
+ feishuLongConnHandler;
27
+ connectionHub;
28
+ bindingManager;
29
+ cleanupInterval = null;
30
+ // Track streaming messages: messageId -> { openId, feishuMessageId, elements, currentTextContent, hasUpdated, createdAt, deviceId }
31
+ streamingMessages = new Map();
32
+ STREAMING_SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes timeout
33
+ constructor(config, store) {
34
+ this.config = config;
35
+ this.store = store;
36
+ this.app = new koa_1.default();
37
+ this.connectionHub = new ConnectionHub_1.ConnectionHub();
38
+ this.bindingManager = new BindingManager_1.BindingManager(store);
39
+ // Initialize FeishuLongConnHandler (WebSocket mode)
40
+ this.feishuLongConnHandler = new FeishuLongConnHandler_1.FeishuLongConnHandler({
41
+ appId: config.get('feishu', 'appId'),
42
+ appSecret: config.get('feishu', 'appSecret'),
43
+ store: this.store
44
+ });
45
+ // Share ConnectionHub with Feishu handler
46
+ this.feishuLongConnHandler.setConnectionHub(this.connectionHub);
47
+ // Register callback for streaming message start
48
+ this.feishuLongConnHandler.setOnStartStreaming((messageId, openId, feishuMessageId, deviceId) => {
49
+ console.log(`[RouterServer] Registering streaming session: msgId=${messageId}, feishuMsgId=${feishuMessageId}, deviceId=${deviceId}`);
50
+ // Register this message as a streaming message so chunks and response update the same card
51
+ // hasUpdated starts as false to ensure first content is immediately shown
52
+ this.streamingMessages.set(messageId, {
53
+ openId,
54
+ feishuMessageId,
55
+ elements: [],
56
+ currentTextContent: '',
57
+ hasUpdated: false,
58
+ createdAt: Date.now(),
59
+ deviceId
60
+ });
61
+ console.log(`[RouterServer] Total streaming sessions: ${this.streamingMessages.size}`);
62
+ });
63
+ this.setupMiddleware();
64
+ this.setupRoutes();
65
+ }
66
+ /**
67
+ * Setup Koa middleware
68
+ */
69
+ setupMiddleware() {
70
+ this.app.use((0, koa_bodyparser_1.default)());
71
+ // Error handling
72
+ this.app.use(async (ctx, next) => {
73
+ try {
74
+ await next();
75
+ }
76
+ catch (error) {
77
+ console.error('Request error:', error);
78
+ ctx.status = error.status || 500;
79
+ ctx.body = {
80
+ success: false,
81
+ error: error.message || 'Internal server error'
82
+ };
83
+ }
84
+ });
85
+ // Request logging
86
+ this.app.use(async (ctx, next) => {
87
+ const start = Date.now();
88
+ await next();
89
+ const ms = Date.now() - start;
90
+ console.log(`${ctx.method} ${ctx.url} - ${ctx.status} (${ms}ms)`);
91
+ });
92
+ }
93
+ /**
94
+ * Setup HTTP routes
95
+ */
96
+ setupRoutes() {
97
+ const router = new router_1.default();
98
+ // Health check endpoint
99
+ router.get('/health', (ctx) => {
100
+ const stats = this.connectionHub.getConnectionStats();
101
+ ctx.body = {
102
+ status: 'ok',
103
+ timestamp: Date.now(),
104
+ connections: stats.totalConnections,
105
+ devices: stats.deviceIds
106
+ };
107
+ });
108
+ // Binding code request endpoint
109
+ router.post('/api/bind/request', async (ctx) => {
110
+ const { deviceId, deviceName, platform } = ctx.request.body;
111
+ // Validate required fields
112
+ if (!deviceId) {
113
+ ctx.status = 400;
114
+ ctx.body = {
115
+ success: false,
116
+ error: 'deviceId is required'
117
+ };
118
+ return;
119
+ }
120
+ try {
121
+ // Generate binding code
122
+ const bindingCode = await this.bindingManager.generateBindingCode(deviceId, deviceName || 'Unknown Device');
123
+ ctx.body = {
124
+ success: true,
125
+ bindingCode: bindingCode.code,
126
+ expiresAt: bindingCode.expiresAt,
127
+ expiresIn: Math.floor((bindingCode.expiresAt - Date.now()) / 1000) // seconds
128
+ };
129
+ }
130
+ catch (error) {
131
+ console.error('Failed to generate binding code:', error);
132
+ ctx.status = 500;
133
+ ctx.body = {
134
+ success: false,
135
+ error: error.message || 'Failed to generate binding code'
136
+ };
137
+ }
138
+ });
139
+ this.app.use(router.routes());
140
+ this.app.use(router.allowedMethods());
141
+ }
142
+ /**
143
+ * Setup WebSocket server
144
+ */
145
+ setupWebSocket(server) {
146
+ this.wss = new ws_1.WebSocketServer({
147
+ server,
148
+ path: '/ws'
149
+ });
150
+ this.wss.on('connection', (ws, req) => {
151
+ console.log('New WebSocket connection from:', req.socket.remoteAddress);
152
+ let deviceId = null;
153
+ let heartbeatTimeout = null;
154
+ // Reset heartbeat timeout
155
+ const resetHeartbeat = () => {
156
+ if (heartbeatTimeout)
157
+ clearTimeout(heartbeatTimeout);
158
+ // If no heartbeat received within 3x interval, consider connection dead
159
+ const interval = this.config.get('websocket', 'heartbeatInterval');
160
+ heartbeatTimeout = setTimeout(() => {
161
+ console.log('Heartbeat timeout for device:', deviceId);
162
+ ws.close();
163
+ }, interval * 3);
164
+ };
165
+ resetHeartbeat();
166
+ // Handle incoming messages
167
+ ws.on('message', async (data) => {
168
+ try {
169
+ const message = JSON.parse(data.toString());
170
+ // Update heartbeat on any message
171
+ resetHeartbeat();
172
+ switch (message.type) {
173
+ case types_1.MessageType.BINDING_REQUEST:
174
+ // Device sends binding request with deviceId
175
+ deviceId = message.data.deviceId;
176
+ if (deviceId) {
177
+ this.connectionHub.registerConnection(deviceId, ws);
178
+ console.log('Device registered:', deviceId);
179
+ // Send confirmation
180
+ ws.send(JSON.stringify({
181
+ type: types_1.MessageType.BINDING_CONFIRM,
182
+ messageId: message.messageId,
183
+ timestamp: Date.now(),
184
+ data: { success: true }
185
+ }));
186
+ }
187
+ break;
188
+ case types_1.MessageType.HEARTBEAT:
189
+ // Update last active time for the device
190
+ if (deviceId) {
191
+ this.connectionHub.updateLastActive(deviceId);
192
+ }
193
+ // Respond to heartbeat
194
+ ws.send(JSON.stringify({
195
+ type: types_1.MessageType.HEARTBEAT,
196
+ messageId: message.messageId,
197
+ timestamp: Date.now(),
198
+ data: {}
199
+ }));
200
+ break;
201
+ case types_1.MessageType.RESPONSE:
202
+ // Device sends response to command - forward to Feishu via long connection
203
+ const responseOpenId = message.openId || message.data?.openId;
204
+ const responseMessageId = message.messageId;
205
+ const sessionAbbr = message.sessionAbbr || message.data?.sessionAbbr;
206
+ if (responseMessageId && responseOpenId) {
207
+ // Check if this was a streaming message (stream chunks were sent)
208
+ if (this.streamingMessages.has(responseMessageId)) {
209
+ await this.finalizeStreamingMessage(responseMessageId, message.success ?? message.data?.success, message.output || message.data?.output, message.error || message.data?.error, sessionAbbr);
210
+ }
211
+ else {
212
+ // No streaming session found - session should have been created when command was sent
213
+ // This might happen if there was an error. Just send the result as plain text.
214
+ const output = message.output || message.data?.output;
215
+ const success = message.success ?? message.data?.success;
216
+ const errorMsg = message.error || message.data?.error;
217
+ if (success) {
218
+ await this.feishuLongConnHandler.sendMessage(responseOpenId, output || '✅ Command completed successfully');
219
+ }
220
+ else {
221
+ await this.feishuLongConnHandler.sendMessage(responseOpenId, `❌ Command failed:\n${errorMsg || 'Unknown error'}`);
222
+ }
223
+ }
224
+ }
225
+ break;
226
+ case 'stream':
227
+ // Handle streaming output from device
228
+ if (message.messageId && message.openId) {
229
+ const streamType = message.streamType || 'text';
230
+ switch (streamType) {
231
+ case 'text':
232
+ await this.handleTextChunk(message.messageId, message.openId, message.chunk || '');
233
+ break;
234
+ case 'tool_use':
235
+ if (message.toolUse) {
236
+ await this.handleToolUse(message.messageId, message.openId, message.toolUse);
237
+ }
238
+ break;
239
+ case 'tool_result':
240
+ if (message.toolResult) {
241
+ await this.handleToolResult(message.messageId, message.openId, message.toolResult);
242
+ }
243
+ break;
244
+ }
245
+ }
246
+ break;
247
+ case types_1.MessageType.NOTIFICATION:
248
+ // Handle notification from device - only forward actionable notifications
249
+ // that require user intervention (authorization, input required)
250
+ if (message.openId && message.title && message.message) {
251
+ const actionablePrefixes = ['🔒', '⌨️']; // Authorization Required, Waiting for Input
252
+ const isActionable = actionablePrefixes.some(prefix => message.title.startsWith(prefix));
253
+ if (isActionable) {
254
+ console.log(`[RouterServer] Forwarding actionable notification to ${message.openId}: ${message.title}`);
255
+ await this.feishuLongConnHandler.sendMessage(message.openId, `**${message.title}**\n\n${message.message}`);
256
+ }
257
+ else {
258
+ // Log non-actionable notifications but don't forward to user
259
+ console.log(`[RouterServer] Ignoring notification (non-actionable): ${message.title}`);
260
+ }
261
+ }
262
+ break;
263
+ default:
264
+ console.log('Unknown message type:', message.type);
265
+ }
266
+ }
267
+ catch (error) {
268
+ console.error('Error processing message:', error);
269
+ }
270
+ });
271
+ // Handle connection close
272
+ ws.on('close', () => {
273
+ if (heartbeatTimeout)
274
+ clearTimeout(heartbeatTimeout);
275
+ if (deviceId) {
276
+ this.connectionHub.unregisterConnection(deviceId);
277
+ // Clean up any streaming sessions for this device
278
+ this.cleanupStreamingSessionsForDevice(deviceId);
279
+ console.log('Device disconnected:', deviceId);
280
+ }
281
+ });
282
+ // Handle errors
283
+ ws.on('error', (error) => {
284
+ console.error('WebSocket error:', error);
285
+ });
286
+ });
287
+ console.log('WebSocket server listening on /ws');
288
+ }
289
+ /**
290
+ * Start the server
291
+ */
292
+ async start() {
293
+ const port = this.config.get('server', 'port');
294
+ const host = this.config.get('server', 'host');
295
+ // Create HTTP server
296
+ this.httpServer = this.app.listen(port, host);
297
+ // Setup WebSocket server
298
+ this.setupWebSocket(this.httpServer);
299
+ // Start Feishu WebSocket long connection
300
+ try {
301
+ await this.feishuLongConnHandler.start();
302
+ }
303
+ catch (error) {
304
+ console.error('⚠️ Failed to start Feishu long connection:', error);
305
+ console.log(' Server will continue without Feishu integration');
306
+ }
307
+ // Start periodic cleanup of stale connections
308
+ const heartbeatInterval = this.config.get('websocket', 'heartbeatInterval');
309
+ this.cleanupInterval = setInterval(() => {
310
+ // Cleanup connections that haven't sent heartbeat in 3x interval
311
+ this.connectionHub.cleanupStaleConnections(heartbeatInterval * 3);
312
+ // Cleanup stale streaming sessions
313
+ this.cleanupStaleStreamingSessions();
314
+ }, heartbeatInterval);
315
+ console.log(`\n🚀 Router server started successfully!`);
316
+ console.log(` HTTP: http://${host}:${port}`);
317
+ console.log(` WebSocket: ws://${host}:${port}/ws`);
318
+ console.log(` Environment: ${this.config.get('server', 'nodeEnv')}`);
319
+ console.log(`\n✅ Ready to receive connections from local clients\n`);
320
+ }
321
+ // Track last update time for each streaming message to enable time-based updates
322
+ lastStreamUpdateTime = new Map();
323
+ STREAM_UPDATE_INTERVAL_MS = 500; // Update at least every 500ms
324
+ STREAM_UPDATE_MIN_LENGTH = 10; // Update every 10 characters
325
+ /**
326
+ * Handle streaming chunk from device
327
+ */
328
+ /**
329
+ * Handle text streaming chunk
330
+ */
331
+ async handleTextChunk(messageId, openId, chunk) {
332
+ console.log(`[RouterServer] Received text chunk for ${messageId}, chunk length: ${chunk.length}`);
333
+ const streamData = this.streamingMessages.get(messageId);
334
+ // If no streaming session exists, ignore the chunk
335
+ if (!streamData) {
336
+ console.log(`[RouterServer] No streaming session found for ${messageId}, ignoring chunk`);
337
+ return;
338
+ }
339
+ // Accumulate text content
340
+ streamData.currentTextContent += chunk;
341
+ streamData.createdAt = Date.now(); // Update activity timestamp
342
+ // Determine if we should update the card now
343
+ const now = Date.now();
344
+ const lastUpdate = this.lastStreamUpdateTime.get(messageId) || 0;
345
+ const timeSinceLastUpdate = now - lastUpdate;
346
+ const contentLength = streamData.currentTextContent.length;
347
+ // Update if:
348
+ // 1. We have a feishuMessageId
349
+ // 2. Either:
350
+ // a. It's the first content (hasUpdated is false) - show immediately
351
+ // b. We've accumulated enough characters since last update
352
+ // c. Enough time has passed since last update
353
+ const shouldUpdate = streamData.feishuMessageId && (!streamData.hasUpdated || // First content - always show immediately
354
+ (contentLength % this.STREAM_UPDATE_MIN_LENGTH === 0) || // Every N characters
355
+ (timeSinceLastUpdate >= this.STREAM_UPDATE_INTERVAL_MS) // Time-based
356
+ );
357
+ if (shouldUpdate && streamData.feishuMessageId) {
358
+ // Build current element list: existing elements + current text (if any)
359
+ const elements = [...streamData.elements];
360
+ if (streamData.currentTextContent.trim()) {
361
+ elements.push((0, ToolFormatter_1.createMarkdownElement)(streamData.currentTextContent));
362
+ }
363
+ await this.feishuLongConnHandler.updateStreamingMessage(streamData.feishuMessageId, elements, openId);
364
+ this.lastStreamUpdateTime.set(messageId, now);
365
+ streamData.hasUpdated = true;
366
+ }
367
+ }
368
+ /**
369
+ * Handle tool use event
370
+ */
371
+ async handleToolUse(messageId, openId, toolUse) {
372
+ console.log(`[RouterServer] Received tool_use for ${messageId}: ${toolUse.name}`);
373
+ const streamData = this.streamingMessages.get(messageId);
374
+ if (!streamData) {
375
+ console.log(`[RouterServer] No streaming session found for ${messageId}`);
376
+ return;
377
+ }
378
+ // Flush current text content to elements if any
379
+ if (streamData.currentTextContent.trim()) {
380
+ streamData.elements.push((0, ToolFormatter_1.createMarkdownElement)(streamData.currentTextContent));
381
+ streamData.currentTextContent = '';
382
+ }
383
+ // Add tool use elements (divider + markdown)
384
+ const toolUseElements = (0, ToolFormatter_1.createToolUseElement)(toolUse);
385
+ streamData.elements.push(...toolUseElements);
386
+ streamData.createdAt = Date.now();
387
+ // Immediately update card to show tool use
388
+ if (streamData.feishuMessageId) {
389
+ await this.feishuLongConnHandler.updateStreamingMessage(streamData.feishuMessageId, streamData.elements, openId);
390
+ streamData.hasUpdated = true;
391
+ }
392
+ }
393
+ /**
394
+ * Handle tool result event
395
+ */
396
+ async handleToolResult(messageId, openId, toolResult) {
397
+ console.log(`[RouterServer] Received tool_result for ${messageId}: ${toolResult.tool_use_id}`);
398
+ const streamData = this.streamingMessages.get(messageId);
399
+ if (!streamData) {
400
+ console.log(`[RouterServer] No streaming session found for ${messageId}`);
401
+ return;
402
+ }
403
+ // Flush current text content to elements if any
404
+ if (streamData.currentTextContent.trim()) {
405
+ streamData.elements.push((0, ToolFormatter_1.createMarkdownElement)(streamData.currentTextContent));
406
+ streamData.currentTextContent = '';
407
+ }
408
+ // Add tool result elements (markdown + status div)
409
+ const toolResultElements = (0, ToolFormatter_1.createToolResultElement)(toolResult);
410
+ streamData.elements.push(...toolResultElements);
411
+ streamData.createdAt = Date.now();
412
+ // Immediately update card to show tool result
413
+ if (streamData.feishuMessageId) {
414
+ await this.feishuLongConnHandler.updateStreamingMessage(streamData.feishuMessageId, streamData.elements, openId);
415
+ streamData.hasUpdated = true;
416
+ }
417
+ }
418
+ /**
419
+ * Finalize streaming message
420
+ */
421
+ async finalizeStreamingMessage(messageId, success, output, error, sessionAbbr) {
422
+ const streamData = this.streamingMessages.get(messageId);
423
+ if (!streamData)
424
+ return;
425
+ const { feishuMessageId, openId } = streamData;
426
+ if (feishuMessageId) {
427
+ // Flush any remaining text content
428
+ if (streamData.currentTextContent.trim()) {
429
+ streamData.elements.push((0, ToolFormatter_1.createMarkdownElement)(streamData.currentTextContent));
430
+ streamData.currentTextContent = '';
431
+ }
432
+ // If there are no elements at all, use the output parameter as fallback
433
+ if (streamData.elements.length === 0 && output) {
434
+ streamData.elements.push((0, ToolFormatter_1.createMarkdownElement)(output));
435
+ }
436
+ if (success) {
437
+ await this.feishuLongConnHandler.finalizeStreamingMessage(feishuMessageId, streamData.elements, sessionAbbr, openId);
438
+ }
439
+ else {
440
+ // Add error message to elements
441
+ const errorMsg = error || 'Command failed';
442
+ streamData.elements.push((0, ToolFormatter_1.createMarkdownElement)(`\n\n❌ **Error:** ${errorMsg}`));
443
+ await this.feishuLongConnHandler.finalizeStreamingMessage(feishuMessageId, streamData.elements, undefined, openId);
444
+ }
445
+ }
446
+ // Clean up
447
+ this.streamingMessages.delete(messageId);
448
+ this.lastStreamUpdateTime.delete(messageId);
449
+ }
450
+ /**
451
+ * Cleanup stale streaming sessions that have timed out
452
+ * This prevents memory leaks when devices disconnect without sending a response
453
+ */
454
+ cleanupStaleStreamingSessions() {
455
+ const now = Date.now();
456
+ let cleanedCount = 0;
457
+ for (const [messageId, session] of this.streamingMessages.entries()) {
458
+ if (now - session.createdAt > this.STREAMING_SESSION_TIMEOUT_MS) {
459
+ console.log(`[RouterServer] Cleaning up stale streaming session: ${messageId}`);
460
+ this.streamingMessages.delete(messageId);
461
+ this.lastStreamUpdateTime.delete(messageId);
462
+ cleanedCount++;
463
+ }
464
+ }
465
+ if (cleanedCount > 0) {
466
+ console.log(`[RouterServer] Cleaned up ${cleanedCount} stale streaming sessions, remaining: ${this.streamingMessages.size}`);
467
+ }
468
+ }
469
+ /**
470
+ * Cleanup streaming sessions for a specific device when it disconnects
471
+ * @param deviceId Device ID that disconnected
472
+ */
473
+ cleanupStreamingSessionsForDevice(deviceId) {
474
+ let cleanedCount = 0;
475
+ for (const [messageId, session] of this.streamingMessages.entries()) {
476
+ if (session.deviceId === deviceId) {
477
+ console.log(`[RouterServer] Cleaning up streaming session for disconnected device: ${messageId}`);
478
+ this.streamingMessages.delete(messageId);
479
+ this.lastStreamUpdateTime.delete(messageId);
480
+ cleanedCount++;
481
+ }
482
+ }
483
+ if (cleanedCount > 0) {
484
+ console.log(`[RouterServer] Cleaned up ${cleanedCount} streaming sessions for device ${deviceId}, remaining: ${this.streamingMessages.size}`);
485
+ }
486
+ }
487
+ /**
488
+ * Stop the server
489
+ */
490
+ async stop() {
491
+ console.log('Stopping router server...');
492
+ // Stop cleanup interval
493
+ if (this.cleanupInterval) {
494
+ clearInterval(this.cleanupInterval);
495
+ this.cleanupInterval = null;
496
+ }
497
+ // Stop Feishu long connection
498
+ try {
499
+ await this.feishuLongConnHandler.stop();
500
+ }
501
+ catch (error) {
502
+ console.error('Error stopping Feishu long connection:', error);
503
+ }
504
+ // Close all WebSocket connections
505
+ this.connectionHub.closeAllConnections();
506
+ // Close WebSocket server
507
+ if (this.wss) {
508
+ this.wss.close();
509
+ this.wss = null;
510
+ }
511
+ // Close HTTP server
512
+ if (this.httpServer) {
513
+ await new Promise((resolve, reject) => {
514
+ this.httpServer.close((err) => {
515
+ if (err)
516
+ reject(err);
517
+ else
518
+ resolve();
519
+ });
520
+ });
521
+ this.httpServer = null;
522
+ }
523
+ console.log('✅ Router server stopped');
524
+ }
525
+ /**
526
+ * Get connection statistics
527
+ */
528
+ getStats() {
529
+ return this.connectionHub.getConnectionStats();
530
+ }
531
+ }
532
+ exports.RouterServer = RouterServer;
533
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}