@chemx/starter-kit 26.9.12-272 → 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 (42) 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 +13 -10
  6. package/cli/audit/reporter-grades.js +28 -16
  7. package/cli/audit/reporter-markdown.js +31 -16
  8. package/cli/audit/reporter-sections.js +14 -4
  9. package/cli/audit/reporter-utils.js +75 -0
  10. package/cli/audit/reporter.d.ts +13 -4
  11. package/cli/audit/reporter.js +29 -3
  12. package/cli/audit/roadmap.js +236 -0
  13. package/cli/audit/rules-predicates.d.ts +17 -0
  14. package/cli/audit/rules-predicates.js +107 -0
  15. package/cli/audit/rules.js +6 -2
  16. package/cli/audit/social-gh.js +2 -6
  17. package/cli/audit/social-publisher.js +1 -1
  18. package/cli/audit/social.js +25 -9
  19. package/cli/audit/types.d.ts +43 -1
  20. package/cli/audit.js +47 -7
  21. package/cli/build/detector.js +68 -0
  22. package/cli/build/executor.js +58 -0
  23. package/cli/build/grouper.js +78 -0
  24. package/cli/build/parser-matchers.js +116 -0
  25. package/cli/build/parser.js +80 -0
  26. package/cli/build/reporter.js +66 -0
  27. package/cli/build/types.d.ts +58 -0
  28. package/cli/build/types.js +1 -0
  29. package/cli/build.d.ts +16 -0
  30. package/cli/build.js +55 -0
  31. package/cli/help.js +14 -0
  32. package/cli/index.js +38 -19
  33. package/cli/installer-templates.js +42 -3
  34. package/cli/license.js +10 -7
  35. package/cli/navigator-actions.js +34 -6
  36. package/cli/navigator-banner.js +4 -2
  37. package/cli/navigator-menu.js +18 -0
  38. package/cli/navigator-share.js +1 -1
  39. package/cli/navigator.d.ts +8 -1
  40. package/cli/navigator.js +3 -3
  41. package/docs/CHANGELOG.md +36 -0
  42. package/package.json +3 -2
@@ -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) {
@@ -13,7 +13,9 @@ import {
13
13
  resolveHealthHearts,
14
14
  resolveRiskColor,
15
15
  resolveHotspotBadge,
16
- resolveTopSectionColor
16
+ resolveTopSectionColor,
17
+ PILLAR_EMOJIS,
18
+ formatPillarReactionBadgesTerminal
17
19
  } from './reporter-utils.js';
18
20
  import { getAsciiGradeLines, getReportCardAsciiLines } from './reporter-ascii.js';
19
21
  import { renderGroupedViolationsTerminal } from './reporter-grouping.js';
@@ -153,10 +155,18 @@ export const formatPillarsSection = (report, themeColor = null) => {
153
155
  lines.push(`${sectionColor}======================================================================${RESET}`);
154
156
  lines.push(`${BOLD}${sectionColor} 7-PILLAR ARCHITECTURAL COMPLIANCE MATRIX${RESET}`);
155
157
  lines.push(`${sectionColor}======================================================================${RESET}`);
156
- lines.push(` ${DIM}Pillar Name Status Violations${RESET}`);
157
- lines.push(` ${DIM}------------------------------------------------------------------${RESET}`);
158
+
159
+ const reactionStrip = formatPillarReactionBadgesTerminal(pillars);
160
+ if (reactionStrip) {
161
+ lines.push(` ${BOLD}Reaction Badges:${RESET} ${reactionStrip}`);
162
+ lines.push(`${sectionColor}----------------------------------------------------------------------${RESET}`);
163
+ }
164
+
165
+ lines.push(` ${DIM}Pillar Name Status Violations${RESET}`);
166
+ lines.push(` ${DIM}------------------------------------------------------------------------${RESET}`);
158
167
  for (const [pillarName, data] of Object.entries(pillars)) {
159
- const padName = pillarName.padEnd(45, ' ');
168
+ const icon = PILLAR_EMOJIS[pillarName] || '🏛️';
169
+ const padName = `[ ${icon} ] ${pillarName}`.padEnd(51, ' ');
160
170
  const badge = getStatusBadge(data.status).padEnd(16, ' ');
161
171
  const countStr = data.violations === 0 ? `${GREEN}0${RESET}` : `${RED}${data.violations}${RESET}`;
162
172
  lines.push(` ${padName} ${badge} ${countStr}`);
@@ -129,6 +129,49 @@ export const PILLAR_EMOJIS = {
129
129
  'Naming Conventions': '🏷️'
130
130
  };
131
131
 
132
+ export const PILLAR_SHORT_NAMES = {
133
+ 'Line Budgets & Monolith Decomposition': 'Monoliths',
134
+ 'Control Flow & Boolean Logic': 'Logic',
135
+ 'Reactivity & Composable Contracts': 'Reactivity',
136
+ 'Type Architecture & Data Integrity': 'Types',
137
+ 'Design System & Styling Hygiene': 'Styling',
138
+ 'Timers & Macro-Task Discipline': 'Timers',
139
+ 'Global Hygiene & Typography': 'Hygiene',
140
+ 'Accessibility & Semantic Integrity': 'A11y',
141
+ 'Security & Content Safety': 'Security',
142
+ 'Testing Discipline': 'Testing',
143
+ 'Naming Conventions': 'Naming'
144
+ };
145
+
146
+ export const resolveBadgeColor = (score) => {
147
+ if (score >= 90) return '06b6d4';
148
+ if (score >= 70) return 'f59e0b';
149
+ return 'ef4444';
150
+ };
151
+
152
+ export const formatPillarShieldBadges = (pillars = {}) => {
153
+ const badges = [];
154
+ for (const [pillarName, data] of Object.entries(pillars)) {
155
+ const icon = PILLAR_EMOJIS[pillarName] || '🏛️';
156
+ const shortName = PILLAR_SHORT_NAMES[pillarName] || pillarName.split(' ')[0];
157
+ const rawLabel = `${icon} ${shortName}`.replace(/-/g, '--').replace(/ /g, '_');
158
+ const label = encodeURIComponent(rawLabel);
159
+ let statusText = 'PASS';
160
+ let color = '06b6d4';
161
+ if (data?.status === 'WARN') {
162
+ const v = data?.violations || 0;
163
+ statusText = encodeURIComponent(`WARN ${v}`.replace(/-/g, '--').replace(/ /g, '_'));
164
+ color = 'f59e0b';
165
+ } else if (data?.status === 'FAILED') {
166
+ const v = data?.violations || 0;
167
+ statusText = encodeURIComponent(`FAIL ${v}`.replace(/-/g, '--').replace(/ /g, '_'));
168
+ color = 'ef4444';
169
+ }
170
+ badges.push(`[![${shortName}](https://img.shields.io/badge/${label}-${statusText}-${color}?style=for-the-badge)](https://chemicalx.xophz.com)`);
171
+ }
172
+ return badges.join(' ');
173
+ };
174
+
132
175
  export const NUMBER_EMOJIS = ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣', '🔟'];
133
176
 
134
177
  export const resolvePriorityBadge = (idx) => {
@@ -147,3 +190,35 @@ export const resolveMarkdownMonolithText = (lineCount) => {
147
190
  if (lineCount > 500) return '🟡 **WARNING (> 500 lines of code)**';
148
191
  return '🟢 Compliant';
149
192
  };
193
+
194
+ export const formatPillarReactionBadgesTerminal = (pillars = {}) => {
195
+ const badges = [];
196
+ for (const [pillarName, data] of Object.entries(pillars)) {
197
+ const icon = PILLAR_EMOJIS[pillarName] || '🏛️';
198
+ const violations = data?.violations || 0;
199
+ if (data?.status === 'PASSED') {
200
+ badges.push(`${GREEN}[ ${icon} PASS ]${RESET}`);
201
+ } else if (data?.status === 'WARN') {
202
+ badges.push(`${YELLOW}[ ${icon} WARN (${violations}) ]${RESET}`);
203
+ } else {
204
+ badges.push(`${RED}[ ${icon} FAIL (${violations}) ]${RESET}`);
205
+ }
206
+ }
207
+ return badges.join(' ');
208
+ };
209
+
210
+ export const formatPillarReactionBadgesMarkdown = (pillars = {}) => {
211
+ const badges = [];
212
+ for (const [pillarName, data] of Object.entries(pillars)) {
213
+ const icon = PILLAR_EMOJIS[pillarName] || '🏛️';
214
+ const violations = data?.violations || 0;
215
+ if (data?.status === 'PASSED') {
216
+ badges.push(`\`[ ${icon} PASS ]\``);
217
+ } else if (data?.status === 'WARN') {
218
+ badges.push(`\`[ ${icon} WARN: ${violations} ]\``);
219
+ } else {
220
+ badges.push(`\`[ ${icon} FAIL: ${violations} ]\``);
221
+ }
222
+ }
223
+ return badges.join(' ');
224
+ };
@@ -6,11 +6,20 @@ export * from './reporter-sections';
6
6
  export * from './reporter-summary';
7
7
  export * from './reporter-grouping';
8
8
 
9
+ export interface FormatGradeOptions {
10
+ readonly includePrompt?: boolean;
11
+ }
12
+
9
13
  export declare function formatTerminalReport(report: AuditReport): string;
10
14
  export declare function generateMarkdownReport(report: AuditReport): string;
11
15
  export declare function resolveTopSectionColor(report: AuditReport): string;
12
- export declare function formatGradeFSection(report: AuditReport): string;
13
- export declare function formatGradeDSection(report: AuditReport): string;
14
- export declare function formatGradeCSection(report: AuditReport): string;
15
- export declare function formatGradeBSection(report: AuditReport): string;
16
+ export declare function formatGradeFSection(report: AuditReport, options?: FormatGradeOptions): string;
17
+ export declare function formatGradeDSection(report: AuditReport, options?: FormatGradeOptions): string;
18
+ export declare function formatGradeCSection(report: AuditReport, options?: FormatGradeOptions): string;
19
+ export declare function formatGradeBSection(report: AuditReport, options?: FormatGradeOptions): string;
16
20
  export declare function formatGradeASection(report: AuditReport): string;
21
+ export declare function formatPillarReactionBadgesTerminal(pillars?: Record<string, unknown>): string;
22
+ export declare function formatPillarReactionBadgesMarkdown(pillars?: Record<string, unknown>): string;
23
+ export declare const PILLAR_SHORT_NAMES: Record<string, string>;
24
+ export declare function resolveBadgeColor(score: number): string;
25
+ export declare function formatPillarShieldBadges(pillars?: Record<string, unknown>): string;
@@ -20,6 +20,24 @@ import {
20
20
  formatContextAnalysisSection,
21
21
  formatAiSlopSection
22
22
  } from './reporter-sections.js';
23
+ import {
24
+ formatRoadmapSection,
25
+ formatRoadmapMarkdown,
26
+ buildSelfHealingRoadmapPrompt
27
+ } from './roadmap.js';
28
+ import {
29
+ formatGradeASection,
30
+ formatGradeBSection,
31
+ formatGradeCSection,
32
+ formatGradeDSection,
33
+ formatGradeFSection
34
+ } from './reporter-grades.js';
35
+
36
+ export {
37
+ formatRoadmapSection,
38
+ formatRoadmapMarkdown,
39
+ buildSelfHealingRoadmapPrompt
40
+ };
23
41
 
24
42
  export {
25
43
  groupViolationsBySeverity,
@@ -32,7 +50,12 @@ export {
32
50
  resolveTopSectionColor,
33
51
  resolveMarkdownStatusIcon,
34
52
  resolveMarkdownMonolithText,
53
+ formatPillarReactionBadgesTerminal,
54
+ formatPillarReactionBadgesMarkdown,
55
+ formatPillarShieldBadges,
56
+ resolveBadgeColor,
35
57
  PILLAR_EMOJIS,
58
+ PILLAR_SHORT_NAMES,
36
59
  NUMBER_EMOJIS,
37
60
  resolvePriorityBadge,
38
61
  CYAN,
@@ -112,9 +135,12 @@ export const formatTerminalReport = (report) => {
112
135
  lines.push(formatHotspotsSection(report, topColor, { includePrompt: false }));
113
136
  lines.push(formatDirectoryDistributionSection(report, topColor));
114
137
  lines.push(formatAiSlopSection(report, topColor, { includePrompt: false }));
115
- lines.push(formatCriticalSection(report));
116
- lines.push(formatHighMediumSection(report));
117
- lines.push(formatLowSection(report));
138
+ lines.push(formatRoadmapSection(report, topColor));
139
+ lines.push(formatGradeASection(report));
140
+ lines.push(formatGradeBSection(report, { includePrompt: false }));
141
+ lines.push(formatGradeCSection(report, { includePrompt: false }));
142
+ lines.push(formatGradeDSection(report, { includePrompt: false }));
143
+ lines.push(formatGradeFSection(report, { includePrompt: false }));
118
144
 
119
145
  const masterPrompt = buildMasterPrompt(report);
120
146
  if (masterPrompt) {
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Chemical X Protocol: Self-Healing Remediation Roadmap
3
+ * Calculates and formats the optimal sequence of architectural fixes.
4
+ */
5
+
6
+ import {
7
+ CYAN,
8
+ GREEN,
9
+ YELLOW,
10
+ RED,
11
+ ORANGE,
12
+ DIM,
13
+ BOLD,
14
+ RESET,
15
+ resolveTopSectionColor,
16
+ groupViolationsBySeverity
17
+ } from './reporter-utils.js';
18
+
19
+ export const buildRemediationRoadmap = (report) => {
20
+ const { hotspots = [], violations = [], patterns = [] } = report;
21
+ const { critical, high, medium, low } = groupViolationsBySeverity(violations);
22
+
23
+ const extremeMonoliths = hotspots.filter((h) => h.lineCount >= 2000);
24
+ const severeMonoliths = hotspots.filter((h) => h.lineCount >= 1000 && h.lineCount < 2000);
25
+ const warningMonoliths = hotspots.filter((h) => h.lineCount >= 500 && h.lineCount < 1000);
26
+
27
+ const phases = [];
28
+
29
+ // Phase 1: Pattern Recognition & Canonical Harvesting
30
+ phases.push({
31
+ step: 1,
32
+ phase: 'PHASE 1: PATTERN HARVESTING & CANONICAL EXTRACTION',
33
+ roi: 'MAXIMUM (Compounding Reuse)',
34
+ rationale: 'Extract reusable UI structures and shared domain types before slicing monoliths to eliminate redundant bespoke code.',
35
+ items: patterns.length > 0
36
+ ? patterns.map((p) => ({
37
+ title: p.label,
38
+ target: p.suggestedCapsule,
39
+ action: p.recommendation,
40
+ locations: p.occurrences.slice(0, 3).map((o) => `${o.filePath}:${o.line}`)
41
+ }))
42
+ : [
43
+ {
44
+ title: 'Cross-Monolith Pattern Survey',
45
+ target: 'src/components/molecules/',
46
+ action: 'Audit shared card layouts, common status unions, and repeated filter predicates across candidate files before code splitting.',
47
+ locations: []
48
+ }
49
+ ]
50
+ });
51
+
52
+ // Phase 2: Domain Foundations & Type Architecture
53
+ const typeViolations = violations.filter((v) => v.rule === 'TYPE_MONOLITH' || v.pillar?.includes('Pillar 4'));
54
+ phases.push({
55
+ step: 2,
56
+ phase: 'PHASE 2: DOMAIN FOUNDATIONS & TYPE INTEGRITY',
57
+ roi: 'HIGH (Compile-Time Guardrails)',
58
+ rationale: 'Co-locate granular types/*.d.ts capsules to provide strict discriminated unions for decomposing components.',
59
+ items: typeViolations.length > 0
60
+ ? typeViolations.slice(0, 5).map((v) => ({
61
+ title: v.hazard,
62
+ target: `${v.filePath} -> types/*.d.ts`,
63
+ action: v.directive,
64
+ locations: [`${v.filePath}:${v.line}`]
65
+ }))
66
+ : [
67
+ {
68
+ title: 'Domain Type Co-location',
69
+ target: 'types/*.d.ts',
70
+ action: 'Ensure molecule capsules own co-located type declarations (< 100 lines each) with zero root type dumping.',
71
+ locations: []
72
+ }
73
+ ]
74
+ });
75
+
76
+ // Phase 3: Monolith Decomposition (Grade F & D)
77
+ const topMonoliths = [...extremeMonoliths, ...severeMonoliths, ...warningMonoliths].slice(0, 6);
78
+ phases.push({
79
+ step: 3,
80
+ phase: 'PHASE 3: MONOLITH DECOMPOSITION (HOTSPOTS)',
81
+ roi: 'VERY HIGH (Context Window Unlocking)',
82
+ rationale: 'Decompose giant views into 10-20 line Table-of-Contents templates by importing canonical capsules harvested in Phase 1.',
83
+ items: topMonoliths.map((m) => ({
84
+ title: `${m.filePath} (${m.lineCount} lines, ${m.violationCount} hazards)`,
85
+ target: m.filePath,
86
+ action: 'Decompose into crystalline single-responsibility capsules (< 100 lines per molecule) reusing Phase 1 components.',
87
+ locations: [`${m.filePath}:1`]
88
+ }))
89
+ });
90
+
91
+ // Phase 4: Component Hygiene & Polish (Grade C & B)
92
+ phases.push({
93
+ step: 4,
94
+ phase: 'PHASE 4: COMPONENT HYGIENE & DESIGN SYSTEM POLISH',
95
+ roi: 'MEDIUM (Visual & Syntax Standardization)',
96
+ rationale: 'Clean up inline styles into mixins (@include glass), two-stage booleans, typography, and logging on the newly lean capsules.',
97
+ items: [
98
+ {
99
+ title: `Medium Severity Debts (${medium.length} items)`,
100
+ target: 'Component stylesheets & logic',
101
+ action: 'Replace raw inline styles with atom props or SCSS mixins (@include glass); extract anonymous callbacks into named handlers.',
102
+ locations: []
103
+ },
104
+ {
105
+ title: `Hygiene & Typography Debts (${low.length} items)`,
106
+ target: 'Copy, comments & logs',
107
+ action: 'Eliminate em dashes (use hyphens or colons), route console logs through debug proxy, and ensure FontAwesome SVG compliance.',
108
+ locations: []
109
+ }
110
+ ]
111
+ });
112
+
113
+ // Phase 5: Verification & Gatekeeping
114
+ phases.push({
115
+ step: 5,
116
+ phase: 'PHASE 5: AUTOMATED GATEKEEPING & CI ENFORCEMENT',
117
+ roi: 'PERMANENT (Zero-Entropy Protection)',
118
+ rationale: 'Verify the newly refactored codebase passes with Grade A / Score >= 90 and install pre-commit guardrails.',
119
+ items: [
120
+ {
121
+ title: 'Run Architectural Re-Audit',
122
+ target: 'chemx audit',
123
+ action: 'Execute npx chemx audit --strict to confirm zero monolith hazards remain.',
124
+ locations: []
125
+ },
126
+ {
127
+ title: 'Install Pre-Commit & CI Gatekeepers',
128
+ target: '.git/hooks/pre-commit & .github/workflows/',
129
+ action: 'Run npx chemx install to lock in line budgets and prevent future monolith regressions.',
130
+ locations: []
131
+ },
132
+ {
133
+ title: 'Branch, Commit & Pull Request Workflow',
134
+ target: 'git checkout -b chem-x/NAMEOFIMPROVEMENT',
135
+ action: 'Change to a branch prefixed with chem-x/NAMEOFIMPROVEMENT to make changes, commit the branch, and create a PR to main.',
136
+ locations: []
137
+ }
138
+ ]
139
+ });
140
+
141
+ return phases;
142
+ };
143
+
144
+ export const formatRoadmapSection = (report, themeColor = null) => {
145
+ const sectionColor = themeColor || resolveTopSectionColor(report);
146
+ const phases = buildRemediationRoadmap(report);
147
+ const lines = [];
148
+
149
+ lines.push('');
150
+ lines.push(`${sectionColor}======================================================================${RESET}`);
151
+ lines.push(`${BOLD}${sectionColor} SELF-HEALING REMEDIATION ROADMAP (OPTIMAL FIX SEQUENCE)${RESET}`);
152
+ lines.push(`${DIM} Fix in this sequence to harvest patterns first and compound code reuse${RESET}`);
153
+ lines.push(`${sectionColor}======================================================================${RESET}`);
154
+
155
+ phases.forEach((p) => {
156
+ lines.push(`\n ${CYAN}${BOLD}[STEP ${p.step}] ${p.phase}${RESET}`);
157
+ lines.push(` ${DIM}ROI: ${p.roi}${RESET}`);
158
+ lines.push(` ${YELLOW}Strategy: ${p.rationale}${RESET}`);
159
+
160
+ p.items.forEach((item, idx) => {
161
+ lines.push(` ${idx + 1}. ${BOLD}${item.title}${RESET}`);
162
+ lines.push(` Target: ${CYAN}${item.target}${RESET}`);
163
+ lines.push(` Action: ${item.action}`);
164
+ if (item.locations.length > 0) {
165
+ lines.push(` Locations: ${DIM}${item.locations.join(', ')}${RESET}`);
166
+ }
167
+ });
168
+ });
169
+
170
+ lines.push(`\n${sectionColor}======================================================================${RESET}\n`);
171
+ return lines.join('\n');
172
+ };
173
+
174
+ export const formatRoadmapMarkdown = (report) => {
175
+ const phases = buildRemediationRoadmap(report);
176
+ const lines = [];
177
+
178
+ lines.push('## 🗺 Recommended Remediation Sequence (Self-Healing Roadmap)\n');
179
+ lines.push('> Follow this sequence strictly: harvesting patterns first creates reusable building blocks that eliminate duplicate work during subsequent monolith slicing.\n');
180
+
181
+ phases.forEach((p) => {
182
+ lines.push(`### Step ${p.step}: ${p.phase}`);
183
+ lines.push(`**ROI**: ${p.roi} | **Strategy**: ${p.rationale}\n`);
184
+
185
+ p.items.forEach((item) => {
186
+ lines.push(`- [ ] **${item.title}**`);
187
+ lines.push(` - **Target**: \`${item.target}\``);
188
+ lines.push(` - **Action**: ${item.action}`);
189
+ if (item.locations.length > 0) {
190
+ lines.push(` - **Locations**: \`${item.locations.join('`, `')}\``);
191
+ }
192
+ });
193
+ lines.push('');
194
+ });
195
+
196
+ return lines.join('\n');
197
+ };
198
+
199
+ export const buildSelfHealingRoadmapPrompt = (report) => {
200
+ const phases = buildRemediationRoadmap(report);
201
+ const lines = [];
202
+
203
+ lines.push('Act as a Principal Systems Architect. Execute a self-healing architectural remediation of our codebase by following this strict multi-phase sequence in order:\n');
204
+
205
+ lines.push('### MANDATORY GIT BRANCHING & PR WORKFLOW:');
206
+ lines.push('1. Before modifying any files, change to a dedicated feature branch prefixed with `chem-x/NAMEOFIMPROVEMENT`:');
207
+ lines.push(' `git checkout -b chem-x/NAMEOFIMPROVEMENT`');
208
+ lines.push('2. Execute each remediation phase sequentially on this branch.');
209
+ lines.push('3. Commit the branch with atomic, intention-revealing commit messages.');
210
+ lines.push('4. Create a Pull Request (PR) to `main` upon completing the remediation phases.\n');
211
+
212
+ phases.forEach((p) => {
213
+ lines.push(`### STEP ${p.step}: ${p.phase}`);
214
+ lines.push(`Goal: ${p.rationale}\n`);
215
+ p.items.forEach((item, idx) => {
216
+ lines.push(`${idx + 1}. Task: ${item.title}`);
217
+ lines.push(` Target: ${item.target}`);
218
+ lines.push(` Execution: ${item.action}`);
219
+ if (item.locations.length > 0) {
220
+ lines.push(` Files: ${item.locations.join(', ')}`);
221
+ }
222
+ });
223
+ lines.push('');
224
+ });
225
+
226
+ lines.push('### EXECUTION DISCIPLINE:');
227
+ lines.push('1. Branch First: Change to a new branch prefixed with `chem-x/NAMEOFIMPROVEMENT` (e.g. `git checkout -b chem-x/<name-of-improvement>`) before making any changes.');
228
+ lines.push('2. Complete Step 1 (Pattern Harvesting) completely before touching any monolithic file in Step 3.');
229
+ lines.push('3. Spliced views in Step 3 must directly import and bind to the canonical capsules created in Step 1.');
230
+ lines.push('4. Every new molecule component must stay under 100 lines.');
231
+ lines.push('5. Top-level page views must be 10-20 line declarative Table-of-Contents templates assembling molecules via named slots.');
232
+ lines.push('6. Zero synthetic or mock data; zero em dashes (use hyphens or colons).');
233
+ lines.push('7. PR to Main: Commit the branch and create a Pull Request to main.');
234
+
235
+ return lines.join('\n');
236
+ };
@@ -0,0 +1,17 @@
1
+ import type * as babelTypes from '@babel/types';
2
+
3
+ export declare function isComponentPath(path: string): boolean;
4
+ export declare function isCodeLine(line: string): boolean;
5
+ export declare function isConsoleCallStatement(stmt: unknown, t: typeof babelTypes): boolean;
6
+ export declare function isShallowCatchBody(body: readonly unknown[], t: typeof babelTypes): boolean;
7
+ export declare function hasAnyTypeAnnotation(param: unknown, t: typeof babelTypes): boolean;
8
+ export declare function isRedundantPassthroughReturn(curr: unknown, next: unknown, t: typeof babelTypes): boolean;
9
+ export declare function isHookIdentifier(idNode: unknown): boolean;
10
+ export declare function isCustomHookFunction(astPath: unknown): boolean;
11
+ export declare function resolveStartLine(primaryNode?: unknown, fallbackNode?: unknown, defaultLine?: number): number;
12
+ export declare function isZeroDelayTimeout(callee: unknown, delayArg: unknown, t: typeof babelTypes): boolean;
13
+ export declare function isUnguardedConsoleCall(callee: unknown, t: typeof babelTypes): boolean;
14
+ export declare function matchesDiscussionTitle(titleLower: string, targetLower: string): boolean;
15
+ export declare function isGradeBelowMinimum(currentGrade: string, minGrade?: string | null): boolean;
16
+ export declare function evaluateAuditFailure(conditions?: readonly boolean[]): boolean;
17
+ export declare function isNonInteractiveSession(rawArgs: readonly string[], env?: Record<string, string | undefined>): boolean;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Chemical X Protocol: Canonical Predicates for AST & CLI Control Flow
3
+ * Reusable single-concept booleans and higher-order predicate helpers.
4
+ */
5
+
6
+ const COMPONENT_PATH_SEGMENTS = ['molecules', 'components', '/m-', '/views/', '/pages/'];
7
+ const CONSOLE_LOG_METHODS = ['log', 'info', 'warn'];
8
+ const NON_INTERACTIVE_FLAGS = ['--non-interactive', '--no-interactive', '--ci'];
9
+ const GRADE_RANKS = { 'A+': 5, 'A': 4, 'B': 3, 'C': 2, 'D': 1, 'F': 0 };
10
+
11
+ export const isComponentPath = (path) => {
12
+ return COMPONENT_PATH_SEGMENTS.some((segment) => path.includes(segment));
13
+ };
14
+
15
+ export const isCodeLine = (line) => {
16
+ if (!line) return false;
17
+ const isLineComment = line.startsWith('//');
18
+ const isBlockComment = line.startsWith('/*');
19
+ return !isLineComment && !isBlockComment;
20
+ };
21
+
22
+ export const isConsoleCallStatement = (stmt, t) => {
23
+ if (!t.isExpressionStatement(stmt)) return false;
24
+ const expr = stmt.expression;
25
+ if (!t.isCallExpression(expr)) return false;
26
+ const callee = expr.callee;
27
+ if (!t.isMemberExpression(callee)) return false;
28
+ return t.isIdentifier(callee.object, { name: 'console' });
29
+ };
30
+
31
+ export const isShallowCatchBody = (body, t) => {
32
+ if (body.length === 0) return true;
33
+ if (body.length === 1) return isConsoleCallStatement(body[0], t);
34
+ return false;
35
+ };
36
+
37
+ export const hasAnyTypeAnnotation = (param, t) => {
38
+ if (!param || !t.isIdentifier(param)) return false;
39
+ const typeAnn = param.typeAnnotation;
40
+ if (!typeAnn || !t.isTSTypeAnnotation(typeAnn)) return false;
41
+ return t.isTSAnyKeyword(typeAnn.typeAnnotation);
42
+ };
43
+
44
+ export const isRedundantPassthroughReturn = (curr, next, t) => {
45
+ if (!t.isVariableDeclaration(curr) || curr.declarations.length !== 1) return false;
46
+ const decl = curr.declarations[0];
47
+ if (!t.isIdentifier(decl.id)) return false;
48
+ if (!t.isReturnStatement(next) || !t.isIdentifier(next.argument)) return false;
49
+ return decl.id.name === next.argument.name;
50
+ };
51
+
52
+ export const isHookIdentifier = (idNode) => {
53
+ return Boolean(idNode?.name && /^use[A-Z0-9]/.test(idNode.name));
54
+ };
55
+
56
+ export const isCustomHookFunction = (astPath) => {
57
+ const hasHookId = isHookIdentifier(astPath.node.id);
58
+ const hasParentHookId = isHookIdentifier(astPath.parentPath?.node?.id);
59
+ return hasHookId || hasParentHookId;
60
+ };
61
+
62
+ export const resolveStartLine = (primaryNode, fallbackNode, defaultLine = 1) => {
63
+ return primaryNode?.loc?.start?.line ?? fallbackNode?.loc?.start?.line ?? defaultLine;
64
+ };
65
+
66
+ export const isZeroDelayTimeout = (callee, delayArg, t) => {
67
+ const isTimeoutId = t.isIdentifier(callee, { name: 'setTimeout' });
68
+ const isZeroNumeric = t.isNumericLiteral(delayArg) && delayArg.value === 0;
69
+ return isTimeoutId && isZeroNumeric;
70
+ };
71
+
72
+ export const isUnguardedConsoleCall = (callee, t) => {
73
+ if (!t.isMemberExpression(callee)) return false;
74
+ if (!t.isIdentifier(callee.object, { name: 'console' })) return false;
75
+ if (!t.isIdentifier(callee.property)) return false;
76
+ return CONSOLE_LOG_METHODS.includes(callee.property.name);
77
+ };
78
+
79
+ export const matchesDiscussionTitle = (titleLower, targetLower) => {
80
+ const patterns = [
81
+ ` ${targetLower} :`,
82
+ ` ${targetLower} [`,
83
+ `: ${targetLower}`,
84
+ `${targetLower} audit`
85
+ ];
86
+ return patterns.some((p) => titleLower.includes(p));
87
+ };
88
+
89
+ export const isGradeBelowMinimum = (currentGrade, minGrade) => {
90
+ if (!minGrade) return false;
91
+ const currentRank = GRADE_RANKS[currentGrade];
92
+ const minRank = GRADE_RANKS[minGrade];
93
+ const hasValidRanks = currentRank !== undefined && minRank !== undefined;
94
+ return hasValidRanks && currentRank < minRank;
95
+ };
96
+
97
+ export const evaluateAuditFailure = (conditions = []) => {
98
+ return conditions.some(Boolean);
99
+ };
100
+
101
+ export const isNonInteractiveSession = (rawArgs, env = process.env) => {
102
+ const hasCliFlag = NON_INTERACTIVE_FLAGS.some((flag) => rawArgs.includes(flag));
103
+ const hasOutputFlag = rawArgs.some((arg) => arg.startsWith('--output=') || arg.startsWith('-o='));
104
+ const hasFormatFlag = rawArgs.includes('--markdown') || rawArgs.includes('--md') || rawArgs.includes('--json');
105
+ const hasCiEnv = Boolean(env.CI || env.GIT_DIR);
106
+ return hasCliFlag || hasOutputFlag || hasFormatFlag || hasCiEnv;
107
+ };