@lydt/geogebra-studio 0.0.0-stage → 0.4.0-rc.2

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 (189) hide show
  1. package/.agents/plugins/marketplace.json +21 -0
  2. package/.codex-plugin/plugin.json +21 -0
  3. package/.mcp.json +18 -0
  4. package/LICENSE +339 -0
  5. package/LICENSE-MIT +21 -0
  6. package/README.md +108 -2
  7. package/README.zh-CN.md +89 -0
  8. package/THIRD_PARTY_NOTICES.md +35 -0
  9. package/dist/cli.d.ts +27 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +234 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/export/files.d.ts +4 -0
  14. package/dist/export/files.d.ts.map +1 -0
  15. package/dist/export/files.js +44 -0
  16. package/dist/export/files.js.map +1 -0
  17. package/dist/export/gikz.d.ts +11 -0
  18. package/dist/export/gikz.d.ts.map +1 -0
  19. package/dist/export/gikz.js +28 -0
  20. package/dist/export/gikz.js.map +1 -0
  21. package/dist/export/html.d.ts +14 -0
  22. package/dist/export/html.d.ts.map +1 -0
  23. package/dist/export/html.js +97 -0
  24. package/dist/export/html.js.map +1 -0
  25. package/dist/export/semantic.d.ts +43 -0
  26. package/dist/export/semantic.d.ts.map +1 -0
  27. package/dist/export/semantic.js +212 -0
  28. package/dist/export/semantic.js.map +1 -0
  29. package/dist/export/viewer-themes.d.ts +76 -0
  30. package/dist/export/viewer-themes.d.ts.map +1 -0
  31. package/dist/export/viewer-themes.js +169 -0
  32. package/dist/export/viewer-themes.js.map +1 -0
  33. package/dist/export/workspace.d.ts +4 -0
  34. package/dist/export/workspace.d.ts.map +1 -0
  35. package/dist/export/workspace.js +25 -0
  36. package/dist/export/workspace.js.map +1 -0
  37. package/dist/gikz-browser.js +770 -0
  38. package/dist/index.d.ts +5 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +84 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/server.d.ts +35 -0
  43. package/dist/server.d.ts.map +1 -0
  44. package/dist/server.js +187 -0
  45. package/dist/server.js.map +1 -0
  46. package/dist/studio/artifact.d.ts +37 -0
  47. package/dist/studio/artifact.d.ts.map +1 -0
  48. package/dist/studio/artifact.js +61 -0
  49. package/dist/studio/artifact.js.map +1 -0
  50. package/dist/studio/browser.d.ts +7 -0
  51. package/dist/studio/browser.d.ts.map +1 -0
  52. package/dist/studio/browser.js +67 -0
  53. package/dist/studio/browser.js.map +1 -0
  54. package/dist/studio/install.d.ts +4 -0
  55. package/dist/studio/install.d.ts.map +1 -0
  56. package/dist/studio/install.js +60 -0
  57. package/dist/studio/install.js.map +1 -0
  58. package/dist/tools/apps-api-tools.d.ts +4 -0
  59. package/dist/tools/apps-api-tools.d.ts.map +1 -0
  60. package/dist/tools/apps-api-tools.js +96 -0
  61. package/dist/tools/apps-api-tools.js.map +1 -0
  62. package/dist/tools/educational-templates.d.ts +33 -0
  63. package/dist/tools/educational-templates.d.ts.map +1 -0
  64. package/dist/tools/educational-templates.js +261 -0
  65. package/dist/tools/educational-templates.js.map +1 -0
  66. package/dist/tools/export-tools.d.ts +3 -0
  67. package/dist/tools/export-tools.d.ts.map +1 -0
  68. package/dist/tools/export-tools.js +118 -0
  69. package/dist/tools/export-tools.js.map +1 -0
  70. package/dist/tools/geogebra-tools.d.ts +15 -0
  71. package/dist/tools/geogebra-tools.d.ts.map +1 -0
  72. package/dist/tools/geogebra-tools.js +3442 -0
  73. package/dist/tools/geogebra-tools.js.map +1 -0
  74. package/dist/tools/index.d.ts +43 -0
  75. package/dist/tools/index.d.ts.map +1 -0
  76. package/dist/tools/index.js +183 -0
  77. package/dist/tools/index.js.map +1 -0
  78. package/dist/tools/performance-tools.d.ts +7 -0
  79. package/dist/tools/performance-tools.d.ts.map +1 -0
  80. package/dist/tools/performance-tools.js +312 -0
  81. package/dist/tools/performance-tools.js.map +1 -0
  82. package/dist/tools/templates/algebra-templates.d.ts +7 -0
  83. package/dist/tools/templates/algebra-templates.d.ts.map +1 -0
  84. package/dist/tools/templates/algebra-templates.js +568 -0
  85. package/dist/tools/templates/algebra-templates.js.map +1 -0
  86. package/dist/tools/templates/geometry-templates.d.ts +7 -0
  87. package/dist/tools/templates/geometry-templates.d.ts.map +1 -0
  88. package/dist/tools/templates/geometry-templates.js +492 -0
  89. package/dist/tools/templates/geometry-templates.js.map +1 -0
  90. package/dist/types/geogebra.d.ts +103 -0
  91. package/dist/types/geogebra.d.ts.map +1 -0
  92. package/dist/types/geogebra.js +34 -0
  93. package/dist/types/geogebra.js.map +1 -0
  94. package/dist/types/mcp.d.ts +125 -0
  95. package/dist/types/mcp.d.ts.map +1 -0
  96. package/dist/types/mcp.js +19 -0
  97. package/dist/types/mcp.js.map +1 -0
  98. package/dist/utils/app-info.d.ts +12 -0
  99. package/dist/utils/app-info.d.ts.map +1 -0
  100. package/dist/utils/app-info.js +30 -0
  101. package/dist/utils/app-info.js.map +1 -0
  102. package/dist/utils/errors.d.ts +37 -0
  103. package/dist/utils/errors.d.ts.map +1 -0
  104. package/dist/utils/errors.js +72 -0
  105. package/dist/utils/errors.js.map +1 -0
  106. package/dist/utils/gemini-compatibility.d.ts +39 -0
  107. package/dist/utils/gemini-compatibility.d.ts.map +1 -0
  108. package/dist/utils/gemini-compatibility.js +154 -0
  109. package/dist/utils/gemini-compatibility.js.map +1 -0
  110. package/dist/utils/geogebra-instance.d.ts +252 -0
  111. package/dist/utils/geogebra-instance.d.ts.map +1 -0
  112. package/dist/utils/geogebra-instance.js +1560 -0
  113. package/dist/utils/geogebra-instance.js.map +1 -0
  114. package/dist/utils/geogebra-mock.d.ts +172 -0
  115. package/dist/utils/geogebra-mock.d.ts.map +1 -0
  116. package/dist/utils/geogebra-mock.js +732 -0
  117. package/dist/utils/geogebra-mock.js.map +1 -0
  118. package/dist/utils/logger.d.ts +4 -0
  119. package/dist/utils/logger.d.ts.map +1 -0
  120. package/dist/utils/logger.js +46 -0
  121. package/dist/utils/logger.js.map +1 -0
  122. package/dist/utils/performance/index.d.ts +76 -0
  123. package/dist/utils/performance/index.d.ts.map +1 -0
  124. package/dist/utils/performance/index.js +163 -0
  125. package/dist/utils/performance/index.js.map +1 -0
  126. package/dist/utils/performance/instance-pool.d.ts +78 -0
  127. package/dist/utils/performance/instance-pool.d.ts.map +1 -0
  128. package/dist/utils/performance/instance-pool.js +268 -0
  129. package/dist/utils/performance/instance-pool.js.map +1 -0
  130. package/dist/utils/validation.d.ts +92 -0
  131. package/dist/utils/validation.d.ts.map +1 -0
  132. package/dist/utils/validation.js +557 -0
  133. package/dist/utils/validation.js.map +1 -0
  134. package/dist/widget.html +110 -0
  135. package/docs/APPS-API-BRIDGE.md +28 -0
  136. package/docs/MODERNIZATION.md +15 -0
  137. package/docs/TANGENT-REGRESSION.md +34 -0
  138. package/docs/VALIDATION.md +26 -0
  139. package/docs/VISUAL-STANDARD.md +26 -0
  140. package/docs/images/native-construction.png +0 -0
  141. package/examples/tangent-construction.json +26 -0
  142. package/gikz/LICENSE +339 -0
  143. package/gikz/PROVENANCE.md +8 -0
  144. package/gikz/browser.cjs +2 -0
  145. package/gikz/cli.cjs +195 -0
  146. package/gikz/core.cjs +806 -0
  147. package/mcp.json +20 -0
  148. package/package.json +107 -4
  149. package/plugin.json +35 -0
  150. package/runtime/package.json +4 -0
  151. package/scripts/build-plugin.cjs +15 -0
  152. package/scripts/build-widget.cjs +7 -0
  153. package/skills/geogebra-construct/SKILL.md +40 -0
  154. package/skills/geogebra-setup/SKILL.md +37 -0
  155. package/skills/geometry-export/SKILL.md +31 -0
  156. package/src/cli.ts +212 -0
  157. package/src/export/files.ts +26 -0
  158. package/src/export/gikz.ts +22 -0
  159. package/src/export/html.ts +108 -0
  160. package/src/export/semantic.ts +180 -0
  161. package/src/export/viewer-themes.ts +165 -0
  162. package/src/export/workspace.ts +15 -0
  163. package/src/index.ts +71 -0
  164. package/src/server.ts +168 -0
  165. package/src/studio/artifact.ts +50 -0
  166. package/src/studio/browser.ts +38 -0
  167. package/src/studio/install.ts +43 -0
  168. package/src/tools/apps-api-tools.ts +96 -0
  169. package/src/tools/educational-templates.ts +299 -0
  170. package/src/tools/export-tools.ts +110 -0
  171. package/src/tools/geogebra-tools.ts +3836 -0
  172. package/src/tools/index.ts +192 -0
  173. package/src/tools/performance-tools.ts +322 -0
  174. package/src/tools/templates/algebra-templates.ts +619 -0
  175. package/src/tools/templates/geometry-templates.ts +550 -0
  176. package/src/types/geogebra.ts +140 -0
  177. package/src/types/global.d.ts +31 -0
  178. package/src/types/mcp.ts +141 -0
  179. package/src/utils/app-info.ts +35 -0
  180. package/src/utils/errors.ts +97 -0
  181. package/src/utils/gemini-compatibility.ts +193 -0
  182. package/src/utils/geogebra-instance.ts +1712 -0
  183. package/src/utils/geogebra-mock.ts +867 -0
  184. package/src/utils/logger.ts +60 -0
  185. package/src/utils/performance/index.ts +211 -0
  186. package/src/utils/performance/instance-pool.ts +323 -0
  187. package/src/utils/validation.ts +647 -0
  188. package/tsconfig.json +35 -0
  189. package/widget/main.ts +12 -0
@@ -0,0 +1,192 @@
1
+ import { McpTool, ToolDefinition } from '../types/mcp';
2
+ import { errors } from '../utils/errors';
3
+ import logger from '../utils/logger';
4
+ import { getAppInfo } from '../utils/app-info';
5
+ import { geogebraTools } from './geogebra-tools';
6
+ import { exportTools } from './export-tools';
7
+ import { educationalTemplateTools } from './educational-templates';
8
+ import { performanceTools } from './performance-tools';
9
+ import { appsApiTools } from './apps-api-tools';
10
+
11
+ // Check if we're in MCP mode (stdio communication)
12
+ // When piping input, process.stdin.isTTY is undefined, not false
13
+ const isMcpMode = !process.stdin.isTTY;
14
+ const appInfo = getAppInfo();
15
+
16
+ /**
17
+ * Tool Registry for managing MCP tools
18
+ */
19
+ export class ToolRegistry {
20
+ private tools: Map<string, ToolDefinition> = new Map();
21
+
22
+ /**
23
+ * Register a new tool
24
+ */
25
+ register(definition: ToolDefinition): void {
26
+ const name = definition.tool.name;
27
+ const readOnly = ['echo', 'ping', 'server_info', 'geogebra_get_objects',
28
+ 'geogebra_instance_status', 'geogebra_get_prompt_framework', 'geogebra_get_semantic_scene'].includes(name);
29
+ definition.tool.annotations ??= {
30
+ readOnlyHint: readOnly,
31
+ destructiveHint: !readOnly,
32
+ idempotentHint: readOnly,
33
+ openWorldHint: name.startsWith('geogebra_') && !['geogebra_create_html', 'geogebra_clean_tikz'].includes(name),
34
+ };
35
+ this.tools.set(name, definition);
36
+ if (!isMcpMode) {
37
+ logger.info(`Registered tool: ${definition.tool.name}`);
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Get all registered tools
43
+ */
44
+ getTools(): McpTool[] {
45
+ return Array.from(this.tools.values()).map(def => def.tool);
46
+ }
47
+
48
+ /**
49
+ * Get a specific tool by name
50
+ */
51
+ getTool(name: string): ToolDefinition | undefined {
52
+ return this.tools.get(name);
53
+ }
54
+
55
+ /**
56
+ * Execute a tool by name with given parameters
57
+ */
58
+ async executeTool(name: string, params: Record<string, unknown> = {}) {
59
+ const toolDef = this.tools.get(name);
60
+
61
+ if (!toolDef) {
62
+ throw errors.toolNotFound(name);
63
+ }
64
+
65
+ try {
66
+ if (!isMcpMode) {
67
+ logger.info(`Executing tool: ${name}`, { params });
68
+ }
69
+ const result = await toolDef.handler(params);
70
+ if (!isMcpMode) {
71
+ logger.info(`Tool execution completed: ${name}`);
72
+ }
73
+ return result;
74
+ } catch (error) {
75
+ logger.error(`Tool execution failed: ${name}`, error);
76
+ throw errors.toolExecutionError(name, error instanceof Error ? error.message : String(error));
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Check if a tool exists
82
+ */
83
+ hasTool(name: string): boolean {
84
+ return this.tools.has(name);
85
+ }
86
+
87
+ /**
88
+ * Get the number of registered tools
89
+ */
90
+ getToolCount(): number {
91
+ return this.tools.size;
92
+ }
93
+ }
94
+
95
+ // Create global tool registry instance
96
+ export const toolRegistry = new ToolRegistry();
97
+
98
+ // Example tools for testing and demonstration
99
+ const exampleTools: ToolDefinition[] = [
100
+ {
101
+ tool: {
102
+ name: 'echo',
103
+ description: 'Echo back the provided message',
104
+ inputSchema: {
105
+ type: 'object',
106
+ properties: {
107
+ message: {
108
+ type: 'string',
109
+ description: 'The message to echo back'
110
+ }
111
+ },
112
+ required: ['message']
113
+ }
114
+ },
115
+ handler: async (params: Record<string, unknown>) => {
116
+ const message = params['message'] as string;
117
+ return {
118
+ content: [{
119
+ type: 'text' as const,
120
+ text: `Echo: ${message}`
121
+ }]
122
+ };
123
+ }
124
+ },
125
+ {
126
+ tool: {
127
+ name: 'ping',
128
+ description: 'Simple ping tool that returns pong',
129
+ inputSchema: {
130
+ type: 'object',
131
+ properties: {},
132
+ required: []
133
+ }
134
+ },
135
+ handler: async () => {
136
+ return {
137
+ content: [{
138
+ type: 'text' as const,
139
+ text: 'pong'
140
+ }]
141
+ };
142
+ }
143
+ },
144
+ {
145
+ tool: {
146
+ name: 'server_info',
147
+ description: 'Get information about the MCP server',
148
+ inputSchema: {
149
+ type: 'object',
150
+ properties: {},
151
+ required: []
152
+ }
153
+ },
154
+ handler: async () => {
155
+ return {
156
+ content: [{
157
+ type: 'text' as const,
158
+ text: JSON.stringify({
159
+ name: 'GeoGebra Studio',
160
+ version: appInfo.version,
161
+ description: appInfo.description,
162
+ toolCount: toolRegistry.getToolCount(),
163
+ timestamp: new Date().toISOString()
164
+ }, null, 2)
165
+ }]
166
+ };
167
+ }
168
+ }
169
+ ];
170
+
171
+ // Register example tools
172
+ exampleTools.forEach(tool => {
173
+ toolRegistry.register(tool);
174
+ });
175
+
176
+ // Register GeoGebra tools
177
+ geogebraTools.forEach(tool => {
178
+ toolRegistry.register(tool);
179
+ });
180
+
181
+ // Register Educational Template tools
182
+ educationalTemplateTools.forEach(tool => {
183
+ toolRegistry.register(tool);
184
+ });
185
+
186
+ // Register Performance tools
187
+ performanceTools.forEach(tool => {
188
+ toolRegistry.register(tool);
189
+ });
190
+
191
+ exportTools.forEach(tool => toolRegistry.register(tool));
192
+ appsApiTools.forEach(tool => toolRegistry.register(tool));
@@ -0,0 +1,322 @@
1
+ /**
2
+ * Performance Optimization Tools
3
+ * GEB-9: Performance Optimization: Response Time and Resource Management
4
+ */
5
+
6
+ import { ToolDefinition } from '../types/mcp';
7
+ import { performanceMonitor } from '../utils/performance';
8
+ import { optimizedInstancePool } from '../utils/performance/instance-pool';
9
+ import logger from '../utils/logger';
10
+
11
+ export const performanceTools: ToolDefinition[] = [
12
+ {
13
+ tool: {
14
+ name: 'performance_get_stats',
15
+ description: 'Get performance statistics for operations',
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {
19
+ operationName: {
20
+ type: 'string',
21
+ description: 'Specific operation name to get stats for (optional - if not provided, gets overall stats)'
22
+ }
23
+ }
24
+ }
25
+ },
26
+ handler: async (params) => {
27
+ try {
28
+ const operationName = params['operationName'] as string | undefined;
29
+ const stats = performanceMonitor.getStats(operationName);
30
+ const operationNames = performanceMonitor.getOperationNames();
31
+
32
+ return {
33
+ content: [{
34
+ type: 'text' as const,
35
+ text: JSON.stringify({
36
+ success: true,
37
+ operationName: operationName || 'overall',
38
+ stats,
39
+ availableOperations: operationNames,
40
+ summary: {
41
+ totalOperations: stats.count,
42
+ averageResponseTime: `${stats.averageDuration.toFixed(2)}ms`,
43
+ successRate: `${(stats.successRate * 100).toFixed(1)}%`,
44
+ p95ResponseTime: `${stats.p95Duration.toFixed(2)}ms`,
45
+ performanceStatus: stats.p95Duration < 2000 ? 'GOOD' : 'NEEDS_ATTENTION'
46
+ }
47
+ }, null, 2)
48
+ }]
49
+ };
50
+ } catch (error) {
51
+ logger.error('Failed to get performance stats', error);
52
+ return {
53
+ content: [{
54
+ type: 'text' as const,
55
+ text: JSON.stringify({
56
+ success: false,
57
+ error: error instanceof Error ? error.message : String(error)
58
+ }, null, 2)
59
+ }],
60
+ isError: true
61
+ };
62
+ }
63
+ }
64
+ },
65
+
66
+ {
67
+ tool: {
68
+ name: 'performance_get_pool_stats',
69
+ description: 'Get instance pool performance and resource statistics',
70
+ inputSchema: {
71
+ type: 'object',
72
+ properties: {}
73
+ }
74
+ },
75
+ handler: async () => {
76
+ try {
77
+ const poolStats = optimizedInstancePool.getStats();
78
+
79
+ return {
80
+ content: [{
81
+ type: 'text' as const,
82
+ text: JSON.stringify({
83
+ success: true,
84
+ poolStats,
85
+ resourceStatus: {
86
+ memoryUsage: `${poolStats.memoryEstimate}MB estimated`,
87
+ efficiency: poolStats.averageUsage > 5 ? 'HIGH' : 'NORMAL',
88
+ poolUtilization: `${((poolStats.activeInstances / poolStats.totalInstances) * 100).toFixed(1)}%`,
89
+ recommendation: poolStats.totalInstances === 0
90
+ ? 'Pool empty - instances will be created on demand'
91
+ : poolStats.averageUsage > 10
92
+ ? 'Consider increasing pool size for high usage'
93
+ : 'Pool size appropriate for current usage'
94
+ }
95
+ }, null, 2)
96
+ }]
97
+ };
98
+ } catch (error) {
99
+ logger.error('Failed to get pool stats', error);
100
+ return {
101
+ content: [{
102
+ type: 'text' as const,
103
+ text: JSON.stringify({
104
+ success: false,
105
+ error: error instanceof Error ? error.message : String(error)
106
+ }, null, 2)
107
+ }],
108
+ isError: true
109
+ };
110
+ }
111
+ }
112
+ },
113
+
114
+ {
115
+ tool: {
116
+ name: 'performance_warm_up_pool',
117
+ description: 'Pre-warm the instance pool for better performance',
118
+ inputSchema: {
119
+ type: 'object',
120
+ properties: {
121
+ count: {
122
+ type: 'number',
123
+ description: 'Number of instances to pre-create (default: 1, max: 3)',
124
+ minimum: 1,
125
+ maximum: 3
126
+ }
127
+ }
128
+ }
129
+ },
130
+ handler: async (params) => {
131
+ try {
132
+ const count = Math.min((params['count'] as number) || 1, 3);
133
+
134
+ const startTime = Date.now();
135
+ await optimizedInstancePool.warmUp(count);
136
+ const duration = Date.now() - startTime;
137
+
138
+ const poolStats = optimizedInstancePool.getStats();
139
+
140
+ return {
141
+ content: [{
142
+ type: 'text' as const,
143
+ text: JSON.stringify({
144
+ success: true,
145
+ message: `Pool warmed up with ${count} instances`,
146
+ warmUpTime: `${duration}ms`,
147
+ poolStats: {
148
+ totalInstances: poolStats.totalInstances,
149
+ memoryEstimate: `${poolStats.memoryEstimate}MB`
150
+ }
151
+ }, null, 2)
152
+ }]
153
+ };
154
+ } catch (error) {
155
+ logger.error('Failed to warm up pool', error);
156
+ return {
157
+ content: [{
158
+ type: 'text' as const,
159
+ text: JSON.stringify({
160
+ success: false,
161
+ error: error instanceof Error ? error.message : String(error)
162
+ }, null, 2)
163
+ }],
164
+ isError: true
165
+ };
166
+ }
167
+ }
168
+ },
169
+
170
+ {
171
+ tool: {
172
+ name: 'performance_clear_metrics',
173
+ description: 'Clear all performance metrics (useful for testing)',
174
+ inputSchema: {
175
+ type: 'object',
176
+ properties: {}
177
+ }
178
+ },
179
+ handler: async () => {
180
+ try {
181
+ performanceMonitor.clearMetrics();
182
+
183
+ return {
184
+ content: [{
185
+ type: 'text' as const,
186
+ text: JSON.stringify({
187
+ success: true,
188
+ message: 'All performance metrics cleared'
189
+ }, null, 2)
190
+ }]
191
+ };
192
+ } catch (error) {
193
+ logger.error('Failed to clear metrics', error);
194
+ return {
195
+ content: [{
196
+ type: 'text' as const,
197
+ text: JSON.stringify({
198
+ success: false,
199
+ error: error instanceof Error ? error.message : String(error)
200
+ }, null, 2)
201
+ }],
202
+ isError: true
203
+ };
204
+ }
205
+ }
206
+ },
207
+
208
+ {
209
+ tool: {
210
+ name: 'performance_benchmark',
211
+ description: 'Run performance benchmark tests',
212
+ inputSchema: {
213
+ type: 'object',
214
+ properties: {
215
+ testType: {
216
+ type: 'string',
217
+ description: 'Type of benchmark to run',
218
+ enum: ['basic', 'command_execution', 'export_operations', 'all']
219
+ },
220
+ iterations: {
221
+ type: 'number',
222
+ description: 'Number of iterations to run (default: 5)',
223
+ minimum: 1,
224
+ maximum: 20
225
+ }
226
+ },
227
+ required: ['testType']
228
+ }
229
+ },
230
+ handler: async (params) => {
231
+ try {
232
+ const testType = params['testType'] as string;
233
+ const iterations = Math.min((params['iterations'] as number) || 5, 20);
234
+
235
+ const benchmarkResults: any = {
236
+ testType,
237
+ iterations,
238
+ results: [],
239
+ summary: {}
240
+ };
241
+
242
+ const instance = await optimizedInstancePool.getInstance();
243
+
244
+ try {
245
+ if (testType === 'basic' || testType === 'all') {
246
+ // Basic command execution benchmark
247
+ const durations: number[] = [];
248
+ for (let i = 0; i < iterations; i++) {
249
+ const startTime = Date.now();
250
+ await instance.evalCommand(`TestPoint${i} = (${i}, ${i})`);
251
+ durations.push(Date.now() - startTime);
252
+ }
253
+
254
+ benchmarkResults.results.push({
255
+ operation: 'basic_command_execution',
256
+ durations,
257
+ average: durations.reduce((a, b) => a + b, 0) / durations.length,
258
+ min: Math.min(...durations),
259
+ max: Math.max(...durations)
260
+ });
261
+ }
262
+
263
+ if (testType === 'export_operations' || testType === 'all') {
264
+ // Export benchmark
265
+ await instance.evalCommand('A = (0, 0)');
266
+ await instance.evalCommand('B = (1, 1)');
267
+ await instance.evalCommand('line1 = Line(A, B)');
268
+
269
+ const exportDurations: number[] = [];
270
+ for (let i = 0; i < Math.min(iterations, 3); i++) { // Limit export tests
271
+ const startTime = Date.now();
272
+ await instance.exportSVG();
273
+ exportDurations.push(Date.now() - startTime);
274
+ }
275
+
276
+ benchmarkResults.results.push({
277
+ operation: 'svg_export',
278
+ durations: exportDurations,
279
+ average: exportDurations.reduce((a, b) => a + b, 0) / exportDurations.length,
280
+ min: Math.min(...exportDurations),
281
+ max: Math.max(...exportDurations)
282
+ });
283
+ }
284
+
285
+ // Calculate overall summary
286
+ benchmarkResults.summary = {
287
+ totalTests: benchmarkResults.results.length,
288
+ allTestsPassed: benchmarkResults.results.every((r: any) => r.average < 2000),
289
+ recommendedAction: benchmarkResults.results.some((r: any) => r.average > 1500)
290
+ ? 'Consider pool warm-up or optimization'
291
+ : 'Performance is within acceptable range'
292
+ };
293
+
294
+ } finally {
295
+ await optimizedInstancePool.releaseInstance(instance);
296
+ }
297
+
298
+ return {
299
+ content: [{
300
+ type: 'text' as const,
301
+ text: JSON.stringify({
302
+ success: true,
303
+ benchmark: benchmarkResults
304
+ }, null, 2)
305
+ }]
306
+ };
307
+ } catch (error) {
308
+ logger.error('Failed to run benchmark', error);
309
+ return {
310
+ content: [{
311
+ type: 'text' as const,
312
+ text: JSON.stringify({
313
+ success: false,
314
+ error: error instanceof Error ? error.message : String(error)
315
+ }, null, 2)
316
+ }],
317
+ isError: true
318
+ };
319
+ }
320
+ }
321
+ }
322
+ ];