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,504 @@
1
+ /**
2
+ * Report Synthesizer Utilities
3
+ * Tools for combining script outputs into comprehensive reports for agent processing
4
+ */
5
+
6
+ import { readFileSync } from 'fs';
7
+
8
+ export class ReportSynthesizer {
9
+ constructor() {
10
+ this.reports = [];
11
+ }
12
+
13
+ /**
14
+ * Add a report from JSON string or object
15
+ */
16
+ addReport(report, type = 'generic') {
17
+ const reportData = typeof report === 'string' ? JSON.parse(report) : report;
18
+
19
+ this.reports.push({
20
+ type,
21
+ timestamp: reportData.timestamp || new Date().toISOString(),
22
+ data: reportData
23
+ });
24
+ }
25
+
26
+ /**
27
+ * Add report from file
28
+ */
29
+ addReportFromFile(filePath, type = 'generic') {
30
+ const content = readFileSync(filePath, 'utf8');
31
+ this.addReport(content, type);
32
+ }
33
+
34
+ /**
35
+ * Synthesize all reports into comprehensive analysis
36
+ */
37
+ synthesize() {
38
+ const synthesis = {
39
+ timestamp: new Date().toISOString(),
40
+ reports_analyzed: this.reports.length,
41
+ site_info: this.extractSiteInfo(),
42
+ executive_summary: this.generateExecutiveSummary(),
43
+ critical_issues: this.extractCriticalIssues(),
44
+ warnings: this.extractWarnings(),
45
+ metrics: this.aggregateMetrics(),
46
+ recommendations: this.prioritizeRecommendations(),
47
+ action_items: this.generateActionItems()
48
+ };
49
+
50
+ return synthesis;
51
+ }
52
+
53
+ /**
54
+ * Extract common site information from reports
55
+ */
56
+ extractSiteInfo() {
57
+ const siteReport = this.reports.find(r => r.data.site);
58
+ if (!siteReport) return null;
59
+
60
+ return {
61
+ name: siteReport.data.site.name,
62
+ url: siteReport.data.site.url,
63
+ wordpress_version: siteReport.data.site.wordpress_version,
64
+ analysis_date: siteReport.timestamp
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Generate executive summary
70
+ */
71
+ generateExecutiveSummary() {
72
+ const summary = {
73
+ overall_status: 'unknown',
74
+ health_score: null,
75
+ security_score: null,
76
+ performance_score: null,
77
+ key_findings: []
78
+ };
79
+
80
+ this.reports.forEach(report => {
81
+ // Extract scores
82
+ if (report.data.overall_health?.score) {
83
+ summary.health_score = report.data.overall_health.score;
84
+ }
85
+
86
+ if (report.data.security_score !== undefined) {
87
+ summary.security_score = report.data.security_score;
88
+ }
89
+
90
+ if (report.data.performance_score !== undefined) {
91
+ summary.performance_score = report.data.performance_score;
92
+ }
93
+
94
+ // Extract key findings
95
+ if (report.data.overall_health?.status) {
96
+ summary.key_findings.push({
97
+ type: 'health',
98
+ status: report.data.overall_health.status,
99
+ score: report.data.overall_health.score
100
+ });
101
+ }
102
+
103
+ if (report.data.summary?.status) {
104
+ summary.key_findings.push({
105
+ type: report.type,
106
+ status: report.data.summary.status,
107
+ critical: report.data.summary.critical_issues || 0,
108
+ warnings: report.data.summary.warnings || 0
109
+ });
110
+ }
111
+ });
112
+
113
+ // Determine overall status
114
+ const hasHealthIssues = summary.health_score && summary.health_score < 70;
115
+ const hasSecurityIssues = summary.security_score && summary.security_score < 70;
116
+ const hasPerformanceIssues = summary.performance_score && summary.performance_score < 70;
117
+
118
+ if (hasSecurityIssues) {
119
+ summary.overall_status = 'critical';
120
+ } else if (hasHealthIssues || hasPerformanceIssues) {
121
+ summary.overall_status = 'warning';
122
+ } else {
123
+ summary.overall_status = 'healthy';
124
+ }
125
+
126
+ return summary;
127
+ }
128
+
129
+ /**
130
+ * Extract all critical issues
131
+ */
132
+ extractCriticalIssues() {
133
+ const criticalIssues = [];
134
+
135
+ this.reports.forEach(report => {
136
+ // From health checks
137
+ if (report.data.checks) {
138
+ const critical = report.data.checks.filter(c => c.status === 'critical');
139
+ critical.forEach(issue => {
140
+ criticalIssues.push({
141
+ source: report.type,
142
+ check: issue.check,
143
+ message: issue.message,
144
+ severity: 'critical'
145
+ });
146
+ });
147
+ }
148
+
149
+ // From security scans
150
+ if (report.data.vulnerabilities) {
151
+ report.data.vulnerabilities.forEach(vuln => {
152
+ criticalIssues.push({
153
+ source: 'security',
154
+ type: vuln.type,
155
+ severity: vuln.severity,
156
+ details: vuln.details
157
+ });
158
+ });
159
+ }
160
+ });
161
+
162
+ return criticalIssues;
163
+ }
164
+
165
+ /**
166
+ * Extract all warnings
167
+ */
168
+ extractWarnings() {
169
+ const warnings = [];
170
+
171
+ this.reports.forEach(report => {
172
+ // From health checks
173
+ if (report.data.checks) {
174
+ const warningChecks = report.data.checks.filter(c => c.status === 'warning');
175
+ warningChecks.forEach(warning => {
176
+ warnings.push({
177
+ source: report.type,
178
+ check: warning.check,
179
+ message: warning.message
180
+ });
181
+ });
182
+ }
183
+
184
+ // From security scans
185
+ if (report.data.warnings) {
186
+ report.data.warnings.forEach(warning => {
187
+ warnings.push({
188
+ source: 'security',
189
+ type: warning.type,
190
+ severity: warning.severity,
191
+ count: warning.count,
192
+ summary: warning.details?.[0] || 'See details'
193
+ });
194
+ });
195
+ }
196
+
197
+ // From performance analysis
198
+ if (report.data.analysis) {
199
+ Object.entries(report.data.analysis).forEach(([key, value]) => {
200
+ if (value.status === 'warning' || value.status === 'critical') {
201
+ warnings.push({
202
+ source: 'performance',
203
+ check: key,
204
+ status: value.status,
205
+ message: value.message
206
+ });
207
+ }
208
+ });
209
+ }
210
+ });
211
+
212
+ return warnings;
213
+ }
214
+
215
+ /**
216
+ * Aggregate metrics from all reports
217
+ */
218
+ aggregateMetrics() {
219
+ const metrics = {};
220
+
221
+ this.reports.forEach(report => {
222
+ if (report.data.metrics) {
223
+ Object.assign(metrics, report.data.metrics);
224
+ }
225
+
226
+ if (report.data.timing) {
227
+ metrics.api_response_time = report.data.timing.average;
228
+ }
229
+
230
+ if (report.data.post_stats) {
231
+ metrics.posts = report.data.post_stats;
232
+ }
233
+
234
+ if (report.data.media_stats) {
235
+ metrics.media = report.data.media_stats;
236
+ }
237
+ });
238
+
239
+ return metrics;
240
+ }
241
+
242
+ /**
243
+ * Prioritize and deduplicate recommendations
244
+ */
245
+ prioritizeRecommendations() {
246
+ const allRecommendations = [];
247
+
248
+ this.reports.forEach(report => {
249
+ if (Array.isArray(report.data.recommendations)) {
250
+ // Simple string recommendations
251
+ report.data.recommendations.forEach(rec => {
252
+ if (typeof rec === 'string') {
253
+ allRecommendations.push({
254
+ priority: 'medium',
255
+ source: report.type,
256
+ recommendation: rec
257
+ });
258
+ } else {
259
+ // Structured recommendations
260
+ allRecommendations.push({
261
+ priority: rec.priority || 'medium',
262
+ source: report.type,
263
+ area: rec.area,
264
+ action: rec.action || rec.recommendation,
265
+ impact: rec.impact
266
+ });
267
+ }
268
+ });
269
+ }
270
+ });
271
+
272
+ // Deduplicate by action/recommendation text
273
+ const unique = new Map();
274
+ allRecommendations.forEach(rec => {
275
+ const key = rec.action || rec.recommendation;
276
+ if (!unique.has(key)) {
277
+ unique.set(key, rec);
278
+ }
279
+ });
280
+
281
+ // Sort by priority
282
+ const priorityOrder = { high: 0, medium: 1, low: 2 };
283
+ return Array.from(unique.values()).sort((a, b) => {
284
+ return (priorityOrder[a.priority] || 1) - (priorityOrder[b.priority] || 1);
285
+ });
286
+ }
287
+
288
+ /**
289
+ * Generate prioritized action items
290
+ */
291
+ generateActionItems() {
292
+ const actionItems = [];
293
+
294
+ // Critical issues become immediate actions
295
+ const critical = this.extractCriticalIssues();
296
+ critical.forEach((issue, index) => {
297
+ actionItems.push({
298
+ priority: 1,
299
+ category: 'critical',
300
+ action: `Address critical issue: ${issue.message || issue.type}`,
301
+ source: issue.source
302
+ });
303
+ });
304
+
305
+ // High-priority recommendations
306
+ const recommendations = this.prioritizeRecommendations();
307
+ recommendations
308
+ .filter(rec => rec.priority === 'high')
309
+ .forEach(rec => {
310
+ actionItems.push({
311
+ priority: 2,
312
+ category: 'high-priority',
313
+ action: rec.action || rec.recommendation,
314
+ area: rec.area,
315
+ impact: rec.impact
316
+ });
317
+ });
318
+
319
+ // Medium-priority warnings
320
+ const warnings = this.extractWarnings();
321
+ const uniqueWarnings = new Map();
322
+ warnings.forEach(warning => {
323
+ const key = warning.check || warning.type;
324
+ if (!uniqueWarnings.has(key)) {
325
+ uniqueWarnings.set(key, warning);
326
+ }
327
+ });
328
+
329
+ Array.from(uniqueWarnings.values())
330
+ .slice(0, 5) // Top 5 warnings
331
+ .forEach(warning => {
332
+ actionItems.push({
333
+ priority: 3,
334
+ category: 'warning',
335
+ action: `Review warning: ${warning.message || warning.type}`,
336
+ source: warning.source
337
+ });
338
+ });
339
+
340
+ return actionItems.slice(0, 10); // Top 10 action items
341
+ }
342
+
343
+ /**
344
+ * Generate comprehensive markdown report
345
+ */
346
+ generateMarkdownReport() {
347
+ const synthesis = this.synthesize();
348
+ const lines = [];
349
+
350
+ lines.push('# WordPress Comprehensive Analysis Report');
351
+ lines.push('');
352
+
353
+ if (synthesis.site_info) {
354
+ lines.push('## Site Information');
355
+ lines.push(`- **Name**: ${synthesis.site_info.name}`);
356
+ lines.push(`- **URL**: ${synthesis.site_info.url}`);
357
+ lines.push(`- **WordPress Version**: ${synthesis.site_info.wordpress_version}`);
358
+ lines.push(`- **Analysis Date**: ${synthesis.site_info.analysis_date}`);
359
+ lines.push('');
360
+ }
361
+
362
+ lines.push('## Executive Summary');
363
+ lines.push('');
364
+ lines.push(`**Overall Status**: ${synthesis.executive_summary.overall_status.toUpperCase()}`);
365
+ lines.push('');
366
+ lines.push('### Scores');
367
+ if (synthesis.executive_summary.health_score) {
368
+ lines.push(`- Health: ${synthesis.executive_summary.health_score}/100`);
369
+ }
370
+ if (synthesis.executive_summary.security_score !== null) {
371
+ lines.push(`- Security: ${synthesis.executive_summary.security_score}/100`);
372
+ }
373
+ if (synthesis.executive_summary.performance_score !== null) {
374
+ lines.push(`- Performance: ${synthesis.executive_summary.performance_score}/100`);
375
+ }
376
+ lines.push('');
377
+
378
+ if (synthesis.critical_issues.length > 0) {
379
+ lines.push('## 🚨 Critical Issues');
380
+ lines.push('');
381
+ synthesis.critical_issues.forEach((issue, i) => {
382
+ lines.push(`${i + 1}. **${issue.check || issue.type}** (${issue.source})`);
383
+ lines.push(` - ${issue.message || issue.details?.[0] || 'See details'}`);
384
+ lines.push('');
385
+ });
386
+ }
387
+
388
+ if (synthesis.warnings.length > 0) {
389
+ lines.push('## ⚠️ Warnings');
390
+ lines.push('');
391
+ synthesis.warnings.slice(0, 10).forEach((warning, i) => {
392
+ lines.push(`${i + 1}. **${warning.check || warning.type}** (${warning.source})`);
393
+ lines.push(` - ${warning.message || warning.summary}`);
394
+ lines.push('');
395
+ });
396
+
397
+ if (synthesis.warnings.length > 10) {
398
+ lines.push(`_... and ${synthesis.warnings.length - 10} more warnings_`);
399
+ lines.push('');
400
+ }
401
+ }
402
+
403
+ lines.push('## 📊 Key Metrics');
404
+ lines.push('');
405
+ if (synthesis.metrics.post_count !== undefined) {
406
+ lines.push(`- **Posts**: ${synthesis.metrics.post_count}`);
407
+ }
408
+ if (synthesis.metrics.media_count !== undefined) {
409
+ lines.push(`- **Media Files**: ${synthesis.metrics.media_count}`);
410
+ }
411
+ if (synthesis.metrics.plugin_count !== undefined) {
412
+ lines.push(`- **Plugins**: ${synthesis.metrics.plugin_count} (${synthesis.metrics.active_plugins} active)`);
413
+ }
414
+ if (synthesis.metrics.api_response_time) {
415
+ lines.push(`- **API Response Time**: ${synthesis.metrics.api_response_time}ms`);
416
+ }
417
+ lines.push('');
418
+
419
+ if (synthesis.recommendations.length > 0) {
420
+ lines.push('## 💡 Recommendations');
421
+ lines.push('');
422
+ synthesis.recommendations.forEach((rec, i) => {
423
+ const priorityIcon = {
424
+ high: '🔴',
425
+ medium: '🟡',
426
+ low: '🟢'
427
+ }[rec.priority] || '⚪';
428
+
429
+ lines.push(`${i + 1}. ${priorityIcon} **${rec.area || rec.source}**`);
430
+ lines.push(` - ${rec.action || rec.recommendation}`);
431
+ if (rec.impact) {
432
+ lines.push(` - _Impact_: ${rec.impact}`);
433
+ }
434
+ lines.push('');
435
+ });
436
+ }
437
+
438
+ if (synthesis.action_items.length > 0) {
439
+ lines.push('## ✅ Action Items');
440
+ lines.push('');
441
+ lines.push('Priority-ordered tasks:');
442
+ lines.push('');
443
+ synthesis.action_items.forEach((item, i) => {
444
+ lines.push(`${i + 1}. [${item.category.toUpperCase()}] ${item.action}`);
445
+ if (item.impact) {
446
+ lines.push(` - ${item.impact}`);
447
+ }
448
+ });
449
+ lines.push('');
450
+ }
451
+
452
+ lines.push('---');
453
+ lines.push(`_Report generated: ${synthesis.timestamp}_`);
454
+
455
+ return lines.join('\n');
456
+ }
457
+
458
+ /**
459
+ * Generate JSON report for agent consumption
460
+ */
461
+ generateJSONReport() {
462
+ return JSON.stringify(this.synthesize(), null, 2);
463
+ }
464
+
465
+ /**
466
+ * Reset synthesizer state
467
+ */
468
+ reset() {
469
+ this.reports = [];
470
+ }
471
+ }
472
+
473
+ /**
474
+ * Convenience function to synthesize multiple report files
475
+ */
476
+ export async function synthesizeReports(reportFiles, options = {}) {
477
+ const synthesizer = new ReportSynthesizer();
478
+
479
+ reportFiles.forEach(file => {
480
+ const type = file.type || inferReportType(file.path);
481
+ synthesizer.addReportFromFile(file.path, type);
482
+ });
483
+
484
+ if (options.format === 'markdown') {
485
+ return synthesizer.generateMarkdownReport();
486
+ }
487
+
488
+ return synthesizer.generateJSONReport();
489
+ }
490
+
491
+ /**
492
+ * Infer report type from filename
493
+ */
494
+ function inferReportType(filePath) {
495
+ const fileName = filePath.toLowerCase();
496
+
497
+ if (fileName.includes('health')) return 'health';
498
+ if (fileName.includes('security')) return 'security';
499
+ if (fileName.includes('performance') || fileName.includes('perf')) return 'performance';
500
+
501
+ return 'generic';
502
+ }
503
+
504
+ export default ReportSynthesizer;