myaidev-method 0.3.3 → 0.3.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.
Files changed (132) hide show
  1. package/.claude-plugin/plugin.json +0 -1
  2. package/.env.example +5 -4
  3. package/CHANGELOG.md +2 -2
  4. package/CONTENT_CREATION_GUIDE.md +489 -3211
  5. package/DEVELOPER_USE_CASES.md +1 -1
  6. package/MODULAR_INSTALLATION.md +2 -2
  7. package/README.md +39 -33
  8. package/TECHNICAL_ARCHITECTURE.md +1 -1
  9. package/USER_GUIDE.md +242 -190
  10. package/agents/content-editor-agent.md +90 -0
  11. package/agents/content-planner-agent.md +97 -0
  12. package/agents/content-research-agent.md +62 -0
  13. package/agents/content-seo-agent.md +101 -0
  14. package/agents/content-writer-agent.md +69 -0
  15. package/agents/infographic-analyzer-agent.md +63 -0
  16. package/agents/infographic-designer-agent.md +72 -0
  17. package/bin/cli.js +777 -535
  18. package/{content-rules.example.md → content-rules-example.md} +2 -2
  19. package/dist/mcp/health-check.js +82 -68
  20. package/dist/mcp/mcp-config.json +8 -0
  21. package/dist/mcp/openstack-server.js +1746 -1262
  22. package/dist/server/.tsbuildinfo +1 -1
  23. package/extension.json +21 -4
  24. package/package.json +181 -184
  25. package/skills/company-config/SKILL.md +133 -0
  26. package/skills/configure/SKILL.md +1 -1
  27. package/skills/myai-configurator/SKILL.md +77 -0
  28. package/skills/myai-configurator/content-creation-configurator/SKILL.md +516 -0
  29. package/skills/myai-configurator/content-maintenance-configurator/SKILL.md +397 -0
  30. package/skills/myai-content-enrichment/SKILL.md +114 -0
  31. package/skills/myai-content-ideation/SKILL.md +288 -0
  32. package/skills/myai-content-ideation/evals/evals.json +182 -0
  33. package/skills/myai-content-production-coordinator/SKILL.md +946 -0
  34. package/skills/{content-rules-setup → myai-content-rules-setup}/SKILL.md +1 -1
  35. package/skills/{content-verifier → myai-content-verifier}/SKILL.md +1 -1
  36. package/skills/myai-content-writer/SKILL.md +333 -0
  37. package/skills/myai-content-writer/agents/editor-agent.md +138 -0
  38. package/skills/myai-content-writer/agents/planner-agent.md +121 -0
  39. package/skills/myai-content-writer/agents/research-agent.md +83 -0
  40. package/skills/myai-content-writer/agents/seo-agent.md +139 -0
  41. package/skills/myai-content-writer/agents/visual-planner-agent.md +110 -0
  42. package/skills/myai-content-writer/agents/writer-agent.md +85 -0
  43. package/skills/{infographic → myai-infographic}/SKILL.md +1 -1
  44. package/skills/myai-proprietary-content-verifier/SKILL.md +175 -0
  45. package/skills/myai-proprietary-content-verifier/evals/evals.json +36 -0
  46. package/skills/myai-skill-builder/SKILL.md +699 -0
  47. package/skills/myai-skill-builder/agents/analyzer-agent.md +137 -0
  48. package/skills/myai-skill-builder/agents/comparator-agent.md +77 -0
  49. package/skills/myai-skill-builder/agents/grader-agent.md +103 -0
  50. package/skills/myai-skill-builder/assets/eval_review.html +131 -0
  51. package/skills/myai-skill-builder/references/schemas.md +211 -0
  52. package/skills/myai-skill-builder/scripts/aggregate_benchmark.py +190 -0
  53. package/skills/myai-skill-builder/scripts/generate_review.py +381 -0
  54. package/skills/myai-skill-builder/scripts/package_skill.py +91 -0
  55. package/skills/myai-skill-builder/scripts/run_eval.py +105 -0
  56. package/skills/myai-skill-builder/scripts/run_loop.py +211 -0
  57. package/skills/myai-skill-builder/scripts/utils.py +123 -0
  58. package/skills/myai-visual-generator/SKILL.md +125 -0
  59. package/skills/myai-visual-generator/evals/evals.json +155 -0
  60. package/skills/myai-visual-generator/references/infographic-pipeline.md +73 -0
  61. package/skills/myai-visual-generator/references/research-visuals.md +57 -0
  62. package/skills/myai-visual-generator/references/services.md +89 -0
  63. package/skills/myai-visual-generator/scripts/visual-generation-utils.js +1272 -0
  64. package/skills/myaidev-analyze/agents/dependency-mapper-agent.md +236 -0
  65. package/skills/myaidev-analyze/agents/pattern-detector-agent.md +240 -0
  66. package/skills/myaidev-analyze/agents/structure-scanner-agent.md +171 -0
  67. package/skills/myaidev-analyze/agents/tech-profiler-agent.md +291 -0
  68. package/skills/myaidev-architect/agents/compliance-checker-agent.md +287 -0
  69. package/skills/myaidev-architect/agents/requirements-analyst-agent.md +194 -0
  70. package/skills/myaidev-architect/agents/system-designer-agent.md +315 -0
  71. package/skills/myaidev-coder/agents/implementer-agent.md +185 -0
  72. package/skills/myaidev-coder/agents/integration-agent.md +168 -0
  73. package/skills/myaidev-coder/agents/pattern-scanner-agent.md +161 -0
  74. package/skills/myaidev-coder/agents/self-reviewer-agent.md +168 -0
  75. package/skills/myaidev-debug/agents/fix-agent-debug.md +317 -0
  76. package/skills/myaidev-debug/agents/hypothesis-agent.md +226 -0
  77. package/skills/myaidev-debug/agents/investigator-agent.md +250 -0
  78. package/skills/myaidev-debug/agents/symptom-collector-agent.md +231 -0
  79. package/skills/myaidev-documenter/agents/code-reader-agent.md +172 -0
  80. package/skills/myaidev-documenter/agents/doc-validator-agent.md +174 -0
  81. package/skills/myaidev-documenter/agents/doc-writer-agent.md +379 -0
  82. package/skills/myaidev-figma/SKILL.md +212 -0
  83. package/skills/myaidev-figma/capture.js +133 -0
  84. package/skills/myaidev-figma/crawl.js +130 -0
  85. package/skills/myaidev-figma-configure/SKILL.md +130 -0
  86. package/skills/myaidev-migrate/agents/migration-planner-agent.md +237 -0
  87. package/skills/myaidev-migrate/agents/migration-writer-agent.md +248 -0
  88. package/skills/myaidev-migrate/agents/schema-analyzer-agent.md +190 -0
  89. package/skills/myaidev-performance/agents/benchmark-agent.md +281 -0
  90. package/skills/myaidev-performance/agents/optimizer-agent.md +277 -0
  91. package/skills/myaidev-performance/agents/profiler-agent.md +252 -0
  92. package/skills/myaidev-refactor/agents/refactor-executor-agent.md +221 -0
  93. package/skills/myaidev-refactor/agents/refactor-planner-agent.md +213 -0
  94. package/skills/myaidev-refactor/agents/regression-guard-agent.md +242 -0
  95. package/skills/myaidev-refactor/agents/smell-detector-agent.md +233 -0
  96. package/skills/myaidev-reviewer/agents/auto-fixer-agent.md +238 -0
  97. package/skills/myaidev-reviewer/agents/code-analyst-agent.md +220 -0
  98. package/skills/myaidev-reviewer/agents/security-scanner-agent.md +262 -0
  99. package/skills/myaidev-tester/agents/coverage-analyst-agent.md +163 -0
  100. package/skills/myaidev-tester/agents/tdd-driver-agent.md +242 -0
  101. package/skills/myaidev-tester/agents/test-runner-agent.md +176 -0
  102. package/skills/myaidev-tester/agents/test-strategist-agent.md +154 -0
  103. package/skills/myaidev-tester/agents/test-writer-agent.md +242 -0
  104. package/skills/myaidev-workflow/agents/analyzer-agent.md +317 -0
  105. package/skills/myaidev-workflow/agents/coordinator-agent.md +253 -0
  106. package/skills/openstack-manager/SKILL.md +1 -1
  107. package/skills/payloadcms-publisher/SKILL.md +141 -77
  108. package/skills/payloadcms-publisher/references/field-mapping.md +142 -0
  109. package/skills/payloadcms-publisher/references/lexical-format.md +97 -0
  110. package/skills/security-auditor/SKILL.md +1 -1
  111. package/src/cli/commands/addon.js +184 -123
  112. package/src/config/workflows.js +172 -228
  113. package/src/lib/ascii-banner.js +197 -182
  114. package/src/lib/{content-coordinator.js → content-production-coordinator.js} +649 -459
  115. package/src/lib/installation-detector.js +93 -59
  116. package/src/lib/payloadcms-utils.js +285 -510
  117. package/src/lib/update-manager.js +120 -61
  118. package/src/lib/workflow-installer.js +55 -0
  119. package/src/mcp/health-check.js +82 -68
  120. package/src/mcp/openstack-server.js +1746 -1262
  121. package/src/scripts/configure-visual-apis.js +224 -173
  122. package/src/scripts/configure-wordpress-mcp.js +96 -66
  123. package/src/scripts/init/install.js +109 -85
  124. package/src/scripts/init-project.js +138 -67
  125. package/src/scripts/utils/write-content.js +67 -52
  126. package/src/scripts/wordpress/publish-to-wordpress.js +128 -128
  127. package/src/templates/claude/CLAUDE.md +131 -0
  128. package/hooks/hooks.json +0 -26
  129. package/skills/content-coordinator/SKILL.md +0 -130
  130. package/skills/content-enrichment/SKILL.md +0 -80
  131. package/skills/content-writer/SKILL.md +0 -285
  132. package/skills/visual-generator/SKILL.md +0 -140
@@ -1,96 +1,160 @@
1
1
  ---
2
2
  name: payloadcms-publisher
3
- description: Publishes markdown content to PayloadCMS with Lexical rich text conversion and media handling. Use when publishing content to a PayloadCMS instance.
3
+ description: Publishes markdown content to PayloadCMS with automatic Lexical rich text conversion, SEO metadata generation, and media uploads. Use when publishing content to a PayloadCMS instance, uploading articles to Payload CMS, or when the user mentions PayloadCMS publishing.
4
4
  argument-hint: "[file.md] [--status draft|published] [--collection posts] [--dry-run]"
5
- allowed-tools: [Read, Write, Edit, Bash, Glob, Grep]
5
+ allowed-tools: [Read, Edit, Bash, Glob, Grep]
6
6
  disable-model-invocation: true
7
7
  ---
8
8
 
9
9
  # PayloadCMS Publisher
10
10
 
11
- You are a **PayloadCMS Publishing Agent** converting markdown content to PayloadCMS Lexical rich text format and publishing via the REST API.
12
-
13
- ## Arguments
14
-
15
- - `[file.md]` → Source markdown file (required)
16
- - `--status draft|published` → Publish status (default: draft)
17
- - `--collection <name>` → Target collection (default: posts)
18
- - `--id <doc-id>` → Update existing document
19
- - `--dry-run` → Validate without publishing
20
- - `--verbose` → Show detailed progress
21
-
22
- ## Workflow
23
-
24
- 1. **Read source file** — Parse frontmatter and markdown content
25
- 2. **Load credentials** — Read from .env: `PAYLOADCMS_URL`, `PAYLOADCMS_EMAIL`, `PAYLOADCMS_PASSWORD`
26
- 3. **Authenticate** — Login via `POST /api/users/login`
27
- 4. **Convert markdown to Lexical:**
28
- - Headings → heading nodes with proper levels
29
- - Paragraphs → paragraph nodes with text children
30
- - Lists → list nodes (ordered/unordered)
31
- - Code blocks → code nodes with language
32
- - Links → link nodes with URL
33
- - Images → upload nodes (upload media first)
34
- - Bold/italic → text nodes with format flags
35
- 5. **Handle media:**
36
- - Extract image references from content
37
- - Upload images via `POST /api/media`
38
- - Replace references with upload IDs
39
- 6. **Publish:**
40
- - New: `POST /api/{collection}`
41
- - Update: `PATCH /api/{collection}/{id}`
42
- - Set `_status` field based on --status flag
43
- 7. **Report:** Document URL and ID
44
-
45
- ## Lexical Format
46
-
47
- PayloadCMS uses Lexical editor format:
48
- ```json
49
- {
50
- "root": {
51
- "type": "root",
52
- "children": [
53
- {
54
- "type": "heading",
55
- "tag": "h2",
56
- "children": [{"type": "text", "text": "Title"}]
57
- },
58
- {
59
- "type": "paragraph",
60
- "children": [{"type": "text", "text": "Content"}]
61
- }
62
- ]
63
- }
64
- }
11
+ Publish markdown files to PayloadCMS via the bundled script. The script handles authentication, markdown-to-Lexical conversion, image uploads, and API calls.
12
+
13
+ ## Prerequisites
14
+
15
+ Credentials in `.env`:
16
+
17
+ ```
18
+ PAYLOADCMS_URL=https://your-payload-instance.com
19
+ PAYLOADCMS_EMAIL=admin@example.com
20
+ PAYLOADCMS_PASSWORD=your-password
65
21
  ```
66
22
 
67
- ## Field Mapping
23
+ Run `/myaidev-method:configure payloadcms` to set these up.
68
24
 
69
- | Frontmatter | PayloadCMS Field |
70
- |-------------|-----------------|
71
- | title | title |
72
- | meta_description | meta.description |
73
- | slug | slug |
74
- | tags | tags (relationship) |
75
- | category | category (relationship) |
76
- | featured_image | featuredImage (upload) |
25
+ ## Publishing workflow
77
26
 
78
- ## Prerequisites
27
+ Follow these steps in order.
28
+
29
+ ### Step 1: Read and validate the source file
79
30
 
80
- - PayloadCMS instance with REST API enabled
81
- - Credentials configured via `/configure payloadcms`
82
- - Target collection must exist in PayloadCMS schema
31
+ Read the markdown file. Verify it has YAML frontmatter with at least a `title`. Stop if missing.
83
32
 
84
- ## Error Handling
33
+ ### Step 2: Auto-populate missing fields
85
34
 
86
- - Auth failure report credential issue, suggest `/configure payloadcms`
87
- - Collection not found → list available collections
88
- - Validation error → show which fields failed
89
- - Upload failure → publish without images, report which failed
35
+ Inspect the frontmatter. For any of these fields that are **missing or empty**, generate them from the content body and write them into the frontmatter before publishing:
90
36
 
91
- ## Script Integration
37
+ | Field | How to generate | Max length |
38
+ |-------|----------------|------------|
39
+ | `slug` | Kebab-case from `title` | 80 chars |
40
+ | `excerpt` | Summarize the article in 1-2 sentences. Capture the core value proposition. | 160 chars |
41
+ | `meta.title` | SEO-optimized variation of `title`. Include primary keyword near the front. | 60 chars |
42
+ | `meta.description` | Compelling search snippet. Include primary keyword, end with implicit CTA. | 155 chars |
43
+ | `heroImage` | If the first element in the content body is a standalone image (`![alt](path)` on its own line), **promote** it: remove it from the body and note the path for hero image upload in Step 3. | |
44
+
45
+ **Do not overwrite** fields the user already set. Only fill gaps.
46
+
47
+ After generating, write the updated frontmatter back to the file, then re-read to confirm.
48
+
49
+ ### Step 3: Upload hero image (if needed)
50
+
51
+ If Step 2 identified a hero image to promote, upload it before publishing:
92
52
 
93
- Can invoke the publishing script for complex operations:
94
53
  ```bash
95
- node .myaidev-method/scripts/payloadcms-publish.js "article.md" --status draft
54
+ node --input-type=module -e "
55
+ import { PayloadCMSUtils } from '${CLAUDE_PLUGIN_ROOT}/src/lib/payloadcms-utils.js';
56
+ const u = new PayloadCMSUtils(); await u.authenticate();
57
+ const r = await u.uploadMedia('<hero-path>', '<hero-alt>');
58
+ console.log(JSON.stringify({ id: r.doc?.id || r.id }));
59
+ "
60
+ ```
61
+
62
+ Substitute `<hero-path>` and `<hero-alt>` with the image path and alt text from the promoted image.
63
+
64
+ Then set `heroImage` in frontmatter to the returned media ID.
65
+
66
+ ### Step 4: Dry run
67
+
68
+ ```bash
69
+ node "${CLAUDE_PLUGIN_ROOT}/src/scripts/payloadcms-publish.js" "<file>" --collection "<collection>" --status "<status>" --dry-run --json --verbose
70
+ ```
71
+
72
+ Defaults: collection=`posts`, status=`draft`. Parse stdout as JSON. If `"success": false`, use the [error recovery table](#error-recovery) and stop.
73
+
74
+ ### Step 5: Publish
75
+
76
+ ```bash
77
+ node "${CLAUDE_PLUGIN_ROOT}/src/scripts/payloadcms-publish.js" "<file>" --collection "<collection>" --status "<status>" --json --verbose
78
+ ```
79
+
80
+ Add `--id <id>` if updating an existing document.
81
+
82
+ ### Step 6: Report result
83
+
84
+ ```
85
+ PayloadCMS Publish Result
86
+ Action: created | updated
87
+ Document: <document.id>
88
+ Collection: <document.collection>
89
+ Title: <document.title>
90
+ Auto-generated: <list any fields you populated in Step 2>
91
+ ```
92
+
93
+ ## Script CLI reference
94
+
95
+ Script: `${CLAUDE_PLUGIN_ROOT}/src/scripts/payloadcms-publish.js`
96
+
97
+ | Flag | Description | Default |
98
+ |------|-------------|---------|
99
+ | `<file>` | Markdown file path (positional, or `--file`/`-f`) | Required |
100
+ | `--collection`, `-c` | Target collection | `posts` |
101
+ | `--status`, `-s` | `draft` or `published` | `draft` |
102
+ | `--id` | Document ID for updates | New document |
103
+ | `--dry-run` | Validate health + auth only | Off |
104
+ | `--json` | Machine-readable JSON on stdout | Off |
105
+ | `--verbose`, `-v` | Progress on stderr | Off |
106
+
107
+ **Always pass `--json --verbose`**.
108
+
109
+ ## Markdown file format
110
+
111
+ ```markdown
112
+ ---
113
+ title: My Article Title
114
+ slug: my-article-title
115
+ excerpt: A brief summary for listing pages.
116
+ meta:
117
+ title: SEO Title - Primary Keyword
118
+ description: Compelling meta description with keyword and implicit CTA.
119
+ heroImage: 64a1b2c3d4e5f6
120
+ tags: [tag1, tag2]
121
+ category: tutorials
122
+ ---
123
+
124
+ Your article content here with **bold**, *italic*, `code`, [links](https://...), lists, headings, and code blocks.
125
+ ```
126
+
127
+ Any frontmatter key maps directly to a PayloadCMS field. See [references/field-mapping.md](references/field-mapping.md) for all supported fields and patterns (hero images, SEO, excerpts, glossary, relationships).
128
+
129
+ See [references/lexical-format.md](references/lexical-format.md) for Lexical conversion details and supported node types.
130
+
131
+ ## Error recovery
132
+
133
+ | Error | Cause | Fix |
134
+ |-------|-------|-----|
135
+ | `Failed to load PayloadCMS configuration` | Missing `.env` | Run `/myaidev-method:configure payloadcms` |
136
+ | `PayloadCMS is not reachable` | Wrong URL or down | Check `PAYLOADCMS_URL` |
137
+ | `Authentication failed (401)` | Bad credentials | Check email/password |
138
+ | `HTTP 404` | Collection missing | Verify collection name |
139
+ | `HTTP 400` | Validation error | Check required fields against schema |
140
+ | `parseEditorState: type "X" not found` | Feature not enabled | Enable in Payload config: `BlocksFeature({ blocks: [CodeBlock()] })`, `ChecklistFeature()`, `TableFeature()` |
141
+ | `Media upload failed` | File not found or rejected | Check image paths relative to markdown file |
142
+
143
+ ## Examples
144
+
145
+ ```bash
146
+ # Publish as draft (auto-generates missing SEO fields)
147
+ /myaidev-method:payloadcms-publisher article.md
148
+
149
+ # Publish immediately
150
+ /myaidev-method:payloadcms-publisher article.md --status published
151
+
152
+ # Different collection
153
+ /myaidev-method:payloadcms-publisher article.md --collection tutorials
154
+
155
+ # Update existing
156
+ /myaidev-method:payloadcms-publisher article.md --id 60d5ec49f8d2e
157
+
158
+ # Dry run
159
+ /myaidev-method:payloadcms-publisher article.md --dry-run
96
160
  ```
@@ -0,0 +1,142 @@
1
+ # PayloadCMS Field Mapping
2
+
3
+ Frontmatter fields in the markdown source are mapped to PayloadCMS document fields by the publishing script.
4
+
5
+ ## Standard fields
6
+
7
+ | Frontmatter Key | PayloadCMS Field | Type | Auto-populated | Notes |
8
+ |-----------------|-----------------|------|----------------|-------|
9
+ | `title` | `title` | string | No | Required — must be set by user |
10
+ | `slug` | `slug` | string | Yes | Kebab-case from title, max 80 chars |
11
+ | `excerpt` | `excerpt` | textarea | Yes | 1-2 sentence summary, max 160 chars |
12
+ | `meta.title` | `meta.title` | string | Yes | SEO title with primary keyword, max 60 chars |
13
+ | `meta.description` | `meta.description` | string | Yes | Search snippet with keyword + CTA, max 155 chars |
14
+ | `heroImage` | `heroImage` | upload | Yes | Promoted from first content image if standalone |
15
+ | `tags` | `tags` | relationship[] | No | Array of tag names or IDs |
16
+ | `category` | `category` | relationship | No | Category name or ID |
17
+ | `status` | `status` | string | No | Overridden by `--status` CLI flag |
18
+
19
+ **Auto-populated** fields are generated by Claude during the publishing workflow (Step 2) when missing from frontmatter. User-provided values always take precedence.
20
+
21
+ ## How mapping works
22
+
23
+ The script uses `gray-matter` to parse YAML frontmatter, then spreads all frontmatter fields directly into the PayloadCMS document payload:
24
+
25
+ ```yaml
26
+ ---
27
+ title: My Post
28
+ customField: some value
29
+ nestedField:
30
+ subField: nested value
31
+ ---
32
+ ```
33
+
34
+ Becomes:
35
+
36
+ ```json
37
+ {
38
+ "title": "My Post",
39
+ "customField": "some value",
40
+ "nestedField": { "subField": "nested value" },
41
+ "content": { "root": { ... } },
42
+ "status": "draft"
43
+ }
44
+ ```
45
+
46
+ Any custom fields defined in your PayloadCMS collection schema can be set via frontmatter — the script passes them through as-is.
47
+
48
+ ## Hero image (featured image)
49
+
50
+ PayloadCMS handles hero/featured images as a collection-level `upload` field — not inside the Lexical editor. This is the same pattern as WordPress featured images.
51
+
52
+ ```yaml
53
+ ---
54
+ title: My Post
55
+ heroImage: 64a1b2c3d4e5f6 # media document ID
56
+ ---
57
+ ```
58
+
59
+ The field name depends on your collection schema (common names: `heroImage`, `featuredImage`, `image`, `hero.media`). Provide the media ID directly. If you need to upload first, use the `uploadMedia()` utility and reference the returned ID.
60
+
61
+ For nested hero fields:
62
+
63
+ ```yaml
64
+ ---
65
+ hero:
66
+ type: highImpact
67
+ media: 64a1b2c3d4e5f6
68
+ ---
69
+ ```
70
+
71
+ ## SEO / Meta fields
72
+
73
+ If your PayloadCMS instance uses `@payloadcms/plugin-seo`, SEO fields are collection-level (not Lexical nodes). The plugin adds a `meta` group field:
74
+
75
+ ```yaml
76
+ ---
77
+ title: My Post
78
+ meta:
79
+ title: SEO Title Override
80
+ description: Meta description for search engines
81
+ image: 64a1b2c3d4e5f6 # media ID for og:image
82
+ ---
83
+ ```
84
+
85
+ If your schema uses flat field names instead (no plugin), adjust accordingly:
86
+
87
+ ```yaml
88
+ ---
89
+ meta_title: SEO Title
90
+ meta_description: Meta description
91
+ ---
92
+ ```
93
+
94
+ ## Excerpt
95
+
96
+ Excerpts are typically a plain `textarea` field on the collection, not part of the Lexical editor:
97
+
98
+ ```yaml
99
+ ---
100
+ title: My Post
101
+ excerpt: A brief summary of the article shown in listing pages and social cards.
102
+ ---
103
+ ```
104
+
105
+ ## Glossary
106
+
107
+ PayloadCMS has no built-in glossary feature. Glossaries are implemented as either:
108
+
109
+ 1. **A separate `glossary` collection** with `term` and `definition` fields — reference terms via a relationship field on your post:
110
+
111
+ ```yaml
112
+ ---
113
+ glossaryTerms: [term-id-1, term-id-2]
114
+ ---
115
+ ```
116
+
117
+ 2. **A custom Lexical block** via `BlocksFeature` — these are rendered inside the rich text editor but require a custom block definition on the PayloadCMS instance. The markdown converter cannot produce custom blocks; they must be injected programmatically after conversion.
118
+
119
+ ## Relationship fields
120
+
121
+ Tags and categories are typically relationship fields in PayloadCMS. Provide either:
122
+ - **Names** (if your schema has a `name` field): `tags: [javascript, tutorial]`
123
+ - **IDs** (for direct references): `tags: [abc123, def456]`
124
+
125
+ The exact behavior depends on your PayloadCMS collection schema configuration.
126
+
127
+ ## Media uploads (in content body)
128
+
129
+ The publishing script automatically uploads images referenced in the markdown content body. During `publishContent()`:
130
+
131
+ 1. `<div class="infographic" ...>` and `</div>` wrapper lines are stripped
132
+ 2. Standalone `![alt](path)` image lines are detected
133
+ 3. Each image file is uploaded to `/api/media` via `uploadMedia()`
134
+ 4. The image reference is replaced with an `upload` Lexical node pointing to the media ID
135
+
136
+ Image paths are resolved relative to the markdown file's directory. If an image file doesn't exist or upload fails, a warning is logged and the image markdown is left as-is (rendered as text).
137
+
138
+ Media referenced in frontmatter fields (e.g. `heroImage`) is **not** auto-uploaded — provide a media ID directly for those fields.
139
+
140
+ ## Inline images
141
+
142
+ PayloadCMS Lexical does **not** support inline images. The `UploadNode` is block-level only (`isInline()` returns `false`). Images in content are always rendered as standalone blocks between paragraphs, never inline with text. This is a Lexical architecture constraint, not a limitation of this script.
@@ -0,0 +1,97 @@
1
+ # PayloadCMS Lexical Rich Text Format
2
+
3
+ PayloadCMS uses the Lexical editor by default. The publishing script converts markdown to Lexical JSON automatically via `convertMarkdownToLexical()` in `payloadcms-utils.js`, which uses a headless Lexical editor with PayloadCMS's own node classes and markdown transformers from `@payloadcms/richtext-lexical`.
4
+
5
+ ## Root structure
6
+
7
+ ```json
8
+ {
9
+ "root": {
10
+ "type": "root",
11
+ "format": "",
12
+ "indent": 0,
13
+ "version": 1,
14
+ "children": [ ... ],
15
+ "direction": null
16
+ }
17
+ }
18
+ ```
19
+
20
+ ## Supported node types
21
+
22
+ | Markdown | Lexical Node | Key Properties |
23
+ |----------|-------------|----------------|
24
+ | `# Heading` | `heading` | `tag: "h1"` through `"h6"` |
25
+ | Paragraph text | `paragraph` | `children: [text nodes]`, `textFormat`, `textStyle` |
26
+ | `- list item` | `list` + `listitem` | `listType: "bullet"` or `"number"`, `tag: "ul"` or `"ol"` |
27
+ | `> blockquote` | `quote` | Wraps text children directly |
28
+ | `---` | `horizontalrule` | DecoratorNode, no children |
29
+ | `[link](url)` | `link` | `fields: { url, linkType, newTab }`, `version: 3` |
30
+ | `\| col \| col \|` | `table` > `tablerow` > `tablecell` | `headerState: 0\|1`, `colSpan`, `rowSpan` |
31
+ | `![alt](path)` | `upload` | `relationTo: "media"`, `value: "<media-id>"`, `id: "<node-id>"`, `fields: {}`, `version: 3` |
32
+ | `` ```lang `` | `block` | `fields: { blockType: "Code", code, language, id }`, `version: 2` |
33
+ | `- [ ] item` | `list` + `listitem` | `listType: "check"`, `checked: true\|false` |
34
+
35
+ Code blocks (triple backticks) are converted to PayloadCMS `block` nodes with `blockType: "Code"` via the premade CodeBlock feature. The `language` field captures the language tag and `code` contains the block content. The PayloadCMS instance must have `BlocksFeature({ blocks: [CodeBlock()] })` enabled to render these blocks.
36
+
37
+ Checklists (`- [ ]` / `- [x]`) produce `list` nodes with `listType: "check"`. Each `listitem` has a `checked` boolean. The PayloadCMS instance must have `ChecklistFeature()` enabled.
38
+
39
+ Images (`![alt](path)`) are handled during `publishContent()` — the file is uploaded to the `media` collection first, then an `upload` node referencing the media ID is injected into the Lexical JSON. Upload nodes require both an `id` (unique node identifier, not the media document ID) and a `fields` object (can be empty `{}`). Without these, the PayloadCMS frontend renderer fails to display the image in preview. Tables require the `EXPERIMENTAL_TableFeature` to be enabled on the PayloadCMS instance.
40
+
41
+ ## Text formatting (bitwise flags)
42
+
43
+ Inline formatting uses Lexical's bitwise format codes:
44
+
45
+ | Format | Code | Markdown |
46
+ |--------|------|----------|
47
+ | Plain | `0` | `text` |
48
+ | Bold | `1` | `**text**` |
49
+ | Italic | `2` | `*text*` |
50
+ | Bold + Italic | `3` | `***text***` |
51
+ | Strikethrough | `4` | `~~text~~` |
52
+ | Underline | `8` | N/A |
53
+ | Code | `16` | `` `text` `` |
54
+ | Subscript | `32` | N/A |
55
+ | Superscript | `64` | N/A |
56
+ | Highlight | `128` | `==text==` |
57
+
58
+ Formats combine via bitwise OR. For example, bold italic code = `1 | 2 | 16 = 19`.
59
+
60
+ ## Text node structure
61
+
62
+ ```json
63
+ {
64
+ "type": "text",
65
+ "text": "Hello world",
66
+ "format": 0,
67
+ "mode": "normal",
68
+ "style": "",
69
+ "detail": 0,
70
+ "version": 1
71
+ }
72
+ ```
73
+
74
+ ## Coverage: markdown-producible vs non-markdown nodes
75
+
76
+ The converter handles **every Lexical node type that can be produced from markdown input**. The table above is the complete set.
77
+
78
+ PayloadCMS's default Lexical editor also registers these node types, which are **not producible from markdown** and therefore not part of this conversion pipeline:
79
+
80
+ | Node | Purpose | How to use |
81
+ |------|---------|------------|
82
+ | `relationship` | Embed a reference to another collection document | Programmatic only — use `RelationshipServerNode` |
83
+ | `autolink` | Auto-detected URLs in editor typing | Client-side only — never produced from markdown |
84
+
85
+ These nodes exist for interactive editor use and API round-tripping, not markdown conversion.
86
+
87
+ ### What about hero images, SEO, excerpts?
88
+
89
+ These are **collection-level fields**, not Lexical editor nodes. They're set via frontmatter and passed through to the PayloadCMS API payload. See [field-mapping.md](field-mapping.md) for details.
90
+
91
+ ### Inline images
92
+
93
+ PayloadCMS Lexical does not support inline images. `UploadNode` is block-level only. Images are always rendered as standalone blocks between paragraphs.
94
+
95
+ ## Validation
96
+
97
+ The converter uses Lexical's own serialization (`editor.getEditorState().toJSON()`), so the output is guaranteed to be structurally valid. No separate validation step is needed — the JSON is identical to what PayloadCMS's editor produces.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: security-auditor
3
3
  description: Performs security compliance audits and code security reviews against industry standards (OWASP, SOC2, HIPAA, PCI-DSS). Use when auditing code for security vulnerabilities, checking compliance, or generating security reports.
4
- argument-hint: [path] [--standard=owasp]
4
+ argument-hint: "[path] [--standard=owasp]"
5
5
  allowed-tools: [Read, Glob, Grep, Task, WebSearch]
6
6
  ---
7
7