myaidev-method 0.0.7 → 0.0.8
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/CLAUDE.md +52 -0
- package/.claude/agents/content-writer.md +155 -0
- package/.claude/commands/myai-configure.md +44 -0
- package/.claude/commands/myai-content-writer.md +78 -0
- package/.claude/commands/myai-wordpress-publish.md +120 -0
- package/.claude/mcp/gutenberg-converter.js +447 -0
- package/.claude/mcp/mcp-config.json +101 -0
- package/.claude/mcp/wordpress-server-simple.js +182 -0
- package/.claude/mcp/wordpress-server.js +1277 -0
- package/.claude/settings.local.json +12 -0
- package/README.md +4 -4
- package/bin/cli.js +17 -22
- package/dist/mcp/gutenberg-converter.js +447 -0
- package/dist/mcp/mcp-config.json +101 -0
- package/dist/mcp/wordpress-server-simple.js +182 -0
- package/dist/mcp/wordpress-server.js +1277 -0
- package/package.json +16 -3
- package/src/mcp/health-check.js +190 -0
- package/src/mcp/mcp-launcher.js +237 -0
- package/src/templates/claude/agents/wordpress-admin.md +228 -271
- package/src/templates/claude/commands/myai-configure.md +10 -74
- package/src/templates/claude/commands/myai-wordpress-publish.md +16 -8
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# MyAIDev Method
|
|
2
2
|
|
|
3
|
-
> **🚀 The easiest way to supercharge your AI CLI with professional agents and
|
|
3
|
+
> **🚀 The easiest way to supercharge your AI CLI with professional agents and get real work done!**
|
|
4
4
|
|
|
5
|
-
A comprehensive package for AI CLI tools (Claude Code, Gemini CLI, Codex CLI) that provides custom subagents and MCP integrations for enhanced development workflows. **Zero
|
|
5
|
+
A comprehensive package for AI CLI tools (Claude Code, Gemini CLI, Codex CLI) that provides custom subagents and MCP integrations for enhanced development workflows. **Zero code required** - just run one command and start creating professional content!
|
|
6
6
|
|
|
7
7
|
**✨ What makes this special:**
|
|
8
8
|
- **Instant setup**: One `npx` command and you're ready
|
|
9
9
|
- **Professional agents**: Content writer and WordPress admin out-of-the-box
|
|
10
|
-
- **Claude Code native**: Follows official standards for maximum compatibility
|
|
11
|
-
- **No dependencies**: Works standalone, WordPress integration is optional
|
|
10
|
+
- **Claude Code native**: Follows official standards for maximum compatibility, with Gemini and OpenAI Codex CLI too.
|
|
11
|
+
- **No dependencies**: Works standalone, leverages MCPs for WordPress, Notion, Google Workspace integration is optional
|
|
12
12
|
|
|
13
13
|
## 📋 Table of Contents
|
|
14
14
|
|
package/bin/cli.js
CHANGED
|
@@ -99,10 +99,12 @@ async function setupClaude(projectDir) {
|
|
|
99
99
|
const claudeDir = path.join(projectDir, '.claude');
|
|
100
100
|
const commandsDir = path.join(claudeDir, 'commands');
|
|
101
101
|
const agentsDir = path.join(claudeDir, 'agents');
|
|
102
|
+
const mcpDir = path.join(claudeDir, 'mcp');
|
|
102
103
|
|
|
103
104
|
// Ensure directories exist
|
|
104
105
|
await fs.ensureDir(commandsDir);
|
|
105
106
|
await fs.ensureDir(agentsDir);
|
|
107
|
+
await fs.ensureDir(mcpDir);
|
|
106
108
|
|
|
107
109
|
// Copy command markdown files
|
|
108
110
|
const templateCommandsDir = path.join(__dirname, '..', 'src', 'templates', 'claude', 'commands');
|
|
@@ -132,6 +134,20 @@ async function setupClaude(projectDir) {
|
|
|
132
134
|
}
|
|
133
135
|
}
|
|
134
136
|
|
|
137
|
+
// Copy MCP server files
|
|
138
|
+
const templateMcpDir = path.join(__dirname, '..', '.claude', 'mcp');
|
|
139
|
+
if (await fs.pathExists(templateMcpDir)) {
|
|
140
|
+
const mcpFiles = await fs.readdir(templateMcpDir);
|
|
141
|
+
for (const file of mcpFiles) {
|
|
142
|
+
if (file.endsWith('.js') || file.endsWith('.json')) {
|
|
143
|
+
await fs.copy(
|
|
144
|
+
path.join(templateMcpDir, file),
|
|
145
|
+
path.join(mcpDir, file)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
135
151
|
// Create CLAUDE.md configuration file
|
|
136
152
|
const claudeMd = `# Claude Code Configuration
|
|
137
153
|
|
|
@@ -197,28 +213,7 @@ DEFAULT_TONE=professional
|
|
|
197
213
|
|
|
198
214
|
await fs.writeFile(path.join(projectDir, '.env.example'), envExample);
|
|
199
215
|
|
|
200
|
-
//
|
|
201
|
-
const mcpDir = path.join(claudeDir, 'mcp');
|
|
202
|
-
await fs.ensureDir(mcpDir);
|
|
203
|
-
|
|
204
|
-
const wordpressMcpServer = path.join(__dirname, '..', '.claude', 'mcp', 'wordpress-server.js');
|
|
205
|
-
if (await fs.pathExists(wordpressMcpServer)) {
|
|
206
|
-
await fs.copy(wordpressMcpServer, path.join(mcpDir, 'wordpress-server.js'));
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Copy Gutenberg converter
|
|
210
|
-
const gutenbergConverter = path.join(__dirname, '..', '.claude', 'mcp', 'gutenberg-converter.js');
|
|
211
|
-
if (await fs.pathExists(gutenbergConverter)) {
|
|
212
|
-
await fs.copy(gutenbergConverter, path.join(mcpDir, 'gutenberg-converter.js'));
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Copy scripts directory
|
|
216
|
-
const scriptsTemplateDir = path.join(__dirname, '..', 'src', 'templates', 'scripts');
|
|
217
|
-
const scriptsDestDir = path.join(projectDir, 'scripts');
|
|
218
|
-
|
|
219
|
-
if (await fs.pathExists(scriptsTemplateDir)) {
|
|
220
|
-
await fs.copy(scriptsTemplateDir, scriptsDestDir);
|
|
221
|
-
}
|
|
216
|
+
// Note: MCP integration disabled for now - using native tools for WordPress REST API
|
|
222
217
|
|
|
223
218
|
// Copy USER_GUIDE.md - Essential for users to understand customization
|
|
224
219
|
const userGuide = path.join(__dirname, '..', 'USER_GUIDE.md');
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gutenberg Block Converter
|
|
3
|
+
* Converts HTML/Markdown content to WordPress Gutenberg block format
|
|
4
|
+
* Following WordPress Block Editor Handbook specifications
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export class GutenbergConverter {
|
|
8
|
+
/**
|
|
9
|
+
* Convert HTML content to Gutenberg blocks
|
|
10
|
+
* @param {string} html - HTML content to convert
|
|
11
|
+
* @returns {string} - Gutenberg block formatted content
|
|
12
|
+
*/
|
|
13
|
+
static htmlToGutenberg(html) {
|
|
14
|
+
// Parse HTML and convert to blocks
|
|
15
|
+
let gutenbergContent = '';
|
|
16
|
+
|
|
17
|
+
// Split content into sections for processing
|
|
18
|
+
const sections = this.parseHTMLSections(html);
|
|
19
|
+
|
|
20
|
+
sections.forEach(section => {
|
|
21
|
+
const block = this.createBlock(section);
|
|
22
|
+
if (block) {
|
|
23
|
+
gutenbergContent += block + '\n\n';
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return gutenbergContent.trim();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parse HTML into sections for block conversion
|
|
32
|
+
*/
|
|
33
|
+
static parseHTMLSections(html) {
|
|
34
|
+
const sections = [];
|
|
35
|
+
|
|
36
|
+
// Remove excess whitespace and normalize
|
|
37
|
+
const normalizedHtml = html.replace(/\n\s*\n/g, '\n').trim();
|
|
38
|
+
|
|
39
|
+
// Regular expressions for different HTML elements
|
|
40
|
+
const patterns = {
|
|
41
|
+
heading: /<h([1-6])(?:\s[^>]*)?>(.+?)<\/h\1>/gi,
|
|
42
|
+
paragraph: /<p(?:\s[^>]*)?>(.+?)<\/p>/gi,
|
|
43
|
+
list: /<(ul|ol)(?:\s[^>]*)?>(.+?)<\/\1>/gis,
|
|
44
|
+
blockquote: /<blockquote(?:\s[^>]*)?>(.+?)<\/blockquote>/gis,
|
|
45
|
+
pre: /<pre(?:\s[^>]*)?><code(?:\s[^>]*)?>(.+?)<\/code><\/pre>/gis,
|
|
46
|
+
image: /<img\s+([^>]+)>/gi,
|
|
47
|
+
hr: /<hr(?:\s[^>]*)?>/gi
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Process the HTML string sequentially
|
|
51
|
+
let lastIndex = 0;
|
|
52
|
+
const processedParts = [];
|
|
53
|
+
|
|
54
|
+
// Create a combined pattern to find all blocks
|
|
55
|
+
const combinedPattern = new RegExp(
|
|
56
|
+
'(' +
|
|
57
|
+
'<h[1-6](?:\\s[^>]*)?>.*?</h[1-6]>|' +
|
|
58
|
+
'<p(?:\\s[^>]*)?>.*?</p>|' +
|
|
59
|
+
'<(?:ul|ol)(?:\\s[^>]*)?>.*?</(?:ul|ol)>|' +
|
|
60
|
+
'<blockquote(?:\\s[^>]*)?>.*?</blockquote>|' +
|
|
61
|
+
'<pre(?:\\s[^>]*)?><code(?:\\s[^>]*)?>.*?</code></pre>|' +
|
|
62
|
+
'<img\\s+[^>]+>|' +
|
|
63
|
+
'<hr(?:\\s[^>]*)?>' +
|
|
64
|
+
')',
|
|
65
|
+
'gis'
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
let match;
|
|
69
|
+
while ((match = combinedPattern.exec(normalizedHtml)) !== null) {
|
|
70
|
+
// Add any text between matches as a paragraph
|
|
71
|
+
if (match.index > lastIndex) {
|
|
72
|
+
const text = normalizedHtml.substring(lastIndex, match.index).trim();
|
|
73
|
+
if (text && !text.match(/^\s*$/)) {
|
|
74
|
+
sections.push({ type: 'paragraph', content: this.stripTags(text) });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const fullMatch = match[0];
|
|
79
|
+
|
|
80
|
+
// Determine block type and extract content
|
|
81
|
+
if (fullMatch.match(/<h([1-6])/i)) {
|
|
82
|
+
const level = fullMatch.match(/<h([1-6])/i)[1];
|
|
83
|
+
const content = fullMatch.replace(/<\/?h[1-6](?:\s[^>]*)?>/gi, '');
|
|
84
|
+
sections.push({ type: 'heading', level: parseInt(level), content: this.stripTags(content) });
|
|
85
|
+
}
|
|
86
|
+
else if (fullMatch.match(/<p(?:\s|>)/i)) {
|
|
87
|
+
const content = fullMatch.replace(/<\/?p(?:\s[^>]*)?>/gi, '');
|
|
88
|
+
sections.push({ type: 'paragraph', content: this.stripTags(content) });
|
|
89
|
+
}
|
|
90
|
+
else if (fullMatch.match(/<(ul|ol)/i)) {
|
|
91
|
+
const listType = fullMatch.match(/<(ul|ol)/i)[1];
|
|
92
|
+
const items = this.parseListItems(fullMatch);
|
|
93
|
+
sections.push({ type: 'list', ordered: listType === 'ol', items });
|
|
94
|
+
}
|
|
95
|
+
else if (fullMatch.match(/<blockquote/i)) {
|
|
96
|
+
const content = fullMatch.replace(/<\/?blockquote(?:\s[^>]*)?>/gi, '');
|
|
97
|
+
sections.push({ type: 'quote', content: this.stripTags(content) });
|
|
98
|
+
}
|
|
99
|
+
else if (fullMatch.match(/<pre/i)) {
|
|
100
|
+
const content = fullMatch.replace(/<\/?(?:pre|code)(?:\s[^>]*)?>/gi, '');
|
|
101
|
+
sections.push({ type: 'code', content: this.decodeHtml(content) });
|
|
102
|
+
}
|
|
103
|
+
else if (fullMatch.match(/<img/i)) {
|
|
104
|
+
const attrs = this.parseImageAttributes(fullMatch);
|
|
105
|
+
sections.push({ type: 'image', ...attrs });
|
|
106
|
+
}
|
|
107
|
+
else if (fullMatch.match(/<hr/i)) {
|
|
108
|
+
sections.push({ type: 'separator' });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
lastIndex = match.index + fullMatch.length;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Add any remaining content
|
|
115
|
+
if (lastIndex < normalizedHtml.length) {
|
|
116
|
+
const text = normalizedHtml.substring(lastIndex).trim();
|
|
117
|
+
if (text && !text.match(/^\s*$/)) {
|
|
118
|
+
sections.push({ type: 'paragraph', content: this.stripTags(text) });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return sections;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Parse list items from HTML list
|
|
127
|
+
*/
|
|
128
|
+
static parseListItems(listHtml) {
|
|
129
|
+
const items = [];
|
|
130
|
+
const itemPattern = /<li(?:\s[^>]*)?>(.+?)<\/li>/gis;
|
|
131
|
+
let match;
|
|
132
|
+
|
|
133
|
+
while ((match = itemPattern.exec(listHtml)) !== null) {
|
|
134
|
+
items.push(this.stripTags(match[1].trim()));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return items;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Parse image attributes from img tag
|
|
142
|
+
*/
|
|
143
|
+
static parseImageAttributes(imgTag) {
|
|
144
|
+
const attrs = {};
|
|
145
|
+
|
|
146
|
+
// Extract src
|
|
147
|
+
const srcMatch = imgTag.match(/src=["']([^"']+)["']/i);
|
|
148
|
+
if (srcMatch) attrs.url = srcMatch[1];
|
|
149
|
+
|
|
150
|
+
// Extract alt text
|
|
151
|
+
const altMatch = imgTag.match(/alt=["']([^"']+)["']/i);
|
|
152
|
+
if (altMatch) attrs.alt = altMatch[1];
|
|
153
|
+
|
|
154
|
+
// Extract title
|
|
155
|
+
const titleMatch = imgTag.match(/title=["']([^"']+)["']/i);
|
|
156
|
+
if (titleMatch) attrs.caption = titleMatch[1];
|
|
157
|
+
|
|
158
|
+
return attrs;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Create a Gutenberg block from a section
|
|
163
|
+
*/
|
|
164
|
+
static createBlock(section) {
|
|
165
|
+
switch (section.type) {
|
|
166
|
+
case 'heading':
|
|
167
|
+
return this.createHeadingBlock(section.level, section.content);
|
|
168
|
+
|
|
169
|
+
case 'paragraph':
|
|
170
|
+
return this.createParagraphBlock(section.content);
|
|
171
|
+
|
|
172
|
+
case 'list':
|
|
173
|
+
return this.createListBlock(section.items, section.ordered);
|
|
174
|
+
|
|
175
|
+
case 'quote':
|
|
176
|
+
return this.createQuoteBlock(section.content);
|
|
177
|
+
|
|
178
|
+
case 'code':
|
|
179
|
+
return this.createCodeBlock(section.content);
|
|
180
|
+
|
|
181
|
+
case 'image':
|
|
182
|
+
return this.createImageBlock(section.url, section.alt, section.caption);
|
|
183
|
+
|
|
184
|
+
case 'separator':
|
|
185
|
+
return this.createSeparatorBlock();
|
|
186
|
+
|
|
187
|
+
default:
|
|
188
|
+
return this.createParagraphBlock(section.content || '');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Create heading block
|
|
194
|
+
*/
|
|
195
|
+
static createHeadingBlock(level, content) {
|
|
196
|
+
return `<!-- wp:heading {"level":${level}} -->
|
|
197
|
+
<h${level} class="wp-block-heading">${this.escapeHtml(content)}</h${level}>
|
|
198
|
+
<!-- /wp:heading -->`;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Create paragraph block
|
|
203
|
+
*/
|
|
204
|
+
static createParagraphBlock(content) {
|
|
205
|
+
// Handle empty paragraphs
|
|
206
|
+
if (!content || content.trim() === '') {
|
|
207
|
+
return '';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return `<!-- wp:paragraph -->
|
|
211
|
+
<p>${this.escapeHtml(content)}</p>
|
|
212
|
+
<!-- /wp:paragraph -->`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Create list block
|
|
217
|
+
*/
|
|
218
|
+
static createListBlock(items, ordered = false) {
|
|
219
|
+
const tag = ordered ? 'ol' : 'ul';
|
|
220
|
+
const blockName = ordered ? 'list' : 'list';
|
|
221
|
+
const listItems = items.map(item => `<li>${this.escapeHtml(item)}</li>`).join('\n');
|
|
222
|
+
|
|
223
|
+
const attributes = ordered ? ' {"ordered":true}' : '';
|
|
224
|
+
|
|
225
|
+
return `<!-- wp:list${attributes} -->
|
|
226
|
+
<${tag} class="wp-block-list">${listItems}</${tag}>
|
|
227
|
+
<!-- /wp:list -->`;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Create quote block
|
|
232
|
+
*/
|
|
233
|
+
static createQuoteBlock(content) {
|
|
234
|
+
return `<!-- wp:quote -->
|
|
235
|
+
<blockquote class="wp-block-quote">
|
|
236
|
+
<p>${this.escapeHtml(content)}</p>
|
|
237
|
+
</blockquote>
|
|
238
|
+
<!-- /wp:quote -->`;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Create code block
|
|
243
|
+
*/
|
|
244
|
+
static createCodeBlock(code) {
|
|
245
|
+
// Escape the code content for HTML
|
|
246
|
+
const escapedCode = this.escapeHtml(code);
|
|
247
|
+
|
|
248
|
+
return `<!-- wp:code -->
|
|
249
|
+
<pre class="wp-block-code"><code>${escapedCode}</code></pre>
|
|
250
|
+
<!-- /wp:code -->`;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Create image block
|
|
255
|
+
*/
|
|
256
|
+
static createImageBlock(url, alt = '', caption = '') {
|
|
257
|
+
let attributes = {};
|
|
258
|
+
if (alt) attributes.alt = alt;
|
|
259
|
+
|
|
260
|
+
const attributesJson = Object.keys(attributes).length > 0
|
|
261
|
+
? ' ' + JSON.stringify(attributes)
|
|
262
|
+
: '';
|
|
263
|
+
|
|
264
|
+
let imageHtml = `<!-- wp:image${attributesJson} -->
|
|
265
|
+
<figure class="wp-block-image"><img src="${url}"${alt ? ` alt="${this.escapeHtml(alt)}"` : ''}/>`;
|
|
266
|
+
|
|
267
|
+
if (caption) {
|
|
268
|
+
imageHtml += `<figcaption class="wp-element-caption">${this.escapeHtml(caption)}</figcaption>`;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
imageHtml += `</figure>
|
|
272
|
+
<!-- /wp:image -->`;
|
|
273
|
+
|
|
274
|
+
return imageHtml;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Create separator block
|
|
279
|
+
*/
|
|
280
|
+
static createSeparatorBlock() {
|
|
281
|
+
return `<!-- wp:separator -->
|
|
282
|
+
<hr class="wp-block-separator has-alpha-channel-opacity"/>
|
|
283
|
+
<!-- /wp:separator -->`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Create columns block for advanced layouts
|
|
288
|
+
*/
|
|
289
|
+
static createColumnsBlock(columns) {
|
|
290
|
+
const columnCount = columns.length;
|
|
291
|
+
let columnsHtml = `<!-- wp:columns {"columns":${columnCount}} -->\n<div class="wp-block-columns">`;
|
|
292
|
+
|
|
293
|
+
columns.forEach(column => {
|
|
294
|
+
columnsHtml += `\n<!-- wp:column -->\n<div class="wp-block-column">`;
|
|
295
|
+
columnsHtml += `\n${column}`;
|
|
296
|
+
columnsHtml += `\n</div>\n<!-- /wp:column -->`;
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
columnsHtml += `\n</div>\n<!-- /wp:columns -->`;
|
|
300
|
+
return columnsHtml;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Create button block
|
|
305
|
+
*/
|
|
306
|
+
static createButtonBlock(text, url = '#', align = 'none') {
|
|
307
|
+
return `<!-- wp:buttons {"layout":{"type":"flex","justifyContent":"${align}"}} -->
|
|
308
|
+
<div class="wp-block-buttons">
|
|
309
|
+
<!-- wp:button -->
|
|
310
|
+
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="${url}">${this.escapeHtml(text)}</a></div>
|
|
311
|
+
<!-- /wp:button -->
|
|
312
|
+
</div>
|
|
313
|
+
<!-- /wp:buttons -->`;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Create table block
|
|
318
|
+
*/
|
|
319
|
+
static createTableBlock(headers, rows) {
|
|
320
|
+
let tableHtml = `<!-- wp:table -->
|
|
321
|
+
<figure class="wp-block-table"><table class="wp-block-table">`;
|
|
322
|
+
|
|
323
|
+
// Add headers
|
|
324
|
+
if (headers && headers.length > 0) {
|
|
325
|
+
tableHtml += '\n<thead>\n<tr>';
|
|
326
|
+
headers.forEach(header => {
|
|
327
|
+
tableHtml += `<th>${this.escapeHtml(header)}</th>`;
|
|
328
|
+
});
|
|
329
|
+
tableHtml += '</tr>\n</thead>';
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Add rows
|
|
333
|
+
tableHtml += '\n<tbody>';
|
|
334
|
+
rows.forEach(row => {
|
|
335
|
+
tableHtml += '\n<tr>';
|
|
336
|
+
row.forEach(cell => {
|
|
337
|
+
tableHtml += `<td>${this.escapeHtml(cell)}</td>`;
|
|
338
|
+
});
|
|
339
|
+
tableHtml += '</tr>';
|
|
340
|
+
});
|
|
341
|
+
tableHtml += '\n</tbody>';
|
|
342
|
+
|
|
343
|
+
tableHtml += `\n</table></figure>
|
|
344
|
+
<!-- /wp:table -->`;
|
|
345
|
+
|
|
346
|
+
return tableHtml;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Utility: Strip HTML tags from text
|
|
351
|
+
*/
|
|
352
|
+
static stripTags(text) {
|
|
353
|
+
return text.replace(/<[^>]+>/g, '').trim();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Utility: Escape HTML special characters
|
|
358
|
+
*/
|
|
359
|
+
static escapeHtml(text) {
|
|
360
|
+
const map = {
|
|
361
|
+
'&': '&',
|
|
362
|
+
'<': '<',
|
|
363
|
+
'>': '>',
|
|
364
|
+
'"': '"',
|
|
365
|
+
"'": ''',
|
|
366
|
+
"/": '/'
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
return text.replace(/[&<>"'/]/g, char => map[char]);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Utility: Decode HTML entities
|
|
374
|
+
*/
|
|
375
|
+
static decodeHtml(text) {
|
|
376
|
+
const entities = {
|
|
377
|
+
'&': '&',
|
|
378
|
+
'<': '<',
|
|
379
|
+
'>': '>',
|
|
380
|
+
'"': '"',
|
|
381
|
+
''': "'",
|
|
382
|
+
'/': '/',
|
|
383
|
+
''': "'",
|
|
384
|
+
' ': ' '
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
return text.replace(/&[#a-z0-9]+;/gi, entity => entities[entity] || entity);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Convert markdown to Gutenberg blocks (bonus feature)
|
|
392
|
+
*/
|
|
393
|
+
static markdownToGutenberg(markdown) {
|
|
394
|
+
// First convert markdown to HTML (simplified version)
|
|
395
|
+
let html = markdown
|
|
396
|
+
// Headers
|
|
397
|
+
.replace(/^### (.+)$/gm, '<h3>$1</h3>')
|
|
398
|
+
.replace(/^## (.+)$/gm, '<h2>$1</h2>')
|
|
399
|
+
.replace(/^# (.+)$/gm, '<h1>$1</h1>')
|
|
400
|
+
// Bold
|
|
401
|
+
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
|
402
|
+
// Italic
|
|
403
|
+
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
|
404
|
+
// Code blocks
|
|
405
|
+
.replace(/```[\s\S]*?```/g, match => {
|
|
406
|
+
const code = match.slice(3, -3).trim();
|
|
407
|
+
return `<pre><code>${code}</code></pre>`;
|
|
408
|
+
})
|
|
409
|
+
// Inline code
|
|
410
|
+
.replace(/`(.+?)`/g, '<code>$1</code>')
|
|
411
|
+
// Blockquotes
|
|
412
|
+
.replace(/^> (.+)$/gm, '<blockquote>$1</blockquote>')
|
|
413
|
+
// Horizontal rules
|
|
414
|
+
.replace(/^---$/gm, '<hr>')
|
|
415
|
+
// Lists (simplified)
|
|
416
|
+
.replace(/^- (.+)$/gm, '<li>$1</li>')
|
|
417
|
+
.replace(/^(\d+)\. (.+)$/gm, '<li>$2</li>');
|
|
418
|
+
|
|
419
|
+
// Wrap consecutive li elements in ul/ol
|
|
420
|
+
html = html.replace(/(<li>.*<\/li>\n?)+/g, match => {
|
|
421
|
+
return `<ul>${match}</ul>`;
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Convert paragraphs
|
|
425
|
+
const lines = html.split('\n');
|
|
426
|
+
const processedLines = [];
|
|
427
|
+
let inBlock = false;
|
|
428
|
+
|
|
429
|
+
lines.forEach(line => {
|
|
430
|
+
const trimmed = line.trim();
|
|
431
|
+
if (trimmed === '') {
|
|
432
|
+
inBlock = false;
|
|
433
|
+
} else if (!trimmed.startsWith('<')) {
|
|
434
|
+
processedLines.push(`<p>${trimmed}</p>`);
|
|
435
|
+
} else {
|
|
436
|
+
processedLines.push(trimmed);
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
html = processedLines.join('\n');
|
|
441
|
+
|
|
442
|
+
// Now convert HTML to Gutenberg
|
|
443
|
+
return this.htmlToGutenberg(html);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export default GutenbergConverter;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"server": {
|
|
3
|
+
"name": "myaidev-wordpress-mcp-server",
|
|
4
|
+
"version": "2.0.0",
|
|
5
|
+
"description": "Enhanced WordPress MCP Server with session management and memory persistence",
|
|
6
|
+
"mcpName": "io.github.myaione/myaidev-method",
|
|
7
|
+
"transport": "stdio"
|
|
8
|
+
},
|
|
9
|
+
"tools": [
|
|
10
|
+
{
|
|
11
|
+
"name": "wp_session_create",
|
|
12
|
+
"description": "Create a new session for tracking operations and maintaining context",
|
|
13
|
+
"category": "session_management"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "wp_session_status",
|
|
17
|
+
"description": "Get current session information and operation history",
|
|
18
|
+
"category": "session_management"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "wp_memory_store",
|
|
22
|
+
"description": "Store data in memory for persistence across operations",
|
|
23
|
+
"category": "memory_management"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "wp_memory_retrieve",
|
|
27
|
+
"description": "Retrieve stored data from memory",
|
|
28
|
+
"category": "memory_management"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "wp_memory_list",
|
|
32
|
+
"description": "List all stored data in a namespace",
|
|
33
|
+
"category": "memory_management"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "wp_health_check",
|
|
37
|
+
"description": "Comprehensive health check of WordPress site and MCP server",
|
|
38
|
+
"category": "health_monitoring"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "wp_get_site_info",
|
|
42
|
+
"description": "Get WordPress site statistics, version, and health information",
|
|
43
|
+
"category": "wordpress_operations"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "wp_create_post",
|
|
47
|
+
"description": "Create a new WordPress post or page with enhanced tracking and validation",
|
|
48
|
+
"category": "wordpress_operations"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "wp_update_post",
|
|
52
|
+
"description": "Update an existing WordPress post",
|
|
53
|
+
"category": "wordpress_operations"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "wp_delete_post",
|
|
57
|
+
"description": "Delete a WordPress post (move to trash)",
|
|
58
|
+
"category": "wordpress_operations"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "wp_list_posts",
|
|
62
|
+
"description": "Get posts with filtering options",
|
|
63
|
+
"category": "wordpress_operations"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "wp_batch_publish",
|
|
67
|
+
"description": "Publish multiple posts from markdown files with enhanced tracking",
|
|
68
|
+
"category": "batch_operations"
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"capabilities": [
|
|
72
|
+
"session_management",
|
|
73
|
+
"memory_persistence",
|
|
74
|
+
"health_monitoring",
|
|
75
|
+
"wordpress_integration",
|
|
76
|
+
"batch_operations",
|
|
77
|
+
"gutenberg_support",
|
|
78
|
+
"error_tracking"
|
|
79
|
+
],
|
|
80
|
+
"environment": {
|
|
81
|
+
"required": [
|
|
82
|
+
"WORDPRESS_URL",
|
|
83
|
+
"WORDPRESS_USERNAME",
|
|
84
|
+
"WORDPRESS_APP_PASSWORD"
|
|
85
|
+
],
|
|
86
|
+
"optional": [
|
|
87
|
+
"WORDPRESS_USE_GUTENBERG"
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
"installation": {
|
|
91
|
+
"command": "npm install myaidev-method",
|
|
92
|
+
"global_command": "npm install -g myaidev-method",
|
|
93
|
+
"setup_command": "npx myaidev-method init --claude"
|
|
94
|
+
},
|
|
95
|
+
"usage": {
|
|
96
|
+
"start_server": "npm run mcp:start",
|
|
97
|
+
"health_check": "npm run mcp:health",
|
|
98
|
+
"status_check": "npm run mcp:status",
|
|
99
|
+
"publish_command": "/myai-wordpress-publish \"your-file.md\" --status draft"
|
|
100
|
+
}
|
|
101
|
+
}
|