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.
- package/.env.example +40 -0
- package/CHANGELOG.md +96 -0
- package/CONTENT_CREATION_GUIDE.md +3399 -0
- package/DEVELOPER_USE_CASES.md +2085 -0
- package/README.md +209 -2
- package/VISUAL_GENERATION_FILE_ORGANIZATION.md +105 -0
- package/bin/cli.js +46 -0
- package/package.json +18 -3
- package/src/lib/asset-management.js +532 -0
- package/src/lib/visual-config-utils.js +424 -0
- package/src/lib/visual-generation-utils.js +880 -0
- package/src/scripts/configure-visual-apis.js +413 -0
- package/src/scripts/generate-visual-cli.js +279 -0
- package/src/templates/claude/agents/content-production-coordinator.md +111 -0
- package/src/templates/claude/agents/content-writer.md +209 -4
- package/src/templates/claude/agents/proprietary-content-verifier.md +96 -0
- package/src/templates/claude/agents/visual-content-generator.md +520 -0
- package/src/templates/claude/commands/myai-content-writer.md +33 -8
- package/src/templates/claude/commands/myai-coordinate-content.md +136 -0
- package/src/templates/claude/commands/myai-generate-visual.md +318 -0
- package/src/templates/codex/commands/myai-generate-visual.md +307 -0
- package/src/templates/gemini/commands/myai-generate-visual.md +200 -0
- package/.claude/CLAUDE.md +0 -52
- package/.claude/agents/content-writer.md +0 -155
- package/.claude/agents/wordpress-admin.md +0 -271
- package/.claude/commands/myai-configure.md +0 -44
- package/.claude/commands/myai-content-writer.md +0 -78
- package/.claude/commands/myai-wordpress-publish.md +0 -120
- package/.claude/mcp/gutenberg-converter.js +0 -447
- package/.claude/mcp/mcp-config.json +0 -184
- package/.claude/mcp/wordpress-server-simple.js +0 -182
- 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
|
+
}
|