fivocell 5.0.0 → 5.2.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/__tests__/ci-reporter.test.d.ts +2 -0
- package/dist/__tests__/ci-reporter.test.d.ts.map +1 -0
- package/dist/__tests__/ci-reporter.test.js +109 -0
- package/dist/__tests__/ci-reporter.test.js.map +1 -0
- package/dist/__tests__/code-health.test.d.ts +2 -0
- package/dist/__tests__/code-health.test.d.ts.map +1 -0
- package/dist/__tests__/code-health.test.js +90 -0
- package/dist/__tests__/code-health.test.js.map +1 -0
- package/dist/__tests__/developer-velocity.test.d.ts +2 -0
- package/dist/__tests__/developer-velocity.test.d.ts.map +1 -0
- package/dist/__tests__/developer-velocity.test.js +66 -0
- package/dist/__tests__/developer-velocity.test.js.map +1 -0
- package/dist/__tests__/error-trends.test.d.ts +2 -0
- package/dist/__tests__/error-trends.test.d.ts.map +1 -0
- package/dist/__tests__/error-trends.test.js +61 -0
- package/dist/__tests__/error-trends.test.js.map +1 -0
- package/dist/__tests__/memory-growth.test.d.ts +2 -0
- package/dist/__tests__/memory-growth.test.d.ts.map +1 -0
- package/dist/__tests__/memory-growth.test.js +61 -0
- package/dist/__tests__/memory-growth.test.js.map +1 -0
- package/dist/walls/06-memory/stores/ci-reporter.d.ts +68 -0
- package/dist/walls/06-memory/stores/ci-reporter.d.ts.map +1 -0
- package/dist/walls/06-memory/stores/ci-reporter.js +272 -0
- package/dist/walls/06-memory/stores/ci-reporter.js.map +1 -0
- package/dist/walls/06-memory/stores/code-health.d.ts +40 -0
- package/dist/walls/06-memory/stores/code-health.d.ts.map +1 -0
- package/dist/walls/06-memory/stores/code-health.js +344 -0
- package/dist/walls/06-memory/stores/code-health.js.map +1 -0
- package/dist/walls/06-memory/stores/developer-velocity.d.ts +53 -0
- package/dist/walls/06-memory/stores/developer-velocity.d.ts.map +1 -0
- package/dist/walls/06-memory/stores/developer-velocity.js +225 -0
- package/dist/walls/06-memory/stores/developer-velocity.js.map +1 -0
- package/dist/walls/06-memory/stores/error-trends.d.ts +53 -0
- package/dist/walls/06-memory/stores/error-trends.d.ts.map +1 -0
- package/dist/walls/06-memory/stores/error-trends.js +232 -0
- package/dist/walls/06-memory/stores/error-trends.js.map +1 -0
- package/dist/walls/06-memory/stores/memory-growth.d.ts +34 -0
- package/dist/walls/06-memory/stores/memory-growth.d.ts.map +1 -0
- package/dist/walls/06-memory/stores/memory-growth.js +150 -0
- package/dist/walls/06-memory/stores/memory-growth.js.map +1 -0
- package/dist/walls/07-runtime/cli/cli.js +247 -0
- package/dist/walls/07-runtime/cli/cli.js.map +1 -1
- package/dist/walls/07-runtime/daemon/server.d.ts.map +1 -1
- package/dist/walls/07-runtime/daemon/server.js +96 -0
- package/dist/walls/07-runtime/daemon/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reportCIBuild = reportCIBuild;
|
|
4
|
+
exports.reportCITest = reportCITest;
|
|
5
|
+
exports.reportCIDeploy = reportCIDeploy;
|
|
6
|
+
exports.getCISummary = getCISummary;
|
|
7
|
+
exports.detectCIFailurePatterns = detectCIFailurePatterns;
|
|
8
|
+
exports.getBuildTrend = getBuildTrend;
|
|
9
|
+
exports.formatCISummary = formatCISummary;
|
|
10
|
+
const database_1 = require("../database/database");
|
|
11
|
+
const memory_event_store_1 = require("../stores/memory-event-store");
|
|
12
|
+
function reportCIBuild(result) {
|
|
13
|
+
const topic = result.status === 'failure' ? 'ci-build-failed' : 'ci-build';
|
|
14
|
+
const type = result.status === 'failure' ? 'error' : 'verification';
|
|
15
|
+
const importance = result.status === 'failure' ? 7 : 5;
|
|
16
|
+
const summary = `Build ${result.status}: ${result.stage} [${result.ciPlatform}] ${result.commitHash.slice(0, 8)}`;
|
|
17
|
+
const event = {
|
|
18
|
+
project: result.project,
|
|
19
|
+
branch: result.branch,
|
|
20
|
+
type,
|
|
21
|
+
topic,
|
|
22
|
+
summary,
|
|
23
|
+
details: {
|
|
24
|
+
buildId: result.buildId,
|
|
25
|
+
status: result.status,
|
|
26
|
+
duration: result.duration,
|
|
27
|
+
stage: result.stage,
|
|
28
|
+
commitHash: result.commitHash,
|
|
29
|
+
commitMessage: result.commitMessage,
|
|
30
|
+
author: result.author,
|
|
31
|
+
ciPlatform: result.ciPlatform,
|
|
32
|
+
logSnippet: result.logSnippet,
|
|
33
|
+
source: 'ci-reporter',
|
|
34
|
+
},
|
|
35
|
+
files: [],
|
|
36
|
+
importance,
|
|
37
|
+
tool: 'cell-ci',
|
|
38
|
+
};
|
|
39
|
+
return (0, memory_event_store_1.recordMemoryEvent)(event);
|
|
40
|
+
}
|
|
41
|
+
function reportCITest(result) {
|
|
42
|
+
const allPassed = result.failed === 0;
|
|
43
|
+
const type = allPassed ? 'verification' : 'error';
|
|
44
|
+
const topic = allPassed ? 'ci-test-passed' : 'ci-test-failed';
|
|
45
|
+
const importance = result.failed > 0 ? 7 : 4;
|
|
46
|
+
const summary = `Tests: ${result.passed}/${result.totalTests} passed` +
|
|
47
|
+
(result.failed > 0 ? `, ${result.failed} failed` : '') +
|
|
48
|
+
(result.skipped > 0 ? `, ${result.skipped} skipped` : '') +
|
|
49
|
+
(result.coverage !== undefined ? ` (${result.coverage}% coverage)` : '');
|
|
50
|
+
const event = {
|
|
51
|
+
project: result.project,
|
|
52
|
+
branch: result.branch,
|
|
53
|
+
type,
|
|
54
|
+
topic,
|
|
55
|
+
summary,
|
|
56
|
+
details: {
|
|
57
|
+
buildId: result.buildId,
|
|
58
|
+
totalTests: result.totalTests,
|
|
59
|
+
passed: result.passed,
|
|
60
|
+
failed: result.failed,
|
|
61
|
+
skipped: result.skipped,
|
|
62
|
+
duration: result.duration,
|
|
63
|
+
failedTests: result.failedTests,
|
|
64
|
+
coverage: result.coverage,
|
|
65
|
+
source: 'ci-reporter',
|
|
66
|
+
},
|
|
67
|
+
files: [],
|
|
68
|
+
importance,
|
|
69
|
+
tool: 'cell-ci',
|
|
70
|
+
};
|
|
71
|
+
return (0, memory_event_store_1.recordMemoryEvent)(event);
|
|
72
|
+
}
|
|
73
|
+
function reportCIDeploy(result) {
|
|
74
|
+
const type = result.status === 'success' ? 'publish' : 'error';
|
|
75
|
+
const topic = result.status === 'success' ? 'ci-deploy' : 'ci-deploy-failed';
|
|
76
|
+
const importance = result.status === 'failed' ? 8 : 6;
|
|
77
|
+
const summary = `Deploy ${result.status}: ${result.version} → ${result.environment}` +
|
|
78
|
+
(result.status === 'rolled_back' ? ' (rolled back)' : '');
|
|
79
|
+
const event = {
|
|
80
|
+
project: result.project,
|
|
81
|
+
branch: '',
|
|
82
|
+
type,
|
|
83
|
+
topic,
|
|
84
|
+
summary,
|
|
85
|
+
details: {
|
|
86
|
+
environment: result.environment,
|
|
87
|
+
status: result.status,
|
|
88
|
+
version: result.version,
|
|
89
|
+
duration: result.duration,
|
|
90
|
+
source: 'ci-reporter',
|
|
91
|
+
},
|
|
92
|
+
files: [],
|
|
93
|
+
importance,
|
|
94
|
+
tool: 'cell-ci',
|
|
95
|
+
};
|
|
96
|
+
return (0, memory_event_store_1.recordMemoryEvent)(event);
|
|
97
|
+
}
|
|
98
|
+
function getCISummary(project, days = 30) {
|
|
99
|
+
const db = (0, database_1.getDb)();
|
|
100
|
+
const since = new Date(Date.now() - days * 86400000).toISOString();
|
|
101
|
+
const builds = db.prepare(`
|
|
102
|
+
SELECT details_json, type FROM memory_events
|
|
103
|
+
WHERE project = ? AND topic LIKE 'ci-build%' AND created_at >= ?
|
|
104
|
+
`).all(project, since);
|
|
105
|
+
const tests = db.prepare(`
|
|
106
|
+
SELECT details_json, type FROM memory_events
|
|
107
|
+
WHERE project = ? AND topic LIKE 'ci-test%' AND created_at >= ?
|
|
108
|
+
`).all(project, since);
|
|
109
|
+
const deploys = db.prepare(`
|
|
110
|
+
SELECT details_json, type FROM memory_events
|
|
111
|
+
WHERE project = ? AND topic LIKE 'ci-deploy%' AND created_at >= ?
|
|
112
|
+
`).all(project, since);
|
|
113
|
+
// Build stats
|
|
114
|
+
let totalBuilds = builds.length;
|
|
115
|
+
let successfulBuilds = 0;
|
|
116
|
+
let totalDuration = 0;
|
|
117
|
+
for (const b of builds) {
|
|
118
|
+
try {
|
|
119
|
+
const d = JSON.parse(b.details_json);
|
|
120
|
+
if (d.status === 'success')
|
|
121
|
+
successfulBuilds++;
|
|
122
|
+
totalDuration += d.duration || 0;
|
|
123
|
+
}
|
|
124
|
+
catch { }
|
|
125
|
+
}
|
|
126
|
+
// Test stats
|
|
127
|
+
let totalTests = 0;
|
|
128
|
+
let totalPassed = 0;
|
|
129
|
+
for (const t of tests) {
|
|
130
|
+
try {
|
|
131
|
+
const d = JSON.parse(t.details_json);
|
|
132
|
+
totalTests += d.totalTests || 0;
|
|
133
|
+
totalPassed += d.passed || 0;
|
|
134
|
+
}
|
|
135
|
+
catch { }
|
|
136
|
+
}
|
|
137
|
+
// Deploy stats
|
|
138
|
+
let totalDeploys = deploys.length;
|
|
139
|
+
let successfulDeploys = 0;
|
|
140
|
+
for (const d of deploys) {
|
|
141
|
+
try {
|
|
142
|
+
const details = JSON.parse(d.details_json);
|
|
143
|
+
if (details.status === 'success')
|
|
144
|
+
successfulDeploys++;
|
|
145
|
+
}
|
|
146
|
+
catch { }
|
|
147
|
+
}
|
|
148
|
+
const successRate = totalBuilds > 0 ? Math.round(successfulBuilds / totalBuilds * 100) : 0;
|
|
149
|
+
const testPassRate = totalTests > 0 ? Math.round(totalPassed / totalTests * 100) : 0;
|
|
150
|
+
const deploySuccessRate = totalDeploys > 0 ? Math.round(successfulDeploys / totalDeploys * 100) : 0;
|
|
151
|
+
const avgBuildDuration = totalBuilds > 0 ? Math.round(totalDuration / totalBuilds) : 0;
|
|
152
|
+
const failurePatterns = detectCIFailurePatterns(project, days);
|
|
153
|
+
return {
|
|
154
|
+
totalBuilds,
|
|
155
|
+
successRate,
|
|
156
|
+
avgBuildDuration,
|
|
157
|
+
totalTests,
|
|
158
|
+
testPassRate,
|
|
159
|
+
deployments: totalDeploys,
|
|
160
|
+
deploySuccessRate,
|
|
161
|
+
failurePatterns,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function detectCIFailurePatterns(project, days = 30) {
|
|
165
|
+
const db = (0, database_1.getDb)();
|
|
166
|
+
const since = new Date(Date.now() - days * 86400000).toISOString();
|
|
167
|
+
const failures = db.prepare(`
|
|
168
|
+
SELECT summary, branch, created_at FROM memory_events
|
|
169
|
+
WHERE project = ? AND type = 'error' AND (topic LIKE 'ci-%')
|
|
170
|
+
AND created_at >= ? ORDER BY created_at
|
|
171
|
+
`).all(project, since);
|
|
172
|
+
if (failures.length === 0)
|
|
173
|
+
return [];
|
|
174
|
+
// Group by summary pattern
|
|
175
|
+
const patternMap = new Map();
|
|
176
|
+
for (const f of failures) {
|
|
177
|
+
// Normalize: remove commit hashes, IDs, timestamps
|
|
178
|
+
const pattern = f.summary
|
|
179
|
+
.replace(/\[[a-f0-9]{8}\]/g, '[hash]')
|
|
180
|
+
.replace(/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}/g, '[time]')
|
|
181
|
+
.replace(/run[_-]?\d+/gi, '[run]')
|
|
182
|
+
.slice(0, 100);
|
|
183
|
+
const existing = patternMap.get(pattern) || {
|
|
184
|
+
count: 0,
|
|
185
|
+
firstSeen: f.created_at,
|
|
186
|
+
lastSeen: f.created_at,
|
|
187
|
+
branches: new Set(),
|
|
188
|
+
};
|
|
189
|
+
existing.count++;
|
|
190
|
+
if (f.created_at < existing.firstSeen)
|
|
191
|
+
existing.firstSeen = f.created_at;
|
|
192
|
+
if (f.created_at > existing.lastSeen)
|
|
193
|
+
existing.lastSeen = f.created_at;
|
|
194
|
+
existing.branches.add(f.branch);
|
|
195
|
+
patternMap.set(pattern, existing);
|
|
196
|
+
}
|
|
197
|
+
const patterns = [];
|
|
198
|
+
for (const [pattern, data] of patternMap) {
|
|
199
|
+
if (data.count < 2)
|
|
200
|
+
continue; // Only report patterns with 2+ occurrences
|
|
201
|
+
patterns.push({
|
|
202
|
+
pattern,
|
|
203
|
+
count: data.count,
|
|
204
|
+
firstSeen: data.firstSeen,
|
|
205
|
+
lastSeen: data.lastSeen,
|
|
206
|
+
affectedBranches: [...data.branches],
|
|
207
|
+
severity: data.count >= 5 ? 'critical' : data.count >= 2 ? 'warning' : 'info',
|
|
208
|
+
suggestion: data.count >= 5
|
|
209
|
+
? 'Frequent failure — investigate root cause immediately'
|
|
210
|
+
: 'Recurring failure — consider adding retries or fixing root cause',
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return patterns.sort((a, b) => b.count - a.count).slice(0, 10);
|
|
214
|
+
}
|
|
215
|
+
function getBuildTrend(project, days = 14) {
|
|
216
|
+
const db = (0, database_1.getDb)();
|
|
217
|
+
const since = new Date(Date.now() - days * 86400000).toISOString();
|
|
218
|
+
const rows = db.prepare(`
|
|
219
|
+
SELECT date(created_at) as date, details_json FROM memory_events
|
|
220
|
+
WHERE project = ? AND topic LIKE 'ci-build%' AND created_at >= ?
|
|
221
|
+
ORDER BY date
|
|
222
|
+
`).all(project, since);
|
|
223
|
+
const dayMap = new Map();
|
|
224
|
+
for (const r of rows) {
|
|
225
|
+
const existing = dayMap.get(r.date) || { total: 0, successes: 0 };
|
|
226
|
+
existing.total++;
|
|
227
|
+
try {
|
|
228
|
+
const d = JSON.parse(r.details_json);
|
|
229
|
+
if (d.status === 'success')
|
|
230
|
+
existing.successes++;
|
|
231
|
+
}
|
|
232
|
+
catch { }
|
|
233
|
+
dayMap.set(r.date, existing);
|
|
234
|
+
}
|
|
235
|
+
return [...dayMap.entries()].map(([date, data]) => ({
|
|
236
|
+
date,
|
|
237
|
+
builds: data.total,
|
|
238
|
+
successes: data.successes,
|
|
239
|
+
failures: data.total - data.successes,
|
|
240
|
+
successRate: data.total > 0 ? Math.round(data.successes / data.total * 100) : 0,
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
function formatCISummary(summary) {
|
|
244
|
+
const lines = [];
|
|
245
|
+
lines.push('## CI/CD Summary\n');
|
|
246
|
+
lines.push('| Metric | Value |');
|
|
247
|
+
lines.push('|--------|-------|');
|
|
248
|
+
lines.push(`| Total builds | ${summary.totalBuilds} |`);
|
|
249
|
+
lines.push(`| Build success rate | ${summary.successRate}% |`);
|
|
250
|
+
lines.push(`| Avg build duration | ${formatDuration(summary.avgBuildDuration)} |`);
|
|
251
|
+
lines.push(`| Total tests | ${summary.totalTests} |`);
|
|
252
|
+
lines.push(`| Test pass rate | ${summary.testPassRate}% |`);
|
|
253
|
+
lines.push(`| Deployments | ${summary.deployments} |`);
|
|
254
|
+
lines.push(`| Deploy success rate | ${summary.deploySuccessRate}% |`);
|
|
255
|
+
if (summary.failurePatterns.length > 0) {
|
|
256
|
+
lines.push('\n### Failure Patterns');
|
|
257
|
+
for (const p of summary.failurePatterns) {
|
|
258
|
+
lines.push(`- [${p.severity}] ${p.pattern} (×${p.count}, branches: ${p.affectedBranches.join(', ')})`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return lines.join('\n');
|
|
262
|
+
}
|
|
263
|
+
function formatDuration(ms) {
|
|
264
|
+
if (ms === 0)
|
|
265
|
+
return 'N/A';
|
|
266
|
+
if (ms < 60000)
|
|
267
|
+
return `${Math.round(ms / 1000)}s`;
|
|
268
|
+
if (ms < 3600000)
|
|
269
|
+
return `${Math.round(ms / 60000)}m`;
|
|
270
|
+
return `${(ms / 3600000).toFixed(1)}h`;
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=ci-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-reporter.js","sourceRoot":"","sources":["../../../../src/walls/06-memory/stores/ci-reporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface CodeHealthScore {
|
|
2
|
+
project: string;
|
|
3
|
+
overallScore: number;
|
|
4
|
+
grade: 'A+' | 'A' | 'B+' | 'B' | 'C+' | 'C' | 'D' | 'F';
|
|
5
|
+
dimensions: {
|
|
6
|
+
complexity: number;
|
|
7
|
+
duplication: number;
|
|
8
|
+
testCoverage: number;
|
|
9
|
+
documentation: number;
|
|
10
|
+
errorHandling: number;
|
|
11
|
+
modularity: number;
|
|
12
|
+
};
|
|
13
|
+
files: FileHealth[];
|
|
14
|
+
suggestions: string[];
|
|
15
|
+
metrics: CodeMetrics;
|
|
16
|
+
computedAt: string;
|
|
17
|
+
}
|
|
18
|
+
export interface CodeMetrics {
|
|
19
|
+
totalFiles: number;
|
|
20
|
+
totalLines: number;
|
|
21
|
+
avgFileSize: number;
|
|
22
|
+
largestFile: string;
|
|
23
|
+
largestFileSize: number;
|
|
24
|
+
testFiles: number;
|
|
25
|
+
testRatio: number;
|
|
26
|
+
docFiles: number;
|
|
27
|
+
configFiles: number;
|
|
28
|
+
avgComplexity: number;
|
|
29
|
+
highComplexityFiles: number;
|
|
30
|
+
}
|
|
31
|
+
export interface FileHealth {
|
|
32
|
+
path: string;
|
|
33
|
+
lines: number;
|
|
34
|
+
complexity: number;
|
|
35
|
+
health: 'good' | 'warning' | 'critical';
|
|
36
|
+
issues: string[];
|
|
37
|
+
}
|
|
38
|
+
export declare function computeCodeHealth(projectDir: string, project: string): CodeHealthScore;
|
|
39
|
+
export declare function formatCodeHealth(health: CodeHealthScore): string;
|
|
40
|
+
//# sourceMappingURL=code-health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-health.d.ts","sourceRoot":"","sources":["../../../../src/walls/06-memory/stores/code-health.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACxD,UAAU,EAAE;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,WAAW,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;IACxC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CA+EtF;AAwLD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CA+BhE"}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.computeCodeHealth = computeCodeHealth;
|
|
37
|
+
exports.formatCodeHealth = formatCodeHealth;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
function computeCodeHealth(projectDir, project) {
|
|
41
|
+
const suggestions = [];
|
|
42
|
+
// Scan files
|
|
43
|
+
const files = scanCodeFiles(projectDir);
|
|
44
|
+
const metrics = computeMetrics(files, projectDir);
|
|
45
|
+
// Complexity analysis (simplified: line count as proxy)
|
|
46
|
+
const complexity = computeComplexityScore(files);
|
|
47
|
+
// Duplication detection (simplified: similar file sizes)
|
|
48
|
+
const duplication = computeDuplicationScore(files);
|
|
49
|
+
// Test coverage (test file ratio)
|
|
50
|
+
const testCoverage = computeTestCoverage(files);
|
|
51
|
+
// Documentation (README, docs)
|
|
52
|
+
const documentation = computeDocumentationScore(projectDir);
|
|
53
|
+
// Error handling (try/catch usage)
|
|
54
|
+
const errorHandling = computeErrorHandlingScore(files);
|
|
55
|
+
// Modularity (avg file size, number of modules)
|
|
56
|
+
const modularity = computeModularityScore(files);
|
|
57
|
+
// Generate suggestions
|
|
58
|
+
if (metrics.testRatio < 0.2) {
|
|
59
|
+
suggestions.push('Add more test files — current test ratio is low');
|
|
60
|
+
}
|
|
61
|
+
if (metrics.highComplexityFiles > 3) {
|
|
62
|
+
suggestions.push('Refactor high-complexity files');
|
|
63
|
+
}
|
|
64
|
+
if (metrics.avgFileSize > 500) {
|
|
65
|
+
suggestions.push('Consider splitting large files');
|
|
66
|
+
}
|
|
67
|
+
if (documentation < 50) {
|
|
68
|
+
suggestions.push('Add README and documentation');
|
|
69
|
+
}
|
|
70
|
+
if (duplication < 60) {
|
|
71
|
+
suggestions.push('Reduce code duplication');
|
|
72
|
+
}
|
|
73
|
+
if (errorHandling < 50) {
|
|
74
|
+
suggestions.push('Improve error handling with try/catch');
|
|
75
|
+
}
|
|
76
|
+
// Overall score
|
|
77
|
+
const overallScore = Math.round(complexity * 0.2 +
|
|
78
|
+
duplication * 0.15 +
|
|
79
|
+
testCoverage * 0.25 +
|
|
80
|
+
documentation * 0.1 +
|
|
81
|
+
errorHandling * 0.15 +
|
|
82
|
+
modularity * 0.15);
|
|
83
|
+
const grade = scoreToGrade(overallScore);
|
|
84
|
+
// Top files by complexity
|
|
85
|
+
const topFiles = files
|
|
86
|
+
.sort((a, b) => b.lines - a.lines)
|
|
87
|
+
.slice(0, 20)
|
|
88
|
+
.map(f => ({
|
|
89
|
+
path: path.relative(projectDir, f.path),
|
|
90
|
+
lines: f.lines,
|
|
91
|
+
complexity: f.complexity,
|
|
92
|
+
health: f.lines > 500 ? 'critical' : f.lines > 200 ? 'warning' : 'good',
|
|
93
|
+
issues: f.lines > 500 ? ['File too large'] : [],
|
|
94
|
+
}));
|
|
95
|
+
return {
|
|
96
|
+
project,
|
|
97
|
+
overallScore,
|
|
98
|
+
grade,
|
|
99
|
+
dimensions: { complexity, duplication, testCoverage, documentation, errorHandling, modularity },
|
|
100
|
+
files: topFiles,
|
|
101
|
+
suggestions,
|
|
102
|
+
metrics,
|
|
103
|
+
computedAt: new Date().toISOString(),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function scanCodeFiles(dir) {
|
|
107
|
+
const files = [];
|
|
108
|
+
const extensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.rs', '.java']);
|
|
109
|
+
const ignoreDirs = new Set(['node_modules', '.git', 'dist', 'build', '.cell', '__tests__', '__mocks__']);
|
|
110
|
+
function walk(currentDir) {
|
|
111
|
+
try {
|
|
112
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
if (ignoreDirs.has(entry.name))
|
|
115
|
+
continue;
|
|
116
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
117
|
+
if (entry.isDirectory()) {
|
|
118
|
+
walk(fullPath);
|
|
119
|
+
}
|
|
120
|
+
else if (extensions.has(path.extname(entry.name).toLowerCase())) {
|
|
121
|
+
try {
|
|
122
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
123
|
+
const lines = content.split('\n').length;
|
|
124
|
+
const complexity = estimateComplexity(content);
|
|
125
|
+
const isTest = entry.name.includes('.test.') || entry.name.includes('.spec.') || fullPath.includes('__tests__');
|
|
126
|
+
const isDoc = entry.name.endsWith('.md') || entry.name.endsWith('.txt');
|
|
127
|
+
const isConfig = entry.name.endsWith('.json') || entry.name.endsWith('.yaml') || entry.name.endsWith('.yml');
|
|
128
|
+
files.push({ path: fullPath, lines, complexity, isTest, isDoc, isConfig });
|
|
129
|
+
}
|
|
130
|
+
catch { }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch { }
|
|
135
|
+
}
|
|
136
|
+
walk(dir);
|
|
137
|
+
return files;
|
|
138
|
+
}
|
|
139
|
+
function estimateComplexity(content) {
|
|
140
|
+
// Simple complexity heuristic: count control flow statements
|
|
141
|
+
let complexity = 1;
|
|
142
|
+
const lines = content.split('\n');
|
|
143
|
+
for (const line of lines) {
|
|
144
|
+
const trimmed = line.trim();
|
|
145
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*'))
|
|
146
|
+
continue;
|
|
147
|
+
if (/\b(if|else if|else)\b/.test(trimmed))
|
|
148
|
+
complexity++;
|
|
149
|
+
if (/\b(for|while|do)\b/.test(trimmed))
|
|
150
|
+
complexity++;
|
|
151
|
+
if (/\b(switch|case)\b/.test(trimmed))
|
|
152
|
+
complexity++;
|
|
153
|
+
if (/\b(try|catch|finally)\b/.test(trimmed))
|
|
154
|
+
complexity++;
|
|
155
|
+
if (/\b(function|class|=>)\b/.test(trimmed))
|
|
156
|
+
complexity++;
|
|
157
|
+
}
|
|
158
|
+
return complexity;
|
|
159
|
+
}
|
|
160
|
+
function computeMetrics(files, projectDir) {
|
|
161
|
+
const codeFiles = files.filter(f => !f.isDoc && !f.isConfig);
|
|
162
|
+
const testFiles = files.filter(f => f.isTest);
|
|
163
|
+
const docFiles = files.filter(f => f.isDoc);
|
|
164
|
+
const configFiles = files.filter(f => f.isConfig);
|
|
165
|
+
const totalLines = codeFiles.reduce((s, f) => s + f.lines, 0);
|
|
166
|
+
const avgFileSize = codeFiles.length > 0 ? Math.round(totalLines / codeFiles.length) : 0;
|
|
167
|
+
const largest = codeFiles.reduce((max, f) => f.lines > max.lines ? f : max, { path: '', lines: 0 });
|
|
168
|
+
const testRatio = codeFiles.length > 0 ? Math.round(testFiles.length / codeFiles.length * 100) : 0;
|
|
169
|
+
const highComplexityFiles = codeFiles.filter(f => f.complexity > 50).length;
|
|
170
|
+
const avgComplexity = codeFiles.length > 0
|
|
171
|
+
? Math.round(codeFiles.reduce((s, f) => s + f.complexity, 0) / codeFiles.length)
|
|
172
|
+
: 0;
|
|
173
|
+
return {
|
|
174
|
+
totalFiles: codeFiles.length,
|
|
175
|
+
totalLines,
|
|
176
|
+
avgFileSize,
|
|
177
|
+
largestFile: path.relative(projectDir, largest.path),
|
|
178
|
+
largestFileSize: largest.lines,
|
|
179
|
+
testFiles: testFiles.length,
|
|
180
|
+
testRatio,
|
|
181
|
+
docFiles: docFiles.length,
|
|
182
|
+
configFiles: configFiles.length,
|
|
183
|
+
avgComplexity,
|
|
184
|
+
highComplexityFiles,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function computeComplexityScore(files) {
|
|
188
|
+
const codeFiles = files.filter(f => !f.isDoc && !f.isConfig);
|
|
189
|
+
if (codeFiles.length === 0)
|
|
190
|
+
return 50;
|
|
191
|
+
const avgComplexity = codeFiles.reduce((s, f) => s + f.complexity, 0) / codeFiles.length;
|
|
192
|
+
// Lower complexity = higher score
|
|
193
|
+
if (avgComplexity < 10)
|
|
194
|
+
return 95;
|
|
195
|
+
if (avgComplexity < 20)
|
|
196
|
+
return 85;
|
|
197
|
+
if (avgComplexity < 30)
|
|
198
|
+
return 75;
|
|
199
|
+
if (avgComplexity < 50)
|
|
200
|
+
return 60;
|
|
201
|
+
if (avgComplexity < 80)
|
|
202
|
+
return 45;
|
|
203
|
+
return 30;
|
|
204
|
+
}
|
|
205
|
+
function computeDuplicationScore(files) {
|
|
206
|
+
// Simple: check if many files have same line count (proxy for copy-paste)
|
|
207
|
+
const codeFiles = files.filter(f => !f.isDoc && !f.isConfig && f.lines > 10);
|
|
208
|
+
if (codeFiles.length === 0)
|
|
209
|
+
return 80;
|
|
210
|
+
const lineCounts = codeFiles.map(f => f.lines);
|
|
211
|
+
const unique = new Set(lineCounts);
|
|
212
|
+
const ratio = unique.size / lineCounts.length;
|
|
213
|
+
return Math.round(ratio * 100);
|
|
214
|
+
}
|
|
215
|
+
function computeTestCoverage(files) {
|
|
216
|
+
const codeFiles = files.filter(f => !f.isDoc && !f.isConfig);
|
|
217
|
+
const testFiles = files.filter(f => f.isTest);
|
|
218
|
+
if (codeFiles.length === 0)
|
|
219
|
+
return 50;
|
|
220
|
+
const ratio = testFiles.length / codeFiles.length;
|
|
221
|
+
if (ratio > 0.5)
|
|
222
|
+
return 95;
|
|
223
|
+
if (ratio > 0.3)
|
|
224
|
+
return 85;
|
|
225
|
+
if (ratio > 0.2)
|
|
226
|
+
return 70;
|
|
227
|
+
if (ratio > 0.1)
|
|
228
|
+
return 55;
|
|
229
|
+
if (ratio > 0.05)
|
|
230
|
+
return 40;
|
|
231
|
+
return 25;
|
|
232
|
+
}
|
|
233
|
+
function computeDocumentationScore(projectDir) {
|
|
234
|
+
let score = 0;
|
|
235
|
+
const readme = path.join(projectDir, 'README.md');
|
|
236
|
+
if (fs.existsSync(readme))
|
|
237
|
+
score += 40;
|
|
238
|
+
const docsDir = path.join(projectDir, 'docs');
|
|
239
|
+
if (fs.existsSync(docsDir))
|
|
240
|
+
score += 30;
|
|
241
|
+
const changelog = path.join(projectDir, 'CHANGELOG.md');
|
|
242
|
+
if (fs.existsSync(changelog))
|
|
243
|
+
score += 15;
|
|
244
|
+
const license = path.join(projectDir, 'LICENSE');
|
|
245
|
+
if (fs.existsSync(license))
|
|
246
|
+
score += 15;
|
|
247
|
+
return Math.min(100, score);
|
|
248
|
+
}
|
|
249
|
+
function computeErrorHandlingScore(files) {
|
|
250
|
+
let totalFiles = 0;
|
|
251
|
+
let filesWithTry = 0;
|
|
252
|
+
for (const f of files) {
|
|
253
|
+
if (f.isTest || f.isDoc || f.isConfig)
|
|
254
|
+
continue;
|
|
255
|
+
totalFiles++;
|
|
256
|
+
try {
|
|
257
|
+
const content = fs.readFileSync(f.path, 'utf-8');
|
|
258
|
+
if (/\b(try|catch)\b/.test(content))
|
|
259
|
+
filesWithTry++;
|
|
260
|
+
}
|
|
261
|
+
catch { }
|
|
262
|
+
}
|
|
263
|
+
if (totalFiles === 0)
|
|
264
|
+
return 50;
|
|
265
|
+
const ratio = filesWithTry / totalFiles;
|
|
266
|
+
if (ratio > 0.5)
|
|
267
|
+
return 90;
|
|
268
|
+
if (ratio > 0.3)
|
|
269
|
+
return 75;
|
|
270
|
+
if (ratio > 0.15)
|
|
271
|
+
return 60;
|
|
272
|
+
if (ratio > 0.05)
|
|
273
|
+
return 45;
|
|
274
|
+
return 30;
|
|
275
|
+
}
|
|
276
|
+
function computeModularityScore(files) {
|
|
277
|
+
const codeFiles = files.filter(f => !f.isDoc && !f.isConfig);
|
|
278
|
+
if (codeFiles.length === 0)
|
|
279
|
+
return 50;
|
|
280
|
+
const avgSize = codeFiles.reduce((s, f) => s + f.lines, 0) / codeFiles.length;
|
|
281
|
+
// Smaller avg size = better modularity
|
|
282
|
+
if (avgSize < 100)
|
|
283
|
+
return 95;
|
|
284
|
+
if (avgSize < 200)
|
|
285
|
+
return 85;
|
|
286
|
+
if (avgSize < 300)
|
|
287
|
+
return 75;
|
|
288
|
+
if (avgSize < 500)
|
|
289
|
+
return 60;
|
|
290
|
+
if (avgSize < 800)
|
|
291
|
+
return 45;
|
|
292
|
+
return 30;
|
|
293
|
+
}
|
|
294
|
+
function scoreToGrade(score) {
|
|
295
|
+
if (score >= 95)
|
|
296
|
+
return 'A+';
|
|
297
|
+
if (score >= 90)
|
|
298
|
+
return 'A';
|
|
299
|
+
if (score >= 85)
|
|
300
|
+
return 'B+';
|
|
301
|
+
if (score >= 75)
|
|
302
|
+
return 'B';
|
|
303
|
+
if (score >= 70)
|
|
304
|
+
return 'C+';
|
|
305
|
+
if (score >= 60)
|
|
306
|
+
return 'C';
|
|
307
|
+
if (score >= 40)
|
|
308
|
+
return 'D';
|
|
309
|
+
return 'F';
|
|
310
|
+
}
|
|
311
|
+
function formatCodeHealth(health) {
|
|
312
|
+
const lines = [];
|
|
313
|
+
lines.push(`## Code Health — ${health.project}`);
|
|
314
|
+
lines.push(`**Score: ${health.overallScore}/100 (${health.grade})**\n`);
|
|
315
|
+
lines.push(`### Dimensions`);
|
|
316
|
+
lines.push(`| Dimension | Score |`);
|
|
317
|
+
lines.push(`|-----------|-------|`);
|
|
318
|
+
lines.push(`| Complexity | ${health.dimensions.complexity} |`);
|
|
319
|
+
lines.push(`| Duplication | ${health.dimensions.duplication} |`);
|
|
320
|
+
lines.push(`| Test Coverage | ${health.dimensions.testCoverage} |`);
|
|
321
|
+
lines.push(`| Documentation | ${health.dimensions.documentation} |`);
|
|
322
|
+
lines.push(`| Error Handling | ${health.dimensions.errorHandling} |`);
|
|
323
|
+
lines.push(`| Modularity | ${health.dimensions.modularity} |`);
|
|
324
|
+
lines.push('');
|
|
325
|
+
lines.push(`### Metrics`);
|
|
326
|
+
lines.push(`| Metric | Value |`);
|
|
327
|
+
lines.push(`|--------|-------|`);
|
|
328
|
+
lines.push(`| Total files | ${health.metrics.totalFiles} |`);
|
|
329
|
+
lines.push(`| Total lines | ${health.metrics.totalLines} |`);
|
|
330
|
+
lines.push(`| Avg file size | ${health.metrics.avgFileSize} lines |`);
|
|
331
|
+
lines.push(`| Largest file | ${health.metrics.largestFile} (${health.metrics.largestFileSize} lines) |`);
|
|
332
|
+
lines.push(`| Test files | ${health.metrics.testFiles} (${health.metrics.testRatio}% ratio) |`);
|
|
333
|
+
lines.push(`| Doc files | ${health.metrics.docFiles} |`);
|
|
334
|
+
lines.push(`| Avg complexity | ${health.metrics.avgComplexity} |`);
|
|
335
|
+
lines.push(`| High complexity | ${health.metrics.highComplexityFiles} files |`);
|
|
336
|
+
if (health.suggestions.length > 0) {
|
|
337
|
+
lines.push('');
|
|
338
|
+
lines.push(`### Suggestions`);
|
|
339
|
+
for (const s of health.suggestions)
|
|
340
|
+
lines.push(`- ${s}`);
|
|
341
|
+
}
|
|
342
|
+
return lines.join('\n');
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=code-health.js.map
|