myaidev-method 0.0.8 → 0.1.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.
@@ -0,0 +1,461 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * WordPress Performance Analysis Script
5
+ * Scriptable performance check with JSON output for agent processing
6
+ *
7
+ * Usage:
8
+ * npx myaidev-method wordpress:performance-check [options]
9
+ * node src/scripts/wordpress-performance-check.js [options]
10
+ */
11
+
12
+ import { WordPressAdminUtils } from '../lib/wordpress-admin-utils.js';
13
+ import { writeFileSync } from 'fs';
14
+ import { resolve } from 'path';
15
+
16
+ const args = process.argv.slice(2);
17
+
18
+ const options = {
19
+ format: 'json', // json or text
20
+ output: null, // file path for output
21
+ verbose: false,
22
+ iterations: 3 // Number of iterations for timing measurements
23
+ };
24
+
25
+ // Parse arguments
26
+ for (let i = 0; i < args.length; i++) {
27
+ switch (args[i]) {
28
+ case '--format':
29
+ options.format = args[++i] || 'json';
30
+ break;
31
+ case '--output':
32
+ case '-o':
33
+ options.output = args[++i];
34
+ break;
35
+ case '--verbose':
36
+ case '-v':
37
+ options.verbose = true;
38
+ break;
39
+ case '--iterations':
40
+ case '-i':
41
+ options.iterations = parseInt(args[++i]) || 3;
42
+ break;
43
+ case '--help':
44
+ case '-h':
45
+ printHelp();
46
+ process.exit(0);
47
+ }
48
+ }
49
+
50
+ function printHelp() {
51
+ console.log(`
52
+ WordPress Performance Analysis Script
53
+
54
+ Usage:
55
+ npx myaidev-method wordpress:performance-check [options]
56
+
57
+ Options:
58
+ --format <type> Output format: json or text (default: json)
59
+ --output <file> Write output to file
60
+ -o <file> Alias for --output
61
+ --verbose Show detailed progress information
62
+ -v Alias for --verbose
63
+ --iterations <n> Number of timing test iterations (default: 3)
64
+ -i <n> Alias for --iterations
65
+ --help Show this help message
66
+ -h Alias for --help
67
+
68
+ Environment Variables (from .env):
69
+ WORDPRESS_URL WordPress site URL
70
+ WORDPRESS_USERNAME Admin username
71
+ WORDPRESS_APP_PASSWORD Application password
72
+
73
+ Performance Checks:
74
+ ✓ API response time measurement
75
+ ✓ Database content analysis
76
+ ✓ Media file optimization opportunities
77
+ ✓ Plugin performance impact
78
+ ✓ Resource usage patterns
79
+
80
+ Examples:
81
+ # Run performance check with JSON output
82
+ npx myaidev-method wordpress:performance-check
83
+
84
+ # Save performance report to file
85
+ npx myaidev-method wordpress:performance-check --output perf-report.json
86
+
87
+ # Display human-readable text report
88
+ npx myaidev-method wordpress:performance-check --format text
89
+
90
+ # Run 5 timing iterations for more accurate measurements
91
+ npx myaidev-method wordpress:performance-check --iterations 5 --verbose
92
+
93
+ Output Structure (JSON):
94
+ {
95
+ "success": true,
96
+ "timestamp": "2025-10-01T12:00:00.000Z",
97
+ "site": { "name": "...", "url": "..." },
98
+ "performance_score": 85,
99
+ "metrics": {
100
+ "api_response_time_ms": 250,
101
+ "post_count": 150,
102
+ "media_count": 400,
103
+ "plugin_count": 15,
104
+ "active_plugins": 12
105
+ },
106
+ "analysis": {...},
107
+ "recommendations": [...]
108
+ }
109
+
110
+ Exit Codes:
111
+ 0 - No performance issues
112
+ 1 - Check error occurred
113
+ 2 - Performance warnings
114
+ `);
115
+ }
116
+
117
+ async function measureResponseTime(wpUtils, iterations) {
118
+ const measurements = [];
119
+
120
+ for (let i = 0; i < iterations; i++) {
121
+ const start = Date.now();
122
+ try {
123
+ await wpUtils.request('/');
124
+ const duration = Date.now() - start;
125
+ measurements.push(duration);
126
+ } catch (error) {
127
+ // Skip failed measurements
128
+ }
129
+
130
+ // Small delay between iterations
131
+ if (i < iterations - 1) {
132
+ await new Promise(resolve => setTimeout(resolve, 100));
133
+ }
134
+ }
135
+
136
+ if (measurements.length === 0) {
137
+ return null;
138
+ }
139
+
140
+ // Calculate statistics
141
+ const avg = measurements.reduce((a, b) => a + b, 0) / measurements.length;
142
+ const sorted = measurements.sort((a, b) => a - b);
143
+ const median = sorted[Math.floor(sorted.length / 2)];
144
+ const min = sorted[0];
145
+ const max = sorted[sorted.length - 1];
146
+
147
+ return {
148
+ average: Math.round(avg),
149
+ median: Math.round(median),
150
+ min,
151
+ max,
152
+ measurements
153
+ };
154
+ }
155
+
156
+ function analyzePerformance(metrics, timing) {
157
+ const analysis = {
158
+ api_performance: { status: 'good', message: '' },
159
+ content_volume: { status: 'good', message: '' },
160
+ media_optimization: { status: 'good', message: '' },
161
+ plugin_impact: { status: 'good', message: '' }
162
+ };
163
+
164
+ // API performance
165
+ if (timing && timing.average > 1000) {
166
+ analysis.api_performance = {
167
+ status: 'critical',
168
+ message: `Slow API response time: ${timing.average}ms (target: <500ms)`
169
+ };
170
+ } else if (timing && timing.average > 500) {
171
+ analysis.api_performance = {
172
+ status: 'warning',
173
+ message: `Moderate API response time: ${timing.average}ms (target: <500ms)`
174
+ };
175
+ } else if (timing) {
176
+ analysis.api_performance = {
177
+ status: 'good',
178
+ message: `Good API response time: ${timing.average}ms`
179
+ };
180
+ }
181
+
182
+ // Content volume
183
+ const totalContent = metrics.post_count + metrics.media_count;
184
+ if (totalContent > 10000) {
185
+ analysis.content_volume = {
186
+ status: 'warning',
187
+ message: `High content volume: ${totalContent} items (consider archiving strategy)`
188
+ };
189
+ } else {
190
+ analysis.content_volume = {
191
+ status: 'good',
192
+ message: `Content volume: ${totalContent} items`
193
+ };
194
+ }
195
+
196
+ // Media optimization
197
+ if (metrics.media_count > 1000) {
198
+ analysis.media_optimization = {
199
+ status: 'warning',
200
+ message: `Large media library: ${metrics.media_count} files (consider CDN and optimization)`
201
+ };
202
+ }
203
+
204
+ // Plugin impact
205
+ if (metrics.active_plugins > 20) {
206
+ analysis.plugin_impact = {
207
+ status: 'warning',
208
+ message: `Many active plugins: ${metrics.active_plugins} (each adds overhead)`
209
+ };
210
+ } else if (metrics.active_plugins > 30) {
211
+ analysis.plugin_impact = {
212
+ status: 'critical',
213
+ message: `Excessive active plugins: ${metrics.active_plugins} (significant performance impact)`
214
+ };
215
+ }
216
+
217
+ return analysis;
218
+ }
219
+
220
+ function generateRecommendations(analysis, metrics) {
221
+ const recommendations = [];
222
+
223
+ if (analysis.api_performance.status !== 'good') {
224
+ recommendations.push({
225
+ priority: 'high',
226
+ area: 'API Performance',
227
+ action: 'Implement page caching and object caching',
228
+ impact: 'Reduce API response time by 50-80%'
229
+ });
230
+ }
231
+
232
+ if (analysis.plugin_impact.status !== 'good') {
233
+ recommendations.push({
234
+ priority: 'medium',
235
+ area: 'Plugin Optimization',
236
+ action: 'Audit and deactivate unused plugins',
237
+ impact: 'Reduce overhead and improve load times'
238
+ });
239
+ }
240
+
241
+ if (analysis.media_optimization.status !== 'good') {
242
+ recommendations.push({
243
+ priority: 'medium',
244
+ area: 'Media Optimization',
245
+ action: 'Implement image optimization and lazy loading',
246
+ impact: 'Reduce bandwidth usage and improve page speed'
247
+ });
248
+ }
249
+
250
+ if (metrics.post_count > 1000) {
251
+ recommendations.push({
252
+ priority: 'low',
253
+ area: 'Database Optimization',
254
+ action: 'Schedule regular database cleanup and optimization',
255
+ impact: 'Maintain query performance over time'
256
+ });
257
+ }
258
+
259
+ return recommendations;
260
+ }
261
+
262
+ function calculatePerformanceScore(analysis, timing) {
263
+ let score = 100;
264
+
265
+ // API performance impact (0-30 points)
266
+ if (timing) {
267
+ if (timing.average > 1000) {
268
+ score -= 30;
269
+ } else if (timing.average > 500) {
270
+ score -= 15;
271
+ } else if (timing.average > 300) {
272
+ score -= 5;
273
+ }
274
+ }
275
+
276
+ // Plugin impact (0-20 points)
277
+ if (analysis.plugin_impact.status === 'critical') {
278
+ score -= 20;
279
+ } else if (analysis.plugin_impact.status === 'warning') {
280
+ score -= 10;
281
+ }
282
+
283
+ // Media optimization (0-15 points)
284
+ if (analysis.media_optimization.status === 'warning') {
285
+ score -= 10;
286
+ }
287
+
288
+ // Content volume (0-10 points)
289
+ if (analysis.content_volume.status === 'warning') {
290
+ score -= 10;
291
+ }
292
+
293
+ return Math.max(0, score);
294
+ }
295
+
296
+ function formatPerformanceReport(perfData) {
297
+ if (!perfData.success) {
298
+ return `ERROR: ${perfData.error}`;
299
+ }
300
+
301
+ const lines = [];
302
+ lines.push('='.repeat(60));
303
+ lines.push('WordPress Performance Analysis Report');
304
+ lines.push('='.repeat(60));
305
+ lines.push(`Site: ${perfData.site.name || perfData.site.url}`);
306
+ lines.push(`Timestamp: ${perfData.timestamp}`);
307
+ lines.push('');
308
+ lines.push(`Performance Score: ${perfData.performance_score}/100`);
309
+ lines.push('');
310
+
311
+ if (perfData.timing) {
312
+ lines.push('API Response Time:');
313
+ lines.push(` Average: ${perfData.timing.average}ms`);
314
+ lines.push(` Median: ${perfData.timing.median}ms`);
315
+ lines.push(` Range: ${perfData.timing.min}ms - ${perfData.timing.max}ms`);
316
+ lines.push('');
317
+ }
318
+
319
+ lines.push('Performance Metrics:');
320
+ lines.push('-'.repeat(60));
321
+ lines.push(`Posts: ${perfData.metrics.post_count}`);
322
+ lines.push(`Media Files: ${perfData.metrics.media_count}`);
323
+ lines.push(`Plugins: ${perfData.metrics.plugin_count} (${perfData.metrics.active_plugins} active)`);
324
+ lines.push('');
325
+
326
+ lines.push('Performance Analysis:');
327
+ lines.push('-'.repeat(60));
328
+ Object.entries(perfData.analysis).forEach(([key, value]) => {
329
+ const statusIcon = {
330
+ good: '✓',
331
+ warning: '⚠',
332
+ critical: '✗'
333
+ }[value.status] || '?';
334
+
335
+ lines.push(`${statusIcon} ${key}: ${value.message}`);
336
+ });
337
+
338
+ if (perfData.recommendations.length > 0) {
339
+ lines.push('');
340
+ lines.push('Recommendations:');
341
+ lines.push('-'.repeat(60));
342
+ perfData.recommendations.forEach((rec, i) => {
343
+ lines.push(`${i + 1}. [${rec.priority.toUpperCase()}] ${rec.area}`);
344
+ lines.push(` Action: ${rec.action}`);
345
+ lines.push(` Impact: ${rec.impact}`);
346
+ });
347
+ }
348
+
349
+ lines.push('');
350
+ lines.push('='.repeat(60));
351
+
352
+ return lines.join('\n');
353
+ }
354
+
355
+ async function runPerformanceCheck() {
356
+ try {
357
+ if (options.verbose) {
358
+ console.error('Initializing WordPress connection...');
359
+ }
360
+
361
+ const wpUtils = new WordPressAdminUtils();
362
+
363
+ if (options.verbose) {
364
+ console.error(`Running performance tests (${options.iterations} iterations)...`);
365
+ }
366
+
367
+ // Measure response time
368
+ const timing = await measureResponseTime(wpUtils, options.iterations);
369
+
370
+ if (options.verbose) {
371
+ console.error('Collecting performance metrics...');
372
+ }
373
+
374
+ // Get performance metrics
375
+ const metrics = await wpUtils.getPerformanceMetrics();
376
+
377
+ if (options.verbose) {
378
+ console.error('Analyzing performance data...');
379
+ }
380
+
381
+ // Analyze results
382
+ const analysis = analyzePerformance(metrics, timing);
383
+ const recommendations = generateRecommendations(analysis, metrics);
384
+ const performanceScore = calculatePerformanceScore(analysis, timing);
385
+
386
+ const siteInfo = await wpUtils.getSiteInfo().catch(() => ({ url: wpUtils.url }));
387
+
388
+ const perfData = {
389
+ success: true,
390
+ timestamp: new Date().toISOString(),
391
+ site: siteInfo,
392
+ performance_score: performanceScore,
393
+ timing,
394
+ metrics,
395
+ analysis,
396
+ recommendations
397
+ };
398
+
399
+ if (options.verbose) {
400
+ console.error('Performance analysis completed.');
401
+ }
402
+
403
+ // Format output
404
+ let output;
405
+ if (options.format === 'text') {
406
+ output = formatPerformanceReport(perfData);
407
+ } else {
408
+ output = JSON.stringify(perfData, null, 2);
409
+ }
410
+
411
+ // Write to file or stdout
412
+ if (options.output) {
413
+ const outputPath = resolve(options.output);
414
+ writeFileSync(outputPath, output, 'utf8');
415
+
416
+ if (options.verbose) {
417
+ console.error(`Report written to: ${outputPath}`);
418
+ }
419
+
420
+ // Also output summary to stdout for piping
421
+ console.log(JSON.stringify({
422
+ success: true,
423
+ output_file: outputPath,
424
+ performance_score: perfData.performance_score,
425
+ avg_response_time: timing?.average
426
+ }));
427
+ } else {
428
+ console.log(output);
429
+ }
430
+
431
+ // Exit with appropriate code
432
+ const hasWarnings = Object.values(analysis).some(a => a.status === 'warning' || a.status === 'critical');
433
+
434
+ if (hasWarnings) {
435
+ process.exit(2); // Performance warnings
436
+ }
437
+
438
+ process.exit(0);
439
+ } catch (error) {
440
+ const errorOutput = {
441
+ success: false,
442
+ error: error.message,
443
+ timestamp: new Date().toISOString()
444
+ };
445
+
446
+ if (options.format === 'json') {
447
+ console.log(JSON.stringify(errorOutput, null, 2));
448
+ } else {
449
+ console.error(`ERROR: ${error.message}`);
450
+ }
451
+
452
+ process.exit(1);
453
+ }
454
+ }
455
+
456
+ // Run if called directly
457
+ if (import.meta.url === `file://${process.argv[1]}`) {
458
+ runPerformanceCheck();
459
+ }
460
+
461
+ export { runPerformanceCheck };
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * WordPress Security Scan Script
5
+ * Scriptable security scan with JSON output for agent processing
6
+ *
7
+ * Usage:
8
+ * npx myaidev-method wordpress:security-scan [options]
9
+ * node src/scripts/wordpress-security-scan.js [options]
10
+ */
11
+
12
+ import { WordPressAdminUtils } from '../lib/wordpress-admin-utils.js';
13
+ import { writeFileSync } from 'fs';
14
+ import { resolve } from 'path';
15
+
16
+ const args = process.argv.slice(2);
17
+
18
+ const options = {
19
+ format: 'json', // json or text
20
+ output: null, // file path for output
21
+ verbose: false,
22
+ detailed: false
23
+ };
24
+
25
+ // Parse arguments
26
+ for (let i = 0; i < args.length; i++) {
27
+ switch (args[i]) {
28
+ case '--format':
29
+ options.format = args[++i] || 'json';
30
+ break;
31
+ case '--output':
32
+ case '-o':
33
+ options.output = args[++i];
34
+ break;
35
+ case '--verbose':
36
+ case '-v':
37
+ options.verbose = true;
38
+ break;
39
+ case '--detailed':
40
+ case '-d':
41
+ options.detailed = true;
42
+ break;
43
+ case '--help':
44
+ case '-h':
45
+ printHelp();
46
+ process.exit(0);
47
+ }
48
+ }
49
+
50
+ function printHelp() {
51
+ console.log(`
52
+ WordPress Security Scan Script
53
+
54
+ Usage:
55
+ npx myaidev-method wordpress:security-scan [options]
56
+
57
+ Options:
58
+ --format <type> Output format: json or text (default: json)
59
+ --output <file> Write output to file
60
+ -o <file> Alias for --output
61
+ --verbose Show detailed progress information
62
+ -v Alias for --verbose
63
+ --detailed Include detailed vulnerability information
64
+ -d Alias for --detailed
65
+ --help Show this help message
66
+ -h Alias for --help
67
+
68
+ Environment Variables (from .env):
69
+ WORDPRESS_URL WordPress site URL
70
+ WORDPRESS_USERNAME Admin username
71
+ WORDPRESS_APP_PASSWORD Application password
72
+
73
+ Security Checks:
74
+ ✓ User account security audit
75
+ ✓ Plugin vulnerability detection
76
+ ✓ Outdated software detection
77
+ ✓ Common security misconfigurations
78
+ ✓ Weak password patterns
79
+
80
+ Examples:
81
+ # Run security scan with JSON output
82
+ npx myaidev-method wordpress:security-scan
83
+
84
+ # Save detailed scan to file
85
+ npx myaidev-method wordpress:security-scan --detailed --output security-report.json
86
+
87
+ # Display human-readable text report
88
+ npx myaidev-method wordpress:security-scan --format text
89
+
90
+ # Verbose mode with progress information
91
+ npx myaidev-method wordpress:security-scan --verbose
92
+
93
+ Output Structure (JSON):
94
+ {
95
+ "success": true,
96
+ "timestamp": "2025-10-01T12:00:00.000Z",
97
+ "site": { "name": "...", "url": "..." },
98
+ "security_score": 85,
99
+ "vulnerabilities": [],
100
+ "warnings": [...],
101
+ "summary": {
102
+ "critical_issues": 0,
103
+ "warnings": 2,
104
+ "status": "warning"
105
+ },
106
+ "recommendations": [...]
107
+ }
108
+
109
+ Exit Codes:
110
+ 0 - No security issues found
111
+ 1 - Scan error occurred
112
+ 2 - Security warnings found
113
+ 3 - Critical vulnerabilities found
114
+ `);
115
+ }
116
+
117
+ async function runSecurityScan() {
118
+ try {
119
+ if (options.verbose) {
120
+ console.error('Initializing WordPress connection...');
121
+ }
122
+
123
+ const wpUtils = new WordPressAdminUtils();
124
+
125
+ if (options.verbose) {
126
+ console.error('Running security scan...');
127
+ console.error(' - Auditing user accounts...');
128
+ }
129
+
130
+ const securityData = await wpUtils.runSecurityScan();
131
+
132
+ if (options.verbose) {
133
+ console.error(' - Checking plugin vulnerabilities...');
134
+ console.error(' - Analyzing security configuration...');
135
+ console.error('Security scan completed.');
136
+ }
137
+
138
+ // Remove detailed info if not requested
139
+ if (!options.detailed && securityData.success) {
140
+ // Truncate detailed information for cleaner output
141
+ if (securityData.warnings) {
142
+ securityData.warnings.forEach(warning => {
143
+ if (warning.details && warning.details.length > 5) {
144
+ warning.details = [
145
+ ...warning.details.slice(0, 5),
146
+ `... and ${warning.details.length - 5} more`
147
+ ];
148
+ }
149
+ });
150
+ }
151
+ }
152
+
153
+ // Format output
154
+ let output;
155
+ if (options.format === 'text') {
156
+ output = wpUtils.formatSecurityReport(securityData);
157
+ } else {
158
+ output = JSON.stringify(securityData, null, 2);
159
+ }
160
+
161
+ // Write to file or stdout
162
+ if (options.output) {
163
+ const outputPath = resolve(options.output);
164
+ writeFileSync(outputPath, output, 'utf8');
165
+
166
+ if (options.verbose) {
167
+ console.error(`Report written to: ${outputPath}`);
168
+ }
169
+
170
+ // Also output summary to stdout for piping
171
+ console.log(JSON.stringify({
172
+ success: true,
173
+ output_file: outputPath,
174
+ security_score: securityData.security_score,
175
+ critical_issues: securityData.summary?.critical_issues || 0,
176
+ warnings: securityData.summary?.warnings || 0
177
+ }));
178
+ } else {
179
+ console.log(output);
180
+ }
181
+
182
+ // Exit with appropriate code
183
+ if (!securityData.success) {
184
+ process.exit(1);
185
+ }
186
+
187
+ const criticalIssues = securityData.vulnerabilities?.length || 0;
188
+ const warnings = securityData.warnings?.length || 0;
189
+
190
+ if (criticalIssues > 0) {
191
+ process.exit(3); // Critical vulnerabilities found
192
+ }
193
+
194
+ if (warnings > 0) {
195
+ process.exit(2); // Warnings found
196
+ }
197
+
198
+ process.exit(0); // All clear
199
+ } catch (error) {
200
+ const errorOutput = {
201
+ success: false,
202
+ error: error.message,
203
+ timestamp: new Date().toISOString()
204
+ };
205
+
206
+ if (options.format === 'json') {
207
+ console.log(JSON.stringify(errorOutput, null, 2));
208
+ } else {
209
+ console.error(`ERROR: ${error.message}`);
210
+ }
211
+
212
+ process.exit(1);
213
+ }
214
+ }
215
+
216
+ // Run if called directly
217
+ if (import.meta.url === `file://${process.argv[1]}`) {
218
+ runSecurityScan();
219
+ }
220
+
221
+ export { runSecurityScan };