@djangocfg/imgai 2.1.42 → 2.1.44

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/dist/cli/bin.js CHANGED
@@ -1,260 +1,17 @@
1
1
  #!/usr/bin/env node
2
+ import chalk from 'chalk';
2
3
  import { Command } from 'commander';
3
- import path2 from 'path';
4
- import { fileURLToPath } from 'url';
5
4
  import dotenv from 'dotenv';
6
- import chalk from 'chalk';
7
5
  import ora from 'ora';
8
- import inquirer from 'inquirer';
9
- import fs from 'fs-extra';
10
- import sharp from 'sharp';
6
+ import path from 'path';
7
+ import { fileURLToPath } from 'url';
8
+ import fs3 from 'fs-extra';
9
+ import { glob } from 'glob';
10
+ import sharp2 from 'sharp';
11
11
  import OpenAI from 'openai';
12
12
  import Anthropic from '@anthropic-ai/sdk';
13
- import { glob } from 'glob';
14
-
15
- var ImageGenerator = class {
16
- config;
17
- openai;
18
- anthropic;
19
- constructor(config) {
20
- this.config = config;
21
- this.initializeProviders();
22
- }
23
- initializeProviders() {
24
- const openaiKey = this.config.openaiApiKey || process.env.OPENAI_API_KEY;
25
- const anthropicKey = this.config.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
26
- if (openaiKey) {
27
- this.openai = new OpenAI({ apiKey: openaiKey });
28
- }
29
- if (anthropicKey) {
30
- this.anthropic = new Anthropic({ apiKey: anthropicKey });
31
- }
32
- if (!this.openai && this.config.provider === "openai") {
33
- throw new Error("OpenAI API key required. Set OPENAI_API_KEY or pass openaiApiKey in config.");
34
- }
35
- }
36
- // ──────────────────────────────────────────────────────────────────────────
37
- // SINGLE IMAGE GENERATION
38
- // ──────────────────────────────────────────────────────────────────────────
39
- async generate(options) {
40
- const startTime = Date.now();
41
- try {
42
- const fullPrompt = this.buildPrompt(options.prompt);
43
- const imageData = await this.generateWithOpenAI(fullPrompt);
44
- const filename = options.filename || this.generateFilename(options.prompt);
45
- const category = options.category || "general";
46
- const outputDir = path2.join(
47
- this.config.projectRoot,
48
- this.config.outputDir,
49
- category
50
- );
51
- await fs.ensureDir(outputDir);
52
- const originalPath = path2.join(outputDir, `${filename}.png`);
53
- await fs.writeFile(originalPath, Buffer.from(imageData, "base64"));
54
- const resizeOptions = options.resize || this.config.resize;
55
- let finalPath = originalPath;
56
- if (resizeOptions) {
57
- finalPath = await this.resizeImage(originalPath, resizeOptions);
58
- if (finalPath !== originalPath) {
59
- await fs.remove(originalPath);
60
- }
61
- }
62
- const imageInfo = await this.getImageInfo(finalPath, category);
63
- imageInfo.metadata = {
64
- prompt: options.prompt,
65
- caption: options.metadata?.caption,
66
- tags: options.tags,
67
- category,
68
- generatedAt: /* @__PURE__ */ new Date(),
69
- model: "dall-e-3"
70
- };
71
- const duration = Date.now() - startTime;
72
- return {
73
- success: true,
74
- imagePath: finalPath,
75
- imageUrl: imageInfo.url,
76
- imageInfo,
77
- duration
78
- };
79
- } catch (error) {
80
- return {
81
- success: false,
82
- error: error instanceof Error ? error.message : "Unknown error",
83
- duration: Date.now() - startTime
84
- };
85
- }
86
- }
87
- // ──────────────────────────────────────────────────────────────────────────
88
- // BATCH GENERATION
89
- // ──────────────────────────────────────────────────────────────────────────
90
- async generateBatch(options) {
91
- const startTime = Date.now();
92
- const results = [];
93
- const concurrency = options.concurrency || 2;
94
- const delayBetween = options.delayBetween || 2e3;
95
- for (let i = 0; i < options.items.length; i += concurrency) {
96
- const batch = options.items.slice(i, i + concurrency);
97
- const batchPromises = batch.map(async (item) => {
98
- const result = await this.generate({
99
- prompt: item.prompt,
100
- filename: item.filename,
101
- category: item.category
102
- });
103
- return result;
104
- });
105
- const batchResults = await Promise.all(batchPromises);
106
- for (const result of batchResults) {
107
- results.push(result);
108
- if (options.onProgress) {
109
- options.onProgress(results.length, options.items.length, result);
110
- }
111
- }
112
- if (i + concurrency < options.items.length) {
113
- await this.delay(delayBetween);
114
- }
115
- }
116
- return {
117
- total: results.length,
118
- success: results.filter((r) => r.success).length,
119
- failed: results.filter((r) => !r.success).length,
120
- results,
121
- duration: Date.now() - startTime
122
- };
123
- }
124
- // ──────────────────────────────────────────────────────────────────────────
125
- // PROMPT ENHANCEMENT (using Claude/GPT)
126
- // ──────────────────────────────────────────────────────────────────────────
127
- async enhancePrompt(basePrompt, context) {
128
- const systemPrompt = `You are an expert at creating image generation prompts.
129
- Given a description, create:
130
- 1. A detailed visual prompt (max 150 words) for DALL-E 3
131
- 2. A descriptive filename (lowercase, hyphens, max 30 chars)
132
- 3. A short caption (max 50 words)
133
-
134
- ${this.config.prefix ? `Style prefix: ${this.config.prefix}` : ""}
135
- ${this.config.suffix ? `Style suffix: ${this.config.suffix}` : ""}
136
-
137
- Return ONLY valid JSON: {"prompt": "...", "filename": "...", "caption": "..."}`;
138
- const userPrompt = context ? `Description: ${basePrompt}
139
- Context: ${context}` : `Description: ${basePrompt}`;
140
- if (this.anthropic && this.config.provider === "anthropic") {
141
- const response = await this.anthropic.messages.create({
142
- model: "claude-3-5-sonnet-20241022",
143
- max_tokens: 500,
144
- messages: [
145
- { role: "user", content: `${systemPrompt}
13
+ import inquirer from 'inquirer';
146
14
 
147
- ${userPrompt}` }
148
- ]
149
- });
150
- const text = response.content[0].type === "text" ? response.content[0].text : "";
151
- return JSON.parse(text);
152
- }
153
- if (this.openai) {
154
- const response = await this.openai.chat.completions.create({
155
- model: "gpt-4-turbo-preview",
156
- messages: [
157
- { role: "system", content: systemPrompt },
158
- { role: "user", content: userPrompt }
159
- ],
160
- max_tokens: 500,
161
- temperature: 0.7,
162
- response_format: { type: "json_object" }
163
- });
164
- const text = response.choices[0]?.message?.content || "{}";
165
- return JSON.parse(text);
166
- }
167
- throw new Error("No AI provider configured for prompt enhancement");
168
- }
169
- // ──────────────────────────────────────────────────────────────────────────
170
- // PRIVATE METHODS
171
- // ──────────────────────────────────────────────────────────────────────────
172
- async generateWithOpenAI(prompt) {
173
- if (!this.openai) {
174
- throw new Error("OpenAI client not initialized");
175
- }
176
- const response = await this.openai.images.generate({
177
- model: "dall-e-3",
178
- prompt,
179
- n: 1,
180
- size: this.config.size,
181
- quality: this.config.quality,
182
- style: this.config.dalleStyle || "natural",
183
- response_format: "b64_json"
184
- });
185
- const imageData = response.data?.[0]?.b64_json;
186
- if (!imageData) {
187
- throw new Error("No image data received from OpenAI");
188
- }
189
- return imageData;
190
- }
191
- async resizeImage(inputPath, options) {
192
- const { width, height, quality = 85, format = "webp", fit = "inside" } = options;
193
- let pipeline = sharp(inputPath);
194
- if (width || height) {
195
- pipeline = pipeline.resize(width, height, {
196
- fit,
197
- withoutEnlargement: true
198
- });
199
- }
200
- const outputPath = inputPath.replace(/\.[^.]+$/, `.${format}`);
201
- switch (format) {
202
- case "webp":
203
- pipeline = pipeline.webp({ quality });
204
- break;
205
- case "jpeg":
206
- pipeline = pipeline.jpeg({ quality });
207
- break;
208
- case "png":
209
- pipeline = pipeline.png({ quality });
210
- break;
211
- case "avif":
212
- pipeline = pipeline.avif({ quality });
213
- break;
214
- }
215
- await pipeline.toFile(outputPath);
216
- return outputPath;
217
- }
218
- async getImageInfo(imagePath, category) {
219
- const stats = await fs.stat(imagePath);
220
- const metadata = await sharp(imagePath).metadata();
221
- const filename = path2.basename(imagePath);
222
- const extension = path2.extname(filename).slice(1);
223
- const id = path2.basename(filename, path2.extname(filename));
224
- const publicDir = path2.join(this.config.projectRoot, this.config.publicDir);
225
- const relativePath = path2.relative(publicDir, imagePath);
226
- const url = "/" + relativePath.replace(/\\/g, "/");
227
- return {
228
- id,
229
- filename,
230
- extension,
231
- path: relativePath,
232
- url,
233
- size: stats.size,
234
- width: metadata.width,
235
- height: metadata.height,
236
- createdAt: stats.birthtime,
237
- modifiedAt: stats.mtime
238
- };
239
- }
240
- buildPrompt(basePrompt) {
241
- const parts = [];
242
- if (this.config.prefix) {
243
- parts.push(this.config.prefix);
244
- }
245
- parts.push(basePrompt);
246
- if (this.config.suffix) {
247
- parts.push(this.config.suffix);
248
- }
249
- return parts.join(" ");
250
- }
251
- generateFilename(prompt) {
252
- return prompt.toLowerCase().replace(/[^a-z0-9\s]/g, "").replace(/\s+/g, "-").substring(0, 30);
253
- }
254
- delay(ms) {
255
- return new Promise((resolve) => setTimeout(resolve, ms));
256
- }
257
- };
258
15
  var DEFAULT_EXTENSIONS = ["png", "jpg", "jpeg", "webp", "avif", "gif", "svg"];
259
16
  var DEFAULT_DIRECTORIES = ["static/images", "images", "assets"];
260
17
  var ImageScanner = class {
@@ -273,15 +30,15 @@ var ImageScanner = class {
273
30
  includeDimensions = true,
274
31
  recursive = true
275
32
  } = options;
276
- const publicDir = path2.join(this.config.projectRoot, this.config.publicDir);
33
+ const publicDir = path.join(this.config.projectRoot, this.config.publicDir);
277
34
  const images = [];
278
35
  const byCategory = {};
279
36
  const byExtension = {};
280
37
  let totalSize = 0;
281
38
  const patterns = directories.flatMap((dir) => {
282
- const basePath = path2.join(publicDir, dir);
39
+ const basePath = path.join(publicDir, dir);
283
40
  const extPattern = `*.{${extensions.join(",")}}`;
284
- return recursive ? [path2.join(basePath, "**", extPattern)] : [path2.join(basePath, extPattern)];
41
+ return recursive ? [path.join(basePath, "**", extPattern)] : [path.join(basePath, extPattern)];
285
42
  });
286
43
  for (const pattern of patterns) {
287
44
  const files = await glob(pattern, { nodir: true });
@@ -348,17 +105,17 @@ var ImageScanner = class {
348
105
  // PRIVATE METHODS
349
106
  // ──────────────────────────────────────────────────────────────────────────
350
107
  async processImage(filePath, publicDir, includeDimensions) {
351
- const stats = await fs.stat(filePath);
352
- const filename = path2.basename(filePath);
353
- const extension = path2.extname(filename).slice(1).toLowerCase();
354
- const id = path2.basename(filename, path2.extname(filename));
355
- const relativePath = path2.relative(publicDir, filePath).replace(/\\/g, "/");
108
+ const stats = await fs3.stat(filePath);
109
+ const filename = path.basename(filePath);
110
+ const extension = path.extname(filename).slice(1).toLowerCase();
111
+ const id = path.basename(filename, path.extname(filename));
112
+ const relativePath = path.relative(publicDir, filePath).replace(/\\/g, "/");
356
113
  const url = "/" + relativePath;
357
114
  let width;
358
115
  let height;
359
116
  if (includeDimensions && extension !== "svg") {
360
117
  try {
361
- const metadata = await sharp(filePath).metadata();
118
+ const metadata = await sharp2(filePath).metadata();
362
119
  width = metadata.width;
363
120
  height = metadata.height;
364
121
  } catch {
@@ -396,6 +153,8 @@ function formatDuration(ms) {
396
153
  if (ms < 1e3) return `${ms}ms`;
397
154
  return `${(ms / 1e3).toFixed(2)}s`;
398
155
  }
156
+
157
+ // src/config/generator.ts
399
158
  var ConfigGenerator = class {
400
159
  config;
401
160
  scanner;
@@ -408,10 +167,10 @@ var ConfigGenerator = class {
408
167
  // ──────────────────────────────────────────────────────────────────────────
409
168
  async generate() {
410
169
  const catalog = await this.scanner.buildCatalog();
411
- const outputPath = path2.join(this.config.projectRoot, this.config.configOutputPath);
412
- await fs.ensureDir(path2.dirname(outputPath));
170
+ const outputPath = path.join(this.config.projectRoot, this.config.configOutputPath);
171
+ await fs3.ensureDir(path.dirname(outputPath));
413
172
  const content = this.generateTypeScript(catalog);
414
- await fs.writeFile(outputPath, content, "utf-8");
173
+ await fs3.writeFile(outputPath, content, "utf-8");
415
174
  return outputPath;
416
175
  }
417
176
  // ──────────────────────────────────────────────────────────────────────────
@@ -527,8 +286,249 @@ export const IMAGE_CATALOG_META = {
527
286
  return ` '${category}': [${imageRefs.join(", ")}]`;
528
287
  }
529
288
  };
289
+ var ImageGenerator = class {
290
+ config;
291
+ openai;
292
+ anthropic;
293
+ constructor(config) {
294
+ this.config = config;
295
+ this.initializeProviders();
296
+ }
297
+ initializeProviders() {
298
+ const openaiKey = this.config.openaiApiKey || process.env.OPENAI_API_KEY;
299
+ const anthropicKey = this.config.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
300
+ if (openaiKey) {
301
+ this.openai = new OpenAI({ apiKey: openaiKey });
302
+ }
303
+ if (anthropicKey) {
304
+ this.anthropic = new Anthropic({ apiKey: anthropicKey });
305
+ }
306
+ if (!this.openai && this.config.provider === "openai") {
307
+ throw new Error("OpenAI API key required. Set OPENAI_API_KEY or pass openaiApiKey in config.");
308
+ }
309
+ }
310
+ // ──────────────────────────────────────────────────────────────────────────
311
+ // SINGLE IMAGE GENERATION
312
+ // ──────────────────────────────────────────────────────────────────────────
313
+ async generate(options) {
314
+ const startTime = Date.now();
315
+ try {
316
+ const fullPrompt = this.buildPrompt(options.prompt);
317
+ const imageData = await this.generateWithOpenAI(fullPrompt);
318
+ const filename = options.filename || this.generateFilename(options.prompt);
319
+ const category = options.category || "general";
320
+ const outputDir = path.join(
321
+ this.config.projectRoot,
322
+ this.config.outputDir,
323
+ category
324
+ );
325
+ await fs3.ensureDir(outputDir);
326
+ const originalPath = path.join(outputDir, `${filename}.png`);
327
+ await fs3.writeFile(originalPath, Buffer.from(imageData, "base64"));
328
+ const resizeOptions = options.resize || this.config.resize;
329
+ let finalPath = originalPath;
330
+ if (resizeOptions) {
331
+ finalPath = await this.resizeImage(originalPath, resizeOptions);
332
+ if (finalPath !== originalPath) {
333
+ await fs3.remove(originalPath);
334
+ }
335
+ }
336
+ const imageInfo = await this.getImageInfo(finalPath, category);
337
+ imageInfo.metadata = {
338
+ prompt: options.prompt,
339
+ caption: options.metadata?.caption,
340
+ tags: options.tags,
341
+ category,
342
+ generatedAt: /* @__PURE__ */ new Date(),
343
+ model: "dall-e-3"
344
+ };
345
+ const duration = Date.now() - startTime;
346
+ return {
347
+ success: true,
348
+ imagePath: finalPath,
349
+ imageUrl: imageInfo.url,
350
+ imageInfo,
351
+ duration
352
+ };
353
+ } catch (error) {
354
+ return {
355
+ success: false,
356
+ error: error instanceof Error ? error.message : "Unknown error",
357
+ duration: Date.now() - startTime
358
+ };
359
+ }
360
+ }
361
+ // ──────────────────────────────────────────────────────────────────────────
362
+ // BATCH GENERATION
363
+ // ──────────────────────────────────────────────────────────────────────────
364
+ async generateBatch(options) {
365
+ const startTime = Date.now();
366
+ const results = [];
367
+ const concurrency = options.concurrency || 2;
368
+ const delayBetween = options.delayBetween || 2e3;
369
+ for (let i = 0; i < options.items.length; i += concurrency) {
370
+ const batch = options.items.slice(i, i + concurrency);
371
+ const batchPromises = batch.map(async (item) => {
372
+ const result = await this.generate({
373
+ prompt: item.prompt,
374
+ filename: item.filename,
375
+ category: item.category
376
+ });
377
+ return result;
378
+ });
379
+ const batchResults = await Promise.all(batchPromises);
380
+ for (const result of batchResults) {
381
+ results.push(result);
382
+ if (options.onProgress) {
383
+ options.onProgress(results.length, options.items.length, result);
384
+ }
385
+ }
386
+ if (i + concurrency < options.items.length) {
387
+ await this.delay(delayBetween);
388
+ }
389
+ }
390
+ return {
391
+ total: results.length,
392
+ success: results.filter((r) => r.success).length,
393
+ failed: results.filter((r) => !r.success).length,
394
+ results,
395
+ duration: Date.now() - startTime
396
+ };
397
+ }
398
+ // ──────────────────────────────────────────────────────────────────────────
399
+ // PROMPT ENHANCEMENT (using Claude/GPT)
400
+ // ──────────────────────────────────────────────────────────────────────────
401
+ async enhancePrompt(basePrompt, context) {
402
+ const systemPrompt = `You are an expert at creating image generation prompts.
403
+ Given a description, create:
404
+ 1. A detailed visual prompt (max 150 words) for DALL-E 3
405
+ 2. A descriptive filename (lowercase, hyphens, max 30 chars)
406
+ 3. A short caption (max 50 words)
407
+
408
+ ${this.config.prefix ? `Style prefix: ${this.config.prefix}` : ""}
409
+ ${this.config.suffix ? `Style suffix: ${this.config.suffix}` : ""}
530
410
 
531
- // src/cli/index.ts
411
+ Return ONLY valid JSON: {"prompt": "...", "filename": "...", "caption": "..."}`;
412
+ const userPrompt = context ? `Description: ${basePrompt}
413
+ Context: ${context}` : `Description: ${basePrompt}`;
414
+ if (this.anthropic && this.config.provider === "anthropic") {
415
+ const response = await this.anthropic.messages.create({
416
+ model: "claude-3-5-sonnet-20241022",
417
+ max_tokens: 500,
418
+ messages: [
419
+ { role: "user", content: `${systemPrompt}
420
+
421
+ ${userPrompt}` }
422
+ ]
423
+ });
424
+ const text = response.content[0].type === "text" ? response.content[0].text : "";
425
+ return JSON.parse(text);
426
+ }
427
+ if (this.openai) {
428
+ const response = await this.openai.chat.completions.create({
429
+ model: "gpt-4-turbo-preview",
430
+ messages: [
431
+ { role: "system", content: systemPrompt },
432
+ { role: "user", content: userPrompt }
433
+ ],
434
+ max_tokens: 500,
435
+ temperature: 0.7,
436
+ response_format: { type: "json_object" }
437
+ });
438
+ const text = response.choices[0]?.message?.content || "{}";
439
+ return JSON.parse(text);
440
+ }
441
+ throw new Error("No AI provider configured for prompt enhancement");
442
+ }
443
+ // ──────────────────────────────────────────────────────────────────────────
444
+ // PRIVATE METHODS
445
+ // ──────────────────────────────────────────────────────────────────────────
446
+ async generateWithOpenAI(prompt) {
447
+ if (!this.openai) {
448
+ throw new Error("OpenAI client not initialized");
449
+ }
450
+ const response = await this.openai.images.generate({
451
+ model: "dall-e-3",
452
+ prompt,
453
+ n: 1,
454
+ size: this.config.size,
455
+ quality: this.config.quality,
456
+ style: this.config.dalleStyle || "natural",
457
+ response_format: "b64_json"
458
+ });
459
+ const imageData = response.data?.[0]?.b64_json;
460
+ if (!imageData) {
461
+ throw new Error("No image data received from OpenAI");
462
+ }
463
+ return imageData;
464
+ }
465
+ async resizeImage(inputPath, options) {
466
+ const { width, height, quality = 85, format = "webp", fit = "inside" } = options;
467
+ let pipeline = sharp2(inputPath);
468
+ if (width || height) {
469
+ pipeline = pipeline.resize(width, height, {
470
+ fit,
471
+ withoutEnlargement: true
472
+ });
473
+ }
474
+ const outputPath = inputPath.replace(/\.[^.]+$/, `.${format}`);
475
+ switch (format) {
476
+ case "webp":
477
+ pipeline = pipeline.webp({ quality });
478
+ break;
479
+ case "jpeg":
480
+ pipeline = pipeline.jpeg({ quality });
481
+ break;
482
+ case "png":
483
+ pipeline = pipeline.png({ quality });
484
+ break;
485
+ case "avif":
486
+ pipeline = pipeline.avif({ quality });
487
+ break;
488
+ }
489
+ await pipeline.toFile(outputPath);
490
+ return outputPath;
491
+ }
492
+ async getImageInfo(imagePath, category) {
493
+ const stats = await fs3.stat(imagePath);
494
+ const metadata = await sharp2(imagePath).metadata();
495
+ const filename = path.basename(imagePath);
496
+ const extension = path.extname(filename).slice(1);
497
+ const id = path.basename(filename, path.extname(filename));
498
+ const publicDir = path.join(this.config.projectRoot, this.config.publicDir);
499
+ const relativePath = path.relative(publicDir, imagePath);
500
+ const url = "/" + relativePath.replace(/\\/g, "/");
501
+ return {
502
+ id,
503
+ filename,
504
+ extension,
505
+ path: relativePath,
506
+ url,
507
+ size: stats.size,
508
+ width: metadata.width,
509
+ height: metadata.height,
510
+ createdAt: stats.birthtime,
511
+ modifiedAt: stats.mtime
512
+ };
513
+ }
514
+ buildPrompt(basePrompt) {
515
+ const parts = [];
516
+ if (this.config.prefix) {
517
+ parts.push(this.config.prefix);
518
+ }
519
+ parts.push(basePrompt);
520
+ if (this.config.suffix) {
521
+ parts.push(this.config.suffix);
522
+ }
523
+ return parts.join(" ");
524
+ }
525
+ generateFilename(prompt) {
526
+ return prompt.toLowerCase().replace(/[^a-z0-9\s]/g, "").replace(/\s+/g, "-").substring(0, 30);
527
+ }
528
+ delay(ms) {
529
+ return new Promise((resolve) => setTimeout(resolve, ms));
530
+ }
531
+ };
532
532
  var ImageAICLI = class {
533
533
  config;
534
534
  generator;
@@ -858,10 +858,10 @@ var ImageAICLI = class {
858
858
 
859
859
  // src/cli/bin.ts
860
860
  var __filename$1 = fileURLToPath(import.meta.url);
861
- var __dirname$1 = path2.dirname(__filename$1);
861
+ var __dirname$1 = path.dirname(__filename$1);
862
862
  dotenv.config();
863
- dotenv.config({ path: path2.resolve(process.cwd(), ".env.local") });
864
- dotenv.config({ path: path2.resolve(__dirname$1, "../../.env") });
863
+ dotenv.config({ path: path.resolve(process.cwd(), ".env.local") });
864
+ dotenv.config({ path: path.resolve(__dirname$1, "../../.env") });
865
865
  var program = new Command();
866
866
  function createConfig(options) {
867
867
  const projectRoot = options.root || process.cwd();
@@ -959,7 +959,7 @@ program.command("batch").alias("b").description("Batch generate images from file
959
959
  const config = createConfig(options);
960
960
  const generator = new ImageGenerator(config);
961
961
  const fs4 = await import('fs-extra');
962
- const filePath = path2.resolve(process.cwd(), file);
962
+ const filePath = path.resolve(process.cwd(), file);
963
963
  if (!await fs4.pathExists(filePath)) {
964
964
  console.error(chalk.red(`File not found: ${filePath}`));
965
965
  process.exit(1);