myaidev-method 0.2.23 → 0.2.24-2
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/.claude-plugin/plugin.json +251 -0
- package/PLUGIN_ARCHITECTURE.md +276 -0
- package/README.md +204 -0
- package/USER_GUIDE.md +436 -9
- package/bin/cli.js +370 -38
- package/dist/server/.tsbuildinfo +1 -1
- package/extension.json +174 -0
- package/hooks/hooks.json +221 -0
- package/marketplace.json +179 -0
- package/package.json +24 -7
- package/skills/content-verifier/SKILL.md +178 -0
- package/skills/content-writer/SKILL.md +151 -0
- package/skills/coolify-deployer/SKILL.md +207 -0
- package/skills/openstack-manager/SKILL.md +213 -0
- package/skills/security-auditor/SKILL.md +180 -0
- package/skills/security-tester/SKILL.md +171 -0
- package/skills/sparc-architect/SKILL.md +146 -0
- package/skills/sparc-coder/SKILL.md +136 -0
- package/skills/sparc-documenter/SKILL.md +195 -0
- package/skills/sparc-reviewer/SKILL.md +179 -0
- package/skills/sparc-tester/SKILL.md +156 -0
- package/skills/visual-generator/SKILL.md +147 -0
- package/skills/wordpress-publisher/SKILL.md +150 -0
- package/src/config/workflows.js +28 -44
- package/src/lib/ascii-banner.js +214 -0
- package/src/lib/config-manager.js +470 -0
- package/src/lib/content-coordinator.js +2562 -0
- package/src/lib/content-generator.js +427 -0
- package/src/lib/html-conversion-utils.js +843 -0
- package/src/lib/installation-detector.js +266 -0
- package/src/lib/seo-optimizer.js +515 -0
- package/src/lib/visual-config-utils.js +1 -1
- package/src/lib/visual-generation-utils.js +34 -14
- package/src/lib/wordpress-client.js +633 -0
- package/src/lib/workflow-installer.js +3 -3
- package/src/scripts/generate-visual-cli.js +39 -10
- package/src/scripts/html-conversion-cli.js +526 -0
- package/src/scripts/init/configure.js +436 -0
- package/src/scripts/init/install.js +460 -0
- package/src/scripts/ping.js +0 -1
- package/src/scripts/utils/file-utils.js +404 -0
- package/src/scripts/utils/logger.js +300 -0
- package/src/scripts/utils/write-content.js +293 -0
- package/src/templates/claude/agents/content-production-coordinator.md +689 -15
- package/src/templates/claude/agents/visual-content-generator.md +129 -4
- package/src/templates/claude/commands/myai-content-enrichment.md +227 -0
- package/src/templates/claude/commands/myai-content-writer.md +48 -37
- package/src/templates/claude/commands/myai-convert-html.md +186 -0
- package/src/templates/claude/commands/myai-coordinate-content.md +347 -11
- package/src/templates/diagrams/architecture.d2 +52 -0
- package/src/templates/diagrams/flowchart.d2 +42 -0
- package/src/templates/diagrams/sequence.d2 +47 -0
- package/src/templates/docs/content-creation-guide.md +164 -0
- package/src/templates/docs/deployment-guide.md +336 -0
- package/src/templates/docs/visual-generation-guide.md +248 -0
- package/src/templates/docs/wordpress-publishing-guide.md +208 -0
- package/src/templates/infographics/comparison-table.html +347 -0
- package/src/templates/infographics/data-chart.html +268 -0
- package/src/templates/infographics/process-flow.html +365 -0
- /package/src/scripts/{wordpress-health-check.js → wordpress/wordpress-health-check.js} +0 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Write Content CLI
|
|
5
|
+
* Command-line wrapper for content generation
|
|
6
|
+
* Usage: node write-content.js "Topic" [options]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ContentGenerator } from '../../lib/content-generator.js';
|
|
10
|
+
import { SEOOptimizer } from '../../lib/seo-optimizer.js';
|
|
11
|
+
import { logger, formatTable } from './logger.js';
|
|
12
|
+
import fs from 'fs-extra';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parse command line arguments
|
|
17
|
+
* @param {string[]} args - Command line arguments
|
|
18
|
+
* @returns {Object} Parsed options
|
|
19
|
+
*/
|
|
20
|
+
function parseArgs(args) {
|
|
21
|
+
const options = {
|
|
22
|
+
topic: '',
|
|
23
|
+
contentType: 'blog-post',
|
|
24
|
+
wordCount: 1500,
|
|
25
|
+
tone: 'professional',
|
|
26
|
+
keywords: [],
|
|
27
|
+
outputDir: './content',
|
|
28
|
+
outputFile: '',
|
|
29
|
+
analyze: false,
|
|
30
|
+
help: false
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
let i = 0;
|
|
34
|
+
while (i < args.length) {
|
|
35
|
+
const arg = args[i];
|
|
36
|
+
|
|
37
|
+
if (arg === '--help' || arg === '-h') {
|
|
38
|
+
options.help = true;
|
|
39
|
+
} else if (arg === '--type' || arg === '-t') {
|
|
40
|
+
options.contentType = args[++i];
|
|
41
|
+
} else if (arg === '--word-count' || arg === '-w') {
|
|
42
|
+
options.wordCount = parseInt(args[++i], 10);
|
|
43
|
+
} else if (arg === '--tone') {
|
|
44
|
+
options.tone = args[++i];
|
|
45
|
+
} else if (arg === '--keywords' || arg === '-k') {
|
|
46
|
+
options.keywords = args[++i].split(',').map(k => k.trim());
|
|
47
|
+
} else if (arg === '--output' || arg === '-o') {
|
|
48
|
+
options.outputFile = args[++i];
|
|
49
|
+
} else if (arg === '--output-dir') {
|
|
50
|
+
options.outputDir = args[++i];
|
|
51
|
+
} else if (arg === '--analyze' || arg === '-a') {
|
|
52
|
+
options.analyze = true;
|
|
53
|
+
} else if (!arg.startsWith('-')) {
|
|
54
|
+
options.topic = arg;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
i++;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return options;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Show help message
|
|
65
|
+
*/
|
|
66
|
+
function showHelp() {
|
|
67
|
+
console.log(`
|
|
68
|
+
Write Content - Content Generation CLI
|
|
69
|
+
|
|
70
|
+
Usage: node write-content.js "Topic" [options]
|
|
71
|
+
|
|
72
|
+
Options:
|
|
73
|
+
-h, --help Show this help message
|
|
74
|
+
-t, --type <type> Content type (blog-post, tutorial, how-to, listicle, product-review, comparison)
|
|
75
|
+
-w, --word-count <num> Target word count (default: 1500)
|
|
76
|
+
--tone <tone> Writing tone (professional, conversational, technical, casual, authoritative)
|
|
77
|
+
-k, --keywords <list> Comma-separated keywords for SEO
|
|
78
|
+
-o, --output <file> Output filename (auto-generated if not specified)
|
|
79
|
+
--output-dir <dir> Output directory (default: ./content)
|
|
80
|
+
-a, --analyze Analyze content for SEO after generation
|
|
81
|
+
|
|
82
|
+
Examples:
|
|
83
|
+
node write-content.js "How to Train a Puppy" --type tutorial --tone conversational
|
|
84
|
+
node write-content.js "Best Laptops 2024" --type listicle --keywords "laptops,tech,reviews"
|
|
85
|
+
node write-content.js "React vs Vue" --type comparison --word-count 2500 --analyze
|
|
86
|
+
`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Generate content specification for the content-writer agent
|
|
91
|
+
* @param {Object} options - Generation options
|
|
92
|
+
*/
|
|
93
|
+
async function generateContentSpec(options) {
|
|
94
|
+
const generator = new ContentGenerator({
|
|
95
|
+
outputDir: options.outputDir,
|
|
96
|
+
tone: options.tone,
|
|
97
|
+
wordCount: options.wordCount
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
await generator.initialize();
|
|
101
|
+
|
|
102
|
+
// Validate options
|
|
103
|
+
const validation = generator.validateOptions(options);
|
|
104
|
+
if (!validation.valid) {
|
|
105
|
+
for (const error of validation.errors) {
|
|
106
|
+
logger.error(error);
|
|
107
|
+
}
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Generate content specification
|
|
112
|
+
const spec = generator.generateContentSpec(options.topic, {
|
|
113
|
+
contentType: options.contentType,
|
|
114
|
+
wordCount: options.wordCount,
|
|
115
|
+
tone: options.tone,
|
|
116
|
+
keywords: options.keywords
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
logger.header('Content Specification');
|
|
120
|
+
logger.log(`Topic: ${spec.topic}`);
|
|
121
|
+
logger.log(`Type: ${spec.contentType}`);
|
|
122
|
+
logger.log(`Word Count Target: ${spec.wordCount}`);
|
|
123
|
+
logger.log(`Tone: ${spec.tone}`);
|
|
124
|
+
logger.log(`Keywords: ${spec.keywords.length > 0 ? spec.keywords.join(', ') : 'None specified'}`);
|
|
125
|
+
logger.blank();
|
|
126
|
+
|
|
127
|
+
logger.section('Required Sections');
|
|
128
|
+
for (const section of spec.sections) {
|
|
129
|
+
logger.log(` • ${section}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
logger.section('Frontmatter Fields');
|
|
133
|
+
for (const field of spec.requiredFrontmatter) {
|
|
134
|
+
logger.log(` • ${field}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Generate filename
|
|
138
|
+
const filename = options.outputFile || generator.generateFilename(options.topic);
|
|
139
|
+
const outputPath = path.join(options.outputDir, filename);
|
|
140
|
+
|
|
141
|
+
logger.section('Output');
|
|
142
|
+
logger.log(`Filename: ${filename}`);
|
|
143
|
+
logger.log(`Path: ${outputPath}`);
|
|
144
|
+
logger.blank();
|
|
145
|
+
|
|
146
|
+
// Generate frontmatter template
|
|
147
|
+
const frontmatterData = {
|
|
148
|
+
title: options.topic,
|
|
149
|
+
description: '',
|
|
150
|
+
date: new Date().toISOString().split('T')[0],
|
|
151
|
+
author: '',
|
|
152
|
+
categories: [],
|
|
153
|
+
tags: options.keywords,
|
|
154
|
+
status: 'draft'
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const frontmatter = generator.generateFrontmatter(frontmatterData);
|
|
158
|
+
|
|
159
|
+
// Create template file
|
|
160
|
+
const templateContent = `${frontmatter}
|
|
161
|
+
# ${options.topic}
|
|
162
|
+
|
|
163
|
+
<!-- Introduction -->
|
|
164
|
+
|
|
165
|
+
## Overview
|
|
166
|
+
|
|
167
|
+
[Write introduction here]
|
|
168
|
+
|
|
169
|
+
${spec.sections.slice(1).map(section => `
|
|
170
|
+
## ${section.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}
|
|
171
|
+
|
|
172
|
+
[Write ${section} content here]
|
|
173
|
+
`).join('\n')}
|
|
174
|
+
|
|
175
|
+
<!-- Call to Action -->
|
|
176
|
+
|
|
177
|
+
## Conclusion
|
|
178
|
+
|
|
179
|
+
[Write conclusion here]
|
|
180
|
+
`;
|
|
181
|
+
|
|
182
|
+
await fs.ensureDir(options.outputDir);
|
|
183
|
+
await fs.writeFile(outputPath, templateContent, 'utf-8');
|
|
184
|
+
|
|
185
|
+
logger.success(`Template created: ${outputPath}`);
|
|
186
|
+
logger.blank();
|
|
187
|
+
logger.info('Use the content-writer agent to generate full content:');
|
|
188
|
+
logger.log(` /myai-content-writer "${options.topic}" --type ${options.contentType}`);
|
|
189
|
+
|
|
190
|
+
return { spec, outputPath, templateContent };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Analyze existing content file
|
|
195
|
+
* @param {string} filePath - Path to content file
|
|
196
|
+
* @param {string[]} keywords - Keywords to check
|
|
197
|
+
*/
|
|
198
|
+
async function analyzeContent(filePath, keywords) {
|
|
199
|
+
const optimizer = new SEOOptimizer();
|
|
200
|
+
|
|
201
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
202
|
+
|
|
203
|
+
// Extract title from frontmatter or first heading
|
|
204
|
+
const titleMatch = content.match(/^title:\s*(.+)$/m) || content.match(/^#\s+(.+)$/m);
|
|
205
|
+
const title = titleMatch ? titleMatch[1].trim() : '';
|
|
206
|
+
|
|
207
|
+
logger.header('SEO Analysis');
|
|
208
|
+
logger.log(`File: ${filePath}`);
|
|
209
|
+
logger.log(`Title: ${title || 'Not found'}`);
|
|
210
|
+
logger.blank();
|
|
211
|
+
|
|
212
|
+
const analysis = optimizer.analyzeSEO(content, keywords, title);
|
|
213
|
+
|
|
214
|
+
// Score display
|
|
215
|
+
const scoreColor = analysis.score >= 80 ? 'green' : analysis.score >= 60 ? 'yellow' : 'red';
|
|
216
|
+
logger.log(`SEO Score: ${analysis.score}/100 (Grade: ${analysis.grade})`);
|
|
217
|
+
logger.log(`Word Count: ${analysis.wordCount}`);
|
|
218
|
+
if (analysis.keywordDensity !== null) {
|
|
219
|
+
logger.log(`Keyword Density: ${analysis.keywordDensity}%`);
|
|
220
|
+
}
|
|
221
|
+
logger.blank();
|
|
222
|
+
|
|
223
|
+
// Issues
|
|
224
|
+
if (analysis.issues.length > 0) {
|
|
225
|
+
logger.section('Issues');
|
|
226
|
+
for (const issue of analysis.issues) {
|
|
227
|
+
logger.error(issue);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Recommendations
|
|
232
|
+
if (analysis.recommendations.length > 0) {
|
|
233
|
+
logger.section('Recommendations');
|
|
234
|
+
for (const rec of analysis.recommendations) {
|
|
235
|
+
logger.warn(rec);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Meta description
|
|
240
|
+
logger.section('Generated Meta Description');
|
|
241
|
+
const metaDesc = optimizer.generateMetaDescription(content);
|
|
242
|
+
logger.log(metaDesc);
|
|
243
|
+
logger.log(`Length: ${metaDesc.length} characters`);
|
|
244
|
+
|
|
245
|
+
// Slug
|
|
246
|
+
if (title) {
|
|
247
|
+
logger.section('Generated Slug');
|
|
248
|
+
logger.log(optimizer.generateSlug(title));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return analysis;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Main function
|
|
256
|
+
*/
|
|
257
|
+
async function main() {
|
|
258
|
+
const args = process.argv.slice(2);
|
|
259
|
+
const options = parseArgs(args);
|
|
260
|
+
|
|
261
|
+
if (options.help) {
|
|
262
|
+
showHelp();
|
|
263
|
+
process.exit(0);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (!options.topic && !options.analyze) {
|
|
267
|
+
logger.error('Topic is required. Use --help for usage information.');
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
if (options.analyze && options.topic) {
|
|
273
|
+
// If topic looks like a file path, analyze it
|
|
274
|
+
if (options.topic.endsWith('.md') || options.topic.includes('/')) {
|
|
275
|
+
await analyzeContent(options.topic, options.keywords);
|
|
276
|
+
} else {
|
|
277
|
+
// Generate spec and analyze
|
|
278
|
+
const { outputPath } = await generateContentSpec(options);
|
|
279
|
+
await analyzeContent(outputPath, options.keywords);
|
|
280
|
+
}
|
|
281
|
+
} else if (options.analyze && !options.topic) {
|
|
282
|
+
logger.error('Please provide a file path to analyze.');
|
|
283
|
+
process.exit(1);
|
|
284
|
+
} else {
|
|
285
|
+
await generateContentSpec(options);
|
|
286
|
+
}
|
|
287
|
+
} catch (error) {
|
|
288
|
+
logger.error(`Error: ${error.message}`);
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
main();
|