@oalacea/daemon 0.5.1 → 0.6.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.
- package/dist/cli/cli.d.ts +42 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +89 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/commands/detect.command.d.ts +39 -0
- package/dist/cli/commands/detect.command.d.ts.map +1 -0
- package/dist/cli/commands/detect.command.js +111 -0
- package/dist/cli/commands/detect.command.js.map +1 -0
- package/dist/cli/commands/index.d.ts +14 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +11 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init.command.d.ts +41 -0
- package/dist/cli/commands/init.command.d.ts.map +1 -0
- package/dist/cli/commands/init.command.js +111 -0
- package/dist/cli/commands/init.command.js.map +1 -0
- package/dist/cli/commands/test.command.d.ts +58 -0
- package/dist/cli/commands/test.command.d.ts.map +1 -0
- package/dist/cli/commands/test.command.js +180 -0
- package/dist/cli/commands/test.command.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +10 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/config/daemon.config.d.ts +32 -0
- package/dist/core/config/daemon.config.d.ts.map +1 -0
- package/dist/core/config/daemon.config.js +83 -0
- package/dist/core/config/daemon.config.js.map +1 -0
- package/dist/core/config/index.d.ts +5 -0
- package/dist/core/config/index.d.ts.map +1 -0
- package/dist/core/config/index.js +5 -0
- package/dist/core/config/index.js.map +1 -0
- package/dist/core/constants.d.ts +36 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +56 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/types/common.types.d.ts +250 -0
- package/dist/core/types/common.types.d.ts.map +1 -0
- package/dist/core/types/common.types.js +7 -0
- package/dist/core/types/common.types.js.map +1 -0
- package/dist/core/types/detection.types.d.ts +232 -0
- package/dist/core/types/detection.types.d.ts.map +1 -0
- package/dist/core/types/detection.types.js +22 -0
- package/dist/core/types/detection.types.js.map +1 -0
- package/dist/core/types/docker.types.d.ts +322 -0
- package/dist/core/types/docker.types.d.ts.map +1 -0
- package/dist/core/types/docker.types.js +7 -0
- package/dist/core/types/docker.types.js.map +1 -0
- package/dist/core/types/index.d.ts +11 -0
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/core/types/index.js +7 -0
- package/dist/core/types/index.js.map +1 -0
- package/dist/core/types/project.types.d.ts +74 -0
- package/dist/core/types/project.types.d.ts.map +1 -0
- package/dist/core/types/project.types.js +7 -0
- package/dist/core/types/project.types.js.map +1 -0
- package/dist/core/types/shared.types.d.ts +118 -0
- package/dist/core/types/shared.types.d.ts.map +1 -0
- package/dist/core/types/shared.types.js +7 -0
- package/dist/core/types/shared.types.js.map +1 -0
- package/dist/core/types/test.types.d.ts +230 -0
- package/dist/core/types/test.types.d.ts.map +1 -0
- package/dist/core/types/test.types.js +7 -0
- package/dist/core/types/test.types.js.map +1 -0
- package/dist/services/detection/__tests__/framework-detector.test.d.ts +5 -0
- package/dist/services/detection/__tests__/framework-detector.test.d.ts.map +1 -0
- package/dist/services/detection/__tests__/framework-detector.test.js +52 -0
- package/dist/services/detection/__tests__/framework-detector.test.js.map +1 -0
- package/dist/services/detection/framework-detector.d.ts +179 -0
- package/dist/services/detection/framework-detector.d.ts.map +1 -0
- package/dist/services/detection/framework-detector.js +636 -0
- package/dist/services/detection/framework-detector.js.map +1 -0
- package/dist/services/detection/index.d.ts +10 -0
- package/dist/services/detection/index.d.ts.map +1 -0
- package/dist/services/detection/index.js +7 -0
- package/dist/services/detection/index.js.map +1 -0
- package/dist/services/docker/__tests__/docker-manager.test.d.ts +5 -0
- package/dist/services/docker/__tests__/docker-manager.test.d.ts.map +1 -0
- package/dist/services/docker/__tests__/docker-manager.test.js +67 -0
- package/dist/services/docker/__tests__/docker-manager.test.js.map +1 -0
- package/dist/services/docker/docker-manager.d.ts +157 -0
- package/dist/services/docker/docker-manager.d.ts.map +1 -0
- package/dist/services/docker/docker-manager.js +516 -0
- package/dist/services/docker/docker-manager.js.map +1 -0
- package/dist/services/docker/index.d.ts +9 -0
- package/dist/services/docker/index.d.ts.map +1 -0
- package/dist/services/docker/index.js +9 -0
- package/dist/services/docker/index.js.map +1 -0
- package/dist/services/index.d.ts +10 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +8 -0
- package/dist/services/index.js.map +1 -0
- package/dist/shared/errors/__tests__/base.error.test.d.ts +5 -0
- package/dist/shared/errors/__tests__/base.error.test.d.ts.map +1 -0
- package/dist/shared/errors/__tests__/base.error.test.js +61 -0
- package/dist/shared/errors/__tests__/base.error.test.js.map +1 -0
- package/dist/shared/errors/__tests__/command.error.test.d.ts +5 -0
- package/dist/shared/errors/__tests__/command.error.test.d.ts.map +1 -0
- package/dist/shared/errors/__tests__/command.error.test.js +62 -0
- package/dist/shared/errors/__tests__/command.error.test.js.map +1 -0
- package/dist/shared/errors/__tests__/file.error.test.d.ts +5 -0
- package/dist/shared/errors/__tests__/file.error.test.d.ts.map +1 -0
- package/dist/shared/errors/__tests__/file.error.test.js +75 -0
- package/dist/shared/errors/__tests__/file.error.test.js.map +1 -0
- package/dist/shared/errors/__tests__/index.test.d.ts +5 -0
- package/dist/shared/errors/__tests__/index.test.d.ts.map +1 -0
- package/dist/shared/errors/__tests__/index.test.js +62 -0
- package/dist/shared/errors/__tests__/index.test.js.map +1 -0
- package/dist/shared/errors/__tests__/validation.error.test.d.ts +5 -0
- package/dist/shared/errors/__tests__/validation.error.test.d.ts.map +1 -0
- package/dist/shared/errors/__tests__/validation.error.test.js +79 -0
- package/dist/shared/errors/__tests__/validation.error.test.js.map +1 -0
- package/dist/shared/errors/base.error.d.ts +54 -0
- package/dist/shared/errors/base.error.d.ts.map +1 -0
- package/dist/shared/errors/base.error.js +85 -0
- package/dist/shared/errors/base.error.js.map +1 -0
- package/dist/shared/errors/command.error.d.ts +58 -0
- package/dist/shared/errors/command.error.d.ts.map +1 -0
- package/dist/shared/errors/command.error.js +102 -0
- package/dist/shared/errors/command.error.js.map +1 -0
- package/dist/shared/errors/detection.error.d.ts +42 -0
- package/dist/shared/errors/detection.error.d.ts.map +1 -0
- package/dist/shared/errors/detection.error.js +82 -0
- package/dist/shared/errors/detection.error.js.map +1 -0
- package/dist/shared/errors/docker.error.d.ts +142 -0
- package/dist/shared/errors/docker.error.d.ts.map +1 -0
- package/dist/shared/errors/docker.error.js +172 -0
- package/dist/shared/errors/docker.error.js.map +1 -0
- package/dist/shared/errors/file.error.d.ts +66 -0
- package/dist/shared/errors/file.error.d.ts.map +1 -0
- package/dist/shared/errors/file.error.js +93 -0
- package/dist/shared/errors/file.error.js.map +1 -0
- package/dist/shared/errors/index.d.ts +56 -0
- package/dist/shared/errors/index.d.ts.map +1 -0
- package/dist/shared/errors/index.js +86 -0
- package/dist/shared/errors/index.js.map +1 -0
- package/dist/shared/errors/validation.error.d.ts +67 -0
- package/dist/shared/errors/validation.error.d.ts.map +1 -0
- package/dist/shared/errors/validation.error.js +97 -0
- package/dist/shared/errors/validation.error.js.map +1 -0
- package/dist/shared/templates/index.d.ts +2 -0
- package/dist/shared/templates/index.d.ts.map +1 -0
- package/dist/shared/templates/index.js +2 -0
- package/dist/shared/templates/index.js.map +1 -0
- package/dist/shared/templates/prompt-builder.d.ts +2 -0
- package/dist/shared/templates/prompt-builder.d.ts.map +1 -0
- package/dist/shared/templates/prompt-builder.js +2 -0
- package/dist/shared/templates/prompt-builder.js.map +1 -0
- package/dist/shared/templates/template-engine.d.ts +2 -0
- package/dist/shared/templates/template-engine.d.ts.map +1 -0
- package/dist/shared/templates/template-engine.js +2 -0
- package/dist/shared/templates/template-engine.js.map +1 -0
- package/dist/shared/utils/__tests__/command-executor.test.d.ts +5 -0
- package/dist/shared/utils/__tests__/command-executor.test.d.ts.map +1 -0
- package/dist/shared/utils/__tests__/command-executor.test.js +45 -0
- package/dist/shared/utils/__tests__/command-executor.test.js.map +1 -0
- package/dist/shared/utils/__tests__/file-helper.test.d.ts +5 -0
- package/dist/shared/utils/__tests__/file-helper.test.d.ts.map +1 -0
- package/dist/shared/utils/__tests__/file-helper.test.js +71 -0
- package/dist/shared/utils/__tests__/file-helper.test.js.map +1 -0
- package/dist/shared/utils/__tests__/logger.test.d.ts +5 -0
- package/dist/shared/utils/__tests__/logger.test.d.ts.map +1 -0
- package/dist/shared/utils/__tests__/logger.test.js +83 -0
- package/dist/shared/utils/__tests__/logger.test.js.map +1 -0
- package/dist/shared/utils/command-executer.d.ts +2 -0
- package/dist/shared/utils/command-executer.d.ts.map +1 -0
- package/dist/shared/utils/command-executer.js +2 -0
- package/dist/shared/utils/command-executer.js.map +1 -0
- package/dist/shared/utils/command-executor.d.ts +255 -0
- package/dist/shared/utils/command-executor.d.ts.map +1 -0
- package/dist/shared/utils/command-executor.js +287 -0
- package/dist/shared/utils/command-executor.js.map +1 -0
- package/dist/shared/utils/file-helper.d.ts +86 -0
- package/dist/shared/utils/file-helper.d.ts.map +1 -0
- package/dist/shared/utils/file-helper.js +323 -0
- package/dist/shared/utils/file-helper.js.map +1 -0
- package/dist/shared/utils/index.d.ts +9 -0
- package/dist/shared/utils/index.d.ts.map +1 -0
- package/dist/shared/utils/index.js +9 -0
- package/dist/shared/utils/index.js.map +1 -0
- package/dist/shared/utils/logger.d.ts +163 -0
- package/dist/shared/utils/logger.d.ts.map +1 -0
- package/dist/shared/utils/logger.js +389 -0
- package/dist/shared/utils/logger.js.map +1 -0
- package/package.json +25 -6
- package/CHANGELOG.md +0 -46
- package/agents/deps-analyzer.js +0 -366
- package/agents/detector.js +0 -570
- package/agents/fix-engine.js +0 -305
- package/agents/lighthouse-scanner.js +0 -405
- package/agents/perf-analyzer.js +0 -294
- package/agents/perf-front-analyzer.js +0 -229
- package/agents/test-generator.js +0 -387
- package/agents/test-runner.js +0 -318
- package/bin/cli.js +0 -449
- package/lib/config.js +0 -250
- package/lib/docker.js +0 -207
- package/lib/reporter.js +0 -297
- package/scripts/dev.js +0 -106
package/agents/perf-analyzer.js
DELETED
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Daemon - Performance Analyzer Agent
|
|
3
|
-
*
|
|
4
|
-
* Analyzes application performance including:
|
|
5
|
-
* - API response times
|
|
6
|
-
* - Database query efficiency
|
|
7
|
-
* - Bundle size
|
|
8
|
-
* - Web Vitals
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const { execSync } = require('child_process');
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
|
|
15
|
-
const CONFIG = {
|
|
16
|
-
container: 'daemon-tools',
|
|
17
|
-
docker: 'docker exec',
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Run k6 performance test
|
|
22
|
-
*/
|
|
23
|
-
function runK6Test(testFile, options = {}) {
|
|
24
|
-
const stages = options.stages || [
|
|
25
|
-
{ duration: '30s', target: 20 },
|
|
26
|
-
{ duration: '1m', target: 20 },
|
|
27
|
-
{ duration: '30s', target: 0 },
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
const thresholds = options.thresholds || [
|
|
31
|
-
'http_req_duration[p(95)]<200',
|
|
32
|
-
'http_req_failed<0.01',
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
// Create temp k6 script
|
|
36
|
-
const script = generateK6Script(options.target || 'http://host.docker.internal:3000', stages, thresholds);
|
|
37
|
-
|
|
38
|
-
return runDockerCommand(`k6 run -`, { input: script });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Generate k6 test script
|
|
43
|
-
*/
|
|
44
|
-
function generateK6Script(target, stages, thresholds) {
|
|
45
|
-
return `
|
|
46
|
-
import http from 'k6/http';
|
|
47
|
-
import { check, sleep } from 'k6';
|
|
48
|
-
|
|
49
|
-
export const options = {
|
|
50
|
-
stages: ${JSON.stringify(stages)},
|
|
51
|
-
thresholds: {
|
|
52
|
-
${thresholds.map(t => `'${t}': true`).join(',\n ')}
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const BASE_URL = '${target}';
|
|
57
|
-
|
|
58
|
-
export default function () {
|
|
59
|
-
let res = http.get(\`\${BASE_URL}/\`);
|
|
60
|
-
check(res, {
|
|
61
|
-
'homepage OK': r => r.status === 200,
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
sleep(1);
|
|
65
|
-
|
|
66
|
-
res = http.get(\`\${BASE_URL}/api/users\`);
|
|
67
|
-
check(res, {
|
|
68
|
-
'users API OK': r => r.status === 200,
|
|
69
|
-
'response time < 200ms': r => r.timings.duration < 200,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
sleep(1);
|
|
73
|
-
}
|
|
74
|
-
`;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Analyze bundle size
|
|
79
|
-
*/
|
|
80
|
-
function analyzeBundleSize(projectDir) {
|
|
81
|
-
const buildDir = path.join(projectDir, '.next', 'static', 'chunks');
|
|
82
|
-
const distDir = path.join(projectDir, 'dist', 'assets');
|
|
83
|
-
|
|
84
|
-
let chunksDir;
|
|
85
|
-
if (fs.existsSync(buildDir)) chunksDir = buildDir;
|
|
86
|
-
else if (fs.existsSync(distDir)) chunksDir = distDir;
|
|
87
|
-
else return null;
|
|
88
|
-
|
|
89
|
-
const chunks = [];
|
|
90
|
-
let totalSize = 0;
|
|
91
|
-
|
|
92
|
-
function analyzeDir(dir) {
|
|
93
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
94
|
-
|
|
95
|
-
for (const entry of entries) {
|
|
96
|
-
const fullPath = path.join(dir, entry.name);
|
|
97
|
-
|
|
98
|
-
if (entry.isDirectory()) {
|
|
99
|
-
analyzeDir(fullPath);
|
|
100
|
-
} else if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.css'))) {
|
|
101
|
-
const stats = fs.statSync(fullPath);
|
|
102
|
-
const size = stats.size;
|
|
103
|
-
totalSize += size;
|
|
104
|
-
|
|
105
|
-
chunks.push({
|
|
106
|
-
name: entry.name,
|
|
107
|
-
size: size,
|
|
108
|
-
sizeKB: (size / 1024).toFixed(2),
|
|
109
|
-
path: path.relative(projectDir, fullPath),
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
analyzeDir(chunksDir);
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
totalSize,
|
|
119
|
-
totalSizeKB: (totalSize / 1024).toFixed(2),
|
|
120
|
-
totalSizeMB: (totalSize / 1024 / 1024).toFixed(2),
|
|
121
|
-
chunks: chunks.sort((a, b) => b.size - a.size).slice(0, 20), // Top 20
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Analyze database queries (Prisma)
|
|
127
|
-
*/
|
|
128
|
-
function analyzeDbQueries(projectDir) {
|
|
129
|
-
const prismaDir = path.join(projectDir, 'prisma');
|
|
130
|
-
if (!fs.existsSync(prismaDir)) {
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const schemaPath = path.join(prismaDir, 'schema.prisma');
|
|
135
|
-
if (!fs.existsSync(schemaPath)) {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const schema = fs.readFileSync(schemaPath, 'utf-8');
|
|
140
|
-
|
|
141
|
-
const models = [];
|
|
142
|
-
const modelMatches = schema.matchAll(/model\s+(\w+)\s*{([^}]+)}/g);
|
|
143
|
-
|
|
144
|
-
for (const match of modelMatches) {
|
|
145
|
-
const modelName = match[1];
|
|
146
|
-
const body = match[2];
|
|
147
|
-
|
|
148
|
-
const fields = [];
|
|
149
|
-
const fieldMatches = body.matchAll(/(\w+)\s+(\w+)(?:\s+@([^{\s]+[^}]*))?/g);
|
|
150
|
-
|
|
151
|
-
for (const fieldMatch of fieldMatches) {
|
|
152
|
-
const fieldName = fieldMatch[1];
|
|
153
|
-
const fieldType = fieldMatch[2];
|
|
154
|
-
const attributes = fieldMatch[3] || '';
|
|
155
|
-
|
|
156
|
-
fields.push({
|
|
157
|
-
name: fieldName,
|
|
158
|
-
type: fieldType,
|
|
159
|
-
attributes: attributes,
|
|
160
|
-
isIndexed: attributes.includes('index') || attributes.includes('unique') || attributes.includes('id'),
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
models.push({
|
|
165
|
-
name: modelName,
|
|
166
|
-
fields: fields,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
models,
|
|
172
|
-
recommendations: generateDbRecommendations(models),
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Generate database recommendations
|
|
178
|
-
*/
|
|
179
|
-
function generateDbRecommendations(models) {
|
|
180
|
-
const recommendations = [];
|
|
181
|
-
|
|
182
|
-
for (const model of models) {
|
|
183
|
-
// Check for common filter fields without indexes
|
|
184
|
-
const filterFields = ['email', 'username', 'slug', 'status', 'published', 'createdAt'];
|
|
185
|
-
|
|
186
|
-
for (const field of model.fields) {
|
|
187
|
-
if (filterFields.includes(field.name) && !field.isIndexed) {
|
|
188
|
-
recommendations.push({
|
|
189
|
-
type: 'index',
|
|
190
|
-
model: model.name,
|
|
191
|
-
field: field.name,
|
|
192
|
-
message: `Consider adding index on ${model.name}.${field.name}`,
|
|
193
|
-
priority: field.name === 'email' ? 'high' : 'medium',
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return recommendations;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Analyze Web Vitals (Lighthouse)
|
|
204
|
-
*/
|
|
205
|
-
function analyzeWebVitals(target) {
|
|
206
|
-
// This would run Playwright with metrics
|
|
207
|
-
return runDockerCommand(`npx playwright test --reporter=json`, {
|
|
208
|
-
cwd: path.join(process.cwd(), 'tests', 'e2e'),
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Run command in Docker container
|
|
214
|
-
*/
|
|
215
|
-
function runDockerCommand(command, options = {}) {
|
|
216
|
-
const dockerCmd = `${CONFIG.docker} ${CONFIG.container} ${command}`;
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
return {
|
|
220
|
-
success: true,
|
|
221
|
-
output: execSync(dockerCmd, {
|
|
222
|
-
encoding: 'utf-8',
|
|
223
|
-
stdio: options.silent ? 'pipe' : 'inherit',
|
|
224
|
-
input: options.input,
|
|
225
|
-
}),
|
|
226
|
-
};
|
|
227
|
-
} catch (error) {
|
|
228
|
-
return {
|
|
229
|
-
success: false,
|
|
230
|
-
error: error.message,
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Generate performance report
|
|
237
|
-
*/
|
|
238
|
-
function generateReport(analysis) {
|
|
239
|
-
const report = {
|
|
240
|
-
summary: {},
|
|
241
|
-
recommendations: [],
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
// Bundle analysis
|
|
245
|
-
if (analysis.bundle) {
|
|
246
|
-
report.summary.bundle = {
|
|
247
|
-
totalSize: analysis.bundle.totalSizeMB + ' MB',
|
|
248
|
-
largestChunks: analysis.bundle.chunks.slice(0, 5),
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
// Check for large bundles
|
|
252
|
-
analysis.bundle.chunks.forEach((chunk) => {
|
|
253
|
-
if (chunk.size > 200 * 1024) { // > 200KB
|
|
254
|
-
report.recommendations.push({
|
|
255
|
-
type: 'bundle',
|
|
256
|
-
message: `Large chunk: ${chunk.name} (${chunk.sizeKB} KB)`,
|
|
257
|
-
priority: 'medium',
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// DB analysis
|
|
264
|
-
if (analysis.db) {
|
|
265
|
-
report.summary.database = {
|
|
266
|
-
models: analysis.db.models.length,
|
|
267
|
-
recommendations: analysis.db.recommendations,
|
|
268
|
-
};
|
|
269
|
-
report.recommendations.push(...analysis.db.recommendations);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return report;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Full performance analysis
|
|
277
|
-
*/
|
|
278
|
-
function analyze(projectDir) {
|
|
279
|
-
const analysis = {
|
|
280
|
-
bundle: analyzeBundleSize(projectDir),
|
|
281
|
-
db: analyzeDbQueries(projectDir),
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
return generateReport(analysis);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
module.exports = {
|
|
288
|
-
runK6Test,
|
|
289
|
-
analyzeBundleSize,
|
|
290
|
-
analyzeDbQueries,
|
|
291
|
-
analyzeWebVitals,
|
|
292
|
-
generateReport,
|
|
293
|
-
analyze,
|
|
294
|
-
};
|
|
@@ -1,229 +0,0 @@
|
|
|
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
|
-
};
|