@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.
@@ -38,9 +38,9 @@ export const resolveBadgeColor = (score) => {
38
38
  };
39
39
 
40
40
  export const resolveHotspotTierText = (lineCount) => {
41
- if (lineCount >= 2000) return '🔴 **CRITICAL (>= 2,000 LOC)**';
42
- if (lineCount >= 1000) return '🟠 **SEVERE (>= 1,000 LOC)**';
43
- if (lineCount > 500) return '🟡 **WARNING (> 500 LOC)**';
41
+ if (lineCount >= 2000) return '🔴 **CRITICAL (>= 2,000 lines of code)**';
42
+ if (lineCount >= 1000) return '🟠 **SEVERE (>= 1,000 lines of code)**';
43
+ if (lineCount > 500) return '🟡 **WARNING (> 500 lines of code)**';
44
44
  return '🟢 Compliant';
45
45
  };
46
46
 
@@ -62,6 +62,25 @@ export const formatWebUrl = (url) => {
62
62
  return `[${href}](${href})`;
63
63
  };
64
64
 
65
+ export const resolveExcessCostPerPass = (tokensObj, fallbackCostPerMillion = 3.0) => {
66
+ if (tokensObj?.excessCostPerPass !== undefined) return tokensObj.excessCostPerPass;
67
+ const costPerMillion = tokensObj?.costPerMillion || fallbackCostPerMillion;
68
+ const excess = tokensObj?.estimatedExcessTokens || 0;
69
+ return Number(((excess / 1000000) * costPerMillion).toFixed(3));
70
+ };
71
+
72
+ export const resolveMonthlyWastePerDev = (tokensObj, fallbackCostPerMillion = 3.0) => {
73
+ if (tokensObj?.monthlyWastePerDev !== undefined) return tokensObj.monthlyWastePerDev;
74
+ const pass = resolveExcessCostPerPass(tokensObj, fallbackCostPerMillion);
75
+ return Number((pass * 20 * 5 * 4).toFixed(2));
76
+ };
77
+
78
+ export const resolveWeeklyWastePerDev = (tokensObj, fallbackCostPerMillion = 3.0) => {
79
+ if (tokensObj?.weeklyWastePerDev !== undefined) return tokensObj.weeklyWastePerDev;
80
+ const pass = resolveExcessCostPerPass(tokensObj, fallbackCostPerMillion);
81
+ return Number((pass * 20 * 5).toFixed(2));
82
+ };
83
+
65
84
  export const generateDiscussionContent = (report, username, projectName = 'Codebase', repoUrl = '', liveUrl = '') => {
66
85
  const { health, metrics, pillars, hotspots, contextAnalysis, violations } = report;
67
86
  const isHighScoring = health.score >= 80;
@@ -90,8 +109,14 @@ export const generateDiscussionContent = (report, username, projectName = 'Codeb
90
109
  }
91
110
  }
92
111
  lines.push(`* **Molecular Health Index**: **${health.score} / 100** (Grade: **${health.grade}** - ${health.label})`);
93
- lines.push(`* **Source Files Analyzed**: ${metrics.scannedFiles} files (${metrics.totalLoc} total LOC)`);
112
+ lines.push(`* **Source Files Analyzed**: ${metrics.scannedFiles} files (${metrics.totalLoc} total lines of code)`);
94
113
  lines.push(`* **Token Reduction Potential**: **${contextAnalysis.potentialSavingsPct}%** (Estimated ${contextAnalysis.estimatedTokens.toLocaleString()} tokens)`);
114
+ const costPass = resolveExcessCostPerPass(contextAnalysis);
115
+ const costMonth = resolveMonthlyWastePerDev(contextAnalysis);
116
+ const costWeek = resolveWeeklyWastePerDev(contextAnalysis);
117
+ const pricingModel = contextAnalysis?.pricingModel || 'Frontier Blended ($3.00/1M)';
118
+ lines.push(`* **Monolith Cost per Turn**: **$${costPass.toFixed(3)}** (${pricingModel})`);
119
+ lines.push(`* **Projected Dev Context Tax**: **$${costMonth.toFixed(2)} / mo** per engineer ($${costWeek.toFixed(2)} / wk)`);
95
120
  lines.push('');
96
121
  lines.push('---');
97
122
  lines.push('');
@@ -130,11 +155,11 @@ export const generateDiscussionContent = (report, username, projectName = 'Codeb
130
155
  lines.push('');
131
156
  lines.push('## 2. Monolith & Architectural Hazard Summary');
132
157
  lines.push('');
133
- lines.push(`* **Monolith Files (> 500 LOC)**: **${totalMonoliths} files**`);
158
+ lines.push(`* **Monolith Files (> 500 lines of code)**: **${totalMonoliths} files**`);
134
159
  if (totalMonoliths > 0) {
135
- lines.push(` * Warning Tier (500 - 999 LOC): ${warningMonoliths} files`);
136
- lines.push(` * Severe Tier (1,000 - 1,999 LOC): ${severeMonoliths} files`);
137
- lines.push(` * Extreme Monoliths (2,000+ LOC): ${extremeMonoliths} files`);
160
+ lines.push(` * Warning Tier (500 - 999 lines of code): ${warningMonoliths} files`);
161
+ lines.push(` * Severe Tier (1,000 - 1,999 lines of code): ${severeMonoliths} files`);
162
+ lines.push(` * Extreme Monoliths (2,000+ lines of code): ${extremeMonoliths} files`);
138
163
  }
139
164
  lines.push(`* **Hazard Breakdown**: Critical: **${critical.length}** | High/Med: **${high.length + medium.length}** | Low: **${low.length}**`);
140
165
  lines.push('');
@@ -146,7 +171,7 @@ export const generateDiscussionContent = (report, username, projectName = 'Codeb
146
171
  lines.push('This project follows Chemical X Molecular Architecture principles with isolated capsules and self-cleaning hooks.');
147
172
  } else {
148
173
  lines.push('### Seeking Refactoring Feedback');
149
- lines.push('Looking for recommendations on breaking down flagged monolithic debts into crystalline molecule capsules (< 100 LOC). Any advice is welcome!');
174
+ lines.push('Looking for recommendations on breaking down flagged monolithic debts into crystalline molecule capsules (< 100 lines of code). Any advice is welcome!');
150
175
  }
151
176
  lines.push('');
152
177
  lines.push('*Audited using [Chemical X Protocol Starter Kit](https://github.com/Chemical-X-Protocol/awesome-secret-sauce).*');
@@ -187,6 +212,28 @@ export const generateTransformationDiscussionContent = (
187
212
  return isGood ? `🟢 **${sign}**` : `🔴 **${sign}**`;
188
213
  };
189
214
 
215
+ const costPassBefore = resolveExcessCostPerPass(beforeSnapshot.tokens);
216
+ const costPassAfter = resolveExcessCostPerPass(afterSnapshot.tokens);
217
+ const costPassDelta = Number((costPassAfter - costPassBefore).toFixed(3));
218
+
219
+ const monthlyTaxBefore = resolveMonthlyWastePerDev(beforeSnapshot.tokens);
220
+ const monthlyTaxAfter = resolveMonthlyWastePerDev(afterSnapshot.tokens);
221
+ const monthlyTaxDelta = Number((monthlyTaxAfter - monthlyTaxBefore).toFixed(2));
222
+
223
+ const formatCostPassDelta = (val) => {
224
+ if (val === 0) return '0 (No change)';
225
+ const isGood = val < 0;
226
+ const sign = val > 0 ? `+$${val.toFixed(3)}` : `-$${Math.abs(val).toFixed(3)}`;
227
+ return isGood ? `🟢 **${sign}**` : `🔴 **${sign}**`;
228
+ };
229
+
230
+ const formatMonthlyTaxDelta = (val) => {
231
+ if (val === 0) return '0 (No change)';
232
+ const isGood = val < 0;
233
+ const sign = val > 0 ? `+$${val.toFixed(2)}/mo` : `-$${Math.abs(val).toFixed(2)}/mo`;
234
+ return isGood ? `🟢 **${sign}**` : `🔴 **${sign}**`;
235
+ };
236
+
190
237
  const lines = [];
191
238
  lines.push(`# 🚀 Architectural Transformation: ${projectName}`);
192
239
  lines.push('');
@@ -214,8 +261,10 @@ export const generateTransformationDiscussionContent = (
214
261
  lines.push(`| **Molecular Health (MHI)** | ${scoreBefore} / 100 (${beforeSnapshot.health.grade}) | ${scoreAfter} / 100 (${afterSnapshot.health.grade}) | ${formatDelta(scoreDelta)} |`);
215
262
  lines.push(`| **Critical Hazards** | ${beforeSnapshot.violations.critical} | ${afterSnapshot.violations.critical} | ${formatDelta(critDelta, true)} |`);
216
263
  lines.push(`| **Total Violations** | ${beforeSnapshot.violations.total} | ${afterSnapshot.violations.total} | ${formatDelta(totalDelta, true)} |`);
217
- lines.push(`| **Monolith Files (>500 LOC)** | ${beforeSnapshot.monoliths.total} | ${afterSnapshot.monoliths.total} | ${formatDelta(monoDelta, true)} |`);
264
+ lines.push(`| **Monolith Files (> 500 lines of code)** | ${beforeSnapshot.monoliths.total} | ${afterSnapshot.monoliths.total} | ${formatDelta(monoDelta, true)} |`);
218
265
  lines.push(`| **Excess Token Burn** | ${beforeSnapshot.tokens.estimatedExcessTokens.toLocaleString()} tok | ${afterSnapshot.tokens.estimatedExcessTokens.toLocaleString()} tok | ${formatDelta(tokensDelta, true)} |`);
266
+ lines.push(`| **Monolith Cost per Turn** | $${costPassBefore.toFixed(3)} | $${costPassAfter.toFixed(3)} | ${formatCostPassDelta(costPassDelta)} |`);
267
+ lines.push(`| **Dev Context Tax (Monthly)** | $${monthlyTaxBefore.toFixed(2)}/mo | $${monthlyTaxAfter.toFixed(2)}/mo | ${formatMonthlyTaxDelta(monthlyTaxDelta)} |`);
219
268
  lines.push('');
220
269
  lines.push('---');
221
270
  lines.push('');
@@ -241,7 +290,7 @@ export const generateTransformationDiscussionContent = (
241
290
  lines.push('---');
242
291
  lines.push('');
243
292
  lines.push('### Community Takeaway');
244
- lines.push('Refactored using Chemical X Molecular Architecture standards. Monoliths decomposed into crystalline domain capsules (< 100 LOC) with self-cleaning hooks.');
293
+ lines.push('Refactored using Chemical X Molecular Architecture standards. Monoliths decomposed into crystalline domain capsules (< 100 lines of code) with self-cleaning hooks.');
245
294
  lines.push('');
246
295
  lines.push('*Transformation tracked via [Chemical X Protocol Starter Kit](https://github.com/Chemical-X-Protocol/awesome-secret-sauce).*');
247
296
 
@@ -58,6 +58,11 @@ export interface ContextTokenAnalysis {
58
58
  readonly estimatedExcessTokens: number;
59
59
  readonly potentialSavingsPct: number;
60
60
  readonly riskLevel: RiskLevel;
61
+ readonly pricingModel?: string;
62
+ readonly costPerMillion?: number;
63
+ readonly excessCostPerPass?: number;
64
+ readonly weeklyWastePerDev?: number;
65
+ readonly monthlyWastePerDev?: number;
61
66
  }
62
67
 
63
68
  export interface HotspotFile {
@@ -117,6 +122,10 @@ export declare function formatGradeCSection(report: AuditReport): string;
117
122
  export declare function formatGradeBSection(report: AuditReport): string;
118
123
  export declare function formatGradeASection(report: AuditReport): string;
119
124
  export declare function getChemicalXAsciiBanner(gradeOrReport?: string | AuditReport | null): string;
125
+ export declare function getAsciiGradeLines(grade?: string, color?: string, withEquals?: boolean): readonly string[];
126
+ export declare function formatAsciiGrade(grade?: string, color?: string, indent?: string, withEquals?: boolean): string;
127
+ export declare const REPORT_CARD_ASCII: readonly string[];
128
+ export declare function getReportCardAsciiLines(color?: string): readonly string[];
120
129
 
121
130
  export * from './social';
122
131
 
package/cli/audit.js CHANGED
@@ -27,7 +27,11 @@ import {
27
27
  formatGradeCSection,
28
28
  formatGradeBSection,
29
29
  formatGradeASection,
30
- getChemicalXAsciiBanner
30
+ getChemicalXAsciiBanner,
31
+ getAsciiGradeLines,
32
+ formatAsciiGrade,
33
+ getReportCardAsciiLines,
34
+ REPORT_CARD_ASCII
31
35
  } from './audit/reporter.js';
32
36
 
33
37
  const IGNORED_DIRS = new Set([
@@ -207,7 +211,11 @@ export {
207
211
  formatGradeCSection,
208
212
  formatGradeBSection,
209
213
  formatGradeASection,
210
- getChemicalXAsciiBanner
214
+ getChemicalXAsciiBanner,
215
+ getAsciiGradeLines,
216
+ formatAsciiGrade,
217
+ getReportCardAsciiLines,
218
+ REPORT_CARD_ASCII
211
219
  };
212
220
 
213
221
  export default {
@@ -233,6 +241,10 @@ export default {
233
241
  formatGradeBSection,
234
242
  formatGradeASection,
235
243
  getChemicalXAsciiBanner,
244
+ getAsciiGradeLines,
245
+ formatAsciiGrade,
246
+ getReportCardAsciiLines,
247
+ REPORT_CARD_ASCII,
236
248
  PILLARS,
237
249
  RULE_REGISTRY
238
250
  };
package/cli/help.js CHANGED
@@ -25,7 +25,7 @@ export const printHelp = () => {
25
25
  '',
26
26
  ` ${CYAN}generate${RESET} <m-name> ${DIM}(aliases: capsule, add)${RESET}`,
27
27
  ` Scaffold an isolated crystalline molecule capsule directory:`,
28
- ` ${DIM}- ${RESET}<m-name>/<m-name>.tsx ${DIM}(declarative component < 50 LOC)${RESET}`,
28
+ ` ${DIM}- ${RESET}<m-name>/<m-name>.tsx ${DIM}(declarative component < 50 lines of code)${RESET}`,
29
29
  ` ${DIM}- ${RESET}<m-name>/types.d.ts ${DIM}(props and emits interfaces)${RESET}`,
30
30
  ` ${DIM}- ${RESET}<m-name>/index.ts ${DIM}(clean public barrel export)${RESET}`,
31
31
  ` Free evaluation mode supported with non-blocking license reminder.`,
@@ -35,12 +35,12 @@ export const printHelp = () => {
35
35
  ` ${YELLOW}[PAID]${RESET} Drop full Chemical X blueprints, core hooks (toResult,`,
36
36
  ` useAsyncData, useSelfCleaningTimer), and AGENTS.md directives into`,
37
37
  ` an existing codebase. Default destination: ${CYAN}src/chemical-x${RESET}.`,
38
- ` Requires Single Dev ($27) or Team Power Puff 💯 ($47: 100 Seats) license.`,
38
+ ` Requires Single Dev ($27) or Team Power Puff ($97: Unlimited Lifetime) license.`,
39
39
  '',
40
40
  ` ${CYAN}create${RESET} [directory] ${DIM}(or: npm create chemx [directory])${RESET}`,
41
41
  ` ${YELLOW}[PAID]${RESET} Scaffold a complete, clean-slate project wired with full`,
42
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.`,
43
+ ` Requires Single Dev ($27) or Team Power Puff ($97: Unlimited Lifetime) license.`,
44
44
  '',
45
45
  ` ${CYAN}install-hooks${RESET} [directory] ${DIM}(aliases: hook, setup-ci)${RESET}`,
46
46
  ` ${GREEN}[FREE]${RESET} Install git pre-commit hook (.git/hooks/pre-commit) and`,
@@ -95,7 +95,7 @@ export const printHelp = () => {
95
95
  '',
96
96
  ` ${CYAN}--license=<key>${RESET}`,
97
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).`,
98
+ ` Tiers: Single Dev ($27) | Team Power Puff ($97: Unlimited Lifetime).`,
99
99
  '',
100
100
  `${BOLD}ENVIRONMENT VARIABLES${RESET}`,
101
101
  ` ${GREEN}CHEMX_MIN_GRADE${RESET}`,
@@ -31,9 +31,20 @@ if [ "\$FAILED" -eq 1 ]; then
31
31
  printf "\\n\\033[1m\\033[31m[Chemical X] Commit Blocked: Staged files exceed architectural line budgets\\033[0m\\n\$ERRORS\\n\\n"
32
32
  fi
33
33
 
34
- if command -v npx >/dev/null 2>&1; then
34
+ AUDIT_BIN=""
35
+ if [ -f "./cli/index.js" ]; then
36
+ AUDIT_BIN="node ./cli/index.js"
37
+ elif [ -x "./node_modules/.bin/chemx" ]; then
38
+ AUDIT_BIN="./node_modules/.bin/chemx"
39
+ elif command -v chemx >/dev/null 2>&1; then
40
+ AUDIT_BIN="chemx"
41
+ elif command -v npx >/dev/null 2>&1; then
42
+ AUDIT_BIN="npx chemx"
43
+ fi
44
+
45
+ if [ -n "\$AUDIT_BIN" ]; then
35
46
  printf "\\033[38;2;98;201;255m[Chemical X] Verifying architectural health (Min Grade: %s, Min Score: %s)...\\033[0m\\n" "\$MIN_GRADE" "\$MIN_SCORE"
36
- if ! npx chemx audit --min-grade="\$MIN_GRADE" --min-score="\$MIN_SCORE" --prompt-on-fail; then
47
+ if ! \$AUDIT_BIN audit --min-grade="\$MIN_GRADE" --min-score="\$MIN_SCORE" --prompt-on-fail; then
37
48
  printf "\\n\\033[1m\\033[31m[Chemical X] Commit Blocked: Codebase falls below required Grade %s (Score %s)\\033[0m\\n" "\$MIN_GRADE" "\$MIN_SCORE"
38
49
  printf "\\033[36m💡 Tip: Want crystalline drop-in templates? Run 'npm create chemx' or sponsor at https://github.com/sponsors/Chemical-X-Protocol\\033[0m\\n\\n"
39
50
  exit 1
@@ -17,4 +17,5 @@ export declare function buildGitHubWorkflowScript(minGrade?: string, minScore?:
17
17
  export declare function installPreCommitHook(targetDir?: string, options?: InstallOptions): boolean;
18
18
  export declare function installGitHubWorkflow(targetDir?: string, options?: InstallOptions): boolean;
19
19
  export declare function saveProjectConfig(targetDir?: string, config?: Partial<ProjectConfig>): void;
20
+ export declare function areGuardrailsInstalled(targetDir?: string): boolean;
20
21
  export declare function runInstallWizard(targetDir?: string): Promise<void>;
package/cli/installer.js CHANGED
@@ -30,6 +30,54 @@ export const saveProjectConfig = (targetDir = '.', config = {}) => {
30
30
  process.stdout.write(` \x1b[32m✔\x1b[0m Saved project settings to: .chemx/config.json\n`);
31
31
  };
32
32
 
33
+ export const areGuardrailsInstalled = (targetDir = '.') => {
34
+ const resolvedTarget = path.resolve(targetDir);
35
+ const wfPath = path.join(resolvedTarget, '.github', 'workflows', 'chemx-audit.yml');
36
+ const hasWf = fs.existsSync(wfPath);
37
+
38
+ const gitPath = path.join(resolvedTarget, '.git');
39
+ let hasGit = false;
40
+ let hooksDir = null;
41
+
42
+ if (fs.existsSync(gitPath)) {
43
+ try {
44
+ const stat = fs.statSync(gitPath);
45
+ if (stat.isDirectory()) {
46
+ hasGit = true;
47
+ hooksDir = path.join(gitPath, 'hooks');
48
+ } else if (stat.isFile()) {
49
+ hasGit = true;
50
+ const gitContent = fs.readFileSync(gitPath, 'utf-8');
51
+ const match = gitContent.match(/gitdir:\s*(.+)/);
52
+ if (match) {
53
+ hooksDir = path.resolve(resolvedTarget, match[1].trim(), 'hooks');
54
+ }
55
+ }
56
+ } catch {
57
+ hasGit = false;
58
+ }
59
+ }
60
+
61
+ if (!hasGit) {
62
+ return hasWf;
63
+ }
64
+
65
+ let hasHook = false;
66
+ if (hooksDir) {
67
+ const hookPath = path.join(hooksDir, 'pre-commit');
68
+ if (fs.existsSync(hookPath)) {
69
+ try {
70
+ const hookContent = fs.readFileSync(hookPath, 'utf-8');
71
+ hasHook = hookContent.includes('Chemical X') || hookContent.includes('chemx');
72
+ } catch {
73
+ hasHook = false;
74
+ }
75
+ }
76
+ }
77
+
78
+ return hasWf && hasHook;
79
+ };
80
+
33
81
  export const runInstallWizard = async (targetDir = '.') => {
34
82
  const isGit = fs.existsSync(path.resolve(targetDir, '.git'));
35
83
  process.stdout.write('\n\x1b[1m\x1b[38;2;98;201;255mChemical X: Architecture Guardrail Installer\x1b[0m\n\n');
package/cli/license.js CHANGED
@@ -83,7 +83,7 @@ export const obtainLicenseKey = async (rawArgs = [], onRunAudit = null) => {
83
83
  [
84
84
  '1. Visit chemicalx.xophz.com to learn more',
85
85
  '2. Buy Standard Vault: Single Dev License ($27) -> Launch Checkout',
86
- '3. Buy Team Power Puff: 100 Devs / Seats ($47) -> Launch Checkout',
86
+ '3. Buy Team Power Puff: Unlimited Lifetime ($97) -> Launch Checkout',
87
87
  '4. Enter License Key (CX-XXXX-XXXX-XXXX)',
88
88
  '5. Run Free Public Audit (npx chemx audit)',
89
89
  '6. Exit'
@@ -106,7 +106,7 @@ export const obtainLicenseKey = async (rawArgs = [], onRunAudit = null) => {
106
106
  }
107
107
 
108
108
  if (choice.startsWith('3.')) {
109
- process.stdout.write(`\x1b[36mOpening Team Power Puff checkout (100 Devs / 100 Seats) in default browser:\x1b[0m ${URL_MASTER}\n`);
109
+ process.stdout.write(`\x1b[36mOpening Team Power Puff checkout (Unlimited Lifetime) in default browser:\x1b[0m ${URL_MASTER}\n`);
110
110
  openBrowser(URL_MASTER);
111
111
  process.stdout.write('\nOnce completed, paste your Sponsor / VIP License Key below.\n');
112
112
  return gumInput('License Key (CX-XXXX-XXXX-XXXX):', 'CX-XXXX-XXXX-XXXX');
@@ -131,7 +131,7 @@ export const obtainLicenseKey = async (rawArgs = [], onRunAudit = null) => {
131
131
  process.stdout.write('\x1b[1mChemical X Scaffolding Requires a Paid License:\x1b[0m\n');
132
132
  process.stdout.write(' [1] Visit chemicalx.xophz.com to learn more\n');
133
133
  process.stdout.write(' [2] Buy Standard Vault: Single Dev License ($27) - Opens browser\n');
134
- process.stdout.write(' [3] Buy Team Power Puff: 100 Devs / Seats ($47) - Opens browser\n');
134
+ process.stdout.write(' [3] Buy Team Power Puff: Unlimited Lifetime ($97) - Opens browser\n');
135
135
  process.stdout.write(' [4] Enter License Key\n');
136
136
  process.stdout.write(' [5] Run Free Public Audit (npx chemx audit)\n');
137
137
  process.stdout.write(' [6] Exit\n\n');
@@ -190,7 +190,7 @@ export const checkOrPromptEvaluation = async (actionLabel = 'generate capsule')
190
190
  '--bold',
191
191
  '⚡ Chemical X: Evaluation Mode (Unlicensed)\n' +
192
192
  'Support vibe coding standards: chemicalx.xophz.com\n' +
193
- 'Single Dev ($27) | Team Power Puff 💯 (100 Seats: $47)'
193
+ 'Single Dev ($27) | Team Power Puff ($97: Unlimited Lifetime)'
194
194
  ],
195
195
  { stdio: 'inherit' }
196
196
  );
@@ -198,8 +198,8 @@ export const checkOrPromptEvaluation = async (actionLabel = 'generate capsule')
198
198
  const choice = gumChoose(
199
199
  [
200
200
  `1. ⚡ Continue in Evaluation Mode (Press Enter to ${actionLabel})`,
201
- '2. 🔑 Enter License Key (Power Puff Team 💯 or Single Dev)',
202
- '3. 💎 Buy License ($27 Solo / $47 Team Power Puff 100 Seats)',
201
+ '2. 🔑 Enter License Key (Team Power Puff or Single Dev)',
202
+ '3. 💎 Buy License ($27 Solo / $97 Team Power Puff Unlimited Lifetime)',
203
203
  '4. 🚪 Cancel'
204
204
  ],
205
205
  `Evaluation Mode: ${actionLabel}`
@@ -242,8 +242,8 @@ export const checkOrPromptEvaluation = async (actionLabel = 'generate capsule')
242
242
  '\n\x1b[38;5;208;1m⚡ Chemical X: Evaluation Mode (Unlicensed)\x1b[0m\n' +
243
243
  'Support vibe coding standards: chemicalx.xophz.com\n' +
244
244
  ` [1] Continue in Evaluation Mode (Press Enter to ${actionLabel})\n` +
245
- ' [2] Enter License Key (Power Puff Team 💯 or Single Dev)\n' +
246
- ' [3] Buy License ($27 Solo / $47 Team Power Puff 100 Seats)\n' +
245
+ ' [2] Enter License Key (Team Power Puff or Single Dev)\n' +
246
+ ' [3] Buy License ($27 Solo / $97 Team Power Puff Unlimited Lifetime)\n' +
247
247
  ' [4] Cancel\n\n'
248
248
  );
249
249
 
@@ -0,0 +1,274 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import {
4
+ hasGum,
5
+ gumChoose,
6
+ gumInput,
7
+ promptQuestion
8
+ } from "./terminal.js";
9
+ import {
10
+ formatTerminalReport,
11
+ generateMarkdownReport,
12
+ groupViolationsBySeverity,
13
+ formatGradeFSection,
14
+ formatGradeDSection,
15
+ formatGradeCSection,
16
+ formatGradeBSection,
17
+ formatGradeASection,
18
+ getAuditHistory,
19
+ getAuditBaseline,
20
+ createSnapshotFromReport,
21
+ formatTransformationTerminal,
22
+ formatHistoryTimelineTerminal,
23
+ buildGradeFPrompt,
24
+ buildGradeDPrompt,
25
+ buildGradeCPrompt,
26
+ buildGradeBPrompt,
27
+ buildMasterPrompt,
28
+ copyToClipboard
29
+ } from "./audit.js";
30
+ import { resolveGradeBadge } from "./navigator-grades.js";
31
+ import { showPagedContent } from "./navigator-paged.js";
32
+ import { showConversionMenu } from "./navigator-conversion.js";
33
+ import { handleShareToDiscussions } from "./navigator-share.js";
34
+ import { runInstallWizard } from "./installer.js";
35
+ import { formatButtonTag } from "./navigator-menu.js";
36
+
37
+ const isExtremeMonolith = (h) => h.lineCount >= 2000;
38
+ const isSevereMonolith = (h) => h.lineCount >= 1000 && h.lineCount < 2000;
39
+ const isWarningMonolith = (h) => h.lineCount >= 500 && h.lineCount < 1000;
40
+ const isPassedPillar = (p) => p.status === "PASSED";
41
+ const hasGradeItems = (g) => g.count > 0;
42
+
43
+ export const buildActiveGrades = (report) => {
44
+ const { hotspots, violations, pillars } = report;
45
+ const { critical, high, medium, low } = groupViolationsBySeverity(violations);
46
+
47
+ const passedPillarsCount = Object.values(pillars || {}).filter(isPassedPillar).length;
48
+
49
+ const extremeMonoliths = hotspots.filter(isExtremeMonolith);
50
+ const severeMonoliths = hotspots.filter(isSevereMonolith);
51
+ const warningMonoliths = hotspots.filter(isWarningMonolith);
52
+
53
+ const gradeFCount = critical.length + extremeMonoliths.length;
54
+ const gradeDCount = high.length + severeMonoliths.length;
55
+ const gradeCCount = medium.length + warningMonoliths.length;
56
+ const gradeBCount = low.length;
57
+ const gradeACount = passedPillarsCount;
58
+
59
+ const handleGradeAAction = async () => {
60
+ await showPagedContent(formatGradeASection(report));
61
+ };
62
+ const handleGradeBAction = async () => {
63
+ await showPagedContent(formatGradeBSection(report), buildGradeBPrompt(report));
64
+ };
65
+ const handleGradeCAction = async () => {
66
+ await showPagedContent(formatGradeCSection(report), buildGradeCPrompt(report));
67
+ };
68
+ const handleGradeDAction = async () => {
69
+ await showPagedContent(formatGradeDSection(report), buildGradeDPrompt(report));
70
+ };
71
+ const handleGradeFAction = async () => {
72
+ await showPagedContent(formatGradeFSection(report), buildGradeFPrompt(report));
73
+ };
74
+
75
+ const gradeTiers = [
76
+ {
77
+ grade: "A",
78
+ count: gradeACount,
79
+ icon: "✅",
80
+ description: "Compliant Checks & Passing Pillars",
81
+ action: handleGradeAAction
82
+ },
83
+ {
84
+ grade: "B",
85
+ count: gradeBCount,
86
+ icon: "💣",
87
+ description: "Low Hygiene Issues & Minor Debts",
88
+ action: handleGradeBAction
89
+ },
90
+ {
91
+ grade: "C",
92
+ count: gradeCCount,
93
+ icon: "⚡",
94
+ description: "Medium Severity Debts & Monolith Drift",
95
+ action: handleGradeCAction
96
+ },
97
+ {
98
+ grade: "D",
99
+ count: gradeDCount,
100
+ icon: "🔥",
101
+ description: "High Severity Debts & Severe Monoliths",
102
+ action: handleGradeDAction
103
+ },
104
+ {
105
+ grade: "F",
106
+ count: gradeFCount,
107
+ icon: "💥",
108
+ description: "Critical Hazards & Extreme Monoliths",
109
+ action: handleGradeFAction
110
+ }
111
+ ];
112
+
113
+ const createActiveGradeItem = (g) => ({
114
+ key: `grade_${g.grade.toLowerCase()}`,
115
+ grade: g.grade.toLowerCase(),
116
+ tag: resolveGradeBadge(g.grade, 11),
117
+ label: `${g.icon} Grade ${g.grade}: ${g.description} (${g.count} ${g.grade === "A" ? "clean" : "items"})`,
118
+ action: g.action
119
+ });
120
+
121
+ return gradeTiers.filter(hasGradeItems).map(createActiveGradeItem);
122
+ };
123
+
124
+ export const buildDashboardActionGroups = ({ report, onScaffold = null }) => {
125
+ const handleInstallAction = async () => {
126
+ await runInstallWizard(process.cwd());
127
+ if (hasGum()) {
128
+ gumChoose(["<-- Back to Audit Dashboard"]);
129
+ }
130
+ };
131
+
132
+ const handleUpgradeAction = async () => {
133
+ await showConversionMenu(onScaffold);
134
+ };
135
+
136
+ const handleReportAction = async () => {
137
+ await showPagedContent(formatTerminalReport(report), buildMasterPrompt(report));
138
+ };
139
+
140
+ const handleShareAction = async () => {
141
+ await handleShareToDiscussions(report);
142
+ };
143
+
144
+ const handleProgressAction = async () => {
145
+ const baseline = getAuditBaseline();
146
+ const history = getAuditHistory();
147
+ const currentSnapshot = createSnapshotFromReport(report);
148
+
149
+ let output = "";
150
+ if (baseline) {
151
+ output += formatTransformationTerminal(baseline, currentSnapshot);
152
+ } else {
153
+ output +=
154
+ "\n\x1b[33mNo baseline audit found. Current audit established as baseline.\x1b[0m\n";
155
+ }
156
+
157
+ if (history.length > 0) {
158
+ output += "\n\n" + formatHistoryTimelineTerminal(history);
159
+ }
160
+
161
+ await showPagedContent(output);
162
+ };
163
+
164
+ const handleExportAction = async () => {
165
+ const outName = hasGum()
166
+ ? gumInput("Export file path:", "AUDIT_REPORT.md") || "AUDIT_REPORT.md"
167
+ : (await promptQuestion("Export file path [AUDIT_REPORT.md]: ")) || "AUDIT_REPORT.md";
168
+ const md = generateMarkdownReport(report);
169
+ fs.writeFileSync(path.resolve(process.cwd(), outName), md, "utf-8");
170
+ process.stdout.write(`\x1b[32m✔ Exported markdown audit report to ${outName}\x1b[0m\n\n`);
171
+ if (hasGum()) {
172
+ gumChoose(["<-- Back to Audit Dashboard"]);
173
+ }
174
+ };
175
+
176
+ const handleCopyPromptAction = async () => {
177
+ const masterPrompt = buildMasterPrompt(report);
178
+ if (!masterPrompt) {
179
+ process.stdout.write("\n\x1b[32m✔ Codebase is pristine (Grade A+). No refactoring prompt needed!\x1b[0m\n\n");
180
+ if (hasGum()) {
181
+ gumChoose(["<-- Back to Audit Dashboard"]);
182
+ }
183
+ return;
184
+ }
185
+ const success = copyToClipboard(masterPrompt);
186
+ if (success) {
187
+ process.stdout.write(
188
+ "\n\x1b[1m\x1b[32m✔ AI Agent refactoring prompt copied to clipboard!\x1b[0m\n" +
189
+ "\x1b[36mPaste directly into Cursor, Claude, or Windsurf to resolve architectural hazards.\x1b[0m\n\n"
190
+ );
191
+ } else {
192
+ process.stdout.write("\n\x1b[33m⚠ Could not access system clipboard.\x1b[0m\n\n");
193
+ }
194
+ if (hasGum()) {
195
+ gumChoose(["<-- Back to Audit Dashboard"]);
196
+ }
197
+ };
198
+
199
+ const handleExitAction = async () => {};
200
+
201
+ const installAction = {
202
+ key: "install",
203
+ tag: formatButtonTag("Install", "\x1b[32m"),
204
+ label: "🪝 Install Pre-Commit Hook & GitHub CI Workflow",
205
+ action: handleInstallAction
206
+ };
207
+
208
+ const upgradeAction = {
209
+ key: "upgrade",
210
+ tag: formatButtonTag("Upgrade", "\x1b[33m"),
211
+ label: "💎 Unlock Full Molecular Rules & Scaffolding (Chemical X: Team Power Puff)",
212
+ action: handleUpgradeAction
213
+ };
214
+
215
+ const reportAction = {
216
+ key: "report",
217
+ tag: formatButtonTag("Full Report", "\x1b[36m"),
218
+ label: "📋 Show Full Report (All Sections at Once)",
219
+ action: handleReportAction
220
+ };
221
+
222
+ const shareAction = {
223
+ key: "share",
224
+ tag: formatButtonTag("Share", "\x1b[35m"),
225
+ label: "🕵 Plug your site and Post to GitHub Discussions (npx chemx audit)",
226
+ action: handleShareAction
227
+ };
228
+
229
+ const progressAction = {
230
+ key: "progress",
231
+ tag: formatButtonTag("Progress", "\x1b[32m"),
232
+ label: "📈 View Before & After Transformation Progress",
233
+ action: handleProgressAction
234
+ };
235
+
236
+ const exportAction = {
237
+ key: "export",
238
+ tag: formatButtonTag("Export", "\x1b[36m"),
239
+ label: "💾 Export Markdown Report to File",
240
+ action: handleExportAction
241
+ };
242
+
243
+ const copyPromptAction = {
244
+ key: "prompt",
245
+ tag: formatButtonTag("Prompt", "\x1b[38;2;98;201;255m"),
246
+ label: "📋 Copy AI Prompt Fix to Clipboard",
247
+ action: handleCopyPromptAction
248
+ };
249
+
250
+ const exitAction = {
251
+ key: "exit",
252
+ tag: formatButtonTag("Exit", "\x1b[90m"),
253
+ label: "🚪 Exit",
254
+ action: handleExitAction
255
+ };
256
+
257
+ const masterPrompt = buildMasterPrompt(report);
258
+ const isGradeAPlus = report?.health?.grade === "A+" || report?.metrics?.grade === "A+";
259
+ const hasPromptToCopy = Boolean(masterPrompt && masterPrompt.trim().length > 0);
260
+ const isCleanAPlus = isGradeAPlus && !hasPromptToCopy;
261
+ const shouldShowPromptAction = hasPromptToCopy && !isCleanAPlus;
262
+
263
+ return {
264
+ installAction,
265
+ upgradeAction,
266
+ reportAction,
267
+ shareAction,
268
+ progressAction,
269
+ exportAction,
270
+ copyPromptAction,
271
+ exitAction,
272
+ shouldShowPromptAction
273
+ };
274
+ };