myaidev-method 0.2.12 → 0.2.16

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 (32) hide show
  1. package/.env.example +40 -0
  2. package/CHANGELOG.md +96 -0
  3. package/CONTENT_CREATION_GUIDE.md +3399 -0
  4. package/DEVELOPER_USE_CASES.md +2085 -0
  5. package/README.md +209 -2
  6. package/VISUAL_GENERATION_FILE_ORGANIZATION.md +105 -0
  7. package/bin/cli.js +46 -0
  8. package/package.json +18 -3
  9. package/src/lib/asset-management.js +532 -0
  10. package/src/lib/visual-config-utils.js +424 -0
  11. package/src/lib/visual-generation-utils.js +880 -0
  12. package/src/scripts/configure-visual-apis.js +413 -0
  13. package/src/scripts/generate-visual-cli.js +279 -0
  14. package/src/templates/claude/agents/content-production-coordinator.md +111 -0
  15. package/src/templates/claude/agents/content-writer.md +209 -4
  16. package/src/templates/claude/agents/proprietary-content-verifier.md +96 -0
  17. package/src/templates/claude/agents/visual-content-generator.md +520 -0
  18. package/src/templates/claude/commands/myai-content-writer.md +33 -8
  19. package/src/templates/claude/commands/myai-coordinate-content.md +136 -0
  20. package/src/templates/claude/commands/myai-generate-visual.md +318 -0
  21. package/src/templates/codex/commands/myai-generate-visual.md +307 -0
  22. package/src/templates/gemini/commands/myai-generate-visual.md +200 -0
  23. package/.claude/CLAUDE.md +0 -52
  24. package/.claude/agents/content-writer.md +0 -155
  25. package/.claude/agents/wordpress-admin.md +0 -271
  26. package/.claude/commands/myai-configure.md +0 -44
  27. package/.claude/commands/myai-content-writer.md +0 -78
  28. package/.claude/commands/myai-wordpress-publish.md +0 -120
  29. package/.claude/mcp/gutenberg-converter.js +0 -447
  30. package/.claude/mcp/mcp-config.json +0 -184
  31. package/.claude/mcp/wordpress-server-simple.js +0 -182
  32. package/.claude/settings.local.json +0 -12
@@ -0,0 +1,424 @@
1
+ /**
2
+ * Visual Configuration Utilities
3
+ *
4
+ * Manages configuration, validation, and environment setup for visual content generation.
5
+ *
6
+ * Platform support: Claude Code, Gemini CLI, Codex CLI
7
+ *
8
+ * @module visual-config-utils
9
+ */
10
+
11
+ import fs from 'fs-extra';
12
+ import path from 'path';
13
+ import dotenv from 'dotenv';
14
+
15
+ dotenv.config();
16
+
17
+ /**
18
+ * Load visual generation configuration from environment
19
+ *
20
+ * @returns {Object} Configuration object
21
+ */
22
+ export function loadVisualConfig() {
23
+ return {
24
+ googleApiKey: process.env.GOOGLE_API_KEY || null,
25
+ openaiApiKey: process.env.OPENAI_API_KEY || null,
26
+ defaultService: process.env.VISUAL_DEFAULT_SERVICE || 'gemini',
27
+ defaultQuality: process.env.VISUAL_DEFAULT_QUALITY || 'standard',
28
+ assetsPath: process.env.VISUAL_ASSETS_PATH || './content-assets',
29
+ dailyBudget: parseFloat(process.env.VISUAL_DAILY_BUDGET || 5.0),
30
+ monthlyBudget: parseFloat(process.env.VISUAL_MONTHLY_BUDGET || 50.0),
31
+ warnThreshold: parseFloat(process.env.VISUAL_WARN_THRESHOLD || 0.8)
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Validate visual generation configuration
37
+ *
38
+ * @returns {Object} Validation results
39
+ */
40
+ export function validateVisualConfig() {
41
+ const config = loadVisualConfig();
42
+
43
+ const validation = {
44
+ isValid: false,
45
+ hasGoogle: false,
46
+ hasOpenAI: false,
47
+ hasAnyAPIKeys: false,
48
+ availableServices: [],
49
+ errors: [],
50
+ warnings: []
51
+ };
52
+
53
+ // Validate API keys
54
+ if (config.googleApiKey && config.googleApiKey.length > 20) {
55
+ validation.hasGoogle = true;
56
+ validation.availableServices.push('gemini', 'imagen', 'veo');
57
+ } else if (config.googleApiKey) {
58
+ validation.errors.push('GOOGLE_API_KEY appears to be invalid (too short)');
59
+ }
60
+
61
+ if (config.openaiApiKey && config.openaiApiKey.length > 20) {
62
+ validation.hasOpenAI = true;
63
+ validation.availableServices.push('dalle');
64
+ } else if (config.openaiApiKey) {
65
+ validation.errors.push('OPENAI_API_KEY appears to be invalid (too short)');
66
+ }
67
+
68
+ validation.hasAnyAPIKeys = validation.hasGoogle || validation.hasOpenAI;
69
+
70
+ // Validate default service
71
+ if (config.defaultService && !validation.availableServices.includes(config.defaultService)) {
72
+ validation.warnings.push(`Default service '${config.defaultService}' is not available with current API keys`);
73
+ }
74
+
75
+ // Validate budget values
76
+ if (config.dailyBudget <= 0) {
77
+ validation.warnings.push('Daily budget should be greater than 0');
78
+ }
79
+
80
+ if (config.monthlyBudget <= 0) {
81
+ validation.warnings.push('Monthly budget should be greater than 0');
82
+ }
83
+
84
+ if (config.monthlyBudget < config.dailyBudget) {
85
+ validation.warnings.push('Monthly budget is less than daily budget');
86
+ }
87
+
88
+ // Configuration is valid if at least one API key is configured
89
+ validation.isValid = validation.hasAnyAPIKeys && validation.errors.length === 0;
90
+
91
+ return validation;
92
+ }
93
+
94
+ /**
95
+ * Check if any API keys are configured
96
+ *
97
+ * @returns {boolean} True if at least one API key is configured
98
+ */
99
+ export function hasAnyAPIKeys() {
100
+ const validation = validateVisualConfig();
101
+ return validation.hasAnyAPIKeys;
102
+ }
103
+
104
+ /**
105
+ * Get available services based on configured API keys
106
+ *
107
+ * @returns {Array<string>} List of available service names
108
+ */
109
+ export function getAvailableServices() {
110
+ const validation = validateVisualConfig();
111
+ return validation.availableServices;
112
+ }
113
+
114
+ /**
115
+ * Get service display name and information
116
+ *
117
+ * @param {string} service - Service identifier
118
+ * @returns {Object} Service information
119
+ */
120
+ export function getServiceDisplayInfo(service) {
121
+ const services = {
122
+ gemini: {
123
+ id: 'gemini',
124
+ name: 'Gemini 2.5 Flash Image',
125
+ nickname: '"Nano Banana"',
126
+ provider: 'Google',
127
+ apiKey: 'GOOGLE_API_KEY',
128
+ speed: 'Fast ⚡⚡⚡',
129
+ cost: '$0.02/image',
130
+ quality: 'Good',
131
+ bestFor: 'Quick hero images, high volume'
132
+ },
133
+ imagen: {
134
+ id: 'imagen',
135
+ name: 'Imagen 3',
136
+ nickname: 'Premium Quality',
137
+ provider: 'Google',
138
+ apiKey: 'GOOGLE_API_KEY',
139
+ speed: 'Medium ⚡⚡',
140
+ cost: '$0.03/image',
141
+ quality: 'Excellent',
142
+ bestFor: 'Premium hero images, photorealistic content'
143
+ },
144
+ dalle: {
145
+ id: 'dalle',
146
+ name: 'DALL-E 3',
147
+ nickname: 'Creative AI',
148
+ provider: 'OpenAI',
149
+ apiKey: 'OPENAI_API_KEY',
150
+ speed: 'Medium ⚡⚡',
151
+ cost: '$0.04-0.12/image',
152
+ quality: 'Excellent',
153
+ bestFor: 'Creative illustrations, concept art'
154
+ },
155
+ veo: {
156
+ id: 'veo',
157
+ name: 'Veo 2',
158
+ nickname: 'Video Generation',
159
+ provider: 'Google',
160
+ apiKey: 'GOOGLE_API_KEY',
161
+ speed: 'Slow ⚡',
162
+ cost: '$0.10/video (est.)',
163
+ quality: 'Good',
164
+ bestFor: 'Product demos, animated diagrams'
165
+ }
166
+ };
167
+
168
+ return services[service] || null;
169
+ }
170
+
171
+ /**
172
+ * Get configuration status message
173
+ *
174
+ * @param {boolean} verbose - Include detailed information
175
+ * @returns {string} Status message
176
+ */
177
+ export function getConfigStatusMessage(verbose = false) {
178
+ const validation = validateVisualConfig();
179
+ const config = loadVisualConfig();
180
+
181
+ if (!validation.hasAnyAPIKeys) {
182
+ return `⚠️ Visual content generation not configured
183
+
184
+ No API keys found. To enable image/video generation:
185
+
186
+ 1. Run: /myai-configure visual
187
+ OR
188
+ 2. Add to your .env file:
189
+ GOOGLE_API_KEY=your_key_here # For Gemini, Imagen, Veo
190
+ OPENAI_API_KEY=your_key_here # For DALL-E
191
+
192
+ Get API keys:
193
+ • Google: https://ai.google.dev/
194
+ • OpenAI: https://platform.openai.com/api-keys`;
195
+ }
196
+
197
+ let message = `✅ Visual content generation configured\n\n`;
198
+
199
+ // Show available services
200
+ message += `📋 Available Services:\n`;
201
+ for (const service of validation.availableServices) {
202
+ const info = getServiceDisplayInfo(service);
203
+ message += ` • ${info.name} - ${info.cost}\n`;
204
+ }
205
+
206
+ if (verbose) {
207
+ message += `\n⚙️ Settings:\n`;
208
+ message += ` Default Service: ${config.defaultService}\n`;
209
+ message += ` Default Quality: ${config.defaultQuality}\n`;
210
+ message += ` Assets Path: ${config.assetsPath}\n`;
211
+ message += ` Daily Budget: $${config.dailyBudget.toFixed(2)}\n`;
212
+ message += ` Monthly Budget: $${config.monthlyBudget.toFixed(2)}\n`;
213
+ }
214
+
215
+ // Show warnings
216
+ if (validation.warnings.length > 0) {
217
+ message += `\n⚠️ Warnings:\n`;
218
+ for (const warning of validation.warnings) {
219
+ message += ` • ${warning}\n`;
220
+ }
221
+ }
222
+
223
+ return message;
224
+ }
225
+
226
+ /**
227
+ * Update .env file with new configuration values
228
+ *
229
+ * @param {Object} updates - Key-value pairs to update
230
+ * @returns {Promise<void>}
231
+ */
232
+ export async function updateEnvFile(updates) {
233
+ const envPath = path.join(process.cwd(), '.env');
234
+ let envContent = '';
235
+
236
+ // Read existing .env file
237
+ if (await fs.pathExists(envPath)) {
238
+ envContent = await fs.readFile(envPath, 'utf-8');
239
+ }
240
+
241
+ // Update or add each key
242
+ for (const [key, value] of Object.entries(updates)) {
243
+ const regex = new RegExp(`^${key}=.*$`, 'm');
244
+ const line = `${key}=${value}`;
245
+
246
+ if (regex.test(envContent)) {
247
+ // Update existing key
248
+ envContent = envContent.replace(regex, line);
249
+ } else {
250
+ // Add new key
251
+ envContent += `\n${line}`;
252
+ }
253
+ }
254
+
255
+ // Write back to file
256
+ await fs.writeFile(envPath, envContent.trim() + '\n');
257
+
258
+ // Reload environment variables
259
+ dotenv.config({ override: true });
260
+ }
261
+
262
+ /**
263
+ * Mask API key for display (show first 8 and last 4 characters)
264
+ *
265
+ * @param {string} apiKey - API key to mask
266
+ * @returns {string} Masked API key
267
+ */
268
+ export function maskAPIKey(apiKey) {
269
+ if (!apiKey || apiKey.length < 16) {
270
+ return '****';
271
+ }
272
+
273
+ const start = apiKey.substring(0, 8);
274
+ const end = apiKey.substring(apiKey.length - 4);
275
+ const masked = `${start}${'*'.repeat(Math.max(4, apiKey.length - 12))}${end}`;
276
+
277
+ return masked;
278
+ }
279
+
280
+ /**
281
+ * Test API key validity by making a simple API call
282
+ *
283
+ * @param {string} service - Service to test (google, openai)
284
+ * @returns {Promise<Object>} Test result
285
+ */
286
+ export async function testAPIKey(service) {
287
+ const config = loadVisualConfig();
288
+
289
+ try {
290
+ if (service === 'google') {
291
+ if (!config.googleApiKey) {
292
+ return { success: false, error: 'GOOGLE_API_KEY not configured' };
293
+ }
294
+
295
+ // Simple test: list models
296
+ const response = await fetch(
297
+ `https://generativelanguage.googleapis.com/v1beta/models?key=${config.googleApiKey}`,
298
+ { method: 'GET' }
299
+ );
300
+
301
+ if (response.ok) {
302
+ return { success: true, service: 'google' };
303
+ } else {
304
+ const error = await response.text();
305
+ return { success: false, error: `Google API test failed: ${error}` };
306
+ }
307
+ }
308
+
309
+ if (service === 'openai') {
310
+ if (!config.openaiApiKey) {
311
+ return { success: false, error: 'OPENAI_API_KEY not configured' };
312
+ }
313
+
314
+ // Simple test: list models
315
+ const response = await fetch(
316
+ 'https://api.openai.com/v1/models',
317
+ {
318
+ method: 'GET',
319
+ headers: {
320
+ 'Authorization': `Bearer ${config.openaiApiKey}`
321
+ }
322
+ }
323
+ );
324
+
325
+ if (response.ok) {
326
+ return { success: true, service: 'openai' };
327
+ } else {
328
+ const error = await response.text();
329
+ return { success: false, error: `OpenAI API test failed: ${error}` };
330
+ }
331
+ }
332
+
333
+ return { success: false, error: `Unknown service: ${service}` };
334
+
335
+ } catch (error) {
336
+ return { success: false, error: error.message };
337
+ }
338
+ }
339
+
340
+ /**
341
+ * Generate configuration summary for display
342
+ *
343
+ * @returns {Object} Configuration summary
344
+ */
345
+ export function getConfigSummary() {
346
+ const validation = validateVisualConfig();
347
+ const config = loadVisualConfig();
348
+
349
+ return {
350
+ configured: validation.hasAnyAPIKeys,
351
+ services: {
352
+ google: {
353
+ configured: validation.hasGoogle,
354
+ available: ['gemini', 'imagen', 'veo'].filter(s =>
355
+ validation.availableServices.includes(s)
356
+ )
357
+ },
358
+ openai: {
359
+ configured: validation.hasOpenAI,
360
+ available: validation.availableServices.includes('dalle') ? ['dalle'] : []
361
+ }
362
+ },
363
+ settings: {
364
+ defaultService: config.defaultService,
365
+ defaultQuality: config.defaultQuality,
366
+ assetsPath: config.assetsPath,
367
+ budgets: {
368
+ daily: config.dailyBudget,
369
+ monthly: config.monthlyBudget,
370
+ warnThreshold: config.warnThreshold
371
+ }
372
+ },
373
+ validation: {
374
+ isValid: validation.isValid,
375
+ errors: validation.errors,
376
+ warnings: validation.warnings
377
+ }
378
+ };
379
+ }
380
+
381
+ /**
382
+ * Check if a specific service is available
383
+ *
384
+ * @param {string} service - Service name (gemini, imagen, dalle, veo)
385
+ * @returns {boolean} True if service is available
386
+ */
387
+ export function isServiceAvailable(service) {
388
+ const available = getAvailableServices();
389
+ return available.includes(service);
390
+ }
391
+
392
+ /**
393
+ * Get recommended service based on image type
394
+ *
395
+ * @param {string} type - Image type (hero, illustration, diagram, screenshot)
396
+ * @returns {string} Recommended service name
397
+ */
398
+ export function getRecommendedService(type) {
399
+ const available = getAvailableServices();
400
+ const config = loadVisualConfig();
401
+
402
+ // Recommendations by type
403
+ const recommendations = {
404
+ hero: ['imagen', 'dalle', 'gemini'], // Premium quality for hero
405
+ illustration: ['dalle', 'imagen', 'gemini'], // Creative for illustrations
406
+ diagram: ['gemini', 'dalle', 'imagen'], // Fast for diagrams
407
+ screenshot: ['gemini', 'imagen', 'dalle'], // Fast for screenshots
408
+ video: ['veo'] // Only Veo for video
409
+ };
410
+
411
+ const preferred = recommendations[type] || recommendations.hero;
412
+
413
+ // Return first available from preferred list
414
+ for (const service of preferred) {
415
+ if (available.includes(service)) {
416
+ return service;
417
+ }
418
+ }
419
+
420
+ // Fallback to default or first available
421
+ return available.includes(config.defaultService)
422
+ ? config.defaultService
423
+ : available[0];
424
+ }