@chemx/starter-kit 26.9.9-786 → 26.9.11-362

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 (40) 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 +63 -0
  4. package/cli/audit/history.js +352 -0
  5. package/cli/audit/metrics.js +179 -0
  6. package/cli/audit/prompts.js +174 -0
  7. package/cli/audit/reporter-grades.js +259 -0
  8. package/cli/audit/reporter-markdown.js +136 -0
  9. package/cli/audit/reporter-utils.js +107 -0
  10. package/cli/audit/reporter.js +459 -0
  11. package/cli/audit/rules-helpers.js +109 -0
  12. package/cli/audit/rules-registry.js +97 -0
  13. package/cli/audit/rules.js +123 -0
  14. package/cli/audit/social-constants.js +4 -0
  15. package/cli/audit/social-gh.js +126 -0
  16. package/cli/audit/social-git.js +214 -0
  17. package/cli/audit/social-http.js +222 -0
  18. package/cli/audit/social-publisher.js +193 -0
  19. package/cli/audit/social.d.ts +66 -0
  20. package/cli/audit/social.js +254 -0
  21. package/cli/audit/types.d.ts +131 -0
  22. package/cli/audit.d.ts +3 -24
  23. package/cli/audit.js +195 -210
  24. package/cli/help.d.ts +1 -0
  25. package/cli/help.js +136 -0
  26. package/cli/index.js +128 -566
  27. package/cli/installer-templates.js +80 -0
  28. package/cli/installer.d.ts +20 -0
  29. package/cli/installer.js +56 -0
  30. package/cli/license.js +320 -0
  31. package/cli/navigator-conversion.js +100 -0
  32. package/cli/navigator-grades.js +70 -0
  33. package/cli/navigator-paged.js +86 -0
  34. package/cli/navigator-share.js +129 -0
  35. package/cli/navigator.d.ts +24 -0
  36. package/cli/navigator.js +400 -0
  37. package/cli/scaffold.js +148 -0
  38. package/cli/terminal.js +126 -0
  39. package/docs/CHANGELOG.md +73 -0
  40. package/package.json +11 -10
package/cli/audit.js CHANGED
@@ -1,189 +1,48 @@
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
+ } from './audit/reporter.js';
32
+
33
+ const IGNORED_DIRS = new Set([
34
+ 'node_modules',
35
+ 'dist',
36
+ 'build',
37
+ 'vendor',
38
+ '.git',
39
+ '.next',
40
+ '.turbo',
41
+ '.output',
42
+ '.nuxt',
43
+ '.cache',
44
+ 'out'
45
+ ]);
187
46
 
188
47
  const isSourceFile = (name) => {
189
48
  return (
@@ -195,9 +54,19 @@ const isSourceFile = (name) => {
195
54
  );
196
55
  };
197
56
 
198
- export const scanDirectory = (targetDir, baseDir) => {
199
- let results = [];
200
- if (!fs.existsSync(targetDir)) return results;
57
+ export const auditFile = (filePath, relativePath) => {
58
+ const content = fs.readFileSync(filePath, 'utf-8');
59
+ return auditCode(content, filePath, relativePath);
60
+ };
61
+
62
+ export const scanTree = (targetDir, baseDir) => {
63
+ let violations = [];
64
+ let fileStats = [];
65
+ let totalHooks = 0;
66
+
67
+ if (!fs.existsSync(targetDir)) {
68
+ return { violations, fileStats, totalHooks };
69
+ }
201
70
 
202
71
  const entries = fs.readdirSync(targetDir, { withFileTypes: true });
203
72
  for (const entry of entries) {
@@ -206,48 +75,164 @@ export const scanDirectory = (targetDir, baseDir) => {
206
75
 
207
76
  if (entry.isDirectory()) {
208
77
  if (!IGNORED_DIRS.has(entry.name)) {
209
- results = results.concat(scanDirectory(fullPath, baseDir));
78
+ const sub = scanTree(fullPath, baseDir);
79
+ violations = violations.concat(sub.violations);
80
+ fileStats = fileStats.concat(sub.fileStats);
81
+ totalHooks += sub.totalHooks;
210
82
  }
211
83
  } else if (isSourceFile(entry.name)) {
212
- results = results.concat(auditFile(fullPath, relPath));
84
+ const content = fs.readFileSync(fullPath, 'utf-8');
85
+ const lines = content.split('\n');
86
+ const isMolecule = relPath.includes('molecules') || relPath.includes('/m-') || entry.name.startsWith('m-');
87
+
88
+ fileStats.push({
89
+ fullPath,
90
+ relativePath: relPath,
91
+ lineCount: lines.length,
92
+ charCount: content.length,
93
+ isMolecule
94
+ });
95
+
96
+ // Count hook declarations / invocations for metric
97
+ const hookMatches = content.match(/\buse[A-Z0-9]\w*\b/g);
98
+ if (hookMatches) {
99
+ totalHooks += hookMatches.length;
100
+ }
101
+
102
+ const fileViolations = auditCode(content, fullPath, relPath);
103
+ violations = violations.concat(fileViolations);
213
104
  }
214
105
  }
215
- return results;
106
+
107
+ return { violations, fileStats, totalHooks };
108
+ };
109
+
110
+ export const scanDirectory = (targetDir, baseDir) => {
111
+ const { violations } = scanTree(targetDir, baseDir);
112
+ return violations;
216
113
  };
217
114
 
218
- const countTotalScannedFiles = (targetDir) => {
219
- let count = 0;
220
- if (!fs.existsSync(targetDir)) return count;
115
+ export const runAudit = (targetDir = 'src', options = {}) => {
116
+ const cwd = process.cwd();
117
+ const absoluteTarget = path.resolve(cwd, targetDir);
118
+ const { violations, fileStats, totalHooks } = scanTree(absoluteTarget, cwd);
221
119
 
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);
120
+ const scannedFiles = fileStats.length;
121
+ const totalLoc = fileStats.reduce((acc, f) => acc + f.lineCount, 0);
122
+ const avgLoc = scannedFiles > 0 ? Math.round(totalLoc / scannedFiles) : 0;
123
+
124
+ let largestFile = { filePath: '', lineCount: 0 };
125
+ let moleculeCount = 0;
126
+ let moleculeCompliantCount = 0;
127
+
128
+ for (const f of fileStats) {
129
+ if (f.lineCount > largestFile.lineCount) {
130
+ largestFile = { filePath: f.relativePath, lineCount: f.lineCount };
131
+ }
132
+ if (f.isMolecule) {
133
+ moleculeCount += 1;
134
+ if (f.lineCount <= 100) {
135
+ moleculeCompliantCount += 1;
228
136
  }
229
- } else if (isSourceFile(entry.name)) {
230
- count += 1;
231
137
  }
232
138
  }
233
- return count;
234
- };
235
139
 
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);
140
+ const moleculeCompliantPct = moleculeCount > 0
141
+ ? Math.round((moleculeCompliantCount / moleculeCount) * 100)
142
+ : 100;
143
+
144
+ const metrics = {
145
+ scannedFiles,
146
+ totalLoc,
147
+ avgLoc,
148
+ largestFile,
149
+ moleculeCount,
150
+ moleculeCompliantCount,
151
+ moleculeCompliantPct,
152
+ hookCount: totalHooks
153
+ };
241
154
 
242
- return {
155
+ const health = calculateMolecularHealthScore(violations, scannedFiles);
156
+ const pillars = calculatePillarBreakdown(violations);
157
+ const contextAnalysis = calculateTokenBurnAnalytics(fileStats, options);
158
+ const hotspots = calculateHotspots(violations, fileStats, 5);
159
+
160
+ const report = {
243
161
  scannedFiles,
244
162
  totalViolations: violations.length,
163
+ metrics,
164
+ health,
165
+ pillars,
166
+ contextAnalysis,
167
+ hotspots,
245
168
  violations
246
169
  };
170
+
171
+ if (options.outputFile) {
172
+ const outPath = path.resolve(cwd, options.outputFile);
173
+ const mdContent = generateMarkdownReport(report);
174
+ fs.writeFileSync(outPath, mdContent, 'utf-8');
175
+ }
176
+
177
+ return report;
178
+ };
179
+
180
+ export * from './audit/social.js';
181
+ export * from './audit/prompts.js';
182
+ export * from './audit/history.js';
183
+
184
+ export {
185
+ calculateMolecularHealthScore,
186
+ calculateQuantumHealthScore,
187
+ calculatePillarBreakdown,
188
+ calculateTokenBurnAnalytics,
189
+ calculateHotspots,
190
+ PILLARS,
191
+ RULE_REGISTRY,
192
+ formatTerminalReport,
193
+ generateMarkdownReport,
194
+ groupViolationsBySeverity,
195
+ resolveTopSectionColor,
196
+ formatScorecardSection,
197
+ formatCriticalSection,
198
+ formatHighMediumSection,
199
+ formatLowSection,
200
+ formatPillarsSection,
201
+ formatHotspotsSection,
202
+ formatContextAnalysisSection,
203
+ formatFailuresSection,
204
+ formatPassesSection,
205
+ formatGradeFSection,
206
+ formatGradeDSection,
207
+ formatGradeCSection,
208
+ formatGradeBSection,
209
+ formatGradeASection,
210
+ getChemicalXAsciiBanner
247
211
  };
248
212
 
249
213
  export default {
250
214
  auditFile,
251
215
  scanDirectory,
252
- runAudit
216
+ runAudit,
217
+ formatTerminalReport,
218
+ generateMarkdownReport,
219
+ groupViolationsBySeverity,
220
+ resolveTopSectionColor,
221
+ formatScorecardSection,
222
+ formatCriticalSection,
223
+ formatHighMediumSection,
224
+ formatLowSection,
225
+ formatPillarsSection,
226
+ formatHotspotsSection,
227
+ formatContextAnalysisSection,
228
+ formatFailuresSection,
229
+ formatPassesSection,
230
+ formatGradeFSection,
231
+ formatGradeDSection,
232
+ formatGradeCSection,
233
+ formatGradeBSection,
234
+ formatGradeASection,
235
+ getChemicalXAsciiBanner,
236
+ PILLARS,
237
+ RULE_REGISTRY
253
238
  };
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 LOC)${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 💯 ($47: 100 Seats) 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 💯 ($47: 100 Seats) 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 💯 ($47: 100 Device Seats / Honor System).`,
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
+ };