myaidev-method 0.0.2 → 0.0.5

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/USER_GUIDE.md CHANGED
@@ -301,23 +301,32 @@ Save as markdown with:
301
301
 
302
302
  ### Initial Setup
303
303
 
304
- 1. **Create environment file**:
305
- ```bash
306
- cp .env.example .env
307
- ```
304
+ Use the interactive configuration command to set up WordPress:
305
+
306
+ ```bash
307
+ /myai-configure wordpress
308
+ ```
308
309
 
309
- 2. **Configure WordPress credentials**:
310
+ This will guide you through:
311
+ - WordPress site URL
312
+ - Username
313
+ - Application Password creation
314
+
315
+ **Alternative manual setup**:
316
+ 1. Create `.env` file in your project root
317
+ 2. Add your WordPress credentials:
310
318
  ```bash
311
- # Edit .env file
312
319
  WORDPRESS_URL=https://your-site.com
313
320
  WORDPRESS_USERNAME=your-username
314
321
  WORDPRESS_APP_PASSWORD=your-app-password
315
322
  ```
316
323
 
317
- 3. **Create Application Password**:
318
- - Go to WordPress Admin → Users → Your Profile
319
- - Find "Application Passwords" section
320
- - Enter name and click "Add New"
324
+ ### Creating Application Password
325
+
326
+ 1. Go to WordPress Admin → Users → Your Profile
327
+ 2. Find "Application Passwords" section
328
+ 3. Enter name (e.g., "MyAIDev CLI") and click "Add New"
329
+ 4. Copy the generated password
321
330
  - Copy the generated password
322
331
 
323
332
  ### WordPress Commands
@@ -341,6 +350,55 @@ Save as markdown with:
341
350
  /myai-content-writer "Blog Post Title" --publish_to_wordpress true
342
351
  ```
343
352
 
353
+ ### Publishing Workflow
354
+
355
+ **Important**: WordPress publishing works through Claude Code slash commands, not terminal commands.
356
+
357
+ #### To Publish Content:
358
+
359
+ 1. **Inside Claude Code** (not terminal):
360
+ ```bash
361
+ /myai-wordpress-publish "your-article.md" --status draft
362
+ ```
363
+
364
+ 2. **The command will**:
365
+ - Read your markdown file
366
+ - Extract frontmatter (title, meta_description, tags, etc.)
367
+ - Connect to WordPress REST API
368
+ - Create/update the post
369
+ - Return post ID and URLs
370
+
371
+ #### Common Publishing Options:
372
+
373
+ ```bash
374
+ # Publish as draft (default)
375
+ /myai-wordpress-publish "article.md"
376
+
377
+ # Publish immediately
378
+ /myai-wordpress-publish "article.md" --status publish
379
+
380
+ # Schedule for review
381
+ /myai-wordpress-publish "article.md" --status pending
382
+ ```
383
+
384
+ #### Content Format Expected:
385
+
386
+ Your markdown files should have frontmatter:
387
+
388
+ ```markdown
389
+ ---
390
+ title: "Your Article Title"
391
+ meta_description: "SEO description for the post"
392
+ slug: "your-article-slug"
393
+ tags: ["tag1", "tag2"]
394
+ category: "Blog"
395
+ ---
396
+
397
+ # Your Article Content
398
+
399
+ Content goes here...
400
+ ```
401
+
344
402
  ### WordPress Configuration Options
345
403
 
346
404
  ```bash
package/bin/cli.js CHANGED
@@ -65,15 +65,26 @@ program
65
65
 
66
66
  spinner.succeed(chalk.green(`Successfully initialized ${cliType} configuration!`));
67
67
 
68
- console.log('\n' + chalk.cyan('Next steps:'));
68
+ console.log('\n' + chalk.cyan('🎉 You\'re all set! Here\'s how to get started:'));
69
69
  if (cliType === 'claude') {
70
- console.log(chalk.gray('1. Review the commands in .claude/commands/'));
71
- console.log(chalk.gray('2. Review the agents in .claude/agents/'));
72
- console.log(chalk.gray('3. Configure WordPress settings by creating a .env file'));
73
- console.log(chalk.gray('4. Use /myai-content-writer in Claude Code to create content'));
74
- console.log(chalk.gray('5. Use /myai-wordpress-publish to publish to WordPress'));
70
+ console.log(chalk.green('\n✨ Start creating content immediately:'));
71
+ console.log(chalk.gray(' /myai-content-writer "Your Article Topic"'));
72
+
73
+ console.log(chalk.yellow('\n🎨 Customize your content writer (optional):'));
74
+ console.log(chalk.gray(' Edit .claude/agents/content-writer.md to match your style'));
75
+ console.log(chalk.gray(' • Read USER_GUIDE.md for step-by-step customization tips'));
76
+ console.log(chalk.gray(' • Use /myai-configure agents to manage your agents safely'));
77
+
78
+ console.log(chalk.blue('\n🔌 Add WordPress integration (optional):'));
79
+ console.log(chalk.gray(' • Run /myai-configure wordpress for guided setup'));
80
+ console.log(chalk.gray(' • Publish content with /myai-wordpress-publish filename.md'));
81
+ console.log(chalk.gray(' • Check WORDPRESS_INTEGRATION.md for detailed workflow guide'));
82
+
83
+ console.log(chalk.magenta('\n📚 Need help?'));
84
+ console.log(chalk.gray(' • Check USER_GUIDE.md for detailed instructions'));
85
+ console.log(chalk.gray(' • Visit: https://github.com/myaione/myaidev-method'));
75
86
  }
76
- console.log(chalk.gray(`\nRestart your ${cliType} CLI to load the new configuration`));
87
+ console.log(chalk.cyan(`\n🔄 Restart ${cliType} to load your new AI-powered commands!`));
77
88
 
78
89
  } catch (error) {
79
90
  spinner.fail(chalk.red('Failed to initialize configuration'));
@@ -193,6 +204,34 @@ DEFAULT_TONE=professional
193
204
  if (await fs.pathExists(wordpressMcpServer)) {
194
205
  await fs.copy(wordpressMcpServer, path.join(mcpDir, 'wordpress-server.js'));
195
206
  }
207
+
208
+ // Copy Gutenberg converter
209
+ const gutenbergConverter = path.join(__dirname, '..', 'src', 'mcp', 'gutenberg-converter.js');
210
+ if (await fs.pathExists(gutenbergConverter)) {
211
+ await fs.copy(gutenbergConverter, path.join(mcpDir, 'gutenberg-converter.js'));
212
+ }
213
+
214
+ // Copy USER_GUIDE.md
215
+ const userGuide = path.join(__dirname, '..', 'USER_GUIDE.md');
216
+ if (await fs.pathExists(userGuide)) {
217
+ await fs.copy(userGuide, path.join(projectDir, 'USER_GUIDE.md'));
218
+ }
219
+
220
+ // Copy WordPress documentation
221
+ const wordpressIntegrationDoc = path.join(__dirname, '..', 'src', 'templates', 'docs', 'WORDPRESS_INTEGRATION.md');
222
+ if (await fs.pathExists(wordpressIntegrationDoc)) {
223
+ await fs.copy(wordpressIntegrationDoc, path.join(projectDir, 'WORDPRESS_INTEGRATION.md'));
224
+ }
225
+
226
+ const wordpressExamplesDoc = path.join(__dirname, '..', 'src', 'templates', 'docs', 'wordpress-api-examples.md');
227
+ if (await fs.pathExists(wordpressExamplesDoc)) {
228
+ await fs.copy(wordpressExamplesDoc, path.join(projectDir, 'wordpress-api-examples.md'));
229
+ }
230
+
231
+ const wordpressTroubleshoot = path.join(__dirname, '..', 'src', 'templates', 'docs', 'wordpress-troubleshoot.js');
232
+ if (await fs.pathExists(wordpressTroubleshoot)) {
233
+ await fs.copy(wordpressTroubleshoot, path.join(projectDir, 'wordpress-troubleshoot.js'));
234
+ }
196
235
  }
197
236
 
198
237
  async function setupGemini(projectDir) {
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "myaidev-method",
3
- "version": "0.0.2",
3
+ "version": "0.0.5",
4
4
  "description": "AI CLI tools package with custom subagents and MCP integrations for Claude Code, Gemini CLI, and more",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "myaidev-method": "./bin/cli.js"
8
8
  },
9
9
  "scripts": {
10
- "test": "echo \"Error: no test specified\" && exit 1",
11
- "prepublishOnly": "npm install",
12
- "postinstall": "echo \"MyAIDev Method installed successfully! Run 'npx myaidev-method init --claude' to get started.\""
10
+ "test": "node test/run-tests.js",
11
+ "test:gutenberg": "node test/test-gutenberg-converter.js",
12
+ "test:install": "node test/test-installation.js",
13
+ "prepublishOnly": "npm install && npm test",
14
+ "postinstall": "echo \"MyAIDev Method installed successfully! Run 'npx myaidev-method init --claude' to get started.\"",
15
+ "wordpress:troubleshoot": "node src/templates/docs/wordpress-troubleshoot.js"
13
16
  },
14
17
  "keywords": [
15
18
  "claude-code",
@@ -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
+ '&': '&amp;',
362
+ '<': '&lt;',
363
+ '>': '&gt;',
364
+ '"': '&quot;',
365
+ "'": '&#x27;',
366
+ "/": '&#x2F;'
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
+ '&amp;': '&',
378
+ '&lt;': '<',
379
+ '&gt;': '>',
380
+ '&quot;': '"',
381
+ '&#x27;': "'",
382
+ '&#x2F;': '/',
383
+ '&#39;': "'",
384
+ '&nbsp;': ' '
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;
@@ -1,4 +1,5 @@
1
1
  import fetch from 'node-fetch';
2
+ import { GutenbergConverter } from './gutenberg-converter.js';
2
3
 
3
4
  export class WordPressMCP {
4
5
  constructor(config) {
@@ -32,9 +33,15 @@ export class WordPressMCP {
32
33
  }
33
34
 
34
35
  async createPost(params) {
36
+ // Convert content to Gutenberg format if requested
37
+ let content = params.content;
38
+ if (params.use_gutenberg === true || params.gutenberg === true) {
39
+ content = GutenbergConverter.htmlToGutenberg(params.content);
40
+ }
41
+
35
42
  const postData = {
36
43
  title: params.title,
37
- content: params.content,
44
+ content: content,
38
45
  status: params.status || this.defaults.post_status,
39
46
  categories: params.categories || [],
40
47
  tags: params.tags || [],
@@ -191,9 +198,10 @@ export class WordPressMCP {
191
198
  content: contentData.content,
192
199
  excerpt: contentData.meta_description,
193
200
  slug: contentData.slug,
194
- status: 'draft', // Always create as draft for review
201
+ status: contentData.status || 'draft', // Default to draft for review
195
202
  tags: tags,
196
- categories: categoryId ? [categoryId] : []
203
+ categories: categoryId ? [categoryId] : [],
204
+ use_gutenberg: contentData.use_gutenberg || false // Pass Gutenberg option
197
205
  };
198
206
 
199
207
  // Create the post
@@ -9,11 +9,50 @@ Configure MyAI Method settings based on the parameter: $ARGUMENTS
9
9
  ## Available Configurations
10
10
 
11
11
  ### wordpress
12
- Set up WordPress connection:
13
- 1. Prompt for WordPress site URL
14
- 2. Prompt for username
15
- 3. Guide through Application Password creation
16
- 4. Save to `.env` file in project root
12
+ Interactive WordPress setup - no manual .env file creation needed!
13
+
14
+ **Process:**
15
+ 1. **Collect WordPress site URL**
16
+ - Prompt: "Enter your WordPress site URL (e.g., https://yoursite.com):"
17
+ - Validate URL format and accessibility
18
+ - Test basic connectivity
19
+
20
+ 2. **Get WordPress username**
21
+ - Prompt: "Enter your WordPress admin username:"
22
+ - Validate username format
23
+
24
+ 3. **Guide through Application Password creation**
25
+ - Show step-by-step instructions:
26
+ * "Go to your WordPress Admin → Users → Your Profile"
27
+ * "Scroll down to 'Application Passwords' section"
28
+ * "Enter a name like 'MyAI Dev Method' and click 'Add New'"
29
+ * "Copy the generated password (it looks like: xxxx xxxx xxxx xxxx)"
30
+ - Prompt: "Paste your Application Password here:"
31
+ - Validate password format
32
+
33
+ 4. **Test connection**
34
+ - Verify credentials by making test API call
35
+ - Show success/failure message with troubleshooting tips
36
+
37
+ 5. **Save configuration**
38
+ - Create/update `.env` file automatically
39
+ - Set proper file permissions (600)
40
+ - Show confirmation of saved settings
41
+
42
+ 6. **Optional SSH setup**
43
+ - Ask: "Do you want to set up SSH for advanced WordPress administration? (y/n)"
44
+ - If yes, prompt for SSH details:
45
+ * SSH host/IP
46
+ * SSH username
47
+ * SSH key path (optional)
48
+ - Test SSH connection if credentials provided
49
+
50
+ **Success message:**
51
+ "✅ WordPress integration configured successfully!
52
+ - Site: [URL]
53
+ - User: [username]
54
+ - Connection: ✅ Verified
55
+ - Available commands: /myai-wordpress-admin, /myai-wordpress-publish"
17
56
 
18
57
  ### defaults
19
58
  Configure default content settings:
@@ -40,6 +79,47 @@ List and manage available agents:
40
79
  4. Save to appropriate location (.env or .claude/config/)
41
80
  5. Confirm successful configuration
42
81
 
82
+ ## WordPress Setup Example
83
+
84
+ ```bash
85
+ # User runs the command
86
+ /myai-configure wordpress
87
+
88
+ # System prompts and responses:
89
+ ? Enter your WordPress site URL: https://myblog.com
90
+ ✓ URL format valid, testing connection...
91
+ ✓ WordPress site accessible
92
+
93
+ ? Enter your WordPress admin username: john_admin
94
+ ✓ Username format valid
95
+
96
+ # System shows instructions
97
+ 📝 Create Application Password:
98
+ 1. Go to https://myblog.com/wp-admin/profile.php
99
+ 2. Scroll to "Application Passwords"
100
+ 3. Enter name: "MyAI Dev Method"
101
+ 4. Click "Add New"
102
+ 5. Copy the generated password
103
+
104
+ ? Paste your Application Password: abcd efgh ijkl mnop
105
+ ✓ Password format valid, testing connection...
106
+ ✓ WordPress API connection successful!
107
+
108
+ ? Set up SSH for advanced features? (y/n): y
109
+ ? SSH host/IP: myblog.com
110
+ ? SSH username: john
111
+ ? SSH key path (press enter for default): /home/user/.ssh/id_rsa
112
+ ✓ SSH connection tested successfully
113
+
114
+ ✅ Configuration saved to .env
115
+ ✅ File permissions set to 600 (secure)
116
+
117
+ WordPress integration ready! Available commands:
118
+ • /myai-wordpress-admin health-check
119
+ • /myai-wordpress-publish filename.md
120
+ • /myai-content-writer "topic" --publish_to_wordpress true
121
+ ```
122
+
43
123
  ## Agent Management Examples
44
124
 
45
125
  ```bash
@@ -18,21 +18,29 @@ Read and publish the file specified in $ARGUMENTS to WordPress.
18
18
  - slug
19
19
  - tags
20
20
  - category
21
+ - use_gutenberg (optional, default: false)
21
22
  3. **Check WordPress configuration** in environment variables:
22
23
  - WORDPRESS_URL
23
24
  - WORDPRESS_USERNAME
24
25
  - WORDPRESS_APP_PASSWORD
26
+ - WORDPRESS_USE_GUTENBERG (optional, default: false)
25
27
  4. **Connect to WordPress** using the REST API
26
- 5. **Create or update the post** with status (default: draft)
27
- 6. **Report the result** including:
28
+ 5. **Convert content format** if Gutenberg is enabled:
29
+ - If use_gutenberg is true or WORDPRESS_USE_GUTENBERG is true
30
+ - Convert HTML to Gutenberg block format
31
+ 6. **Create or update the post** with status (default: draft)
32
+ 7. **Report the result** including:
28
33
  - Post ID
29
34
  - Preview URL
30
35
  - Edit URL in WordPress admin
36
+ - Format used (Classic or Gutenberg)
31
37
 
32
38
  ## Parameters
33
39
 
34
40
  - File path (required): Path to markdown file
35
- - Status: draft (default), publish, pending, private
41
+ - --status: draft (default), publish, pending, private
42
+ - --gutenberg: Use Gutenberg block format (default: false)
43
+ - --classic: Force classic editor format (overrides defaults)
36
44
 
37
45
  ## Error Handling
38
46
 
@@ -0,0 +1,143 @@
1
+ # WordPress Integration - How It Works
2
+
3
+ ## Overview
4
+
5
+ The MyAIDev Method package provides WordPress integration through Claude Code slash commands, not terminal npm scripts. This is the correct design for Claude Code packages.
6
+
7
+ ## Publishing Workflow
8
+
9
+ ### ❌ Incorrect Usage (What You Tried)
10
+ ```bash
11
+ # This doesn't work - there's no npm script
12
+ npm run wordpress:publish -- --file lovable-to-ultrastack-deployment.md --status draft
13
+ ```
14
+
15
+ ### ✅ Correct Usage (Inside Claude Code)
16
+ ```bash
17
+ # Use this slash command inside Claude Code
18
+ /myai-wordpress-publish "lovable-to-ultrastack-deployment.md" --status draft
19
+ ```
20
+
21
+ ## How It Works
22
+
23
+ 1. **Command Definition**: `.claude/commands/myai-wordpress-publish.md`
24
+ - Defines the slash command interface
25
+ - Specifies parameters and expected behavior
26
+ - Uses Claude Code's built-in tools (Read, Task, WebFetch)
27
+
28
+ 2. **MCP Integration**: `.claude/mcp/wordpress-server.js`
29
+ - Provides WordPress REST API integration
30
+ - Handles authentication via Application Passwords
31
+ - Manages posts, categories, tags, and media
32
+
33
+ 3. **Configuration**: Environment variables or `.env` file
34
+ - `WORDPRESS_URL`: Your site URL
35
+ - `WORDPRESS_USERNAME`: WordPress username
36
+ - `WORDPRESS_APP_PASSWORD`: Application password
37
+
38
+ ## Step-by-Step Publishing Process
39
+
40
+ ### 1. Setup WordPress Credentials (One Time)
41
+ Inside Claude Code:
42
+ ```bash
43
+ /myai-configure wordpress
44
+ ```
45
+
46
+ This creates a `.env` file with:
47
+ ```
48
+ WORDPRESS_URL=https://your-site.com
49
+ WORDPRESS_USERNAME=your-username
50
+ WORDPRESS_APP_PASSWORD=your-app-password
51
+ ```
52
+
53
+ ### 2. Prepare Your Content
54
+ Create a markdown file with frontmatter:
55
+ ```markdown
56
+ ---
57
+ title: "Your Article Title"
58
+ meta_description: "SEO description"
59
+ slug: "your-article-slug"
60
+ tags: ["web-development", "tutorial"]
61
+ category: "Blog"
62
+ ---
63
+
64
+ # Your Article Content
65
+
66
+ Content goes here...
67
+ ```
68
+
69
+ ### 3. Publish to WordPress
70
+ Inside Claude Code:
71
+ ```bash
72
+ /myai-wordpress-publish "your-file.md" --status draft
73
+ ```
74
+
75
+ ### 4. What Happens Next
76
+ The command will:
77
+ - Read your markdown file
78
+ - Parse the frontmatter
79
+ - Connect to WordPress REST API
80
+ - Create categories/tags if needed
81
+ - Create the post as a draft
82
+ - Return post ID and URLs
83
+
84
+ ## Expected Output
85
+
86
+ ```
87
+ ✅ Successfully published to WordPress!
88
+ - Post ID: 123
89
+ - Status: draft
90
+ - Preview: https://your-site.com/?p=123&preview=true
91
+ - Edit: https://your-site.com/wp-admin/post.php?post=123&action=edit
92
+ ```
93
+
94
+ ## WordPress Application Password Setup
95
+
96
+ 1. Go to your WordPress Admin → Users → Your Profile
97
+ 2. Scroll to "Application Passwords" section
98
+ 3. Enter name: "MyAIDev CLI"
99
+ 4. Click "Add New"
100
+ 5. Copy the generated password (save it!)
101
+ 6. Use this password in your `.env` file
102
+
103
+ ## Why No npm Scripts?
104
+
105
+ This is a **Claude Code package**, not a traditional npm package with CLI scripts. The functionality is designed to work within Claude Code's environment using:
106
+
107
+ - Slash commands (like `/myai-wordpress-publish`)
108
+ - Claude Code's built-in tools (Read, Write, WebFetch, etc.)
109
+ - MCP (Model Context Protocol) integrations
110
+ - Environment variable access
111
+
112
+ This design provides better integration with Claude Code's AI capabilities and workflow.
113
+
114
+ ## Troubleshooting
115
+
116
+ ### "package.json not found" Error
117
+ This happens when trying to use `npm run` commands. Use slash commands instead.
118
+
119
+ ### "WordPress credentials not configured"
120
+ Run `/myai-configure wordpress` to set up credentials.
121
+
122
+ ### "File not found" Error
123
+ Check the file path is correct relative to your current directory.
124
+
125
+ ### Authentication Errors
126
+ Verify your Application Password is correct and has proper permissions.
127
+
128
+ ## Development Notes
129
+
130
+ If you want to add npm scripts for WordPress publishing, you would need to:
131
+
132
+ 1. Add scripts to `package.json`:
133
+ ```json
134
+ {
135
+ "scripts": {
136
+ "wordpress:publish": "node scripts/wordpress-publish.js"
137
+ }
138
+ }
139
+ ```
140
+
141
+ 2. Create `scripts/wordpress-publish.js` that uses the MCP integration
142
+
143
+ However, this goes against the Claude Code design pattern. The slash command approach is the intended and recommended method.
@@ -0,0 +1,159 @@
1
+ # WordPress REST API Testing Examples
2
+
3
+ ## Your Credentials
4
+ - **Username:** admin
5
+ - **Application Password:** iqMC L5Eh JexQ 0Ior BJIo pLH3
6
+ - **WordPress URL:** [You need to provide this]
7
+
8
+ ## Basic Authentication Test
9
+
10
+ ### Using curl (Terminal)
11
+ ```bash
12
+ # Replace YOUR_SITE_URL with your actual WordPress URL
13
+ curl -X GET "YOUR_SITE_URL/wp-json/wp/v2/posts?per_page=1" \
14
+ -H "Authorization: Basic $(echo -n 'admin:iqMC L5Eh JexQ 0Ior BJIo pLH3' | base64)" \
15
+ -H "Content-Type: application/json"
16
+ ```
17
+
18
+ ### Expected Response
19
+ ```json
20
+ [
21
+ {
22
+ "id": 1,
23
+ "title": {"rendered": "Hello world!"},
24
+ "status": "publish",
25
+ "link": "https://your-site.com/hello-world/"
26
+ }
27
+ ]
28
+ ```
29
+
30
+ ## Create a Test Post
31
+
32
+ ### Using curl
33
+ ```bash
34
+ curl -X POST "YOUR_SITE_URL/wp-json/wp/v2/posts" \
35
+ -H "Authorization: Basic $(echo -n 'admin:iqMC L5Eh JexQ 0Ior BJIo pLH3' | base64)" \
36
+ -H "Content-Type: application/json" \
37
+ -d '{
38
+ "title": "MyAIDev Test Post",
39
+ "content": "<h2>Test Post</h2><p>This is a test post created via REST API.</p>",
40
+ "status": "draft",
41
+ "excerpt": "Test post from MyAIDev Method"
42
+ }'
43
+ ```
44
+
45
+ ### Expected Response
46
+ ```json
47
+ {
48
+ "id": 123,
49
+ "title": {"rendered": "MyAIDev Test Post"},
50
+ "status": "draft",
51
+ "link": "https://your-site.com/?p=123",
52
+ "content": {"rendered": "<h2>Test Post</h2><p>This is a test post created via REST API.</p>"}
53
+ }
54
+ ```
55
+
56
+ ## Using JavaScript/Node.js
57
+
58
+ ### Basic Example
59
+ ```javascript
60
+ import fetch from 'node-fetch';
61
+
62
+ const siteUrl = 'YOUR_SITE_URL';
63
+ const username = 'admin';
64
+ const appPassword = 'iqMC L5Eh JexQ 0Ior BJIo pLH3';
65
+ const auth = Buffer.from(`${username}:${appPassword}`).toString('base64');
66
+
67
+ // Test connection
68
+ const response = await fetch(`${siteUrl}/wp-json/wp/v2/posts?per_page=1`, {
69
+ headers: {
70
+ 'Authorization': `Basic ${auth}`,
71
+ 'Content-Type': 'application/json'
72
+ }
73
+ });
74
+
75
+ if (response.ok) {
76
+ const posts = await response.json();
77
+ console.log('✅ Connection successful!', posts.length, 'posts found');
78
+ } else {
79
+ console.error('❌ Connection failed:', response.status, response.statusText);
80
+ }
81
+ ```
82
+
83
+ ### Create Post Example
84
+ ```javascript
85
+ // Create a new post
86
+ const postData = {
87
+ title: 'MyAIDev Method Test',
88
+ content: '<h2>Hello from MyAIDev!</h2><p>This post was created via REST API.</p>',
89
+ status: 'draft',
90
+ excerpt: 'Test post created by MyAIDev Method package.'
91
+ };
92
+
93
+ const createResponse = await fetch(`${siteUrl}/wp-json/wp/v2/posts`, {
94
+ method: 'POST',
95
+ headers: {
96
+ 'Authorization': `Basic ${auth}`,
97
+ 'Content-Type': 'application/json'
98
+ },
99
+ body: JSON.stringify(postData)
100
+ });
101
+
102
+ if (createResponse.ok) {
103
+ const newPost = await createResponse.json();
104
+ console.log('✅ Post created!');
105
+ console.log('ID:', newPost.id);
106
+ console.log('Preview:', newPost.link + '?preview=true');
107
+ } else {
108
+ const error = await createResponse.text();
109
+ console.error('❌ Failed to create post:', error);
110
+ }
111
+ ```
112
+
113
+ ## Testing Steps
114
+
115
+ 1. **Replace YOUR_SITE_URL** with your actual WordPress site URL (e.g., `https://mysite.com`)
116
+
117
+ 2. **Test connection first:**
118
+ ```bash
119
+ node simple-wp-test.js
120
+ ```
121
+
122
+ 3. **Check WordPress admin** to see if the test post was created
123
+
124
+ 4. **Verify the Application Password** is still active in WordPress Admin > Users > Profile
125
+
126
+ ## Troubleshooting Common Issues
127
+
128
+ ### 401 Unauthorized
129
+ - Check if Application Password is correct
130
+ - Verify username is 'admin'
131
+ - Ensure Application Password is still active
132
+
133
+ ### 403 Forbidden
134
+ - User might not have permission to create posts
135
+ - Check if REST API is disabled
136
+
137
+ ### 404 Not Found
138
+ - WordPress URL might be incorrect
139
+ - REST API might be disabled
140
+ - Permalinks might need to be refreshed
141
+
142
+ ### SSL/Certificate Errors
143
+ - If using HTTPS, ensure SSL certificate is valid
144
+ - For testing, you might need to add SSL bypass (not recommended for production)
145
+
146
+ ## WordPress Site Requirements
147
+
148
+ Your WordPress site needs:
149
+ - ✅ REST API enabled (default in WordPress 4.7+)
150
+ - ✅ Application Passwords enabled (WordPress 5.6+)
151
+ - ✅ User with post creation permissions
152
+ - ✅ Valid SSL certificate (if using HTTPS)
153
+
154
+ ## Next Steps
155
+
156
+ 1. Provide your WordPress site URL
157
+ 2. Run the test script with your URL
158
+ 3. Check if posts are created successfully
159
+ 4. If working, the MyAIDev Method slash commands will work perfectly!
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * WordPress Integration Troubleshooting Script
5
+ * Quick diagnostic tool for MyAIDev Method WordPress integration
6
+ */
7
+
8
+ import fetch from 'node-fetch';
9
+ import fs from 'fs-extra';
10
+ import path from 'path';
11
+
12
+ async function troubleshootWordPress() {
13
+ console.log('🔍 MyAIDev Method WordPress Troubleshooting');
14
+ console.log('═══════════════════════════════════════════════');
15
+
16
+ try {
17
+ // 1. Check for .env file
18
+ console.log('\n1️⃣ Checking configuration...');
19
+ const envPath = path.join(process.cwd(), '.env');
20
+
21
+ if (await fs.pathExists(envPath)) {
22
+ console.log('✅ .env file found');
23
+
24
+ const envContent = await fs.readFile(envPath, 'utf8');
25
+ const hasUrl = envContent.includes('WORDPRESS_URL');
26
+ const hasUsername = envContent.includes('WORDPRESS_USERNAME');
27
+ const hasPassword = envContent.includes('WORDPRESS_APP_PASSWORD');
28
+
29
+ console.log(` - WORDPRESS_URL: ${hasUrl ? '✅' : '❌'}`);
30
+ console.log(` - WORDPRESS_USERNAME: ${hasUsername ? '✅' : '❌'}`);
31
+ console.log(` - WORDPRESS_APP_PASSWORD: ${hasPassword ? '✅' : '❌'}`);
32
+
33
+ if (!hasUrl || !hasUsername || !hasPassword) {
34
+ console.log('⚠️ Missing WordPress credentials. Run: /myai-configure wordpress');
35
+ }
36
+ } else {
37
+ console.log('❌ .env file not found');
38
+ console.log('💡 Solution: Run /myai-configure wordpress to create configuration');
39
+ }
40
+
41
+ // 2. Check Claude configuration
42
+ console.log('\n2️⃣ Checking Claude Code setup...');
43
+ const claudeDir = path.join(process.cwd(), '.claude');
44
+ const commandsDir = path.join(claudeDir, 'commands');
45
+
46
+ if (await fs.pathExists(claudeDir)) {
47
+ console.log('✅ .claude directory found');
48
+
49
+ const wpPublishCommand = path.join(commandsDir, 'myai-wordpress-publish.md');
50
+ const wpConfigCommand = path.join(commandsDir, 'myai-configure.md');
51
+
52
+ console.log(` - WordPress publish command: ${await fs.pathExists(wpPublishCommand) ? '✅' : '❌'}`);
53
+ console.log(` - Configuration command: ${await fs.pathExists(wpConfigCommand) ? '✅' : '❌'}`);
54
+ } else {
55
+ console.log('❌ .claude directory not found');
56
+ console.log('💡 Solution: Run npx myaidev-method init --claude');
57
+ }
58
+
59
+ // 3. Test connection if credentials exist
60
+ if (await fs.pathExists(envPath)) {
61
+ console.log('\n3️⃣ Testing WordPress connection...');
62
+
63
+ try {
64
+ // Parse environment variables
65
+ const envContent = await fs.readFile(envPath, 'utf8');
66
+ const envVars = {};
67
+
68
+ envContent.split('\n').forEach(line => {
69
+ const [key, value] = line.split('=');
70
+ if (key && value) {
71
+ envVars[key.trim()] = value.trim();
72
+ }
73
+ });
74
+
75
+ if (envVars.WORDPRESS_URL && envVars.WORDPRESS_USERNAME && envVars.WORDPRESS_APP_PASSWORD) {
76
+ const auth = Buffer.from(`${envVars.WORDPRESS_USERNAME}:${envVars.WORDPRESS_APP_PASSWORD}`).toString('base64');
77
+ const apiUrl = `${envVars.WORDPRESS_URL}/wp-json/wp/v2`;
78
+
79
+ console.log(` Testing: ${apiUrl}`);
80
+
81
+ const response = await fetch(`${apiUrl}/posts?per_page=1`, {
82
+ headers: {
83
+ 'Authorization': `Basic ${auth}`,
84
+ 'Content-Type': 'application/json'
85
+ }
86
+ });
87
+
88
+ if (response.ok) {
89
+ console.log('✅ WordPress API connection successful');
90
+
91
+ // Test post creation
92
+ const testResponse = await fetch(`${apiUrl}/posts`, {
93
+ method: 'POST',
94
+ headers: {
95
+ 'Authorization': `Basic ${auth}`,
96
+ 'Content-Type': 'application/json'
97
+ },
98
+ body: JSON.stringify({
99
+ title: 'MyAIDev Test - ' + Date.now(),
100
+ content: 'Test post from troubleshooting script',
101
+ status: 'draft'
102
+ })
103
+ });
104
+
105
+ if (testResponse.ok) {
106
+ const post = await testResponse.json();
107
+ console.log('✅ Post creation successful');
108
+ console.log(` - Test post ID: ${post.id}`);
109
+ console.log(` - Preview: ${post.link}?preview=true`);
110
+ } else {
111
+ console.log('❌ Post creation failed');
112
+ const error = await testResponse.text();
113
+ console.log(` Error: ${error.substring(0, 100)}...`);
114
+ }
115
+ } else {
116
+ console.log(`❌ WordPress API connection failed: ${response.status}`);
117
+ console.log('💡 Check your WordPress URL and Application Password');
118
+ }
119
+ } else {
120
+ console.log('⚠️ Incomplete WordPress credentials in .env file');
121
+ }
122
+ } catch (error) {
123
+ console.log(`❌ Connection test failed: ${error.message}`);
124
+ }
125
+ }
126
+
127
+ console.log('\n📋 Next Steps:');
128
+ console.log('1. If configuration is missing: /myai-configure wordpress');
129
+ console.log('2. If Claude setup is missing: npx myaidev-method init --claude');
130
+ console.log('3. If connection fails: Check WordPress Application Password');
131
+ console.log('4. For detailed help: Read WORDPRESS_INTEGRATION.md');
132
+
133
+ } catch (error) {
134
+ console.error('❌ Troubleshooting failed:', error.message);
135
+ }
136
+ }
137
+
138
+ // Export for programmatic use
139
+ export { troubleshootWordPress };
140
+
141
+ // Run if called directly
142
+ if (import.meta.url === `file://${process.argv[1]}`) {
143
+ troubleshootWordPress();
144
+ }