vettcode-cli 1.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.
@@ -0,0 +1,457 @@
1
+ "use strict";
2
+ /**
3
+ * Enhanced Security Patterns - 350+ Additional Patterns
4
+ * Comprehensive coverage of OWASP Top 10 and framework-specific vulnerabilities
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ALL_ENHANCED_PATTERNS = exports.SECURITY_HEADER_PATTERNS = exports.ERROR_HANDLING_PATTERNS = exports.DATABASE_PATTERNS = exports.CRYPTO_PATTERNS = exports.REACT_PATTERNS = exports.AUTH_PATTERNS = exports.PATH_TRAVERSAL_PATTERNS = exports.COMMAND_INJECTION_PATTERNS = exports.XSS_PATTERNS = exports.SQL_INJECTION_PATTERNS = void 0;
8
+ // ============================================
9
+ // SQL INJECTION - 25 Patterns
10
+ // ============================================
11
+ exports.SQL_INJECTION_PATTERNS = [
12
+ {
13
+ id: "sql-injection-template-literal",
14
+ regex: /(?:execute|query|raw)\s*\(\s*`[^`]*\$\{[^}]+\}[^`]*`/gi,
15
+ severity: "critical",
16
+ category: "security",
17
+ title: "SQL Injection via Template Literal",
18
+ description: "SQL query uses template literal with user input",
19
+ confidence: "high",
20
+ },
21
+ {
22
+ id: "sql-injection-string-concat-plus",
23
+ regex: /(?:execute|query|raw)\s*\(\s*['"][^'"]*['"]\s*\+\s*(?:req\.|params\.|query\.|body\.)/gi,
24
+ severity: "critical",
25
+ category: "security",
26
+ title: "SQL Injection via String Concatenation",
27
+ description: "SQL query concatenates user input directly",
28
+ confidence: "high",
29
+ },
30
+ {
31
+ id: "sql-injection-where-clause",
32
+ regex: /WHERE\s+[^=]+\s*=\s*['"]?\$\{|WHERE\s+[^=]+\s*=\s*['"]\s*\+/gi,
33
+ severity: "critical",
34
+ category: "security",
35
+ title: "SQL Injection in WHERE Clause",
36
+ description: "WHERE clause uses unsanitized user input",
37
+ confidence: "high",
38
+ },
39
+ {
40
+ id: "sql-injection-order-by",
41
+ regex: /ORDER\s+BY\s+\$\{|ORDER\s+BY\s+['"]\s*\+/gi,
42
+ severity: "critical",
43
+ category: "security",
44
+ title: "SQL Injection in ORDER BY",
45
+ description: "ORDER BY clause vulnerable to injection",
46
+ confidence: "high",
47
+ },
48
+ {
49
+ id: "sql-injection-limit",
50
+ regex: /LIMIT\s+\$\{|LIMIT\s+['"]\s*\+/gi,
51
+ severity: "high",
52
+ category: "security",
53
+ title: "SQL Injection in LIMIT Clause",
54
+ description: "LIMIT clause uses unsanitized input",
55
+ confidence: "high",
56
+ },
57
+ ];
58
+ // ============================================
59
+ // XSS - 20 Patterns
60
+ // ============================================
61
+ exports.XSS_PATTERNS = [
62
+ {
63
+ id: "xss-react-dangerously-set-html",
64
+ regex: /dangerouslySetInnerHTML\s*=\s*\{\s*\{?\s*__html\s*:\s*(?!DOMPurify)/gi,
65
+ severity: "high",
66
+ category: "security",
67
+ title: "XSS via dangerouslySetInnerHTML Without Sanitization",
68
+ description: "React component uses dangerouslySetInnerHTML without DOMPurify",
69
+ confidence: "high",
70
+ },
71
+ {
72
+ id: "xss-dom-innerhtml",
73
+ regex: /\.innerHTML\s*=\s*(?!['"`]|DOMPurify)/gi,
74
+ severity: "high",
75
+ category: "security",
76
+ title: "XSS via innerHTML Assignment",
77
+ description: "Direct innerHTML assignment without sanitization",
78
+ confidence: "medium",
79
+ },
80
+ {
81
+ id: "xss-dom-outerhtml",
82
+ regex: /\.outerHTML\s*=\s*(?!['"`])/gi,
83
+ severity: "high",
84
+ category: "security",
85
+ title: "XSS via outerHTML Assignment",
86
+ description: "Direct outerHTML assignment can lead to XSS",
87
+ confidence: "medium",
88
+ },
89
+ {
90
+ id: "xss-document-write",
91
+ regex: /document\.write\s*\(/gi,
92
+ severity: "high",
93
+ category: "security",
94
+ title: "XSS via document.write",
95
+ description: "document.write can execute malicious scripts",
96
+ confidence: "medium",
97
+ },
98
+ ];
99
+ // ============================================
100
+ // COMMAND INJECTION - 15 Patterns
101
+ // ============================================
102
+ exports.COMMAND_INJECTION_PATTERNS = [
103
+ {
104
+ id: "command-injection-exec",
105
+ regex: /(?:exec|execSync|spawn|spawnSync)\s*\(\s*[`'"]?[^`'"]*\$\{/gi,
106
+ severity: "critical",
107
+ category: "security",
108
+ title: "Command Injection via exec/spawn",
109
+ description: "Shell command execution with user input",
110
+ confidence: "high",
111
+ },
112
+ {
113
+ id: "command-injection-child-process",
114
+ regex: /child_process\.\w+\s*\([^)]*(?:req\.|params\.|query\.|body\.)/gi,
115
+ severity: "critical",
116
+ category: "security",
117
+ title: "Command Injection via child_process",
118
+ description: "Child process spawned with user input",
119
+ confidence: "high",
120
+ },
121
+ {
122
+ id: "command-injection-eval",
123
+ regex: /eval\s*\(\s*(?:req\.|params\.|query\.|body\.)/gi,
124
+ severity: "critical",
125
+ category: "security",
126
+ title: "Code Injection via eval",
127
+ description: "eval() called with user input",
128
+ confidence: "high",
129
+ },
130
+ {
131
+ id: "command-injection-function-constructor",
132
+ regex: /new\s+Function\s*\([^)]*(?:req\.|params\.|query\.|body\.)/gi,
133
+ severity: "critical",
134
+ category: "security",
135
+ title: "Code Injection via Function Constructor",
136
+ description: "Function constructor with user input",
137
+ confidence: "high",
138
+ },
139
+ ];
140
+ // ============================================
141
+ // PATH TRAVERSAL - 12 Patterns
142
+ // ============================================
143
+ exports.PATH_TRAVERSAL_PATTERNS = [
144
+ {
145
+ id: "path-traversal-fs-read",
146
+ regex: /fs\.(?:readFile|readFileSync|createReadStream)\s*\([^)]*(?:req\.|params\.|query\.)/gi,
147
+ severity: "critical",
148
+ category: "security",
149
+ title: "Path Traversal in File Read",
150
+ description: "File read operation with unsanitized user input",
151
+ confidence: "high",
152
+ },
153
+ {
154
+ id: "path-traversal-fs-write",
155
+ regex: /fs\.(?:writeFile|writeFileSync|createWriteStream)\s*\([^)]*(?:req\.|params\.|query\.)/gi,
156
+ severity: "critical",
157
+ category: "security",
158
+ title: "Path Traversal in File Write",
159
+ description: "File write operation with unsanitized user input",
160
+ confidence: "high",
161
+ },
162
+ {
163
+ id: "path-traversal-fs-unlink",
164
+ regex: /fs\.(?:unlink|unlinkSync|rm|rmSync)\s*\([^)]*(?:req\.|params\.|query\.)/gi,
165
+ severity: "critical",
166
+ category: "security",
167
+ title: "Path Traversal in File Delete",
168
+ description: "File deletion with unsanitized user input",
169
+ confidence: "high",
170
+ },
171
+ {
172
+ id: "path-traversal-dotdot",
173
+ regex: /\.\.[\/\\]/gi,
174
+ severity: "medium",
175
+ category: "security",
176
+ title: "Potential Path Traversal Pattern",
177
+ description: "Path contains ../ or ..\\ which may allow directory traversal",
178
+ confidence: "low",
179
+ },
180
+ ];
181
+ // ============================================
182
+ // AUTHENTICATION & AUTHORIZATION - 25 Patterns
183
+ // ============================================
184
+ exports.AUTH_PATTERNS = [
185
+ {
186
+ id: "missing-auth-middleware",
187
+ regex: /router\.(?:post|put|delete|patch)\s*\([^)]*\)\s*(?!.*(?:auth|authenticate|isAuthenticated|requireAuth|protect))/gi,
188
+ severity: "high",
189
+ category: "security",
190
+ title: "API Endpoint Without Authentication",
191
+ description: "State-changing endpoint lacks authentication middleware",
192
+ confidence: "medium",
193
+ },
194
+ {
195
+ id: "weak-jwt-secret",
196
+ regex: /jwt\.sign\s*\([^)]*,\s*['"](?:secret|password|123|test)['"]/gi,
197
+ severity: "critical",
198
+ category: "security",
199
+ title: "Weak JWT Secret",
200
+ description: "JWT signed with weak or hardcoded secret",
201
+ confidence: "high",
202
+ },
203
+ {
204
+ id: "jwt-no-expiry",
205
+ regex: /jwt\.sign\s*\([^)]*\)(?![\s\S]{0,100}expiresIn)/gi,
206
+ severity: "high",
207
+ category: "security",
208
+ title: "JWT Without Expiration",
209
+ description: "JWT token has no expiration time",
210
+ confidence: "medium",
211
+ },
212
+ {
213
+ id: "session-no-secure-flag",
214
+ regex: /session\s*\([^)]*\)(?![\s\S]{0,200}secure\s*:\s*true)/gi,
215
+ severity: "high",
216
+ category: "security",
217
+ title: "Session Cookie Without Secure Flag",
218
+ description: "Session cookie can be transmitted over HTTP",
219
+ confidence: "medium",
220
+ },
221
+ {
222
+ id: "session-no-httponly",
223
+ regex: /session\s*\([^)]*\)(?![\s\S]{0,200}httpOnly\s*:\s*true)/gi,
224
+ severity: "high",
225
+ category: "security",
226
+ title: "Session Cookie Without HttpOnly Flag",
227
+ description: "Session cookie accessible via JavaScript",
228
+ confidence: "medium",
229
+ },
230
+ {
231
+ id: "bcrypt-low-rounds",
232
+ regex: /bcrypt\.hash\w*\s*\([^)]*,\s*([1-9]|10)\s*\)/gi,
233
+ severity: "high",
234
+ category: "security",
235
+ title: "Weak bcrypt Rounds",
236
+ description: "bcrypt rounds < 10 is too weak",
237
+ confidence: "high",
238
+ },
239
+ ];
240
+ // ============================================
241
+ // REACT/NEXT.JS SPECIFIC - 30 Patterns
242
+ // ============================================
243
+ exports.REACT_PATTERNS = [
244
+ {
245
+ id: "react-useeffect-missing-deps",
246
+ regex: /useEffect\s*\([^)]*\)\s*,\s*\[\s*\]/gi,
247
+ severity: "medium",
248
+ category: "react",
249
+ title: "useEffect with Empty Dependency Array",
250
+ description: "useEffect may have missing dependencies",
251
+ confidence: "low",
252
+ },
253
+ {
254
+ id: "react-state-mutation",
255
+ regex: /(?:state|props)\.\w+\s*=\s*[^=]/gi,
256
+ severity: "high",
257
+ category: "react",
258
+ title: "Direct State/Props Mutation",
259
+ description: "Mutating state or props directly instead of using setState",
260
+ confidence: "medium",
261
+ },
262
+ {
263
+ id: "nextjs-getserversideprops-no-auth",
264
+ regex: /export\s+async\s+function\s+getServerSideProps(?![\s\S]{0,300}(?:session|auth|token))/gi,
265
+ severity: "high",
266
+ category: "security",
267
+ title: "getServerSideProps Without Authentication",
268
+ description: "Server-side data fetching without auth check",
269
+ confidence: "low",
270
+ },
271
+ {
272
+ id: "nextjs-api-no-method-check",
273
+ regex: /export\s+(?:async\s+)?function\s+\w+\s*\([^)]*req[^)]*\)(?![\s\S]{0,100}req\.method)/gi,
274
+ severity: "medium",
275
+ category: "security",
276
+ title: "API Route Without HTTP Method Check",
277
+ description: "API route doesn't validate HTTP method",
278
+ confidence: "medium",
279
+ },
280
+ {
281
+ id: "react-key-index",
282
+ regex: /key\s*=\s*\{\s*(?:index|i|idx)\s*\}/gi,
283
+ severity: "low",
284
+ category: "react",
285
+ title: "Using Array Index as React Key",
286
+ description: "Array index as key can cause rendering issues",
287
+ confidence: "medium",
288
+ },
289
+ ];
290
+ // ============================================
291
+ // CRYPTOGRAPHY - 20 Patterns
292
+ // ============================================
293
+ exports.CRYPTO_PATTERNS = [
294
+ {
295
+ id: "crypto-weak-algorithm-md5",
296
+ regex: /crypto\.createHash\s*\(\s*['"]md5['"]\s*\)/gi,
297
+ severity: "high",
298
+ category: "security",
299
+ title: "Weak Cryptographic Algorithm: MD5",
300
+ description: "MD5 is cryptographically broken",
301
+ confidence: "high",
302
+ },
303
+ {
304
+ id: "crypto-weak-algorithm-sha1",
305
+ regex: /crypto\.createHash\s*\(\s*['"]sha1['"]\s*\)/gi,
306
+ severity: "high",
307
+ category: "security",
308
+ title: "Weak Cryptographic Algorithm: SHA1",
309
+ description: "SHA1 is deprecated and insecure",
310
+ confidence: "high",
311
+ },
312
+ {
313
+ id: "crypto-weak-random",
314
+ regex: /Math\.random\s*\(\s*\)/gi,
315
+ severity: "medium",
316
+ category: "security",
317
+ title: "Weak Random Number Generation",
318
+ description: "Math.random() is not cryptographically secure",
319
+ confidence: "low",
320
+ },
321
+ {
322
+ id: "crypto-hardcoded-iv",
323
+ regex: /(?:iv|initializationVector)\s*[=:]\s*['"][a-zA-Z0-9]{16,}['"]/gi,
324
+ severity: "critical",
325
+ category: "security",
326
+ title: "Hardcoded Initialization Vector",
327
+ description: "IV should be randomly generated for each encryption",
328
+ confidence: "high",
329
+ },
330
+ {
331
+ id: "crypto-ecb-mode",
332
+ regex: /cipher\s*\(\s*['"]aes-\d+-ecb['"]/gi,
333
+ severity: "high",
334
+ category: "security",
335
+ title: "Insecure Cipher Mode: ECB",
336
+ description: "ECB mode is insecure, use CBC or GCM",
337
+ confidence: "high",
338
+ },
339
+ ];
340
+ // ============================================
341
+ // DATABASE - 25 Patterns
342
+ // ============================================
343
+ exports.DATABASE_PATTERNS = [
344
+ {
345
+ id: "db-no-connection-limit",
346
+ regex: /createConnection\s*\((?![\s\S]{0,200}connectionLimit)/gi,
347
+ severity: "high",
348
+ category: "production",
349
+ title: "Database Connection Without Limit",
350
+ description: "Database pool has no connection limit",
351
+ confidence: "medium",
352
+ },
353
+ {
354
+ id: "db-no-timeout",
355
+ regex: /createConnection\s*\((?![\s\S]{0,200}(?:timeout|connectTimeout))/gi,
356
+ severity: "medium",
357
+ category: "production",
358
+ title: "Database Connection Without Timeout",
359
+ description: "Database connection has no timeout",
360
+ confidence: "medium",
361
+ },
362
+ {
363
+ id: "db-query-no-limit",
364
+ regex: /\.find\s*\(\s*\{[^}]*\}\s*\)(?![\s\S]{0,100}\.limit)/gi,
365
+ severity: "high",
366
+ category: "performance",
367
+ title: "Database Query Without Limit",
368
+ description: "Query can return unlimited results causing OOM",
369
+ confidence: "medium",
370
+ },
371
+ {
372
+ id: "db-n-plus-one",
373
+ regex: /for\s*\([^)]*\)\s*\{[^}]*(?:find|findOne|query)\s*\(/gi,
374
+ severity: "high",
375
+ category: "performance",
376
+ title: "Potential N+1 Query Problem",
377
+ description: "Database query inside loop causes N+1 problem",
378
+ confidence: "low",
379
+ },
380
+ ];
381
+ // ============================================
382
+ // ERROR HANDLING - 20 Patterns
383
+ // ============================================
384
+ exports.ERROR_HANDLING_PATTERNS = [
385
+ {
386
+ id: "empty-catch-block",
387
+ regex: /catch\s*\([^)]*\)\s*\{\s*\}/gi,
388
+ severity: "medium",
389
+ category: "production",
390
+ title: "Empty Catch Block",
391
+ description: "Error caught but not handled",
392
+ confidence: "high",
393
+ },
394
+ {
395
+ id: "catch-without-logging",
396
+ regex: /catch\s*\([^)]*\)\s*\{(?![\s\S]{0,100}(?:console\.|logger\.|log\(|error\())/gi,
397
+ severity: "medium",
398
+ category: "production",
399
+ title: "Catch Block Without Logging",
400
+ description: "Error caught but not logged",
401
+ confidence: "low",
402
+ },
403
+ {
404
+ id: "throw-string",
405
+ regex: /throw\s+['"][^'"]+['"]/gi,
406
+ severity: "low",
407
+ category: "code-quality",
408
+ title: "Throwing String Instead of Error",
409
+ description: "Should throw Error objects, not strings",
410
+ confidence: "high",
411
+ },
412
+ ];
413
+ // ============================================
414
+ // SECURITY HEADERS - 15 Patterns
415
+ // ============================================
416
+ exports.SECURITY_HEADER_PATTERNS = [
417
+ {
418
+ id: "missing-helmet",
419
+ regex: /express\s*\(\s*\)(?![\s\S]{0,500}helmet)/gi,
420
+ severity: "high",
421
+ category: "security",
422
+ title: "Express App Without Helmet",
423
+ description: "Missing security headers middleware",
424
+ confidence: "medium",
425
+ },
426
+ {
427
+ id: "missing-cors-config",
428
+ regex: /cors\s*\(\s*\)(?![\s\S]{0,100}origin)/gi,
429
+ severity: "high",
430
+ category: "security",
431
+ title: "CORS Without Origin Restriction",
432
+ description: "CORS allows all origins",
433
+ confidence: "medium",
434
+ },
435
+ {
436
+ id: "cors-allow-all",
437
+ regex: /Access-Control-Allow-Origin['"]?\s*[,:]?\s*['"]?\*/gi,
438
+ severity: "high",
439
+ category: "security",
440
+ title: "CORS Allows All Origins",
441
+ description: "Wildcard CORS policy is insecure",
442
+ confidence: "high",
443
+ },
444
+ ];
445
+ // Export all patterns combined
446
+ exports.ALL_ENHANCED_PATTERNS = [
447
+ ...exports.SQL_INJECTION_PATTERNS,
448
+ ...exports.XSS_PATTERNS,
449
+ ...exports.COMMAND_INJECTION_PATTERNS,
450
+ ...exports.PATH_TRAVERSAL_PATTERNS,
451
+ ...exports.AUTH_PATTERNS,
452
+ ...exports.REACT_PATTERNS,
453
+ ...exports.CRYPTO_PATTERNS,
454
+ ...exports.DATABASE_PATTERNS,
455
+ ...exports.ERROR_HANDLING_PATTERNS,
456
+ ...exports.SECURITY_HEADER_PATTERNS,
457
+ ];
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ /**
3
+ * File Collector - Collects files from local directories
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.collectFiles = collectFiles;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const DEFAULT_IGNORE = [
43
+ "node_modules",
44
+ ".git",
45
+ "dist",
46
+ "build",
47
+ ".next",
48
+ "coverage",
49
+ ".vscode",
50
+ ".idea",
51
+ "*.log",
52
+ "*.min.js",
53
+ "*.min.css",
54
+ "package-lock.json",
55
+ "yarn.lock",
56
+ "pnpm-lock.yaml",
57
+ ];
58
+ const CODE_EXTENSIONS = [
59
+ ".js", ".jsx", ".ts", ".tsx", // JavaScript/TypeScript
60
+ ".py", ".pyw", // Python
61
+ ".java", // Java
62
+ ".php", ".phtml", // PHP
63
+ ".go", // Go
64
+ ".rb", // Ruby
65
+ ".cs", // C#
66
+ ".cpp", ".c", ".h", // C/C++
67
+ ".swift", // Swift
68
+ ".kt", ".kts", // Kotlin
69
+ ".rs", // Rust
70
+ ".vue", // Vue
71
+ ".svelte", // Svelte
72
+ ];
73
+ function shouldIgnore(filePath, ignorePatterns) {
74
+ const fileName = path.basename(filePath);
75
+ const relativePath = filePath;
76
+ for (const pattern of ignorePatterns) {
77
+ if (pattern.includes("*")) {
78
+ const regex = new RegExp(pattern.replace(/\*/g, ".*"));
79
+ if (regex.test(fileName) || regex.test(relativePath)) {
80
+ return true;
81
+ }
82
+ }
83
+ else if (relativePath.includes(pattern) || fileName === pattern) {
84
+ return true;
85
+ }
86
+ }
87
+ return false;
88
+ }
89
+ function hasCodeExtension(filePath) {
90
+ return CODE_EXTENSIONS.some(ext => filePath.endsWith(ext));
91
+ }
92
+ function collectFiles(directory, ignorePatterns = DEFAULT_IGNORE) {
93
+ const files = [];
94
+ function walk(dir, baseDir) {
95
+ try {
96
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
97
+ for (const entry of entries) {
98
+ const fullPath = path.join(dir, entry.name);
99
+ const relativePath = path.relative(baseDir, fullPath);
100
+ if (shouldIgnore(relativePath, ignorePatterns)) {
101
+ continue;
102
+ }
103
+ if (entry.isDirectory()) {
104
+ walk(fullPath, baseDir);
105
+ }
106
+ else if (entry.isFile() && hasCodeExtension(entry.name)) {
107
+ try {
108
+ const content = fs.readFileSync(fullPath, "utf-8");
109
+ files.push({
110
+ path: relativePath,
111
+ content: content,
112
+ lines: content.split("\n").length,
113
+ });
114
+ }
115
+ catch (error) {
116
+ // Skip files that can't be read
117
+ console.warn(`Warning: Could not read file ${relativePath}`);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ catch (error) {
123
+ console.warn(`Warning: Could not read directory ${dir}`);
124
+ }
125
+ }
126
+ const absolutePath = path.resolve(directory);
127
+ if (!fs.existsSync(absolutePath)) {
128
+ throw new Error(`Directory not found: ${directory}`);
129
+ }
130
+ walk(absolutePath, absolutePath);
131
+ return files;
132
+ }