@chemx/starter-kit 26.9.11-362 → 26.9.11-481

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.
@@ -40,6 +40,12 @@ export interface TransformationDelta {
40
40
  readonly totalDelta: number;
41
41
  readonly monolithDelta: number;
42
42
  readonly tokensDelta: number;
43
+ readonly costPassBefore?: number;
44
+ readonly costPassAfter?: number;
45
+ readonly costPassDelta?: number;
46
+ readonly monthlyTaxBefore?: number;
47
+ readonly monthlyTaxAfter?: number;
48
+ readonly monthlyTaxDelta?: number;
43
49
  readonly pillarDeltas: Record<string, PillarDelta>;
44
50
  readonly isImproved: boolean;
45
51
  }
@@ -88,7 +88,12 @@ export const createSnapshotFromReport = (report) => {
88
88
  estimatedTokens: contextAnalysis.estimatedTokens || 0,
89
89
  estimatedExcessTokens: contextAnalysis.estimatedExcessTokens || 0,
90
90
  potentialSavingsPct: contextAnalysis.potentialSavingsPct || 0,
91
- riskLevel: contextAnalysis.riskLevel || 'LOW'
91
+ riskLevel: contextAnalysis.riskLevel || 'LOW',
92
+ pricingModel: contextAnalysis.pricingModel || 'Frontier Blended ($3.00/1M)',
93
+ costPerMillion: contextAnalysis.costPerMillion !== undefined ? contextAnalysis.costPerMillion : 3.0,
94
+ excessCostPerPass: contextAnalysis.excessCostPerPass !== undefined ? contextAnalysis.excessCostPerPass : 0,
95
+ weeklyWastePerDev: contextAnalysis.weeklyWastePerDev !== undefined ? contextAnalysis.weeklyWastePerDev : 0,
96
+ monthlyWastePerDev: contextAnalysis.monthlyWastePerDev !== undefined ? contextAnalysis.monthlyWastePerDev : 0
92
97
  },
93
98
  pillars: pillarSummaries
94
99
  };
@@ -196,6 +201,28 @@ export const calculateTransformationDelta = (beforeSnapshot, afterSnapshot) => {
196
201
  const tokensAfter = afterSnapshot.tokens.estimatedExcessTokens;
197
202
  const tokensDelta = tokensAfter - tokensBefore;
198
203
 
204
+ const costPerMillion = afterSnapshot.tokens?.costPerMillion || beforeSnapshot.tokens?.costPerMillion || 3.0;
205
+
206
+ const resolveCostPass = (tokensObj) => {
207
+ if (tokensObj?.excessCostPerPass !== undefined) return tokensObj.excessCostPerPass;
208
+ const excess = tokensObj?.estimatedExcessTokens || 0;
209
+ return Number(((excess / 1000000) * costPerMillion).toFixed(3));
210
+ };
211
+
212
+ const resolveMonthlyTax = (tokensObj) => {
213
+ if (tokensObj?.monthlyWastePerDev !== undefined) return tokensObj.monthlyWastePerDev;
214
+ const costPass = resolveCostPass(tokensObj);
215
+ return Number((costPass * 20 * 5 * 4).toFixed(2));
216
+ };
217
+
218
+ const costPassBefore = resolveCostPass(beforeSnapshot.tokens);
219
+ const costPassAfter = resolveCostPass(afterSnapshot.tokens);
220
+ const costPassDelta = Number((costPassAfter - costPassBefore).toFixed(3));
221
+
222
+ const monthlyTaxBefore = resolveMonthlyTax(beforeSnapshot.tokens);
223
+ const monthlyTaxAfter = resolveMonthlyTax(afterSnapshot.tokens);
224
+ const monthlyTaxDelta = Number((monthlyTaxAfter - monthlyTaxBefore).toFixed(2));
225
+
199
226
  const pillarDeltas = {};
200
227
  const allPillars = new Set([
201
228
  ...Object.keys(beforeSnapshot.pillars || {}),
@@ -220,6 +247,12 @@ export const calculateTransformationDelta = (beforeSnapshot, afterSnapshot) => {
220
247
  totalDelta,
221
248
  monolithDelta,
222
249
  tokensDelta,
250
+ costPassBefore,
251
+ costPassAfter,
252
+ costPassDelta,
253
+ monthlyTaxBefore,
254
+ monthlyTaxAfter,
255
+ monthlyTaxDelta,
223
256
  pillarDeltas,
224
257
  isImproved: scoreDelta > 0 || critDelta < 0 || totalDelta < 0
225
258
  };
@@ -237,6 +270,14 @@ export const formatTransformationTerminal = (beforeSnapshot, afterSnapshot) => {
237
270
  return `${color}${BOLD}${sign}${RESET}`;
238
271
  };
239
272
 
273
+ const formatDeltaCurrency = (val, perUnit = '') => {
274
+ if (val === 0) return `${DIM}0 (No change)${RESET}`;
275
+ const isGood = val < 0;
276
+ const sign = val > 0 ? `+$${val.toFixed(2)}` : `-$${Math.abs(val).toFixed(2)}`;
277
+ const color = isGood ? GREEN : RED;
278
+ return `${color}${BOLD}${sign}${perUnit}${RESET}`;
279
+ };
280
+
240
281
  lines.push('');
241
282
  lines.push(`${CYAN}======================================================================${RESET}`);
242
283
  lines.push(`${BOLD}${CYAN} ARCHITECTURAL TRANSFORMATION : BEFORE & AFTER PROGRESSION${RESET}`);
@@ -252,31 +293,35 @@ export const formatTransformationTerminal = (beforeSnapshot, afterSnapshot) => {
252
293
  lines.push('');
253
294
 
254
295
  lines.push(`${BOLD} METRIC COMPARISON TABLE${RESET}`);
255
- lines.push(` ------------------------------------------------------------------`);
256
- lines.push(` ${'Metric'.padEnd(26)} ${'Before'.padEnd(16)} ${'After'.padEnd(16)} Delta`);
257
- lines.push(` ------------------------------------------------------------------`);
296
+ lines.push(` ----------------------------------------------------------------------------`);
297
+ lines.push(` ${'Metric'.padEnd(40)} ${'Before'.padEnd(16)} ${'After'.padEnd(16)} Delta`);
298
+ lines.push(` ----------------------------------------------------------------------------`);
258
299
 
259
300
  const scoreBeforeStr = `${beforeSnapshot.health.score} (${beforeSnapshot.health.grade})`;
260
301
  const scoreAfterStr = `${afterSnapshot.health.score} (${afterSnapshot.health.grade})`;
261
- lines.push(` ${'Molecular Health (MHI)'.padEnd(26)} ${scoreBeforeStr.padEnd(16)} ${scoreAfterStr.padEnd(16)} ${formatDeltaNumber(delta.scoreDelta)}`);
302
+ lines.push(` ${'Molecular Health (MHI)'.padEnd(40)} ${scoreBeforeStr.padEnd(16)} ${scoreAfterStr.padEnd(16)} ${formatDeltaNumber(delta.scoreDelta)}`);
262
303
 
263
304
  const critBeforeStr = `${beforeSnapshot.violations.critical}`;
264
305
  const critAfterStr = `${afterSnapshot.violations.critical}`;
265
- lines.push(` ${'Critical Hazards'.padEnd(26)} ${critBeforeStr.padEnd(16)} ${critAfterStr.padEnd(16)} ${formatDeltaNumber(delta.critDelta, true)}`);
306
+ lines.push(` ${'Critical Hazards'.padEnd(40)} ${critBeforeStr.padEnd(16)} ${critAfterStr.padEnd(16)} ${formatDeltaNumber(delta.critDelta, true)}`);
266
307
 
267
308
  const totalBeforeStr = `${beforeSnapshot.violations.total}`;
268
309
  const totalAfterStr = `${afterSnapshot.violations.total}`;
269
- lines.push(` ${'Total Violations'.padEnd(26)} ${totalBeforeStr.padEnd(16)} ${totalAfterStr.padEnd(16)} ${formatDeltaNumber(delta.totalDelta, true)}`);
310
+ lines.push(` ${'Total Violations'.padEnd(40)} ${totalBeforeStr.padEnd(16)} ${totalAfterStr.padEnd(16)} ${formatDeltaNumber(delta.totalDelta, true)}`);
270
311
 
271
312
  const monoBeforeStr = `${beforeSnapshot.monoliths.total}`;
272
313
  const monoAfterStr = `${afterSnapshot.monoliths.total}`;
273
- lines.push(` ${'Monolith Files (>500 LOC)'.padEnd(26)} ${monoBeforeStr.padEnd(16)} ${monoAfterStr.padEnd(16)} ${formatDeltaNumber(delta.monolithDelta, true)}`);
314
+ lines.push(` ${'Monolith Files (>500 lines of code)'.padEnd(40)} ${monoBeforeStr.padEnd(16)} ${monoAfterStr.padEnd(16)} ${formatDeltaNumber(delta.monolithDelta, true)}`);
274
315
 
275
316
  const excessBeforeStr = `${beforeSnapshot.tokens.estimatedExcessTokens.toLocaleString()} tok`;
276
317
  const excessAfterStr = `${afterSnapshot.tokens.estimatedExcessTokens.toLocaleString()} tok`;
277
- lines.push(` ${'Excess Token Burn'.padEnd(26)} ${excessBeforeStr.padEnd(16)} ${excessAfterStr.padEnd(16)} ${formatDeltaNumber(delta.tokensDelta, true)}`);
318
+ lines.push(` ${'Excess Token Burn'.padEnd(40)} ${excessBeforeStr.padEnd(16)} ${excessAfterStr.padEnd(16)} ${formatDeltaNumber(delta.tokensDelta, true)}`);
319
+
320
+ const taxBeforeStr = `$${delta.monthlyTaxBefore.toFixed(2)}/mo`;
321
+ const taxAfterStr = `$${delta.monthlyTaxAfter.toFixed(2)}/mo`;
322
+ lines.push(` ${'Dev Context Tax (Monthly)'.padEnd(40)} ${taxBeforeStr.padEnd(16)} ${taxAfterStr.padEnd(16)} ${formatDeltaCurrency(delta.monthlyTaxDelta, '/mo')}`);
278
323
 
279
- lines.push(` ------------------------------------------------------------------`);
324
+ lines.push(` ----------------------------------------------------------------------------`);
280
325
  lines.push('');
281
326
 
282
327
  const resolvePillarDeltaArrow = (pDelta) => {
@@ -290,12 +335,12 @@ export const formatTransformationTerminal = (beforeSnapshot, afterSnapshot) => {
290
335
  };
291
336
 
292
337
  lines.push(`${BOLD} 7-PILLAR PROGRESSION${RESET}`);
293
- lines.push(` ------------------------------------------------------------------`);
338
+ lines.push(` ----------------------------------------------------------------------------`);
294
339
  for (const [pillar, pDelta] of Object.entries(delta.pillarDeltas)) {
295
340
  const arrow = resolvePillarDeltaArrow(pDelta);
296
- lines.push(` ${pillar.padEnd(28)} ${pDelta.beforeStatus.padEnd(10)} -> ${pDelta.afterStatus.padEnd(10)} ${arrow}`);
341
+ lines.push(` ${pillar.padEnd(40)} ${pDelta.beforeStatus.padEnd(8)} -> ${pDelta.afterStatus.padEnd(8)} ${arrow}`);
297
342
  }
298
- lines.push(` ------------------------------------------------------------------`);
343
+ lines.push(` ----------------------------------------------------------------------------`);
299
344
  lines.push('');
300
345
 
301
346
  if (delta.isImproved) {
@@ -325,7 +370,7 @@ export const formatHistoryTimelineTerminal = (history) => {
325
370
  }
326
371
 
327
372
  lines.push(` ${'#'.padEnd(4)} ${'Date/Time'.padEnd(22)} ${'Score'.padEnd(12)} ${'Grade'.padEnd(10)} ${'Monoliths'.padEnd(12)} Hazards`);
328
- lines.push(` ------------------------------------------------------------------`);
373
+ lines.push(` ----------------------------------------------------------------------------`);
329
374
 
330
375
  const resolveScoreGradeColor = (score) => {
331
376
  if (score >= 90) return GREEN;
@@ -346,7 +391,7 @@ export const formatHistoryTimelineTerminal = (history) => {
346
391
 
347
392
  history.forEach(renderTimelineRow);
348
393
 
349
- lines.push(` ------------------------------------------------------------------`);
394
+ lines.push(` ----------------------------------------------------------------------------`);
350
395
  lines.push('');
351
396
  return lines.join('\n');
352
397
  };
@@ -14,7 +14,7 @@ export const buildGradeFPrompt = (report) => {
14
14
  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
15
 
16
16
  if (extremeMonoliths.length > 0) {
17
- lines.push('### EXTREME MONOLITHS (>= 2,000 LOC) : MONOLITH DECOMPOSITION');
17
+ lines.push('### EXTREME MONOLITHS (>= 2,000 lines of code) : MONOLITH DECOMPOSITION');
18
18
  extremeMonoliths.forEach((h, i) => {
19
19
  lines.push(`${i + 1}. File: \`${h.filePath}\` (${h.lineCount} lines)`);
20
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.');
@@ -53,10 +53,10 @@ export const buildGradeDPrompt = (report) => {
53
53
  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
54
 
55
55
  if (severeMonoliths.length > 0) {
56
- lines.push('### SEVERE MONOLITHS (1,000 - 1,999 LOC)');
56
+ lines.push('### SEVERE MONOLITHS (1,000 - 1,999 lines of code)');
57
57
  severeMonoliths.forEach((h, i) => {
58
58
  lines.push(`${i + 1}. File: \`${h.filePath}\` (${h.lineCount} lines)`);
59
- lines.push(' Action: Extract sub-features into isolated molecule capsules (< 100 LOC) and domain composables.');
59
+ lines.push(' Action: Extract sub-features into isolated molecule capsules (< 100 lines of code) and domain composables.');
60
60
  });
61
61
  lines.push('');
62
62
  }
@@ -90,7 +90,7 @@ export const buildGradeCPrompt = (report) => {
90
90
  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
91
 
92
92
  if (warningMonoliths.length > 0) {
93
- lines.push('### WARNING MONOLITHS (500 - 999 LOC)');
93
+ lines.push('### WARNING MONOLITHS (500 - 999 lines of code)');
94
94
  warningMonoliths.forEach((h, i) => {
95
95
  lines.push(`${i + 1}. File: \`${h.filePath}\` (${h.lineCount} lines)`);
96
96
  lines.push(' Action: Bring file under 500 line budget by extracting helper functions, types, and child molecules.');
@@ -111,7 +111,7 @@ export const buildGradeCPrompt = (report) => {
111
111
  lines.push('### STRICT EXECUTION RULES:');
112
112
  lines.push('1. Zero raw inline styles: Replace style={{...}} with atom props, SCSS mixins (@include glass), or scoped BEM classes.');
113
113
  lines.push('2. Extract anonymous inline callbacks into named functions before passing as props.');
114
- lines.push('3. Co-locate granular types (*.d.ts) inside feature capsules (< 100 LOC). Avoid type monoliths.');
114
+ lines.push('3. Co-locate granular types (*.d.ts) inside feature capsules (< 100 lines of code). Avoid type monoliths.');
115
115
 
116
116
  return lines.join('\n');
117
117
  };
@@ -0,0 +1,4 @@
1
+ export declare const REPORT_CARD_ASCII: readonly string[];
2
+ export declare function getReportCardAsciiLines(color?: string): readonly string[];
3
+ export declare function getAsciiGradeLines(grade?: string, color?: string, withEquals?: boolean): readonly string[];
4
+ export declare function formatAsciiGrade(grade?: string, color?: string, indent?: string, withEquals?: boolean): string;
@@ -0,0 +1,99 @@
1
+ import { BOLD, RESET } from './reporter-utils.js';
2
+
3
+ const EQUALS_GLYPH = [
4
+ ' ',
5
+ '███████╗',
6
+ '╚══════╝',
7
+ '███████╗',
8
+ '╚══════╝',
9
+ ' '
10
+ ];
11
+
12
+ const LETTER_GLYPHS = {
13
+ A: [
14
+ ' █████╗ ',
15
+ '██╔══██╗',
16
+ '███████║',
17
+ '██╔══██║',
18
+ '██║ ██║',
19
+ '╚═╝ ╚═╝'
20
+ ],
21
+ B: [
22
+ '██████╗ ',
23
+ '██╔══██╗',
24
+ '██████╔╝',
25
+ '██╔══██╗',
26
+ '██████╔╝',
27
+ '╚═════╝ '
28
+ ],
29
+ C: [
30
+ ' ██████╗',
31
+ '██╔════╝',
32
+ '██║ ',
33
+ '██║ ',
34
+ '╚██████╗',
35
+ ' ╚═════╝'
36
+ ],
37
+ D: [
38
+ '██████╗ ',
39
+ '██╔══██╗',
40
+ '██║ ██║',
41
+ '██║ ██║',
42
+ '██████╔╝',
43
+ '╚═════╝ '
44
+ ],
45
+ F: [
46
+ '███████╗',
47
+ '██╔════╝',
48
+ '█████╗ ',
49
+ '██╔══╝ ',
50
+ '██║ ',
51
+ '╚═╝ '
52
+ ],
53
+ PLUS: [
54
+ ' ',
55
+ ' ██╗ ',
56
+ '██████╗',
57
+ '╚═██╔═╝',
58
+ ' ╚═╝ ',
59
+ ' '
60
+ ]
61
+ };
62
+
63
+ export const getAsciiGradeLines = (grade = 'A', color = '', withEquals = false) => {
64
+ const normGrade = String(grade || 'A').trim().toUpperCase();
65
+ const letter = normGrade.replace('+', '');
66
+ const hasPlus = normGrade.includes('+');
67
+ const glyph = LETTER_GLYPHS[letter] || LETTER_GLYPHS.A;
68
+
69
+ const lines = [];
70
+ for (let i = 0; i < 6; i++) {
71
+ let letterPart = glyph[i];
72
+ if (hasPlus) {
73
+ letterPart += ` ${LETTER_GLYPHS.PLUS[i]}`;
74
+ }
75
+ const coloredLetter = color ? `${color}${BOLD}${letterPart}${RESET}` : letterPart;
76
+
77
+ if (withEquals) {
78
+ const eqPart = `${BOLD}\x1b[37m${EQUALS_GLYPH[i]}${RESET}`;
79
+ lines.push(`${eqPart} ${coloredLetter}`);
80
+ } else {
81
+ lines.push(coloredLetter);
82
+ }
83
+ }
84
+ return lines;
85
+ };
86
+
87
+ export const formatAsciiGrade = (grade = 'A', color = '', indent = ' ', withEquals = false) =>
88
+ getAsciiGradeLines(grade, color, withEquals).map((l) => `${indent}${l}`).join('\n');
89
+
90
+ export const REPORT_CARD_ASCII = [
91
+ '▗▄▄▖ ▗▄▄▄▖▗▄▄▖ ▗▄▖ ▗▄▄▖▗▄▄▄▖ ▗▄▄▖ ▗▄▖ ▗▄▄▖ ▗▄▄▄ ',
92
+ '▐▌ ▐▌▐▌ ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌ █ ▐▌ ▐▌ ▐▌▐▌ ▐▌▐▌ █',
93
+ '▐▛▀▚▖▐▛▀▀▘▐▛▀▘ ▐▌ ▐▌▐▛▀▚▖ █ ▐▌ ▐▛▀▜▌▐▛▀▚▖▐▌ █',
94
+ '▐▌ ▐▌▐▙▄▄▖▐▌ ▝▚▄▞▘▐▌ ▐▌ █ ▝▚▄▄▖▐▌ ▐▌▐▌ ▐▌▐▙▄▄▀'
95
+ ];
96
+
97
+ export const getReportCardAsciiLines = (color = '') =>
98
+ REPORT_CARD_ASCII.map((row) => (color ? `${color}${BOLD}${row}${RESET}` : row));
99
+
@@ -16,6 +16,7 @@ import {
16
16
  RESET,
17
17
  groupViolationsBySeverity
18
18
  } from './reporter-utils.js';
19
+ import { getReportCardAsciiLines } from './reporter-ascii.js';
19
20
 
20
21
  export const formatGradeFSection = (report) => {
21
22
  const { violations, hotspots, pillars } = report;
@@ -25,9 +26,12 @@ export const formatGradeFSection = (report) => {
25
26
  const lines = [];
26
27
 
27
28
  lines.push('');
29
+ for (const rcLine of getReportCardAsciiLines(RED)) {
30
+ lines.push(` ${rcLine}`);
31
+ }
28
32
  lines.push(`${RED}======================================================================${RESET}`);
29
33
  lines.push(`${BOLD}${RED} GRADE F : CRITICAL ARCHITECTURAL HAZARDS & EXTREME MONOLITHS${RESET}`);
30
- lines.push(`${DIM} Immediate action required: >2,000 LOC monoliths, render hacks, mock data${RESET}`);
34
+ lines.push(`${DIM} Immediate action required: >2,000 lines of code monoliths, render hacks, mock data${RESET}`);
31
35
  lines.push(`${RED}======================================================================${RESET}`);
32
36
  lines.push(` Critical Violations: ${critical.length > 0 ? `${RED}${BOLD}${critical.length}${RESET}` : `${GREEN}0${RESET}`}`);
33
37
  lines.push(` Extreme Monoliths: ${extremeMonoliths.length > 0 ? `${RED}${BOLD}${extremeMonoliths.length}${RESET}` : `${GREEN}0${RESET}`}`);
@@ -37,7 +41,7 @@ export const formatGradeFSection = (report) => {
37
41
  const totalGradeFItems = critical.length + extremeMonoliths.length + failedPillars.length;
38
42
  if (totalGradeFItems === 0) {
39
43
  lines.push(`\n ${GREEN}✔ Outstanding! Zero Grade F hazards detected.${RESET}`);
40
- lines.push(` ${DIM}Codebase is free of extreme monoliths (>2k LOC) and critical violations.${RESET}`);
44
+ lines.push(` ${DIM}Codebase is free of extreme monoliths (>2,000 lines of code) and critical violations.${RESET}`);
41
45
  } else {
42
46
  if (critical.length > 0) {
43
47
  lines.push(`\n ${BOLD}${RED}🚨 CRITICAL AST VIOLATIONS (${critical.length}):${RESET}`);
@@ -83,9 +87,12 @@ export const formatGradeDSection = (report) => {
83
87
  const lines = [];
84
88
 
85
89
  lines.push('');
90
+ for (const rcLine of getReportCardAsciiLines(ORANGE)) {
91
+ lines.push(` ${rcLine}`);
92
+ }
86
93
  lines.push(`${ORANGE}======================================================================${RESET}`);
87
94
  lines.push(`${BOLD}${ORANGE} GRADE D : HIGH SEVERITY DEBTS & SEVERE MONOLITHS${RESET}`);
88
- lines.push(`${DIM} Refactoring priorities: 1,000 to 1,999 LOC files and hook saturation > 5${RESET}`);
95
+ lines.push(`${DIM} Refactoring priorities: 1,000 to 1,999 lines of code files and hook saturation > 5${RESET}`);
89
96
  lines.push(`${ORANGE}======================================================================${RESET}`);
90
97
  lines.push(` High Severity Debts: ${high.length > 0 ? `${ORANGE}${BOLD}${high.length}${RESET}` : `${GREEN}0${RESET}`}`);
91
98
  lines.push(` Severe Monoliths: ${severeMonoliths.length > 0 ? `${ORANGE}${BOLD}${severeMonoliths.length}${RESET}` : `${GREEN}0${RESET}`}`);
@@ -95,7 +102,7 @@ export const formatGradeDSection = (report) => {
95
102
  const totalGradeDItems = high.length + severeMonoliths.length + warnPillars.length;
96
103
  if (totalGradeDItems === 0) {
97
104
  lines.push(`\n ${GREEN}✔ Zero Grade D debts detected.${RESET}`);
98
- lines.push(` ${DIM}No severe monoliths (1k-2k LOC) or saturated hook anti-patterns.${RESET}`);
105
+ lines.push(` ${DIM}No severe monoliths (1,000-1,999 lines of code) or saturated hook anti-patterns.${RESET}`);
99
106
  } else {
100
107
  if (high.length > 0) {
101
108
  lines.push(`\n ${BOLD}${ORANGE}⚠️ HIGH SEVERITY VIOLATIONS (${high.length}):${RESET}`);
@@ -139,9 +146,12 @@ export const formatGradeCSection = (report) => {
139
146
  const lines = [];
140
147
 
141
148
  lines.push('');
149
+ for (const rcLine of getReportCardAsciiLines(CYAN)) {
150
+ lines.push(` ${rcLine}`);
151
+ }
142
152
  lines.push(`${CYAN}======================================================================${RESET}`);
143
153
  lines.push(`${BOLD}${CYAN} GRADE C : MEDIUM SEVERITY DEBTS & MONOLITHIC DRIFT${RESET}`);
144
- lines.push(`${DIM} Architecture debts: 500 to 999 LOC files and raw inline style attributes${RESET}`);
154
+ lines.push(`${DIM} Architecture debts: 500 to 999 lines of code files and raw inline style attributes${RESET}`);
145
155
  lines.push(`${CYAN}======================================================================${RESET}`);
146
156
  lines.push(` Medium Debts: ${medium.length > 0 ? `${YELLOW}${BOLD}${medium.length}${RESET}` : `${GREEN}0${RESET}`}`);
147
157
  lines.push(` Warning Monoliths: ${warningMonoliths.length > 0 ? `${YELLOW}${BOLD}${warningMonoliths.length}${RESET}` : `${GREEN}0${RESET}`}`);
@@ -185,6 +195,9 @@ export const formatGradeBSection = (report) => {
185
195
  const lines = [];
186
196
 
187
197
  lines.push('');
198
+ for (const rcLine of getReportCardAsciiLines(YELLOW)) {
199
+ lines.push(` ${rcLine}`);
200
+ }
188
201
  lines.push(`${YELLOW}======================================================================${RESET}`);
189
202
  lines.push(`${BOLD}${YELLOW} GRADE B : LOW SEVERITY HYGIENE & MINOR CODE SMELLS${RESET}`);
190
203
  lines.push(`${DIM} Hygiene & polish: Em dash typography leaks and unguarded console logging${RESET}`);
@@ -219,13 +232,16 @@ export const formatGradeASection = (report) => {
219
232
  const lines = [];
220
233
 
221
234
  lines.push('');
235
+ for (const rcLine of getReportCardAsciiLines(GREEN)) {
236
+ lines.push(` ${rcLine}`);
237
+ }
222
238
  lines.push(`${GREEN}======================================================================${RESET}`);
223
239
  lines.push(`${BOLD}${GREEN} GRADE A : COMPLIANT ARCHITECTURE & PASSING PILLARS${RESET}`);
224
240
  lines.push(`${DIM} Molecular Architecture verified clean areas and crystalline modules${RESET}`);
225
241
  lines.push(`${GREEN}======================================================================${RESET}`);
226
242
  lines.push(` Molecular Health Score: ${BOLD}${GREEN}${health.score}/100${RESET} [Grade: ${BOLD}${GREEN}${health.grade}${RESET}]`);
227
243
  lines.push(` Passing Pillars: ${BOLD}${GREEN}${passedPillars.length} / 7 Pillars PASSED${RESET}`);
228
- lines.push(` Capsule Compliance: ${BOLD}${GREEN}${metrics.moleculeCompliantPct}%${RESET} compliant (< 100 LOC)`);
244
+ lines.push(` Capsule Compliance: ${BOLD}${GREEN}${metrics.moleculeCompliantPct}%${RESET} compliant (< 100 lines of code)`);
229
245
  lines.push(`${GREEN}----------------------------------------------------------------------${RESET}`);
230
246
 
231
247
  lines.push(`\n ${BOLD}${GREEN}✔ COMPLIANT PILLARS (${passedPillars.length} / 7):${RESET}`);
@@ -244,11 +260,11 @@ export const formatGradeASection = (report) => {
244
260
  }
245
261
  const hasExtremeMonolith = hotspots.some((h) => h.lineCount >= 2000);
246
262
  if (!hasExtremeMonolith) {
247
- lines.push(` ${GREEN}✔${RESET} Zero Extreme Monoliths (0 files >= 2,000 LOC)`);
263
+ lines.push(` ${GREEN}✔${RESET} Zero Extreme Monoliths (0 files >= 2,000 lines of code)`);
248
264
  }
249
265
  const hasSevereMonolith = hotspots.some((h) => h.lineCount >= 1000);
250
266
  if (!hasSevereMonolith) {
251
- lines.push(` ${GREEN}✔${RESET} Zero Severe Monoliths (0 files >= 1,000 LOC)`);
267
+ lines.push(` ${GREEN}✔${RESET} Zero Severe Monoliths (0 files >= 1,000 lines of code)`);
252
268
  }
253
269
  if (contextAnalysis.riskLevel === 'LOW') {
254
270
  lines.push(` ${GREEN}✔${RESET} Low Context Hazard & Token Burn Risk`);
@@ -1,6 +1,7 @@
1
1
  import { buildMasterPrompt } from './prompts.js';
2
2
  import {
3
3
  groupViolationsBySeverity,
4
+ resolveHealthHearts,
4
5
  resolveMarkdownStatusIcon,
5
6
  resolveMarkdownMonolithText,
6
7
  PILLAR_EMOJIS,
@@ -14,17 +15,17 @@ export const generateMarkdownReport = (report) => {
14
15
 
15
16
  lines.push('# Chemical X Protocol: Architectural Audit Report');
16
17
  lines.push('');
17
- lines.push(`**Generated**: ${new Date().toISOString()}`);
18
- lines.push('');
19
- lines.push('---');
18
+ lines.push('> *Comprehensive static analysis report enforcing Chemical X Molecular Architecture standards.*');
20
19
  lines.push('');
21
20
  lines.push('## 1. Executive Summary & Scorecard');
22
21
  lines.push('');
23
22
  lines.push('| Metric | Value | Status |');
24
23
  lines.push('| :--- | :--- | :--- |');
24
+ const hearts = resolveHealthHearts(health?.grade, health?.score, false);
25
+ lines.push(`| **Life / Health Meter** | ${hearts} (Grade **${health.grade}**) | ${health.score} / 100 (${health.label}) |`);
25
26
  lines.push(`| **Molecular Health Index** | **${health.score} / 100** | Grade: **${health.grade}** (${health.label}) |`);
26
27
  lines.push(`| **Scanned Files** | ${metrics.scannedFiles} source files | Verified |`);
27
- lines.push(`| **Total Lines of Code** | ${metrics.totalLoc} LOC | Avg ${metrics.avgLoc} LOC/file |`);
28
+ lines.push(`| **Total Lines of Code** | ${metrics.totalLoc} lines of code | Avg ${metrics.avgLoc} lines/file |`);
28
29
  lines.push(`| **Largest File** | \`${metrics.largestFile.filePath || 'None'}\` | ${metrics.largestFile.lineCount} lines |`);
29
30
  lines.push(`| **Context Token Overhead** | ~${contextAnalysis.estimatedTokens.toLocaleString()} tokens | Est. Bloat: ~${contextAnalysis.estimatedExcessTokens.toLocaleString()} tokens |`);
30
31
  lines.push(`| **Token Reduction Target** | **${contextAnalysis.potentialSavingsPct}%** | Risk Level: **${contextAnalysis.riskLevel}** |`);
@@ -71,12 +71,30 @@ export const resolveRiskColor = (riskLevel) => {
71
71
  };
72
72
 
73
73
  export const resolveHotspotBadge = (lineCount) => {
74
- if (lineCount >= 2000) return ` ${RED}[CRITICAL MONOLITH >= 2,000 LOC]${RESET}`;
75
- if (lineCount >= 1000) return ` ${ORANGE}[SEVERE MONOLITH >= 1,000 LOC]${RESET}`;
76
- if (lineCount > 500) return ` ${YELLOW}[MONOLITH WARNING > 500 LOC]${RESET}`;
74
+ if (lineCount >= 2000) return ` ${RED}[CRITICAL MONOLITH >= 2,000 lines of code]${RESET}`;
75
+ if (lineCount >= 1000) return ` ${ORANGE}[SEVERE MONOLITH >= 1,000 lines of code]${RESET}`;
76
+ if (lineCount > 500) return ` ${YELLOW}[MONOLITH WARNING > 500 lines of code]${RESET}`;
77
77
  return '';
78
78
  };
79
79
 
80
+ export const resolveHealthHearts = (grade, score = 0, isAnsi = true) => {
81
+ const g = String(grade || '').toUpperCase();
82
+ let filled = 1;
83
+ if (g.startsWith('A') || score >= 90) filled = 5;
84
+ else if (g.startsWith('B') || score >= 80) filled = 4;
85
+ else if (g.startsWith('C') || score >= 70) filled = 3;
86
+ else if (g.startsWith('D') || score >= 60) filled = 2;
87
+ else filled = score === 0 ? 0 : 1;
88
+
89
+ const empty = 5 - filled;
90
+ if (!isAnsi) {
91
+ return '❤︎'.repeat(filled) + '♡'.repeat(empty);
92
+ }
93
+ const redHearts = `${RED}${BOLD}` + '❤︎'.repeat(filled) + RESET;
94
+ const dimHearts = `${DIM}` + '♡'.repeat(empty) + RESET;
95
+ return `${redHearts}${dimHearts}`;
96
+ };
97
+
80
98
  export const PILLAR_EMOJIS = {
81
99
  'Line Budgets & Monolith Decomposition': '📏',
82
100
  'Control Flow & Boolean Logic': '🔀',
@@ -100,8 +118,8 @@ export const resolveMarkdownStatusIcon = (status) => {
100
118
  };
101
119
 
102
120
  export const resolveMarkdownMonolithText = (lineCount) => {
103
- if (lineCount >= 2000) return '🔴 **CRITICAL (>= 2,000 LOC)**';
104
- if (lineCount >= 1000) return '🟠 **SEVERE (>= 1,000 LOC)**';
105
- if (lineCount > 500) return '🟡 **WARNING (> 500 LOC)**';
121
+ if (lineCount >= 2000) return '🔴 **CRITICAL (>= 2,000 lines of code)**';
122
+ if (lineCount >= 1000) return '🟠 **SEVERE (>= 1,000 lines of code)**';
123
+ if (lineCount > 500) return '🟡 **WARNING (> 500 lines of code)**';
106
124
  return '🟢 Compliant';
107
125
  };
@@ -15,6 +15,7 @@ import {
15
15
  groupViolationsBySeverity,
16
16
  getStatusBadge,
17
17
  resolveGradeColor,
18
+ resolveHealthHearts,
18
19
  resolveRiskColor,
19
20
  resolveHotspotBadge
20
21
  } from './reporter-utils.js';
@@ -24,6 +25,7 @@ export {
24
25
  getSeverityBadge,
25
26
  getStatusBadge,
26
27
  resolveGradeColor,
28
+ resolveHealthHearts,
27
29
  resolveRiskColor,
28
30
  resolveHotspotBadge,
29
31
  resolveMarkdownStatusIcon,
@@ -51,6 +53,15 @@ export {
51
53
  formatGradeASection
52
54
  } from './reporter-grades.js';
53
55
 
56
+ export {
57
+ getAsciiGradeLines,
58
+ formatAsciiGrade,
59
+ getReportCardAsciiLines,
60
+ REPORT_CARD_ASCII
61
+ } from './reporter-ascii.js';
62
+
63
+ import { getAsciiGradeLines, getReportCardAsciiLines } from './reporter-ascii.js';
64
+
54
65
  export const resolveTopSectionColor = (report) => {
55
66
  const hasNoViolations = (report?.violations?.length ?? 0) === 0;
56
67
  const hasNoHotspots = (report?.hotspots?.length ?? 0) === 0;
@@ -62,18 +73,33 @@ export const resolveTopSectionColor = (report) => {
62
73
  export const formatScorecardSection = (report, themeColor = null) => {
63
74
  const { metrics, health } = report;
64
75
  const sectionColor = themeColor || resolveTopSectionColor(report);
65
- const gradeColor = resolveGradeColor(health.score);
76
+ const gradeColor = resolveGradeColor(health?.score ?? health?.grade ?? 'A');
66
77
  const lines = [];
67
78
 
68
79
  lines.push('');
80
+ for (const rcLine of getReportCardAsciiLines(sectionColor)) {
81
+ lines.push(` ${rcLine}`);
82
+ }
69
83
  lines.push(`${sectionColor}======================================================================${RESET}`);
70
84
  lines.push(`${BOLD}${sectionColor} MOLECULAR HEALTH INDEX & CODEBASE OVERVIEW${RESET}`);
71
85
  lines.push(`${sectionColor}======================================================================${RESET}`);
72
- lines.push(` Health Score: ${gradeColor}${BOLD}${health.score} / 100${RESET} (Grade: ${gradeColor}${BOLD}${health.grade}${RESET} - ${health.label})`);
86
+
87
+ const asciiGradeLines = getAsciiGradeLines(health?.grade || 'A', gradeColor);
88
+ if (asciiGradeLines.length > 0) {
89
+ lines.push('');
90
+ for (const asciiLine of asciiGradeLines) {
91
+ lines.push(` ${asciiLine}`);
92
+ }
93
+ lines.push('');
94
+ lines.push(`${sectionColor}----------------------------------------------------------------------${RESET}`);
95
+ }
96
+
97
+ const hearts = resolveHealthHearts(health?.grade, health?.score);
98
+ lines.push(` Life / Health Meter: ${hearts} ${gradeColor}${BOLD}${health.score} / 100${RESET} (Grade: ${gradeColor}${BOLD}${health.grade}${RESET} - ${health.label})`);
73
99
  lines.push(` Files Scanned: ${BOLD}${metrics.scannedFiles}${RESET} source files`);
74
- lines.push(` Total Lines of Code: ${BOLD}${metrics.totalLoc}${RESET} LOC (avg: ${metrics.avgLoc} lines/file)`);
100
+ lines.push(` Total Lines of Code: ${BOLD}${metrics.totalLoc}${RESET} lines of code (avg: ${metrics.avgLoc} lines/file)`);
75
101
  lines.push(` Largest File: ${BOLD}${metrics.largestFile.filePath || 'None'}${RESET} (${metrics.largestFile.lineCount} lines)`);
76
- lines.push(` Molecule Capsules: ${metrics.moleculeCount} found (${metrics.moleculeCompliantPct}% compliant < 100 lines)`);
102
+ lines.push(` Molecule Capsules: ${metrics.moleculeCount} found (${metrics.moleculeCompliantPct}% compliant < 100 lines of code)`);
77
103
  lines.push(` Custom Hooks: ${metrics.hookCount} detected`);
78
104
  lines.push(`${sectionColor}======================================================================${RESET}\n`);
79
105
 
@@ -259,6 +285,11 @@ export const getChemicalXAsciiBanner = (gradeOrReport = null) => {
259
285
 
260
286
  lines.push(' \x1b[1m\x1b[37mThe Secret Sauce to \x1b[38;2;98;201;255mVibe Coding\x1b[0m');
261
287
 
288
+ const gColor = grade ? resolveGradeColor(grade) : '';
289
+ const gradeLines = grade ? getAsciiGradeLines(grade, gColor, true) : [];
290
+ const termWidth = process.stdout.columns || 0;
291
+ const isSideBySide = Boolean(!termWidth || termWidth >= 105);
292
+
262
293
  for (let lineIdx = 0; lineIdx < art.length; lineIdx++) {
263
294
  const line = art[lineIdx];
264
295
  let out = '';
@@ -284,9 +315,8 @@ export const getChemicalXAsciiBanner = (gradeOrReport = null) => {
284
315
  out += `\x1b[38;2;${r};${g};${b}m\x1b[1m${ch}\x1b[0m`;
285
316
  }
286
317
 
287
- if (grade && lineIdx === 2) {
288
- const gColor = resolveGradeColor(grade);
289
- out += ` \x1b[1m\x1b[37m=\x1b[0m ${gColor}\x1b[1mGrade ${grade}\x1b[0m`;
318
+ if (isSideBySide && gradeLines.length > lineIdx) {
319
+ out += ` ${gradeLines[lineIdx]}`;
290
320
  }
291
321
 
292
322
  lines.push(out);
@@ -295,6 +325,14 @@ export const getChemicalXAsciiBanner = (gradeOrReport = null) => {
295
325
  const subtitle = 'Architectural guardrails to eliminate token burn and AI hallucinations.';
296
326
  const pad = ' '.repeat(Math.max(0, Math.floor((maxLen - subtitle.length) / 2)));
297
327
  lines.push(`${pad}\x1b[2m${subtitle}\x1b[0m\n`);
328
+
329
+ if (!isSideBySide && gradeLines.length > 0) {
330
+ for (const gl of gradeLines) {
331
+ lines.push(` ${gl}`);
332
+ }
333
+ lines.push('');
334
+ }
335
+
298
336
  return lines.join('\n');
299
337
  };
300
338
 
@@ -424,8 +462,8 @@ export const formatPassesSection = (report) => {
424
462
 
425
463
  lines.push(` Molecular Health Score: ${BOLD}${GREEN}${health.score}/100${RESET} [Grade: ${BOLD}${GREEN}${health.grade}${RESET}]`);
426
464
  lines.push(` Passing Pillars: ${BOLD}${GREEN}${passedPillars.length} / 7 Pillars PASSED${RESET}`);
427
- lines.push(` Capsule Compliance: ${BOLD}${GREEN}${metrics.moleculeCompliantPct}%${RESET} molecules compliant (< 100 LOC)`);
428
- lines.push(` Total Files Scanned: ${metrics.scannedFiles} source files (${metrics.totalLoc} total LOC)`);
465
+ lines.push(` Capsule Compliance: ${BOLD}${GREEN}${metrics.moleculeCompliantPct}%${RESET} molecules compliant (< 100 lines of code)`);
466
+ lines.push(` Total Files Scanned: ${metrics.scannedFiles} source files (${metrics.totalLoc} total lines of code)`);
429
467
  lines.push(`${GREEN}----------------------------------------------------------------------${RESET}`);
430
468
 
431
469
  lines.push(`\n ${BOLD}${GREEN}✔ COMPLIANT ARCHITECTURAL PILLARS:${RESET}`);
@@ -444,11 +482,11 @@ export const formatPassesSection = (report) => {
444
482
  }
445
483
  const hasExtremeMonolith = hotspots.some((h) => h.lineCount >= 2000);
446
484
  if (!hasExtremeMonolith) {
447
- lines.push(` ${GREEN}✔${RESET} Zero Extreme Monoliths (0 files >= 2,000 LOC)`);
485
+ lines.push(` ${GREEN}✔${RESET} Zero Extreme Monoliths (0 files >= 2,000 lines of code)`);
448
486
  }
449
487
  const hasSevereMonolith = hotspots.some((h) => h.lineCount >= 1000);
450
488
  if (!hasSevereMonolith) {
451
- lines.push(` ${GREEN}✔${RESET} Zero Severe Monoliths (0 files >= 1,000 LOC)`);
489
+ lines.push(` ${GREEN}✔${RESET} Zero Severe Monoliths (0 files >= 1,000 lines of code)`);
452
490
  }
453
491
  if (contextAnalysis.riskLevel === 'LOW') {
454
492
  lines.push(` ${GREEN}✔${RESET} Low Context Hazard & Token Burn Risk`);
@@ -28,6 +28,9 @@ export declare function resolveBadgeColor(score: number): string;
28
28
  export declare function resolveHotspotTierText(lineCount: number): string;
29
29
  export declare function resolvePillarProgressionBadge(isImproved: boolean, beforeStatus: string, afterStatus: string): string;
30
30
  export declare function formatWebUrl(url: string): string;
31
+ export declare function resolveExcessCostPerPass(tokensObj?: any, fallbackCostPerMillion?: number): number;
32
+ export declare function resolveMonthlyWastePerDev(tokensObj?: any, fallbackCostPerMillion?: number): number;
33
+ export declare function resolveWeeklyWastePerDev(tokensObj?: any, fallbackCostPerMillion?: number): number;
31
34
  export declare function generateDiscussionContent(report: AuditReport, username: string, projectName?: string, repoUrl?: string, liveUrl?: string): DiscussionContent;
32
35
  export declare function generateTransformationDiscussionContent(beforeSnapshot: AuditSnapshot, afterSnapshot: AuditSnapshot, username: string, projectName?: string, repoUrl?: string, liveUrl?: string): DiscussionContent;
33
36
  export declare function publishDiscussionViaGh(repo: string, title: string, body: string, category?: string): { success: boolean; url: string | null; error?: string | null };