@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.
@@ -0,0 +1,98 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { getChemicalXAsciiBanner } from "./audit.js";
4
+ import { resolveGradeColor, resolveHealthHearts } from "./navigator-grades.js";
5
+
6
+ const visualWidth = (s) => {
7
+ const stripped = s.replace(/\x1b\[[0-9;]*m/g, "");
8
+ let w = 0;
9
+ for (const seg of new Intl.Segmenter().segment(stripped)) {
10
+ const char = seg.segment;
11
+ const isDoubleWidth = char === "❤️" || char === "🖤" || char.codePointAt(0) > 0x1f000;
12
+ w += isDoubleWidth ? 2 : char.length;
13
+ }
14
+ return w;
15
+ };
16
+
17
+ const resolveProjectName = () => {
18
+ try {
19
+ const pkgPath = path.resolve(process.cwd(), "package.json");
20
+ if (fs.existsSync(pkgPath)) return JSON.parse(fs.readFileSync(pkgPath, "utf-8")).name || path.basename(process.cwd());
21
+ } catch {}
22
+ return path.basename(process.cwd()) || "Project";
23
+ };
24
+
25
+ const truncatePath = (p, maxLen) => (p.length <= maxLen ? p : `…${p.slice(p.length - maxLen + 1)}`);
26
+
27
+ export const renderDashboardBanner = (
28
+ health,
29
+ metrics,
30
+ violations,
31
+ critical,
32
+ highMediumCount,
33
+ low,
34
+ contextAnalysis = null
35
+ ) => {
36
+ if (process.stdout.isTTY) console.clear();
37
+ process.stdout.write(getChemicalXAsciiBanner(health.grade));
38
+
39
+ const gColor = resolveGradeColor(health.grade);
40
+ const critColor = critical.length > 0 ? "\x1b[31;1m" : "\x1b[32m";
41
+ const highMedColor = highMediumCount > 0 ? "\x1b[38;5;208;1m" : "\x1b[32m";
42
+ const lowColor = low.length > 0 ? "\x1b[33;1m" : "\x1b[32m";
43
+
44
+ const hearts = resolveHealthHearts(health.grade, health.score);
45
+ const scoreBadge = `${health.score}/100 [Grade: ${health.grade}]`;
46
+ const labelStr = health.label ? ` (${health.label})` : "";
47
+ const healthStr = `${hearts} ${gColor}${scoreBadge}\x1b[0m${gColor}${labelStr}\x1b[0m`;
48
+
49
+ const filesStr = `${metrics.scannedFiles} Files`;
50
+ const locStr = `${(metrics.totalLoc || 0).toLocaleString()}`;
51
+ const hazardsStr = `💥 ${critColor}${critical.length} Critical\x1b[0m | 🔥 ${highMedColor}${highMediumCount} High/Med\x1b[0m | 💣 ${lowColor}${low.length} Low\x1b[0m`;
52
+
53
+ const tokens = contextAnalysis?.estimatedTokens || 0;
54
+ const pct = contextAnalysis?.potentialSavingsPct || 0;
55
+ const costPass = contextAnalysis?.excessCostPerPass !== undefined
56
+ ? contextAnalysis.excessCostPerPass
57
+ : Number((((contextAnalysis?.estimatedExcessTokens || 0) / 1000000) * 3.0).toFixed(3));
58
+ const costMonth = contextAnalysis?.monthlyWastePerDev !== undefined
59
+ ? contextAnalysis.monthlyWastePerDev
60
+ : Number((costPass * 20 * 5 * 4).toFixed(2));
61
+
62
+ const tokensStr = `~${tokens.toLocaleString()} tokens` + (pct > 0 ? ` (${pct}% cut)` : "");
63
+ const costStr = costPass > 0
64
+ ? `\x1b[38;5;208;1m$${costPass.toFixed(3)}\x1b[0m\x1b[2m/turn\x1b[0m | \x1b[31;1m$${costMonth.toFixed(2)}\x1b[0m\x1b[2m/mo\x1b[0m`
65
+ : `\x1b[32;1m$0.000\x1b[0m\x1b[2m/turn\x1b[0m | \x1b[32;1m$0.00\x1b[0m\x1b[2m/mo\x1b[0m`;
66
+
67
+ const col1 = [
68
+ "\x1b[36;1m-FILES-\x1b[0m", `\x1b[36m${filesStr}\x1b[0m`,
69
+ "\x1b[36;1m-LINES OF CODE-\x1b[0m", `\x1b[36m${locStr}\x1b[0m`,
70
+ "\x1b[36;1m-TOKEN EST-\x1b[0m", `\x1b[36m${tokensStr}\x1b[0m`
71
+ ];
72
+ const col2 = [
73
+ "\x1b[31;1m-HEALTH-\x1b[0m", healthStr,
74
+ "\x1b[33;1m-HAZARDS-\x1b[0m", hazardsStr,
75
+ "\x1b[32;1m-CURRENCY-\x1b[0m", costStr
76
+ ];
77
+
78
+ const col1Pad = 32;
79
+ const rows = [];
80
+ let maxW = 0;
81
+ for (let i = 0; i < col1.length; i++) {
82
+ const pad = " ".repeat(Math.max(2, col1Pad - visualWidth(col1[i])));
83
+ const content = col1[i] + pad + col2[i];
84
+ const w = visualWidth(content);
85
+ if (w > maxW) maxW = w;
86
+ rows.push({ content, width: w });
87
+ }
88
+
89
+ const projectName = resolveProjectName();
90
+ const innerWidth = Math.max(maxW, visualWidth(projectName) + 4);
91
+ const bColor = "\x1b[1;38;5;81m";
92
+ const topBorder = `${bColor}╭── \x1b[1;37m${projectName}${bColor} ${"─".repeat(Math.max(2, innerWidth - visualWidth(projectName)))}╮\x1b[0m`;
93
+ const displayPwd = truncatePath(process.cwd(), Math.max(10, innerWidth - 4));
94
+ const botBorder = `${bColor}╰── \x1b[36m${displayPwd}${bColor} ${"─".repeat(Math.max(2, innerWidth - visualWidth(displayPwd)))}╯\x1b[0m`;
95
+ const bodyLines = rows.map((r) => `${bColor}│\x1b[0m ${r.content}${" ".repeat(innerWidth - r.width)} ${bColor}│\x1b[0m`);
96
+
97
+ process.stdout.write(`\n${[topBorder, ...bodyLines, botBorder].join("\n")}\n\n`);
98
+ };
@@ -23,7 +23,7 @@ export const showConversionMenu = async (onScaffold = null) => {
23
23
  const choice = gumChoose([
24
24
  '1. Sponsor on GitHub: $9/mo Solo / $49/mo Team Unlimited -> Launch Sponsors',
25
25
  '2. Buy Standard Vault: Single Dev License ($27) -> Launch Checkout',
26
- '3. Buy Team Power Puff: 100 Devs / Team Honor System 💯 ($47) -> Launch Checkout',
26
+ '3. Buy Team Power Puff: Unlimited Lifetime ($97) -> Launch Checkout',
27
27
  '4. Enter License Key to Scaffold (Sponsors & License Holders)',
28
28
  '5. Visit chemicalx.xophz.com to learn more',
29
29
  '6. Back to Navigator'
@@ -40,7 +40,7 @@ export const showConversionMenu = async (onScaffold = null) => {
40
40
  continue;
41
41
  }
42
42
  if (choice.startsWith('3.')) {
43
- process.stdout.write(`\n\x1b[36mOpening Team Power Puff checkout (100 Devs / Team Honor System 💯):\x1b[0m ${URL_MASTER}\n\n`);
43
+ process.stdout.write(`\n\x1b[36mOpening Team Power Puff checkout (Unlimited Lifetime):\x1b[0m ${URL_MASTER}\n\n`);
44
44
  openBrowser(URL_MASTER);
45
45
  continue;
46
46
  }
@@ -64,7 +64,7 @@ export const showConversionMenu = async (onScaffold = null) => {
64
64
  );
65
65
  process.stdout.write(` [1] Sponsor on GitHub ($9/mo Solo / $49/mo Team Unlimited) - ${URL_SPONSOR}\n Includes: Instant GitHub org access to private starter-kit, continuous model prompt updates\n`);
66
66
  process.stdout.write(` [2] Buy Standard Vault: Single Dev License ($27) - ${URL_STANDARD}\n Includes: Kindle/Print PDF eBook, 7 Molecular Architecture Chapters, Universal AGENTS.md\n`);
67
- process.stdout.write(` [3] Buy Team Power Puff: 100 Devs / Team Honor System 💯 ($47) - ${URL_MASTER}\n Includes: 100 Team Seats (Honor System), Private Starter-Kit Repo, Pre-Commit Line Budget Hooks, VIP Discord\n`);
67
+ process.stdout.write(` [3] Buy Team Power Puff: Unlimited Lifetime ($97) - ${URL_MASTER}\n Includes: Unlimited Team Seats, Private Starter-Kit Repo, Pre-Commit Line Budget Hooks, VIP Discord\n`);
68
68
  process.stdout.write(' [4] Enter License Key to Scaffold (Sponsors & License Holders)\n');
69
69
  process.stdout.write(` [5] Visit chemicalx.xophz.com to learn more - ${URL_LEARN}\n`);
70
70
  process.stdout.write(' [6] Back to Navigator\n\n');
@@ -6,10 +6,27 @@ export const resolveGradeColor = (grade) => {
6
6
  return '\x1b[31;1m';
7
7
  };
8
8
 
9
- export const resolveGradeBadge = (grade) => {
9
+ export const resolveGradeBadge = (grade, width = 11) => {
10
10
  const color = resolveGradeColor(grade);
11
- const padded = grade.length === 1 ? `${grade} ` : grade;
12
- return `${color}[Grade: ${padded}]\x1b[0m`;
11
+ const text = `Grade: ${grade}`;
12
+ const totalPadding = Math.max(0, width - text.length);
13
+ const leftPad = Math.floor(totalPadding / 2);
14
+ const rightPad = totalPadding - leftPad;
15
+ const padded = `${' '.repeat(leftPad)}${text}${' '.repeat(rightPad)}`;
16
+ return `${color}[${padded}]\x1b[0m`;
17
+ };
18
+
19
+ export const resolveHealthHearts = (grade, score = 0) => {
20
+ const g = String(grade || '').toUpperCase();
21
+ let filled = 1;
22
+ if (g.startsWith('A') || score >= 90) filled = 5;
23
+ else if (g.startsWith('B') || score >= 80) filled = 4;
24
+ else if (g.startsWith('C') || score >= 70) filled = 3;
25
+ else if (g.startsWith('D') || score >= 60) filled = 2;
26
+ else filled = score === 0 ? 0 : 1;
27
+
28
+ const empty = 5 - filled;
29
+ return '❤️'.repeat(filled) + '🖤'.repeat(empty);
13
30
  };
14
31
 
15
32
  export const resolveCriticalGrade = (count) => {
@@ -0,0 +1,127 @@
1
+ export const formatButtonTag = (label, color = "", width = 11) => {
2
+ const totalPadding = Math.max(0, width - label.length);
3
+ const leftPad = Math.floor(totalPadding / 2);
4
+ const rightPad = totalPadding - leftPad;
5
+ const inner = `${" ".repeat(leftPad)}${label}${" ".repeat(rightPad)}`;
6
+ return color ? `${color}[${inner}]\x1b[0m` : `[${inner}]`;
7
+ };
8
+
9
+ const isNonEmptyGroup = (group) => group.length > 0;
10
+
11
+ export const buildNavigatorMenu = (topActions, activeGrades, midActions, bottomActions) => {
12
+ const groups = [topActions, activeGrades, midActions, bottomActions].filter(isNonEmptyGroup);
13
+ const menuItems = groups.flat();
14
+ const menuOptions = [];
15
+ let currentIndex = 1;
16
+ const divider = "──────────────────────────────────────────────────────────────────────";
17
+
18
+ groups.forEach((group, idx) => {
19
+ for (const item of group) {
20
+ item.index = currentIndex;
21
+ const pad = String(currentIndex).padStart(2, " ");
22
+ menuOptions.push(` ${pad}. ${item.tag} ${item.label}`);
23
+ currentIndex++;
24
+ }
25
+ if (idx < groups.length - 1) {
26
+ menuOptions.push(divider);
27
+ }
28
+ });
29
+
30
+ return { menuItems, menuOptions };
31
+ };
32
+
33
+ const isChoiceMatchingItem = (cleanChoice) => (item) => {
34
+ const prefix = `${item.index}.`;
35
+ if (cleanChoice.startsWith(prefix) || cleanChoice === String(item.index)) return true;
36
+ if (
37
+ item.key === "exit" &&
38
+ (cleanChoice.includes("Exit") || cleanChoice.toLowerCase() === "exit")
39
+ ) {
40
+ return true;
41
+ }
42
+ if (
43
+ item.key === "prompt" &&
44
+ (cleanChoice.includes("Prompt") || cleanChoice.includes("Clipboard"))
45
+ ) {
46
+ return true;
47
+ }
48
+ if (
49
+ item.key === "report" &&
50
+ (cleanChoice.includes("Report") || cleanChoice.includes("Full Report"))
51
+ ) {
52
+ return true;
53
+ }
54
+ if (item.key === "progress" && cleanChoice.includes("Progress")) return true;
55
+ if (
56
+ item.key === "share" &&
57
+ (cleanChoice.includes("Share") ||
58
+ cleanChoice.includes("Discussions") ||
59
+ cleanChoice.includes("Plug your"))
60
+ ) {
61
+ return true;
62
+ }
63
+ if (item.key === "export" && cleanChoice.includes("Export")) return true;
64
+ if (
65
+ item.key === "install" &&
66
+ (cleanChoice.includes("Install") ||
67
+ cleanChoice.includes("Pre-Commit") ||
68
+ cleanChoice.includes("Workflow"))
69
+ ) {
70
+ return true;
71
+ }
72
+ if (
73
+ item.key === "upgrade" &&
74
+ (cleanChoice.includes("Upgrade") ||
75
+ cleanChoice.includes("Power Puff") ||
76
+ cleanChoice.includes("Team Power Puff") ||
77
+ cleanChoice.includes("Molecular Rules"))
78
+ ) {
79
+ return true;
80
+ }
81
+ if (
82
+ item.grade &&
83
+ (cleanChoice.toLowerCase().includes(`grade ${item.grade}`) ||
84
+ cleanChoice.toLowerCase().includes(`grade: ${item.grade}`))
85
+ ) {
86
+ return true;
87
+ }
88
+ return false;
89
+ };
90
+
91
+ export const matchGumChoice = (cleanChoice, menuItems) => {
92
+ const matcher = isChoiceMatchingItem(cleanChoice);
93
+ return menuItems.find(matcher);
94
+ };
95
+
96
+ const isEffectiveMatchingItem = (effective, exitIndex) => (item) => {
97
+ if (effective === String(item.index)) return true;
98
+ if (item.key === "exit" && (effective === "exit" || effective === String(exitIndex))) {
99
+ return true;
100
+ }
101
+ if (
102
+ item.key === "prompt" &&
103
+ (effective === "prompt" ||
104
+ effective === "copy" ||
105
+ effective === "c" ||
106
+ effective === "clipboard")
107
+ ) {
108
+ return true;
109
+ }
110
+ if (
111
+ item.key === "report" &&
112
+ (effective === "report" || effective === "full report" || effective === "full")
113
+ ) {
114
+ return true;
115
+ }
116
+ if (item.key === "share" && (effective === "share" || effective === "post")) return true;
117
+ if (item.key === effective) return true;
118
+ if (item.grade && (effective === item.grade || effective === `grade ${item.grade}`)) {
119
+ return true;
120
+ }
121
+ return false;
122
+ };
123
+
124
+ export const matchFallbackChoice = (effective, menuItems, exitIndex) => {
125
+ const matcher = isEffectiveMatchingItem(effective, exitIndex);
126
+ return menuItems.find(matcher);
127
+ };
@@ -1,7 +1,8 @@
1
1
  import type { AuditReport } from './audit/types';
2
2
 
3
3
  export declare function resolveGradeColor(grade: string): string;
4
- export declare function resolveGradeBadge(grade: string): string;
4
+ export declare function resolveGradeBadge(grade: string, width?: number): string;
5
+ export declare function resolveHealthHearts(grade: string, score?: number, isAnsi?: boolean): string;
5
6
  export declare function resolveCriticalGrade(count: number): string;
6
7
  export declare function resolveHighMedGrade(count: number): string;
7
8
  export declare function resolveLowGrade(count: number): string;
@@ -9,6 +10,23 @@ export declare function resolvePillarGrade(pillars: Record<string, unknown>): st
9
10
  export declare function resolveHotspotGrade(hotspots: readonly { readonly lineCount: number }[]): string;
10
11
  export declare function resolveContextGrade(riskTier: string): string;
11
12
 
13
+ export interface NavigatorMenuItem {
14
+ key?: string;
15
+ grade?: string;
16
+ tag: string;
17
+ label: string;
18
+ index?: number;
19
+ action: () => Promise<void>;
20
+ }
21
+
22
+ export declare function formatButtonTag(label: string, color?: string, width?: number): string;
23
+ export declare function buildNavigatorMenu(
24
+ topActions: readonly NavigatorMenuItem[],
25
+ activeGrades: readonly NavigatorMenuItem[],
26
+ midActions: readonly NavigatorMenuItem[],
27
+ bottomActions: readonly NavigatorMenuItem[]
28
+ ): { menuItems: NavigatorMenuItem[]; menuOptions: string[] };
29
+
12
30
  export declare function extractPromptFromContent(content: string): string | null;
13
31
  export declare function showPagedContent(content: string, promptText?: string | null): Promise<void>;
14
32
  export declare function showConversionMenu(onScaffold?: (() => Promise<void>) | null): Promise<void>;
@@ -19,6 +37,7 @@ export declare function renderDashboardBanner(
19
37
  violations: AuditReport['violations'],
20
38
  critical: readonly unknown[],
21
39
  highMediumCount: number,
22
- low: readonly unknown[]
40
+ low: readonly unknown[],
41
+ contextAnalysis?: AuditReport['contextAnalysis'] | null
23
42
  ): void;
24
43
  export declare function runInteractiveAuditNavigator(report: AuditReport, onScaffold?: (() => Promise<void>) | null): Promise<void>;