@chemx/starter-kit 26.9.11-481 â 26.9.12-107
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/cli/audit/ai-slop-detector.js +262 -0
- package/cli/audit/extended-visitors.js +359 -0
- package/cli/audit/history.js +19 -2
- package/cli/audit/metrics.js +69 -0
- package/cli/audit/prompts.js +175 -48
- package/cli/audit/reporter-banner.d.ts +3 -0
- package/cli/audit/reporter-banner.js +74 -0
- package/cli/audit/reporter-grades.js +11 -26
- package/cli/audit/reporter-grouping-markdown.js +83 -0
- package/cli/audit/reporter-grouping.d.ts +42 -0
- package/cli/audit/reporter-grouping.js +243 -0
- package/cli/audit/reporter-markdown.js +34 -22
- package/cli/audit/reporter-sections.d.ts +10 -0
- package/cli/audit/reporter-sections.js +259 -0
- package/cli/audit/reporter-summary.d.ts +4 -0
- package/cli/audit/reporter-summary.js +142 -0
- package/cli/audit/reporter-utils.js +13 -1
- package/cli/audit/reporter.d.ts +16 -0
- package/cli/audit/reporter.js +47 -420
- package/cli/audit/rules-helpers.js +16 -0
- package/cli/audit/rules-registry.js +88 -1
- package/cli/audit/rules.js +32 -1
- package/cli/audit/social-git.js +133 -131
- package/cli/audit/social.js +15 -2
- package/cli/audit/types.d.ts +28 -27
- package/cli/audit.js +56 -3
- package/cli/badge.js +262 -0
- package/cli/generator-templates.js +264 -0
- package/cli/generator.d.ts +10 -0
- package/cli/generator.js +151 -0
- package/cli/help.js +17 -7
- package/cli/index.js +26 -16
- package/cli/installer.d.ts +2 -0
- package/cli/installer.js +52 -38
- package/cli/license.js +17 -4
- package/cli/navigator-actions.js +63 -1
- package/cli/navigator-banner.js +17 -6
- package/cli/navigator-grades.js +9 -0
- package/cli/navigator-menu.js +36 -0
- package/cli/navigator-share.js +7 -4
- package/cli/navigator.d.ts +5 -1
- package/cli/navigator.js +49 -12
- package/cli/scaffold.js +3 -54
- package/cli/terminal.js +4 -1
- package/docs/CHANGELOG.md +50 -0
- package/package.json +1 -1
package/cli/audit/metrics.js
CHANGED
|
@@ -7,6 +7,7 @@ export const calculateMolecularHealthScore = (violations, totalFiles) => {
|
|
|
7
7
|
|
|
8
8
|
let penalty = 0;
|
|
9
9
|
for (const v of violations) {
|
|
10
|
+
if (v.isAiSlop) continue;
|
|
10
11
|
if (v.severity === 'CRITICAL') penalty += 8;
|
|
11
12
|
else if (v.severity === 'HIGH') penalty += 4;
|
|
12
13
|
else if (v.severity === 'MEDIUM') penalty += 2;
|
|
@@ -56,6 +57,7 @@ export const calculatePillarBreakdown = (violations) => {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
for (const v of violations) {
|
|
60
|
+
if (v.isAiSlop) continue;
|
|
59
61
|
const pillarName = v.pillar || PILLARS.PILLAR_1;
|
|
60
62
|
if (!breakdown[pillarName]) {
|
|
61
63
|
breakdown[pillarName] = {
|
|
@@ -177,3 +179,70 @@ export const calculateHotspots = (violations, fileStats, limit = 5) => {
|
|
|
177
179
|
};
|
|
178
180
|
|
|
179
181
|
export const calculateQuantumHealthScore = calculateMolecularHealthScore;
|
|
182
|
+
|
|
183
|
+
export const calculateAiSlopScore = (violations, totalFiles) => {
|
|
184
|
+
const slopViolations = violations.filter((v) => v.isAiSlop);
|
|
185
|
+
if (totalFiles === 0) {
|
|
186
|
+
return {
|
|
187
|
+
score: 100,
|
|
188
|
+
grade: 'A+',
|
|
189
|
+
label: 'Pure Artisanal',
|
|
190
|
+
violationsCount: 0,
|
|
191
|
+
breakdown: { critical: 0, high: 0, medium: 0, low: 0 }
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
let penalty = 0;
|
|
196
|
+
let critical = 0;
|
|
197
|
+
let high = 0;
|
|
198
|
+
let medium = 0;
|
|
199
|
+
let low = 0;
|
|
200
|
+
|
|
201
|
+
for (const v of slopViolations) {
|
|
202
|
+
if (v.severity === 'CRITICAL') {
|
|
203
|
+
penalty += 10;
|
|
204
|
+
critical += 1;
|
|
205
|
+
} else if (v.severity === 'HIGH') {
|
|
206
|
+
penalty += 5;
|
|
207
|
+
high += 1;
|
|
208
|
+
} else if (v.severity === 'MEDIUM') {
|
|
209
|
+
penalty += 2;
|
|
210
|
+
medium += 1;
|
|
211
|
+
} else {
|
|
212
|
+
penalty += 1;
|
|
213
|
+
low += 1;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const scale = Math.max(1, Math.log10(totalFiles + 1));
|
|
218
|
+
const adjustedPenalty = penalty / scale;
|
|
219
|
+
const score = Math.max(0, Math.min(100, Math.round(100 - adjustedPenalty)));
|
|
220
|
+
|
|
221
|
+
let grade = 'F';
|
|
222
|
+
let label = 'Severe AI Slop Infection';
|
|
223
|
+
|
|
224
|
+
if (score >= 95) {
|
|
225
|
+
grade = 'A+';
|
|
226
|
+
label = 'Pure Artisanal';
|
|
227
|
+
} else if (score >= 90) {
|
|
228
|
+
grade = 'A';
|
|
229
|
+
label = 'Near-Zero Slop';
|
|
230
|
+
} else if (score >= 80) {
|
|
231
|
+
grade = 'B';
|
|
232
|
+
label = 'Low AI Residue';
|
|
233
|
+
} else if (score >= 70) {
|
|
234
|
+
grade = 'C';
|
|
235
|
+
label = 'Moderate Slop Drift';
|
|
236
|
+
} else if (score >= 60) {
|
|
237
|
+
grade = 'D';
|
|
238
|
+
label = 'High AI Slop Hazard';
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
score,
|
|
243
|
+
grade,
|
|
244
|
+
label,
|
|
245
|
+
violationsCount: slopViolations.length,
|
|
246
|
+
breakdown: { critical, high, medium, low }
|
|
247
|
+
};
|
|
248
|
+
};
|
package/cli/audit/prompts.js
CHANGED
|
@@ -1,35 +1,108 @@
|
|
|
1
|
+
import { groupViolationsByRule } from './reporter-grouping.js';
|
|
2
|
+
|
|
1
3
|
const CYAN = '\x1b[38;2;98;201;255m';
|
|
2
4
|
const BOLD = '\x1b[1m';
|
|
3
5
|
const DIM = '\x1b[2m';
|
|
4
6
|
const RESET = '\x1b[0m';
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
const {
|
|
8
|
-
|
|
8
|
+
const buildPathTree = (violations) => {
|
|
9
|
+
const root = { dirs: new Map(), files: new Map() };
|
|
10
|
+
|
|
11
|
+
for (const v of violations) {
|
|
12
|
+
const rawPath = v.filePath || '';
|
|
13
|
+
const normalized = rawPath.replace(/\\/g, '/').replace(/^\.\//, '');
|
|
14
|
+
const segments = normalized.split('/');
|
|
15
|
+
const fileName = segments.pop();
|
|
16
|
+
|
|
17
|
+
let current = root;
|
|
18
|
+
for (const seg of segments) {
|
|
19
|
+
const segName = seg.endsWith('/') ? seg : `${seg}/`;
|
|
20
|
+
if (!current.dirs.has(segName)) {
|
|
21
|
+
current.dirs.set(segName, { dirs: new Map(), files: new Map() });
|
|
22
|
+
}
|
|
23
|
+
current = current.dirs.get(segName);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!current.files.has(fileName)) {
|
|
27
|
+
current.files.set(fileName, []);
|
|
28
|
+
}
|
|
29
|
+
const loc = v.column ? `${v.line}:${v.column}` : `${v.line}`;
|
|
30
|
+
current.files.get(fileName).push(loc);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return root;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const renderTreeLines = (node, depth = 0) => {
|
|
37
|
+
const lines = [];
|
|
38
|
+
const indent = ' ' + ' '.repeat(depth);
|
|
39
|
+
|
|
40
|
+
const sortedDirs = Array.from(node.dirs.entries()).sort((a, b) => a[0].localeCompare(b[0]));
|
|
41
|
+
for (const [dirName, childNode] of sortedDirs) {
|
|
42
|
+
lines.push(`${indent}* ${dirName}`);
|
|
43
|
+
const childLines = renderTreeLines(childNode, depth + 1);
|
|
44
|
+
lines.push(...childLines);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const sortedFiles = Array.from(node.files.entries()).sort((a, b) => a[0].localeCompare(b[0]));
|
|
48
|
+
for (const [fileName, locs] of sortedFiles) {
|
|
49
|
+
const uniqueLocs = Array.from(new Set(locs)).join(', ');
|
|
50
|
+
lines.push(`${indent}- \`${fileName}:${uniqueLocs}\``);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return lines;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const formatGroupedPromptViolations = (violations = []) => {
|
|
57
|
+
const hasNoViolations = violations.length === 0;
|
|
58
|
+
if (hasNoViolations) return [];
|
|
59
|
+
|
|
60
|
+
const ruleGroups = groupViolationsByRule(violations);
|
|
61
|
+
const lines = [];
|
|
62
|
+
|
|
63
|
+
ruleGroups.forEach((rg, idx) => {
|
|
64
|
+
const countLabel = rg.total === 1 ? '1 item' : `${rg.total} items`;
|
|
65
|
+
lines.push(`${idx + 1}. [${rg.rule}] (${countLabel})`);
|
|
66
|
+
lines.push(` Hazard: ${rg.hazard}`);
|
|
67
|
+
lines.push(` Directive: ${rg.directive}`);
|
|
68
|
+
lines.push(' Locations:');
|
|
69
|
+
|
|
70
|
+
const tree = buildPathTree(rg.violations);
|
|
71
|
+
const treeLines = renderTreeLines(tree, 0);
|
|
72
|
+
lines.push(...treeLines);
|
|
73
|
+
lines.push('');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return lines;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const buildGradeFPrompt = (report, options = {}) => {
|
|
80
|
+
const { excludeAiSlop = false } = options;
|
|
81
|
+
const { violations = [], hotspots = [] } = report;
|
|
82
|
+
const critical = violations
|
|
83
|
+
.filter((v) => v.severity === 'CRITICAL')
|
|
84
|
+
.filter((v) => (excludeAiSlop ? !v.isAiSlop : true));
|
|
9
85
|
const extremeMonoliths = hotspots.filter((h) => h.lineCount >= 2000);
|
|
10
86
|
|
|
11
|
-
|
|
87
|
+
const hasNoCritical = critical.length === 0;
|
|
88
|
+
const hasNoMonoliths = extremeMonoliths.length === 0;
|
|
89
|
+
if (hasNoCritical && hasNoMonoliths) return '';
|
|
12
90
|
|
|
13
91
|
const lines = [];
|
|
14
92
|
lines.push('Act as a Principal Systems Architect. Surgically refactor the following Grade F Critical Context Hazards in our codebase according to Chemical X Molecular Architecture Standards:\n');
|
|
15
93
|
|
|
16
94
|
if (extremeMonoliths.length > 0) {
|
|
17
95
|
lines.push('### EXTREME MONOLITHS (>= 2,000 lines of code) : MONOLITH DECOMPOSITION');
|
|
96
|
+
lines.push('Action: Decompose into crystalline single-responsibility capsules (< 100 lines per molecule). Convert top-level view into a declarative Table-of-Contents view.\n');
|
|
18
97
|
extremeMonoliths.forEach((h, i) => {
|
|
19
98
|
lines.push(`${i + 1}. File: \`${h.filePath}\` (${h.lineCount} lines)`);
|
|
20
|
-
lines.push(' Action: Decompose this monolith into crystalline single-responsibility capsules (< 100 lines per molecule). Convert top-level view into a declarative Table-of-Contents view.');
|
|
21
99
|
});
|
|
22
100
|
lines.push('');
|
|
23
101
|
}
|
|
24
102
|
|
|
25
103
|
if (critical.length > 0) {
|
|
26
104
|
lines.push('### CRITICAL AST VIOLATIONS');
|
|
27
|
-
|
|
28
|
-
lines.push(`${i + 1}. \`${v.filePath}:${v.line}:${v.column}\` [${v.rule}]`);
|
|
29
|
-
lines.push(` Hazard: ${v.hazard}`);
|
|
30
|
-
lines.push(` Directive: ${v.directive}`);
|
|
31
|
-
});
|
|
32
|
-
lines.push('');
|
|
105
|
+
lines.push(...formatGroupedPromptViolations(critical));
|
|
33
106
|
}
|
|
34
107
|
|
|
35
108
|
lines.push('### STRICT EXECUTION RULES:');
|
|
@@ -42,33 +115,33 @@ export const buildGradeFPrompt = (report) => {
|
|
|
42
115
|
return lines.join('\n');
|
|
43
116
|
};
|
|
44
117
|
|
|
45
|
-
export const buildGradeDPrompt = (report) => {
|
|
46
|
-
const {
|
|
47
|
-
const
|
|
118
|
+
export const buildGradeDPrompt = (report, options = {}) => {
|
|
119
|
+
const { excludeAiSlop = false } = options;
|
|
120
|
+
const { violations = [], hotspots = [] } = report;
|
|
121
|
+
const high = violations
|
|
122
|
+
.filter((v) => v.severity === 'HIGH')
|
|
123
|
+
.filter((v) => (excludeAiSlop ? !v.isAiSlop : true));
|
|
48
124
|
const severeMonoliths = hotspots.filter((h) => h.lineCount >= 1000 && h.lineCount < 2000);
|
|
49
125
|
|
|
50
|
-
|
|
126
|
+
const hasNoHigh = high.length === 0;
|
|
127
|
+
const hasNoMonoliths = severeMonoliths.length === 0;
|
|
128
|
+
if (hasNoHigh && hasNoMonoliths) return '';
|
|
51
129
|
|
|
52
130
|
const lines = [];
|
|
53
131
|
lines.push('Act as a Principal Systems Architect. Refactor the following Grade D High-Severity Architectural Debts according to Chemical X Molecular Architecture Standards:\n');
|
|
54
132
|
|
|
55
133
|
if (severeMonoliths.length > 0) {
|
|
56
134
|
lines.push('### SEVERE MONOLITHS (1,000 - 1,999 lines of code)');
|
|
135
|
+
lines.push('Action: Extract sub-features into isolated molecule capsules (< 100 lines of code) and domain composables.\n');
|
|
57
136
|
severeMonoliths.forEach((h, i) => {
|
|
58
137
|
lines.push(`${i + 1}. File: \`${h.filePath}\` (${h.lineCount} lines)`);
|
|
59
|
-
lines.push(' Action: Extract sub-features into isolated molecule capsules (< 100 lines of code) and domain composables.');
|
|
60
138
|
});
|
|
61
139
|
lines.push('');
|
|
62
140
|
}
|
|
63
141
|
|
|
64
142
|
if (high.length > 0) {
|
|
65
143
|
lines.push('### HIGH SEVERITY VIOLATIONS');
|
|
66
|
-
|
|
67
|
-
lines.push(`${i + 1}. \`${v.filePath}:${v.line}:${v.column}\` [${v.rule}]`);
|
|
68
|
-
lines.push(` Hazard: ${v.hazard}`);
|
|
69
|
-
lines.push(` Directive: ${v.directive}`);
|
|
70
|
-
});
|
|
71
|
-
lines.push('');
|
|
144
|
+
lines.push(...formatGroupedPromptViolations(high));
|
|
72
145
|
}
|
|
73
146
|
|
|
74
147
|
lines.push('### STRICT EXECUTION RULES:');
|
|
@@ -79,33 +152,33 @@ export const buildGradeDPrompt = (report) => {
|
|
|
79
152
|
return lines.join('\n');
|
|
80
153
|
};
|
|
81
154
|
|
|
82
|
-
export const buildGradeCPrompt = (report) => {
|
|
83
|
-
const {
|
|
84
|
-
const
|
|
155
|
+
export const buildGradeCPrompt = (report, options = {}) => {
|
|
156
|
+
const { excludeAiSlop = false } = options;
|
|
157
|
+
const { violations = [], hotspots = [] } = report;
|
|
158
|
+
const medium = violations
|
|
159
|
+
.filter((v) => v.severity === 'MEDIUM')
|
|
160
|
+
.filter((v) => (excludeAiSlop ? !v.isAiSlop : true));
|
|
85
161
|
const warningMonoliths = hotspots.filter((h) => h.lineCount >= 500 && h.lineCount < 1000);
|
|
86
162
|
|
|
87
|
-
|
|
163
|
+
const hasNoMedium = medium.length === 0;
|
|
164
|
+
const hasNoMonoliths = warningMonoliths.length === 0;
|
|
165
|
+
if (hasNoMedium && hasNoMonoliths) return '';
|
|
88
166
|
|
|
89
167
|
const lines = [];
|
|
90
168
|
lines.push('Act as a Senior Frontend Engineer. Refactor the following Grade C Medium-Severity Technical Debts according to Chemical X Molecular Architecture Standards:\n');
|
|
91
169
|
|
|
92
170
|
if (warningMonoliths.length > 0) {
|
|
93
171
|
lines.push('### WARNING MONOLITHS (500 - 999 lines of code)');
|
|
172
|
+
lines.push('Action: Bring file under 500 line budget by extracting helper functions, types, and child molecules.\n');
|
|
94
173
|
warningMonoliths.forEach((h, i) => {
|
|
95
174
|
lines.push(`${i + 1}. File: \`${h.filePath}\` (${h.lineCount} lines)`);
|
|
96
|
-
lines.push(' Action: Bring file under 500 line budget by extracting helper functions, types, and child molecules.');
|
|
97
175
|
});
|
|
98
176
|
lines.push('');
|
|
99
177
|
}
|
|
100
178
|
|
|
101
179
|
if (medium.length > 0) {
|
|
102
180
|
lines.push('### MEDIUM SEVERITY VIOLATIONS');
|
|
103
|
-
|
|
104
|
-
lines.push(`${i + 1}. \`${v.filePath}:${v.line}:${v.column}\` [${v.rule}]`);
|
|
105
|
-
lines.push(` Hazard: ${v.hazard}`);
|
|
106
|
-
lines.push(` Directive: ${v.directive}`);
|
|
107
|
-
});
|
|
108
|
-
lines.push('');
|
|
181
|
+
lines.push(...formatGroupedPromptViolations(medium));
|
|
109
182
|
}
|
|
110
183
|
|
|
111
184
|
lines.push('### STRICT EXECUTION RULES:');
|
|
@@ -116,22 +189,21 @@ export const buildGradeCPrompt = (report) => {
|
|
|
116
189
|
return lines.join('\n');
|
|
117
190
|
};
|
|
118
191
|
|
|
119
|
-
export const buildGradeBPrompt = (report) => {
|
|
120
|
-
const {
|
|
121
|
-
const
|
|
192
|
+
export const buildGradeBPrompt = (report, options = {}) => {
|
|
193
|
+
const { excludeAiSlop = false } = options;
|
|
194
|
+
const { violations = [] } = report;
|
|
195
|
+
const low = violations
|
|
196
|
+
.filter((v) => v.severity === 'LOW')
|
|
197
|
+
.filter((v) => (excludeAiSlop ? !v.isAiSlop : true));
|
|
122
198
|
|
|
123
|
-
|
|
199
|
+
const hasNoLow = low.length === 0;
|
|
200
|
+
if (hasNoLow) return '';
|
|
124
201
|
|
|
125
202
|
const lines = [];
|
|
126
203
|
lines.push('Act as a Clean Code Specialist. Clean up the following Grade B Low-Severity Hygiene Issues according to Chemical X standards:\n');
|
|
127
204
|
|
|
128
205
|
lines.push('### LOW HYGIENE VIOLATIONS');
|
|
129
|
-
|
|
130
|
-
lines.push(`${i + 1}. \`${v.filePath}:${v.line}:${v.column}\` [${v.rule}]`);
|
|
131
|
-
lines.push(` Hazard: ${v.hazard}`);
|
|
132
|
-
lines.push(` Directive: ${v.directive}`);
|
|
133
|
-
});
|
|
134
|
-
lines.push('');
|
|
206
|
+
lines.push(...formatGroupedPromptViolations(low));
|
|
135
207
|
|
|
136
208
|
lines.push('### STRICT EXECUTION RULES:');
|
|
137
209
|
lines.push('1. Typography Hygiene: Replace all em dashes with standard hyphens (-) or colons (:).');
|
|
@@ -141,15 +213,70 @@ export const buildGradeBPrompt = (report) => {
|
|
|
141
213
|
return lines.join('\n');
|
|
142
214
|
};
|
|
143
215
|
|
|
216
|
+
export const buildAiSlopPrompt = (report) => {
|
|
217
|
+
const { violations = [] } = report;
|
|
218
|
+
const slopViolations = violations.filter((v) => Boolean(v.isAiSlop));
|
|
219
|
+
|
|
220
|
+
const hasNoSlop = slopViolations.length === 0;
|
|
221
|
+
if (hasNoSlop) return '';
|
|
222
|
+
|
|
223
|
+
const lines = [];
|
|
224
|
+
lines.push('Act as a Clean Code Specialist and Code Authenticity Guardian. Eliminate the following AI Slop and conversational artifacts from our codebase according to Chemical X standards:\n');
|
|
225
|
+
|
|
226
|
+
lines.push('### AI SLOP & CODE AUTHENTICITY VIOLATIONS');
|
|
227
|
+
lines.push(...formatGroupedPromptViolations(slopViolations));
|
|
228
|
+
|
|
229
|
+
lines.push('### STRICT EXECUTION RULES:');
|
|
230
|
+
lines.push('1. Conversational Residue: Completely remove leaked AI conversational preambles, assistant markdown code fences, and pleasantry comments.');
|
|
231
|
+
lines.push('2. Truncation Placeholders: Replace lazy AI truncation placeholders with complete, robust, and verifiable implementations.');
|
|
232
|
+
lines.push('3. Echo Comments: Delete trivial parroting comments that merely restate adjacent self-documenting code.');
|
|
233
|
+
lines.push('4. Paranoia Catch Wrappers: Replace shallow or empty catch blocks with intentional error propagation or ResultTuple ([data, error]).');
|
|
234
|
+
lines.push('5. Inline Utility Reinventions: Replace reinvented inline helper utilities with shared project utilities or native methods.');
|
|
235
|
+
lines.push('6. Type Widening: Eliminate lazy "any" type casts on error parameters or variables; enforce strict typing.');
|
|
236
|
+
|
|
237
|
+
return lines.join('\n');
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
export const buildHotspotsPrompt = (report) => {
|
|
241
|
+
const { hotspots = [] } = report;
|
|
242
|
+
const monolithHotspots = hotspots.filter((h) => h.isMonolith || h.lineCount > 500);
|
|
243
|
+
|
|
244
|
+
const hasNoMonoliths = monolithHotspots.length === 0;
|
|
245
|
+
if (hasNoMonoliths) return '';
|
|
246
|
+
|
|
247
|
+
const lines = [];
|
|
248
|
+
lines.push('Act as a Principal Systems Architect. Surgically decompose the following monolithic hotspot files according to Chemical X Molecular Architecture Standards:\n');
|
|
249
|
+
|
|
250
|
+
lines.push('### MONOLITHIC REFACTORING HOTSPOTS');
|
|
251
|
+
lines.push('Action: Decompose into single-responsibility crystalline molecule capsules (< 100 lines) and dedicated domain composables.\n');
|
|
252
|
+
monolithHotspots.forEach((h, i) => {
|
|
253
|
+
const tier = h.monolithTier ? `[${h.monolithTier} MONOLITH]` : '[MONOLITH]';
|
|
254
|
+
lines.push(`${i + 1}. File: \`${h.filePath}\` (${h.lineCount} lines, ${h.violationCount} hazards) ${tier}`);
|
|
255
|
+
});
|
|
256
|
+
lines.push('');
|
|
257
|
+
|
|
258
|
+
lines.push('### STRICT EXECUTION RULES:');
|
|
259
|
+
lines.push('1. Molecular Limits: Molecule capsules must strictly remain under 100 lines per file.');
|
|
260
|
+
lines.push('2. Table-of-Contents Views: Top-level page views must be 10 to 20 line declarative Table of Contents assembling molecules via named slots.');
|
|
261
|
+
lines.push('3. Composable Return Contracts: Custom hooks/composables must strictly limit returns to 3 to 5 properties (State + Status + Actions).');
|
|
262
|
+
lines.push('4. Type Co-location: Co-locate granular types/*.d.ts files inside each feature capsule (< 100 lines per type file) instead of creating type monoliths.');
|
|
263
|
+
lines.push('5. Zero breaking changes to external component APIs, route exports, or existing props.');
|
|
264
|
+
|
|
265
|
+
return lines.join('\n');
|
|
266
|
+
};
|
|
267
|
+
|
|
144
268
|
export const buildMasterPrompt = (report) => {
|
|
145
269
|
const sections = [
|
|
146
|
-
buildGradeFPrompt(report),
|
|
147
|
-
buildGradeDPrompt(report),
|
|
148
|
-
buildGradeCPrompt(report),
|
|
149
|
-
buildGradeBPrompt(report)
|
|
270
|
+
buildGradeFPrompt(report, { excludeAiSlop: true }),
|
|
271
|
+
buildGradeDPrompt(report, { excludeAiSlop: true }),
|
|
272
|
+
buildGradeCPrompt(report, { excludeAiSlop: true }),
|
|
273
|
+
buildGradeBPrompt(report, { excludeAiSlop: true }),
|
|
274
|
+
buildAiSlopPrompt(report),
|
|
275
|
+
buildHotspotsPrompt(report)
|
|
150
276
|
].filter(Boolean);
|
|
151
277
|
|
|
152
|
-
|
|
278
|
+
const hasNoSections = sections.length === 0;
|
|
279
|
+
if (hasNoSections) return '';
|
|
153
280
|
|
|
154
281
|
const header = `Act as a Principal Systems Architect. Execute a phased architectural refactoring of our codebase according to Chemical X Molecular Architecture Standards.\n\n`;
|
|
155
282
|
return header + sections.join('\n\n---\n\n');
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { resolveGradeColor } from './reporter-utils.js';
|
|
2
|
+
import { getAsciiGradeLines } from './reporter-ascii.js';
|
|
3
|
+
|
|
4
|
+
const BANNER_ART = [
|
|
5
|
+
' ââââââââââ âââââââââââââââ âââââââ âââââââ ââââââ âââ âââ âââ',
|
|
6
|
+
'âââââââââââ ââââââââââââââââ âââââââââââââââââââââââââââ ââââââââ',
|
|
7
|
+
'âââ ââââââââââââââ âââââââââââââââââ âââââââââââ ââââââ ',
|
|
8
|
+
'âââ ââââââââââââââ âââââââââââââââââ âââââââââââ ââââââ ',
|
|
9
|
+
'âââââââââââ ââââââââââââââ âââ âââââââââââââââââ âââââââââââ ââââ âââ',
|
|
10
|
+
' ââââââââââ ââââââââââââââ ââââââ ââââââââââ âââââââââââ âââ âââ'
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const MAX_BANNER_LEN = 74;
|
|
14
|
+
|
|
15
|
+
export const getChemicalXAsciiBanner = (gradeOrReport = null) => {
|
|
16
|
+
const grade = typeof gradeOrReport === 'object' && gradeOrReport !== null
|
|
17
|
+
? gradeOrReport.health?.grade
|
|
18
|
+
: gradeOrReport;
|
|
19
|
+
|
|
20
|
+
const lines = [];
|
|
21
|
+
lines.push(' \x1b[1m\x1b[37mThe Secret Sauce to \x1b[38;2;98;201;255mVibe Coding\x1b[0m');
|
|
22
|
+
|
|
23
|
+
const gColor = grade ? resolveGradeColor(grade) : '';
|
|
24
|
+
const gradeLines = grade ? getAsciiGradeLines(grade, gColor, true) : [];
|
|
25
|
+
const termWidth = process.stdout.columns || 0;
|
|
26
|
+
const isSideBySide = Boolean(!termWidth || termWidth >= 105);
|
|
27
|
+
|
|
28
|
+
for (let lineIdx = 0; lineIdx < BANNER_ART.length; lineIdx++) {
|
|
29
|
+
const line = BANNER_ART[lineIdx];
|
|
30
|
+
let out = '';
|
|
31
|
+
for (let i = 0; i < line.length; i++) {
|
|
32
|
+
const ch = line[i];
|
|
33
|
+
if (ch === ' ') {
|
|
34
|
+
out += ' ';
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const t = i / (MAX_BANNER_LEN - 1);
|
|
38
|
+
let r;
|
|
39
|
+
let g;
|
|
40
|
+
let b;
|
|
41
|
+
if (t < 0.5) {
|
|
42
|
+
const factor = t * 2;
|
|
43
|
+
r = Math.round(244 * (1 - factor) + 192 * factor);
|
|
44
|
+
g = Math.round(114 * (1 - factor) + 132 * factor);
|
|
45
|
+
b = Math.round(182 * (1 - factor) + 252 * factor);
|
|
46
|
+
} else {
|
|
47
|
+
const factor = (t - 0.5) * 2;
|
|
48
|
+
r = Math.round(192 * (1 - factor) + 129 * factor);
|
|
49
|
+
g = Math.round(132 * (1 - factor) + 140 * factor);
|
|
50
|
+
b = Math.round(252 * (1 - factor) + 248 * factor);
|
|
51
|
+
}
|
|
52
|
+
out += `\x1b[38;2;${r};${g};${b}m\x1b[1m${ch}\x1b[0m`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (isSideBySide && gradeLines.length > lineIdx) {
|
|
56
|
+
out += ` ${gradeLines[lineIdx]}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
lines.push(out);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const subtitle = 'Architectural guardrails to eliminate token burn and AI hallucinations.';
|
|
63
|
+
const pad = ' '.repeat(Math.max(0, Math.floor((MAX_BANNER_LEN - subtitle.length) / 2)));
|
|
64
|
+
lines.push(`${pad}\x1b[2m${subtitle}\x1b[0m\n`);
|
|
65
|
+
|
|
66
|
+
if (!isSideBySide && gradeLines.length > 0) {
|
|
67
|
+
for (const gl of gradeLines) {
|
|
68
|
+
lines.push(` ${gl}`);
|
|
69
|
+
}
|
|
70
|
+
lines.push('');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return lines.join('\n');
|
|
74
|
+
};
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
groupViolationsBySeverity
|
|
18
18
|
} from './reporter-utils.js';
|
|
19
19
|
import { getReportCardAsciiLines } from './reporter-ascii.js';
|
|
20
|
+
import { renderGroupedViolationsTerminal } from './reporter-grouping.js';
|
|
20
21
|
|
|
21
22
|
export const formatGradeFSection = (report) => {
|
|
22
23
|
const { violations, hotspots, pillars } = report;
|
|
@@ -44,12 +45,8 @@ export const formatGradeFSection = (report) => {
|
|
|
44
45
|
lines.push(` ${DIM}Codebase is free of extreme monoliths (>2,000 lines of code) and critical violations.${RESET}`);
|
|
45
46
|
} else {
|
|
46
47
|
if (critical.length > 0) {
|
|
47
|
-
lines.push(`\n ${BOLD}${RED}đ¨ CRITICAL AST VIOLATIONS (${critical.length}):${RESET}`);
|
|
48
|
-
|
|
49
|
-
lines.push(` ${RED}[#${idx + 1} CRITICAL]${RESET} [${v.rule}] ${YELLOW}${v.filePath}:${v.line}:${v.column}${RESET}`);
|
|
50
|
-
lines.push(` Hazard: ${v.hazard}`);
|
|
51
|
-
lines.push(` Directive: ${CYAN}${v.directive}${RESET}\n`);
|
|
52
|
-
});
|
|
48
|
+
lines.push(`\n ${BOLD}${RED}đ¨ CRITICAL AST VIOLATIONS (${critical.length}):${RESET}\n`);
|
|
49
|
+
lines.push(renderGroupedViolationsTerminal(critical));
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
if (extremeMonoliths.length > 0) {
|
|
@@ -105,12 +102,8 @@ export const formatGradeDSection = (report) => {
|
|
|
105
102
|
lines.push(` ${DIM}No severe monoliths (1,000-1,999 lines of code) or saturated hook anti-patterns.${RESET}`);
|
|
106
103
|
} else {
|
|
107
104
|
if (high.length > 0) {
|
|
108
|
-
lines.push(`\n ${BOLD}${ORANGE}â ī¸ HIGH SEVERITY VIOLATIONS (${high.length}):${RESET}`);
|
|
109
|
-
|
|
110
|
-
lines.push(` ${ORANGE}[#${idx + 1} HIGH]${RESET} [${v.rule}] ${YELLOW}${v.filePath}:${v.line}:${v.column}${RESET}`);
|
|
111
|
-
lines.push(` Hazard: ${v.hazard}`);
|
|
112
|
-
lines.push(` Directive: ${CYAN}${v.directive}${RESET}\n`);
|
|
113
|
-
});
|
|
105
|
+
lines.push(`\n ${BOLD}${ORANGE}â ī¸ HIGH SEVERITY VIOLATIONS (${high.length}):${RESET}\n`);
|
|
106
|
+
lines.push(renderGroupedViolationsTerminal(high));
|
|
114
107
|
}
|
|
115
108
|
|
|
116
109
|
if (severeMonoliths.length > 0) {
|
|
@@ -163,12 +156,8 @@ export const formatGradeCSection = (report) => {
|
|
|
163
156
|
lines.push(` ${DIM}All files remain under 500 lines with clean styling and handlers.${RESET}`);
|
|
164
157
|
} else {
|
|
165
158
|
if (medium.length > 0) {
|
|
166
|
-
lines.push(`\n ${BOLD}${CYAN}⥠MEDIUM SEVERITY VIOLATIONS (${medium.length}):${RESET}`);
|
|
167
|
-
|
|
168
|
-
lines.push(` ${YELLOW}[#${idx + 1} MED]${RESET} [${v.rule}] ${YELLOW}${v.filePath}:${v.line}:${v.column}${RESET}`);
|
|
169
|
-
lines.push(` Hazard: ${v.hazard}`);
|
|
170
|
-
lines.push(` Directive: ${CYAN}${v.directive}${RESET}\n`);
|
|
171
|
-
});
|
|
159
|
+
lines.push(`\n ${BOLD}${CYAN}⥠MEDIUM SEVERITY VIOLATIONS (${medium.length}):${RESET}\n`);
|
|
160
|
+
lines.push(renderGroupedViolationsTerminal(medium));
|
|
172
161
|
}
|
|
173
162
|
|
|
174
163
|
if (warningMonoliths.length > 0) {
|
|
@@ -209,12 +198,8 @@ export const formatGradeBSection = (report) => {
|
|
|
209
198
|
lines.push(`\n ${GREEN}â Outstanding hygiene! Zero Grade B issues detected.${RESET}`);
|
|
210
199
|
lines.push(` ${DIM}Zero em dashes and zero unguarded console statements found.${RESET}`);
|
|
211
200
|
} else {
|
|
212
|
-
lines.push(`\n ${BOLD}${YELLOW}âšī¸ LOW HYGIENE VIOLATIONS (${low.length}):${RESET}`);
|
|
213
|
-
|
|
214
|
-
lines.push(` ${YELLOW}[#${idx + 1} LOW]${RESET} [${v.rule}] ${YELLOW}${v.filePath}:${v.line}:${v.column}${RESET}`);
|
|
215
|
-
lines.push(` Hazard: ${v.hazard}`);
|
|
216
|
-
lines.push(` Directive: ${CYAN}${v.directive}${RESET}\n`);
|
|
217
|
-
});
|
|
201
|
+
lines.push(`\n ${BOLD}${YELLOW}âšī¸ LOW HYGIENE VIOLATIONS (${low.length}):${RESET}\n`);
|
|
202
|
+
lines.push(renderGroupedViolationsTerminal(low));
|
|
218
203
|
}
|
|
219
204
|
|
|
220
205
|
const promptB = buildGradeBPrompt(report);
|
|
@@ -240,11 +225,11 @@ export const formatGradeASection = (report) => {
|
|
|
240
225
|
lines.push(`${DIM} Molecular Architecture verified clean areas and crystalline modules${RESET}`);
|
|
241
226
|
lines.push(`${GREEN}======================================================================${RESET}`);
|
|
242
227
|
lines.push(` Molecular Health Score: ${BOLD}${GREEN}${health.score}/100${RESET} [Grade: ${BOLD}${GREEN}${health.grade}${RESET}]`);
|
|
243
|
-
lines.push(` Passing Pillars: ${BOLD}${GREEN}${passedPillars.length} /
|
|
228
|
+
lines.push(` Passing Pillars: ${BOLD}${GREEN}${passedPillars.length} / ${Object.keys(pillars).length} Pillars PASSED${RESET}`);
|
|
244
229
|
lines.push(` Capsule Compliance: ${BOLD}${GREEN}${metrics.moleculeCompliantPct}%${RESET} compliant (< 100 lines of code)`);
|
|
245
230
|
lines.push(`${GREEN}----------------------------------------------------------------------${RESET}`);
|
|
246
231
|
|
|
247
|
-
lines.push(`\n ${BOLD}${GREEN}â COMPLIANT PILLARS (${passedPillars.length} /
|
|
232
|
+
lines.push(`\n ${BOLD}${GREEN}â COMPLIANT PILLARS (${passedPillars.length} / ${Object.keys(pillars).length}):${RESET}`);
|
|
248
233
|
if (passedPillars.length === 0) {
|
|
249
234
|
lines.push(` ${YELLOW}No pillars are currently 100% compliant.${RESET}\n`);
|
|
250
235
|
} else {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import {
|
|
3
|
+
groupViolationsByDirectory,
|
|
4
|
+
groupViolationsByRule
|
|
5
|
+
} from './reporter-grouping.js';
|
|
6
|
+
|
|
7
|
+
export const formatDirectoryRollupMarkdown = (violations = []) => {
|
|
8
|
+
const dirGroups = groupViolationsByDirectory(violations);
|
|
9
|
+
const lines = [];
|
|
10
|
+
|
|
11
|
+
lines.push('### Directory Hazard Rollup');
|
|
12
|
+
lines.push('');
|
|
13
|
+
|
|
14
|
+
const hasNoViolations = dirGroups.length === 0;
|
|
15
|
+
if (hasNoViolations) {
|
|
16
|
+
lines.push('đĸ Zero violations detected across all project directories.');
|
|
17
|
+
lines.push('');
|
|
18
|
+
return lines.join('\n');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
lines.push('| Directory | Total Hazards | Critical | High | Med | Low | Primary Hazards |');
|
|
22
|
+
lines.push('| :--- | :---: | :---: | :---: | :---: | :---: | :--- |');
|
|
23
|
+
|
|
24
|
+
for (const g of dirGroups) {
|
|
25
|
+
const topHazards = g.topRules
|
|
26
|
+
.slice(0, 2)
|
|
27
|
+
.map((r) => `\`${r.rule}\` (${r.count})`)
|
|
28
|
+
.join(', ');
|
|
29
|
+
const displayHazards = topHazards || 'None';
|
|
30
|
+
lines.push(`| \`${g.directory}\` | **${g.total}** | ${g.critical} | ${g.high} | ${g.medium} | ${g.low} | ${displayHazards} |`);
|
|
31
|
+
}
|
|
32
|
+
lines.push('');
|
|
33
|
+
|
|
34
|
+
return lines.join('\n');
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const renderGroupedViolationsMarkdown = (violations = [], options = {}) => {
|
|
38
|
+
const { showSeverity = false } = options;
|
|
39
|
+
const hasNoViolations = violations.length === 0;
|
|
40
|
+
if (hasNoViolations) return '';
|
|
41
|
+
|
|
42
|
+
const ruleGroups = groupViolationsByRule(violations);
|
|
43
|
+
const lines = [];
|
|
44
|
+
|
|
45
|
+
const headers = showSeverity
|
|
46
|
+
? '| Rule | Severity | Count | Directive | Affected Locations by Directory |'
|
|
47
|
+
: '| Rule | Count | Directive | Affected Locations by Directory |';
|
|
48
|
+
const divider = showSeverity
|
|
49
|
+
? '| :--- | :---: | :---: | :--- | :--- |'
|
|
50
|
+
: '| :--- | :---: | :--- | :--- |';
|
|
51
|
+
|
|
52
|
+
lines.push(headers);
|
|
53
|
+
lines.push(divider);
|
|
54
|
+
|
|
55
|
+
for (const rg of ruleGroups) {
|
|
56
|
+
const dirSummaries = rg.directories.map((d) => {
|
|
57
|
+
const formatLocationItem = (v) => {
|
|
58
|
+
const base = path.basename(v.filePath);
|
|
59
|
+
return `\`${base}:${v.line}\``;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const locList = d.violations.slice(0, 3).map(formatLocationItem);
|
|
63
|
+
const remaining = d.violations.length - 3;
|
|
64
|
+
const hasRemaining = remaining > 0;
|
|
65
|
+
if (hasRemaining) {
|
|
66
|
+
locList.push(`*(+${remaining} more)*`);
|
|
67
|
+
}
|
|
68
|
+
return `đ **\`${d.directory}\`** (${d.count}): ${locList.join(', ')}`;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const locationCell = dirSummaries.join('<br>');
|
|
72
|
+
const sanitizedDirective = rg.directive.replace(/\|/g, '\\|');
|
|
73
|
+
|
|
74
|
+
if (showSeverity) {
|
|
75
|
+
lines.push(`| \`${rg.rule}\` | ${rg.severity} | **${rg.total}** | ${sanitizedDirective} | ${locationCell} |`);
|
|
76
|
+
} else {
|
|
77
|
+
lines.push(`| \`${rg.rule}\` | **${rg.total}** | ${sanitizedDirective} | ${locationCell} |`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
lines.push('');
|
|
81
|
+
|
|
82
|
+
return lines.join('\n');
|
|
83
|
+
};
|