unreal-engine-mcp-server 0.2.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 (155) hide show
  1. package/.dockerignore +57 -0
  2. package/.env.production +25 -0
  3. package/.eslintrc.json +54 -0
  4. package/.github/workflows/publish-mcp.yml +75 -0
  5. package/Dockerfile +54 -0
  6. package/LICENSE +21 -0
  7. package/Public/icon.png +0 -0
  8. package/README.md +209 -0
  9. package/claude_desktop_config_example.json +13 -0
  10. package/dist/cli.d.ts +3 -0
  11. package/dist/cli.js +7 -0
  12. package/dist/index.d.ts +31 -0
  13. package/dist/index.js +484 -0
  14. package/dist/prompts/index.d.ts +14 -0
  15. package/dist/prompts/index.js +38 -0
  16. package/dist/python-utils.d.ts +29 -0
  17. package/dist/python-utils.js +54 -0
  18. package/dist/resources/actors.d.ts +13 -0
  19. package/dist/resources/actors.js +83 -0
  20. package/dist/resources/assets.d.ts +23 -0
  21. package/dist/resources/assets.js +245 -0
  22. package/dist/resources/levels.d.ts +17 -0
  23. package/dist/resources/levels.js +94 -0
  24. package/dist/tools/actors.d.ts +51 -0
  25. package/dist/tools/actors.js +459 -0
  26. package/dist/tools/animation.d.ts +196 -0
  27. package/dist/tools/animation.js +579 -0
  28. package/dist/tools/assets.d.ts +21 -0
  29. package/dist/tools/assets.js +304 -0
  30. package/dist/tools/audio.d.ts +170 -0
  31. package/dist/tools/audio.js +416 -0
  32. package/dist/tools/blueprint.d.ts +144 -0
  33. package/dist/tools/blueprint.js +652 -0
  34. package/dist/tools/build_environment_advanced.d.ts +66 -0
  35. package/dist/tools/build_environment_advanced.js +484 -0
  36. package/dist/tools/consolidated-tool-definitions.d.ts +2598 -0
  37. package/dist/tools/consolidated-tool-definitions.js +607 -0
  38. package/dist/tools/consolidated-tool-handlers.d.ts +2 -0
  39. package/dist/tools/consolidated-tool-handlers.js +1050 -0
  40. package/dist/tools/debug.d.ts +185 -0
  41. package/dist/tools/debug.js +265 -0
  42. package/dist/tools/editor.d.ts +88 -0
  43. package/dist/tools/editor.js +365 -0
  44. package/dist/tools/engine.d.ts +30 -0
  45. package/dist/tools/engine.js +36 -0
  46. package/dist/tools/foliage.d.ts +155 -0
  47. package/dist/tools/foliage.js +525 -0
  48. package/dist/tools/introspection.d.ts +98 -0
  49. package/dist/tools/introspection.js +683 -0
  50. package/dist/tools/landscape.d.ts +158 -0
  51. package/dist/tools/landscape.js +375 -0
  52. package/dist/tools/level.d.ts +110 -0
  53. package/dist/tools/level.js +362 -0
  54. package/dist/tools/lighting.d.ts +159 -0
  55. package/dist/tools/lighting.js +1179 -0
  56. package/dist/tools/materials.d.ts +34 -0
  57. package/dist/tools/materials.js +146 -0
  58. package/dist/tools/niagara.d.ts +145 -0
  59. package/dist/tools/niagara.js +289 -0
  60. package/dist/tools/performance.d.ts +163 -0
  61. package/dist/tools/performance.js +412 -0
  62. package/dist/tools/physics.d.ts +189 -0
  63. package/dist/tools/physics.js +784 -0
  64. package/dist/tools/rc.d.ts +110 -0
  65. package/dist/tools/rc.js +363 -0
  66. package/dist/tools/sequence.d.ts +112 -0
  67. package/dist/tools/sequence.js +675 -0
  68. package/dist/tools/tool-definitions.d.ts +4919 -0
  69. package/dist/tools/tool-definitions.js +891 -0
  70. package/dist/tools/tool-handlers.d.ts +47 -0
  71. package/dist/tools/tool-handlers.js +830 -0
  72. package/dist/tools/ui.d.ts +171 -0
  73. package/dist/tools/ui.js +337 -0
  74. package/dist/tools/visual.d.ts +29 -0
  75. package/dist/tools/visual.js +67 -0
  76. package/dist/types/env.d.ts +10 -0
  77. package/dist/types/env.js +18 -0
  78. package/dist/types/index.d.ts +323 -0
  79. package/dist/types/index.js +28 -0
  80. package/dist/types/tool-types.d.ts +274 -0
  81. package/dist/types/tool-types.js +13 -0
  82. package/dist/unreal-bridge.d.ts +126 -0
  83. package/dist/unreal-bridge.js +992 -0
  84. package/dist/utils/cache-manager.d.ts +64 -0
  85. package/dist/utils/cache-manager.js +176 -0
  86. package/dist/utils/error-handler.d.ts +66 -0
  87. package/dist/utils/error-handler.js +243 -0
  88. package/dist/utils/errors.d.ts +133 -0
  89. package/dist/utils/errors.js +256 -0
  90. package/dist/utils/http.d.ts +26 -0
  91. package/dist/utils/http.js +135 -0
  92. package/dist/utils/logger.d.ts +12 -0
  93. package/dist/utils/logger.js +32 -0
  94. package/dist/utils/normalize.d.ts +17 -0
  95. package/dist/utils/normalize.js +49 -0
  96. package/dist/utils/response-validator.d.ts +34 -0
  97. package/dist/utils/response-validator.js +121 -0
  98. package/dist/utils/safe-json.d.ts +4 -0
  99. package/dist/utils/safe-json.js +97 -0
  100. package/dist/utils/stdio-redirect.d.ts +2 -0
  101. package/dist/utils/stdio-redirect.js +20 -0
  102. package/dist/utils/validation.d.ts +50 -0
  103. package/dist/utils/validation.js +173 -0
  104. package/mcp-config-example.json +14 -0
  105. package/package.json +63 -0
  106. package/server.json +60 -0
  107. package/src/cli.ts +7 -0
  108. package/src/index.ts +543 -0
  109. package/src/prompts/index.ts +51 -0
  110. package/src/python/editor_compat.py +181 -0
  111. package/src/python-utils.ts +57 -0
  112. package/src/resources/actors.ts +92 -0
  113. package/src/resources/assets.ts +251 -0
  114. package/src/resources/levels.ts +83 -0
  115. package/src/tools/actors.ts +480 -0
  116. package/src/tools/animation.ts +713 -0
  117. package/src/tools/assets.ts +305 -0
  118. package/src/tools/audio.ts +548 -0
  119. package/src/tools/blueprint.ts +736 -0
  120. package/src/tools/build_environment_advanced.ts +526 -0
  121. package/src/tools/consolidated-tool-definitions.ts +619 -0
  122. package/src/tools/consolidated-tool-handlers.ts +1093 -0
  123. package/src/tools/debug.ts +368 -0
  124. package/src/tools/editor.ts +360 -0
  125. package/src/tools/engine.ts +32 -0
  126. package/src/tools/foliage.ts +652 -0
  127. package/src/tools/introspection.ts +778 -0
  128. package/src/tools/landscape.ts +523 -0
  129. package/src/tools/level.ts +410 -0
  130. package/src/tools/lighting.ts +1316 -0
  131. package/src/tools/materials.ts +148 -0
  132. package/src/tools/niagara.ts +312 -0
  133. package/src/tools/performance.ts +549 -0
  134. package/src/tools/physics.ts +924 -0
  135. package/src/tools/rc.ts +437 -0
  136. package/src/tools/sequence.ts +791 -0
  137. package/src/tools/tool-definitions.ts +907 -0
  138. package/src/tools/tool-handlers.ts +941 -0
  139. package/src/tools/ui.ts +499 -0
  140. package/src/tools/visual.ts +60 -0
  141. package/src/types/env.ts +27 -0
  142. package/src/types/index.ts +414 -0
  143. package/src/types/tool-types.ts +343 -0
  144. package/src/unreal-bridge.ts +1118 -0
  145. package/src/utils/cache-manager.ts +213 -0
  146. package/src/utils/error-handler.ts +320 -0
  147. package/src/utils/errors.ts +312 -0
  148. package/src/utils/http.ts +184 -0
  149. package/src/utils/logger.ts +30 -0
  150. package/src/utils/normalize.ts +54 -0
  151. package/src/utils/response-validator.ts +145 -0
  152. package/src/utils/safe-json.ts +112 -0
  153. package/src/utils/stdio-redirect.ts +18 -0
  154. package/src/utils/validation.ts +212 -0
  155. package/tsconfig.json +33 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Cache Manager for API responses
3
+ * Implements LRU cache with TTL support for optimizing repeated API calls
4
+ */
5
+ interface CacheOptions {
6
+ maxSize?: number;
7
+ defaultTTL?: number;
8
+ enableMetrics?: boolean;
9
+ }
10
+ interface CacheMetrics {
11
+ hits: number;
12
+ misses: number;
13
+ evictions: number;
14
+ size: number;
15
+ }
16
+ export declare class CacheManager<T = any> {
17
+ private cache;
18
+ private readonly maxSize;
19
+ private readonly defaultTTL;
20
+ private readonly enableMetrics;
21
+ private metrics;
22
+ constructor(options?: CacheOptions);
23
+ /**
24
+ * Get item from cache
25
+ */
26
+ get(key: string): T | null;
27
+ /**
28
+ * Set item in cache
29
+ */
30
+ set(key: string, data: T): void;
31
+ /**
32
+ * Check if key exists and is valid
33
+ */
34
+ has(key: string): boolean;
35
+ /**
36
+ * Clear specific key or all cache
37
+ */
38
+ clear(key?: string): void;
39
+ /**
40
+ * Get cache metrics
41
+ */
42
+ getMetrics(): CacheMetrics;
43
+ /**
44
+ * Get cache hit rate
45
+ */
46
+ getHitRate(): number;
47
+ /**
48
+ * Wrap async function with cache
49
+ */
50
+ wrap<R = T>(key: string, fn: () => Promise<R>): Promise<R>;
51
+ /**
52
+ * Batch get multiple keys
53
+ */
54
+ getBatch(keys: string[]): Map<string, T | null>;
55
+ /**
56
+ * Invalidate cache entries by pattern
57
+ */
58
+ invalidatePattern(pattern: RegExp): number;
59
+ }
60
+ export declare const assetCache: CacheManager<any>;
61
+ export declare const engineCache: CacheManager<any>;
62
+ export declare const commandCache: CacheManager<any>;
63
+ export {};
64
+ //# sourceMappingURL=cache-manager.d.ts.map
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Cache Manager for API responses
3
+ * Implements LRU cache with TTL support for optimizing repeated API calls
4
+ */
5
+ export class CacheManager {
6
+ cache;
7
+ maxSize;
8
+ defaultTTL;
9
+ enableMetrics;
10
+ metrics;
11
+ constructor(options = {}) {
12
+ this.cache = new Map();
13
+ this.maxSize = options.maxSize || 100;
14
+ this.defaultTTL = options.defaultTTL || 60000; // 1 minute default
15
+ this.enableMetrics = options.enableMetrics || false;
16
+ this.metrics = {
17
+ hits: 0,
18
+ misses: 0,
19
+ evictions: 0,
20
+ size: 0
21
+ };
22
+ }
23
+ /**
24
+ * Get item from cache
25
+ */
26
+ get(key) {
27
+ const entry = this.cache.get(key);
28
+ if (!entry) {
29
+ if (this.enableMetrics)
30
+ this.metrics.misses++;
31
+ return null;
32
+ }
33
+ // Check if expired
34
+ if (Date.now() - entry.timestamp > this.defaultTTL) {
35
+ this.cache.delete(key);
36
+ if (this.enableMetrics) {
37
+ this.metrics.misses++;
38
+ this.metrics.size--;
39
+ }
40
+ return null;
41
+ }
42
+ // Update hit count and move to end (LRU)
43
+ entry.hits++;
44
+ this.cache.delete(key);
45
+ this.cache.set(key, entry);
46
+ if (this.enableMetrics)
47
+ this.metrics.hits++;
48
+ return entry.data;
49
+ }
50
+ /**
51
+ * Set item in cache
52
+ */
53
+ set(key, data) {
54
+ // Evict oldest if at max size
55
+ if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
56
+ const firstKey = this.cache.keys().next().value;
57
+ if (firstKey) {
58
+ this.cache.delete(firstKey);
59
+ if (this.enableMetrics) {
60
+ this.metrics.evictions++;
61
+ this.metrics.size--;
62
+ }
63
+ }
64
+ }
65
+ const entry = {
66
+ data,
67
+ timestamp: Date.now(),
68
+ hits: 0
69
+ };
70
+ this.cache.set(key, entry);
71
+ if (this.enableMetrics)
72
+ this.metrics.size = this.cache.size;
73
+ }
74
+ /**
75
+ * Check if key exists and is valid
76
+ */
77
+ has(key) {
78
+ const entry = this.cache.get(key);
79
+ if (!entry)
80
+ return false;
81
+ // Check expiration
82
+ if (Date.now() - entry.timestamp > this.defaultTTL) {
83
+ this.cache.delete(key);
84
+ if (this.enableMetrics)
85
+ this.metrics.size--;
86
+ return false;
87
+ }
88
+ return true;
89
+ }
90
+ /**
91
+ * Clear specific key or all cache
92
+ */
93
+ clear(key) {
94
+ if (key) {
95
+ this.cache.delete(key);
96
+ if (this.enableMetrics)
97
+ this.metrics.size = this.cache.size;
98
+ }
99
+ else {
100
+ this.cache.clear();
101
+ if (this.enableMetrics) {
102
+ this.metrics.size = 0;
103
+ }
104
+ }
105
+ }
106
+ /**
107
+ * Get cache metrics
108
+ */
109
+ getMetrics() {
110
+ return { ...this.metrics };
111
+ }
112
+ /**
113
+ * Get cache hit rate
114
+ */
115
+ getHitRate() {
116
+ const total = this.metrics.hits + this.metrics.misses;
117
+ return total > 0 ? this.metrics.hits / total : 0;
118
+ }
119
+ /**
120
+ * Wrap async function with cache
121
+ */
122
+ async wrap(key, fn) {
123
+ // Check cache first
124
+ const cached = this.get(key);
125
+ if (cached !== null) {
126
+ return cached;
127
+ }
128
+ // Execute function and cache result
129
+ const result = await fn();
130
+ this.set(key, result);
131
+ return result;
132
+ }
133
+ /**
134
+ * Batch get multiple keys
135
+ */
136
+ getBatch(keys) {
137
+ const results = new Map();
138
+ for (const key of keys) {
139
+ results.set(key, this.get(key));
140
+ }
141
+ return results;
142
+ }
143
+ /**
144
+ * Invalidate cache entries by pattern
145
+ */
146
+ invalidatePattern(pattern) {
147
+ let count = 0;
148
+ for (const key of this.cache.keys()) {
149
+ if (pattern.test(key)) {
150
+ this.cache.delete(key);
151
+ count++;
152
+ }
153
+ }
154
+ if (this.enableMetrics) {
155
+ this.metrics.size = this.cache.size;
156
+ }
157
+ return count;
158
+ }
159
+ }
160
+ // Global cache instances for different purposes
161
+ export const assetCache = new CacheManager({
162
+ maxSize: 500,
163
+ defaultTTL: 300000, // 5 minutes for assets
164
+ enableMetrics: true
165
+ });
166
+ export const engineCache = new CacheManager({
167
+ maxSize: 50,
168
+ defaultTTL: 600000, // 10 minutes for engine info
169
+ enableMetrics: true
170
+ });
171
+ export const commandCache = new CacheManager({
172
+ maxSize: 100,
173
+ defaultTTL: 30000, // 30 seconds for commands
174
+ enableMetrics: true
175
+ });
176
+ //# sourceMappingURL=cache-manager.js.map
@@ -0,0 +1,66 @@
1
+ import { BaseToolResponse } from '../types/tool-types.js';
2
+ /**
3
+ * Error types for categorization
4
+ */
5
+ export declare enum ErrorType {
6
+ VALIDATION = "VALIDATION",
7
+ CONNECTION = "CONNECTION",
8
+ UNREAL_ENGINE = "UNREAL_ENGINE",
9
+ PARAMETER = "PARAMETER",
10
+ EXECUTION = "EXECUTION",
11
+ TIMEOUT = "TIMEOUT",
12
+ UNKNOWN = "UNKNOWN"
13
+ }
14
+ /**
15
+ * Custom error class for MCP tools
16
+ */
17
+ export declare class ToolError extends Error {
18
+ type: ErrorType;
19
+ toolName: string;
20
+ originalError?: any | undefined;
21
+ constructor(type: ErrorType, toolName: string, message: string, originalError?: any | undefined);
22
+ }
23
+ /**
24
+ * Consistent error handling for all tools
25
+ */
26
+ export declare class ErrorHandler {
27
+ /**
28
+ * Create a standardized error response
29
+ */
30
+ static createErrorResponse(error: any, toolName: string, context?: any): BaseToolResponse;
31
+ /**
32
+ * Create a standardized warning response
33
+ */
34
+ static createWarningResponse(message: string, result: any, toolName: string): BaseToolResponse;
35
+ /**
36
+ * Create a standardized success response
37
+ */
38
+ static createSuccessResponse(message: string, data?: any): BaseToolResponse;
39
+ /**
40
+ * Categorize error by type
41
+ */
42
+ private static categorizeError;
43
+ /**
44
+ * Get user-friendly error message
45
+ */
46
+ private static getUserFriendlyMessage;
47
+ /** Determine if an error is likely retriable */
48
+ private static isRetriable;
49
+ /**
50
+ * Wrap async function with error handling
51
+ */
52
+ static wrapAsync<T extends BaseToolResponse>(toolName: string, fn: () => Promise<T>, context?: any): Promise<T>;
53
+ /**
54
+ * Validate required parameters
55
+ */
56
+ static validateParams(params: any, required: string[], toolName: string): void;
57
+ /**
58
+ * Handle Unreal Engine specific errors
59
+ */
60
+ static handleUnrealError(error: any, operation: string): string;
61
+ /**
62
+ * Create operation result with consistent structure
63
+ */
64
+ static createResult<T extends BaseToolResponse>(success: boolean, message: string, data?: Partial<T>): T;
65
+ }
66
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1,243 @@
1
+ import { Logger } from './logger.js';
2
+ const log = new Logger('ErrorHandler');
3
+ /**
4
+ * Error types for categorization
5
+ */
6
+ export var ErrorType;
7
+ (function (ErrorType) {
8
+ ErrorType["VALIDATION"] = "VALIDATION";
9
+ ErrorType["CONNECTION"] = "CONNECTION";
10
+ ErrorType["UNREAL_ENGINE"] = "UNREAL_ENGINE";
11
+ ErrorType["PARAMETER"] = "PARAMETER";
12
+ ErrorType["EXECUTION"] = "EXECUTION";
13
+ ErrorType["TIMEOUT"] = "TIMEOUT";
14
+ ErrorType["UNKNOWN"] = "UNKNOWN";
15
+ })(ErrorType || (ErrorType = {}));
16
+ /**
17
+ * Custom error class for MCP tools
18
+ */
19
+ export class ToolError extends Error {
20
+ type;
21
+ toolName;
22
+ originalError;
23
+ constructor(type, toolName, message, originalError) {
24
+ super(message);
25
+ this.type = type;
26
+ this.toolName = toolName;
27
+ this.originalError = originalError;
28
+ this.name = 'ToolError';
29
+ }
30
+ }
31
+ /**
32
+ * Consistent error handling for all tools
33
+ */
34
+ export class ErrorHandler {
35
+ /**
36
+ * Create a standardized error response
37
+ */
38
+ static createErrorResponse(error, toolName, context) {
39
+ const errorType = this.categorizeError(error);
40
+ const userMessage = this.getUserFriendlyMessage(errorType, error);
41
+ const retriable = this.isRetriable(error);
42
+ const scope = context?.scope || `tool-call/${toolName}`;
43
+ log.error(`Tool ${toolName} failed:`, {
44
+ type: errorType,
45
+ message: error.message || error,
46
+ retriable,
47
+ scope,
48
+ context
49
+ });
50
+ return {
51
+ success: false,
52
+ error: userMessage,
53
+ message: `Failed to execute ${toolName}: ${userMessage}`,
54
+ retriable: retriable,
55
+ scope: scope,
56
+ // Add debug info in development
57
+ ...(process.env.NODE_ENV === 'development' && {
58
+ _debug: {
59
+ errorType,
60
+ originalError: error.message || String(error),
61
+ stack: error.stack,
62
+ context,
63
+ retriable,
64
+ scope
65
+ }
66
+ })
67
+ };
68
+ }
69
+ /**
70
+ * Create a standardized warning response
71
+ */
72
+ static createWarningResponse(message, result, toolName) {
73
+ log.warn(`Tool ${toolName} warning: ${message}`);
74
+ return {
75
+ success: true,
76
+ warning: message,
77
+ message: `${toolName} completed with warnings`,
78
+ ...result
79
+ };
80
+ }
81
+ /**
82
+ * Create a standardized success response
83
+ */
84
+ static createSuccessResponse(message, data = {}) {
85
+ return {
86
+ success: true,
87
+ message,
88
+ ...data
89
+ };
90
+ }
91
+ /**
92
+ * Categorize error by type
93
+ */
94
+ static categorizeError(error) {
95
+ if (error instanceof ToolError) {
96
+ return error.type;
97
+ }
98
+ const errorMessage = error.message?.toLowerCase() || String(error).toLowerCase();
99
+ // Connection errors
100
+ if (errorMessage.includes('econnrefused') ||
101
+ errorMessage.includes('timeout') ||
102
+ errorMessage.includes('connection') ||
103
+ errorMessage.includes('network')) {
104
+ return ErrorType.CONNECTION;
105
+ }
106
+ // Validation errors
107
+ if (errorMessage.includes('invalid') ||
108
+ errorMessage.includes('required') ||
109
+ errorMessage.includes('must be') ||
110
+ errorMessage.includes('validation')) {
111
+ return ErrorType.VALIDATION;
112
+ }
113
+ // Unreal Engine specific errors
114
+ if (errorMessage.includes('unreal') ||
115
+ errorMessage.includes('remote control') ||
116
+ errorMessage.includes('blueprint') ||
117
+ errorMessage.includes('actor') ||
118
+ errorMessage.includes('asset')) {
119
+ return ErrorType.UNREAL_ENGINE;
120
+ }
121
+ // Parameter errors
122
+ if (errorMessage.includes('parameter') ||
123
+ errorMessage.includes('argument') ||
124
+ errorMessage.includes('missing')) {
125
+ return ErrorType.PARAMETER;
126
+ }
127
+ // Timeout errors
128
+ if (errorMessage.includes('timeout')) {
129
+ return ErrorType.TIMEOUT;
130
+ }
131
+ return ErrorType.UNKNOWN;
132
+ }
133
+ /**
134
+ * Get user-friendly error message
135
+ */
136
+ static getUserFriendlyMessage(type, error) {
137
+ const originalMessage = error.message || String(error);
138
+ switch (type) {
139
+ case ErrorType.CONNECTION:
140
+ return 'Failed to connect to Unreal Engine. Please ensure Remote Control is enabled and the engine is running.';
141
+ case ErrorType.VALIDATION:
142
+ return `Invalid input: ${originalMessage}`;
143
+ case ErrorType.UNREAL_ENGINE:
144
+ return `Unreal Engine error: ${originalMessage}`;
145
+ case ErrorType.PARAMETER:
146
+ return `Invalid parameters: ${originalMessage}`;
147
+ case ErrorType.TIMEOUT:
148
+ return 'Operation timed out. Unreal Engine may be busy or unresponsive.';
149
+ case ErrorType.EXECUTION:
150
+ return `Execution failed: ${originalMessage}`;
151
+ default:
152
+ return originalMessage;
153
+ }
154
+ }
155
+ /** Determine if an error is likely retriable */
156
+ static isRetriable(error) {
157
+ try {
158
+ const code = (error?.code || '').toString().toUpperCase();
159
+ const msg = (error?.message || String(error) || '').toLowerCase();
160
+ const status = Number((error?.response?.status));
161
+ if (['ECONNRESET', 'ECONNREFUSED', 'ETIMEDOUT', 'EPIPE'].includes(code))
162
+ return true;
163
+ if (/timeout|timed out|network|connection|closed|unavailable|busy|temporar/.test(msg))
164
+ return true;
165
+ if (!isNaN(status) && (status === 429 || (status >= 500 && status < 600)))
166
+ return true;
167
+ }
168
+ catch { }
169
+ return false;
170
+ }
171
+ /**
172
+ * Wrap async function with error handling
173
+ */
174
+ static async wrapAsync(toolName, fn, context) {
175
+ try {
176
+ const result = await fn();
177
+ // Ensure result has success field
178
+ if (typeof result === 'object' && result !== null) {
179
+ if (!('success' in result)) {
180
+ result.success = true;
181
+ }
182
+ }
183
+ return result;
184
+ }
185
+ catch (error) {
186
+ return this.createErrorResponse(error, toolName, context);
187
+ }
188
+ }
189
+ /**
190
+ * Validate required parameters
191
+ */
192
+ static validateParams(params, required, toolName) {
193
+ if (!params || typeof params !== 'object') {
194
+ throw new ToolError(ErrorType.PARAMETER, toolName, 'Invalid parameters: expected object');
195
+ }
196
+ for (const field of required) {
197
+ if (!(field in params) || params[field] === undefined || params[field] === null) {
198
+ throw new ToolError(ErrorType.PARAMETER, toolName, `Missing required parameter: ${field}`);
199
+ }
200
+ // Additional validation for common types
201
+ if (field.includes('Path') || field.includes('Name')) {
202
+ if (typeof params[field] !== 'string' || params[field].trim() === '') {
203
+ throw new ToolError(ErrorType.PARAMETER, toolName, `Invalid ${field}: must be a non-empty string`);
204
+ }
205
+ }
206
+ }
207
+ }
208
+ /**
209
+ * Handle Unreal Engine specific errors
210
+ */
211
+ static handleUnrealError(error, operation) {
212
+ const errorStr = String(error.message || error).toLowerCase();
213
+ // Common Unreal errors
214
+ if (errorStr.includes('worldcontext')) {
215
+ return `${operation} completed (WorldContext warnings are normal)`;
216
+ }
217
+ if (errorStr.includes('does not exist')) {
218
+ return `Asset or object not found for ${operation}`;
219
+ }
220
+ if (errorStr.includes('access denied') || errorStr.includes('read-only')) {
221
+ return `Permission denied for ${operation}. Check file permissions.`;
222
+ }
223
+ if (errorStr.includes('already exists')) {
224
+ return `Object already exists for ${operation}`;
225
+ }
226
+ return `Unreal Engine error during ${operation}: ${error.message || error}`;
227
+ }
228
+ /**
229
+ * Create operation result with consistent structure
230
+ */
231
+ static createResult(success, message, data) {
232
+ const result = {
233
+ success,
234
+ message,
235
+ ...(data || {})
236
+ };
237
+ if (!success && !result.error) {
238
+ result.error = message;
239
+ }
240
+ return result;
241
+ }
242
+ }
243
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Enhanced error types for better error handling and recovery
3
+ */
4
+ export declare enum ErrorCode {
5
+ CONNECTION_FAILED = "CONNECTION_FAILED",
6
+ CONNECTION_TIMEOUT = "CONNECTION_TIMEOUT",
7
+ CONNECTION_REFUSED = "CONNECTION_REFUSED",
8
+ API_ERROR = "API_ERROR",
9
+ INVALID_RESPONSE = "INVALID_RESPONSE",
10
+ RATE_LIMITED = "RATE_LIMITED",
11
+ VALIDATION_ERROR = "VALIDATION_ERROR",
12
+ INVALID_PARAMETERS = "INVALID_PARAMETERS",
13
+ MISSING_REQUIRED_FIELD = "MISSING_REQUIRED_FIELD",
14
+ RESOURCE_NOT_FOUND = "RESOURCE_NOT_FOUND",
15
+ RESOURCE_LOCKED = "RESOURCE_LOCKED",
16
+ RESOURCE_UNAVAILABLE = "RESOURCE_UNAVAILABLE",
17
+ UNAUTHORIZED = "UNAUTHORIZED",
18
+ FORBIDDEN = "FORBIDDEN",
19
+ INTERNAL_ERROR = "INTERNAL_ERROR",
20
+ CIRCUIT_BREAKER_OPEN = "CIRCUIT_BREAKER_OPEN",
21
+ SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE"
22
+ }
23
+ export interface ErrorMetadata {
24
+ code: ErrorCode;
25
+ statusCode?: number;
26
+ retriable: boolean;
27
+ context?: Record<string, any>;
28
+ timestamp: Date;
29
+ correlationId?: string;
30
+ }
31
+ /**
32
+ * Base application error with metadata
33
+ */
34
+ export declare class AppError extends Error {
35
+ readonly metadata: ErrorMetadata;
36
+ constructor(message: string, metadata?: Partial<ErrorMetadata>);
37
+ toJSON(): {
38
+ stack: string | undefined;
39
+ code: ErrorCode;
40
+ statusCode?: number;
41
+ retriable: boolean;
42
+ context?: Record<string, any>;
43
+ timestamp: Date;
44
+ correlationId?: string;
45
+ name: string;
46
+ message: string;
47
+ };
48
+ }
49
+ /**
50
+ * Connection-related errors
51
+ */
52
+ export declare class ConnectionError extends AppError {
53
+ constructor(message: string, metadata?: Partial<ErrorMetadata>);
54
+ }
55
+ /**
56
+ * API-related errors
57
+ */
58
+ export declare class ApiError extends AppError {
59
+ constructor(message: string, statusCode: number, metadata?: Partial<ErrorMetadata>);
60
+ }
61
+ /**
62
+ * Validation errors
63
+ */
64
+ export declare class ValidationError extends AppError {
65
+ constructor(message: string, metadata?: Partial<ErrorMetadata>);
66
+ }
67
+ /**
68
+ * Resource errors
69
+ */
70
+ export declare class ResourceError extends AppError {
71
+ constructor(message: string, code: ErrorCode, metadata?: Partial<ErrorMetadata>);
72
+ }
73
+ /**
74
+ * Circuit Breaker implementation for fault tolerance
75
+ */
76
+ export declare enum CircuitState {
77
+ CLOSED = "CLOSED",
78
+ OPEN = "OPEN",
79
+ HALF_OPEN = "HALF_OPEN"
80
+ }
81
+ interface CircuitBreakerOptions {
82
+ threshold: number;
83
+ timeout: number;
84
+ resetTimeout: number;
85
+ onStateChange?: (oldState: CircuitState, newState: CircuitState) => void;
86
+ }
87
+ export declare class CircuitBreaker {
88
+ private state;
89
+ private failures;
90
+ private successCount;
91
+ private lastFailureTime?;
92
+ private readonly options;
93
+ constructor(options?: Partial<CircuitBreakerOptions>);
94
+ /**
95
+ * Execute function with circuit breaker protection
96
+ */
97
+ execute<T>(fn: () => Promise<T>): Promise<T>;
98
+ private onSuccess;
99
+ private onFailure;
100
+ private shouldAttemptReset;
101
+ private transitionTo;
102
+ getState(): CircuitState;
103
+ getMetrics(): {
104
+ state: CircuitState;
105
+ failures: number;
106
+ successCount: number;
107
+ lastFailureTime: Date | undefined;
108
+ };
109
+ }
110
+ /**
111
+ * Error recovery strategies
112
+ */
113
+ export declare class ErrorRecovery {
114
+ private static circuitBreakers;
115
+ /**
116
+ * Get or create circuit breaker for a service
117
+ */
118
+ static getCircuitBreaker(service: string, options?: Partial<CircuitBreakerOptions>): CircuitBreaker;
119
+ /**
120
+ * Wrap function with error recovery
121
+ */
122
+ static withRecovery<T>(fn: () => Promise<T>, options: {
123
+ service: string;
124
+ fallback?: () => T | Promise<T>;
125
+ onError?: (error: Error) => void;
126
+ }): Promise<T>;
127
+ /**
128
+ * Check if error is retriable
129
+ */
130
+ static isRetriable(error: Error): boolean;
131
+ }
132
+ export {};
133
+ //# sourceMappingURL=errors.d.ts.map