@local-labs-jpollock/local-cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/addon-dist/bin/mcp-stdio.js +2808 -0
  2. package/addon-dist/lib/common/constants.d.ts +22 -0
  3. package/addon-dist/lib/common/constants.js +26 -0
  4. package/addon-dist/lib/common/theme.d.ts +68 -0
  5. package/addon-dist/lib/common/theme.js +126 -0
  6. package/addon-dist/lib/common/types.d.ts +298 -0
  7. package/addon-dist/lib/common/types.js +6 -0
  8. package/addon-dist/lib/main/config/ConnectionInfo.d.ts +25 -0
  9. package/addon-dist/lib/main/config/ConnectionInfo.js +82 -0
  10. package/addon-dist/lib/main/index.d.ts +12 -0
  11. package/addon-dist/lib/main/index.js +3322 -0
  12. package/addon-dist/lib/main/mcp/McpAuth.d.ts +37 -0
  13. package/addon-dist/lib/main/mcp/McpAuth.js +87 -0
  14. package/addon-dist/lib/main/mcp/McpServer.d.ts +67 -0
  15. package/addon-dist/lib/main/mcp/McpServer.js +343 -0
  16. package/addon-dist/lib/main/mcp/tools/changePhpVersion.d.ts +7 -0
  17. package/addon-dist/lib/main/mcp/tools/changePhpVersion.js +81 -0
  18. package/addon-dist/lib/main/mcp/tools/cloneSite.d.ts +7 -0
  19. package/addon-dist/lib/main/mcp/tools/cloneSite.js +66 -0
  20. package/addon-dist/lib/main/mcp/tools/createSite.d.ts +7 -0
  21. package/addon-dist/lib/main/mcp/tools/createSite.js +137 -0
  22. package/addon-dist/lib/main/mcp/tools/deleteSite.d.ts +7 -0
  23. package/addon-dist/lib/main/mcp/tools/deleteSite.js +72 -0
  24. package/addon-dist/lib/main/mcp/tools/exportDatabase.d.ts +7 -0
  25. package/addon-dist/lib/main/mcp/tools/exportDatabase.js +72 -0
  26. package/addon-dist/lib/main/mcp/tools/exportSite.d.ts +7 -0
  27. package/addon-dist/lib/main/mcp/tools/exportSite.js +103 -0
  28. package/addon-dist/lib/main/mcp/tools/getLocalInfo.d.ts +7 -0
  29. package/addon-dist/lib/main/mcp/tools/getLocalInfo.js +72 -0
  30. package/addon-dist/lib/main/mcp/tools/getSite.d.ts +7 -0
  31. package/addon-dist/lib/main/mcp/tools/getSite.js +68 -0
  32. package/addon-dist/lib/main/mcp/tools/getSiteLogs.d.ts +7 -0
  33. package/addon-dist/lib/main/mcp/tools/getSiteLogs.js +149 -0
  34. package/addon-dist/lib/main/mcp/tools/helpers.d.ts +59 -0
  35. package/addon-dist/lib/main/mcp/tools/helpers.js +179 -0
  36. package/addon-dist/lib/main/mcp/tools/importDatabase.d.ts +7 -0
  37. package/addon-dist/lib/main/mcp/tools/importDatabase.js +109 -0
  38. package/addon-dist/lib/main/mcp/tools/importSite.d.ts +7 -0
  39. package/addon-dist/lib/main/mcp/tools/importSite.js +149 -0
  40. package/addon-dist/lib/main/mcp/tools/index.d.ts +26 -0
  41. package/addon-dist/lib/main/mcp/tools/index.js +117 -0
  42. package/addon-dist/lib/main/mcp/tools/listBlueprints.d.ts +7 -0
  43. package/addon-dist/lib/main/mcp/tools/listBlueprints.js +54 -0
  44. package/addon-dist/lib/main/mcp/tools/listServices.d.ts +7 -0
  45. package/addon-dist/lib/main/mcp/tools/listServices.js +112 -0
  46. package/addon-dist/lib/main/mcp/tools/listSites.d.ts +7 -0
  47. package/addon-dist/lib/main/mcp/tools/listSites.js +62 -0
  48. package/addon-dist/lib/main/mcp/tools/openAdminer.d.ts +7 -0
  49. package/addon-dist/lib/main/mcp/tools/openAdminer.js +59 -0
  50. package/addon-dist/lib/main/mcp/tools/openSite.d.ts +7 -0
  51. package/addon-dist/lib/main/mcp/tools/openSite.js +62 -0
  52. package/addon-dist/lib/main/mcp/tools/renameSite.d.ts +7 -0
  53. package/addon-dist/lib/main/mcp/tools/renameSite.js +70 -0
  54. package/addon-dist/lib/main/mcp/tools/restartSite.d.ts +7 -0
  55. package/addon-dist/lib/main/mcp/tools/restartSite.js +56 -0
  56. package/addon-dist/lib/main/mcp/tools/saveBlueprint.d.ts +7 -0
  57. package/addon-dist/lib/main/mcp/tools/saveBlueprint.js +89 -0
  58. package/addon-dist/lib/main/mcp/tools/startSite.d.ts +7 -0
  59. package/addon-dist/lib/main/mcp/tools/startSite.js +54 -0
  60. package/addon-dist/lib/main/mcp/tools/stopSite.d.ts +7 -0
  61. package/addon-dist/lib/main/mcp/tools/stopSite.js +54 -0
  62. package/addon-dist/lib/main/mcp/tools/toggleXdebug.d.ts +7 -0
  63. package/addon-dist/lib/main/mcp/tools/toggleXdebug.js +69 -0
  64. package/addon-dist/lib/main/mcp/tools/trustSsl.d.ts +7 -0
  65. package/addon-dist/lib/main/mcp/tools/trustSsl.js +59 -0
  66. package/addon-dist/lib/main/mcp/tools/wpCli.d.ts +7 -0
  67. package/addon-dist/lib/main/mcp/tools/wpCli.js +110 -0
  68. package/addon-dist/lib/main.d.ts +1 -0
  69. package/addon-dist/lib/main.js +10 -0
  70. package/addon-dist/lib/renderer/index.d.ts +7 -0
  71. package/addon-dist/lib/renderer/index.js +479 -0
  72. package/addon-dist/package.json +73 -0
  73. package/bin/lwp.js +10 -0
  74. package/lib/bootstrap/index.d.ts +98 -0
  75. package/lib/bootstrap/index.js +493 -0
  76. package/lib/bootstrap/paths.d.ts +28 -0
  77. package/lib/bootstrap/paths.js +96 -0
  78. package/lib/client/GraphQLClient.d.ts +38 -0
  79. package/lib/client/GraphQLClient.js +71 -0
  80. package/lib/client/index.d.ts +4 -0
  81. package/lib/client/index.js +10 -0
  82. package/lib/formatters/index.d.ts +75 -0
  83. package/lib/formatters/index.js +139 -0
  84. package/lib/index.d.ts +8 -0
  85. package/lib/index.js +1173 -0
  86. package/package.json +72 -0
@@ -0,0 +1,37 @@
1
+ /**
2
+ * MCP Authentication Manager
3
+ * Handles token generation and validation
4
+ */
5
+ export declare class McpAuth {
6
+ private token;
7
+ private logger;
8
+ constructor(logger: any);
9
+ /**
10
+ * Generate a new authentication token
11
+ */
12
+ generateToken(): string;
13
+ /**
14
+ * Get current token or generate if not exists
15
+ */
16
+ getToken(): string;
17
+ /**
18
+ * Set token (for loading from saved config)
19
+ */
20
+ setToken(token: string): void;
21
+ /**
22
+ * Regenerate the authentication token
23
+ */
24
+ regenerateToken(): string;
25
+ /**
26
+ * Validate provided token against stored token
27
+ */
28
+ validateToken(providedToken: string | undefined): boolean;
29
+ /**
30
+ * Validate that request comes from trusted IP
31
+ */
32
+ validateIP(ip: string | undefined): boolean;
33
+ /**
34
+ * Extract Bearer token from Authorization header
35
+ */
36
+ extractBearerToken(authHeader: string | undefined): string | undefined;
37
+ }
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ /**
3
+ * MCP Authentication Manager
4
+ * Handles token generation and validation
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.McpAuth = void 0;
11
+ const crypto_1 = __importDefault(require("crypto"));
12
+ const constants_1 = require("../../common/constants");
13
+ class McpAuth {
14
+ constructor(logger) {
15
+ this.token = null;
16
+ this.logger = logger;
17
+ }
18
+ /**
19
+ * Generate a new authentication token
20
+ */
21
+ generateToken() {
22
+ this.token = crypto_1.default.randomBytes(constants_1.AUTH_TOKEN_LENGTH / 2).toString('base64');
23
+ this.logger.info(`[MCP] Generated new authentication token: ${this.token.substring(0, 20)}...`);
24
+ return this.token;
25
+ }
26
+ /**
27
+ * Get current token or generate if not exists
28
+ */
29
+ getToken() {
30
+ if (!this.token) {
31
+ return this.generateToken();
32
+ }
33
+ return this.token;
34
+ }
35
+ /**
36
+ * Set token (for loading from saved config)
37
+ */
38
+ setToken(token) {
39
+ this.token = token;
40
+ }
41
+ /**
42
+ * Regenerate the authentication token
43
+ */
44
+ regenerateToken() {
45
+ this.logger.info('[MCP] Regenerating authentication token');
46
+ return this.generateToken();
47
+ }
48
+ /**
49
+ * Validate provided token against stored token
50
+ */
51
+ validateToken(providedToken) {
52
+ if (!this.token || !providedToken) {
53
+ this.logger.warn(`[MCP Auth] Validation failed: token=${!!this.token}, provided=${!!providedToken}`);
54
+ return false;
55
+ }
56
+ // Support both raw token and Bearer prefix
57
+ const rawToken = providedToken.startsWith('Bearer ') ? providedToken.slice(7) : providedToken;
58
+ const isValid = rawToken === this.token;
59
+ if (!isValid) {
60
+ this.logger.warn(`[MCP Auth] Token mismatch: provided=${rawToken.substring(0, 20)}... stored=${this.token.substring(0, 20)}...`);
61
+ }
62
+ return isValid;
63
+ }
64
+ /**
65
+ * Validate that request comes from trusted IP
66
+ */
67
+ validateIP(ip) {
68
+ if (!ip) {
69
+ return false;
70
+ }
71
+ return constants_1.TRUSTED_IPS.includes(ip);
72
+ }
73
+ /**
74
+ * Extract Bearer token from Authorization header
75
+ */
76
+ extractBearerToken(authHeader) {
77
+ if (!authHeader) {
78
+ return undefined;
79
+ }
80
+ if (authHeader.startsWith('Bearer ')) {
81
+ return authHeader.slice(7);
82
+ }
83
+ return authHeader;
84
+ }
85
+ }
86
+ exports.McpAuth = McpAuth;
87
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWNwQXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tYWluL21jcC9NY3BBdXRoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O0dBR0c7Ozs7OztBQUVILG9EQUE0QjtBQUM1QixzREFBd0U7QUFFeEUsTUFBYSxPQUFPO0lBSWxCLFlBQVksTUFBVztRQUhmLFVBQUssR0FBa0IsSUFBSSxDQUFDO1FBSWxDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7T0FFRztJQUNILGFBQWE7UUFDWCxJQUFJLENBQUMsS0FBSyxHQUFHLGdCQUFNLENBQUMsV0FBVyxDQUFDLDZCQUFpQixHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUMxRSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyw2Q0FBNkMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNoRyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsUUFBUTtRQUNOLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDaEIsT0FBTyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDOUIsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQztJQUNwQixDQUFDO0lBRUQ7O09BRUc7SUFDSCxRQUFRLENBQUMsS0FBYTtRQUNwQixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztJQUNyQixDQUFDO0lBRUQ7O09BRUc7SUFDSCxlQUFlO1FBQ2IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMseUNBQXlDLENBQUMsQ0FBQztRQUM1RCxPQUFPLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUM5QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxhQUFhLENBQUMsYUFBaUM7UUFDN0MsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNsQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDZCx1Q0FBdUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLGNBQWMsQ0FBQyxDQUFDLGFBQWEsRUFBRSxDQUNuRixDQUFDO1lBQ0YsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBRUQsMkNBQTJDO1FBQzNDLE1BQU0sUUFBUSxHQUFHLGFBQWEsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQztRQUU5RixNQUFNLE9BQU8sR0FBRyxRQUFRLEtBQUssSUFBSSxDQUFDLEtBQUssQ0FBQztRQUN4QyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDYixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDZCx1Q0FBdUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLGNBQWMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQy9HLENBQUM7UUFDSixDQUFDO1FBQ0QsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsVUFBVSxDQUFDLEVBQXNCO1FBQy9CLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNSLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztRQUNELE9BQVEsdUJBQWlDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRDs7T0FFRztJQUNILGtCQUFrQixDQUFDLFVBQThCO1FBQy9DLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUNoQixPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDO1FBRUQsSUFBSSxVQUFVLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDckMsT0FBTyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdCLENBQUM7UUFFRCxPQUFPLFVBQVUsQ0FBQztJQUNwQixDQUFDO0NBQ0Y7QUF6RkQsMEJBeUZDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNQ1AgQXV0aGVudGljYXRpb24gTWFuYWdlclxuICogSGFuZGxlcyB0b2tlbiBnZW5lcmF0aW9uIGFuZCB2YWxpZGF0aW9uXG4gKi9cblxuaW1wb3J0IGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgQVVUSF9UT0tFTl9MRU5HVEgsIFRSVVNURURfSVBTIH0gZnJvbSAnLi4vLi4vY29tbW9uL2NvbnN0YW50cyc7XG5cbmV4cG9ydCBjbGFzcyBNY3BBdXRoIHtcbiAgcHJpdmF0ZSB0b2tlbjogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbG9nZ2VyOiBhbnk7XG5cbiAgY29uc3RydWN0b3IobG9nZ2VyOiBhbnkpIHtcbiAgICB0aGlzLmxvZ2dlciA9IGxvZ2dlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBhIG5ldyBhdXRoZW50aWNhdGlvbiB0b2tlblxuICAgKi9cbiAgZ2VuZXJhdGVUb2tlbigpOiBzdHJpbmcge1xuICAgIHRoaXMudG9rZW4gPSBjcnlwdG8ucmFuZG9tQnl0ZXMoQVVUSF9UT0tFTl9MRU5HVEggLyAyKS50b1N0cmluZygnYmFzZTY0Jyk7XG4gICAgdGhpcy5sb2dnZXIuaW5mbyhgW01DUF0gR2VuZXJhdGVkIG5ldyBhdXRoZW50aWNhdGlvbiB0b2tlbjogJHt0aGlzLnRva2VuLnN1YnN0cmluZygwLCAyMCl9Li4uYCk7XG4gICAgcmV0dXJuIHRoaXMudG9rZW47XG4gIH1cblxuICAvKipcbiAgICogR2V0IGN1cnJlbnQgdG9rZW4gb3IgZ2VuZXJhdGUgaWYgbm90IGV4aXN0c1xuICAgKi9cbiAgZ2V0VG9rZW4oKTogc3RyaW5nIHtcbiAgICBpZiAoIXRoaXMudG9rZW4pIHtcbiAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlVG9rZW4oKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMudG9rZW47XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRva2VuIChmb3IgbG9hZGluZyBmcm9tIHNhdmVkIGNvbmZpZylcbiAgICovXG4gIHNldFRva2VuKHRva2VuOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLnRva2VuID0gdG9rZW47XG4gIH1cblxuICAvKipcbiAgICogUmVnZW5lcmF0ZSB0aGUgYXV0aGVudGljYXRpb24gdG9rZW5cbiAgICovXG4gIHJlZ2VuZXJhdGVUb2tlbigpOiBzdHJpbmcge1xuICAgIHRoaXMubG9nZ2VyLmluZm8oJ1tNQ1BdIFJlZ2VuZXJhdGluZyBhdXRoZW50aWNhdGlvbiB0b2tlbicpO1xuICAgIHJldHVybiB0aGlzLmdlbmVyYXRlVG9rZW4oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBwcm92aWRlZCB0b2tlbiBhZ2FpbnN0IHN0b3JlZCB0b2tlblxuICAgKi9cbiAgdmFsaWRhdGVUb2tlbihwcm92aWRlZFRva2VuOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgICBpZiAoIXRoaXMudG9rZW4gfHwgIXByb3ZpZGVkVG9rZW4pIHtcbiAgICAgIHRoaXMubG9nZ2VyLndhcm4oXG4gICAgICAgIGBbTUNQIEF1dGhdIFZhbGlkYXRpb24gZmFpbGVkOiB0b2tlbj0keyEhdGhpcy50b2tlbn0sIHByb3ZpZGVkPSR7ISFwcm92aWRlZFRva2VufWBcbiAgICAgICk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gU3VwcG9ydCBib3RoIHJhdyB0b2tlbiBhbmQgQmVhcmVyIHByZWZpeFxuICAgIGNvbnN0IHJhd1Rva2VuID0gcHJvdmlkZWRUb2tlbi5zdGFydHNXaXRoKCdCZWFyZXIgJykgPyBwcm92aWRlZFRva2VuLnNsaWNlKDcpIDogcHJvdmlkZWRUb2tlbjtcblxuICAgIGNvbnN0IGlzVmFsaWQgPSByYXdUb2tlbiA9PT0gdGhpcy50b2tlbjtcbiAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgIHRoaXMubG9nZ2VyLndhcm4oXG4gICAgICAgIGBbTUNQIEF1dGhdIFRva2VuIG1pc21hdGNoOiBwcm92aWRlZD0ke3Jhd1Rva2VuLnN1YnN0cmluZygwLCAyMCl9Li4uIHN0b3JlZD0ke3RoaXMudG9rZW4uc3Vic3RyaW5nKDAsIDIwKX0uLi5gXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gaXNWYWxpZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGF0IHJlcXVlc3QgY29tZXMgZnJvbSB0cnVzdGVkIElQXG4gICAqL1xuICB2YWxpZGF0ZUlQKGlwOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgICBpZiAoIWlwKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiAoVFJVU1RFRF9JUFMgYXMgcmVhZG9ubHkgc3RyaW5nW10pLmluY2x1ZGVzKGlwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0IEJlYXJlciB0b2tlbiBmcm9tIEF1dGhvcml6YXRpb24gaGVhZGVyXG4gICAqL1xuICBleHRyYWN0QmVhcmVyVG9rZW4oYXV0aEhlYWRlcjogc3RyaW5nIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIWF1dGhIZWFkZXIpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgaWYgKGF1dGhIZWFkZXIuc3RhcnRzV2l0aCgnQmVhcmVyICcpKSB7XG4gICAgICByZXR1cm4gYXV0aEhlYWRlci5zbGljZSg3KTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXV0aEhlYWRlcjtcbiAgfVxufVxuIl19
@@ -0,0 +1,67 @@
1
+ /**
2
+ * MCP Server
3
+ * Main server class that handles HTTP/SSE connections for MCP protocol
4
+ */
5
+ import { McpConnectionInfo, McpServerConfig, McpServerStatus, LocalServices } from '../../common/types';
6
+ export declare class McpServer {
7
+ private server;
8
+ private port;
9
+ private auth;
10
+ private connectionInfo;
11
+ private services;
12
+ private logger;
13
+ private startTime;
14
+ constructor(config: McpServerConfig, services: LocalServices, logger: any);
15
+ /**
16
+ * Start the MCP server
17
+ */
18
+ start(): Promise<void>;
19
+ /**
20
+ * Stop the MCP server
21
+ */
22
+ stop(): Promise<void>;
23
+ /**
24
+ * Check if server is running
25
+ */
26
+ isRunning(): boolean;
27
+ /**
28
+ * Get server status
29
+ */
30
+ getStatus(): McpServerStatus;
31
+ /**
32
+ * Get connection info for external tools
33
+ */
34
+ getConnectionInfo(): McpConnectionInfo;
35
+ /**
36
+ * Regenerate the authentication token
37
+ */
38
+ regenerateToken(): Promise<string>;
39
+ /**
40
+ * Find an available port starting from the preferred port
41
+ */
42
+ private findAvailablePort;
43
+ /**
44
+ * Handle incoming HTTP requests
45
+ */
46
+ private handleRequest;
47
+ /**
48
+ * Handle health check requests
49
+ */
50
+ private handleHealth;
51
+ /**
52
+ * Handle SSE connection for MCP protocol
53
+ */
54
+ private handleSSE;
55
+ /**
56
+ * Handle MCP message requests
57
+ */
58
+ private handleMessage;
59
+ /**
60
+ * Process an MCP message and return response
61
+ */
62
+ private processMessage;
63
+ /**
64
+ * Send an error response
65
+ */
66
+ private sendError;
67
+ }
@@ -0,0 +1,343 @@
1
+ "use strict";
2
+ /**
3
+ * MCP Server
4
+ * Main server class that handles HTTP/SSE connections for MCP protocol
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.McpServer = void 0;
11
+ const http_1 = __importDefault(require("http"));
12
+ const url_1 = require("url");
13
+ const constants_1 = require("../../common/constants");
14
+ const McpAuth_1 = require("./McpAuth");
15
+ const ConnectionInfo_1 = require("../config/ConnectionInfo");
16
+ const tools_1 = require("./tools");
17
+ class McpServer {
18
+ constructor(config, services, logger) {
19
+ this.server = null;
20
+ this.startTime = 0;
21
+ this.port = config.port || constants_1.MCP_SERVER.DEFAULT_PORT;
22
+ this.services = services;
23
+ this.logger = logger;
24
+ this.auth = new McpAuth_1.McpAuth(logger);
25
+ this.connectionInfo = new ConnectionInfo_1.ConnectionInfoManager(logger);
26
+ // Set token if provided
27
+ if (config.authToken) {
28
+ this.auth.setToken(config.authToken);
29
+ }
30
+ // Register all tools
31
+ (0, tools_1.registerTools)();
32
+ }
33
+ /**
34
+ * Start the MCP server
35
+ */
36
+ async start() {
37
+ if (this.server) {
38
+ this.logger.warn('[MCP] Server already running');
39
+ return;
40
+ }
41
+ // Try to load existing token from connection info (for persistence across restarts)
42
+ const existingInfo = await this.connectionInfo.load();
43
+ if (existingInfo?.authToken) {
44
+ this.auth.setToken(existingInfo.authToken);
45
+ this.logger.info(`[MCP] Loaded existing auth token: ${existingInfo.authToken.substring(0, 20)}...`);
46
+ }
47
+ // Find available port
48
+ this.port = await this.findAvailablePort(this.port);
49
+ return new Promise((resolve, reject) => {
50
+ this.server = http_1.default.createServer((req, res) => this.handleRequest(req, res));
51
+ this.server.on('error', (err) => {
52
+ if (err.code === 'EADDRINUSE') {
53
+ this.logger.error(`[MCP] Port ${this.port} is in use`);
54
+ reject(new Error(`Port ${this.port} is already in use`));
55
+ }
56
+ else {
57
+ this.logger.error('[MCP] Server error:', err);
58
+ reject(err);
59
+ }
60
+ });
61
+ this.server.listen(this.port, '127.0.0.1', async () => {
62
+ this.startTime = Date.now();
63
+ this.logger.info(`[MCP] Server started on http://127.0.0.1:${this.port}`);
64
+ // Save connection info
65
+ const info = this.getConnectionInfo();
66
+ await this.connectionInfo.save(info);
67
+ resolve();
68
+ });
69
+ });
70
+ }
71
+ /**
72
+ * Stop the MCP server
73
+ */
74
+ async stop() {
75
+ if (!this.server) {
76
+ return;
77
+ }
78
+ return new Promise((resolve) => {
79
+ this.server.close(() => {
80
+ this.logger.info('[MCP] Server stopped');
81
+ this.server = null;
82
+ this.connectionInfo.delete();
83
+ resolve();
84
+ });
85
+ });
86
+ }
87
+ /**
88
+ * Check if server is running
89
+ */
90
+ isRunning() {
91
+ return this.server !== null;
92
+ }
93
+ /**
94
+ * Get server status
95
+ */
96
+ getStatus() {
97
+ return {
98
+ running: this.isRunning(),
99
+ port: this.port,
100
+ uptime: this.isRunning() ? (Date.now() - this.startTime) / 1000 : 0,
101
+ };
102
+ }
103
+ /**
104
+ * Get connection info for external tools
105
+ */
106
+ getConnectionInfo() {
107
+ return {
108
+ url: `http://127.0.0.1:${this.port}`,
109
+ authToken: this.auth.getToken(),
110
+ port: this.port,
111
+ version: constants_1.MCP_SERVER.VERSION,
112
+ tools: (0, tools_1.getToolNames)(),
113
+ };
114
+ }
115
+ /**
116
+ * Regenerate the authentication token
117
+ */
118
+ async regenerateToken() {
119
+ const newToken = this.auth.regenerateToken();
120
+ // Update connection info file with new token
121
+ const info = this.getConnectionInfo();
122
+ await this.connectionInfo.save(info);
123
+ this.logger.info(`[MCP] Auth token regenerated`);
124
+ return newToken;
125
+ }
126
+ /**
127
+ * Find an available port starting from the preferred port
128
+ */
129
+ async findAvailablePort(preferredPort) {
130
+ const isPortAvailable = (port) => {
131
+ return new Promise((resolve) => {
132
+ const testServer = http_1.default.createServer();
133
+ testServer.once('error', () => resolve(false));
134
+ testServer.once('listening', () => {
135
+ testServer.close(() => resolve(true));
136
+ });
137
+ testServer.listen(port, '127.0.0.1');
138
+ });
139
+ };
140
+ for (let port = preferredPort; port <= constants_1.MCP_SERVER.PORT_RANGE.MAX; port++) {
141
+ if (await isPortAvailable(port)) {
142
+ if (port !== preferredPort) {
143
+ this.logger.info(`[MCP] Port ${preferredPort} unavailable, using ${port}`);
144
+ }
145
+ return port;
146
+ }
147
+ }
148
+ throw new Error(`No available ports in range ${constants_1.MCP_SERVER.PORT_RANGE.MIN}-${constants_1.MCP_SERVER.PORT_RANGE.MAX}`);
149
+ }
150
+ /**
151
+ * Handle incoming HTTP requests
152
+ */
153
+ async handleRequest(req, res) {
154
+ const url = new url_1.URL(req.url || '/', `http://127.0.0.1:${this.port}`);
155
+ const pathname = url.pathname;
156
+ // IP check
157
+ if (!this.auth.validateIP(req.socket.remoteAddress)) {
158
+ this.sendError(res, 403, 'Forbidden: Only localhost connections allowed');
159
+ return;
160
+ }
161
+ // Health endpoint (no auth required)
162
+ if (pathname === constants_1.MCP_ENDPOINTS.HEALTH) {
163
+ this.handleHealth(req, res);
164
+ return;
165
+ }
166
+ // Auth check for all other endpoints
167
+ const authHeader = req.headers.authorization;
168
+ if (!this.auth.validateToken(authHeader)) {
169
+ this.sendError(res, 401, 'Unauthorized: Invalid or missing authentication token');
170
+ return;
171
+ }
172
+ // Handle CORS preflight
173
+ if (req.method === 'OPTIONS') {
174
+ res.writeHead(200, {
175
+ 'Access-Control-Allow-Origin': '*',
176
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
177
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
178
+ 'Access-Control-Max-Age': '86400',
179
+ });
180
+ res.end();
181
+ return;
182
+ }
183
+ // Route to appropriate handler
184
+ if (pathname === constants_1.MCP_ENDPOINTS.SSE && req.method === 'GET') {
185
+ this.handleSSE(req, res);
186
+ }
187
+ else if (pathname === constants_1.MCP_ENDPOINTS.MESSAGES && req.method === 'POST') {
188
+ await this.handleMessage(req, res);
189
+ }
190
+ else {
191
+ this.sendError(res, 404, 'Not Found');
192
+ }
193
+ }
194
+ /**
195
+ * Handle health check requests
196
+ */
197
+ handleHealth(req, res) {
198
+ const status = this.getStatus();
199
+ const token = this.auth.getToken();
200
+ res.writeHead(200, { 'Content-Type': 'application/json' });
201
+ res.end(JSON.stringify({
202
+ status: 'ok',
203
+ version: constants_1.MCP_SERVER.VERSION,
204
+ uptime: status.uptime,
205
+ tools: (0, tools_1.getToolNames)(),
206
+ tokenPrefix: token.substring(0, 20),
207
+ }));
208
+ }
209
+ /**
210
+ * Handle SSE connection for MCP protocol
211
+ */
212
+ handleSSE(req, res) {
213
+ res.writeHead(200, {
214
+ 'Content-Type': 'text/event-stream',
215
+ 'Cache-Control': 'no-cache',
216
+ Connection: 'keep-alive',
217
+ 'Access-Control-Allow-Origin': '*',
218
+ });
219
+ // Send endpoint information
220
+ const messagesUrl = `http://127.0.0.1:${this.port}${constants_1.MCP_ENDPOINTS.MESSAGES}`;
221
+ res.write(`event: endpoint\ndata: ${messagesUrl}\n\n`);
222
+ // Keep connection alive
223
+ const keepAlive = setInterval(() => {
224
+ res.write(': keepalive\n\n');
225
+ }, 30000);
226
+ req.on('close', () => {
227
+ clearInterval(keepAlive);
228
+ });
229
+ }
230
+ /**
231
+ * Handle MCP message requests
232
+ */
233
+ async handleMessage(req, res) {
234
+ let body = '';
235
+ req.on('data', (chunk) => {
236
+ body += chunk;
237
+ });
238
+ req.on('end', async () => {
239
+ try {
240
+ const request = JSON.parse(body);
241
+ // Notifications don't have an id and don't expect a response
242
+ if (request.method?.startsWith('notifications/')) {
243
+ this.logger.info(`[MCP] Received notification: ${request.method}`);
244
+ res.writeHead(200, { 'Content-Type': 'application/json' });
245
+ res.end('{}');
246
+ return;
247
+ }
248
+ const response = await this.processMessage(request);
249
+ res.writeHead(200, {
250
+ 'Content-Type': 'application/json',
251
+ 'Access-Control-Allow-Origin': '*',
252
+ });
253
+ res.end(JSON.stringify(response));
254
+ }
255
+ catch (error) {
256
+ this.logger.error('[MCP] Message handling error:', error);
257
+ this.sendError(res, 400, `Invalid request: ${error.message}`);
258
+ }
259
+ });
260
+ }
261
+ /**
262
+ * Process an MCP message and return response
263
+ */
264
+ async processMessage(request) {
265
+ const { id, method, params } = request;
266
+ switch (method) {
267
+ case 'initialize':
268
+ return {
269
+ jsonrpc: '2.0',
270
+ id,
271
+ result: {
272
+ protocolVersion: '2024-11-05',
273
+ capabilities: {
274
+ tools: {},
275
+ },
276
+ serverInfo: {
277
+ name: constants_1.MCP_SERVER.NAME,
278
+ version: constants_1.MCP_SERVER.VERSION,
279
+ },
280
+ },
281
+ };
282
+ case 'tools/list':
283
+ return {
284
+ jsonrpc: '2.0',
285
+ id,
286
+ result: {
287
+ tools: (0, tools_1.getToolDefinitions)(),
288
+ },
289
+ };
290
+ case 'tools/call':
291
+ if (!params?.name) {
292
+ return {
293
+ jsonrpc: '2.0',
294
+ id,
295
+ error: {
296
+ code: -32602,
297
+ message: 'Missing tool name',
298
+ },
299
+ };
300
+ }
301
+ if (!(0, tools_1.hasTool)(params.name)) {
302
+ return {
303
+ jsonrpc: '2.0',
304
+ id,
305
+ error: {
306
+ code: -32602,
307
+ message: `Unknown tool: ${params.name}`,
308
+ },
309
+ };
310
+ }
311
+ const result = await (0, tools_1.executeTool)(params.name, params.arguments || {}, this.services);
312
+ return {
313
+ jsonrpc: '2.0',
314
+ id,
315
+ result,
316
+ };
317
+ case 'ping':
318
+ return {
319
+ jsonrpc: '2.0',
320
+ id,
321
+ result: {},
322
+ };
323
+ default:
324
+ return {
325
+ jsonrpc: '2.0',
326
+ id,
327
+ error: {
328
+ code: -32601,
329
+ message: `Unknown method: ${method}`,
330
+ },
331
+ };
332
+ }
333
+ }
334
+ /**
335
+ * Send an error response
336
+ */
337
+ sendError(res, statusCode, message) {
338
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
339
+ res.end(JSON.stringify({ error: message }));
340
+ }
341
+ }
342
+ exports.McpServer = McpServer;
343
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWNwU2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21haW4vbWNwL01jcFNlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztHQUdHOzs7Ozs7QUFFSCxnREFBd0I7QUFDeEIsNkJBQTBCO0FBQzFCLHNEQUFtRTtBQVNuRSx1Q0FBb0M7QUFDcEMsNkRBQWlFO0FBQ2pFLG1DQUFnRztBQUVoRyxNQUFhLFNBQVM7SUFTcEIsWUFBWSxNQUF1QixFQUFFLFFBQXVCLEVBQUUsTUFBVztRQVJqRSxXQUFNLEdBQXVCLElBQUksQ0FBQztRQU1sQyxjQUFTLEdBQVcsQ0FBQyxDQUFDO1FBRzVCLElBQUksQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksSUFBSSxzQkFBVSxDQUFDLFlBQVksQ0FBQztRQUNuRCxJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUN6QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksaUJBQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNoQyxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksc0NBQXFCLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFeEQsd0JBQXdCO1FBQ3hCLElBQUksTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3JCLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN2QyxDQUFDO1FBRUQscUJBQXFCO1FBQ3JCLElBQUEscUJBQWEsR0FBRSxDQUFDO0lBQ2xCLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxLQUFLO1FBQ1QsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsOEJBQThCLENBQUMsQ0FBQztZQUNqRCxPQUFPO1FBQ1QsQ0FBQztRQUVELG9GQUFv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Q0YsTUFBTSxFQUFFLEVBQUU7aUJBQ1gsQ0FBQztZQUVKO2dCQUNFLE9BQU87b0JBQ0wsT0FBTyxFQUFFLEtBQUs7b0JBQ2QsRUFBRTtvQkFDRixLQUFLLEVBQUU7d0JBQ0wsSUFBSSxFQUFFLENBQUMsS0FBSzt3QkFDWixPQUFPLEVBQUUsbUJBQW1CLE1BQU0sRUFBRTtxQkFDckM7aUJBQ0YsQ0FBQztRQUNOLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxTQUFTLENBQUMsR0FBd0IsRUFBRSxVQUFrQixFQUFFLE9BQWU7UUFDN0UsR0FBRyxDQUFDLFNBQVMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxjQUFjLEVBQUUsa0JBQWtCLEVBQUUsQ0FBQyxDQUFDO1FBQ2xFLEdBQUcsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDOUMsQ0FBQztDQUNGO0FBMVhELDhCQTBYQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTUNQIFNlcnZlclxuICogTWFpbiBzZXJ2ZXIgY2xhc3MgdGhhdCBoYW5kbGVzIEhUVFAvU1NFIGNvbm5lY3Rpb25zIGZvciBNQ1AgcHJvdG9jb2xcbiAqL1xuXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcbmltcG9ydCB7IFVSTCB9IGZyb20gJ3VybCc7XG5pbXBvcnQgeyBNQ1BfU0VSVkVSLCBNQ1BfRU5EUE9JTlRTIH0gZnJvbSAnLi4vLi4vY29tbW9uL2NvbnN0YW50cyc7XG5pbXBvcnQge1xuICBNY3BDb25uZWN0aW9uSW5mbyxcbiAgTWNwU2VydmVyQ29uZmlnLFxuICBNY3BTZXJ2ZXJTdGF0dXMsXG4gIE1jcFJlcXVlc3QsXG4gIE1jcFJlc3BvbnNlLFxuICBMb2NhbFNlcnZpY2VzLFxufSBmcm9tICcuLi8uLi9jb21tb24vdHlwZXMnO1xuaW1wb3J0IHsgTWNwQXV0aCB9IGZyb20gJy4vTWNwQXV0aCc7XG5pbXBvcnQgeyBDb25uZWN0aW9uSW5mb01hbmFnZXIgfSBmcm9tICcuLi9jb25maWcvQ29ubmVjdGlvbkluZm8nO1xuaW1wb3J0IHsgcmVnaXN0ZXJUb29scywgZ2V0VG9vbERlZmluaXRpb25zLCBnZXRUb29sTmFtZXMsIGV4ZWN1dGVUb29sLCBoYXNUb29sIH0gZnJvbSAnLi90b29scyc7XG5cbmV4cG9ydCBjbGFzcyBNY3BTZXJ2ZXIge1xuICBwcml2YXRlIHNlcnZlcjogaHR0cC5TZXJ2ZXIgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBwb3J0OiBudW1iZXI7XG4gIHByaXZhdGUgYXV0aDogTWNwQXV0aDtcbiAgcHJpdmF0ZSBjb25uZWN0aW9uSW5mbzogQ29ubmVjdGlvbkluZm9NYW5hZ2VyO1xuICBwcml2YXRlIHNlcnZpY2VzOiBMb2NhbFNlcnZpY2VzO1xuICBwcml2YXRlIGxvZ2dlcjogYW55O1xuICBwcml2YXRlIHN0YXJ0VGltZTogbnVtYmVyID0gMDtcblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IE1jcFNlcnZlckNvbmZpZywgc2VydmljZXM6IExvY2FsU2VydmljZXMsIGxvZ2dlcjogYW55KSB7XG4gICAgdGhpcy5wb3J0ID0gY29uZmlnLnBvcnQgfHwgTUNQX1NFUlZFUi5ERUZBVUxUX1BPUlQ7XG4gICAgdGhpcy5zZXJ2aWNlcyA9IHNlcnZpY2VzO1xuICAgIHRoaXMubG9nZ2VyID0gbG9nZ2VyO1xuICAgIHRoaXMuYXV0aCA9IG5ldyBNY3BBdXRoKGxvZ2dlcik7XG4gICAgdGhpcy5jb25uZWN0aW9uSW5mbyA9IG5ldyBDb25uZWN0aW9uSW5mb01hbmFnZXIobG9nZ2VyKTtcblxuICAgIC8vIFNldCB0b2tlbiBpZiBwcm92aWRlZFxuICAgIGlmIChjb25maWcuYXV0aFRva2VuKSB7XG4gICAgICB0aGlzLmF1dGguc2V0VG9rZW4oY29uZmlnLmF1dGhUb2tlbik7XG4gICAgfVxuXG4gICAgLy8gUmVnaXN0ZXIgYWxsIHRvb2xzXG4gICAgcmVnaXN0ZXJUb29scygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IHRoZSBNQ1Agc2VydmVyXG4gICAqL1xuICBhc3luYyBzdGFydCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5zZXJ2ZXIpIHtcbiAgICAgIHRoaXMubG9nZ2VyLndhcm4oJ1tNQ1BdIFNlcnZlciBhbHJlYWR5IHJ1bm5pbmcnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBUcnkgdG8gbG9hZCBleGlzdGluZyB0b2tlbiBmcm9tIGNvbm5lY3Rpb24gaW5mbyAoZm9yIHBlcnNpc3RlbmNlIGFjcm9zcyByZXN0YXJ0cylcbiAgICBjb25zdCBleGlzdGluZ0luZm8gPSBhd2FpdCB0aGlzLmNvbm5lY3Rpb25JbmZvLmxvYWQoKTtcbiAgICBpZiAoZXhpc3RpbmdJbmZvPy5hdXRoVG9rZW4pIHtcbiAgICAgIHRoaXMuYXV0aC5zZXRUb2tlbihleGlzdGluZ0luZm8uYXV0aFRva2VuKTtcbiAgICAgIHRoaXMubG9nZ2VyLmluZm8oXG4gICAgICAgIGBbTUNQXSBMb2FkZWQgZXhpc3RpbmcgYXV0aCB0b2tlbjogJHtleGlzdGluZ0luZm8uYXV0aFRva2VuLnN1YnN0cmluZygwLCAyMCl9Li4uYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBGaW5kIGF2YWlsYWJsZSBwb3J0XG4gICAgdGhpcy5wb3J0ID0gYXdhaXQgdGhpcy5maW5kQXZhaWxhYmxlUG9ydCh0aGlzLnBvcnQpO1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHRoaXMuc2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoKHJlcSwgcmVzKSA9PiB0aGlzLmhhbmRsZVJlcXVlc3QocmVxLCByZXMpKTtcblxuICAgICAgdGhpcy5zZXJ2ZXIub24oJ2Vycm9yJywgKGVycjogYW55KSA9PiB7XG4gICAgICAgIGlmIChlcnIuY29kZSA9PT0gJ0VBRERSSU5VU0UnKSB7XG4gICAgICAgICAgdGhpcy5sb2dnZXIuZXJyb3IoYFtNQ1BdIFBvcnQgJHt0aGlzLnBvcnR9IGlzIGluIHVzZWApO1xuICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoYFBvcnQgJHt0aGlzLnBvcnR9IGlzIGFscmVhZHkgaW4gdXNlYCkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKCdbTUNQXSBTZXJ2ZXIgZXJyb3I6JywgZXJyKTtcbiAgICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuc2VydmVyLmxpc3Rlbih0aGlzLnBvcnQsICcxMjcuMC4wLjEnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIHRoaXMuc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgdGhpcy5sb2dnZXIuaW5mbyhgW01DUF0gU2VydmVyIHN0YXJ0ZWQgb24gaHR0cDovLzEyNy4wLjAuMToke3RoaXMucG9ydH1gKTtcblxuICAgICAgICAvLyBTYXZlIGNvbm5lY3Rpb24gaW5mb1xuICAgICAgICBjb25zdCBpbmZvID0gdGhpcy5nZXRDb25uZWN0aW9uSW5mbygpO1xuICAgICAgICBhd2FpdCB0aGlzLmNvbm5lY3Rpb25JbmZvLnNhdmUoaW5mbyk7XG5cbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU3RvcCB0aGUgTUNQIHNlcnZlclxuICAgKi9cbiAgYXN5bmMgc3RvcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMuc2VydmVyKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICB0aGlzLnNlcnZlciEuY2xvc2UoKCkgPT4ge1xuICAgICAgICB0aGlzLmxvZ2dlci5pbmZvKCdbTUNQXSBTZXJ2ZXIgc3RvcHBlZCcpO1xuICAgICAgICB0aGlzLnNlcnZlciA9IG51bGw7XG4gICAgICAgIHRoaXMuY29ubmVjdGlvbkluZm8uZGVsZXRlKCk7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIHNlcnZlciBpcyBydW5uaW5nXG4gICAqL1xuICBpc1J1bm5pbmcoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2VydmVyICE9PSBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBzZXJ2ZXIgc3RhdHVzXG4gICAqL1xuICBnZXRTdGF0dXMoKTogTWNwU2VydmVyU3RhdHVzIHtcbiAgICByZXR1cm4ge1xuICAgICAgcnVubmluZzogdGhpcy5pc1J1bm5pbmcoKSxcbiAgICAgIHBvcnQ6IHRoaXMucG9ydCxcbiAgICAgIHVwdGltZTogdGhpcy5pc1J1bm5pbmcoKSA/IChEYXRlLm5vdygpIC0gdGhpcy5zdGFydFRpbWUpIC8gMTAwMCA6IDAsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY29ubmVjdGlvbiBpbmZvIGZvciBleHRlcm5hbCB0b29sc1xuICAgKi9cbiAgZ2V0Q29ubmVjdGlvbkluZm8oKTogTWNwQ29ubmVjdGlvbkluZm8ge1xuICAgIHJldHVybiB7XG4gICAgICB1cmw6IGBodHRwOi8vMTI3LjAuMC4xOiR7dGhpcy5wb3J0fWAsXG4gICAgICBhdXRoVG9rZW46IHRoaXMuYXV0aC5nZXRUb2tlbigpLFxuICAgICAgcG9ydDogdGhpcy5wb3J0LFxuICAgICAgdmVyc2lvbjogTUNQX1NFUlZFUi5WRVJTSU9OLFxuICAgICAgdG9vbHM6IGdldFRvb2xOYW1lcygpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmVnZW5lcmF0ZSB0aGUgYXV0aGVudGljYXRpb24gdG9rZW5cbiAgICovXG4gIGFzeW5jIHJlZ2VuZXJhdGVUb2tlbigpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IG5ld1Rva2VuID0gdGhpcy5hdXRoLnJlZ2VuZXJhdGVUb2tlbigpO1xuICAgIC8vIFVwZGF0ZSBjb25uZWN0aW9uIGluZm8gZmlsZSB3aXRoIG5ldyB0b2tlblxuICAgIGNvbnN0IGluZm8gPSB0aGlzLmdldENvbm5lY3Rpb25JbmZvKCk7XG4gICAgYXdhaXQgdGhpcy5jb25uZWN0aW9uSW5mby5zYXZlKGluZm8pO1xuICAgIHRoaXMubG9nZ2VyLmluZm8oYFtNQ1BdIEF1dGggdG9rZW4gcmVnZW5lcmF0ZWRgKTtcbiAgICByZXR1cm4gbmV3VG9rZW47XG4gIH1cblxuICAvKipcbiAgICogRmluZCBhbiBhdmFpbGFibGUgcG9ydCBzdGFydGluZyBmcm9tIHRoZSBwcmVmZXJyZWQgcG9ydFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBmaW5kQXZhaWxhYmxlUG9ydChwcmVmZXJyZWRQb3J0OiBudW1iZXIpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IGlzUG9ydEF2YWlsYWJsZSA9IChwb3J0OiBudW1iZXIpOiBQcm9taXNlPGJvb2xlYW4+ID0+IHtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICBjb25zdCB0ZXN0U2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoKTtcbiAgICAgICAgdGVzdFNlcnZlci5vbmNlKCdlcnJvcicsICgpID0+IHJlc29sdmUoZmFsc2UpKTtcbiAgICAgICAgdGVzdFNlcnZlci5vbmNlKCdsaXN0ZW5pbmcnLCAoKSA9PiB7XG4gICAgICAgICAgdGVzdFNlcnZlci5jbG9zZSgoKSA9PiByZXNvbHZlKHRydWUpKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRlc3RTZXJ2ZXIubGlzdGVuKHBvcnQsICcxMjcuMC4wLjEnKTtcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICBmb3IgKGxldCBwb3J0ID0gcHJlZmVycmVkUG9ydDsgcG9ydCA8PSBNQ1BfU0VSVkVSLlBPUlRfUkFOR0UuTUFYOyBwb3J0KyspIHtcbiAgICAgIGlmIChhd2FpdCBpc1BvcnRBdmFpbGFibGUocG9ydCkpIHtcbiAgICAgICAgaWYgKHBvcnQgIT09IHByZWZlcnJlZFBvcnQpIHtcbiAgICAgICAgICB0aGlzLmxvZ2dlci5pbmZvKGBbTUNQXSBQb3J0ICR7cHJlZmVycmVkUG9ydH0gdW5hdmFpbGFibGUsIHVzaW5nICR7cG9ydH1gKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcG9ydDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgTm8gYXZhaWxhYmxlIHBvcnRzIGluIHJhbmdlICR7TUNQX1NFUlZFUi5QT1JUX1JBTkdFLk1JTn0tJHtNQ1BfU0VSVkVSLlBPUlRfUkFOR0UuTUFYfWBcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEhhbmRsZSBpbmNvbWluZyBIVFRQIHJlcXVlc3RzXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGhhbmRsZVJlcXVlc3QocmVxOiBodHRwLkluY29taW5nTWVzc2FnZSwgcmVzOiBodHRwLlNlcnZlclJlc3BvbnNlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChyZXEudXJsIHx8ICcvJywgYGh0dHA6Ly8xMjcuMC4wLjE6JHt0aGlzLnBvcnR9YCk7XG4gICAgY29uc3QgcGF0aG5hbWUgPSB1cmwucGF0aG5hbWU7XG5cbiAgICAvLyBJUCBjaGVja1xuICAgIGlmICghdGhpcy5hdXRoLnZhbGlkYXRlSVAocmVxLnNvY2tldC5yZW1vdGVBZGRyZXNzKSkge1xuICAgICAgdGhpcy5zZW5kRXJyb3IocmVzLCA0MDMsICdGb3JiaWRkZW46IE9ubHkgbG9jYWxob3N0IGNvbm5lY3Rpb25zIGFsbG93ZWQnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBIZWFsdGggZW5kcG9pbnQgKG5vIGF1dGggcmVxdWlyZWQpXG4gICAgaWYgKHBhdGhuYW1lID09PSBNQ1BfRU5EUE9JTlRTLkhFQUxUSCkge1xuICAgICAgdGhpcy5oYW5kbGVIZWFsdGgocmVxLCByZXMpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEF1dGggY2hlY2sgZm9yIGFsbCBvdGhlciBlbmRwb2ludHNcbiAgICBjb25zdCBhdXRoSGVhZGVyID0gcmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbjtcbiAgICBpZiAoIXRoaXMuYXV0aC52YWxpZGF0ZVRva2VuKGF1dGhIZWFkZXIpKSB7XG4gICAgICB0aGlzLnNlbmRFcnJvcihyZXMsIDQwMSwgJ1VuYXV0aG9yaXplZDogSW52YWxpZCBvciBtaXNzaW5nIGF1dGhlbnRpY2F0aW9uIHRva2VuJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIENPUlMgcHJlZmxpZ2h0XG4gICAgaWYgKHJlcS5tZXRob2QgPT09ICdPUFRJT05TJykge1xuICAgICAgcmVzLndyaXRlSGVhZCgyMDAsIHtcbiAgICAgICAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbic6ICcqJyxcbiAgICAgICAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU1ldGhvZHMnOiAnR0VULCBQT1NULCBPUFRJT05TJyxcbiAgICAgICAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnMnOiAnQ29udGVudC1UeXBlLCBBdXRob3JpemF0aW9uJyxcbiAgICAgICAgJ0FjY2Vzcy1Db250cm9sLU1heC1BZ2UnOiAnODY0MDAnLFxuICAgICAgfSk7XG4gICAgICByZXMuZW5kKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gUm91dGUgdG8gYXBwcm9wcmlhdGUgaGFuZGxlclxuICAgIGlmIChwYXRobmFtZSA9PT0gTUNQX0VORFBPSU5UUy5TU0UgJiYgcmVxLm1ldGhvZCA9PT0gJ0dFVCcpIHtcbiAgICAgIHRoaXMuaGFuZGxlU1NFKHJlcSwgcmVzKTtcbiAgICB9IGVsc2UgaWYgKHBhdGhuYW1lID09PSBNQ1BfRU5EUE9JTlRTLk1FU1NBR0VTICYmIHJlcS5tZXRob2QgPT09ICdQT1NUJykge1xuICAgICAgYXdhaXQgdGhpcy5oYW5kbGVNZXNzYWdlKHJlcSwgcmVzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zZW5kRXJyb3IocmVzLCA0MDQsICdOb3QgRm91bmQnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSGFuZGxlIGhlYWx0aCBjaGVjayByZXF1ZXN0c1xuICAgKi9cbiAgcHJpdmF0ZSBoYW5kbGVIZWFsdGgocmVxOiBodHRwLkluY29taW5nTWVzc2FnZSwgcmVzOiBodHRwLlNlcnZlclJlc3BvbnNlKTogdm9pZCB7XG4gICAgY29uc3Qgc3RhdHVzID0gdGhpcy5nZXRTdGF0dXMoKTtcbiAgICBjb25zdCB0b2tlbiA9IHRoaXMuYXV0aC5nZXRUb2tlbigpO1xuICAgIHJlcy53cml0ZUhlYWQoMjAwLCB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicgfSk7XG4gICAgcmVzLmVuZChcbiAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgc3RhdHVzOiAnb2snLFxuICAgICAgICB2ZXJzaW9uOiBNQ1BfU0VSVkVSLlZFUlNJT04sXG4gICAgICAgIHVwdGltZTogc3RhdHVzLnVwdGltZSxcbiAgICAgICAgdG9vbHM6IGdldFRvb2xOYW1lcygpLFxuICAgICAgICB0b2tlblByZWZpeDogdG9rZW4uc3Vic3RyaW5nKDAsIDIwKSxcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGUgU1NFIGNvbm5lY3Rpb24gZm9yIE1DUCBwcm90b2NvbFxuICAgKi9cbiAgcHJpdmF0ZSBoYW5kbGVTU0UocmVxOiBodHRwLkluY29taW5nTWVzc2FnZSwgcmVzOiBodHRwLlNlcnZlclJlc3BvbnNlKTogdm9pZCB7XG4gICAgcmVzLndyaXRlSGVhZCgyMDAsIHtcbiAgICAgICdDb250ZW50LVR5cGUnOiAndGV4dC9ldmVudC1zdHJlYW0nLFxuICAgICAgJ0NhY2hlLUNvbnRyb2wnOiAnbm8tY2FjaGUnLFxuICAgICAgQ29ubmVjdGlvbjogJ2tlZXAtYWxpdmUnLFxuICAgICAgJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbic6ICcqJyxcbiAgICB9KTtcblxuICAgIC8vIFNlbmQgZW5kcG9pbnQgaW5mb3JtYXRpb25cbiAgICBjb25zdCBtZXNzYWdlc1VybCA9IGBodHRwOi8vMTI3LjAuMC4xOiR7dGhpcy5wb3J0fSR7TUNQX0VORFBPSU5UUy5NRVNTQUdFU31gO1xuICAgIHJlcy53cml0ZShgZXZlbnQ6IGVuZHBvaW50XFxuZGF0YTogJHttZXNzYWdlc1VybH1cXG5cXG5gKTtcblxuICAgIC8vIEtlZXAgY29ubmVjdGlvbiBhbGl2ZVxuICAgIGNvbnN0IGtlZXBBbGl2ZSA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgIHJlcy53cml0ZSgnOiBrZWVwYWxpdmVcXG5cXG4nKTtcbiAgICB9LCAzMDAwMCk7XG5cbiAgICByZXEub24oJ2Nsb3NlJywgKCkgPT4ge1xuICAgICAgY2xlYXJJbnRlcnZhbChrZWVwQWxpdmUpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEhhbmRsZSBNQ1AgbWVzc2FnZSByZXF1ZXN0c1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBoYW5kbGVNZXNzYWdlKHJlcTogaHR0cC5JbmNvbWluZ01lc3NhZ2UsIHJlczogaHR0cC5TZXJ2ZXJSZXNwb25zZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxldCBib2R5ID0gJyc7XG5cbiAgICByZXEub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcbiAgICAgIGJvZHkgKz0gY2h1bms7XG4gICAgfSk7XG5cbiAgICByZXEub24oJ2VuZCcsIGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlcXVlc3Q6IE1jcFJlcXVlc3QgPSBKU09OLnBhcnNlKGJvZHkpO1xuXG4gICAgICAgIC8vIE5vdGlmaWNhdGlvbnMgZG9uJ3QgaGF2ZSBhbiBpZCBhbmQgZG9uJ3QgZXhwZWN0IGEgcmVzcG9uc2VcbiAgICAgICAgaWYgKHJlcXVlc3QubWV0aG9kPy5zdGFydHNXaXRoKCdub3RpZmljYXRpb25zLycpKSB7XG4gICAgICAgICAgdGhpcy5sb2dnZXIuaW5mbyhgW01DUF0gUmVjZWl2ZWQgbm90aWZpY2F0aW9uOiAke3JlcXVlc3QubWV0aG9kfWApO1xuICAgICAgICAgIHJlcy53cml0ZUhlYWQoMjAwLCB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicgfSk7XG4gICAgICAgICAgcmVzLmVuZCgne30nKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMucHJvY2Vzc01lc3NhZ2UocmVxdWVzdCk7XG5cbiAgICAgICAgcmVzLndyaXRlSGVhZCgyMDAsIHtcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICdBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nOiAnKicsXG4gICAgICAgIH0pO1xuICAgICAgICByZXMuZW5kKEpTT04uc3RyaW5naWZ5KHJlc3BvbnNlKSk7XG4gICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKCdbTUNQXSBNZXNzYWdlIGhhbmRsaW5nIGVycm9yOicsIGVycm9yKTtcbiAgICAgICAgdGhpcy5zZW5kRXJyb3IocmVzLCA0MDAsIGBJbnZhbGlkIHJlcXVlc3Q6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcm9jZXNzIGFuIE1DUCBtZXNzYWdlIGFuZCByZXR1cm4gcmVzcG9uc2VcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcHJvY2Vzc01lc3NhZ2UocmVxdWVzdDogTWNwUmVxdWVzdCk6IFByb21pc2U8TWNwUmVzcG9uc2U+IHtcbiAgICBjb25zdCB7IGlkLCBtZXRob2QsIHBhcmFtcyB9ID0gcmVxdWVzdDtcblxuICAgIHN3aXRjaCAobWV0aG9kKSB7XG4gICAgICBjYXNlICdpbml0aWFsaXplJzpcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBqc29ucnBjOiAnMi4wJyxcbiAgICAgICAgICBpZCxcbiAgICAgICAgICByZXN1bHQ6IHtcbiAgICAgICAgICAgIHByb3RvY29sVmVyc2lvbjogJzIwMjQtMTEtMDUnLFxuICAgICAgICAgICAgY2FwYWJpbGl0aWVzOiB7XG4gICAgICAgICAgICAgIHRvb2xzOiB7fSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzZXJ2ZXJJbmZvOiB7XG4gICAgICAgICAgICAgIG5hbWU6IE1DUF9TRVJWRVIuTkFNRSxcbiAgICAgICAgICAgICAgdmVyc2lvbjogTUNQX1NFUlZFUi5WRVJTSU9OLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9O1xuXG4gICAgICBjYXNlICd0b29scy9saXN0JzpcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBqc29ucnBjOiAnMi4wJyxcbiAgICAgICAgICBpZCxcbiAgICAgICAgICByZXN1bHQ6IHtcbiAgICAgICAgICAgIHRvb2xzOiBnZXRUb29sRGVmaW5pdGlvbnMoKSxcbiAgICAgICAgICB9LFxuICAgICAgICB9O1xuXG4gICAgICBjYXNlICd0b29scy9jYWxsJzpcbiAgICAgICAgaWYgKCFwYXJhbXM/Lm5hbWUpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAganNvbnJwYzogJzIuMCcsXG4gICAgICAgICAgICBpZCxcbiAgICAgICAgICAgIGVycm9yOiB7XG4gICAgICAgICAgICAgIGNvZGU6IC0zMjYwMixcbiAgICAgICAgICAgICAgbWVzc2FnZTogJ01pc3NpbmcgdG9vbCBuYW1lJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghaGFzVG9vbChwYXJhbXMubmFtZSkpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAganNvbnJwYzogJzIuMCcsXG4gICAgICAgICAgICBpZCxcbiAgICAgICAgICAgIGVycm9yOiB7XG4gICAgICAgICAgICAgIGNvZGU6IC0zMjYwMixcbiAgICAgICAgICAgICAgbWVzc2FnZTogYFVua25vd24gdG9vbDogJHtwYXJhbXMubmFtZX1gLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZXhlY3V0ZVRvb2wocGFyYW1zLm5hbWUsIHBhcmFtcy5hcmd1bWVudHMgfHwge30sIHRoaXMuc2VydmljZXMpO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAganNvbnJwYzogJzIuMCcsXG4gICAgICAgICAgaWQsXG4gICAgICAgICAgcmVzdWx0LFxuICAgICAgICB9O1xuXG4gICAgICBjYXNlICdwaW5nJzpcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBqc29ucnBjOiAnMi4wJyxcbiAgICAgICAgICBpZCxcbiAgICAgICAgICByZXN1bHQ6IHt9LFxuICAgICAgICB9O1xuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGpzb25ycGM6ICcyLjAnLFxuICAgICAgICAgIGlkLFxuICAgICAgICAgIGVycm9yOiB7XG4gICAgICAgICAgICBjb2RlOiAtMzI2MDEsXG4gICAgICAgICAgICBtZXNzYWdlOiBgVW5rbm93biBtZXRob2Q6ICR7bWV0aG9kfWAsXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2VuZCBhbiBlcnJvciByZXNwb25zZVxuICAgKi9cbiAgcHJpdmF0ZSBzZW5kRXJyb3IocmVzOiBodHRwLlNlcnZlclJlc3BvbnNlLCBzdGF0dXNDb2RlOiBudW1iZXIsIG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xuICAgIHJlcy53cml0ZUhlYWQoc3RhdHVzQ29kZSwgeyAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nIH0pO1xuICAgIHJlcy5lbmQoSlNPTi5zdHJpbmdpZnkoeyBlcnJvcjogbWVzc2FnZSB9KSk7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,7 @@
1
+ /**
2
+ * change_php_version Tool
3
+ * Change PHP version for a site
4
+ */
5
+ import { McpToolDefinition, McpToolResult, LocalServices } from '../../../common/types';
6
+ export declare const changePhpVersionDefinition: McpToolDefinition;
7
+ export declare function changePhpVersion(args: Record<string, unknown>, services: LocalServices): Promise<McpToolResult>;