infernoflow 0.37.1 → 0.37.4
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.
- package/CHANGELOG.md +71 -0
- package/dist/bin/infernoflow.mjs +29 -277
- package/dist/lib/adopters/angular.mjs +1 -128
- package/dist/lib/adopters/css.mjs +1 -111
- package/dist/lib/adopters/react.mjs +1 -104
- package/dist/lib/ai/ideDetection.mjs +1 -31
- package/dist/lib/ai/localProvider.mjs +1 -88
- package/dist/lib/ai/providerRouter.mjs +2 -295
- package/dist/lib/commands/adopt.mjs +20 -869
- package/dist/lib/commands/adoptWizard.mjs +9 -320
- package/dist/lib/commands/agent.mjs +5 -191
- package/dist/lib/commands/ai.mjs +2 -407
- package/dist/lib/commands/ask.mjs +4 -299
- package/dist/lib/commands/audit.mjs +13 -300
- package/dist/lib/commands/changelog.mjs +26 -594
- package/dist/lib/commands/check.mjs +3 -184
- package/dist/lib/commands/ci.mjs +3 -208
- package/dist/lib/commands/claudeMd.mjs +30 -135
- package/dist/lib/commands/cloud.mjs +10 -773
- package/dist/lib/commands/context.mjs +34 -346
- package/dist/lib/commands/coverage.mjs +2 -282
- package/dist/lib/commands/dashboard.mjs +123 -635
- package/dist/lib/commands/demo.mjs +8 -465
- package/dist/lib/commands/diff.mjs +5 -274
- package/dist/lib/commands/docGate.mjs +2 -81
- package/dist/lib/commands/doctor.mjs +3 -321
- package/dist/lib/commands/explain.mjs +8 -438
- package/dist/lib/commands/export.mjs +10 -239
- package/dist/lib/commands/feedback.mjs +12 -216
- package/dist/lib/commands/generateSkills.mjs +38 -163
- package/dist/lib/commands/graph.mjs +11 -378
- package/dist/lib/commands/health.mjs +2 -309
- package/dist/lib/commands/impact.mjs +2 -325
- package/dist/lib/commands/implement.mjs +7 -103
- package/dist/lib/commands/init.mjs +45 -631
- package/dist/lib/commands/installCursorHooks.mjs +1 -36
- package/dist/lib/commands/installVsCodeCopilotHooks.mjs +1 -37
- package/dist/lib/commands/link.mjs +2 -342
- package/dist/lib/commands/log.mjs +18 -248
- package/dist/lib/commands/monorepo.mjs +4 -428
- package/dist/lib/commands/notify.mjs +4 -258
- package/dist/lib/commands/onboard.mjs +4 -296
- package/dist/lib/commands/prComment.mjs +2 -361
- package/dist/lib/commands/prImpact.mjs +2 -157
- package/dist/lib/commands/publish.mjs +15 -316
- package/dist/lib/commands/recap.mjs +6 -380
- package/dist/lib/commands/report.mjs +28 -272
- package/dist/lib/commands/review.mjs +9 -223
- package/dist/lib/commands/run.mjs +8 -336
- package/dist/lib/commands/scaffold.mjs +54 -419
- package/dist/lib/commands/scan.mjs +11 -1118
- package/dist/lib/commands/scout.mjs +2 -291
- package/dist/lib/commands/setup.mjs +5 -310
- package/dist/lib/commands/share.mjs +13 -196
- package/dist/lib/commands/snapshot.mjs +3 -383
- package/dist/lib/commands/stability.mjs +2 -293
- package/dist/lib/commands/stats.mjs +5 -402
- package/dist/lib/commands/status.mjs +4 -172
- package/dist/lib/commands/suggest.mjs +21 -563
- package/dist/lib/commands/switch.mjs +13 -520
- package/dist/lib/commands/syncAuto.mjs +1 -96
- package/dist/lib/commands/synthesize.mjs +10 -228
- package/dist/lib/commands/teamSync.mjs +2 -388
- package/dist/lib/commands/test.mjs +6 -363
- package/dist/lib/commands/theme.mjs +18 -195
- package/dist/lib/commands/uninstall.mjs +13 -406
- package/dist/lib/commands/upgrade.mjs +20 -153
- package/dist/lib/commands/version.mjs +2 -282
- package/dist/lib/commands/vibe.mjs +7 -357
- package/dist/lib/commands/watch.mjs +4 -203
- package/dist/lib/commands/why.mjs +4 -358
- package/dist/lib/cursorHooksInstall.mjs +1 -60
- package/dist/lib/draftToolingInstall.mjs +7 -68
- package/dist/lib/git/detect-drift.mjs +4 -208
- package/dist/lib/learning/adapt.mjs +6 -101
- package/dist/lib/learning/observe.mjs +1 -119
- package/dist/lib/learning/patternDetector.mjs +1 -298
- package/dist/lib/learning/profile.mjs +2 -279
- package/dist/lib/learning/skillSynthesizer.mjs +24 -145
- package/dist/lib/telemetry.mjs +19 -269
- package/dist/lib/templates/index.mjs +1 -131
- package/dist/lib/theme/scanner.mjs +4 -343
- package/dist/lib/ui/errors.mjs +1 -142
- package/dist/lib/ui/output.mjs +6 -95
- package/dist/lib/ui/prompts.mjs +6 -147
- package/dist/lib/vsCodeCopilotHooksInstall.mjs +1 -42
- package/package.json +2 -4
- package/scripts/postinstall.js +2 -2
|
@@ -1,343 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* from CSS, SCSS, CSS-in-JS, Tailwind config, and HTML files.
|
|
6
|
-
*
|
|
7
|
-
* Captures what AI can't reliably infer from scattered style files —
|
|
8
|
-
* the actual design system: palette, typography, spacing tokens.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import * as fs from "node:fs";
|
|
12
|
-
import * as path from "node:path";
|
|
13
|
-
|
|
14
|
-
// ── File discovery ────────────────────────────────────────────────────────────
|
|
15
|
-
|
|
16
|
-
const STYLE_EXTENSIONS = new Set([".css", ".scss", ".sass", ".less", ".styl"]);
|
|
17
|
-
const JS_EXTENSIONS = new Set([".js", ".mjs", ".jsx", ".ts", ".tsx"]);
|
|
18
|
-
const SKIP_DIRS = new Set(["node_modules", ".git", "dist", "build", "out", ".next", "coverage", ".cache"]);
|
|
19
|
-
|
|
20
|
-
function walkDir(dir, maxDepth = 6, depth = 0) {
|
|
21
|
-
if (depth > maxDepth) return [];
|
|
22
|
-
let files = [];
|
|
23
|
-
try {
|
|
24
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
25
|
-
if (SKIP_DIRS.has(entry.name)) continue;
|
|
26
|
-
const full = path.join(dir, entry.name);
|
|
27
|
-
if (entry.isDirectory()) {
|
|
28
|
-
files = files.concat(walkDir(full, maxDepth, depth + 1));
|
|
29
|
-
} else if (entry.isFile()) {
|
|
30
|
-
files.push(full);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
} catch {}
|
|
34
|
-
return files;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ── Color extraction ──────────────────────────────────────────────────────────
|
|
38
|
-
|
|
39
|
-
const HEX_RE = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})\b/g;
|
|
40
|
-
const RGB_RE = /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*[\d.]+)?\s*\)/g;
|
|
41
|
-
const HSL_RE = /hsla?\(\s*(\d{1,3})\s*,\s*[\d.]+%\s*,\s*[\d.]+%(?:\s*,\s*[\d.]+)?\s*\)/g;
|
|
42
|
-
|
|
43
|
-
// Colors to ignore — common resets, white/black, etc.
|
|
44
|
-
const SKIP_COLORS = new Set([
|
|
45
|
-
"#000", "#000000", "#fff", "#ffffff", "#transparent",
|
|
46
|
-
"#333", "#666", "#999", "#ccc", "#eee",
|
|
47
|
-
]);
|
|
48
|
-
|
|
49
|
-
function normalizeHex(hex) {
|
|
50
|
-
if (hex.length === 4) {
|
|
51
|
-
return "#" + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3];
|
|
52
|
-
}
|
|
53
|
-
return hex.toLowerCase();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function rgbToHex(r, g, b) {
|
|
57
|
-
return "#" + [r, g, b].map(v => parseInt(v).toString(16).padStart(2, "0")).join("");
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function extractColors(text) {
|
|
61
|
-
const freq = {};
|
|
62
|
-
|
|
63
|
-
for (const m of text.matchAll(HEX_RE)) {
|
|
64
|
-
const hex = normalizeHex(m[0]);
|
|
65
|
-
if (!SKIP_COLORS.has(hex)) freq[hex] = (freq[hex] || 0) + 1;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
for (const m of text.matchAll(RGB_RE)) {
|
|
69
|
-
const hex = rgbToHex(m[1], m[2], m[3]);
|
|
70
|
-
if (!SKIP_COLORS.has(hex)) freq[hex] = (freq[hex] || 0) + 1;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return freq;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ── Font extraction ───────────────────────────────────────────────────────────
|
|
77
|
-
|
|
78
|
-
const FONT_FAMILY_RE = /font-family\s*:\s*([^;}{]+)/gi;
|
|
79
|
-
const FONT_FACE_RE = /@font-face\s*\{[^}]*font-family\s*:\s*['"]?([^'";]+)['"]?/gi;
|
|
80
|
-
const GOOGLE_FONT_RE = /fonts\.googleapis\.com\/css[^"']*family=([^"'&]+)/gi;
|
|
81
|
-
const NEXT_FONT_RE = /from\s+['"]next\/font['"]\s*.*?{\s*([A-Z][a-zA-Z_]+)\s*}/gs;
|
|
82
|
-
const IMPORT_FONT_RE = /import\s+\{([^}]+)\}\s+from\s+['"]@fontsource\/([^'"]+)['"]/g;
|
|
83
|
-
|
|
84
|
-
function cleanFontName(raw) {
|
|
85
|
-
return raw.split(",")[0].trim().replace(/['"]/g, "").replace(/\s+/g, " ").trim();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function extractFonts(text, filePath) {
|
|
89
|
-
const fonts = new Set();
|
|
90
|
-
const sources = new Set();
|
|
91
|
-
|
|
92
|
-
for (const m of text.matchAll(FONT_FAMILY_RE)) {
|
|
93
|
-
const name = cleanFontName(m[1]);
|
|
94
|
-
if (name && !name.includes("var(") && name.length > 2) fonts.add(name);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
for (const m of text.matchAll(FONT_FACE_RE)) {
|
|
98
|
-
const name = m[1].trim().replace(/['"]/g, "");
|
|
99
|
-
if (name) { fonts.add(name); sources.add("local/@font-face"); }
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
for (const m of text.matchAll(GOOGLE_FONT_RE)) {
|
|
103
|
-
const families = decodeURIComponent(m[1]).split("|");
|
|
104
|
-
for (const fam of families) {
|
|
105
|
-
const name = fam.split(":")[0].replace(/\+/g, " ").trim();
|
|
106
|
-
if (name) { fonts.add(name); sources.add("Google Fonts"); }
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
for (const m of text.matchAll(IMPORT_FONT_RE)) {
|
|
111
|
-
const pkg = m[2].trim();
|
|
112
|
-
const name = pkg.split("/").pop().replace(/-/g, " ").replace(/\b\w/g, c => c.toUpperCase());
|
|
113
|
-
fonts.add(name);
|
|
114
|
-
sources.add("@fontsource");
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return { fonts: [...fonts], sources: [...sources] };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// ── CSS variable extraction ───────────────────────────────────────────────────
|
|
121
|
-
|
|
122
|
-
const CSS_VAR_DEF_RE = /--([\w-]+)\s*:\s*([^;}{]+)/g;
|
|
123
|
-
|
|
124
|
-
function extractCssVars(text) {
|
|
125
|
-
// Only extract vars defined in :root or at top-level (not inside selectors)
|
|
126
|
-
const vars = {};
|
|
127
|
-
|
|
128
|
-
// Find :root blocks
|
|
129
|
-
const rootBlocks = [];
|
|
130
|
-
const rootRe = /(?::root|html)\s*\{([^}]+)\}/gi;
|
|
131
|
-
for (const m of text.matchAll(rootRe)) rootBlocks.push(m[1]);
|
|
132
|
-
|
|
133
|
-
// Also scan top-level (some projects define vars without :root)
|
|
134
|
-
rootBlocks.push(text);
|
|
135
|
-
|
|
136
|
-
for (const block of rootBlocks) {
|
|
137
|
-
for (const m of block.matchAll(CSS_VAR_DEF_RE)) {
|
|
138
|
-
const name = "--" + m[1].trim();
|
|
139
|
-
const value = m[2].trim();
|
|
140
|
-
if (value && !value.includes("{")) {
|
|
141
|
-
vars[name] = value;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return vars;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// ── Tailwind config extraction ────────────────────────────────────────────────
|
|
150
|
-
|
|
151
|
-
function extractTailwindTheme(filePath) {
|
|
152
|
-
try {
|
|
153
|
-
const text = fs.readFileSync(filePath, "utf8");
|
|
154
|
-
|
|
155
|
-
const colors = {};
|
|
156
|
-
const fonts = {};
|
|
157
|
-
|
|
158
|
-
// Extract colors from theme.colors / theme.extend.colors
|
|
159
|
-
const colorBlockRe = /colors\s*:\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/g;
|
|
160
|
-
for (const m of text.matchAll(colorBlockRe)) {
|
|
161
|
-
const block = m[1];
|
|
162
|
-
for (const entry of block.matchAll(/['"]?([\w-]+)['"]?\s*:\s*['"]?(#[0-9a-fA-F]{3,6})['"]?/g)) {
|
|
163
|
-
colors[entry[1]] = normalizeHex(entry[2]);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Extract fontFamily
|
|
168
|
-
const fontBlockRe = /fontFamily\s*:\s*\{([^}]+)\}/g;
|
|
169
|
-
for (const m of text.matchAll(fontBlockRe)) {
|
|
170
|
-
const block = m[1];
|
|
171
|
-
for (const entry of block.matchAll(/['"]?([\w-]+)['"]?\s*:\s*\[['"]([^'"]+)['"]/g)) {
|
|
172
|
-
fonts[entry[1]] = entry[2];
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return { colors, fonts };
|
|
177
|
-
} catch { return null; }
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// ── Framework detection ───────────────────────────────────────────────────────
|
|
181
|
-
|
|
182
|
-
function detectFramework(files, allText) {
|
|
183
|
-
const hasFile = (name) => files.some(f => path.basename(f) === name);
|
|
184
|
-
const hasText = (s) => allText.includes(s);
|
|
185
|
-
|
|
186
|
-
if (hasFile("tailwind.config.js") || hasFile("tailwind.config.ts") || hasFile("tailwind.config.mjs")) return "tailwind";
|
|
187
|
-
if (hasText("styled-components") || hasText("createGlobalStyle")) return "styled-components";
|
|
188
|
-
if (hasText("@emotion/react") || hasText("css`") && hasText("emotion")) return "emotion";
|
|
189
|
-
if (hasText("createTheme") && hasText("@mui/material")) return "mui";
|
|
190
|
-
if (hasText("ChakraProvider") || hasText("@chakra-ui")) return "chakra";
|
|
191
|
-
if (hasText(".module.css") || hasText(".module.scss")) return "css-modules";
|
|
192
|
-
if (files.some(f => STYLE_EXTENSIONS.has(path.extname(f)))) return "plain-css";
|
|
193
|
-
return "unknown";
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// ── Color palette builder ─────────────────────────────────────────────────────
|
|
197
|
-
|
|
198
|
-
function buildPalette(colorFreq, cssVars) {
|
|
199
|
-
// Sort by frequency descending
|
|
200
|
-
const sorted = Object.entries(colorFreq).sort((a, b) => b[1] - a[1]);
|
|
201
|
-
|
|
202
|
-
// Top 12 most-used colors
|
|
203
|
-
const topColors = sorted.slice(0, 12).map(([hex]) => hex);
|
|
204
|
-
|
|
205
|
-
// Try to classify by role based on CSS var names
|
|
206
|
-
const palette = {};
|
|
207
|
-
const varColorMap = {};
|
|
208
|
-
|
|
209
|
-
for (const [name, val] of Object.entries(cssVars)) {
|
|
210
|
-
if (/^#[0-9a-fA-F]{3,6}$/.test(val)) {
|
|
211
|
-
varColorMap[normalizeHex(val)] = name;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Classify colors
|
|
216
|
-
for (const hex of topColors) {
|
|
217
|
-
const varName = varColorMap[hex];
|
|
218
|
-
if (varName) {
|
|
219
|
-
// Use the var name to guess role
|
|
220
|
-
const role = varName.replace(/^--/, "").replace(/-color$/, "");
|
|
221
|
-
palette[role] = hex;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// If palette is sparse, add raw top colors
|
|
226
|
-
if (Object.keys(palette).length < 3) {
|
|
227
|
-
topColors.slice(0, 6).forEach((hex, i) => {
|
|
228
|
-
if (!Object.values(palette).includes(hex)) {
|
|
229
|
-
palette[`color${i + 1}`] = hex;
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Detect dark/light mode
|
|
235
|
-
const bgColors = Object.entries(palette)
|
|
236
|
-
.filter(([k]) => /bg|background|surface|base/.test(k))
|
|
237
|
-
.map(([, v]) => v);
|
|
238
|
-
|
|
239
|
-
let mode = "unknown";
|
|
240
|
-
if (bgColors.length) {
|
|
241
|
-
const bg = parseInt(bgColors[0].slice(1), 16);
|
|
242
|
-
const brightness = ((bg >> 16) & 0xff) * 0.299 + ((bg >> 8) & 0xff) * 0.587 + (bg & 0xff) * 0.114;
|
|
243
|
-
mode = brightness < 128 ? "dark" : "light";
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return { palette, mode, raw: topColors };
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// ── Main scanner ──────────────────────────────────────────────────────────────
|
|
250
|
-
|
|
251
|
-
export function scanTheme(cwd = process.cwd()) {
|
|
252
|
-
const allFiles = walkDir(cwd);
|
|
253
|
-
const styleFiles = allFiles.filter(f => STYLE_EXTENSIONS.has(path.extname(f)));
|
|
254
|
-
const jsFiles = allFiles.filter(f => JS_EXTENSIONS.has(path.extname(f)));
|
|
255
|
-
const htmlFiles = allFiles.filter(f => [".html", ".htm"].includes(path.extname(f)));
|
|
256
|
-
|
|
257
|
-
const tailwindConfig = allFiles.find(f =>
|
|
258
|
-
/tailwind\.config\.(js|ts|mjs|cjs)$/.test(f)
|
|
259
|
-
);
|
|
260
|
-
|
|
261
|
-
// Read all style + HTML content
|
|
262
|
-
const styleTexts = [...styleFiles, ...htmlFiles].map(f => {
|
|
263
|
-
try { return fs.readFileSync(f, "utf8"); } catch { return ""; }
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
// Read JS files for CSS-in-JS patterns (but skip large ones)
|
|
267
|
-
const jsTexts = jsFiles
|
|
268
|
-
.filter(f => { try { return fs.statSync(f).size < 200_000; } catch { return false; } })
|
|
269
|
-
.map(f => { try { return fs.readFileSync(f, "utf8"); } catch { return ""; } });
|
|
270
|
-
|
|
271
|
-
const allStyleText = styleTexts.join("\n");
|
|
272
|
-
const allJsText = jsTexts.join("\n");
|
|
273
|
-
const allText = allStyleText + "\n" + allJsText;
|
|
274
|
-
|
|
275
|
-
// Extract
|
|
276
|
-
const colorFreq = extractColors(allStyleText);
|
|
277
|
-
|
|
278
|
-
// Also get colors from JS (CSS-in-JS)
|
|
279
|
-
const jsColorFreq = extractColors(allJsText);
|
|
280
|
-
for (const [hex, count] of Object.entries(jsColorFreq)) {
|
|
281
|
-
colorFreq[hex] = (colorFreq[hex] || 0) + Math.round(count * 0.5); // weight JS colors less
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const cssVars = extractCssVars(allStyleText);
|
|
285
|
-
|
|
286
|
-
const fontData = { fonts: new Set(), sources: new Set() };
|
|
287
|
-
for (const text of [...styleTexts, ...jsTexts]) {
|
|
288
|
-
const { fonts, sources } = extractFonts(text, "");
|
|
289
|
-
fonts.forEach(f => fontData.fonts.add(f));
|
|
290
|
-
sources.forEach(s => fontData.sources.add(s));
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const framework = detectFramework(allFiles, allText);
|
|
294
|
-
|
|
295
|
-
// Tailwind override
|
|
296
|
-
let tailwindTheme = null;
|
|
297
|
-
if (tailwindConfig) {
|
|
298
|
-
tailwindTheme = extractTailwindTheme(tailwindConfig);
|
|
299
|
-
if (tailwindTheme) {
|
|
300
|
-
for (const [name, hex] of Object.entries(tailwindTheme.colors)) {
|
|
301
|
-
colorFreq[hex] = (colorFreq[hex] || 0) + 5; // boost Tailwind colors
|
|
302
|
-
}
|
|
303
|
-
for (const [role, family] of Object.entries(tailwindTheme.fonts)) {
|
|
304
|
-
fontData.fonts.add(family);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const { palette, mode, raw } = buildPalette(colorFreq, cssVars);
|
|
310
|
-
|
|
311
|
-
// Classify fonts
|
|
312
|
-
const fontList = [...fontData.fonts].filter(f =>
|
|
313
|
-
!["inherit", "initial", "unset", "system-ui", "sans-serif", "serif", "monospace",
|
|
314
|
-
"-apple-system", "BlinkMacSystemFont", "Segoe UI"].includes(f)
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
const monoKeywords = /mono|code|courier|consol|jetbrain|fira|hack|source code/i;
|
|
318
|
-
const monoFont = fontList.find(f => monoKeywords.test(f));
|
|
319
|
-
const primaryFont = fontList.find(f => !monoKeywords.test(f));
|
|
320
|
-
|
|
321
|
-
return {
|
|
322
|
-
fonts: {
|
|
323
|
-
primary: primaryFont || null,
|
|
324
|
-
mono: monoFont || null,
|
|
325
|
-
all: fontList,
|
|
326
|
-
sources: [...fontData.sources],
|
|
327
|
-
},
|
|
328
|
-
colors: {
|
|
329
|
-
palette,
|
|
330
|
-
mode,
|
|
331
|
-
raw: raw.slice(0, 20),
|
|
332
|
-
},
|
|
333
|
-
cssVars,
|
|
334
|
-
framework,
|
|
335
|
-
tailwind: tailwindTheme,
|
|
336
|
-
stats: {
|
|
337
|
-
styleFiles: styleFiles.length,
|
|
338
|
-
jsFiles: jsFiles.length,
|
|
339
|
-
colorsFound: Object.keys(colorFreq).length,
|
|
340
|
-
varsFound: Object.keys(cssVars).length,
|
|
341
|
-
},
|
|
342
|
-
};
|
|
343
|
-
}
|
|
1
|
+
import*as p from"node:fs";import*as d from"node:path";const k=new Set([".css",".scss",".sass",".less",".styl"]),v=new Set([".js",".mjs",".jsx",".ts",".tsx"]),L=new Set(["node_modules",".git","dist","build","out",".next","coverage",".cache"]);function T(s,c=6,n=0){if(n>c)return[];let t=[];try{for(const o of p.readdirSync(s,{withFileTypes:!0})){if(L.has(o.name))continue;const r=d.join(s,o.name);o.isDirectory()?t=t.concat(T(r,c,n+1)):o.isFile()&&t.push(r)}}catch{}return t}const P=/#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})\b/g,B=/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*[\d.]+)?\s*\)/g,Z=/hsla?\(\s*(\d{1,3})\s*,\s*[\d.]+%\s*,\s*[\d.]+%(?:\s*,\s*[\d.]+)?\s*\)/g,_=new Set(["#000","#000000","#fff","#ffffff","#transparent","#333","#666","#999","#ccc","#eee"]);function b(s){return s.length===4?"#"+s[1]+s[1]+s[2]+s[2]+s[3]+s[3]:s.toLowerCase()}function G(s,c,n){return"#"+[s,c,n].map(t=>parseInt(t).toString(16).padStart(2,"0")).join("")}function E(s){const c={};for(const n of s.matchAll(P)){const t=b(n[0]);_.has(t)||(c[t]=(c[t]||0)+1)}for(const n of s.matchAll(B)){const t=G(n[1],n[2],n[3]);_.has(t)||(c[t]=(c[t]||0)+1)}return c}const M=/font-family\s*:\s*([^;}{]+)/gi,D=/@font-face\s*\{[^}]*font-family\s*:\s*['"]?([^'";]+)['"]?/gi,H=/fonts\.googleapis\.com\/css[^"']*family=([^"'&]+)/gi,Q=/from\s+['"]next\/font['"]\s*.*?{\s*([A-Z][a-zA-Z_]+)\s*}/gs,X=/import\s+\{([^}]+)\}\s+from\s+['"]@fontsource\/([^'"]+)['"]/g;function $(s){return s.split(",")[0].trim().replace(/['"]/g,"").replace(/\s+/g," ").trim()}function q(s,c){const n=new Set,t=new Set;for(const o of s.matchAll(M)){const r=$(o[1]);r&&!r.includes("var(")&&r.length>2&&n.add(r)}for(const o of s.matchAll(D)){const r=o[1].trim().replace(/['"]/g,"");r&&(n.add(r),t.add("local/@font-face"))}for(const o of s.matchAll(H)){const r=decodeURIComponent(o[1]).split("|");for(const i of r){const l=i.split(":")[0].replace(/\+/g," ").trim();l&&(n.add(l),t.add("Google Fonts"))}}for(const o of s.matchAll(X)){const i=o[2].trim().split("/").pop().replace(/-/g," ").replace(/\b\w/g,l=>l.toUpperCase());n.add(i),t.add("@fontsource")}return{fonts:[...n],sources:[...t]}}const z=/--([\w-]+)\s*:\s*([^;}{]+)/g;function K(s){const c={},n=[],t=/(?::root|html)\s*\{([^}]+)\}/gi;for(const o of s.matchAll(t))n.push(o[1]);n.push(s);for(const o of n)for(const r of o.matchAll(z)){const i="--"+r[1].trim(),l=r[2].trim();l&&!l.includes("{")&&(c[i]=l)}return c}function U(s){try{const c=p.readFileSync(s,"utf8"),n={},t={},o=/colors\s*:\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/g;for(const i of c.matchAll(o)){const l=i[1];for(const e of l.matchAll(/['"]?([\w-]+)['"]?\s*:\s*['"]?(#[0-9a-fA-F]{3,6})['"]?/g))n[e[1]]=b(e[2])}const r=/fontFamily\s*:\s*\{([^}]+)\}/g;for(const i of c.matchAll(r)){const l=i[1];for(const e of l.matchAll(/['"]?([\w-]+)['"]?\s*:\s*\[['"]([^'"]+)['"]/g))t[e[1]]=e[2]}return{colors:n,fonts:t}}catch{return null}}function V(s,c){const n=o=>s.some(r=>d.basename(r)===o),t=o=>c.includes(o);return n("tailwind.config.js")||n("tailwind.config.ts")||n("tailwind.config.mjs")?"tailwind":t("styled-components")||t("createGlobalStyle")?"styled-components":t("@emotion/react")||t("css`")&&t("emotion")?"emotion":t("createTheme")&&t("@mui/material")?"mui":t("ChakraProvider")||t("@chakra-ui")?"chakra":t(".module.css")||t(".module.scss")?"css-modules":s.some(o=>k.has(d.extname(o)))?"plain-css":"unknown"}function J(s,c){const t=Object.entries(s).sort((e,f)=>f[1]-e[1]).slice(0,12).map(([e])=>e),o={},r={};for(const[e,f]of Object.entries(c))/^#[0-9a-fA-F]{3,6}$/.test(f)&&(r[b(f)]=e);for(const e of t){const f=r[e];if(f){const y=f.replace(/^--/,"").replace(/-color$/,"");o[y]=e}}Object.keys(o).length<3&&t.slice(0,6).forEach((e,f)=>{Object.values(o).includes(e)||(o[`color${f+1}`]=e)});const i=Object.entries(o).filter(([e])=>/bg|background|surface|base/.test(e)).map(([,e])=>e);let l="unknown";if(i.length){const e=parseInt(i[0].slice(1),16);l=(e>>16&255)*.299+(e>>8&255)*.587+(e&255)*.114<128?"dark":"light"}return{palette:o,mode:l,raw:t}}function W(s=process.cwd()){const c=T(s),n=c.filter(a=>k.has(d.extname(a))),t=c.filter(a=>v.has(d.extname(a))),o=c.filter(a=>[".html",".htm"].includes(d.extname(a))),r=c.find(a=>/tailwind\.config\.(js|ts|mjs|cjs)$/.test(a)),i=[...n,...o].map(a=>{try{return p.readFileSync(a,"utf8")}catch{return""}}),l=t.filter(a=>{try{return p.statSync(a).size<2e5}catch{return!1}}).map(a=>{try{return p.readFileSync(a,"utf8")}catch{return""}}),e=i.join(`
|
|
2
|
+
`),f=l.join(`
|
|
3
|
+
`),y=e+`
|
|
4
|
+
`+f,u=E(e),O=E(f);for(const[a,m]of Object.entries(O))u[a]=(u[a]||0)+Math.round(m*.5);const F=K(e),h={fonts:new Set,sources:new Set};for(const a of[...i,...l]){const{fonts:m,sources:I}=q(a,"");m.forEach(S=>h.fonts.add(S)),I.forEach(S=>h.sources.add(S))}const A=V(c,y);let g=null;if(r&&(g=U(r),g)){for(const[a,m]of Object.entries(g.colors))u[m]=(u[m]||0)+5;for(const[a,m]of Object.entries(g.fonts))h.fonts.add(m)}const{palette:R,mode:x,raw:C}=J(u,F),w=[...h.fonts].filter(a=>!["inherit","initial","unset","system-ui","sans-serif","serif","monospace","-apple-system","BlinkMacSystemFont","Segoe UI"].includes(a)),j=/mono|code|courier|consol|jetbrain|fira|hack|source code/i,N=w.find(a=>j.test(a));return{fonts:{primary:w.find(a=>!j.test(a))||null,mono:N||null,all:w,sources:[...h.sources]},colors:{palette:R,mode:x,raw:C.slice(0,20)},cssVars:F,framework:A,tailwind:g,stats:{styleFiles:n.length,jsFiles:t.length,colorsFound:Object.keys(u).length,varsFound:Object.keys(F).length}}}export{W as scanTheme};
|
package/dist/lib/ui/errors.mjs
CHANGED
|
@@ -1,142 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Shared error handling utilities for infernoflow commands.
|
|
3
|
-
*
|
|
4
|
-
* Provides consistent, friendly error messages with actionable hints.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { warn, info, bold, cyan, gray, red } from "./output.mjs";
|
|
8
|
-
|
|
9
|
-
// ── Common error types ────────────────────────────────────────────────────────
|
|
10
|
-
|
|
11
|
-
export const ERR = {
|
|
12
|
-
NO_INFERNO_DIR: "inferno/ directory not found.",
|
|
13
|
-
NO_CONTRACT: "No contract.json or capabilities.json found.",
|
|
14
|
-
NO_GIT: "This directory is not a git repository.",
|
|
15
|
-
NO_NETWORK: "Network request failed.",
|
|
16
|
-
INVALID_JSON: "Invalid JSON in response.",
|
|
17
|
-
PERMISSION: "Permission denied.",
|
|
18
|
-
TIMEOUT: "Command timed out.",
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// ── Error formatter ───────────────────────────────────────────────────────────
|
|
22
|
-
|
|
23
|
-
export function fatalError(message, hint, jsonMode = false) {
|
|
24
|
-
if (jsonMode) {
|
|
25
|
-
console.log(JSON.stringify({ ok: false, error: message, hint: hint || undefined }));
|
|
26
|
-
} else {
|
|
27
|
-
console.error();
|
|
28
|
-
console.error(` ${red("✗")} ${bold(message)}`);
|
|
29
|
-
if (hint) console.error(` ${gray(hint)}`);
|
|
30
|
-
console.error();
|
|
31
|
-
}
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function softWarn(message, hint, jsonMode = false) {
|
|
36
|
-
if (!jsonMode) {
|
|
37
|
-
warn(message);
|
|
38
|
-
if (hint) console.error(` ${gray(hint)}`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// ── Pre-flight checks ─────────────────────────────────────────────────────────
|
|
43
|
-
|
|
44
|
-
import * as fs from "node:fs";
|
|
45
|
-
import * as path from "node:path";
|
|
46
|
-
import { execSync } from "node:child_process";
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Ensure inferno/ exists. Exits with a friendly message if not.
|
|
50
|
-
*/
|
|
51
|
-
export function requireInfernoDir(cwd, jsonMode = false) {
|
|
52
|
-
const infernoDir = path.join(cwd, "inferno");
|
|
53
|
-
if (!fs.existsSync(infernoDir)) {
|
|
54
|
-
fatalError(
|
|
55
|
-
ERR.NO_INFERNO_DIR,
|
|
56
|
-
"Run: infernoflow init (or: infernoflow setup for full setup)",
|
|
57
|
-
jsonMode
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
return infernoDir;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Ensure a git repo exists. Exits with a friendly message if not.
|
|
65
|
-
*/
|
|
66
|
-
export function requireGitRepo(cwd, jsonMode = false) {
|
|
67
|
-
try {
|
|
68
|
-
execSync("git rev-parse --git-dir", { cwd, stdio: "ignore" });
|
|
69
|
-
} catch {
|
|
70
|
-
fatalError(
|
|
71
|
-
ERR.NO_GIT,
|
|
72
|
-
"Run: git init && git add . && git commit -m 'init'",
|
|
73
|
-
jsonMode
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Read and parse a JSON file, with a friendly error on failure.
|
|
80
|
-
*/
|
|
81
|
-
export function readJsonFile(filePath, label, jsonMode = false) {
|
|
82
|
-
if (!fs.existsSync(filePath)) return null;
|
|
83
|
-
try {
|
|
84
|
-
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
85
|
-
} catch (err) {
|
|
86
|
-
fatalError(
|
|
87
|
-
`Could not parse ${label}: ${err.message}`,
|
|
88
|
-
`Check the file for syntax errors: ${filePath}`,
|
|
89
|
-
jsonMode
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Read contract.json or capabilities.json, whichever exists.
|
|
96
|
-
*/
|
|
97
|
-
export function readContract(infernoDir, jsonMode = false) {
|
|
98
|
-
for (const f of ["contract.json", "capabilities.json"]) {
|
|
99
|
-
const p = path.join(infernoDir, f);
|
|
100
|
-
const data = readJsonFile(p, f, jsonMode);
|
|
101
|
-
if (data) return data;
|
|
102
|
-
}
|
|
103
|
-
fatalError(ERR.NO_CONTRACT, "Run: infernoflow init", jsonMode);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Parse a semver string. Returns { major, minor, patch } or null.
|
|
108
|
-
*/
|
|
109
|
-
export function parseSemver(v) {
|
|
110
|
-
const m = String(v || "").match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
111
|
-
if (!m) return null;
|
|
112
|
-
return { major: +m[1], minor: +m[2], patch: +m[3], raw: m[0] };
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Validate a URL string. Returns true if valid http/https URL.
|
|
117
|
-
*/
|
|
118
|
-
export function isValidUrl(str) {
|
|
119
|
-
try {
|
|
120
|
-
const u = new URL(str);
|
|
121
|
-
return u.protocol === "http:" || u.protocol === "https:";
|
|
122
|
-
} catch { return false; }
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Wrap an async command handler with top-level error catching.
|
|
127
|
-
* Prints a friendly message instead of a raw stack trace.
|
|
128
|
-
*/
|
|
129
|
-
export function withErrorHandling(fn, jsonMode = false) {
|
|
130
|
-
return fn().catch(err => {
|
|
131
|
-
if (jsonMode) {
|
|
132
|
-
console.log(JSON.stringify({ ok: false, error: err.message }));
|
|
133
|
-
} else {
|
|
134
|
-
console.error();
|
|
135
|
-
console.error(` ${red("✗")} ${bold("Unexpected error:")} ${err.message}`);
|
|
136
|
-
if (process.env.DEBUG) console.error(err.stack);
|
|
137
|
-
else console.error(` ${gray("Set DEBUG=1 for a full stack trace.")}`);
|
|
138
|
-
console.error();
|
|
139
|
-
}
|
|
140
|
-
process.exit(1);
|
|
141
|
-
});
|
|
142
|
-
}
|
|
1
|
+
import{warn as p,bold as a,gray as i,red as l}from"./output.mjs";const s={NO_INFERNO_DIR:"inferno/ directory not found.",NO_CONTRACT:"No contract.json or capabilities.json found.",NO_GIT:"This directory is not a git repository.",NO_NETWORK:"Network request failed.",INVALID_JSON:"Invalid JSON in response.",PERMISSION:"Permission denied.",TIMEOUT:"Command timed out."};function n(o,r,e=!1){e?console.log(JSON.stringify({ok:!1,error:o,hint:r||void 0})):(console.error(),console.error(` ${l("\u2717")} ${a(o)}`),r&&console.error(` ${i(r)}`),console.error()),process.exit(1)}function g(o,r,e=!1){e||(p(o),r&&console.error(` ${i(r)}`))}import*as c from"node:fs";import*as u from"node:path";import{execSync as d}from"node:child_process";function R(o,r=!1){const e=u.join(o,"inferno");return c.existsSync(e)||n(s.NO_INFERNO_DIR,"Run: infernoflow init (or: infernoflow setup for full setup)",r),e}function S(o,r=!1){try{d("git rev-parse --git-dir",{cwd:o,stdio:"ignore"})}catch{n(s.NO_GIT,"Run: git init && git add . && git commit -m 'init'",r)}}function N(o,r,e=!1){if(!c.existsSync(o))return null;try{return JSON.parse(c.readFileSync(o,"utf8"))}catch(t){n(`Could not parse ${r}: ${t.message}`,`Check the file for syntax errors: ${o}`,e)}}function I(o,r=!1){for(const e of["contract.json","capabilities.json"]){const t=u.join(o,e),f=N(t,e,r);if(f)return f}n(s.NO_CONTRACT,"Run: infernoflow init",r)}function $(o){const r=String(o||"").match(/^(\d+)\.(\d+)\.(\d+)/);return r?{major:+r[1],minor:+r[2],patch:+r[3],raw:r[0]}:null}function E(o){try{const r=new URL(o);return r.protocol==="http:"||r.protocol==="https:"}catch{return!1}}function T(o,r=!1){return o().catch(e=>{r?console.log(JSON.stringify({ok:!1,error:e.message})):(console.error(),console.error(` ${l("\u2717")} ${a("Unexpected error:")} ${e.message}`),process.env.DEBUG?console.error(e.stack):console.error(` ${i("Set DEBUG=1 for a full stack trace.")}`),console.error()),process.exit(1)})}export{s as ERR,n as fatalError,E as isValidUrl,$ as parseSemver,I as readContract,N as readJsonFile,S as requireGitRepo,R as requireInfernoDir,g as softWarn,T as withErrorHandling};
|
package/dist/lib/ui/output.mjs
CHANGED
|
@@ -1,95 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if (process.env.WT_SESSION) return true;
|
|
8
|
-
// ConEmu / Cmder
|
|
9
|
-
if (process.env.ConEmuPID) return true;
|
|
10
|
-
// VS Code integrated terminal
|
|
11
|
-
if (process.env.TERM_PROGRAM === "vscode") return true;
|
|
12
|
-
// Default cmd.exe / PowerShell — no unicode box drawing
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
return true; // Mac/Linux always support it
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const CHARS = supportsUnicode()
|
|
19
|
-
? { h: "─", v: "│", tl: "┌", tr: "┐", bl: "└", br: "┘",
|
|
20
|
-
dot: "·", arrow: "→", check: "✔", cross: "✘", warn: "⚠", fire: "🔥" }
|
|
21
|
-
: { h: "-", v: "|", tl: "+", tr: "+", bl: "+", br: "+",
|
|
22
|
-
dot: "*", arrow: "->", check: "[OK]", cross: "[X]", warn: "[!]", fire: "**" };
|
|
23
|
-
|
|
24
|
-
export const HR = CHARS.h.repeat(50);
|
|
25
|
-
|
|
26
|
-
const c = {
|
|
27
|
-
reset: "\x1b[0m",
|
|
28
|
-
bold: "\x1b[1m",
|
|
29
|
-
red: "\x1b[31m",
|
|
30
|
-
green: "\x1b[32m",
|
|
31
|
-
yellow: "\x1b[33m",
|
|
32
|
-
blue: "\x1b[34m",
|
|
33
|
-
cyan: "\x1b[36m",
|
|
34
|
-
white: "\x1b[37m",
|
|
35
|
-
gray: "\x1b[90m",
|
|
36
|
-
orange: "\x1b[38;5;208m",
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const noColor = !process.stdout.isTTY || process.env.NO_COLOR;
|
|
40
|
-
|
|
41
|
-
function paint(code, text) {
|
|
42
|
-
if (noColor) return text;
|
|
43
|
-
return `${code}${text}${c.reset}`;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export const bold = t => paint(c.bold, t);
|
|
47
|
-
export const red = t => paint(c.red, t);
|
|
48
|
-
export const green = t => paint(c.green, t);
|
|
49
|
-
export const yellow = t => paint(c.yellow, t);
|
|
50
|
-
export const cyan = t => paint(c.cyan, t);
|
|
51
|
-
export const gray = t => paint(c.gray, t);
|
|
52
|
-
export const white = t => paint(c.white, t);
|
|
53
|
-
export const orange = t => paint(c.orange, t);
|
|
54
|
-
export const boldRed = t => paint(c.bold + c.red, t);
|
|
55
|
-
export const boldGreen = t => paint(c.bold + c.green, t);
|
|
56
|
-
export const boldYellow = t => paint(c.bold + c.yellow, t);
|
|
57
|
-
export const boldOrange = t => paint(c.bold + c.orange, t);
|
|
58
|
-
|
|
59
|
-
function strip(str) {
|
|
60
|
-
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function header(text) {
|
|
64
|
-
const title = boldOrange(CHARS.fire + " infernoflow") + gray(" — " + text);
|
|
65
|
-
console.log("\n" + title);
|
|
66
|
-
console.log(gray(HR));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function ok(msg) { console.log(" " + green(CHARS.check) + " " + msg); }
|
|
70
|
-
export function fail(msg, hint) {
|
|
71
|
-
console.log(" " + red(CHARS.cross) + " " + red(msg));
|
|
72
|
-
if (hint) console.log(" " + gray(CHARS.arrow + " " + hint));
|
|
73
|
-
}
|
|
74
|
-
export function warn(msg) { console.log(" " + yellow(CHARS.warn) + " " + yellow(msg)); }
|
|
75
|
-
export function info(msg) { console.log(" " + cyan("ℹ") + " " + msg); }
|
|
76
|
-
export function section(title) { console.log("\n" + bold(white(title))); }
|
|
77
|
-
|
|
78
|
-
export function done(msg) {
|
|
79
|
-
console.log("\n" + boldGreen("✨ " + msg) + "\n");
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function nextSteps(steps) {
|
|
83
|
-
console.log(bold("Next steps:"));
|
|
84
|
-
steps.forEach((s, i) => {
|
|
85
|
-
console.log(" " + gray((i + 1) + ".") + " " + s);
|
|
86
|
-
});
|
|
87
|
-
console.log();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function errorAndExit(msg, hint) {
|
|
91
|
-
console.error("\n" + boldRed("Error: ") + red(msg));
|
|
92
|
-
if (hint) console.error(gray(" → " + hint));
|
|
93
|
-
console.error();
|
|
94
|
-
process.exit(1);
|
|
95
|
-
}
|
|
1
|
+
function i(){return process.platform==="win32"?!!(process.env.WT_SESSION||process.env.ConEmuPID||process.env.TERM_PROGRAM==="vscode"):!0}const t=i()?{h:"\u2500",v:"\u2502",tl:"\u250C",tr:"\u2510",bl:"\u2514",br:"\u2518",dot:"\xB7",arrow:"\u2192",check:"\u2714",cross:"\u2718",warn:"\u26A0",fire:"\u{1F525}"}:{h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",dot:"*",arrow:"->",check:"[OK]",cross:"[X]",warn:"[!]",fire:"**"},f=t.h.repeat(50),e={reset:"\x1B[0m",bold:"\x1B[1m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",cyan:"\x1B[36m",white:"\x1B[37m",gray:"\x1B[90m",orange:"\x1B[38;5;208m"},u=!process.stdout.isTTY||process.env.NO_COLOR;function n(o,r){return u?r:`${o}${r}${e.reset}`}const l=o=>n(e.bold,o),s=o=>n(e.red,o),b=o=>n(e.green,o),p=o=>n(e.yellow,o),a=o=>n(e.cyan,o),c=o=>n(e.gray,o),g=o=>n(e.white,o),y=o=>n(e.orange,o),d=o=>n(e.bold+e.red,o),w=o=>n(e.bold+e.green,o),h=o=>n(e.bold+e.yellow,o),m=o=>n(e.bold+e.orange,o);function v(o){return o.replace(/\x1b\[[0-9;]*m/g,"")}function O(o){const r=m(t.fire+" infernoflow")+c(" \u2014 "+o);console.log(`
|
|
2
|
+
`+r),console.log(c(f))}function R(o){console.log(" "+b(t.check)+" "+o)}function E(o,r){console.log(" "+s(t.cross)+" "+s(o)),r&&console.log(" "+c(t.arrow+" "+r))}function S(o){console.log(" "+p(t.warn)+" "+p(o))}function k(o){console.log(" "+a("\u2139")+" "+o)}function C(o){console.log(`
|
|
3
|
+
`+l(g(o)))}function T(o){console.log(`
|
|
4
|
+
`+w("\u2728 "+o)+`
|
|
5
|
+
`)}function A(o){console.log(l("Next steps:")),o.forEach((r,x)=>{console.log(" "+c(x+1+".")+" "+r)}),console.log()}function N(o,r){console.error(`
|
|
6
|
+
`+d("Error: ")+s(o)),r&&console.error(c(" \u2192 "+r)),console.error(),process.exit(1)}export{t as CHARS,f as HR,l as bold,w as boldGreen,m as boldOrange,d as boldRed,h as boldYellow,a as cyan,T as done,N as errorAndExit,E as fail,c as gray,b as green,O as header,k as info,A as nextSteps,R as ok,y as orange,s as red,C as section,S as warn,g as white,p as yellow};
|