myaidev-method 0.2.18 → 0.2.22

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 (31) hide show
  1. package/.claude/mcp/sparc-orchestrator-server.js +0 -0
  2. package/.claude/mcp/wordpress-server.js +0 -0
  3. package/CHANGELOG.md +145 -0
  4. package/README.md +205 -13
  5. package/TECHNICAL_ARCHITECTURE.md +64 -2
  6. package/bin/cli.js +169 -2
  7. package/dist/mcp/mcp-config.json +138 -1
  8. package/dist/mcp/openstack-server.js +1607 -0
  9. package/package.json +2 -2
  10. package/src/config/workflows.js +532 -0
  11. package/src/lib/payloadcms-utils.js +343 -10
  12. package/src/lib/visual-generation-utils.js +445 -294
  13. package/src/lib/workflow-installer.js +512 -0
  14. package/src/libs/security/authorization-checker.js +606 -0
  15. package/src/mcp/openstack-server.js +1607 -0
  16. package/src/scripts/openstack-setup.sh +110 -0
  17. package/src/scripts/security/environment-detect.js +425 -0
  18. package/src/templates/claude/agents/openstack-vm-manager.md +281 -0
  19. package/src/templates/claude/agents/osint-researcher.md +1075 -0
  20. package/src/templates/claude/agents/penetration-tester.md +908 -0
  21. package/src/templates/claude/agents/security-auditor.md +244 -0
  22. package/src/templates/claude/agents/security-setup.md +1094 -0
  23. package/src/templates/claude/agents/webapp-security-tester.md +581 -0
  24. package/src/templates/claude/commands/myai-configure.md +84 -0
  25. package/src/templates/claude/commands/myai-openstack.md +229 -0
  26. package/src/templates/claude/commands/sc:security-exploit.md +464 -0
  27. package/src/templates/claude/commands/sc:security-recon.md +281 -0
  28. package/src/templates/claude/commands/sc:security-report.md +756 -0
  29. package/src/templates/claude/commands/sc:security-scan.md +441 -0
  30. package/src/templates/claude/commands/sc:security-setup.md +501 -0
  31. package/src/templates/claude/mcp_config.json +44 -0
@@ -144,7 +144,7 @@ export class PayloadCMSUtils {
144
144
 
145
145
  case 'list':
146
146
  return {
147
- type: token.ordered ? 'number' : 'bullet',
147
+ type: 'list',
148
148
  listType: token.ordered ? 'number' : 'bullet',
149
149
  start: token.start || 1,
150
150
  tag: token.ordered ? 'ol' : 'ul',
@@ -213,7 +213,10 @@ export class PayloadCMSUtils {
213
213
  }
214
214
  };
215
215
 
216
- const children = tokens.map(convertToken);
216
+ // Filter out space tokens and convert remaining tokens
217
+ const children = tokens
218
+ .filter(token => token.type !== 'space')
219
+ .map(convertToken);
217
220
 
218
221
  return {
219
222
  root: {
@@ -229,24 +232,353 @@ export class PayloadCMSUtils {
229
232
 
230
233
  /**
231
234
  * Parse inline text with formatting (bold, italic, code, links)
235
+ * Supports markdown formatters and converts to Lexical format codes:
236
+ * - **bold** → format: 1
237
+ * - *italic* → format: 2
238
+ * - `code` → format: 16
239
+ * - ***bold+italic*** → format: 3
232
240
  */
233
241
  parseInlineText(text) {
234
- // Simple inline parser for bold, italic, code, links
235
242
  const children = [];
236
243
 
237
- // For now, return simple text node
238
- // TODO: Enhance with full inline formatting support
239
- children.push({
244
+ // Strip HTML tags first
245
+ text = text.replace(/<[^>]+>/g, '');
246
+
247
+ // Parse markdown inline formatting using marked's inline lexer
248
+ try {
249
+ const tokens = marked.lexer(text);
250
+
251
+ // Extract inline tokens from paragraph if present
252
+ let inlineTokens = [];
253
+ if (tokens[0]?.type === 'paragraph' && tokens[0].tokens) {
254
+ inlineTokens = tokens[0].tokens;
255
+ } else if (tokens[0]?.tokens) {
256
+ inlineTokens = tokens[0].tokens;
257
+ } else {
258
+ // No inline tokens, return plain text
259
+ return [{
260
+ type: 'text',
261
+ text: text,
262
+ format: 0,
263
+ mode: 'normal',
264
+ style: '',
265
+ detail: 0,
266
+ version: 1
267
+ }];
268
+ }
269
+
270
+ // Convert each inline token to Lexical format
271
+ for (const token of inlineTokens) {
272
+ switch (token.type) {
273
+ case 'text':
274
+ children.push({
275
+ type: 'text',
276
+ text: token.text,
277
+ format: 0,
278
+ mode: 'normal',
279
+ style: '',
280
+ detail: 0,
281
+ version: 1
282
+ });
283
+ break;
284
+
285
+ case 'strong':
286
+ children.push({
287
+ type: 'text',
288
+ text: token.text,
289
+ format: 1, // IS_BOLD
290
+ mode: 'normal',
291
+ style: '',
292
+ detail: 0,
293
+ version: 1
294
+ });
295
+ break;
296
+
297
+ case 'em':
298
+ children.push({
299
+ type: 'text',
300
+ text: token.text,
301
+ format: 2, // IS_ITALIC
302
+ mode: 'normal',
303
+ style: '',
304
+ detail: 0,
305
+ version: 1
306
+ });
307
+ break;
308
+
309
+ case 'codespan':
310
+ children.push({
311
+ type: 'text',
312
+ text: token.text,
313
+ format: 16, // IS_CODE
314
+ mode: 'normal',
315
+ style: '',
316
+ detail: 0,
317
+ version: 1
318
+ });
319
+ break;
320
+
321
+ case 'link':
322
+ children.push({
323
+ type: 'link',
324
+ url: token.href,
325
+ children: [{
326
+ type: 'text',
327
+ text: token.text,
328
+ format: 0,
329
+ mode: 'normal',
330
+ style: '',
331
+ detail: 0,
332
+ version: 1
333
+ }],
334
+ direction: 'ltr',
335
+ format: '',
336
+ indent: 0,
337
+ version: 3
338
+ });
339
+ break;
340
+
341
+ default:
342
+ // Fallback for any unhandled token types
343
+ children.push({
344
+ type: 'text',
345
+ text: token.raw || token.text || '',
346
+ format: 0,
347
+ mode: 'normal',
348
+ style: '',
349
+ detail: 0,
350
+ version: 1
351
+ });
352
+ }
353
+ }
354
+ } catch (error) {
355
+ // If parsing fails, return plain text
356
+ children.push({
357
+ type: 'text',
358
+ text: text,
359
+ format: 0,
360
+ mode: 'normal',
361
+ style: '',
362
+ detail: 0,
363
+ version: 1
364
+ });
365
+ }
366
+
367
+ return children.length > 0 ? children : [{
240
368
  type: 'text',
241
- text: text.replace(/<[^>]+>/g, ''), // Strip HTML tags
369
+ text: text,
242
370
  format: 0,
243
371
  mode: 'normal',
244
372
  style: '',
245
373
  detail: 0,
246
374
  version: 1
375
+ }];
376
+ }
377
+
378
+ /**
379
+ * Validate Lexical JSON structure
380
+ * Ensures output matches PayloadCMS Lexical editor format
381
+ * @param {Object} lexicalJSON - The Lexical JSON to validate
382
+ * @param {Object} options - Validation options
383
+ * @returns {Object} Validation result with errors array
384
+ */
385
+ validateLexicalStructure(lexicalJSON, options = {}) {
386
+ const errors = [];
387
+ const warnings = [];
388
+
389
+ // Check root structure
390
+ if (!lexicalJSON || typeof lexicalJSON !== 'object') {
391
+ errors.push('Lexical JSON must be an object');
392
+ return { valid: false, errors, warnings };
393
+ }
394
+
395
+ if (!lexicalJSON.root) {
396
+ errors.push('Missing root node');
397
+ return { valid: false, errors, warnings };
398
+ }
399
+
400
+ const root = lexicalJSON.root;
401
+
402
+ // Validate root node
403
+ if (root.type !== 'root') {
404
+ errors.push(`Root type must be 'root', got '${root.type}'`);
405
+ }
406
+
407
+ if (!Array.isArray(root.children)) {
408
+ errors.push('Root must have children array');
409
+ return { valid: false, errors, warnings };
410
+ }
411
+
412
+ // Validate each child node
413
+ const validateNode = (node, path = 'root') => {
414
+ if (!node || typeof node !== 'object') {
415
+ errors.push(`${path}: Node must be an object`);
416
+ return;
417
+ }
418
+
419
+ if (!node.type) {
420
+ errors.push(`${path}: Node missing type property`);
421
+ return;
422
+ }
423
+
424
+ // Validate based on node type
425
+ switch (node.type) {
426
+ case 'heading':
427
+ if (!node.tag || !/^h[1-6]$/.test(node.tag)) {
428
+ errors.push(`${path}: Heading must have tag h1-h6, got '${node.tag}'`);
429
+ }
430
+ if (!Array.isArray(node.children)) {
431
+ errors.push(`${path}: Heading must have children array`);
432
+ }
433
+ break;
434
+
435
+ case 'paragraph':
436
+ if (!Array.isArray(node.children)) {
437
+ errors.push(`${path}: Paragraph must have children array`);
438
+ }
439
+ break;
440
+
441
+ case 'list':
442
+ if (!['bullet', 'number', 'check'].includes(node.listType)) {
443
+ errors.push(`${path}: List listType must be bullet/number/check, got '${node.listType}'`);
444
+ }
445
+ if (!['ul', 'ol'].includes(node.tag)) {
446
+ errors.push(`${path}: List tag must be ul/ol, got '${node.tag}'`);
447
+ }
448
+ if (!Array.isArray(node.children)) {
449
+ errors.push(`${path}: List must have children array`);
450
+ }
451
+ // Validate list items
452
+ node.children?.forEach((item, i) => {
453
+ if (item.type !== 'listitem') {
454
+ errors.push(`${path}.children[${i}]: List child must be listitem, got '${item.type}'`);
455
+ }
456
+ });
457
+ break;
458
+
459
+ case 'listitem':
460
+ if (!Array.isArray(node.children)) {
461
+ errors.push(`${path}: Listitem must have children array`);
462
+ }
463
+ break;
464
+
465
+ case 'text':
466
+ if (typeof node.text !== 'string') {
467
+ errors.push(`${path}: Text node must have string text property`);
468
+ }
469
+ if (typeof node.format !== 'number') {
470
+ errors.push(`${path}: Text node format must be number, got ${typeof node.format}`);
471
+ }
472
+ // Validate format is valid bitwise combination
473
+ if (node.format !== 0 && options.strictFormat) {
474
+ const validFormats = [1, 2, 3, 4, 8, 16, 32, 64, 128];
475
+ const isValidCombination = (format) => {
476
+ // Check if format is valid bitwise combination of base values
477
+ return format <= 255 && (format & ~255) === 0;
478
+ };
479
+ if (!isValidCombination(node.format)) {
480
+ warnings.push(`${path}: Unusual format value ${node.format}, expected bitwise combination`);
481
+ }
482
+ }
483
+ break;
484
+
485
+ case 'link':
486
+ if (typeof node.url !== 'string') {
487
+ errors.push(`${path}: Link must have string url property`);
488
+ }
489
+ if (!Array.isArray(node.children)) {
490
+ errors.push(`${path}: Link must have children array`);
491
+ }
492
+ break;
493
+
494
+ case 'code':
495
+ if (!Array.isArray(node.children)) {
496
+ errors.push(`${path}: Code must have children array`);
497
+ }
498
+ break;
499
+
500
+ case 'quote':
501
+ if (!Array.isArray(node.children)) {
502
+ errors.push(`${path}: Quote must have children array`);
503
+ }
504
+ break;
505
+
506
+ case 'horizontalrule':
507
+ // HR nodes don't have children
508
+ break;
509
+
510
+ default:
511
+ if (options.strict) {
512
+ warnings.push(`${path}: Unknown node type '${node.type}'`);
513
+ }
514
+ }
515
+
516
+ // Recursively validate children
517
+ if (Array.isArray(node.children)) {
518
+ node.children.forEach((child, i) => {
519
+ validateNode(child, `${path}.children[${i}]`);
520
+ });
521
+ }
522
+ };
523
+
524
+ // Validate all root children
525
+ root.children.forEach((child, i) => {
526
+ validateNode(child, `root.children[${i}]`);
247
527
  });
248
528
 
249
- return children;
529
+ return {
530
+ valid: errors.length === 0,
531
+ errors,
532
+ warnings
533
+ };
534
+ }
535
+
536
+ /**
537
+ * Validate and optionally fix Lexical format codes
538
+ * Ensures format codes follow Lexical bitwise specification
539
+ * @param {number} format - The format code to validate
540
+ * @returns {Object} Validation result
541
+ */
542
+ validateFormatCode(format) {
543
+ const VALID_FORMATS = {
544
+ BOLD: 1, // 1 << 0
545
+ ITALIC: 2, // 1 << 1
546
+ STRIKETHROUGH: 4, // 1 << 2
547
+ UNDERLINE: 8, // 1 << 3
548
+ CODE: 16, // 1 << 4
549
+ SUBSCRIPT: 32, // 1 << 5
550
+ SUPERSCRIPT: 64, // 1 << 6
551
+ HIGHLIGHT: 128 // 1 << 7
552
+ };
553
+
554
+ if (typeof format !== 'number') {
555
+ return {
556
+ valid: false,
557
+ error: `Format must be number, got ${typeof format}`
558
+ };
559
+ }
560
+
561
+ if (format < 0 || format > 255) {
562
+ return {
563
+ valid: false,
564
+ error: `Format must be between 0 and 255, got ${format}`
565
+ };
566
+ }
567
+
568
+ // Decompose format into individual flags
569
+ const flags = [];
570
+ Object.entries(VALID_FORMATS).forEach(([name, value]) => {
571
+ if ((format & value) === value) {
572
+ flags.push(name);
573
+ }
574
+ });
575
+
576
+ return {
577
+ valid: true,
578
+ format,
579
+ flags,
580
+ description: flags.length > 0 ? flags.join(' + ') : 'Plain text'
581
+ };
250
582
  }
251
583
 
252
584
  /**
@@ -372,11 +704,12 @@ export class PayloadCMSUtils {
372
704
  }
373
705
 
374
706
  /**
375
- * Health check
707
+ * Health check - verifies PayloadCMS connectivity and database access
708
+ * Uses /api/posts endpoint to verify both API and database are accessible
376
709
  */
377
710
  async healthCheck() {
378
711
  try {
379
- const response = await fetch(`${this.url}/api`);
712
+ const response = await fetch(`${this.url}/api/posts?limit=1`);
380
713
  return response.ok;
381
714
  } catch (error) {
382
715
  return false;