@wingman-ai/gateway 0.2.2 → 0.2.4

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 (160) hide show
  1. package/.wingman/agents/README.md +7 -1
  2. package/.wingman/agents/coding/agent.md +299 -201
  3. package/.wingman/agents/coding-v2/agent.md +127 -0
  4. package/.wingman/agents/coding-v2/implementor.md +89 -0
  5. package/.wingman/agents/main/agent.md +4 -0
  6. package/README.md +1 -0
  7. package/dist/agent/config/agentConfig.cjs +31 -17
  8. package/dist/agent/config/agentConfig.d.ts +23 -1
  9. package/dist/agent/config/agentConfig.js +30 -19
  10. package/dist/agent/config/agentLoader.cjs +26 -8
  11. package/dist/agent/config/agentLoader.d.ts +4 -2
  12. package/dist/agent/config/agentLoader.js +26 -8
  13. package/dist/agent/config/modelFactory.cjs +95 -25
  14. package/dist/agent/config/modelFactory.d.ts +13 -1
  15. package/dist/agent/config/modelFactory.js +95 -25
  16. package/dist/agent/config/toolRegistry.cjs +19 -6
  17. package/dist/agent/config/toolRegistry.d.ts +5 -2
  18. package/dist/agent/config/toolRegistry.js +19 -6
  19. package/dist/agent/middleware/hooks/types.cjs +13 -13
  20. package/dist/agent/middleware/hooks/types.d.ts +1 -1
  21. package/dist/agent/middleware/hooks/types.js +14 -14
  22. package/dist/agent/tests/agentConfig.test.cjs +22 -2
  23. package/dist/agent/tests/agentConfig.test.js +22 -2
  24. package/dist/agent/tests/agentLoader.test.cjs +38 -1
  25. package/dist/agent/tests/agentLoader.test.js +38 -1
  26. package/dist/agent/tests/backgroundTerminal.test.cjs +70 -0
  27. package/dist/agent/tests/backgroundTerminal.test.d.ts +1 -0
  28. package/dist/agent/tests/backgroundTerminal.test.js +64 -0
  29. package/dist/agent/tests/commandExecuteTool.test.cjs +29 -0
  30. package/dist/agent/tests/commandExecuteTool.test.d.ts +1 -0
  31. package/dist/agent/tests/commandExecuteTool.test.js +23 -0
  32. package/dist/agent/tests/modelFactory.test.cjs +47 -5
  33. package/dist/agent/tests/modelFactory.test.js +47 -5
  34. package/dist/agent/tests/terminalSessionManager.test.cjs +121 -0
  35. package/dist/agent/tests/terminalSessionManager.test.d.ts +1 -0
  36. package/dist/agent/tests/terminalSessionManager.test.js +115 -0
  37. package/dist/agent/tests/toolRegistry.test.cjs +14 -2
  38. package/dist/agent/tests/toolRegistry.test.js +14 -2
  39. package/dist/agent/tools/background_terminal.cjs +128 -0
  40. package/dist/agent/tools/background_terminal.d.ts +41 -0
  41. package/dist/agent/tools/background_terminal.js +94 -0
  42. package/dist/agent/tools/code_search.cjs +6 -6
  43. package/dist/agent/tools/code_search.d.ts +1 -1
  44. package/dist/agent/tools/code_search.js +7 -7
  45. package/dist/agent/tools/command_execute.cjs +22 -7
  46. package/dist/agent/tools/command_execute.d.ts +3 -2
  47. package/dist/agent/tools/command_execute.js +23 -8
  48. package/dist/agent/tools/git_status.cjs +3 -3
  49. package/dist/agent/tools/git_status.d.ts +1 -1
  50. package/dist/agent/tools/git_status.js +4 -4
  51. package/dist/agent/tools/internet_search.cjs +6 -6
  52. package/dist/agent/tools/internet_search.d.ts +1 -1
  53. package/dist/agent/tools/internet_search.js +7 -7
  54. package/dist/agent/tools/terminal_session_manager.cjs +321 -0
  55. package/dist/agent/tools/terminal_session_manager.d.ts +77 -0
  56. package/dist/agent/tools/terminal_session_manager.js +284 -0
  57. package/dist/agent/tools/think.cjs +4 -4
  58. package/dist/agent/tools/think.d.ts +1 -1
  59. package/dist/agent/tools/think.js +5 -5
  60. package/dist/agent/tools/ui_registry.cjs +13 -13
  61. package/dist/agent/tools/ui_registry.d.ts +4 -4
  62. package/dist/agent/tools/ui_registry.js +14 -14
  63. package/dist/agent/tools/web_crawler.cjs +4 -4
  64. package/dist/agent/tools/web_crawler.d.ts +1 -1
  65. package/dist/agent/tools/web_crawler.js +5 -5
  66. package/dist/agent/utils.cjs +2 -1
  67. package/dist/agent/utils.js +2 -1
  68. package/dist/cli/commands/init.cjs +7 -6
  69. package/dist/cli/commands/init.js +7 -6
  70. package/dist/cli/commands/provider.cjs +17 -3
  71. package/dist/cli/commands/provider.js +17 -3
  72. package/dist/cli/config/loader.cjs +27 -0
  73. package/dist/cli/config/loader.js +27 -0
  74. package/dist/cli/config/schema.cjs +146 -68
  75. package/dist/cli/config/schema.d.ts +89 -1
  76. package/dist/cli/config/schema.js +134 -68
  77. package/dist/cli/core/agentInvoker.cjs +344 -17
  78. package/dist/cli/core/agentInvoker.d.ts +63 -3
  79. package/dist/cli/core/agentInvoker.js +303 -12
  80. package/dist/cli/core/sessionManager.cjs +32 -5
  81. package/dist/cli/core/sessionManager.js +32 -5
  82. package/dist/cli/core/streamParser.cjs +15 -0
  83. package/dist/cli/core/streamParser.js +15 -0
  84. package/dist/cli/index.cjs +6 -5
  85. package/dist/cli/index.js +6 -5
  86. package/dist/cli/types.d.ts +32 -0
  87. package/dist/cli/ui/toolDisplayHelpers.cjs +2 -0
  88. package/dist/cli/ui/toolDisplayHelpers.js +2 -0
  89. package/dist/gateway/hooks/registry.cjs +2 -1
  90. package/dist/gateway/hooks/registry.d.ts +1 -1
  91. package/dist/gateway/hooks/registry.js +2 -1
  92. package/dist/gateway/hooks/types.cjs +11 -11
  93. package/dist/gateway/hooks/types.d.ts +1 -1
  94. package/dist/gateway/hooks/types.js +12 -12
  95. package/dist/gateway/http/agents.cjs +67 -4
  96. package/dist/gateway/http/agents.js +67 -4
  97. package/dist/gateway/http/sessions.cjs +7 -7
  98. package/dist/gateway/http/sessions.js +7 -7
  99. package/dist/gateway/http/types.d.ts +5 -3
  100. package/dist/gateway/http/webhooks.cjs +6 -5
  101. package/dist/gateway/http/webhooks.js +6 -5
  102. package/dist/gateway/server.cjs +198 -41
  103. package/dist/gateway/server.d.ts +9 -1
  104. package/dist/gateway/server.js +198 -41
  105. package/dist/gateway/types.d.ts +1 -0
  106. package/dist/gateway/validation.cjs +39 -39
  107. package/dist/gateway/validation.d.ts +1 -1
  108. package/dist/gateway/validation.js +40 -40
  109. package/dist/providers/codex.cjs +167 -0
  110. package/dist/providers/codex.d.ts +15 -0
  111. package/dist/providers/codex.js +127 -0
  112. package/dist/providers/credentials.cjs +8 -0
  113. package/dist/providers/credentials.js +8 -0
  114. package/dist/providers/registry.cjs +11 -0
  115. package/dist/providers/registry.d.ts +1 -1
  116. package/dist/providers/registry.js +11 -0
  117. package/dist/tests/additionalMessageMiddleware.test.cjs +3 -0
  118. package/dist/tests/additionalMessageMiddleware.test.js +3 -0
  119. package/dist/tests/agentInvokerSummarization.test.cjs +455 -0
  120. package/dist/tests/agentInvokerSummarization.test.d.ts +1 -0
  121. package/dist/tests/agentInvokerSummarization.test.js +449 -0
  122. package/dist/tests/agents-api.test.cjs +45 -5
  123. package/dist/tests/agents-api.test.js +45 -5
  124. package/dist/tests/cli-config-loader.test.cjs +88 -0
  125. package/dist/tests/cli-config-loader.test.js +88 -0
  126. package/dist/tests/cli-init.test.cjs +27 -3
  127. package/dist/tests/cli-init.test.js +27 -3
  128. package/dist/tests/codex-credentials-precedence.test.cjs +94 -0
  129. package/dist/tests/codex-credentials-precedence.test.d.ts +1 -0
  130. package/dist/tests/codex-credentials-precedence.test.js +88 -0
  131. package/dist/tests/codex-provider.test.cjs +210 -0
  132. package/dist/tests/codex-provider.test.d.ts +1 -0
  133. package/dist/tests/codex-provider.test.js +204 -0
  134. package/dist/tests/gateway.test.cjs +115 -8
  135. package/dist/tests/gateway.test.js +115 -8
  136. package/dist/tests/provider-command-codex.test.cjs +57 -0
  137. package/dist/tests/provider-command-codex.test.d.ts +1 -0
  138. package/dist/tests/provider-command-codex.test.js +51 -0
  139. package/dist/tests/sessionStateMessages.test.cjs +38 -0
  140. package/dist/tests/sessionStateMessages.test.js +38 -0
  141. package/dist/tests/toolDisplayHelpers.test.cjs +3 -0
  142. package/dist/tests/toolDisplayHelpers.test.js +3 -0
  143. package/dist/tools/mcp-finance.cjs +48 -48
  144. package/dist/tools/mcp-finance.js +48 -48
  145. package/dist/types/mcp.cjs +15 -15
  146. package/dist/types/mcp.d.ts +1 -1
  147. package/dist/types/mcp.js +16 -16
  148. package/dist/types/voice.cjs +21 -21
  149. package/dist/types/voice.d.ts +1 -1
  150. package/dist/types/voice.js +22 -22
  151. package/dist/webui/assets/index-DVWQluit.css +11 -0
  152. package/dist/webui/assets/index-Dlyzwalc.js +270 -0
  153. package/dist/webui/favicon-32x32.png +0 -0
  154. package/dist/webui/favicon-64x64.png +0 -0
  155. package/dist/webui/favicon.webp +0 -0
  156. package/dist/webui/index.html +4 -2
  157. package/package.json +13 -12
  158. package/.wingman/agents/coding/implementor.md +0 -79
  159. package/dist/webui/assets/index-CPhfGPHc.js +0 -182
  160. package/dist/webui/assets/index-DDsMIOTX.css +0 -11
@@ -1,28 +1,29 @@
1
- import { NodeManager } from "./node.js";
2
- import { BroadcastGroupManager } from "./broadcast.js";
3
- import { GatewayAuth } from "./auth.js";
4
- import { validateGatewayMessage } from "./validation.js";
5
- import { getGatewayTokenFromEnv } from "./env.js";
6
- import { MDNSDiscoveryService, TailscaleDiscoveryService } from "./discovery/index.js";
7
- import { createLogger } from "../logger.js";
1
+ import { existsSync, mkdirSync, statSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, isAbsolute, join, normalize, sep } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { TerminalSessionManager } from "../agent/tools/terminal_session_manager.js";
8
6
  import { WingmanConfigLoader } from "../cli/config/loader.js";
9
- import { GatewayRouter } from "./router.js";
10
- import { OutputManager } from "../cli/core/outputManager.js";
11
7
  import { AgentInvoker } from "../cli/core/agentInvoker.js";
8
+ import { OutputManager } from "../cli/core/outputManager.js";
12
9
  import { SessionManager } from "../cli/core/sessionManager.js";
10
+ import { createLogger } from "../logger.js";
11
+ import { DiscordGatewayAdapter } from "./adapters/discord.js";
12
+ import { GatewayAuth } from "./auth.js";
13
+ import { BroadcastGroupManager } from "./broadcast.js";
14
+ import { MDNSDiscoveryService, TailscaleDiscoveryService } from "./discovery/index.js";
15
+ import { getGatewayTokenFromEnv } from "./env.js";
16
+ import { InternalHookRegistry } from "./hooks/registry.js";
13
17
  import { handleAgentsApi } from "./http/agents.js";
14
18
  import { handleFsApi } from "./http/fs.js";
15
19
  import { handleProvidersApi } from "./http/providers.js";
16
- import { handleVoiceApi } from "./http/voice.js";
20
+ import { createRoutineStore, handleRoutinesApi } from "./http/routines.js";
17
21
  import { handleSessionsApi } from "./http/sessions.js";
22
+ import { handleVoiceApi } from "./http/voice.js";
18
23
  import { createWebhookStore, handleWebhookInvoke, handleWebhooksApi } from "./http/webhooks.js";
19
- import { createRoutineStore, handleRoutinesApi } from "./http/routines.js";
20
- import { DiscordGatewayAdapter } from "./adapters/discord.js";
21
- import { InternalHookRegistry } from "./hooks/registry.js";
22
- import { homedir } from "node:os";
23
- import { dirname, isAbsolute, join, normalize, sep } from "node:path";
24
- import { existsSync, mkdirSync, statSync, writeFileSync } from "node:fs";
25
- import { fileURLToPath } from "node:url";
24
+ import { NodeManager } from "./node.js";
25
+ import { GatewayRouter } from "./router.js";
26
+ import { validateGatewayMessage } from "./validation.js";
26
27
  function _define_property(obj, key, value) {
27
28
  if (key in obj) Object.defineProperty(obj, key, {
28
29
  value: value,
@@ -76,6 +77,7 @@ class GatewayServer {
76
77
  });
77
78
  return;
78
79
  }
80
+ if (url.pathname.startsWith("/api/")) return this.handleUiRequest(req);
79
81
  const webhookResponse = await handleWebhookInvoke(this.getHttpContext(), this.webhookStore, req, url);
80
82
  if (webhookResponse) return webhookResponse;
81
83
  if (this.controlUiSamePort) return this.handleUiRequest(req);
@@ -132,6 +134,7 @@ class GatewayServer {
132
134
  this.uiServer.stop();
133
135
  this.uiServer = null;
134
136
  }
137
+ this.terminalSessionManager.dispose();
135
138
  this.log("info", "Gateway stopped");
136
139
  }
137
140
  getPort() {
@@ -319,6 +322,7 @@ class GatewayServer {
319
322
  existing?.abortController.abort();
320
323
  this.activeAgentRequests.delete(msg.id);
321
324
  }
325
+ this.removeQueuedRequestById(msg.id);
322
326
  const payload = msg.payload;
323
327
  const content = "string" == typeof payload?.content ? payload.content : "";
324
328
  const attachments = Array.isArray(payload?.attachments) ? payload.attachments : [];
@@ -328,6 +332,7 @@ class GatewayServer {
328
332
  const agentId = this.router.selectAgent(payload.agentId, payload.routing);
329
333
  if (!agentId) return void this.sendAgentError(ws, msg.id, "No agent matched the request");
330
334
  const sessionKey = payload.sessionKey || this.router.buildSessionKey(agentId, payload.routing);
335
+ const sessionQueueKey = this.buildSessionQueueKey(agentId, sessionKey);
331
336
  const sessionManager = await this.getSessionManager(agentId);
332
337
  const existingSession = sessionManager.getSession(sessionKey);
333
338
  const session = existingSession || sessionManager.getOrCreateSession(sessionKey, agentId);
@@ -378,9 +383,70 @@ class GatewayServer {
378
383
  ],
379
384
  skipSessionId: sessionKey
380
385
  });
386
+ const request = {
387
+ ws,
388
+ msg,
389
+ payload,
390
+ agentId,
391
+ sessionKey,
392
+ sessionQueueKey,
393
+ content,
394
+ attachments,
395
+ sessionManager,
396
+ workdir,
397
+ defaultOutputDir
398
+ };
399
+ this.requestSessionKeys.set(msg.id, sessionQueueKey);
400
+ const queueIfBusy = false !== payload.queueIfBusy;
401
+ const activeRequestId = this.activeSessionRequests.get(sessionQueueKey);
402
+ if (activeRequestId && queueIfBusy) {
403
+ const queued = this.queuedSessionRequests.get(sessionQueueKey) || [];
404
+ queued.push(request);
405
+ this.queuedSessionRequests.set(sessionQueueKey, queued);
406
+ const position = queued.length;
407
+ this.sendMessage(ws, {
408
+ type: "ack",
409
+ id: msg.id,
410
+ payload: {
411
+ action: "req:agent",
412
+ status: "queued",
413
+ requestId: msg.id,
414
+ sessionId: sessionKey,
415
+ agentId,
416
+ position
417
+ },
418
+ timestamp: Date.now()
419
+ });
420
+ this.sendMessage(ws, {
421
+ type: "event:agent",
422
+ id: msg.id,
423
+ clientId: ws.data.clientId,
424
+ payload: this.attachSessionContext({
425
+ type: "request-queued",
426
+ position
427
+ }, sessionKey, agentId),
428
+ timestamp: Date.now()
429
+ });
430
+ return;
431
+ }
432
+ if (activeRequestId && !queueIfBusy) {
433
+ this.requestSessionKeys.delete(msg.id);
434
+ this.sendAgentError(ws, msg.id, "Session already has an in-flight request. Set queueIfBusy=true to enqueue.", {
435
+ sessionId: sessionKey,
436
+ agentId
437
+ });
438
+ return;
439
+ }
440
+ this.executeAgentRequest(request);
441
+ }
442
+ async executeAgentRequest(request) {
443
+ const { ws, msg, agentId, sessionKey, sessionQueueKey, content, attachments, sessionManager, workdir, defaultOutputDir } = request;
444
+ this.activeSessionRequests.set(sessionQueueKey, msg.id);
381
445
  const outputManager = new OutputManager("interactive");
446
+ let emittedAgentError = false;
382
447
  const outputHandler = (event)=>{
383
448
  const payloadWithSession = this.attachSessionContext(event, sessionKey, agentId);
449
+ if (payloadWithSession && "object" == typeof payloadWithSession && !Array.isArray(payloadWithSession) && "agent-error" === payloadWithSession.type) emittedAgentError = true;
384
450
  const baseMessage = {
385
451
  type: "event:agent",
386
452
  id: msg.id,
@@ -401,6 +467,7 @@ class GatewayServer {
401
467
  outputManager,
402
468
  logger: this.logger,
403
469
  sessionManager,
470
+ terminalSessionManager: this.terminalSessionManager,
404
471
  workdir,
405
472
  defaultOutputDir
406
473
  });
@@ -419,41 +486,111 @@ class GatewayServer {
419
486
  });
420
487
  } catch (error) {
421
488
  this.logger.error("Agent invocation failed", error);
489
+ if (!emittedAgentError) {
490
+ const message = error instanceof Error ? error.message : String(error);
491
+ const stack = error instanceof Error ? error.stack : void 0;
492
+ this.sendAgentError(ws, msg.id, message, {
493
+ sessionId: sessionKey,
494
+ agentId,
495
+ stack,
496
+ broadcastToSession: true,
497
+ exclude: ws
498
+ });
499
+ }
422
500
  } finally{
423
501
  this.activeAgentRequests.delete(msg.id);
502
+ this.activeSessionRequests.delete(sessionQueueKey);
503
+ this.requestSessionKeys.delete(msg.id);
424
504
  outputManager.off("output-event", outputHandler);
505
+ this.processNextQueuedAgentRequest(sessionQueueKey);
425
506
  }
426
507
  }
508
+ processNextQueuedAgentRequest(sessionQueueKey) {
509
+ if (this.activeSessionRequests.has(sessionQueueKey)) return;
510
+ const queue = this.queuedSessionRequests.get(sessionQueueKey);
511
+ if (!queue || 0 === queue.length) return void this.queuedSessionRequests.delete(sessionQueueKey);
512
+ const next = queue.shift();
513
+ if (!next) return;
514
+ if (0 === queue.length) this.queuedSessionRequests.delete(sessionQueueKey);
515
+ else this.queuedSessionRequests.set(sessionQueueKey, queue);
516
+ this.sendMessage(next.ws, {
517
+ type: "ack",
518
+ id: next.msg.id,
519
+ payload: {
520
+ action: "req:agent",
521
+ status: "dequeued",
522
+ requestId: next.msg.id,
523
+ sessionId: next.sessionKey,
524
+ agentId: next.agentId,
525
+ remaining: queue.length
526
+ },
527
+ timestamp: Date.now()
528
+ });
529
+ this.executeAgentRequest(next);
530
+ }
427
531
  handleAgentCancel(ws, msg) {
428
532
  if (!ws.data.authenticated) return void this.sendError(ws, "AUTH_FAILED", "Client is not authenticated");
429
533
  const payload = msg.payload;
430
534
  const requestId = "string" == typeof payload?.requestId && payload.requestId || void 0;
431
535
  if (!requestId) return void this.sendError(ws, "INVALID_REQUEST", "Missing requestId for cancellation");
432
536
  const active = this.activeAgentRequests.get(requestId);
433
- if (!active) return void this.sendMessage(ws, {
434
- type: "ack",
435
- id: msg.id,
436
- payload: {
437
- action: "req:agent:cancel",
438
- requestId,
439
- status: "not_found"
440
- },
441
- timestamp: Date.now()
442
- });
443
- if (active.socket !== ws) return void this.sendError(ws, "FORBIDDEN", "Cannot cancel a request started by another client");
444
- active.abortController.abort();
445
- this.activeAgentRequests.delete(requestId);
537
+ if (active) {
538
+ if (active.socket !== ws) return void this.sendError(ws, "FORBIDDEN", "Cannot cancel a request started by another client");
539
+ active.abortController.abort();
540
+ this.activeAgentRequests.delete(requestId);
541
+ this.sendMessage(ws, {
542
+ type: "ack",
543
+ id: msg.id,
544
+ payload: {
545
+ action: "req:agent:cancel",
546
+ requestId,
547
+ status: "cancelled"
548
+ },
549
+ timestamp: Date.now()
550
+ });
551
+ return;
552
+ }
553
+ const queued = this.removeQueuedRequestById(requestId);
554
+ if (queued) {
555
+ if (queued.ws !== ws) return void this.sendError(ws, "FORBIDDEN", "Cannot cancel a request started by another client");
556
+ this.sendMessage(ws, {
557
+ type: "ack",
558
+ id: msg.id,
559
+ payload: {
560
+ action: "req:agent:cancel",
561
+ requestId,
562
+ status: "cancelled_queued"
563
+ },
564
+ timestamp: Date.now()
565
+ });
566
+ return;
567
+ }
446
568
  this.sendMessage(ws, {
447
569
  type: "ack",
448
570
  id: msg.id,
449
571
  payload: {
450
572
  action: "req:agent:cancel",
451
573
  requestId,
452
- status: "cancelled"
574
+ status: "not_found"
453
575
  },
454
576
  timestamp: Date.now()
455
577
  });
456
578
  }
579
+ buildSessionQueueKey(agentId, sessionKey) {
580
+ return `${agentId}:${sessionKey}`;
581
+ }
582
+ removeQueuedRequestById(requestId) {
583
+ for (const [queueKey, queue] of this.queuedSessionRequests){
584
+ const index = queue.findIndex((item)=>item.msg.id === requestId);
585
+ if (-1 === index) continue;
586
+ const [removed] = queue.splice(index, 1);
587
+ if (0 === queue.length) this.queuedSessionRequests.delete(queueKey);
588
+ else this.queuedSessionRequests.set(queueKey, queue);
589
+ this.requestSessionKeys.delete(requestId);
590
+ return removed || null;
591
+ }
592
+ return null;
593
+ }
457
594
  handleRegister(ws, msg) {
458
595
  const payload = msg.payload;
459
596
  if (!this.auth.validate({
@@ -616,23 +753,39 @@ class GatewayServer {
616
753
  timestamp: Date.now()
617
754
  });
618
755
  }
619
- sendAgentError(ws, requestId, message) {
620
- this.sendMessage(ws, {
756
+ sendAgentError(ws, requestId, message, options) {
757
+ let payload = {
758
+ type: "agent-error",
759
+ error: message,
760
+ timestamp: new Date().toISOString()
761
+ };
762
+ if (options?.stack) payload.stack = options.stack;
763
+ if (options?.sessionId && options?.agentId) payload = this.attachSessionContext(payload, options.sessionId, options.agentId);
764
+ const baseMessage = {
621
765
  type: "event:agent",
622
766
  id: requestId,
623
- payload: {
624
- type: "agent-error",
625
- error: message,
626
- timestamp: new Date().toISOString()
627
- },
767
+ payload,
628
768
  timestamp: Date.now()
769
+ };
770
+ this.sendMessage(ws, {
771
+ ...baseMessage,
772
+ clientId: ws.data.clientId
629
773
  });
774
+ if (options?.broadcastToSession && options.sessionId) this.broadcastSessionEvent(options.sessionId, baseMessage, options.exclude);
630
775
  }
631
776
  cancelSocketAgentRequests(ws) {
632
777
  for (const [requestId, active] of this.activeAgentRequests)if (active.socket === ws) {
633
778
  active.abortController.abort();
634
779
  this.activeAgentRequests.delete(requestId);
635
780
  }
781
+ for (const [queueKey, queue] of this.queuedSessionRequests){
782
+ const nextQueue = queue.filter((request)=>request.ws !== ws);
783
+ if (nextQueue.length !== queue.length) {
784
+ for (const request of queue)if (request.ws === ws && request.msg.id) this.requestSessionKeys.delete(request.msg.id);
785
+ if (0 === nextQueue.length) this.queuedSessionRequests.delete(queueKey);
786
+ else this.queuedSessionRequests.set(queueKey, nextQueue);
787
+ }
788
+ }
636
789
  }
637
790
  attachSessionContext(event, sessionId, agentId) {
638
791
  if (event && "object" == typeof event && !Array.isArray(event)) return {
@@ -752,6 +905,7 @@ class GatewayServer {
752
905
  resolveFsRoots: ()=>this.resolveFsRoots(),
753
906
  resolveFsPath: (path)=>this.resolveFsPath(path),
754
907
  isPathWithinRoots: (path, roots)=>this.isPathWithinRoots(path, roots),
908
+ getTerminalSessionManager: ()=>this.terminalSessionManager,
755
909
  getBuiltInTools: ()=>this.getBuiltInTools()
756
910
  };
757
911
  }
@@ -824,9 +978,7 @@ class GatewayServer {
824
978
  ];
825
979
  for (const candidate of candidates)try {
826
980
  if (existsSync(candidate) && statSync(candidate).isDirectory() && existsSync(join(candidate, "index.html"))) return candidate;
827
- } catch {
828
- continue;
829
- }
981
+ } catch {}
830
982
  return null;
831
983
  }
832
984
  async getSessionManager(agentId) {
@@ -1150,6 +1302,10 @@ class GatewayServer {
1150
1302
  _define_property(this, "socketSubscriptions", new Map());
1151
1303
  _define_property(this, "connectedClients", new Set());
1152
1304
  _define_property(this, "activeAgentRequests", new Map());
1305
+ _define_property(this, "activeSessionRequests", new Map());
1306
+ _define_property(this, "queuedSessionRequests", new Map());
1307
+ _define_property(this, "requestSessionKeys", new Map());
1308
+ _define_property(this, "terminalSessionManager", void 0);
1153
1309
  _define_property(this, "bridgeQueues", new Map());
1154
1310
  _define_property(this, "bridgePollWaiters", new Map());
1155
1311
  this.workspace = config.workspace || process.cwd();
@@ -1200,6 +1356,7 @@ class GatewayServer {
1200
1356
  this.controlUiPort = controlUi?.port || 18790;
1201
1357
  this.controlUiSamePort = this.controlUiEnabled && this.controlUiPort === this.config.port;
1202
1358
  this.uiDistDir = this.controlUiEnabled ? this.resolveControlUiDir() : null;
1359
+ this.terminalSessionManager = new TerminalSessionManager();
1203
1360
  }
1204
1361
  }
1205
1362
  function buildAttachmentPreview(attachments) {
@@ -60,6 +60,7 @@ export interface AgentRequestPayload {
60
60
  attachments?: MediaAttachment[];
61
61
  routing?: RoutingInfo;
62
62
  sessionKey?: string;
63
+ queueIfBusy?: boolean;
63
64
  }
64
65
  export interface AgentCancelPayload {
65
66
  requestId: string;
@@ -38,7 +38,7 @@ __webpack_require__.d(__webpack_exports__, {
38
38
  BroadcastPayloadSchema: ()=>BroadcastPayloadSchema
39
39
  });
40
40
  const external_zod_namespaceObject = require("zod");
41
- const MessageTypeSchema = external_zod_namespaceObject.z["enum"]([
41
+ const MessageTypeSchema = external_zod_namespaceObject["enum"]([
42
42
  "connect",
43
43
  "res",
44
44
  "req:agent",
@@ -58,52 +58,52 @@ const MessageTypeSchema = external_zod_namespaceObject.z["enum"]([
58
58
  "error",
59
59
  "ack"
60
60
  ]);
61
- const GatewayMessageSchema = external_zod_namespaceObject.z.object({
61
+ const GatewayMessageSchema = external_zod_namespaceObject.object({
62
62
  type: MessageTypeSchema,
63
- id: external_zod_namespaceObject.z.string().optional(),
64
- client: external_zod_namespaceObject.z.object({
65
- instanceId: external_zod_namespaceObject.z.string().min(1),
66
- clientType: external_zod_namespaceObject.z.string().min(1),
67
- version: external_zod_namespaceObject.z.string().optional()
63
+ id: external_zod_namespaceObject.string().optional(),
64
+ client: external_zod_namespaceObject.object({
65
+ instanceId: external_zod_namespaceObject.string().min(1),
66
+ clientType: external_zod_namespaceObject.string().min(1),
67
+ version: external_zod_namespaceObject.string().optional()
68
68
  }).optional(),
69
- auth: external_zod_namespaceObject.z.object({
70
- token: external_zod_namespaceObject.z.string().optional(),
71
- password: external_zod_namespaceObject.z.string().optional(),
72
- deviceId: external_zod_namespaceObject.z.string().optional()
69
+ auth: external_zod_namespaceObject.object({
70
+ token: external_zod_namespaceObject.string().optional(),
71
+ password: external_zod_namespaceObject.string().optional(),
72
+ deviceId: external_zod_namespaceObject.string().optional()
73
73
  }).optional(),
74
- ok: external_zod_namespaceObject.z.boolean().optional(),
75
- clientId: external_zod_namespaceObject.z.string().optional(),
76
- nodeId: external_zod_namespaceObject.z.string().optional(),
77
- groupId: external_zod_namespaceObject.z.string().optional(),
78
- roomId: external_zod_namespaceObject.z.string().optional(),
79
- targetNodeId: external_zod_namespaceObject.z.string().optional(),
80
- payload: external_zod_namespaceObject.z.unknown().optional(),
81
- timestamp: external_zod_namespaceObject.z.number(),
82
- messageId: external_zod_namespaceObject.z.string().optional()
74
+ ok: external_zod_namespaceObject.boolean().optional(),
75
+ clientId: external_zod_namespaceObject.string().optional(),
76
+ nodeId: external_zod_namespaceObject.string().optional(),
77
+ groupId: external_zod_namespaceObject.string().optional(),
78
+ roomId: external_zod_namespaceObject.string().optional(),
79
+ targetNodeId: external_zod_namespaceObject.string().optional(),
80
+ payload: external_zod_namespaceObject.unknown().optional(),
81
+ timestamp: external_zod_namespaceObject.number(),
82
+ messageId: external_zod_namespaceObject.string().optional()
83
83
  });
84
- const RegisterPayloadSchema = external_zod_namespaceObject.z.object({
85
- name: external_zod_namespaceObject.z.string().min(1).max(100),
86
- capabilities: external_zod_namespaceObject.z.array(external_zod_namespaceObject.z.string()).optional(),
87
- token: external_zod_namespaceObject.z.string().optional()
84
+ const RegisterPayloadSchema = external_zod_namespaceObject.object({
85
+ name: external_zod_namespaceObject.string().min(1).max(100),
86
+ capabilities: external_zod_namespaceObject.array(external_zod_namespaceObject.string()).optional(),
87
+ token: external_zod_namespaceObject.string().optional()
88
88
  });
89
- const JoinGroupPayloadSchema = external_zod_namespaceObject.z.object({
90
- groupId: external_zod_namespaceObject.z.string().optional(),
91
- groupName: external_zod_namespaceObject.z.string().min(1).max(100).optional(),
92
- createIfNotExists: external_zod_namespaceObject.z.boolean().optional(),
93
- description: external_zod_namespaceObject.z.string().max(500).optional()
89
+ const JoinGroupPayloadSchema = external_zod_namespaceObject.object({
90
+ groupId: external_zod_namespaceObject.string().optional(),
91
+ groupName: external_zod_namespaceObject.string().min(1).max(100).optional(),
92
+ createIfNotExists: external_zod_namespaceObject.boolean().optional(),
93
+ description: external_zod_namespaceObject.string().max(500).optional()
94
94
  });
95
- const BroadcastPayloadSchema = external_zod_namespaceObject.z.object({
96
- groupId: external_zod_namespaceObject.z.string().min(1),
97
- message: external_zod_namespaceObject.z.unknown()
95
+ const BroadcastPayloadSchema = external_zod_namespaceObject.object({
96
+ groupId: external_zod_namespaceObject.string().min(1),
97
+ message: external_zod_namespaceObject.unknown()
98
98
  });
99
- const DirectPayloadSchema = external_zod_namespaceObject.z.object({
100
- targetNodeId: external_zod_namespaceObject.z.string().min(1),
101
- message: external_zod_namespaceObject.z.unknown()
99
+ const DirectPayloadSchema = external_zod_namespaceObject.object({
100
+ targetNodeId: external_zod_namespaceObject.string().min(1),
101
+ message: external_zod_namespaceObject.unknown()
102
102
  });
103
- const ErrorPayloadSchema = external_zod_namespaceObject.z.object({
104
- code: external_zod_namespaceObject.z.string().min(1),
105
- message: external_zod_namespaceObject.z.string().min(1),
106
- details: external_zod_namespaceObject.z.unknown().optional()
103
+ const ErrorPayloadSchema = external_zod_namespaceObject.object({
104
+ code: external_zod_namespaceObject.string().min(1),
105
+ message: external_zod_namespaceObject.string().min(1),
106
+ details: external_zod_namespaceObject.unknown().optional()
107
107
  });
108
108
  function validateGatewayMessage(data) {
109
109
  try {
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import * as z from "zod";
2
2
  import type { GatewayMessage, RegisterPayload, JoinGroupPayload, BroadcastPayload, DirectPayload } from "./types.js";
3
3
  /**
4
4
  * Message type enum for validation
@@ -1,5 +1,5 @@
1
- import { z } from "zod";
2
- const MessageTypeSchema = z["enum"]([
1
+ import { array, boolean as external_zod_boolean, enum as external_zod_enum, number, object, string, unknown } from "zod";
2
+ const MessageTypeSchema = external_zod_enum([
3
3
  "connect",
4
4
  "res",
5
5
  "req:agent",
@@ -19,52 +19,52 @@ const MessageTypeSchema = z["enum"]([
19
19
  "error",
20
20
  "ack"
21
21
  ]);
22
- const GatewayMessageSchema = z.object({
22
+ const GatewayMessageSchema = object({
23
23
  type: MessageTypeSchema,
24
- id: z.string().optional(),
25
- client: z.object({
26
- instanceId: z.string().min(1),
27
- clientType: z.string().min(1),
28
- version: z.string().optional()
24
+ id: string().optional(),
25
+ client: object({
26
+ instanceId: string().min(1),
27
+ clientType: string().min(1),
28
+ version: string().optional()
29
29
  }).optional(),
30
- auth: z.object({
31
- token: z.string().optional(),
32
- password: z.string().optional(),
33
- deviceId: z.string().optional()
30
+ auth: object({
31
+ token: string().optional(),
32
+ password: string().optional(),
33
+ deviceId: string().optional()
34
34
  }).optional(),
35
- ok: z.boolean().optional(),
36
- clientId: z.string().optional(),
37
- nodeId: z.string().optional(),
38
- groupId: z.string().optional(),
39
- roomId: z.string().optional(),
40
- targetNodeId: z.string().optional(),
41
- payload: z.unknown().optional(),
42
- timestamp: z.number(),
43
- messageId: z.string().optional()
35
+ ok: external_zod_boolean().optional(),
36
+ clientId: string().optional(),
37
+ nodeId: string().optional(),
38
+ groupId: string().optional(),
39
+ roomId: string().optional(),
40
+ targetNodeId: string().optional(),
41
+ payload: unknown().optional(),
42
+ timestamp: number(),
43
+ messageId: string().optional()
44
44
  });
45
- const RegisterPayloadSchema = z.object({
46
- name: z.string().min(1).max(100),
47
- capabilities: z.array(z.string()).optional(),
48
- token: z.string().optional()
45
+ const RegisterPayloadSchema = object({
46
+ name: string().min(1).max(100),
47
+ capabilities: array(string()).optional(),
48
+ token: string().optional()
49
49
  });
50
- const JoinGroupPayloadSchema = z.object({
51
- groupId: z.string().optional(),
52
- groupName: z.string().min(1).max(100).optional(),
53
- createIfNotExists: z.boolean().optional(),
54
- description: z.string().max(500).optional()
50
+ const JoinGroupPayloadSchema = object({
51
+ groupId: string().optional(),
52
+ groupName: string().min(1).max(100).optional(),
53
+ createIfNotExists: external_zod_boolean().optional(),
54
+ description: string().max(500).optional()
55
55
  });
56
- const BroadcastPayloadSchema = z.object({
57
- groupId: z.string().min(1),
58
- message: z.unknown()
56
+ const BroadcastPayloadSchema = object({
57
+ groupId: string().min(1),
58
+ message: unknown()
59
59
  });
60
- const DirectPayloadSchema = z.object({
61
- targetNodeId: z.string().min(1),
62
- message: z.unknown()
60
+ const DirectPayloadSchema = object({
61
+ targetNodeId: string().min(1),
62
+ message: unknown()
63
63
  });
64
- const ErrorPayloadSchema = z.object({
65
- code: z.string().min(1),
66
- message: z.string().min(1),
67
- details: z.unknown().optional()
64
+ const ErrorPayloadSchema = object({
65
+ code: string().min(1),
66
+ message: string().min(1),
67
+ details: unknown().optional()
68
68
  });
69
69
  function validateGatewayMessage(data) {
70
70
  try {