myaidev-method 0.2.12 → 0.2.15

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.
Files changed (28) hide show
  1. package/.claude/CLAUDE.md +46 -0
  2. package/.claude/agents/content-production-coordinator.md +111 -0
  3. package/.claude/agents/proprietary-content-verifier.md +96 -0
  4. package/.claude/agents/visual-content-generator.md +520 -0
  5. package/.claude/commands/myai-coordinate-content.md +136 -0
  6. package/.claude/settings.local.json +3 -2
  7. package/.env.example +33 -0
  8. package/CHANGELOG.md +64 -0
  9. package/CONTENT_CREATION_GUIDE.md +3399 -0
  10. package/DEVELOPER_USE_CASES.md +2085 -0
  11. package/README.md +209 -2
  12. package/VISUAL_GENERATION_FILE_ORGANIZATION.md +105 -0
  13. package/bin/cli.js +46 -0
  14. package/package.json +17 -2
  15. package/src/lib/asset-management.js +532 -0
  16. package/src/lib/visual-config-utils.js +424 -0
  17. package/src/lib/visual-generation-utils.js +668 -0
  18. package/src/scripts/configure-visual-apis.js +413 -0
  19. package/src/scripts/generate-visual-cli.js +279 -0
  20. package/src/templates/claude/agents/content-production-coordinator.md +111 -0
  21. package/src/templates/claude/agents/content-writer.md +209 -4
  22. package/src/templates/claude/agents/proprietary-content-verifier.md +96 -0
  23. package/src/templates/claude/agents/visual-content-generator.md +520 -0
  24. package/src/templates/claude/commands/myai-content-writer.md +33 -8
  25. package/src/templates/claude/commands/myai-coordinate-content.md +136 -0
  26. package/src/templates/claude/commands/myai-generate-visual.md +318 -0
  27. package/src/templates/codex/commands/myai-generate-visual.md +307 -0
  28. package/src/templates/gemini/commands/myai-generate-visual.md +200 -0
@@ -0,0 +1,413 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Visual Content Generation API Configuration Script
5
+ *
6
+ * Interactive configuration wizard for setting up Google AI and OpenAI API keys
7
+ * for image and video generation.
8
+ *
9
+ * Usage:
10
+ * node configure-visual-apis.js
11
+ * OR
12
+ * /myai-configure visual (from Claude Code)
13
+ *
14
+ * Platform support: Claude Code, Gemini CLI, Codex CLI
15
+ */
16
+
17
+ import inquirer from 'inquirer';
18
+ import fs from 'fs-extra';
19
+ import path from 'path';
20
+ import dotenv from 'dotenv';
21
+ import chalk from 'chalk';
22
+ import ora from 'ora';
23
+ import { fileURLToPath } from 'url';
24
+
25
+ // Load existing environment variables
26
+ dotenv.config();
27
+
28
+ const __filename = fileURLToPath(import.meta.url);
29
+ const __dirname = path.dirname(__filename);
30
+
31
+ /**
32
+ * Main configuration function
33
+ */
34
+ export async function configureVisualAPIs() {
35
+ console.log(chalk.blue('\nšŸŽØ Visual Content Generation Configuration'));
36
+ console.log(chalk.gray('Configure Google AI and OpenAI APIs for image/video generation\n'));
37
+
38
+ console.log(chalk.cyan('Supported Platforms:'));
39
+ console.log(chalk.gray('āœ… Claude Code'));
40
+ console.log(chalk.gray('āœ… Gemini CLI'));
41
+ console.log(chalk.gray('āœ… Codex CLI\n'));
42
+
43
+ try {
44
+ // Step 1: Which services to configure
45
+ const { services } = await inquirer.prompt([{
46
+ type: 'checkbox',
47
+ name: 'services',
48
+ message: 'Which services do you want to configure?',
49
+ choices: [
50
+ {
51
+ name: 'Google AI (Gemini Flash, Imagen 3, Veo 2)',
52
+ value: 'google',
53
+ checked: true
54
+ },
55
+ {
56
+ name: 'OpenAI (DALL-E 3)',
57
+ value: 'openai',
58
+ checked: true
59
+ }
60
+ ],
61
+ validate: (answer) => {
62
+ if (answer.length < 1) {
63
+ return 'You must choose at least one service.';
64
+ }
65
+ return true;
66
+ }
67
+ }]);
68
+
69
+ const config = {};
70
+
71
+ // Step 2: Configure Google AI
72
+ if (services.includes('google')) {
73
+ console.log(chalk.yellow('\nšŸ“‹ Google AI API Setup:'));
74
+ console.log(chalk.gray('1. Visit: https://ai.google.dev/'));
75
+ console.log(chalk.gray('2. Sign in with your Google account'));
76
+ console.log(chalk.gray('3. Click "Get API key" in Google AI Studio'));
77
+ console.log(chalk.gray('4. Create or select a project'));
78
+ console.log(chalk.gray('5. Click "Create API key"'));
79
+ console.log(chalk.gray('6. Copy the API key\n'));
80
+
81
+ const currentGoogleKey = process.env.GOOGLE_API_KEY;
82
+ if (currentGoogleKey) {
83
+ console.log(chalk.gray(`Current key: ${maskKey(currentGoogleKey)}\n`));
84
+ }
85
+
86
+ const { googleKey, confirmGoogle } = await inquirer.prompt([
87
+ {
88
+ type: 'password',
89
+ name: 'googleKey',
90
+ message: 'Enter your Google API Key:',
91
+ mask: '*',
92
+ validate: (input) => {
93
+ if (!input) return 'API key is required';
94
+ if (input.length < 20) return 'API key appears to be too short';
95
+ return true;
96
+ }
97
+ },
98
+ {
99
+ type: 'confirm',
100
+ name: 'confirmGoogle',
101
+ message: 'Test API key connectivity?',
102
+ default: true
103
+ }
104
+ ]);
105
+
106
+ config.GOOGLE_API_KEY = googleKey;
107
+
108
+ // Test Google API
109
+ if (confirmGoogle) {
110
+ const spinner = ora('Testing Google API connection...').start();
111
+ try {
112
+ const testResult = await testGoogleAPI(googleKey);
113
+ if (testResult.success) {
114
+ spinner.succeed(chalk.green('Google API connection successful!'));
115
+ } else {
116
+ spinner.fail(chalk.red(`Google API test failed: ${testResult.error}`));
117
+ const { continueAnyway } = await inquirer.prompt([{
118
+ type: 'confirm',
119
+ name: 'continueAnyway',
120
+ message: 'Continue with this API key anyway?',
121
+ default: false
122
+ }]);
123
+ if (!continueAnyway) {
124
+ delete config.GOOGLE_API_KEY;
125
+ }
126
+ }
127
+ } catch (error) {
128
+ spinner.fail(chalk.red(`Google API test error: ${error.message}`));
129
+ }
130
+ }
131
+ }
132
+
133
+ // Step 3: Configure OpenAI
134
+ if (services.includes('openai')) {
135
+ console.log(chalk.yellow('\nšŸ“‹ OpenAI API Setup:'));
136
+ console.log(chalk.gray('1. Visit: https://platform.openai.com/api-keys'));
137
+ console.log(chalk.gray('2. Sign in to your OpenAI account'));
138
+ console.log(chalk.gray('3. Click "Create new secret key"'));
139
+ console.log(chalk.gray('4. Name your key (e.g., "MyAIDev Visual Generation")'));
140
+ console.log(chalk.gray('5. Copy the API key (you won\'t see it again!)\n'));
141
+
142
+ const currentOpenAIKey = process.env.OPENAI_API_KEY;
143
+ if (currentOpenAIKey) {
144
+ console.log(chalk.gray(`Current key: ${maskKey(currentOpenAIKey)}\n`));
145
+ }
146
+
147
+ const { openaiKey, confirmOpenAI } = await inquirer.prompt([
148
+ {
149
+ type: 'password',
150
+ name: 'openaiKey',
151
+ message: 'Enter your OpenAI API Key:',
152
+ mask: '*',
153
+ validate: (input) => {
154
+ if (!input) return 'API key is required';
155
+ if (input.length < 20) return 'API key appears to be too short';
156
+ if (!input.startsWith('sk-')) return 'OpenAI API keys typically start with "sk-"';
157
+ return true;
158
+ }
159
+ },
160
+ {
161
+ type: 'confirm',
162
+ name: 'confirmOpenAI',
163
+ message: 'Test API key connectivity?',
164
+ default: true
165
+ }
166
+ ]);
167
+
168
+ config.OPENAI_API_KEY = openaiKey;
169
+
170
+ // Test OpenAI API
171
+ if (confirmOpenAI) {
172
+ const spinner = ora('Testing OpenAI API connection...').start();
173
+ try {
174
+ const testResult = await testOpenAIAPI(openaiKey);
175
+ if (testResult.success) {
176
+ spinner.succeed(chalk.green('OpenAI API connection successful!'));
177
+ } else {
178
+ spinner.fail(chalk.red(`OpenAI API test failed: ${testResult.error}`));
179
+ const { continueAnyway } = await inquirer.prompt([{
180
+ type: 'confirm',
181
+ name: 'continueAnyway',
182
+ message: 'Continue with this API key anyway?',
183
+ default: false
184
+ }]);
185
+ if (!continueAnyway) {
186
+ delete config.OPENAI_API_KEY;
187
+ }
188
+ }
189
+ } catch (error) {
190
+ spinner.fail(chalk.red(`OpenAI API test error: ${error.message}`));
191
+ }
192
+ }
193
+ }
194
+
195
+ // Step 4: Preferences
196
+ if (Object.keys(config).length > 0) {
197
+ console.log(chalk.yellow('\nāš™ļø Preferences:\n'));
198
+
199
+ const serviceChoices = [];
200
+ if (config.GOOGLE_API_KEY) {
201
+ serviceChoices.push(
202
+ { name: 'Gemini Flash (Fast & Cheap, $0.02)', value: 'gemini' },
203
+ { name: 'Imagen 3 (Premium Quality, $0.03)', value: 'imagen' }
204
+ );
205
+ }
206
+ if (config.OPENAI_API_KEY) {
207
+ serviceChoices.push(
208
+ { name: 'DALL-E 3 (Creative, $0.04-0.12)', value: 'dalle' }
209
+ );
210
+ }
211
+
212
+ const preferences = await inquirer.prompt([
213
+ {
214
+ type: 'list',
215
+ name: 'defaultService',
216
+ message: 'Default image generation service?',
217
+ choices: serviceChoices,
218
+ default: 'gemini'
219
+ },
220
+ {
221
+ type: 'list',
222
+ name: 'defaultQuality',
223
+ message: 'Default quality level?',
224
+ choices: [
225
+ { name: 'Standard (faster, cheaper)', value: 'standard' },
226
+ { name: 'HD (higher quality, more expensive)', value: 'hd' }
227
+ ],
228
+ default: 'standard'
229
+ },
230
+ {
231
+ type: 'number',
232
+ name: 'dailyBudget',
233
+ message: 'Daily budget limit (USD)?',
234
+ default: 5.00,
235
+ validate: (input) => {
236
+ if (input <= 0) return 'Budget must be greater than 0';
237
+ if (input > 1000) return 'Budget seems unusually high (max: $1000)';
238
+ return true;
239
+ }
240
+ },
241
+ {
242
+ type: 'number',
243
+ name: 'monthlyBudget',
244
+ message: 'Monthly budget limit (USD)?',
245
+ default: 50.00,
246
+ validate: (input) => {
247
+ if (input <= 0) return 'Budget must be greater than 0';
248
+ if (input > 10000) return 'Budget seems unusually high (max: $10,000)';
249
+ return true;
250
+ }
251
+ }
252
+ ]);
253
+
254
+ config.VISUAL_DEFAULT_SERVICE = preferences.defaultService;
255
+ config.VISUAL_DEFAULT_QUALITY = preferences.defaultQuality;
256
+ config.VISUAL_DAILY_BUDGET = preferences.dailyBudget;
257
+ config.VISUAL_MONTHLY_BUDGET = preferences.monthlyBudget;
258
+ config.VISUAL_WARN_THRESHOLD = 0.80;
259
+ config.VISUAL_ASSETS_PATH = './content-assets';
260
+
261
+ // Step 5: Update .env file
262
+ console.log('');
263
+ const spinner = ora('Updating .env file...').start();
264
+
265
+ try {
266
+ await updateEnvFile(config);
267
+ spinner.succeed(chalk.green('.env file updated successfully!'));
268
+ } catch (error) {
269
+ spinner.fail(chalk.red(`Failed to update .env: ${error.message}`));
270
+ throw error;
271
+ }
272
+
273
+ // Step 6: Summary
274
+ console.log(chalk.green('\nāœ… Configuration Complete!\n'));
275
+
276
+ console.log(chalk.cyan('šŸ“‹ Summary:'));
277
+ if (config.GOOGLE_API_KEY) {
278
+ console.log(chalk.gray(` āœ… Google AI configured (Gemini, Imagen, Veo)`));
279
+ }
280
+ if (config.OPENAI_API_KEY) {
281
+ console.log(chalk.gray(` āœ… OpenAI configured (DALL-E 3)`));
282
+ }
283
+ console.log(chalk.gray(` Default service: ${config.VISUAL_DEFAULT_SERVICE}`));
284
+ console.log(chalk.gray(` Default quality: ${config.VISUAL_DEFAULT_QUALITY}`));
285
+ console.log(chalk.gray(` Daily budget: $${config.VISUAL_DAILY_BUDGET.toFixed(2)}`));
286
+ console.log(chalk.gray(` Monthly budget: $${config.VISUAL_MONTHLY_BUDGET.toFixed(2)}`));
287
+
288
+ console.log(chalk.yellow('\nšŸ’” Quick Start:\n'));
289
+ console.log(chalk.cyan(' # Generate hero image'));
290
+ console.log(chalk.gray(' /myai-generate-visual "Modern developer workspace"\n'));
291
+
292
+ console.log(chalk.cyan(' # Generate with specific service'));
293
+ console.log(chalk.gray(' /myai-generate-visual "AI concept" --type=illustration --service=dalle\n'));
294
+
295
+ console.log(chalk.cyan(' # Generate article with images'));
296
+ console.log(chalk.gray(' /myai-content-writer "Article Title" --with-images\n'));
297
+
298
+ console.log(chalk.white('šŸ“š Documentation:'));
299
+ console.log(chalk.gray(' VISUAL_CONTENT_GENERATION_GUIDE.md - Complete guide'));
300
+ console.log(chalk.gray(' CONTENT_CREATION_GUIDE.md - Content workflow\n'));
301
+
302
+ } else {
303
+ console.log(chalk.yellow('\nāš ļø No configuration saved (no valid API keys)\n'));
304
+ }
305
+
306
+ } catch (error) {
307
+ if (error.isTtyError) {
308
+ console.error(chalk.red('\nāŒ Prompt couldn\'t be rendered in the current environment'));
309
+ } else {
310
+ console.error(chalk.red(`\nāŒ Configuration error: ${error.message}`));
311
+ }
312
+ process.exit(1);
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Update .env file with configuration
318
+ */
319
+ async function updateEnvFile(config) {
320
+ const envPath = path.join(process.cwd(), '.env');
321
+ let envContent = '';
322
+
323
+ // Read existing .env if it exists
324
+ if (await fs.pathExists(envPath)) {
325
+ envContent = await fs.readFile(envPath, 'utf-8');
326
+ }
327
+
328
+ // Update or add each config value
329
+ for (const [key, value] of Object.entries(config)) {
330
+ const regex = new RegExp(`^${key}=.*$`, 'm');
331
+ const line = `${key}=${value}`;
332
+
333
+ if (regex.test(envContent)) {
334
+ // Update existing key
335
+ envContent = envContent.replace(regex, line);
336
+ } else {
337
+ // Add new key
338
+ if (!envContent.endsWith('\n') && envContent.length > 0) {
339
+ envContent += '\n';
340
+ }
341
+ envContent += `${line}\n`;
342
+ }
343
+ }
344
+
345
+ // Write back to file
346
+ await fs.writeFile(envPath, envContent);
347
+
348
+ // Reload environment variables
349
+ dotenv.config({ override: true });
350
+ }
351
+
352
+ /**
353
+ * Test Google API connectivity
354
+ */
355
+ async function testGoogleAPI(apiKey) {
356
+ try {
357
+ const response = await fetch(
358
+ `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`,
359
+ { method: 'GET' }
360
+ );
361
+
362
+ if (response.ok) {
363
+ return { success: true };
364
+ } else {
365
+ const errorText = await response.text();
366
+ return { success: false, error: `HTTP ${response.status}: ${errorText}` };
367
+ }
368
+ } catch (error) {
369
+ return { success: false, error: error.message };
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Test OpenAI API connectivity
375
+ */
376
+ async function testOpenAIAPI(apiKey) {
377
+ try {
378
+ const response = await fetch(
379
+ 'https://api.openai.com/v1/models',
380
+ {
381
+ method: 'GET',
382
+ headers: {
383
+ 'Authorization': `Bearer ${apiKey}`
384
+ }
385
+ }
386
+ );
387
+
388
+ if (response.ok) {
389
+ return { success: true };
390
+ } else {
391
+ const errorData = await response.json();
392
+ return { success: false, error: errorData.error?.message || `HTTP ${response.status}` };
393
+ }
394
+ } catch (error) {
395
+ return { success: false, error: error.message };
396
+ }
397
+ }
398
+
399
+ /**
400
+ * Mask API key for display
401
+ */
402
+ function maskKey(key) {
403
+ if (!key || key.length < 16) return '****';
404
+ return `${key.substring(0, 8)}${'*'.repeat(Math.max(4, key.length - 12))}${key.substring(key.length - 4)}`;
405
+ }
406
+
407
+ // Run if executed directly
408
+ if (import.meta.url === `file://${process.argv[1]}`) {
409
+ configureVisualAPIs().catch(error => {
410
+ console.error(chalk.red(`\nFatal error: ${error.message}`));
411
+ process.exit(1);
412
+ });
413
+ }
@@ -0,0 +1,279 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Visual Content Generation CLI Script
5
+ *
6
+ * Standalone CLI script for generating images and videos.
7
+ * Used by Gemini CLI and Codex CLI platforms.
8
+ *
9
+ * Usage:
10
+ * node generate-visual-cli.js "prompt" --type=hero --service=gemini
11
+ *
12
+ * Platform support: Claude Code, Gemini CLI, Codex CLI
13
+ */
14
+
15
+ import { generateImage, generateVideoVeo, estimateCost, validateAPIKeys } from '../lib/visual-generation-utils.js';
16
+ import { saveImage, saveVideo, generateMarkdownReference, checkBudgetLimit, getTodaysCost, getMonthCost } from '../lib/asset-management.js';
17
+ import { hasAnyAPIKeys, getConfigStatusMessage, getServiceDisplayInfo } from '../lib/visual-config-utils.js';
18
+ import chalk from 'chalk';
19
+ import ora from 'ora';
20
+
21
+ // Parse command line arguments
22
+ const args = process.argv.slice(2);
23
+
24
+ if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
25
+ showHelp();
26
+ process.exit(0);
27
+ }
28
+
29
+ // Extract prompt (first non-option argument)
30
+ const prompt = args.find(arg => !arg.startsWith('--'));
31
+
32
+ if (!prompt) {
33
+ console.error(chalk.red('āŒ Error: Prompt is required'));
34
+ console.log('\nUsage: node generate-visual-cli.js "your prompt" --type=hero --service=gemini');
35
+ process.exit(1);
36
+ }
37
+
38
+ // Parse options
39
+ const options = {
40
+ type: getOption('type', 'hero'),
41
+ service: getOption('service', null),
42
+ size: getOption('size', '1024x1024'),
43
+ quality: getOption('quality', 'standard'),
44
+ description: getOption('description', null)
45
+ };
46
+
47
+ // Main execution
48
+ (async () => {
49
+ try {
50
+ // Check configuration
51
+ if (!hasAnyAPIKeys()) {
52
+ console.log(chalk.yellow(getConfigStatusMessage()));
53
+ process.exit(1);
54
+ }
55
+
56
+ // Validate type
57
+ const validTypes = ['hero', 'illustration', 'diagram', 'screenshot', 'video'];
58
+ if (!validTypes.includes(options.type)) {
59
+ console.error(chalk.red(`āŒ Invalid type: ${options.type}`));
60
+ console.log(chalk.gray(`Valid types: ${validTypes.join(', ')}`));
61
+ process.exit(1);
62
+ }
63
+
64
+ // Display configuration
65
+ console.log(chalk.blue('\nšŸŽØ Visual Content Generation\n'));
66
+ console.log(chalk.gray(`Type: ${options.type}`));
67
+ console.log(chalk.gray(`Prompt: "${prompt}"`));
68
+ if (options.service) {
69
+ console.log(chalk.gray(`Service: ${options.service}`));
70
+ }
71
+ console.log('');
72
+
73
+ // Estimate cost
74
+ let service = options.service;
75
+ if (!service) {
76
+ // Auto-select based on available services
77
+ const validation = validateAPIKeys();
78
+ service = validation.availableServices[0];
79
+ console.log(chalk.gray(`Auto-selected service: ${service}`));
80
+ }
81
+
82
+ const cost = estimateCost(service, { quality: options.quality, size: options.size });
83
+
84
+ // Check budget
85
+ const budget = await checkBudgetLimit(cost);
86
+ const todayCost = await getTodaysCost();
87
+ const monthCost = await getMonthCost();
88
+
89
+ console.log(chalk.cyan('šŸ’° Cost Estimate:'));
90
+ console.log(chalk.gray(` This generation: $${cost.toFixed(2)}`));
91
+ console.log(chalk.gray(` Today: $${todayCost.toFixed(2)} / $${budget.dailyBudget.toFixed(2)} (${Math.round((todayCost/budget.dailyBudget)*100)}%)`));
92
+ console.log(chalk.gray(` Month: $${monthCost.toFixed(2)} / $${budget.monthlyBudget.toFixed(2)} (${Math.round((monthCost/budget.monthlyBudget)*100)}%)`));
93
+ console.log('');
94
+
95
+ // Check if budget exceeded
96
+ if (budget.exceedsDailyBudget) {
97
+ console.error(chalk.red('āŒ Daily budget limit exceeded!'));
98
+ console.log(chalk.yellow(`\nCurrent usage: $${budget.todaysCost.toFixed(2)}`));
99
+ console.log(chalk.yellow(`Daily limit: $${budget.dailyBudget.toFixed(2)}`));
100
+ console.log(chalk.gray('\nOptions:'));
101
+ console.log(chalk.gray('1. Increase VISUAL_DAILY_BUDGET in .env'));
102
+ console.log(chalk.gray('2. Wait until tomorrow (resets at midnight)'));
103
+ process.exit(1);
104
+ }
105
+
106
+ if (budget.exceedsMonthlyBudget) {
107
+ console.error(chalk.red('āŒ Monthly budget limit exceeded!'));
108
+ console.log(chalk.yellow(`\nCurrent usage: $${budget.monthCost.toFixed(2)}`));
109
+ console.log(chalk.yellow(`Monthly limit: $${budget.monthlyBudget.toFixed(2)}`));
110
+ console.log(chalk.gray('\nOptions:'));
111
+ console.log(chalk.gray('1. Increase VISUAL_MONTHLY_BUDGET in .env'));
112
+ console.log(chalk.gray('2. Wait until next month'));
113
+ process.exit(1);
114
+ }
115
+
116
+ // Warnings
117
+ if (budget.dailyWarning) {
118
+ console.log(chalk.yellow(`āš ļø Warning: Approaching daily budget limit (${Math.round((budget.newDailyCost/budget.dailyBudget)*100)}%)`));
119
+ console.log('');
120
+ }
121
+
122
+ // Generate content
123
+ const spinner = ora(`Generating ${options.type} using ${service}...`).start();
124
+
125
+ let result;
126
+ let saved;
127
+
128
+ if (options.type === 'video') {
129
+ // Generate video
130
+ spinner.text = `Generating video using ${service}...`;
131
+ result = await generateVideoVeo(prompt, {
132
+ duration: 5,
133
+ aspectRatio: '16:9'
134
+ });
135
+
136
+ spinner.text = 'Saving video...';
137
+ saved = await saveVideo(result.buffer || Buffer.from(result.data, 'base64'), {
138
+ description: options.description || prompt,
139
+ service: result.service,
140
+ cost: result.cost,
141
+ prompt: prompt,
142
+ duration: result.duration || 5
143
+ });
144
+
145
+ } else {
146
+ // Generate image
147
+ spinner.text = `Generating ${options.type} using ${service}...`;
148
+ result = await generateImage(prompt, {
149
+ preferredService: service,
150
+ type: options.type,
151
+ quality: options.quality,
152
+ size: options.size
153
+ });
154
+
155
+ spinner.text = 'Saving image...';
156
+ saved = await saveImage(result.buffer, {
157
+ type: options.type,
158
+ description: options.description || prompt,
159
+ service: result.service,
160
+ cost: result.cost,
161
+ prompt: result.prompt
162
+ });
163
+ }
164
+
165
+ spinner.succeed(chalk.green(`${options.type === 'video' ? 'Video' : 'Image'} generated successfully!`));
166
+
167
+ // Display results
168
+ console.log('');
169
+ console.log(chalk.cyan(`šŸ“ø Details:`));
170
+
171
+ const serviceInfo = getServiceDisplayInfo(result.service);
172
+ if (serviceInfo) {
173
+ console.log(chalk.gray(` Service: ${serviceInfo.name}`));
174
+ }
175
+
176
+ console.log(chalk.gray(` Type: ${options.type.charAt(0).toUpperCase() + options.type.slice(1)}`));
177
+ console.log(chalk.gray(` Cost: $${result.cost.toFixed(2)}`));
178
+ console.log(chalk.gray(` File: ${saved.relativePath}`));
179
+ console.log(chalk.gray(` Size: ${(saved.size / 1024).toFixed(1)} KB`));
180
+ if (options.type === 'video' && result.duration) {
181
+ console.log(chalk.gray(` Duration: ${result.duration}s`));
182
+ }
183
+
184
+ // Display updated budget
185
+ const newTodayCost = await getTodaysCost();
186
+ const newMonthCost = await getMonthCost();
187
+
188
+ console.log('');
189
+ console.log(chalk.cyan('šŸ’° Updated Budget:'));
190
+ console.log(chalk.gray(` Today: $${newTodayCost.toFixed(2)} / $${budget.dailyBudget.toFixed(2)} (${Math.round((newTodayCost/budget.dailyBudget)*100)}%)`));
191
+ console.log(chalk.gray(` Month: $${newMonthCost.toFixed(2)} / $${budget.monthlyBudget.toFixed(2)} (${Math.round((newMonthCost/budget.monthlyBudget)*100)}%)`));
192
+
193
+ // Generate markdown
194
+ const altText = `${options.type} ${options.type === 'video' ? 'video' : 'image'}: ${prompt}`;
195
+ const markdown = generateMarkdownReference(saved.relativePath, altText);
196
+
197
+ console.log('');
198
+ console.log(chalk.cyan('šŸ“‹ Markdown Reference:'));
199
+ console.log(chalk.white(markdown));
200
+ console.log('');
201
+ console.log(chalk.gray('Copy and paste into your content ↑'));
202
+ console.log('');
203
+
204
+ } catch (error) {
205
+ console.error(chalk.red(`\nāŒ Error: ${error.message}`));
206
+
207
+ // Provide helpful error messages
208
+ if (error.message.includes('rate_limit') || error.message.includes('rate limit')) {
209
+ console.log(chalk.yellow('\nāš ļø Rate limited by API'));
210
+ console.log(chalk.gray('Options:'));
211
+ console.log(chalk.gray('1. Wait 60 seconds and try again'));
212
+ console.log(chalk.gray('2. Switch to different service: --service=dalle'));
213
+ console.log(chalk.gray('3. Check your API quota limits'));
214
+ } else if (error.message.includes('API key') || error.message.includes('unauthorized')) {
215
+ console.log(chalk.yellow('\nāš ļø API key issue'));
216
+ console.log(chalk.gray('Run configuration: node src/scripts/configure-visual-apis.js'));
217
+ }
218
+
219
+ process.exit(1);
220
+ }
221
+ })();
222
+
223
+ /**
224
+ * Get option value from command line arguments
225
+ */
226
+ function getOption(name, defaultValue) {
227
+ const arg = args.find(a => a.startsWith(`--${name}=`));
228
+ if (arg) {
229
+ return arg.split('=')[1];
230
+ }
231
+ return defaultValue;
232
+ }
233
+
234
+ /**
235
+ * Show help message
236
+ */
237
+ function showHelp() {
238
+ console.log(chalk.blue('\nšŸŽØ Visual Content Generation CLI\n'));
239
+
240
+ console.log(chalk.white('Usage:'));
241
+ console.log(chalk.gray(' node generate-visual-cli.js "prompt" [options]\n'));
242
+
243
+ console.log(chalk.white('Options:'));
244
+ console.log(chalk.gray(' --type=<type> Content type (default: hero)'));
245
+ console.log(chalk.gray(' Values: hero, illustration, diagram, screenshot, video'));
246
+ console.log(chalk.gray(' --service=<service> AI service (default: auto-select)'));
247
+ console.log(chalk.gray(' Values: gemini, imagen, dalle, veo'));
248
+ console.log(chalk.gray(' --size=<size> Image size (default: 1024x1024)'));
249
+ console.log(chalk.gray(' Values: 1024x1024, 1792x1024, 1024x1792'));
250
+ console.log(chalk.gray(' --quality=<quality> Quality level (default: standard)'));
251
+ console.log(chalk.gray(' Values: standard, hd'));
252
+ console.log(chalk.gray(' --description=<desc> Filename description (default: from prompt)\n'));
253
+
254
+ console.log(chalk.white('Examples:'));
255
+ console.log(chalk.gray(' # Generate hero image (auto-select service)'));
256
+ console.log(chalk.cyan(' node generate-visual-cli.js "Modern developer workspace"\n'));
257
+
258
+ console.log(chalk.gray(' # Generate diagram with Gemini'));
259
+ console.log(chalk.cyan(' node generate-visual-cli.js "System architecture" --type=diagram --service=gemini\n'));
260
+
261
+ console.log(chalk.gray(' # Generate HD illustration with DALL-E'));
262
+ console.log(chalk.cyan(' node generate-visual-cli.js "AI brain network" --type=illustration --service=dalle --quality=hd\n'));
263
+
264
+ console.log(chalk.gray(' # Generate video'));
265
+ console.log(chalk.cyan(' node generate-visual-cli.js "Product demo" --type=video --service=veo\n'));
266
+
267
+ console.log(chalk.white('Services:'));
268
+ console.log(chalk.gray(' gemini Gemini 2.5 Flash - Fast, $0.02/image'));
269
+ console.log(chalk.gray(' imagen Imagen 3 - Premium quality, $0.03/image'));
270
+ console.log(chalk.gray(' dalle DALL-E 3 - Creative, $0.04-0.12/image'));
271
+ console.log(chalk.gray(' veo Veo 2 - Video generation, $0.10/video\n'));
272
+
273
+ console.log(chalk.white('Prerequisites:'));
274
+ console.log(chalk.gray(' 1. Configure API keys: node src/scripts/configure-visual-apis.js'));
275
+ console.log(chalk.gray(' 2. Or add to .env: GOOGLE_API_KEY=xxx and/or OPENAI_API_KEY=xxx\n'));
276
+
277
+ console.log(chalk.white('Documentation:'));
278
+ console.log(chalk.gray(' See VISUAL_CONTENT_GENERATION_GUIDE.md for complete guide\n'));
279
+ }