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.
Files changed (46) hide show
  1. package/dist/__tests__/ci-reporter.test.d.ts +2 -0
  2. package/dist/__tests__/ci-reporter.test.d.ts.map +1 -0
  3. package/dist/__tests__/ci-reporter.test.js +109 -0
  4. package/dist/__tests__/ci-reporter.test.js.map +1 -0
  5. package/dist/__tests__/code-health.test.d.ts +2 -0
  6. package/dist/__tests__/code-health.test.d.ts.map +1 -0
  7. package/dist/__tests__/code-health.test.js +90 -0
  8. package/dist/__tests__/code-health.test.js.map +1 -0
  9. package/dist/__tests__/developer-velocity.test.d.ts +2 -0
  10. package/dist/__tests__/developer-velocity.test.d.ts.map +1 -0
  11. package/dist/__tests__/developer-velocity.test.js +66 -0
  12. package/dist/__tests__/developer-velocity.test.js.map +1 -0
  13. package/dist/__tests__/error-trends.test.d.ts +2 -0
  14. package/dist/__tests__/error-trends.test.d.ts.map +1 -0
  15. package/dist/__tests__/error-trends.test.js +61 -0
  16. package/dist/__tests__/error-trends.test.js.map +1 -0
  17. package/dist/__tests__/memory-growth.test.d.ts +2 -0
  18. package/dist/__tests__/memory-growth.test.d.ts.map +1 -0
  19. package/dist/__tests__/memory-growth.test.js +61 -0
  20. package/dist/__tests__/memory-growth.test.js.map +1 -0
  21. package/dist/walls/06-memory/stores/ci-reporter.d.ts +68 -0
  22. package/dist/walls/06-memory/stores/ci-reporter.d.ts.map +1 -0
  23. package/dist/walls/06-memory/stores/ci-reporter.js +272 -0
  24. package/dist/walls/06-memory/stores/ci-reporter.js.map +1 -0
  25. package/dist/walls/06-memory/stores/code-health.d.ts +40 -0
  26. package/dist/walls/06-memory/stores/code-health.d.ts.map +1 -0
  27. package/dist/walls/06-memory/stores/code-health.js +344 -0
  28. package/dist/walls/06-memory/stores/code-health.js.map +1 -0
  29. package/dist/walls/06-memory/stores/developer-velocity.d.ts +53 -0
  30. package/dist/walls/06-memory/stores/developer-velocity.d.ts.map +1 -0
  31. package/dist/walls/06-memory/stores/developer-velocity.js +225 -0
  32. package/dist/walls/06-memory/stores/developer-velocity.js.map +1 -0
  33. package/dist/walls/06-memory/stores/error-trends.d.ts +53 -0
  34. package/dist/walls/06-memory/stores/error-trends.d.ts.map +1 -0
  35. package/dist/walls/06-memory/stores/error-trends.js +232 -0
  36. package/dist/walls/06-memory/stores/error-trends.js.map +1 -0
  37. package/dist/walls/06-memory/stores/memory-growth.d.ts +34 -0
  38. package/dist/walls/06-memory/stores/memory-growth.d.ts.map +1 -0
  39. package/dist/walls/06-memory/stores/memory-growth.js +150 -0
  40. package/dist/walls/06-memory/stores/memory-growth.js.map +1 -0
  41. package/dist/walls/07-runtime/cli/cli.js +247 -0
  42. package/dist/walls/07-runtime/cli/cli.js.map +1 -1
  43. package/dist/walls/07-runtime/daemon/server.d.ts.map +1 -1
  44. package/dist/walls/07-runtime/daemon/server.js +96 -0
  45. package/dist/walls/07-runtime/daemon/server.js.map +1 -1
  46. 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