enterprise-ui-architect-cli 1.0.0 → 2.0.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.
@@ -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)
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+ import { initCommand } from "./commands/init.js";
3
+ import { verifyImportsCommand } from "./commands/verify-imports.js";
4
+ import { verifyI18nCommand } from "./commands/verify-i18n.js";
5
+
6
+ function showHelp(): void {
7
+ console.log(`
8
+ Enterprise UI Architect CLI
9
+
10
+ Usage:
11
+ enterprise-ui init [options]
12
+ enterprise-ui verify-imports [options]
13
+ enterprise-ui verify-i18n [options]
14
+
15
+ Commands:
16
+ init Install skill into AI coding assistants
17
+ verify-imports Scan source files and report missing npm packages
18
+ verify-i18n Scan source files and report missing translation keys
19
+
20
+ Options:
21
+ --ai <assistant> Target AI assistant: cursor, claude, windsurf, copilot, codex, all (default: all)
22
+ --offline Use local assets without network (default: false)
23
+ --src <dir> Source directory to scan (default: current directory)
24
+ --help Show this help
25
+ --version Show version
26
+
27
+ Examples:
28
+ enterprise-ui init --ai cursor
29
+ enterprise-ui init --ai claude --offline
30
+ enterprise-ui verify-imports
31
+ enterprise-ui verify-imports --src ./src
32
+ enterprise-ui verify-i18n
33
+ enterprise-ui verify-i18n --src ./src
34
+ `);
35
+ }
36
+
37
+ function parseArgs(args: string[]): {
38
+ command?: string;
39
+ ai: string;
40
+ offline: boolean;
41
+ srcDir: string;
42
+ help: boolean;
43
+ version: boolean;
44
+ } {
45
+ const result = { ai: "all", offline: false, srcDir: process.cwd(), help: false, version: false };
46
+ let command: string | undefined;
47
+
48
+ for (let i = 0; i < args.length; i++) {
49
+ const arg = args[i];
50
+ if (arg === "init" || arg === "verify-imports" || arg === "verify-i18n") {
51
+ command = arg;
52
+ } else if (arg === "--ai" && i + 1 < args.length) {
53
+ result.ai = args[++i];
54
+ } else if (arg === "--offline") {
55
+ result.offline = true;
56
+ } else if (arg === "--src" && i + 1 < args.length) {
57
+ result.srcDir = args[++i];
58
+ } else if (arg === "--help" || arg === "-h") {
59
+ result.help = true;
60
+ } else if (arg === "--version" || arg === "-v") {
61
+ result.version = true;
62
+ }
63
+ }
64
+
65
+ return { command, ...result };
66
+ }
67
+
68
+ function main(): number {
69
+ const args = process.argv.slice(2);
70
+ const parsed = parseArgs(args);
71
+
72
+ if (parsed.version) {
73
+ console.log("2.0.0");
74
+ return 0;
75
+ }
76
+
77
+ if (parsed.help || args.length === 0) {
78
+ showHelp();
79
+ return 0;
80
+ }
81
+
82
+ if (parsed.command === "init") {
83
+ try {
84
+ initCommand({ ai: parsed.ai, offline: parsed.offline });
85
+ return 0;
86
+ } catch (err) {
87
+ console.error(`Error: ${(err as Error).message}`);
88
+ return 1;
89
+ }
90
+ }
91
+
92
+ if (parsed.command === "verify-imports") {
93
+ try {
94
+ verifyImportsCommand({ srcDir: parsed.srcDir });
95
+ return 0;
96
+ } catch (err) {
97
+ console.error(`Error: ${(err as Error).message}`);
98
+ return 1;
99
+ }
100
+ }
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
+
112
+ console.error(`Unknown command. Run --help for usage.`);
113
+ return 1;
114
+ }
115
+
116
+ process.exit(main());
@@ -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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"}
@@ -0,0 +1,7 @@
1
+ interface VerifyOptions {
2
+ srcDir: string;
3
+ packageJsonPath: string;
4
+ }
5
+ export declare function verifyImportsCommand(options?: Partial<VerifyOptions>): void;
6
+ export {};
7
+ //# sourceMappingURL=verify-imports.d.ts.map
@@ -0,0 +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;AA8KD,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM,GAAG,IAAI,CA2E/E"}
@@ -0,0 +1,222 @@
1
+ import { readFileSync, existsSync, readdirSync } from "fs";
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
+ ]);
12
+ function findPackageJson(startDir) {
13
+ let dir = resolve(startDir);
14
+ while (dir !== dirname(dir)) {
15
+ const pkgPath = join(dir, "package.json");
16
+ if (existsSync(pkgPath))
17
+ return pkgPath;
18
+ dir = dirname(dir);
19
+ }
20
+ return null;
21
+ }
22
+ function findTsConfig(startDir) {
23
+ let dir = resolve(startDir);
24
+ while (dir !== dirname(dir)) {
25
+ const tsPath = join(dir, "tsconfig.json");
26
+ if (existsSync(tsPath))
27
+ return tsPath;
28
+ dir = dirname(dir);
29
+ }
30
+ return null;
31
+ }
32
+ function getInstalledPackages(packageJsonPath) {
33
+ const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
34
+ const deps = Object.keys(pkg.dependencies || {});
35
+ const devDeps = Object.keys(pkg.devDependencies || {});
36
+ const peerDeps = Object.keys(pkg.peerDependencies || {});
37
+ const optionalDeps = Object.keys(pkg.optionalDependencies || {});
38
+ return new Set([...deps, ...devDeps, ...peerDeps, ...optionalDeps]);
39
+ }
40
+ function getPathAliases(tsConfigPath) {
41
+ try {
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 : ["@/*"];
56
+ }
57
+ catch {
58
+ return ["@/*"];
59
+ }
60
+ }
61
+ function isPathAlias(source, aliases) {
62
+ for (const alias of aliases) {
63
+ const prefix = alias.replace(/\/\*$/, "");
64
+ if (alias.endsWith("/*")) {
65
+ if (source === prefix || source.startsWith(prefix + "/")) {
66
+ return true;
67
+ }
68
+ }
69
+ else {
70
+ if (source === alias) {
71
+ return true;
72
+ }
73
+ }
74
+ }
75
+ return false;
76
+ }
77
+ function getSourceFiles(dir) {
78
+ const results = [];
79
+ const entries = readdirSync(dir, { withFileTypes: true });
80
+ for (const entry of entries) {
81
+ const fullPath = join(dir, entry.name);
82
+ if (entry.isDirectory()) {
83
+ if (entry.name === "node_modules" ||
84
+ entry.name === "dist" ||
85
+ entry.name === "build" ||
86
+ entry.name === ".next" ||
87
+ entry.name.startsWith(".")) {
88
+ continue;
89
+ }
90
+ results.push(...getSourceFiles(fullPath));
91
+ }
92
+ else if (entry.isFile()) {
93
+ const ext = extname(entry.name);
94
+ if (ext === ".ts" || ext === ".tsx" || ext === ".js" || ext === ".jsx") {
95
+ results.push(fullPath);
96
+ }
97
+ }
98
+ }
99
+ return results;
100
+ }
101
+ function extractImports(filePath) {
102
+ const content = readFileSync(filePath, "utf-8");
103
+ const lines = content.split("\n");
104
+ const imports = [];
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+["']([^"';]+)["'];?/;
109
+ for (let i = 0; i < lines.length; i++) {
110
+ const line = lines[i].trim();
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
+ }
129
+ }
130
+ }
131
+ return imports;
132
+ }
133
+ function resolvePackageName(source) {
134
+ if (source.startsWith(".") || source.startsWith("/"))
135
+ return null;
136
+ if (source.startsWith("node:"))
137
+ return null;
138
+ if (source.startsWith("@/"))
139
+ return null;
140
+ if (source.startsWith("@")) {
141
+ const parts = source.split("/");
142
+ return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null;
143
+ }
144
+ const idx = source.indexOf("/");
145
+ return idx > 0 ? source.slice(0, idx) : source;
146
+ }
147
+ function isNodeBuiltin(pkg) {
148
+ return NODE_BUILTINS.has(pkg) || NODE_BUILTINS.has(`node:${pkg}`);
149
+ }
150
+ function detectPackageManager(lockFiles) {
151
+ if (lockFiles.some((f) => f.endsWith("bun.lockb")))
152
+ return "bun";
153
+ if (lockFiles.some((f) => f.endsWith("pnpm-lock.yaml")))
154
+ return "pnpm";
155
+ if (lockFiles.some((f) => f.endsWith("yarn.lock")))
156
+ return "yarn";
157
+ if (lockFiles.some((f) => f.endsWith("package-lock.json")))
158
+ return "npm";
159
+ return "unknown";
160
+ }
161
+ export function verifyImportsCommand(options = {}) {
162
+ const srcDir = options.srcDir || process.cwd();
163
+ const packageJsonPath = options.packageJsonPath || findPackageJson(srcDir);
164
+ if (!packageJsonPath) {
165
+ console.error("❌ package.json not found. Run this from a project root.");
166
+ process.exit(1);
167
+ }
168
+ const installed = getInstalledPackages(packageJsonPath);
169
+ const projectRoot = dirname(packageJsonPath);
170
+ const tsConfigPath = findTsConfig(srcDir);
171
+ const pathAliases = tsConfigPath ? getPathAliases(tsConfigPath) : [];
172
+ const lockFiles = ["package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lockb"].map((f) => join(projectRoot, f));
173
+ const existingLocks = lockFiles.filter((f) => existsSync(f));
174
+ const pkgManager = detectPackageManager(existingLocks);
175
+ const files = getSourceFiles(srcDir);
176
+ const allImports = [];
177
+ for (const file of files) {
178
+ allImports.push(...extractImports(file));
179
+ }
180
+ const missing = new Map();
181
+ for (const imp of allImports) {
182
+ if (isPathAlias(imp.source, pathAliases))
183
+ continue;
184
+ const pkg = resolvePackageName(imp.source);
185
+ if (!pkg)
186
+ continue;
187
+ if (isNodeBuiltin(pkg))
188
+ continue;
189
+ if (installed.has(pkg))
190
+ continue;
191
+ const list = missing.get(pkg) || [];
192
+ list.push(imp);
193
+ missing.set(pkg, list);
194
+ }
195
+ if (missing.size === 0) {
196
+ console.log(`✅ All imports resolve to installed packages (${allImports.length} imports checked).`);
197
+ return;
198
+ }
199
+ console.log(`⚠️ Found ${missing.size} missing package(s):\n`);
200
+ for (const [pkg, imports] of missing) {
201
+ console.log(` 📦 ${pkg}`);
202
+ console.log(` Used in:`);
203
+ for (const imp of imports.slice(0, 3)) {
204
+ const relPath = imp.path.replace(projectRoot + sep, "").replace(/^\//, "");
205
+ console.log(` - ${relPath}:${imp.line} → import from "${imp.source}"`);
206
+ }
207
+ if (imports.length > 3) {
208
+ console.log(` ... and ${imports.length - 3} more`);
209
+ }
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}`;
217
+ console.log(` Install: ${installCmd}\n`);
218
+ }
219
+ console.log(`Run the install command(s) above, then re-run this check.\n`);
220
+ process.exit(1);
221
+ }
222
+ //# sourceMappingURL=verify-imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-imports.js","sourceRoot":"","sources":["../../src/commands/verify-imports.ts"],"names":[],"mappings":"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"}