@mseep/ai-tech-app-agent 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/.env +24 -0
  2. package/.env.example +24 -0
  3. package/Jenkinsfile +210 -0
  4. package/MCP-SERVER-GUIDE.md +405 -0
  5. package/README.MD +450 -0
  6. package/dist/config/app.config.d.ts +65 -0
  7. package/dist/config/app.config.d.ts.map +1 -0
  8. package/dist/config/app.config.js +94 -0
  9. package/dist/config/app.config.js.map +1 -0
  10. package/dist/config/llm.config.d.ts +63 -0
  11. package/dist/config/llm.config.d.ts.map +1 -0
  12. package/dist/config/llm.config.js +158 -0
  13. package/dist/config/llm.config.js.map +1 -0
  14. package/dist/config/mcp.config.d.ts +175 -0
  15. package/dist/config/mcp.config.d.ts.map +1 -0
  16. package/dist/config/mcp.config.js +215 -0
  17. package/dist/config/mcp.config.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +175 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/llm/llamaClient.d.ts +14 -0
  23. package/dist/llm/llamaClient.d.ts.map +1 -0
  24. package/dist/llm/llamaClient.js +136 -0
  25. package/dist/llm/llamaClient.js.map +1 -0
  26. package/dist/mcp/mcpClient.d.ts +132 -0
  27. package/dist/mcp/mcpClient.d.ts.map +1 -0
  28. package/dist/mcp/mcpClient.js +784 -0
  29. package/dist/mcp/mcpClient.js.map +1 -0
  30. package/dist/models/testSpec.d.ts +78 -0
  31. package/dist/models/testSpec.d.ts.map +1 -0
  32. package/dist/models/testSpec.js +3 -0
  33. package/dist/models/testSpec.js.map +1 -0
  34. package/dist/orchestrator/aiTestRunner.d.ts +18 -0
  35. package/dist/orchestrator/aiTestRunner.d.ts.map +1 -0
  36. package/dist/orchestrator/aiTestRunner.js +247 -0
  37. package/dist/orchestrator/aiTestRunner.js.map +1 -0
  38. package/dist/utils/logger.d.ts +4 -0
  39. package/dist/utils/logger.d.ts.map +1 -0
  40. package/dist/utils/logger.js +49 -0
  41. package/dist/utils/logger.js.map +1 -0
  42. package/dist/utils/promptBuilder.d.ts +62 -0
  43. package/dist/utils/promptBuilder.d.ts.map +1 -0
  44. package/dist/utils/promptBuilder.js +333 -0
  45. package/dist/utils/promptBuilder.js.map +1 -0
  46. package/knowledge/app-knowledge.txt +100 -0
  47. package/logs/combined.log +486 -0
  48. package/logs/error.log +50 -0
  49. package/package.json +62 -0
  50. package/reports/screenshots/screenshot_1764535110518.png +0 -0
  51. package/reports/test-report.json +106 -0
  52. package/scripts/check-mcp-server.sh +100 -0
  53. package/scripts/extract-pom-knowledge.js +222 -0
  54. package/scripts/pre-test-setup.js +262 -0
  55. package/scripts/start-mcp-server.sh +76 -0
  56. package/src/config/app.config.ts +175 -0
  57. package/src/config/llm.config.ts +220 -0
  58. package/src/config/mcp.config.ts +291 -0
  59. package/src/index.ts +161 -0
  60. package/src/llm/llamaClient.ts +159 -0
  61. package/src/mcp/mcpClient.ts +878 -0
  62. package/src/models/testSpec.ts +85 -0
  63. package/src/orchestrator/aiTestRunner.ts +286 -0
  64. package/src/utils/logger.ts +59 -0
  65. package/src/utils/promptBuilder.ts +384 -0
  66. package/tests/nlp-specs/login-flow.yaml +31 -0
  67. package/tsconfig.json +31 -0
@@ -0,0 +1,262 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Pre-test setup script
5
+ * Ensures all required services are running before executing tests
6
+ */
7
+
8
+ const { spawn } = require('child_process');
9
+ const axios = require('axios');
10
+ const dotenv = require('dotenv');
11
+
12
+ dotenv.config();
13
+
14
+ const colors = {
15
+ red: '\x1b[31m',
16
+ green: '\x1b[32m',
17
+ yellow: '\x1b[33m',
18
+ reset: '\x1b[0m'
19
+ };
20
+
21
+ function log(message, color = 'reset') {
22
+ console.log(`${colors[color]}${message}${colors.reset}`);
23
+ }
24
+
25
+ async function checkOllama() {
26
+ const ollamaUrl = process.env.OLLAMA_BASE_URL || 'http://localhost:11434';
27
+ const modelName = process.env.LLM_MODEL || 'llama3.2:3b';
28
+
29
+ log('\n1. Checking Ollama (LLM) Server...', 'yellow');
30
+
31
+ try {
32
+ // Check if Ollama is running
33
+ const response = await axios.get(`${ollamaUrl}/api/tags`, { timeout: 5000 });
34
+ log('✓ Ollama is running', 'green');
35
+
36
+ // Check if model is available
37
+ const models = response.data.models || [];
38
+ const modelExists = models.some(m => m.name === modelName);
39
+
40
+ if (modelExists) {
41
+ log(`✓ Model ${modelName} is available`, 'green');
42
+ return true;
43
+ } else {
44
+ log(`✗ Model ${modelName} not found`, 'red');
45
+ log(` Available models: ${models.map(m => m.name).join(', ')}`, 'yellow');
46
+ log(` Run: ollama pull ${modelName}`, 'yellow');
47
+ return false;
48
+ }
49
+ } catch (error) {
50
+ log('✗ Ollama is not running or not accessible', 'red');
51
+ log(' Start Ollama with: ollama serve', 'yellow');
52
+ log(` Then pull model: ollama pull ${modelName}`, 'yellow');
53
+ return false;
54
+ }
55
+ }
56
+
57
+ async function checkAppium() {
58
+ const appiumUrl = process.env.APPIUM_SERVER_URL || 'http://localhost:4723';
59
+
60
+ log('\n2. Checking Appium Server...', 'yellow');
61
+
62
+ try {
63
+ const response = await axios.get(`${appiumUrl}/status`, { timeout: 5000 });
64
+ log(`✓ Appium server is running at ${appiumUrl}`, 'green');
65
+ log(` Build: ${JSON.stringify(response.data.value?.build || 'unknown')}`, 'reset');
66
+ return true;
67
+ } catch (error) {
68
+ log(`⚠ Appium server not accessible at ${appiumUrl}`, 'yellow');
69
+
70
+ // Check if using LambdaTest
71
+ const ltUrl = process.env.LAMBDATEST_GRID_URL;
72
+ if (ltUrl && ltUrl.includes('lambdatest')) {
73
+ log(' Using LambdaTest remote grid - this is OK', 'green');
74
+ return true;
75
+ } else {
76
+ log(' If using local Appium, start with: appium', 'yellow');
77
+ log(' If using LambdaTest, ensure LAMBDATEST_GRID_URL is set', 'yellow');
78
+ return false;
79
+ }
80
+ }
81
+ }
82
+
83
+ async function checkMCPServer() {
84
+ const mcpPort = process.env.MCP_SERVER_PORT || 3000;
85
+
86
+ log('\n3. Checking MCP-Appium Server...', 'yellow');
87
+
88
+ try {
89
+ // Try to connect to MCP server
90
+ await axios.get(`http://localhost:${mcpPort}/health`, { timeout: 2000 });
91
+ log('✓ MCP-Appium server is running', 'green');
92
+ return true;
93
+ } catch (error) {
94
+ log('⚠ MCP-Appium server not running', 'yellow');
95
+ log(' MCP server starts automatically when tests run', 'green');
96
+ log(' Or start manually: npm run start-mcp', 'yellow');
97
+ return true; // Not critical, will start automatically
98
+ }
99
+ }
100
+
101
+ function checkEnvironmentVariables() {
102
+ log('\n4. Checking Environment Variables...', 'yellow');
103
+
104
+ const required = [
105
+ 'LAMBDATEST_USERNAME',
106
+ 'LAMBDATEST_ACCESS_KEY',
107
+ ];
108
+
109
+ const optional = [
110
+ 'OLLAMA_BASE_URL',
111
+ 'LLM_MODEL',
112
+ 'APPIUM_SERVER_URL',
113
+ ];
114
+
115
+ let allPresent = true;
116
+
117
+ required.forEach(varName => {
118
+ if (!process.env[varName]) {
119
+ log(`✗ Required: ${varName} is not set`, 'red');
120
+ allPresent = false;
121
+ } else {
122
+ const value = varName.includes('KEY') || varName.includes('PASSWORD')
123
+ ? '***'
124
+ : process.env[varName];
125
+ log(`✓ ${varName}: ${value}`, 'green');
126
+ }
127
+ });
128
+
129
+ optional.forEach(varName => {
130
+ if (process.env[varName]) {
131
+ log(`✓ ${varName}: ${process.env[varName]}`, 'green');
132
+ }
133
+ });
134
+
135
+ return allPresent;
136
+ }
137
+
138
+ async function checkProjectStructure() {
139
+ const fs = require('fs');
140
+ const path = require('path');
141
+
142
+ log('\n5. Checking Project Structure...', 'yellow');
143
+
144
+ const requiredDirs = [
145
+ 'src/config',
146
+ 'src/mcp',
147
+ 'src/llm',
148
+ 'src/utils',
149
+ 'src/orchestrator',
150
+ 'tests/nlp-specs',
151
+ 'logs',
152
+ 'reports',
153
+ ];
154
+
155
+ let allExist = true;
156
+
157
+ requiredDirs.forEach(dir => {
158
+ const fullPath = path.join(process.cwd(), dir);
159
+ if (fs.existsSync(fullPath)) {
160
+ log(`✓ ${dir}`, 'green');
161
+ } else {
162
+ log(`✗ ${dir} not found`, 'red');
163
+ allExist = false;
164
+ }
165
+ });
166
+
167
+ // Check if build exists
168
+ const distPath = path.join(process.cwd(), 'dist');
169
+ if (fs.existsSync(distPath)) {
170
+ log('✓ TypeScript compiled (dist/ exists)', 'green');
171
+ } else {
172
+ log('✗ Project not built. Run: npm run build', 'red');
173
+ allExist = false;
174
+ }
175
+
176
+ return allExist;
177
+ }
178
+
179
+ async function startOllama() {
180
+ log('\nAttempting to start Ollama...', 'yellow');
181
+
182
+ return new Promise((resolve) => {
183
+ const ollama = spawn('ollama', ['serve'], {
184
+ detached: true,
185
+ stdio: 'ignore'
186
+ });
187
+
188
+ ollama.unref();
189
+
190
+ log('✓ Ollama server started in background', 'green');
191
+ log(' Waiting 3 seconds for initialization...', 'yellow');
192
+
193
+ setTimeout(() => resolve(true), 3000);
194
+ });
195
+ }
196
+
197
+ async function main() {
198
+ console.log('==========================================');
199
+ console.log('Pre-Test Setup Checker');
200
+ console.log('==========================================');
201
+
202
+ const results = {
203
+ ollama: false,
204
+ appium: false,
205
+ mcp: false,
206
+ env: false,
207
+ structure: false,
208
+ };
209
+
210
+ // Check all services
211
+ results.ollama = await checkOllama();
212
+ results.appium = await checkAppium();
213
+ results.mcp = await checkMCPServer();
214
+ results.env = checkEnvironmentVariables();
215
+ results.structure = await checkProjectStructure();
216
+
217
+ // Summary
218
+ log('\n==========================================', 'yellow');
219
+ log('Setup Summary', 'yellow');
220
+ log('==========================================', 'yellow');
221
+
222
+ const allGood = Object.values(results).every(r => r === true);
223
+
224
+ if (allGood) {
225
+ log('\n✓ All checks passed! Ready to run tests.', 'green');
226
+ log('\nRun your tests with:', 'reset');
227
+ log(' npm run test', 'yellow');
228
+ log(' or', 'reset');
229
+ log(' npm run test:single', 'yellow');
230
+ process.exit(0);
231
+ } else {
232
+ log('\n⚠ Some checks failed. Please fix the issues above.', 'yellow');
233
+
234
+ // Auto-fix attempt
235
+ log('\nAttempting auto-fixes...', 'yellow');
236
+
237
+ if (!results.ollama) {
238
+ try {
239
+ await startOllama();
240
+ // Re-check Ollama
241
+ const ollamaOk = await checkOllama();
242
+ if (ollamaOk) {
243
+ log('✓ Ollama started successfully!', 'green');
244
+ }
245
+ } catch (error) {
246
+ log('✗ Could not auto-start Ollama', 'red');
247
+ log(' Please start manually: ollama serve', 'yellow');
248
+ }
249
+ }
250
+
251
+ log('\nAfter fixing issues, run this script again:', 'reset');
252
+ log(' node scripts/pre-test-setup.js', 'yellow');
253
+
254
+ process.exit(1);
255
+ }
256
+ }
257
+
258
+ // Run the checks
259
+ main().catch(error => {
260
+ log(`\nError: ${error.message}`, 'red');
261
+ process.exit(1);
262
+ });
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+
3
+ # Start MCP-Appium server manually
4
+ # This script is optional - MCP starts automatically during tests
5
+
6
+ set -e
7
+
8
+ # Color codes
9
+ GREEN='\033[0;32m'
10
+ YELLOW='\033[1;33m'
11
+ RED='\033[0;31m'
12
+ NC='\033[0m'
13
+
14
+ echo "=========================================="
15
+ echo "Starting MCP-Appium Server"
16
+ echo "=========================================="
17
+ echo ""
18
+
19
+ # Load environment variables
20
+ if [ -f .env ]; then
21
+ export $(cat .env | grep -v '^#' | xargs)
22
+ echo -e "${GREEN}✓${NC} Loaded environment variables from .env"
23
+ else
24
+ echo -e "${YELLOW}⚠${NC} No .env file found, using defaults"
25
+ fi
26
+
27
+ # Set defaults
28
+ APPIUM_SERVER_URL=${APPIUM_SERVER_URL:-http://localhost:4723}
29
+ MCP_SERVER_PORT=${MCP_SERVER_PORT:-3000}
30
+
31
+ echo "Configuration:"
32
+ echo " Appium URL: $APPIUM_SERVER_URL"
33
+ echo " MCP Port: $MCP_SERVER_PORT"
34
+ echo ""
35
+
36
+ # Check if mcp-appium is installed
37
+ if ! command -v npx &> /dev/null; then
38
+ echo -e "${RED}✗${NC} npx not found. Please install Node.js"
39
+ exit 1
40
+ fi
41
+
42
+ # Check if already running
43
+ if lsof -Pi :$MCP_SERVER_PORT -sTCP:LISTEN -t >/dev/null 2>&1; then
44
+ PID=$(lsof -Pi :$MCP_SERVER_PORT -sTCP:LISTEN -t)
45
+ echo -e "${YELLOW}⚠${NC} Port $MCP_SERVER_PORT is already in use by PID: $PID"
46
+ read -p "Kill existing process? (y/n) " -n 1 -r
47
+ echo
48
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
49
+ kill -9 $PID
50
+ echo -e "${GREEN}✓${NC} Killed existing process"
51
+ sleep 2
52
+ else
53
+ echo "Exiting..."
54
+ exit 1
55
+ fi
56
+ fi
57
+
58
+ # Check if Appium is accessible
59
+ echo "Checking Appium server connectivity..."
60
+ if curl -s "$APPIUM_SERVER_URL/status" > /dev/null 2>&1; then
61
+ echo -e "${GREEN}✓${NC} Appium server is accessible"
62
+ else
63
+ echo -e "${YELLOW}⚠${NC} Cannot reach Appium server at $APPIUM_SERVER_URL"
64
+ echo " If using LambdaTest, this is OK"
65
+ fi
66
+
67
+ echo ""
68
+ echo "Starting MCP-Appium server..."
69
+ echo "Press Ctrl+C to stop"
70
+ echo ""
71
+
72
+ # Start MCP-Appium server
73
+ npx mcp-appium
74
+
75
+ # Note: The process will run in foreground
76
+ # To run in background, use: npx mcp-appium > logs/mcp-server.log 2>&1 &
@@ -0,0 +1,175 @@
1
+ import dotenv from 'dotenv';
2
+ import path from 'path';
3
+
4
+ dotenv.config();
5
+
6
+ export interface AppConfig {
7
+ env: string;
8
+ name: string;
9
+ version: string;
10
+
11
+ // Directories
12
+ paths: {
13
+ root: string;
14
+ logs: string;
15
+ reports: string;
16
+ screenshots: string;
17
+ testSpecs: string;
18
+ knowledge: string;
19
+ };
20
+
21
+ // Test execution settings
22
+ execution: {
23
+ defaultTimeout: number;
24
+ maxRetryAttempts: number;
25
+ retryFailedSteps: boolean;
26
+ screenshotOnFailure: boolean;
27
+ continueOnFailure: boolean;
28
+ parallelExecution: boolean;
29
+ maxParallelTests: number;
30
+ };
31
+
32
+ // Element interaction settings
33
+ interaction: {
34
+ implicitWait: number;
35
+ explicitWait: number;
36
+ actionDelay: number;
37
+ tapDuration: number;
38
+ swipeSpeed: number;
39
+ scrollPercentage: number;
40
+ };
41
+
42
+ // Reporting
43
+ reporting: {
44
+ format: 'json' | 'html' | 'allure';
45
+ includeScreenshots: boolean;
46
+ includeStepDetails: boolean;
47
+ includeTimestamps: boolean;
48
+ verboseLogging: boolean;
49
+ };
50
+
51
+ // LambdaTest configuration
52
+ lambdatest: {
53
+ username: string;
54
+ accessKey: string;
55
+ gridUrl: string;
56
+ tunnel: boolean;
57
+ tunnelName?: string;
58
+ buildName: string;
59
+ projectName: string;
60
+ tags: string[];
61
+ network: boolean;
62
+ video: boolean;
63
+ console: boolean;
64
+ visual: boolean;
65
+ };
66
+
67
+ // Device preferences
68
+ devices: {
69
+ android: {
70
+ defaultVersion: string;
71
+ defaultDevice: string;
72
+ };
73
+ ios: {
74
+ defaultVersion: string;
75
+ defaultDevice: string;
76
+ };
77
+ };
78
+ }
79
+
80
+ const appConfig: AppConfig = {
81
+ env: process.env.NODE_ENV || 'development',
82
+ name: process.env.APP_NAME || 'ai-tech-app-agent',
83
+ version: process.env.APP_VERSION || '1.0.0',
84
+
85
+ paths: {
86
+ root: process.cwd(),
87
+ logs: path.resolve(process.cwd(), process.env.LOG_DIR || './logs'),
88
+ reports: path.resolve(process.cwd(), process.env.REPORT_DIR || './reports'),
89
+ screenshots: path.resolve(process.cwd(), process.env.SCREENSHOT_DIR || './reports/screenshots'),
90
+ testSpecs: path.resolve(process.cwd(), process.env.TEST_SPEC_DIR || './tests/nlp-specs'),
91
+ knowledge: path.resolve(process.cwd(), process.env.KNOWLEDGE_DIR || './knowledge'),
92
+ },
93
+
94
+ execution: {
95
+ defaultTimeout: parseInt(process.env.DEFAULT_TIMEOUT || '30000'),
96
+ maxRetryAttempts: parseInt(process.env.MAX_RETRY_ATTEMPTS || '2'),
97
+ retryFailedSteps: process.env.RETRY_FAILED_STEPS === 'true',
98
+ screenshotOnFailure: process.env.SCREENSHOT_ON_FAILURE !== 'false',
99
+ continueOnFailure: process.env.CONTINUE_ON_FAILURE === 'true',
100
+ parallelExecution: process.env.PARALLEL_EXECUTION === 'true',
101
+ maxParallelTests: parseInt(process.env.MAX_PARALLEL_TESTS || '3'),
102
+ },
103
+
104
+ interaction: {
105
+ implicitWait: parseInt(process.env.IMPLICIT_WAIT || '5000'),
106
+ explicitWait: parseInt(process.env.EXPLICIT_WAIT || '10000'),
107
+ actionDelay: parseInt(process.env.ACTION_DELAY || '500'),
108
+ tapDuration: parseInt(process.env.TAP_DURATION || '100'),
109
+ swipeSpeed: parseInt(process.env.SWIPE_SPEED || '1000'),
110
+ scrollPercentage: parseFloat(process.env.SCROLL_PERCENTAGE || '0.75'),
111
+ },
112
+
113
+ reporting: {
114
+ format: (process.env.REPORT_FORMAT as 'json' | 'html' | 'allure') || 'json',
115
+ includeScreenshots: process.env.INCLUDE_SCREENSHOTS !== 'false',
116
+ includeStepDetails: process.env.INCLUDE_STEP_DETAILS !== 'false',
117
+ includeTimestamps: process.env.INCLUDE_TIMESTAMPS !== 'false',
118
+ verboseLogging: process.env.VERBOSE_LOGGING === 'true',
119
+ },
120
+
121
+ lambdatest: {
122
+ username: process.env.LAMBDATEST_USERNAME || '',
123
+ accessKey: process.env.LAMBDATEST_ACCESS_KEY || '',
124
+ gridUrl: process.env.LAMBDATEST_GRID_URL || 'https://mobile-hub.lambdatest.com/wd/hub',
125
+ tunnel: process.env.LAMBDATEST_TUNNEL === 'true',
126
+ tunnelName: process.env.LAMBDATEST_TUNNEL_NAME,
127
+ buildName: process.env.LAMBDATEST_BUILD_NAME || `AI-Test-Build`,
128
+ projectName: process.env.LAMBDATEST_PROJECT_NAME || 'AI Mobile Test Automation',
129
+ tags: (process.env.LAMBDATEST_TAGS || 'ai,mcp,automation').split(','),
130
+ network: process.env.LAMBDATEST_NETWORK !== 'false',
131
+ video: process.env.LAMBDATEST_VIDEO !== 'false',
132
+ console: process.env.LAMBDATEST_CONSOLE !== 'false',
133
+ visual: process.env.LAMBDATEST_VISUAL !== 'false',
134
+ },
135
+
136
+ devices: {
137
+ android: {
138
+ defaultVersion: process.env.ANDROID_DEFAULT_VERSION || '13',
139
+ defaultDevice: process.env.ANDROID_DEFAULT_DEVICE || 'Pixel 7',
140
+ },
141
+ ios: {
142
+ defaultVersion: process.env.IOS_DEFAULT_VERSION || '16',
143
+ defaultDevice: process.env.IOS_DEFAULT_DEVICE || 'iPhone 14',
144
+ },
145
+ },
146
+ };
147
+
148
+ // Validation
149
+ export function validateAppConfig(): void {
150
+ const errors: string[] = [];
151
+
152
+ // Check required LambdaTest credentials
153
+ if (!appConfig.lambdatest.username) {
154
+ errors.push('LAMBDATEST_USERNAME is required');
155
+ }
156
+ if (!appConfig.lambdatest.accessKey) {
157
+ errors.push('LAMBDATEST_ACCESS_KEY is required');
158
+ }
159
+
160
+ // Validate timeout values
161
+ if (appConfig.execution.defaultTimeout < 1000) {
162
+ errors.push('DEFAULT_TIMEOUT must be at least 1000ms');
163
+ }
164
+
165
+ // Validate retry attempts
166
+ if (appConfig.execution.maxRetryAttempts < 0 || appConfig.execution.maxRetryAttempts > 5) {
167
+ errors.push('MAX_RETRY_ATTEMPTS must be between 0 and 5');
168
+ }
169
+
170
+ if (errors.length > 0) {
171
+ throw new Error(`App configuration validation failed:\n${errors.join('\n')}`);
172
+ }
173
+ }
174
+
175
+ export default appConfig;