@chemx/starter-kit 26.9.12-93 → 26.9.13-272

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 (49) hide show
  1. package/cli/audit/ai-slop-detector.js +25 -41
  2. package/cli/audit/ast-visitors.js +10 -13
  3. package/cli/audit/history.js +45 -11
  4. package/cli/audit/pattern-detector.js +182 -0
  5. package/cli/audit/prompts.js +129 -72
  6. package/cli/audit/reporter-banner.js +4 -16
  7. package/cli/audit/reporter-grades.js +28 -16
  8. package/cli/audit/reporter-grouping.d.ts +6 -0
  9. package/cli/audit/reporter-grouping.js +48 -5
  10. package/cli/audit/reporter-markdown.js +31 -16
  11. package/cli/audit/reporter-sections.js +28 -12
  12. package/cli/audit/reporter-utils.js +88 -1
  13. package/cli/audit/reporter.d.ts +13 -4
  14. package/cli/audit/reporter.js +32 -5
  15. package/cli/audit/roadmap.js +236 -0
  16. package/cli/audit/rules-predicates.d.ts +17 -0
  17. package/cli/audit/rules-predicates.js +107 -0
  18. package/cli/audit/rules.js +6 -2
  19. package/cli/audit/social-gh.js +2 -6
  20. package/cli/audit/social-publisher.js +1 -1
  21. package/cli/audit/social.js +25 -9
  22. package/cli/audit/types.d.ts +52 -5
  23. package/cli/audit.js +76 -7
  24. package/cli/badge.js +9 -2
  25. package/cli/build/detector.js +68 -0
  26. package/cli/build/executor.js +58 -0
  27. package/cli/build/grouper.js +78 -0
  28. package/cli/build/parser-matchers.js +116 -0
  29. package/cli/build/parser.js +80 -0
  30. package/cli/build/reporter.js +66 -0
  31. package/cli/build/types.d.ts +58 -0
  32. package/cli/build/types.js +1 -0
  33. package/cli/build.d.ts +16 -0
  34. package/cli/build.js +55 -0
  35. package/cli/help.js +14 -0
  36. package/cli/index.js +39 -14
  37. package/cli/installer-templates.js +43 -4
  38. package/cli/license.js +10 -7
  39. package/cli/navigator-actions.js +34 -6
  40. package/cli/navigator-banner.js +4 -2
  41. package/cli/navigator-menu.js +18 -0
  42. package/cli/navigator-share.js +1 -1
  43. package/cli/navigator.d.ts +8 -1
  44. package/cli/navigator.js +3 -3
  45. package/cli/terminal.js +6 -5
  46. package/cli/theme.d.ts +41 -0
  47. package/cli/theme.js +84 -0
  48. package/docs/CHANGELOG.md +46 -0
  49. package/package.json +3 -2
@@ -1,74 +1,132 @@
1
- const CYAN = '\x1b[38;2;98;201;255m';
2
- const BOLD = '\x1b[1m';
3
- const DIM = '\x1b[2m';
4
- const RESET = '\x1b[0m';
5
-
6
- export const buildGradeFPrompt = (report) => {
7
- const { violations, hotspots } = report;
8
- const critical = violations.filter((v) => v.severity === 'CRITICAL');
1
+ import { groupViolationsByRule, buildPathTree } from './reporter-grouping.js';
2
+ import {
3
+ CYAN,
4
+ YELLOW,
5
+ RED,
6
+ ORANGE,
7
+ DIM,
8
+ BOLD,
9
+ RESET
10
+ } from './reporter-utils.js';
11
+
12
+ const SEVERITY_COLORS = {
13
+ CRITICAL: RED,
14
+ HIGH: ORANGE,
15
+ MEDIUM: YELLOW,
16
+ LOW: DIM
17
+ };
18
+
19
+ const renderTreeLines = (node, depth = 0) => {
20
+ const lines = [];
21
+ const indent = ' ' + ' '.repeat(depth);
22
+
23
+ const sortedDirs = Array.from(node.dirs.entries()).sort((a, b) => a[0].localeCompare(b[0]));
24
+ for (const [dirName, childNode] of sortedDirs) {
25
+ lines.push(`${indent}📁 ${BOLD}${dirName}${RESET}`);
26
+ const childLines = renderTreeLines(childNode, depth + 1);
27
+ lines.push(...childLines);
28
+ }
29
+
30
+ const sortedFiles = Array.from(node.files.entries()).sort((a, b) => a[0].localeCompare(b[0]));
31
+ for (const [fileName, locs] of sortedFiles) {
32
+ const uniqueLocs = Array.from(new Set(locs)).join(', ');
33
+ lines.push(`${indent}- \`${YELLOW}${fileName}:${uniqueLocs}${RESET}\``);
34
+ }
35
+
36
+ return lines;
37
+ };
38
+
39
+ export const formatGroupedPromptViolations = (violations = []) => {
40
+ const hasNoViolations = violations.length === 0;
41
+ if (hasNoViolations) return [];
42
+
43
+ const ruleGroups = groupViolationsByRule(violations);
44
+ const lines = [];
45
+
46
+ ruleGroups.forEach((rg, idx) => {
47
+ const sevColor = SEVERITY_COLORS[rg.severity] || YELLOW;
48
+ const countLabel = rg.total === 1 ? '1 item' : `${rg.total} items`;
49
+ lines.push(`${idx + 1}. ${sevColor}[${rg.rule}]${RESET} ${BOLD}(${countLabel})${RESET}`);
50
+ lines.push(` Hazard: ${rg.hazard}`);
51
+ lines.push(` Directive: ${CYAN}${rg.directive}${RESET}`);
52
+ lines.push(' Locations:');
53
+
54
+ const tree = buildPathTree(rg.violations);
55
+ const treeLines = renderTreeLines(tree, 0);
56
+ lines.push(...treeLines);
57
+ lines.push('');
58
+ });
59
+
60
+ return lines;
61
+ };
62
+
63
+ export const buildGradeFPrompt = (report, options = {}) => {
64
+ const { excludeAiSlop = false } = options;
65
+ const { violations = [], hotspots = [] } = report;
66
+ const critical = violations
67
+ .filter((v) => v.severity === 'CRITICAL')
68
+ .filter((v) => (excludeAiSlop ? !v.isAiSlop : true));
9
69
  const extremeMonoliths = hotspots.filter((h) => h.lineCount >= 2000);
10
70
 
11
- if (critical.length === 0 && extremeMonoliths.length === 0) return '';
71
+ const hasNoCritical = critical.length === 0;
72
+ const hasNoMonoliths = extremeMonoliths.length === 0;
73
+ if (hasNoCritical && hasNoMonoliths) return '';
12
74
 
13
75
  const lines = [];
14
76
  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
77
 
16
78
  if (extremeMonoliths.length > 0) {
17
79
  lines.push('### EXTREME MONOLITHS (>= 2,000 lines of code) : MONOLITH DECOMPOSITION');
80
+ 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
81
  extremeMonoliths.forEach((h, i) => {
19
82
  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
83
  });
22
84
  lines.push('');
23
85
  }
24
86
 
25
87
  if (critical.length > 0) {
26
88
  lines.push('### CRITICAL AST VIOLATIONS');
27
- critical.forEach((v, i) => {
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('');
89
+ lines.push(...formatGroupedPromptViolations(critical));
33
90
  }
34
91
 
35
92
  lines.push('### STRICT EXECUTION RULES:');
36
- lines.push('1. Every new molecule component must stay under 100 lines.');
37
- lines.push('2. Top-level page views must be 10-20 line declarative Table-of-Contents templates assembling components via named slots.');
38
- lines.push('3. Zero synthetic or mock data: return live data or explicit empty states.');
39
- lines.push('4. Zero render-hack setTimeout: replace with await nextTick() or flush: post.');
40
- lines.push('5. Output surgical diffs or modular replacements. Preserve existing external exports.');
93
+ lines.push('1. Pre-Split Pattern Discovery: Survey cross-file patterns before slicing; extract canonical shared capsules first to avoid proliferating duplicate one-off patterns.');
94
+ lines.push('2. Every new molecule component must stay under 100 lines.');
95
+ lines.push('3. Top-level page views must be 10-20 line declarative Table-of-Contents templates assembling components via named slots.');
96
+ lines.push('4. Zero synthetic or mock data: return live data or explicit empty states.');
97
+ lines.push('5. Zero render-hack setTimeout: replace with await nextTick() or flush: post.');
98
+ lines.push('6. Output surgical diffs or modular replacements. Preserve existing external exports.');
41
99
 
42
100
  return lines.join('\n');
43
101
  };
44
102
 
45
- export const buildGradeDPrompt = (report) => {
46
- const { violations, hotspots } = report;
47
- const high = violations.filter((v) => v.severity === 'HIGH');
103
+ export const buildGradeDPrompt = (report, options = {}) => {
104
+ const { excludeAiSlop = false } = options;
105
+ const { violations = [], hotspots = [] } = report;
106
+ const high = violations
107
+ .filter((v) => v.severity === 'HIGH')
108
+ .filter((v) => (excludeAiSlop ? !v.isAiSlop : true));
48
109
  const severeMonoliths = hotspots.filter((h) => h.lineCount >= 1000 && h.lineCount < 2000);
49
110
 
50
- if (high.length === 0 && severeMonoliths.length === 0) return '';
111
+ const hasNoHigh = high.length === 0;
112
+ const hasNoMonoliths = severeMonoliths.length === 0;
113
+ if (hasNoHigh && hasNoMonoliths) return '';
51
114
 
52
115
  const lines = [];
53
116
  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
117
 
55
118
  if (severeMonoliths.length > 0) {
56
119
  lines.push('### SEVERE MONOLITHS (1,000 - 1,999 lines of code)');
120
+ lines.push('Action: Extract sub-features into isolated molecule capsules (< 100 lines of code) and domain composables.\n');
57
121
  severeMonoliths.forEach((h, i) => {
58
122
  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
123
  });
61
124
  lines.push('');
62
125
  }
63
126
 
64
127
  if (high.length > 0) {
65
128
  lines.push('### HIGH SEVERITY VIOLATIONS');
66
- high.forEach((v, i) => {
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('');
129
+ lines.push(...formatGroupedPromptViolations(high));
72
130
  }
73
131
 
74
132
  lines.push('### STRICT EXECUTION RULES:');
@@ -79,33 +137,33 @@ export const buildGradeDPrompt = (report) => {
79
137
  return lines.join('\n');
80
138
  };
81
139
 
82
- export const buildGradeCPrompt = (report) => {
83
- const { violations, hotspots } = report;
84
- const medium = violations.filter((v) => v.severity === 'MEDIUM');
140
+ export const buildGradeCPrompt = (report, options = {}) => {
141
+ const { excludeAiSlop = false } = options;
142
+ const { violations = [], hotspots = [] } = report;
143
+ const medium = violations
144
+ .filter((v) => v.severity === 'MEDIUM')
145
+ .filter((v) => (excludeAiSlop ? !v.isAiSlop : true));
85
146
  const warningMonoliths = hotspots.filter((h) => h.lineCount >= 500 && h.lineCount < 1000);
86
147
 
87
- if (medium.length === 0 && warningMonoliths.length === 0) return '';
148
+ const hasNoMedium = medium.length === 0;
149
+ const hasNoMonoliths = warningMonoliths.length === 0;
150
+ if (hasNoMedium && hasNoMonoliths) return '';
88
151
 
89
152
  const lines = [];
90
153
  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
154
 
92
155
  if (warningMonoliths.length > 0) {
93
156
  lines.push('### WARNING MONOLITHS (500 - 999 lines of code)');
157
+ lines.push('Action: Bring file under 500 line budget by extracting helper functions, types, and child molecules.\n');
94
158
  warningMonoliths.forEach((h, i) => {
95
159
  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
160
  });
98
161
  lines.push('');
99
162
  }
100
163
 
101
164
  if (medium.length > 0) {
102
165
  lines.push('### MEDIUM SEVERITY VIOLATIONS');
103
- medium.forEach((v, i) => {
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('');
166
+ lines.push(...formatGroupedPromptViolations(medium));
109
167
  }
110
168
 
111
169
  lines.push('### STRICT EXECUTION RULES:');
@@ -116,22 +174,21 @@ export const buildGradeCPrompt = (report) => {
116
174
  return lines.join('\n');
117
175
  };
118
176
 
119
- export const buildGradeBPrompt = (report) => {
120
- const { violations } = report;
121
- const low = violations.filter((v) => v.severity === 'LOW');
177
+ export const buildGradeBPrompt = (report, options = {}) => {
178
+ const { excludeAiSlop = false } = options;
179
+ const { violations = [] } = report;
180
+ const low = violations
181
+ .filter((v) => v.severity === 'LOW')
182
+ .filter((v) => (excludeAiSlop ? !v.isAiSlop : true));
122
183
 
123
- if (low.length === 0) return '';
184
+ const hasNoLow = low.length === 0;
185
+ if (hasNoLow) return '';
124
186
 
125
187
  const lines = [];
126
188
  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
189
 
128
190
  lines.push('### LOW HYGIENE VIOLATIONS');
129
- low.forEach((v, i) => {
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('');
191
+ lines.push(...formatGroupedPromptViolations(low));
135
192
 
136
193
  lines.push('### STRICT EXECUTION RULES:');
137
194
  lines.push('1. Typography Hygiene: Replace all em dashes with standard hyphens (-) or colons (:).');
@@ -145,18 +202,14 @@ export const buildAiSlopPrompt = (report) => {
145
202
  const { violations = [] } = report;
146
203
  const slopViolations = violations.filter((v) => Boolean(v.isAiSlop));
147
204
 
148
- if (slopViolations.length === 0) return '';
205
+ const hasNoSlop = slopViolations.length === 0;
206
+ if (hasNoSlop) return '';
149
207
 
150
208
  const lines = [];
151
209
  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');
152
210
 
153
211
  lines.push('### AI SLOP & CODE AUTHENTICITY VIOLATIONS');
154
- slopViolations.forEach((v, i) => {
155
- lines.push(`${i + 1}. \`${v.filePath}:${v.line}:${v.column}\` [${v.rule}]`);
156
- lines.push(` Hazard: ${v.hazard}`);
157
- lines.push(` Directive: ${v.directive}`);
158
- });
159
- lines.push('');
212
+ lines.push(...formatGroupedPromptViolations(slopViolations));
160
213
 
161
214
  lines.push('### STRICT EXECUTION RULES:');
162
215
  lines.push('1. Conversational Residue: Completely remove leaked AI conversational preambles, assistant markdown code fences, and pleasantry comments.');
@@ -173,40 +226,44 @@ export const buildHotspotsPrompt = (report) => {
173
226
  const { hotspots = [] } = report;
174
227
  const monolithHotspots = hotspots.filter((h) => h.isMonolith || h.lineCount > 500);
175
228
 
176
- if (monolithHotspots.length === 0) return '';
229
+ const hasNoMonoliths = monolithHotspots.length === 0;
230
+ if (hasNoMonoliths) return '';
177
231
 
178
232
  const lines = [];
179
233
  lines.push('Act as a Principal Systems Architect. Surgically decompose the following monolithic hotspot files according to Chemical X Molecular Architecture Standards:\n');
180
234
 
181
235
  lines.push('### MONOLITHIC REFACTORING HOTSPOTS');
236
+ lines.push('Action: Decompose into single-responsibility crystalline molecule capsules (< 100 lines) and dedicated domain composables.\n');
182
237
  monolithHotspots.forEach((h, i) => {
183
238
  const tier = h.monolithTier ? `[${h.monolithTier} MONOLITH]` : '[MONOLITH]';
184
239
  lines.push(`${i + 1}. File: \`${h.filePath}\` (${h.lineCount} lines, ${h.violationCount} hazards) ${tier}`);
185
- lines.push(' Action: Decompose into single-responsibility crystalline molecule capsules (< 100 lines) and dedicated domain composables.');
186
240
  });
187
241
  lines.push('');
188
242
 
189
243
  lines.push('### STRICT EXECUTION RULES:');
190
- lines.push('1. Molecular Limits: Molecule capsules must strictly remain under 100 lines per file.');
191
- 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.');
192
- lines.push('3. Composable Return Contracts: Custom hooks/composables must strictly limit returns to 3 to 5 properties (State + Status + Actions).');
193
- 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.');
194
- lines.push('5. Zero breaking changes to external component APIs, route exports, or existing props.');
244
+ lines.push('1. Branch First: Change to a new branch prefixed with `chem-x/NAMEOFIMPROVEMENT` before making changes, then commit the branch and create a PR to main.');
245
+ lines.push('2. Pre-Split Pattern Discovery: Audit recurring UI layouts, state machines, and predicates across monoliths first; extract canonical shared capsules before slicing to prevent bespoke pattern duplication.');
246
+ lines.push('3. Molecular Limits: Molecule capsules must strictly remain under 100 lines per file.');
247
+ lines.push('4. Table-of-Contents Views: Top-level page views must be 10 to 20 line declarative Table of Contents assembling molecules via named slots.');
248
+ lines.push('5. Composable Return Contracts: Custom hooks/composables must strictly limit returns to 3 to 5 properties (State + Status + Actions).');
249
+ lines.push('6. Type Co-location: Co-locate granular types/*.d.ts files inside each feature capsule (< 100 lines per type file) instead of creating type monoliths.');
250
+ lines.push('7. Zero breaking changes to external component APIs, route exports, or existing props.');
195
251
 
196
252
  return lines.join('\n');
197
253
  };
198
254
 
199
255
  export const buildMasterPrompt = (report) => {
200
256
  const sections = [
201
- buildGradeFPrompt(report),
202
- buildGradeDPrompt(report),
203
- buildGradeCPrompt(report),
204
- buildGradeBPrompt(report),
257
+ buildGradeFPrompt(report, { excludeAiSlop: true }),
258
+ buildGradeDPrompt(report, { excludeAiSlop: true }),
259
+ buildGradeCPrompt(report, { excludeAiSlop: true }),
260
+ buildGradeBPrompt(report, { excludeAiSlop: true }),
205
261
  buildAiSlopPrompt(report),
206
262
  buildHotspotsPrompt(report)
207
263
  ].filter(Boolean);
208
264
 
209
- if (sections.length === 0) return '';
265
+ const hasNoSections = sections.length === 0;
266
+ if (hasNoSections) return '';
210
267
 
211
268
  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`;
212
269
  return header + sections.join('\n\n---\n\n');
@@ -1,5 +1,6 @@
1
1
  import { resolveGradeColor } from './reporter-utils.js';
2
2
  import { getAsciiGradeLines } from './reporter-ascii.js';
3
+ import { getChemicalXGradientColor, ANSI } from '../theme.js';
3
4
 
4
5
  const BANNER_ART = [
5
6
  ' ██████╗██╗ ██╗███████╗███╗ ███╗██╗ ██████╗ █████╗ ██╗ ██╗ ██╗',
@@ -18,7 +19,7 @@ export const getChemicalXAsciiBanner = (gradeOrReport = null) => {
18
19
  : gradeOrReport;
19
20
 
20
21
  const lines = [];
21
- lines.push(' \x1b[1m\x1b[37mThe Secret Sauce to \x1b[38;2;98;201;255mVibe Coding\x1b[0m');
22
+ lines.push(` ${ANSI.BOLD}${ANSI.GOLD}The Secret Sauce to Vibe Coding!${ANSI.RESET}`);
22
23
 
23
24
  const gColor = grade ? resolveGradeColor(grade) : '';
24
25
  const gradeLines = grade ? getAsciiGradeLines(grade, gColor, true) : [];
@@ -35,21 +36,8 @@ export const getChemicalXAsciiBanner = (gradeOrReport = null) => {
35
36
  continue;
36
37
  }
37
38
  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`;
39
+ const { ansi } = getChemicalXGradientColor(t);
40
+ out += `${ansi}${ANSI.BOLD}${ch}${ANSI.RESET}`;
53
41
  }
54
42
 
55
43
  if (isSideBySide && gradeLines.length > lineIdx) {
@@ -19,7 +19,8 @@ import {
19
19
  import { getReportCardAsciiLines } from './reporter-ascii.js';
20
20
  import { renderGroupedViolationsTerminal } from './reporter-grouping.js';
21
21
 
22
- export const formatGradeFSection = (report) => {
22
+ export const formatGradeFSection = (report, options = {}) => {
23
+ const { includePrompt = true } = options;
23
24
  const { violations, hotspots, pillars } = report;
24
25
  const { critical } = groupViolationsBySeverity(violations);
25
26
  const extremeMonoliths = hotspots.filter((h) => h.lineCount >= 2000);
@@ -67,16 +68,19 @@ export const formatGradeFSection = (report) => {
67
68
  }
68
69
  }
69
70
 
70
- const promptF = buildGradeFPrompt(report);
71
- if (promptF) {
72
- lines.push(formatPromptBox('🤖 AI AGENT REFACTORING PROMPT (GRADE F HAZARDS)', promptF));
71
+ if (includePrompt) {
72
+ const promptF = buildGradeFPrompt(report);
73
+ if (promptF) {
74
+ lines.push(formatPromptBox('🤖 AI AGENT REFACTORING PROMPT (GRADE F HAZARDS)', promptF));
75
+ }
73
76
  }
74
77
 
75
78
  lines.push(`${RED}======================================================================${RESET}\n`);
76
79
  return lines.join('\n');
77
80
  };
78
81
 
79
- export const formatGradeDSection = (report) => {
82
+ export const formatGradeDSection = (report, options = {}) => {
83
+ const { includePrompt = true } = options;
80
84
  const { violations, hotspots, pillars } = report;
81
85
  const { high } = groupViolationsBySeverity(violations);
82
86
  const severeMonoliths = hotspots.filter((h) => h.lineCount >= 1000 && h.lineCount < 2000);
@@ -123,16 +127,19 @@ export const formatGradeDSection = (report) => {
123
127
  }
124
128
  }
125
129
 
126
- const promptD = buildGradeDPrompt(report);
127
- if (promptD) {
128
- lines.push(formatPromptBox('🤖 AI AGENT REFACTORING PROMPT (GRADE D DEBTS)', promptD));
130
+ if (includePrompt) {
131
+ const promptD = buildGradeDPrompt(report);
132
+ if (promptD) {
133
+ lines.push(formatPromptBox('🤖 AI AGENT REFACTORING PROMPT (GRADE D DEBTS)', promptD));
134
+ }
129
135
  }
130
136
 
131
137
  lines.push(`${ORANGE}======================================================================${RESET}\n`);
132
138
  return lines.join('\n');
133
139
  };
134
140
 
135
- export const formatGradeCSection = (report) => {
141
+ export const formatGradeCSection = (report, options = {}) => {
142
+ const { includePrompt = true } = options;
136
143
  const { violations, hotspots } = report;
137
144
  const { medium } = groupViolationsBySeverity(violations);
138
145
  const warningMonoliths = hotspots.filter((h) => h.lineCount >= 500 && h.lineCount < 1000);
@@ -169,16 +176,19 @@ export const formatGradeCSection = (report) => {
169
176
  }
170
177
  }
171
178
 
172
- const promptC = buildGradeCPrompt(report);
173
- if (promptC) {
174
- lines.push(formatPromptBox('🤖 AI AGENT REFACTORING PROMPT (GRADE C DEBTS)', promptC));
179
+ if (includePrompt) {
180
+ const promptC = buildGradeCPrompt(report);
181
+ if (promptC) {
182
+ lines.push(formatPromptBox('🤖 AI AGENT REFACTORING PROMPT (GRADE C DEBTS)', promptC));
183
+ }
175
184
  }
176
185
 
177
186
  lines.push(`${CYAN}======================================================================${RESET}\n`);
178
187
  return lines.join('\n');
179
188
  };
180
189
 
181
- export const formatGradeBSection = (report) => {
190
+ export const formatGradeBSection = (report, options = {}) => {
191
+ const { includePrompt = true } = options;
182
192
  const { violations } = report;
183
193
  const { low } = groupViolationsBySeverity(violations);
184
194
  const lines = [];
@@ -202,9 +212,11 @@ export const formatGradeBSection = (report) => {
202
212
  lines.push(renderGroupedViolationsTerminal(low));
203
213
  }
204
214
 
205
- const promptB = buildGradeBPrompt(report);
206
- if (promptB) {
207
- lines.push(formatPromptBox('🤖 AI AGENT REFACTORING PROMPT (GRADE B HYGIENE)', promptB));
215
+ if (includePrompt) {
216
+ const promptB = buildGradeBPrompt(report);
217
+ if (promptB) {
218
+ lines.push(formatPromptBox('🤖 AI AGENT REFACTORING PROMPT (GRADE B HYGIENE)', promptB));
219
+ }
208
220
  }
209
221
 
210
222
  lines.push(`${YELLOW}======================================================================${RESET}\n`);
@@ -29,9 +29,15 @@ export interface RuleHazardSummary {
29
29
  readonly directories: readonly RuleDirectoryOccurrence[];
30
30
  }
31
31
 
32
+ export interface PathTreeNode {
33
+ readonly dirs: Map<string, PathTreeNode>;
34
+ readonly files: Map<string, string[]>;
35
+ }
36
+
32
37
  export declare function resolveDirectory(filePath?: string): string;
33
38
  export declare function groupViolationsByDirectory(violations?: readonly HazardViolation[]): readonly DirectoryHazardSummary[];
34
39
  export declare function groupViolationsByRule(violations?: readonly HazardViolation[]): readonly RuleHazardSummary[];
40
+ export declare function buildPathTree(violations?: readonly HazardViolation[]): PathTreeNode;
35
41
  export declare function formatCompactLocations(violations: readonly HazardViolation[], maxShown?: number): string;
36
42
  export declare function renderGroupedViolationsTerminal(violations: readonly HazardViolation[]): string;
37
43
  export declare function formatDirectoryDistributionSection(report: AuditReport, themeColor?: string | null): string;
@@ -157,6 +157,34 @@ const resolveSeverityColor = (severity) => {
157
157
  return DIM;
158
158
  };
159
159
 
160
+ export const buildPathTree = (violations = []) => {
161
+ const root = { dirs: new Map(), files: new Map() };
162
+
163
+ for (const v of violations) {
164
+ const rawPath = v.filePath || '';
165
+ const normalized = rawPath.replace(/\\/g, '/').replace(/^\.\//, '');
166
+ const segments = normalized.split('/');
167
+ const fileName = segments.pop();
168
+
169
+ let current = root;
170
+ for (const seg of segments) {
171
+ const segName = seg.endsWith('/') ? seg : `${seg}/`;
172
+ if (!current.dirs.has(segName)) {
173
+ current.dirs.set(segName, { dirs: new Map(), files: new Map() });
174
+ }
175
+ current = current.dirs.get(segName);
176
+ }
177
+
178
+ if (!current.files.has(fileName)) {
179
+ current.files.set(fileName, []);
180
+ }
181
+ const loc = v.column ? `${v.line}:${v.column}` : `${v.line}`;
182
+ current.files.get(fileName).push(loc);
183
+ }
184
+
185
+ return root;
186
+ };
187
+
160
188
  export const formatCompactLocations = (violations, maxShown = 4) => {
161
189
  const formatLocationItem = (v) => {
162
190
  const base = path.basename(v.filePath);
@@ -186,7 +214,8 @@ export const renderGroupedViolationsTerminal = (violations) => {
186
214
 
187
215
  if (isSingleOccurrence) {
188
216
  const v = rg.violations[0];
189
- lines.push(` ${sevColor}[#${idx + 1} ${rg.severity}]${RESET} [${rg.rule}] ${YELLOW}${v.filePath}:${v.line}:${v.column}${RESET}`);
217
+ const colStr = v.column ? `:${v.column}` : '';
218
+ lines.push(` ${sevColor}[#${idx + 1} ${rg.severity}]${RESET} [${rg.rule}] ${YELLOW}${v.filePath}:${v.line}${colStr}${RESET}`);
190
219
  lines.push(` Hazard: ${rg.hazard}`);
191
220
  lines.push(` Directive: ${CYAN}${rg.directive}${RESET}\n`);
192
221
  return;
@@ -199,10 +228,24 @@ export const renderGroupedViolationsTerminal = (violations) => {
199
228
  lines.push(` Directive: ${CYAN}${rg.directive}${RESET}`);
200
229
  lines.push(` Locations:`);
201
230
 
202
- for (const d of rg.directories) {
203
- const locs = formatCompactLocations(d.violations, 4);
204
- lines.push(` 📁 ${d.directory} (${d.count}): ${locs}`);
205
- }
231
+ const tree = buildPathTree(rg.violations);
232
+ const renderTerminalTree = (node, depth = 0) => {
233
+ const indent = ' ' + ' '.repeat(depth);
234
+
235
+ const sortedDirs = Array.from(node.dirs.entries()).sort((a, b) => a[0].localeCompare(b[0]));
236
+ for (const [dirName, childNode] of sortedDirs) {
237
+ lines.push(`${indent}📁 ${BOLD}${dirName}${RESET}`);
238
+ renderTerminalTree(childNode, depth + 1);
239
+ }
240
+
241
+ const sortedFiles = Array.from(node.files.entries()).sort((a, b) => a[0].localeCompare(b[0]));
242
+ for (const [fileName, locs] of sortedFiles) {
243
+ const uniqueLocs = Array.from(new Set(locs)).join(', ');
244
+ lines.push(`${indent}- ${YELLOW}${fileName}:${uniqueLocs}${RESET}`);
245
+ }
246
+ };
247
+
248
+ renderTerminalTree(tree, 0);
206
249
  lines.push('');
207
250
  });
208
251
 
@@ -4,6 +4,9 @@ import {
4
4
  resolveHealthHearts,
5
5
  resolveMarkdownStatusIcon,
6
6
  resolveMarkdownMonolithText,
7
+ formatPillarReactionBadgesMarkdown,
8
+ formatPillarShieldBadges,
9
+ resolveBadgeColor,
7
10
  PILLAR_EMOJIS,
8
11
  NUMBER_EMOJIS
9
12
  } from './reporter-utils.js';
@@ -11,14 +14,30 @@ import {
11
14
  formatDirectoryRollupMarkdown,
12
15
  renderGroupedViolationsMarkdown
13
16
  } from './reporter-grouping-markdown.js';
17
+ import { formatRoadmapMarkdown } from './roadmap.js';
14
18
 
15
19
  export const generateMarkdownReport = (report) => {
16
20
  const { metrics, health, pillars, contextAnalysis, hotspots, violations, aiSlop } = report;
17
21
  const { critical, high, medium, low } = groupViolationsBySeverity(violations);
18
22
  const lines = [];
19
23
 
24
+ const badgeColor = resolveBadgeColor(health.score);
25
+ const encodedGrade = encodeURIComponent(`${health.score}/100 (${health.grade})`);
26
+ const slopScore = aiSlop?.score ?? 100;
27
+ const slopGrade = aiSlop?.grade ?? 'A+';
28
+ const slopLabel = aiSlop?.label ?? 'Pure Artisanal';
29
+ const slopBadgeColor = resolveBadgeColor(slopScore);
30
+ const encodedSlop = encodeURIComponent(`${slopScore}/100 (${slopGrade})`);
31
+
20
32
  lines.push('# Chemical X Protocol: Architectural Audit Report');
21
33
  lines.push('');
34
+ lines.push(`[![Chemical X Protocol](https://img.shields.io/badge/Chemical%20X-Architecture%20Audit-62c9ff?style=for-the-badge)](https://chemicalx.xophz.com) [![Chemical X MHI](https://img.shields.io/badge/Chemical%20X%20MHI-${encodedGrade}-${badgeColor}?style=for-the-badge)](https://chemicalx.xophz.com) [![AI Slop Index](https://img.shields.io/badge/AI%20Slop%20Index-${encodedSlop}-${slopBadgeColor}?style=for-the-badge)](https://chemicalx.xophz.com)`);
35
+ lines.push('');
36
+ const pillarShields = formatPillarShieldBadges(pillars);
37
+ if (pillarShields) {
38
+ lines.push(pillarShields);
39
+ lines.push('');
40
+ }
22
41
  lines.push('> *Comprehensive static analysis report enforcing Chemical X Molecular Architecture standards.*');
23
42
  lines.push('');
24
43
  lines.push('## 1. Executive Summary & Scorecard');
@@ -28,9 +47,6 @@ export const generateMarkdownReport = (report) => {
28
47
  const hearts = resolveHealthHearts(health?.grade, health?.score, false);
29
48
  lines.push(`| **Life / Health Meter** | ${hearts} (Grade **${health.grade}**) | ${health.score} / 100 (${health.label}) |`);
30
49
  lines.push(`| **Molecular Health Index** | **${health.score} / 100** | Grade: **${health.grade}** (${health.label}) |`);
31
- const slopScore = aiSlop?.score ?? 100;
32
- const slopGrade = aiSlop?.grade ?? 'A+';
33
- const slopLabel = aiSlop?.label ?? 'Pure Artisanal';
34
50
  lines.push(`| **AI Slop Index (ASI)** | **${slopScore} / 100** | Grade: **${slopGrade}** (${slopLabel}) |`);
35
51
  lines.push(`| **Scanned Files** | ${metrics.scannedFiles} source files | Verified |`);
36
52
  lines.push(`| **Total Lines of Code** | ${metrics.totalLoc} lines of code | Avg ${metrics.avgLoc} lines/file |`);
@@ -86,19 +102,25 @@ export const generateMarkdownReport = (report) => {
86
102
  lines.push(formatDirectoryRollupMarkdown(violations));
87
103
 
88
104
  if (critical.length > 0) {
89
- lines.push('### Critical Hazards (Immediate Action Required)');
105
+ lines.push('### Grade F: Critical Hazards & Extreme Monoliths (Immediate Action Required)');
90
106
  lines.push('');
91
107
  lines.push(renderGroupedViolationsMarkdown(critical, { showSeverity: false }));
92
108
  }
93
109
 
94
- if (high.length > 0 || medium.length > 0) {
95
- lines.push('### High & Medium Hazards (Architecture Debts)');
110
+ if (high.length > 0) {
111
+ lines.push('### Grade D: High Severity Debts & Severe Monoliths');
96
112
  lines.push('');
97
- lines.push(renderGroupedViolationsMarkdown([...high, ...medium], { showSeverity: true }));
113
+ lines.push(renderGroupedViolationsMarkdown(high, { showSeverity: false }));
114
+ }
115
+
116
+ if (medium.length > 0) {
117
+ lines.push('### Grade C: Medium Severity Debts & Monolithic Drift');
118
+ lines.push('');
119
+ lines.push(renderGroupedViolationsMarkdown(medium, { showSeverity: false }));
98
120
  }
99
121
 
100
122
  if (low.length > 0) {
101
- lines.push('### Low & Hygiene Issues (Typography & Logging)');
123
+ lines.push('### Grade B: Low Severity Hygiene & Minor Debts');
102
124
  lines.push('');
103
125
  lines.push(renderGroupedViolationsMarkdown(low, { showSeverity: false }));
104
126
  }
@@ -122,14 +144,7 @@ export const generateMarkdownReport = (report) => {
122
144
 
123
145
  lines.push('---');
124
146
  lines.push('');
125
- lines.push('## 6. Remediation Roadmap');
126
- lines.push('');
127
- lines.push('1. **Decompose Monoliths**: Break down any file exceeding 500 lines into single-responsibility capsules.');
128
- lines.push('2. **Cap Molecule Size**: Ensure all molecule components (`m-*`) remain strictly under 100 lines.');
129
- lines.push('3. **Two-Stage Boolean Logic**: Replace complex multi-clause expressions with atomic boolean variables.');
130
- lines.push('4. **Lifecycle-Safe Timers**: Migrate raw `setInterval` and `setTimeout` calls to self-cleaning composables.');
131
- lines.push('5. **Purge AI Slop**: Remove conversational residue, eliminate echo comments, and inline single-use passthrough assignments.');
132
- lines.push('');
147
+ lines.push(formatRoadmapMarkdown(report));
133
148
 
134
149
  const masterPrompt = buildMasterPrompt(report);
135
150
  if (masterPrompt) {