@oalacea/daemon 0.5.0 → 0.5.1

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 (38) hide show
  1. package/CHANGELOG.md +46 -38
  2. package/LICENSE +23 -23
  3. package/README.md +147 -141
  4. package/agents/deps-analyzer.js +366 -366
  5. package/agents/detector.js +570 -570
  6. package/agents/fix-engine.js +305 -305
  7. package/agents/lighthouse-scanner.js +405 -405
  8. package/agents/perf-analyzer.js +294 -294
  9. package/agents/perf-front-analyzer.js +229 -229
  10. package/agents/test-generator.js +387 -387
  11. package/agents/test-runner.js +318 -318
  12. package/bin/Dockerfile +75 -74
  13. package/bin/cli.js +449 -449
  14. package/lib/config.js +250 -250
  15. package/lib/docker.js +207 -207
  16. package/lib/reporter.js +297 -297
  17. package/package.json +34 -34
  18. package/prompts/DEPS_EFFICIENCY.md +558 -558
  19. package/prompts/E2E.md +491 -491
  20. package/prompts/EXECUTE.md +1060 -1060
  21. package/prompts/INTEGRATION_API.md +484 -484
  22. package/prompts/INTEGRATION_DB.md +425 -425
  23. package/prompts/PERF_API.md +433 -433
  24. package/prompts/PERF_DB.md +430 -430
  25. package/prompts/PERF_FRONT.md +357 -357
  26. package/prompts/REMEDIATION.md +482 -482
  27. package/prompts/UNIT.md +260 -260
  28. package/scripts/dev.js +106 -106
  29. package/templates/README.md +38 -38
  30. package/templates/k6/load-test.js +54 -54
  31. package/templates/playwright/e2e.spec.ts +61 -61
  32. package/templates/vitest/angular-component.test.ts +38 -38
  33. package/templates/vitest/api.test.ts +51 -51
  34. package/templates/vitest/component.test.ts +27 -27
  35. package/templates/vitest/hook.test.ts +36 -36
  36. package/templates/vitest/solid-component.test.ts +34 -34
  37. package/templates/vitest/svelte-component.test.ts +33 -33
  38. package/templates/vitest/vue-component.test.ts +39 -39
@@ -1,229 +1,229 @@
1
- /**
2
- * Daemon - Frontend Performance Analyzer
3
- *
4
- * Analyzes frontend performance using Lighthouse:
5
- * - Core Web Vitals (LCP, FID, CLS)
6
- * - Performance score
7
- * - Accessibility
8
- * - Best Practices
9
- * - SEO
10
- */
11
-
12
- const { execSync } = require('child_process');
13
- const fs = require('fs');
14
- const path = require('path');
15
-
16
- const CONFIG = {
17
- container: 'daemon-tools',
18
- docker: 'docker exec',
19
- };
20
-
21
- /**
22
- * Run Lighthouse audit
23
- */
24
- function runLighthouse(url, options = {}) {
25
- const outputPath = options.output || path.join(process.cwd(), 'lighthouse-report.json');
26
- const htmlOutput = outputPath.replace('.json', '.html');
27
-
28
- const cmd = [
29
- `docker exec ${CONFIG.container} npx lighthouse`,
30
- url,
31
- `--output=json --output=html`,
32
- `--chrome-flags="--headless --no-sandbox --disable-gpu"`,
33
- `--quiet`,
34
- options.onlyCategories ? `--only-categories=${options.onlyCategories}` : '',
35
- options.formFactor ? `--form-factor=${options.formFactor}` : '--throttling-method=devtools',
36
- options.screenEmulation ? `--screen-emulation=${options.screenEmulation}` : '',
37
- ].filter(Boolean).join(' ');
38
-
39
- try {
40
- execSync(cmd, { encoding: 'utf-8', stdio: 'pipe', timeout: 120000 });
41
-
42
- // Read the JSON report (container writes to /app)
43
- const reportPath = path.join(process.cwd(), 'lighthouse-report.json');
44
- if (fs.existsSync(reportPath)) {
45
- const report = JSON.parse(fs.readFileSync(reportPath, 'utf-8'));
46
- return { success: true, report, htmlOutput };
47
- }
48
- } catch (error) {
49
- return {
50
- success: false,
51
- error: error.message,
52
- };
53
- }
54
- }
55
-
56
- /**
57
- * Analyze Lighthouse results
58
- */
59
- function analyzeResults(report) {
60
- const categories = report.categories || {};
61
- const audits = report.audits || {};
62
-
63
- return {
64
- scores: {
65
- performance: categories.performance?.score || 0,
66
- accessibility: categories.accessibility?.score || 0,
67
- bestPractices: categories['best-practices']?.score || 0,
68
- seo: categories.seo?.score || 0,
69
- pwa: categories.pwa?.score || 0,
70
- },
71
- coreWebVitals: {
72
- lcp: audits['largest-contentful-paint']?.displayValue || 'N/A',
73
- fid: audits['max-potential-fid']?.displayValue || 'N/A',
74
- cls: audits['cumulative-layout-shift']?.displayValue || 'N/A',
75
- ttfb: audits['time-to-first-byte']?.displayValue || 'N/A',
76
- fcp: audits['first-contentful-paint']?.displayValue || 'N/A',
77
- tti: audits['interactive']?.displayValue || 'N/A',
78
- si: audits['speed-index']?.displayValue || 'N/A',
79
- },
80
- opportunities: (opportunities || []).map(item => ({
81
- id: item.id,
82
- title: item.title,
83
- description: item.description,
84
- score: item.score,
85
- displayValue: item.displayValue,
86
- })),
87
- diagnostics: Object.values(audits)
88
- .filter(audit => audit.details && audit.details.type === 'table')
89
- .map(audit => ({
90
- id: audit.id,
91
- title: audit.title,
92
- description: audit.description,
93
- items: audit.details?.items || [],
94
- })),
95
- };
96
- }
97
-
98
- /**
99
- * Get performance opportunities
100
- */
101
- function getOpportunities(report) {
102
- const opportunities = [];
103
-
104
- if (!report.audits) return opportunities;
105
-
106
- const opportunityAudits = [
107
- 'render-blocking-resources',
108
- 'unminified-css',
109
- 'unminified-javascript',
110
- 'unused-css-rules',
111
- 'unused-javascript',
112
- 'modern-image-formats',
113
- 'offscreen-images',
114
- 'scaled-images',
115
- 'efficient-animated-content',
116
- 'text-compression',
117
- 'uses-long-cache-ttl',
118
- 'total-byte-weight',
119
- 'uses-optimized-images',
120
- ];
121
-
122
- for (const id of opportunityAudits) {
123
- const audit = report.audits[id];
124
- if (audit && audit.score !== null && audit.score < 1) {
125
- opportunities.push({
126
- id,
127
- title: audit.title,
128
- description: audit.description,
129
- score: audit.score,
130
- displayValue: audit.displayValue,
131
- severity: audit.score < 0.5 ? 'high' : 'medium',
132
- });
133
- }
134
- }
135
-
136
- return opportunities.sort((a, b) => a.score - b.score);
137
- }
138
-
139
- /**
140
- * Generate performance recommendations
141
- */
142
- function generateRecommendations(results) {
143
- const recommendations = [];
144
- const { scores, coreWebVitals, opportunities } = results;
145
-
146
- // Performance score recommendations
147
- if (scores.performance < 0.5) {
148
- recommendations.push({
149
- type: 'critical',
150
- message: `Performance score is ${(scores.performance * 100).toFixed(0)}/100. Immediate optimization required.`,
151
- });
152
- } else if (scores.performance < 0.8) {
153
- recommendations.push({
154
- type: 'warning',
155
- message: `Performance score is ${(scores.performance * 100).toFixed(0)}/100. Optimization recommended.`,
156
- });
157
- }
158
-
159
- // Core Web Vitals recommendations
160
- if (coreWebVitals.lcp) {
161
- const lcpValue = parseFloat(coreWebVitals.lcp);
162
- if (lcpValue > 4000) {
163
- recommendations.push({
164
- type: 'critical',
165
- metric: 'LCP',
166
- message: `LCP is ${coreWebVitals.lcp} (target: <2.5s). Consider lazy loading, code splitting, or optimizing images.`,
167
- });
168
- }
169
- }
170
-
171
- if (coreWebVitals.cls) {
172
- const clsValue = parseFloat(coreWebVitals.cls);
173
- if (clsValue > 0.25) {
174
- recommendations.push({
175
- type: 'critical',
176
- metric: 'CLS',
177
- message: `CLS is ${coreWebVitals.cls} (target: <0.1). Reserve space for dynamic content.`,
178
- });
179
- }
180
- }
181
-
182
- // Opportunity-based recommendations
183
- for (const opp of opportunities.slice(0, 5)) {
184
- recommendations.push({
185
- type: opp.severity === 'high' ? 'warning' : 'info',
186
- message: `${opp.title}: ${opp.displayValue || 'Needs improvement'}`,
187
- });
188
- }
189
-
190
- return recommendations;
191
- }
192
-
193
- /**
194
- * Run mobile audit
195
- */
196
- function runMobileAudit(url) {
197
- return runLighthouse(url, {
198
- formFactor: 'mobile',
199
- screenEmulation: 'mobile',
200
- });
201
- }
202
-
203
- /**
204
- * Run desktop audit
205
- */
206
- function runDesktopAudit(url) {
207
- return runLighthouse(url, {
208
- formFactor: 'desktop',
209
- });
210
- }
211
-
212
- /**
213
- * Run performance-only audit (faster)
214
- */
215
- function runPerformanceOnlyAudit(url) {
216
- return runLighthouse(url, {
217
- onlyCategories: 'performance',
218
- });
219
- }
220
-
221
- module.exports = {
222
- runLighthouse,
223
- analyzeResults,
224
- getOpportunities,
225
- generateRecommendations,
226
- runMobileAudit,
227
- runDesktopAudit,
228
- runPerformanceOnlyAudit,
229
- };
1
+ /**
2
+ * Daemon - Frontend Performance Analyzer
3
+ *
4
+ * Analyzes frontend performance using Lighthouse:
5
+ * - Core Web Vitals (LCP, FID, CLS)
6
+ * - Performance score
7
+ * - Accessibility
8
+ * - Best Practices
9
+ * - SEO
10
+ */
11
+
12
+ const { execSync } = require('child_process');
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ const CONFIG = {
17
+ container: 'daemon-tools',
18
+ docker: 'docker exec',
19
+ };
20
+
21
+ /**
22
+ * Run Lighthouse audit
23
+ */
24
+ function runLighthouse(url, options = {}) {
25
+ const outputPath = options.output || path.join(process.cwd(), 'lighthouse-report.json');
26
+ const htmlOutput = outputPath.replace('.json', '.html');
27
+
28
+ const cmd = [
29
+ `docker exec ${CONFIG.container} npx lighthouse`,
30
+ url,
31
+ `--output=json --output=html`,
32
+ `--chrome-flags="--headless --no-sandbox --disable-gpu"`,
33
+ `--quiet`,
34
+ options.onlyCategories ? `--only-categories=${options.onlyCategories}` : '',
35
+ options.formFactor ? `--form-factor=${options.formFactor}` : '--throttling-method=devtools',
36
+ options.screenEmulation ? `--screen-emulation=${options.screenEmulation}` : '',
37
+ ].filter(Boolean).join(' ');
38
+
39
+ try {
40
+ execSync(cmd, { encoding: 'utf-8', stdio: 'pipe', timeout: 120000 });
41
+
42
+ // Read the JSON report (container writes to /app)
43
+ const reportPath = path.join(process.cwd(), 'lighthouse-report.json');
44
+ if (fs.existsSync(reportPath)) {
45
+ const report = JSON.parse(fs.readFileSync(reportPath, 'utf-8'));
46
+ return { success: true, report, htmlOutput };
47
+ }
48
+ } catch (error) {
49
+ return {
50
+ success: false,
51
+ error: error.message,
52
+ };
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Analyze Lighthouse results
58
+ */
59
+ function analyzeResults(report) {
60
+ const categories = report.categories || {};
61
+ const audits = report.audits || {};
62
+
63
+ return {
64
+ scores: {
65
+ performance: categories.performance?.score || 0,
66
+ accessibility: categories.accessibility?.score || 0,
67
+ bestPractices: categories['best-practices']?.score || 0,
68
+ seo: categories.seo?.score || 0,
69
+ pwa: categories.pwa?.score || 0,
70
+ },
71
+ coreWebVitals: {
72
+ lcp: audits['largest-contentful-paint']?.displayValue || 'N/A',
73
+ fid: audits['max-potential-fid']?.displayValue || 'N/A',
74
+ cls: audits['cumulative-layout-shift']?.displayValue || 'N/A',
75
+ ttfb: audits['time-to-first-byte']?.displayValue || 'N/A',
76
+ fcp: audits['first-contentful-paint']?.displayValue || 'N/A',
77
+ tti: audits['interactive']?.displayValue || 'N/A',
78
+ si: audits['speed-index']?.displayValue || 'N/A',
79
+ },
80
+ opportunities: (opportunities || []).map(item => ({
81
+ id: item.id,
82
+ title: item.title,
83
+ description: item.description,
84
+ score: item.score,
85
+ displayValue: item.displayValue,
86
+ })),
87
+ diagnostics: Object.values(audits)
88
+ .filter(audit => audit.details && audit.details.type === 'table')
89
+ .map(audit => ({
90
+ id: audit.id,
91
+ title: audit.title,
92
+ description: audit.description,
93
+ items: audit.details?.items || [],
94
+ })),
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Get performance opportunities
100
+ */
101
+ function getOpportunities(report) {
102
+ const opportunities = [];
103
+
104
+ if (!report.audits) return opportunities;
105
+
106
+ const opportunityAudits = [
107
+ 'render-blocking-resources',
108
+ 'unminified-css',
109
+ 'unminified-javascript',
110
+ 'unused-css-rules',
111
+ 'unused-javascript',
112
+ 'modern-image-formats',
113
+ 'offscreen-images',
114
+ 'scaled-images',
115
+ 'efficient-animated-content',
116
+ 'text-compression',
117
+ 'uses-long-cache-ttl',
118
+ 'total-byte-weight',
119
+ 'uses-optimized-images',
120
+ ];
121
+
122
+ for (const id of opportunityAudits) {
123
+ const audit = report.audits[id];
124
+ if (audit && audit.score !== null && audit.score < 1) {
125
+ opportunities.push({
126
+ id,
127
+ title: audit.title,
128
+ description: audit.description,
129
+ score: audit.score,
130
+ displayValue: audit.displayValue,
131
+ severity: audit.score < 0.5 ? 'high' : 'medium',
132
+ });
133
+ }
134
+ }
135
+
136
+ return opportunities.sort((a, b) => a.score - b.score);
137
+ }
138
+
139
+ /**
140
+ * Generate performance recommendations
141
+ */
142
+ function generateRecommendations(results) {
143
+ const recommendations = [];
144
+ const { scores, coreWebVitals, opportunities } = results;
145
+
146
+ // Performance score recommendations
147
+ if (scores.performance < 0.5) {
148
+ recommendations.push({
149
+ type: 'critical',
150
+ message: `Performance score is ${(scores.performance * 100).toFixed(0)}/100. Immediate optimization required.`,
151
+ });
152
+ } else if (scores.performance < 0.8) {
153
+ recommendations.push({
154
+ type: 'warning',
155
+ message: `Performance score is ${(scores.performance * 100).toFixed(0)}/100. Optimization recommended.`,
156
+ });
157
+ }
158
+
159
+ // Core Web Vitals recommendations
160
+ if (coreWebVitals.lcp) {
161
+ const lcpValue = parseFloat(coreWebVitals.lcp);
162
+ if (lcpValue > 4000) {
163
+ recommendations.push({
164
+ type: 'critical',
165
+ metric: 'LCP',
166
+ message: `LCP is ${coreWebVitals.lcp} (target: <2.5s). Consider lazy loading, code splitting, or optimizing images.`,
167
+ });
168
+ }
169
+ }
170
+
171
+ if (coreWebVitals.cls) {
172
+ const clsValue = parseFloat(coreWebVitals.cls);
173
+ if (clsValue > 0.25) {
174
+ recommendations.push({
175
+ type: 'critical',
176
+ metric: 'CLS',
177
+ message: `CLS is ${coreWebVitals.cls} (target: <0.1). Reserve space for dynamic content.`,
178
+ });
179
+ }
180
+ }
181
+
182
+ // Opportunity-based recommendations
183
+ for (const opp of opportunities.slice(0, 5)) {
184
+ recommendations.push({
185
+ type: opp.severity === 'high' ? 'warning' : 'info',
186
+ message: `${opp.title}: ${opp.displayValue || 'Needs improvement'}`,
187
+ });
188
+ }
189
+
190
+ return recommendations;
191
+ }
192
+
193
+ /**
194
+ * Run mobile audit
195
+ */
196
+ function runMobileAudit(url) {
197
+ return runLighthouse(url, {
198
+ formFactor: 'mobile',
199
+ screenEmulation: 'mobile',
200
+ });
201
+ }
202
+
203
+ /**
204
+ * Run desktop audit
205
+ */
206
+ function runDesktopAudit(url) {
207
+ return runLighthouse(url, {
208
+ formFactor: 'desktop',
209
+ });
210
+ }
211
+
212
+ /**
213
+ * Run performance-only audit (faster)
214
+ */
215
+ function runPerformanceOnlyAudit(url) {
216
+ return runLighthouse(url, {
217
+ onlyCategories: 'performance',
218
+ });
219
+ }
220
+
221
+ module.exports = {
222
+ runLighthouse,
223
+ analyzeResults,
224
+ getOpportunities,
225
+ generateRecommendations,
226
+ runMobileAudit,
227
+ runDesktopAudit,
228
+ runPerformanceOnlyAudit,
229
+ };