enterprise-ui-architect-cli 1.1.0 → 2.1.0

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/assets/SKILL.md CHANGED
@@ -557,6 +557,59 @@ After install:
557
557
  - Using different package managers within the same repo
558
558
  - Adding unused dependencies "just in case"
559
559
 
560
+ ## Translation Discipline (i18n)
561
+
562
+ When building multi-language admin dashboards with `next-intl`, `react-i18next`, or similar:
563
+
564
+ ### 1. Always Use `t()` for User-Facing Text
565
+ Every string visible to users must go through the translation function. No hardcoded labels, buttons, placeholders, or error messages.
566
+
567
+ ```tsx
568
+ // ✅ Correct
569
+ <Button>{t("form.save")}</Button>
570
+ <CustomTextField label={t("auth.username")} />
571
+
572
+ // ❌ Wrong
573
+ <Button>Save</Button>
574
+ <CustomTextField label="Username" />
575
+ ```
576
+
577
+ ### 2. Add Keys to All Locale Files
578
+ When you introduce a new `t("key")` call, you **must** add that key to **every** `messages/*.json` file before finishing.
579
+
580
+ ```bash
581
+ # Verify all keys exist in every locale
582
+ enterprise-ui verify-i18n --src ./src
583
+ ```
584
+
585
+ ### 3. Namespace Convention
586
+ Use `useTranslations("namespace")` for page-scoped keys. This keeps locale files organized and prevents key collisions.
587
+
588
+ ```tsx
589
+ const t = useTranslations("admin.users");
590
+ // keys become: admin.users.title, admin.users.column.name, etc.
591
+ ```
592
+
593
+ ### 4. Dynamic Keys
594
+ Avoid dynamic template literals for translation keys when possible:
595
+
596
+ ```tsx
597
+ // ✅ Prefer explicit mapping
598
+ const statusKey = status === "active" ? "status.active" : "status.inactive";
599
+ <Chip label={t(statusKey)} />
600
+
601
+ // ❌ Avoid
602
+ <Chip label={t(`status.${status}`)} />
603
+ ```
604
+
605
+ If dynamic keys are unavoidable, ensure all possible values are documented and present in locale files.
606
+
607
+ ### 5. Pre-Delivery Check
608
+ Before marking a feature complete:
609
+ - [ ] All `t()` keys exist in every locale file
610
+ - [ ] No hardcoded user-facing strings remain
611
+ - [ ] `enterprise-ui verify-i18n` passes with zero missing keys
612
+
560
613
  ## Keyboard Navigation
561
614
  MUI components require specific keyboard patterns:
562
615
 
@@ -0,0 +1,213 @@
1
+ import { readFileSync, existsSync, readdirSync } from "fs";
2
+ import { resolve, dirname, join, sep, extname } from "path";
3
+
4
+ interface VerifyOptions {
5
+ srcDir: string;
6
+ messagesDir: string;
7
+ }
8
+
9
+ interface KeyLocation {
10
+ key: string;
11
+ file: string;
12
+ line: number;
13
+ }
14
+
15
+ function findMessagesDir(startDir: string): string | null {
16
+ let dir = resolve(startDir);
17
+ while (dir !== dirname(dir)) {
18
+ const messagesPath = join(dir, "messages");
19
+ if (existsSync(messagesPath)) return messagesPath;
20
+ dir = dirname(dir);
21
+ }
22
+ return null;
23
+ }
24
+
25
+ function getSourceFiles(dir: string): string[] {
26
+ const results: string[] = [];
27
+ const entries = readdirSync(dir, { withFileTypes: true });
28
+
29
+ for (const entry of entries) {
30
+ const fullPath = join(dir, entry.name);
31
+ if (entry.isDirectory()) {
32
+ if (
33
+ entry.name === "node_modules" ||
34
+ entry.name === "dist" ||
35
+ entry.name === "build" ||
36
+ entry.name === ".next" ||
37
+ entry.name.startsWith(".")
38
+ ) {
39
+ continue;
40
+ }
41
+ results.push(...getSourceFiles(fullPath));
42
+ } else if (entry.isFile()) {
43
+ const ext = extname(entry.name);
44
+ if (ext === ".ts" || ext === ".tsx" || ext === ".js" || ext === ".jsx") {
45
+ results.push(fullPath);
46
+ }
47
+ }
48
+ }
49
+
50
+ return results;
51
+ }
52
+
53
+ function loadTranslations(messagesDir: string): Record<string, Record<string, unknown>> {
54
+ const files = readdirSync(messagesDir).filter((f) => f.endsWith(".json"));
55
+ const translations: Record<string, Record<string, unknown>> = {};
56
+
57
+ for (const file of files) {
58
+ const locale = file.replace(".json", "");
59
+ const content = readFileSync(join(messagesDir, file), "utf-8");
60
+ translations[locale] = JSON.parse(content);
61
+ }
62
+
63
+ return translations;
64
+ }
65
+
66
+ function getNestedValue(obj: Record<string, unknown>, path: string): unknown {
67
+ const parts = path.split(".");
68
+ let current: unknown = obj;
69
+
70
+ for (const part of parts) {
71
+ if (current === null || current === undefined) return undefined;
72
+ if (typeof current !== "object") return undefined;
73
+ current = (current as Record<string, unknown>)[part];
74
+ }
75
+
76
+ return current;
77
+ }
78
+
79
+ function extractNamespace(content: string): string | null {
80
+ const match = /useTranslations\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/.exec(content);
81
+ return match ? match[1] : null;
82
+ }
83
+
84
+ function isInsideStringLiteral(line: string, matchIndex: number): boolean {
85
+ // Check if the character before t( is inside a string literal
86
+ const before = line.slice(0, matchIndex);
87
+ let inSingle = false;
88
+ let inDouble = false;
89
+ let escaped = false;
90
+
91
+ for (const ch of before) {
92
+ if (escaped) {
93
+ escaped = false;
94
+ continue;
95
+ }
96
+ if (ch === "\\") {
97
+ escaped = true;
98
+ continue;
99
+ }
100
+ if (ch === '"' && !inSingle) {
101
+ inDouble = !inDouble;
102
+ } else if (ch === "'" && !inDouble) {
103
+ inSingle = !inSingle;
104
+ }
105
+ }
106
+
107
+ return inSingle || inDouble;
108
+ }
109
+
110
+ function extractTranslationKeys(content: string, namespace: string | null): KeyLocation[] {
111
+ const lines = content.split("\n");
112
+ const keys: KeyLocation[] = [];
113
+ const seen = new Set<string>();
114
+
115
+ const regex = /\bt\s*\(\s*["'`]([a-zA-Z0-9_.-]+)["'`]/g;
116
+
117
+ for (let i = 0; i < lines.length; i++) {
118
+ const line = lines[i];
119
+ // Skip comment-only lines
120
+ const codePart = line.split("//")[0];
121
+ if (!codePart.includes("t(")) continue;
122
+
123
+ let match: RegExpExecArray | null;
124
+ while ((match = regex.exec(line)) !== null) {
125
+ if (isInsideStringLiteral(line, match.index)) continue;
126
+
127
+ const rawKey = match[1];
128
+ const key = namespace ? `${namespace}.${rawKey}` : rawKey;
129
+ if (!seen.has(key)) {
130
+ seen.add(key);
131
+ keys.push({ key, file: "", line: i + 1 });
132
+ }
133
+ }
134
+ }
135
+
136
+ return keys;
137
+ }
138
+
139
+ export function verifyI18nCommand(options: Partial<VerifyOptions> = {}): void {
140
+ const srcDir = options.srcDir || process.cwd();
141
+ const messagesDir = options.messagesDir || findMessagesDir(srcDir);
142
+
143
+ if (!messagesDir) {
144
+ console.error("❌ messages/ directory not found. Run this from a project root.");
145
+ process.exit(1);
146
+ }
147
+
148
+ const translations = loadTranslations(messagesDir);
149
+ const locales = Object.keys(translations);
150
+
151
+ if (locales.length === 0) {
152
+ console.error("❌ No translation files found in messages/ directory.");
153
+ process.exit(1);
154
+ }
155
+
156
+ const files = getSourceFiles(srcDir);
157
+ const allKeys: Map<string, Array<{ file: string; line: number }>> = new Map();
158
+
159
+ for (const file of files) {
160
+ const content = readFileSync(file, "utf-8");
161
+ const namespace = extractNamespace(content);
162
+ const keys = extractTranslationKeys(content, namespace);
163
+ for (const { key, line } of keys) {
164
+ const list = allKeys.get(key) || [];
165
+ list.push({ file, line });
166
+ allKeys.set(key, list);
167
+ }
168
+ }
169
+
170
+ if (allKeys.size === 0) {
171
+ console.log("ℹ️ No translation keys found in source files.");
172
+ return;
173
+ }
174
+
175
+ const missingByLocale: Map<string, KeyLocation[]> = new Map();
176
+
177
+ for (const [key, locations] of allKeys) {
178
+ for (const locale of locales) {
179
+ const value = getNestedValue(translations[locale], key);
180
+ if (value === undefined) {
181
+ const list = missingByLocale.get(locale) || [];
182
+ list.push({ key, file: locations[0].file, line: locations[0].line });
183
+ missingByLocale.set(locale, list);
184
+ }
185
+ }
186
+ }
187
+
188
+ const totalMissing = Array.from(missingByLocale.values()).reduce((sum, list) => sum + list.length, 0);
189
+
190
+ if (totalMissing === 0) {
191
+ console.log(`✅ All ${allKeys.size} translation key(s) exist in every locale (${locales.join(", ")}).`);
192
+ return;
193
+ }
194
+
195
+ console.log(`⚠️ Found ${totalMissing} missing translation key(s):\n`);
196
+
197
+ for (const [locale, missing] of missingByLocale) {
198
+ if (missing.length === 0) continue;
199
+ console.log(` 🌐 ${locale}.json (${missing.length} missing):`);
200
+ for (const { key, file, line } of missing.slice(0, 10)) {
201
+ const relPath = file.replace(srcDir + sep, "").replace(/^\//, "");
202
+ console.log(` - ${key}`);
203
+ console.log(` used in: ${relPath}:${line}`);
204
+ }
205
+ if (missing.length > 10) {
206
+ console.log(` ... and ${missing.length - 10} more`);
207
+ }
208
+ console.log("");
209
+ }
210
+
211
+ console.log(`Add the missing keys to all ${locales.length} locale files.\n`);
212
+ process.exit(1);
213
+ }
@@ -1,5 +1,5 @@
1
- import { readFileSync, existsSync, readdirSync, statSync } from "fs";
2
- import { resolve, dirname, join, extname } from "path";
1
+ import { readFileSync, existsSync, readdirSync } from "fs";
2
+ import { resolve, dirname, join, sep, extname } from "path";
3
3
 
4
4
  interface VerifyOptions {
5
5
  srcDir: string;
@@ -12,6 +12,16 @@ interface ImportInfo {
12
12
  source: string;
13
13
  }
14
14
 
15
+ const NODE_BUILTINS = new Set([
16
+ "assert", "async_hooks", "buffer", "child_process", "cluster", "console",
17
+ "constants", "crypto", "dgram", "diagnostics_channel", "dns", "domain",
18
+ "events", "fs", "http", "http2", "https", "inspector", "module", "net",
19
+ "os", "path", "perf_hooks", "process", "punycode", "querystring", "readline",
20
+ "repl", "stream", "string_decoder", "sys", "timers", "timers/promises",
21
+ "tls", "trace_events", "tty", "url", "util", "v8", "vm", "wasi", "worker_threads",
22
+ "zlib", "node:test",
23
+ ]);
24
+
15
25
  function findPackageJson(startDir: string): string | null {
16
26
  let dir = resolve(startDir);
17
27
  while (dir !== dirname(dir)) {
@@ -36,22 +46,34 @@ function getInstalledPackages(packageJsonPath: string): Set<string> {
36
46
  const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
37
47
  const deps = Object.keys(pkg.dependencies || {});
38
48
  const devDeps = Object.keys(pkg.devDependencies || {});
39
- return new Set([...deps, ...devDeps]);
49
+ const peerDeps = Object.keys(pkg.peerDependencies || {});
50
+ const optionalDeps = Object.keys(pkg.optionalDependencies || {});
51
+ return new Set([...deps, ...devDeps, ...peerDeps, ...optionalDeps]);
40
52
  }
41
53
 
42
54
  function getPathAliases(tsConfigPath: string): string[] {
43
55
  try {
44
- const tsconfig = JSON.parse(readFileSync(tsConfigPath, "utf-8"));
45
- const paths = tsconfig.compilerOptions?.paths || {};
46
- return Object.keys(paths);
56
+ const raw = readFileSync(tsConfigPath, "utf-8");
57
+ // Extract path aliases via regex — tolerant to comments and trailing commas
58
+ const aliases: string[] = [];
59
+ // Match patterns like "@core/*" or "@/components/*" inside "paths": { ... }
60
+ const pathsMatch = raw.match(/"paths"\s*:\s*\{([\s\S]*?)\}/);
61
+ if (pathsMatch) {
62
+ const pathsBlock = pathsMatch[1];
63
+ const keyRegex = /"(@[^"]+)"\s*:/g;
64
+ let m: RegExpExecArray | null;
65
+ while ((m = keyRegex.exec(pathsBlock)) !== null) {
66
+ aliases.push(m[1]);
67
+ }
68
+ }
69
+ return aliases.length > 0 ? aliases : ["@/*"];
47
70
  } catch {
48
- return [];
71
+ return ["@/*"];
49
72
  }
50
73
  }
51
74
 
52
75
  function isPathAlias(source: string, aliases: string[]): boolean {
53
76
  for (const alias of aliases) {
54
- // Convert tsconfig glob to regex: @core/* → /^@core\//
55
77
  const prefix = alias.replace(/\/\*$/, "");
56
78
  if (alias.endsWith("/*")) {
57
79
  if (source === prefix || source.startsWith(prefix + "/")) {
@@ -72,7 +94,6 @@ function getSourceFiles(dir: string): string[] {
72
94
 
73
95
  for (const entry of entries) {
74
96
  const fullPath = join(dir, entry.name);
75
-
76
97
  if (entry.isDirectory()) {
77
98
  if (
78
99
  entry.name === "node_modules" ||
@@ -100,13 +121,31 @@ function extractImports(filePath: string): ImportInfo[] {
100
121
  const lines = content.split("\n");
101
122
  const imports: ImportInfo[] = [];
102
123
 
103
- const importRegex = /^(?:import\s+.*?from\s+|import\s*\(|require\s*\()["']([^"';]+)["'];?/;
124
+ // Matches single-line imports: import ... from "..."
125
+ const singleLineRegex = /^(?:import\s+.*?from\s+|import\s*\(|require\s*\()["']([^"';]+)["'];?/;
126
+
127
+ // Matches multi-line import end: from "..."
128
+ const multiLineEndRegex = /from\s+["']([^"';]+)["'];?/;
104
129
 
105
130
  for (let i = 0; i < lines.length; i++) {
106
131
  const line = lines[i].trim();
107
- const match = importRegex.exec(line);
108
- if (match) {
109
- imports.push({ path: filePath, line: i + 1, source: match[1] });
132
+ const singleMatch = singleLineRegex.exec(line);
133
+ if (singleMatch) {
134
+ imports.push({ path: filePath, line: i + 1, source: singleMatch[1] });
135
+ continue;
136
+ }
137
+ // Multi-line import: starts with "import" but no "from" on same line
138
+ if (line.startsWith("import") && !line.includes("from") && !line.includes("(")) {
139
+ // Look ahead up to 5 lines for "from '...'"
140
+ for (let j = i + 1; j < Math.min(i + 6, lines.length); j++) {
141
+ const nextLine = lines[j].trim();
142
+ const multiMatch = multiLineEndRegex.exec(nextLine);
143
+ if (multiMatch) {
144
+ imports.push({ path: filePath, line: j + 1, source: multiMatch[1] });
145
+ break;
146
+ }
147
+ if (nextLine.endsWith(";")) break; // End of import without from
148
+ }
110
149
  }
111
150
  }
112
151
 
@@ -127,7 +166,12 @@ function resolvePackageName(source: string): string | null {
127
166
  return idx > 0 ? source.slice(0, idx) : source;
128
167
  }
129
168
 
130
- function detectPackageManager(lockFiles: string[]): "npm" | "yarn" | "pnpm" | "unknown" {
169
+ function isNodeBuiltin(pkg: string): boolean {
170
+ return NODE_BUILTINS.has(pkg) || NODE_BUILTINS.has(`node:${pkg}`);
171
+ }
172
+
173
+ function detectPackageManager(lockFiles: string[]): "npm" | "yarn" | "pnpm" | "bun" | "unknown" {
174
+ if (lockFiles.some((f) => f.endsWith("bun.lockb"))) return "bun";
131
175
  if (lockFiles.some((f) => f.endsWith("pnpm-lock.yaml"))) return "pnpm";
132
176
  if (lockFiles.some((f) => f.endsWith("yarn.lock"))) return "yarn";
133
177
  if (lockFiles.some((f) => f.endsWith("package-lock.json"))) return "npm";
@@ -149,7 +193,7 @@ export function verifyImportsCommand(options: Partial<VerifyOptions> = {}): void
149
193
  const tsConfigPath = findTsConfig(srcDir);
150
194
  const pathAliases = tsConfigPath ? getPathAliases(tsConfigPath) : [];
151
195
 
152
- const lockFiles = ["package-lock.json", "yarn.lock", "pnpm-lock.yaml"].map((f) =>
196
+ const lockFiles = ["package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lockb"].map((f) =>
153
197
  join(projectRoot, f)
154
198
  );
155
199
  const existingLocks = lockFiles.filter((f) => existsSync(f));
@@ -169,6 +213,7 @@ export function verifyImportsCommand(options: Partial<VerifyOptions> = {}): void
169
213
 
170
214
  const pkg = resolvePackageName(imp.source);
171
215
  if (!pkg) continue;
216
+ if (isNodeBuiltin(pkg)) continue;
172
217
  if (installed.has(pkg)) continue;
173
218
 
174
219
  const list = missing.get(pkg) || [];
@@ -187,7 +232,7 @@ export function verifyImportsCommand(options: Partial<VerifyOptions> = {}): void
187
232
  console.log(` 📦 ${pkg}`);
188
233
  console.log(` Used in:`);
189
234
  for (const imp of imports.slice(0, 3)) {
190
- const relPath = imp.path.replace(projectRoot + "/", "");
235
+ const relPath = imp.path.replace(projectRoot + sep, "").replace(/^\//, "");
191
236
  console.log(` - ${relPath}:${imp.line} → import from "${imp.source}"`);
192
237
  }
193
238
  if (imports.length > 3) {
@@ -195,11 +240,13 @@ export function verifyImportsCommand(options: Partial<VerifyOptions> = {}): void
195
240
  }
196
241
 
197
242
  const installCmd =
198
- pkgManager === "pnpm"
199
- ? `pnpm add ${pkg}`
200
- : pkgManager === "yarn"
201
- ? `yarn add ${pkg}`
202
- : `npm install ${pkg}`;
243
+ pkgManager === "bun"
244
+ ? `bun add ${pkg}`
245
+ : pkgManager === "pnpm"
246
+ ? `pnpm add ${pkg}`
247
+ : pkgManager === "yarn"
248
+ ? `yarn add ${pkg}`
249
+ : `npm install ${pkg}`;
203
250
 
204
251
  console.log(` Install: ${installCmd}\n`);
205
252
  }
@@ -53,4 +53,6 @@ id,area,bad_pattern,why_bad,fix
53
53
  52,Charts,No empty state for charts with zero data points,Empty chart looks broken or crashes chart library,Show empty state illustration or zero baseline when no data
54
54
  53,Charts,Using real-time updates without transition animations,Jarring jumps in chart data poor perceived performance,Use Recharts animation or smooth transitions for live data updates
55
55
  54,Charts,Fetching all chart data on every small filter change,Excessive API calls slow performance backend overload,Debounce filter changes use TanStack Query staleTime cache filter state in URL
56
- 56,Dependencies,Adding new imports without verifying the package is installed,Build fails in CI or for teammates TypeScript errors runtime crashes silent failures,Always check package.json before adding an import If package is missing ask user for confirmation then install with the correct package manager
56
+ 55,Dependencies,Adding new imports without verifying the package is installed,Build fails in CI or for teammates TypeScript errors runtime crashes silent failures,Always check package.json before adding an import If package is missing ask user for confirmation then install with the correct package manager
57
+ 57,Dependencies,Adding translation keys in source code without updating all locale files,Users see raw keys or missing text in unsupported languages breaks i18n contract,When adding t(key) always add the key to every messages locale file Run verify-i18n to check
58
+ 56,i18n,Adding translation keys in code without updating all locale files,Users see raw keys or missing text in unsupported languages breaks i18n contract,When adding t(key) always add the key to every messages locale file Run verify-i18n to check
@@ -11,7 +11,7 @@ id,chart_type,library,use_case,admin_context,best_for_data,avoid_when
11
11
  10,Heatmap,ApexCharts / MUI X-Charts,Density matrix,User activity by hour/day correlation matrix,Finding patterns in dense data,Simple sparse data
12
12
  11,Scatter Plot,Recharts / ApexCharts,Correlation analysis,Price vs sales customer age vs spend,Finding relationships clusters outliers,Single variable data
13
13
  12,Bubble Chart,Recharts / ApexCharts,3-variable correlation,Deal size vs probability vs revenue impact,Adding size dimension to scatter,Too many bubbles overlap
14
- 13,Candlestick,ApexCharts / MUI X-Charts,Financial OHLC,Stock price crypto forex trading data,Open high low close financial data,Non-financial contexts
14
+ 13,Candlestick,ApexCharts,Financial OHLC,Stock price crypto forex trading data,Open high low close financial data,Non-financial contexts
15
15
  14,Sparkline,Recharts / ApexCharts,Mini trend inline,Table row mini chart card header trend,Quick trend in small space,Detailed analysis needed
16
16
  15,Gauge Chart,ApexCharts / MUI X-Charts,Single KPI progress,CPU usage disk space quota utilization,0-100% progress toward goal,Multiple metrics
17
17
  16,Funnel Chart,Recharts / ApexCharts,Conversion stages,Sales pipeline recruitment funnel drop-off,Sequential stages with drop-off,Non-sequential data
@@ -1,16 +1,16 @@
1
1
  id,industry,display_name,pattern,style_priority,color_mood,typography_mood,key_effects,anti_patterns
2
2
  1,saas,SaaS / B2B Platform,Feature-Rich Dashboard + Onboarding,bento-grid minimalism soft-ui,Clean blues + white + accent purple,Inter / Public Sans sans-serif,Micro-interactions smooth transitions 200ms subtle shadows,Skeuomorphism bright neon colors cluttered hero slow animations
3
- 2,fintech,Fintech / Banking,Data-Dense Dashboard + Transaction Table,minimalism dark-mode-optional glassmorphism,Deep navy + emerald green + gold accents,Plus Jakarta Sans / DM Sans modern geometric,Real-time data updates subtle pulse animations card hover elevation,Playful colors rounded corners everywhere emoji icons insufficient contrast
3
+ 2,fintech,Fintech / Banking,Data-Dense Dashboard + Transaction Table,minimalism dark-mode glassmorphism,Deep navy + emerald green + gold accents,Plus Jakarta Sans / DM Sans modern geometric,Real-time data updates subtle pulse animations card hover elevation,Playful colors rounded corners everywhere emoji icons insufficient contrast
4
4
  3,healthcare,Healthcare / Medical,Patient List + Appointment Calendar + Charts,minimalism accessible soft-ui,Soft teal + white + warm gray + alert red,Open Sans / Roboto highly readable,Clear visual hierarchy status badges with icons gentle transitions,Small text poor contrast complex medical jargon without tooltips missing loading states
5
5
  4,ecommerce,E-commerce Admin,Order Management + Inventory Grid + Sales Charts,bento-grid data-dense,Orange accent + white + dark sidebar + success green,Inter / Source Sans Pro clean functional,Quick actions contextual menus real-time stock indicators,Bright sales-y colors distracting animations missing empty states for out-of-stock
6
- 5,logistics,Logistics / Supply Chain,Map + Shipment Tracker + Fleet Table,real-time-monitoring glassmorphism,Deep blue + bright cyan + warning amber + map green,Roboto Mono / Inter monospace for tracking IDs,Map integrations timeline views live status indicators,Cluttered maps poor mobile experience missing offline indicators
6
+ 5,logistics,Logistics / Supply Chain,Map + Shipment Tracker + Fleet Table,real-time glassmorphism,Deep blue + bright cyan + warning amber + map green,Roboto Mono / Inter monospace for tracking IDs,Map integrations timeline views live status indicators,Cluttered maps poor mobile experience missing offline indicators
7
7
  6,hr,HR / People Management,Employee Directory + Org Chart + Payroll Table,minimalism soft-ui bento-grid,Warm purple + soft gray + white + status colors,Work Sans / Lato friendly professional,Profile cards org tree visualizations approval workflows,Overly casual fonts missing privacy indicators complex navigation too many clicks
8
8
  7,crm,CRM / Sales,Pipeline Board + Contact List + Activity Feed,bento-grid soft-ui,Electric blue + white + warm gray + deal stage colors,Inter / SF Pro clean crisp,Drag-drop pipeline activity timelines win/loss indicators,Missing empty pipeline states poor mobile card layout overwhelming notifications
9
9
  8,erp,ERP / Manufacturing,Production Dashboard + Inventory + BOM Table,data-dense executive,Industrial gray + safety orange + machine blue + alert red,IBM Plex Sans / Roboto technical precise,Machine status gauges production line visuals alert banners,Overly decorative fonts cluttered tables missing real-time indicators slow refresh
10
10
  9,education,Education / LMS,Course List + Student Progress + Gradebook,minimalism accessible soft-ui,Academic blue + warm white + success green + caution amber,Lora / Open Sans readable elegant,Progress bars achievement badges calendar views,Childish fonts excessive gamification poor accessibility missing progress persistence
11
- 10,government,Government / Public Sector,Case Management + Document List + Reporting,minimalism accessible flat-design,Official blue + white + gray + priority red,Merriweather / Open Sans formal trustworthy,Clear status workflows document version tracking audit trails,Political colors overly modern flashy design missing WCAG compliance complex language
12
- 11,cybersecurity,Cybersecurity / SOC,Alert Feed + Threat Map + Incident Table,dark-mode hud-scifi,Deep black + alert red + cyber cyan + warning amber,Fira Code / Inter monospace for logs technical,Dark theme real-time alerts threat level indicators SOC timeline,Light theme by default poor alert visibility cluttered dashboards missing severity colors
11
+ 10,government,Government / Public Sector,Case Management + Document List + Reporting,minimalism accessible,Official blue + white + gray + priority red,Merriweather / Open Sans formal trustworthy,Clear status workflows document version tracking audit trails,Political colors overly modern flashy design missing WCAG compliance complex language
12
+ 11,cybersecurity,Cybersecurity / SOC,Alert Feed + Threat Map + Incident Table,dark-mode ai-native,Deep black + alert red + cyber cyan + warning amber,Fira Code / Inter monospace for logs technical,Dark theme real-time alerts threat level indicators SOC timeline,Light theme by default poor alert visibility cluttered dashboards missing severity colors
13
13
  12,real-estate,Real Estate / Property,Property Grid + Map + Lead Pipeline,bento-grid soft-ui,Premium navy + gold accent + white + status green,Playfair Display / Inter luxury clean,Property cards map pins lead scoring visual comparison tools,Excessive imagery poor table performance missing price formatting cluttered filters
14
- 13,energy,Energy / Utilities,Grid Monitor + Meter Readings + Outage Map,real-time-monitoring data-dense,Power blue + grid yellow + outage red + eco green,Roboto / Source Sans Pro technical functional,Real-time gauges geographic outage maps consumption charts,Missing time-series data poor mobile map experience slow data refresh
14
+ 13,energy,Energy / Utilities,Grid Monitor + Meter Readings + Outage Map,real-time data-dense,Power blue + grid yellow + outage red + eco green,Roboto / Source Sans Pro technical functional,Real-time gauges geographic outage maps consumption charts,Missing time-series data poor mobile map experience slow data refresh
15
15
  14,media,Media / Content Management,Asset Library + Editorial Calendar + Analytics,minimalism bento-grid,Dark charcoal + vibrant accent + white + video red,Montserrat / Inter modern dynamic,Media previews drag-drop upload editorial timeline engagement charts,Cluttered asset grids missing metadata poor search missing preview thumbnails
16
16
  15,nonprofit,Nonprofit / NGO,Donor CRM + Campaign Tracker + Impact Dashboard,soft-ui accessible minimalism,Hope blue + growth green + warm white + heart red,Merriweather / Lora trustworthy warm,Donor profiles campaign progress impact visualization volunteer management,Overly corporate design missing donation CTAs poor mobile donation flow complex reporting
@@ -37,3 +37,6 @@ id,page_type,check,severity,why_it_matters
37
37
  36,dependencies,All new imports resolve to installed packages,High,Missing packages break builds and CI
38
38
  37,dependencies,No unused imports or dead dependencies,Medium,Bloats bundle and confuses developers
39
39
  38,dependencies,Package manager lockfile is in sync with package.json,High,Prevents inconsistent installs across environments
40
+ 39,i18n,All translation keys exist in every locale file,High,Missing keys show raw text to users
41
+ 40,i18n,No hardcoded user-facing strings outside t() calls,High,Breaks multi-language support
42
+ 41,i18n,New translation keys added to all messages files before commit,High,Prevents incomplete translations
@@ -1,6 +1,6 @@
1
1
  id,category,score_1_3,score_4_6,score_7_8,score_9_10
2
- 1,Premium Admin Visual Quality,Layout is broken or unrecognizable as admin UI; no cards; random spacing,Cards present but inconsistent; spacing varies; some hierarchy; looks like generic AntD,Clean card hierarchy; consistent spacing; feels like admin panel; status chips styled,Premium Enterprise admin feel; balanced rhythm; excellent hierarchy; polished status and actions; visually cohesive
3
- 2,AntD Architecture Quality,No typed props; inline everything; no reusable components; raw AntD dumped,Some abstractions; partial types; mixed patterns; inconsistent API surfaces,Good component boundaries; typed props; consistent Form/Table patterns; token usage,Excellent architecture; predictable APIs; disciplined abstractions; token-first; fully typed
2
+ 1,Premium Admin Visual Quality,Layout is broken or unrecognizable as admin UI; no cards; random spacing,Cards present but inconsistent; spacing varies; some hierarchy; looks like generic MUI,Clean card hierarchy; consistent spacing; feels like admin panel; status chips styled,Premium Enterprise admin feel; balanced rhythm; excellent hierarchy; polished status and actions; visually cohesive
3
+ 2,MUI Architecture Quality,No typed props; inline everything; no reusable components; raw MUI dumped,Some abstractions; partial types; mixed patterns; inconsistent API surfaces,Good component boundaries; typed props; consistent Form/Table patterns; token usage,Excellent architecture; predictable APIs; disciplined abstractions; token-first; fully typed
4
4
  3,Component Reusability,Everything inline; copy-paste patterns; no shared UI primitives,Some shared components but inconsistent props; magic numbers; hardcoded text,Reusable PageLayout Card Table Form primitives; configurable via props,Highly reusable system; composable patterns; design-token driven; minimal duplication
5
5
  4,Form Quality,No validation; no loading; no feedback; inline styles; missing labels,Basic validation; some feedback; inconsistent layout; partial loading state,Full typed Form; validation rules; helper text; dirty guard; responsive grid,Enterprise form discipline; accessible labels; clear errors; submit loading; cancel/reset; sectioned layout
6
6
  5,Table Quality,No pagination; no sorting; no rowKey; no empty state; inline columns,Basic table with some features; missing loading or error state; hardcoded columns,Typed columns; loading/empty/error; pagination; sorting; row actions; responsive plan,Production table standard; server-side ready; accessible headers; status tags; formatted values; bulk actions
@@ -52,8 +52,8 @@ def find_data_dir() -> Path:
52
52
  return candidates[0]
53
53
 
54
54
 
55
- def bm25_score(row: dict, query_terms: list[str], avgdl: float, k1: float = 1.5, b: float = 0.75) -> float:
56
- """Simple BM25-inspired scoring across all row values."""
55
+ def bm25_score(row: dict, query_terms: list[str], term_doc_counts: dict[str, int], total_docs: int, avgdl: float, k1: float = 1.5, b: float = 0.75) -> float:
56
+ """BM25 scoring with proper IDF across all row values."""
57
57
  text = " ".join(str(v).lower() for v in row.values() if v is not None)
58
58
  doc_len = len(text.split())
59
59
  score = 0.0
@@ -61,9 +61,9 @@ def bm25_score(row: dict, query_terms: list[str], avgdl: float, k1: float = 1.5,
61
61
  tf = text.count(term.lower())
62
62
  if tf == 0:
63
63
  continue
64
- # IDF approximation: log(1 + N/n) where N=total docs, n=docs with term
65
- # For simplicity, use a fixed reasonable IDF
66
- idf = 1.0
64
+ n = term_doc_counts.get(term.lower(), 1)
65
+ idf = max(0.0, (total_docs - n + 0.5) / (n + 0.5))
66
+ idf = max(0.01, idf) # Prevent negative IDF
67
67
  tf_component = (tf * (k1 + 1)) / (tf + k1 * (1 - b + b * (doc_len / max(avgdl, 1))))
68
68
  score += idf * tf_component
69
69
  return score
@@ -79,11 +79,11 @@ def search_csv(data_dir: Path, domain: str, query: str, max_results: int = 10) -
79
79
  if not filepath.exists():
80
80
  return f"Error: File not found: {filepath}"
81
81
 
82
- query_terms = query.split()
82
+ query_terms = [t.lower() for t in query.split()]
83
83
  results = []
84
84
  total_docs = 0
85
85
 
86
- # First pass: count total docs and average doc length
86
+ # First pass: count total docs, avgdl, and term document frequencies
87
87
  with open(filepath, newline="", encoding="utf-8") as f:
88
88
  reader = csv.DictReader(f)
89
89
  docs = list(reader)
@@ -91,9 +91,18 @@ def search_csv(data_dir: Path, domain: str, query: str, max_results: int = 10) -
91
91
  total_len = sum(len(" ".join(str(v) for v in r.values() if v is not None).split()) for r in docs)
92
92
  avgdl = total_len / max(total_docs, 1)
93
93
 
94
+ term_doc_counts: dict[str, int] = {}
95
+ for term in query_terms:
96
+ count = 0
97
+ for row in docs:
98
+ text = " ".join(str(v).lower() for v in row.values() if v is not None)
99
+ if term in text:
100
+ count += 1
101
+ term_doc_counts[term] = max(count, 1)
102
+
94
103
  # Second pass: score
95
104
  for row in docs:
96
- s = bm25_score(row, query_terms, avgdl)
105
+ s = bm25_score(row, query_terms, term_doc_counts, total_docs, avgdl)
97
106
  if s > 0:
98
107
  results.append((s, row))
99
108
 
@@ -227,10 +236,13 @@ def main():
227
236
 
228
237
  if args.domain == "all":
229
238
  for domain in DOMAINS:
239
+ result = search_csv(data_dir, domain, args.query, args.n)
240
+ if "No results" in result:
241
+ continue
230
242
  print(f"\n{'='*60}")
231
243
  print(f"Domain: {domain}")
232
244
  print(f"{'='*60}")
233
- print(search_csv(data_dir, domain, args.query, args.n))
245
+ print(result)
234
246
  return
235
247
 
236
248
  output = search_csv(data_dir, args.domain, args.query, args.n)
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { initCommand } from "./commands/init.js";
3
3
  import { verifyImportsCommand } from "./commands/verify-imports.js";
4
+ import { verifyI18nCommand } from "./commands/verify-i18n.js";
4
5
 
5
6
  function showHelp(): void {
6
7
  console.log(`
@@ -9,10 +10,12 @@ Enterprise UI Architect CLI
9
10
  Usage:
10
11
  enterprise-ui init [options]
11
12
  enterprise-ui verify-imports [options]
13
+ enterprise-ui verify-i18n [options]
12
14
 
13
15
  Commands:
14
16
  init Install skill into AI coding assistants
15
17
  verify-imports Scan source files and report missing npm packages
18
+ verify-i18n Scan source files and report missing translation keys
16
19
 
17
20
  Options:
18
21
  --ai <assistant> Target AI assistant: cursor, claude, windsurf, copilot, codex, all (default: all)
@@ -26,6 +29,8 @@ Examples:
26
29
  enterprise-ui init --ai claude --offline
27
30
  enterprise-ui verify-imports
28
31
  enterprise-ui verify-imports --src ./src
32
+ enterprise-ui verify-i18n
33
+ enterprise-ui verify-i18n --src ./src
29
34
  `);
30
35
  }
31
36
 
@@ -42,7 +47,7 @@ function parseArgs(args: string[]): {
42
47
 
43
48
  for (let i = 0; i < args.length; i++) {
44
49
  const arg = args[i];
45
- if (arg === "init" || arg === "verify-imports") {
50
+ if (arg === "init" || arg === "verify-imports" || arg === "verify-i18n") {
46
51
  command = arg;
47
52
  } else if (arg === "--ai" && i + 1 < args.length) {
48
53
  result.ai = args[++i];
@@ -65,7 +70,7 @@ function main(): number {
65
70
  const parsed = parseArgs(args);
66
71
 
67
72
  if (parsed.version) {
68
- console.log("1.0.0");
73
+ console.log("2.0.0");
69
74
  return 0;
70
75
  }
71
76
 
@@ -94,6 +99,16 @@ function main(): number {
94
99
  }
95
100
  }
96
101
 
102
+ if (parsed.command === "verify-i18n") {
103
+ try {
104
+ verifyI18nCommand({ srcDir: parsed.srcDir });
105
+ return 0;
106
+ } catch (err) {
107
+ console.error(`Error: ${(err as Error).message}`);
108
+ return 1;
109
+ }
110
+ }
111
+
97
112
  console.error(`Unknown command. Run --help for usage.`);
98
113
  return 1;
99
114
  }
@@ -93,6 +93,24 @@ python scripts/search.py --query "saas" --design-system --persist --product "MyA
93
93
  - [ ] Implement retry + error fallback for unstable APIs
94
94
  - [ ] Use refetchInterval or WebSocket for real-time dashboards
95
95
 
96
+ ## Package Import Verification
97
+ ```bash
98
+ enterprise-ui verify-imports --src ./src
99
+ ```
100
+ - [ ] All new imports resolve to installed packages
101
+ - [ ] Check package.json before adding imports
102
+ - [ ] Ask user before installing missing packages
103
+ - [ ] Post-install: run `npx tsc --noEmit`
104
+
105
+ ## Translation Verification
106
+ ```bash
107
+ enterprise-ui verify-i18n --src ./src
108
+ ```
109
+ - [ ] All user-facing strings use `t()` — no hardcoded text
110
+ - [ ] Every `t("key")` exists in all `messages/*.json` files
111
+ - [ ] Use `useTranslations("namespace")` for page-scoped keys
112
+ - [ ] Avoid dynamic template literals for keys
113
+
96
114
  ## Pre-Delivery Checklist
97
115
  - [ ] All interactive elements have hover states and cursor-pointer
98
116
  - [ ] Focus states are visible and consistent
@@ -0,0 +1,7 @@
1
+ interface VerifyOptions {
2
+ srcDir: string;
3
+ messagesDir: string;
4
+ }
5
+ export declare function verifyI18nCommand(options?: Partial<VerifyOptions>): void;
6
+ export {};
7
+ //# sourceMappingURL=verify-i18n.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-i18n.d.ts","sourceRoot":"","sources":["../../src/commands/verify-i18n.ts"],"names":[],"mappings":"AAGA,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAoID,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM,GAAG,IAAI,CA0E5E"}
@@ -0,0 +1,175 @@
1
+ import { readFileSync, existsSync, readdirSync } from "fs";
2
+ import { resolve, dirname, join, sep, extname } from "path";
3
+ function findMessagesDir(startDir) {
4
+ let dir = resolve(startDir);
5
+ while (dir !== dirname(dir)) {
6
+ const messagesPath = join(dir, "messages");
7
+ if (existsSync(messagesPath))
8
+ return messagesPath;
9
+ dir = dirname(dir);
10
+ }
11
+ return null;
12
+ }
13
+ function getSourceFiles(dir) {
14
+ const results = [];
15
+ const entries = readdirSync(dir, { withFileTypes: true });
16
+ for (const entry of entries) {
17
+ const fullPath = join(dir, entry.name);
18
+ if (entry.isDirectory()) {
19
+ if (entry.name === "node_modules" ||
20
+ entry.name === "dist" ||
21
+ entry.name === "build" ||
22
+ entry.name === ".next" ||
23
+ entry.name.startsWith(".")) {
24
+ continue;
25
+ }
26
+ results.push(...getSourceFiles(fullPath));
27
+ }
28
+ else if (entry.isFile()) {
29
+ const ext = extname(entry.name);
30
+ if (ext === ".ts" || ext === ".tsx" || ext === ".js" || ext === ".jsx") {
31
+ results.push(fullPath);
32
+ }
33
+ }
34
+ }
35
+ return results;
36
+ }
37
+ function loadTranslations(messagesDir) {
38
+ const files = readdirSync(messagesDir).filter((f) => f.endsWith(".json"));
39
+ const translations = {};
40
+ for (const file of files) {
41
+ const locale = file.replace(".json", "");
42
+ const content = readFileSync(join(messagesDir, file), "utf-8");
43
+ translations[locale] = JSON.parse(content);
44
+ }
45
+ return translations;
46
+ }
47
+ function getNestedValue(obj, path) {
48
+ const parts = path.split(".");
49
+ let current = obj;
50
+ for (const part of parts) {
51
+ if (current === null || current === undefined)
52
+ return undefined;
53
+ if (typeof current !== "object")
54
+ return undefined;
55
+ current = current[part];
56
+ }
57
+ return current;
58
+ }
59
+ function extractNamespace(content) {
60
+ const match = /useTranslations\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/.exec(content);
61
+ return match ? match[1] : null;
62
+ }
63
+ function isInsideStringLiteral(line, matchIndex) {
64
+ // Check if the character before t( is inside a string literal
65
+ const before = line.slice(0, matchIndex);
66
+ let inSingle = false;
67
+ let inDouble = false;
68
+ let escaped = false;
69
+ for (const ch of before) {
70
+ if (escaped) {
71
+ escaped = false;
72
+ continue;
73
+ }
74
+ if (ch === "\\") {
75
+ escaped = true;
76
+ continue;
77
+ }
78
+ if (ch === '"' && !inSingle) {
79
+ inDouble = !inDouble;
80
+ }
81
+ else if (ch === "'" && !inDouble) {
82
+ inSingle = !inSingle;
83
+ }
84
+ }
85
+ return inSingle || inDouble;
86
+ }
87
+ function extractTranslationKeys(content, namespace) {
88
+ const lines = content.split("\n");
89
+ const keys = [];
90
+ const seen = new Set();
91
+ const regex = /\bt\s*\(\s*["'`]([a-zA-Z0-9_.-]+)["'`]/g;
92
+ for (let i = 0; i < lines.length; i++) {
93
+ const line = lines[i];
94
+ // Skip comment-only lines
95
+ const codePart = line.split("//")[0];
96
+ if (!codePart.includes("t("))
97
+ continue;
98
+ let match;
99
+ while ((match = regex.exec(line)) !== null) {
100
+ if (isInsideStringLiteral(line, match.index))
101
+ continue;
102
+ const rawKey = match[1];
103
+ const key = namespace ? `${namespace}.${rawKey}` : rawKey;
104
+ if (!seen.has(key)) {
105
+ seen.add(key);
106
+ keys.push({ key, file: "", line: i + 1 });
107
+ }
108
+ }
109
+ }
110
+ return keys;
111
+ }
112
+ export function verifyI18nCommand(options = {}) {
113
+ const srcDir = options.srcDir || process.cwd();
114
+ const messagesDir = options.messagesDir || findMessagesDir(srcDir);
115
+ if (!messagesDir) {
116
+ console.error("❌ messages/ directory not found. Run this from a project root.");
117
+ process.exit(1);
118
+ }
119
+ const translations = loadTranslations(messagesDir);
120
+ const locales = Object.keys(translations);
121
+ if (locales.length === 0) {
122
+ console.error("❌ No translation files found in messages/ directory.");
123
+ process.exit(1);
124
+ }
125
+ const files = getSourceFiles(srcDir);
126
+ const allKeys = new Map();
127
+ for (const file of files) {
128
+ const content = readFileSync(file, "utf-8");
129
+ const namespace = extractNamespace(content);
130
+ const keys = extractTranslationKeys(content, namespace);
131
+ for (const { key, line } of keys) {
132
+ const list = allKeys.get(key) || [];
133
+ list.push({ file, line });
134
+ allKeys.set(key, list);
135
+ }
136
+ }
137
+ if (allKeys.size === 0) {
138
+ console.log("ℹ️ No translation keys found in source files.");
139
+ return;
140
+ }
141
+ const missingByLocale = new Map();
142
+ for (const [key, locations] of allKeys) {
143
+ for (const locale of locales) {
144
+ const value = getNestedValue(translations[locale], key);
145
+ if (value === undefined) {
146
+ const list = missingByLocale.get(locale) || [];
147
+ list.push({ key, file: locations[0].file, line: locations[0].line });
148
+ missingByLocale.set(locale, list);
149
+ }
150
+ }
151
+ }
152
+ const totalMissing = Array.from(missingByLocale.values()).reduce((sum, list) => sum + list.length, 0);
153
+ if (totalMissing === 0) {
154
+ console.log(`✅ All ${allKeys.size} translation key(s) exist in every locale (${locales.join(", ")}).`);
155
+ return;
156
+ }
157
+ console.log(`⚠️ Found ${totalMissing} missing translation key(s):\n`);
158
+ for (const [locale, missing] of missingByLocale) {
159
+ if (missing.length === 0)
160
+ continue;
161
+ console.log(` 🌐 ${locale}.json (${missing.length} missing):`);
162
+ for (const { key, file, line } of missing.slice(0, 10)) {
163
+ const relPath = file.replace(srcDir + sep, "").replace(/^\//, "");
164
+ console.log(` - ${key}`);
165
+ console.log(` used in: ${relPath}:${line}`);
166
+ }
167
+ if (missing.length > 10) {
168
+ console.log(` ... and ${missing.length - 10} more`);
169
+ }
170
+ console.log("");
171
+ }
172
+ console.log(`Add the missing keys to all ${locales.length} locale files.\n`);
173
+ process.exit(1);
174
+ }
175
+ //# sourceMappingURL=verify-i18n.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-i18n.js","sourceRoot":"","sources":["../../src/commands/verify-i18n.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"verify-imports.d.ts","sourceRoot":"","sources":["../../src/commands/verify-imports.ts"],"names":[],"mappings":"AAGA,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;CACzB;AAkID,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM,GAAG,IAAI,CAwE/E"}
1
+ {"version":3,"file":"verify-imports.d.ts","sourceRoot":"","sources":["../../src/commands/verify-imports.ts"],"names":[],"mappings":"AAGA,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;CACzB;AA8KD,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM,GAAG,IAAI,CA2E/E"}
@@ -1,5 +1,14 @@
1
1
  import { readFileSync, existsSync, readdirSync } from "fs";
2
- import { resolve, dirname, join, extname } from "path";
2
+ import { resolve, dirname, join, sep, extname } from "path";
3
+ const NODE_BUILTINS = new Set([
4
+ "assert", "async_hooks", "buffer", "child_process", "cluster", "console",
5
+ "constants", "crypto", "dgram", "diagnostics_channel", "dns", "domain",
6
+ "events", "fs", "http", "http2", "https", "inspector", "module", "net",
7
+ "os", "path", "perf_hooks", "process", "punycode", "querystring", "readline",
8
+ "repl", "stream", "string_decoder", "sys", "timers", "timers/promises",
9
+ "tls", "trace_events", "tty", "url", "util", "v8", "vm", "wasi", "worker_threads",
10
+ "zlib", "node:test",
11
+ ]);
3
12
  function findPackageJson(startDir) {
4
13
  let dir = resolve(startDir);
5
14
  while (dir !== dirname(dir)) {
@@ -24,21 +33,33 @@ function getInstalledPackages(packageJsonPath) {
24
33
  const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
25
34
  const deps = Object.keys(pkg.dependencies || {});
26
35
  const devDeps = Object.keys(pkg.devDependencies || {});
27
- return new Set([...deps, ...devDeps]);
36
+ const peerDeps = Object.keys(pkg.peerDependencies || {});
37
+ const optionalDeps = Object.keys(pkg.optionalDependencies || {});
38
+ return new Set([...deps, ...devDeps, ...peerDeps, ...optionalDeps]);
28
39
  }
29
40
  function getPathAliases(tsConfigPath) {
30
41
  try {
31
- const tsconfig = JSON.parse(readFileSync(tsConfigPath, "utf-8"));
32
- const paths = tsconfig.compilerOptions?.paths || {};
33
- return Object.keys(paths);
42
+ const raw = readFileSync(tsConfigPath, "utf-8");
43
+ // Extract path aliases via regex — tolerant to comments and trailing commas
44
+ const aliases = [];
45
+ // Match patterns like "@core/*" or "@/components/*" inside "paths": { ... }
46
+ const pathsMatch = raw.match(/"paths"\s*:\s*\{([\s\S]*?)\}/);
47
+ if (pathsMatch) {
48
+ const pathsBlock = pathsMatch[1];
49
+ const keyRegex = /"(@[^"]+)"\s*:/g;
50
+ let m;
51
+ while ((m = keyRegex.exec(pathsBlock)) !== null) {
52
+ aliases.push(m[1]);
53
+ }
54
+ }
55
+ return aliases.length > 0 ? aliases : ["@/*"];
34
56
  }
35
57
  catch {
36
- return [];
58
+ return ["@/*"];
37
59
  }
38
60
  }
39
61
  function isPathAlias(source, aliases) {
40
62
  for (const alias of aliases) {
41
- // Convert tsconfig glob to regex: @core/* → /^@core\//
42
63
  const prefix = alias.replace(/\/\*$/, "");
43
64
  if (alias.endsWith("/*")) {
44
65
  if (source === prefix || source.startsWith(prefix + "/")) {
@@ -81,12 +102,30 @@ function extractImports(filePath) {
81
102
  const content = readFileSync(filePath, "utf-8");
82
103
  const lines = content.split("\n");
83
104
  const imports = [];
84
- const importRegex = /^(?:import\s+.*?from\s+|import\s*\(|require\s*\()["']([^"';]+)["'];?/;
105
+ // Matches single-line imports: import ... from "..."
106
+ const singleLineRegex = /^(?:import\s+.*?from\s+|import\s*\(|require\s*\()["']([^"';]+)["'];?/;
107
+ // Matches multi-line import end: from "..."
108
+ const multiLineEndRegex = /from\s+["']([^"';]+)["'];?/;
85
109
  for (let i = 0; i < lines.length; i++) {
86
110
  const line = lines[i].trim();
87
- const match = importRegex.exec(line);
88
- if (match) {
89
- imports.push({ path: filePath, line: i + 1, source: match[1] });
111
+ const singleMatch = singleLineRegex.exec(line);
112
+ if (singleMatch) {
113
+ imports.push({ path: filePath, line: i + 1, source: singleMatch[1] });
114
+ continue;
115
+ }
116
+ // Multi-line import: starts with "import" but no "from" on same line
117
+ if (line.startsWith("import") && !line.includes("from") && !line.includes("(")) {
118
+ // Look ahead up to 5 lines for "from '...'"
119
+ for (let j = i + 1; j < Math.min(i + 6, lines.length); j++) {
120
+ const nextLine = lines[j].trim();
121
+ const multiMatch = multiLineEndRegex.exec(nextLine);
122
+ if (multiMatch) {
123
+ imports.push({ path: filePath, line: j + 1, source: multiMatch[1] });
124
+ break;
125
+ }
126
+ if (nextLine.endsWith(";"))
127
+ break; // End of import without from
128
+ }
90
129
  }
91
130
  }
92
131
  return imports;
@@ -105,7 +144,12 @@ function resolvePackageName(source) {
105
144
  const idx = source.indexOf("/");
106
145
  return idx > 0 ? source.slice(0, idx) : source;
107
146
  }
147
+ function isNodeBuiltin(pkg) {
148
+ return NODE_BUILTINS.has(pkg) || NODE_BUILTINS.has(`node:${pkg}`);
149
+ }
108
150
  function detectPackageManager(lockFiles) {
151
+ if (lockFiles.some((f) => f.endsWith("bun.lockb")))
152
+ return "bun";
109
153
  if (lockFiles.some((f) => f.endsWith("pnpm-lock.yaml")))
110
154
  return "pnpm";
111
155
  if (lockFiles.some((f) => f.endsWith("yarn.lock")))
@@ -125,7 +169,7 @@ export function verifyImportsCommand(options = {}) {
125
169
  const projectRoot = dirname(packageJsonPath);
126
170
  const tsConfigPath = findTsConfig(srcDir);
127
171
  const pathAliases = tsConfigPath ? getPathAliases(tsConfigPath) : [];
128
- const lockFiles = ["package-lock.json", "yarn.lock", "pnpm-lock.yaml"].map((f) => join(projectRoot, f));
172
+ const lockFiles = ["package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lockb"].map((f) => join(projectRoot, f));
129
173
  const existingLocks = lockFiles.filter((f) => existsSync(f));
130
174
  const pkgManager = detectPackageManager(existingLocks);
131
175
  const files = getSourceFiles(srcDir);
@@ -140,6 +184,8 @@ export function verifyImportsCommand(options = {}) {
140
184
  const pkg = resolvePackageName(imp.source);
141
185
  if (!pkg)
142
186
  continue;
187
+ if (isNodeBuiltin(pkg))
188
+ continue;
143
189
  if (installed.has(pkg))
144
190
  continue;
145
191
  const list = missing.get(pkg) || [];
@@ -155,17 +201,19 @@ export function verifyImportsCommand(options = {}) {
155
201
  console.log(` 📦 ${pkg}`);
156
202
  console.log(` Used in:`);
157
203
  for (const imp of imports.slice(0, 3)) {
158
- const relPath = imp.path.replace(projectRoot + "/", "");
204
+ const relPath = imp.path.replace(projectRoot + sep, "").replace(/^\//, "");
159
205
  console.log(` - ${relPath}:${imp.line} → import from "${imp.source}"`);
160
206
  }
161
207
  if (imports.length > 3) {
162
208
  console.log(` ... and ${imports.length - 3} more`);
163
209
  }
164
- const installCmd = pkgManager === "pnpm"
165
- ? `pnpm add ${pkg}`
166
- : pkgManager === "yarn"
167
- ? `yarn add ${pkg}`
168
- : `npm install ${pkg}`;
210
+ const installCmd = pkgManager === "bun"
211
+ ? `bun add ${pkg}`
212
+ : pkgManager === "pnpm"
213
+ ? `pnpm add ${pkg}`
214
+ : pkgManager === "yarn"
215
+ ? `yarn add ${pkg}`
216
+ : `npm install ${pkg}`;
169
217
  console.log(` Install: ${installCmd}\n`);
170
218
  }
171
219
  console.log(`Run the install command(s) above, then re-run this check.\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"verify-imports.js","sourceRoot":"","sources":["../../src/commands/verify-imports.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verify-imports.js","sourceRoot":"","sources":["../../src/commands/verify-imports.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { initCommand } from "./commands/init.js";
3
3
  import { verifyImportsCommand } from "./commands/verify-imports.js";
4
+ import { verifyI18nCommand } from "./commands/verify-i18n.js";
4
5
  function showHelp() {
5
6
  console.log(`
6
7
  Enterprise UI Architect CLI
@@ -8,10 +9,12 @@ Enterprise UI Architect CLI
8
9
  Usage:
9
10
  enterprise-ui init [options]
10
11
  enterprise-ui verify-imports [options]
12
+ enterprise-ui verify-i18n [options]
11
13
 
12
14
  Commands:
13
15
  init Install skill into AI coding assistants
14
16
  verify-imports Scan source files and report missing npm packages
17
+ verify-i18n Scan source files and report missing translation keys
15
18
 
16
19
  Options:
17
20
  --ai <assistant> Target AI assistant: cursor, claude, windsurf, copilot, codex, all (default: all)
@@ -25,6 +28,8 @@ Examples:
25
28
  enterprise-ui init --ai claude --offline
26
29
  enterprise-ui verify-imports
27
30
  enterprise-ui verify-imports --src ./src
31
+ enterprise-ui verify-i18n
32
+ enterprise-ui verify-i18n --src ./src
28
33
  `);
29
34
  }
30
35
  function parseArgs(args) {
@@ -32,7 +37,7 @@ function parseArgs(args) {
32
37
  let command;
33
38
  for (let i = 0; i < args.length; i++) {
34
39
  const arg = args[i];
35
- if (arg === "init" || arg === "verify-imports") {
40
+ if (arg === "init" || arg === "verify-imports" || arg === "verify-i18n") {
36
41
  command = arg;
37
42
  }
38
43
  else if (arg === "--ai" && i + 1 < args.length) {
@@ -57,7 +62,7 @@ function main() {
57
62
  const args = process.argv.slice(2);
58
63
  const parsed = parseArgs(args);
59
64
  if (parsed.version) {
60
- console.log("1.0.0");
65
+ console.log("2.1.0");
61
66
  return 0;
62
67
  }
63
68
  if (parsed.help || args.length === 0) {
@@ -84,6 +89,16 @@ function main() {
84
89
  return 1;
85
90
  }
86
91
  }
92
+ if (parsed.command === "verify-i18n") {
93
+ try {
94
+ verifyI18nCommand({ srcDir: parsed.srcDir });
95
+ return 0;
96
+ }
97
+ catch (err) {
98
+ console.error(`Error: ${err.message}`);
99
+ return 1;
100
+ }
101
+ }
87
102
  console.error(`Unknown command. Run --help for usage.`);
88
103
  return 1;
89
104
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "enterprise-ui-architect-cli",
3
- "version": "1.1.0",
3
+ "version": "2.1.0",
4
4
  "description": "CLI for installing Enterprise UI Architect skill into AI coding assistants",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",