aws-runtime-bridge 1.2.0 → 1.3.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 (92) hide show
  1. package/README.md +77 -77
  2. package/dist/adapter/ClaudeSdkAdapter.d.ts +1 -0
  3. package/dist/adapter/ClaudeSdkAdapter.d.ts.map +1 -1
  4. package/dist/adapter/ClaudeSdkAdapter.js +7 -3
  5. package/dist/adapter/ClaudeSdkAdapter.test.js +2 -2
  6. package/dist/adapter/CodexSdkAdapter.d.ts.map +1 -1
  7. package/dist/adapter/CodexSdkAdapter.js +7 -4
  8. package/dist/adapter/CodexSdkAdapter.test.js +4 -2
  9. package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
  10. package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -1
  11. package/dist/adapter/OpencodeSdkAdapter.js +15 -1
  12. package/dist/adapter/OpencodeSdkAdapter.test.js +5 -0
  13. package/dist/index.js +0 -0
  14. package/dist/routes/properties.test.js +4 -4
  15. package/dist/routes/runtime-binding.d.ts.map +1 -1
  16. package/dist/routes/runtime-binding.js +8 -13
  17. package/dist/routes/runtime-mcp-proxy.d.ts +3 -0
  18. package/dist/routes/runtime-mcp-proxy.d.ts.map +1 -0
  19. package/dist/routes/runtime-mcp-proxy.js +102 -0
  20. package/dist/routes/runtime-mcp-proxy.test.d.ts +2 -0
  21. package/dist/routes/runtime-mcp-proxy.test.d.ts.map +1 -0
  22. package/dist/routes/runtime-mcp-proxy.test.js +111 -0
  23. package/dist/routes/terminal.js +2 -5
  24. package/dist/routes/terminal.test.js +3 -4
  25. package/dist/services/auto-register.d.ts +6 -0
  26. package/dist/services/auto-register.d.ts.map +1 -1
  27. package/dist/services/auto-register.js +63 -1
  28. package/dist/services/aws-client-agent-mcp.d.ts.map +1 -1
  29. package/dist/services/aws-client-agent-mcp.js +73 -7
  30. package/dist/services/aws-client-agent-mcp.test.js +83 -2
  31. package/dist/services/mcp-launch-binding-queue.d.ts +0 -2
  32. package/dist/services/mcp-launch-binding-queue.d.ts.map +1 -1
  33. package/dist/services/mcp-launch-binding-queue.js +44 -16
  34. package/dist/services/mcp-launch-binding-queue.test.js +42 -37
  35. package/dist/services/runtime-binding.d.ts +1 -0
  36. package/dist/services/runtime-binding.d.ts.map +1 -1
  37. package/dist/services/runtime-binding.js +39 -5
  38. package/dist/services/runtime-binding.test.d.ts +2 -0
  39. package/dist/services/runtime-binding.test.d.ts.map +1 -0
  40. package/dist/services/runtime-binding.test.js +11 -0
  41. package/dist/utils/yaml-utils.test.js +129 -129
  42. package/node_modules/@cc-switch/sdk/README.md +540 -540
  43. package/node_modules/@cc-switch/sdk/dist/sdk-import.test.d.ts +2 -0
  44. package/node_modules/@cc-switch/sdk/dist/sdk-import.test.d.ts.map +1 -0
  45. package/node_modules/@cc-switch/sdk/dist/sdk-import.test.js +119 -0
  46. package/node_modules/@cc-switch/sdk/package.json +31 -31
  47. package/package/aws-client-agent-mcp/README.md +288 -288
  48. package/package/aws-client-agent-mcp/dist/config.d.ts.map +1 -1
  49. package/package/aws-client-agent-mcp/dist/config.js +96 -13
  50. package/package/aws-client-agent-mcp/dist/config.js.map +1 -1
  51. package/package/aws-client-agent-mcp/dist/config.test.js +26 -8
  52. package/package/aws-client-agent-mcp/dist/config.test.js.map +1 -1
  53. package/package/aws-client-agent-mcp/dist/constants.d.ts +0 -1
  54. package/package/aws-client-agent-mcp/dist/constants.d.ts.map +1 -1
  55. package/package/aws-client-agent-mcp/dist/constants.js +0 -1
  56. package/package/aws-client-agent-mcp/dist/constants.js.map +1 -1
  57. package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -1
  58. package/package/aws-client-agent-mcp/dist/http-client.js +49 -13
  59. package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -1
  60. package/package/aws-client-agent-mcp/dist/http-client.test.js +40 -13
  61. package/package/aws-client-agent-mcp/dist/http-client.test.js.map +1 -1
  62. package/package/aws-client-agent-mcp/dist/index.js +11 -6
  63. package/package/aws-client-agent-mcp/dist/index.js.map +1 -1
  64. package/package/aws-client-agent-mcp/dist/logger.d.ts +11 -1
  65. package/package/aws-client-agent-mcp/dist/logger.d.ts.map +1 -1
  66. package/package/aws-client-agent-mcp/dist/logger.js +91 -6
  67. package/package/aws-client-agent-mcp/dist/logger.js.map +1 -1
  68. package/package/aws-client-agent-mcp/dist/logger.test.d.ts +2 -0
  69. package/package/aws-client-agent-mcp/dist/logger.test.d.ts.map +1 -0
  70. package/package/aws-client-agent-mcp/dist/logger.test.js +27 -0
  71. package/package/aws-client-agent-mcp/dist/logger.test.js.map +1 -0
  72. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.d.ts.map +1 -1
  73. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js +18 -14
  74. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js.map +1 -1
  75. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js +51 -21
  76. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js.map +1 -1
  77. package/package/aws-client-agent-mcp/dist/types.d.ts +3 -2
  78. package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
  79. package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
  80. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts +1 -0
  81. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
  82. package/package/aws-client-agent-mcp/dist/websocket-client.js +18 -0
  83. package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
  84. package/package/aws-client-agent-mcp/dist/websocket-client.test.js +53 -2
  85. package/package/aws-client-agent-mcp/dist/websocket-client.test.js.map +1 -1
  86. package/package/aws-client-agent-mcp/package.json +52 -52
  87. package/package/cc-switch-sdk/README.md +540 -540
  88. package/package/cc-switch-sdk/dist/sdk-import.test.d.ts +2 -0
  89. package/package/cc-switch-sdk/dist/sdk-import.test.d.ts.map +1 -0
  90. package/package/cc-switch-sdk/dist/sdk-import.test.js +119 -0
  91. package/package/cc-switch-sdk/package.json +31 -31
  92. package/package.json +78 -78
@@ -80,7 +80,7 @@ terminalRouter.post('/start', validateToken, async (req, res) => {
80
80
  });
81
81
  // SDK 模式
82
82
  if (mode === 'sdk') {
83
- await startSdkSession(req, res, queuedBinding?.id);
83
+ await startSdkSession(req, res);
84
84
  return;
85
85
  }
86
86
  // PTY 模式(原有逻辑)
@@ -110,7 +110,6 @@ terminalRouter.post('/start', validateToken, async (req, res) => {
110
110
  env: {
111
111
  ...process.env,
112
112
  AWS_AGENT_ID: String(agentId),
113
- AWS_MCP_LAUNCH_BINDING_ID: queuedBinding?.id || '',
114
113
  AWS_MCP_CLAIM_LAUNCH_BINDING: 'true',
115
114
  },
116
115
  });
@@ -176,14 +175,13 @@ terminalRouter.post('/start', validateToken, async (req, res) => {
176
175
  workspacePath,
177
176
  command: actualCommand,
178
177
  mode: 'pty',
179
- mcpLaunchBindingId: queuedBinding?.id,
180
178
  });
181
179
  });
182
180
  /**
183
181
  * 启动 SDK 会话
184
182
  * 支持 MCP 配置和空闲命令
185
183
  */
186
- async function startSdkSession(req, res, mcpLaunchBindingId) {
184
+ async function startSdkSession(req, res) {
187
185
  const { agentId, workspacePath, command, autoAccept = true, initialPrompt,
188
186
  // MCP 配置 - 加载 aws-client-agent-mcp
189
187
  mcpConfigPath, extraMcpServers,
@@ -213,7 +211,6 @@ async function startSdkSession(req, res, mcpLaunchBindingId) {
213
211
  envOverrides: {
214
212
  AWS_AGENT_ID: String(agentId),
215
213
  AWS_WORKSPACE_PATH: String(workspacePath),
216
- AWS_MCP_LAUNCH_BINDING_ID: mcpLaunchBindingId || '',
217
214
  AWS_MCP_CLAIM_LAUNCH_BINDING: 'true',
218
215
  },
219
216
  };
@@ -56,15 +56,14 @@ describe('terminal configuration', () => {
56
56
  expect(getShellConfig('linux').shell).toBe('bash');
57
57
  });
58
58
  it('builds correct terminal environment', () => {
59
- const buildTerminalEnv = (agentId, bindingId, baseEnv) => ({
59
+ const buildTerminalEnv = (agentId, baseEnv) => ({
60
60
  ...baseEnv,
61
61
  AWS_AGENT_ID: agentId,
62
- AWS_MCP_LAUNCH_BINDING_ID: bindingId,
63
62
  AWS_MCP_CLAIM_LAUNCH_BINDING: 'true',
64
63
  });
65
- const env = buildTerminalEnv('agent-123', 'binding-456', { PATH: '/usr/bin' });
64
+ const env = buildTerminalEnv('agent-123', { PATH: '/usr/bin' });
66
65
  expect(env.AWS_AGENT_ID).toBe('agent-123');
67
- expect(env.AWS_MCP_LAUNCH_BINDING_ID).toBe('binding-456');
66
+ expect(env.AWS_MCP_LAUNCH_BINDING_ID).toBeUndefined();
68
67
  expect(env.AWS_MCP_CLAIM_LAUNCH_BINDING).toBe('true');
69
68
  });
70
69
  });
@@ -75,6 +75,12 @@ export declare function requestRuntimeAccessTokenRefresh(): Promise<{
75
75
  updated?: boolean;
76
76
  error?: string;
77
77
  }>;
78
+ export declare function requestRuntimeAccessTokenRefreshForServer(serverBaseUrl: string): Promise<{
79
+ success: boolean;
80
+ runtimeAccessToken?: string;
81
+ updated?: boolean;
82
+ error?: string;
83
+ }>;
78
84
  export declare function unregister(): Promise<boolean>;
79
85
  /**
80
86
  * 获取注册状态
@@ -1 +1 @@
1
- {"version":3,"file":"auto-register.d.ts","sourceRoot":"","sources":["../../src/services/auto-register.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+CH;;GAEG;AACH,UAAU,kBAAkB;IAC1B,eAAe;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwBD,wBAAgB,2BAA2B,IAAI,MAAM,EAAE,CAEtD;AA6DD;;GAEG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAGtD;AAyJD;;;;;;GAMG;AACH,wBAAgB,UAAU,IAAI,kBAAkB,CA2C/C;AAED,wBAAgB,WAAW,IAAI,kBAAkB,EAAE,CA0ClD;AA4OD;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,YAAY,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GACzC,OAAO,CAAC,OAAO,CAAC,CAalB;AAyHD;;GAEG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAqED;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAuBnD;AAED;;GAEG;AACH,wBAAgB,oBAAoB;gBAlzBtB,OAAO;iBACN,MAAM;mBACJ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;kBACvB,IAAI;YACV,MAAM;EAgzBf;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,GAAG,SAAS,CAElD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA2ED"}
1
+ {"version":3,"file":"auto-register.d.ts","sourceRoot":"","sources":["../../src/services/auto-register.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiDH;;GAEG;AACH,UAAU,kBAAkB;IAC1B,eAAe;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwBD,wBAAgB,2BAA2B,IAAI,MAAM,EAAE,CAEtD;AAiED;;GAEG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAGtD;AAyJD;;;;;;GAMG;AACH,wBAAgB,UAAU,IAAI,kBAAkB,CA2C/C;AAED,wBAAgB,WAAW,IAAI,kBAAkB,EAAE,CA0ClD;AA4OD;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,YAAY,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GACzC,OAAO,CAAC,OAAO,CAAC,CAalB;AAyHD;;GAEG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAqED;AAED,wBAAsB,yCAAyC,CAC7D,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA2ED;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAuBnD;AAED;;GAEG;AACH,wBAAgB,oBAAoB;gBA14BtB,OAAO;iBACN,MAAM;mBACJ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;kBACvB,IAAI;YACV,MAAM;EAw4Bf;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,GAAG,SAAS,CAElD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA2ED"}
@@ -13,7 +13,7 @@ import path from "node:path";
13
13
  import fs from "node:fs";
14
14
  import { logger } from "../utils/logger.js";
15
15
  import { schedulerBaseUrl, runtimeToken } from "../config.js";
16
- import { getRuntimeAccessToken, getRuntimeBindingPublicState, loadRuntimeBinding, saveRuntimeBinding, } from "./runtime-binding.js";
16
+ import { getRuntimeAccessToken, getRuntimeBindingPublicState, loadRuntimeBinding, normalizeSchedulerBaseUrl, saveRuntimeBinding, saveScopedRuntimeAccessToken, } from "./runtime-binding.js";
17
17
  // 默认配置
18
18
  const DEFAULT_CONFIG = {
19
19
  enabled: false,
@@ -37,6 +37,9 @@ function normalizeOptionalString(value) {
37
37
  const normalized = String(value).trim();
38
38
  return normalized || undefined;
39
39
  }
40
+ function normalizeSchedulerHttpBaseUrl(value) {
41
+ return normalizeSchedulerBaseUrl(value);
42
+ }
40
43
  function normalizeOptionalBoolean(value) {
41
44
  if (typeof value === "boolean") {
42
45
  return value;
@@ -649,6 +652,65 @@ export async function requestRuntimeAccessTokenRefresh() {
649
652
  return { success: false, error: message };
650
653
  }
651
654
  }
655
+ export async function requestRuntimeAccessTokenRefreshForServer(serverBaseUrl) {
656
+ const targetServerUrl = normalizeSchedulerHttpBaseUrl(serverBaseUrl);
657
+ if (!targetServerUrl) {
658
+ return { success: false, error: "serverUrl is required for runtime token refresh" };
659
+ }
660
+ const config = loadConfigs().find((item) => normalizeSchedulerHttpBaseUrl(item.serverUrl) === targetServerUrl) || loadPrimaryLifecycleConfig();
661
+ if (!config.userKey) {
662
+ return {
663
+ success: false,
664
+ error: "userKey is required for runtime token refresh",
665
+ };
666
+ }
667
+ const state = getRuntimeBindingPublicState();
668
+ const localIp = getLocalIpAddress(targetServerUrl);
669
+ const runtimeBridgePort = process.env.AWS_RUNTIME_BRIDGE_PORT || 18081;
670
+ const runtimeBridgeBaseUrl = `http://${config.registerIp || config.virtualIp || localIp}:${runtimeBridgePort}`;
671
+ try {
672
+ const response = await axios.post(`${targetServerUrl}/api/instances/runtime-tokens/refresh`, {
673
+ tenantId: config.tenantId,
674
+ userKey: config.userKey,
675
+ instanceId: state.instanceId,
676
+ instanceName: config.instanceName,
677
+ runtimeBridgeBaseUrl,
678
+ }, {
679
+ headers: {
680
+ "Content-Type": "application/json",
681
+ "X-Runtime-Token": runtimeToken,
682
+ },
683
+ timeout: 10000,
684
+ });
685
+ if (!response.data.success || !response.data.runtimeAccessToken) {
686
+ return {
687
+ success: false,
688
+ error: response.data.message ||
689
+ "scheduler did not return runtimeAccessToken",
690
+ };
691
+ }
692
+ const userId = response.data.userId || config.userKey;
693
+ const previousToken = getRuntimeAccessToken(userId, targetServerUrl);
694
+ const updated = previousToken !== response.data.runtimeAccessToken;
695
+ saveScopedRuntimeAccessToken({
696
+ userId,
697
+ serverBaseUrl: targetServerUrl,
698
+ accessToken: response.data.runtimeAccessToken,
699
+ });
700
+ return {
701
+ success: true,
702
+ runtimeAccessToken: response.data.runtimeAccessToken,
703
+ updated,
704
+ };
705
+ }
706
+ catch (error) {
707
+ const err = error;
708
+ const message = err.response?.data
709
+ ? JSON.stringify(err.response.data)
710
+ : err.message;
711
+ return { success: false, error: message };
712
+ }
713
+ }
652
714
  export async function unregister() {
653
715
  if (!registrationState.registered || !registrationState.instanceId) {
654
716
  logger.info("[AutoRegister] 实例未注册,无需注销");
@@ -1 +1 @@
1
- {"version":3,"file":"aws-client-agent-mcp.d.ts","sourceRoot":"","sources":["../../src/services/aws-client-agent-mcp.ts"],"names":[],"mappings":"AAqBA,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAuB7C,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,sCAAsC;IACrD,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IACvC,OAAO,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,sCAAsC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAaD,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;CAC3C;AAqBD,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AA0FD,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,sCAA2C,GACnD,MAAM,GAAG,IAAI,CAgDf;AA2ED,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,sCAA2C,GACnD,kBAAkB,CAEpB;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,GAAE,sCAA2C,GACnD,kBAAkB,CAsBpB;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,uBAAuB,GAC7B,kBAAkB,CAwBpB;AAED,wBAAgB,+BAA+B,IAAI,IAAI,CAgBtD"}
1
+ {"version":3,"file":"aws-client-agent-mcp.d.ts","sourceRoot":"","sources":["../../src/services/aws-client-agent-mcp.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAsB7C,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,sCAAsC;IACrD,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IACvC,OAAO,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,sCAAsC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAaD,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;CAC3C;AAuBD,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAgLD,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,sCAA2C,GACnD,MAAM,GAAG,IAAI,CAoDf;AA2ED,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,sCAA2C,GACnD,kBAAkB,CAEpB;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,GAAE,sCAA2C,GACnD,kBAAkB,CAsBpB;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,uBAAuB,GAC7B,kBAAkB,CA0BpB;AAED,wBAAgB,+BAA+B,IAAI,IAAI,CAgBtD"}
@@ -1,13 +1,12 @@
1
1
  import { createHash } from "node:crypto";
2
- import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from "node:fs";
2
+ import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, statSync, symlinkSync, writeFileSync, } from "node:fs";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { getRuntimeHomeDir, port, schedulerBaseUrl } from "../config.js";
6
6
  import { logger } from "../utils/logger.js";
7
- import { getRuntimeAccessToken, loadRuntimeBinding, } from "./runtime-binding.js";
7
+ import { getRuntimeAccessToken, loadRuntimeBinding, normalizeSchedulerBaseUrl, } from "./runtime-binding.js";
8
8
  export const AWS_MCP_SERVER_NAME = "aws-mcp";
9
9
  const AWS_MCP_ALLOWED_ENV_KEYS = [
10
- "AWS_INTERNAL_API_KEY",
11
10
  "AWS_PROJECT_NAME",
12
11
  "AWS_PROMPT",
13
12
  "AWS_ROLE_NAME",
@@ -32,7 +31,10 @@ function getPackageRoot() {
32
31
  return path.resolve(path.dirname(currentFile), "..", "..");
33
32
  }
34
33
  function getBundledEntryPath(packageRoot = getPackageRoot()) {
35
- return path.join(packageRoot, "package", "aws-client-agent-mcp", "dist", "index.js");
34
+ return path.join(getBundledMcpRoot(packageRoot), "dist", "index.js");
35
+ }
36
+ function getBundledMcpRoot(packageRoot) {
37
+ return path.join(packageRoot, "package", "aws-client-agent-mcp");
36
38
  }
37
39
  function getReleasedMcpRoot() {
38
40
  return path.join(getRuntimeHomeDir(), ".aws-bridge", "mcp");
@@ -56,7 +58,66 @@ function getBridgeVersion(packageRoot) {
56
58
  return readPackageVersion(path.join(packageRoot, "package.json"));
57
59
  }
58
60
  function getBundledMcpVersion(packageRoot) {
59
- return readPackageVersion(path.join(packageRoot, "package", "aws-client-agent-mcp", "package.json"));
61
+ return readPackageVersion(path.join(getBundledMcpRoot(packageRoot), "package.json"));
62
+ }
63
+ function copyIfExists(sourcePath, targetPath) {
64
+ if (!existsSync(sourcePath)) {
65
+ return;
66
+ }
67
+ copyFileOrDirectory(sourcePath, targetPath);
68
+ }
69
+ function copyFileOrDirectory(sourcePath, targetPath) {
70
+ const stat = statSync(sourcePath);
71
+ if (stat.isDirectory()) {
72
+ cpSync(sourcePath, targetPath, {
73
+ errorOnExist: false,
74
+ force: true,
75
+ recursive: true,
76
+ });
77
+ return;
78
+ }
79
+ cpSync(sourcePath, targetPath, { errorOnExist: false, force: true });
80
+ }
81
+ function syncReleasedPackageMetadata(packageRoot, releasedRoot) {
82
+ const bundledMcpRoot = getBundledMcpRoot(packageRoot);
83
+ copyIfExists(path.join(bundledMcpRoot, "package.json"), path.join(releasedRoot, "package.json"));
84
+ copyIfExists(path.join(bundledMcpRoot, "README.md"), path.join(releasedRoot, "README.md"));
85
+ copyIfExists(path.join(bundledMcpRoot, "package-lock.json"), path.join(releasedRoot, "package-lock.json"));
86
+ }
87
+ function shouldReplaceNodeModulesLink(targetPath) {
88
+ if (!existsSync(targetPath)) {
89
+ return true;
90
+ }
91
+ const stat = lstatSync(targetPath);
92
+ return stat.isSymbolicLink() || stat.isDirectory();
93
+ }
94
+ function isExpectedNodeModulesLink(targetPath, sourcePath) {
95
+ if (!existsSync(targetPath)) {
96
+ return false;
97
+ }
98
+ try {
99
+ return realpathSync(targetPath) === realpathSync(sourcePath);
100
+ }
101
+ catch {
102
+ return false;
103
+ }
104
+ }
105
+ function ensureReleasedNodeModules(packageRoot, releasedRoot) {
106
+ const sourceNodeModules = path.join(packageRoot, "node_modules");
107
+ const releasedNodeModules = path.join(releasedRoot, "node_modules");
108
+ if (!existsSync(sourceNodeModules)) {
109
+ logger.warn(`[runtime-bridge] ${AWS_MCP_SERVER_NAME} MCP 未找到依赖目录,release 产物可能无法解析运行时依赖: ${sourceNodeModules}`);
110
+ return;
111
+ }
112
+ if (isExpectedNodeModulesLink(releasedNodeModules, sourceNodeModules)) {
113
+ return;
114
+ }
115
+ if (!shouldReplaceNodeModulesLink(releasedNodeModules)) {
116
+ logger.warn(`[runtime-bridge] ${AWS_MCP_SERVER_NAME} MCP 依赖路径已存在但不是目录或链接,已保留: ${releasedNodeModules}`);
117
+ return;
118
+ }
119
+ rmSync(releasedNodeModules, { recursive: true, force: true });
120
+ symlinkSync(sourceNodeModules, releasedNodeModules, process.platform === "win32" ? "junction" : "dir");
60
121
  }
61
122
  function listDistFiles(dirPath, rootPath = dirPath) {
62
123
  return readdirSync(dirPath, { withFileTypes: true }).flatMap((entry) => {
@@ -128,6 +189,8 @@ export function releaseBundledAwsClientAgentMcp(options = {}) {
128
189
  if (shouldRefreshReleasedMcp(releasedEntry, currentManifest, nextManifest)) {
129
190
  rmSync(releasedDist, { recursive: true, force: true });
130
191
  mkdirSync(releasedRoot, { recursive: true });
192
+ syncReleasedPackageMetadata(packageRoot, releasedRoot);
193
+ ensureReleasedNodeModules(packageRoot, releasedRoot);
131
194
  cpSync(bundledDist, releasedDist, {
132
195
  errorOnExist: false,
133
196
  force: true,
@@ -140,6 +203,8 @@ export function releaseBundledAwsClientAgentMcp(options = {}) {
140
203
  logger.info(`[runtime-bridge] ${AWS_MCP_SERVER_NAME} MCP 已更新到: ${releasedDist}`);
141
204
  }
142
205
  else {
206
+ syncReleasedPackageMetadata(packageRoot, releasedRoot);
207
+ ensureReleasedNodeModules(packageRoot, releasedRoot);
143
208
  logger.info(`[runtime-bridge] ${AWS_MCP_SERVER_NAME} MCP 已是最新: ${releasedDist}`);
144
209
  }
145
210
  return releasedEntry;
@@ -170,7 +235,7 @@ function parseAwsClientAgentMcpArgs(raw) {
170
235
  return [];
171
236
  }
172
237
  function toWebSocketUrl(baseUrl) {
173
- const url = new URL("/ws/agent", baseUrl);
238
+ const url = new URL("/ws/agent", normalizeSchedulerBaseUrl(baseUrl) || baseUrl);
174
239
  if (url.protocol === "https:") {
175
240
  url.protocol = "wss:";
176
241
  }
@@ -180,7 +245,7 @@ function toWebSocketUrl(baseUrl) {
180
245
  return url.toString();
181
246
  }
182
247
  function toMcpHttpUrl(baseUrl) {
183
- return new URL("/mcp/call", baseUrl).toString();
248
+ return new URL("/mcp/call", normalizeSchedulerBaseUrl(baseUrl) || baseUrl).toString();
184
249
  }
185
250
  function resolveSchedulerBaseUrlForMcp() {
186
251
  const envSchedulerBaseUrl = String(process.env.AWS_RUNTIME_SCHEDULER_BASE_URL || "").trim();
@@ -231,6 +296,7 @@ export function buildAwsMcpServerConfig(input) {
231
296
  AWS_SERVER_URL: env.AWS_SERVER_URL || toWebSocketUrl(effectiveSchedulerBaseUrl),
232
297
  AWS_MCP_HTTP_URL: env.AWS_MCP_HTTP_URL || toMcpHttpUrl(effectiveSchedulerBaseUrl),
233
298
  AWS_RUNTIME_BRIDGE_BASE_URL: env.AWS_RUNTIME_BRIDGE_BASE_URL || `http://127.0.0.1:${port}`,
299
+ AWS_MCP_CLAIM_LAUNCH_BINDING: env.AWS_MCP_CLAIM_LAUNCH_BINDING || "true",
234
300
  ...(issuedRuntimeAccessToken
235
301
  ? { AWS_RUNTIME_ACCESS_TOKEN: issuedRuntimeAccessToken }
236
302
  : {}),
@@ -1,4 +1,5 @@
1
- import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
1
+ import { spawnSync } from 'node:child_process';
2
+ import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readlinkSync, realpathSync, rmSync, writeFileSync, } from 'node:fs';
2
3
  import os from 'node:os';
3
4
  import path from 'node:path';
4
5
  import { afterEach, describe, expect, it, vi } from 'vitest';
@@ -13,7 +14,31 @@ function createBundledMcpPackage(version = '1.0.0') {
13
14
  const bundledDist = path.join(packageRoot, 'package', 'aws-client-agent-mcp', 'dist');
14
15
  mkdirSync(bundledDist, { recursive: true });
15
16
  writeFileSync(path.join(packageRoot, 'package.json'), JSON.stringify({ name: 'aws-runtime-bridge', version: '9.9.9' }), 'utf-8');
16
- writeFileSync(path.join(packageRoot, 'package', 'aws-client-agent-mcp', 'package.json'), JSON.stringify({ name: 'aws-client-agent-mcp', version }), 'utf-8');
17
+ writeFileSync(path.join(packageRoot, 'package', 'aws-client-agent-mcp', 'package.json'), JSON.stringify({
18
+ name: 'aws-client-agent-mcp',
19
+ version,
20
+ type: 'module',
21
+ main: 'dist/index.js',
22
+ dependencies: {
23
+ '@modelcontextprotocol/sdk': '^1.27.1',
24
+ ws: '^8.14.2',
25
+ yaml: '^2.3.4',
26
+ },
27
+ }), 'utf-8');
28
+ writeFileSync(path.join(packageRoot, 'package', 'aws-client-agent-mcp', 'README.md'), '# aws-client-agent-mcp\n', 'utf-8');
29
+ mkdirSync(path.join(packageRoot, 'node_modules', '@modelcontextprotocol', 'sdk'), {
30
+ recursive: true,
31
+ });
32
+ writeFileSync(path.join(packageRoot, 'node_modules', '@modelcontextprotocol', 'sdk', 'package.json'), JSON.stringify({
33
+ name: '@modelcontextprotocol/sdk',
34
+ version: '1.27.1',
35
+ type: 'module',
36
+ main: 'index.js',
37
+ exports: './index.js',
38
+ }), 'utf-8');
39
+ writeFileSync(path.join(packageRoot, 'node_modules', '@modelcontextprotocol', 'sdk', 'index.js'), 'export const sdkMarker = "resolved-sdk";\n', 'utf-8');
40
+ mkdirSync(path.join(packageRoot, 'node_modules', 'ws'), { recursive: true });
41
+ mkdirSync(path.join(packageRoot, 'node_modules', 'yaml'), { recursive: true });
17
42
  writeFileSync(path.join(bundledDist, 'index.js'), 'console.log("mcp v1");\n', 'utf-8');
18
43
  return packageRoot;
19
44
  }
@@ -56,8 +81,21 @@ describe('aws-client-agent-mcp service', () => {
56
81
  });
57
82
  const releasedIndex = path.join(releasedRoot, 'dist', 'index.js');
58
83
  const manifestPath = path.join(releasedRoot, '.release.json');
84
+ const releasedPackageJson = path.join(releasedRoot, 'package.json');
85
+ const releasedNodeModules = path.join(releasedRoot, 'node_modules');
59
86
  expect(firstRelease).toBe(releasedIndex);
60
87
  expect(existsSync(releasedIndex)).toBe(true);
88
+ expect(JSON.parse(readFileSync(releasedPackageJson, 'utf-8'))).toMatchObject({
89
+ name: 'aws-client-agent-mcp',
90
+ version: '1.0.0',
91
+ dependencies: {
92
+ '@modelcontextprotocol/sdk': '^1.27.1',
93
+ },
94
+ });
95
+ expect(readFileSync(path.join(releasedRoot, 'README.md'), 'utf-8')).toBe('# aws-client-agent-mcp\n');
96
+ expect(lstatSync(releasedNodeModules).isSymbolicLink()).toBe(true);
97
+ expect(realpathSync(releasedNodeModules)).toBe(realpathSync(path.join(packageRoot, 'node_modules')));
98
+ expect(path.resolve(readlinkSync(releasedNodeModules))).toBe(path.join(packageRoot, 'node_modules'));
61
99
  const firstManifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
62
100
  expect(firstManifest).toMatchObject({
63
101
  bridgeVersion: '9.9.9',
@@ -66,12 +104,15 @@ describe('aws-client-agent-mcp service', () => {
66
104
  });
67
105
  expect(firstManifest.distHash).toMatch(/^sha256:/);
68
106
  writeFileSync(releasedIndex, 'console.log("local marker");\n', 'utf-8');
107
+ rmSync(releasedNodeModules, { recursive: true, force: true });
108
+ mkdirSync(releasedNodeModules, { recursive: true });
69
109
  mod.releaseBundledAwsClientAgentMcp({
70
110
  packageRoot,
71
111
  releasedRoot,
72
112
  now: () => '2026-05-05T00:00:00.000Z',
73
113
  });
74
114
  expect(readFileSync(releasedIndex, 'utf-8')).toBe('console.log("local marker");\n');
115
+ expect(realpathSync(releasedNodeModules)).toBe(realpathSync(path.join(packageRoot, 'node_modules')));
75
116
  expect(JSON.parse(readFileSync(manifestPath, 'utf-8')).releasedAt).toBe('2026-05-04T00:00:00.000Z');
76
117
  }
77
118
  finally {
@@ -102,6 +143,32 @@ describe('aws-client-agent-mcp service', () => {
102
143
  rmSync(releasedRoot, { recursive: true, force: true });
103
144
  }
104
145
  });
146
+ it('releases a runnable package root that resolves bundled mcp runtime dependencies', async () => {
147
+ process.env.AWS_CLIENT_AGENT_MCP_COMMAND = '';
148
+ const packageRoot = createBundledMcpPackage('1.0.0');
149
+ const releasedRoot = mkdtempSync(path.join(os.tmpdir(), 'aws-mcp-release-'));
150
+ try {
151
+ const bundledIndex = path.join(packageRoot, 'package', 'aws-client-agent-mcp', 'dist', 'index.js');
152
+ writeFileSync(bundledIndex, 'import { sdkMarker } from "@modelcontextprotocol/sdk";\nconsole.log(sdkMarker);\n', 'utf-8');
153
+ const mod = await import('./aws-client-agent-mcp.js');
154
+ const releasedEntry = mod.releaseBundledAwsClientAgentMcp({ packageRoot, releasedRoot });
155
+ expect(releasedEntry).toBe(path.join(releasedRoot, 'dist', 'index.js'));
156
+ if (!releasedEntry) {
157
+ throw new Error('Expected bundled MCP release entry to exist');
158
+ }
159
+ const result = spawnSync(process.execPath, [releasedEntry], {
160
+ cwd: releasedRoot,
161
+ encoding: 'utf-8',
162
+ });
163
+ expect(result.stderr).toBe('');
164
+ expect(result.status).toBe(0);
165
+ expect(result.stdout.trim()).toBe('resolved-sdk');
166
+ }
167
+ finally {
168
+ rmSync(packageRoot, { recursive: true, force: true });
169
+ rmSync(releasedRoot, { recursive: true, force: true });
170
+ }
171
+ });
105
172
  it('releases bundled mcp into home directory when runtime dist is missing', async () => {
106
173
  process.env.AWS_CLIENT_AGENT_MCP_COMMAND = '';
107
174
  const mod = await import('./aws-client-agent-mcp.js');
@@ -149,6 +216,20 @@ describe('aws-client-agent-mcp service', () => {
149
216
  expect(config.env.AWS_RUNTIME_CALLBACK_TOKEN).toBeUndefined();
150
217
  expect(config.env.CUSTOM_SECRET).toBeUndefined();
151
218
  });
219
+ it('repairs duplicated scheduler ports when building MCP URLs', async () => {
220
+ process.env.AWS_CLIENT_AGENT_MCP_COMMAND = 'aws-client-agent-mcp';
221
+ process.env.AWS_RUNTIME_HOME_DIR = mkdtempSync(path.join(os.tmpdir(), 'aws-mcp-config-'));
222
+ process.env.AWS_RUNTIME_SCHEDULER_BASE_URL = 'http://127.0.0.1:8080:8080';
223
+ process.env.AWS_SERVER_URL = '';
224
+ process.env.AWS_MCP_HTTP_URL = '';
225
+ const mod = await import('./aws-client-agent-mcp.js');
226
+ const config = mod.buildAwsMcpServerConfig({
227
+ agentId: 'agent-1',
228
+ workspacePath: '/workspace/demo',
229
+ });
230
+ expect(config.env.AWS_SERVER_URL).toBe('ws://127.0.0.1:8080/ws/agent');
231
+ expect(config.env.AWS_MCP_HTTP_URL).toBe('http://127.0.0.1:8080/mcp/call');
232
+ });
152
233
  it('ignores malformed AWS_CLIENT_AGENT_MCP_ARGS JSON', async () => {
153
234
  process.env.AWS_CLIENT_AGENT_MCP_COMMAND = 'custom-aws-client-agent-mcp';
154
235
  process.env.AWS_CLIENT_AGENT_MCP_ARGS = '{bad json';
@@ -24,8 +24,6 @@ export interface ClaimedMcpLaunchBinding extends McpLaunchBinding {
24
24
  schedulerBaseUrl?: string;
25
25
  }
26
26
  export interface McpLaunchBindingClaimRequest {
27
- agentId: unknown;
28
- bindingId?: unknown;
29
27
  workspacePath: unknown;
30
28
  serverUrl?: unknown;
31
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-launch-binding-queue.d.ts","sourceRoot":"","sources":["../../src/services/mcp-launch-binding-queue.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAqCD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,GAAG,IAAI,CAoB7F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,uBAAuB,GAAG,IAAI,CAoC3G;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,OAAO,GAAG,MAAM,CAMpE;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
1
+ {"version":3,"file":"mcp-launch-binding-queue.d.ts","sourceRoot":"","sources":["../../src/services/mcp-launch-binding-queue.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,4BAA4B;IAC3C,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAmDD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,GAAG,IAAI,CA+B7F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,uBAAuB,GAAG,IAAI,CA0C3G;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,OAAO,GAAG,MAAM,CAOpE;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
@@ -1,5 +1,7 @@
1
1
  import path from "node:path";
2
- import { getRuntimeAccessToken, loadRuntimeBinding } from "./runtime-binding.js";
2
+ import { schedulerBaseUrl as defaultSchedulerBaseUrl } from "../config.js";
3
+ import { getRuntimeAccessToken, loadRuntimeBinding, normalizeSchedulerBaseUrl } from "./runtime-binding.js";
4
+ const LAUNCH_BINDING_TTL_MS = 5 * 60 * 1000;
3
5
  const launchBindings = [];
4
6
  function normalizeWorkspacePath(workspacePath) {
5
7
  const raw = String(workspacePath || "").trim();
@@ -11,57 +13,82 @@ function normalizeWorkspacePath(workspacePath) {
11
13
  function normalizeOptionalUrl(value) {
12
14
  return String(value || "").trim();
13
15
  }
14
- function normalizeServerUrl(serverUrl) {
15
- const raw = String(serverUrl || "").trim();
16
+ function normalizeSchedulerOrigin(serverUrl) {
17
+ const raw = normalizeSchedulerBaseUrl(serverUrl) || String(serverUrl || "").trim();
16
18
  if (!raw) {
17
19
  return "";
18
20
  }
19
21
  try {
20
22
  const url = new URL(raw);
21
- url.protocol = url.protocol.toLowerCase();
23
+ if (url.protocol === "ws:") {
24
+ url.protocol = "http:";
25
+ }
26
+ else if (url.protocol === "wss:") {
27
+ url.protocol = "https:";
28
+ }
29
+ else {
30
+ url.protocol = url.protocol.toLowerCase();
31
+ }
22
32
  url.hostname = url.hostname.toLowerCase();
23
- url.pathname = url.pathname.replace(/\/+$/, "");
24
- return url.toString().replace(/\/+$/, "");
33
+ return url.origin;
25
34
  }
26
35
  catch {
27
36
  return raw.replace(/\/+$/, "").toLowerCase();
28
37
  }
29
38
  }
39
+ function pruneExpiredBindings(now = Date.now()) {
40
+ for (let index = launchBindings.length - 1; index >= 0; index -= 1) {
41
+ const enqueuedAt = Date.parse(launchBindings[index]?.enqueuedAt || "");
42
+ if (!Number.isFinite(enqueuedAt) || now - enqueuedAt > LAUNCH_BINDING_TTL_MS) {
43
+ launchBindings.splice(index, 1);
44
+ }
45
+ }
46
+ }
30
47
  function createBindingId(agentId) {
31
48
  return `${agentId}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
32
49
  }
33
50
  export function enqueueMcpLaunchBinding(input) {
51
+ pruneExpiredBindings();
34
52
  const agentId = String(input.agentId || "").trim();
35
53
  const workspaceKey = normalizeWorkspacePath(input.workspacePath);
36
54
  if (!agentId || !workspaceKey) {
37
55
  return null;
38
56
  }
57
+ const runtimeState = loadRuntimeBinding();
58
+ const schedulerUrl = normalizeSchedulerBaseUrl(input.serverUrl || input.schedulerBaseUrl || runtimeState.schedulerBaseUrl || defaultSchedulerBaseUrl) || normalizeOptionalUrl(input.serverUrl || input.schedulerBaseUrl || runtimeState.schedulerBaseUrl || defaultSchedulerBaseUrl);
59
+ const schedulerBindingBaseUrl = normalizeSchedulerBaseUrl(input.schedulerBaseUrl || runtimeState.schedulerBaseUrl || defaultSchedulerBaseUrl) || normalizeOptionalUrl(input.schedulerBaseUrl || runtimeState.schedulerBaseUrl || defaultSchedulerBaseUrl);
39
60
  const binding = {
40
61
  id: createBindingId(agentId),
41
62
  agentId,
42
63
  workspacePath: path.resolve(String(input.workspacePath)),
43
- serverUrl: normalizeOptionalUrl(input.serverUrl || input.schedulerBaseUrl),
64
+ serverUrl: schedulerUrl,
44
65
  mcpHttpUrl: normalizeOptionalUrl(input.mcpHttpUrl),
45
66
  runtimeAccessToken: normalizeOptionalUrl(input.runtimeAccessToken),
46
67
  userId: normalizeOptionalUrl(input.userId),
47
- schedulerBaseUrl: normalizeOptionalUrl(input.schedulerBaseUrl),
68
+ schedulerBaseUrl: schedulerBindingBaseUrl,
48
69
  enqueuedAt: new Date().toISOString(),
49
70
  };
50
71
  launchBindings.push(binding);
51
72
  return binding;
52
73
  }
53
74
  export function claimMcpLaunchBinding(request) {
54
- const agentId = String(request.agentId || "").trim();
55
- const bindingId = String(request.bindingId || "").trim();
75
+ pruneExpiredBindings();
56
76
  const workspaceKey = normalizeWorkspacePath(request.workspacePath);
57
- const serverKey = normalizeServerUrl(request.serverUrl);
58
- if (!agentId || !bindingId || !workspaceKey || !serverKey) {
77
+ const serverKey = normalizeSchedulerOrigin(request.serverUrl);
78
+ if (!workspaceKey) {
59
79
  return null;
60
80
  }
61
- const bindingIndex = launchBindings.findIndex((binding) => binding.agentId === agentId &&
62
- binding.id === bindingId &&
63
- normalizeWorkspacePath(binding.workspacePath) === workspaceKey &&
64
- normalizeServerUrl(binding.serverUrl || binding.schedulerBaseUrl) === serverKey);
81
+ let bindingIndex = launchBindings.findIndex((binding) => normalizeWorkspacePath(binding.workspacePath) === workspaceKey &&
82
+ serverKey &&
83
+ normalizeSchedulerOrigin(binding.serverUrl || binding.schedulerBaseUrl) === serverKey);
84
+ if (bindingIndex < 0) {
85
+ const workspaceMatches = launchBindings
86
+ .map((binding, index) => ({ binding, index }))
87
+ .filter(({ binding }) => normalizeWorkspacePath(binding.workspacePath) === workspaceKey);
88
+ if (workspaceMatches.length === 1) {
89
+ bindingIndex = workspaceMatches[0]?.index ?? -1;
90
+ }
91
+ }
65
92
  if (bindingIndex < 0) {
66
93
  return null;
67
94
  }
@@ -81,6 +108,7 @@ export function claimMcpLaunchBinding(request) {
81
108
  };
82
109
  }
83
110
  export function getMcpLaunchQueueSize(workspacePath) {
111
+ pruneExpiredBindings();
84
112
  const workspaceKey = normalizeWorkspacePath(workspacePath);
85
113
  if (!workspaceKey) {
86
114
  return 0;