myaidev-method 0.2.22 → 0.2.24-1

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 (59) hide show
  1. package/USER_GUIDE.md +453 -48
  2. package/bin/cli.js +236 -38
  3. package/content-rules.example.md +80 -0
  4. package/dist/mcp/mcp-launcher.js +237 -0
  5. package/dist/server/.tsbuildinfo +1 -1
  6. package/dist/server/auth/layers.d.ts +1 -1
  7. package/dist/server/auth/services/AuthService.d.ts +1 -1
  8. package/dist/server/auth/services/TokenService.js.map +1 -1
  9. package/dist/server/auth/services/example.d.ts +5 -5
  10. package/package.json +22 -17
  11. package/src/config/workflows.js +28 -44
  12. package/src/index.js +21 -8
  13. package/src/lib/ascii-banner.js +214 -0
  14. package/src/lib/config-manager.js +470 -0
  15. package/src/lib/content-generator.js +427 -0
  16. package/src/lib/html-conversion-utils.js +843 -0
  17. package/src/lib/seo-optimizer.js +515 -0
  18. package/src/lib/update-manager.js +2 -1
  19. package/src/lib/visual-config-utils.js +321 -295
  20. package/src/lib/visual-generation-utils.js +1000 -811
  21. package/src/lib/wordpress-client.js +633 -0
  22. package/src/lib/workflow-installer.js +3 -3
  23. package/src/scripts/configure-wordpress-mcp.js +8 -3
  24. package/src/scripts/generate-visual-cli.js +365 -235
  25. package/src/scripts/html-conversion-cli.js +526 -0
  26. package/src/scripts/init/configure.js +436 -0
  27. package/src/scripts/init/install.js +460 -0
  28. package/src/scripts/ping.js +250 -0
  29. package/src/scripts/utils/file-utils.js +404 -0
  30. package/src/scripts/utils/logger.js +300 -0
  31. package/src/scripts/utils/write-content.js +293 -0
  32. package/src/scripts/wordpress/publish-to-wordpress.js +165 -0
  33. package/src/server/auth/services/TokenService.ts +1 -1
  34. package/src/templates/claude/agents/content-rules-setup.md +657 -0
  35. package/src/templates/claude/agents/content-writer.md +328 -1
  36. package/src/templates/claude/agents/visual-content-generator.md +311 -8
  37. package/src/templates/claude/commands/myai-configure.md +1 -1
  38. package/src/templates/claude/commands/myai-content-rules-setup.md +204 -0
  39. package/src/templates/claude/commands/myai-convert-html.md +186 -0
  40. package/src/templates/codex/commands/myai-content-rules-setup.md +85 -0
  41. package/src/templates/diagrams/architecture.d2 +52 -0
  42. package/src/templates/diagrams/flowchart.d2 +42 -0
  43. package/src/templates/diagrams/sequence.d2 +47 -0
  44. package/src/templates/docs/content-creation-guide.md +164 -0
  45. package/src/templates/docs/deployment-guide.md +336 -0
  46. package/src/templates/docs/visual-generation-guide.md +248 -0
  47. package/src/templates/docs/wordpress-publishing-guide.md +208 -0
  48. package/src/templates/gemini/commands/myai-content-rules-setup.toml +57 -0
  49. package/src/templates/infographics/comparison-table.html +347 -0
  50. package/src/templates/infographics/data-chart.html +268 -0
  51. package/src/templates/infographics/process-flow.html +365 -0
  52. package/.claude/mcp/sparc-orchestrator-server.js +0 -607
  53. package/.claude/mcp/wordpress-server.js +0 -1277
  54. package/src/agents/content-writer-prompt.md +0 -164
  55. package/src/agents/content-writer.json +0 -70
  56. package/src/templates/claude/mcp_config.json +0 -74
  57. package/src/templates/claude/slash_commands.json +0 -166
  58. package/src/templates/scripts/configure-wordpress-mcp.js +0 -181
  59. /package/src/scripts/{wordpress-health-check.js → wordpress/wordpress-health-check.js} +0 -0
@@ -0,0 +1,470 @@
1
+ /**
2
+ * Configuration Manager
3
+ * Central configuration management for MyAIDev Method
4
+ * Handles loading, validating, and persisting configurations
5
+ */
6
+
7
+ import path from 'path';
8
+ import fs from 'fs-extra';
9
+
10
+ // Configuration schemas for validation
11
+ export const SCHEMAS = {
12
+ wordpress: {
13
+ required: ['WORDPRESS_URL', 'WORDPRESS_USERNAME', 'WORDPRESS_APP_PASSWORD'],
14
+ optional: ['WORDPRESS_DEFAULT_STATUS', 'WORDPRESS_DEFAULT_CATEGORIES'],
15
+ defaults: {
16
+ WORDPRESS_DEFAULT_STATUS: 'draft'
17
+ }
18
+ },
19
+ openstack: {
20
+ required: ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD', 'OS_PROJECT_NAME'],
21
+ optional: ['OS_REGION_NAME', 'OS_USER_DOMAIN_NAME', 'OS_PROJECT_DOMAIN_NAME'],
22
+ defaults: {
23
+ OS_USER_DOMAIN_NAME: 'Default',
24
+ OS_PROJECT_DOMAIN_NAME: 'Default'
25
+ }
26
+ },
27
+ content: {
28
+ required: [],
29
+ optional: ['DEFAULT_WORD_COUNT', 'DEFAULT_TONE', 'CONTENT_OUTPUT_DIR'],
30
+ defaults: {
31
+ DEFAULT_WORD_COUNT: '1500',
32
+ DEFAULT_TONE: 'professional',
33
+ CONTENT_OUTPUT_DIR: './content'
34
+ }
35
+ },
36
+ defaults: {
37
+ required: [],
38
+ optional: ['LOG_LEVEL', 'CLI_TYPE'],
39
+ defaults: {
40
+ LOG_LEVEL: 'INFO',
41
+ CLI_TYPE: 'claude'
42
+ }
43
+ }
44
+ };
45
+
46
+ /**
47
+ * Configuration Manager Class
48
+ */
49
+ export class ConfigManager {
50
+ constructor(projectRoot = process.cwd()) {
51
+ this.projectRoot = projectRoot;
52
+ this.configCache = null;
53
+ this.lastLoad = null;
54
+ }
55
+
56
+ /**
57
+ * Get path to .env file
58
+ * @returns {string}
59
+ */
60
+ getEnvPath() {
61
+ return path.join(this.projectRoot, '.env');
62
+ }
63
+
64
+ /**
65
+ * Get path to .claude/config directory
66
+ * @returns {string}
67
+ */
68
+ getClaudeConfigDir() {
69
+ return path.join(this.projectRoot, '.claude', 'config');
70
+ }
71
+
72
+ /**
73
+ * Load all configurations from various sources
74
+ * @param {boolean} [force=false] - Force reload even if cached
75
+ * @returns {Promise<Object>} Merged configuration
76
+ */
77
+ async loadAll(force = false) {
78
+ // Return cached config if recent (within 5 seconds)
79
+ if (!force && this.configCache && this.lastLoad) {
80
+ const age = Date.now() - this.lastLoad;
81
+ if (age < 5000) {
82
+ return this.configCache;
83
+ }
84
+ }
85
+
86
+ const config = {};
87
+
88
+ // 1. Load from .env file
89
+ const envConfig = await this.loadEnvFile();
90
+ Object.assign(config, envConfig);
91
+
92
+ // 2. Load from .claude/config/*.json files
93
+ const claudeConfigs = await this.loadClaudeConfigs();
94
+ Object.assign(config, claudeConfigs);
95
+
96
+ // 3. Apply defaults for any missing values
97
+ this.applyDefaults(config);
98
+
99
+ // Cache the result
100
+ this.configCache = config;
101
+ this.lastLoad = Date.now();
102
+
103
+ return config;
104
+ }
105
+
106
+ /**
107
+ * Load configuration from .env file
108
+ * @returns {Promise<Object>}
109
+ */
110
+ async loadEnvFile() {
111
+ const envPath = this.getEnvPath();
112
+
113
+ try {
114
+ const exists = await fs.pathExists(envPath);
115
+ if (!exists) {
116
+ return {};
117
+ }
118
+
119
+ const content = await fs.readFile(envPath, 'utf-8');
120
+ return this.parseEnvContent(content);
121
+ } catch (error) {
122
+ console.warn(`Warning: Failed to load .env file: ${error.message}`);
123
+ return {};
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Load configuration files from .claude/config/
129
+ * @returns {Promise<Object>}
130
+ */
131
+ async loadClaudeConfigs() {
132
+ const configDir = this.getClaudeConfigDir();
133
+ const merged = {};
134
+
135
+ try {
136
+ const exists = await fs.pathExists(configDir);
137
+ if (!exists) {
138
+ return merged;
139
+ }
140
+
141
+ const files = await fs.readdir(configDir);
142
+ const jsonFiles = files.filter(f => f.endsWith('.json'));
143
+
144
+ for (const file of jsonFiles) {
145
+ const filePath = path.join(configDir, file);
146
+ try {
147
+ const content = await fs.readFile(filePath, 'utf-8');
148
+ const data = JSON.parse(content);
149
+ Object.assign(merged, data);
150
+ } catch (err) {
151
+ console.warn(`Warning: Failed to load config file ${file}: ${err.message}`);
152
+ }
153
+ }
154
+
155
+ return merged;
156
+ } catch (error) {
157
+ console.warn(`Warning: Failed to load claude configs: ${error.message}`);
158
+ return merged;
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Apply default values for missing configuration
164
+ * @param {Object} config - Configuration object to modify
165
+ */
166
+ applyDefaults(config) {
167
+ for (const schema of Object.values(SCHEMAS)) {
168
+ for (const [key, value] of Object.entries(schema.defaults || {})) {
169
+ if (config[key] === undefined) {
170
+ config[key] = value;
171
+ }
172
+ }
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Get a specific configuration value
178
+ * @param {string} key - Configuration key
179
+ * @param {any} [defaultValue] - Default value if not found
180
+ * @returns {Promise<any>}
181
+ */
182
+ async getConfig(key, defaultValue = undefined) {
183
+ const config = await this.loadAll();
184
+ return config[key] !== undefined ? config[key] : defaultValue;
185
+ }
186
+
187
+ /**
188
+ * Save workflow-specific configuration
189
+ * @param {string} name - Workflow/config name (e.g., 'wordpress', 'openstack')
190
+ * @param {Object} config - Configuration values
191
+ * @returns {Promise<boolean>}
192
+ */
193
+ async saveWorkflowConfig(name, config) {
194
+ const configDir = this.getClaudeConfigDir();
195
+
196
+ try {
197
+ await fs.ensureDir(configDir);
198
+
199
+ const configPath = path.join(configDir, `${name}.json`);
200
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
201
+
202
+ // Invalidate cache
203
+ this.configCache = null;
204
+
205
+ return true;
206
+ } catch (error) {
207
+ console.error(`Failed to save ${name} config: ${error.message}`);
208
+ return false;
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Save configuration to .env file
214
+ * @param {Object} config - Configuration to save
215
+ * @param {boolean} [merge=true] - Merge with existing .env
216
+ * @returns {Promise<boolean>}
217
+ */
218
+ async saveEnvConfig(config, merge = true) {
219
+ const envPath = this.getEnvPath();
220
+
221
+ try {
222
+ let existing = {};
223
+ if (merge) {
224
+ existing = await this.loadEnvFile();
225
+ }
226
+
227
+ const merged = { ...existing, ...config };
228
+ const content = this.formatEnvContent(merged);
229
+
230
+ await fs.writeFile(envPath, content, 'utf-8');
231
+
232
+ // Invalidate cache
233
+ this.configCache = null;
234
+
235
+ return true;
236
+ } catch (error) {
237
+ console.error(`Failed to save .env config: ${error.message}`);
238
+ return false;
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Validate configuration against a schema
244
+ * @param {Object} config - Configuration to validate
245
+ * @param {string} schemaName - Schema name ('wordpress', 'openstack', etc.)
246
+ * @returns {{valid: boolean, missing: string[], warnings: string[]}}
247
+ */
248
+ validateConfig(config, schemaName) {
249
+ const schema = SCHEMAS[schemaName];
250
+ if (!schema) {
251
+ return { valid: false, missing: [], warnings: [`Unknown schema: ${schemaName}`] };
252
+ }
253
+
254
+ const missing = [];
255
+ const warnings = [];
256
+
257
+ // Check required fields
258
+ for (const field of schema.required || []) {
259
+ if (!config[field] || config[field].trim() === '') {
260
+ missing.push(field);
261
+ }
262
+ }
263
+
264
+ // Check for empty optional fields
265
+ for (const field of schema.optional || []) {
266
+ if (config[field] === '') {
267
+ warnings.push(`${field} is empty, using default`);
268
+ }
269
+ }
270
+
271
+ return {
272
+ valid: missing.length === 0,
273
+ missing,
274
+ warnings
275
+ };
276
+ }
277
+
278
+ /**
279
+ * Merge multiple configurations
280
+ * @param {Object} base - Base configuration
281
+ * @param {...Object} overrides - Override configurations
282
+ * @returns {Object} Merged configuration
283
+ */
284
+ mergeConfigs(base, ...overrides) {
285
+ const result = { ...base };
286
+
287
+ for (const override of overrides) {
288
+ for (const [key, value] of Object.entries(override)) {
289
+ if (value !== undefined && value !== null && value !== '') {
290
+ result[key] = value;
291
+ }
292
+ }
293
+ }
294
+
295
+ return result;
296
+ }
297
+
298
+ /**
299
+ * Check if a specific configuration is complete
300
+ * @param {string} schemaName - Schema name to check
301
+ * @returns {Promise<{complete: boolean, missing: string[]}>}
302
+ */
303
+ async isConfigured(schemaName) {
304
+ const config = await this.loadAll();
305
+ const validation = this.validateConfig(config, schemaName);
306
+
307
+ return {
308
+ complete: validation.valid,
309
+ missing: validation.missing
310
+ };
311
+ }
312
+
313
+ /**
314
+ * Get configuration for a specific workflow
315
+ * @param {string} workflowName - Workflow name
316
+ * @returns {Promise<Object>}
317
+ */
318
+ async getWorkflowConfig(workflowName) {
319
+ const config = await this.loadAll();
320
+ const prefix = workflowName.toUpperCase() + '_';
321
+
322
+ const workflowConfig = {};
323
+ for (const [key, value] of Object.entries(config)) {
324
+ if (key.startsWith(prefix) || key.startsWith(workflowName.toUpperCase())) {
325
+ workflowConfig[key] = value;
326
+ }
327
+ }
328
+
329
+ return workflowConfig;
330
+ }
331
+
332
+ /**
333
+ * Parse .env content into object
334
+ * @param {string} content - .env file content
335
+ * @returns {Object}
336
+ */
337
+ parseEnvContent(content) {
338
+ const result = {};
339
+ const lines = content.split('\n');
340
+
341
+ for (const line of lines) {
342
+ const trimmed = line.trim();
343
+
344
+ // Skip empty lines and comments
345
+ if (!trimmed || trimmed.startsWith('#')) {
346
+ continue;
347
+ }
348
+
349
+ const match = trimmed.match(/^([^=]+)=(.*)$/);
350
+ if (match) {
351
+ const key = match[1].trim();
352
+ let value = match[2].trim();
353
+
354
+ // Remove quotes if present
355
+ if ((value.startsWith('"') && value.endsWith('"')) ||
356
+ (value.startsWith("'") && value.endsWith("'"))) {
357
+ value = value.slice(1, -1);
358
+ }
359
+
360
+ result[key] = value;
361
+ }
362
+ }
363
+
364
+ return result;
365
+ }
366
+
367
+ /**
368
+ * Format object as .env content
369
+ * @param {Object} config - Configuration object
370
+ * @returns {string}
371
+ */
372
+ formatEnvContent(config) {
373
+ const lines = [];
374
+
375
+ // Group by prefix for better organization
376
+ const groups = {};
377
+ const noPrefix = [];
378
+
379
+ for (const [key, value] of Object.entries(config)) {
380
+ if (value === undefined || value === null) continue;
381
+
382
+ const prefixMatch = key.match(/^([A-Z]+)_/);
383
+ if (prefixMatch) {
384
+ const prefix = prefixMatch[1];
385
+ if (!groups[prefix]) groups[prefix] = [];
386
+ groups[prefix].push([key, value]);
387
+ } else {
388
+ noPrefix.push([key, value]);
389
+ }
390
+ }
391
+
392
+ // Format groups
393
+ for (const [prefix, entries] of Object.entries(groups)) {
394
+ lines.push(`# ${prefix} Configuration`);
395
+ for (const [key, value] of entries) {
396
+ lines.push(this.formatEnvLine(key, value));
397
+ }
398
+ lines.push('');
399
+ }
400
+
401
+ // Format ungrouped
402
+ if (noPrefix.length > 0) {
403
+ lines.push('# General Configuration');
404
+ for (const [key, value] of noPrefix) {
405
+ lines.push(this.formatEnvLine(key, value));
406
+ }
407
+ }
408
+
409
+ return lines.join('\n');
410
+ }
411
+
412
+ /**
413
+ * Format a single .env line
414
+ * @param {string} key - Key
415
+ * @param {any} value - Value
416
+ * @returns {string}
417
+ */
418
+ formatEnvLine(key, value) {
419
+ const stringValue = String(value);
420
+ const needsQuotes = stringValue.includes(' ') ||
421
+ stringValue.includes('#') ||
422
+ stringValue.includes('=');
423
+
424
+ return needsQuotes ? `${key}="${stringValue}"` : `${key}=${stringValue}`;
425
+ }
426
+
427
+ /**
428
+ * Delete a configuration key
429
+ * @param {string} key - Key to delete
430
+ * @returns {Promise<boolean>}
431
+ */
432
+ async deleteConfig(key) {
433
+ const config = await this.loadEnvFile();
434
+
435
+ if (config[key] !== undefined) {
436
+ delete config[key];
437
+ await this.saveEnvConfig(config, false);
438
+ this.configCache = null;
439
+ return true;
440
+ }
441
+
442
+ return false;
443
+ }
444
+
445
+ /**
446
+ * List all configuration keys
447
+ * @returns {Promise<string[]>}
448
+ */
449
+ async listConfigKeys() {
450
+ const config = await this.loadAll();
451
+ return Object.keys(config).sort();
452
+ }
453
+ }
454
+
455
+ // Singleton instance for convenience
456
+ let defaultInstance = null;
457
+
458
+ /**
459
+ * Get the default ConfigManager instance
460
+ * @param {string} [projectRoot] - Project root directory
461
+ * @returns {ConfigManager}
462
+ */
463
+ export function getConfigManager(projectRoot) {
464
+ if (!defaultInstance || (projectRoot && projectRoot !== defaultInstance.projectRoot)) {
465
+ defaultInstance = new ConfigManager(projectRoot);
466
+ }
467
+ return defaultInstance;
468
+ }
469
+
470
+ export default ConfigManager;