@chemx/starter-kit 26.9.9-786 → 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.
Files changed (45) hide show
  1. package/cli/audit/ast-visitors.js +243 -0
  2. package/cli/audit/discussion-store.js +39 -0
  3. package/cli/audit/history.d.ts +69 -0
  4. package/cli/audit/history.js +397 -0
  5. package/cli/audit/metrics.js +179 -0
  6. package/cli/audit/prompts.js +174 -0
  7. package/cli/audit/reporter-ascii.d.ts +4 -0
  8. package/cli/audit/reporter-ascii.js +99 -0
  9. package/cli/audit/reporter-grades.js +275 -0
  10. package/cli/audit/reporter-markdown.js +137 -0
  11. package/cli/audit/reporter-utils.js +125 -0
  12. package/cli/audit/reporter.js +497 -0
  13. package/cli/audit/rules-helpers.js +109 -0
  14. package/cli/audit/rules-registry.js +97 -0
  15. package/cli/audit/rules.js +123 -0
  16. package/cli/audit/social-constants.js +4 -0
  17. package/cli/audit/social-gh.js +126 -0
  18. package/cli/audit/social-git.js +214 -0
  19. package/cli/audit/social-http.js +222 -0
  20. package/cli/audit/social-publisher.js +193 -0
  21. package/cli/audit/social.d.ts +69 -0
  22. package/cli/audit/social.js +303 -0
  23. package/cli/audit/types.d.ts +140 -0
  24. package/cli/audit.d.ts +3 -24
  25. package/cli/audit.js +207 -210
  26. package/cli/help.d.ts +1 -0
  27. package/cli/help.js +136 -0
  28. package/cli/index.js +128 -566
  29. package/cli/installer-templates.js +91 -0
  30. package/cli/installer.d.ts +21 -0
  31. package/cli/installer.js +104 -0
  32. package/cli/license.js +320 -0
  33. package/cli/navigator-actions.js +274 -0
  34. package/cli/navigator-banner.js +98 -0
  35. package/cli/navigator-conversion.js +100 -0
  36. package/cli/navigator-grades.js +87 -0
  37. package/cli/navigator-menu.js +127 -0
  38. package/cli/navigator-paged.js +86 -0
  39. package/cli/navigator-share.js +129 -0
  40. package/cli/navigator.d.ts +43 -0
  41. package/cli/navigator.js +126 -0
  42. package/cli/scaffold.js +148 -0
  43. package/cli/terminal.js +126 -0
  44. package/docs/CHANGELOG.md +101 -0
  45. package/package.json +11 -10
package/cli/audit.js CHANGED
@@ -1,189 +1,52 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { parse } from '@babel/parser';
4
- import traverse from '@babel/traverse';
5
- import * as t from '@babel/types';
6
-
7
- const countLogicalOperators = (node) => {
8
- let count = 0;
9
- if (t.isLogicalExpression(node)) {
10
- count += 1;
11
- count += countLogicalOperators(node.left);
12
- count += countLogicalOperators(node.right);
13
- } else if (t.isUnaryExpression(node) && node.operator === '!') {
14
- count += 1;
15
- count += countLogicalOperators(node.argument);
16
- }
17
- return count;
18
- };
19
-
20
- const extractParseableCode = (content, ext) => {
21
- if (ext === '.vue') {
22
- const scriptMatch = content.match(/<script\b[^>]*>([\s\S]*?)<\/script>/i);
23
- return scriptMatch ? scriptMatch[1] : '';
24
- }
25
- return content;
26
- };
27
-
28
- export const auditFile = (filePath, relativePath) => {
29
- const violations = [];
30
- const content = fs.readFileSync(filePath, 'utf-8');
31
- const lines = content.split('\n');
32
- const lineCount = lines.length;
33
- const ext = path.extname(filePath);
34
-
35
- // 1. Line Budget Checks
36
- const isMolecule = relativePath.includes('molecules') || relativePath.includes('/m-');
37
- if (lineCount > 500) {
38
- violations.push({
39
- filePath: relativePath,
40
- line: 1,
41
- hazard: `File line budget exceeded (${lineCount} > 500 lines)`,
42
- rule: 'LINE_BUDGET_FILE',
43
- directive: 'Decompose monolith into domain capsules and molecules'
44
- });
45
- } else if (isMolecule && lineCount > 100) {
46
- violations.push({
47
- filePath: relativePath,
48
- line: 1,
49
- hazard: `Molecule capsule budget exceeded (${lineCount} > 100 lines)`,
50
- rule: 'LINE_BUDGET_MOLECULE',
51
- directive: 'Split molecule into focused sub-molecules or extract state to hook'
52
- });
53
- }
54
-
55
- const codeToParse = extractParseableCode(content, ext);
56
- if (!codeToParse.trim()) {
57
- return violations;
58
- }
59
-
60
- let ast;
61
- try {
62
- ast = parse(codeToParse, {
63
- sourceType: 'module',
64
- plugins: ['typescript', 'jsx']
65
- });
66
- } catch (err) {
67
- const errorMsg = err instanceof Error ? err.message : String(err);
68
- violations.push({
69
- filePath: relativePath,
70
- line: 1,
71
- hazard: `Parse error: ${errorMsg}`,
72
- rule: 'SYNTAX_PARSE_ERROR',
73
- directive: 'Fix syntax errors before static analysis'
74
- });
75
- return violations;
76
- }
77
-
78
- const traverseFn = traverse.default || traverse;
79
-
80
- traverseFn(ast, {
81
- // 2. Hook Saturation Check
82
- Function(astPath) {
83
- let hookCount = 0;
84
- astPath.traverse({
85
- CallExpression(callPath) {
86
- if (t.isIdentifier(callPath.node.callee) && /^use[A-Z0-9]/.test(callPath.node.callee.name)) {
87
- if (callPath.getFunctionParent() === astPath) {
88
- hookCount += 1;
89
- }
90
- }
91
- }
92
- });
93
-
94
- if (hookCount > 5) {
95
- const line = astPath.node.loc?.start.line || 1;
96
- violations.push({
97
- filePath: relativePath,
98
- line,
99
- hazard: `Hook saturation detected (${hookCount} hooks > 5 limit)`,
100
- rule: 'HOOK_SATURATION',
101
- directive: 'Extract related state and effects into dedicated domain hooks'
102
- });
103
- }
104
- },
105
-
106
- // 3. Control Flow Complexity
107
- JSXExpressionContainer(astPath) {
108
- const expr = astPath.node.expression;
109
- if (t.isLogicalExpression(expr) || t.isUnaryExpression(expr)) {
110
- const opCount = countLogicalOperators(expr);
111
- if (opCount > 2) {
112
- const line = expr.loc?.start.line || astPath.node.loc?.start.line || 1;
113
- violations.push({
114
- filePath: relativePath,
115
- line,
116
- hazard: `Inline boolean complexity (${opCount} logical operators > 2 limit)`,
117
- rule: 'CONTROL_FLOW_INLINE_BOOLEAN',
118
- directive: 'Compose booleans into Stage 1 concepts and Stage 2 decision variables'
119
- });
120
- }
121
- }
122
- },
123
-
124
- ConditionalExpression(astPath) {
125
- if (t.isConditionalExpression(astPath.node.consequent) || t.isConditionalExpression(astPath.node.alternate)) {
126
- const line = astPath.node.loc?.start.line || 1;
127
- violations.push({
128
- filePath: relativePath,
129
- line,
130
- hazard: 'Nested ternary operator detected',
131
- rule: 'CONTROL_FLOW_NESTED_TERNARY',
132
- directive: 'Extract display states into computed descriptor objects or early returns'
133
- });
134
- }
135
- },
136
-
137
- // 4. Timer Discipline
138
- CallExpression(astPath) {
139
- const callee = astPath.node.callee;
140
- if (t.isIdentifier(callee) && (callee.name === 'setInterval' || callee.name === 'setTimeout')) {
141
- const fnParent = astPath.getFunctionParent();
142
- let hasCleanup = false;
143
- if (fnParent) {
144
- fnParent.traverse({
145
- ReturnStatement(retPath) {
146
- if (retPath.node.argument) {
147
- hasCleanup = true;
148
- }
149
- }
150
- });
151
- }
152
-
153
- if (!hasCleanup) {
154
- const line = astPath.node.loc?.start.line || 1;
155
- violations.push({
156
- filePath: relativePath,
157
- line,
158
- hazard: `Raw ${callee.name} lacking lifecycle scope disposal`,
159
- rule: 'TIMER_DISCIPLINE',
160
- directive: 'Wrap timers in self-cleaning hooks returning cleanup disposers'
161
- });
162
- }
163
- }
164
- },
165
-
166
- // 5. Type Co-location
167
- TSTypeLiteral(astPath) {
168
- if (astPath.node.members.length > 3) {
169
- if (!astPath.findParent((p) => p.isTSTypeAliasDeclaration() || p.isTSInterfaceDeclaration())) {
170
- const line = astPath.node.loc?.start.line || 1;
171
- violations.push({
172
- filePath: relativePath,
173
- line,
174
- hazard: `Inlined anonymous complex type (${astPath.node.members.length} members)`,
175
- rule: 'TYPE_COLOCATION',
176
- directive: 'Define co-located domain interfaces in types/*.d.ts'
177
- });
178
- }
179
- }
180
- }
181
- });
182
-
183
- return violations;
184
- };
185
-
186
- const IGNORED_DIRS = new Set(['node_modules', 'dist', 'build', 'vendor', '.git', '.next', '.turbo', '.output', 'out']);
3
+ import { auditCode, PILLARS, RULE_REGISTRY } from './audit/rules.js';
4
+ import {
5
+ calculateMolecularHealthScore,
6
+ calculateQuantumHealthScore,
7
+ calculatePillarBreakdown,
8
+ calculateTokenBurnAnalytics,
9
+ calculateHotspots
10
+ } from './audit/metrics.js';
11
+ import {
12
+ formatTerminalReport,
13
+ generateMarkdownReport,
14
+ groupViolationsBySeverity,
15
+ resolveTopSectionColor,
16
+ formatScorecardSection,
17
+ formatCriticalSection,
18
+ formatHighMediumSection,
19
+ formatLowSection,
20
+ formatPillarsSection,
21
+ formatHotspotsSection,
22
+ formatContextAnalysisSection,
23
+ formatFailuresSection,
24
+ formatPassesSection,
25
+ formatGradeFSection,
26
+ formatGradeDSection,
27
+ formatGradeCSection,
28
+ formatGradeBSection,
29
+ formatGradeASection,
30
+ getChemicalXAsciiBanner,
31
+ getAsciiGradeLines,
32
+ formatAsciiGrade,
33
+ getReportCardAsciiLines,
34
+ REPORT_CARD_ASCII
35
+ } from './audit/reporter.js';
36
+
37
+ const IGNORED_DIRS = new Set([
38
+ 'node_modules',
39
+ 'dist',
40
+ 'build',
41
+ 'vendor',
42
+ '.git',
43
+ '.next',
44
+ '.turbo',
45
+ '.output',
46
+ '.nuxt',
47
+ '.cache',
48
+ 'out'
49
+ ]);
187
50
 
188
51
  const isSourceFile = (name) => {
189
52
  return (
@@ -195,9 +58,19 @@ const isSourceFile = (name) => {
195
58
  );
196
59
  };
197
60
 
198
- export const scanDirectory = (targetDir, baseDir) => {
199
- let results = [];
200
- if (!fs.existsSync(targetDir)) return results;
61
+ export const auditFile = (filePath, relativePath) => {
62
+ const content = fs.readFileSync(filePath, 'utf-8');
63
+ return auditCode(content, filePath, relativePath);
64
+ };
65
+
66
+ export const scanTree = (targetDir, baseDir) => {
67
+ let violations = [];
68
+ let fileStats = [];
69
+ let totalHooks = 0;
70
+
71
+ if (!fs.existsSync(targetDir)) {
72
+ return { violations, fileStats, totalHooks };
73
+ }
201
74
 
202
75
  const entries = fs.readdirSync(targetDir, { withFileTypes: true });
203
76
  for (const entry of entries) {
@@ -206,48 +79,172 @@ export const scanDirectory = (targetDir, baseDir) => {
206
79
 
207
80
  if (entry.isDirectory()) {
208
81
  if (!IGNORED_DIRS.has(entry.name)) {
209
- results = results.concat(scanDirectory(fullPath, baseDir));
82
+ const sub = scanTree(fullPath, baseDir);
83
+ violations = violations.concat(sub.violations);
84
+ fileStats = fileStats.concat(sub.fileStats);
85
+ totalHooks += sub.totalHooks;
210
86
  }
211
87
  } else if (isSourceFile(entry.name)) {
212
- results = results.concat(auditFile(fullPath, relPath));
88
+ const content = fs.readFileSync(fullPath, 'utf-8');
89
+ const lines = content.split('\n');
90
+ const isMolecule = relPath.includes('molecules') || relPath.includes('/m-') || entry.name.startsWith('m-');
91
+
92
+ fileStats.push({
93
+ fullPath,
94
+ relativePath: relPath,
95
+ lineCount: lines.length,
96
+ charCount: content.length,
97
+ isMolecule
98
+ });
99
+
100
+ // Count hook declarations / invocations for metric
101
+ const hookMatches = content.match(/\buse[A-Z0-9]\w*\b/g);
102
+ if (hookMatches) {
103
+ totalHooks += hookMatches.length;
104
+ }
105
+
106
+ const fileViolations = auditCode(content, fullPath, relPath);
107
+ violations = violations.concat(fileViolations);
213
108
  }
214
109
  }
215
- return results;
110
+
111
+ return { violations, fileStats, totalHooks };
112
+ };
113
+
114
+ export const scanDirectory = (targetDir, baseDir) => {
115
+ const { violations } = scanTree(targetDir, baseDir);
116
+ return violations;
216
117
  };
217
118
 
218
- const countTotalScannedFiles = (targetDir) => {
219
- let count = 0;
220
- if (!fs.existsSync(targetDir)) return count;
119
+ export const runAudit = (targetDir = 'src', options = {}) => {
120
+ const cwd = process.cwd();
121
+ const absoluteTarget = path.resolve(cwd, targetDir);
122
+ const { violations, fileStats, totalHooks } = scanTree(absoluteTarget, cwd);
221
123
 
222
- const entries = fs.readdirSync(targetDir, { withFileTypes: true });
223
- for (const entry of entries) {
224
- const fullPath = path.join(targetDir, entry.name);
225
- if (entry.isDirectory()) {
226
- if (!IGNORED_DIRS.has(entry.name)) {
227
- count += countTotalScannedFiles(fullPath);
124
+ const scannedFiles = fileStats.length;
125
+ const totalLoc = fileStats.reduce((acc, f) => acc + f.lineCount, 0);
126
+ const avgLoc = scannedFiles > 0 ? Math.round(totalLoc / scannedFiles) : 0;
127
+
128
+ let largestFile = { filePath: '', lineCount: 0 };
129
+ let moleculeCount = 0;
130
+ let moleculeCompliantCount = 0;
131
+
132
+ for (const f of fileStats) {
133
+ if (f.lineCount > largestFile.lineCount) {
134
+ largestFile = { filePath: f.relativePath, lineCount: f.lineCount };
135
+ }
136
+ if (f.isMolecule) {
137
+ moleculeCount += 1;
138
+ if (f.lineCount <= 100) {
139
+ moleculeCompliantCount += 1;
228
140
  }
229
- } else if (isSourceFile(entry.name)) {
230
- count += 1;
231
141
  }
232
142
  }
233
- return count;
234
- };
235
143
 
236
- export const runAudit = (targetDir = 'src') => {
237
- const cwd = process.cwd();
238
- const absoluteTarget = path.resolve(cwd, targetDir);
239
- const violations = scanDirectory(absoluteTarget, cwd);
240
- const scannedFiles = countTotalScannedFiles(absoluteTarget);
144
+ const moleculeCompliantPct = moleculeCount > 0
145
+ ? Math.round((moleculeCompliantCount / moleculeCount) * 100)
146
+ : 100;
147
+
148
+ const metrics = {
149
+ scannedFiles,
150
+ totalLoc,
151
+ avgLoc,
152
+ largestFile,
153
+ moleculeCount,
154
+ moleculeCompliantCount,
155
+ moleculeCompliantPct,
156
+ hookCount: totalHooks
157
+ };
241
158
 
242
- return {
159
+ const health = calculateMolecularHealthScore(violations, scannedFiles);
160
+ const pillars = calculatePillarBreakdown(violations);
161
+ const contextAnalysis = calculateTokenBurnAnalytics(fileStats, options);
162
+ const hotspots = calculateHotspots(violations, fileStats, 5);
163
+
164
+ const report = {
243
165
  scannedFiles,
244
166
  totalViolations: violations.length,
167
+ metrics,
168
+ health,
169
+ pillars,
170
+ contextAnalysis,
171
+ hotspots,
245
172
  violations
246
173
  };
174
+
175
+ if (options.outputFile) {
176
+ const outPath = path.resolve(cwd, options.outputFile);
177
+ const mdContent = generateMarkdownReport(report);
178
+ fs.writeFileSync(outPath, mdContent, 'utf-8');
179
+ }
180
+
181
+ return report;
182
+ };
183
+
184
+ export * from './audit/social.js';
185
+ export * from './audit/prompts.js';
186
+ export * from './audit/history.js';
187
+
188
+ export {
189
+ calculateMolecularHealthScore,
190
+ calculateQuantumHealthScore,
191
+ calculatePillarBreakdown,
192
+ calculateTokenBurnAnalytics,
193
+ calculateHotspots,
194
+ PILLARS,
195
+ RULE_REGISTRY,
196
+ formatTerminalReport,
197
+ generateMarkdownReport,
198
+ groupViolationsBySeverity,
199
+ resolveTopSectionColor,
200
+ formatScorecardSection,
201
+ formatCriticalSection,
202
+ formatHighMediumSection,
203
+ formatLowSection,
204
+ formatPillarsSection,
205
+ formatHotspotsSection,
206
+ formatContextAnalysisSection,
207
+ formatFailuresSection,
208
+ formatPassesSection,
209
+ formatGradeFSection,
210
+ formatGradeDSection,
211
+ formatGradeCSection,
212
+ formatGradeBSection,
213
+ formatGradeASection,
214
+ getChemicalXAsciiBanner,
215
+ getAsciiGradeLines,
216
+ formatAsciiGrade,
217
+ getReportCardAsciiLines,
218
+ REPORT_CARD_ASCII
247
219
  };
248
220
 
249
221
  export default {
250
222
  auditFile,
251
223
  scanDirectory,
252
- runAudit
224
+ runAudit,
225
+ formatTerminalReport,
226
+ generateMarkdownReport,
227
+ groupViolationsBySeverity,
228
+ resolveTopSectionColor,
229
+ formatScorecardSection,
230
+ formatCriticalSection,
231
+ formatHighMediumSection,
232
+ formatLowSection,
233
+ formatPillarsSection,
234
+ formatHotspotsSection,
235
+ formatContextAnalysisSection,
236
+ formatFailuresSection,
237
+ formatPassesSection,
238
+ formatGradeFSection,
239
+ formatGradeDSection,
240
+ formatGradeCSection,
241
+ formatGradeBSection,
242
+ formatGradeASection,
243
+ getChemicalXAsciiBanner,
244
+ getAsciiGradeLines,
245
+ formatAsciiGrade,
246
+ getReportCardAsciiLines,
247
+ REPORT_CARD_ASCII,
248
+ PILLARS,
249
+ RULE_REGISTRY
253
250
  };
package/cli/help.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function printHelp(): void;
package/cli/help.js ADDED
@@ -0,0 +1,136 @@
1
+ import { renderBanner } from './terminal.js';
2
+
3
+ export const printHelp = () => {
4
+ renderBanner('Chemical X Protocol: CLI Usage & Reference');
5
+
6
+ const BOLD = '\x1b[1m';
7
+ const CYAN = '\x1b[36m';
8
+ const DIM = '\x1b[2m';
9
+ const YELLOW = '\x1b[33m';
10
+ const GREEN = '\x1b[32m';
11
+ const RESET = '\x1b[0m';
12
+
13
+ const out = [
14
+ `${BOLD}USAGE${RESET}`,
15
+ ` ${CYAN}npx chemx${RESET} <command> [options]`,
16
+ ` ${CYAN}npm create chemx${RESET} [directory]`,
17
+ '',
18
+ `${BOLD}COMMANDS${RESET}`,
19
+ ` ${CYAN}audit${RESET} [options]`,
20
+ ` Run the 7-Pillar Molecular Architecture static analysis audit.`,
21
+ ` Scans AST for line budgets, control flow booleans, nested ternaries,`,
22
+ ` hook limits, self-cleaning timers, and Anti-Tailwind-Soup compliance.`,
23
+ ` Computes Molecular Health Index (MHI: 0-100) and letter grades (A+ to F).`,
24
+ ` Defaults to interactive zero-scroll Gum terminal dashboard.`,
25
+ '',
26
+ ` ${CYAN}generate${RESET} <m-name> ${DIM}(aliases: capsule, add)${RESET}`,
27
+ ` Scaffold an isolated crystalline molecule capsule directory:`,
28
+ ` ${DIM}- ${RESET}<m-name>/<m-name>.tsx ${DIM}(declarative component < 50 lines of code)${RESET}`,
29
+ ` ${DIM}- ${RESET}<m-name>/types.d.ts ${DIM}(props and emits interfaces)${RESET}`,
30
+ ` ${DIM}- ${RESET}<m-name>/index.ts ${DIM}(clean public barrel export)${RESET}`,
31
+ ` Free evaluation mode supported with non-blocking license reminder.`,
32
+ ` Example: ${CYAN}npx chemx generate m-user-avatar${RESET}`,
33
+ '',
34
+ ` ${CYAN}init${RESET} [directory]`,
35
+ ` ${YELLOW}[PAID]${RESET} Drop full Chemical X blueprints, core hooks (toResult,`,
36
+ ` useAsyncData, useSelfCleaningTimer), and AGENTS.md directives into`,
37
+ ` an existing codebase. Default destination: ${CYAN}src/chemical-x${RESET}.`,
38
+ ` Requires Single Dev ($27) or Team Power Puff ($97: Unlimited Lifetime) license.`,
39
+ '',
40
+ ` ${CYAN}create${RESET} [directory] ${DIM}(or: npm create chemx [directory])${RESET}`,
41
+ ` ${YELLOW}[PAID]${RESET} Scaffold a complete, clean-slate project wired with full`,
42
+ ` Chemical X molecular standards, pre-commit line budget hooks, and rules.`,
43
+ ` Requires Single Dev ($27) or Team Power Puff ($97: Unlimited Lifetime) license.`,
44
+ '',
45
+ ` ${CYAN}install-hooks${RESET} [directory] ${DIM}(aliases: hook, setup-ci)${RESET}`,
46
+ ` ${GREEN}[FREE]${RESET} Install git pre-commit hook (.git/hooks/pre-commit) and`,
47
+ ` GitHub Actions CI workflow (.github/workflows/chemx-audit.yml).`,
48
+ ` Enforces 500-line file ceilings, 100-line molecule budgets, and configurable`,
49
+ ` minimum grade/score thresholds with automatic AI prompt clipboard copying.`,
50
+ ` Example: ${CYAN}npx chemx install-hooks${RESET}`,
51
+ '',
52
+ ` ${CYAN}help${RESET}, ${CYAN}--help${RESET}, ${CYAN}-h${RESET}`,
53
+ ` Display this comprehensive CLI documentation and options guide.`,
54
+ '',
55
+ `${BOLD}AUDIT OPTIONS & FLAGS${RESET}`,
56
+ ` ${CYAN}--dir=<path>${RESET}`,
57
+ ` Directory to analyze. Defaults to ${CYAN}src${RESET} if present, else current working directory.`,
58
+ ` Example: ${CYAN}npx chemx audit --dir=apps/web/src${RESET}`,
59
+ '',
60
+ ` ${CYAN}--json${RESET}`,
61
+ ` Output structured machine-readable JSON report to stdout.`,
62
+ ` Ideal for CI/CD pipelines, automated gating, and custom tooling.`,
63
+ '',
64
+ ` ${CYAN}--markdown${RESET}, ${CYAN}--md${RESET}`,
65
+ ` Output formatted GitHub Flavored Markdown report to stdout.`,
66
+ '',
67
+ ` ${CYAN}--output=<file>${RESET}, ${CYAN}-o=<file>${RESET}`,
68
+ ` Save formatted Markdown report directly to the specified file path.`,
69
+ ` Example: ${CYAN}npx chemx audit --output=AUDIT_REPORT.md${RESET}`,
70
+ '',
71
+ ` ${CYAN}--unroll${RESET}, ${CYAN}--all${RESET}`,
72
+ ` Stream full unrolled report directly to terminal without interactive Gum menu.`,
73
+ '',
74
+ ` ${CYAN}--share${RESET}, ${CYAN}--post${RESET}`,
75
+ ` Publish or update report on GitHub Discussions without entering dashboard.`,
76
+ ` Automatically archives prior audit snapshots as discussion comments.`,
77
+ '',
78
+ ` ${CYAN}--strict${RESET}`,
79
+ ` Strict CI failure mode: exits with status 1 on ANY violation, including`,
80
+ ` Low hygiene issues (typography and console logging).`,
81
+ '',
82
+ ` ${CYAN}--min-grade=<tier>${RESET}`,
83
+ ` Fail audit if Molecular Health Index grade falls below tier (A+, A, B, C, D).`,
84
+ ` Default: None (or B when executed via pre-commit gatekeeper).`,
85
+ '',
86
+ ` ${CYAN}--min-score=<0-100>${RESET}`,
87
+ ` Fail audit if Molecular Health Index score falls below number (e.g. 80).`,
88
+ '',
89
+ ` ${CYAN}--model=<claude|gpt4o|blended>${RESET}`,
90
+ ` Pricing baseline for context burn dollar calculations ($3.00/1M blended).`,
91
+ '',
92
+ ` ${CYAN}--prompt-on-fail${RESET}, ${CYAN}--copy-prompt${RESET}`,
93
+ ` Automatically copy the synthesized AI refactoring prompt to system clipboard`,
94
+ ` when architectural violations or threshold failures are detected.`,
95
+ '',
96
+ ` ${CYAN}--license=<key>${RESET}`,
97
+ ` Pass Chemical X Sponsor or Team license key non-interactively via CLI.`,
98
+ ` Tiers: Single Dev ($27) | Team Power Puff ($97: Unlimited Lifetime).`,
99
+ '',
100
+ `${BOLD}ENVIRONMENT VARIABLES${RESET}`,
101
+ ` ${GREEN}CHEMX_MIN_GRADE${RESET}`,
102
+ ` Default minimum grade threshold for pre-commit gatekeeper (default: B).`,
103
+ '',
104
+ ` ${GREEN}CHEMX_MIN_SCORE${RESET}`,
105
+ ` Default minimum score threshold for pre-commit gatekeeper (default: 80).`,
106
+ '',
107
+ ` ${GREEN}GH_TOKEN${RESET} / ${GREEN}GITHUB_TOKEN${RESET}`,
108
+ ` GitHub personal access token for automated discussion publishing via GraphQL.`,
109
+ ` If omitted, the CLI automatically delegates to local ${CYAN}gh${RESET} CLI authentication.`,
110
+ '',
111
+ ` ${GREEN}CHEMICAL_X_API_URL${RESET}`,
112
+ ` Custom licensing edge verification endpoint. Default: ${CYAN}https://chemicalx.xophz.com${RESET}.`,
113
+ '',
114
+ `${BOLD}EXAMPLES${RESET}`,
115
+ ` ${DIM}# Run interactive audit dashboard with ASCII banner and health scorecard:${RESET}`,
116
+ ` ${CYAN}npx chemx audit${RESET}`,
117
+ '',
118
+ ` ${DIM}# Scan a sub-package in strict mode for CI gating:${RESET}`,
119
+ ` ${CYAN}npx chemx audit --dir=packages/core --strict${RESET}`,
120
+ '',
121
+ ` ${DIM}# Export markdown scorecard to file:${RESET}`,
122
+ ` ${CYAN}npx chemx audit --markdown --output=AUDIT.md${RESET}`,
123
+ '',
124
+ ` ${DIM}# Pipe JSON metrics to jq:${RESET}`,
125
+ ` ${CYAN}npx chemx audit --json | jq .health${RESET}`,
126
+ '',
127
+ ` ${DIM}# Generate a new molecule capsule:${RESET}`,
128
+ ` ${CYAN}npx chemx generate m-spark-kpi${RESET}`,
129
+ '',
130
+ ` ${DIM}# Scaffold a new project:${RESET}`,
131
+ ` ${CYAN}npm create chemx my-awesome-app${RESET}`,
132
+ ''
133
+ ].join('\n');
134
+
135
+ process.stdout.write(out + '\n');
136
+ };