@performance-agent/mcp-server 1.0.1 → 1.0.6

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 (45) hide show
  1. package/README.md +400 -25
  2. package/dist/index.d.ts +14 -4
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +783 -47
  5. package/dist/index.js.map +1 -1
  6. package/dist/prompts/jmx_prompt.txt +262 -0
  7. package/dist/prompts/prompts/jmx_prompt.txt +262 -0
  8. package/dist/tools/azure-infra/config-parser.d.ts +14 -0
  9. package/dist/tools/azure-infra/config-parser.d.ts.map +1 -0
  10. package/dist/tools/azure-infra/config-parser.js +361 -0
  11. package/dist/tools/azure-infra/config-parser.js.map +1 -0
  12. package/dist/tools/azure-infra/index.d.ts +52 -0
  13. package/dist/tools/azure-infra/index.d.ts.map +1 -0
  14. package/dist/tools/azure-infra/index.js +448 -0
  15. package/dist/tools/azure-infra/index.js.map +1 -0
  16. package/dist/tools/azure-infra/terraform-generator.d.ts +19 -0
  17. package/dist/tools/azure-infra/terraform-generator.d.ts.map +1 -0
  18. package/dist/tools/azure-infra/terraform-generator.js +458 -0
  19. package/dist/tools/azure-infra/terraform-generator.js.map +1 -0
  20. package/dist/tools/azure-infra/types.d.ts +123 -0
  21. package/dist/tools/azure-infra/types.d.ts.map +1 -0
  22. package/dist/tools/azure-infra/types.js +95 -0
  23. package/dist/tools/azure-infra/types.js.map +1 -0
  24. package/dist/tools/cloud-executor/index.d.ts +78 -0
  25. package/dist/tools/cloud-executor/index.d.ts.map +1 -0
  26. package/dist/tools/cloud-executor/index.js +528 -0
  27. package/dist/tools/cloud-executor/index.js.map +1 -0
  28. package/dist/tools/cloud-executor/result-analyzer.d.ts +65 -0
  29. package/dist/tools/cloud-executor/result-analyzer.d.ts.map +1 -0
  30. package/dist/tools/cloud-executor/result-analyzer.js +367 -0
  31. package/dist/tools/cloud-executor/result-analyzer.js.map +1 -0
  32. package/dist/tools/cloud-executor/vm-metrics.d.ts +87 -0
  33. package/dist/tools/cloud-executor/vm-metrics.d.ts.map +1 -0
  34. package/dist/tools/cloud-executor/vm-metrics.js +506 -0
  35. package/dist/tools/cloud-executor/vm-metrics.js.map +1 -0
  36. package/dist/tools/jmx-generator/index.d.ts +20 -0
  37. package/dist/tools/jmx-generator/index.d.ts.map +1 -0
  38. package/dist/tools/jmx-generator/index.js +115 -0
  39. package/dist/tools/jmx-generator/index.js.map +1 -0
  40. package/dist/tools/jmx-generator/sanitizer.d.ts +19 -0
  41. package/dist/tools/jmx-generator/sanitizer.d.ts.map +1 -0
  42. package/dist/tools/jmx-generator/sanitizer.js +166 -0
  43. package/dist/tools/jmx-generator/sanitizer.js.map +1 -0
  44. package/package.json +5 -2
  45. package/scripts/copy-prompts.js +46 -0
@@ -0,0 +1,115 @@
1
+ /**
2
+ * JMX Generator - Generate JMeter scripts from Swagger/OpenAPI specifications using Azure OpenAI
3
+ *
4
+ * This module provides direct OpenAI integration for JMX generation, eliminating the need
5
+ * for the Flask backend API.
6
+ */
7
+ import { readFileSync } from 'fs';
8
+ import { join, dirname } from 'path';
9
+ import { fileURLToPath } from 'url';
10
+ import { sanitizeJMX } from './sanitizer.js';
11
+ // ES module equivalent of __dirname
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+ // Azure OpenAI configuration from environment variables
15
+ const OPENAI_ENDPOINT = process.env.OPENAI_ENDPOINT || process.env.AZURE_OPENAI_ENDPOINT || '';
16
+ const OPENAI_API_KEY = process.env.OPENAI_API_KEY || process.env.AZURE_OPENAI_KEY || '';
17
+ const OPENAI_DEPLOYMENT = process.env.OPENAI_DEPLOYMENT || process.env.AZURE_OPENAI_DEPLOYMENT || 'gpt-4';
18
+ const OPENAI_API_VERSION = process.env.OPENAI_API_VERSION || '2024-02-15-preview';
19
+ /**
20
+ * Generate JMeter JMX script from Swagger/OpenAPI specification
21
+ * @param swaggerContent Swagger/OpenAPI JSON object
22
+ * @param repoName Optional repository name for logging
23
+ * @returns Result object with success status and JMX script or error
24
+ */
25
+ export async function generateJMX(swaggerContent, repoName) {
26
+ try {
27
+ console.log(`[JMX Generator] Starting JMX generation${repoName ? ` for repo: ${repoName}` : ''}...`);
28
+ // Validate Azure OpenAI configuration
29
+ if (!OPENAI_ENDPOINT || !OPENAI_API_KEY) {
30
+ const error = 'Azure OpenAI configuration missing. Set OPENAI_ENDPOINT and OPENAI_API_KEY environment variables.';
31
+ console.error(`[JMX Generator] ${error}`);
32
+ return { success: false, error };
33
+ }
34
+ // Load JMX prompt template
35
+ const promptPath = join(__dirname, '../../prompts/jmx_prompt.txt');
36
+ let promptTemplate;
37
+ try {
38
+ promptTemplate = readFileSync(promptPath, 'utf-8');
39
+ console.log('[JMX Generator] Loaded JMX prompt template');
40
+ }
41
+ catch (err) {
42
+ const error = `Failed to load JMX prompt template from ${promptPath}: ${err}`;
43
+ console.error(`[JMX Generator] ${error}`);
44
+ return { success: false, error };
45
+ }
46
+ // Format prompt with Swagger content
47
+ const swaggerText = JSON.stringify(swaggerContent, null, 2);
48
+ const formattedPrompt = promptTemplate.replace('{swagger_text}', swaggerText);
49
+ console.log(`[JMX Generator] Formatted prompt (${formattedPrompt.length} chars, Swagger: ${swaggerText.length} chars)`);
50
+ // Call Azure OpenAI API using fetch
51
+ console.log(`[JMX Generator] Calling Azure OpenAI at ${OPENAI_ENDPOINT}...`);
52
+ const url = `${OPENAI_ENDPOINT}/openai/deployments/${OPENAI_DEPLOYMENT}/chat/completions?api-version=${OPENAI_API_VERSION}`;
53
+ const response = await fetch(url, {
54
+ method: 'POST',
55
+ headers: {
56
+ 'Content-Type': 'application/json',
57
+ 'api-key': OPENAI_API_KEY,
58
+ },
59
+ body: JSON.stringify({
60
+ messages: [
61
+ {
62
+ role: 'user',
63
+ content: formattedPrompt,
64
+ },
65
+ ]
66
+ }),
67
+ });
68
+ if (!response.ok) {
69
+ const errorText = await response.text();
70
+ const error = `Azure OpenAI API error (${response.status}): ${errorText}`;
71
+ console.error(`[JMX Generator] ${error}`);
72
+ return { success: false, error };
73
+ }
74
+ const data = await response.json();
75
+ if (!data.choices || data.choices.length === 0) {
76
+ const error = 'Azure OpenAI returned no choices';
77
+ console.error(`[JMX Generator] ${error}`);
78
+ return { success: false, error };
79
+ }
80
+ let jmxScript = data.choices[0].message?.content?.trim() || '';
81
+ console.log(`[JMX Generator] Received response from OpenAI (${jmxScript.length} chars)`);
82
+ // Remove markdown code blocks if present
83
+ if (jmxScript.startsWith('```')) {
84
+ console.log('[JMX Generator] Removing markdown code blocks...');
85
+ jmxScript = jmxScript
86
+ .replace(/^```xml\n?/i, '')
87
+ .replace(/^```\n?/, '')
88
+ .replace(/\n?```$/, '')
89
+ .trim();
90
+ }
91
+ // Sanitize the JMX script
92
+ console.log('[JMX Generator] Sanitizing JMX script...');
93
+ jmxScript = sanitizeJMX(jmxScript);
94
+ // Validate that we have XML content
95
+ if (!jmxScript.startsWith('<?xml')) {
96
+ const error = 'Generated content is not valid XML';
97
+ console.error(`[JMX Generator] ${error}. Content preview: ${jmxScript.substring(0, 200)}`);
98
+ return { success: false, error };
99
+ }
100
+ console.log(`[JMX Generator] Successfully generated JMX script (${jmxScript.length} chars)`);
101
+ return {
102
+ success: true,
103
+ jmx_script: jmxScript,
104
+ };
105
+ }
106
+ catch (error) {
107
+ const errorMsg = `JMX generation failed: ${error}`;
108
+ console.error(`[JMX Generator] ${errorMsg}`);
109
+ return {
110
+ success: false,
111
+ error: errorMsg,
112
+ };
113
+ }
114
+ }
115
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/jmx-generator/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * JMX Sanitizer - Cleans up common invalid JMeter XML patterns in AI output
3
+ *
4
+ * This module sanitizes JMX (JMeter XML) files to fix common issues:
5
+ * - Adds missing guiclass attributes for test elements
6
+ * - Replaces ArrayList-based HTTP file args with proper HTTPFileArgs container
7
+ * - Removes ArrayList elementProp entries that cause casting errors
8
+ * - Fixes invalid <argument> tags into proper <elementProp elementType="Argument">
9
+ * - Ensures Arguments blocks have <collectionProp> wrapper
10
+ * - Normalizes enabled="true" attributes
11
+ * - Ensures every major element is followed by <hashTree/>
12
+ */
13
+ /**
14
+ * Sanitize JMeter XML to fix common AI-generated errors
15
+ * @param xmlText Raw XML text from AI model
16
+ * @returns Sanitized XML text that's loadable in JMeter
17
+ */
18
+ export declare function sanitizeJMX(xmlText: string): string;
19
+ //# sourceMappingURL=sanitizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../../../src/tools/jmx-generator/sanitizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA4PnD"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * JMX Sanitizer - Cleans up common invalid JMeter XML patterns in AI output
3
+ *
4
+ * This module sanitizes JMX (JMeter XML) files to fix common issues:
5
+ * - Adds missing guiclass attributes for test elements
6
+ * - Replaces ArrayList-based HTTP file args with proper HTTPFileArgs container
7
+ * - Removes ArrayList elementProp entries that cause casting errors
8
+ * - Fixes invalid <argument> tags into proper <elementProp elementType="Argument">
9
+ * - Ensures Arguments blocks have <collectionProp> wrapper
10
+ * - Normalizes enabled="true" attributes
11
+ * - Ensures every major element is followed by <hashTree/>
12
+ */
13
+ /**
14
+ * Sanitize JMeter XML to fix common AI-generated errors
15
+ * @param xmlText Raw XML text from AI model
16
+ * @returns Sanitized XML text that's loadable in JMeter
17
+ */
18
+ export function sanitizeJMX(xmlText) {
19
+ if (!xmlText) {
20
+ return xmlText;
21
+ }
22
+ try {
23
+ console.log('[JMX Sanitizer] Starting sanitization...');
24
+ // Fix invalid root structure: jmeterTestPlan should not have testclass/guiclass
25
+ xmlText = xmlText.replace(/<jmeterTestPlan\s+guiclass="[^"]*"\s+testclass="[^"]*"\s+testname="[^"]*"\s+enabled="[^"]*"/g, '<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.3"');
26
+ // Fix: Extract user-defined variables from TestPlan property and create separate Arguments element
27
+ const userVarsMatch = xmlText.match(/<stringProp name="TestPlan\.user_defined_variables">\s*((?:<elementProp[^>]*>.*?<\/elementProp>\s*)+)<\/stringProp>/s);
28
+ if (userVarsMatch) {
29
+ console.log('[JMX Sanitizer] Extracting user-defined variables to separate Arguments element...');
30
+ const variablesContent = userVarsMatch[1];
31
+ // Create proper Arguments element with collectionProp wrapper
32
+ const argumentsElement = `<Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
33
+ <collectionProp name="Arguments.arguments">
34
+ ${variablesContent.trim()}
35
+ </collectionProp>
36
+ </Arguments>
37
+ <hashTree/>`;
38
+ // Remove the TestPlan.user_defined_variables property
39
+ xmlText = xmlText.replace(/<stringProp name="TestPlan\.user_defined_variables">.*?<\/stringProp>\s*/s, '');
40
+ // Insert the Arguments element as first child in TestPlan's hashTree
41
+ xmlText = xmlText.replace(/(<\/TestPlan>\s*<\/hashTree>)/, `</TestPlan>\n <hashTree>\n ${argumentsElement}\n `);
42
+ const varCount = (variablesContent.match(/elementProp/g) || []).length;
43
+ console.log(`[JMX Sanitizer] Created separate User Defined Variables with ${varCount} variables`);
44
+ }
45
+ // Fix missing TestPlan wrapper after jmeterTestPlan
46
+ if (/<jmeterTestPlan[^>]*>\s*<hashTree\/>\s*<stringProp/.test(xmlText)) {
47
+ console.log('[JMX Sanitizer] Fixing missing TestPlan wrapper...');
48
+ xmlText = xmlText.replace(/(<jmeterTestPlan[^>]*>)\s*<hashTree\/>\s*(<stringProp)/, '$1\n <hashTree>\n <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="API Test Plan" enabled="true">\n $2');
49
+ }
50
+ // Ensure TestPlan properties are wrapped correctly
51
+ if (/<\/TestPlan>\s*<hashTree\/>\s*<elementProp name="User Defined Variables"/.test(xmlText)) {
52
+ console.log('[JMX Sanitizer] Moving User Defined Variables inside TestPlan...');
53
+ xmlText = xmlText.replace(/(<\/TestPlan>)\s*<hashTree\/>\s*(<elementProp name="User Defined Variables"[^>]*>.*?<\/elementProp>)/s, '$2\n <boolProp name="TestPlan.functional_mode">false</boolProp>\n <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>\n $1');
54
+ }
55
+ // Fix invalid elementType values
56
+ xmlText = xmlText.replace(/elementType="StringParameter"/g, 'elementType="Argument"');
57
+ // Fix invalid property type names
58
+ if (xmlText.includes('booleanProp')) {
59
+ console.log('[JMX Sanitizer] Fixing booleanProp -> boolProp...');
60
+ xmlText = xmlText.replace(/<booleanProp/g, '<boolProp');
61
+ xmlText = xmlText.replace(/<\/booleanProp>/g, '</boolProp>');
62
+ }
63
+ // Fix common XML nesting errors in ResponseAssertion
64
+ xmlText = xmlText.replace(/(<collectionProp[^>]*>)\s*(<stringProp[^>]*>[^<]*<\/stringProp>)\s*<\/stringProp>/g, '$1\n $2');
65
+ // Fix: <collectionProp> closed with </stringProp>
66
+ xmlText = xmlText.replace(/(<collectionProp[^>]*>.*?)<\/stringProp>(\s*<\/ResponseAssertion>)/gs, '$1</collectionProp>$2');
67
+ // Fix: <stringProp> closed with </collectionProp> in ResponseAssertion
68
+ if (xmlText.includes('Assertion.test_field')) {
69
+ xmlText = xmlText.replace(/(<stringProp name="Assertion\.test_field">[^<]*)<\/collectionProp>/g, '$1</stringProp>');
70
+ console.log('[JMX Sanitizer] Fixed mismatched closing tag for Assertion.test_field');
71
+ }
72
+ // General fix: <stringProp> incorrectly closed with </collectionProp>
73
+ xmlText = xmlText.replace(/(<stringProp[^>]*>[^<]*)<\/collectionProp>/g, '$1</stringProp>');
74
+ // Fix: Remove invalid elementProp with elementType="Assertion" inside ResponseAssertion
75
+ if (xmlText.includes('elementType="Assertion"')) {
76
+ console.log('[JMX Sanitizer] Fixing invalid elementType="Assertion" in ResponseAssertion...');
77
+ xmlText = xmlText.replace(/<elementProp[^>]*elementType="Assertion"[^>]*>\s*(<stringProp[^>]*>[^<]*<\/stringProp>)\s*<\/elementProp>/g, '$1');
78
+ }
79
+ // Fix stray <argument> tags into proper elementProp Argument
80
+ if (xmlText.includes('<argument>')) {
81
+ console.log('[JMX Sanitizer] Fixing <argument> tags to proper elementProp...');
82
+ // Pattern 1: <argument><name>...</name><value>...</value></argument>
83
+ xmlText = xmlText.replace(/<argument>\s*<name>([^<]+)<\/name>\s*<value>([^<]*)<\/value>\s*<\/argument>/g, `<elementProp name="$1" elementType="Argument">
84
+ <stringProp name="Argument.name">$1</stringProp>
85
+ <stringProp name="Argument.value">$2</stringProp>
86
+ <stringProp name="Argument.metadata">=</stringProp>
87
+ </elementProp>`);
88
+ // Pattern 2: Simple <argument>value</argument>
89
+ xmlText = xmlText.replace(/<argument>([^<]*)<\/argument>/g, `<elementProp name="arg" elementType="Argument">
90
+ <stringProp name="Argument.name">arg</stringProp>
91
+ <stringProp name="Argument.value">$1</stringProp>
92
+ <stringProp name="Argument.metadata">=</stringProp>
93
+ </elementProp>`);
94
+ }
95
+ // Fix duplicate/malformed collectionProp on same line
96
+ xmlText = xmlText.replace(/<collectionProp name="Arguments\.arguments">\s*<collectionProp name="Arguments\.arguments">/g, '<collectionProp name="Arguments.arguments">');
97
+ console.log('[JMX Sanitizer] Checked for duplicate collectionProp tags');
98
+ // Fix Argument -> HTTPArgument inside HTTPsampler.Arguments
99
+ xmlText = xmlText.replace(/<elementProp name="HTTPsampler\.Arguments"[^>]*>.*?<\/elementProp>/gs, (match) => {
100
+ let content = match;
101
+ if (content.includes('elementType="Argument"') && content.includes('HTTPsampler.Arguments')) {
102
+ console.log('[JMX Sanitizer] Fixing Argument -> HTTPArgument in HTTPsampler.Arguments...');
103
+ content = content.replace(/<elementProp\s+name="[^"]*"\s+elementType="Argument">/g, (m) => m.replace('elementType="Argument"', 'elementType="HTTPArgument"'));
104
+ if (!content.includes('HTTPArgument.always_encode')) {
105
+ content = content.replace(/(<elementProp[^>]*elementType="HTTPArgument">)/, '$1\n <boolProp name="HTTPArgument.always_encode">false</boolProp>');
106
+ }
107
+ if (!content.includes('HTTPArgument.use_equals')) {
108
+ content = content.replace(/(<\/elementProp>)(?=.*HTTPArgument)/, ' <boolProp name="HTTPArgument.use_equals">true</boolProp>\n $1');
109
+ }
110
+ }
111
+ return content;
112
+ });
113
+ // Fix common hashTree structure issues
114
+ xmlText = xmlText.replace(/<hashTree>\s*<hashTree\/>\s*<\/hashTree>/g, '<hashTree/>');
115
+ xmlText = xmlText.replace(/<hashTree>\s*<hashTree>\s*<\/hashTree>\s*<\/hashTree>/g, '<hashTree/>');
116
+ // Ensure every major test element is followed by hashTree
117
+ const elements = ['HTTPSamplerProxy', 'HeaderManager', 'ResponseAssertion', 'ThreadGroup', 'Arguments'];
118
+ for (const element of elements) {
119
+ const pattern = new RegExp(`(</${element}>)(?!\\s*<hashTree)`, 'g');
120
+ xmlText = xmlText.replace(pattern, '$1\n <hashTree/>');
121
+ }
122
+ // Fix missing guiclass attributes
123
+ const guiclassMappings = {
124
+ '<TestPlan\\s+testclass="TestPlan"(?!\\s+guiclass=)': '<TestPlan testclass="TestPlan" guiclass="TestPlanGui"',
125
+ '<ThreadGroup\\s+testclass="ThreadGroup"(?!\\s+guiclass=)': '<ThreadGroup testclass="ThreadGroup" guiclass="ThreadGroupGui"',
126
+ '<HTTPSamplerProxy\\s+testclass="HTTPSamplerProxy"(?!\\s+guiclass=)': '<HTTPSamplerProxy testclass="HTTPSamplerProxy" guiclass="HttpTestSampleGui"',
127
+ '<Arguments\\s+testclass="Arguments"(?!\\s+guiclass=)': '<Arguments testclass="Arguments" guiclass="ArgumentsPanel"',
128
+ '<ResponseAssertion\\s+testclass="ResponseAssertion"(?!\\s+guiclass=)': '<ResponseAssertion testclass="ResponseAssertion" guiclass="AssertionGui"',
129
+ '<HeaderManager\\s+testclass="HeaderManager"(?!\\s+guiclass=)': '<HeaderManager testclass="HeaderManager" guiclass="HeaderPanel"',
130
+ '<LoopController\\s+testclass="LoopController"(?!\\s+guiclass=)': '<LoopController testclass="LoopController" guiclass="LoopControlPanel"',
131
+ };
132
+ for (const [pattern, replacement] of Object.entries(guiclassMappings)) {
133
+ xmlText = xmlText.replace(new RegExp(pattern, 'g'), replacement);
134
+ }
135
+ // Normalize enabled="true" attributes
136
+ const elementsToNormalize = ['TestPlan', 'ThreadGroup', 'HTTPSamplerProxy', 'Arguments', 'ResponseAssertion', 'HeaderManager'];
137
+ for (const element of elementsToNormalize) {
138
+ xmlText = xmlText.replace(new RegExp(`(<${element}[^>]*)(?<!enabled="true")>`, 'g'), '$1 enabled="true">');
139
+ }
140
+ // Fix ArrayList issues - comprehensive check
141
+ if (xmlText.includes('ArrayList')) {
142
+ console.log('[JMX Sanitizer] Found ArrayList references, fixing...');
143
+ // Fix HTTPsampler.Files with ArrayList
144
+ xmlText = xmlText.replace(/<elementProp name="HTTPsampler\.Files" elementType="ArrayList"\/>/g, '<elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">\n <collectionProp name="HTTPFileArgs.files"/>\n </elementProp>');
145
+ xmlText = xmlText.replace(/<elementProp name="HTTPsampler\.Files" elementType="ArrayList"[^>]*>.*?<\/elementProp>/gs, '<elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">\n <collectionProp name="HTTPFileArgs.files"/>\n </elementProp>');
146
+ // Remove any other ArrayList elementProp (self-closing or with content)
147
+ xmlText = xmlText.replace(/<elementProp[^>]*elementType="ArrayList"[^>]*\/>/g, '');
148
+ xmlText = xmlText.replace(/<elementProp[^>]*elementType="ArrayList"[^>]*>.*?<\/elementProp>/gs, '');
149
+ // Fix any collectionProp that might contain ArrayList references
150
+ xmlText = xmlText.replace(/<collectionProp name="Arguments\.arguments">\s*<ArrayList\/>/g, '<collectionProp name="Arguments.arguments">');
151
+ xmlText = xmlText.replace(/<collectionProp name="Arguments\.arguments">\s*<ArrayList>.*?<\/ArrayList>/gs, '<collectionProp name="Arguments.arguments">');
152
+ // Remove any standalone <ArrayList> tags
153
+ xmlText = xmlText.replace(/<ArrayList\s*\/>/g, '');
154
+ xmlText = xmlText.replace(/<ArrayList>.*?<\/ArrayList>/gs, '');
155
+ console.log('[JMX Sanitizer] ArrayList references removed');
156
+ }
157
+ console.log('[JMX Sanitizer] Sanitization complete');
158
+ // Note: XML validation is skipped in TypeScript version
159
+ // JMeter will validate when loading the file
160
+ }
161
+ catch (error) {
162
+ console.error(`[JMX Sanitizer] Error during sanitization: ${error}`);
163
+ }
164
+ return xmlText;
165
+ }
166
+ //# sourceMappingURL=sanitizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitizer.js","sourceRoot":"","sources":["../../../src/tools/jmx-generator/sanitizer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@performance-agent/mcp-server",
3
- "version": "1.0.1",
3
+ "version": "1.0.6",
4
4
  "description": "MCP Server for Performance Testing Agent - JMX generation, test execution, and result analysis",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -8,7 +8,7 @@
8
8
  "performance-agent-mcp": "./dist/index.js"
9
9
  },
10
10
  "scripts": {
11
- "build": "tsc && chmod +x dist/index.js",
11
+ "build": "tsc && node scripts/copy-prompts.js",
12
12
  "dev": "tsx src/index.ts",
13
13
  "prepare": "npm run build",
14
14
  "test": "jest"
@@ -34,11 +34,14 @@
34
34
  "escomplex": "^2.0.0-alpha",
35
35
  "fs-extra": "^11.2.0",
36
36
  "glob": "^10.3.0",
37
+ "openai": "^6.16.0",
37
38
  "simple-git": "^3.21.0"
38
39
  },
39
40
  "devDependencies": {
40
41
  "@types/fs-extra": "^11.0.4",
41
42
  "@types/node": "^20.10.0",
43
+ "cpy-cli": "^6.0.0",
44
+ "cross-env": "^10.1.0",
42
45
  "tsx": "^4.7.0",
43
46
  "typescript": "^5.3.0"
44
47
  },
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cross-platform script to copy prompts directory
5
+ * Works on Windows, macOS, and Linux
6
+ */
7
+
8
+ import fs from 'fs-extra';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+
15
+ const projectRoot = path.resolve(__dirname, '..');
16
+ const srcPrompts = path.join(projectRoot, 'src', 'prompts');
17
+ const distPrompts = path.join(projectRoot, 'dist', 'prompts');
18
+ const distIndex = path.join(projectRoot, 'dist', 'index.js');
19
+
20
+ async function copyPrompts() {
21
+ try {
22
+ // Copy prompts directory
23
+ console.log('📁 Copying prompts directory...');
24
+ await fs.copy(srcPrompts, distPrompts, { overwrite: true });
25
+ console.log('✅ Prompts copied successfully');
26
+
27
+ // Make index.js executable (Unix/Linux/macOS only, no-op on Windows)
28
+ if (process.platform !== 'win32') {
29
+ try {
30
+ await fs.chmod(distIndex, 0o755);
31
+ console.log('✅ Made index.js executable');
32
+ } catch (err) {
33
+ console.warn('âš ī¸ Could not make index.js executable (not critical):', err.message);
34
+ }
35
+ } else {
36
+ console.log('â„šī¸ Skipping chmod on Windows (not needed)');
37
+ }
38
+
39
+ console.log('🎉 Build post-processing complete!');
40
+ } catch (error) {
41
+ console.error('❌ Error during build post-processing:', error);
42
+ process.exit(1);
43
+ }
44
+ }
45
+
46
+ copyPrompts();