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.
Files changed (60) hide show
  1. package/.claude-plugin/plugin.json +251 -0
  2. package/PLUGIN_ARCHITECTURE.md +276 -0
  3. package/README.md +204 -0
  4. package/USER_GUIDE.md +436 -9
  5. package/bin/cli.js +370 -38
  6. package/dist/server/.tsbuildinfo +1 -1
  7. package/extension.json +174 -0
  8. package/hooks/hooks.json +221 -0
  9. package/marketplace.json +179 -0
  10. package/package.json +24 -7
  11. package/skills/content-verifier/SKILL.md +178 -0
  12. package/skills/content-writer/SKILL.md +151 -0
  13. package/skills/coolify-deployer/SKILL.md +207 -0
  14. package/skills/openstack-manager/SKILL.md +213 -0
  15. package/skills/security-auditor/SKILL.md +180 -0
  16. package/skills/security-tester/SKILL.md +171 -0
  17. package/skills/sparc-architect/SKILL.md +146 -0
  18. package/skills/sparc-coder/SKILL.md +136 -0
  19. package/skills/sparc-documenter/SKILL.md +195 -0
  20. package/skills/sparc-reviewer/SKILL.md +179 -0
  21. package/skills/sparc-tester/SKILL.md +156 -0
  22. package/skills/visual-generator/SKILL.md +147 -0
  23. package/skills/wordpress-publisher/SKILL.md +150 -0
  24. package/src/config/workflows.js +28 -44
  25. package/src/lib/ascii-banner.js +214 -0
  26. package/src/lib/config-manager.js +470 -0
  27. package/src/lib/content-coordinator.js +2562 -0
  28. package/src/lib/content-generator.js +427 -0
  29. package/src/lib/html-conversion-utils.js +843 -0
  30. package/src/lib/installation-detector.js +266 -0
  31. package/src/lib/seo-optimizer.js +515 -0
  32. package/src/lib/visual-config-utils.js +1 -1
  33. package/src/lib/visual-generation-utils.js +34 -14
  34. package/src/lib/wordpress-client.js +633 -0
  35. package/src/lib/workflow-installer.js +3 -3
  36. package/src/scripts/generate-visual-cli.js +39 -10
  37. package/src/scripts/html-conversion-cli.js +526 -0
  38. package/src/scripts/init/configure.js +436 -0
  39. package/src/scripts/init/install.js +460 -0
  40. package/src/scripts/ping.js +0 -1
  41. package/src/scripts/utils/file-utils.js +404 -0
  42. package/src/scripts/utils/logger.js +300 -0
  43. package/src/scripts/utils/write-content.js +293 -0
  44. package/src/templates/claude/agents/content-production-coordinator.md +689 -15
  45. package/src/templates/claude/agents/visual-content-generator.md +129 -4
  46. package/src/templates/claude/commands/myai-content-enrichment.md +227 -0
  47. package/src/templates/claude/commands/myai-content-writer.md +48 -37
  48. package/src/templates/claude/commands/myai-convert-html.md +186 -0
  49. package/src/templates/claude/commands/myai-coordinate-content.md +347 -11
  50. package/src/templates/diagrams/architecture.d2 +52 -0
  51. package/src/templates/diagrams/flowchart.d2 +42 -0
  52. package/src/templates/diagrams/sequence.d2 +47 -0
  53. package/src/templates/docs/content-creation-guide.md +164 -0
  54. package/src/templates/docs/deployment-guide.md +336 -0
  55. package/src/templates/docs/visual-generation-guide.md +248 -0
  56. package/src/templates/docs/wordpress-publishing-guide.md +208 -0
  57. package/src/templates/infographics/comparison-table.html +347 -0
  58. package/src/templates/infographics/data-chart.html +268 -0
  59. package/src/templates/infographics/process-flow.html +365 -0
  60. /package/src/scripts/{wordpress-health-check.js → wordpress/wordpress-health-check.js} +0 -0
@@ -0,0 +1,633 @@
1
+ /**
2
+ * WordPress Client
3
+ * High-level WordPress API client for content publishing
4
+ * Wraps wordpress-admin-utils.js functionality
5
+ */
6
+
7
+ import { getConfigManager } from './config-manager.js';
8
+
9
+ /**
10
+ * WordPress Client Class
11
+ */
12
+ export class WordPressClient {
13
+ constructor(options = {}) {
14
+ this.siteUrl = options.siteUrl || null;
15
+ this.username = options.username || null;
16
+ this.appPassword = options.appPassword || null;
17
+ this.configManager = options.configManager || getConfigManager();
18
+ this.initialized = false;
19
+ }
20
+
21
+ /**
22
+ * Initialize the client with configuration
23
+ * @returns {Promise<boolean>} True if initialization successful
24
+ */
25
+ async initialize() {
26
+ if (this.initialized) {
27
+ return true;
28
+ }
29
+
30
+ const config = await this.configManager.loadAll();
31
+
32
+ this.siteUrl = this.siteUrl || config.WORDPRESS_URL;
33
+ this.username = this.username || config.WORDPRESS_USERNAME;
34
+ this.appPassword = this.appPassword || config.WORDPRESS_APP_PASSWORD;
35
+ this.defaultStatus = config.WORDPRESS_DEFAULT_STATUS || 'draft';
36
+
37
+ // Validate required fields
38
+ if (!this.siteUrl || !this.username || !this.appPassword) {
39
+ return false;
40
+ }
41
+
42
+ // Normalize site URL
43
+ this.siteUrl = this.siteUrl.replace(/\/+$/, '');
44
+ if (!this.siteUrl.startsWith('http')) {
45
+ this.siteUrl = 'https://' + this.siteUrl;
46
+ }
47
+
48
+ this.initialized = true;
49
+ return true;
50
+ }
51
+
52
+ /**
53
+ * Get authentication header
54
+ * @returns {Object} Headers object with authorization
55
+ */
56
+ getAuthHeaders() {
57
+ const auth = Buffer.from(`${this.username}:${this.appPassword}`).toString('base64');
58
+ return {
59
+ 'Authorization': `Basic ${auth}`,
60
+ 'Content-Type': 'application/json'
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Validate connection to WordPress
66
+ * @returns {Promise<{valid: boolean, message: string, user?: Object}>}
67
+ */
68
+ async validateConnection() {
69
+ const initialized = await this.initialize();
70
+ if (!initialized) {
71
+ return {
72
+ valid: false,
73
+ message: 'WordPress credentials not configured. Run /myai-configure wordpress'
74
+ };
75
+ }
76
+
77
+ try {
78
+ const response = await fetch(`${this.siteUrl}/wp-json/wp/v2/users/me`, {
79
+ method: 'GET',
80
+ headers: this.getAuthHeaders()
81
+ });
82
+
83
+ if (!response.ok) {
84
+ const text = await response.text();
85
+ return {
86
+ valid: false,
87
+ message: `Authentication failed: ${response.status} ${text}`
88
+ };
89
+ }
90
+
91
+ const user = await response.json();
92
+ return {
93
+ valid: true,
94
+ message: `Connected as ${user.name} (${user.slug})`,
95
+ user
96
+ };
97
+ } catch (error) {
98
+ return {
99
+ valid: false,
100
+ message: `Connection error: ${error.message}`
101
+ };
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Publish a post to WordPress
107
+ * @param {Object} postData - Post data
108
+ * @param {string} postData.title - Post title
109
+ * @param {string} postData.content - Post content (HTML or markdown)
110
+ * @param {string} [postData.status='draft'] - Post status (draft, publish, pending)
111
+ * @param {string} [postData.excerpt] - Post excerpt
112
+ * @param {number[]} [postData.categories] - Category IDs
113
+ * @param {number[]} [postData.tags] - Tag IDs
114
+ * @param {string} [postData.slug] - URL slug
115
+ * @param {number} [postData.featured_media] - Featured image ID
116
+ * @returns {Promise<{success: boolean, post?: Object, error?: string}>}
117
+ */
118
+ async publishPost(postData) {
119
+ const initialized = await this.initialize();
120
+ if (!initialized) {
121
+ return {
122
+ success: false,
123
+ error: 'WordPress credentials not configured'
124
+ };
125
+ }
126
+
127
+ try {
128
+ const payload = {
129
+ title: postData.title,
130
+ content: this.convertMarkdownToHtml(postData.content),
131
+ status: postData.status || this.defaultStatus,
132
+ excerpt: postData.excerpt || '',
133
+ categories: postData.categories || [],
134
+ tags: postData.tags || [],
135
+ slug: postData.slug || this.generateSlug(postData.title),
136
+ featured_media: postData.featured_media || 0
137
+ };
138
+
139
+ const response = await fetch(`${this.siteUrl}/wp-json/wp/v2/posts`, {
140
+ method: 'POST',
141
+ headers: this.getAuthHeaders(),
142
+ body: JSON.stringify(payload)
143
+ });
144
+
145
+ if (!response.ok) {
146
+ const error = await response.json();
147
+ return {
148
+ success: false,
149
+ error: error.message || `HTTP ${response.status}`
150
+ };
151
+ }
152
+
153
+ const post = await response.json();
154
+ return {
155
+ success: true,
156
+ post: {
157
+ id: post.id,
158
+ title: post.title.rendered,
159
+ status: post.status,
160
+ link: post.link,
161
+ editLink: `${this.siteUrl}/wp-admin/post.php?post=${post.id}&action=edit`
162
+ }
163
+ };
164
+ } catch (error) {
165
+ return {
166
+ success: false,
167
+ error: error.message
168
+ };
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Create a draft post
174
+ * @param {Object} postData - Post data (same as publishPost)
175
+ * @returns {Promise<{success: boolean, post?: Object, error?: string}>}
176
+ */
177
+ async createDraft(postData) {
178
+ return this.publishPost({ ...postData, status: 'draft' });
179
+ }
180
+
181
+ /**
182
+ * Update an existing post
183
+ * @param {number} postId - Post ID to update
184
+ * @param {Object} data - Data to update
185
+ * @returns {Promise<{success: boolean, post?: Object, error?: string}>}
186
+ */
187
+ async updatePost(postId, data) {
188
+ const initialized = await this.initialize();
189
+ if (!initialized) {
190
+ return {
191
+ success: false,
192
+ error: 'WordPress credentials not configured'
193
+ };
194
+ }
195
+
196
+ try {
197
+ const payload = {};
198
+
199
+ if (data.title) payload.title = data.title;
200
+ if (data.content) payload.content = this.convertMarkdownToHtml(data.content);
201
+ if (data.status) payload.status = data.status;
202
+ if (data.excerpt) payload.excerpt = data.excerpt;
203
+ if (data.categories) payload.categories = data.categories;
204
+ if (data.tags) payload.tags = data.tags;
205
+ if (data.slug) payload.slug = data.slug;
206
+ if (data.featured_media !== undefined) payload.featured_media = data.featured_media;
207
+
208
+ const response = await fetch(`${this.siteUrl}/wp-json/wp/v2/posts/${postId}`, {
209
+ method: 'POST',
210
+ headers: this.getAuthHeaders(),
211
+ body: JSON.stringify(payload)
212
+ });
213
+
214
+ if (!response.ok) {
215
+ const error = await response.json();
216
+ return {
217
+ success: false,
218
+ error: error.message || `HTTP ${response.status}`
219
+ };
220
+ }
221
+
222
+ const post = await response.json();
223
+ return {
224
+ success: true,
225
+ post: {
226
+ id: post.id,
227
+ title: post.title.rendered,
228
+ status: post.status,
229
+ link: post.link,
230
+ editLink: `${this.siteUrl}/wp-admin/post.php?post=${post.id}&action=edit`
231
+ }
232
+ };
233
+ } catch (error) {
234
+ return {
235
+ success: false,
236
+ error: error.message
237
+ };
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Search for posts
243
+ * @param {string} keyword - Search keyword
244
+ * @param {Object} [options] - Search options
245
+ * @param {string} [options.status] - Filter by status
246
+ * @param {number} [options.perPage=10] - Results per page
247
+ * @returns {Promise<{success: boolean, posts?: Object[], error?: string}>}
248
+ */
249
+ async searchPosts(keyword, options = {}) {
250
+ const initialized = await this.initialize();
251
+ if (!initialized) {
252
+ return {
253
+ success: false,
254
+ error: 'WordPress credentials not configured'
255
+ };
256
+ }
257
+
258
+ try {
259
+ const params = new URLSearchParams({
260
+ search: keyword,
261
+ per_page: String(options.perPage || 10)
262
+ });
263
+
264
+ if (options.status) {
265
+ params.append('status', options.status);
266
+ }
267
+
268
+ const response = await fetch(
269
+ `${this.siteUrl}/wp-json/wp/v2/posts?${params.toString()}`,
270
+ {
271
+ method: 'GET',
272
+ headers: this.getAuthHeaders()
273
+ }
274
+ );
275
+
276
+ if (!response.ok) {
277
+ const error = await response.json();
278
+ return {
279
+ success: false,
280
+ error: error.message || `HTTP ${response.status}`
281
+ };
282
+ }
283
+
284
+ const posts = await response.json();
285
+ return {
286
+ success: true,
287
+ posts: posts.map(p => ({
288
+ id: p.id,
289
+ title: p.title.rendered,
290
+ status: p.status,
291
+ link: p.link,
292
+ date: p.date,
293
+ modified: p.modified
294
+ }))
295
+ };
296
+ } catch (error) {
297
+ return {
298
+ success: false,
299
+ error: error.message
300
+ };
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Get a single post by ID
306
+ * @param {number} postId - Post ID
307
+ * @returns {Promise<{success: boolean, post?: Object, error?: string}>}
308
+ */
309
+ async getPost(postId) {
310
+ const initialized = await this.initialize();
311
+ if (!initialized) {
312
+ return {
313
+ success: false,
314
+ error: 'WordPress credentials not configured'
315
+ };
316
+ }
317
+
318
+ try {
319
+ const response = await fetch(
320
+ `${this.siteUrl}/wp-json/wp/v2/posts/${postId}`,
321
+ {
322
+ method: 'GET',
323
+ headers: this.getAuthHeaders()
324
+ }
325
+ );
326
+
327
+ if (!response.ok) {
328
+ const error = await response.json();
329
+ return {
330
+ success: false,
331
+ error: error.message || `HTTP ${response.status}`
332
+ };
333
+ }
334
+
335
+ const post = await response.json();
336
+ return {
337
+ success: true,
338
+ post: {
339
+ id: post.id,
340
+ title: post.title.rendered,
341
+ content: post.content.rendered,
342
+ status: post.status,
343
+ link: post.link,
344
+ date: post.date,
345
+ modified: post.modified,
346
+ categories: post.categories,
347
+ tags: post.tags
348
+ }
349
+ };
350
+ } catch (error) {
351
+ return {
352
+ success: false,
353
+ error: error.message
354
+ };
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Delete a post
360
+ * @param {number} postId - Post ID
361
+ * @param {boolean} [force=false] - Permanently delete (skip trash)
362
+ * @returns {Promise<{success: boolean, error?: string}>}
363
+ */
364
+ async deletePost(postId, force = false) {
365
+ const initialized = await this.initialize();
366
+ if (!initialized) {
367
+ return {
368
+ success: false,
369
+ error: 'WordPress credentials not configured'
370
+ };
371
+ }
372
+
373
+ try {
374
+ const params = force ? '?force=true' : '';
375
+ const response = await fetch(
376
+ `${this.siteUrl}/wp-json/wp/v2/posts/${postId}${params}`,
377
+ {
378
+ method: 'DELETE',
379
+ headers: this.getAuthHeaders()
380
+ }
381
+ );
382
+
383
+ if (!response.ok) {
384
+ const error = await response.json();
385
+ return {
386
+ success: false,
387
+ error: error.message || `HTTP ${response.status}`
388
+ };
389
+ }
390
+
391
+ return { success: true };
392
+ } catch (error) {
393
+ return {
394
+ success: false,
395
+ error: error.message
396
+ };
397
+ }
398
+ }
399
+
400
+ /**
401
+ * Get categories
402
+ * @returns {Promise<{success: boolean, categories?: Object[], error?: string}>}
403
+ */
404
+ async getCategories() {
405
+ const initialized = await this.initialize();
406
+ if (!initialized) {
407
+ return {
408
+ success: false,
409
+ error: 'WordPress credentials not configured'
410
+ };
411
+ }
412
+
413
+ try {
414
+ const response = await fetch(
415
+ `${this.siteUrl}/wp-json/wp/v2/categories?per_page=100`,
416
+ {
417
+ method: 'GET',
418
+ headers: this.getAuthHeaders()
419
+ }
420
+ );
421
+
422
+ if (!response.ok) {
423
+ return {
424
+ success: false,
425
+ error: `HTTP ${response.status}`
426
+ };
427
+ }
428
+
429
+ const categories = await response.json();
430
+ return {
431
+ success: true,
432
+ categories: categories.map(c => ({
433
+ id: c.id,
434
+ name: c.name,
435
+ slug: c.slug,
436
+ count: c.count
437
+ }))
438
+ };
439
+ } catch (error) {
440
+ return {
441
+ success: false,
442
+ error: error.message
443
+ };
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Get tags
449
+ * @returns {Promise<{success: boolean, tags?: Object[], error?: string}>}
450
+ */
451
+ async getTags() {
452
+ const initialized = await this.initialize();
453
+ if (!initialized) {
454
+ return {
455
+ success: false,
456
+ error: 'WordPress credentials not configured'
457
+ };
458
+ }
459
+
460
+ try {
461
+ const response = await fetch(
462
+ `${this.siteUrl}/wp-json/wp/v2/tags?per_page=100`,
463
+ {
464
+ method: 'GET',
465
+ headers: this.getAuthHeaders()
466
+ }
467
+ );
468
+
469
+ if (!response.ok) {
470
+ return {
471
+ success: false,
472
+ error: `HTTP ${response.status}`
473
+ };
474
+ }
475
+
476
+ const tags = await response.json();
477
+ return {
478
+ success: true,
479
+ tags: tags.map(t => ({
480
+ id: t.id,
481
+ name: t.name,
482
+ slug: t.slug,
483
+ count: t.count
484
+ }))
485
+ };
486
+ } catch (error) {
487
+ return {
488
+ success: false,
489
+ error: error.message
490
+ };
491
+ }
492
+ }
493
+
494
+ /**
495
+ * Create a category
496
+ * @param {string} name - Category name
497
+ * @param {string} [description] - Category description
498
+ * @returns {Promise<{success: boolean, category?: Object, error?: string}>}
499
+ */
500
+ async createCategory(name, description = '') {
501
+ const initialized = await this.initialize();
502
+ if (!initialized) {
503
+ return {
504
+ success: false,
505
+ error: 'WordPress credentials not configured'
506
+ };
507
+ }
508
+
509
+ try {
510
+ const response = await fetch(
511
+ `${this.siteUrl}/wp-json/wp/v2/categories`,
512
+ {
513
+ method: 'POST',
514
+ headers: this.getAuthHeaders(),
515
+ body: JSON.stringify({
516
+ name,
517
+ description,
518
+ slug: this.generateSlug(name)
519
+ })
520
+ }
521
+ );
522
+
523
+ if (!response.ok) {
524
+ const error = await response.json();
525
+ return {
526
+ success: false,
527
+ error: error.message || `HTTP ${response.status}`
528
+ };
529
+ }
530
+
531
+ const category = await response.json();
532
+ return {
533
+ success: true,
534
+ category: {
535
+ id: category.id,
536
+ name: category.name,
537
+ slug: category.slug
538
+ }
539
+ };
540
+ } catch (error) {
541
+ return {
542
+ success: false,
543
+ error: error.message
544
+ };
545
+ }
546
+ }
547
+
548
+ /**
549
+ * Convert markdown to HTML (basic conversion)
550
+ * @param {string} markdown - Markdown content
551
+ * @returns {string} HTML content
552
+ */
553
+ convertMarkdownToHtml(markdown) {
554
+ if (!markdown) return '';
555
+
556
+ let html = markdown;
557
+
558
+ // Headers
559
+ html = html.replace(/^######\s+(.+)$/gm, '<h6>$1</h6>');
560
+ html = html.replace(/^#####\s+(.+)$/gm, '<h5>$1</h5>');
561
+ html = html.replace(/^####\s+(.+)$/gm, '<h4>$1</h4>');
562
+ html = html.replace(/^###\s+(.+)$/gm, '<h3>$1</h3>');
563
+ html = html.replace(/^##\s+(.+)$/gm, '<h2>$1</h2>');
564
+ html = html.replace(/^#\s+(.+)$/gm, '<h1>$1</h1>');
565
+
566
+ // Bold and italic
567
+ html = html.replace(/\*\*\*(.+?)\*\*\*/g, '<strong><em>$1</em></strong>');
568
+ html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
569
+ html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
570
+
571
+ // Links
572
+ html = html.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2">$1</a>');
573
+
574
+ // Images
575
+ html = html.replace(/!\[(.+?)\]\((.+?)\)/g, '<img src="$2" alt="$1">');
576
+
577
+ // Code blocks
578
+ html = html.replace(/```(\w+)?\n([\s\S]+?)```/g, '<pre><code>$2</code></pre>');
579
+ html = html.replace(/`(.+?)`/g, '<code>$1</code>');
580
+
581
+ // Lists
582
+ html = html.replace(/^\*\s+(.+)$/gm, '<li>$1</li>');
583
+ html = html.replace(/^-\s+(.+)$/gm, '<li>$1</li>');
584
+ html = html.replace(/(<li>.*<\/li>\n?)+/g, '<ul>$&</ul>');
585
+
586
+ html = html.replace(/^\d+\.\s+(.+)$/gm, '<li>$1</li>');
587
+ html = html.replace(/(<li>.*<\/li>\n?)+/g, (match) => {
588
+ if (match.includes('<ul>')) return match;
589
+ return '<ol>' + match + '</ol>';
590
+ });
591
+
592
+ // Paragraphs
593
+ html = html.replace(/\n\n+/g, '</p><p>');
594
+ html = '<p>' + html + '</p>';
595
+ html = html.replace(/<p>(<h\d>)/g, '$1');
596
+ html = html.replace(/(<\/h\d>)<\/p>/g, '$1');
597
+ html = html.replace(/<p>(<ul>)/g, '$1');
598
+ html = html.replace(/(<\/ul>)<\/p>/g, '$1');
599
+ html = html.replace(/<p>(<ol>)/g, '$1');
600
+ html = html.replace(/(<\/ol>)<\/p>/g, '$1');
601
+ html = html.replace(/<p>(<pre>)/g, '$1');
602
+ html = html.replace(/(<\/pre>)<\/p>/g, '$1');
603
+ html = html.replace(/<p>\s*<\/p>/g, '');
604
+
605
+ // Line breaks
606
+ html = html.replace(/\n/g, '<br>');
607
+ html = html.replace(/<br><br>/g, '</p><p>');
608
+
609
+ return html;
610
+ }
611
+
612
+ /**
613
+ * Generate URL slug from title
614
+ * @param {string} title - Title to slugify
615
+ * @returns {string} URL slug
616
+ */
617
+ generateSlug(title) {
618
+ return title
619
+ .toLowerCase()
620
+ .trim()
621
+ .replace(/[^\w\s-]/g, '')
622
+ .replace(/[\s_]+/g, '-')
623
+ .replace(/-+/g, '-')
624
+ .replace(/^-+|-+$/g, '');
625
+ }
626
+ }
627
+
628
+ // Factory function
629
+ export function createWordPressClient(options) {
630
+ return new WordPressClient(options);
631
+ }
632
+
633
+ export default WordPressClient;
@@ -107,7 +107,7 @@ class WorkflowInstaller {
107
107
 
108
108
  let installed = 0;
109
109
  for (const agent of agents) {
110
- const sourcePath = path.join(__dirname, '..', 'agents', `${agent}.md`);
110
+ const sourcePath = path.join(__dirname, '..', 'templates', 'claude', 'agents', `${agent}.md`);
111
111
  const targetPath = path.join(agentsDir, `${agent}.md`);
112
112
 
113
113
  try {
@@ -141,7 +141,7 @@ class WorkflowInstaller {
141
141
 
142
142
  let installed = 0;
143
143
  for (const command of commands) {
144
- const sourcePath = path.join(__dirname, '..', 'commands', `${command}.md`);
144
+ const sourcePath = path.join(__dirname, '..', 'templates', 'claude', 'commands', `${command}.md`);
145
145
  const targetPath = path.join(commandsDir, `${command}.md`);
146
146
 
147
147
  try {
@@ -240,7 +240,7 @@ class WorkflowInstaller {
240
240
 
241
241
  let installed = 0;
242
242
  for (const doc of docs) {
243
- const sourcePath = path.join(__dirname, '..', '..', 'docs', doc);
243
+ const sourcePath = path.join(__dirname, '..', 'templates', 'docs', doc);
244
244
  const targetPath = path.join(docsDir, doc);
245
245
 
246
246
  try {